mirror of
https://github.com/86Box/86Box.git
synced 2025-01-22 09:11:50 -05:00
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:
parent
3dea388ae4
commit
4008010131
7 changed files with 546 additions and 482 deletions
|
@ -333,6 +333,20 @@
|
|||
|
||||
#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_COMMAND 0x01
|
||||
#define PHASE_DATA_IN 0x02
|
||||
|
@ -420,6 +434,36 @@ typedef struct scsi_device_t {
|
|||
void (*command_stop)(scsi_common_t *sc);
|
||||
} 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. */
|
||||
#define SCSI_NONE 0x0060
|
||||
#define SCSI_FIXED_DISK 0x0000
|
||||
|
@ -454,6 +498,8 @@ extern void scsi_device_init(void);
|
|||
|
||||
extern void scsi_reset(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 double scsi_bus_get_speed(uint8_t bus);
|
||||
|
|
|
@ -44,6 +44,9 @@
|
|||
#define ICR_ACK 0x10
|
||||
#define ICR_ARB_LOST 0x20
|
||||
#define ICR_ARB_IN_PROGRESS 0x40
|
||||
#define ICR_RST 0x80
|
||||
#define ICR_PHASE 0x9e
|
||||
#define ICR_WRITE 0x9f
|
||||
|
||||
#define MODE_ARBITRATE 0x01
|
||||
#define MODE_DMA 0x02
|
||||
|
@ -63,70 +66,33 @@
|
|||
#define TCR_REQ 0x08
|
||||
#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 {
|
||||
uint8_t icr;
|
||||
uint8_t mode;
|
||||
uint8_t tcr;
|
||||
uint8_t data_wait;
|
||||
uint8_t isr;
|
||||
uint8_t output_data;
|
||||
uint8_t target_id;
|
||||
uint8_t tx_data;
|
||||
uint8_t msglun;
|
||||
uint8_t irq_state;
|
||||
|
||||
uint8_t command[20];
|
||||
uint8_t msgout[4];
|
||||
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;
|
||||
|
||||
double period;
|
||||
|
||||
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_initiator_receive_ext)(void *priv, void *ext_priv);
|
||||
void (*timer)(void *ext_priv, double period);
|
||||
|
||||
scsi_bus_t scsibus;
|
||||
} ncr_t;
|
||||
|
||||
extern int ncr5380_cmd_len[8];
|
||||
|
||||
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 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 uint8_t ncr5380_read(uint16_t port, ncr_t *ncr);
|
||||
|
||||
|
|
|
@ -16,10 +16,14 @@
|
|||
* Copyright 2016-2018 Miran Grca.
|
||||
* Copyright 2017-2018 Fred N. van Kempen.
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/hdd.h>
|
||||
|
@ -29,9 +33,29 @@
|
|||
#include <86box/plat_unused.h>
|
||||
|
||||
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 };
|
||||
|
||||
#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
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,8 +42,6 @@
|
|||
#include <86box/scsi_device.h>
|
||||
#include <86box/scsi_ncr5380.h>
|
||||
|
||||
int ncr5380_cmd_len[8] = { 6, 10, 10, 6, 16, 12, 10, 6 };
|
||||
|
||||
#ifdef ENABLE_NCR5380_LOG
|
||||
int ncr5380_do_log = ENABLE_NCR5380_LOG;
|
||||
|
||||
|
@ -62,8 +60,6 @@ ncr5380_log(const char *fmt, ...)
|
|||
# define ncr5380_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
#define SET_BUS_STATE(ncr, state) ncr->cur_bus = (ncr->cur_bus & ~(SCSI_PHASE_MESSAGE_IN)) | (state & (SCSI_PHASE_MESSAGE_IN))
|
||||
|
||||
void
|
||||
ncr5380_irq(ncr_t *ncr, int set_irq)
|
||||
{
|
||||
|
@ -86,45 +82,15 @@ ncr5380_set_irq(ncr_t *ncr, int 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
|
||||
ncr5380_reset(ncr_t *ncr)
|
||||
{
|
||||
ncr->command_pos = 0;
|
||||
ncr->data_pos = 0;
|
||||
ncr->state = STATE_IDLE;
|
||||
ncr->clear_req = 0;
|
||||
ncr->cur_bus = 0;
|
||||
ncr->tx_data = 0;
|
||||
scsi_bus_t *scsi_bus = &ncr->scsibus;
|
||||
|
||||
ncr->output_data = 0;
|
||||
ncr->data_wait = 0;
|
||||
ncr->mode = 0;
|
||||
ncr->tcr = 0;
|
||||
ncr->icr = 0;
|
||||
ncr->dma_mode = DMA_IDLE;
|
||||
ncr5380_log("NCR Reset\n");
|
||||
|
||||
ncr->timer(ncr->priv, 0.0);
|
||||
|
@ -132,6 +98,17 @@ ncr5380_reset(ncr_t *ncr)
|
|||
for (int i = 0; i < 8; 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);
|
||||
}
|
||||
|
||||
|
@ -173,280 +150,10 @@ ncr5380_get_bus_host(ncr_t *ncr)
|
|||
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
|
||||
ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr)
|
||||
{
|
||||
scsi_bus_t *scsi_bus = &ncr->scsibus;
|
||||
int bus_host = 0;
|
||||
|
||||
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)) {
|
||||
ncr5380_log("Resetting the 5380\n");
|
||||
ncr5380_reset(ncr);
|
||||
ncr5380_irq(ncr, 1);
|
||||
}
|
||||
ncr->icr = val;
|
||||
ncr5380_log("ICR WaitData=%d, ClearReq=%d.\n", scsi_bus->wait_data, scsi_bus->clear_req);
|
||||
break;
|
||||
|
||||
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_IN_PROGRESS;
|
||||
}
|
||||
|
||||
ncr->mode = val;
|
||||
|
||||
ncr->dma_mode_ext(ncr, ncr->priv);
|
||||
ncr->dma_mode_ext(ncr, ncr->priv, val);
|
||||
break;
|
||||
|
||||
case 3: /* Target Command Register */
|
||||
|
@ -488,17 +195,17 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr)
|
|||
break;
|
||||
|
||||
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*/
|
||||
ncr->dma_mode = DMA_SEND;
|
||||
scsi_bus->tx_mode = DMA_OUT_TX_BUS;
|
||||
if (ncr->dma_send_ext)
|
||||
ncr->dma_send_ext(ncr, ncr->priv);
|
||||
break;
|
||||
|
||||
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*/
|
||||
ncr->dma_mode = DMA_INITIATOR_RECEIVE;
|
||||
scsi_bus->tx_mode = DMA_IN_TX_BUS;
|
||||
if (ncr->dma_initiator_receive_ext)
|
||||
ncr->dma_initiator_receive_ext(ncr, ncr->priv);
|
||||
break;
|
||||
|
@ -509,12 +216,13 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr)
|
|||
}
|
||||
|
||||
bus_host = ncr5380_get_bus_host(ncr);
|
||||
ncr5380_bus_update(ncr, bus_host);
|
||||
scsi_bus_update(scsi_bus, bus_host);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
ncr5380_read(uint16_t port, ncr_t *ncr)
|
||||
{
|
||||
scsi_bus_t *scsi_bus = &ncr->scsibus;
|
||||
uint8_t ret = 0xff;
|
||||
int bus;
|
||||
int bus_state;
|
||||
|
@ -524,12 +232,17 @@ ncr5380_read(uint16_t port, ncr_t *ncr)
|
|||
ncr5380_log("Read: Current SCSI data register\n");
|
||||
if (ncr->icr & ICR_DBP) {
|
||||
/*Return the data from the output register if on data bus phase from ICR*/
|
||||
ret = ncr->output_data;
|
||||
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);
|
||||
if (scsi_bus->command_issued) {
|
||||
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 {
|
||||
/*Return the data from the SCSI bus*/
|
||||
ncr5380_bus_read(ncr);
|
||||
ret = BUS_GETDATA(ncr->cur_bus);
|
||||
bus = scsi_bus_read(scsi_bus);
|
||||
ret = BUS_GETDATA(bus);
|
||||
ncr5380_log("[%04X:%08X]: NCR Get SCSI bus data=%02x.\n", CS, cpu_state.pc, ret);
|
||||
}
|
||||
break;
|
||||
|
@ -552,15 +265,16 @@ ncr5380_read(uint16_t port, ncr_t *ncr)
|
|||
case 4: /* Current SCSI Bus status */
|
||||
ncr5380_log("Read: SCSI bus status register\n");
|
||||
ret = 0;
|
||||
ncr5380_bus_read(ncr);
|
||||
ncr5380_log("NCR cur bus stat=%02x\n", ncr->cur_bus & 0xff);
|
||||
ret |= (ncr->cur_bus & 0xff);
|
||||
bus = scsi_bus_read(scsi_bus);
|
||||
ret |= (bus & 0xff);
|
||||
if (ncr->icr & ICR_SEL)
|
||||
ret |= BUS_SEL;
|
||||
if (ncr->icr & ICR_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;
|
||||
|
||||
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");
|
||||
|
||||
/*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");
|
||||
ret |= STATUS_PHASE_MATCH;
|
||||
}
|
||||
|
||||
ncr5380_bus_read(ncr);
|
||||
bus = ncr->cur_bus;
|
||||
bus = scsi_bus_read(scsi_bus);
|
||||
|
||||
if ((bus & BUS_ACK) || (ncr->icr & ICR_ACK))
|
||||
ret |= STATUS_ACK;
|
||||
|
@ -610,8 +323,8 @@ ncr5380_read(uint16_t port, ncr_t *ncr)
|
|||
|
||||
case 6:
|
||||
ncr5380_log("Read: Input Data.\n");
|
||||
ncr5380_bus_read(ncr);
|
||||
ret = BUS_GETDATA(ncr->cur_bus);
|
||||
bus = scsi_bus_read(scsi_bus);
|
||||
ret = BUS_GETDATA(bus);
|
||||
break;
|
||||
|
||||
case 7: /* reset Parity/Interrupt */
|
||||
|
|
|
@ -121,7 +121,8 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv)
|
|||
{
|
||||
ncr53c400_t *ncr400 = (ncr53c400_t *) priv;
|
||||
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;
|
||||
|
||||
|
@ -146,16 +147,9 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv)
|
|||
if (ncr400->buffer_host_pos == MIN(128, dev->buffer_length)) {
|
||||
ncr400->status_ctrl |= STATUS_BUFFER_NOT_READY;
|
||||
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;
|
||||
|
||||
case 0x3980:
|
||||
|
@ -173,7 +167,7 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv)
|
|||
break;
|
||||
|
||||
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_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)) {
|
||||
memset(ncr400->buffer, 0, MIN(128, dev->buffer_length));
|
||||
if (ncr->mode & MODE_MONITOR_BUSY)
|
||||
timer_on_auto(&ncr400->timer, (ncr->period / 4.0) * 3.0);
|
||||
else if (scsi_device_get_callback(dev) > 0.0)
|
||||
timer_on_auto(&ncr400->timer, 40.0);
|
||||
else
|
||||
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));
|
||||
}
|
||||
timer_on_auto(&ncr400->timer, scsi_bus->period);
|
||||
ncr53c400_log("DMA timer on=%02x, callback=%lf, scsi buflen=%d, waitdata=%d, waitcomplete=%d, clearreq=%d, p=%lf enabled=%d.\n",
|
||||
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));
|
||||
} else
|
||||
ncr53c400_log("No Timer.\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -216,7 +204,8 @@ ncr53c400_read(uint32_t addr, void *priv)
|
|||
{
|
||||
ncr53c400_t *ncr400 = (ncr53c400_t *) priv;
|
||||
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;
|
||||
|
||||
addr &= 0x3fff;
|
||||
|
@ -240,7 +229,7 @@ ncr53c400_read(uint32_t addr, void *priv)
|
|||
break;
|
||||
|
||||
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;
|
||||
ncr53c400_log("No Read.\n");
|
||||
} else {
|
||||
|
@ -249,15 +238,6 @@ ncr53c400_read(uint32_t addr, void *priv)
|
|||
|
||||
if (ncr400->buffer_host_pos == MIN(128, dev->buffer_length)) {
|
||||
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;
|
||||
|
@ -272,7 +252,7 @@ ncr53c400_read(uint32_t addr, void *priv)
|
|||
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.*/
|
||||
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);
|
||||
|
@ -411,46 +391,47 @@ t130b_in(uint16_t port, void *priv)
|
|||
}
|
||||
|
||||
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;
|
||||
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*/
|
||||
ncr53c400_log("BlockCountLoaded=%d.\n", ncr400->block_count_loaded);
|
||||
if (!ncr400->block_count_loaded) {
|
||||
if (!(ncr->mode & MODE_DMA)) {
|
||||
ncr53c400_log("No DMA mode\n");
|
||||
ncr->tcr &= ~TCR_LAST_BYTE_SENT;
|
||||
ncr->isr &= ~STATUS_END_OF_DMA;
|
||||
ncr->dma_mode = DMA_IDLE;
|
||||
}
|
||||
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 (!(val & MODE_DMA) && (ncr->mode & MODE_DMA)) {
|
||||
ncr->tcr &= ~TCR_LAST_BYTE_SENT;
|
||||
ncr->isr &= ~STATUS_END_OF_DMA;
|
||||
scsi_bus->tx_mode = PIO_TX_BUS;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ncr53c400_callback(void *priv)
|
||||
{
|
||||
ncr53c400_t *ncr400 = (void *) priv;
|
||||
ncr53c400_t *ncr400 = (ncr53c400_t *) priv;
|
||||
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;
|
||||
uint8_t c;
|
||||
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);
|
||||
|
||||
if (ncr->data_wait & 1) {
|
||||
ncr->clear_req = 3;
|
||||
ncr->data_wait &= ~1;
|
||||
if (scsi_bus->data_wait & 1) {
|
||||
scsi_bus->clear_req = 3;
|
||||
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;
|
||||
}
|
||||
|
||||
switch (ncr->dma_mode) {
|
||||
case DMA_SEND:
|
||||
switch (scsi_bus->tx_mode) {
|
||||
case DMA_OUT_TX_BUS:
|
||||
if (ncr400->status_ctrl & CTRL_DATA_DIR) {
|
||||
ncr53c400_log("DMA_SEND with DMA direction set wrong\n");
|
||||
break;
|
||||
|
@ -468,8 +449,8 @@ ncr53c400_callback(void *priv)
|
|||
|
||||
while (1) {
|
||||
for (c = 0; c < 10; c++) {
|
||||
ncr5380_bus_read(ncr);
|
||||
if (ncr->cur_bus & BUS_REQ)
|
||||
status = scsi_bus_read(scsi_bus);
|
||||
if (status & BUS_REQ)
|
||||
break;
|
||||
}
|
||||
/* Data ready. */
|
||||
|
@ -478,8 +459,8 @@ ncr53c400_callback(void *priv)
|
|||
bus = ncr5380_get_bus_host(ncr) & ~BUS_DATAMASK;
|
||||
bus |= BUS_SETDATA(temp);
|
||||
|
||||
ncr5380_bus_update(ncr, bus | BUS_ACK);
|
||||
ncr5380_bus_update(ncr, bus & ~BUS_ACK);
|
||||
scsi_bus_update(scsi_bus, bus | BUS_ACK);
|
||||
scsi_bus_update(scsi_bus, bus & ~BUS_ACK);
|
||||
|
||||
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;
|
||||
ncr53c400_log("NCR 53c400 Remaining blocks to be written=%d\n", ncr400->block_count);
|
||||
if (!ncr400->block_count) {
|
||||
ncr->dma_mode = DMA_IDLE;
|
||||
scsi_bus->tx_mode = PIO_TX_BUS;
|
||||
ncr400->block_count_loaded = 0;
|
||||
ncr53c400_log("IO End of write transfer\n");
|
||||
ncr->tcr |= TCR_LAST_BYTE_SENT;
|
||||
|
@ -507,7 +488,7 @@ ncr53c400_callback(void *priv)
|
|||
}
|
||||
break;
|
||||
|
||||
case DMA_INITIATOR_RECEIVE:
|
||||
case DMA_IN_TX_BUS:
|
||||
if (!(ncr400->status_ctrl & CTRL_DATA_DIR)) {
|
||||
ncr53c400_log("DMA_INITIATOR_RECEIVE with DMA direction set wrong\n");
|
||||
break;
|
||||
|
@ -523,18 +504,18 @@ ncr53c400_callback(void *priv)
|
|||
|
||||
while (1) {
|
||||
for (c = 0; c < 10; c++) {
|
||||
ncr5380_bus_read(ncr);
|
||||
if (ncr->cur_bus & BUS_REQ)
|
||||
status = scsi_bus_read(scsi_bus);
|
||||
if (status & BUS_REQ)
|
||||
break;
|
||||
}
|
||||
/* Data ready. */
|
||||
ncr5380_bus_read(ncr);
|
||||
temp = BUS_GETDATA(ncr->cur_bus);
|
||||
bus = scsi_bus_read(scsi_bus);
|
||||
temp = BUS_GETDATA(bus);
|
||||
|
||||
bus = ncr5380_get_bus_host(ncr);
|
||||
|
||||
ncr5380_bus_update(ncr, bus | BUS_ACK);
|
||||
ncr5380_bus_update(ncr, bus & ~BUS_ACK);
|
||||
scsi_bus_update(scsi_bus, bus | BUS_ACK);
|
||||
scsi_bus_update(scsi_bus, bus & ~BUS_ACK);
|
||||
|
||||
ncr400->buffer[ncr400->buffer_pos++] = temp;
|
||||
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;
|
||||
ncr53c400_log("NCR 53c400 Remaining blocks to be read=%d\n", ncr400->block_count);
|
||||
if (!ncr400->block_count) {
|
||||
ncr->dma_mode = DMA_IDLE;
|
||||
scsi_bus->tx_mode = PIO_TX_BUS;
|
||||
ncr400->block_count_loaded = 0;
|
||||
ncr53c400_log("IO End of read transfer\n");
|
||||
ncr->isr |= STATUS_END_OF_DMA;
|
||||
|
@ -564,13 +545,12 @@ ncr53c400_callback(void *priv)
|
|||
break;
|
||||
}
|
||||
|
||||
ncr53c400_log("Bus Read.\n");
|
||||
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)) {
|
||||
ncr53c400_log("Updating DMA\n");
|
||||
ncr->mode &= ~MODE_DMA;
|
||||
ncr->dma_mode = DMA_IDLE;
|
||||
scsi_bus->tx_mode = PIO_TX_BUS;
|
||||
ncr400->block_count_loaded = 0;
|
||||
}
|
||||
}
|
||||
|
@ -643,6 +623,7 @@ ncr53c400_init(const device_t *info)
|
|||
const char *fn;
|
||||
ncr53c400_t *ncr400;
|
||||
ncr_t *ncr;
|
||||
scsi_bus_t *scsi_bus;
|
||||
|
||||
ncr400 = malloc(sizeof(ncr53c400_t));
|
||||
memset(ncr400, 0x00, sizeof(ncr53c400_t));
|
||||
|
@ -651,6 +632,7 @@ ncr53c400_init(const device_t *info)
|
|||
ncr400->type = info->local;
|
||||
|
||||
ncr->bus = scsi_get_bus();
|
||||
scsi_bus = &ncr->scsibus;
|
||||
|
||||
switch (ncr400->type) {
|
||||
case ROM_LCS6821N: /* Longshine LCS6821N */
|
||||
|
@ -734,11 +716,17 @@ ncr53c400_init(const device_t *info)
|
|||
ncr->dma_send_ext = NULL;
|
||||
ncr->dma_initiator_receive_ext = NULL;
|
||||
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->buffer_host_pos = 128;
|
||||
timer_add(&ncr400->timer, ncr53c400_callback, ncr400, 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;
|
||||
}
|
||||
|
|
|
@ -69,7 +69,8 @@ t128_write(uint32_t addr, uint8_t val, void *priv)
|
|||
{
|
||||
t128_t *t128 = (t128_t *) priv;
|
||||
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;
|
||||
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);
|
||||
else if ((addr >= 0x1e00) && (addr < 0x2000)) {
|
||||
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->host_pos++;
|
||||
|
||||
|
@ -106,7 +107,8 @@ t128_read(uint32_t addr, void *priv)
|
|||
{
|
||||
t128_t *t128 = (t128_t *) priv;
|
||||
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;
|
||||
|
||||
addr &= 0x3fff;
|
||||
|
@ -124,7 +126,7 @@ t128_read(uint32_t addr, void *priv)
|
|||
ret = ncr5380_read((addr - 0x1d00) >> 5, ncr);
|
||||
else if (addr >= 0x1e00 && addr < 0x2000) {
|
||||
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;
|
||||
else {
|
||||
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)) {
|
||||
t128->status &= ~0x04;
|
||||
t128_log("T128 Transfer busy read, status = %02x, period = %lf\n",
|
||||
t128->status, ncr->period);
|
||||
if ((ncr->period == 0.2) || (ncr->period == 0.02))
|
||||
t128->status, scsi_bus->period);
|
||||
if ((scsi_bus->period == 0.2) || (scsi_bus->period == 0.02))
|
||||
timer_on_auto(&t128->timer, 40.2);
|
||||
} else if ((t128->host_pos < MIN(512, dev->buffer_length)) &&
|
||||
(scsi_device_get_callback(dev) > 100.0))
|
||||
|
@ -148,15 +150,16 @@ t128_read(uint32_t addr, void *priv)
|
|||
}
|
||||
|
||||
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;
|
||||
ncr_t *ncr = (ncr_t *) priv;
|
||||
scsi_bus_t *scsi_bus = &ncr->scsibus;
|
||||
|
||||
/*Don't stop the timer until it finishes the transfer*/
|
||||
if (t128->block_loaded && (ncr->mode & MODE_DMA)) {
|
||||
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*/
|
||||
|
@ -164,7 +167,7 @@ t128_dma_mode_ext(void *priv, void *ext_priv)
|
|||
t128_log("No DMA mode\n");
|
||||
ncr->tcr &= ~TCR_LAST_BYTE_SENT;
|
||||
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;
|
||||
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)) {
|
||||
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;
|
||||
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)) {
|
||||
memset(t128->buffer, 0, MIN(512, dev->buffer_length));
|
||||
|
@ -227,27 +232,29 @@ t128_callback(void *priv)
|
|||
{
|
||||
t128_t *t128 = (void *) priv;
|
||||
ncr_t *ncr = &t128->ncr;
|
||||
scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id];
|
||||
int bus;
|
||||
uint8_t c;
|
||||
uint8_t temp;
|
||||
scsi_bus_t *scsi_bus = &ncr->scsibus;
|
||||
scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id];
|
||||
int bus;
|
||||
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)
|
||||
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) {
|
||||
ncr->clear_req = 3;
|
||||
ncr->data_wait &= ~1;
|
||||
if (ncr->dma_mode == DMA_IDLE)
|
||||
if (scsi_bus->data_wait & 1) {
|
||||
scsi_bus->clear_req = 3;
|
||||
scsi_bus->data_wait &= ~1;
|
||||
if (scsi_bus->tx_mode == PIO_TX_BUS)
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ncr->dma_mode) {
|
||||
case DMA_SEND:
|
||||
switch (scsi_bus->tx_mode) {
|
||||
case DMA_OUT_TX_BUS:
|
||||
if (!(t128->status & 0x04)) {
|
||||
t128_log("Write status busy, block count = %i, host pos = %i\n", t128->block_count, t128->host_pos);
|
||||
break;
|
||||
|
@ -263,8 +270,8 @@ t128_callback(void *priv)
|
|||
|
||||
write_again:
|
||||
for (c = 0; c < 10; c++) {
|
||||
ncr5380_bus_read(ncr);
|
||||
if (ncr->cur_bus & BUS_REQ)
|
||||
status = scsi_bus_read(scsi_bus);
|
||||
if (status & BUS_REQ)
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -274,8 +281,8 @@ write_again:
|
|||
bus = ncr5380_get_bus_host(ncr) & ~BUS_DATAMASK;
|
||||
bus |= BUS_SETDATA(temp);
|
||||
|
||||
ncr5380_bus_update(ncr, bus | BUS_ACK);
|
||||
ncr5380_bus_update(ncr, bus & ~BUS_ACK);
|
||||
scsi_bus_update(scsi_bus, bus | BUS_ACK);
|
||||
scsi_bus_update(scsi_bus, bus & ~BUS_ACK);
|
||||
|
||||
t128->pos++;
|
||||
t128_log("T128 Buffer pos for writing = %d\n", t128->pos);
|
||||
|
@ -302,7 +309,7 @@ write_again:
|
|||
goto write_again;
|
||||
break;
|
||||
|
||||
case DMA_INITIATOR_RECEIVE:
|
||||
case DMA_IN_TX_BUS:
|
||||
if (!(t128->status & 0x04)) {
|
||||
t128_log("Read status busy, block count = %i, host pos = %i\n", t128->block_count, t128->host_pos);
|
||||
break;
|
||||
|
@ -318,19 +325,19 @@ write_again:
|
|||
|
||||
read_again:
|
||||
for (c = 0; c < 10; c++) {
|
||||
ncr5380_bus_read(ncr);
|
||||
if (ncr->cur_bus & BUS_REQ)
|
||||
status = scsi_bus_read(scsi_bus);
|
||||
if (status & BUS_REQ)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Data ready. */
|
||||
ncr5380_bus_read(ncr);
|
||||
temp = BUS_GETDATA(ncr->cur_bus);
|
||||
bus = scsi_bus_read(scsi_bus);
|
||||
temp = BUS_GETDATA(bus);
|
||||
|
||||
bus = ncr5380_get_bus_host(ncr);
|
||||
|
||||
ncr5380_bus_update(ncr, bus | BUS_ACK);
|
||||
ncr5380_bus_update(ncr, bus & ~BUS_ACK);
|
||||
scsi_bus_update(scsi_bus, bus | BUS_ACK);
|
||||
scsi_bus_update(scsi_bus, bus & ~BUS_ACK);
|
||||
|
||||
t128->buffer[t128->pos++] = temp;
|
||||
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;
|
||||
}
|
||||
|
||||
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");
|
||||
ncr->mode &= ~MODE_DMA;
|
||||
ncr->dma_mode = DMA_IDLE;
|
||||
scsi_bus->tx_mode = PIO_TX_BUS;
|
||||
timer_on_auto(&t128->timer, 10.0);
|
||||
}
|
||||
}
|
||||
|
@ -467,12 +474,14 @@ t128_init(const device_t *info)
|
|||
{
|
||||
t128_t *t128;
|
||||
ncr_t *ncr;
|
||||
scsi_bus_t *scsi_bus;
|
||||
|
||||
t128 = malloc(sizeof(t128_t));
|
||||
memset(t128, 0x00, sizeof(t128_t));
|
||||
ncr = &t128->ncr;
|
||||
|
||||
ncr->bus = scsi_get_bus();
|
||||
scsi_bus = &ncr->scsibus;
|
||||
|
||||
if (info->flags & DEVICE_MCA) {
|
||||
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_initiator_receive_ext = t128_dma_initiator_receive_ext;
|
||||
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->host_pos = 512;
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -706,6 +706,7 @@ static uint8_t
|
|||
pas16_in(uint16_t port, void *priv)
|
||||
{
|
||||
pas16_t *pas16 = (pas16_t *) priv;
|
||||
scsi_bus_t *scsi_bus = NULL;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
port -= pas16->base;
|
||||
|
@ -784,9 +785,11 @@ pas16_in(uint16_t port, void *priv)
|
|||
ret = t128_read(0x1e00, pas16->scsi);
|
||||
break;
|
||||
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. */
|
||||
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;
|
||||
case 0x5c03:
|
||||
if (pas16->has_scsi)
|
||||
|
@ -1183,10 +1186,11 @@ pas16_scsi_callback(void *priv)
|
|||
{
|
||||
pas16_t * pas16 = (pas16_t *) priv;
|
||||
t128_t * dev = pas16->scsi;
|
||||
scsi_bus_t * scsi_bus = &dev->ncr.scsibus;
|
||||
|
||||
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);
|
||||
pas16->timeout_status &= 0x7f;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue