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, ...)
{
@@ -216,7 +212,6 @@ esdi_mca_log(const char *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)
{
@@ -325,21 +323,20 @@ complete_command_status(esdi_t *dev)
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;
drive_t *drive;
int val;
double cmd_time = 0.0;
esdi_mca_set_callback(dev, 0);
@@ -410,14 +407,15 @@ esdi_callback(void *priv)
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);
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:
@@ -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;
}
@@ -495,17 +493,16 @@ 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);
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:
@@ -526,18 +523,30 @@ esdi_callback(void *priv)
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;
}
dev->rba += dev->sector_count;
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();
@@ -547,12 +556,28 @@ esdi_callback(void *priv)
return;
}
if ((dev->rba + dev->sector_count) > hdd_image_get_last_sector(drive->hdd_num)) {
rba_out_of_range(dev);
return;
}
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;
}
break;
case CMD_GET_DEV_STATUS:
ESDI_DRIVE_ONLY();
@@ -580,6 +605,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_DEV_CONFIG:
@@ -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:
@@ -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;
@@ -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,6 +786,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 CMD_FORMAT_UNIT:
@@ -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,7 +846,6 @@ esdi_callback(void *priv)
}
}
static uint8_t
esdi_read(uint16_t port, void *priv)
{
@@ -840,7 +869,6 @@ esdi_read(uint16_t port, void *priv)
return (ret);
}
static void
esdi_write(uint16_t port, uint8_t val, void *priv)
{
@@ -948,7 +976,6 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
}
}
static uint16_t
esdi_readw(uint16_t port, void *priv)
{
@@ -959,7 +986,8 @@ esdi_readw(uint16_t port, void *priv)
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) {
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;
}
@@ -972,7 +1000,6 @@ esdi_readw(uint16_t port, void *priv)
return (ret);
}
static void
esdi_writew(uint16_t port, uint16_t val, void *priv)
{
@@ -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,7 +1032,6 @@ esdi_writew(uint16_t port, uint16_t val, void *priv)
}
}
static uint8_t
esdi_mca_read(int port, void *priv)
{
@@ -1016,7 +1042,6 @@ esdi_mca_read(int port, void *priv)
return (dev->pos_regs[port & 7]);
}
static void
esdi_mca_write(int port, uint8_t val, void *priv)
{
@@ -1077,7 +1102,6 @@ esdi_mca_write(int port, uint8_t val, void *priv)
}
}
static uint8_t
esdi_mca_feedb(void *priv)
{
@@ -1086,7 +1110,6 @@ esdi_mca_feedb(void *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. */
@@ -1120,6 +1144,8 @@ esdi_init(const device_t *info)
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. */
@@ -1152,7 +1179,6 @@ esdi_init(const device_t *info)
return (dev);
}
static void
esdi_close(void *priv)
{
@@ -1171,7 +1197,6 @@ esdi_close(void *priv)
free(dev);
}
static int
esdi_available(void)
{