summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/53c7xx.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/53c7xx.cpp')
-rw-r--r--src/devices/machine/53c7xx.cpp1776
1 files changed, 1776 insertions, 0 deletions
diff --git a/src/devices/machine/53c7xx.cpp b/src/devices/machine/53c7xx.cpp
new file mode 100644
index 00000000000..f2aad1ad75b
--- /dev/null
+++ b/src/devices/machine/53c7xx.cpp
@@ -0,0 +1,1776 @@
+// license:BSD-3-Clause
+// copyright-holders:Philip Bennett
+/*********************************************************************
+
+ 53c7xx.c
+
+ NCR 53C700 SCSI I/O Processor
+
+
+ TODO:
+ * Low-level register accesses
+ * Remove arbitrary delays
+ * Add unimplemented SCRIPTS opcodes
+
+*********************************************************************/
+
+#include "emu.h"
+#include "53c7xx.h"
+
+
+
+//**************************************************************************
+// DEBUGGERY
+//**************************************************************************
+
+#define DEBUG_LOG 1
+#define DEBUG_LEVEL 0
+
+#if DEBUG_LOG
+ #define VERBOSE_LOG(machine, level, ...) verbose_log(machine, level, __VA_ARGS__)
+#else
+ #define VERBOSE_LOG(machine, level, ...)
+#endif
+
+static void ATTR_PRINTF(3,4) verbose_log(running_machine &machine, int level, const char* format, ...)
+{
+ if (level <= DEBUG_LEVEL)
+ {
+ char buffer[32768];
+ va_list v;
+
+ va_start(v, format);
+ vsprintf(buffer, format, v);
+ va_end(v);
+
+ printf("53C7XX (%s): %s", machine.describe_context(), buffer);
+ }
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+const device_type NCR53C7XX = &device_creator<ncr53c7xx_device>;
+
+//-------------------------------------------------
+// ncr53c7xx_device - constructor/destructor
+//-------------------------------------------------
+
+ncr53c7xx_device::ncr53c7xx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nscsi_device(mconfig, NCR53C7XX, "53C7xx SCSI", tag, owner, clock, "ncr537xx", __FILE__),
+ device_execute_interface(mconfig, *this),
+ m_icount(0),
+ m_irq_handler(*this),
+ m_host_write(*this),
+ m_host_read(*this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void ncr53c7xx_device::device_start()
+{
+ // set our instruction counter
+ m_icountptr = &m_icount;
+
+ // resolve line callbacks
+ m_irq_handler.resolve_safe();
+ m_host_read.resolve_safe(0);
+ m_host_write.resolve_safe();
+
+ m_tm = timer_alloc(0);
+
+ // The SCRIPTS processor runs at ~2 MIPS so approximate this
+ set_unscaled_clock(2000000);
+
+ // savestate support
+ save_item(NAME(m_scntl));
+ save_item(NAME(m_sdid));
+ save_item(NAME(m_sien));
+ save_item(NAME(m_scid));
+ save_item(NAME(m_sxfer));
+ save_item(NAME(m_sodl));
+ save_item(NAME(m_socl));
+ save_item(NAME(m_sfbr));
+ save_item(NAME(m_sidl));
+ save_item(NAME(m_sbdl));
+ save_item(NAME(m_sbcl));
+ save_item(NAME(m_dstat));
+ save_item(NAME(m_sstat));
+ save_item(NAME(m_ctest));
+ save_item(NAME(m_temp));
+ save_item(NAME(m_dfifo));
+ save_item(NAME(m_istat));
+ save_item(NAME(m_dbc));
+ save_item(NAME(m_dcmd));
+ save_item(NAME(m_dnad));
+ save_item(NAME(m_dsp));
+ save_item(NAME(m_dsps));
+ save_item(NAME(m_dmode));
+ save_item(NAME(m_dien));
+ save_item(NAME(m_dwt));
+ save_item(NAME(m_dcntl));
+
+ // other state
+ save_item(NAME(m_scsi_state));
+ save_item(NAME(m_connected));
+ save_item(NAME(m_finished));
+ save_item(NAME(m_last_data));
+ save_item(NAME(m_xfr_phase));
+
+ save_item(NAME(m_scripts_state));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void ncr53c7xx_device::device_reset()
+{
+ // Reset registers to defaults
+ m_scntl[0] = 3 << SCNTL0_ARB_SHIFT;
+ m_scntl[1] = 0;
+ m_sdid = 0;
+ m_sien = 0;
+ m_scid = 0;
+ m_sxfer = 0;
+ m_sodl = 0;
+ m_socl = 0;
+ m_sfbr = 0;
+ m_sidl = 0;
+ m_sbdl = 0;
+ m_sbcl = 0;
+ m_dstat = DSTAT_DFE;
+ m_sstat[0] = 0;
+ m_sstat[1] = 0;
+ m_sstat[2] = 0;
+ m_ctest[0] = 0;
+ m_ctest[1] = 0xf0;
+ m_ctest[2] = 0x21;
+ m_ctest[3] = 0;
+ m_ctest[4] = 0;
+ m_ctest[5] = 0;
+ m_ctest[6] = 0;
+ m_ctest[7] = 0;
+ m_dfifo = 0;
+ m_istat = 0;//ISTAT_PRE;
+ m_dmode = 0;
+ m_dien = 0;
+ m_dcntl = 0;
+
+ m_finished = false;
+ m_connected = false;
+
+ scsi_bus->ctrl_wait(scsi_refid, S_SEL | S_BSY | S_RST, S_ALL);
+ set_scripts_state(SCRIPTS_IDLE);
+ set_scsi_state(IDLE);
+
+ m_irq_handler(CLEAR_LINE);
+}
+
+
+//**************************************************************************
+// MEMORY HANDLERS
+//**************************************************************************
+
+//-------------------------------------------------
+// read - Host read handler
+//-------------------------------------------------
+
+READ32_MEMBER( ncr53c7xx_device::read )
+{
+ VERBOSE_LOG(machine(), 1, "REG R: [%x] (%08X)\n", offset, mem_mask);
+
+ UINT32 ret = 0;
+
+ switch (offset)
+ {
+ case 0x0:
+ {
+ if (ACCESSING_BITS_0_7)
+ {
+ ret = m_scntl[0];
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ ret |= m_scntl[1] << 8;
+ }
+ if (ACCESSING_BITS_16_23)
+ {
+ ret |= m_sdid << 16;
+ }
+ if (ACCESSING_BITS_24_31)
+ {
+ ret |= m_sien << 24;
+ }
+
+ break;
+ }
+
+ case 0x1:
+ {
+ if (ACCESSING_BITS_0_7)
+ {
+ ret = m_scid;
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ ret |= m_sxfer << 8;
+ }
+ if (ACCESSING_BITS_16_23)
+ {
+ ret |= m_sodl << 16;
+ }
+ if (ACCESSING_BITS_24_31)
+ {
+ ret |= m_socl << 24;
+ }
+
+ break;
+ }
+
+ case 0x2:
+ {
+ if (ACCESSING_BITS_0_7)
+ {
+ ret = m_sfbr;
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ ret |= m_sidl << 8;
+ }
+ if (ACCESSING_BITS_16_23)
+ {
+ ret |= m_sbdl << 16;
+ }
+ if (ACCESSING_BITS_24_31)
+ {
+ ret |= m_sbcl << 24;
+ }
+
+ break;
+ }
+
+ case 0x3:
+ {
+ if (ACCESSING_BITS_0_7)
+ {
+ ret = m_dstat;
+ m_dstat = 0;
+ update_irqs();
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ ret |= m_sstat[0] << 8;
+ m_sstat[0] = 0;
+ update_irqs();
+ }
+ if (ACCESSING_BITS_16_23)
+ {
+ ret |= m_sstat[1] << 16;
+ }
+ if (ACCESSING_BITS_24_31)
+ {
+ ret |= m_sstat[2] << 24;
+ }
+
+ break;
+ }
+
+ case 0x5:
+ {
+ if (ACCESSING_BITS_0_7)
+ {
+ ret = m_ctest[0];
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ ret |= m_ctest[1] << 8;
+ }
+ if (ACCESSING_BITS_16_23)
+ {
+ ret |= m_ctest[2] << 16;
+ }
+ if (ACCESSING_BITS_24_31)
+ {
+ ret |= m_ctest[3] << 24;
+ }
+
+ break;
+ }
+
+ case 0x6:
+ {
+ if (ACCESSING_BITS_0_7)
+ {
+ ret = m_ctest[4];
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ ret |= m_ctest[5] << 8;
+ }
+ if (ACCESSING_BITS_16_23)
+ {
+ ret |= m_ctest[6] << 16;
+ }
+ if (ACCESSING_BITS_24_31)
+ {
+ ret |= m_ctest[7] << 24;
+ }
+
+ break;
+ }
+
+ case 0x7:
+ {
+ ret = m_temp;
+
+ break;
+ }
+
+ case 0x8:
+ {
+ if (ACCESSING_BITS_0_7)
+ {
+ ret = m_dfifo;
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ ret |= m_istat << 8;
+ }
+
+ break;
+ }
+
+ case 0x9:
+ {
+ if (ACCESSING_BITS_0_7 || ACCESSING_BITS_8_15 || ACCESSING_BITS_16_23)
+ {
+ ret = m_dbc;
+ }
+ if (ACCESSING_BITS_24_31)
+ {
+ ret |= m_dcmd << 24;
+ }
+
+ break;
+ }
+
+ case 0xa:
+ {
+ ret = m_dnad;
+
+ break;
+ }
+
+ case 0xb:
+ {
+ ret = m_dsp;
+
+ break;
+ }
+
+ case 0xc:
+ {
+ ret = m_dsps;
+
+ break;
+ }
+
+ case 0xd:
+ {
+ if (ACCESSING_BITS_0_7)
+ {
+ ret = m_dmode;
+ }
+
+ break;
+ }
+
+ case 0xe:
+ {
+ if (ACCESSING_BITS_8_15)
+ {
+ ret = m_dien << 8;
+ }
+ if (ACCESSING_BITS_16_23)
+ {
+ ret |= m_dwt << 16;
+
+ }
+ if (ACCESSING_BITS_24_31)
+ {
+ ret |= m_dcntl << 24;
+ }
+
+ break;
+ }
+
+ default:
+ {
+ VERBOSE_LOG(machine(), 0, "Unhandled register access");
+ }
+ }
+
+ return ret;
+}
+
+
+//-------------------------------------------------
+// write - Host write handler
+//-------------------------------------------------
+
+WRITE32_MEMBER( ncr53c7xx_device::write )
+{
+ VERBOSE_LOG(machine(), 1, "REG W: [%x] (%08X) %x\n", offset, mem_mask, data);
+
+ switch (offset)
+ {
+ case 0x0:
+ {
+ if (ACCESSING_BITS_0_7)
+ {
+ m_scntl[0] = data;
+
+ if (data & SCNTL0_TRG)
+ fatalerror("53c7xx: Target mode unsupported!");
+
+ if (data & SCNTL0_START)
+ {
+ // Start arbitration
+ set_scsi_state(ARBITRATE_WAIT_FREE);
+ step(true);
+ }
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ m_scntl[1] = data >> 8;
+ }
+ if (ACCESSING_BITS_16_23)
+ {
+ m_sdid = data >> 16;
+ }
+ if (ACCESSING_BITS_24_31)
+ {
+ m_sien = data >> 24;
+ }
+
+ break;
+ }
+
+ case 0x1:
+ {
+ if (ACCESSING_BITS_0_7)
+ {
+ m_scid = data;
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ m_sxfer = data >> 8;
+ }
+ if (ACCESSING_BITS_16_23)
+ {
+ m_sodl = data >> 16;
+ }
+ if (ACCESSING_BITS_24_31)
+ {
+ m_socl = data >> 24;
+ }
+
+ break;
+ }
+
+ case 0x6:
+ {
+ if (ACCESSING_BITS_0_7)
+ {
+ m_ctest[4] = data;
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ m_ctest[5] = data >> 8;
+ }
+ if (ACCESSING_BITS_16_23)
+ {
+ m_ctest[6] = data >> 16;
+ }
+ if (ACCESSING_BITS_24_31)
+ {
+ m_ctest[7] = data >> 24;
+ }
+
+ break;
+ }
+
+ case 0x7:
+ {
+ m_temp = data;
+
+ break;
+ }
+
+ case 0x8:
+ {
+ if (ACCESSING_BITS_0_7)
+ {
+ m_dfifo = data;
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ m_istat = data >> 8;
+ }
+
+ break;
+ }
+
+ case 0x9:
+ {
+ if (ACCESSING_BITS_0_7 || ACCESSING_BITS_8_15 || ACCESSING_BITS_16_23)
+ {
+ m_dbc = data & 0xffffff;
+ }
+ if (ACCESSING_BITS_24_31)
+ {
+ m_dcmd = data >> 24;
+ }
+
+ break;
+ }
+
+ case 0xa:
+ {
+ m_dnad = data;
+
+ break;
+ }
+
+ case 0xb:
+ {
+ // Write to the upper byte starts the fetch
+ m_dsp = data;
+
+ if (m_dmode & 1)
+ {
+ set_scripts_state(SCRIPTS_WAIT_MANUAL_START);
+ }
+ else
+ {
+ set_scripts_state(SCRIPTS_FETCH);
+ }
+
+ break;
+ }
+
+ case 0xc:
+ {
+ m_dsps = data;
+
+ break;
+ }
+
+ case 0xd:
+ {
+ if (ACCESSING_BITS_0_7)
+ {
+ m_dmode = data;
+ }
+
+ break;
+ }
+
+ case 0xe:
+ {
+ if (ACCESSING_BITS_8_15)
+ {
+ m_dien = data >> 8;
+ }
+ if (ACCESSING_BITS_16_23)
+ {
+ m_dwt = data >> 16;
+
+ if (m_dwt)
+ fatalerror("53c7xx: DMA Watchdog Timer enabled!");
+ }
+ if (ACCESSING_BITS_24_31)
+ {
+ m_dcntl = data >> 24;
+
+ // Note: not self-clearing
+ if (m_dcntl & 1) // RST
+ {
+ device_reset();
+ }
+ else if (m_dcntl & 2) // STD
+ {
+ // Only applies to these modes:
+ // * Manual Start
+ // * Single Step
+ // * Pipeline
+ fatalerror("53c7xx: Start DMA");
+ }
+ else if (m_dcntl & 4)
+ {
+ fatalerror("53c7xx: SCSI Low-Level Mode not supported!");
+ }
+
+ // TODO: Update clocking
+ }
+
+ break;
+ }
+
+ default:
+ {
+ VERBOSE_LOG(machine(), 0, "Unhandled register access");
+ }
+ }
+}
+
+
+
+//**************************************************************************
+// SCSI STATE MACHINE
+//**************************************************************************
+
+//-------------------------------------------------
+// update_irqs -
+//-------------------------------------------------
+void ncr53c7xx_device::update_irqs()
+{
+ if (m_sstat[0] & m_sien)
+ m_istat |= ISTAT_SIP;
+ else
+ m_istat &= ~ISTAT_SIP;
+
+ if (m_dstat & m_dien)
+ m_istat |= ISTAT_DIP;
+ else
+ m_istat &= ~ISTAT_DIP;
+
+ m_irq_handler(m_istat ? ASSERT_LINE : CLEAR_LINE);
+}
+
+//-------------------------------------------------
+// set_scsi_state - change SCSI state
+//-------------------------------------------------
+
+void ncr53c7xx_device::set_scsi_state(int state)
+{
+ VERBOSE_LOG(machine(), 2, "SCSI state change: %x to %x\n", m_scsi_state, state);
+
+ m_scsi_state = state;
+}
+
+
+//-------------------------------------------------
+// delay - step the SCSI state machine following
+// a time delay
+//-------------------------------------------------
+
+void ncr53c7xx_device::delay(const attotime &delay)
+{
+ m_tm->adjust(delay);
+}
+
+
+//-------------------------------------------------
+// scsi_ctrl_changed - callback from nscsi_device
+//-------------------------------------------------
+
+void ncr53c7xx_device::scsi_ctrl_changed()
+{
+ step(false);
+}
+
+
+//-------------------------------------------------
+// send_byte - send data to a SCSI device
+//-------------------------------------------------
+
+void ncr53c7xx_device::send_byte()
+{
+ if (m_dbc == 0)
+ fatalerror("53C7XX: send_byte() - DBC should not be 0\n");
+
+ set_scsi_state( (m_scsi_state & STATE_MASK) | (SEND_WAIT_SETTLE << SUB_SHIFT) );
+
+ UINT32 data = m_host_read(m_dnad & ~3, 0xffffffff);
+ data = data >> ((m_dnad & 3) * 8) & 0xff;
+
+ ++m_dnad;
+ --m_dbc;
+
+ scsi_bus->data_w(scsi_refid, data);
+ scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK);
+ scsi_bus->ctrl_wait(scsi_refid, S_REQ, S_REQ);
+ delay(attotime::from_nsec(5));
+}
+
+
+//-------------------------------------------------
+// recv_byte - receive data from a SCSI device
+//-------------------------------------------------
+
+void ncr53c7xx_device::recv_byte()
+{
+ scsi_bus->ctrl_wait(scsi_refid, S_REQ, S_REQ);
+ set_scsi_state( (m_scsi_state & STATE_MASK) | (RECV_WAIT_REQ_1 << SUB_SHIFT) );
+ step(false);
+}
+
+
+//-------------------------------------------------
+// device_timer - callback to step the SCSI
+// state machine
+//-------------------------------------------------
+
+void ncr53c7xx_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ step(true);
+}
+
+
+//-------------------------------------------------
+// step - advance the SCSI state machine
+//-------------------------------------------------
+
+void ncr53c7xx_device::step(bool timeout)
+{
+ UINT32 ctrl = scsi_bus->ctrl_r();
+ UINT32 data = scsi_bus->data_r();
+
+ VERBOSE_LOG(machine(), 2, "Step: CTRL:%x DATA:%x (%d.%d) Timeout:%d\n", ctrl, data, m_scsi_state & STATE_MASK, m_scsi_state >> SUB_SHIFT, timeout);
+
+ // Check for disconnect from target
+ if (!(m_scntl[0] & SCNTL0_TRG) && m_connected && !(ctrl & S_BSY))
+ {
+ set_scsi_state(FINISHED);
+ m_connected = false;
+// istatus |= I_DISCONNECT;
+// reset_disconnect();
+// check_irq();
+ }
+
+ switch (m_scsi_state & SUB_MASK ? m_scsi_state & SUB_MASK : m_scsi_state & STATE_MASK)
+ {
+ case IDLE:
+ {
+ break;
+ }
+
+ case FINISHED:
+ {
+ m_finished = true;
+ set_scsi_state(IDLE);
+ step(true);
+
+ break;
+ }
+
+ case ARBITRATE_WAIT_FREE:
+ {
+ if (!timeout)
+ break;
+
+ // Is the bus free?
+ if (ctrl & (S_BSY | S_SEL))
+ {
+ // Keep trying until it is
+ delay(attotime::from_nsec(800));
+ }
+ else
+ {
+ // Bus is free; next phase
+ delay(attotime::from_nsec(800));
+ set_scsi_state(ARBITRATE_CHECK_FREE);
+ }
+
+ break;
+ }
+
+ case ARBITRATE_CHECK_FREE:
+ {
+ if ((ctrl & (S_BSY | S_SEL)) == 0)
+ {
+ // Bus is free - assert the controller SCSI ID and BUSY
+ scsi_bus->ctrl_w(scsi_refid, S_BSY, S_BSY);
+
+ if (((m_scntl[0] >> SCNTL0_ARB_SHIFT) & SCNTL0_ARB_MASK) == 3)
+ {
+ // Full arbitration
+ scsi_bus->data_w(scsi_refid, m_scid);
+ }
+ else
+ {
+ // Simple arbitration
+ scsi_bus->data_w(scsi_refid, m_sodl);
+ }
+
+ set_scsi_state(ARBITRATE_EXAMINE_BUS);
+ delay(attotime::from_nsec(2400));
+ }
+
+ break;
+ }
+
+ case ARBITRATE_EXAMINE_BUS:
+ {
+ if (!timeout)
+ break;
+
+ if (ctrl & S_SEL)
+ {
+ scsi_bus->ctrl_w(scsi_refid, 0, S_BSY);
+ scsi_bus->data_w(scsi_refid, 0);
+
+ if (((m_scntl[0] >> SCNTL0_ARB_SHIFT) & SCNTL0_ARB_MASK) == 3)
+ {
+ // Try again
+ set_scsi_state(ARBITRATE_WAIT_FREE);
+ delay(attotime::from_nsec(2400));
+ }
+ else
+ {
+ // TODO: Is this right?
+ m_sstat[1] |= SSTAT1_LOA;
+ m_scntl[0] &= ~SCNTL0_START;
+ m_sstat[0] |= SSTAT0_CMP;
+ update_irqs();
+
+ set_scsi_state(FINISHED);
+ step(true);
+ }
+
+ break;
+ }
+
+ // Full arbitration?
+ if (((m_scntl[0] >> SCNTL0_ARB_SHIFT) & SCNTL0_ARB_MASK) == 3)
+ {
+ int win;
+ for (win = 7; win >=0 && !(data & (1 << win)); win--);
+
+ if ((1 << win) != m_scid)
+ {
+ scsi_bus->data_w(scsi_refid, 0);
+ scsi_bus->ctrl_w(scsi_refid, 0, S_ALL);
+
+ delay(attotime::from_nsec(2400));
+ break;
+ }
+
+ // Begin the select phase; assert SEL
+ m_sstat[1] |= SSTAT1_WOA;
+ scsi_bus->ctrl_w(scsi_refid, S_SEL, S_SEL);
+ set_scsi_state(ARBITRATE_ASSERT_SEL);
+ delay(attotime::from_nsec(1200));
+ }
+ else
+ {
+ // TODO: Worth adding another state here?
+ m_sstat[0] |= SSTAT0_CMP;
+ m_scntl[0] &= ~SCNTL0_START;
+ update_irqs();
+ set_scsi_state(FINISHED);
+ step(true);
+ }
+
+ break;
+ }
+
+ case ARBITRATE_ASSERT_SEL:
+ {
+ if (!timeout)
+ break;
+
+ // Activate data line of the thing
+ scsi_bus->data_w(scsi_refid, m_sdid);
+
+ set_scsi_state(ARBITRATE_SELECT_DEST);
+ delay(attotime::from_nsec(2));
+
+ break;
+ }
+
+ case ARBITRATE_SELECT_DEST:
+ {
+ if (!timeout)
+ break;
+
+ scsi_bus->ctrl_w(scsi_refid, m_scntl[0] & SCNTL0_WATN ? S_ATN : 0, S_ATN | S_BSY);
+
+ set_scsi_state(ARBITRATE_RELEASE_BSY);
+ delay(attotime::from_nsec(20));
+
+ break;
+ }
+
+ case ARBITRATE_RELEASE_BSY:
+ {
+ if (!timeout)
+ break;
+
+ set_scsi_state(ARBITRATE_DESKEW_WAIT);
+ delay(attotime::from_nsec(500));
+
+ break;
+ }
+
+ case ARBITRATE_DESKEW_WAIT:
+ {
+ if (!timeout)
+ break;
+
+ // Clear everything
+ scsi_bus->data_w(scsi_refid, 0);
+ scsi_bus->ctrl_w(scsi_refid, 0, S_SEL);
+
+ // Done?
+ m_sstat[0] |= SSTAT0_CMP;
+ m_scntl[0] &= ~SCNTL0_START;
+ //update_irqs();
+ set_scsi_state(FINISHED);
+ m_connected = true;
+
+ step(true);
+ break;
+ }
+
+
+ // Note this is actually block transfers
+ case INIT_XFER:
+ {
+ if (ctrl & S_INP)
+ {
+ set_scsi_state(m_dbc ? INIT_XFER_RECV_BYTE_ACK : INIT_XFER_RECV_BYTE_NACK);
+ recv_byte();
+ }
+ else
+ {
+ if (m_dbc == 1)
+ scsi_bus->ctrl_w(scsi_refid, 0, S_ATN);
+
+ set_scsi_state(INIT_XFER_SEND_BYTE);
+ send_byte();
+ }
+
+ break;
+ }
+
+ case INIT_XFER_SEND_BYTE:
+ {
+ if (m_dbc == 0)
+ {
+ set_scsi_state(FINISHED);
+ step(true);
+ }
+ else
+ {
+ set_scsi_state(INIT_XFER_WAIT_REQ);
+ }
+
+ break;
+ }
+
+ case INIT_XFER_RECV_BYTE_ACK:
+ {
+ set_scsi_state(INIT_XFER_WAIT_REQ);
+ scsi_bus->ctrl_w(scsi_refid, 0, S_ACK);
+
+ break;
+ }
+
+ case INIT_XFER_RECV_BYTE_NACK:
+ {
+ set_scsi_state(FINISHED);
+ step(true);
+
+ break;
+ }
+
+ case INIT_XFER_WAIT_REQ:
+ {
+ if (!(ctrl & S_REQ))
+ break;
+
+ if ((ctrl & S_PHASE_MASK) != m_xfr_phase)
+ {
+ set_scsi_state(FINISHED);
+ step(true);
+ }
+ else
+ {
+ set_scsi_state(INIT_XFER);
+ step(false);
+ }
+
+ break;
+ }
+
+ case SEND_WAIT_SETTLE << SUB_SHIFT:
+ {
+ if (!timeout)
+ break;
+
+ set_scsi_state( (m_scsi_state & STATE_MASK) | (SEND_WAIT_REQ_0 << SUB_SHIFT) );
+ step(false);
+
+ break;
+ }
+
+ case SEND_WAIT_REQ_0 << SUB_SHIFT:
+ {
+ if (ctrl & S_REQ)
+ break;
+
+ set_scsi_state(m_scsi_state & STATE_MASK);
+ scsi_bus->data_w(scsi_refid, 0);
+ scsi_bus->ctrl_w(scsi_refid, 0, S_ACK);
+
+ step(false);
+
+ break;
+ }
+
+ case RECV_WAIT_REQ_1 << SUB_SHIFT:
+ {
+ if (!(ctrl & S_REQ))
+ break;
+
+ set_scsi_state( (m_scsi_state & STATE_MASK) | (RECV_WAIT_SETTLE << SUB_SHIFT) );
+ delay(attotime::from_nsec(5));
+
+ break;
+ }
+
+ case RECV_WAIT_SETTLE << SUB_SHIFT:
+ {
+ if (!timeout)
+ break;
+
+ if ((m_scsi_state & STATE_MASK) != INIT_XFER_RECV_PAD)
+ {
+ m_last_data = scsi_bus->data_r();
+
+ UINT32 shift = (8 * (m_dnad & 3));
+ UINT32 mem_mask = 0xff << shift;
+ m_host_write(m_dnad & ~3, data << shift, mem_mask);
+
+ ++m_dnad;
+ --m_dbc;
+ }
+
+ scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK);
+ set_scsi_state( (m_scsi_state & STATE_MASK) | (RECV_WAIT_REQ_0 << SUB_SHIFT) );
+ step(false);
+
+ break;
+ }
+
+ case RECV_WAIT_REQ_0 << SUB_SHIFT:
+ {
+ if (ctrl & S_REQ)
+ break;
+
+ set_scsi_state(m_scsi_state & STATE_MASK);
+ step(false);
+
+ break;
+ }
+
+ default:
+ fatalerror("Unknown state! (%x)\n", m_scsi_state);
+
+ }
+}
+
+
+//**************************************************************************
+// SCSI SCRIPTS
+//**************************************************************************
+
+#define UNIMPLEMENTED fatalerror("%s is unimplemented\n", __FUNCTION__)
+
+//-------------------------------------------------
+// set_scripts_state -
+//-------------------------------------------------
+
+void ncr53c7xx_device::set_scripts_state(scripts_state state)
+{
+ m_scripts_state = state;
+}
+
+
+//-------------------------------------------------
+// scripts_yield - suspend execution
+//-------------------------------------------------
+void ncr53c7xx_device::scripts_yield()
+{
+ m_icount = 0;
+}
+
+
+//-------------------------------------------------
+// execute_run - SCRIPTS execution loop
+//-------------------------------------------------
+
+void ncr53c7xx_device::execute_run()
+{
+ // Not processing anything so bail
+ if (m_scripts_state < SCRIPTS_FETCH)
+ {
+ m_icount = 0;
+ return;
+ }
+
+ do
+ {
+ switch (m_scripts_state)
+ {
+ case SCRIPTS_FETCH:
+ {
+ m_finished = false;
+
+ // Fetch the instruction
+ UINT32 inst = m_host_read(m_dsp, 0xffffffff);
+
+ m_dcmd = inst >> 24;
+ m_dbc = inst & 0xffffff;
+
+ // Unless we encounter an illegal instruction...
+ set_scripts_state(SCRIPTS_EXECUTE);
+
+ // Decode the relevant group
+ switch ((m_dcmd >> 6) & 3)
+ {
+ case 0:
+ scripts_decode_bm();
+ break;
+
+ case 1:
+ scripts_decode_io();
+ break;
+
+ case 2:
+ scripts_decode_tc();
+ break;
+
+ case 3:
+ illegal();
+ }
+
+ VERBOSE_LOG(machine(), 3, "%s", disassemble_scripts());
+ break;
+ }
+
+ case SCRIPTS_EXECUTE:
+ {
+ (*this.*m_scripts_op)();
+ break;
+ }
+ }
+
+ m_icount--;
+ } while (m_icount > 0);
+}
+
+
+//-------------------------------------------------
+// scripts_decode_bm - decode block move
+//-------------------------------------------------
+
+void ncr53c7xx_device::scripts_decode_bm(void)
+{
+ // Decode our instruction
+ if (m_scntl[0] & SCNTL0_TRG)
+ {
+ // Target mode
+ switch ((m_dcmd >> 3) & 3)
+ {
+ case 0:
+ m_scripts_op = &ncr53c7xx_device::bm_t_move;
+ break;
+
+ default:
+ illegal();
+ return;
+ }
+ }
+ else
+ {
+ // Initiator mode
+ switch ((m_dcmd >> 3) & 3)
+ {
+ case 0:
+ m_scripts_op = &ncr53c7xx_device::bm_i_move;
+ break;
+
+ case 1:
+ m_scripts_op = &ncr53c7xx_device::bm_i_wmov;
+ break;
+
+ default:
+ illegal();
+ return;
+ }
+ }
+
+ m_dnad = m_host_read(m_dsp + 4, 0xffffffff);
+ m_dsp += 8;
+}
+
+
+//-------------------------------------------------
+// scripts_decode_io - decode IO
+//-------------------------------------------------
+
+void ncr53c7xx_device::scripts_decode_io(void)
+{
+ // Set Target Mode?
+ if (m_dbc & (1 << 9))
+ m_scntl[0] |= SCNTL0_TRG;
+
+ // Decode our instruction
+ if (m_scntl[0] & SCNTL0_TRG)
+ {
+ // Initiator mode
+ switch ((m_dcmd >> 3) & 7)
+ {
+ case 0:
+ m_scripts_op = &ncr53c7xx_device::io_t_reselect;
+ break;
+
+ case 1:
+ m_scripts_op = &ncr53c7xx_device::io_t_disconnect;
+ break;
+
+ case 2:
+ m_scripts_op = &ncr53c7xx_device::io_t_waitselect;
+ break;
+
+ case 3:
+ m_scripts_op = &ncr53c7xx_device::io_t_set;
+ break;
+
+ case 4:
+ m_scripts_op = &ncr53c7xx_device::io_t_clear;
+ break;
+
+ default:
+ illegal();
+ return;
+ }
+ }
+ else
+ {
+ // Initiator mode
+ switch ((m_dcmd >> 3) & 7)
+ {
+ case 0:
+ m_scripts_op = &ncr53c7xx_device::io_i_select;
+ break;
+
+ case 1:
+ m_scripts_op = &ncr53c7xx_device::io_i_waitdisconnect;
+ break;
+
+ case 2:
+ m_scripts_op = &ncr53c7xx_device::io_i_waitreselect;
+ break;
+
+ case 3:
+ m_scripts_op = &ncr53c7xx_device::io_i_set;
+ break;
+
+ case 4:
+ m_scripts_op = &ncr53c7xx_device::io_i_clear;
+ break;
+
+ default:
+ illegal();
+ return;
+ }
+ }
+
+ // Set some additional registers
+ m_dnad = m_dsps = m_host_read(m_dsp + 4, 0xffffffff);
+ m_dsp += 8;
+}
+
+
+//-------------------------------------------------
+// scripts_decode_tc - decode transfer control
+//-------------------------------------------------
+
+void ncr53c7xx_device::scripts_decode_tc(void)
+{
+ // Decode our instruction
+ switch ((m_dcmd >> 3) & 7)
+ {
+ case 0:
+ m_scripts_op = &ncr53c7xx_device::tc_jump;
+ break;
+
+ case 1:
+ m_scripts_op = &ncr53c7xx_device::tc_call;
+ break;
+
+ case 2:
+ m_scripts_op = &ncr53c7xx_device::tc_return;
+ break;
+
+ case 3:
+ m_scripts_op = &ncr53c7xx_device::tc_int;
+ break;
+
+ default:
+ illegal();
+ break;
+ }
+
+ m_dnad = m_dsps = m_host_read(m_dsp + 4, 0xffffffff);
+ m_dsp += 8;
+}
+
+//**************************************************************************
+// SCSI SCRIPTS INSTRUCTIONS
+//**************************************************************************
+
+//-------------------------------------------------
+// illegal - illegal instruction
+//-------------------------------------------------
+
+void ncr53c7xx_device::illegal()
+{
+ m_dstat |= DSTAT_OPC;
+ update_irqs();
+ set_scripts_state(SCRIPTS_IDLE);
+
+}
+
+
+//-------------------------------------------------
+// bm_t_move - block move (target)
+//-------------------------------------------------
+
+void ncr53c7xx_device::bm_t_move()
+{
+ UNIMPLEMENTED;
+}
+
+
+//-------------------------------------------------
+// bm_i_move - block move (initiator)
+//-------------------------------------------------
+
+void ncr53c7xx_device::bm_i_move()
+{
+ UNIMPLEMENTED;
+}
+
+
+//-------------------------------------------------
+// bm_i_wmov - wait block move (initiator)
+//-------------------------------------------------
+
+void ncr53c7xx_device::bm_i_wmov()
+{
+ if (!m_finished)
+ {
+ if (m_scsi_state == IDLE)
+ {
+ if (m_dbc == 0)
+ {
+ VERBOSE_LOG(machine(), 0, "DBC should not be 0\n");
+ illegal();
+ }
+
+ // Indirect addressing
+ if (m_dcmd & (1 << 5))
+ m_dnad = m_host_read(m_dnad, 0xffffffff);
+
+ // Compare the phase bits
+ if ((scsi_bus->ctrl_r() & 7) == (m_dcmd & 7))
+ {
+ // Transfer bytes
+ set_scsi_state(INIT_XFER);
+ m_xfr_phase = m_dcmd & 7;
+ step(false);
+ }
+ else
+ {
+ fatalerror("Phase mismatch\n");
+ }
+ }
+ else
+ {
+ scripts_yield();
+ }
+ }
+ else
+ {
+ // TODO: We should see what happened here; different behaviour
+ // depending on whether or not we won arbitration
+ set_scripts_state(SCRIPTS_FETCH);
+ }
+}
+
+
+//-------------------------------------------------
+// io_t_reselect -
+//-------------------------------------------------
+
+void ncr53c7xx_device::io_t_reselect()
+{
+ UNIMPLEMENTED;
+}
+
+
+//-------------------------------------------------
+// io_t_disconnect -
+//-------------------------------------------------
+
+void ncr53c7xx_device::io_t_disconnect()
+{
+ UNIMPLEMENTED;
+}
+
+
+//-------------------------------------------------
+// io_t_waitselect -
+//-------------------------------------------------
+
+void ncr53c7xx_device::io_t_waitselect()
+{
+ UNIMPLEMENTED;
+}
+
+
+//-------------------------------------------------
+// io_t_set -
+//-------------------------------------------------
+
+void ncr53c7xx_device::io_t_set()
+{
+ UNIMPLEMENTED;
+}
+
+
+//-------------------------------------------------
+// io_t_clear -
+//-------------------------------------------------
+
+void ncr53c7xx_device::io_t_clear()
+{
+ UNIMPLEMENTED;
+}
+
+
+//-------------------------------------------------
+// io_i_select -
+//-------------------------------------------------
+
+void ncr53c7xx_device::io_i_select()
+{
+ if (!m_finished)
+ {
+ if (m_scsi_state == IDLE)
+ {
+ m_sdid = m_dbc >> 16;
+ m_scntl[0] |= (3 << SCNTL0_ARB_SHIFT) | SCNTL0_START;
+
+ // Set select with ATN bit
+ if (m_dcmd & 1)
+ m_scntl[0] |= SCNTL0_WATN;
+
+ // Start the arbitration
+ set_scsi_state(ARBITRATE_WAIT_FREE);
+ step(true);
+ }
+
+ scripts_yield();
+ }
+ else
+ {
+ // TODO: We should see what happened here; different behaviour
+ // depending on whether or not we won arbitration
+ set_scripts_state(SCRIPTS_FETCH);
+ }
+}
+
+
+//-------------------------------------------------
+// io_i_waitdisconnect -
+//-------------------------------------------------
+
+void ncr53c7xx_device::io_i_waitdisconnect()
+{
+ if (scsi_bus->ctrl_r() & (S_BSY | S_SEL))
+ scripts_yield();
+ else
+ set_scripts_state(SCRIPTS_FETCH);
+}
+
+
+//-------------------------------------------------
+// io_i_waitreselect -
+//-------------------------------------------------
+
+void ncr53c7xx_device::io_i_waitreselect()
+{
+ UNIMPLEMENTED;
+}
+
+
+//-------------------------------------------------
+// io_i_set -
+//-------------------------------------------------
+
+void ncr53c7xx_device::io_i_set()
+{
+ UINT32 mask = 0;
+
+ if (m_dbc & (1 << 3))
+ mask |= S_ATN;
+
+ if (m_dbc & (1 << 6))
+ mask |= S_ACK;
+
+ scsi_bus->ctrl_w(scsi_refid, mask, mask);
+
+ set_scripts_state(SCRIPTS_FETCH);
+}
+
+
+//-------------------------------------------------
+// io_i_clear -
+//-------------------------------------------------
+
+void ncr53c7xx_device::io_i_clear()
+{
+ UINT32 mask = 0;
+
+ if (m_dbc & (1 << 3))
+ mask |= S_ATN;
+
+ if (m_dbc & (1 << 6))
+ mask |= S_ACK;
+
+ scsi_bus->ctrl_w(scsi_refid, 0, mask);
+
+ set_scripts_state(SCRIPTS_FETCH);
+}
+
+
+//-------------------------------------------------
+// tc_jump -
+//-------------------------------------------------
+
+void ncr53c7xx_device::tc_jump()
+{
+// if (m_dbc & (1 << 16))
+// printf("Must wait for valid phase?\n");
+
+ bool jump = true;
+
+ if (m_dbc & (1 << 17))
+ {
+ // Phase
+ jump &= (m_dcmd & 7) == (scsi_bus->ctrl_r() & 7);
+ }
+ if (m_dbc & (1 << 18))
+ {
+ // Data
+ jump &= (m_dbc & 0xff) == m_last_data;
+ }
+
+ if (!(m_dbc & (1 << 19)))
+ jump = !jump;
+
+ if (jump)
+ {
+ m_dsp = m_dsps;
+ }
+ set_scripts_state(SCRIPTS_FETCH);
+}
+
+
+//-------------------------------------------------
+// tc_call -
+//-------------------------------------------------
+
+void ncr53c7xx_device::tc_call()
+{
+ bool jump = true;
+
+ if (m_dbc & (1 << 17))
+ {
+ // Phase
+ jump &= (m_dcmd & 7) == (scsi_bus->ctrl_r() & 7);
+ }
+ if (m_dbc & (1 << 18))
+ {
+ // Data
+ jump &= (m_dbc & 0xff) == m_last_data;
+ }
+
+ if (!(m_dbc & (1 << 19)))
+ jump = !jump;
+
+ if (jump)
+ {
+ m_temp = m_dsp;
+ m_dsp = m_dsps;
+ }
+ set_scripts_state(SCRIPTS_FETCH);
+}
+
+
+//-------------------------------------------------
+// tc_return -
+//-------------------------------------------------
+
+void ncr53c7xx_device::tc_return()
+{
+ bool jump = true;
+
+ if (m_dbc & (1 << 17))
+ {
+ // Phase
+ jump &= (m_dcmd & 7) == (scsi_bus->ctrl_r() & 7);
+ }
+ if (m_dbc & (1 << 18))
+ {
+ // Data
+ jump &= (m_dbc & 0xff) == m_last_data;
+ }
+
+ if (!(m_dbc & (1 << 19)))
+ jump = !jump;
+
+ if (jump)
+ {
+ m_dsp = m_temp;
+ }
+ set_scripts_state(SCRIPTS_FETCH);
+}
+
+
+//-------------------------------------------------
+// tc_int -
+//-------------------------------------------------
+
+void ncr53c7xx_device::tc_int()
+{
+ bool jump = true;
+
+ if (m_dbc & (1 << 17))
+ {
+ // Phase
+ jump &= (m_dcmd & 7) == (scsi_bus->ctrl_r() & 7);
+ }
+ if (m_dbc & (1 << 18))
+ {
+ // Data
+ jump &= (m_dbc & 0xff) == m_last_data;
+ }
+
+ if (!(m_dbc & (1 << 19)))
+ jump = !jump;
+
+ if (jump)
+ {
+ m_dstat |= DSTAT_SIR;
+ update_irqs();
+ set_scripts_state(SCRIPTS_IDLE);
+ }
+ else
+ {
+ set_scripts_state(SCRIPTS_FETCH);
+ }
+}
+
+
+//**************************************************************************
+// SCSI SCRIPTS DISASSEMBLY
+//**************************************************************************
+
+//-------------------------------------------------
+// disassemble_scripts -
+//-------------------------------------------------
+
+const char* ncr53c7xx_device::disassemble_scripts()
+{
+ static const char* phases[] =
+ {
+ "Data Out",
+ "Data In",
+ "Command",
+ "Status",
+ "Reserved",
+ "Reserved",
+ "Message Out",
+ "Message In"
+ };
+
+ static char buffer[64];
+ char opstring[64];
+
+ switch ((m_dcmd >> 6) & 3)
+ {
+ case 0:
+ {
+ sprintf(opstring, "BMOV: %s [%x] %d bytes\n", phases[m_dcmd & 7], m_dnad, m_dbc);
+ break;
+ }
+ case 1:
+ {
+ static const char* ops[] =
+ {
+ "SELECT",
+ "DISCONNECT",
+ "RESELECT",
+ "SET",
+ "CLEAR",
+ "ILLEGAL",
+ "ILLEGAL",
+ "ILLEGAL",
+ };
+
+ sprintf(opstring, "IO: %s (%x)\n", ops[(m_dcmd >> 3) & 7], m_dnad);
+ break;
+ }
+ case 2:
+ {
+ static const char* ops[] =
+ {
+ "JUMP",
+ "CALL",
+ "RETURN",
+ "INT",
+ "ILLEGAL",
+ "ILLEGAL",
+ "ILLEGAL",
+ "ILLEGAL",
+ };
+
+ sprintf(opstring, "TC: %s %c (%s) (%x)\n", ops[(m_dcmd >> 3) & 7], m_dbc & (1 << 19) ? 'T' : 'F', phases[m_dcmd & 7], m_dnad);
+ break;
+ }
+ case 3:
+ {
+ sprintf(opstring, "ILLEGAL");
+ break;
+ }
+ }
+
+ sprintf(buffer, "SCRIPTS [%08x]: %s", m_dsp - 8, opstring);
+
+ return buffer;
+}