mirror of
https://github.com/holub/mame
synced 2025-04-23 00:39:36 +03:00
dc7061: new device stub
This commit is contained in:
parent
c398cf3073
commit
e4ab1b97db
701
src/mame/dec/dc7061.cpp
Normal file
701
src/mame/dec/dc7061.cpp
Normal file
@ -0,0 +1,701 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Patrick Mackinlay
|
||||
|
||||
/*
|
||||
* DEC DC7061 SII SCSI gate array.
|
||||
*
|
||||
* Sources:
|
||||
* - DECstation 3100 Desktop Workstation Functional Specification, Revision 1.3, August 28, 1990, Workstation Systems Engineering, Digital Equipment Corporation
|
||||
*
|
||||
* TODO:
|
||||
* - everything, stub only
|
||||
*/
|
||||
/*
|
||||
* WIP notes:
|
||||
* boot -f rz(0,4,0)vmunix
|
||||
*
|
||||
[:scsi:7:sii] csr_w 0x0010 (':cpu' (BFC12F24)) # enable bus arbitration
|
||||
[:scsi:7:sii] id_w 0x8006 (':cpu' (BFC12F8C)) # set scsi id
|
||||
[:scsi:7:sii] dmctrl_w 0x0000 (':cpu' (BFC12F94)) # clear req/ack offset
|
||||
[:scsi:7:sii] cstat_w 0x3080 (':cpu' (BFC12FA0)) # clear rst|ber|sch
|
||||
[:scsi:7:sii] dictrl_w 0x0004 (':cpu' (BFC12FAC)) # enable port
|
||||
[:scsi:7:sii] comm_w 0x4000 (':cpu' (BFC12FB8)) # scsi reset
|
||||
[:scsi:7:sii] cstat_w 0x2080 (':cpu' (BFC12FE0)) # clear rst|sch
|
||||
[:scsi:7:sii] csr_w 0x001f (':cpu' (BFC12FF4)) # enable reseletion, selection, parity and interrupts
|
||||
[:scsi:7:sii] cstat_w 0x0300 (':cpu' (BFC12304)) # clear rst|ber
|
||||
[:scsi:7:sii] slcsr_w 0x0004 (':cpu' (BFC12400)) # target id 4
|
||||
[:scsi:7:sii] comm_w 0x0400 (':cpu' (BFC1240C)) # select
|
||||
[:scsi:7:sii] comm_w 0x0100 (':cpu' (BFC12AE0)) # disconnect
|
||||
[:] control_w 0x0040
|
||||
[:scsi:7:sii] comm_w 0x0000 (':cpu' (BFC12B3C)) # no command?
|
||||
[:] control_w 0x002c
|
||||
[:scsi:7:sii] cstat_w 0x0300 (':cpu' (BFC12304)) # clear rst|ber
|
||||
[:scsi:7:sii] slcsr_w 0x0004 (':cpu' (BFC12400)) # target id 4
|
||||
[:scsi:7:sii] comm_w 0x0400 (':cpu' (BFC1240C)) # select
|
||||
[:scsi:7:sii] comm_w 0x0100 (':cpu' (BFC12AE0)) # disconnect
|
||||
[:] control_w 0x0040
|
||||
[:scsi:7:sii] comm_w 0x0000 (':cpu' (BFC12B3C)) # no command?
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
#include "dc7061.h"
|
||||
|
||||
#define LOG_REGW (1U << 1)
|
||||
#define LOG_REGR (1U << 2)
|
||||
#define LOG_SCSI (1U << 3)
|
||||
#define LOG_ARB (1U << 4)
|
||||
#define LOG_SEL (1U << 5)
|
||||
#define LOG_PIO (1U << 6)
|
||||
#define LOG_DMA (1U << 7)
|
||||
|
||||
//#define VERBOSE (LOG_GENERAL|LOG_REGW|LOG_REGR|LOG_SCSI|LOG_ARB|LOG_SEL|LOG_PIO|LOG_DMA)
|
||||
#include "logmacro.h"
|
||||
|
||||
enum sdb_mask : u16
|
||||
{
|
||||
SDB_DATA = 0x00ff,
|
||||
SDB_PTY = 0x0100,
|
||||
SDB_MSK = 0x01ff,
|
||||
};
|
||||
enum sc1_mask : u16
|
||||
{
|
||||
SC1_IO = 0x0001,
|
||||
SC1_CD = 0x0002,
|
||||
SC1_MSG = 0x0004,
|
||||
SC1_ATN = 0x0008,
|
||||
SC1_REQ = 0x0010,
|
||||
SC1_ACK = 0x0020,
|
||||
SC1_RST = 0x0040,
|
||||
SC1_SEL = 0x0080,
|
||||
SC1_BSY = 0x0100,
|
||||
SC1_MSK = 0x01ff,
|
||||
};
|
||||
enum sc2_mask : u16
|
||||
{
|
||||
SC2_SBE = 0x0001, // drive scsi data bus and parity lines
|
||||
SC2_ARB = 0x0002, // enable scsi drivers for arbitration
|
||||
SC2_TGS = 0x0004, // steer scsi drivers for target role
|
||||
SC2_IGS = 0x0008, // steer scsi drivers for initiator role
|
||||
SC2_MSK = 0x000f,
|
||||
};
|
||||
enum csr_mask : u16
|
||||
{
|
||||
CSR_IE = 0x0001, // interrupt enable
|
||||
CSR_PCE = 0x0002, // parity check enable
|
||||
CSR_SLE = 0x0004, // selection enable
|
||||
CSR_RSE = 0x0008, // reselection enable
|
||||
CSR_HPM = 0x0010, // host bus arbitration enable
|
||||
CSR_MSK = 0x001f,
|
||||
};
|
||||
enum id_mask : u16
|
||||
{
|
||||
ID_ID = 0x0007, // bus id
|
||||
ID_IO = 0x8000, // id output enable
|
||||
ID_MSK = 0x8007,
|
||||
};
|
||||
enum slcsr_mask : u16
|
||||
{
|
||||
SLCSR_ID = 0x0007, // select/reselect destination id
|
||||
SLCSR_MSK = 0x0007,
|
||||
};
|
||||
enum destat_mask : u16
|
||||
{
|
||||
DESTAT_ID = 0x0007, // select source id
|
||||
DESTAT_MSK = 0x0007,
|
||||
};
|
||||
enum dmctrl_mask : u16
|
||||
{
|
||||
DMCTRL_RAO = 0x0003, // req/ack offset
|
||||
DMCTRL_MSK = 0x0003,
|
||||
};
|
||||
enum dmlotc_mask : u16
|
||||
{
|
||||
DMLOTC_CNT = 0x1fff, // transfer count
|
||||
DMLOTC_MSK = 0x1fff,
|
||||
};
|
||||
enum dmaddrh_mask : u16
|
||||
{
|
||||
DMADDRH_ADR = 0x0003, // dma address high
|
||||
DMADDRH_MSK = 0x0003,
|
||||
};
|
||||
enum cstat_mask : u16
|
||||
{
|
||||
// * indicates interrupt source
|
||||
CSTAT_LST = 0x0002, // lost arbitration (r/o)
|
||||
CSTAT_SIP = 0x0004, // selection in progress (r/o)
|
||||
CSTAT_SWA = 0x0008, // selected with atn (w1c)
|
||||
CSTAT_TGT = 0x0010, // target (r/o)
|
||||
CSTAT_DST = 0x0020, // destination (r/o)
|
||||
CSTAT_CON = 0x0040, // connected (r/o)
|
||||
CSTAT_SCH = 0x0080, // state change (w1c, *)
|
||||
CSTAT_LDN = 0x0100, // unused (w1c?, *)
|
||||
CSTAT_BUF = 0x0200, // unused (w1c?, *)
|
||||
CSTAT_TZ = 0x0400, // unused
|
||||
CSTAT_OBC = 0x0800, // unused (w1c?, *)
|
||||
CSTAT_BER = 0x1000, // bus error (w1c, *)
|
||||
CSTAT_RST = 0x2000, // rst asserted (w1c, *)
|
||||
CSTAT_DI = 0x4000, // dstat interrupt (r/o)
|
||||
CSTAT_CI = 0x8000, // cstat interrupt (r/o)
|
||||
CSTAT_MSK = 0x3f88,
|
||||
CSTAT_W1C = 0x3b88,
|
||||
};
|
||||
enum dstat_mask : u16
|
||||
{
|
||||
// * indicates interrupt source
|
||||
DSTAT_IO = 0x0001, // i/o asserted (r/o)
|
||||
DSTAT_CD = 0x0002, // c/d asserted (r/o)
|
||||
DSTAT_MSG = 0x0004, // msg asserted (r/o)
|
||||
DSTAT_ATN = 0x0008, // atn asserted (w1c)
|
||||
DSTAT_MIS = 0x0010, // phase mismatch (r/o?, *)
|
||||
DSTAT_OBB = 0x0100, // odd byte boundary (r/o?)
|
||||
DSTAT_IPE = 0x0200, // incoming parity error (r/o?)
|
||||
DSTAT_IBF = 0x0400, // input buffer full (r/o?, *)
|
||||
DSTAT_TBE = 0x0800, // transmit buffer empty (r/o?, *)
|
||||
DSTAT_TCZ = 0x1000, // transfer counter zero (r/o?)
|
||||
DSTAT_DNE = 0x2000, // transfer done (w1c, *)
|
||||
DSTAT_DI = 0x4000, // dstat interrupt (r/o)
|
||||
DSTAT_CI = 0x8000, // cstat interrupt (r/o)
|
||||
DSTAT_MSK = 0x2008,
|
||||
DSTAT_W1C = 0x2008,
|
||||
};
|
||||
enum comm_mask : u16
|
||||
{
|
||||
COMM_IO = 0x0001, // assert i/o (t)
|
||||
COMM_CD = 0x0002, // assert c/d (t)
|
||||
COMM_MSG = 0x0004, // assert msg (t)
|
||||
COMM_ATN = 0x0008, // assert atn (i)
|
||||
COMM_TGT = 0x0010, // expect target
|
||||
COMM_DST = 0x0020, // expect destination
|
||||
COMM_CON = 0x0040, // expect connected
|
||||
COMM_CMD = 0x0f80, // command
|
||||
COMM_RSL = 0x1000, // attempt reselection
|
||||
COMM_RST = 0x4000, // assert rst
|
||||
COMM_DMA = 0x8000, // dma enable
|
||||
COMM_MSK = 0x9fff,
|
||||
COMM_PHM = 0x0007,
|
||||
};
|
||||
enum comm_cmd_mask : u16
|
||||
{
|
||||
CMD_RST = 0x0080, // chip reset
|
||||
CMD_DSC = 0x0100, // disconnect
|
||||
CMD_REQ = 0x0200, // request data
|
||||
CMD_SEL = 0x0400, // select
|
||||
CMD_XFR = 0x0800, // information transfer
|
||||
};
|
||||
enum dictrl_mask : u16
|
||||
{
|
||||
DICTRL_TST = 0x0001, // test mode
|
||||
DICTRL_DIA = 0x0002, // external loopback
|
||||
DICTRL_PRE = 0x0004, // port enable
|
||||
DICTRL_LPB = 0x0008, // internal loopback
|
||||
DICTRL_MSK = 0x000f,
|
||||
};
|
||||
|
||||
enum state : u32
|
||||
{
|
||||
IDLE,
|
||||
|
||||
// arbitration
|
||||
ARB_BUS_FREE,
|
||||
ARB_START,
|
||||
ARB_EVALUATE,
|
||||
|
||||
// selection
|
||||
SEL_START,
|
||||
SEL_DELAY,
|
||||
SEL_WAIT_BSY,
|
||||
SEL_COMPLETE,
|
||||
|
||||
XFR_DMA,
|
||||
XFR_DMA_IN_REQ,
|
||||
XFR_DMA_IN_ACK,
|
||||
XFR_DMA_OUT,
|
||||
|
||||
XFR_PIO,
|
||||
XFR_PIO_IN,
|
||||
XFR_PIO_OUT,
|
||||
XFR_PIO_OUT_ACK,
|
||||
|
||||
// dma transfer
|
||||
DMA_IN_REQ,
|
||||
DMA_IN_ACK,
|
||||
DMA_OUT_REQ,
|
||||
DMA_OUT_DRQ,
|
||||
DMA_OUT_ACK,
|
||||
};
|
||||
|
||||
static unsigned const SCSI_ARB_DELAY = 2'400;
|
||||
static unsigned const SCSI_BUS_CLEAR = 800;
|
||||
static unsigned const SCSI_BUS_FREE = 800;
|
||||
static unsigned const SCSI_BUS_SETTLE = 400;
|
||||
static unsigned const SCSI_BUS_SKEW = 10;
|
||||
static unsigned const SCSI_RST_HOLD = 25'000;
|
||||
|
||||
DEFINE_DEVICE_TYPE(DC7061, dc7061_device, "dc7061", "DEC DC7061 SII")
|
||||
|
||||
dc7061_device::dc7061_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
|
||||
: nscsi_device(mconfig, DC7061, tag, owner, clock)
|
||||
, nscsi_slot_card_interface(mconfig, *this, DEVICE_SELF)
|
||||
, m_sys_int(*this)
|
||||
, m_dma_r(*this, 0)
|
||||
, m_dma_w(*this)
|
||||
{
|
||||
}
|
||||
|
||||
void dc7061_device::map(address_map &map)
|
||||
{
|
||||
map(0x00, 0x01).rw(FUNC(dc7061_device::sdb_r), FUNC(dc7061_device::sdb_w));
|
||||
map(0x02, 0x03).rw(FUNC(dc7061_device::sc1_r), FUNC(dc7061_device::sc1_w));
|
||||
map(0x04, 0x05).rw(FUNC(dc7061_device::sc2_r), FUNC(dc7061_device::sc2_w));
|
||||
map(0x06, 0x07).rw(FUNC(dc7061_device::csr_r), FUNC(dc7061_device::csr_w));
|
||||
map(0x08, 0x09).rw(FUNC(dc7061_device::id_r), FUNC(dc7061_device::id_w));
|
||||
map(0x0a, 0x0b).rw(FUNC(dc7061_device::slcsr_r), FUNC(dc7061_device::slcsr_w));
|
||||
map(0x0c, 0x0d).r(FUNC(dc7061_device::destat_r));
|
||||
//map(0x0e, 0x0f).rw(FUNC(dc7061_device::dstmo_r), FUNC(dc7061_device::dstmo_w));
|
||||
map(0x10, 0x11).rw(FUNC(dc7061_device::data_r), FUNC(dc7061_device::data_w));
|
||||
map(0x12, 0x13).rw(FUNC(dc7061_device::dmctrl_r), FUNC(dc7061_device::dmctrl_w));
|
||||
map(0x14, 0x15).rw(FUNC(dc7061_device::dmlotc_r), FUNC(dc7061_device::dmlotc_w));
|
||||
map(0x16, 0x17).rw(FUNC(dc7061_device::dmaddrl_r), FUNC(dc7061_device::dmaddrl_w));
|
||||
map(0x18, 0x19).rw(FUNC(dc7061_device::dmaddrh_r), FUNC(dc7061_device::dmaddrh_w));
|
||||
map(0x1a, 0x1b).rw(FUNC(dc7061_device::dmabyte_r), FUNC(dc7061_device::dmabyte_w));
|
||||
//map(0x1c, 0x1d).rw(FUNC(dc7061_device::stlp_r), FUNC(dc7061_device::stlp_w));
|
||||
//map(0x1e, 0x1f).rw(FUNC(dc7061_device::ltlp_r), FUNC(dc7061_device::ltlp_w));
|
||||
//map(0x20, 0x21).rw(FUNC(dc7061_device::ilp_r), FUNC(dc7061_device::ilp_w));
|
||||
//map(0x22, 0x23).rw(FUNC(dc7061_device::dsctrl_r), FUNC(dc7061_device::dsctrl_w));
|
||||
map(0x24, 0x25).rw(FUNC(dc7061_device::cstat_r), FUNC(dc7061_device::cstat_w));
|
||||
map(0x26, 0x27).rw(FUNC(dc7061_device::dstat_r), FUNC(dc7061_device::dstat_w));
|
||||
map(0x28, 0x29).rw(FUNC(dc7061_device::comm_r), FUNC(dc7061_device::comm_w));
|
||||
map(0x2a, 0x2b).rw(FUNC(dc7061_device::dictrl_r), FUNC(dc7061_device::dictrl_w));
|
||||
}
|
||||
|
||||
void dc7061_device::device_start()
|
||||
{
|
||||
m_state_timer = timer_alloc(timer_expired_delegate(FUNC(dc7061_device::state_timer), this));
|
||||
|
||||
save_item(NAME(m_state));
|
||||
|
||||
save_item(NAME(m_sdb));
|
||||
save_item(NAME(m_sc1));
|
||||
save_item(NAME(m_sc2));
|
||||
save_item(NAME(m_csr));
|
||||
save_item(NAME(m_id));
|
||||
save_item(NAME(m_slcsr));
|
||||
save_item(NAME(m_destat));
|
||||
save_item(NAME(m_data));
|
||||
save_item(NAME(m_dmctrl));
|
||||
save_item(NAME(m_dmlotc));
|
||||
save_item(NAME(m_dmaddrl));
|
||||
save_item(NAME(m_dmaddrh));
|
||||
save_item(NAME(m_dmabyte));
|
||||
save_item(NAME(m_cstat));
|
||||
save_item(NAME(m_dstat));
|
||||
save_item(NAME(m_comm));
|
||||
save_item(NAME(m_dictrl));
|
||||
|
||||
save_item(NAME(m_scsi_ctrl));
|
||||
save_item(NAME(m_sys_int_state));
|
||||
}
|
||||
|
||||
void dc7061_device::device_reset()
|
||||
{
|
||||
m_state = IDLE;
|
||||
|
||||
// clear scsi bus
|
||||
scsi_bus->data_w(scsi_refid, 0);
|
||||
scsi_bus->ctrl_w(scsi_refid, 0, S_ALL);
|
||||
|
||||
// monitor all control lines
|
||||
m_scsi_ctrl = 0;
|
||||
scsi_bus->ctrl_wait(scsi_refid, S_ALL, S_ALL);
|
||||
|
||||
// clear output lines
|
||||
set_irq(false);
|
||||
}
|
||||
|
||||
void dc7061_device::scsi_ctrl_changed()
|
||||
{
|
||||
u32 const ctrl = scsi_bus->ctrl_r();
|
||||
|
||||
if (VERBOSE & LOG_SCSI)
|
||||
{
|
||||
static char const *const nscsi_phase[] = { "DATA OUT", "DATA IN", "COMMAND", "STATUS", "*", "*", "MESSAGE OUT", "MESSAGE IN" };
|
||||
|
||||
if (ctrl & S_RST)
|
||||
LOGMASKED(LOG_SCSI, "scsi_ctrl_changed 0x%x BUS RESET\n", ctrl);
|
||||
else if ((ctrl & S_BSY) && !(ctrl & S_SEL))
|
||||
LOGMASKED(LOG_SCSI, "scsi_ctrl_changed 0x%x phase %s%s%s\n", ctrl, nscsi_phase[ctrl & S_PHASE_MASK],
|
||||
ctrl & S_REQ ? " REQ" : "", ctrl & S_ACK ? " ACK" : "");
|
||||
else if (ctrl & S_BSY)
|
||||
LOGMASKED(LOG_SCSI, "scsi_ctrl_changed 0x%x arbitration/selection\n", ctrl);
|
||||
else
|
||||
LOGMASKED(LOG_SCSI, "scsi_ctrl_changed 0x%x BUS FREE\n", ctrl);
|
||||
}
|
||||
|
||||
if (ctrl & S_RST)
|
||||
{
|
||||
LOG("scsi reset received\n");
|
||||
device_reset();
|
||||
|
||||
set_irq(true);
|
||||
}
|
||||
else if (!(m_cstat & CSTAT_TGT) && (m_scsi_ctrl & S_BSY) && !(ctrl & S_BSY))
|
||||
{
|
||||
LOG("target disconnected\n");
|
||||
m_state = IDLE;
|
||||
m_state_timer->enable(false);
|
||||
|
||||
// clear scsi bus
|
||||
scsi_bus->data_w(scsi_refid, 0);
|
||||
scsi_bus->ctrl_w(scsi_refid, 0, S_ALL);
|
||||
}
|
||||
else if (!(m_scsi_ctrl & S_REQ) && (ctrl & S_REQ))
|
||||
{
|
||||
// target asserted REQ
|
||||
if ((ctrl & S_PHASE_MASK) == (m_comm & COMM_PHM))
|
||||
{
|
||||
if (m_comm & COMM_DMA)
|
||||
{
|
||||
// transfer cycle
|
||||
if (m_state != IDLE && !m_state_timer->enabled())
|
||||
m_state_timer->adjust(attotime::zero);
|
||||
}
|
||||
else
|
||||
set_dstat(DSTAT_TBE, DSTAT_TBE);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("phase mismatch %d != %d\n", ctrl & S_PHASE_MASK, m_comm & COMM_PHM);
|
||||
|
||||
m_state = IDLE;
|
||||
m_state_timer->enable(false);
|
||||
|
||||
if (ctrl & S_INP)
|
||||
set_dstat(DSTAT_MIS | DSTAT_TBE, DSTAT_MIS | DSTAT_TBE);
|
||||
else
|
||||
set_dstat(DSTAT_MIS, DSTAT_MIS);
|
||||
}
|
||||
}
|
||||
|
||||
m_scsi_ctrl = ctrl;
|
||||
}
|
||||
|
||||
void dc7061_device::set_cstat(u16 data, u16 mask)
|
||||
{
|
||||
m_cstat = (m_cstat & ~mask) | (data & mask);
|
||||
|
||||
if (m_cstat & (CSTAT_RST | CSTAT_BER | CSTAT_OBC | CSTAT_BUF | CSTAT_LDN | CSTAT_SCH))
|
||||
{
|
||||
m_dstat |= DSTAT_CI;
|
||||
m_cstat |= CSTAT_CI;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dstat &= ~DSTAT_CI;
|
||||
m_cstat &= ~CSTAT_CI;
|
||||
}
|
||||
|
||||
set_irq(m_cstat & (CSTAT_CI | CSTAT_DI));
|
||||
}
|
||||
|
||||
void dc7061_device::set_dstat(u16 data, u16 mask)
|
||||
{
|
||||
m_dstat = (m_dstat & ~mask) | (data & mask);
|
||||
|
||||
if (m_dstat & (DSTAT_DNE | DSTAT_TBE | DSTAT_IBF | DSTAT_MIS))
|
||||
{
|
||||
m_dstat |= DSTAT_DI;
|
||||
m_cstat |= CSTAT_DI;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dstat &= ~DSTAT_DI;
|
||||
m_cstat &= ~CSTAT_DI;
|
||||
}
|
||||
|
||||
set_irq(m_dstat & (DSTAT_CI | DSTAT_DI));
|
||||
}
|
||||
|
||||
void dc7061_device::set_irq(bool irq_state)
|
||||
{
|
||||
if (irq_state != m_sys_int_state)
|
||||
{
|
||||
LOG("set_irq %d cstat 0x%04x dstat 0x%04x\n", irq_state, m_cstat, m_dstat);
|
||||
|
||||
m_sys_int_state = irq_state;
|
||||
m_sys_int(m_sys_int_state);
|
||||
}
|
||||
}
|
||||
|
||||
u16 dc7061_device::sdb_r() { LOGMASKED(LOG_REGR, "sdb_r 0x%04x (%s)\n", m_sdb, machine().describe_context()); return m_sdb; }
|
||||
u16 dc7061_device::sc1_r() { LOGMASKED(LOG_REGR, "sc1_r 0x%04x (%s)\n", m_sc1, machine().describe_context()); return m_sc1; }
|
||||
u16 dc7061_device::sc2_r() { LOGMASKED(LOG_REGR, "sc2_r 0x%04x (%s)\n", m_sc2, machine().describe_context()); return m_sc2; }
|
||||
u16 dc7061_device::csr_r() { LOGMASKED(LOG_REGR, "csr_r 0x%04x (%s)\n", m_csr, machine().describe_context()); return m_csr; }
|
||||
u16 dc7061_device::id_r() { LOGMASKED(LOG_REGR, "id_r 0x%04x (%s)\n", m_id, machine().describe_context()); return m_id; }
|
||||
u16 dc7061_device::slcsr_r() { LOGMASKED(LOG_REGR, "slcsr_r 0x%04x (%s)\n", m_slcsr, machine().describe_context()); return m_slcsr; }
|
||||
u16 dc7061_device::destat_r() { LOGMASKED(LOG_REGR, "destat_r 0x%04x (%s)\n", m_destat, machine().describe_context()); return m_destat; }
|
||||
u16 dc7061_device::data_r() { LOGMASKED(LOG_REGR, "data_r 0x%04x (%s)\n", m_data, machine().describe_context()); return m_data; }
|
||||
u16 dc7061_device::dmctrl_r() { LOGMASKED(LOG_REGR, "dmctrl_r 0x%04x (%s)\n", m_dmctrl, machine().describe_context()); return m_dmctrl; }
|
||||
u16 dc7061_device::dmlotc_r() { LOGMASKED(LOG_REGR, "dmlotc_r 0x%04x (%s)\n", m_dmlotc, machine().describe_context()); return m_dmlotc; }
|
||||
u16 dc7061_device::dmaddrl_r() { LOGMASKED(LOG_REGR, "dmaddrl_r 0x%04x (%s)\n", m_dmaddrl, machine().describe_context()); return m_dmaddrl; }
|
||||
u16 dc7061_device::dmaddrh_r() { LOGMASKED(LOG_REGR, "dmaddrh_r 0x%04x (%s)\n", m_dmaddrh, machine().describe_context()); return m_dmaddrh; }
|
||||
u16 dc7061_device::dmabyte_r() { LOGMASKED(LOG_REGR, "dmabyte_r 0x%04x (%s)\n", m_dmabyte, machine().describe_context()); return m_dmabyte; }
|
||||
u16 dc7061_device::cstat_r() { LOGMASKED(LOG_REGR, "cstat_r 0x%04x (%s)\n", m_cstat, machine().describe_context()); return m_cstat; }
|
||||
|
||||
u16 dc7061_device::dstat_r()
|
||||
{
|
||||
u16 const data = m_dstat | (scsi_bus->ctrl_r() & S_PHASE_MASK);
|
||||
|
||||
LOGMASKED(LOG_REGR, "dstat_r 0x%04x (%s)\n", data, machine().describe_context());
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
u16 dc7061_device::comm_r() { logerror("comm_r 0x%04x (%s)\n", m_comm, machine().describe_context()); return m_comm; }
|
||||
u16 dc7061_device::dictrl_r() { logerror("dictrl_r 0x%04x (%s)\n", m_dictrl, machine().describe_context()); return m_dictrl; }
|
||||
|
||||
void dc7061_device::sdb_w(u16 data) { LOGMASKED(LOG_REGW, "sdb_w 0x%04x (%s)\n", data, machine().describe_context()); m_sdb = data & SDB_MSK; }
|
||||
void dc7061_device::sc1_w(u16 data) { LOGMASKED(LOG_REGW, "sc1_w 0x%04x (%s)\n", data, machine().describe_context()); m_sc1 = data & SC1_MSK; }
|
||||
void dc7061_device::sc2_w(u16 data) { LOGMASKED(LOG_REGW, "sc2_w 0x%04x (%s)\n", data, machine().describe_context()); m_sc2 = data & SC2_MSK; }
|
||||
void dc7061_device::csr_w(u16 data) { LOGMASKED(LOG_REGW, "csr_w 0x%04x (%s)\n", data, machine().describe_context()); m_csr = data & CSR_MSK; }
|
||||
void dc7061_device::id_w(u16 data) { LOGMASKED(LOG_REGW, "src id %d (%s)\n", data & ID_ID, machine().describe_context()); m_id = data & ID_MSK; }
|
||||
void dc7061_device::slcsr_w(u16 data) { LOGMASKED(LOG_REGW, "dst id %d (%s)\n", data & SLCSR_ID, machine().describe_context()); m_slcsr = data & SLCSR_MSK; }
|
||||
|
||||
void dc7061_device::data_w(u16 data)
|
||||
{
|
||||
LOGMASKED(LOG_REGW, "data_w 0x%04x (%s)\n", data, machine().describe_context());
|
||||
m_data = u8(data);
|
||||
}
|
||||
|
||||
void dc7061_device::dmctrl_w(u16 data) { LOGMASKED(LOG_REGW, "dmctrl_w 0x%04x (%s)\n", data, machine().describe_context()); m_dmctrl = data & DMCTRL_MSK; }
|
||||
void dc7061_device::dmlotc_w(u16 data) { LOGMASKED(LOG_REGW, "dmlotc_w 0x%04x (%s)\n", data, machine().describe_context()); m_dmlotc = data & DMLOTC_MSK; }
|
||||
void dc7061_device::dmaddrl_w(u16 data) { LOGMASKED(LOG_REGW, "dmaddrl_w 0x%04x (%s)\n", data, machine().describe_context()); m_dmaddrl = data; }
|
||||
void dc7061_device::dmaddrh_w(u16 data) { LOGMASKED(LOG_REGW, "dmaddrh_w 0x%04x (%s)\n", data, machine().describe_context()); m_dmaddrh = data & DMADDRH_MSK; }
|
||||
void dc7061_device::dmabyte_w(u16 data) { LOGMASKED(LOG_REGW, "dmabyte_w 0x%04x (%s)\n", data, machine().describe_context()); m_dmabyte = u8(data); }
|
||||
|
||||
void dc7061_device::cstat_w(u16 data)
|
||||
{
|
||||
LOGMASKED(LOG_REGW, "cstat_w 0x%04x (%s)\n", data, machine().describe_context());
|
||||
|
||||
m_cstat = (m_cstat & (~CSTAT_MSK & ~(data & CSTAT_W1C))) | (data & (CSTAT_MSK & ~CSTAT_W1C));
|
||||
|
||||
set_cstat(0, 0);
|
||||
}
|
||||
|
||||
void dc7061_device::dstat_w(u16 data)
|
||||
{
|
||||
LOGMASKED(LOG_REGW, "dstat_w 0x%04x (%s)\n", data, machine().describe_context());
|
||||
|
||||
m_dstat = (m_dstat & (~DSTAT_MSK & ~(data & DSTAT_W1C))) | (data & (DSTAT_MSK & ~DSTAT_W1C));
|
||||
|
||||
set_dstat(0, 0);
|
||||
}
|
||||
|
||||
void dc7061_device::comm_w(u16 data)
|
||||
{
|
||||
LOGMASKED(LOG_REGW, "comm_w 0x%04x (%s)\n", data, machine().describe_context());
|
||||
m_comm = data & COMM_MSK;
|
||||
|
||||
set_dstat((scsi_bus->ctrl_r() & S_PHASE_MASK) == (m_comm & COMM_PHM) ? 0 : DSTAT_MIS, DSTAT_MIS);
|
||||
|
||||
switch (data & COMM_CMD)
|
||||
{
|
||||
case CMD_RST:
|
||||
LOG("chip reset\n");
|
||||
reset();
|
||||
break;
|
||||
case CMD_DSC:
|
||||
LOG("disconnect\n");
|
||||
set_cstat(0, CSTAT_CON | CSTAT_SIP | CSTAT_LST); // CHECK:
|
||||
|
||||
scsi_bus->data_w(scsi_refid, 0);
|
||||
scsi_bus->ctrl_w(scsi_refid, 0, S_ATN | S_SEL | S_BSY); // CHECK:
|
||||
break;
|
||||
case CMD_REQ:
|
||||
LOG("request data\n");
|
||||
break;
|
||||
case CMD_SEL:
|
||||
LOG("select id %d\n", m_slcsr & SLCSR_ID);
|
||||
m_state = ARB_BUS_FREE;
|
||||
m_state_timer->adjust(attotime::zero);
|
||||
break;
|
||||
case CMD_XFR:
|
||||
LOG("information transfer\n");
|
||||
m_state = (m_comm & COMM_DMA) ? XFR_DMA : XFR_PIO;
|
||||
m_state_timer->adjust(attotime::zero);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void dc7061_device::dictrl_w(u16 data) { LOGMASKED(LOG_REGW, "dictrl_w 0x%04x (%s)\n", data, machine().describe_context()); m_dictrl = data & DICTRL_MSK; }
|
||||
|
||||
void dc7061_device::state_timer(s32 param)
|
||||
{
|
||||
// step state machine
|
||||
int const delay = state_step();
|
||||
|
||||
// check for data stall
|
||||
if (delay < 0)
|
||||
return;
|
||||
|
||||
// repeat until idle
|
||||
if (m_state != IDLE)
|
||||
m_state_timer->adjust(attotime::from_nsec(delay));
|
||||
}
|
||||
|
||||
int dc7061_device::state_step()
|
||||
{
|
||||
int delay = 0;
|
||||
|
||||
u8 const oid = 1 << m_id;
|
||||
u8 const tid = 1 << m_slcsr;
|
||||
|
||||
switch (m_state)
|
||||
{
|
||||
case IDLE:
|
||||
break;
|
||||
|
||||
case ARB_BUS_FREE:
|
||||
LOGMASKED(LOG_ARB, "arbitration: waiting for bus free\n");
|
||||
if (!(scsi_bus->ctrl_r() & (S_SEL | S_BSY | S_RST)))
|
||||
{
|
||||
m_state = ARB_START;
|
||||
delay = SCSI_BUS_FREE;
|
||||
}
|
||||
break;
|
||||
case ARB_START:
|
||||
LOGMASKED(LOG_ARB, "arbitration: started\n");
|
||||
m_state = ARB_EVALUATE;
|
||||
delay = SCSI_ARB_DELAY;
|
||||
|
||||
// assert own ID and BSY
|
||||
scsi_bus->data_w(scsi_refid, oid);
|
||||
scsi_bus->ctrl_w(scsi_refid, S_BSY, S_BSY);
|
||||
break;
|
||||
case ARB_EVALUATE:
|
||||
// check if SEL asserted, or if there's a higher ID on the bus
|
||||
if ((scsi_bus->ctrl_r() & S_SEL) || (scsi_bus->data_r() & ~((oid - 1) | oid)))
|
||||
{
|
||||
LOGMASKED(LOG_ARB, "arbitration: lost\n");
|
||||
set_cstat(CSTAT_LST, CSTAT_LST);
|
||||
|
||||
m_state = ARB_BUS_FREE;
|
||||
delay = SCSI_BUS_FREE; // FIXME: how long?
|
||||
|
||||
// clear data and BSY
|
||||
scsi_bus->data_w(scsi_refid, 0);
|
||||
scsi_bus->ctrl_w(scsi_refid, 0, S_BSY);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGMASKED(LOG_ARB, "arbitration: won\n");
|
||||
set_cstat(CSTAT_SIP, CSTAT_SIP | CSTAT_LST);
|
||||
|
||||
m_state = SEL_START;
|
||||
delay = SCSI_BUS_CLEAR + SCSI_BUS_SETTLE;
|
||||
}
|
||||
break;
|
||||
|
||||
case SEL_START:
|
||||
LOGMASKED(LOG_SEL, "selection: SEL asserted\n");
|
||||
m_state = SEL_DELAY;
|
||||
delay = SCSI_BUS_SKEW * 2;
|
||||
|
||||
// assert own and target ID and SEL
|
||||
scsi_bus->data_w(scsi_refid, oid | tid);
|
||||
scsi_bus->ctrl_w(scsi_refid, S_SEL, S_SEL);
|
||||
break;
|
||||
case SEL_DELAY:
|
||||
LOGMASKED(LOG_SEL, "selection: BSY cleared\n");
|
||||
m_state = SEL_WAIT_BSY;
|
||||
delay = SCSI_BUS_SETTLE;
|
||||
|
||||
// clear BSY, optionally assert ATN
|
||||
if (m_comm & COMM_ATN)
|
||||
scsi_bus->ctrl_w(scsi_refid, S_ATN, S_BSY | S_ATN);
|
||||
else
|
||||
scsi_bus->ctrl_w(scsi_refid, 0, S_BSY);
|
||||
break;
|
||||
case SEL_WAIT_BSY:
|
||||
if (scsi_bus->ctrl_r() & S_BSY)
|
||||
{
|
||||
LOGMASKED(LOG_SEL, "selection: BSY asserted by target\n");
|
||||
m_state = SEL_COMPLETE;
|
||||
delay = SCSI_BUS_SKEW * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGMASKED(LOG_SEL, "selection: timed out\n");
|
||||
m_state = IDLE;
|
||||
|
||||
//scsi_bus->ctrl_w(scsi_refid, 0, S_ATN | S_SEL);
|
||||
}
|
||||
break;
|
||||
case SEL_COMPLETE:
|
||||
LOGMASKED(LOG_SEL, "selection: complete\n");
|
||||
m_state = IDLE;
|
||||
set_cstat(CSTAT_SCH | CSTAT_CON, CSTAT_SCH | CSTAT_CON | CSTAT_SIP);
|
||||
|
||||
// clear data and SEL
|
||||
scsi_bus->data_w(scsi_refid, 0);
|
||||
scsi_bus->ctrl_w(scsi_refid, 0, S_SEL);
|
||||
break;
|
||||
|
||||
case XFR_PIO:
|
||||
// TODO: phase match
|
||||
set_dstat(0, DSTAT_TBE);
|
||||
if (scsi_bus->ctrl_r() & S_REQ)
|
||||
m_state = (scsi_bus->ctrl_r() & S_INP) ? XFR_PIO_IN : XFR_PIO_OUT;
|
||||
break;
|
||||
case XFR_PIO_OUT:
|
||||
LOGMASKED(LOG_PIO, "xfr pio out: data 0x%02x\n", m_data);
|
||||
m_state = XFR_PIO_OUT_ACK;
|
||||
|
||||
// assert data and ACK
|
||||
scsi_bus->data_w(scsi_refid, m_data);
|
||||
scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK);
|
||||
break;
|
||||
case XFR_PIO_OUT_ACK:
|
||||
if (!(scsi_bus->ctrl_r() & S_REQ))
|
||||
{
|
||||
LOGMASKED(LOG_PIO, "xfr pio out: data ACK\n");
|
||||
|
||||
m_state = IDLE;
|
||||
set_dstat(DSTAT_DNE, DSTAT_DNE);
|
||||
|
||||
// clear data and ACK
|
||||
scsi_bus->data_w(scsi_refid, 0);
|
||||
scsi_bus->ctrl_w(scsi_refid, 0, S_ACK);
|
||||
}
|
||||
break;
|
||||
|
||||
case XFR_DMA:
|
||||
// TODO: phase match
|
||||
if (scsi_bus->ctrl_r() & S_REQ)
|
||||
m_state = (scsi_bus->ctrl_r() & S_INP) ? XFR_DMA_IN_REQ : XFR_DMA_OUT;
|
||||
break;
|
||||
case XFR_DMA_IN_REQ:
|
||||
{
|
||||
u8 const data = scsi_bus->data_r();
|
||||
LOGMASKED(LOG_DMA, "xfr dma in: data 0x%02x\n", data);
|
||||
|
||||
if (m_dstat & DSTAT_OBB)
|
||||
{
|
||||
m_dma_w((u32(m_dmaddrh) << 16) | m_dmaddrl, (u16(data) << 8) | m_dmabyte);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dmabyte = data;
|
||||
}
|
||||
|
||||
m_dstat ^= DSTAT_OBB;
|
||||
|
||||
// assert ACK
|
||||
scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return delay;
|
||||
}
|
115
src/mame/dec/dc7061.h
Normal file
115
src/mame/dec/dc7061.h
Normal file
@ -0,0 +1,115 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Patrick Mackinlay
|
||||
|
||||
#ifndef MAME_DEC_DC7061_H
|
||||
#define MAME_DEC_DC7061_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "machine/nscsi_bus.h"
|
||||
|
||||
class dc7061_device
|
||||
: public nscsi_device
|
||||
, public nscsi_slot_card_interface
|
||||
{
|
||||
public:
|
||||
dc7061_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
|
||||
|
||||
// device configuration
|
||||
auto sys_int() { return m_sys_int.bind(); }
|
||||
auto dma_r() { return m_dma_r.bind(); }
|
||||
auto dma_w() { return m_dma_w.bind(); }
|
||||
|
||||
// register access
|
||||
void map(address_map &map);
|
||||
|
||||
protected:
|
||||
// device_t implementation
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
// ncsci_device implementation
|
||||
virtual void scsi_ctrl_changed() override;
|
||||
|
||||
// register read handlers
|
||||
u16 sdb_r();
|
||||
u16 sc1_r();
|
||||
u16 sc2_r();
|
||||
u16 csr_r();
|
||||
u16 id_r();
|
||||
u16 slcsr_r();
|
||||
u16 destat_r();
|
||||
u16 data_r();
|
||||
u16 dmctrl_r();
|
||||
u16 dmlotc_r();
|
||||
u16 dmaddrl_r();
|
||||
u16 dmaddrh_r();
|
||||
u16 dmabyte_r();
|
||||
u16 cstat_r();
|
||||
u16 dstat_r();
|
||||
u16 comm_r();
|
||||
u16 dictrl_r();
|
||||
|
||||
// register write handlers
|
||||
void sdb_w(u16 data);
|
||||
void sc1_w(u16 data);
|
||||
void sc2_w(u16 data);
|
||||
void csr_w(u16 data);
|
||||
void id_w(u16 data);
|
||||
void slcsr_w(u16 data);
|
||||
void data_w(u16 data);
|
||||
void dmctrl_w(u16 data);
|
||||
void dmlotc_w(u16 data);
|
||||
void dmaddrl_w(u16 data);
|
||||
void dmaddrh_w(u16 data);
|
||||
void dmabyte_w(u16 data);
|
||||
void cstat_w(u16 data);
|
||||
void dstat_w(u16 data);
|
||||
void comm_w(u16 data);
|
||||
void dictrl_w(u16 data);
|
||||
|
||||
// state machine
|
||||
void state_timer(s32 param);
|
||||
int state_step();
|
||||
|
||||
// other helpers
|
||||
void set_cstat(u16 data, u16 mask);
|
||||
void set_dstat(u16 data, u16 mask);
|
||||
void set_irq(bool irq_state);
|
||||
|
||||
private:
|
||||
devcb_write_line m_sys_int;
|
||||
devcb_read16 m_dma_r;
|
||||
devcb_write16 m_dma_w;
|
||||
|
||||
// state machine
|
||||
emu_timer *m_state_timer;
|
||||
u32 m_state;
|
||||
|
||||
// registers
|
||||
u16 m_sdb;
|
||||
u16 m_sc1;
|
||||
u16 m_sc2;
|
||||
u16 m_csr;
|
||||
u16 m_id;
|
||||
u16 m_slcsr;
|
||||
u16 m_destat;
|
||||
u16 m_data;
|
||||
u16 m_dmctrl;
|
||||
u16 m_dmlotc;
|
||||
u16 m_dmaddrl;
|
||||
u16 m_dmaddrh;
|
||||
u16 m_dmabyte;
|
||||
u16 m_cstat;
|
||||
u16 m_dstat;
|
||||
u16 m_comm;
|
||||
u16 m_dictrl;
|
||||
|
||||
// line state
|
||||
u32 m_scsi_ctrl;
|
||||
bool m_sys_int_state;
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(DC7061, dc7061_device)
|
||||
|
||||
#endif // MAME_DEC_DC7061_H
|
Loading…
Reference in New Issue
Block a user