XTA fixes for both the regular and IBM PS/1 variants.

This commit is contained in:
OBattler
2023-08-20 17:26:52 +02:00
parent f1174247fa
commit 5ac598378f
2 changed files with 85 additions and 67 deletions

View File

@@ -102,7 +102,7 @@
#include <86box/hdc.h>
#include <86box/hdd.h>
#define HDC_TIME (50 * TIMER_USEC)
#define HDC_TIME (250 * TIMER_USEC)
#define WD_REV_1_BIOS_FILE "roms/hdd/xta/idexywd2.bin"
#define WD_REV_2_BIOS_FILE "roms/hdd/xta/infowdbios.rom"
@@ -248,7 +248,6 @@ typedef struct hdc_t {
uint8_t sense; /* current SENSE ERROR value */
uint8_t status; /* current operational status */
uint8_t intr;
uint64_t callback;
pc_timer_t timer;
/* Data transfer. */
@@ -343,22 +342,6 @@ next_sector(hdc_t *dev, drive_t *drive)
}
}
static void
xta_set_callback(hdc_t *dev, uint64_t callback)
{
if (!dev) {
return;
}
if (callback) {
dev->callback = callback;
timer_set_delay_u64(&dev->timer, dev->callback);
} else {
dev->callback = 0;
timer_disable(&dev->timer);
}
}
/* Perform the seek operation. */
static void
do_seek(hdc_t *dev, drive_t *drive, int cyl)
@@ -457,9 +440,6 @@ hdc_callback(void *priv)
int no_data = 0;
int val;
/* Cancel timer. */
xta_set_callback(dev, 0);
drive = &dev->drives[dcb->drvsel];
dev->comp = (dcb->drvsel) ? COMP_DRIVE : 0x00;
dev->status |= STAT_DCB;
@@ -558,12 +538,12 @@ do_send:
dev->buf_idx = 0;
if (no_data) {
/* Delay a bit, no actual transfer. */
xta_set_callback(dev, HDC_TIME);
timer_advance_u64(&dev->timer, HDC_TIME);
} else {
if (dev->intr & DMA_ENA) {
/* DMA enabled. */
dev->buf_ptr = dev->sector_buf;
xta_set_callback(dev, HDC_TIME);
timer_advance_u64(&dev->timer, HDC_TIME);
} else {
/* Copy from sector to data. */
memcpy(dev->data,
@@ -586,14 +566,14 @@ do_send:
xta_log("%s: CMD_READ_SECTORS out of data (idx=%d, len=%d)!\n", dev->name, dev->buf_idx, dev->buf_len);
dev->status |= (STAT_CD | STAT_IO | STAT_REQ);
xta_set_callback(dev, HDC_TIME);
timer_advance_u64(&dev->timer, HDC_TIME);
return;
}
dev->buf_ptr++;
dev->buf_idx++;
}
}
xta_set_callback(dev, HDC_TIME);
timer_advance_u64(&dev->timer, HDC_TIME);
dev->state = STATE_SDONE;
break;
@@ -654,7 +634,7 @@ do_recv:
if (dev->intr & DMA_ENA) {
/* DMA enabled. */
dev->buf_ptr = dev->sector_buf;
xta_set_callback(dev, HDC_TIME);
timer_advance_u64(&dev->timer, HDC_TIME);
} else {
/* No DMA, do PIO. */
dev->buf_ptr = dev->data;
@@ -673,7 +653,7 @@ do_recv:
xta_log("%s: CMD_WRITE_SECTORS out of data!\n", dev->name);
dev->status |= (STAT_CD | STAT_IO | STAT_REQ);
xta_set_callback(dev, HDC_TIME);
timer_advance_u64(&dev->timer, HDC_TIME);
return;
}
@@ -681,7 +661,7 @@ do_recv:
dev->buf_idx++;
}
dev->state = STATE_RDONE;
xta_set_callback(dev, HDC_TIME);
timer_advance_u64(&dev->timer, HDC_TIME);
}
break;
@@ -785,7 +765,7 @@ do_recv:
dev->state = STATE_RDATA;
if (dev->intr & DMA_ENA) {
dev->buf_ptr = dev->sector_buf;
xta_set_callback(dev, HDC_TIME);
timer_advance_u64(&dev->timer, HDC_TIME);
} else {
dev->buf_ptr = dev->data;
dev->status |= STAT_REQ;
@@ -800,7 +780,7 @@ do_recv:
if (val == DMA_NODATA) {
xta_log("%s: CMD_WRITE_BUFFER out of data!\n", dev->name);
dev->status |= (STAT_CD | STAT_IO | STAT_REQ);
xta_set_callback(dev, HDC_TIME);
timer_advance_u64(&dev->timer, HDC_TIME);
return;
}
@@ -808,7 +788,7 @@ do_recv:
dev->buf_idx++;
}
dev->state = STATE_RDONE;
xta_set_callback(dev, HDC_TIME);
timer_advance_u64(&dev->timer, HDC_TIME);
}
break;
@@ -828,7 +808,7 @@ do_recv:
switch (dev->state) {
case STATE_IDLE:
dev->state = STATE_RDONE;
xta_set_callback(dev, 5 * HDC_TIME);
timer_advance_u64(&dev->timer, 5 * HDC_TIME);
break;
case STATE_RDONE:
@@ -845,7 +825,7 @@ do_recv:
case STATE_IDLE:
if (drive->present) {
dev->state = STATE_RDONE;
xta_set_callback(dev, 5 * HDC_TIME);
timer_advance_u64(&dev->timer, 5 * HDC_TIME);
} else {
dev->comp |= COMP_ERR;
dev->sense = ERR_NOTRDY;
@@ -866,7 +846,7 @@ do_recv:
switch (dev->state) {
case STATE_IDLE:
dev->state = STATE_RDONE;
xta_set_callback(dev, 10 * HDC_TIME);
timer_advance_u64(&dev->timer, 10 * HDC_TIME);
break;
case STATE_RDONE:
@@ -911,7 +891,7 @@ hdc_read(uint16_t port, void *priv)
/* All data sent. */
dev->status &= ~STAT_REQ;
dev->state = STATE_SDONE;
xta_set_callback(dev, HDC_TIME);
timer_set_delay_u64(&dev->timer, HDC_TIME);
}
} else if (dev->state == STATE_COMPL) {
xta_log("DCB=%02X status=%02X comp=%02X\n", dev->dcb.cmd, dev->status, dev->comp);
@@ -969,7 +949,7 @@ hdc_write(uint16_t port, uint8_t val, void *priv)
else
dev->state = STATE_IDLE;
dev->status &= ~STAT_CD;
xta_set_callback(dev, HDC_TIME);
timer_set_delay_u64(&dev->timer, HDC_TIME);
}
}
break;

