diff options
Diffstat (limited to 'src/devices/machine/53c7xx.cpp')
-rw-r--r-- | src/devices/machine/53c7xx.cpp | 1776 |
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; +} |