Big SCSI bus update of the day, NCR 5380 too (January 20th, 2025)

1. Separate the SCSI bus functions from NCR 5380 into true general purpose SCSI bus functions, allowing use of future legacy scsi controllers.
2. Corrected NCR 5380 chip period for the SCSI controllers based on that chip so that CD-ROM speed is correct enough per speed tests and no more breakage (I hope, report if they are still there, please!) on desyncs.
3. A NCR 5380 software reset involves asserting an IRQ.
This commit is contained in:
TC1995 2025-01-20 19:55:18 +01:00
parent 3dea388ae4
commit 4008010131
7 changed files with 546 additions and 482 deletions

View file

@ -333,6 +333,20 @@
#define BUS_IDLE (1 << 31) #define BUS_IDLE (1 << 31)
#define STATE_IDLE 0
#define STATE_COMMAND 1
#define STATE_DATAIN 2
#define STATE_DATAOUT 3
#define STATE_STATUS 4
#define STATE_MESSAGEIN 5
#define STATE_SELECT 6
#define STATE_MESSAGEOUT 7
#define STATE_MESSAGE_ID 8
#define PIO_TX_BUS 0
#define DMA_IN_TX_BUS 1
#define DMA_OUT_TX_BUS 2
#define PHASE_IDLE 0x00 #define PHASE_IDLE 0x00
#define PHASE_COMMAND 0x01 #define PHASE_COMMAND 0x01
#define PHASE_DATA_IN 0x02 #define PHASE_DATA_IN 0x02
@ -420,6 +434,36 @@ typedef struct scsi_device_t {
void (*command_stop)(scsi_common_t *sc); void (*command_stop)(scsi_common_t *sc);
} scsi_device_t; } scsi_device_t;
typedef struct scsi_bus_t {
int tx_mode;
int clear_req;
int wait_data;
int wait_complete;
int bus_out;
int bus_in;
int command_pos;
int command_issued;
int data_pos;
int msgout_pos;
int is_msgout;
int state;
int dma_on_pio_enabled;
uint8_t data;
uint8_t msglun;
uint8_t data_wait;
uint8_t command[16];
uint8_t msgout[4];
uint8_t target_id;
uint8_t bus_device;
uint32_t bus_phase;
double period;
double speed;
double divider;
double multi;
void *priv;
void (*timer)(void *priv, double period);
} scsi_bus_t;
/* These are based on the INQUIRY values. */ /* These are based on the INQUIRY values. */
#define SCSI_NONE 0x0060 #define SCSI_NONE 0x0060
#define SCSI_FIXED_DISK 0x0000 #define SCSI_FIXED_DISK 0x0000
@ -454,6 +498,8 @@ extern void scsi_device_init(void);
extern void scsi_reset(void); extern void scsi_reset(void);
extern uint8_t scsi_get_bus(void); extern uint8_t scsi_get_bus(void);
extern int scsi_bus_read(scsi_bus_t *scsi_bus);
extern void scsi_bus_update(scsi_bus_t *scsi_bus, int bus);
extern void scsi_bus_set_speed(uint8_t bus, double speed); extern void scsi_bus_set_speed(uint8_t bus, double speed);
extern double scsi_bus_get_speed(uint8_t bus); extern double scsi_bus_get_speed(uint8_t bus);

View file

@ -44,6 +44,9 @@
#define ICR_ACK 0x10 #define ICR_ACK 0x10
#define ICR_ARB_LOST 0x20 #define ICR_ARB_LOST 0x20
#define ICR_ARB_IN_PROGRESS 0x40 #define ICR_ARB_IN_PROGRESS 0x40
#define ICR_RST 0x80
#define ICR_PHASE 0x9e
#define ICR_WRITE 0x9f
#define MODE_ARBITRATE 0x01 #define MODE_ARBITRATE 0x01
#define MODE_DMA 0x02 #define MODE_DMA 0x02
@ -63,70 +66,33 @@
#define TCR_REQ 0x08 #define TCR_REQ 0x08
#define TCR_LAST_BYTE_SENT 0x80 #define TCR_LAST_BYTE_SENT 0x80
#define STATE_IDLE 0
#define STATE_COMMAND 1
#define STATE_DATAIN 2
#define STATE_DATAOUT 3
#define STATE_STATUS 4
#define STATE_MESSAGEIN 5
#define STATE_SELECT 6
#define STATE_MESSAGEOUT 7
#define STATE_MESSAGE_ID 8
#define DMA_IDLE 0
#define DMA_SEND 1
#define DMA_INITIATOR_RECEIVE 2
typedef struct ncr_t { typedef struct ncr_t {
uint8_t icr; uint8_t icr;
uint8_t mode; uint8_t mode;
uint8_t tcr; uint8_t tcr;
uint8_t data_wait;
uint8_t isr; uint8_t isr;
uint8_t output_data; uint8_t output_data;
uint8_t target_id;
uint8_t tx_data; uint8_t tx_data;
uint8_t msglun;
uint8_t irq_state; uint8_t irq_state;
uint8_t command[20];
uint8_t msgout[4];
uint8_t bus; uint8_t bus;
int msgout_pos;
int is_msgout;
int dma_mode;
int cur_bus;
int bus_in;
int new_phase;
int state;
int clear_req;
int wait_data;
int wait_data_back;
int wait_complete;
int command_pos;
int data_pos;
int irq; int irq;
double period; double period;
void *priv; void *priv;
void (*dma_mode_ext)(void *priv, void *ext_priv); void (*dma_mode_ext)(void *priv, void *ext_priv, uint8_t val);
int (*dma_send_ext)(void *priv, void *ext_priv); int (*dma_send_ext)(void *priv, void *ext_priv);
int (*dma_initiator_receive_ext)(void *priv, void *ext_priv); int (*dma_initiator_receive_ext)(void *priv, void *ext_priv);
void (*timer)(void *ext_priv, double period); void (*timer)(void *ext_priv, double period);
scsi_bus_t scsibus;
} ncr_t; } ncr_t;
extern int ncr5380_cmd_len[8];
extern void ncr5380_irq(ncr_t *ncr, int set_irq); extern void ncr5380_irq(ncr_t *ncr, int set_irq);
extern void ncr5380_set_irq(ncr_t *ncr, int irq); extern void ncr5380_set_irq(ncr_t *ncr, int irq);
extern uint32_t ncr5380_get_bus_host(ncr_t *ncr); extern uint32_t ncr5380_get_bus_host(ncr_t *ncr);
extern void ncr5380_bus_read(ncr_t *ncr);
extern void ncr5380_bus_update(ncr_t *ncr, int bus);
extern void ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr); extern void ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr);
extern uint8_t ncr5380_read(uint16_t port, ncr_t *ncr); extern uint8_t ncr5380_read(uint16_t port, ncr_t *ncr);

View file

