diff --git a/src/disc.c b/src/disc.c index 372a88cd7..9421df62e 100644 --- a/src/disc.c +++ b/src/disc.c @@ -14,7 +14,8 @@ #include "fdd.h" #include "timer.h" -int disc_poll_time[2] = { 16, 16 }; +int disc_poll_time[2][2] = { { 16, 16 }, { 16, 16 } }; +int disc_poll_enable[2][2] = { { 0, 0 }, { 0, 0 } }; int disc_track[2]; int writeprot[2], fwriteprot[2]; @@ -41,6 +42,11 @@ int disc_changed[2]; int motorspin; int motoron[2]; +int do_poll[2]; + +int head_enable[2][2] = { 0, 0 }; +int head_time[2][2] = { 0, 0 }; + int fdc_indexcount = 52; /*void (*fdc_callback)(); @@ -186,18 +192,18 @@ double disc_real_period(int drive) return (ddbp * dusec); } -void disc_poll(int drive) +void disc_poll(int drive, int head) { - if (drive > 1) + if ((drive > 1) || !motoron[drive]) { - disc_poll_time[drive] += (int) (32.0 * TIMER_USEC); + disc_poll_time[drive][head] += (int) (32.0 * TIMER_USEC); return; } - disc_poll_time[drive] += (int) disc_real_period(drive); + disc_poll_time[drive][head] += (int) disc_real_period(drive); if (drives[drive].poll) - drives[drive].poll(drive); + drives[drive].poll(drive, head); if (disc_notfound) { @@ -207,14 +213,24 @@ void disc_poll(int drive) } } -void disc_poll_0() +void disc_poll_00() { - disc_poll(0); + disc_poll(0, 0); } -void disc_poll_1() +void disc_poll_01() { - disc_poll(1); + disc_poll(0, 1); +} + +void disc_poll_10() +{ + disc_poll(1, 0); +} + +void disc_poll_11() +{ + disc_poll(1, 1); } int disc_get_bitcell_period(int rate) @@ -270,12 +286,126 @@ void disc_set_rate(int drive, int drvden, int rate) } } +/* void disc_head_unload_no_callback(int drive, int head) +{ + disc_head_unload(drive, head); + head_callback[drive][head] = 0; +} */ + +void disc_head_load(int drive, int head) +{ + drive ^= fdd_swap; + + // pclog("Head load start (%i, %i) (%i)\n", drive, head, head_time[drive][head]); + + if (head_time[drive][head]) + { + if (!disc_poll_enable[drive][head]) + { + /* If enabling, do nothing and let it enable. */ + // pclog("Already enabling head (%i, %i)...\n", drive, head); + return; + } + else + { + /* If disabling, stop the timer so it stays enabled. */ + // pclog("Currently disabling head (%i, %i)...\n", drive, head); + head_time[drive][head] = 0; + return; + } + } + + if (disc_poll_enable[drive][head]) + { + /* If it's already enabled, do nothing. */ + // pclog("Head (%i, %i) already enabled...\n", drive, head); + return; + } + + /* Enable or disable not in progress, start enabling. */ + head_time[drive][head] = fdc_get_hlt(); + + // pclog("Head load finished (%i, %i) (%i)\n", drive, head, head_time[drive][head]); +} + +void disc_head_unload(int drive, int head) +{ + drive ^= fdd_swap; + + // pclog("Head unload start (%i, %i) (%i)\n", drive, head, head_time[drive][head]); + + if (head_time[drive][head]) + { + if (disc_poll_enable[drive][head]) + { + /* If disabling, do nothing and let it disable. */ + // pclog("Already disabling head (%i, %i)...\n", drive, head); + return; + } + else + { + /* If enabling, stop the timer so it stays disabled. */ + // pclog("Currently enabling head (%i, %i)...\n", drive, head); + head_time[drive][head] = 0; + return; + } + } + + if (!disc_poll_enable[drive][head]) + { + /* If it's already disabled, do nothing. */ + // pclog("Head (%i, %i) already disabled...\n", drive, head); + return; + } + + /* Enable or disable not in progress, start disabling. */ + head_time[drive][head] = fdc_get_hut(); + + // pclog("Head unload finished (%i, %i) (%i)\n", drive, head, head_time[drive][head]); +} + +void disc_head_poll_common(int drive, int head) +{ + disc_poll_enable[drive][head] ^= 1; + head_time[drive][head] = 0; + if (disc_poll_enable[drive][head]) disc_poll_enable[drive][head ^ 1] = 0; + // pclog("Head (%i, %i) %s\n", drive, head, disc_poll_enable[drive][head] ? "enabled" : "disabled"); +} + +void disc_head_poll_00() +{ + disc_head_poll_common(0, 0); +} + +void disc_head_poll_01() +{ + disc_head_poll_common(0, 1); +} + +void disc_head_poll_10() +{ + disc_head_poll_common(1, 0); +} + +void disc_head_poll_11() +{ + disc_head_poll_common(1, 1); +} + void disc_reset() { curdrive = 0; disc_period = 32; - timer_add(disc_poll_0, &(disc_poll_time[0]), &(motoron[0]), NULL); - timer_add(disc_poll_1, &(disc_poll_time[1]), &(motoron[1]), NULL); + + timer_add(disc_poll_00, &(disc_poll_time[0][0]), &(disc_poll_enable[0][0]), NULL); + timer_add(disc_poll_01, &(disc_poll_time[0][1]), &(disc_poll_enable[0][1]), NULL); + timer_add(disc_poll_10, &(disc_poll_time[1][0]), &(disc_poll_enable[1][0]), NULL); + timer_add(disc_poll_11, &(disc_poll_time[1][1]), &(disc_poll_enable[1][1]), NULL); + + timer_add(disc_head_poll_00, &(head_time[0][0]), &(head_time[0][0]), NULL); + timer_add(disc_head_poll_01, &(head_time[0][1]), &(head_time[0][1]), NULL); + timer_add(disc_head_poll_10, &(head_time[1][0]), &(head_time[1][0]), NULL); + timer_add(disc_head_poll_11, &(head_time[1][1]), &(head_time[1][1]), NULL); } void disc_init() diff --git a/src/disc.h b/src/disc.h index 5525c2635..40acf87b6 100644 --- a/src/disc.h +++ b/src/disc.h @@ -12,7 +12,7 @@ typedef struct int (*hole)(int drive); double (*byteperiod)(int drive); void (*stop)(int drive); - void (*poll)(int drive); + void (*poll)(int drive, int side); } DRIVE; extern DRIVE drives[2]; @@ -24,9 +24,11 @@ void disc_new(int drive, char *fn); void disc_close(int drive); void disc_init(); void disc_reset(); -void disc_poll(int drive); -void disc_poll_0(); -void disc_poll_1(); +void disc_poll(int drive, int head); +void disc_poll_00(); +void disc_poll_00(); +void disc_poll_10(); +void disc_poll_11(); void disc_seek(int drive, int track); void disc_readsector(int drive, int sector, int track, int side, int density, int sector_size); void disc_writesector(int drive, int sector, int track, int side, int density, int sector_size); @@ -39,7 +41,7 @@ void disc_stop(int drive); int disc_empty(int drive); void disc_set_rate(int drive, int drvden, int rate); extern int disc_time; -extern int disc_poll_time[2]; +extern int disc_poll_time[2][2]; void fdc_callback(); int fdc_data(uint8_t dat); @@ -184,3 +186,6 @@ void null_set_sector(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8 uint32_t null_index_hole_pos(int drive, int side); uint32_t common_get_raw_size(int drive, int side); + +void disc_head_load(int drive, int head); +void disc_head_unload(int drive, int head); diff --git a/src/disc_86f.c b/src/disc_86f.c index 187e8a711..0595d7f12 100644 --- a/src/disc_86f.c +++ b/src/disc_86f.c @@ -1365,7 +1365,7 @@ void d86f_read_sector_id(int drive, int side, int match) { d86f[drive].error_condition = 0; d86f[drive].state = STATE_IDLE; - fdc_finishread(); + // fdc_finishread(); fdc_headercrcerror(); } else if (d86f[drive].state == STATE_0A_READ_ID) @@ -1507,7 +1507,7 @@ void d86f_read_sector_data(int drive, int side) d86f[drive].data_find.sync_marks = d86f[drive].data_find.bits_obtained = d86f[drive].data_find.bytes_obtained = 0; d86f[drive].error_condition = 0; d86f[drive].state = STATE_IDLE; - fdc_finishread(); + // fdc_finishread(); fdc_datacrcerror(); } else if ((d86f[drive].calc_crc.word != d86f[drive].track_crc.word) && (d86f[drive].state == STATE_02_READ_DATA)) @@ -1966,12 +1966,10 @@ void d86f_format_track(int drive, int side) } } -void d86f_poll(int drive) +void d86f_poll(int drive, int side) { - int side = 0; int mfm = 1; - side = fdd_get_head(drive); mfm = fdc_is_mfm(); if ((d86f[drive].state & 0xF8) == 0xE8) diff --git a/src/fdc.c b/src/fdc.c index 5f16d84f4..c37d84193 100644 --- a/src/fdc.c +++ b/src/fdc.c @@ -16,26 +16,30 @@ extern int motoron[2]; int ui_writeprot[2] = {0, 0}; -int command_has_drivesel[256] = { [0x02] = 1, /* READ TRACK */ - [0x04] = 1, /* SENSE DRIVE STATUS */ - [0x05] = 1, /* WRITE DATA */ - [0x06] = 1, /* READ DATA */ +/* Bit 0 = Has drive select + Bit 1 = Is read/write + Bit 2 = Has head select */ + +int command_flags[256] = { [0x02] = 7, /* READ TRACK */ + [0x04] = 5, /* SENSE DRIVE STATUS */ + [0x05] = 7, /* WRITE DATA */ + [0x06] = 7, /* READ DATA */ [0x07] = 1, /* RECALIBRATE */ - [0x09] = 1, /* WRITE DELETED DATA */ - [0x0A] = 1, /* READ ID */ - [0x0C] = 1, /* READ DELETED DATA */ - [0x0D] = 1, /* FORMAT TRACK */ - [0x0F] = 1, /* SEEK, RELATIVE SEEK */ - [0x11] = 1, /* SCAN EQUAL */ - [0x16] = 1, /* VERIFY */ - [0x19] = 1, /* SCAN LOW OR EQUAL */ - [0x1D] = 1 }; /* SCAN HIGH OR EQUAL */ + [0x09] = 7, /* WRITE DELETED DATA */ + [0x0A] = 7, /* READ ID */ + [0x0C] = 7, /* READ DELETED DATA */ + [0x0D] = 7, /* FORMAT TRACK */ + [0x0F] = 5, /* SEEK, RELATIVE SEEK */ + [0x11] = 7, /* SCAN EQUAL */ + [0x16] = 7, /* VERIFY */ + [0x19] = 7, /* SCAN LOW OR EQUAL */ + [0x1D] = 7 }; /* SCAN HIGH OR EQUAL */ static int fdc_reset_stat = 0; /*FDC*/ typedef struct FDC { - uint8_t dor,stat,command,dat,st0; + uint8_t dor,tdr,stat,command,dat,st0; int head,track[256],sector,drive,lastdrive; int rw_track; int pos; @@ -196,28 +200,67 @@ int fdc_is_mfm() return fdc.mfm ? 1 : 0; } +double fdc_get_bit_period() +{ + double bcp = 4.0; + + switch(fdc_get_bit_rate()) + { + case 0: + bcp = 2.0; + break; + case 1: + bcp = 20.0 / 6.0; + break; + case 2: + default: + bcp = 4.0; + break; + case 3: + bcp = 1.0; + break; + case 5: + bcp = 0.5; + break; + } + if (!fdc_is_mfm()) + { + bcp *= 2.0; + } + + return bcp; +} + double fdc_get_hut() { int hut = (fdc.specify[0] & 0xF); double dusec; - double bcp = ((double) fdc_get_bitcell_period()) / 250.0; - double dhut = (double) hut; - if (fdc_get_bitcell_period() == 3333) bcp = 160.0 / 6.0; - if (hut == 0) dhut = 16.0; + double bcp; + double dhut; + if (!hut) + { + hut = 0x10; + } + dhut = (double) hut; + bcp = fdc_get_bit_period() * 8.0; dusec = (double) TIMER_USEC; - return (bcp * dhut * dusec * 1000.0); + return (dhut * bcp * 1000.0 * dusec); } double fdc_get_hlt() { int hlt = (fdc.specify[1] >> 1); double dusec; - double bcp = ((double) fdc_get_bitcell_period()) / 2000.0; - double dhlt = (double) hlt; - if (fdc_get_bitcell_period() == 3333) bcp = 20.0 / 6.0; - if (hlt == 0) dhlt = 256.0; + double bcp; + double dhlt; + if (!hlt) + { + hlt = 0x80; + } + dhlt = (double) hlt; + bcp = fdc_get_bit_period() * 8.0; dusec = (double) TIMER_USEC; - return (bcp * dhlt * dusec * 1000.0); + return (dhlt * bcp * 1000.0 * dusec); } void fdc_request_next_sector_id() @@ -609,6 +652,7 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) return; case 3: /* TDR */ + fdc.tdr = val & 3; if (fdc.enh_mode) { drive = (fdc.dor & 1) ^ fdd_swap; @@ -616,6 +660,7 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) } return; case 4: + val &= 0xdf; /* Bit 5 is hardwired to 0. */ if (val & 0x80) { timer_process(); @@ -816,10 +861,19 @@ bad_command: timer_process(); disctime = 1024 * (1 << TIMER_SHIFT); timer_update_outstanding(); - if (command_has_drivesel[discint & 0x1F]) + if (command_flags[discint & 0x1F] & 1) { fdc.drive = fdc.params[0] & 3; } + if (command_flags[discint & 0x1F] & 4) + { + fdd_set_head(fdc.drive, (fdc.params[0] & 4) ? 1 : 0); + if (command_flags[discint & 0x1F] & 2) + { + // pclog("Command %02X, loading head...\n", fdc.command); + disc_head_load(fdc.drive, fdd_get_head(fdc.drive ^ fdd_swap)); + } + } fdc_reset_stat = 0; switch (discint & 0x1F) { @@ -1107,17 +1161,17 @@ uint8_t fdc_read(uint16_t addr, void *priv) presumably implemented outside the FDC on one of the motherboard's support chips.*/ if (fdd_is_525(drive)) - temp = 0x20; + temp = 0x20 | fdc.tdr; else if (fdd_is_ed(drive)) - temp = 0x10; + temp = 0x10 | fdc.tdr; else - temp = 0x00; + temp = 0x00 | fdc.tdr; } else if (!fdc.enh_mode) - temp = 0x20; + temp = fdc.tdr; else { - temp = fdc.rwc[drive] << 4; + temp = (fdc.rwc[drive] << 4) | fdc.tdr; } break; case 4: /*Status*/ @@ -1188,14 +1242,18 @@ uint8_t fdc_read(uint16_t addr, void *priv) return temp; } -void fdc_poll_readwrite_finish(int compare) +void fdc_poll_common_finish(int st5, int compare) { fdc.inread = 0; - discint=-2; + // discint=-2; + disctime=0; + // pclog("Poll common finish...\n"); + disc_head_unload(fdc.drive, fdd_get_head(fdc.drive ^ fdd_swap)); fdc_int(); fdc.stat=0xD0; fdc.res[4]=(fdd_get_head(fdc.drive ^ fdd_swap)?4:0)|fdc.drive; - fdc.res[5]=fdc.res[6]=0; + fdc.res[5]=st5; + fdc.res[6]=0; if (fdc.wrong_am) { fdc.res[6] |= 0x40; @@ -1231,48 +1289,14 @@ void fdc_poll_readwrite_finish(int compare) paramstogo=7; } +void fdc_poll_readwrite_finish(int compare) +{ + fdc_poll_common_finish(0, compare); +} + void fdc_no_dma_end(int compare) { - disctime = 0; - - fdc_int(); - fdc.stat=0xD0; - fdc.res[4]=0x40|(fdd_get_head(fdc.drive ^ fdd_swap)?4:0)|fdc.drive; - fdc.res[5]=0x80; /*NDE (No DMA End)*/ - fdc.res[6]=0; - if (fdc.wrong_am) - { - fdc.res[6] |= 0x40; - fdc.wrong_am = 0; - } - if (compare == 1) - { - if (!fdc.satisfying_sectors) - { - fdc.res[6] |= 4; - } - else if (fdc.satisfying_sectors == (fdc.params[5] << ((fdc.command & 80) ? 1 : 0))) - { - fdc.res[6] |= 8; - } - } - else if (compare == 2) - { - if (fdc.satisfying_sectors & 1) - { - fdc.res[5] |= 0x20; - } - if (fdc.satisfying_sectors & 2) - { - fdc.res[5] |= 0x20; - fdc.res[6] |= 0x20; - } - } - fdc.res[7]=fdc.rw_track; - fdc.res[8]=fdc.head; - fdc.res[9]=fdc.sector; - fdc.res[10]=fdc.params[4]; - paramstogo=7; + fdc_poll_common_finish(0x80, compare); } void fdc_callback() @@ -1619,21 +1643,32 @@ void fdc_callback() // exit(-1); } -void fdc_overrun() +void fdc_error(int st5, int st6) { - disc_stop(fdc.drive); + fdc.inread = 0; disctime = 0; + // pclog("Error (%02X, %02X)...\n", st5, st6); + disc_head_unload(fdc.drive, fdd_get_head(fdc.drive ^ fdd_swap)); + // discint=-2; fdc_int(); fdc.stat=0xD0; fdc.res[4]=0x40|(fdd_get_head(fdc.drive ^ fdd_swap)?4:0)|fdc.drive; - fdc.res[5]=0x10; /*Overrun*/ - fdc.res[6]=0; + fdc.res[5]=st5; + fdc.res[6]=st6; fdc.res[7]=0; fdc.res[8]=0; fdc.res[9]=0; fdc.res[10]=0; paramstogo=7; +// rpclog("c82c711_fdc_notfound\n"); +} + +void fdc_overrun() +{ + disc_stop(fdc.drive); + + fdc_error(0x10, 0); } int fdc_is_verify() @@ -1704,10 +1739,11 @@ int fdc_data(uint8_t data) return 0; } -void fdc_finishcompare(int satisfying) +/* void fdc_finishcompare(int satisfying) { fdc.satisfying_sectors++; fdc.inread = 0; + // disc_head_unload(fdc.drive, fdd_get_head(fdc.drive ^ fdd_swap)); disctime = 200 * TIMER_USEC; // rpclog("fdc_finishread\n"); } @@ -1715,14 +1751,16 @@ void fdc_finishcompare(int satisfying) void fdc_finishread() { fdc.inread = 0; + // disc_head_unload(fdc.drive, fdd_get_head(fdc.drive ^ fdd_swap)); disctime = 200 * TIMER_USEC; // rpclog("fdc_finishread\n"); -} +} */ void fdc_track_finishread(int condition) { fdc.satisfying_sectors |= condition; fdc.inread = 0; + // disc_head_unload(fdc.drive, fdd_get_head(fdc.drive ^ fdd_swap)); fdc_callback(); // rpclog("fdc_finishread\n"); } @@ -1731,6 +1769,7 @@ void fdc_sector_finishcompare(int satisfying) { fdc.satisfying_sectors++; fdc.inread = 0; + // disc_head_unload(fdc.drive, fdd_get_head(fdc.drive ^ fdd_swap)); fdc_callback(); // rpclog("fdc_finishread\n"); } @@ -1738,75 +1777,35 @@ void fdc_sector_finishcompare(int satisfying) void fdc_sector_finishread() { fdc.inread = 0; + // disc_head_unload(fdc.drive, fdd_get_head(fdc.drive ^ fdd_swap)); fdc_callback(); // rpclog("fdc_finishread\n"); } void fdc_notfound() { - disctime = 0; + fdc_error(5, 0); - fdc_int(); - fdc.stat=0xD0; - fdc.res[4]=0x40|(fdd_get_head(fdc.drive ^ fdd_swap)?4:0)|fdc.drive; - fdc.res[5]=5; - fdc.res[6]=0; - fdc.res[7]=0; - fdc.res[8]=0; - fdc.res[9]=0; - fdc.res[10]=0; - paramstogo=7; // rpclog("c82c711_fdc_notfound\n"); } void fdc_datacrcerror() { - disctime = 0; + fdc_error(0x20, 0x20); - fdc_int(); - fdc.stat=0xD0; - fdc.res[4]=0x40|(fdd_get_head(fdc.drive ^ fdd_swap)?4:0)|fdc.drive; - fdc.res[5]=0x20; /*Data error*/ - fdc.res[6]=0x20; /*Data error in data field*/ - fdc.res[7]=0; - fdc.res[8]=0; - fdc.res[9]=0; - fdc.res[10]=0; - paramstogo=7; // rpclog("c82c711_fdc_datacrcerror\n"); } void fdc_headercrcerror() { - disctime = 0; + fdc_error(0x20, 0); - fdc_int(); - fdc.stat=0xD0; - fdc.res[4]=0x40|(fdd_get_head(fdc.drive ^ fdd_swap)?4:0)|fdc.drive; - fdc.res[5]=0x20; /*Data error*/ - fdc.res[6]=0; - fdc.res[7]=0; - fdc.res[8]=0; - fdc.res[9]=0; - fdc.res[10]=0; - paramstogo=7; // rpclog("c82c711_fdc_headercrcerror\n"); } void fdc_writeprotect() { - disctime = 0; - - fdc_int(); - fdc.stat=0xD0; - fdc.res[4]=0x40|(fdd_get_head(fdc.drive ^ fdd_swap)?4:0)|fdc.drive; - fdc.res[5]=0x02; /*Not writeable*/ - fdc.res[6]=0; - fdc.res[7]=0; - fdc.res[8]=0; - fdc.res[9]=0; - fdc.res[10]=0; - paramstogo=7; + fdc_error(0x02, 0); } int fdc_getdata(int last) @@ -1863,7 +1862,10 @@ int fdc_getdata(int last) void fdc_sectorid(uint8_t track, uint8_t side, uint8_t sector, uint8_t size, uint8_t crc1, uint8_t crc2) { -// pclog("SectorID %i %i %i %i\n", track, side, sector, size); + // pclog("SectorID %i %i %i %i\n", track, side, sector, size); + fdc.inread = 0; + disc_head_unload(fdc.drive, fdd_get_head(fdc.drive ^ fdd_swap)); + disctime = 0; fdc_int(); fdc.stat=0xD0; fdc.res[4]=(fdd_get_head(fdc.drive ^ fdd_swap)?4:0)|fdc.drive;