diff options
Diffstat (limited to 'src/devices/machine/cxd1185.cpp')
-rw-r--r-- | src/devices/machine/cxd1185.cpp | 38 |
1 files changed, 29 insertions, 9 deletions
diff --git a/src/devices/machine/cxd1185.cpp b/src/devices/machine/cxd1185.cpp index 8b24126b662..6dfa38915a1 100644 --- a/src/devices/machine/cxd1185.cpp +++ b/src/devices/machine/cxd1185.cpp @@ -33,12 +33,12 @@ DEFINE_DEVICE_TYPE(CXD1185, cxd1185_device, "cxd1185", "Sony CXD1185 SCSI 1 Prot static char const *const nscsi_phase[] = { "DATA OUT", "DATA IN", "COMMAND", "STATUS", "*", "*", "MESSAGE OUT", "MESSAGE IN" }; // FIXME: would be better to reuse from nscsi_full_device -static unsigned const SCSI_ARB_DELAY = 2'400; -static unsigned const SCSI_BUS_CLEAR = 800; -static unsigned const SCSI_BUS_FREE = 800; -static unsigned const SCSI_BUS_SETTLE = 400; -static unsigned const SCSI_BUS_SKEW = 10; -static unsigned const SCSI_RST_HOLD = 25'000; +static constexpr unsigned SCSI_ARB_DELAY = 2'400; +static constexpr unsigned SCSI_BUS_CLEAR = 800; +static constexpr unsigned SCSI_BUS_FREE = 800; +static constexpr unsigned SCSI_BUS_SETTLE = 400; +static constexpr unsigned SCSI_BUS_SKEW = 10; +static constexpr unsigned SCSI_RST_HOLD = 25'000; ALLOW_SAVE_TYPE(cxd1185_device::state); @@ -261,6 +261,7 @@ void cxd1185_device::command_w(u8 data) m_command = data; m_status |= CIP; + m_last_dma_direction = DMA_NONE; switch (data & (CAT | CMD)) { @@ -304,11 +305,13 @@ void cxd1185_device::command_w(u8 data) LOGMASKED(LOG_CMD, "select target %d without atn\n", (m_scsi_id & TID) >> 5); m_status |= INIT; m_state = ARB_BUS_FREE; + m_last_dma_direction = (m_command & DMA) ? DMA_OUT : DMA_NONE; break; case 0x42: LOGMASKED(LOG_CMD, "select target %d with atn\n", (m_scsi_id & TID) >> 5); m_status |= INIT; m_state = ARB_BUS_FREE; + m_last_dma_direction = (m_command & DMA) ? DMA_OUT : DMA_NONE; break; case 0x43: LOGMASKED(LOG_CMD, "enable selection/reselection\n"); break; case 0x44: LOGMASKED(LOG_CMD, "disable selection/reselection\n"); break; @@ -325,10 +328,12 @@ void cxd1185_device::command_w(u8 data) case 0xc0: LOGMASKED(LOG_CMD, "transfer information\n"); m_state = XFR_INFO; + m_last_dma_direction = !(m_command & DMA) ? DMA_NONE : (scsi_bus->ctrl_r() & S_INP) ? DMA_IN : DMA_OUT; break; case 0xc1: LOGMASKED(LOG_CMD, "transfer pad\n"); m_state = XFR_INFO; + m_last_dma_direction = !(m_command & DMA) ? DMA_NONE : (scsi_bus->ctrl_r() & S_INP) ? DMA_IN : DMA_OUT; break; case 0xc2: LOGMASKED(LOG_CMD, "deassert ack\n"); @@ -616,6 +621,11 @@ int cxd1185_device::state_step() // assert ACK scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK); + + // If this is a DMA command and we have data now, assert DRQ so host can start transferring + // (also handles transfers in the case where the counter is not aligned with the expected bytes read) + if (m_command & DMA) + set_drq(true); } else { @@ -649,7 +659,8 @@ int cxd1185_device::state_step() // check if target changed phase if (m_int_req[1] & PHC) { - if (m_command & DMA) + // Lower DRQ unless FIFO still has valid data that the host machine can read out + if ((m_command & DMA) && m_fifo.empty()) set_drq(false); m_state = XFR_INFO_DONE; @@ -831,12 +842,21 @@ void cxd1185_device::int_check() { bool irq_asserted = false; + // When SPHI is set during DMA data in, phase change interrupts are deferred until the DMA transfer is complete + // This will be recalculated at that time once the FIFO is empty + uint8_t int_req1 = m_int_req[1]; + if ((m_mode & SPHI) && !m_fifo.empty() && (m_last_dma_direction == DMA_IN) && (int_req1 & PHC)) + { + LOGMASKED(LOG_INT, "SPHI active, suppressing PHC interrupt\n"); + int_req1 &= ~PHC; + } + // update mirq - if (m_int_req[0] || m_int_req[1]) + if (m_int_req[0] || int_req1) { m_status |= MIRQ; - irq_asserted = (m_int_req[0] & m_int_auth[0]) || (m_int_req[1] & m_int_auth[1]); + irq_asserted = (m_int_req[0] & m_int_auth[0]) || (int_req1 & m_int_auth[1]); } else m_status &= ~MIRQ; |