From 0cd02a1ad91dc0b84a405791b55a0f0117ac8370 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 1 Nov 2019 03:43:56 +0100 Subject: [PATCH] AT MFM hard disk controller fixes. --- src/disk/hdc_st506_at.c | 71 +++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 41 deletions(-) diff --git a/src/disk/hdc_st506_at.c b/src/disk/hdc_st506_at.c index cde098d2c..683ade1fc 100644 --- a/src/disk/hdc_st506_at.c +++ b/src/disk/hdc_st506_at.c @@ -12,7 +12,7 @@ * based design. Most cards were WD1003-WA2 or -WAH, where the * -WA2 cards had a floppy controller as well (to save space.) * - * Version: @(#)hdc_st506_at.c 1.0.20 2019/09/29 + * Version: @(#)hdc_st506_at.c 1.0.21 2019/11/01 * * Authors: Sarah Walker, * Fred N. van Kempen, @@ -112,8 +112,7 @@ typedef struct { pad; int pos; /* offset within data buffer */ - uint64_t callback; /* callback delay timer */ - pc_timer_t timer; + pc_timer_t callback_timer; /* callback delay timer */ uint16_t buffer[256]; /* data buffer (16b wide) */ @@ -154,12 +153,16 @@ irq_raise(mfm_t *mfm) static inline void irq_lower(mfm_t *mfm) { - if (mfm->irqstat) { - if (!(mfm->fdisk & 2)) - picintc(1 << 14); + picintc(1 << 14); +} - mfm->irqstat = 0; - } + + +static void +irq_update(mfm_t *mfm) +{ + if (mfm->irqstat && !((pic2.pend | pic2.ins) & 0x40) && !(mfm->fdisk & 2)) + picint(1 << 14); } @@ -182,12 +185,10 @@ get_sector(mfm_t *mfm, off64_t *addr) /* FIXME: See if this is even needed - if the code is present, IBM AT diagnostics v2.07 will error with: ERROR 152 - SYSTEM BOARD. */ -#ifdef FIXME if (drive->curcyl != mfm->cylinder) { st506_at_log("WD1003(%d) sector: wrong cylinder\n"); return(1); } -#endif if (mfm->head > drive->cfg_hpc) { st506_at_log("WD1003(%d) get_sector: past end of configured heads\n", @@ -201,7 +202,6 @@ get_sector(mfm_t *mfm, off64_t *addr) return(1); } -#if 1 /* We should check this in the SET_DRIVE_PARAMETERS command! --FvK */ if (mfm->head > drive->hpc) { st506_at_log("WD1003(%d) get_sector: past end of heads\n", mfm->drvsel); @@ -212,7 +212,6 @@ get_sector(mfm_t *mfm, off64_t *addr) st506_at_log("WD1003(%d) get_sector: past end of sectors\n", mfm->drvsel); return(1); } -#endif *addr = ((((off64_t) mfm->cylinder * drive->cfg_hpc) + mfm->head) * drive->cfg_spt) + (mfm->sector - 1); @@ -238,20 +237,6 @@ next_sector(mfm_t *mfm) } } -static void -mfm_set_callback(mfm_t *mfm, uint64_t callback) -{ - if (!mfm) - return; - - if (callback) { - mfm->callback = callback; - timer_set_delay_u64(&mfm->timer, mfm->callback); - } else { - mfm->callback = 0ULL; - timer_disable(&mfm->timer); - } -} static void mfm_cmd(mfm_t *mfm, uint8_t val) @@ -264,7 +249,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val) mfm->drvsel, val); mfm->command = 0xff; mfm->status = STAT_BUSY; - mfm_set_callback(mfm, 200 * MFM_TIME); + timer_set_delay_u64(&mfm->callback_timer, 200 * MFM_TIME); return; } @@ -278,6 +263,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val) st506_at_log("WD1003(%d) restore, step=%d\n", mfm->drvsel, drive->steprate); drive->curcyl = 0; + mfm->cylinder = 0; mfm->status = STAT_READY|STAT_DSC; mfm->command &= 0xf0; irq_raise(mfm); @@ -287,7 +273,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val) drive->steprate = (val & 0x0f); mfm->command &= 0xf0; mfm->status = STAT_BUSY; - mfm_set_callback(mfm, 200 * MFM_TIME); + timer_set_delay_u64(&mfm->callback_timer, 200 * MFM_TIME); break; default: @@ -303,7 +289,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val) if (val & 2) fatal("WD1003: READ with ECC\n"); mfm->status = STAT_BUSY; - mfm_set_callback(mfm, 200 * MFM_TIME); + timer_set_delay_u64(&mfm->callback_timer, 200 * MFM_TIME); break; case CMD_WRITE: @@ -323,7 +309,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val) case CMD_VERIFY+1: mfm->command &= 0xfe; mfm->status = STAT_BUSY; - mfm_set_callback(mfm, 200 * MFM_TIME); + timer_set_delay_u64(&mfm->callback_timer, 200 * MFM_TIME); break; case CMD_FORMAT: @@ -333,7 +319,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val) case CMD_DIAGNOSE: mfm->status = STAT_BUSY; - mfm_set_callback(mfm, 200 * MFM_TIME); + timer_set_delay_u64(&mfm->callback_timer, 200 * MFM_TIME); break; case CMD_SET_PARAMETERS: @@ -374,7 +360,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val) default: st506_at_log("WD1003: bad command %02X\n", val); mfm->status = STAT_BUSY; - mfm_set_callback(mfm, 200 * MFM_TIME); + timer_set_delay_u64(&mfm->callback_timer, 200 * MFM_TIME); break; } } @@ -392,7 +378,7 @@ mfm_writew(uint16_t port, uint16_t val, void *priv) if (mfm->pos >= 512) { mfm->pos = 0; mfm->status = STAT_BUSY; - mfm_set_callback(mfm, SECTOR_TIME); + timer_set_delay_u64(&mfm->callback_timer, SECTOR_TIME); } } @@ -445,20 +431,18 @@ mfm_write(uint16_t port, uint8_t val, void *priv) case 0x03f6: /* device control */ val &= 0x0f; if ((mfm->fdisk & 0x04) && !(val & 0x04)) { - mfm_set_callback(mfm, 500 * MFM_TIME); + timer_set_delay_u64(&mfm->callback_timer, 500 * MFM_TIME); mfm->reset = 1; mfm->status = STAT_BUSY; } if (val & 0x04) { /* Drive held in reset. */ - mfm_set_callback(mfm, 0); + timer_disable(&mfm->callback_timer); mfm->status = STAT_BUSY; } mfm->fdisk = val; - /* Lower IRQ on IRQ disable. */ - if ((val & 2) && !(mfm->fdisk & 0x02)) - picintc(1 << 14); + irq_update(mfm); break; } } @@ -480,7 +464,7 @@ mfm_readw(uint16_t port, void *priv) if (mfm->secount) { next_sector(mfm); mfm->status = STAT_BUSY; - mfm_set_callback(mfm, SECTOR_TIME); + timer_set_delay_u64(&mfm->callback_timer, SECTOR_TIME); } else ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 0); } @@ -562,7 +546,6 @@ do_callback(void *priv) drive_t *drive = &mfm->drives[mfm->drvsel]; off64_t addr; - mfm_set_callback(mfm, 0); if (mfm->reset) { st506_at_log("WD1003(%d) reset\n", mfm->drvsel); @@ -667,6 +650,12 @@ do_callback(void *priv) case CMD_DIAGNOSE: st506_at_log("WD1003(%d) diag\n", mfm->drvsel); + + /* This is basically controller diagnostics - it resets drive select to 0, + and resets error and status to ready, DSC, and no error detected. */ + mfm->drvsel = 0; + drive = &mfm->drives[mfm->drvsel]; + drive->steprate = 0x0f; mfm->error = 1; mfm->status = STAT_READY|STAT_DSC; @@ -735,7 +724,7 @@ mfm_init(const device_t *info) io_sethandler(0x03f6, 1, NULL, NULL, NULL, mfm_write, NULL, NULL, mfm); - timer_add(&mfm->timer, do_callback, mfm, 0); + timer_add(&mfm->callback_timer, do_callback, mfm, 0); ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 0);