From 613011ba7ed4da1a28a602e7e4df19fa6ec41279 Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Fri, 30 Jun 2017 13:24:18 +0700 Subject: [PATCH 1/8] improved initiator transfer information logic * split transfer count/counter * added rudimentary 53c90a/53c94 support * reworked initiator transfer information state machine: should now support all scsi phases * improved handling of dma/non-dma commands * added an undocumented hack to make InterPro work --- src/devices/machine/ncr5390.cpp | 213 +++++++++++++++++++++++--------- src/devices/machine/ncr5390.h | 50 ++++++-- 2 files changed, 193 insertions(+), 70 deletions(-) diff --git a/src/devices/machine/ncr5390.cpp b/src/devices/machine/ncr5390.cpp index f4ad2ca4cf3..29f4df78a44 100644 --- a/src/devices/machine/ncr5390.cpp +++ b/src/devices/machine/ncr5390.cpp @@ -7,11 +7,27 @@ #define DELAY_HACK DEFINE_DEVICE_TYPE(NCR5390, ncr5390_device, "ncr5390", "NCR 5390 SCSI") +DEFINE_DEVICE_TYPE(NCR53C90A, ncr53c90a_device, "ncr53c90a", "NCR 53C90A SCSI") DEFINE_DEVICE_TYPE(NCR53C94, ncr53c94_device, "ncr53c94", "NCR 53C94 SCSI") DEVICE_ADDRESS_MAP_START(map, 8, ncr5390_device) - AM_RANGE(0x0, 0x0) AM_READWRITE(tcount_lo_r, tcount_lo_w) - AM_RANGE(0x1, 0x1) AM_READWRITE(tcount_hi_r, tcount_hi_w) + AM_RANGE(0x0, 0x0) AM_READWRITE(tcounter_lo_r, tcount_lo_w) + AM_RANGE(0x1, 0x1) AM_READWRITE(tcounter_hi_r, tcount_hi_w) + AM_RANGE(0x2, 0x2) AM_READWRITE(fifo_r, fifo_w) + AM_RANGE(0x3, 0x3) AM_READWRITE(command_r, command_w) + AM_RANGE(0x4, 0x4) AM_READWRITE(status_r, bus_id_w) + AM_RANGE(0x5, 0x5) AM_READWRITE(istatus_r, timeout_w) + AM_RANGE(0x6, 0x6) AM_READWRITE(seq_step_r, sync_period_w) + AM_RANGE(0x7, 0x7) AM_READWRITE(fifo_flags_r, sync_offset_w) + AM_RANGE(0x8, 0x8) AM_READWRITE(conf_r, conf_w) + AM_RANGE(0xa, 0xa) AM_WRITE(test_w) + AM_RANGE(0x9, 0x9) AM_WRITE(clock_w) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(map, 8, ncr53c90a_device) + // same as 53c90a + AM_RANGE(0x0, 0x0) AM_READWRITE(tcounter_lo_r, tcount_lo_w) + AM_RANGE(0x1, 0x1) AM_READWRITE(tcounter_hi_r, tcount_hi_w) AM_RANGE(0x2, 0x2) AM_READWRITE(fifo_r, fifo_w) AM_RANGE(0x3, 0x3) AM_READWRITE(command_r, command_w) AM_RANGE(0x4, 0x4) AM_READWRITE(status_r, bus_id_w) @@ -20,11 +36,16 @@ DEVICE_ADDRESS_MAP_START(map, 8, ncr5390_device) AM_RANGE(0x7, 0x7) AM_READWRITE(fifo_flags_r, sync_offset_w) AM_RANGE(0x8, 0x8) AM_READWRITE(conf_r, conf_w) AM_RANGE(0x9, 0x9) AM_WRITE(clock_w) + AM_RANGE(0xa, 0xa) AM_WRITE(test_w) + + // additional in 53c90a + AM_RANGE(0xb, 0xb) AM_READWRITE(conf2_r, conf2_w) ADDRESS_MAP_END DEVICE_ADDRESS_MAP_START(map, 8, ncr53c94_device) - AM_RANGE(0x0, 0x0) AM_READWRITE(tcount_lo_r, tcount_lo_w) - AM_RANGE(0x1, 0x1) AM_READWRITE(tcount_hi_r, tcount_hi_w) + // same as 53c90a + AM_RANGE(0x0, 0x0) AM_READWRITE(tcounter_lo_r, tcount_lo_w) + AM_RANGE(0x1, 0x1) AM_READWRITE(tcounter_hi_r, tcount_hi_w) AM_RANGE(0x2, 0x2) AM_READWRITE(fifo_r, fifo_w) AM_RANGE(0x3, 0x3) AM_READWRITE(command_r, command_w) AM_RANGE(0x4, 0x4) AM_READWRITE(status_r, bus_id_w) @@ -35,6 +56,8 @@ DEVICE_ADDRESS_MAP_START(map, 8, ncr53c94_device) AM_RANGE(0x9, 0x9) AM_WRITE(clock_w) AM_RANGE(0xa, 0xa) AM_WRITE(test_w) AM_RANGE(0xb, 0xb) AM_READWRITE(conf2_r, conf2_w) + + // additional in 53c94 AM_RANGE(0xc, 0xc) AM_READWRITE(conf3_r, conf3_w) AM_RANGE(0xf, 0xf) AM_WRITE(fifo_align_w) ADDRESS_MAP_END @@ -42,21 +65,30 @@ ADDRESS_MAP_END ncr5390_device::ncr5390_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : nscsi_device(mconfig, type, tag, owner, clock) , tm(nullptr), config(0), status(0), istatus(0), clock_conv(0), sync_offset(0), sync_period(0), bus_id(0) - , select_timeout(0), seq(0), tcount(0), mode(0), fifo_pos(0), command_pos(0), state(0), xfr_phase(0), command_length(0), dma_dir(0), irq(false), drq(false) + , select_timeout(0), seq(0), tcount(0), tcounter(0), mode(0), fifo_pos(0), command_pos(0), state(0), xfr_phase(0), command_length(0), dma_dir(0), irq(false), drq(false), test_mode(false) , m_irq_handler(*this) , m_drq_handler(*this) { } +ncr53c90a_device::ncr53c90a_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : ncr5390_device(mconfig, type, tag, owner, clock) + , config2(0) +{ +} + ncr5390_device::ncr5390_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : ncr5390_device(mconfig, NCR5390, tag, owner, clock) { } +ncr53c90a_device::ncr53c90a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : ncr53c90a_device(mconfig, NCR53C90A, tag, owner, clock) +{ +} + ncr53c94_device::ncr53c94_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : ncr5390_device(mconfig, NCR53C94, tag, owner, clock) - , test_mode(false) - , config2(0) + : ncr53c90a_device(mconfig, NCR53C94, tag, owner, clock) , config3(0) { } @@ -77,6 +109,7 @@ void ncr5390_device::device_start() save_item(NAME(seq)); save_item(NAME(fifo)); save_item(NAME(tcount)); + save_item(NAME(tcounter)); save_item(NAME(mode)); save_item(NAME(fifo_pos)); save_item(NAME(command_pos)); @@ -86,11 +119,13 @@ void ncr5390_device::device_start() save_item(NAME(dma_dir)); save_item(NAME(irq)); save_item(NAME(drq)); + save_item(NAME(test_mode)); m_irq_handler.resolve_safe(); m_drq_handler.resolve_safe(); tcount = 0; + tcounter = 0; config = 0; status = 0; bus_id = 0; @@ -121,6 +156,7 @@ void ncr5390_device::reset_soft() scsi_bus->ctrl_wait(scsi_refid, S_SEL|S_BSY|S_RST, S_ALL); status &= 0xef; drq = false; + test_mode = false; m_drq_handler(drq); reset_disconnect(); } @@ -410,17 +446,26 @@ void ncr5390_device::step(bool timeout) case INIT_XFR: switch(xfr_phase) { case S_PHASE_DATA_OUT: - dma_set(DMA_OUT); - if(tcount == 0 && fifo_pos == 1) - scsi_bus->ctrl_w(scsi_refid, 0, S_ATN); + case S_PHASE_COMMAND: + case S_PHASE_MSG_OUT: + dma_set(dma_command ? DMA_OUT : DMA_NONE); state = INIT_XFR_SEND_BYTE; + + // 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); + send_byte(); break; case S_PHASE_DATA_IN: - dma_set(DMA_IN); - state = tcount == fifo_pos+1 ? - INIT_XFR_RECV_BYTE_NACK : INIT_XFR_RECV_BYTE_ACK; + case S_PHASE_STATUS: + case S_PHASE_MSG_IN: + dma_set(dma_command ? DMA_IN : DMA_NONE); + + // 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; + recv_byte(); break; @@ -435,20 +480,24 @@ void ncr5390_device::step(bool timeout) if(!(ctrl & S_REQ)) break; - if((ctrl & S_PHASE_MASK) != xfr_phase) { - command_pos = 0; + // check for command complete + if ((dma_command && tcounter == 0 && fifo_pos == 0) // dma in/out: transfer counter == 0 and fifo empty + || (!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(); - } else { - state = INIT_XFR; - step(false); - } + else + // check for phase change + if((ctrl & S_PHASE_MASK) != xfr_phase) { + command_pos = 0; + bus_complete(); + } else { + state = INIT_XFR; + step(false); + } break; case INIT_XFR_SEND_BYTE: - if(tcount == 0 && fifo_pos == 0) - bus_complete(); - else - state = INIT_XFR_WAIT_REQ; + state = INIT_XFR_WAIT_REQ; break; case INIT_XFR_RECV_BYTE_ACK: @@ -474,8 +523,8 @@ void ncr5390_device::step(bool timeout) break; case INIT_XFR_SEND_PAD: - tcount--; - if(tcount) { + tcounter--; + if(tcounter) { state = INIT_XFR_SEND_PAD_WAIT_REQ; step(false); } else @@ -496,8 +545,8 @@ void ncr5390_device::step(bool timeout) break; case INIT_XFR_RECV_PAD: - tcount--; - if(tcount) { + tcounter--; + if(tcounter) { state = INIT_XFR_RECV_PAD_WAIT_REQ; scsi_bus->ctrl_w(scsi_refid, 0, S_ACK); step(false); @@ -575,10 +624,10 @@ void ncr5390_device::delay_cycles(int cycles) tm->adjust(clocks_to_attotime(cycles)); } -READ8_MEMBER(ncr5390_device::tcount_lo_r) +READ8_MEMBER(ncr5390_device::tcounter_lo_r) { - logerror("%s: tcount_lo_r %02x (%s)\n", tag(), tcount & 0xff, machine().describe_context()); - return tcount; + logerror("%s: tcounter_lo_r %02x (%s)\n", tag(), tcounter & 0xff, machine().describe_context()); + return tcounter; } WRITE8_MEMBER(ncr5390_device::tcount_lo_w) @@ -588,10 +637,10 @@ WRITE8_MEMBER(ncr5390_device::tcount_lo_w) logerror("%s: tcount_lo_w %02x (%s)\n", tag(), data, machine().describe_context()); } -READ8_MEMBER(ncr5390_device::tcount_hi_r) +READ8_MEMBER(ncr5390_device::tcounter_hi_r) { - logerror("%s: tcount_hi_r %02x (%s)\n", tag(), tcount >> 8, machine().describe_context()); - return tcount >> 8; + logerror("%s: tcounter_hi_r %02x (%s)\n", tag(), tcounter >> 8, machine().describe_context()); + return tcounter >> 8; } WRITE8_MEMBER(ncr5390_device::tcount_hi_w) @@ -606,7 +655,7 @@ uint8_t ncr5390_device::fifo_pop() uint8_t r = fifo[0]; fifo_pos--; memmove(fifo, fifo+1, fifo_pos); - if((!fifo_pos) && tcount && dma_dir == DMA_OUT) + if((!fifo_pos) && tcounter && dma_dir == DMA_OUT) drq_set(); return r; } @@ -676,6 +725,11 @@ void ncr5390_device::start_command() return; } + // for dma commands, reload transfer counter + dma_command = command[0] & 0x80; + if (dma_command) + tcounter = tcount; + switch(c) { case CM_NOP: command_pop_and_chain(); @@ -728,6 +782,12 @@ void ncr5390_device::start_command() case CI_MSG_ACCEPT: state = INIT_MSG_WAIT_REQ; + // It's undocumented what the sequence register should contain after a message accept + // command, but the InterPro boot code expects it to be non-zero; setting it to an + // arbirary 1 here makes InterPro happy. Also in the InterPro case (perhaps typical), + // after ACK is asserted the device disconnects and the INIT_MSG_WAIT_REQ state is never + // entered, meaning we end up with I_DISCONNECT instead of I_BUS interrupt status. + seq = 1; scsi_bus->ctrl_w(scsi_refid, 0, S_ACK); step(false); break; @@ -847,6 +907,16 @@ WRITE8_MEMBER(ncr5390_device::conf_w) { config = data; scsi_id = data & 7; + + // test mode can only be cleared by hard/soft reset + if (data & 0x8) + test_mode = true; +} + +WRITE8_MEMBER(ncr5390_device::test_w) +{ + if (test_mode) + logerror("%s: test_w %d (%s) - test mode not implemented\n", tag(), data, machine().describe_context()); } WRITE8_MEMBER(ncr5390_device::clock_w) @@ -857,15 +927,15 @@ WRITE8_MEMBER(ncr5390_device::clock_w) void ncr5390_device::dma_set(int dir) { dma_dir = dir; - if(dma_dir == DMA_OUT && fifo_pos != 16 && tcount != 0) + if(dma_dir == DMA_OUT && fifo_pos != 16 && tcounter != 0) drq_set(); } void ncr5390_device::dma_w(uint8_t val) { fifo_push(val); - tcount--; - if(fifo_pos == 16 || tcount == 0) + tcounter--; + if(fifo_pos == 16 || tcounter == 0) drq_clear(); } @@ -874,8 +944,8 @@ uint8_t ncr5390_device::dma_r() uint8_t r = fifo_pop(); if(!fifo_pos) drq_clear(); - tcount--; - if(tcount == 0) { + tcounter--; + if(tcounter == 0) { status |= S_TC0; step(false); } @@ -898,39 +968,64 @@ void ncr5390_device::drq_clear() } } -void ncr53c94_device::device_start() -{ - save_item(NAME(test_mode)); - save_item(NAME(config2)); - save_item(NAME(config3)); +/* + * 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: + * + * - Supports three-byte message exchange SCSI-2 tagged queueing + * - Added select with ATN3 command + * - Added target DMA abort command + * - Added interrupt polling bit + * - Added second configuration register + * - Improved immunity to cable impedance mismatches and improper termination + * - Tri-state DMA request output + * - Cut leakage current on SCSI input pins when powered off + * - Relaxed register timings + * - Relaxed DMA timings + * - Relaxed CLK duty cycle + * - Lengthened read data access time + * - NOP required less often + */ + +void ncr53c90a_device::device_start() +{ + save_item(NAME(config2)); - test_mode = false; config2 = 0; - config3 = 0; ncr5390_device::device_start(); } -void ncr53c94_device::reset_soft() +void ncr53c90a_device::reset_soft() { - test_mode = false; config2 = 0; - config3 = 0; ncr5390_device::reset_soft(); } -WRITE8_MEMBER(ncr53c94_device::conf_w) +READ8_MEMBER(ncr53c90a_device::status_r) { - ncr5390_device::conf_w(space, offset, data, mem_mask); - - // test mode can only be cleared by hard/soft reset - if (data & 0x8) - test_mode = true; + uint32_t ctrl = scsi_bus->ctrl_r(); + uint8_t res = (irq ? S_INTERRUPT : 0) | 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; } -WRITE8_MEMBER(ncr53c94_device::test_w) + +void ncr53c94_device::device_start() { - if (test_mode) - logerror("%s: test_w %d (%s) - test mode not implemented\n", tag(), data, machine().describe_context()); + save_item(NAME(config3)); + + config3 = 0; + + ncr53c90a_device::device_start(); +} + +void ncr53c94_device::reset_soft() +{ + config3 = 0; + + ncr53c90a_device::reset_soft(); } diff --git a/src/devices/machine/ncr5390.h b/src/devices/machine/ncr5390.h index 0f62fe69c5e..7917795fa1c 100644 --- a/src/devices/machine/ncr5390.h +++ b/src/devices/machine/ncr5390.h @@ -24,9 +24,9 @@ public: virtual DECLARE_ADDRESS_MAP(map, 8); - DECLARE_READ8_MEMBER(tcount_lo_r); + DECLARE_READ8_MEMBER(tcounter_lo_r); DECLARE_WRITE8_MEMBER(tcount_lo_w); - DECLARE_READ8_MEMBER(tcount_hi_r); + DECLARE_READ8_MEMBER(tcounter_hi_r); DECLARE_WRITE8_MEMBER(tcount_hi_w); DECLARE_READ8_MEMBER(fifo_r); DECLARE_WRITE8_MEMBER(fifo_w); @@ -42,6 +42,7 @@ public: DECLARE_WRITE8_MEMBER(sync_offset_w); DECLARE_READ8_MEMBER(conf_r); DECLARE_WRITE8_MEMBER(conf_w); + DECLARE_WRITE8_MEMBER(test_w); DECLARE_WRITE8_MEMBER(clock_w); virtual void scsi_ctrl_changed() override; @@ -49,6 +50,10 @@ public: uint8_t dma_r(); void dma_w(uint8_t val); + // memory mapped wrappers for dma read/write + DECLARE_READ8_MEMBER(mdma_r) { return dma_r(); } + DECLARE_WRITE8_MEMBER(mdma_w) { dma_w(data); } + protected: ncr5390_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); @@ -56,7 +61,6 @@ protected: virtual void device_reset() override; virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; -private: enum { MODE_D, MODE_T, MODE_I }; enum { IDLE }; @@ -192,6 +196,7 @@ private: uint8_t clock_conv, sync_offset, sync_period, bus_id, select_timeout, seq; uint8_t fifo[16]; uint16_t tcount; + uint16_t tcounter; int mode, fifo_pos, command_pos; int state, xfr_phase; int command_length; @@ -199,6 +204,8 @@ private: int dma_dir; bool irq, drq; + bool dma_command; + bool test_mode; void dma_set(int dir); void drq_set(); @@ -234,18 +241,40 @@ private: devcb_write_line m_drq_handler; }; -class ncr53c94_device : public ncr5390_device +class ncr53c90a_device : public ncr5390_device +{ +public: + ncr53c90a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual DECLARE_ADDRESS_MAP(map, 8) override; + + DECLARE_READ8_MEMBER(status_r); + + DECLARE_READ8_MEMBER(conf2_r) { return config2; }; + DECLARE_WRITE8_MEMBER(conf2_w) { config2 = data; }; + +protected: + ncr53c90a_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + virtual void device_start() override; + void reset_soft(); + + // 53c90a uses a previously reserved bit as an interrupt flag + enum { + S_INTERRUPT = 0x80, + }; + +private: + u8 config2; +}; + +class ncr53c94_device : public ncr53c90a_device { public: ncr53c94_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); virtual DECLARE_ADDRESS_MAP(map, 8) override; - DECLARE_WRITE8_MEMBER(conf_w); - - DECLARE_WRITE8_MEMBER(test_w); - DECLARE_READ8_MEMBER(conf2_r) { return config2; }; - DECLARE_WRITE8_MEMBER(conf2_w) { config2 = data; }; DECLARE_READ8_MEMBER(conf3_r) { return config3; }; DECLARE_WRITE8_MEMBER(conf3_w) { config3 = data; }; DECLARE_WRITE8_MEMBER(fifo_align_w) { fifo_align = data; }; @@ -255,13 +284,12 @@ protected: void reset_soft(); private: - bool test_mode; - u8 config2; u8 config3; u8 fifo_align; }; DECLARE_DEVICE_TYPE(NCR5390, ncr5390_device) +DECLARE_DEVICE_TYPE(NCR53C90A, ncr53c90a_device) DECLARE_DEVICE_TYPE(NCR53C94, ncr53c94_device) #endif // MAME_MACHINE_NCR5390_H From fcdc00ad81a6d84ee950653999c97aa10334f3d5 Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Fri, 30 Jun 2017 13:57:05 +0700 Subject: [PATCH 2/8] match updated 5390 device --- src/mame/drivers/interpro.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mame/drivers/interpro.cpp b/src/mame/drivers/interpro.cpp index 74bbc224f14..794363adacb 100644 --- a/src/mame/drivers/interpro.cpp +++ b/src/mame/drivers/interpro.cpp @@ -265,8 +265,8 @@ READ8_MEMBER(interpro_state::scsi_r) #if NEW_SCSI switch (offset >> 6) { - case 0x0: return m_scsi->tcount_lo_r(space, 0); - case 0x1: return m_scsi->tcount_hi_r(space, 0); + case 0x0: return m_scsi->tcounter_lo_r(space, 0); + case 0x1: return m_scsi->tcounter_hi_r(space, 0); case 0x2: return m_scsi->fifo_r(space, 0); case 0x3: return m_scsi->command_r(space, 0); case 0x4: return m_scsi->status_r(space, 0); From 027118e41e5296f958b9f86ad5238dc0e0a6ba28 Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Fri, 30 Jun 2017 21:25:51 +0700 Subject: [PATCH 3/8] inherit memory map --- src/devices/machine/ncr5390.cpp | 29 ++--------------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/src/devices/machine/ncr5390.cpp b/src/devices/machine/ncr5390.cpp index 29f4df78a44..3496eba4f07 100644 --- a/src/devices/machine/ncr5390.cpp +++ b/src/devices/machine/ncr5390.cpp @@ -25,39 +25,14 @@ DEVICE_ADDRESS_MAP_START(map, 8, ncr5390_device) ADDRESS_MAP_END DEVICE_ADDRESS_MAP_START(map, 8, ncr53c90a_device) - // same as 53c90a - AM_RANGE(0x0, 0x0) AM_READWRITE(tcounter_lo_r, tcount_lo_w) - AM_RANGE(0x1, 0x1) AM_READWRITE(tcounter_hi_r, tcount_hi_w) - AM_RANGE(0x2, 0x2) AM_READWRITE(fifo_r, fifo_w) - AM_RANGE(0x3, 0x3) AM_READWRITE(command_r, command_w) - AM_RANGE(0x4, 0x4) AM_READWRITE(status_r, bus_id_w) - AM_RANGE(0x5, 0x5) AM_READWRITE(istatus_r, timeout_w) - AM_RANGE(0x6, 0x6) AM_READWRITE(seq_step_r, sync_period_w) - AM_RANGE(0x7, 0x7) AM_READWRITE(fifo_flags_r, sync_offset_w) - AM_RANGE(0x8, 0x8) AM_READWRITE(conf_r, conf_w) - AM_RANGE(0x9, 0x9) AM_WRITE(clock_w) - AM_RANGE(0xa, 0xa) AM_WRITE(test_w) + AM_INHERIT_FROM(ncr5390_device::map) - // additional in 53c90a AM_RANGE(0xb, 0xb) AM_READWRITE(conf2_r, conf2_w) ADDRESS_MAP_END DEVICE_ADDRESS_MAP_START(map, 8, ncr53c94_device) - // same as 53c90a - AM_RANGE(0x0, 0x0) AM_READWRITE(tcounter_lo_r, tcount_lo_w) - AM_RANGE(0x1, 0x1) AM_READWRITE(tcounter_hi_r, tcount_hi_w) - AM_RANGE(0x2, 0x2) AM_READWRITE(fifo_r, fifo_w) - AM_RANGE(0x3, 0x3) AM_READWRITE(command_r, command_w) - AM_RANGE(0x4, 0x4) AM_READWRITE(status_r, bus_id_w) - AM_RANGE(0x5, 0x5) AM_READWRITE(istatus_r, timeout_w) - AM_RANGE(0x6, 0x6) AM_READWRITE(seq_step_r, sync_period_w) - AM_RANGE(0x7, 0x7) AM_READWRITE(fifo_flags_r, sync_offset_w) - AM_RANGE(0x8, 0x8) AM_READWRITE(conf_r, conf_w) - AM_RANGE(0x9, 0x9) AM_WRITE(clock_w) - AM_RANGE(0xa, 0xa) AM_WRITE(test_w) - AM_RANGE(0xb, 0xb) AM_READWRITE(conf2_r, conf2_w) + AM_INHERIT_FROM(ncr53c90a_device::map) - // additional in 53c94 AM_RANGE(0xc, 0xc) AM_READWRITE(conf3_r, conf3_w) AM_RANGE(0xf, 0xf) AM_WRITE(fifo_align_w) ADDRESS_MAP_END From 1da9046e69af57278df43d15fdcf0fa9a0ec1d50 Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Wed, 5 Jul 2017 18:16:14 +0700 Subject: [PATCH 4/8] z80scc: basic wait/dma request implementation --- src/devices/machine/z80scc.cpp | 35 ++++++++++++++++++++++++++++++++++ src/devices/machine/z80scc.h | 2 ++ 2 files changed, 37 insertions(+) diff --git a/src/devices/machine/z80scc.cpp b/src/devices/machine/z80scc.cpp index fc795d688a9..27d6cfd3f99 100644 --- a/src/devices/machine/z80scc.cpp +++ b/src/devices/machine/z80scc.cpp @@ -1136,6 +1136,8 @@ void z80scc_channel::tra_complete() set_rts(1); } + check_waitrequest(); + if (m_wr1 & WR1_TX_INT_ENABLE && m_tx_int_disarm == 0) { if ((m_uart->m_variant & z80scc_device::SET_ESCC) && @@ -1794,6 +1796,8 @@ void z80scc_channel::do_sccreg_wr1(uint8_t data) LOG("- Wait/Ready Function %s\n", (data & WR1_WRDY_FUNCTION) ? "Ready" : "Wait"); LOG("- Wait/Ready on %s\n", (data & WR1_WRDY_ON_RX_TX) ? "Receive" : "Transmit"); + check_waitrequest(); + switch (data & WR1_RX_INT_MODE_MASK) { case WR1_RX_INT_DISABLE: @@ -2410,6 +2414,8 @@ void z80scc_channel::data_write(uint8_t data) m_rr1 &= ~RR1_ALL_SENT; // All is definitelly not sent anymore } + check_waitrequest(); + /* Transmitter enabled? */ if (m_wr5 & WR5_TX_ENABLE) { @@ -2857,3 +2863,32 @@ WRITE_LINE_MEMBER(z80scc_channel::write_rx) if(m_rxc != 0 || m_brg_rate != 0) device_serial_interface::rx_w(state); } + +/* + * This is a partial implementation of the "wait/dma request" functionality of the SCC controlled by + * bits D7, D6 and D5 in WR1. This implementation is sufficient to support DMA request on transmit + * used by the InterPro driver. + * + * TODO: + * - wait function (D6=0) + * - wait/request function on receive (D5=1) + */ +void z80scc_channel::check_waitrequest() +{ + // don't do anything if wait/request function is not enabled + if ((m_wr1 & WR1_WRDY_ENABLE) == 0) + return; + + // wait/request function for receive not implemented + if (m_wr1 & WR1_WRDY_ON_RX_TX) + return; + + // if dma request function is enabled + if (m_wr1 & WR1_WRDY_FUNCTION) + { + // assert /W//REQ if transmit buffer is empty, clear if it's not + int state = (m_rr0 & RR0_TX_BUFFER_EMPTY) ? ASSERT_LINE : CLEAR_LINE; + + m_index ? m_uart->m_out_wrdyb_cb(state) : m_uart->m_out_wrdya_cb(state); + } +} diff --git a/src/devices/machine/z80scc.h b/src/devices/machine/z80scc.h index c78d4775a17..1bb25e04ec8 100644 --- a/src/devices/machine/z80scc.h +++ b/src/devices/machine/z80scc.h @@ -631,6 +631,8 @@ protected: // SCC specifics int m_ph; // Point high command to access regs 08-0f uint8_t m_zc; + + void check_waitrequest(); }; From 748677f43b575c87cc2bd24ecef429211433577b Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Thu, 6 Jul 2017 10:13:26 +0700 Subject: [PATCH 5/8] z80scc: renamed WRDY to WREQ to match datasheet, minor touch-up --- src/devices/machine/z80scc.cpp | 22 +++++++++++----------- src/devices/machine/z80scc.h | 25 ++++++++++++------------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/devices/machine/z80scc.cpp b/src/devices/machine/z80scc.cpp index 27d6cfd3f99..d0e1681c9de 100644 --- a/src/devices/machine/z80scc.cpp +++ b/src/devices/machine/z80scc.cpp @@ -174,12 +174,12 @@ z80scc_device::z80scc_device(const machine_config &mconfig, device_type type, co m_out_txda_cb(*this), m_out_dtra_cb(*this), m_out_rtsa_cb(*this), - m_out_wrdya_cb(*this), + m_out_wreqa_cb(*this), m_out_synca_cb(*this), m_out_txdb_cb(*this), m_out_dtrb_cb(*this), m_out_rtsb_cb(*this), - m_out_wrdyb_cb(*this), + m_out_wreqb_cb(*this), m_out_syncb_cb(*this), m_out_int_cb(*this), m_out_rxdrqa_cb(*this), @@ -249,12 +249,12 @@ void z80scc_device::device_start() m_out_txda_cb.resolve_safe(); m_out_dtra_cb.resolve_safe(); m_out_rtsa_cb.resolve_safe(); - m_out_wrdya_cb.resolve_safe(); + m_out_wreqa_cb.resolve_safe(); m_out_synca_cb.resolve_safe(); m_out_txdb_cb.resolve_safe(); m_out_dtrb_cb.resolve_safe(); m_out_rtsb_cb.resolve_safe(); - m_out_wrdyb_cb.resolve_safe(); + m_out_wreqb_cb.resolve_safe(); m_out_syncb_cb.resolve_safe(); m_out_int_cb.resolve_safe(); m_out_rxdrqa_cb.resolve_safe(); @@ -1792,9 +1792,9 @@ void z80scc_channel::do_sccreg_wr1(uint8_t data) LOG("- External Interrupt Enable %u\n", (data & WR1_EXT_INT_ENABLE) ? 1 : 0); LOG("- Transmit Interrupt Enable %u\n", (data & WR1_TX_INT_ENABLE) ? 1 : 0); LOG("- Parity is special condition %u\n", (data & WR1_PARITY_IS_SPEC_COND) ? 1 : 0); - LOG("- Wait/Ready Enable %u\n", (data & WR1_WRDY_ENABLE) ? 1 : 0); - LOG("- Wait/Ready Function %s\n", (data & WR1_WRDY_FUNCTION) ? "Ready" : "Wait"); - LOG("- Wait/Ready on %s\n", (data & WR1_WRDY_ON_RX_TX) ? "Receive" : "Transmit"); + LOG("- Wait/DMA Request Enable %u\n", (data & WR1_WREQ_ENABLE) ? 1 : 0); + LOG("- Wait/DMA Request Function %s\n", (data & WR1_WREQ_FUNCTION) ? "Request" : "Wait"); + LOG("- Wait/DMA Request on %s\n", (data & WR1_WREQ_ON_RX_TX) ? "Receive" : "Transmit"); check_waitrequest(); @@ -2876,19 +2876,19 @@ WRITE_LINE_MEMBER(z80scc_channel::write_rx) void z80scc_channel::check_waitrequest() { // don't do anything if wait/request function is not enabled - if ((m_wr1 & WR1_WRDY_ENABLE) == 0) + if ((m_wr1 & WR1_WREQ_ENABLE) == 0) return; // wait/request function for receive not implemented - if (m_wr1 & WR1_WRDY_ON_RX_TX) + if (m_wr1 & WR1_WREQ_ON_RX_TX) return; // if dma request function is enabled - if (m_wr1 & WR1_WRDY_FUNCTION) + if (m_wr1 & WR1_WREQ_FUNCTION) { // assert /W//REQ if transmit buffer is empty, clear if it's not int state = (m_rr0 & RR0_TX_BUFFER_EMPTY) ? ASSERT_LINE : CLEAR_LINE; - m_index ? m_uart->m_out_wrdyb_cb(state) : m_uart->m_out_wrdya_cb(state); + (m_index ? m_uart->m_out_wreqb_cb : m_uart->m_out_wreqa_cb)(state); } } diff --git a/src/devices/machine/z80scc.h b/src/devices/machine/z80scc.h index 1bb25e04ec8..1d4443596ec 100644 --- a/src/devices/machine/z80scc.h +++ b/src/devices/machine/z80scc.h @@ -98,8 +98,8 @@ #define MCFG_Z80SCC_OUT_RTSA_CB(_devcb) \ devcb = &z80scc_device::set_out_rtsa_callback(*device, DEVCB_##_devcb); -#define MCFG_Z80SCC_OUT_WRDYA_CB(_devcb) \ - devcb = &z80scc_device::set_out_wrdya_callback(*device, DEVCB_##_devcb); +#define MCFG_Z80SCC_OUT_WREQA_CB(_devcb) \ + devcb = &z80scc_device::set_out_wreqa_callback(*device, DEVCB_##_devcb); #define MCFG_Z80SCC_OUT_SYNCA_CB(_devcb) \ devcb = &z80scc_device::set_out_synca_callback(*device, DEVCB_##_devcb); @@ -120,8 +120,8 @@ #define MCFG_Z80SCC_OUT_RTSB_CB(_devcb) \ devcb = &z80scc_device::set_out_rtsb_callback(*device, DEVCB_##_devcb); -#define MCFG_Z80SCC_OUT_WRDYB_CB(_devcb) \ - devcb = &z80scc_device::set_out_wrdyb_callback(*device, DEVCB_##_devcb); +#define MCFG_Z80SCC_OUT_WREQB_CB(_devcb) \ + devcb = &z80scc_device::set_out_wreqb_callback(*device, DEVCB_##_devcb); #define MCFG_Z80SCC_OUT_SYNCB_CB(_devcb) \ devcb = &z80scc_device::set_out_syncb_callback(*device, DEVCB_##_devcb); @@ -412,9 +412,9 @@ protected: WR1_RX_INT_FIRST = 0x08, WR1_RX_INT_ALL = 0x10, WR1_RX_INT_PARITY = 0x18, - WR1_WRDY_ON_RX_TX = 0x20, - WR1_WRDY_FUNCTION = 0x40, - WR1_WRDY_ENABLE = 0x80 + WR1_WREQ_ON_RX_TX = 0x20, + WR1_WREQ_FUNCTION = 0x40, + WR1_WREQ_ENABLE = 0x80 }; enum @@ -587,6 +587,7 @@ protected: int get_rx_word_length(); int get_tx_word_length(); void safe_transmit_register_reset(); + void check_waitrequest(); // receiver state uint8_t m_rx_data_fifo[8]; // receive data FIFO @@ -631,8 +632,6 @@ protected: // SCC specifics int m_ph; // Point high command to access regs 08-0f uint8_t m_zc; - - void check_waitrequest(); }; @@ -649,12 +648,12 @@ public: template static devcb_base &set_out_txda_callback(device_t &device, Object &&cb) { return downcast(device).m_out_txda_cb.set_callback(std::forward(cb)); } template static devcb_base &set_out_dtra_callback(device_t &device, Object &&cb) { return downcast(device).m_out_dtra_cb.set_callback(std::forward(cb)); } template static devcb_base &set_out_rtsa_callback(device_t &device, Object &&cb) { return downcast(device).m_out_rtsa_cb.set_callback(std::forward(cb)); } - template static devcb_base &set_out_wrdya_callback(device_t &device, Object &&cb) { return downcast(device).m_out_wrdya_cb.set_callback(std::forward(cb)); } + template static devcb_base &set_out_wreqa_callback(device_t &device, Object &&cb) { return downcast(device).m_out_wreqa_cb.set_callback(std::forward(cb)); } template static devcb_base &set_out_synca_callback(device_t &device, Object &&cb) { return downcast(device).m_out_synca_cb.set_callback(std::forward(cb)); } template static devcb_base &set_out_txdb_callback(device_t &device, Object &&cb) { return downcast(device).m_out_txdb_cb.set_callback(std::forward(cb)); } template static devcb_base &set_out_dtrb_callback(device_t &device, Object &&cb) { return downcast(device).m_out_dtrb_cb.set_callback(std::forward(cb)); } template static devcb_base &set_out_rtsb_callback(device_t &device, Object &&cb) { return downcast(device).m_out_rtsb_cb.set_callback(std::forward(cb)); } - template static devcb_base &set_out_wrdyb_callback(device_t &device, Object &&cb) { return downcast(device).m_out_wrdyb_cb.set_callback(std::forward(cb)); } + template static devcb_base &set_out_weqb_callback(device_t &device, Object &&cb) { return downcast(device).m_out_wreqb_cb.set_callback(std::forward(cb)); } template static devcb_base &set_out_syncb_callback(device_t &device, Object &&cb) { return downcast(device).m_out_syncb_cb.set_callback(std::forward(cb)); } template static devcb_base &set_out_int_callback(device_t &device, Object &&cb) { return downcast(device).m_out_int_cb.set_callback(std::forward(cb)); } template static devcb_base &set_out_rxdrqa_callback(device_t &device, Object &&cb) { return downcast(device).m_out_rxdrqa_cb.set_callback(std::forward(cb)); } @@ -779,13 +778,13 @@ protected: devcb_write_line m_out_txda_cb; devcb_write_line m_out_dtra_cb; devcb_write_line m_out_rtsa_cb; - devcb_write_line m_out_wrdya_cb; + devcb_write_line m_out_wreqa_cb; devcb_write_line m_out_synca_cb; devcb_write_line m_out_txdb_cb; devcb_write_line m_out_dtrb_cb; devcb_write_line m_out_rtsb_cb; - devcb_write_line m_out_wrdyb_cb; + devcb_write_line m_out_wreqb_cb; devcb_write_line m_out_syncb_cb; devcb_write_line m_out_int_cb; From 498594c049784cacc074ff7790e7e52a84f75ebc Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Thu, 6 Jul 2017 10:33:59 +0700 Subject: [PATCH 6/8] oops --- src/devices/machine/z80scc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices/machine/z80scc.h b/src/devices/machine/z80scc.h index 1d4443596ec..2b0cae0ea76 100644 --- a/src/devices/machine/z80scc.h +++ b/src/devices/machine/z80scc.h @@ -653,7 +653,7 @@ public: template static devcb_base &set_out_txdb_callback(device_t &device, Object &&cb) { return downcast(device).m_out_txdb_cb.set_callback(std::forward(cb)); } template static devcb_base &set_out_dtrb_callback(device_t &device, Object &&cb) { return downcast(device).m_out_dtrb_cb.set_callback(std::forward(cb)); } template static devcb_base &set_out_rtsb_callback(device_t &device, Object &&cb) { return downcast(device).m_out_rtsb_cb.set_callback(std::forward(cb)); } - template static devcb_base &set_out_weqb_callback(device_t &device, Object &&cb) { return downcast(device).m_out_wreqb_cb.set_callback(std::forward(cb)); } + template static devcb_base &set_out_wreqb_callback(device_t &device, Object &&cb) { return downcast(device).m_out_wreqb_cb.set_callback(std::forward(cb)); } template static devcb_base &set_out_syncb_callback(device_t &device, Object &&cb) { return downcast(device).m_out_syncb_cb.set_callback(std::forward(cb)); } template static devcb_base &set_out_int_callback(device_t &device, Object &&cb) { return downcast(device).m_out_int_cb.set_callback(std::forward(cb)); } template static devcb_base &set_out_rxdrqa_callback(device_t &device, Object &&cb) { return downcast(device).m_out_rxdrqa_cb.set_callback(std::forward(cb)); } From bb4773354a1c39409d1d8b741de8a9ad4e73d5df Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Sun, 9 Jul 2017 15:38:20 +0700 Subject: [PATCH 7/8] nscsi_hd: correction for INQUIRY with bad lun (nw) --- src/devices/machine/nscsi_hd.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) 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 From ea154eff6ef6d76c5d011e45f92e0ac0badcc216 Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Sun, 9 Jul 2017 15:40:37 +0700 Subject: [PATCH 8/8] ncr5390: improve tcounter, dma/drq handling --- src/devices/machine/ncr5390.cpp | 85 +++++++++++++++++++++++++-------- src/devices/machine/ncr5390.h | 4 ++ 2 files changed, 68 insertions(+), 21 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; };