diff options
Diffstat (limited to 'src/devices/machine/wd33c9x.cpp')
-rw-r--r-- | src/devices/machine/wd33c9x.cpp | 1064 |
1 files changed, 532 insertions, 532 deletions
diff --git a/src/devices/machine/wd33c9x.cpp b/src/devices/machine/wd33c9x.cpp index d425a9249b9..2ef063ad449 100644 --- a/src/devices/machine/wd33c9x.cpp +++ b/src/devices/machine/wd33c9x.cpp @@ -29,7 +29,8 @@ #define LOG_REGS (LOG_READS | LOG_WRITES) #define LOG_ALL (LOG_REGS | LOG_COMMANDS | LOG_ERRORS | LOG_MISC | LOG_LINES | LOG_STATE | LOG_STEP) -#define VERBOSE (0) +#define VERBOSE (LOG_COMMANDS | LOG_ERRORS | LOG_STATE) +#define LOG_OUTPUT_FUNC printf #include "logmacro.h" enum register_addresses_e : uint8_t { @@ -278,27 +279,6 @@ enum : uint16_t { INIT_CPT_RECV_BYTE_NACK }; -const char *const wd33c9x_base_device::state_names[] = { - "-", - "IDLE", - "FINISHED", - "DISC_SEL_ARBITRATION", - "INIT_MSG_WAIT_REQ", - "INIT_XFR", - "INIT_XFR_SEND_PAD_WAIT_REQ", - "INIT_XFR_SEND_PAD", - "INIT_XFR_RECV_PAD_WAIT_REQ", - "INIT_XFR_RECV_PAD", - "INIT_XFR_RECV_BYTE_ACK", - "INIT_XFR_RECV_BYTE_NACK", - "INIT_XFR_FUNCTION_COMPLETE", - "INIT_XFR_BUS_COMPLETE", - "INIT_XFR_WAIT_REQ", - "INIT_CPT_RECV_BYTE_ACK", - "INIT_CPT_RECV_WAIT_REQ", - "INIT_CPT_RECV_BYTE_NACK", -}; - enum : uint16_t { // Arbitration ARB_WAIT_BUS_FREE = 1, @@ -319,24 +299,6 @@ enum : uint16_t { RECV_WAIT_REQ_0 }; -const char *const wd33c9x_base_device::substate_names[] = { - "-", - "ARB_WAIT_BUS_FREE", - "ARB_CHECK_FREE", - "ARB_EXAMINE_BUS", - "ARB_ASSERT_SEL", - "ARB_SET_DEST", - "ARB_RELEASE_BUSY", - "ARB_TIMEOUT_BUSY", - "ARB_TIMEOUT_ABORT", - "ARB_DESKEW_WAIT", - "SEND_WAIT_SETTLE", - "SEND_WAIT_REQ_0", - "RECV_WAIT_REQ_1", - "RECV_WAIT_SETTLE", - "RECV_WAIT_REQ_0", -}; - enum : uint16_t { STATE_MASK = 0x00ff, SUB_SHIFT = 8, @@ -348,8 +310,8 @@ enum : uint16_t { // LIVE DEVICE //************************************************************************** -DEFINE_DEVICE_TYPE(WD33C92, wd33c92_device, "wd33c92", "Western Digital WD33C92 SCSI Controller") -DEFINE_DEVICE_TYPE(WD33C93, wd33c93_device, "wd33c93", "Western Digital WD33C93 SCSI Controller") +DEFINE_DEVICE_TYPE(WD33C92, wd33c92_device, "wd33c92", "Western Digital WD33C92 SCSI Controller") +DEFINE_DEVICE_TYPE(WD33C93N, wd33c93n_device, "wd33c93", "Western Digital WD33C93 SCSI Controller") DEFINE_DEVICE_TYPE(WD33C93A, wd33c93a_device, "wd33c93a", "Western Digital WD33C93A SCSI Controller") DEFINE_DEVICE_TYPE(WD33C93B, wd33c93b_device, "wd33c93b", "Western Digital WD33C93B SCSI Controller") @@ -362,10 +324,10 @@ wd33c9x_base_device::wd33c9x_base_device(const machine_config &mconfig, device_t , m_addr{ 0 } , m_regs{ 0 } , m_command_length{ 0 } - , m_last_message{ 0 } , m_scsi_state{ IDLE } , m_mode{ MODE_D } , m_xfr_phase{ 0 } + , m_step_count{ 0 } , m_transfer_count{ 0 } , m_data_fifo{ 0 } , m_data_fifo_pos{ 0 } @@ -393,10 +355,10 @@ void wd33c9x_base_device::device_start() save_item(NAME(m_addr)); save_item(NAME(m_regs)); save_item(NAME(m_command_length)); - save_item(NAME(m_last_message)); save_item(NAME(m_mode)); save_item(NAME(m_scsi_state)); save_item(NAME(m_xfr_phase)); + save_item(NAME(m_step_count)); save_item(NAME(m_transfer_count)); save_item(NAME(m_data_fifo)); save_item(NAME(m_data_fifo_pos)); @@ -422,10 +384,10 @@ void wd33c9x_base_device::device_reset() m_regs[reg] = (QUEUE_TAG <= reg && reg <= INVALID_1E) ? 0xff : 0; } m_command_length = 0; - m_last_message = 0; set_scsi_state(IDLE); m_mode = MODE_D; m_xfr_phase = 0; + m_step_count = 0; m_transfer_count = 0; data_fifo_reset(); irq_fifo_reset(); @@ -470,10 +432,10 @@ void wd33c9x_base_device::scsi_ctrl_changed() // dir_r //------------------------------------------------- -uint8_t wd33c9x_base_device::dir_r(offs_t offset) +READ8_MEMBER(wd33c9x_base_device::dir_r) { m_addr = offset & REGS_MASK; - return indir_reg_r(); + return indir_reg_r(space, 0, mem_mask); } @@ -481,10 +443,10 @@ uint8_t wd33c9x_base_device::dir_r(offs_t offset) // dir_w //------------------------------------------------- -void wd33c9x_base_device::dir_w(offs_t offset, uint8_t data) +WRITE8_MEMBER(wd33c9x_base_device::dir_w) { m_addr = offset & REGS_MASK; - indir_reg_w(data); + indir_reg_w(space, 0, data, mem_mask); } @@ -492,15 +454,15 @@ void wd33c9x_base_device::dir_w(offs_t offset, uint8_t data) // indir_r //------------------------------------------------- -uint8_t wd33c9x_base_device::indir_r(offs_t offset) +READ8_MEMBER(wd33c9x_base_device::indir_r) { switch (offset) { case 0: - return indir_addr_r(); + return indir_addr_r(space, 0, mem_mask); case 1: - return indir_reg_r(); + return indir_reg_r(space, 0, mem_mask); default: - LOGMASKED(LOG_READS | LOG_ERRORS, "Read from invalid offset %d\n", offset); + LOGMASKED(LOG_READS | LOG_ERRORS, "%s: Read from invalid offset %d\n", shortname(), offset); break; } return 0; @@ -511,17 +473,17 @@ uint8_t wd33c9x_base_device::indir_r(offs_t offset) // indir_w //------------------------------------------------- -void wd33c9x_base_device::indir_w(offs_t offset, uint8_t data) +WRITE8_MEMBER(wd33c9x_base_device::indir_w) { switch (offset) { case 0: - indir_addr_w(data); + indir_addr_w(space, 0, data, mem_mask); break; case 1: - indir_reg_w(data); + indir_reg_w(space, 0, data, mem_mask); break; default: - LOGMASKED(LOG_WRITES | LOG_ERRORS, "Write to invalid offset %d (data=%02x)\n", offset, data); + LOGMASKED(LOG_WRITES | LOG_ERRORS, "%s: Write to invalid offset %d (data=%02x)\n", shortname(), offset, data); break; } } @@ -531,10 +493,13 @@ void wd33c9x_base_device::indir_w(offs_t offset, uint8_t data) // indir_addr_r //------------------------------------------------- -uint8_t wd33c9x_base_device::indir_addr_r() +READ8_MEMBER(wd33c9x_base_device::indir_addr_r) { - // Trick to push the interrupt flag after the fifo is empty to help cps3 - return m_regs[AUXILIARY_STATUS] & 0x01 ? m_regs[AUXILIARY_STATUS] & 0x7f : m_regs[AUXILIARY_STATUS]; + if (offset != 0) { + fatalerror("%s: Read from invalid address offset %d\n", shortname(), offset); + } + step(false); + return m_regs[AUXILIARY_STATUS]; } @@ -542,8 +507,11 @@ uint8_t wd33c9x_base_device::indir_addr_r() // indir_addr_w //------------------------------------------------- -void wd33c9x_base_device::indir_addr_w(uint8_t data) +WRITE8_MEMBER(wd33c9x_base_device::indir_addr_w) { + if (offset != 0) { + fatalerror("%s: Write to invalid address offset %d (data=%02x)\n", shortname(), offset, data); + } m_addr = data & REGS_MASK; } @@ -552,11 +520,15 @@ void wd33c9x_base_device::indir_addr_w(uint8_t data) // indir_reg_r //------------------------------------------------- -uint8_t wd33c9x_base_device::indir_reg_r() +READ8_MEMBER(wd33c9x_base_device::indir_reg_r) { + if (offset != 0) { + fatalerror("%s: Read from invalid indirect register offset %d\n", shortname(), offset); + } + uint8_t ret; switch (m_addr) { - case DATA: { + case DATA: if (!(m_regs[AUXILIARY_STATUS] & AUXILIARY_STATUS_DBR)) { // The processor, except in one case, should only // access the Data Register when the DBR bit in the @@ -567,14 +539,9 @@ uint8_t wd33c9x_base_device::indir_reg_r() // Data Register. fatalerror("%s: The host should never access the data register without DBR set.\n", shortname()); } - bool was_full = data_fifo_full(); ret = data_fifo_pop(); - if (data_fifo_empty()) - m_regs[AUXILIARY_STATUS] &= ~AUXILIARY_STATUS_DBR; - if (was_full) - step(false); + m_regs[AUXILIARY_STATUS] &= ~AUXILIARY_STATUS_DBR; break; - } default: if (m_addr == OWN_ID) { @@ -604,8 +571,12 @@ uint8_t wd33c9x_base_device::indir_reg_r() // indir_reg_w //------------------------------------------------- -void wd33c9x_base_device::indir_reg_w(uint8_t data) +WRITE8_MEMBER(wd33c9x_base_device::indir_reg_w) { + if (offset != 0) { + fatalerror("%s: Write to invalid indirect register offset %d (data=%02x)\n", shortname(), offset, data); + } + switch (m_addr) { case SCSI_STATUS: case QUEUE_TAG: // Only for 92/93 and 93A @@ -614,7 +585,7 @@ void wd33c9x_base_device::indir_reg_w(uint8_t data) case INVALID_1D: case INVALID_1E: case AUXILIARY_STATUS: - LOGMASKED(LOG_WRITES | LOG_ERRORS, "Write to read-only register address %d (data=%02x)\n", m_addr, data); + LOGMASKED(LOG_WRITES | LOG_ERRORS, "%s: Write to read-only register address %d (data=%02x)\n", shortname(), m_addr, data); break; case COMMAND: { @@ -666,7 +637,7 @@ void wd33c9x_base_device::indir_reg_w(uint8_t data) WRITE_LINE_MEMBER(wd33c9x_base_device::reset_w) { if (state) { - LOGMASKED(LOG_LINES, "Reset via MR line\n"); + LOGMASKED(LOG_LINES, "%s: Reset via MR line\n", shortname()); device_reset(); } } @@ -724,7 +695,7 @@ void wd33c9x_base_device::start_command() switch (cc) { case COMMAND_CC_RESET: - LOGMASKED(LOG_COMMANDS, "Reset Command\n"); + LOGMASKED(LOG_COMMANDS, "%s: Reset Command\n", shortname()); scsi_bus->ctrl_w(scsi_refid, 0, S_ALL); scsi_bus->ctrl_wait(scsi_refid, S_SEL|S_BSY|S_RST, S_ALL); m_regs[OWN_ID] = m_command_length; @@ -738,18 +709,17 @@ void wd33c9x_base_device::start_command() set_scsi_state(FINISHED); irq_fifo_push((m_regs[OWN_ID] & OWN_ID_EAF) ? SCSI_STATUS_RESET_EAF : SCSI_STATUS_RESET); scsi_id = (m_regs[OWN_ID] & OWN_ID_SCSI_ID); - step(false); break; case COMMAND_CC_ABORT: - LOGMASKED(LOG_COMMANDS, "Abort Command\n"); + LOGMASKED(LOG_COMMANDS, "%s: Abort Command\n", shortname()); set_scsi_state(FINISHED); // FIXME irq_fifo_push((m_regs[OWN_ID] & OWN_ID_EAF) ? SCSI_STATUS_RESET_EAF : SCSI_STATUS_RESET); break; case COMMAND_CC_ASSERT_ATN: - LOGMASKED(LOG_COMMANDS, "Assert ATN Command\n"); + LOGMASKED(LOG_COMMANDS, "%s: Assert ATN Command\n", shortname()); if (m_mode != MODE_I) { fatalerror("%s: ASSERT_ATN command only valid in the Initiator state.", shortname()); } @@ -757,7 +727,7 @@ void wd33c9x_base_device::start_command() return; case COMMAND_CC_NEGATE_ACK: - LOGMASKED(LOG_COMMANDS, "Negate ACK Command\n"); + LOGMASKED(LOG_COMMANDS, "%s: Negate ACK Command\n", shortname()); // FIXME - This is causing problems, so ignore for now. //if (m_mode != MODE_I) { // fatalerror("NEGATE_ACK command only valid in the Initiator state."); @@ -766,27 +736,26 @@ void wd33c9x_base_device::start_command() return; case COMMAND_CC_DISCONNECT: - LOGMASKED(LOG_COMMANDS, "Disconnect Command\n"); + LOGMASKED(LOG_COMMANDS, "%s: Disconnect Command\n", shortname()); scsi_bus->ctrl_w(scsi_refid, 0, S_ALL); scsi_bus->ctrl_wait(scsi_refid, S_SEL|S_BSY|S_RST, S_ALL); m_mode = MODE_D; - set_scsi_state(IDLE); - m_regs[AUXILIARY_STATUS] &= ~(AUXILIARY_STATUS_CIP | AUXILIARY_STATUS_BSY); + set_scsi_state(FINISHED); + irq_fifo_push(SCSI_STATUS_DISCONNECT); break; case COMMAND_CC_SELECT: case COMMAND_CC_SELECT_ATN: - LOGMASKED(LOG_COMMANDS, "%s Command\n", select_strings[cc - COMMAND_CC_SELECT_ATN]); + LOGMASKED(LOG_COMMANDS, "%s: %s Command\n", shortname(), select_strings[cc - COMMAND_CC_SELECT_ATN]); if (m_mode != MODE_D) { fatalerror("Select commands only valid in the Disconnected state."); } set_scsi_state((ARB_WAIT_BUS_FREE << SUB_SHIFT) | DISC_SEL_ARBITRATION); - step(false); break; case COMMAND_CC_SELECT_TRANSFER: case COMMAND_CC_SELECT_ATN_TRANSFER: - LOGMASKED(LOG_COMMANDS, "%s Command\n", select_strings[cc - COMMAND_CC_SELECT_ATN]); + LOGMASKED(LOG_COMMANDS, "%s: %s Command\n", shortname(), select_strings[cc - COMMAND_CC_SELECT_ATN]); if (m_mode == MODE_D) { set_scsi_state((ARB_WAIT_BUS_FREE << SUB_SHIFT) | DISC_SEL_ARBITRATION); m_regs[COMMAND_PHASE] = COMMAND_PHASE_ZERO; @@ -799,11 +768,10 @@ void wd33c9x_base_device::start_command() } set_command_length(cc); load_transfer_count(); - step(false); break; case COMMAND_CC_TRANSFER_INFO: - LOGMASKED(LOG_COMMANDS, "Transfer Info Command\n"); + LOGMASKED(LOG_COMMANDS, "%s: Transfer Info Command\n", shortname()); if (m_mode != MODE_I) { fatalerror("%s: TRANSFER_INFO command only valid in the Initiator state.", shortname()); } @@ -819,6 +787,8 @@ void wd33c9x_base_device::start_command() fatalerror("%s: Unimplemented command: 0x%02x", shortname(), cc); break; } + + delay(1); } @@ -840,533 +810,563 @@ static const char * phase_strings[8] = { void wd33c9x_base_device::step(bool timeout) { + if (++m_step_count > 1) { + return; + } + const uint8_t cc = (m_regs[COMMAND] & COMMAND_CC); const bool sat = (cc == COMMAND_CC_SELECT_TRANSFER || cc == COMMAND_CC_SELECT_ATN_TRANSFER); - const uint32_t ctrl = scsi_bus->ctrl_r(); - const uint32_t data = scsi_bus->data_r(); - - LOGMASKED(LOG_STEP, - "%s: step - PHASE:%s BSY:%x SEL:%x REQ:%x ACK:%x ATN:%x RST:%x DATA:%02x (%s.%s) %s\n", - shortname(), - phase_strings[ctrl & S_PHASE_MASK], - (ctrl & S_BSY) ? 1 : 0, - (ctrl & S_SEL) ? 1 : 0, - (ctrl & S_REQ) ? 1 : 0, - (ctrl & S_ACK) ? 1 : 0, - (ctrl & S_ATN) ? 1 : 0, - (ctrl & S_RST) ? 1 : 0, - data, - state_names[m_scsi_state & STATE_MASK], substate_names[m_scsi_state >> SUB_SHIFT], - (timeout) ? "timeout" : "change" - ); - - if (m_mode == MODE_I) { - if (ctrl & S_BSY) { - if (ctrl & S_REQ) { - uint8_t xfr_phase = (ctrl & S_PHASE_MASK); - switch (m_scsi_state) { - case DISC_SEL_ARBITRATION: - m_xfr_phase = xfr_phase; - break; + uint32_t cycles = 0; + do { + const uint32_t ctrl = scsi_bus->ctrl_r(); + const uint32_t data = scsi_bus->data_r(); + + m_step_count = 1; + + LOGMASKED(LOG_STEP, + "%s: step - PHASE:%s BSY:%x SEL:%x REQ:%x ACK:%x ATN:%x RST:%x DATA:%x (%d.%d) %s\n", + shortname(), + phase_strings[ctrl & S_PHASE_MASK], + (ctrl & S_BSY) ? 1 : 0, + (ctrl & S_SEL) ? 1 : 0, + (ctrl & S_REQ) ? 1 : 0, + (ctrl & S_ACK) ? 1 : 0, + (ctrl & S_ATN) ? 1 : 0, + (ctrl & S_RST) ? 1 : 0, + data, + m_scsi_state & STATE_MASK, m_scsi_state >> SUB_SHIFT, + (timeout) ? "timeout" : "change" + ); - case INIT_XFR_WAIT_REQ: - break; + if (m_mode == MODE_I) { + if (ctrl & S_BSY) { + if (ctrl & S_REQ) { + uint8_t xfr_phase = (ctrl & S_PHASE_MASK); + switch (m_scsi_state) { + case DISC_SEL_ARBITRATION: + m_xfr_phase = xfr_phase; + break; - default: - if (m_xfr_phase != xfr_phase) { - fatalerror("%s: Unexpected phase change during state.\n", shortname()); + case INIT_XFR_WAIT_REQ: + break; + + default: + if (m_xfr_phase != xfr_phase) { + fatalerror("%s: Unexpected phase change during state.\n", shortname()); + } + break; } - break; } } - } else { - LOGMASKED(LOG_STATE, "Target disconnected\n"); - if (sat) { - switch (m_regs[COMMAND_PHASE]) { - case COMMAND_PHASE_DISCONNECT_MESSAGE: - set_scsi_state(FINISHED); - m_regs[COMMAND_PHASE] = COMMAND_PHASE_DISCONNECTED; - break; - - case COMMAND_PHASE_COMMAND_COMPLETE: - if (m_regs[CONTROL] & CONTROL_EDI) { + else { + LOGMASKED(LOG_STATE, "%s: Target disconnected\n", shortname()); + if (sat) { + switch (m_regs[COMMAND_PHASE]) { + case COMMAND_PHASE_DISCONNECT_MESSAGE: set_scsi_state(FINISHED); - irq_fifo_push(SCSI_STATUS_SELECT_TRANSFER_SUCCESS); - } else { - // Makes very little sense, but the previous code did it and warzard seems to need it - XXX - m_regs[CONTROL] |= CONTROL_EDI; - } - break; + m_regs[COMMAND_PHASE] = COMMAND_PHASE_DISCONNECTED; + break; - default: - fatalerror("%s: Unhandled command phase during Select-and-Transfer disconnect.\n", shortname()); - break; + case COMMAND_PHASE_COMMAND_COMPLETE: + if (m_regs[CONTROL] & CONTROL_EDI) { + set_scsi_state(FINISHED); + irq_fifo_push(SCSI_STATUS_SELECT_TRANSFER_SUCCESS); + } + break; + + default: + fatalerror("%s: Unhandled command phase during Select-and-Transfer disconnect.\n", shortname()); + break; + } } - } else { - set_scsi_state(FINISHED); - irq_fifo_push(SCSI_STATUS_DISCONNECT); + else { + set_scsi_state(FINISHED); + irq_fifo_push(SCSI_STATUS_DISCONNECT); + } + m_mode = MODE_D; + scsi_bus->ctrl_w(scsi_refid, 0, S_ALL); + scsi_bus->ctrl_wait(scsi_refid, S_SEL|S_BSY|S_RST, S_ALL); + continue; } - m_mode = MODE_D; - scsi_bus->ctrl_w(scsi_refid, 0, S_ALL); - scsi_bus->ctrl_wait(scsi_refid, S_SEL|S_BSY|S_RST, S_ALL); } - } - switch (m_scsi_state & SUB_MASK ? m_scsi_state & SUB_MASK : m_scsi_state & STATE_MASK) { - case IDLE: - break; + switch (m_scsi_state & SUB_MASK ? m_scsi_state & SUB_MASK : m_scsi_state & STATE_MASK) { + case IDLE: + break; - case FINISHED: - set_scsi_state(IDLE); - m_regs[AUXILIARY_STATUS] &= ~(AUXILIARY_STATUS_CIP | AUXILIARY_STATUS_BSY); - update_irq(); - break; + case FINISHED: + set_scsi_state(IDLE); + m_regs[AUXILIARY_STATUS] &= ~(AUXILIARY_STATUS_CIP | AUXILIARY_STATUS_BSY); + update_irq(); + break; - case ARB_WAIT_BUS_FREE << SUB_SHIFT: - if (!(ctrl & (S_BSY | S_SEL))) { - set_scsi_state_sub(ARB_CHECK_FREE); - delay(1); - } - break; + case ARB_WAIT_BUS_FREE << SUB_SHIFT: + if (timeout) { + if (!(ctrl & (S_BSY | S_SEL))) { + set_scsi_state_sub(ARB_CHECK_FREE); + } + cycles = 1; + } + break; - case ARB_CHECK_FREE << SUB_SHIFT: - if (ctrl & (S_BSY | S_SEL)) { - set_scsi_state_sub(ARB_CHECK_FREE); + case ARB_CHECK_FREE << SUB_SHIFT: + if (timeout) { + uint8_t next_state; + if (ctrl & (S_BSY | S_SEL)) { + next_state = ARB_WAIT_BUS_FREE; + cycles = 1; + } + else { + scsi_bus->data_w(scsi_refid, 1 << scsi_id); + scsi_bus->ctrl_w(scsi_refid, S_BSY, S_BSY); + next_state = ARB_EXAMINE_BUS; + cycles = 1; + } + set_scsi_state_sub(next_state); + } break; - } - if (timeout) { - scsi_bus->data_w(scsi_refid, 1 << scsi_id); - scsi_bus->ctrl_w(scsi_refid, S_BSY, S_BSY); - set_scsi_state_sub(ARB_EXAMINE_BUS); - delay(1); - } - break; - case ARB_EXAMINE_BUS << SUB_SHIFT: - if (timeout) { - if (ctrl & S_SEL) { - scsi_bus->ctrl_w(scsi_refid, 0, S_BSY); - scsi_bus->data_w(scsi_refid, 0); - set_scsi_state_sub(ARB_WAIT_BUS_FREE); - } else { - int win; - for (win = 7; win >=0 && !(data & (1 << win)); win--); - if (win == scsi_id) { - scsi_bus->ctrl_w(scsi_refid, S_SEL, S_SEL); - set_scsi_state_sub(ARB_ASSERT_SEL); - delay(1); - } else { + case ARB_EXAMINE_BUS << SUB_SHIFT: + if (timeout) { + if (ctrl & S_SEL) { + scsi_bus->ctrl_w(scsi_refid, 0, S_BSY); scsi_bus->data_w(scsi_refid, 0); - scsi_bus->ctrl_w(scsi_refid, 0, S_ALL); - set_scsi_state_sub(ARB_CHECK_FREE); + set_scsi_state_sub(ARB_WAIT_BUS_FREE); } + else { + int win; + for (win = 7; win >=0 && !(data & (1 << win)); win--) {}; + if (win == scsi_id) { + scsi_bus->ctrl_w(scsi_refid, S_SEL, S_SEL); + set_scsi_state_sub(ARB_ASSERT_SEL); + } + else { + scsi_bus->data_w(scsi_refid, 0); + scsi_bus->ctrl_w(scsi_refid, 0, S_ALL); + } + } + cycles = 1; } - } - break; + break; - case ARB_ASSERT_SEL << SUB_SHIFT: - if (timeout) { - scsi_bus->data_w(scsi_refid, (1 << scsi_id) | (1 << (m_regs[DESTINATION_ID] & DESTINATION_ID_DI))); - set_scsi_state_sub(ARB_SET_DEST); - delay(1); - } - break; + case ARB_ASSERT_SEL << SUB_SHIFT: + if (timeout) { + scsi_bus->data_w(scsi_refid, (1 << scsi_id) | (1 << (m_regs[DESTINATION_ID] & DESTINATION_ID_DI))); + set_scsi_state_sub(ARB_SET_DEST); + cycles = 1; + } + break; - case ARB_SET_DEST << SUB_SHIFT: - if (timeout) { - scsi_bus->ctrl_w(scsi_refid, (cc == COMMAND_CC_SELECT_ATN || cc == COMMAND_CC_SELECT_ATN_TRANSFER) ? S_ATN : 0, S_ATN | S_BSY); - set_scsi_state_sub(ARB_RELEASE_BUSY); - delay(1); - } - break; + case ARB_SET_DEST << SUB_SHIFT: + if (timeout) { + scsi_bus->ctrl_w(scsi_refid, (cc == COMMAND_CC_SELECT_ATN || cc == COMMAND_CC_SELECT_ATN_TRANSFER) ? S_ATN : 0, S_ATN | S_BSY); + set_scsi_state_sub(ARB_RELEASE_BUSY); + cycles = 1; + } + break; - case ARB_RELEASE_BUSY << SUB_SHIFT: - if (timeout) { - if (ctrl & S_BSY) { - set_scsi_state_sub(ARB_DESKEW_WAIT); - if (cc == COMMAND_CC_RESELECT) { - scsi_bus->ctrl_w(scsi_refid, S_BSY, S_BSY); + case ARB_RELEASE_BUSY << SUB_SHIFT: + if (timeout) { + if (ctrl & S_BSY) { + set_scsi_state_sub(ARB_DESKEW_WAIT); + if (cc == COMMAND_CC_RESELECT) { + scsi_bus->ctrl_w(scsi_refid, S_BSY, S_BSY); + } + cycles = 1; + } + else { + set_scsi_state_sub(ARB_TIMEOUT_BUSY); + cycles = 1; } - delay(1); - } else { - set_scsi_state_sub(ARB_TIMEOUT_BUSY); - delay(1); // Should be the select timeout... } - } - break; - - case ARB_DESKEW_WAIT << SUB_SHIFT: - if (timeout) { - scsi_bus->data_w(scsi_refid, 0); - scsi_bus->ctrl_w(scsi_refid, 0, S_SEL); - m_mode = (cc == COMMAND_CC_RESELECT) ? MODE_T : MODE_I; - set_scsi_state_sub(0); - step(true); - } - break; + break; - case ARB_TIMEOUT_BUSY << SUB_SHIFT: - if (timeout) { - scsi_bus->data_w(scsi_refid, 0); - set_scsi_state_sub(ARB_TIMEOUT_ABORT); - delay(1000); - } else if (ctrl & S_BSY) { - set_scsi_state_sub(ARB_DESKEW_WAIT); - if (cc == COMMAND_CC_RESELECT) { - scsi_bus->ctrl_w(scsi_refid, S_BSY, S_BSY); + case ARB_DESKEW_WAIT << SUB_SHIFT: + if (timeout) { + scsi_bus->data_w(scsi_refid, 0); + scsi_bus->ctrl_w(scsi_refid, 0, S_SEL); + m_mode = (cc == COMMAND_CC_RESELECT) ? MODE_T : MODE_I; + set_scsi_state_sub(0); + ++m_step_count; } - delay(1); - } - break; + break; - case ARB_TIMEOUT_ABORT << SUB_SHIFT: - if (timeout) { - if (ctrl & S_BSY) { + case ARB_TIMEOUT_BUSY << SUB_SHIFT: + if (timeout) { + scsi_bus->data_w(scsi_refid, 0); + set_scsi_state_sub(ARB_TIMEOUT_ABORT); + cycles = 1000; + } + else if (ctrl & S_BSY) { set_scsi_state_sub(ARB_DESKEW_WAIT); if (cc == COMMAND_CC_RESELECT) { scsi_bus->ctrl_w(scsi_refid, S_BSY, S_BSY); } - delay(1); - } else { - scsi_bus->ctrl_w(scsi_refid, 0, S_ALL); - scsi_bus->ctrl_wait(scsi_refid, S_SEL|S_BSY|S_RST, S_ALL); - m_regs[AUXILIARY_STATUS] &= ~(AUXILIARY_STATUS_CIP | AUXILIARY_STATUS_BSY); - m_mode = MODE_D; - set_scsi_state(IDLE); - irq_fifo_push(SCSI_STATUS_SELECTION_TIMEOUT); - update_irq(); + cycles = 1; } - } - break; + break; - case SEND_WAIT_SETTLE << SUB_SHIFT: - if (timeout) { - set_scsi_state_sub(SEND_WAIT_REQ_0); - step(false); - } - break; + case ARB_TIMEOUT_ABORT << SUB_SHIFT: + if (timeout) { + if (ctrl & S_BSY) { + set_scsi_state_sub(ARB_DESKEW_WAIT); + if (cc == COMMAND_CC_RESELECT) { + scsi_bus->ctrl_w(scsi_refid, S_BSY, S_BSY); + } + cycles = 1; + } + else { + scsi_bus->ctrl_w(scsi_refid, 0, S_ALL); + scsi_bus->ctrl_wait(scsi_refid, S_SEL|S_BSY|S_RST, S_ALL); + m_regs[AUXILIARY_STATUS] &= ~(AUXILIARY_STATUS_CIP | AUXILIARY_STATUS_BSY); + m_mode = MODE_D; + set_scsi_state(IDLE); + irq_fifo_push(SCSI_STATUS_SELECTION_TIMEOUT); + update_irq(); + } + } + break; - case SEND_WAIT_REQ_0 << SUB_SHIFT: - if (!(ctrl & S_REQ)) { - set_scsi_state_sub(0); - scsi_bus->data_w(scsi_refid, 0); - scsi_bus->ctrl_w(scsi_refid, 0, S_ACK); - if (sat) { - switch (m_xfr_phase) { - case S_PHASE_COMMAND: - ++m_regs[COMMAND_PHASE]; - break; + case SEND_WAIT_SETTLE << SUB_SHIFT: + if (timeout) { + set_scsi_state_sub(SEND_WAIT_REQ_0); + ++m_step_count; + } + break; + + case SEND_WAIT_REQ_0 << SUB_SHIFT: + if (!(ctrl & S_REQ)) { + set_scsi_state_sub(0); + scsi_bus->data_w(scsi_refid, 0); + scsi_bus->ctrl_w(scsi_refid, 0, S_ACK); + if (sat) { + switch (m_xfr_phase) { + case S_PHASE_COMMAND: + ++m_regs[COMMAND_PHASE]; + break; + } } + ++m_step_count; } - step(false); - } - break; + break; - case RECV_WAIT_REQ_1 << SUB_SHIFT: - if (ctrl & S_REQ) { - set_scsi_state_sub(RECV_WAIT_SETTLE); - delay(1); - } - break; + case RECV_WAIT_REQ_1 << SUB_SHIFT: + if (ctrl & S_REQ) { + set_scsi_state_sub(RECV_WAIT_SETTLE); + cycles = 1; + } + break; - case RECV_WAIT_SETTLE << SUB_SHIFT: - if (timeout) { - if (sat) { - switch (m_xfr_phase) { - case S_PHASE_DATA_IN: + case RECV_WAIT_SETTLE << SUB_SHIFT: + if (timeout) { + if (sat) { + switch (m_xfr_phase) { + case S_PHASE_DATA_IN: + data_fifo_push(data); + if ((m_regs[CONTROL] & CONTROL_DM) != CONTROL_DM_POLLED) { + set_drq(); + } + else { + decrement_transfer_count(); + m_regs[AUXILIARY_STATUS] |= AUXILIARY_STATUS_DBR; + } + break; + + case S_PHASE_STATUS: + m_regs[TARGET_LUN] = data; + m_regs[COMMAND_PHASE] = COMMAND_PHASE_STATUS_RECEIVED; + break; + + case S_PHASE_MSG_IN: + data_fifo_push(data); + break; + + default: + fatalerror("%s: Unexpected phase in RECV_WAIT_SETTLE.\n", shortname()); + break; + } + } + else { data_fifo_push(data); - if ((m_regs[CONTROL] & CONTROL_DM) != CONTROL_DM_POLLED) { + if (m_xfr_phase == S_PHASE_DATA_IN && (m_regs[CONTROL] & CONTROL_DM) != CONTROL_DM_POLLED) { set_drq(); - } else { + } + else { decrement_transfer_count(); m_regs[AUXILIARY_STATUS] |= AUXILIARY_STATUS_DBR; } - break; - - case S_PHASE_STATUS: - m_regs[TARGET_LUN] = data; - m_regs[COMMAND_PHASE] = COMMAND_PHASE_STATUS_RECEIVED; - break; - - case S_PHASE_MSG_IN: - m_last_message = data; - break; - - default: - fatalerror("%s: Unexpected phase in RECV_WAIT_SETTLE.\n", shortname()); - break; - } - } else { - data_fifo_push(data); - if (m_xfr_phase == S_PHASE_DATA_IN && (m_regs[CONTROL] & CONTROL_DM) != CONTROL_DM_POLLED) { - set_drq(); - } else { - decrement_transfer_count(); - m_regs[AUXILIARY_STATUS] |= AUXILIARY_STATUS_DBR; } + set_scsi_state_sub(RECV_WAIT_REQ_0); + scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK); + ++m_step_count; } - set_scsi_state_sub(RECV_WAIT_REQ_0); - scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK); - step(false); - } - break; - - case RECV_WAIT_REQ_0 << SUB_SHIFT: - if (!(ctrl & S_REQ)) { - set_scsi_state_sub(0); - step(false); - } - break; + break; - case DISC_SEL_ARBITRATION: - scsi_bus->ctrl_wait(scsi_refid, S_REQ, S_REQ); - if (cc == COMMAND_CC_SELECT || cc == COMMAND_CC_SELECT_ATN) { - set_scsi_state(FINISHED); - irq_fifo_push(SCSI_STATUS_SELECT_SUCCESS); - if (ctrl & S_REQ) { - irq_fifo_push(SCSI_STATUS_REQ | m_xfr_phase); + case RECV_WAIT_REQ_0 << SUB_SHIFT: + if (!(ctrl & S_REQ)) { + set_scsi_state_sub(0); + ++m_step_count; } - } else { - if(cc == COMMAND_CC_SELECT_TRANSFER) { - m_regs[COMMAND_PHASE] = COMMAND_PHASE_CP_BYTES_0; - std::string cmd; - for (uint8_t i = 0; i < m_command_length; ++i) { - const uint8_t command_byte = m_regs[CDB_1 + i]; - cmd += util::string_format(" %02x", command_byte); - data_fifo_push(command_byte); + break; + + case DISC_SEL_ARBITRATION: + scsi_bus->ctrl_wait(scsi_refid, S_REQ, S_REQ); + if (cc == COMMAND_CC_SELECT || cc == COMMAND_CC_SELECT_ATN) { + set_scsi_state(FINISHED); + irq_fifo_push(SCSI_STATUS_SELECT_SUCCESS); + if (ctrl & S_REQ) { + irq_fifo_push(SCSI_STATUS_REQ | m_xfr_phase); } - LOGMASKED(LOG_COMMANDS, "Sending command:%s (%d)\n", cmd, m_transfer_count); - } else + } + else { + set_scsi_state(INIT_XFR); m_regs[COMMAND_PHASE] = COMMAND_PHASE_SELECTED; - set_scsi_state(INIT_XFR); - } - step(false); - break; + } + ++m_step_count; + break; - case INIT_XFR: - if (ctrl & S_REQ) { - switch (m_xfr_phase) { - case S_PHASE_DATA_OUT: - if ((m_regs[CONTROL] & CONTROL_DM) != CONTROL_DM_POLLED) { - if(!data_fifo_full() && m_transfer_count > 0) - set_drq(); - } - if (!data_fifo_empty()) { - set_scsi_state(INIT_XFR_WAIT_REQ); - delay(send_byte()); - } else if ((m_regs[CONTROL] & CONTROL_DM) == CONTROL_DM_POLLED) { - m_regs[AUXILIARY_STATUS] |= AUXILIARY_STATUS_DBR; - } - break; + case INIT_XFR: + if (ctrl & S_REQ) { + switch (m_xfr_phase) { + case S_PHASE_DATA_OUT: + if ((m_regs[CONTROL] & CONTROL_DM) != CONTROL_DM_POLLED) { + while (!data_fifo_full() && m_transfer_count > 0) { + set_drq(); + } + } + if (!data_fifo_empty()) { + set_scsi_state(INIT_XFR_WAIT_REQ); + cycles = send_byte(); + } + else if ((m_regs[CONTROL] & CONTROL_DM) == CONTROL_DM_POLLED) { + m_regs[AUXILIARY_STATUS] |= AUXILIARY_STATUS_DBR; + } + break; - case S_PHASE_COMMAND: - if (!data_fifo_empty()) { - uint32_t mask; - if (sat) { - mask = 0; - } else { + case S_PHASE_COMMAND: + if (!data_fifo_empty()) { + uint32_t mask; + if (sat) { + mask = 0; + } + else { + m_regs[AUXILIARY_STATUS] |= AUXILIARY_STATUS_DBR; + mask = (m_transfer_count == 0 && m_data_fifo_size == 1) ? S_ATN : 0; + } + set_scsi_state(INIT_XFR_WAIT_REQ); + cycles = send_byte(0, mask); + } + else if (!sat) { m_regs[AUXILIARY_STATUS] |= AUXILIARY_STATUS_DBR; - mask = (m_transfer_count == 0 && m_data_fifo_size == 1) ? S_ATN : 0; } - set_scsi_state(INIT_XFR_WAIT_REQ); - delay(send_byte(0, mask)); - } else if (!sat) { - m_regs[AUXILIARY_STATUS] |= AUXILIARY_STATUS_DBR; - } - break; + break; - case S_PHASE_MSG_OUT: - if (sat) { - data_fifo_push(get_msg_out()); - } - if (!data_fifo_empty()) { - uint32_t mask; + case S_PHASE_MSG_OUT: if (sat) { - mask = S_ATN; - } else { + data_fifo_push(get_msg_out()); + } + if (!data_fifo_empty()) { + uint32_t mask; + if (sat) { + mask = S_ATN; + } + else { + m_regs[AUXILIARY_STATUS] |= AUXILIARY_STATUS_DBR; + mask = (m_transfer_count == 0 && m_data_fifo_size == 1) ? S_ATN : 0; + } + set_scsi_state(INIT_XFR_WAIT_REQ); + cycles = send_byte(0, mask); + } + else if (!sat) { m_regs[AUXILIARY_STATUS] |= AUXILIARY_STATUS_DBR; - mask = (m_transfer_count == 0 && m_data_fifo_size == 1) ? S_ATN : 0; } - set_scsi_state(INIT_XFR_WAIT_REQ); - delay(send_byte(0, mask)); - } else if (!sat) { - m_regs[AUXILIARY_STATUS] |= AUXILIARY_STATUS_DBR; - } - break; + break; - case S_PHASE_DATA_IN: - case S_PHASE_STATUS: - case S_PHASE_MSG_IN: - if (!data_fifo_full()) { - // if it's the last message byte, ACK remains asserted, terminate with function_complete() - //state = (m_xfr_phase == S_PHASE_MSG_IN && (!dma_command || tcounter == 1)) ? INIT_XFR_RECV_BYTE_NACK : INIT_XFR_RECV_BYTE_ACK; - scsi_bus->ctrl_wait(scsi_refid, S_REQ, S_REQ); - set_scsi_state((RECV_WAIT_REQ_1 << SUB_SHIFT) | INIT_XFR_RECV_BYTE_ACK); - step(false); - } - break; + case S_PHASE_DATA_IN: + case S_PHASE_STATUS: + case S_PHASE_MSG_IN: + if (!data_fifo_full()) { + // if it's the last message byte, ACK remains asserted, terminate with function_complete() + //state = (m_xfr_phase == S_PHASE_MSG_IN && (!dma_command || tcounter == 1)) ? INIT_XFR_RECV_BYTE_NACK : INIT_XFR_RECV_BYTE_ACK; + scsi_bus->ctrl_wait(scsi_refid, S_REQ, S_REQ); + set_scsi_state((RECV_WAIT_REQ_1 << SUB_SHIFT) | INIT_XFR_RECV_BYTE_ACK); + if (ctrl & S_REQ) { + ++m_step_count; + } + } + break; - default: - fatalerror("%s: Invalid phase during INIT_XFR.\n", shortname()); - break; + default: + fatalerror("%s: Invalid phase during INIT_XFR.\n", shortname()); + break; + } } - } - break; + break; - case INIT_XFR_WAIT_REQ: - if (ctrl & S_REQ) { - uint16_t next_state = m_scsi_state; + case INIT_XFR_WAIT_REQ: + if (ctrl & S_REQ) { + uint16_t next_state = m_scsi_state; - const uint8_t xfr_phase = (ctrl & S_PHASE_MASK); + const uint8_t xfr_phase = (ctrl & S_PHASE_MASK); - switch ((m_xfr_phase << 3) | xfr_phase) { - case ((S_PHASE_MSG_OUT << 3) | S_PHASE_MSG_OUT): - case ((S_PHASE_COMMAND << 3) | S_PHASE_COMMAND): - case ((S_PHASE_MSG_IN << 3) | S_PHASE_MSG_IN): - next_state = INIT_XFR; - break; + switch ((m_xfr_phase << 3) | xfr_phase) { + case ((S_PHASE_MSG_OUT << 3) | S_PHASE_MSG_OUT): + case ((S_PHASE_COMMAND << 3) | S_PHASE_COMMAND): + case ((S_PHASE_MSG_IN << 3) | S_PHASE_MSG_IN): + next_state = INIT_XFR; + break; - case ((S_PHASE_DATA_IN << 3) | S_PHASE_DATA_IN): - case ((S_PHASE_DATA_OUT << 3) | S_PHASE_DATA_OUT): - if (sat || cc == COMMAND_CC_TRANSFER_INFO) { - if (m_transfer_count > 0 || (m_xfr_phase == S_PHASE_DATA_OUT && !data_fifo_empty())) { - next_state = INIT_XFR; + case ((S_PHASE_DATA_IN << 3) | S_PHASE_DATA_IN): + case ((S_PHASE_DATA_OUT << 3) | S_PHASE_DATA_OUT): + if (sat || cc == COMMAND_CC_TRANSFER_INFO) { + if (m_transfer_count > 0 || (m_xfr_phase == S_PHASE_DATA_OUT && !data_fifo_empty())) { + next_state = INIT_XFR; + } + else { + next_state = FINISHED; + uint8_t scsi_status; + if (sat) { + m_regs[COMMAND_PHASE] = COMMAND_PHASE_TRANSFER_COUNT; + scsi_status = SCSI_STATUS_UNEXPECTED_PHASE; + } + else { + scsi_status = SCSI_STATUS_TRANSFER_SUCCESS; + } + irq_fifo_push(scsi_status | m_xfr_phase); + } } else { + fatalerror("%s: Unhandled command in data phase.\n", shortname()); next_state = FINISHED; - uint8_t scsi_status; - if (sat) { - m_regs[COMMAND_PHASE] = COMMAND_PHASE_TRANSFER_COUNT; - scsi_status = SCSI_STATUS_UNEXPECTED_PHASE; - } - else { - scsi_status = SCSI_STATUS_TRANSFER_SUCCESS; + } + break; + + case ((S_PHASE_MSG_OUT << 3) | S_PHASE_COMMAND): + case ((S_PHASE_COMMAND << 3) | S_PHASE_DATA_OUT): + case ((S_PHASE_COMMAND << 3) | S_PHASE_DATA_IN): + case ((S_PHASE_COMMAND << 3) | S_PHASE_STATUS): + case ((S_PHASE_COMMAND << 3) | S_PHASE_MSG_IN): + case ((S_PHASE_DATA_OUT << 3) | S_PHASE_STATUS): + case ((S_PHASE_DATA_IN << 3) | S_PHASE_STATUS): + case ((S_PHASE_STATUS << 3) | S_PHASE_MSG_IN): + if (!(m_xfr_phase & 1) && !data_fifo_empty()) { + fatalerror("%s: Data FIFO is not empty on phase transition.\n", shortname()); + } + + if (sat) { + switch (xfr_phase) { + case S_PHASE_MSG_OUT: + next_state = INIT_XFR; + break; + + case S_PHASE_COMMAND: + next_state = INIT_XFR; + m_regs[COMMAND_PHASE] = COMMAND_PHASE_CP_BYTES_0; + LOGMASKED(LOG_COMMANDS, "%s: Sending Command:", shortname()); + for (uint8_t i = 0; i < m_command_length; ++i) { + const uint8_t command_byte = m_regs[CDB_1 + i]; + LOGMASKED(LOG_COMMANDS, " %02x", command_byte); + data_fifo_push(command_byte); + } + LOGMASKED(LOG_COMMANDS, " (%d)\n", m_transfer_count); + break; + + case S_PHASE_DATA_OUT: + case S_PHASE_DATA_IN: + next_state = INIT_XFR; + break; + + case S_PHASE_STATUS: + next_state = INIT_XFR; + m_regs[COMMAND_PHASE] = COMMAND_PHASE_RECEIVE_STATUS; + break; + + case S_PHASE_MSG_IN: + next_state = INIT_XFR; + break; + + default: + fatalerror("%s: Unhandled phase in Select-w/Atn-and-Transfer.\n", shortname()); + next_state = FINISHED; + break; } - irq_fifo_push(scsi_status | m_xfr_phase); } - } - else { - fatalerror("%s: Unhandled command in data phase.\n", shortname()); + else if (cc == COMMAND_CC_TRANSFER_INFO) { + next_state = FINISHED; + irq_fifo_push(SCSI_STATUS_TRANSFER_SUCCESS | xfr_phase); + } + else { + fatalerror("%s: Unhandled command in data phase.\n", shortname()); + next_state = FINISHED; + } + break; + + default: + fatalerror("%s: Unhandled phase transition in INIT_XFR_WAIT_REQ.\n", shortname()); next_state = FINISHED; + break; } - break; - case ((S_PHASE_MSG_OUT << 3) | S_PHASE_COMMAND): - case ((S_PHASE_COMMAND << 3) | S_PHASE_DATA_OUT): - case ((S_PHASE_COMMAND << 3) | S_PHASE_DATA_IN): - case ((S_PHASE_COMMAND << 3) | S_PHASE_STATUS): - case ((S_PHASE_COMMAND << 3) | S_PHASE_MSG_IN): - case ((S_PHASE_DATA_OUT << 3) | S_PHASE_STATUS): - case ((S_PHASE_DATA_IN << 3) | S_PHASE_STATUS): - case ((S_PHASE_STATUS << 3) | S_PHASE_MSG_IN): - if (!(m_xfr_phase & 1) && !data_fifo_empty()) { - fatalerror("%s: Data FIFO is not empty on phase transition.\n", shortname()); + if (next_state != m_scsi_state) { + set_scsi_state(next_state); + ++m_step_count; + m_xfr_phase = xfr_phase; } + } + break; - if (sat) { - switch (xfr_phase) { - case S_PHASE_MSG_OUT: - next_state = INIT_XFR; - break; - - case S_PHASE_COMMAND: { - next_state = INIT_XFR; - m_regs[COMMAND_PHASE] = COMMAND_PHASE_CP_BYTES_0; - std::string cmd; - for (uint8_t i = 0; i < m_command_length; ++i) { - const uint8_t command_byte = m_regs[CDB_1 + i]; - cmd += util::string_format(" %02x", command_byte); - data_fifo_push(command_byte); - } - LOGMASKED(LOG_COMMANDS, "Sending command:%s (%d)\n", cmd, m_transfer_count); + case INIT_XFR_RECV_BYTE_ACK: + if (sat && m_xfr_phase == S_PHASE_MSG_IN) { + const uint8_t msg = data_fifo_pop(); + if (m_regs[COMMAND_PHASE] <= COMMAND_PHASE_CP_BYTES_C) { + switch (msg) { + case SM_SAVE_DATA_PTR: + set_scsi_state(FINISHED); + irq_fifo_push(SCSI_STATUS_SAVE_DATA_POINTERS); + m_regs[COMMAND_PHASE] = COMMAND_PHASE_SAVE_DATA_POINTER; break; - } - case S_PHASE_DATA_OUT: - case S_PHASE_DATA_IN: - next_state = INIT_XFR; + case SM_DISCONNECT: + m_regs[COMMAND_PHASE] = COMMAND_PHASE_DISCONNECT_MESSAGE; break; - case S_PHASE_STATUS: - next_state = INIT_XFR; - m_regs[COMMAND_PHASE] = COMMAND_PHASE_RECEIVE_STATUS; + default: + fatalerror("%s: Unhandled MSG_IN.\n", shortname()); break; - - case S_PHASE_MSG_IN: - next_state = INIT_XFR; + } + } + else if (m_regs[COMMAND_PHASE] < COMMAND_PHASE_COMMAND_COMPLETE) { + switch (msg) { + case SM_COMMAND_COMPLETE: + set_scsi_state(FINISHED); + irq_fifo_push(SCSI_STATUS_SELECT_TRANSFER_SUCCESS); + m_regs[COMMAND_PHASE] = COMMAND_PHASE_COMMAND_COMPLETE; break; - default: - fatalerror("%s: Unhandled phase in Select-w/Atn-and-Transfer.\n", shortname()); - next_state = FINISHED; + fatalerror("%s: Unhandled MSG_IN.\n", shortname()); break; } } - else if (cc == COMMAND_CC_TRANSFER_INFO) { - next_state = FINISHED; - irq_fifo_push(SCSI_STATUS_TRANSFER_SUCCESS | xfr_phase); - } - else { - fatalerror("%s: Unhandled command in data phase.\n", shortname()); - next_state = FINISHED; - } - break; - - default: - fatalerror("%s: Unhandled phase transition in INIT_XFR_WAIT_REQ.\n", shortname()); - next_state = FINISHED; - break; } - - if (next_state != m_scsi_state) { - set_scsi_state(next_state); - m_xfr_phase = xfr_phase; - step(false); + else { + set_scsi_state(INIT_XFR_WAIT_REQ); } - } - break; + scsi_bus->ctrl_w(scsi_refid, 0, S_ACK); + ++m_step_count; + break; - case INIT_XFR_RECV_BYTE_ACK: - if (sat && m_xfr_phase == S_PHASE_MSG_IN) { - if (m_regs[COMMAND_PHASE] <= COMMAND_PHASE_CP_BYTES_C) { - switch (m_last_message) { - case SM_SAVE_DATA_PTR: - set_scsi_state(FINISHED); - irq_fifo_push(SCSI_STATUS_SAVE_DATA_POINTERS); - m_regs[COMMAND_PHASE] = COMMAND_PHASE_SAVE_DATA_POINTER; - break; + default: + fatalerror("%s: Unhandled state in step.\n", shortname()); + break; + } - case SM_DISCONNECT: - m_regs[COMMAND_PHASE] = COMMAND_PHASE_DISCONNECT_MESSAGE; - break; + timeout = false; - default: - fatalerror("%s: Unhandled MSG_IN %02x.\n", shortname(), m_last_message); - break; - } - } else if (m_regs[COMMAND_PHASE] < COMMAND_PHASE_COMMAND_COMPLETE) { - switch (m_last_message) { - case SM_COMMAND_COMPLETE: - set_scsi_state(FINISHED); - irq_fifo_push(SCSI_STATUS_SELECT_TRANSFER_SUCCESS); - m_regs[COMMAND_PHASE] = COMMAND_PHASE_COMMAND_COMPLETE; - break; - default: - fatalerror("%s: Unhandled MSG_IN %02x.\n", shortname(), m_last_message); - break; - } - } - } else { - set_scsi_state(INIT_XFR_WAIT_REQ); - } - scsi_bus->ctrl_w(scsi_refid, 0, S_ACK); - step(false); - break; + } while (--m_step_count); - default: - fatalerror("%s: Unhandled state in step.\n", shortname()); - break; + if (cycles) { + delay(cycles); } } @@ -1390,7 +1390,7 @@ void wd33c9x_base_device::load_transfer_count() m_transfer_count = 1; } } - LOGMASKED(LOG_COMMANDS, "Transfer Count %d bytes\n", m_transfer_count); + LOGMASKED(LOG_COMMANDS, "%s: Transfer Count %d bytes\n", shortname(), m_transfer_count); } @@ -1499,9 +1499,7 @@ uint32_t wd33c9x_base_device::send_byte(const uint32_t value, const uint32_t mas void wd33c9x_base_device::set_scsi_state(uint16_t state) { - LOGMASKED(LOG_STEP, "SCSI state change: %s.%s to %s.%s\n", - state_names[m_scsi_state & STATE_MASK], substate_names[m_scsi_state >> SUB_SHIFT], - state_names[state & STATE_MASK], substate_names[state >> SUB_SHIFT]); + LOGMASKED(LOG_STEP, "%s: SCSI state change: %x to %x\n", shortname(), m_scsi_state, state); m_scsi_state = state; } @@ -1590,7 +1588,7 @@ void wd33c9x_base_device::update_irq() { if (m_regs[AUXILIARY_STATUS] & AUXILIARY_STATUS_INT) { m_regs[AUXILIARY_STATUS] &= ~AUXILIARY_STATUS_INT; - LOGMASKED(LOG_LINES, "Clearing IRQ\n"); + LOGMASKED(LOG_LINES, "%s: Clearing IRQ\n", shortname()); m_irq_cb(CLEAR_LINE); } if (!irq_fifo_empty()) { @@ -1614,7 +1612,7 @@ void wd33c9x_base_device::update_irq() } } - LOGMASKED(LOG_LINES, "Asserting IRQ - SCSI Status (%02x)\n", m_regs[SCSI_STATUS]); + LOGMASKED(LOG_LINES, "%s: Asserting IRQ - SCSI Status (%02x)\n", shortname(), m_regs[SCSI_STATUS]); m_irq_cb(ASSERT_LINE); } } @@ -1627,7 +1625,7 @@ void wd33c9x_base_device::update_irq() void wd33c9x_base_device::set_drq() { if (!m_drq_state) { - LOGMASKED(LOG_LINES, "Asserting DRQ\n"); + LOGMASKED(LOG_LINES, "%s: Asserting DRQ\n", shortname()); m_drq_state = true; m_drq_cb(ASSERT_LINE); } @@ -1641,7 +1639,7 @@ void wd33c9x_base_device::set_drq() void wd33c9x_base_device::clear_drq() { if (m_drq_state) { - LOGMASKED(LOG_LINES, "Clearing DRQ\n"); + LOGMASKED(LOG_LINES, "%s: Clearing DRQ\n", shortname()); m_drq_state = false; m_drq_cb(CLEAR_LINE); } @@ -1680,13 +1678,15 @@ bool wd33c9x_base_device::set_command_length(const uint8_t cc) if (eaf && (cc == COMMAND_CC_SELECT_TRANSFER || cc == COMMAND_CC_SELECT_ATN_TRANSFER)) { m_command_length &= OWN_ID_CDB_SIZE; ret = true; - } else if (eaf && cc == COMMAND_CC_WAIT_SELECT_RECEIVE_DATA) { + } + else if (eaf && cc == COMMAND_CC_WAIT_SELECT_RECEIVE_DATA) { m_command_length = 6; m_regs[COMMAND_PHASE] = COMMAND_PHASE_CP_BYTES_1; irq_fifo_push(SCSI_STATUS_NEED_COMMAND_SIZE); update_irq(); ret = false; - } else { + } + else { switch (m_regs[CDB_1] >> 5) { default: case 0: m_command_length = 6; break; @@ -1695,7 +1695,7 @@ bool wd33c9x_base_device::set_command_length(const uint8_t cc) } ret = true; } - LOGMASKED(LOG_COMMANDS, "SCSI Command Length %d bytes\n", m_command_length); + LOGMASKED(LOG_COMMANDS, "%s: SCSI Command Length %d bytes\n", shortname(), m_command_length); return ret; } @@ -1715,8 +1715,8 @@ wd33c92_device::wd33c92_device(const machine_config &mconfig, const char *tag, d { } -wd33c93_device::wd33c93_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : wd33c9x_base_device(mconfig, WD33C93, tag, owner, clock) +wd33c93n_device::wd33c93n_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : wd33c9x_base_device(mconfig, WD33C93N, tag, owner, clock) { } |