ESDI MCA: implement HDD timings and fix status icon updating (#2538)

* esdi_mca: clang-format

* esdi_mca: implement hdd timings

* esdi_mca: fix drive status icon updating
This commit is contained in:
Adrien Moulin
2022-07-30 17:14:03 +02:00
committed by GitHub
parent 0cc716bf6b
commit 7aec47583d

View File

@@ -60,12 +60,14 @@
* Copyright 2008-2018 Sarah Walker.
* Copyright 2017,2018 Fred N. van Kempen.
*/
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include <inttypes.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
@@ -80,7 +82,6 @@
#include <86box/hdc.h>
#include <86box/hdd.h>
/* These are hardwired. */
#define ESDI_IOADDR_PRI 0x3510
#define ESDI_IOADDR_SEC 0x3518
@@ -89,11 +90,9 @@
#define BIOS_FILE_L "roms/hdd/esdi/90x8969.bin"
#define BIOS_FILE_H "roms/hdd/esdi/90x8970.bin"
#define ESDI_TIME 512
#define ESDI_TIME 512.0
#define CMD_ADAPTER 0
typedef struct esdi_drive_t {
int spt, hpc;
int tracks;
@@ -134,7 +133,6 @@ typedef struct esdi_t {
int cmd_state;
int in_reset;
uint64_t callback;
pc_timer_t timer;
uint32_t rba;
@@ -196,11 +194,9 @@ typedef struct esdi_t {
#define STATUS_DEVICE(x) ((x) << 5)
#define STATUS_DEVICE_HOST_ADAPTER (7 << 5)
#ifdef ENABLE_ESDI_MCA_LOG
int esdi_mca_do_log = ENABLE_ESDI_MCA_LOG;
static void
esdi_mca_log(const char *fmt, ...)
{
@@ -213,10 +209,9 @@ esdi_mca_log(const char *fmt, ...)
}
}
#else
#define esdi_mca_log(fmt, ...)
# define esdi_mca_log(fmt, ...)
#endif
static __inline void
set_irq(esdi_t *dev)
{
@@ -224,7 +219,6 @@ set_irq(esdi_t *dev)
picint(1 << 14);
}
static __inline void
clear_irq(esdi_t *dev)
{
@@ -232,21 +226,25 @@ clear_irq(esdi_t *dev)
}
static void
esdi_mca_set_callback(esdi_t *dev, uint64_t callback)
esdi_mca_set_callback(esdi_t *dev, double callback)
{
if (!dev) {
return;
}
if (callback) {
dev->callback = callback;
timer_on_auto(&dev->timer, dev->callback);
timer_on_auto(&dev->timer, callback);
} else {
dev->callback = 0;
timer_stop(&dev->timer);
}
}
static double
esdi_mca_get_xfer_time(esdi_t *esdi, int size)
{
/* 390.625 us per sector at 10 Mbit/s = 1280 kB/s. */
return (3125.0 / 8.0) * (double)size;
}
static void
cmd_unsupported(esdi_t *dev)
@@ -266,9 +264,9 @@ cmd_unsupported(esdi_t *dev)
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_FAILURE;
dev->irq_in_progress = 1;
set_irq(dev);
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0);
}
static void
device_not_present(esdi_t *dev)
{
@@ -287,9 +285,9 @@ device_not_present(esdi_t *dev)
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_FAILURE;
dev->irq_in_progress = 1;
set_irq(dev);
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0);
}
static void
rba_out_of_range(esdi_t *dev)
{
@@ -308,9 +306,9 @@ rba_out_of_range(esdi_t *dev)
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_FAILURE;
dev->irq_in_progress = 1;
set_irq(dev);
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0);
}
static void
complete_command_status(esdi_t *dev)
{
@@ -322,24 +320,23 @@ complete_command_status(esdi_t *dev)
dev->status_data[1] = 0x0000; /*Error bits*/
dev->status_data[2] = 0x1900; /*Device status*/
dev->status_data[3] = 0; /*Number of blocks left to do*/
dev->status_data[4] = (dev->rba-1) & 0xffff; /*Last RBA processed*/
dev->status_data[5] = (dev->rba-1) >> 8;
dev->status_data[4] = (dev->rba - 1) & 0xffff; /*Last RBA processed*/
dev->status_data[5] = (dev->rba - 1) >> 8;
dev->status_data[6] = 0; /*Number of blocks requiring error recovery*/
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0);
}
#define ESDI_ADAPTER_ONLY() do \
{ \
if (dev->cmd_dev != ATTN_HOST_ADAPTER) \
{ \
#define ESDI_ADAPTER_ONLY() \
do { \
if (dev->cmd_dev != ATTN_HOST_ADAPTER) { \
cmd_unsupported(dev); \
return; \
} \
} while (0)
#define ESDI_DRIVE_ONLY() do \
{ \
if (dev->cmd_dev != ATTN_DEVICE_0 && dev->cmd_dev != ATTN_DEVICE_1) \
{ \
#define ESDI_DRIVE_ONLY() \
do { \
if (dev->cmd_dev != ATTN_DEVICE_0 && dev->cmd_dev != ATTN_DEVICE_1) { \
cmd_unsupported(dev); \
return; \
} \
@@ -349,13 +346,13 @@ complete_command_status(esdi_t *dev)
drive = &dev->drives[1]; \
} while (0)
static void
esdi_callback(void *priv)
{
esdi_t *dev = (esdi_t *)priv;
esdi_t *dev = (esdi_t *) priv;
drive_t *drive;
int val;
double cmd_time = 0.0;
esdi_mca_set_callback(dev, 0);
@@ -372,7 +369,7 @@ esdi_callback(void *priv)
case CMD_READ:
ESDI_DRIVE_ONLY();
if (! drive->present) {
if (!drive->present) {
device_not_present(dev);
return;
}
@@ -406,18 +403,19 @@ esdi_callback(void *priv)
}
while (dev->sector_pos < dev->sector_count) {
if (! dev->data_pos) {
if (!dev->data_pos) {
if (dev->rba >= drive->sectors)
fatal("Read past end of drive\n");
hdd_image_read(drive->hdd_num, dev->rba, 1, (uint8_t *)dev->data);
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 1);
hdd_image_read(drive->hdd_num, dev->rba, 1, (uint8_t *) dev->data);
cmd_time += hdd_timing_read(&hdd[drive->hdd_num], dev->rba, 1);
cmd_time += esdi_mca_get_xfer_time(dev, 1);
}
while (dev->data_pos < 256) {
val = dma_channel_write(dev->dma, dev->data[dev->data_pos]);
if (val == DMA_NODATA) {
esdi_mca_set_callback(dev, ESDI_TIME);
esdi_mca_set_callback(dev, ESDI_TIME + cmd_time);
return;
}
@@ -431,7 +429,7 @@ esdi_callback(void *priv)
dev->status = STATUS_CMD_IN_PROGRESS;
dev->cmd_state = 2;
esdi_mca_set_callback(dev, ESDI_TIME);
esdi_mca_set_callback(dev, cmd_time);
break;
case 2:
@@ -447,7 +445,7 @@ esdi_callback(void *priv)
case CMD_WRITE:
case CMD_WRITE_VERIFY:
ESDI_DRIVE_ONLY();
if (! drive->present) {
if (!drive->present) {
device_not_present(dev);
return;
}
@@ -475,7 +473,7 @@ esdi_callback(void *priv)
break;
case 1:
if (! (dev->basic_ctrl & CTRL_DMA_ENA)) {
if (!(dev->basic_ctrl & CTRL_DMA_ENA)) {
esdi_mca_set_callback(dev, ESDI_TIME);
return;
}
@@ -485,7 +483,7 @@ esdi_callback(void *priv)
val = dma_channel_read(dev->dma);
if (val == DMA_NODATA) {
esdi_mca_set_callback(dev, ESDI_TIME);
esdi_mca_set_callback(dev, ESDI_TIME + cmd_time);
return;
}
@@ -494,18 +492,17 @@ esdi_callback(void *priv)
if (dev->rba >= drive->sectors)
fatal("Write past end of drive\n");
hdd_image_write(drive->hdd_num, dev->rba, 1, (uint8_t *)dev->data);
hdd_image_write(drive->hdd_num, dev->rba, 1, (uint8_t *) dev->data);
cmd_time += hdd_timing_write(&hdd[drive->hdd_num], dev->rba, 1);
cmd_time += esdi_mca_get_xfer_time(dev, 1);
dev->rba++;
dev->sector_pos++;
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI,
dev->cmd_dev == ATTN_DEVICE_0 ? 0 : 1);
dev->data_pos = 0;
}
dev->status = STATUS_CMD_IN_PROGRESS;
dev->cmd_state = 2;
esdi_mca_set_callback(dev, ESDI_TIME);
esdi_mca_set_callback(dev, cmd_time);
break;
case 2:
@@ -521,7 +518,40 @@ esdi_callback(void *priv)
case CMD_READ_VERIFY:
ESDI_DRIVE_ONLY();
if (! drive->present) {
if (!drive->present) {
device_not_present(dev);
return;
}
switch (dev->cmd_state) {
case 0:
dev->rba = (dev->cmd_data[2] | (dev->cmd_data[3] << 16)) & 0x0fffffff;
dev->sector_count = dev->cmd_data[1];
if ((dev->rba + dev->sector_count) > hdd_image_get_last_sector(drive->hdd_num)) {
rba_out_of_range(dev);
return;
}
cmd_time = hdd_timing_read(&hdd[drive->hdd_num], dev->rba, dev->sector_count);
esdi_mca_set_callback(dev, ESDI_TIME + cmd_time);
dev->cmd_state = 1;
break;
case 1:
complete_command_status(dev);
dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL;
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS;
dev->irq_in_progress = 1;
set_irq(dev);
break;
}
break;
case CMD_SEEK:
ESDI_DRIVE_ONLY();
if (!drive->present) {
device_not_present(dev);
return;
}
@@ -531,33 +561,28 @@ esdi_callback(void *priv)
return;
}
dev->rba += dev->sector_count;
switch (dev->cmd_state) {
case 0:
dev->rba = (dev->cmd_data[2] | (dev->cmd_data[3] << 16)) & 0x0fffffff;
cmd_time = hdd_seek_get_time(&hdd[drive->hdd_num], dev->rba, HDD_OP_SEEK, 0, 0.0);
esdi_mca_set_callback(dev, ESDI_TIME + cmd_time);
dev->cmd_state = 1;
break;
case 1:
complete_command_status(dev);
dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL;
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS;
dev->irq_in_progress = 1;
set_irq(dev);
break;
case CMD_SEEK:
ESDI_DRIVE_ONLY();
if (! drive->present) {
device_not_present(dev);
return;
}
complete_command_status(dev);
dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL;
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS;
dev->irq_in_progress = 1;
set_irq(dev);
break;
case CMD_GET_DEV_STATUS:
ESDI_DRIVE_ONLY();
if (! drive->present) {
if (!drive->present) {
device_not_present(dev);
return;
}
@@ -580,12 +605,13 @@ esdi_callback(void *priv)
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS;
dev->irq_in_progress = 1;
set_irq(dev);
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0);
break;
case CMD_GET_DEV_CONFIG:
ESDI_DRIVE_ONLY();
if (! drive->present) {
if (!drive->present) {
device_not_present(dev);
return;
}
@@ -611,6 +637,7 @@ esdi_callback(void *priv)
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS;
dev->irq_in_progress = 1;
set_irq(dev);
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0);
break;
case CMD_GET_POS_INFO:
@@ -622,8 +649,7 @@ esdi_callback(void *priv)
dev->status_len = 5;
dev->status_data[0] = CMD_GET_POS_INFO | STATUS_LEN(5) | STATUS_DEVICE_HOST_ADAPTER;
dev->status_data[1] = 0xffdd; /*MCA ID*/
dev->status_data[2] = dev->pos_regs[3] |
(dev->pos_regs[2] << 8);
dev->status_data[2] = dev->pos_regs[3] | (dev->pos_regs[2] << 8);
dev->status_data[3] = 0xff;
dev->status_data[4] = 0xff;
@@ -631,6 +657,7 @@ esdi_callback(void *priv)
dev->irq_status = IRQ_HOST_ADAPTER | IRQ_CMD_COMPLETE_SUCCESS;
dev->irq_in_progress = 1;
set_irq(dev);
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0);
break;
case 0x10:
@@ -653,7 +680,7 @@ esdi_callback(void *priv)
break;
case 1:
if (! (dev->basic_ctrl & CTRL_DMA_ENA)) {
if (!(dev->basic_ctrl & CTRL_DMA_ENA)) {
esdi_mca_set_callback(dev, ESDI_TIME);
return;
}
@@ -666,7 +693,8 @@ esdi_callback(void *priv)
return;
}
dev->data[dev->data_pos++] = val & 0xffff;;
dev->data[dev->data_pos++] = val & 0xffff;
;
}
memcpy(dev->sector_buffer[dev->sector_pos++], dev->data, 512);
@@ -683,6 +711,7 @@ esdi_callback(void *priv)
dev->irq_status = IRQ_HOST_ADAPTER | IRQ_CMD_COMPLETE_SUCCESS;
dev->irq_in_progress = 1;
set_irq(dev);
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0);
break;
}
break;
@@ -707,13 +736,13 @@ esdi_callback(void *priv)
break;
case 1:
if (! (dev->basic_ctrl & CTRL_DMA_ENA)) {
if (!(dev->basic_ctrl & CTRL_DMA_ENA)) {
esdi_mca_set_callback(dev, ESDI_TIME);
return;
}
while (dev->sector_pos < dev->sector_count) {
if (! dev->data_pos)
if (!dev->data_pos)
memcpy(dev->data, dev->sector_buffer[dev->sector_pos++], 512);
while (dev->data_pos < 256) {
val = dma_channel_write(dev->dma, dev->data[dev->data_pos]);
@@ -739,6 +768,7 @@ esdi_callback(void *priv)
dev->irq_status = IRQ_HOST_ADAPTER | IRQ_CMD_COMPLETE_SUCCESS;
dev->irq_in_progress = 1;
set_irq(dev);
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0);
break;
}
break;
@@ -756,13 +786,14 @@ esdi_callback(void *priv)
dev->irq_status = IRQ_HOST_ADAPTER | IRQ_CMD_COMPLETE_SUCCESS;
dev->irq_in_progress = 1;
set_irq(dev);
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0);
break;
case CMD_FORMAT_UNIT:
case CMD_FORMAT_PREPARE:
ESDI_DRIVE_ONLY();
if (! drive->present) {
if (!drive->present) {
device_not_present(dev);
return;
}
@@ -794,7 +825,6 @@ esdi_callback(void *priv)
}
hdd_image_zero(drive->hdd_num, dev->rba, dev->sector_count);
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 1);
dev->status = STATUS_CMD_IN_PROGRESS;
dev->cmd_state = 2;
@@ -816,11 +846,10 @@ esdi_callback(void *priv)
}
}
static uint8_t
esdi_read(uint16_t port, void *priv)
{
esdi_t *dev = (esdi_t *)priv;
esdi_t *dev = (esdi_t *) priv;
uint8_t ret = 0xff;
switch (port & 7) {
@@ -837,14 +866,13 @@ esdi_read(uint16_t port, void *priv)
fatal("esdi_read port=%04x\n", port);
}
return(ret);
return (ret);
}
static void
esdi_write(uint16_t port, uint8_t val, void *priv)
{
esdi_t *dev = (esdi_t *)priv;
esdi_t *dev = (esdi_t *) priv;
esdi_mca_log("ESDI: wr(%04x, %02x)\n", port & 7, val);
@@ -857,7 +885,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
}
dev->basic_ctrl = val;
if (! (dev->basic_ctrl & CTRL_IRQ_ENA))
if (!(dev->basic_ctrl & CTRL_IRQ_ENA))
picintc(1 << 14);
break;
@@ -948,18 +976,18 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
}
}
static uint16_t
esdi_readw(uint16_t port, void *priv)
{
esdi_t *dev = (esdi_t *)priv;
esdi_t *dev = (esdi_t *) priv;
uint16_t ret = 0xffff;
switch (port & 7) {
case 0: /*Status Interface Register*/
if (dev->status_pos >= dev->status_len)
return(0);
ret = dev->status_data[dev->status_pos++]; if (dev->status_pos >= dev->status_len) {
return (0);
ret = dev->status_data[dev->status_pos++];
if (dev->status_pos >= dev->status_len) {
dev->status &= ~STATUS_STATUS_OUT_FULL;
dev->status_pos = dev->status_len = 0;
}
@@ -969,14 +997,13 @@ esdi_readw(uint16_t port, void *priv)
fatal("esdi_readw port=%04x\n", port);
}
return(ret);
return (ret);
}
static void
esdi_writew(uint16_t port, uint16_t val, void *priv)
{
esdi_t *dev = (esdi_t *)priv;
esdi_t *dev = (esdi_t *) priv;
esdi_mca_log("ESDI: wrw(%04x, %04x)\n", port & 7, val);
@@ -985,8 +1012,7 @@ esdi_writew(uint16_t port, uint16_t val, void *priv)
if (dev->cmd_pos >= 4)
fatal("CIR pos 4\n");
dev->cmd_data[dev->cmd_pos++] = val;
if (((dev->cmd_data[0] & CMD_SIZE_4) && dev->cmd_pos == 4) ||
(!(dev->cmd_data[0] & CMD_SIZE_4) && dev->cmd_pos == 2)) {
if (((dev->cmd_data[0] & CMD_SIZE_4) && dev->cmd_pos == 4) || (!(dev->cmd_data[0] & CMD_SIZE_4) && dev->cmd_pos == 2)) {
dev->cmd_pos = 0;
dev->cmd_req_in_progress = 0;
dev->cmd_state = 0;
@@ -997,6 +1023,7 @@ esdi_writew(uint16_t port, uint16_t val, void *priv)
esdi_mca_set_callback(dev, ESDI_TIME);
dev->status = STATUS_BUSY;
dev->data_pos = 0;
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 1);
}
break;
@@ -1005,22 +1032,20 @@ esdi_writew(uint16_t port, uint16_t val, void *priv)
}
}
static uint8_t
esdi_mca_read(int port, void *priv)
{
esdi_t *dev = (esdi_t *)priv;
esdi_t *dev = (esdi_t *) priv;
esdi_mca_log("ESDI: mcard(%04x)\n", port);
return(dev->pos_regs[port & 7]);
return (dev->pos_regs[port & 7]);
}
static void
esdi_mca_write(int port, uint8_t val, void *priv)
{
esdi_t *dev = (esdi_t *)priv;
esdi_t *dev = (esdi_t *) priv;
esdi_mca_log("ESDI: mcawr(%04x, %02x) pos[2]=%02x pos[3]=%02x\n",
port, val, dev->pos_regs[2], dev->pos_regs[3]);
@@ -1036,7 +1061,7 @@ esdi_mca_write(int port, uint8_t val, void *priv)
esdi_write, esdi_writew, NULL, dev);
mem_mapping_disable(&dev->bios_rom.mapping);
switch(dev->pos_regs[2] & 0x3c) {
switch (dev->pos_regs[2] & 0x3c) {
case 0x14:
dev->dma = 5;
break;
@@ -1077,16 +1102,14 @@ esdi_mca_write(int port, uint8_t val, void *priv)
}
}
static uint8_t
esdi_mca_feedb(void *priv)
{
esdi_t *dev = (esdi_t *)priv;
esdi_t *dev = (esdi_t *) priv;
return (dev->pos_regs[2] & 1);
}
static void *
esdi_init(const device_t *info)
{
@@ -1095,7 +1118,8 @@ esdi_init(const device_t *info)
int c, i;
dev = malloc(sizeof(esdi_t));
if (dev == NULL) return(NULL);
if (dev == NULL)
return (NULL);
memset(dev, 0x00, sizeof(esdi_t));
/* Mark as unconfigured. */
@@ -1108,18 +1132,20 @@ esdi_init(const device_t *info)
dev->drives[0].present = dev->drives[1].present = 0;
for (c=0,i=0; i<HDD_NUM; i++) {
for (c = 0, i = 0; i < HDD_NUM; i++) {
if ((hdd[i].bus == HDD_BUS_ESDI) && (hdd[i].esdi_channel < ESDI_NUM)) {
/* This is an ESDI drive. */
drive = &dev->drives[hdd[i].esdi_channel];
/* Try to load an image for the drive. */
if (! hdd_image_load(i)) {
if (!hdd_image_load(i)) {
/* Nope. */
drive->present = 0;
continue;
}
hdd_preset_apply(i);
/* OK, so fill in geometry info. */
drive->spt = hdd[i].spt;
drive->hpc = hdd[i].hpc;
@@ -1131,7 +1157,8 @@ esdi_init(const device_t *info)
drive->present = 1;
}
if (++c >= ESDI_NUM) break;
if (++c >= ESDI_NUM)
break;
}
/* Set the MCA ID for this controller, 0xFFDD. */
@@ -1149,20 +1176,19 @@ esdi_init(const device_t *info)
/* Set the reply timer. */
timer_add(&dev->timer, esdi_callback, dev, 0);
return(dev);
return (dev);
}
static void
esdi_close(void *priv)
{
esdi_t *dev = (esdi_t *)priv;
esdi_t *dev = (esdi_t *) priv;
drive_t *drive;
int d;
dev->drives[0].present = dev->drives[1].present = 0;
for (d=0; d<2; d++) {
for (d = 0; d < 2; d++) {
drive = &dev->drives[d];
hdd_image_close(drive->hdd_num);
@@ -1171,11 +1197,10 @@ esdi_close(void *priv)
free(dev);
}
static int
esdi_available(void)
{
return(rom_present(BIOS_FILE_L) && rom_present(BIOS_FILE_H));
return (rom_present(BIOS_FILE_L) && rom_present(BIOS_FILE_H));
}
const device_t esdi_ps2_device = {