From 93a797cb344b10f9fcc4fc5626f5c4084871fa0d Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Mon, 28 May 2018 19:45:41 +0700 Subject: ncr5390: several small but important changes (nw) (#3619) These changes work with InterPro, but haven't been tested on other machines. Despite this, I'm reasonably confident they are all correct according to the observed behaviour and the documentation. * don't wait for REQ after initiator complete with NACK * wait until fifo empty during dma out before command complete * make sure drq is always cleared on bus/function complete * reset happens immediately * always clear TC0 when counter reloaded * check valid commands separately for 5390 and 5390a * handle 5390a initiator set attention command * use logmacro for logging --- src/devices/machine/ncr5390.cpp | 117 ++++++++++++++++++++++++++++------------ src/devices/machine/ncr5390.h | 9 +++- 2 files changed, 91 insertions(+), 35 deletions(-) diff --git a/src/devices/machine/ncr5390.cpp b/src/devices/machine/ncr5390.cpp index f5a211c77c9..d3410411f37 100644 --- a/src/devices/machine/ncr5390.cpp +++ b/src/devices/machine/ncr5390.cpp @@ -4,6 +4,14 @@ #include "emu.h" #include "ncr5390.h" +#define LOG_GENERAL (1U << 0) +#define LOG_STATE (1U << 1) +#define LOG_FIFO (1U << 2) +#define LOG_COMMAND (1U << 3) + +#define VERBOSE (0) +#include "logmacro.h" + #define DELAY_HACK DEFINE_DEVICE_TYPE(NCR5390, ncr5390_device, "ncr5390", "NCR 5390 SCSI") @@ -151,7 +159,7 @@ void ncr5390_device::scsi_ctrl_changed() { uint32_t ctrl = scsi_bus->ctrl_r(); if(ctrl & S_RST) { - logerror("%s: scsi bus reset\n", tag()); + LOG("scsi bus reset\n"); return; } @@ -169,10 +177,9 @@ void ncr5390_device::step(bool timeout) uint32_t data = scsi_bus->data_r(); uint8_t c = command[0] & 0x7f; - if(0) - logerror("%s: state=%d.%d %s\n", - tag(), state & STATE_MASK, (state & SUB_MASK) >> SUB_SHIFT, - timeout ? "timeout" : "change"); + LOGMASKED(LOG_STATE, "state=%d.%d %s\n", + state & STATE_MASK, (state & SUB_MASK) >> SUB_SHIFT, + timeout ? "timeout" : "change"); if(mode == MODE_I && !(ctrl & S_BSY)) { state = IDLE; @@ -246,10 +253,10 @@ void ncr5390_device::step(bool timeout) scsi_bus->ctrl_w(scsi_refid, 0, S_SEL); if(c == CD_RESELECT) { - logerror("%s: mode switch to Target\n", tag()); + LOG("mode switch to Target\n"); mode = MODE_T; } else { - logerror("%s: mode switch to Initiator\n", tag()); + LOG("mode switch to Initiator\n"); mode = MODE_I; } state &= STATE_MASK; @@ -259,7 +266,7 @@ void ncr5390_device::step(bool timeout) case ARB_TIMEOUT_BUSY << SUB_SHIFT: if(timeout) { scsi_bus->data_w(scsi_refid, 0); - logerror("%s: select timeout\n", tag()); + LOG("select timeout\n"); state = (state & STATE_MASK) | (ARB_TIMEOUT_ABORT << SUB_SHIFT); delay(1000); } else if(ctrl & S_BSY) { @@ -411,7 +418,6 @@ void ncr5390_device::step(bool timeout) break; case INIT_CPT_RECV_BYTE_NACK: - scsi_bus->ctrl_wait(scsi_refid, 0, S_REQ); function_complete(); break; @@ -456,7 +462,7 @@ void ncr5390_device::step(bool timeout) break; default: - logerror("%s: xfer on phase %d\n", tag(), scsi_bus->ctrl_r() & S_PHASE_MASK); + LOG("xfer on phase %d\n", scsi_bus->ctrl_r() & S_PHASE_MASK); function_complete(); break; } @@ -467,7 +473,7 @@ void ncr5390_device::step(bool timeout) break; // check for command complete - if ((dma_command && tcounter == 0) // dma in/out: transfer counter == 0 + if ((dma_command && tcounter == 0 && (dma_dir == DMA_IN || fifo_pos == 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 state = INIT_XFR_BUS_COMPLETE; @@ -562,9 +568,8 @@ void ncr5390_device::step(bool timeout) break; default: - logerror("%s: step() unexpected state %d.%d\n", - tag(), - state & STATE_MASK, (state & SUB_MASK) >> SUB_SHIFT); + LOG("step() unexpected state %d.%d\n", + state & STATE_MASK, (state & SUB_MASK) >> SUB_SHIFT); exit(0); } } @@ -596,25 +601,31 @@ void ncr5390_device::recv_byte() void ncr5390_device::function_bus_complete() { + LOG("function_bus_complete\n"); state = IDLE; istatus |= I_FUNCTION|I_BUS; dma_set(DMA_NONE); + drq_clear(); check_irq(); } void ncr5390_device::function_complete() { + LOG("function_complete\n"); state = IDLE; istatus |= I_FUNCTION; dma_set(DMA_NONE); + drq_clear(); check_irq(); } void ncr5390_device::bus_complete() { + LOG("bus_complete\n"); state = IDLE; istatus |= I_BUS; dma_set(DMA_NONE); + drq_clear(); check_irq(); } @@ -633,26 +644,26 @@ void ncr5390_device::delay_cycles(int cycles) READ8_MEMBER(ncr5390_device::tcounter_lo_r) { - logerror("%s: tcounter_lo_r %02x (%s)\n", tag(), tcounter & 0xff, machine().describe_context()); + LOG("tcounter_lo_r %02x (%s)\n", tcounter & 0xff, machine().describe_context()); return tcounter; } WRITE8_MEMBER(ncr5390_device::tcount_lo_w) { tcount = (tcount & 0xff00) | data; - logerror("%s: tcount_lo_w %02x (%s)\n", tag(), data, machine().describe_context()); + LOG("tcount_lo_w %02x (%s)\n", data, machine().describe_context()); } READ8_MEMBER(ncr5390_device::tcounter_hi_r) { - logerror("%s: tcounter_hi_r %02x (%s)\n", tag(), tcounter >> 8, machine().describe_context()); + LOG("tcounter_hi_r %02x (%s)\n", tcounter >> 8, machine().describe_context()); return tcounter >> 8; } WRITE8_MEMBER(ncr5390_device::tcount_hi_w) { tcount = (tcount & 0x00ff) | (data << 8); - logerror("%s: tcount_hi_w %02x (%s)\n", tag(), data, machine().describe_context()); + LOG("tcount_hi_w %02x (%s)\n", data, machine().describe_context()); } uint8_t ncr5390_device::fifo_pop() @@ -681,29 +692,38 @@ READ8_MEMBER(ncr5390_device::fifo_r) memmove(fifo, fifo+1, fifo_pos); } else r = 0; + LOGMASKED(LOG_FIFO, "fifo_r 0x%02x fifo_pos %d (%s)\n", r, fifo_pos, machine().describe_context()); return r; } WRITE8_MEMBER(ncr5390_device::fifo_w) { + LOGMASKED(LOG_FIFO, "fifo_w 0x%02x fifo_pos %d (%s)\n", data, fifo_pos, machine().describe_context()); if(fifo_pos != 16) fifo[fifo_pos++] = data; } READ8_MEMBER(ncr5390_device::command_r) { - logerror("%s: command_r (%s)\n", tag(), machine().describe_context()); + LOG("command_r (%s)\n", machine().describe_context()); return command[0]; } WRITE8_MEMBER(ncr5390_device::command_w) { - logerror("%s: command_w %02x (%s)\n", tag(), data, machine().describe_context()); + LOG("command_w %02x command_pos %d (%s)\n", data, command_pos, machine().describe_context()); if(command_pos == 2) { status |= S_GROSS_ERROR; check_irq(); return; } + /* + * Note the RESET chip and RESET SCSI Bus commands execute as soon as they are loaded into + * the top of the Command Register. + */ + if((data & 0x7f) == CM_RESET || (data & 0x7f) == CM_RESET_BUS) + command_pos = 0; + command[command_pos++] = data; if(command_pos == 1) start_command(); @@ -724,7 +744,7 @@ void ncr5390_device::start_command() { uint8_t c = command[0] & 0x7f; if(!check_valid_command(c)) { - logerror("%s: invalid command %02x\n", tag(), command[0]); + LOG("invalid command %02x\n", command[0]); istatus |= I_ILLEGAL; check_irq(); return; @@ -737,29 +757,33 @@ void ncr5390_device::start_command() tcounter = tcount; // clear transfer count zero flag when counter is reloaded - if (tcounter) - status &= ~S_TC0; + status &= ~S_TC0; } switch(c) { case CM_NOP: + LOGMASKED(LOG_COMMAND, "NOP\n"); command_pop_and_chain(); break; case CM_FLUSH_FIFO: + LOGMASKED(LOG_COMMAND, "Flush FIFO\n"); fifo_pos = 0; command_pop_and_chain(); break; case CM_RESET: + LOGMASKED(LOG_COMMAND, "Reset chip\n"); device_reset(); break; case CM_RESET_BUS: + LOGMASKED(LOG_COMMAND, "Reset SCSI bus\n"); reset_soft(); break; case CD_RESELECT: + LOGMASKED(LOG_COMMAND, "Reselect sequence\n"); state = DISC_REC_ARBITRATION; arbitrate(); break; @@ -767,31 +791,40 @@ void ncr5390_device::start_command() case CD_SELECT: case CD_SELECT_ATN: case CD_SELECT_ATN_STOP: + LOGMASKED(LOG_COMMAND, + (c == CD_SELECT) ? "Select without ATN sequence\n" : + (c == CD_SELECT_ATN) ? "Select with ATN sequence\n" : + "Select with ATN and stop sequence\n"); seq = 0; state = DISC_SEL_ARBITRATION; arbitrate(); break; case CD_ENABLE_SEL: + LOGMASKED(LOG_COMMAND, "Enable selection/reselection\n"); command_pop_and_chain(); break; case CD_DISABLE_SEL: + LOGMASKED(LOG_COMMAND, "Disable selection/reselection\n"); command_pop_and_chain(); break; case CI_XFER: + LOGMASKED(LOG_COMMAND, "Transfer information\n"); state = INIT_XFR; xfr_phase = scsi_bus->ctrl_r() & S_PHASE_MASK; step(false); break; case CI_COMPLETE: + LOGMASKED(LOG_COMMAND, "Initiator command complete sequence\n"); state = INIT_CPT_RECV_BYTE_ACK; recv_byte(); break; case CI_MSG_ACCEPT: + LOGMASKED(LOG_COMMAND, "Message accepted\n"); 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 @@ -804,6 +837,7 @@ void ncr5390_device::start_command() break; case CI_PAD: + LOGMASKED(LOG_COMMAND, "Transfer pad\n"); xfr_phase = scsi_bus->ctrl_r() & S_PHASE_MASK; if(xfr_phase & S_INP) state = INIT_XFR_RECV_PAD_WAIT_REQ; @@ -813,9 +847,14 @@ void ncr5390_device::start_command() step(false); break; + case CI_SET_ATN: + LOGMASKED(LOG_COMMAND, "Set ATN\n"); + scsi_bus->ctrl_w(scsi_refid, S_ATN, S_ATN); + command_pop_and_chain(); + break; + default: - logerror("%s: start unimplemented command %02x\n", tag(), c); - exit(0); + fatalerror("start unimplemented command %02x\n", c); } } @@ -825,7 +864,7 @@ bool ncr5390_device::check_valid_command(uint8_t cmd) switch((cmd >> 4) & 7) { case 0: return subcmd <= 3; case 4: return mode == MODE_D && subcmd <= 5; - case 2: return mode == MODE_T && subcmd <= 13 && subcmd != 6; + case 2: return mode == MODE_T && subcmd <= 11 && subcmd != 6; case 1: return mode == MODE_I && (subcmd <= 2 || subcmd == 8 || subcmd == 10); } return false; @@ -858,7 +897,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()); + LOG("status_r %02x (%s)\n", res, machine().describe_context()); return res; } @@ -866,7 +905,7 @@ READ8_MEMBER(ncr5390_device::status_r) WRITE8_MEMBER(ncr5390_device::bus_id_w) { bus_id = data & 7; - logerror("%s: bus_id=%d\n", tag(), bus_id); + LOG("bus_id=%d\n", bus_id); } READ8_MEMBER(ncr5390_device::istatus_r) @@ -883,18 +922,19 @@ READ8_MEMBER(ncr5390_device::istatus_r) if(res) command_pop_and_chain(); - logerror("%s: istatus_r %02x (%s)\n", tag(), res, machine().describe_context()); + LOG("istatus_r %02x (%s)\n", res, machine().describe_context()); return res; } WRITE8_MEMBER(ncr5390_device::timeout_w) { + LOG("timeout_w 0x%02x\n", data); select_timeout = data; } READ8_MEMBER(ncr5390_device::seq_step_r) { - logerror("%s: seq_step_r %d (%s)\n", tag(), seq, machine().describe_context()); + LOG("seq_step_r %d (%s)\n", seq, machine().describe_context()); return seq; } @@ -931,7 +971,7 @@ WRITE8_MEMBER(ncr5390_device::conf_w) 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()); + logerror("test_w %d (%s) - test mode not implemented\n", data, machine().describe_context()); } WRITE8_MEMBER(ncr5390_device::clock_w) @@ -990,7 +1030,7 @@ void ncr5390_device::decrement_tcounter() } /* - * According to the NCR 53C90A, 53C90B data book (http://bitsavers.informatik.uni-stuttgart.de/pdf/ncr/scsi/NCR53C90ab.pdf), + * According to the NCR 53C90A, 53C90B data book (http://bitsavers.org/pdf/ncr/scsi/NCR53C90ab.pdf), * the following are the differences from the 53C90: * * - Supports three-byte message exchange SCSI-2 tagged queueing @@ -1028,12 +1068,23 @@ READ8_MEMBER(ncr53c90a_device::status_r) { 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()); + LOG("status_r %02x (%s)\n", res, machine().describe_context()); if (irq) status &= ~(S_GROSS_ERROR | S_PARITY | S_TCC); return res; } +bool ncr53c90a_device::check_valid_command(uint8_t cmd) +{ + int subcmd = cmd & 15; + switch ((cmd >> 4) & 7) { + case 0: return subcmd <= 3 || (mode == MODE_T && subcmd == 4); + case 4: return mode == MODE_D && subcmd <= 6; + case 2: return mode == MODE_T && subcmd <= 11 && subcmd != 6; + case 1: return mode == MODE_I && (subcmd <= 2 || subcmd == 8 || subcmd == 10 || subcmd == 11); + } + return false; +} void ncr53c94_device::device_start() { diff --git a/src/devices/machine/ncr5390.h b/src/devices/machine/ncr5390.h index 59ebc50fdbd..4fae63b4a29 100644 --- a/src/devices/machine/ncr5390.h +++ b/src/devices/machine/ncr5390.h @@ -172,6 +172,7 @@ protected: CD_SELECT_ATN_STOP = 0x43, CD_ENABLE_SEL = 0x44, CD_DISABLE_SEL = 0x45, + CD_SELECT_ATN3 = 0x46, // 53c90a CT_SEND_MSG = 0x20, CT_SEND_STATUS = 0x21, CT_SEND_DATA = 0x22, @@ -183,11 +184,13 @@ protected: CT_RECV_CMD = 0x29, CT_RECV_DATA = 0x2a, CT_RECV_CMD_SEQ = 0x2b, + CT_ABORT_DMA = 0x04, // 53c90a CI_XFER = 0x10, CI_COMPLETE = 0x11, CI_MSG_ACCEPT = 0x12, CI_PAD = 0x18, - CI_SET_ATN = 0x1a + CI_SET_ATN = 0x1a, + CI_RESET_ATN = 0x1b, // 53c90a }; enum { DMA_NONE, DMA_IN, DMA_OUT }; @@ -215,7 +218,7 @@ protected: void start_command(); void step(bool timeout); - bool check_valid_command(uint8_t cmd); + virtual bool check_valid_command(uint8_t cmd); int derive_msg_size(uint8_t msg_id); void function_complete(); void function_bus_complete(); @@ -263,6 +266,8 @@ protected: virtual void device_start() override; void reset_soft(); + virtual bool check_valid_command(uint8_t cmd) override; + // 53c90a uses a previously reserved bit as an interrupt flag enum { S_INTERRUPT = 0x80, -- cgit v1.2.3