diff options
author | R. Belmont <rb6502@users.noreply.github.com> | 2017-07-09 20:27:12 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-07-09 20:27:12 -0400 |
commit | 9398fff5f632aa80f9b20a24f12503b03aaafe32 (patch) | |
tree | 4c476dad6cd272a58c37a6591de86a3a0d7f4f50 | |
parent | d31f24c1c2a7f38bb0b5abe877533668e1b4e9de (diff) | |
parent | ea154eff6ef6d76c5d011e45f92e0ac0badcc216 (diff) |
Merge pull request #2455 from pmackinlay/ncr5390
ncr5390: tcounter and dma/drq changes
-rw-r--r-- | src/devices/machine/ncr5390.cpp | 85 | ||||
-rw-r--r-- | src/devices/machine/ncr5390.h | 4 | ||||
-rw-r--r-- | src/devices/machine/nscsi_hd.cpp | 13 |
3 files changed, 76 insertions, 26 deletions
diff --git a/src/devices/machine/ncr5390.cpp b/src/devices/machine/ncr5390.cpp index 53f78a1129d..4cdf09cc3da 100644 --- a/src/devices/machine/ncr5390.cpp +++ b/src/devices/machine/ncr5390.cpp @@ -426,6 +426,10 @@ void ncr5390_device::step(bool timeout) dma_set(dma_command ? DMA_OUT : DMA_NONE); state = INIT_XFR_SEND_BYTE; + // can't send if the fifo is empty + if (fifo_pos == 0) + break; + // if it's the last message byte, deassert ATN before sending if (xfr_phase == S_PHASE_MSG_OUT && ((!dma_command && fifo_pos == 1) || (dma_command && tcounter == 1))) scsi_bus->ctrl_w(scsi_refid, 0, S_ATN); @@ -438,6 +442,10 @@ void ncr5390_device::step(bool timeout) 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; + // if it's the last message byte, ACK remains asserted, terminate with function_complete() state = (xfr_phase == S_PHASE_MSG_IN && (!dma_command || tcounter == 1)) ? INIT_XFR_RECV_BYTE_NACK : INIT_XFR_RECV_BYTE_ACK; @@ -456,34 +464,55 @@ void ncr5390_device::step(bool timeout) break; // check for command complete - if ((dma_command && tcounter == 0 && fifo_pos == 0) // dma in/out: transfer counter == 0 and fifo empty + if ((dma_command && tcounter == 0) // dma in/out: transfer counter == 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 - bus_complete(); + state = INIT_XFR_BUS_COMPLETE; else // check for phase change if((ctrl & S_PHASE_MASK) != xfr_phase) { command_pos = 0; - bus_complete(); + state = INIT_XFR_BUS_COMPLETE; } else { state = INIT_XFR; - step(false); } + step(false); 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) + break; + function_complete(); break; + case INIT_XFR_BUS_COMPLETE: + // wait for the fifo to drain + if (dma_command && fifo_pos) + break; + + bus_complete(); + break; + case INIT_XFR_SEND_PAD_WAIT_REQ: if(!(ctrl & S_REQ)) break; @@ -498,7 +527,7 @@ void ncr5390_device::step(bool timeout) break; case INIT_XFR_SEND_PAD: - tcounter--; + decrement_tcounter(); if(tcounter) { state = INIT_XFR_SEND_PAD_WAIT_REQ; step(false); @@ -520,7 +549,7 @@ void ncr5390_device::step(bool timeout) break; case INIT_XFR_RECV_PAD: - tcounter--; + decrement_tcounter(); if(tcounter) { state = INIT_XFR_RECV_PAD_WAIT_REQ; scsi_bus->ctrl_w(scsi_refid, 0, S_ACK); @@ -608,7 +637,6 @@ READ8_MEMBER(ncr5390_device::tcounter_lo_r) WRITE8_MEMBER(ncr5390_device::tcount_lo_w) { tcount = (tcount & 0xff00) | data; - status &= ~S_TC0; logerror("%s: tcount_lo_w %02x (%s)\n", tag(), data, machine().describe_context()); } @@ -621,7 +649,6 @@ READ8_MEMBER(ncr5390_device::tcounter_hi_r) WRITE8_MEMBER(ncr5390_device::tcount_hi_w) { tcount = (tcount & 0x00ff) | (data << 8); - status &= ~S_TC0; logerror("%s: tcount_hi_w %02x (%s)\n", tag(), data, machine().describe_context()); } @@ -630,7 +657,7 @@ uint8_t ncr5390_device::fifo_pop() uint8_t r = fifo[0]; fifo_pos--; memmove(fifo, fifo+1, fifo_pos); - if((!fifo_pos) && tcounter && dma_dir == DMA_OUT) + if((!fifo_pos) && dma_dir == DMA_OUT) drq_set(); return r; } @@ -703,8 +730,14 @@ void ncr5390_device::start_command() // for dma commands, reload transfer counter dma_command = command[0] & 0x80; if (dma_command) + { tcounter = tcount; + // clear transfer count zero flag when counter is reloaded + if (tcounter) + status &= ~S_TC0; + } + switch(c) { case CM_NOP: command_pop_and_chain(); @@ -823,8 +856,7 @@ READ8_MEMBER(ncr5390_device::status_r) uint32_t ctrl = scsi_bus->ctrl_r(); uint8_t res = status | (ctrl & S_MSG ? 4 : 0) | (ctrl & S_CTL ? 2 : 0) | (ctrl & S_INP ? 1 : 0); logerror("%s: status_r %02x (%s)\n", tag(), res, machine().describe_context()); - if(irq) - status &= ~(S_GROSS_ERROR|S_PARITY|S_TCC); + return res; } @@ -837,8 +869,13 @@ WRITE8_MEMBER(ncr5390_device::bus_id_w) READ8_MEMBER(ncr5390_device::istatus_r) { uint8_t res = istatus; - istatus = 0; - seq = 0; + + if (irq) + { + status &= ~(S_GROSS_ERROR | S_PARITY | S_TCC); + istatus = 0; + seq = 0; + } check_irq(); if(res) command_pop_and_chain(); @@ -902,16 +939,16 @@ WRITE8_MEMBER(ncr5390_device::clock_w) void ncr5390_device::dma_set(int dir) { dma_dir = dir; - if(dma_dir == DMA_OUT && fifo_pos != 16 && tcounter != 0) + if(dma_dir == DMA_OUT && fifo_pos != 16 && tcounter > fifo_pos) drq_set(); } void ncr5390_device::dma_w(uint8_t val) { fifo_push(val); - tcounter--; - if(fifo_pos == 16 || tcounter == 0) + if(fifo_pos == 16) drq_clear(); + step(false); } uint8_t ncr5390_device::dma_r() @@ -919,11 +956,7 @@ uint8_t ncr5390_device::dma_r() uint8_t r = fifo_pop(); if(!fifo_pos) drq_clear(); - tcounter--; - if(tcounter == 0) { - status |= S_TC0; - step(false); - } + step(false); return r; } @@ -943,6 +976,16 @@ void ncr5390_device::drq_clear() } } +void ncr5390_device::decrement_tcounter() +{ + if (!dma_command) + return; + + tcounter--; + if (tcounter == 0) + status |= S_TC0; +} + /* * According to the NCR 53C90A, 53C90B data book (http://bitsavers.informatik.uni-stuttgart.de/pdf/ncr/scsi/NCR53C90ab.pdf), * the following are the differences from the 53C90: diff --git a/src/devices/machine/ncr5390.h b/src/devices/machine/ncr5390.h index 7917795fa1c..fb57114c6b6 100644 --- a/src/devices/machine/ncr5390.h +++ b/src/devices/machine/ncr5390.h @@ -112,6 +112,8 @@ protected: INIT_XFR_RECV_PAD, INIT_XFR_RECV_BYTE_ACK, INIT_XFR_RECV_BYTE_NACK, + INIT_XFR_FUNCTION_COMPLETE, + INIT_XFR_BUS_COMPLETE, INIT_XFR_WAIT_REQ, INIT_CPT_RECV_BYTE_ACK, INIT_CPT_RECV_WAIT_REQ, @@ -237,6 +239,8 @@ private: void delay(int cycles); void delay_cycles(int cycles); + void decrement_tcounter(); + devcb_write_line m_irq_handler; devcb_write_line m_drq_handler; }; diff --git a/src/devices/machine/nscsi_hd.cpp b/src/devices/machine/nscsi_hd.cpp index a3931a9a82d..7650d4063f0 100644 --- a/src/devices/machine/nscsi_hd.cpp +++ b/src/devices/machine/nscsi_hd.cpp @@ -129,17 +129,20 @@ void nscsi_harddisk_device::scsi_command() logerror("%s: command INQUIRY lun=%d EVPD=%d page=%d alloc=%02x link=%02x\n", tag(), lun, scsi_cmdbuf[1] & 1, scsi_cmdbuf[2], scsi_cmdbuf[4], scsi_cmdbuf[5]); - if(lun) { - bad_lun(); - return; - } int page = scsi_cmdbuf[2]; int size = scsi_cmdbuf[4]; switch(page) { case 0: memset(scsi_cmdbuf, 0, 148); - scsi_cmdbuf[0] = 0x00; // device is direct-access (e.g. hard disk) + // From Seagate SCSI Commands Reference Manual (http://www.seagate.com/staticfiles/support/disc/manuals/scsi/100293068a.pdf), page 73: + // If the SCSI target device is not capable of supporting a peripheral device connected to this logical unit, the + // device server shall set these fields to 7Fh (i.e., PERIPHERAL QUALIFIER field set to 011b and PERIPHERAL DEVICE + // TYPE set to 1Fh). + if (lun != 0) + scsi_cmdbuf[0] = 0x7f; + else + scsi_cmdbuf[0] = 0x00; // device is direct-access (e.g. hard disk) scsi_cmdbuf[1] = 0x00; // media is not removable scsi_cmdbuf[2] = 0x05; // device complies with SPC-3 standard scsi_cmdbuf[3] = 0x01; // response data format = CCS |