Merge pull request #2455 from pmackinlay/ncr5390

ncr5390: tcounter and dma/drq changes
This commit is contained in:
R. Belmont 2017-07-09 20:27:12 -04:00 committed by GitHub
commit 9398fff5f6
3 changed files with 76 additions and 26 deletions

View File

@ -426,6 +426,10 @@ void ncr5390_device::step(bool timeout)
dma_set(dma_command ? DMA_OUT : DMA_NONE); dma_set(dma_command ? DMA_OUT : DMA_NONE);
state = INIT_XFR_SEND_BYTE; 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 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))) 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); scsi_bus->ctrl_w(scsi_refid, 0, S_ATN);
@ -438,6 +442,10 @@ void ncr5390_device::step(bool timeout)
case S_PHASE_MSG_IN: case S_PHASE_MSG_IN:
dma_set(dma_command ? DMA_IN : DMA_NONE); 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() // 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; 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; break;
// check for command complete // 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) == 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 || (!dma_command && (xfr_phase & S_INP) == S_INP && fifo_pos == 1)) // non-dma in: every byte
bus_complete(); state = INIT_XFR_BUS_COMPLETE;
else else
// check for phase change // check for phase change
if((ctrl & S_PHASE_MASK) != xfr_phase) { if((ctrl & S_PHASE_MASK) != xfr_phase) {
command_pos = 0; command_pos = 0;
bus_complete(); state = INIT_XFR_BUS_COMPLETE;
} else { } else {
state = INIT_XFR; state = INIT_XFR;
step(false);
} }
step(false);
break; break;
case INIT_XFR_SEND_BYTE: case INIT_XFR_SEND_BYTE:
decrement_tcounter();
state = INIT_XFR_WAIT_REQ; state = INIT_XFR_WAIT_REQ;
step(false);
break; break;
case INIT_XFR_RECV_BYTE_ACK: case INIT_XFR_RECV_BYTE_ACK:
decrement_tcounter();
state = INIT_XFR_WAIT_REQ; state = INIT_XFR_WAIT_REQ;
scsi_bus->ctrl_w(scsi_refid, 0, S_ACK); scsi_bus->ctrl_w(scsi_refid, 0, S_ACK);
break; break;
case INIT_XFR_RECV_BYTE_NACK: 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(); function_complete();
break; 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: case INIT_XFR_SEND_PAD_WAIT_REQ:
if(!(ctrl & S_REQ)) if(!(ctrl & S_REQ))
break; break;
@ -498,7 +527,7 @@ void ncr5390_device::step(bool timeout)
break; break;
case INIT_XFR_SEND_PAD: case INIT_XFR_SEND_PAD:
tcounter--; decrement_tcounter();
if(tcounter) { if(tcounter) {
state = INIT_XFR_SEND_PAD_WAIT_REQ; state = INIT_XFR_SEND_PAD_WAIT_REQ;
step(false); step(false);
@ -520,7 +549,7 @@ void ncr5390_device::step(bool timeout)
break; break;
case INIT_XFR_RECV_PAD: case INIT_XFR_RECV_PAD:
tcounter--; decrement_tcounter();
if(tcounter) { if(tcounter) {
state = INIT_XFR_RECV_PAD_WAIT_REQ; state = INIT_XFR_RECV_PAD_WAIT_REQ;
scsi_bus->ctrl_w(scsi_refid, 0, S_ACK); 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) WRITE8_MEMBER(ncr5390_device::tcount_lo_w)
{ {
tcount = (tcount & 0xff00) | data; tcount = (tcount & 0xff00) | data;
status &= ~S_TC0;
logerror("%s: tcount_lo_w %02x (%s)\n", tag(), data, machine().describe_context()); 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) WRITE8_MEMBER(ncr5390_device::tcount_hi_w)
{ {
tcount = (tcount & 0x00ff) | (data << 8); tcount = (tcount & 0x00ff) | (data << 8);
status &= ~S_TC0;
logerror("%s: tcount_hi_w %02x (%s)\n", tag(), data, machine().describe_context()); 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]; uint8_t r = fifo[0];
fifo_pos--; fifo_pos--;
memmove(fifo, fifo+1, 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(); drq_set();
return r; return r;
} }
@ -703,8 +730,14 @@ void ncr5390_device::start_command()
// for dma commands, reload transfer counter // for dma commands, reload transfer counter
dma_command = command[0] & 0x80; dma_command = command[0] & 0x80;
if (dma_command) if (dma_command)
{
tcounter = tcount; tcounter = tcount;
// clear transfer count zero flag when counter is reloaded
if (tcounter)
status &= ~S_TC0;
}
switch(c) { switch(c) {
case CM_NOP: case CM_NOP:
command_pop_and_chain(); command_pop_and_chain();
@ -823,8 +856,7 @@ READ8_MEMBER(ncr5390_device::status_r)
uint32_t ctrl = scsi_bus->ctrl_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); 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()); logerror("%s: status_r %02x (%s)\n", tag(), res, machine().describe_context());
if(irq)
status &= ~(S_GROSS_ERROR|S_PARITY|S_TCC);
return res; return res;
} }
@ -837,8 +869,13 @@ WRITE8_MEMBER(ncr5390_device::bus_id_w)
READ8_MEMBER(ncr5390_device::istatus_r) READ8_MEMBER(ncr5390_device::istatus_r)
{ {
uint8_t res = istatus; uint8_t res = istatus;
istatus = 0;
seq = 0; if (irq)
{
status &= ~(S_GROSS_ERROR | S_PARITY | S_TCC);
istatus = 0;
seq = 0;
}
check_irq(); check_irq();
if(res) if(res)
command_pop_and_chain(); command_pop_and_chain();
@ -902,16 +939,16 @@ WRITE8_MEMBER(ncr5390_device::clock_w)
void ncr5390_device::dma_set(int dir) void ncr5390_device::dma_set(int dir)
{ {
dma_dir = 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(); drq_set();
} }
void ncr5390_device::dma_w(uint8_t val) void ncr5390_device::dma_w(uint8_t val)
{ {
fifo_push(val); fifo_push(val);
tcounter--; if(fifo_pos == 16)
if(fifo_pos == 16 || tcounter == 0)
drq_clear(); drq_clear();
step(false);
} }
uint8_t ncr5390_device::dma_r() uint8_t ncr5390_device::dma_r()
@ -919,11 +956,7 @@ uint8_t ncr5390_device::dma_r()
uint8_t r = fifo_pop(); uint8_t r = fifo_pop();
if(!fifo_pos) if(!fifo_pos)
drq_clear(); drq_clear();
tcounter--; step(false);
if(tcounter == 0) {
status |= S_TC0;
step(false);
}
return r; 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), * 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: * the following are the differences from the 53C90:

View File

@ -112,6 +112,8 @@ protected:
INIT_XFR_RECV_PAD, INIT_XFR_RECV_PAD,
INIT_XFR_RECV_BYTE_ACK, INIT_XFR_RECV_BYTE_ACK,
INIT_XFR_RECV_BYTE_NACK, INIT_XFR_RECV_BYTE_NACK,
INIT_XFR_FUNCTION_COMPLETE,
INIT_XFR_BUS_COMPLETE,
INIT_XFR_WAIT_REQ, INIT_XFR_WAIT_REQ,
INIT_CPT_RECV_BYTE_ACK, INIT_CPT_RECV_BYTE_ACK,
INIT_CPT_RECV_WAIT_REQ, INIT_CPT_RECV_WAIT_REQ,
@ -237,6 +239,8 @@ private:
void delay(int cycles); void delay(int cycles);
void delay_cycles(int cycles); void delay_cycles(int cycles);
void decrement_tcounter();
devcb_write_line m_irq_handler; devcb_write_line m_irq_handler;
devcb_write_line m_drq_handler; devcb_write_line m_drq_handler;
}; };

View File

@ -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", logerror("%s: command INQUIRY lun=%d EVPD=%d page=%d alloc=%02x link=%02x\n",
tag(), tag(),
lun, scsi_cmdbuf[1] & 1, scsi_cmdbuf[2], scsi_cmdbuf[4], scsi_cmdbuf[5]); 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 page = scsi_cmdbuf[2];
int size = scsi_cmdbuf[4]; int size = scsi_cmdbuf[4];
switch(page) { switch(page) {
case 0: case 0:
memset(scsi_cmdbuf, 0, 148); 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[1] = 0x00; // media is not removable
scsi_cmdbuf[2] = 0x05; // device complies with SPC-3 standard scsi_cmdbuf[2] = 0x05; // device complies with SPC-3 standard
scsi_cmdbuf[3] = 0x01; // response data format = CCS scsi_cmdbuf[3] = 0x01; // response data format = CCS