@ -16,10 +16,14 @@
* Copyright 2016-2018 Miran Grca. * Copyright 2016-2018 Miran Grca.
* Copyright 2017-2018 Fred N. van Kempen. * Copyright 2017-2018 Fred N. van Kempen.
*/ */
#include <inttypes.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <wchar.h> #include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h> #include <86box/86box.h>
#include <86box/device.h> #include <86box/device.h>
#include <86box/hdd.h> #include <86box/hdd.h>
@ -29,9 +33,29 @@
#include <86box/plat_unused.h> #include <86box/plat_unused.h>
scsi_device_t scsi_devices[SCSI_BUS_MAX][SCSI_ID_MAX]; scsi_device_t scsi_devices[SCSI_BUS_MAX][SCSI_ID_MAX];
int scsi_command_length[8] = { 6, 10, 10, 6, 16, 12, 10, 6 };
uint8_t scsi_null_device_sense[18] = { 0x70, 0, SENSE_ILLEGAL_REQUEST, 0, 0, 0, 0, 0, 0, 0, 0, 0, ASC_INV_LUN, 0, 0, 0, 0, 0 }; uint8_t scsi_null_device_sense[18] = { 0x70, 0, SENSE_ILLEGAL_REQUEST, 0, 0, 0, 0, 0, 0, 0, 0, 0, ASC_INV_LUN, 0, 0, 0, 0, 0 };
#define SET_BUS_STATE(scsi_bus, state) scsi_bus->bus_out = (scsi_bus->bus_out & ~(SCSI_PHASE_MESSAGE_IN)) | (state & (SCSI_PHASE_MESSAGE_IN))
#ifdef ENABLE_SCSI_DEVICE_LOG
int scsi_device_do_log = ENABLE_SCSI_DEVICE_LOG;
static void
scsi_device_log(const char *fmt, ...)
{
va_list ap;
if (scsi_device_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define scsi_device_log(fmt, ...)
#endif
static uint8_t static uint8_t
scsi_device_target_command(scsi_device_t *dev, uint8_t *cdb) scsi_device_target_command(scsi_device_t *dev, uint8_t *cdb)
{ {
@ -189,3 +213,311 @@ scsi_device_init(void)
} }
} }
} }
int
scsi_device_get_id(uint8_t data)
{
for (uint8_t c = 0; c < SCSI_ID_MAX; c++) {
if (data & (1 << c))
return c;
}
return -1;
}
static int
scsi_device_get_msg(uint8_t *msgp, int len)
{
uint8_t msg = msgp[0];
if ((msg == 0) || ((msg >= 0x02) && (msg <= 0x1f)) || (msg >= 0x80))
return 1;
if ((msg >= 0x20) && (msg <= 0x2f))
return 2;
if (len < 2)
return 3;
return msgp[1];
}
int
scsi_bus_read(scsi_bus_t *scsi_bus)
{
scsi_device_t *dev;
int phase;
/*Wait processes to handle bus requests*/
if (scsi_bus->clear_req) {
scsi_bus->clear_req--;
if (!scsi_bus->clear_req) {
scsi_device_log("Prelude to command data\n");
SET_BUS_STATE(scsi_bus, scsi_bus->bus_phase);
scsi_bus->bus_out |= BUS_REQ;
}
}
if (scsi_bus->wait_data) {
scsi_bus->wait_data--;
if (!scsi_bus->wait_data) {
dev = &scsi_devices[scsi_bus->bus_device][scsi_bus->target_id];
SET_BUS_STATE(scsi_bus, scsi_bus->bus_phase);
phase = scsi_bus->bus_out & SCSI_PHASE_MESSAGE_IN;
switch (phase) {
case SCSI_PHASE_DATA_IN:
scsi_device_log("DataIn.\n");
scsi_bus->state = STATE_DATAIN;
if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL))
scsi_bus->data = dev->sc->temp_buffer[scsi_bus->data_pos++];
scsi_bus->bus_out = (scsi_bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(scsi_bus->data) | BUS_DBP;
break;
case SCSI_PHASE_DATA_OUT:
if (scsi_bus->bus_phase & BUS_IDLE) {
scsi_device_log("Bus Idle.\n");
scsi_bus->state = STATE_IDLE;
scsi_bus->bus_out &= ~BUS_BSY;
scsi_bus->timer(scsi_bus->priv, 0.0);
} else {
scsi_device_log("DataOut.\n");
scsi_bus->state = STATE_DATAOUT;
}
break;
case SCSI_PHASE_STATUS:
scsi_device_log("Status.\n");
scsi_bus->bus_out |= BUS_REQ;
scsi_bus->state = STATE_STATUS;
scsi_bus->bus_out = (scsi_bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(dev->status) | BUS_DBP;
break;
case SCSI_PHASE_MESSAGE_IN:
scsi_device_log("Message In.\n");
scsi_bus->state = STATE_MESSAGEIN;
scsi_bus->bus_out = (scsi_bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(0) | BUS_DBP;
break;
case SCSI_PHASE_MESSAGE_OUT:
scsi_device_log("Message Out.\n");
scsi_bus->bus_out |= BUS_REQ;
scsi_bus->state = STATE_MESSAGEOUT;
scsi_bus->bus_out = (scsi_bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(scsi_bus->target_id >> 5) | BUS_DBP;
break;
default:
break;
}
}
}
if (scsi_bus->wait_complete) {
scsi_bus->wait_complete--;
if (!scsi_bus->wait_complete)
scsi_bus->bus_out |= BUS_REQ;
}
return scsi_bus->bus_out;
}
void
scsi_bus_update(scsi_bus_t *scsi_bus, int bus)
{
scsi_device_t *dev = &scsi_devices[scsi_bus->bus_device][scsi_bus->target_id];
double p;
uint8_t sel_data;
int msglen;
/*Start the SCSI command layer, which will also make the timings*/
if (bus & BUS_ARB)
scsi_bus->state = STATE_IDLE;
scsi_device_log("State = %i\n", scsi_bus->state);
switch (scsi_bus->state) {
case STATE_IDLE:
scsi_bus->clear_req = scsi_bus->wait_data = scsi_bus->wait_complete = 0;
if ((bus & BUS_SEL) && !(bus & BUS_BSY)) {
sel_data = BUS_GETDATA(bus);
scsi_bus->target_id = scsi_device_get_id(sel_data);
/*Once the device has been found and selected, mark it as busy*/
if ((scsi_bus->target_id != (uint8_t) -1) && scsi_device_present(&scsi_devices[scsi_bus->bus_device][scsi_bus->target_id])) {
scsi_bus->bus_out |= BUS_BSY;
scsi_bus->state = STATE_SELECT;
scsi_device_log("Select - target ID = %i, moving to state = %d.\n", scsi_bus->target_id, scsi_bus->state);
} else {
scsi_device_log("Device not found at ID %i, Current Bus BSY=%02x\n", scsi_bus->target_id, scsi_bus->bus_out);
scsi_bus->bus_out = 0;
}
}
break;
case STATE_SELECT:
if (!(bus & BUS_SEL)) {
if (!(bus & BUS_ATN)) {
if ((scsi_bus->target_id != (uint8_t) -1) && scsi_device_present(&scsi_devices[scsi_bus->bus_device][scsi_bus->target_id])) {
scsi_device_log("Device found at ID %i, Current Bus BSY=%02x\n", scsi_bus->target_id, scsi_bus->bus_out);
scsi_bus->state = STATE_COMMAND;
scsi_bus->bus_out = BUS_BSY | BUS_REQ;
scsi_bus->command_pos = 0;
SET_BUS_STATE(scsi_bus, SCSI_PHASE_COMMAND);
} else {
scsi_device_log("Device not found at ID %i again.\n", scsi_bus->target_id);
scsi_bus->state = STATE_IDLE;
scsi_bus->bus_out = 0;
}
} else {
scsi_device_log("Set to SCSI Message Out\n");
scsi_bus->bus_phase = SCSI_PHASE_MESSAGE_OUT;
scsi_bus->wait_data = 4;
scsi_bus->msgout_pos = 0;
scsi_bus->is_msgout = 1;
}
}
break;
case STATE_COMMAND:
if ((bus & BUS_ACK) && !(scsi_bus->bus_in & BUS_ACK)) {
/*Write command byte to the output data register*/
scsi_bus->command[scsi_bus->command_pos++] = BUS_GETDATA(bus);
scsi_bus->clear_req = 3;
scsi_bus->bus_phase = scsi_bus->bus_out & SCSI_PHASE_MESSAGE_IN;
scsi_bus->bus_out &= ~BUS_REQ;
scsi_device_log("Command pos=%i, output data=%02x\n", scsi_bus->command_pos, BUS_GETDATA(bus));
if (scsi_bus->command_pos == scsi_command_length[(scsi_bus->command[0] >> 5) & 7]) {
if (scsi_bus->is_msgout) {
scsi_bus->is_msgout = 0;
#if 0
scsi_bus->command[1] = (scsi_bus->command[1] & 0x1f) | (scsi_bus->msglun << 5);
#endif
}
/*Reset data position to default*/
scsi_bus->data_pos = 0;
dev = &scsi_devices[scsi_bus->bus_device][scsi_bus->target_id];
scsi_device_log("SCSI Command 0x%02X for ID %d, status code=%02x\n", scsi_bus->command[0], scsi_bus->target_id, dev->status);
dev->buffer_length = -1;
scsi_device_command_phase0(dev, scsi_bus->command);
scsi_device_log("SCSI ID %i: Command %02X: Buffer Length %i, SCSI Phase %02X\n", scsi_bus->target_id, scsi_bus->command[0], dev->buffer_length, dev->phase);
scsi_bus->period = 1.0;
scsi_bus->wait_data = 4;
scsi_bus->data_wait = 0;
scsi_bus->command_issued = 1;
if (dev->status == SCSI_STATUS_OK) {
/*If the SCSI phase is Data In or Data Out, allocate the SCSI buffer based on the transfer length of the command*/
if (dev->buffer_length && ((dev->phase == SCSI_PHASE_DATA_IN) || (dev->phase == SCSI_PHASE_DATA_OUT))) {
p = scsi_device_get_callback(dev);
scsi_bus->period = (p > 0.0) ? ((p / scsi_bus->divider) * scsi_bus->multi) : (((double) dev->buffer_length) * scsi_bus->speed);
scsi_device_log("SCSI ID %i: command 0x%02x for p = %lf, update = %lf, len = %i, dmamode = %x\n", scsi_bus->target_id, scsi_bus->command[0], scsi_device_get_callback(dev), scsi_bus->period, dev->buffer_length, scsi_bus->tx_mode);
}
}
scsi_bus->bus_phase = dev->phase;
}
}
break;
case STATE_DATAIN:
dev = &scsi_devices[scsi_bus->bus_device][scsi_bus->target_id];
if ((bus & BUS_ACK) && !(scsi_bus->bus_in & BUS_ACK)) {
if (scsi_bus->data_pos >= dev->buffer_length) {
scsi_bus->bus_out &= ~BUS_REQ;
scsi_device_command_phase1(dev);
scsi_bus->bus_phase = SCSI_PHASE_STATUS;
scsi_bus->wait_data = 4;
scsi_bus->wait_complete = 8;
} else {
if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL))
scsi_bus->data = dev->sc->temp_buffer[scsi_bus->data_pos++];
scsi_device_log("TXMode DataIn=%x, cmd=%02x.\n", scsi_bus->tx_mode, scsi_bus->command[0]);
scsi_bus->bus_out = (scsi_bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(scsi_bus->data) | BUS_DBP | BUS_REQ;
if (scsi_bus->tx_mode == PIO_TX_BUS) { /*If a data in command that is not read 6/10 has been issued*/
scsi_device_log("DMA mode idle IN=%d.\n", scsi_bus->data_pos);
scsi_bus->data_wait |= 1;
scsi_bus->timer(scsi_bus->priv, scsi_bus->period);
} else {
scsi_device_log("DMA mode IN=%d.\n", scsi_bus->data_pos);
scsi_bus->clear_req = 3;
}
scsi_bus->bus_out &= ~BUS_REQ;
scsi_bus->bus_phase = SCSI_PHASE_DATA_IN;
}
}
break;
case STATE_DATAOUT:
dev = &scsi_devices[scsi_bus->bus_device][scsi_bus->target_id];
if ((bus & BUS_ACK) && !(scsi_bus->bus_in & BUS_ACK)) {
if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL))
dev->sc->temp_buffer[scsi_bus->data_pos++] = BUS_GETDATA(bus);
if (scsi_bus->data_pos >= dev->buffer_length) {
scsi_bus->bus_out &= ~BUS_REQ;
scsi_device_command_phase1(dev);
scsi_bus->bus_phase = SCSI_PHASE_STATUS;
scsi_bus->wait_data = 4;
scsi_bus->wait_complete = 8;
} else {
/*More data is to be transferred, place a request*/
if (scsi_bus->tx_mode == PIO_TX_BUS) { /*If a data in command that is not write 6/10 has been issued*/
scsi_device_log("DMA mode idle OUT=%d.\n", scsi_bus->data_pos);
scsi_bus->data_wait |= 1;
scsi_bus->timer(scsi_bus->priv, scsi_bus->period);
scsi_bus->bus_out &= ~BUS_REQ;
} else {
scsi_device_log("DMA mode OUT=%d.\n", scsi_bus->data_pos);
scsi_bus->bus_out |= BUS_REQ;
}
}
}
break;
case STATE_STATUS:
if ((bus & BUS_ACK) && !(scsi_bus->bus_in & BUS_ACK)) {
/*All transfers done, wait until next transfer*/
scsi_device_identify(&scsi_devices[scsi_bus->bus_device][scsi_bus->target_id], SCSI_LUN_USE_CDB);
scsi_bus->bus_out &= ~BUS_REQ;
scsi_bus->bus_phase = SCSI_PHASE_MESSAGE_IN;
scsi_bus->wait_data = 4;
scsi_bus->wait_complete = 8;
scsi_bus->command_issued = 0;
}
break;
case STATE_MESSAGEIN:
if ((bus & BUS_ACK) && !(scsi_bus->bus_in & BUS_ACK)) {
scsi_bus->bus_out &= ~BUS_REQ;
scsi_bus->bus_phase = BUS_IDLE;
scsi_bus->wait_data = 4;
}
break;
case STATE_MESSAGEOUT:
if ((bus & BUS_ACK) && !(scsi_bus->bus_in & BUS_ACK)) {
scsi_bus->msgout[scsi_bus->msgout_pos++] = BUS_GETDATA(bus);
msglen = scsi_device_get_msg(scsi_bus->msgout, scsi_bus->msgout_pos);
if (scsi_bus->msgout_pos >= msglen) {
if ((scsi_bus->msgout[0] & (0x80 | 0x20)) == 0x80)
scsi_bus->msglun = scsi_bus->msgout[0] & 7;
scsi_bus->bus_out &= ~BUS_REQ;
scsi_bus->state = STATE_MESSAGE_ID;
}
}
break;
case STATE_MESSAGE_ID:
if ((scsi_bus->target_id != (uint8_t) -1) && scsi_device_present(&scsi_devices[scsi_bus->bus_device][scsi_bus->target_id])) {
scsi_device_log("Device found at ID %i on MSGOUT, Current Bus BSY=%02x\n", scsi_bus->target_id, scsi_bus->bus_out);
scsi_device_identify(&scsi_devices[scsi_bus->bus_device][scsi_bus->target_id], scsi_bus->msglun);
scsi_bus->state = STATE_COMMAND;
scsi_bus->bus_out = BUS_BSY | BUS_REQ;
scsi_bus->command_pos = 0;
SET_BUS_STATE(scsi_bus, SCSI_PHASE_COMMAND);
}
break;
default:
break;
}
scsi_bus->bus_in = bus;
}

