diff options
Diffstat (limited to 'src/devices/machine/ncr5390.cpp')
-rw-r--r-- | src/devices/machine/ncr5390.cpp | 337 |
1 files changed, 119 insertions, 218 deletions
diff --git a/src/devices/machine/ncr5390.cpp b/src/devices/machine/ncr5390.cpp index 10b7510d707..62c62a038b6 100644 --- a/src/devices/machine/ncr5390.cpp +++ b/src/devices/machine/ncr5390.cpp @@ -1,12 +1,6 @@ // license:BSD-3-Clause // copyright-holders:Olivier Galibert -/* - * TODO - * - 16 bit dma order, alignment and last byte handling - * - clean up variable naming and protection - */ - #include "emu.h" #include "ncr5390.h" @@ -20,10 +14,9 @@ #define DELAY_HACK -DEFINE_DEVICE_TYPE(NCR5390, ncr5390_device, "ncr5390", "NCR 5390 SCSI Controller") -DEFINE_DEVICE_TYPE(NCR53C90A, ncr53c90a_device, "ncr53c90a", "NCR 53C90A Advanced SCSI Controller") -DEFINE_DEVICE_TYPE(NCR53C94, ncr53c94_device, "ncr53c94", "NCR 53C94 Advanced SCSI Controller") -DEFINE_DEVICE_TYPE(NCR53CF94, ncr53cf94_device, "ncr53cf94", "NCR 53CF94-2 Fast SCSI Controller") // TODO: differences not emulated +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") void ncr5390_device::map(address_map &map) { @@ -40,38 +33,38 @@ void ncr5390_device::map(address_map &map) map(0x9, 0x9).w(FUNC(ncr5390_device::clock_w)); } -uint8_t ncr5390_device::read(offs_t offset) +READ8_MEMBER(ncr5390_device::read) { switch (offset) { - case 0: return tcounter_lo_r(); - case 1: return tcounter_hi_r(); - case 2: return fifo_r(); - case 3: return command_r(); - case 4: return status_r(); - case 5: return istatus_r(); - case 6: return seq_step_r(); - case 7: return fifo_flags_r(); - case 8: return conf_r(); - default: return 0xff; + case 0: return tcounter_lo_r(space, 0); + case 1: return tcounter_hi_r(space, 0); + case 2: return fifo_r(space, 0); + case 3: return command_r(space, 0); + case 4: return status_r(space, 0); + case 5: return istatus_r(space, 0); + case 6: return seq_step_r(space, 0); + case 7: return fifo_flags_r(space, 0); + case 8: return conf_r(space, 0); + default: return 0; } } -void ncr5390_device::write(offs_t offset, uint8_t data) +WRITE8_MEMBER(ncr5390_device::write) { switch (offset) { - case 0: tcount_lo_w(data); break; - case 1: tcount_hi_w(data); break; - case 2: fifo_w(data); break; - case 3: command_w(data); break; - case 4: bus_id_w(data); break; - case 5: timeout_w(data); break; - case 6: sync_period_w(data); break; - case 7: sync_offset_w(data); break; - case 8: conf_w(data); break; - case 9: clock_w(data); break; - case 10: test_w(data); break; + case 0: tcount_lo_w(space, 0, data); break; + case 1: tcount_hi_w(space, 0, data); break; + case 2: fifo_w(space, 0, data); break; + case 3: command_w(space, 0, data); break; + case 4: bus_id_w(space, 0, data); break; + case 5: timeout_w(space, 0, data); break; + case 6: sync_period_w(space, 0, data); break; + case 7: sync_offset_w(space, 0, data); break; + case 8: conf_w(space, 0, data); break; + case 9: clock_w(space, 0, data); break; + case 10: test_w(space, 0, data); break; default: break; } } @@ -83,18 +76,18 @@ void ncr53c90a_device::map(address_map &map) map(0xb, 0xb).rw(FUNC(ncr53c90a_device::conf2_r), FUNC(ncr53c90a_device::conf2_w)); } -uint8_t ncr53c90a_device::read(offs_t offset) +READ8_MEMBER(ncr53c90a_device::read) { if (offset == 11) - return conf2_r(); - return ncr5390_device::read(offset); + return conf2_r(space, 0); + return ncr5390_device::read(space, offset); } -void ncr53c90a_device::write(offs_t offset, uint8_t data) +WRITE8_MEMBER(ncr53c90a_device::write) { if (offset == 11) - return conf2_w(data); - ncr5390_device::write(offset, data); + return conf2_w(space, 0, data); + ncr5390_device::write(space, offset, data); } void ncr53c94_device::map(address_map &map) @@ -105,21 +98,21 @@ void ncr53c94_device::map(address_map &map) map(0xf, 0xf).w(FUNC(ncr53c94_device::fifo_align_w)); } -uint8_t ncr53c94_device::read(offs_t offset) +READ8_MEMBER(ncr53c94_device::read) { if (offset == 12) - return conf3_r(); - return ncr53c90a_device::read(offset); + return conf3_r(space, 0); + return ncr53c90a_device::read(space, offset); } -void ncr53c94_device::write(offs_t offset, uint8_t data) +WRITE8_MEMBER(ncr53c94_device::write) { if (offset == 11) - conf3_w(data); + conf3_w(space, 0, data); else if (offset == 15) - fifo_align_w(data); + fifo_align_w(space, 0, data); else - ncr53c90a_device::write(offset, data); + ncr53c90a_device::write(space, offset, data); } ncr5390_device::ncr5390_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) @@ -148,19 +141,8 @@ ncr53c90a_device::ncr53c90a_device(const machine_config &mconfig, const char *ta } ncr53c94_device::ncr53c94_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : ncr53c94_device(mconfig, NCR53C94, tag, owner, clock) -{ -} - -ncr53c94_device::ncr53c94_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) - : ncr53c90a_device(mconfig, type, tag, owner, clock) + : ncr53c90a_device(mconfig, NCR53C94, tag, owner, clock) , config3(0) - , m_busmd(BUSMD_0) -{ -} - -ncr53cf94_device::ncr53cf94_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : ncr53c94_device(mconfig, NCR53CF94, tag, owner, clock) { } @@ -195,7 +177,10 @@ void ncr5390_device::device_start() m_irq_handler.resolve_safe(); m_drq_handler.resolve_safe(); + tcount = 0; + tcounter = 0; config = 0; + status = 0; bus_id = 0; select_timeout = 0; tm = timer_alloc(0); @@ -211,28 +196,26 @@ void ncr5390_device::device_reset() sync_offset = 0; seq = 0; config &= 7; - status = 0; + status &= 0x90; istatus = 0; irq = false; m_irq_handler(irq); + reset_soft(); +} +void ncr5390_device::reset_soft() +{ state = IDLE; 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); - - scsi_bus->ctrl_w(scsi_refid, 0, S_RST); - tcount = 0; - tcounter = 0; - reset_disconnect(); } void ncr5390_device::reset_disconnect() { - scsi_bus->ctrl_w(scsi_refid, 0, ~S_RST); - command_pos = 0; command_length = 0; memset(command, 0, sizeof(command)); @@ -275,17 +258,6 @@ void ncr5390_device::step(bool timeout) case IDLE: break; - case BUSRESET_WAIT_INT: - state = IDLE; - scsi_bus->ctrl_w(scsi_refid, 0, S_RST); - reset_disconnect(); - - if (!(config & 0x40)) { - istatus |= I_SCSI_RESET; - check_irq(); - } - break; - case ARB_COMPLETE << SUB_SHIFT: { if(!timeout) break; @@ -295,7 +267,7 @@ void ncr5390_device::step(bool timeout) if(win != scsi_id) { scsi_bus->data_w(scsi_refid, 0); scsi_bus->ctrl_w(scsi_refid, 0, S_ALL); - fatalerror("ncr5390_device::step need to wait for bus free\n"); + fatalerror("need to wait for bus free\n"); } state = (state & STATE_MASK) | (ARB_ASSERT_SEL << SUB_SHIFT); scsi_bus->ctrl_w(scsi_refid, S_SEL, S_SEL); @@ -435,13 +407,15 @@ void ncr5390_device::step(bool timeout) case DISC_SEL_ARBITRATION_INIT: // wait until a command is in the fifo - if (!fifo_pos) { + if (!fifo_pos && dma_command && !(status & S_TC0)) { // dma starts after bus arbitration/selection is complete - check_drq(); + dma_set(DMA_OUT); + step(false); break; } - command_length = fifo_pos + tcounter; + // "with atn" variants have a message byte before the command descriptor + command_length = (c == CD_SELECT) ? derive_msg_size(fifo[0]) : 1; state = DISC_SEL_ARBITRATION; step(false); break; @@ -475,6 +449,7 @@ void ncr5390_device::step(bool timeout) seq = 1; function_bus_complete(); } else { + command_length = derive_msg_size(fifo[0]); state = DISC_SEL_WAIT_REQ; } break; @@ -485,8 +460,6 @@ void ncr5390_device::step(bool timeout) if((ctrl & S_PHASE_MASK) != S_PHASE_COMMAND) { if(!command_length) seq = 4; - else - seq = 2; scsi_bus->ctrl_wait(scsi_refid, 0, S_REQ); function_bus_complete(); break; @@ -707,7 +680,7 @@ void ncr5390_device::function_bus_complete() state = IDLE; istatus |= I_FUNCTION|I_BUS; dma_set(DMA_NONE); - check_drq(); + drq_clear(); check_irq(); } @@ -717,7 +690,7 @@ void ncr5390_device::function_complete() state = IDLE; istatus |= I_FUNCTION; dma_set(DMA_NONE); - check_drq(); + drq_clear(); check_irq(); } @@ -727,7 +700,7 @@ void ncr5390_device::bus_complete() state = IDLE; istatus |= I_BUS; dma_set(DMA_NONE); - check_drq(); + drq_clear(); check_irq(); } @@ -744,25 +717,25 @@ void ncr5390_device::delay_cycles(int cycles) tm->adjust(clocks_to_attotime(cycles)); } -uint8_t ncr5390_device::tcounter_lo_r() +READ8_MEMBER(ncr5390_device::tcounter_lo_r) { LOG("tcounter_lo_r %02x (%s)\n", tcounter & 0xff, machine().describe_context()); return tcounter; } -void ncr5390_device::tcount_lo_w(uint8_t data) +WRITE8_MEMBER(ncr5390_device::tcount_lo_w) { tcount = (tcount & 0xff00) | data; LOG("tcount_lo_w %02x (%s)\n", data, machine().describe_context()); } -uint8_t ncr5390_device::tcounter_hi_r() +READ8_MEMBER(ncr5390_device::tcounter_hi_r) { LOG("tcounter_hi_r %02x (%s)\n", tcounter >> 8, machine().describe_context()); return tcounter >> 8; } -void ncr5390_device::tcount_hi_w(uint8_t data) +WRITE8_MEMBER(ncr5390_device::tcount_hi_w) { tcount = (tcount & 0x00ff) | (data << 8); LOG("tcount_hi_w %02x (%s)\n", data, machine().describe_context()); @@ -773,17 +746,19 @@ uint8_t ncr5390_device::fifo_pop() uint8_t r = fifo[0]; fifo_pos--; memmove(fifo, fifo+1, fifo_pos); - check_drq(); + if((!fifo_pos) && dma_dir == DMA_OUT && !(status & S_TC0)) + drq_set(); return r; } void ncr5390_device::fifo_push(uint8_t val) { fifo[fifo_pos++] = val; - check_drq(); + if(!drq && dma_dir == DMA_IN && !(status & S_TC0)) + drq_set(); } -uint8_t ncr5390_device::fifo_r() +READ8_MEMBER(ncr5390_device::fifo_r) { uint8_t r; if(fifo_pos) { @@ -796,20 +771,20 @@ uint8_t ncr5390_device::fifo_r() return r; } -void ncr5390_device::fifo_w(uint8_t data) +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; } -uint8_t ncr5390_device::command_r() +READ8_MEMBER(ncr5390_device::command_r) { LOG("command_r (%s)\n", machine().describe_context()); return command[0]; } -void ncr5390_device::command_w(uint8_t data) +WRITE8_MEMBER(ncr5390_device::command_w) { LOG("command_w %02x command_pos %d (%s)\n", data, command_pos, machine().describe_context()); if(command_pos == 2) { @@ -859,8 +834,6 @@ void ncr5390_device::start_command() // clear transfer count zero flag when counter is reloaded status &= ~S_TC0; } - else - tcounter = 0; switch(c) { case CM_NOP: @@ -881,9 +854,13 @@ void ncr5390_device::start_command() case CM_RESET_BUS: LOGMASKED(LOG_COMMAND, "Reset SCSI bus\n"); - state = BUSRESET_WAIT_INT; - scsi_bus->ctrl_w(scsi_refid, S_RST, S_RST); - delay(130); + reset_soft(); + // FIXME: this interrupt should be generated when the reset is reflected + // back into the device, and not when the device starts the scsi reset + if (!(config & 0x40)) { + istatus = I_SCSI_RESET; + check_irq(); + } break; case CD_RESELECT: @@ -901,7 +878,6 @@ void ncr5390_device::start_command() "Select with ATN and stop sequence\n"); seq = 0; state = DISC_SEL_ARBITRATION_INIT; - dma_set(dma_command ? DMA_OUT : DMA_NONE); arbitrate(); break; @@ -920,7 +896,6 @@ void ncr5390_device::start_command() 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); - check_drq(); step(false); break; @@ -961,14 +936,8 @@ void ncr5390_device::start_command() command_pop_and_chain(); break; - case CI_RESET_ATN: - LOGMASKED(LOG_COMMAND, "Reset ATN\n"); - scsi_bus->ctrl_w(scsi_refid, 0, S_ATN); - command_pop_and_chain(); - break; - default: - fatalerror("ncr5390_device::start_command unimplemented command %02x\n", c); + fatalerror("start unimplemented command %02x\n", c); } } @@ -984,6 +953,12 @@ bool ncr5390_device::check_valid_command(uint8_t cmd) return false; } +int ncr5390_device::derive_msg_size(uint8_t msg_id) +{ + const static int sizes[8] = { 6, 10, 6, 6, 6, 12, 6, 10 }; + return sizes[msg_id >> 5]; +} + void ncr5390_device::arbitrate() { state = (state & STATE_MASK) | (ARB_COMPLETE << SUB_SHIFT); @@ -1001,7 +976,7 @@ void ncr5390_device::check_irq() } -uint8_t ncr5390_device::status_r() +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); @@ -1010,13 +985,13 @@ uint8_t ncr5390_device::status_r() return res; } -void ncr5390_device::bus_id_w(uint8_t data) +WRITE8_MEMBER(ncr5390_device::bus_id_w) { bus_id = data & 7; LOG("bus_id=%d\n", bus_id); } -uint8_t ncr5390_device::istatus_r() +READ8_MEMBER(ncr5390_device::istatus_r) { uint8_t res = istatus; @@ -1034,39 +1009,39 @@ uint8_t ncr5390_device::istatus_r() return res; } -void ncr5390_device::timeout_w(uint8_t data) +WRITE8_MEMBER(ncr5390_device::timeout_w) { LOG("timeout_w 0x%02x\n", data); select_timeout = data; } -uint8_t ncr5390_device::seq_step_r() +READ8_MEMBER(ncr5390_device::seq_step_r) { LOG("seq_step_r %d (%s)\n", seq, machine().describe_context()); return seq; } -void ncr5390_device::sync_period_w(uint8_t data) +WRITE8_MEMBER(ncr5390_device::sync_period_w) { sync_period = data & 0x1f; } -uint8_t ncr5390_device::fifo_flags_r() +READ8_MEMBER(ncr5390_device::fifo_flags_r) { return fifo_pos; } -void ncr5390_device::sync_offset_w(uint8_t data) +WRITE8_MEMBER(ncr5390_device::sync_offset_w) { sync_offset = data & 0x0f; } -uint8_t ncr5390_device::conf_r() +READ8_MEMBER(ncr5390_device::conf_r) { return config; } -void ncr5390_device::conf_w(uint8_t data) +WRITE8_MEMBER(ncr5390_device::conf_w) { config = data; scsi_id = data & 7; @@ -1076,13 +1051,13 @@ void ncr5390_device::conf_w(uint8_t data) test_mode = true; } -void ncr5390_device::test_w(uint8_t data) +WRITE8_MEMBER(ncr5390_device::test_w) { if (test_mode) logerror("test_w %d (%s) - test mode not implemented\n", data, machine().describe_context()); } -void ncr5390_device::clock_w(uint8_t data) +WRITE8_MEMBER(ncr5390_device::clock_w) { clock_conv = data & 0x07; } @@ -1090,17 +1065,16 @@ void ncr5390_device::clock_w(uint8_t data) void ncr5390_device::dma_set(int dir) { dma_dir = dir; - - // account for data already in the fifo - if (dir == DMA_OUT && fifo_pos) - decrement_tcounter(fifo_pos); + if(dma_dir == DMA_OUT && fifo_pos != 16 && ((tcounter > fifo_pos) || !tcounter)) + drq_set(); } void ncr5390_device::dma_w(uint8_t val) { fifo_push(val); decrement_tcounter(); - check_drq(); + if(fifo_pos == 16 || (status & S_TC0)) + drq_clear(); step(false); } @@ -1108,41 +1082,34 @@ uint8_t ncr5390_device::dma_r() { uint8_t r = fifo_pop(); decrement_tcounter(); - check_drq(); + if(!fifo_pos || (status & S_TC0)) + drq_clear(); step(false); return r; } -void ncr5390_device::check_drq() +void ncr5390_device::drq_set() { - bool drq_state = drq; - - switch (dma_dir) { - case DMA_NONE: - drq_state = false; - break; - - case DMA_IN: // device to memory - drq_state = !(status & S_TC0) && fifo_pos; - break; - - case DMA_OUT: // memory to device - drq_state = !(status & S_TC0) && fifo_pos < 16; - break; + if(!drq) { + drq = true; + m_drq_handler(drq); } +} - if (drq_state != drq) { - drq = drq_state; +void ncr5390_device::drq_clear() +{ + if(drq) { + drq = false; m_drq_handler(drq); } } -void ncr5390_device::decrement_tcounter(int count) +void ncr5390_device::decrement_tcounter() { if (!dma_command) return; - tcounter -= count; + tcounter--; if (tcounter == 0) status |= S_TC0; } @@ -1175,14 +1142,14 @@ void ncr53c90a_device::device_start() ncr5390_device::device_start(); } -void ncr53c90a_device::device_reset() +void ncr53c90a_device::reset_soft() { config2 = 0; - ncr5390_device::device_reset(); + ncr5390_device::reset_soft(); } -uint8_t ncr53c90a_device::status_r() +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); @@ -1213,75 +1180,9 @@ void ncr53c94_device::device_start() ncr53c90a_device::device_start(); } -void ncr53c94_device::device_reset() +void ncr53c94_device::reset_soft() { config3 = 0; - ncr53c90a_device::device_reset(); -} - -u16 ncr53c94_device::dma16_r() -{ - // check fifo underflow - if (fifo_pos < 2) - fatalerror("ncr53c94_device::dma16_r fifo_pos %d\n", fifo_pos); - - // pop two bytes from fifo - u16 const data = (fifo[0] << 8) | fifo[1]; - fifo_pos -= 2; - memmove(fifo, fifo + 2, fifo_pos); - - // update drq - decrement_tcounter(2); - check_drq(); - - step(false); - - return data; -} - -void ncr53c94_device::dma16_w(u16 data) -{ - // check fifo overflow - if (fifo_pos > 14) - fatalerror("ncr53c94_device::dma16_w fifo_pos %d\n", fifo_pos); - - // push two bytes into fifo - fifo[fifo_pos++] = data >> 8; - fifo[fifo_pos++] = data; - - // update drq - decrement_tcounter(2); - check_drq(); - - step(false); -} - -void ncr53c94_device::check_drq() -{ - if (m_busmd != BUSMD_0) - { - bool drq_state = drq; - - switch (dma_dir) { - case DMA_NONE: - drq_state = false; - break; - - case DMA_IN: // device to memory - drq_state = !(status & S_TC0) && fifo_pos > 1; - break; - - case DMA_OUT: // memory to device - drq_state = !(status & S_TC0) && fifo_pos < 15; - break; - } - - if (drq_state != drq) { - drq = drq_state; - m_drq_handler(drq); - } - } - else - ncr5390_device::check_drq(); + ncr53c90a_device::reset_soft(); } |