summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/wd33c9x.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/wd33c9x.cpp')
-rw-r--r--src/devices/machine/wd33c9x.cpp76
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;