diff options
Diffstat (limited to 'src/devices/machine/ncr5390.cpp')
-rw-r--r-- | src/devices/machine/ncr5390.cpp | 337 |
1 files changed, 218 insertions, 119 deletions
diff --git a/src/devices/machine/ncr5390.cpp b/src/devices/machine/ncr5390.cpp index 62c62a038b6..10b7510d707 100644 --- a/src/devices/machine/ncr5390.cpp +++ b/src/devices/machine/ncr5390.cpp @@ -1,6 +1,12 @@ // 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" @@ -14,9 +20,10 @@ #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") +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 void ncr5390_device::map(address_map &map) { @@ -33,38 +40,38 @@ void ncr5390_device::map(address_map &map) map(0x9, 0x9).w(FUNC(ncr5390_device::clock_w)); } -READ8_MEMBER(ncr5390_device::read) +uint8_t ncr5390_device::read(offs_t offset) { switch (offset) { - 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; + 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; } } -WRITE8_MEMBER(ncr5390_device::write) +void ncr5390_device::write(offs_t offset, uint8_t data) { switch (offset) { - 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; + 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; default: break; } } @@ -76,18 +83,18 @@ void ncr53c90a_device::map(address_map &map) map(0xb, 0xb).rw(FUNC(ncr53c90a_device::conf2_r), FUNC(ncr53c90a_device::conf2_w)); } -READ8_MEMBER(ncr53c90a_device::read) +uint8_t ncr53c90a_device::read(offs_t offset) { if (offset == 11) - return conf2_r(space, 0); - return ncr5390_device::read(space, offset); + return conf2_r(); + return ncr5390_device::read(offset); } -WRITE8_MEMBER(ncr53c90a_device::write) +void ncr53c90a_device::write(offs_t offset, uint8_t data) { if (offset == 11) - return conf2_w(space, 0, data); - ncr5390_device::write(space, offset, data); + return conf2_w(data); + ncr5390_device::write(offset, data); } void ncr53c94_device::map(address_map &map) @@ -98,21 +105,21 @@ void ncr53c94_device::map(address_map &map) map(0xf, 0xf).w(FUNC(ncr53c94_device::fifo_align_w)); } -READ8_MEMBER(ncr53c94_device::read) +uint8_t ncr53c94_device::read(offs_t offset) { if (offset == 12) - return conf3_r(space, 0); - return ncr53c90a_device::read(space, offset); + return conf3_r(); + return ncr53c90a_device::read(offset); } -WRITE8_MEMBER(ncr53c94_device::write) +void ncr53c94_device::write(offs_t offset, uint8_t data) { if (offset == 11) - conf3_w(space, 0, data); + conf3_w(data); else if (offset == 15) - fifo_align_w(space, 0, data); + fifo_align_w(data); else - ncr53c90a_device::write(space, offset, data); + ncr53c90a_device::write(offset, data); } ncr5390_device::ncr5390_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) @@ -141,8 +148,19 @@ 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) - : ncr53c90a_device(mconfig, NCR53C94, tag, owner, 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) , 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) { } @@ -177,10 +195,7 @@ 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); @@ -196,26 +211,28 @@ void ncr5390_device::device_reset() sync_offset = 0; seq = 0; config &= 7; - status &= 0x90; + status = 0; 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)); @@ -258,6 +275,17 @@ 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; @@ -267,7 +295,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("need to wait for bus free\n"); + fatalerror("ncr5390_device::step 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); @@ -407,15 +435,13 @@ void ncr5390_device::step(bool timeout) case DISC_SEL_ARBITRATION_INIT: // wait until a command is in the fifo - if (!fifo_pos && dma_command && !(status & S_TC0)) { + if (!fifo_pos) { // dma starts after bus arbitration/selection is complete - dma_set(DMA_OUT); - step(false); + check_drq(); break; } - // "with atn" variants have a message byte before the command descriptor - command_length = (c == CD_SELECT) ? derive_msg_size(fifo[0]) : 1; + command_length = fifo_pos + tcounter; state = DISC_SEL_ARBITRATION; step(false); break; @@ -449,7 +475,6 @@ 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; @@ -460,6 +485,8 @@ 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; @@ -680,7 +707,7 @@ void ncr5390_device::function_bus_complete() state = IDLE; istatus |= I_FUNCTION|I_BUS; dma_set(DMA_NONE); - drq_clear(); + check_drq(); check_irq(); } @@ -690,7 +717,7 @@ void ncr5390_device::function_complete() state = IDLE; istatus |= I_FUNCTION; dma_set(DMA_NONE); - drq_clear(); + check_drq(); check_irq(); } @@ -700,7 +727,7 @@ void ncr5390_device::bus_complete() state = IDLE; istatus |= I_BUS; dma_set(DMA_NONE); - drq_clear(); + check_drq(); check_irq(); } @@ -717,25 +744,25 @@ void ncr5390_device::delay_cycles(int cycles) tm->adjust(clocks_to_attotime(cycles)); } -READ8_MEMBER(ncr5390_device::tcounter_lo_r) +uint8_t ncr5390_device::tcounter_lo_r() { LOG("tcounter_lo_r %02x (%s)\n", tcounter & 0xff, machine().describe_context()); return tcounter; } -WRITE8_MEMBER(ncr5390_device::tcount_lo_w) +void ncr5390_device::tcount_lo_w(uint8_t data) { tcount = (tcount & 0xff00) | data; LOG("tcount_lo_w %02x (%s)\n", data, machine().describe_context()); } -READ8_MEMBER(ncr5390_device::tcounter_hi_r) +uint8_t ncr5390_device::tcounter_hi_r() { LOG("tcounter_hi_r %02x (%s)\n", tcounter >> 8, machine().describe_context()); return tcounter >> 8; } -WRITE8_MEMBER(ncr5390_device::tcount_hi_w) +void ncr5390_device::tcount_hi_w(uint8_t data) { tcount = (tcount & 0x00ff) | (data << 8); LOG("tcount_hi_w %02x (%s)\n", data, machine().describe_context()); @@ -746,19 +773,17 @@ 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 && !(status & S_TC0)) - drq_set(); + check_drq(); return r; } void ncr5390_device::fifo_push(uint8_t val) { fifo[fifo_pos++] = val; - if(!drq && dma_dir == DMA_IN && !(status & S_TC0)) - drq_set(); + check_drq(); } -READ8_MEMBER(ncr5390_device::fifo_r) +uint8_t ncr5390_device::fifo_r() { uint8_t r; if(fifo_pos) { @@ -771,20 +796,20 @@ READ8_MEMBER(ncr5390_device::fifo_r) return r; } -WRITE8_MEMBER(ncr5390_device::fifo_w) +void ncr5390_device::fifo_w(uint8_t data) { 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) +uint8_t ncr5390_device::command_r() { LOG("command_r (%s)\n", machine().describe_context()); return command[0]; } -WRITE8_MEMBER(ncr5390_device::command_w) +void ncr5390_device::command_w(uint8_t data) { LOG("command_w %02x command_pos %d (%s)\n", data, command_pos, machine().describe_context()); if(command_pos == 2) { @@ -834,6 +859,8 @@ 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: @@ -854,13 +881,9 @@ void ncr5390_device::start_command() case CM_RESET_BUS: LOGMASKED(LOG_COMMAND, "Reset SCSI bus\n"); - 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(); - } + state = BUSRESET_WAIT_INT; + scsi_bus->ctrl_w(scsi_refid, S_RST, S_RST); + delay(130); break; case CD_RESELECT: @@ -878,6 +901,7 @@ 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; @@ -896,6 +920,7 @@ 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; @@ -936,8 +961,14 @@ 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("start unimplemented command %02x\n", c); + fatalerror("ncr5390_device::start_command unimplemented command %02x\n", c); } } @@ -953,12 +984,6 @@ 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); @@ -976,7 +1001,7 @@ void ncr5390_device::check_irq() } -READ8_MEMBER(ncr5390_device::status_r) +uint8_t 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); @@ -985,13 +1010,13 @@ READ8_MEMBER(ncr5390_device::status_r) return res; } -WRITE8_MEMBER(ncr5390_device::bus_id_w) +void ncr5390_device::bus_id_w(uint8_t data) { bus_id = data & 7; LOG("bus_id=%d\n", bus_id); } -READ8_MEMBER(ncr5390_device::istatus_r) +uint8_t ncr5390_device::istatus_r() { uint8_t res = istatus; @@ -1009,39 +1034,39 @@ READ8_MEMBER(ncr5390_device::istatus_r) return res; } -WRITE8_MEMBER(ncr5390_device::timeout_w) +void ncr5390_device::timeout_w(uint8_t data) { LOG("timeout_w 0x%02x\n", data); select_timeout = data; } -READ8_MEMBER(ncr5390_device::seq_step_r) +uint8_t ncr5390_device::seq_step_r() { LOG("seq_step_r %d (%s)\n", seq, machine().describe_context()); return seq; } -WRITE8_MEMBER(ncr5390_device::sync_period_w) +void ncr5390_device::sync_period_w(uint8_t data) { sync_period = data & 0x1f; } -READ8_MEMBER(ncr5390_device::fifo_flags_r) +uint8_t ncr5390_device::fifo_flags_r() { return fifo_pos; } -WRITE8_MEMBER(ncr5390_device::sync_offset_w) +void ncr5390_device::sync_offset_w(uint8_t data) { sync_offset = data & 0x0f; } -READ8_MEMBER(ncr5390_device::conf_r) +uint8_t ncr5390_device::conf_r() { return config; } -WRITE8_MEMBER(ncr5390_device::conf_w) +void ncr5390_device::conf_w(uint8_t data) { config = data; scsi_id = data & 7; @@ -1051,13 +1076,13 @@ WRITE8_MEMBER(ncr5390_device::conf_w) test_mode = true; } -WRITE8_MEMBER(ncr5390_device::test_w) +void ncr5390_device::test_w(uint8_t data) { if (test_mode) logerror("test_w %d (%s) - test mode not implemented\n", data, machine().describe_context()); } -WRITE8_MEMBER(ncr5390_device::clock_w) +void ncr5390_device::clock_w(uint8_t data) { clock_conv = data & 0x07; } @@ -1065,16 +1090,17 @@ 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 > fifo_pos) || !tcounter)) - drq_set(); + + // account for data already in the fifo + if (dir == DMA_OUT && fifo_pos) + decrement_tcounter(fifo_pos); } void ncr5390_device::dma_w(uint8_t val) { fifo_push(val); decrement_tcounter(); - if(fifo_pos == 16 || (status & S_TC0)) - drq_clear(); + check_drq(); step(false); } @@ -1082,34 +1108,41 @@ uint8_t ncr5390_device::dma_r() { uint8_t r = fifo_pop(); decrement_tcounter(); - if(!fifo_pos || (status & S_TC0)) - drq_clear(); + check_drq(); step(false); return r; } -void ncr5390_device::drq_set() +void ncr5390_device::check_drq() { - if(!drq) { - drq = true; - m_drq_handler(drq); + 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; } -} -void ncr5390_device::drq_clear() -{ - if(drq) { - drq = false; + if (drq_state != drq) { + drq = drq_state; m_drq_handler(drq); } } -void ncr5390_device::decrement_tcounter() +void ncr5390_device::decrement_tcounter(int count) { if (!dma_command) return; - tcounter--; + tcounter -= count; if (tcounter == 0) status |= S_TC0; } @@ -1142,14 +1175,14 @@ void ncr53c90a_device::device_start() ncr5390_device::device_start(); } -void ncr53c90a_device::reset_soft() +void ncr53c90a_device::device_reset() { config2 = 0; - ncr5390_device::reset_soft(); + ncr5390_device::device_reset(); } -READ8_MEMBER(ncr53c90a_device::status_r) +uint8_t 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); @@ -1180,9 +1213,75 @@ void ncr53c94_device::device_start() ncr53c90a_device::device_start(); } -void ncr53c94_device::reset_soft() +void ncr53c94_device::device_reset() { config3 = 0; - ncr53c90a_device::reset_soft(); + 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(); } |