ESDI: implement HDD timings

This commit is contained in:
Adrien Moulin
2022-07-29 00:47:52 +02:00
parent fe98b05da3
commit 6e6436acd7
3 changed files with 68 additions and 22 deletions

View File

@@ -1386,6 +1386,7 @@ load_hard_disks(void)
sprintf(temp, "hdd_%02i_speed", c + 1);
switch (hdd[c].bus) {
case HDD_BUS_IDE:
case HDD_BUS_ESDI:
sprintf(tmp2, "1997_5400rpm");
break;
default:
@@ -2920,7 +2921,7 @@ save_hard_disks(void)
config_delete_var(cat, temp);
sprintf(temp, "hdd_%02i_speed", c + 1);
if (!hdd_is_valid(c) || (hdd[c].bus != HDD_BUS_IDE))
if (!hdd_is_valid(c) || (hdd[c].bus != HDD_BUS_IDE && hdd[c].bus != HDD_BUS_ESDI))
config_delete_var(cat, temp);
else
config_set_string(cat, temp, hdd_preset_get_internal_name(hdd[c].speed_preset));

View File

@@ -41,7 +41,7 @@
#include <86box/hdd.h>
#define HDC_TIME (TIMER_USEC*10LL)
#define HDC_TIME 10.0
#define BIOS_FILE "roms/hdd/esdi_at/62-000279-061.bin"
#define STAT_ERR 0x01
@@ -152,6 +152,26 @@ irq_update(esdi_t *esdi)
picint(1 << 14);
}
static void
esdi_set_callback(esdi_t *esdi, double callback)
{
if (!esdi) {
esdi_at_log("esdi_set_callback(NULL): Set callback failed\n");
return;
}
if (callback == 0.0)
timer_stop(&esdi->callback_timer);
else
timer_on_auto(&esdi->callback_timer, callback);
}
double
esdi_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;
}
/* Return the sector offset for the current register values. */
static int
@@ -160,7 +180,7 @@ get_sector(esdi_t *esdi, off64_t *addr)
drive_t *drive = &esdi->drives[esdi->drive_sel];
int heads = drive->cfg_hpc;
int sectors = drive->cfg_spt;
int c, h, s;
int c, h, s, sector;
if (esdi->head > heads) {
esdi_at_log("esdi_get_sector: past end of configured heads\n");
@@ -172,9 +192,11 @@ get_sector(esdi_t *esdi, off64_t *addr)
return(1);
}
sector = esdi->sector ? esdi->sector : 1;
if (drive->cfg_spt==drive->real_spt && drive->cfg_hpc==drive->real_hpc) {
*addr = ((((off64_t) esdi->cylinder * heads) + esdi->head) *
sectors) + (esdi->sector - 1);
sectors) + (sector - 1);
} else {
/*
* When performing translation, the firmware seems to leave 1
@@ -182,7 +204,7 @@ get_sector(esdi_t *esdi, off64_t *addr)
*/
*addr = ((((off64_t) esdi->cylinder * heads) + esdi->head) *
sectors) + (esdi->sector - 1);
sectors) + (sector - 1);
s = *addr % (drive->real_spt - 1);
h = (*addr / (drive->real_spt - 1)) % drive->real_hpc;
@@ -218,6 +240,7 @@ static void
esdi_writew(uint16_t port, uint16_t val, void *priv)
{
esdi_t *esdi = (esdi_t *)priv;
off64_t addr;
if (port > 0x01f0) {
esdi_write(port, val & 0xff, priv);
@@ -230,8 +253,10 @@ esdi_writew(uint16_t port, uint16_t val, void *priv)
if (esdi->pos >= 512) {
esdi->pos = 0;
esdi->status = STAT_BUSY;
/* 390.625 us per sector at 10 Mbit/s = 1280 kB/s. */
timer_set_delay_u64(&esdi->callback_timer, (3125 * TIMER_USEC) / 8);
get_sector(esdi, &addr);
double seek_time = hdd_timing_write(&hdd[esdi->drives[esdi->drive_sel].hdd_num], addr, 1);
double xfer_time = esdi_get_xfer_time(esdi, 1);
esdi_set_callback(esdi, seek_time + xfer_time);
}
}
}
@@ -241,6 +266,8 @@ static void
esdi_write(uint16_t port, uint8_t val, void *priv)
{
esdi_t *esdi = (esdi_t *)priv;
double seek_time, xfer_time;
off64_t addr;
esdi_at_log("WD1007 write(%04x, %02x)\n", port, val);
@@ -289,20 +316,22 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
case CMD_RESTORE:
esdi->command &= ~0x0f; /*mask off step rate*/
esdi->status = STAT_BUSY;
timer_set_delay_u64(&esdi->callback_timer, 200 * HDC_TIME);
esdi_set_callback(esdi, 200 * HDC_TIME);
break;
case CMD_SEEK:
esdi->command &= ~0x0f; /*mask off step rate*/
esdi->status = STAT_BUSY;
timer_set_delay_u64(&esdi->callback_timer, 200 * HDC_TIME);
get_sector(esdi, &addr);
seek_time = hdd_seek_get_time(&hdd[esdi->drives[esdi->drive_sel].hdd_num], addr, HDD_OP_SEEK, 0, 0.0);
esdi_set_callback(esdi, seek_time);
break;
default:
switch (val) {
case CMD_NOP:
esdi->status = STAT_BUSY;
timer_set_delay_u64(&esdi->callback_timer, 200 * HDC_TIME);
esdi_set_callback(esdi, 200 * HDC_TIME);
break;
case CMD_READ:
@@ -316,7 +345,10 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
case 0xa0:
esdi->status = STAT_BUSY;
timer_set_delay_u64(&esdi->callback_timer, 200 * HDC_TIME);
get_sector(esdi, &addr);
seek_time = hdd_timing_read(&hdd[esdi->drives[esdi->drive_sel].hdd_num], addr, 1);
xfer_time = esdi_get_xfer_time(esdi, 1);
esdi_set_callback(esdi, seek_time + xfer_time);
break;
case CMD_WRITE:
@@ -334,7 +366,10 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
case CMD_VERIFY+1:
esdi->command &= ~0x01;
esdi->status = STAT_BUSY;
timer_set_delay_u64(&esdi->callback_timer, 200 * HDC_TIME);
get_sector(esdi, &addr);
seek_time = hdd_timing_read(&hdd[esdi->drives[esdi->drive_sel].hdd_num], addr, 1);
xfer_time = esdi_get_xfer_time(esdi, 1);
esdi_set_callback(esdi, seek_time + xfer_time);
break;
case CMD_FORMAT:
@@ -344,18 +379,18 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
case CMD_SET_PARAMETERS: /* Initialize Drive Parameters */
esdi->status = STAT_BUSY;
timer_set_delay_u64(&esdi->callback_timer, 30 * HDC_TIME);
esdi_set_callback(esdi, 30 * HDC_TIME);
break;
case CMD_DIAGNOSE: /* Execute Drive Diagnostics */
esdi->status = STAT_BUSY;
timer_set_delay_u64(&esdi->callback_timer, 200 * HDC_TIME);
esdi_set_callback(esdi, 200 * HDC_TIME);
break;
case 0xe0: /*???*/
case CMD_READ_PARAMETERS:
esdi->status = STAT_BUSY;
timer_set_delay_u64(&esdi->callback_timer, 200 * HDC_TIME);
esdi_set_callback(esdi, 200 * HDC_TIME);
break;
default:
@@ -363,7 +398,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
/*FALLTHROUGH*/
case 0xe8: /*???*/
esdi->status = STAT_BUSY;
timer_set_delay_u64(&esdi->callback_timer, 200 * HDC_TIME);
esdi_set_callback(esdi, 200 * HDC_TIME);
break;
}
}
@@ -371,14 +406,14 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
case 0x3f6: /* Device control */
if ((esdi->fdisk & 0x04) && !(val & 0x04)) {
timer_set_delay_u64(&esdi->callback_timer, 500 * HDC_TIME);
esdi_set_callback(esdi, 500 * HDC_TIME);
esdi->reset = 1;
esdi->status = STAT_BUSY;
}
if (val & 0x04) {
/* Drive held in reset. */
timer_disable(&esdi->callback_timer);
esdi_set_callback(esdi, 0);
esdi->status = STAT_BUSY;
}
esdi->fdisk = val;
@@ -393,6 +428,7 @@ esdi_readw(uint16_t port, void *priv)
{
esdi_t *esdi = (esdi_t *)priv;
uint16_t temp;
off64_t addr;
if (port > 0x01f0) {
temp = esdi_read(port, priv);
@@ -412,8 +448,11 @@ esdi_readw(uint16_t port, void *priv)
if (esdi->secount) {
next_sector(esdi);
esdi->status = STAT_BUSY;
get_sector(esdi, &addr);
double seek_time = hdd_timing_read(&hdd[esdi->drives[esdi->drive_sel].hdd_num], addr, 1);
double xfer_time = esdi_get_xfer_time(esdi, 1);
/* 390.625 us per sector at 10 Mbit/s = 1280 kB/s. */
timer_set_delay_u64(&esdi->callback_timer, (3125 * TIMER_USEC) / 8);
esdi_set_callback(esdi, seek_time + xfer_time);
} else
ui_sb_update_icon(SB_HDD|HDD_BUS_ESDI, 0);
}
@@ -477,6 +516,7 @@ esdi_callback(void *priv)
esdi_t *esdi = (esdi_t *)priv;
drive_t *drive = &esdi->drives[esdi->drive_sel];
off64_t addr;
double seek_time;
if (esdi->reset) {
esdi->status = STAT_READY|STAT_DSC;
@@ -580,9 +620,11 @@ esdi_callback(void *priv)
ui_sb_update_icon(SB_HDD|HDD_BUS_ESDI, 1);
next_sector(esdi);
esdi->secount = (esdi->secount - 1) & 0xff;
if (esdi->secount)
timer_set_delay_u64(&esdi->callback_timer, 6 * HDC_TIME);
else {
if (esdi->secount) {
get_sector(esdi, &addr);
seek_time = hdd_timing_read(&hdd[esdi->drives[esdi->drive_sel].hdd_num], addr, 1);
esdi_set_callback(esdi, seek_time + HDC_TIME);
} else {
esdi->pos = 0;
esdi->status = STAT_READY|STAT_DSC;
irq_raise(esdi);
@@ -752,6 +794,8 @@ loadhd(esdi_t *esdi, int hdd_num, int d, const char *fn)
return;
}
hdd_preset_apply(d);
drive->cfg_spt = drive->real_spt = hdd[d].spt;
drive->cfg_hpc = drive->real_hpc = hdd[d].hpc;
drive->real_tracks = hdd[d].tracks;

View File

@@ -59,6 +59,7 @@ void Harddrives::populateSpeeds(QAbstractItemModel *model, int bus) {
switch (bus) {
case HDD_BUS_IDE:
case HDD_BUS_ESDI:
num_preset = hdd_preset_get_num();
break;