diff options
Diffstat (limited to 'src/devices/machine/wd33c9x.cpp')
-rw-r--r-- | src/devices/machine/wd33c9x.cpp | 76 |
1 files changed, 56 insertions, 20 deletions
diff --git a/src/devices/machine/wd33c9x.cpp b/src/devices/machine/wd33c9x.cpp index 7c84c86f72d..9e20893b9d3 100644 --- a/src/devices/machine/wd33c9x.cpp +++ b/src/devices/machine/wd33c9x.cpp @@ -18,14 +18,14 @@ #include "emu.h" #include "wd33c9x.h" -#define LOG_READS (1 << 0) -#define LOG_WRITES (1 << 1) -#define LOG_COMMANDS (1 << 2) -#define LOG_ERRORS (1 << 3) -#define LOG_MISC (1 << 4) -#define LOG_LINES (1 << 5) -#define LOG_STATE (1 << 6) -#define LOG_STEP (1 << 7) +#define LOG_READS (1U << 1) +#define LOG_WRITES (1U << 2) +#define LOG_COMMANDS (1U << 3) +#define LOG_ERRORS (1U << 4) +#define LOG_MISC (1U << 5) +#define LOG_LINES (1U << 6) +#define LOG_STATE (1U << 7) +#define LOG_STEP (1U << 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) @@ -388,9 +388,7 @@ wd33c9x_base_device::wd33c9x_base_device(const machine_config &mconfig, device_t void wd33c9x_base_device::device_start() { - m_irq_cb.resolve_safe(); - m_drq_cb.resolve_safe(); - m_timer = timer_alloc(0); + m_timer = timer_alloc(FUNC(wd33c9x_base_device::update_step), this); save_item(NAME(m_addr)); save_item(NAME(m_regs)); save_item(NAME(m_command_length)); @@ -443,10 +441,10 @@ void wd33c9x_base_device::device_reset() //------------------------------------------------- -// device_timer - device-specific timer handler +// update_step - //------------------------------------------------- -void wd33c9x_base_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +TIMER_CALLBACK_MEMBER(wd33c9x_base_device::update_step) { step(true); } @@ -670,7 +668,7 @@ void wd33c9x_base_device::indir_reg_w(uint8_t data) // reset - Host reset line handler //------------------------------------------------- -WRITE_LINE_MEMBER(wd33c9x_base_device::reset_w) +void wd33c9x_base_device::reset_w(int state) { if (state) { LOGMASKED(LOG_LINES, "Reset via MR line\n"); @@ -809,6 +807,38 @@ void wd33c9x_base_device::start_command() step(false); break; + case COMMAND_CC_TRANSLATE_ADDRESS: + LOGMASKED(LOG_COMMANDS, "Translate Address Command\n"); + { + uint8_t total_sectors = m_regs[CDB_1]; + uint8_t total_heads = m_regs[CDB_2]; + uint16_t total_cylinders = m_regs[CDB_3] << 8 | m_regs[CDB_4]; + uint32_t lba = (m_regs[CDB_5] << 24) | (m_regs[CDB_6] << 16) | (m_regs[CDB_7] << 8) | (m_regs[CDB_8] << 0); + + LOGMASKED(LOG_COMMANDS, "total_sectors=%02x, total_heads=%02x, total_cylinders=%04x, lba=%08x\n", total_sectors, total_heads, total_cylinders, lba); + + uint16_t cylinder = lba / (total_sectors * total_heads); + uint8_t head = (lba - (cylinder * total_sectors * total_heads)) / total_sectors; + uint8_t sector = (lba - (cylinder * total_sectors * total_heads)) % total_sectors; + + LOGMASKED(LOG_COMMANDS, "-> cylinder=%04x, head=%02x, sector=%02x\n", cylinder, head, sector); + + m_regs[CDB_9] = sector; + m_regs[CDB_10] = head; + m_regs[CDB_11] = cylinder >> 8; + m_regs[CDB_12] = cylinder >> 0; + + m_regs[AUXILIARY_STATUS] &= ~(AUXILIARY_STATUS_CIP | AUXILIARY_STATUS_BSY); + + if (cylinder >= total_cylinders) + irq_fifo_push(SCSI_STATUS_LOGICAL_ADDRESS_TOO_LARGE); + else + irq_fifo_push(SCSI_STATUS_TRANSLATE_SUCCESS); + + update_irq(); + } + break; + case COMMAND_CC_TRANSFER_INFO: LOGMASKED(LOG_COMMANDS, "Transfer Info Command\n"); if (m_mode != MODE_I) { @@ -901,8 +931,8 @@ void wd33c9x_base_device::step(bool timeout) 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; + set_scsi_state(FINISHED); + irq_fifo_push(SCSI_STATUS_DISCONNECT); } break; @@ -1164,6 +1194,8 @@ void wd33c9x_base_device::step(bool timeout) delay(send_byte()); } else if ((m_regs[CONTROL] & CONTROL_DM) == CONTROL_DM_POLLED) { m_regs[AUXILIARY_STATUS] |= AUXILIARY_STATUS_DBR; + } else { + delay(1); } break; @@ -1208,9 +1240,13 @@ void wd33c9x_base_device::step(bool timeout) 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); + if (m_drq_state) { + delay(1); + } else { + 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; @@ -1338,7 +1374,7 @@ void wd33c9x_base_device::step(bool timeout) 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: + case SM_SAVE_DATA_POINTER: set_scsi_state(FINISHED); irq_fifo_push(SCSI_STATUS_SAVE_DATA_POINTERS); m_regs[COMMAND_PHASE] = COMMAND_PHASE_SAVE_DATA_POINTER; |