View file

@ -42,8 +42,6 @@
#include <86box/scsi_device.h> #include <86box/scsi_device.h>
#include <86box/scsi_ncr5380.h> #include <86box/scsi_ncr5380.h>
int ncr5380_cmd_len[8] = { 6, 10, 10, 6, 16, 12, 10, 6 };
#ifdef ENABLE_NCR5380_LOG #ifdef ENABLE_NCR5380_LOG
int ncr5380_do_log = ENABLE_NCR5380_LOG; int ncr5380_do_log = ENABLE_NCR5380_LOG;
@ -62,8 +60,6 @@ ncr5380_log(const char *fmt, ...)
# define ncr5380_log(fmt, ...) # define ncr5380_log(fmt, ...)
#endif #endif
#define SET_BUS_STATE(ncr, state) ncr->cur_bus = (ncr->cur_bus & ~(SCSI_PHASE_MESSAGE_IN)) | (state & (SCSI_PHASE_MESSAGE_IN))
void void
ncr5380_irq(ncr_t *ncr, int set_irq) ncr5380_irq(ncr_t *ncr, int set_irq)
{ {
@ -86,45 +82,15 @@ ncr5380_set_irq(ncr_t *ncr, int irq)
ncr->irq = irq; ncr->irq = irq;
} }
static int
ncr5380_get_dev_id(uint8_t data)
{
for (uint8_t c = 0; c < SCSI_ID_MAX; c++) {
if (data & (1 << c))
return c;
}
return -1;
}
static int
ncr5380_getmsglen(uint8_t *msgp, int len)
{
uint8_t msg = msgp[0];
if (msg == 0 || (msg >= 0x02 && msg <= 0x1f) || msg >= 0x80)
return 1;
if (msg >= 0x20 && msg <= 0x2f)
return 2;
if (len < 2)
return 3;
return msgp[1];
}
static void static void
ncr5380_reset(ncr_t *ncr) ncr5380_reset(ncr_t *ncr)
{ {
ncr->command_pos = 0; scsi_bus_t *scsi_bus = &ncr->scsibus;
ncr->data_pos = 0;
ncr->state = STATE_IDLE;
ncr->clear_req = 0;
ncr->cur_bus = 0;
ncr->tx_data = 0;
ncr->output_data = 0; ncr->output_data = 0;
ncr->data_wait = 0;
ncr->mode = 0; ncr->mode = 0;
ncr->tcr = 0; ncr->tcr = 0;
ncr->icr = 0; ncr->icr = 0;
ncr->dma_mode = DMA_IDLE;
ncr5380_log("NCR Reset\n"); ncr5380_log("NCR Reset\n");
ncr->timer(ncr->priv, 0.0); ncr->timer(ncr->priv, 0.0);
@ -132,6 +98,17 @@ ncr5380_reset(ncr_t *ncr)
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
scsi_device_reset(&scsi_devices[ncr->bus][i]); scsi_device_reset(&scsi_devices[ncr->bus][i]);
scsi_bus->state = STATE_IDLE;
scsi_bus->clear_req = 0;
scsi_bus->wait_complete = 0;
scsi_bus->wait_data = 0;
scsi_bus->bus_in = 0;
scsi_bus->bus_out = 0;
scsi_bus->command_pos = 0;
scsi_bus->data_wait = 0;
scsi_bus->data = 0;
scsi_bus->command_issued = 0;
ncr5380_irq(ncr, 0); ncr5380_irq(ncr, 0);
} }
@ -173,280 +150,10 @@ ncr5380_get_bus_host(ncr_t *ncr)
return (bus_host | BUS_SETDATA(ncr->output_data)); return (bus_host | BUS_SETDATA(ncr->output_data));
} }
void
ncr5380_bus_read(ncr_t *ncr)
{
const scsi_device_t *dev;
int phase;
/*Wait processes to handle bus requests*/
if (ncr->clear_req) {
ncr->clear_req--;
if (!ncr->clear_req) {
ncr5380_log("Prelude to command data\n");
SET_BUS_STATE(ncr, ncr->new_phase);
ncr->cur_bus |= BUS_REQ;
}
}
if (ncr->wait_data) {
ncr->wait_data--;
if (!ncr->wait_data) {
dev = &scsi_devices[ncr->bus][ncr->target_id];
SET_BUS_STATE(ncr, ncr->new_phase);
phase = (ncr->cur_bus & SCSI_PHASE_MESSAGE_IN);
if (phase == SCSI_PHASE_DATA_IN) {
if ((ncr->dma_mode == DMA_IDLE) || ncr->dma_initiator_receive_ext || (ncr->wait_data_back == 1)) {
ncr5380_log("Phase Data In.\n");
if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL))
ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++];
ncr->state = STATE_DATAIN;
ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP;
}
} else if (phase == SCSI_PHASE_DATA_OUT) {
if (ncr->new_phase & BUS_IDLE) {
ncr->state = STATE_IDLE;
ncr->cur_bus &= ~BUS_BSY;
} else {
if ((ncr->dma_mode == DMA_IDLE) || ncr->dma_send_ext || (ncr->wait_data_back == 1))
ncr->state = STATE_DATAOUT;
}
} else if (phase == SCSI_PHASE_STATUS) {
ncr5380_log("Phase Status.\n");
ncr->wait_data_back = 0;
ncr->cur_bus |= BUS_REQ;
ncr->state = STATE_STATUS;
ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(dev->status) | BUS_DBP;
} else if (phase == SCSI_PHASE_MESSAGE_IN) {
ncr5380_log("Phase Message In.\n");
ncr->state = STATE_MESSAGEIN;
ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(0) | BUS_DBP;
} else if (phase == SCSI_PHASE_MESSAGE_OUT) {
ncr->cur_bus |= BUS_REQ;
ncr->state = STATE_MESSAGEOUT;
ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->target_id >> 5) | BUS_DBP;
}
}
}
if (ncr->wait_complete) {
ncr->wait_complete--;
if (!ncr->wait_complete)
ncr->cur_bus |= BUS_REQ;
}
}
void
ncr5380_bus_update(ncr_t *ncr, int bus)
{
scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id];
double p;
uint8_t sel_data;
int msglen;
/*Start the SCSI command layer, which will also make the timings*/
if (bus & BUS_ARB)
ncr->state = STATE_IDLE;
ncr5380_log("State = %i\n", ncr->state);
switch (ncr->state) {
case STATE_IDLE:
ncr->clear_req = ncr->wait_data = ncr->wait_complete = 0;
if ((bus & BUS_SEL) && !(bus & BUS_BSY)) {
ncr5380_log("Selection phase\n");
sel_data = BUS_GETDATA(bus);
ncr->target_id = ncr5380_get_dev_id(sel_data);
ncr5380_log("Select - target ID = %i\n", ncr->target_id);
/*Once the device has been found and selected, mark it as busy*/
if ((ncr->target_id != (uint8_t) -1) && scsi_device_present(&scsi_devices[ncr->bus][ncr->target_id])) {
ncr->cur_bus |= BUS_BSY;
ncr->state = STATE_SELECT;
} else {
ncr5380_log("Device not found at ID %i, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus);
ncr->cur_bus = 0;
}
}
break;
case STATE_SELECT:
if (!(bus & BUS_SEL)) {
if (!(bus & BUS_ATN)) {
if ((ncr->target_id != (uint8_t) -1) && scsi_device_present(&scsi_devices[ncr->bus][ncr->target_id])) {
ncr5380_log("Device found at ID %i, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus);
ncr->state = STATE_COMMAND;
ncr->cur_bus = BUS_BSY | BUS_REQ;
ncr5380_log("CurBus BSY|REQ=%02x\n", ncr->cur_bus);
ncr->command_pos = 0;
SET_BUS_STATE(ncr, SCSI_PHASE_COMMAND);
} else {
ncr->state = STATE_IDLE;
ncr->cur_bus = 0;
}
} else {
ncr5380_log("Set to SCSI Message Out\n");
ncr->new_phase = SCSI_PHASE_MESSAGE_OUT;
ncr->wait_data = 4;
ncr->msgout_pos = 0;
ncr->is_msgout = 1;
}
}
break;
case STATE_COMMAND:
if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) {
/*Write command byte to the output data register*/
ncr->command[ncr->command_pos++] = BUS_GETDATA(bus);
ncr->clear_req = 3;
ncr->new_phase = ncr->cur_bus & SCSI_PHASE_MESSAGE_IN;
ncr->cur_bus &= ~BUS_REQ;
ncr5380_log("Command pos=%i, output data=%02x\n", ncr->command_pos, BUS_GETDATA(bus));
if (ncr->command_pos == ncr5380_cmd_len[(ncr->command[0] >> 5) & 7]) {
if (ncr->is_msgout) {
ncr->is_msgout = 0;
#if 0
ncr->command[1] = (ncr->command[1] & 0x1f) | (ncr->msglun << 5);
#endif
}
/*Reset data position to default*/
ncr->data_pos = 0;
dev = &scsi_devices[ncr->bus][ncr->target_id];
ncr5380_log("SCSI Command 0x%02X for ID %d, status code=%02x\n", ncr->command[0], ncr->target_id, dev->status);
dev->buffer_length = -1;
scsi_device_command_phase0(dev, ncr->command);
ncr5380_log("SCSI ID %i: Command %02X: Buffer Length %i, SCSI Phase %02X\n", ncr->target_id, ncr->command[0], dev->buffer_length, dev->phase);
ncr->period = 1.0;
ncr->wait_data = 4;
ncr->data_wait = 0;
if (dev->status == SCSI_STATUS_OK) {
/*If the SCSI phase is Data In or Data Out, allocate the SCSI buffer based on the transfer length of the command*/
if (dev->buffer_length && ((dev->phase == SCSI_PHASE_DATA_IN) || (dev->phase == SCSI_PHASE_DATA_OUT))) {
p = scsi_device_get_callback(dev);
ncr->period = (p > 0.0) ? p : (((double) dev->buffer_length) * 0.2);
ncr5380_log("SCSI ID %i: command 0x%02x for p = %lf, update = %lf, len = %i, dmamode = %x\n", ncr->target_id, ncr->command[0], scsi_device_get_callback(dev), ncr->period, dev->buffer_length, ncr->dma_mode);
}
}
ncr->new_phase = dev->phase;
}
}
break;
case STATE_DATAIN:
dev = &scsi_devices[ncr->bus][ncr->target_id];
if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) {
if (ncr->data_pos >= dev->buffer_length) {
ncr->cur_bus &= ~BUS_REQ;
ncr5380_log("CMD Phase1 DataIn.\n");
scsi_device_command_phase1(dev);
ncr->new_phase = SCSI_PHASE_STATUS;
ncr->wait_data = 4;
ncr->wait_complete = 8;
} else {
if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL))
ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++];
ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ;
if (ncr->dma_mode == DMA_IDLE) { /*If a data in command that is not read 6/10 has been issued*/
ncr->data_wait |= 1;
ncr5380_log("DMA mode idle IN=%d.\n", ncr->data_pos);
ncr->timer(ncr->priv, ncr->period);
} else {
ncr5380_log("DMA mode IN=%d.\n", ncr->data_pos);
ncr->clear_req = 3;
}
ncr->cur_bus &= ~BUS_REQ;
ncr->new_phase = SCSI_PHASE_DATA_IN;
}
}
break;
case STATE_DATAOUT:
dev = &scsi_devices[ncr->bus][ncr->target_id];
if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) {
if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL))
dev->sc->temp_buffer[ncr->data_pos++] = BUS_GETDATA(bus);
if (ncr->data_pos >= dev->buffer_length) {
ncr->cur_bus &= ~BUS_REQ;
scsi_device_command_phase1(dev);
ncr->new_phase = SCSI_PHASE_STATUS;
ncr->wait_data = 4;
ncr->wait_complete = 8;
} else {
/*More data is to be transferred, place a request*/
if (ncr->dma_mode == DMA_IDLE) { /*If a data out command that is not write 6/10 has been issued*/
ncr->data_wait |= 1;
ncr5380_log("DMA mode idle out\n");
ncr->timer(ncr->priv, ncr->period);
} else
ncr->clear_req = 3;
ncr->cur_bus &= ~BUS_REQ;
ncr5380_log("CurBus ~REQ_DataOut=%02x\n", ncr->cur_bus);
}
}
break;
case STATE_STATUS:
if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) {
/*All transfers done, wait until next transfer*/
scsi_device_identify(&scsi_devices[ncr->bus][ncr->target_id], SCSI_LUN_USE_CDB);
ncr->cur_bus &= ~BUS_REQ;
ncr->new_phase = SCSI_PHASE_MESSAGE_IN;
ncr->wait_data = 4;
ncr->wait_complete = 8;
}
break;
case STATE_MESSAGEIN:
if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) {
ncr->cur_bus &= ~BUS_REQ;
ncr->new_phase = BUS_IDLE;
ncr->wait_data = 4;
}
break;
case STATE_MESSAGEOUT:
ncr5380_log("Ack on MSGOUT = %02x\n", (bus & BUS_ACK));
if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) {
ncr->msgout[ncr->msgout_pos++] = BUS_GETDATA(bus);
msglen = ncr5380_getmsglen(ncr->msgout, ncr->msgout_pos);
if (ncr->msgout_pos >= msglen) {
if ((ncr->msgout[0] & (0x80 | 0x20)) == 0x80)
ncr->msglun = ncr->msgout[0] & 7;
ncr->cur_bus &= ~BUS_REQ;
ncr->state = STATE_MESSAGE_ID;
}
}
break;
case STATE_MESSAGE_ID:
if ((ncr->target_id != (uint8_t) -1) && scsi_device_present(&scsi_devices[ncr->bus][ncr->target_id])) {
ncr5380_log("Device found at ID %i on MSGOUT, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus);
scsi_device_identify(&scsi_devices[ncr->bus][ncr->target_id], ncr->msglun);
ncr->state = STATE_COMMAND;
ncr->cur_bus = BUS_BSY | BUS_REQ;
ncr5380_log("CurBus BSY|REQ=%02x\n", ncr->cur_bus);
ncr->command_pos = 0;
SET_BUS_STATE(ncr, SCSI_PHASE_COMMAND);
}
break;
default:
break;
}
ncr->bus_in = bus;
}
void void
ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr) ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr)
{ {
scsi_bus_t *scsi_bus = &ncr->scsibus;
int bus_host = 0; int bus_host = 0;
ncr5380_log("NCR5380 write(%04x,%02x)\n", port & 7, val); ncr5380_log("NCR5380 write(%04x,%02x)\n", port & 7, val);
@ -462,8 +169,10 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr)
if ((val & 0x80) && !(ncr->icr & 0x80)) { if ((val & 0x80) && !(ncr->icr & 0x80)) {
ncr5380_log("Resetting the 5380\n"); ncr5380_log("Resetting the 5380\n");
ncr5380_reset(ncr); ncr5380_reset(ncr);
ncr5380_irq(ncr, 1);
} }
ncr->icr = val; ncr->icr = val;
ncr5380_log("ICR WaitData=%d, ClearReq=%d.\n", scsi_bus->wait_data, scsi_bus->clear_req);
break; break;
case 2: /* Mode register */ case 2: /* Mode register */
@ -472,10 +181,8 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr)
ncr->icr &= ~ICR_ARB_LOST; ncr->icr &= ~ICR_ARB_LOST;
ncr->icr |= ICR_ARB_IN_PROGRESS; ncr->icr |= ICR_ARB_IN_PROGRESS;
} }
ncr->mode = val; ncr->mode = val;
ncr->dma_mode_ext(ncr, ncr->priv, val);
ncr->dma_mode_ext(ncr, ncr->priv);
break; break;
case 3: /* Target Command Register */ case 3: /* Target Command Register */
@ -488,17 +195,17 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr)
break; break;
case 5: /* start DMA Send */ case 5: /* start DMA Send */
ncr5380_log("Write: start DMA send register\n"); pclog("Write: start DMA send register\n");
/*a Write 6/10 has occurred, start the timer when the block count is loaded*/ /*a Write 6/10 has occurred, start the timer when the block count is loaded*/
ncr->dma_mode = DMA_SEND; scsi_bus->tx_mode = DMA_OUT_TX_BUS;
if (ncr->dma_send_ext) if (ncr->dma_send_ext)
ncr->dma_send_ext(ncr, ncr->priv); ncr->dma_send_ext(ncr, ncr->priv);
break; break;
case 7: /* start DMA Initiator Receive */ case 7: /* start DMA Initiator Receive */
ncr5380_log("[%04X:%08X]: Write: start DMA initiator receive register, dma? = %02x\n", CS, cpu_state.pc, ncr->mode & MODE_DMA); ncr5380_log("[%04X:%08X]: Write: start DMA initiator receive register, waitdata=%d, clearreq=%d.\n", CS, cpu_state.pc, scsi_bus->wait_data, scsi_bus->clear_req);
/*a Read 6/10 has occurred, start the timer when the block count is loaded*/ /*a Read 6/10 has occurred, start the timer when the block count is loaded*/
ncr->dma_mode = DMA_INITIATOR_RECEIVE; scsi_bus->tx_mode = DMA_IN_TX_BUS;
if (ncr->dma_initiator_receive_ext) if (ncr->dma_initiator_receive_ext)
ncr->dma_initiator_receive_ext(ncr, ncr->priv); ncr->dma_initiator_receive_ext(ncr, ncr->priv);
break; break;
@ -509,12 +216,13 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr)
} }
bus_host = ncr5380_get_bus_host(ncr); bus_host = ncr5380_get_bus_host(ncr);
ncr5380_bus_update(ncr, bus_host); scsi_bus_update(scsi_bus, bus_host);
} }
uint8_t uint8_t
ncr5380_read(uint16_t port, ncr_t *ncr) ncr5380_read(uint16_t port, ncr_t *ncr)
{ {
scsi_bus_t *scsi_bus = &ncr->scsibus;
uint8_t ret = 0xff; uint8_t ret = 0xff;
int bus; int bus;
int bus_state; int bus_state;
@ -524,12 +232,17 @@ ncr5380_read(uint16_t port, ncr_t *ncr)
ncr5380_log("Read: Current SCSI data register\n"); ncr5380_log("Read: Current SCSI data register\n");
if (ncr->icr & ICR_DBP) { if (ncr->icr & ICR_DBP) {
/*Return the data from the output register if on data bus phase from ICR*/ /*Return the data from the output register if on data bus phase from ICR*/
ret = ncr->output_data; if (scsi_bus->command_issued) {
ncr5380_log("[%04X:%08X]: Data Bus Phase, ret=%02x, clearreq=%d, waitdata=%x.\n", CS, cpu_state.pc, ret, ncr->clear_req, ncr->wait_data); bus = scsi_bus_read(scsi_bus);
ret = BUS_GETDATA(bus);
} else
ret = ncr->output_data;
ncr5380_log("[%04X:%08X]: Data Bus Phase, ret=%02x, clearreq=%d, waitdata=%x, txmode=%x.\n", CS, cpu_state.pc, ret, scsi_bus->clear_req, scsi_bus->wait_data, scsi_bus->tx_mode);
} else { } else {
/*Return the data from the SCSI bus*/ /*Return the data from the SCSI bus*/
ncr5380_bus_read(ncr); bus = scsi_bus_read(scsi_bus);
ret = BUS_GETDATA(ncr->cur_bus); ret = BUS_GETDATA(bus);
ncr5380_log("[%04X:%08X]: NCR Get SCSI bus data=%02x.\n", CS, cpu_state.pc, ret); ncr5380_log("[%04X:%08X]: NCR Get SCSI bus data=%02x.\n", CS, cpu_state.pc, ret);
} }
break; break;
@ -552,15 +265,16 @@ ncr5380_read(uint16_t port, ncr_t *ncr)
case 4: /* Current SCSI Bus status */ case 4: /* Current SCSI Bus status */
ncr5380_log("Read: SCSI bus status register\n"); ncr5380_log("Read: SCSI bus status register\n");
ret = 0; ret = 0;
ncr5380_bus_read(ncr); bus = scsi_bus_read(scsi_bus);
ncr5380_log("NCR cur bus stat=%02x\n", ncr->cur_bus & 0xff); ret |= (bus & 0xff);
ret |= (ncr->cur_bus & 0xff);
if (ncr->icr & ICR_SEL) if (ncr->icr & ICR_SEL)
ret |= BUS_SEL; ret |= BUS_SEL;
if (ncr->icr & ICR_BSY) if (ncr->icr & ICR_BSY)
ret |= BUS_BSY; ret |= BUS_BSY;
// if ((ret & SCSI_PHASE_MESSAGE_IN) == SCSI_PHASE_MESSAGE_IN)
// ret &= ~BUS_REQ; /*Note by TC1995: Horrible hack, I know.*/
(void) scsi_bus_read(scsi_bus);
(void) scsi_bus_read(scsi_bus);
break; break;
case 5: /* Bus and Status register */ case 5: /* Bus and Status register */
@ -571,13 +285,12 @@ ncr5380_read(uint16_t port, ncr_t *ncr)
ncr5380_log("Get host from Interrupt\n"); ncr5380_log("Get host from Interrupt\n");
/*Check if the phase in process matches with TCR's*/ /*Check if the phase in process matches with TCR's*/
if ((bus & SCSI_PHASE_MESSAGE_IN) == (ncr->cur_bus & SCSI_PHASE_MESSAGE_IN)) { if ((bus & SCSI_PHASE_MESSAGE_IN) == (scsi_bus->bus_out & SCSI_PHASE_MESSAGE_IN)) {
ncr5380_log("Phase match\n"); ncr5380_log("Phase match\n");
ret |= STATUS_PHASE_MATCH; ret |= STATUS_PHASE_MATCH;
} }
ncr5380_bus_read(ncr); bus = scsi_bus_read(scsi_bus);
bus = ncr->cur_bus;
if ((bus & BUS_ACK) || (ncr->icr & ICR_ACK)) if ((bus & BUS_ACK) || (ncr->icr & ICR_ACK))
ret |= STATUS_ACK; ret |= STATUS_ACK;
@ -610,8 +323,8 @@ ncr5380_read(uint16_t port, ncr_t *ncr)
case 6: case 6:
ncr5380_log("Read: Input Data.\n"); ncr5380_log("Read: Input Data.\n");
ncr5380_bus_read(ncr); bus = scsi_bus_read(scsi_bus);
ret = BUS_GETDATA(ncr->cur_bus); ret = BUS_GETDATA(bus);
break; break;
case 7: /* reset Parity/Interrupt */ case 7: /* reset Parity/Interrupt */

View file

@ -121,7 +121,8 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv)
{ {
ncr53c400_t *ncr400 = (ncr53c400_t *) priv; ncr53c400_t *ncr400 = (ncr53c400_t *) priv;
ncr_t *ncr = &ncr400->ncr; ncr_t *ncr = &ncr400->ncr;
scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; scsi_bus_t *scsi_bus = &ncr->scsibus;
scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id];
addr &= 0x3fff; addr &= 0x3fff;
@ -146,16 +147,9 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv)
if (ncr400->buffer_host_pos == MIN(128, dev->buffer_length)) { if (ncr400->buffer_host_pos == MIN(128, dev->buffer_length)) {
ncr400->status_ctrl |= STATUS_BUFFER_NOT_READY; ncr400->status_ctrl |= STATUS_BUFFER_NOT_READY;
ncr400->busy = 1; ncr400->busy = 1;
if (!(ncr->mode & MODE_MONITOR_BUSY) && ((scsi_device_get_callback(dev) > 0.0)))
timer_on_auto(&ncr400->timer, ncr->period / 250.0);
else if ((ncr->mode & MODE_MONITOR_BUSY) && !ncr->wait_data) {
if (scsi_device_get_callback(dev) > 0.0)
timer_on_auto(&ncr400->timer, 100.0);
else
timer_on_auto(&ncr400->timer, 40.0);
}
} }
} } else
ncr53c400_log("No Write.\n");
break; break;
case 0x3980: case 0x3980:
@ -173,7 +167,7 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv)
break; break;
case 0x3981: /* block counter register */ case 0x3981: /* block counter register */
ncr53c400_log("Write block counter register: val=%d, dma mode=%x, period=%lf.\n", val, ncr->dma_mode, ncr->period); ncr53c400_log("Write block counter register: val=%d, dma mode=%x, period=%lf.\n", val, scsi_bus->tx_mode, scsi_bus->period);
ncr400->block_count = val; ncr400->block_count = val;
ncr400->block_count_loaded = 1; ncr400->block_count_loaded = 1;
@ -186,17 +180,11 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv)
} }
if ((ncr->mode & MODE_DMA) && (dev->buffer_length > 0)) { if ((ncr->mode & MODE_DMA) && (dev->buffer_length > 0)) {
memset(ncr400->buffer, 0, MIN(128, dev->buffer_length)); memset(ncr400->buffer, 0, MIN(128, dev->buffer_length));
if (ncr->mode & MODE_MONITOR_BUSY) timer_on_auto(&ncr400->timer, scsi_bus->period);
timer_on_auto(&ncr400->timer, (ncr->period / 4.0) * 3.0); ncr53c400_log("DMA timer on=%02x, callback=%lf, scsi buflen=%d, waitdata=%d, waitcomplete=%d, clearreq=%d, p=%lf enabled=%d.\n",
else if (scsi_device_get_callback(dev) > 0.0) ncr->mode & MODE_MONITOR_BUSY, scsi_device_get_callback(dev), dev->buffer_length, scsi_bus->wait_data, scsi_bus->wait_complete, scsi_bus->clear_req, scsi_bus->period, timer_is_enabled(&ncr400->timer));
timer_on_auto(&ncr400->timer, 40.0); } else
else ncr53c400_log("No Timer.\n");
timer_on_auto(&ncr400->timer, ncr->period);
ncr->wait_data_back = ncr->wait_data;
ncr53c400_log("DMA timer on=%02x, callback=%lf, scsi buflen=%d, waitdata=%d, waitcomplete=%d, clearreq=%d, datawait=%d, enabled=%d.\n",
ncr->mode & MODE_MONITOR_BUSY, scsi_device_get_callback(dev), dev->buffer_length, ncr->wait_data, ncr->wait_complete, ncr->clear_req, ncr->data_wait, timer_is_enabled(&ncr400->timer));
}
break; break;
default: default:
@ -216,7 +204,8 @@ ncr53c400_read(uint32_t addr, void *priv)
{ {
ncr53c400_t *ncr400 = (ncr53c400_t *) priv; ncr53c400_t *ncr400 = (ncr53c400_t *) priv;
ncr_t *ncr = &ncr400->ncr; ncr_t *ncr = &ncr400->ncr;
scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; scsi_bus_t *scsi_bus = &ncr->scsibus;
scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id];
uint8_t ret = 0xff; uint8_t ret = 0xff;
addr &= 0x3fff; addr &= 0x3fff;
@ -240,7 +229,7 @@ ncr53c400_read(uint32_t addr, void *priv)
break; break;
case 0x3900: case 0x3900:
if (ncr400->buffer_host_pos >= MIN(128, dev->buffer_length) || (!(ncr400->status_ctrl & CTRL_DATA_DIR))) { if ((ncr400->buffer_host_pos >= MIN(128, dev->buffer_length)) || (!(ncr400->status_ctrl & CTRL_DATA_DIR))) {
ret = 0xff; ret = 0xff;
ncr53c400_log("No Read.\n"); ncr53c400_log("No Read.\n");
} else { } else {
@ -249,15 +238,6 @@ ncr53c400_read(uint32_t addr, void *priv)
if (ncr400->buffer_host_pos == MIN(128, dev->buffer_length)) { if (ncr400->buffer_host_pos == MIN(128, dev->buffer_length)) {
ncr400->status_ctrl |= STATUS_BUFFER_NOT_READY; ncr400->status_ctrl |= STATUS_BUFFER_NOT_READY;
ncr53c400_log("Transfer busy read, status = %02x.\n", ncr400->status_ctrl);
if (!(ncr->mode & MODE_MONITOR_BUSY) && (scsi_device_get_callback(dev) > 0.0))
timer_on_auto(&ncr400->timer, ncr->period / 250.0);
else if ((ncr->mode & MODE_MONITOR_BUSY) && !ncr->wait_data) {
if (scsi_device_get_callback(dev) > 0.0)
timer_on_auto(&ncr400->timer, 100.0);
else
timer_on_auto(&ncr400->timer, 40.0);
}
} }
} }
break; break;
@ -272,7 +252,7 @@ ncr53c400_read(uint32_t addr, void *priv)
if (ncr->mode & 0x30) { /*Parity bits*/ if (ncr->mode & 0x30) { /*Parity bits*/
if (!(ncr->mode & MODE_DMA)) { /*This is to avoid RTBios 8.10R BIOS problems with the hard disk and detection.*/ if (!(ncr->mode & MODE_DMA)) { /*This is to avoid RTBios 8.10R BIOS problems with the hard disk and detection.*/
ret |= 0x01; /*If the parity bits are set, bit 0 of the 53c400 status port should be set as well.*/ ret |= 0x01; /*If the parity bits are set, bit 0 of the 53c400 status port should be set as well.*/
ncr->mode = 0; /*Required by RTASPI10.SYS otherwise it won't initialize.*/ ncr->mode = 0x00; /*Required by RTASPI10.SYS otherwise it won't initialize.*/
} }
} }
ncr53c400_log("NCR 53c400 status=%02x.\n", ret); ncr53c400_log("NCR 53c400 status=%02x.\n", ret);
@ -411,46 +391,47 @@ t130b_in(uint16_t port, void *priv)
} }
static void static void
ncr53c400_dma_mode_ext(void *priv, void *ext_priv) ncr53c400_dma_mode_ext(void *priv, UNUSED(void *ext_priv), uint8_t val)
{ {
ncr53c400_t *ncr400 = (ncr53c400_t *) ext_priv;
ncr_t *ncr = (ncr_t *) priv; ncr_t *ncr = (ncr_t *) priv;
scsi_bus_t *scsi_bus = &ncr->scsibus;
/*When a pseudo-DMA transfer has completed (Send or Initiator Receive), mark it as complete and idle the status*/ /*When a pseudo-DMA transfer has completed (Send or Initiator Receive), mark it as complete and idle the status*/
ncr53c400_log("BlockCountLoaded=%d.\n", ncr400->block_count_loaded); ncr53c400_log("NCR 53c400: BlockCountLoaded=%d, DMA mode enabled=%02x, valDMA=%02x.\n", ncr400->block_count_loaded, ncr->mode & MODE_DMA, val & MODE_DMA);
if (!ncr400->block_count_loaded) { if (!(val & MODE_DMA) && (ncr->mode & MODE_DMA)) {
if (!(ncr->mode & MODE_DMA)) { ncr->tcr &= ~TCR_LAST_BYTE_SENT;
ncr53c400_log("No DMA mode\n"); ncr->isr &= ~STATUS_END_OF_DMA;
ncr->tcr &= ~TCR_LAST_BYTE_SENT; scsi_bus->tx_mode = PIO_TX_BUS;
ncr->isr &= ~STATUS_END_OF_DMA;
ncr->dma_mode = DMA_IDLE;
}
} }
} }
static void static void
ncr53c400_callback(void *priv) ncr53c400_callback(void *priv)
{ {
ncr53c400_t *ncr400 = (void *) priv; ncr53c400_t *ncr400 = (ncr53c400_t *) priv;
ncr_t *ncr = &ncr400->ncr; ncr_t *ncr = &ncr400->ncr;
scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; scsi_bus_t *scsi_bus = &ncr->scsibus;
scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id];
int bus; int bus;
uint8_t c; uint8_t c;
uint8_t temp; uint8_t temp;
uint8_t status;
if (ncr->dma_mode != DMA_IDLE) if (scsi_bus->tx_mode != PIO_TX_BUS)
timer_on_auto(&ncr400->timer, 1.0); timer_on_auto(&ncr400->timer, 1.0);
if (ncr->data_wait & 1) { if (scsi_bus->data_wait & 1) {
ncr->clear_req = 3; scsi_bus->clear_req = 3;
ncr->data_wait &= ~1; scsi_bus->data_wait &= ~1;
} }
if (ncr->dma_mode == DMA_IDLE) if (scsi_bus->tx_mode == PIO_TX_BUS) {
ncr53c400_log("Timer CMD=%02x.\n", scsi_bus->command[0]);
return; return;
}
switch (ncr->dma_mode) { switch (scsi_bus->tx_mode) {
case DMA_SEND: case DMA_OUT_TX_BUS:
if (ncr400->status_ctrl & CTRL_DATA_DIR) { if (ncr400->status_ctrl & CTRL_DATA_DIR) {
ncr53c400_log("DMA_SEND with DMA direction set wrong\n"); ncr53c400_log("DMA_SEND with DMA direction set wrong\n");
break; break;
@ -468,8 +449,8 @@ ncr53c400_callback(void *priv)
while (1) { while (1) {
for (c = 0; c < 10; c++) { for (c = 0; c < 10; c++) {
ncr5380_bus_read(ncr); status = scsi_bus_read(scsi_bus);
if (ncr->cur_bus & BUS_REQ) if (status & BUS_REQ)
break; break;
} }
/* Data ready. */ /* Data ready. */
@ -478,8 +459,8 @@ ncr53c400_callback(void *priv)
bus = ncr5380_get_bus_host(ncr) & ~BUS_DATAMASK; bus = ncr5380_get_bus_host(ncr) & ~BUS_DATAMASK;
bus |= BUS_SETDATA(temp); bus |= BUS_SETDATA(temp);
ncr5380_bus_update(ncr, bus | BUS_ACK); scsi_bus_update(scsi_bus, bus | BUS_ACK);
ncr5380_bus_update(ncr, bus & ~BUS_ACK); scsi_bus_update(scsi_bus, bus & ~BUS_ACK);
ncr400->buffer_pos++; ncr400->buffer_pos++;
ncr53c400_log("NCR 53c400 Buffer pos for writing = %d\n", ncr400->buffer_pos); ncr53c400_log("NCR 53c400 Buffer pos for writing = %d\n", ncr400->buffer_pos);
@ -492,7 +473,7 @@ ncr53c400_callback(void *priv)
ncr400->block_count = (ncr400->block_count - 1) & 0xff; ncr400->block_count = (ncr400->block_count - 1) & 0xff;
ncr53c400_log("NCR 53c400 Remaining blocks to be written=%d\n", ncr400->block_count); ncr53c400_log("NCR 53c400 Remaining blocks to be written=%d\n", ncr400->block_count);
if (!ncr400->block_count) { if (!ncr400->block_count) {
ncr->dma_mode = DMA_IDLE; scsi_bus->tx_mode = PIO_TX_BUS;
ncr400->block_count_loaded = 0; ncr400->block_count_loaded = 0;
ncr53c400_log("IO End of write transfer\n"); ncr53c400_log("IO End of write transfer\n");
ncr->tcr |= TCR_LAST_BYTE_SENT; ncr->tcr |= TCR_LAST_BYTE_SENT;
@ -507,7 +488,7 @@ ncr53c400_callback(void *priv)
} }
break; break;
case DMA_INITIATOR_RECEIVE: case DMA_IN_TX_BUS:
if (!(ncr400->status_ctrl & CTRL_DATA_DIR)) { if (!(ncr400->status_ctrl & CTRL_DATA_DIR)) {
ncr53c400_log("DMA_INITIATOR_RECEIVE with DMA direction set wrong\n"); ncr53c400_log("DMA_INITIATOR_RECEIVE with DMA direction set wrong\n");
break; break;
@ -523,18 +504,18 @@ ncr53c400_callback(void *priv)
while (1) { while (1) {
for (c = 0; c < 10; c++) { for (c = 0; c < 10; c++) {
ncr5380_bus_read(ncr); status = scsi_bus_read(scsi_bus);
if (ncr->cur_bus & BUS_REQ) if (status & BUS_REQ)
break; break;
} }
/* Data ready. */ /* Data ready. */
ncr5380_bus_read(ncr); bus = scsi_bus_read(scsi_bus);
temp = BUS_GETDATA(ncr->cur_bus); temp = BUS_GETDATA(bus);
bus = ncr5380_get_bus_host(ncr); bus = ncr5380_get_bus_host(ncr);
ncr5380_bus_update(ncr, bus | BUS_ACK); scsi_bus_update(scsi_bus, bus | BUS_ACK);
ncr5380_bus_update(ncr, bus & ~BUS_ACK); scsi_bus_update(scsi_bus, bus & ~BUS_ACK);
ncr400->buffer[ncr400->buffer_pos++] = temp; ncr400->buffer[ncr400->buffer_pos++] = temp;
ncr53c400_log("NCR 53c400 Buffer pos for reading = %d\n", ncr400->buffer_pos); ncr53c400_log("NCR 53c400 Buffer pos for reading = %d\n", ncr400->buffer_pos);
@ -546,7 +527,7 @@ ncr53c400_callback(void *priv)
ncr400->block_count = (ncr400->block_count - 1) & 0xff; ncr400->block_count = (ncr400->block_count - 1) & 0xff;
ncr53c400_log("NCR 53c400 Remaining blocks to be read=%d\n", ncr400->block_count); ncr53c400_log("NCR 53c400 Remaining blocks to be read=%d\n", ncr400->block_count);
if (!ncr400->block_count) { if (!ncr400->block_count) {
ncr->dma_mode = DMA_IDLE; scsi_bus->tx_mode = PIO_TX_BUS;
ncr400->block_count_loaded = 0; ncr400->block_count_loaded = 0;
ncr53c400_log("IO End of read transfer\n"); ncr53c400_log("IO End of read transfer\n");
ncr->isr |= STATUS_END_OF_DMA; ncr->isr |= STATUS_END_OF_DMA;
@ -564,13 +545,12 @@ ncr53c400_callback(void *priv)
break; break;
} }
ncr53c400_log("Bus Read.\n"); status = scsi_bus_read(scsi_bus);
ncr5380_bus_read(ncr);
if (!(ncr->cur_bus & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) { if (!(status & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) {
ncr53c400_log("Updating DMA\n"); ncr53c400_log("Updating DMA\n");
ncr->mode &= ~MODE_DMA; ncr->mode &= ~MODE_DMA;
ncr->dma_mode = DMA_IDLE; scsi_bus->tx_mode = PIO_TX_BUS;
ncr400->block_count_loaded = 0; ncr400->block_count_loaded = 0;
} }
} }
@ -643,6 +623,7 @@ ncr53c400_init(const device_t *info)
const char *fn; const char *fn;
ncr53c400_t *ncr400; ncr53c400_t *ncr400;
ncr_t *ncr; ncr_t *ncr;
scsi_bus_t *scsi_bus;
ncr400 = malloc(sizeof(ncr53c400_t)); ncr400 = malloc(sizeof(ncr53c400_t));
memset(ncr400, 0x00, sizeof(ncr53c400_t)); memset(ncr400, 0x00, sizeof(ncr53c400_t));
@ -651,6 +632,7 @@ ncr53c400_init(const device_t *info)
ncr400->type = info->local; ncr400->type = info->local;
ncr->bus = scsi_get_bus(); ncr->bus = scsi_get_bus();
scsi_bus = &ncr->scsibus;
switch (ncr400->type) { switch (ncr400->type) {
case ROM_LCS6821N: /* Longshine LCS6821N */ case ROM_LCS6821N: /* Longshine LCS6821N */
@ -734,11 +716,17 @@ ncr53c400_init(const device_t *info)
ncr->dma_send_ext = NULL; ncr->dma_send_ext = NULL;
ncr->dma_initiator_receive_ext = NULL; ncr->dma_initiator_receive_ext = NULL;
ncr->timer = ncr53c400_timer_on_auto; ncr->timer = ncr53c400_timer_on_auto;
scsi_bus->bus_device = ncr->bus;
scsi_bus->timer = ncr->timer;
scsi_bus->priv = ncr->priv;
ncr400->status_ctrl = STATUS_BUFFER_NOT_READY; ncr400->status_ctrl = STATUS_BUFFER_NOT_READY;
ncr400->buffer_host_pos = 128; ncr400->buffer_host_pos = 128;
timer_add(&ncr400->timer, ncr53c400_callback, ncr400, 0); timer_add(&ncr400->timer, ncr53c400_callback, ncr400, 0);
scsi_bus_set_speed(ncr->bus, 5000000.0); scsi_bus_set_speed(ncr->bus, 5000000.0);
scsi_bus->speed = 0.2;
scsi_bus->divider = 2.0;
scsi_bus->multi = 1.750;
return ncr400; return ncr400;
} }

View file

@ -69,7 +69,8 @@ t128_write(uint32_t addr, uint8_t val, void *priv)
{ {
t128_t *t128 = (t128_t *) priv; t128_t *t128 = (t128_t *) priv;
ncr_t *ncr = &t128->ncr; ncr_t *ncr = &t128->ncr;
const scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; scsi_bus_t *scsi_bus = &ncr->scsibus;
const scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id];
addr &= 0x3fff; addr &= 0x3fff;
if ((addr >= 0x1800) && (addr < 0x1880)) if ((addr >= 0x1800) && (addr < 0x1880))
@ -84,7 +85,7 @@ t128_write(uint32_t addr, uint8_t val, void *priv)
ncr5380_write((addr - 0x1d00) >> 5, val, ncr); ncr5380_write((addr - 0x1d00) >> 5, val, ncr);
else if ((addr >= 0x1e00) && (addr < 0x2000)) { else if ((addr >= 0x1e00) && (addr < 0x2000)) {
if ((t128->host_pos < MIN(512, dev->buffer_length)) && if ((t128->host_pos < MIN(512, dev->buffer_length)) &&
(ncr->dma_mode == DMA_SEND)) { (scsi_bus->tx_mode == DMA_OUT_TX_BUS)) {
t128->buffer[t128->host_pos] = val; t128->buffer[t128->host_pos] = val;
t128->host_pos++; t128->host_pos++;
@ -106,7 +107,8 @@ t128_read(uint32_t addr, void *priv)
{ {
t128_t *t128 = (t128_t *) priv; t128_t *t128 = (t128_t *) priv;
ncr_t *ncr = &t128->ncr; ncr_t *ncr = &t128->ncr;
scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; scsi_bus_t *scsi_bus = &ncr->scsibus;
scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id];
uint8_t ret = 0xff; uint8_t ret = 0xff;
addr &= 0x3fff; addr &= 0x3fff;
@ -124,7 +126,7 @@ t128_read(uint32_t addr, void *priv)
ret = ncr5380_read((addr - 0x1d00) >> 5, ncr); ret = ncr5380_read((addr - 0x1d00) >> 5, ncr);
else if (addr >= 0x1e00 && addr < 0x2000) { else if (addr >= 0x1e00 && addr < 0x2000) {
if ((t128->host_pos >= MIN(512, dev->buffer_length)) || if ((t128->host_pos >= MIN(512, dev->buffer_length)) ||
(ncr->dma_mode != DMA_INITIATOR_RECEIVE)) (scsi_bus->tx_mode != DMA_IN_TX_BUS))
ret = 0xff; ret = 0xff;
else { else {
ret = t128->buffer[t128->host_pos++]; ret = t128->buffer[t128->host_pos++];
@ -135,8 +137,8 @@ t128_read(uint32_t addr, void *priv)
if (t128->host_pos == MIN(512, dev->buffer_length)) { if (t128->host_pos == MIN(512, dev->buffer_length)) {
t128->status &= ~0x04; t128->status &= ~0x04;
t128_log("T128 Transfer busy read, status = %02x, period = %lf\n", t128_log("T128 Transfer busy read, status = %02x, period = %lf\n",
t128->status, ncr->period); t128->status, scsi_bus->period);
if ((ncr->period == 0.2) || (ncr->period == 0.02)) if ((scsi_bus->period == 0.2) || (scsi_bus->period == 0.02))
timer_on_auto(&t128->timer, 40.2); timer_on_auto(&t128->timer, 40.2);
} else if ((t128->host_pos < MIN(512, dev->buffer_length)) && } else if ((t128->host_pos < MIN(512, dev->buffer_length)) &&
(scsi_device_get_callback(dev) > 100.0)) (scsi_device_get_callback(dev) > 100.0))
@ -148,15 +150,16 @@ t128_read(uint32_t addr, void *priv)
} }
static void static void
t128_dma_mode_ext(void *priv, void *ext_priv) t128_dma_mode_ext(void *priv, void *ext_priv, UNUSED(uint8_t val))
{ {
t128_t *t128 = (t128_t *) ext_priv; t128_t *t128 = (t128_t *) ext_priv;
ncr_t *ncr = (ncr_t *) priv; ncr_t *ncr = (ncr_t *) priv;
scsi_bus_t *scsi_bus = &ncr->scsibus;
/*Don't stop the timer until it finishes the transfer*/ /*Don't stop the timer until it finishes the transfer*/
if (t128->block_loaded && (ncr->mode & MODE_DMA)) { if (t128->block_loaded && (ncr->mode & MODE_DMA)) {
t128_log("Continuing DMA mode\n"); t128_log("Continuing DMA mode\n");
timer_on_auto(&t128->timer, ncr->period + 1.0); timer_on_auto(&t128->timer, scsi_bus->period + 1.0);
} }
/*When a pseudo-DMA transfer has completed (Send or Initiator Receive), mark it as complete and idle the status*/ /*When a pseudo-DMA transfer has completed (Send or Initiator Receive), mark it as complete and idle the status*/
@ -164,7 +167,7 @@ t128_dma_mode_ext(void *priv, void *ext_priv)
t128_log("No DMA mode\n"); t128_log("No DMA mode\n");
ncr->tcr &= ~TCR_LAST_BYTE_SENT; ncr->tcr &= ~TCR_LAST_BYTE_SENT;
ncr->isr &= ~STATUS_END_OF_DMA; ncr->isr &= ~STATUS_END_OF_DMA;
ncr->dma_mode = DMA_IDLE; scsi_bus->tx_mode = PIO_TX_BUS;
} }
} }
@ -173,7 +176,8 @@ t128_dma_send_ext(void *priv, void *ext_priv)
{ {
t128_t *t128 = (t128_t *) ext_priv; t128_t *t128 = (t128_t *) ext_priv;
ncr_t *ncr = (ncr_t *) priv; ncr_t *ncr = (ncr_t *) priv;
scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; scsi_bus_t *scsi_bus = &ncr->scsibus;
scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id];
if ((ncr->mode & MODE_DMA) && !timer_is_on(&t128->timer) && (dev->buffer_length > 0)) { if ((ncr->mode & MODE_DMA) && !timer_is_on(&t128->timer) && (dev->buffer_length > 0)) {
memset(t128->buffer, 0, MIN(512, dev->buffer_length)); memset(t128->buffer, 0, MIN(512, dev->buffer_length));
@ -194,7 +198,8 @@ t128_dma_initiator_receive_ext(void *priv, void *ext_priv)
{ {
t128_t *t128 = (t128_t *) ext_priv; t128_t *t128 = (t128_t *) ext_priv;
ncr_t *ncr = (ncr_t *) priv; ncr_t *ncr = (ncr_t *) priv;
scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; scsi_bus_t *scsi_bus = &ncr->scsibus;
scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id];
if ((ncr->mode & MODE_DMA) && !timer_is_on(&t128->timer) && (dev->buffer_length > 0)) { if ((ncr->mode & MODE_DMA) && !timer_is_on(&t128->timer) && (dev->buffer_length > 0)) {
memset(t128->buffer, 0, MIN(512, dev->buffer_length)); memset(t128->buffer, 0, MIN(512, dev->buffer_length));
@ -227,27 +232,29 @@ t128_callback(void *priv)
{ {
t128_t *t128 = (void *) priv; t128_t *t128 = (void *) priv;
ncr_t *ncr = &t128->ncr; ncr_t *ncr = &t128->ncr;
scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; scsi_bus_t *scsi_bus = &ncr->scsibus;
int bus; scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id];
uint8_t c; int bus;
uint8_t temp; uint8_t c;
uint8_t temp;
uint8_t status;
if ((ncr->dma_mode != DMA_IDLE) && (ncr->mode & MODE_DMA) && t128->block_loaded) { if ((scsi_bus->tx_mode != PIO_TX_BUS) && (ncr->mode & MODE_DMA) && t128->block_loaded) {
if ((t128->host_pos == MIN(512, dev->buffer_length)) && t128->block_count) if ((t128->host_pos == MIN(512, dev->buffer_length)) && t128->block_count)
t128->status |= 0x04; t128->status |= 0x04;
timer_on_auto(&t128->timer, ncr->period / 55.0); timer_on_auto(&t128->timer, scsi_bus->period / 55.0);
} }
if (ncr->data_wait & 1) { if (scsi_bus->data_wait & 1) {
ncr->clear_req = 3; scsi_bus->clear_req = 3;
ncr->data_wait &= ~1; scsi_bus->data_wait &= ~1;
if (ncr->dma_mode == DMA_IDLE) if (scsi_bus->tx_mode == PIO_TX_BUS)
return; return;
} }
switch (ncr->dma_mode) { switch (scsi_bus->tx_mode) {
case DMA_SEND: case DMA_OUT_TX_BUS:
if (!(t128->status & 0x04)) { if (!(t128->status & 0x04)) {
t128_log("Write status busy, block count = %i, host pos = %i\n", t128->block_count, t128->host_pos); t128_log("Write status busy, block count = %i, host pos = %i\n", t128->block_count, t128->host_pos);
break; break;
@ -263,8 +270,8 @@ t128_callback(void *priv)
write_again: write_again:
for (c = 0; c < 10; c++) { for (c = 0; c < 10; c++) {
ncr5380_bus_read(ncr); status = scsi_bus_read(scsi_bus);
if (ncr->cur_bus & BUS_REQ) if (status & BUS_REQ)
break; break;
} }
@ -274,8 +281,8 @@ write_again:
bus = ncr5380_get_bus_host(ncr) & ~BUS_DATAMASK; bus = ncr5380_get_bus_host(ncr) & ~BUS_DATAMASK;
bus |= BUS_SETDATA(temp); bus |= BUS_SETDATA(temp);
ncr5380_bus_update(ncr, bus | BUS_ACK); scsi_bus_update(scsi_bus, bus | BUS_ACK);
ncr5380_bus_update(ncr, bus & ~BUS_ACK); scsi_bus_update(scsi_bus, bus & ~BUS_ACK);
t128->pos++; t128->pos++;
t128_log("T128 Buffer pos for writing = %d\n", t128->pos); t128_log("T128 Buffer pos for writing = %d\n", t128->pos);
@ -302,7 +309,7 @@ write_again:
goto write_again; goto write_again;
break; break;
case DMA_INITIATOR_RECEIVE: case DMA_IN_TX_BUS:
if (!(t128->status & 0x04)) { if (!(t128->status & 0x04)) {
t128_log("Read status busy, block count = %i, host pos = %i\n", t128->block_count, t128->host_pos); t128_log("Read status busy, block count = %i, host pos = %i\n", t128->block_count, t128->host_pos);
break; break;
@ -318,19 +325,19 @@ write_again:
read_again: read_again:
for (c = 0; c < 10; c++) { for (c = 0; c < 10; c++) {
ncr5380_bus_read(ncr); status = scsi_bus_read(scsi_bus);
if (ncr->cur_bus & BUS_REQ) if (status & BUS_REQ)
break; break;
} }
/* Data ready. */ /* Data ready. */
ncr5380_bus_read(ncr); bus = scsi_bus_read(scsi_bus);
temp = BUS_GETDATA(ncr->cur_bus); temp = BUS_GETDATA(bus);
bus = ncr5380_get_bus_host(ncr); bus = ncr5380_get_bus_host(ncr);
ncr5380_bus_update(ncr, bus | BUS_ACK); scsi_bus_update(scsi_bus, bus | BUS_ACK);
ncr5380_bus_update(ncr, bus & ~BUS_ACK); scsi_bus_update(scsi_bus, bus & ~BUS_ACK);
t128->buffer[t128->pos++] = temp; t128->buffer[t128->pos++] = temp;
t128_log("T128 Buffer pos for reading=%d, temp=%02x, len=%d.\n", t128->pos, temp, dev->buffer_length); t128_log("T128 Buffer pos for reading=%d, temp=%02x, len=%d.\n", t128->pos, temp, dev->buffer_length);
@ -360,12 +367,12 @@ read_again:
break; break;
} }
ncr5380_bus_read(ncr); status = scsi_bus_read(scsi_bus);
if (!(ncr->cur_bus & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) { if (!(status & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) {
t128_log("Updating DMA\n"); t128_log("Updating DMA\n");
ncr->mode &= ~MODE_DMA; ncr->mode &= ~MODE_DMA;
ncr->dma_mode = DMA_IDLE; scsi_bus->tx_mode = PIO_TX_BUS;
timer_on_auto(&t128->timer, 10.0); timer_on_auto(&t128->timer, 10.0);
} }
} }
@ -467,12 +474,14 @@ t128_init(const device_t *info)
{ {
t128_t *t128; t128_t *t128;
ncr_t *ncr; ncr_t *ncr;
scsi_bus_t *scsi_bus;
t128 = malloc(sizeof(t128_t)); t128 = malloc(sizeof(t128_t));
memset(t128, 0x00, sizeof(t128_t)); memset(t128, 0x00, sizeof(t128_t));
ncr = &t128->ncr; ncr = &t128->ncr;
ncr->bus = scsi_get_bus(); ncr->bus = scsi_get_bus();
scsi_bus = &ncr->scsibus;
if (info->flags & DEVICE_MCA) { if (info->flags & DEVICE_MCA) {
rom_init(&t128->bios_rom, T128_ROM, rom_init(&t128->bios_rom, T128_ROM,
@ -504,6 +513,9 @@ t128_init(const device_t *info)
ncr->dma_send_ext = t128_dma_send_ext; ncr->dma_send_ext = t128_dma_send_ext;
ncr->dma_initiator_receive_ext = t128_dma_initiator_receive_ext; ncr->dma_initiator_receive_ext = t128_dma_initiator_receive_ext;
ncr->timer = t128_timer_on_auto; ncr->timer = t128_timer_on_auto;
scsi_bus->bus_device = ncr->bus;
scsi_bus->timer = ncr->timer;
scsi_bus->priv = ncr->priv;
t128->status = 0x00 /*0x04*/; t128->status = 0x00 /*0x04*/;
t128->host_pos = 512; t128->host_pos = 512;
if (!t128->bios_enabled && !(info->flags & DEVICE_MCA)) if (!t128->bios_enabled && !(info->flags & DEVICE_MCA))
@ -516,6 +528,9 @@ t128_init(const device_t *info)
timer_add(&t128->timer, t128_callback, t128, 0); timer_add(&t128->timer, t128_callback, t128, 0);
scsi_bus_set_speed(ncr->bus, 5000000.0); scsi_bus_set_speed(ncr->bus, 5000000.0);
scsi_bus->speed = 0.2;
scsi_bus->divider = 1.0;
scsi_bus->multi = 1.0;
return t128; return t128;
} }

View file

@ -86,7 +86,7 @@
* Copyright 2008-2024 Sarah Walker. * Copyright 2008-2024 Sarah Walker.
* Copyright 2024 Miran Grca. * Copyright 2024 Miran Grca.
*/ */
#define _USE_MATH_DEFINES #define _USE_MATH_DEFINES
#include <math.h> #include <math.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdint.h> #include <stdint.h>
@ -706,6 +706,7 @@ static uint8_t
pas16_in(uint16_t port, void *priv) pas16_in(uint16_t port, void *priv)
{ {
pas16_t *pas16 = (pas16_t *) priv; pas16_t *pas16 = (pas16_t *) priv;
scsi_bus_t *scsi_bus = NULL;
uint8_t ret = 0xff; uint8_t ret = 0xff;
port -= pas16->base; port -= pas16->base;
@ -784,9 +785,11 @@ pas16_in(uint16_t port, void *priv)
ret = t128_read(0x1e00, pas16->scsi); ret = t128_read(0x1e00, pas16->scsi);
break; break;
case 0x5c01: case 0x5c01:
if (pas16->has_scsi) if (pas16->has_scsi) {
scsi_bus = &pas16->scsi->ncr.scsibus;
/* Bits 0-6 must absolutely be set for SCSI hard disk drivers to work. */ /* Bits 0-6 must absolutely be set for SCSI hard disk drivers to work. */
ret = (((pas16->scsi->ncr.dma_mode != DMA_IDLE) && (pas16->scsi->status & 0x04)) << 7) | 0x7f; ret = (((scsi_bus->tx_mode != PIO_TX_BUS) && (pas16->scsi->status & 0x04)) << 7) | 0x7f;
}
break; break;
case 0x5c03: case 0x5c03:
if (pas16->has_scsi) if (pas16->has_scsi)
@ -1183,10 +1186,11 @@ pas16_scsi_callback(void *priv)
{ {
pas16_t * pas16 = (pas16_t *) priv; pas16_t * pas16 = (pas16_t *) priv;
t128_t * dev = pas16->scsi; t128_t * dev = pas16->scsi;
scsi_bus_t * scsi_bus = &dev->ncr.scsibus;
t128_callback(pas16->scsi); t128_callback(pas16->scsi);
if ((dev->ncr.dma_mode != DMA_IDLE) && (dev->status & 0x04)) { if ((scsi_bus->tx_mode != PIO_TX_BUS) && (dev->status & 0x04)) {
timer_stop(&pas16->scsi_timer); timer_stop(&pas16->scsi_timer);
pas16->timeout_status &= 0x7f; pas16->timeout_status &= 0x7f;
} }