mirror of
https://github.com/86Box/86Box.git
synced 2025-01-22 01:01:51 -05:00
Merge pull request #5172 from 86Box/tc1995
Big SCSI bus update of the day, NCR 5380 too (January 20th, 2025)
This commit is contained in:
commit
78edf7340c
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;
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@
|
|||
* Copyright 2008-2024 Sarah Walker.
|
||||
* Copyright 2024 Miran Grca.
|
||||
*/
|
||||
#define _USE_MATH_DEFINES
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
|
@ -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