From 5acf6483a6a706fcd0c2abadc2800def5643f6e6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 2 Feb 2018 04:54:35 +0100 Subject: [PATCH] Reduced FDC RECALIBRATE and SEEK timings when the FDC is in PCjr mode, made the SENSE INTERRUPT STATUS command no longer stop the in progress RECALIBRATE or SEEK, and fixed the FDC data ready flag in non-DMA mode, fixes floppies on PCjr. --- src/floppy/fdc.c | 162 ++++++++++++++++++++++++++--------------------- 1 file changed, 89 insertions(+), 73 deletions(-) diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index e41e44f81..3e19893ca 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -303,6 +303,8 @@ fdc_fifo_buf_read(fdc_t *fdc) { int temp = fdc->fifobuf[fdc->fifobufpos]; fdc_fifo_buf_advance(fdc); + if (!fdc->fifobufpos) + fdc->data_ready = 0; return temp; } @@ -315,6 +317,9 @@ void fdc_int(fdc_t *fdc) picint(1 << fdc->irq); fdc->fintr = 1; } + } else { + fdc->fintr = 1; + fdc_log("PCjr FDC: FINTR now 1\n"); } } @@ -608,7 +613,7 @@ fdc_bad_command(fdc_t *fdc) { fdc->stat |= 0x10; fdc->interrupt = 0xfc; - timer_process(); + timer_clock(); fdc->time = 200LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); } @@ -640,13 +645,44 @@ fdc_io_command_phase1(fdc_t *fdc, int out) } +static void +fdc_sis(fdc_t *fdc) +{ + int drive_num; + + fdc->stat = (fdc->stat & 0xf) | 0xd0; + + if (fdc->fintr) { + fdc->res[9] = fdc->st0; + fdc->fintr = 0; + } else { + if (fdc->reset_stat) { + drive_num = real_drive(fdc, 4 - fdc->reset_stat); + if ((!fdd_get_flags(drive_num)) || (drive_num >= FDD_NUM)) { + fdd_stop(drive_num); + fdd_set_head(drive_num, 0); + fdc->res[9] = 0xc0 | (4 - fdc->reset_stat) | (fdd_get_head(drive_num) ? 4 : 0); + } else + fdc->res[9] = 0xc0 | (4 - fdc->reset_stat); + + fdc->reset_stat--; + } + } + + fdc->res[10] = fdc->pcn[fdc->res[9] & 3]; + + fdc_log("Sense interrupt status: 2 parameters to go\n"); + fdc->paramstogo = 2; +} + + static void fdc_write(uint16_t addr, uint8_t val, void *priv) { fdc_t *fdc = (fdc_t *) priv; int drive, i, drive_num; - int seek_time, seek_time_base; + int64_t seek_time, seek_time_base; fdc_log("Write FDC %04X %02X\n", addr, val); @@ -663,7 +699,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) picintc(1 << fdc->irq); } if ((val & 0x80) && !(fdc->dor & 0x80)) { - timer_process(); + timer_clock(); fdc->time = 128LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); fdc->interrupt = -1; @@ -672,7 +708,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) } if (!fdd_get_flags(0)) val &= 0xfe; - motoron[0 ^ fdc->swap] = val & 0x01; + motoron[0] = val & 0x01; } else { if (!(val & 8) && (fdc->dor & 8)) { fdc->tc = 1; @@ -688,7 +724,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->pnum = fdc->ptot = 0; } if ((val&4) && !(fdc->dor&4)) { - timer_process(); + timer_clock(); fdc->time = 128LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); fdc->interrupt = -1; @@ -699,7 +735,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc_ctrl_reset(fdc); } - timer_process(); + timer_clock(); timer_update_outstanding(); /* We can now simplify this since each motor now spins separately. */ for (i = 0; i < FDD_NUM; i++) { @@ -722,7 +758,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) return; case 4: if (val & 0x80) { - timer_process(); + timer_clock(); fdc->time = 128LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); fdc->interrupt = -1; @@ -755,9 +791,9 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->tc = 0; fdc->data_ready = 0; - fdc->command=val; + fdc->command = val; fdc->stat |= 0x10; - fdc_log("Starting fdc_t command %02X\n",fdc->command); + fdc_log("Starting FDC command %02X\n",fdc->command); switch (fdc->command & 0x1f) { case 0x01: /*Mode*/ @@ -826,13 +862,10 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->stat |= 0x90; break; case 0x08: /*Sense interrupt status*/ - if (fdc->fintr || fdc->reset_stat) { - fdc->lastdrive = fdc->drive; - fdc->interrupt = 8; - fdc->pos = 0; - fdc_callback(fdc); - } else - fdc_bad_command(fdc); + fdc_log("fdc->fintr = %i, fdc->reset_stat = %i\n", fdc->fintr, fdc->reset_stat); + fdc->lastdrive = fdc->drive; + fdc->pos = 0; + fdc_sis(fdc); break; case 0x0a: /*Read sector ID*/ fdc->pnum = 0; @@ -897,7 +930,10 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->params[fdc->pnum++]=val; if (fdc->pnum == 1) { if (command_has_drivesel[fdc->command & 0x1F]) { - fdc->drive = fdc->dor & 3; + if (fdc->flags & FDC_FLAG_PCJR) + fdc->drive = 0; + else + fdc->drive = fdc->dor & 3; fdc->rw_drive = fdc->params[0] & 3; if (((fdc->command & 0x1F) == 7) || ((fdc->command & 0x1F) == 15)) fdc->stat |= (1 << real_drive(fdc, fdc->drive)); @@ -906,7 +942,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) if (fdc->pnum==fdc->ptot) { fdc_log("Got all params %02X\n", fdc->command); fdc->interrupt = fdc->command & 0x1F; - timer_process(); + timer_clock(); fdc->time = 1024LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); fdc->reset_stat = 0; @@ -973,21 +1009,25 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) drive_num = real_drive(fdc, fdc->drive); /* Three conditions under which the command should fail. */ if (!fdd_get_flags(drive_num) || (drive_num >= FDD_NUM) || !motoron[drive_num] || fdd_track0(drive_num)) { + pclog("Failed recalibrate\n"); if (!fdd_get_flags(drive_num) || (drive_num >= FDD_NUM) || !motoron[drive_num]) fdc->st0 = 0x70 | (fdc->params[0] & 3); else fdc->st0 = 0x20 | (fdc->params[0] & 3); fdc->pcn[fdc->params[0] & 3] = 0; - fdc->time = 0LL; fdc->interrupt = -3; - timer_process(); + timer_clock(); fdc->time = 2048LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); break; } if ((real_drive(fdc, fdc->drive) != 1) || fdc->drv2en) fdc_seek(fdc, fdc->drive, -fdc->max_track); - fdc->time = ((int64_t) fdc->max_track) * ((int64_t) seek_time_base) * TIMER_USEC; + pclog("Recalibrating...\n"); + if (fdc->flags & FDC_FLAG_PCJR) + fdc->time = 5000LL; + else + fdc->time = ((int64_t) fdc->max_track) * ((int64_t) seek_time_base) * TIMER_USEC; break; case 0x0d: /*Format*/ fdc_rate(fdc, fdc->drive); @@ -1019,9 +1059,8 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->pcn[fdc->params[0] & 3] -= fdc->params[1]; } else fdc->pcn[fdc->params[0] & 3] = fdc->params[1]; - fdc->time = 0LL; fdc->interrupt = -3; - timer_process(); + timer_clock(); fdc->time = 2048LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); break; @@ -1041,21 +1080,20 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) } else { fdc->time = ((int64_t) seek_time_base) * TIMER_USEC; fdc->st0 = 0x20 | (fdc->params[0] & 7); - fdc->time = 0LL; fdc->interrupt = -3; - timer_process(); + timer_clock(); fdc->time = 2048LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); break; } } else { - fdc_log("Seeking to track %i...\n", fdc->params[1]); - seek_time = ((int) (fdc->params[1] - fdc->pcn[fdc->params[0] & 3])) * seek_time_base * TIMER_USEC; + fdc_log("Seeking to track %i (PCN = %i)...\n", fdc->params[1], fdc->pcn[fdc->params[0] & 3]); + seek_time = ((int64_t) (fdc->params[1] - fdc->pcn[fdc->params[0] & 3])) * seek_time_base * TIMER_USEC; if ((fdc->params[1] - fdc->pcn[fdc->params[0] & 3]) == 0) { + pclog("Failed seek\n"); fdc->st0 = 0x20 | (fdc->params[0] & 7); - fdc->time = 0LL; fdc->interrupt = -3; - timer_process(); + timer_clock(); fdc->time = 2048LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); break; @@ -1063,7 +1101,11 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc_seek(fdc, fdc->drive, fdc->params[1] - fdc->pcn[fdc->params[0] & 3]); fdc->pcn[fdc->params[0] & 3] = fdc->params[1]; if (seek_time < 0) seek_time = -seek_time; - fdc->time = ((int64_t) seek_time); + if (fdc->flags & FDC_FLAG_PCJR) + fdc->time = 5000LL; + else + fdc->time = seek_time; + pclog("fdc->time = %i\n", fdc->time); } break; case 10: /*Read sector ID*/ @@ -1152,32 +1194,31 @@ fdc_read(uint16_t addr, void *priv) ret = fdc->rwc[drive] << 4; break; case 4: /*Status*/ - if (!(fdc->dor & 4) & !(fdc->flags & FDC_FLAG_PCJR)) { - ret = 0; - break; - } ret = fdc->stat; break; case 5: /*Data*/ - fdc->stat&=~0x80; if ((fdc->stat & 0xf0) == 0xf0) { - if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->fifo) + fdc->stat &= ~0x80; + if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->fifo) { + fdc->data_ready = 0; ret = fdc->dat; - else + } else ret = fdc_fifo_buf_read(fdc); break; } + fdc->stat &= ~0x80; if (fdc->paramstogo) { + fdc_log("%i parameters to go\n", fdc->paramstogo); fdc->paramstogo--; ret = fdc->res[10 - fdc->paramstogo]; if (!fdc->paramstogo) - fdc->stat=0x80; + fdc->stat = 0x80; else - fdc->stat|=0xC0; + fdc->stat |= 0xC0; } else { if (lastbyte) fdc->stat = 0x80; - lastbyte=0; + lastbyte = 0; ret = fdc->dat; fdc->data_ready = 0; } @@ -1273,6 +1314,7 @@ fdc_callback(void *priv) int drive_num = 0; int old_sector = 0; fdc->time = 0LL; + pclog("fdc_callback(): %i\n", fdc->interrupt); switch (fdc->interrupt) { case -3: /*End of command with interrupt*/ fdc_int(fdc); @@ -1445,41 +1487,15 @@ fdc_callback(void *priv) if (!fdd_track0(drive_num)) fdc->st0 |= 0x50; fdc->interrupt = -3; - timer_process(); + timer_clock(); fdc->time = 2048LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); fdc->stat = 0x80 | (1 << fdc->drive); return; - case 8: /*Sense interrupt status*/ - fdc->stat = (fdc->stat & 0xf) | 0xd0; - - if (fdc->fintr) { - fdc->res[9] = fdc->st0; - fdc->fintr = 0; - } else { - if (fdc->reset_stat) { - drive_num = real_drive(fdc, 4 - fdc->reset_stat); - if ((!fdd_get_flags(drive_num)) || (drive_num >= FDD_NUM)) { - fdd_stop(drive_num); - fdd_set_head(drive_num, 0); - fdc->res[9] = 0xc0 | (4 - fdc->reset_stat) | (fdd_get_head(drive_num) ? 4 : 0); - } else - fdc->res[9] = 0xc0 | (4 - fdc->reset_stat); - - fdc->reset_stat--; - } - } - - fdc->res[10] = fdc->pcn[fdc->res[9] & 3]; - - fdc->paramstogo = 2; - fdc->interrupt = 0; - fdc->time = 0LL; - return; case 0x0d: /*Format track*/ if (fdc->format_state == 1) { fdc->format_state = 2; - timer_process(); + timer_clock(); fdc->time = 128LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); } else if (fdc->format_state == 2) { @@ -1521,10 +1537,11 @@ fdc_callback(void *priv) drive_num = real_drive(fdc, fdc->rw_drive); fdc->st0 = 0x20 | (fdc->params[0] & 7); fdc->interrupt = -3; - timer_process(); + /* timer_clock(); fdc->time = 2048LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); + timer_update_outstanding(); */ fdc->stat = 0x80 | (1 << fdc->drive); + fdc_callback(fdc); return; case 0x10: /*Version*/ case 0x18: /*NSC*/ @@ -1574,7 +1591,7 @@ fdc_error(fdc_t *fdc, int st5, int st6) fdc->res[4] = 0x40 | (fdd_get_head(real_drive(fdc, fdc->drive)) ? 4 : 0) | fdc->rw_drive; fdc->res[5] = st5; fdc->res[6] = st6; - fdc_log("fdc_t Error: %02X %02X %02X\n", fdc->res[4], fdc->res[5], fdc->res[6]); + fdc_log("FDC Error: %02X %02X %02X\n", fdc->res[4], fdc->res[5], fdc->res[6]); switch(fdc->interrupt) { case 0x02: case 0x05: @@ -1920,7 +1937,6 @@ fdc_reset(void *priv) default_rwc = (fdc->flags & FDC_FLAG_START_RWC_1) ? 1 : 0; - fdc->flags &= ~FDC_FLAG_DISKCHG_ACTLOW; fdc->enable_3f1 = 1; fdc_update_is_nsc(fdc, 0); @@ -2000,7 +2016,7 @@ fdc_init(device_t *info) else fdc->dma_ch = 2; - pclog("FDC added: %04X (flags: %08X)\n", fdc->base_address, fdc->flags); + fdc_log("FDC added: %04X (flags: %08X)\n", fdc->base_address, fdc->flags); timer_add(fdc_callback, &fdc->time, &fdc->time, fdc);