summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
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
commit8d9cf973396024dbad89fda6b81f063ac7bd1c69 (patch)
tree416d3e3c609145c5b4ecf27e5624bf40cb18b370
parentba0b4a0d5b1975447f311fdae9f40fd60b3f45ed (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.cpp45
-rw-r--r--src/devices/machine/ncr5390.h1
-rw-r--r--src/mame/drivers/sun4.cpp27
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;
}