View File

@@ -99,7 +99,7 @@
#include <86box/ui.h>
#include <86box/machine.h>
#define HDC_TIME (50 * TIMER_USEC)
#define HDC_TIME (250 * TIMER_USEC)
#define HDC_TYPE_USER 47 /* user drive type */
enum {
@@ -380,7 +380,6 @@ typedef struct hdc_t {
uint8_t *reg_91; /* handle to system board's register 0x91 */
/* Controller state. */
uint64_t callback;
pc_timer_t timer;
int8_t state; /* controller state */
int8_t reset; /* reset state counter */
@@ -463,6 +462,7 @@ static const geom_t ibm_type_table[] = {
// clang-format on
};
#define ENABLE_PS1_HDC_LOG 1
#ifdef ENABLE_PS1_HDC_LOG
int ps1_hdc_do_log = ENABLE_PS1_HDC_LOG;
@@ -481,22 +481,6 @@ ps1_hdc_log(const char *fmt, ...)
# define ps1_hdc_log(fmt, ...)
#endif
static void
hdc_set_callback(hdc_t *dev, uint64_t callback)
{
if (!dev) {
return;
}
if (callback) {
dev->callback = callback;
timer_set_delay_u64(&dev->timer, dev->callback);
} else {
dev->callback = 0;
timer_disable(&dev->timer);
}
}
/* FIXME: we should use the disk/hdd_table.c code with custom tables! */
static int
ibm_drive_type(drive_t *drive)
@@ -633,7 +617,7 @@ do_format(hdc_t *dev, drive_t *drive, ccb_t *ccb)
/* Enable for PIO or DMA, as needed. */
#if NOT_USED
if (dev->ctrl & ACR_DMA_EN)
hdc_set_callback(dev, HDC_TIME);
timer_advance_u64(&dev->timer, HDC_TIME);
else
#endif
dev->status |= ASR_DATA_REQ;
@@ -653,7 +637,7 @@ do_format(hdc_t *dev, drive_t *drive, ccb_t *ccb)
dev->buf_idx++;
}
dev->state = STATE_RDONE;
hdc_set_callback(dev, HDC_TIME);
timer_advance_u64(&dev->timer, HDC_TIME);
break;
case STATE_RDONE:
@@ -737,9 +721,7 @@ hdc_callback(void *priv)
off64_t addr;
int no_data = 0;
int val;
/* Cancel timer. */
dev->callback = 0;
uint8_t cmd = ccb->cmd & 0x0f;
/* Clear the SSB error bits. */
dev->ssb.track_0 = 0;
@@ -758,6 +740,8 @@ hdc_callback(void *priv)
/* We really only support one drive, but ohwell. */
drive = &dev->drives[0];
ps1_hdc_log("hdc_callback(): %02X\n", cmd);
switch (ccb->cmd) {
case CMD_READ_VERIFY:
no_data = 1;
@@ -812,12 +796,12 @@ do_send:
dev->buf_idx = 0;
if (no_data) {
/* Delay a bit, no actual transfer. */
hdc_set_callback(dev, HDC_TIME);
timer_advance_u64(&dev->timer, HDC_TIME);
} else {
if (dev->ctrl & ACR_DMA_EN) {
/* DMA enabled. */
dev->buf_ptr = dev->sector_buf;
hdc_set_callback(dev, HDC_TIME);
timer_advance_u64(&dev->timer, HDC_TIME);
} else {
/* No DMA, do PIO. */
dev->status |= (ASR_DATA_REQ | ASR_DIR);
@@ -852,7 +836,7 @@ do_send:
}
}
dev->state = STATE_SDONE;
hdc_set_callback(dev, HDC_TIME);
timer_advance_u64(&dev->timer, HDC_TIME);
break;
case STATE_SDONE:
@@ -880,7 +864,6 @@ do_send:
}
break;
case CMD_READ_EXT: /* READ_EXT */
case CMD_READ_ID: /* READ_ID */
if (!drive->present) {
dev->ssb.not_ready = 1;
@@ -888,6 +871,56 @@ do_send:
return;
}
switch (dev->state) {
case STATE_IDLE:
/* Seek to cylinder if requested. */
if (ccb->auto_seek) {
if (do_seek(dev, drive,
(ccb->cyl_low | (ccb->cyl_high << 8)))) {
do_finish(dev);
return;
}
}
dev->head = ccb->head;
/* Get sector count and size. */
dev->count = (int) ccb->count;
dev->buf_len = (128 << dev->ssb.sect_size);
/* Activate the status icon. */
ui_sb_update_icon(SB_HDD | HDD_BUS_XTA, 1);
/* Ready to transfer the data out. */
dev->state = STATE_SDONE;
dev->buf_idx = 0;
/* Delay a bit, no actual transfer. */
timer_advance_u64(&dev->timer, HDC_TIME);
break;
case STATE_SDONE:
dev->buf_idx = 0;
/* De-activate the status icon. */
ui_sb_update_icon(SB_HDD | HDD_BUS_XTA, 0);
if (!(dev->ctrl & ACR_DMA_EN))
dev->status &= ~(ASR_DATA_REQ | ASR_DIR);
dev->ssb.cmd_syndrome = 0x14;
do_finish(dev);
break;
default:
break;
}
break;
case CMD_READ_EXT: /* READ_EXT */
if (!drive->present) {
dev->ssb.not_ready = 1;
do_finish(dev);
return;
}
dev->intstat |= ISR_INVALID_CMD;
do_finish(dev);
break;
@@ -943,12 +976,12 @@ do_recv:
dev->buf_idx = 0;
if (no_data) {
/* Delay a bit, no actual transfer. */
hdc_set_callback(dev, HDC_TIME);
timer_advance_u64(&dev->timer, HDC_TIME);
} else {
if (dev->ctrl & ACR_DMA_EN) {
/* DMA enabled. */
dev->buf_ptr = dev->sector_buf;
hdc_set_callback(dev, HDC_TIME);
timer_advance_u64(&dev->timer, HDC_TIME);
} else {
/* No DMA, do PIO. */
dev->buf_ptr = dev->data;
@@ -978,7 +1011,7 @@ do_recv:
}
}
dev->state = STATE_RDONE;
hdc_set_callback(dev, HDC_TIME);
timer_advance_u64(&dev->timer, HDC_TIME);
break;
case STATE_RDONE:
@@ -1140,6 +1173,8 @@ hdc_read(uint16_t port, void *priv)
break;
}
ps1_hdc_log("[%04X:%08X] [R] %04X = %02X\n", CS, cpu_state.pc, port, ret);
return ret;
}
@@ -1148,6 +1183,8 @@ hdc_write(uint16_t port, uint8_t val, void *priv)
{
hdc_t *dev = (hdc_t *) priv;
ps1_hdc_log("[%04X:%08X] [W] %04X = %02X\n", CS, cpu_state.pc, port, val);
/* TRM: tell system board we are alive. */
*dev->reg_91 |= 0x01;
@@ -1164,6 +1201,7 @@ hdc_write(uint16_t port, uint8_t val, void *priv)
/* Store the data into the buffer. */
dev->buf_ptr[dev->buf_idx] = val;
ps1_hdc_log("dev->buf_ptr[%02X] = %02X\n", dev->buf_idx, val);
if (++dev->buf_idx == dev->buf_len) {
/* We got all the data we need. */
dev->status &= ~ASR_DATA_REQ;
@@ -1182,7 +1220,7 @@ hdc_write(uint16_t port, uint8_t val, void *priv)
dev->status |= ASR_BUSY;
/* Schedule command execution. */
hdc_set_callback(dev, HDC_TIME);
timer_set_delay_u64(&dev->timer, HDC_TIME);
}
}
}