diff --git a/samples/mitsumi_offseek_80_tracks_1000ms_48000_16_1_PCM.wav b/samples/mitsumi_offseek_80_tracks_1000ms_48000_16_1_PCM.wav new file mode 100644 index 000000000..afd95b8d0 Binary files /dev/null and b/samples/mitsumi_offseek_80_tracks_1000ms_48000_16_1_PCM.wav differ diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 9d68365d2..57bee9f2e 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -664,6 +664,28 @@ real_drive(fdc_t *fdc, int drive) return drive; } +/* FDD notifies FDC when seek operation is complete */ +void +fdc_seek_complete_interrupt(fdc_t *fdc, int drive) +{ + if (!fdc) { + fdc_log("ERROR: fdc_seek_complete_interrupt called with NULL fdc!\n"); + return; + } + + fdc_log("FDD %c: Seek complete interrupt\n", 0x41 + drive); + + fdc->fintr = 1; + fdc->st0 = 0x20 | (drive & 3); + + if (fdd_get_head(drive)) + fdc->st0 |= 0x04; + + fdc_int(fdc, 1); + + fdc->stat = (fdc->stat & 0xf) | 0x80; +} + void fdc_seek(fdc_t *fdc, int drive, int params) { @@ -1231,7 +1253,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) case 0x0f: /* Seek */ fdc->rw_drive = fdc->params[0] & 3; fdc->stat = (1 << fdc->drive); - if (!(fdc->flags & FDC_FLAG_PCJR)) + if (!(fdc->flags & FDC_FLAG_PCJR)) fdc->stat |= 0x80; fdc->head = 0; /* TODO: See if this is correct. */ fdc->st0 = fdc->params[0] & 0x03; @@ -1909,7 +1931,10 @@ fdc_callback(void *priv) timer_set_delay_u64(&fdc->timer, 1024 * TIMER_USEC); } else { fdc->interrupt = -3; - fdc_callback(fdc); + // 10 seconds before timeout -> error, Usually BIOS gets angry before this happens + // FDD does the seeking and calls callback when done + timer_set_delay_u64(&fdc->timer, 1024 * 1024 * 10 * TIMER_USEC); + // fdc_callback(fdc); // Immediate callback causes seek to be instant } return; case 0x10: /*Version*/ diff --git a/src/floppy/fdd.c b/src/floppy/fdd.c index 178e3c333..41e3ba216 100644 --- a/src/floppy/fdd.c +++ b/src/floppy/fdd.c @@ -83,6 +83,7 @@ char floppyfns[FDD_NUM][512]; char *fdd_image_history[FDD_NUM][FLOPPY_IMAGE_HISTORY]; pc_timer_t fdd_poll_time[FDD_NUM]; +pc_timer_t fdd_seek_timer[FDD_NUM]; static int fdd_notfound = 0; static int driveloaders[FDD_NUM]; @@ -187,11 +188,32 @@ int fdd_do_log = ENABLE_FDD_LOG; static void fdd_log(const char *fmt, ...) { - va_list ap; + va_list ap, ap_copy; + char timebuf[32]; + char fullbuf[1056]; // 32 + 1024 bytes for timestamp + message if (fdd_do_log) { + uint32_t ticks = plat_get_ticks(); + uint32_t seconds = ticks / 1000; + uint32_t milliseconds = ticks % 1000; + + snprintf(timebuf, sizeof(timebuf), "[%07u.%03u] ", seconds, milliseconds); + va_start(ap, fmt); - pclog_ex(fmt, ap); + va_copy(ap_copy, ap); + + strcpy(fullbuf, timebuf); + vsnprintf(fullbuf + strlen(timebuf), sizeof(fullbuf) - strlen(timebuf), fmt, ap_copy); + + va_end(ap_copy); + va_end(ap); + + va_start(ap, fmt); + va_end(ap); + + char *msg = fullbuf; + va_start(ap, fmt); + pclog_ex("%s", (va_list) &msg); va_end(ap); } } @@ -247,9 +269,21 @@ fdd_forced_seek(int drive, int track_diff) fdd_do_seek(drive, fdd[drive].track); } +static void +fdd_seek_complete_callback(void *priv) +{ + DRIVE *drive = (DRIVE *) priv; + + fdd_log("fdd_seek_complete_callback(drive=%d) - TIMER FIRED! seek_in_progress=1\n", drive->id); + fdd_log("Notifying FDC of seek completion\n"); + + fdc_seek_complete_interrupt(fdd_fdc, drive->id); +} + void fdd_seek(int drive, int track_diff) { + fdd_log("fdd_seek(drive=%d, track_diff=%d)\n", drive, track_diff); if (!track_diff) return; @@ -274,13 +308,23 @@ fdd_seek(int drive, int track_diff) /* Multi-track seek */ fdd_audio_play_multi_track_seek(drive, old_track, fdd[drive].track); } - + + // Count actual seek time (6ms per track + 50ms base) + // 80 tracks -> 50 + 6 * 80 = 530ms + uint64_t seek_time_us = (50000 + (abs(track_diff) * 6000)) * TIMER_USEC; + if (!fdd_seek_timer[drive].callback) { + timer_add(&(fdd_seek_timer[drive]), fdd_seek_complete_callback, &drives[drive], 0); + } + + timer_set_delay_u64(&fdd_seek_timer[drive], seek_time_us); fdd_do_seek(drive, fdd[drive].track); } int fdd_track0(int drive) { + fdd_log("fdd_track0(drive=%d)\n", drive); + /* If drive is disabled, TRK0 never gets set. */ if (!drive_types[fdd[drive].type].max_track) return 0; @@ -423,6 +467,7 @@ fdd_is_double_sided(int drive) void fdd_set_head(int drive, int head) { + fdd_log("fdd_set_head(%d, %d)\n", drive, head); if (head && !fdd_is_double_sided(drive)) fdd[drive].head = 0; else @@ -470,6 +515,7 @@ fdd_get_densel(int drive) void fdd_load(int drive, char *fn) { + fdd_log("fdd_load(%d, %s)\n", drive, fn); int c = 0; int size; const char *p; @@ -558,6 +604,7 @@ fdd_byteperiod(int drive) void fdd_set_motor_enable(int drive, int motor_enable) { + fdd_log("fdd_set_motor_enable(%d, %d)\n", drive, motor_enable); fdd_audio_set_motor_enable(drive, motor_enable); if (motor_enable && !motoron[drive]) { @@ -629,6 +676,7 @@ fdd_reset(void) void fdd_readsector(int drive, int sector, int track, int side, int density, int sector_size) { + fdd_log("fdd_readsector(%d, %d, %d, %d, %d, %d)\n", drive, sector, track, side, density, sector_size); if (drives[drive].readsector) drives[drive].readsector(drive, sector, track, side, density, sector_size); else @@ -638,6 +686,7 @@ fdd_readsector(int drive, int sector, int track, int side, int density, int sect void fdd_writesector(int drive, int sector, int track, int side, int density, int sector_size) { + fdd_log("fdd_writesector(%d, %d, %d, %d, %d, %d)\n", drive, sector, track, side, density, sector_size); if (drives[drive].writesector) drives[drive].writesector(drive, sector, track, side, density, sector_size); else diff --git a/src/include/86box/fdc.h b/src/include/86box/fdc.h index cd1e58db7..d5d0022f1 100644 --- a/src/include/86box/fdc.h +++ b/src/include/86box/fdc.h @@ -251,6 +251,7 @@ extern uint8_t fdc_read(uint16_t addr, void *priv); extern void fdc_reset(void *priv); extern uint8_t fdc_get_current_drive(void); +extern void fdc_seek_complete_interrupt(fdc_t *fdc, int drive); #ifdef EMU_DEVICE_H extern const device_t fdc_xt_device;