diff options
author | Patrick Mackinlay <pmackinlay@hotmail.com> | 2018-05-30 14:06:42 +0700 |
---|---|---|
committer | Olivier Galibert <galibert@pobox.com> | 2018-05-30 09:06:42 +0200 |
commit | 8d9cf973396024dbad89fda6b81f063ac7bd1c69 (patch) | |
tree | 416d3e3c609145c5b4ecf27e5624bf40cb18b370 | |
parent | ba0b4a0d5b1975447f311fdae9f40fd60b3f45ed (diff) |
ncr5390: scsi and dma fixes (nw) (#3624)
These changes make sun4 scsi work to some extent, and don't break interpro.
* ncr5390: dma support for disconnected state commands
* ncr5390: fix dma bug with tcounter=0 (meaning 65536)
* ncr5390: improve dma start and counter decrement
* sun4: fix dma control register writes
-rw-r--r-- | src/devices/machine/ncr5390.cpp | 45 | ||||
-rw-r--r-- | src/devices/machine/ncr5390.h | 1 | ||||
-rw-r--r-- | src/mame/drivers/sun4.cpp | 27 |
3 files changed, 37 insertions, 36 deletions
diff --git a/src/devices/machine/ncr5390.cpp b/src/devices/machine/ncr5390.cpp index d3410411f37..4a6d801a630 100644 --- a/src/devices/machine/ncr5390.cpp +++ b/src/devices/machine/ncr5390.cpp @@ -338,10 +338,19 @@ void ncr5390_device::step(bool timeout) step(false); break; + case DISC_SEL_ARBITRATION_INIT: + // wait until a command is in the fifo + if (!fifo_pos || (dma_command && !(status & S_TC0))) + break; + + command_length = derive_msg_size(fifo[0]); + state = DISC_SEL_ARBITRATION; + step(false); + break; + case DISC_SEL_ARBITRATION: if(c == CD_SELECT) { state = DISC_SEL_WAIT_REQ; - command_length = derive_msg_size(fifo[0]); } else state = DISC_SEL_ATN_WAIT_REQ; @@ -432,7 +441,6 @@ void ncr5390_device::step(bool timeout) case S_PHASE_DATA_OUT: case S_PHASE_COMMAND: case S_PHASE_MSG_OUT: - dma_set(dma_command ? DMA_OUT : DMA_NONE); state = INIT_XFR_SEND_BYTE; // can't send if the fifo is empty @@ -449,8 +457,6 @@ void ncr5390_device::step(bool timeout) case S_PHASE_DATA_IN: case S_PHASE_STATUS: case S_PHASE_MSG_IN: - dma_set(dma_command ? DMA_IN : DMA_NONE); - // can't receive if the fifo is full if (fifo_pos == 16) break; @@ -473,7 +479,7 @@ void ncr5390_device::step(bool timeout) break; // check for command complete - if ((dma_command && tcounter == 0 && (dma_dir == DMA_IN || fifo_pos == 0)) // dma in/out: transfer counter == 0 + if ((dma_command && (status & S_TC0) && (dma_dir == DMA_IN || fifo_pos == 0)) // dma in/out: transfer count == 0 || (!dma_command && (xfr_phase & S_INP) == 0 && fifo_pos == 0) // non-dma out: fifo empty || (!dma_command && (xfr_phase & S_INP) == S_INP && fifo_pos == 1)) // non-dma in: every byte state = INIT_XFR_BUS_COMPLETE; @@ -489,34 +495,31 @@ void ncr5390_device::step(bool timeout) break; case INIT_XFR_SEND_BYTE: - decrement_tcounter(); state = INIT_XFR_WAIT_REQ; step(false); break; case INIT_XFR_RECV_BYTE_ACK: - decrement_tcounter(); state = INIT_XFR_WAIT_REQ; scsi_bus->ctrl_w(scsi_refid, 0, S_ACK); break; case INIT_XFR_RECV_BYTE_NACK: - decrement_tcounter(); state = INIT_XFR_FUNCTION_COMPLETE; step(false); break; case INIT_XFR_FUNCTION_COMPLETE: - // wait for the fifo to drain - if (dma_command && fifo_pos) + // wait for dma transfer to complete + if (dma_command && !(status & S_TC0)) break; function_complete(); break; case INIT_XFR_BUS_COMPLETE: - // wait for the fifo to drain - if (dma_command && fifo_pos) + // wait for dma transfer to complete + if (dma_command && !(status & S_TC0)) break; bus_complete(); @@ -537,7 +540,7 @@ void ncr5390_device::step(bool timeout) case INIT_XFR_SEND_PAD: decrement_tcounter(); - if(tcounter) { + if(!(status & S_TC0)) { state = INIT_XFR_SEND_PAD_WAIT_REQ; step(false); } else @@ -559,7 +562,7 @@ void ncr5390_device::step(bool timeout) case INIT_XFR_RECV_PAD: decrement_tcounter(); - if(tcounter) { + if(!(status & S_TC0)) { state = INIT_XFR_RECV_PAD_WAIT_REQ; scsi_bus->ctrl_w(scsi_refid, 0, S_ACK); step(false); @@ -671,7 +674,7 @@ uint8_t ncr5390_device::fifo_pop() uint8_t r = fifo[0]; fifo_pos--; memmove(fifo, fifo+1, fifo_pos); - if((!fifo_pos) && dma_dir == DMA_OUT) + if((!fifo_pos) && dma_dir == DMA_OUT && !(status & S_TC0)) drq_set(); return r; } @@ -679,7 +682,7 @@ uint8_t ncr5390_device::fifo_pop() void ncr5390_device::fifo_push(uint8_t val) { fifo[fifo_pos++] = val; - if(!drq && dma_dir == DMA_IN) + if(!drq && dma_dir == DMA_IN && !(status & S_TC0)) drq_set(); } @@ -796,7 +799,8 @@ void ncr5390_device::start_command() (c == CD_SELECT_ATN) ? "Select with ATN sequence\n" : "Select with ATN and stop sequence\n"); seq = 0; - state = DISC_SEL_ARBITRATION; + state = DISC_SEL_ARBITRATION_INIT; + dma_set(dma_command ? DMA_OUT : DMA_NONE); arbitrate(); break; @@ -814,6 +818,7 @@ void ncr5390_device::start_command() LOGMASKED(LOG_COMMAND, "Transfer information\n"); state = INIT_XFR; xfr_phase = scsi_bus->ctrl_r() & S_PHASE_MASK; + dma_set(dma_command ? ((xfr_phase & S_INP) ? DMA_IN : DMA_OUT) : DMA_NONE); step(false); break; @@ -989,7 +994,8 @@ void ncr5390_device::dma_set(int dir) void ncr5390_device::dma_w(uint8_t val) { fifo_push(val); - if(fifo_pos == 16) + decrement_tcounter(); + if(fifo_pos == 16 || (status & S_TC0)) drq_clear(); step(false); } @@ -997,7 +1003,8 @@ void ncr5390_device::dma_w(uint8_t val) uint8_t ncr5390_device::dma_r() { uint8_t r = fifo_pop(); - if(!fifo_pos) + decrement_tcounter(); + if(!fifo_pos || (status & S_TC0)) drq_clear(); step(false); return r; diff --git a/src/devices/machine/ncr5390.h b/src/devices/machine/ncr5390.h index 4fae63b4a29..4e24a20eec8 100644 --- a/src/devices/machine/ncr5390.h +++ b/src/devices/machine/ncr5390.h @@ -79,6 +79,7 @@ protected: BUSRESET_RESET_BOARD, // Disconnected state commands + DISC_SEL_ARBITRATION_INIT, DISC_SEL_ARBITRATION, DISC_SEL_ATN_WAIT_REQ, DISC_SEL_ATN_SEND_BYTE, diff --git a/src/mame/drivers/sun4.cpp b/src/mame/drivers/sun4.cpp index d900781f072..244d3be326f 100644 --- a/src/mame/drivers/sun4.cpp +++ b/src/mame/drivers/sun4.cpp @@ -482,7 +482,7 @@ #define DMA_INT_PEND (0x00000001) // interrupt pending, set when TC=1 #define DMA_READ_ONLY (DMA_TC | DMA_BYTE_ADDR | DMA_REQ_PEND | DMA_PACK_CNT | DMA_ERR_PEND | DMA_INT_PEND) #define DMA_WRITE_ONLY (DMA_FLUSH) -#define DMA_READ_WRITE (DMA_EN_CNT | DMA_EN_DMA | DMA_WRITE | DMA_RESET | DMA_INT_EN) +#define DMA_READ_WRITE (DMA_EN_CNT | DMA_EN_DMA | DMA_WRITE | DMA_RESET | DMA_DRAIN | DMA_INT_EN) #define DMA_CTRL (0) #define DMA_ADDR (1) #define DMA_BYTE_COUNT (2) @@ -1808,29 +1808,22 @@ WRITE32_MEMBER( sun4_state::dma_w ) { // clear write-only bits logerror("dma_w: ctrl: %08x\n", data); - uint32_t old_ctrl = m_dma[DMA_CTRL]; - m_dma[DMA_CTRL] &= (DMA_WRITE_ONLY | DMA_READ_WRITE); - m_dma[DMA_CTRL] |= (data & (DMA_WRITE_ONLY | DMA_READ_WRITE)); + mem_mask &= (DMA_READ_WRITE); + COMBINE_DATA(&m_dma[DMA_CTRL]); - uint32_t diff = old_ctrl ^ m_dma[DMA_CTRL]; - - if (diff & DMA_FLUSH) + if (data & DMA_RESET) + m_dma[DMA_CTRL] &= ~(DMA_ERR_PEND | DMA_PACK_CNT | DMA_INT_EN | DMA_FLUSH | DMA_DRAIN | DMA_WRITE | DMA_EN_DMA | DMA_REQ_PEND | DMA_EN_CNT | DMA_TC); + else if (data & DMA_FLUSH) { - m_dma[DMA_CTRL] &= ~DMA_PACK_CNT; - m_dma[DMA_CTRL] &= ~DMA_ERR_PEND; - m_dma[DMA_CTRL] &= ~DMA_TC; + m_dma[DMA_CTRL] &= ~(DMA_PACK_CNT | DMA_ERR_PEND | DMA_TC); dma_check_interrupts(); } + // TODO: DMA_DRAIN - if (diff & DMA_EN_DMA) - { - if ((data & DMA_EN_DMA) != 0 && (m_dma[DMA_CTRL] & DMA_REQ_PEND) != 0) - { - dma_transfer(); - } - } + if (data & DMA_EN_DMA && (m_dma[DMA_CTRL] & DMA_REQ_PEND)) + dma_transfer(); break; } |