From 64d9cdc6655509757e0006a110a4400ae2bf90b6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 5 Oct 2016 00:47:50 +0200 Subject: [PATCH] TD0 and IMD images of DMF media are now loaded with the correct sector interleave; Fixed several bugs in TD0 and IMD loading; Added FDC READ DELETED DATA, WRITE DELETED DATA, and VERIFY commands; Mismatching data address marks are now handled correctly. --- src/disc.h | 3 ++ src/disc_86f.c | 61 ++++++++++++++++++++++++++-- src/disc_imd.c | 96 +++++++++++++++++++++++++++++++++++++++----- src/disc_img_86box.c | 2 +- src/disc_td0.c | 75 +++++++++++++++++++++++++++++----- src/fdc.c | 84 ++++++++++++++++++++++++++++++++++++++ src/fdc.h | 3 ++ 7 files changed, 298 insertions(+), 26 deletions(-) diff --git a/src/disc.h b/src/disc.h index a3c8033df..1bfaa9ea6 100644 --- a/src/disc.h +++ b/src/disc.h @@ -148,6 +148,7 @@ int null_format_conditions(int drive); void d86f_unregister(int drive); void d86f_reset_index_hole_pos(int drive, int side); +uint8_t dmf_r[21]; uint8_t xdf_physical_sectors[2][2]; uint8_t xdf_gap3_sizes[2][2]; uint16_t xdf_trackx_spos[2][8]; @@ -168,3 +169,5 @@ xdf_sector_t xdf_img_layout[2][2][46]; xdf_sector_t xdf_disk_layout[2][2][38]; uint32_t td0_get_raw_tsize(int side_flags, int slower_rpm); + +void d86f_set_track_pos(int drive, uint32_t track_pos); diff --git a/src/disc_86f.c b/src/disc_86f.c index bf6c33ba9..bc3210454 100644 --- a/src/disc_86f.c +++ b/src/disc_86f.c @@ -290,6 +290,11 @@ void d86f_register_86f(int drive) d86f_handler[drive].check_crc = 1; } +void d86f_set_track_pos(int drive, uint32_t track_pos) +{ + d86f[drive].track_pos = track_pos; +} + /* Needed for formatting! */ int d86f_is_40_track(int drive) { @@ -2099,8 +2104,10 @@ void d86f_poll_find_nf(int drive, int side) { uint8_t mfm = 0; uint8_t am_len = 0; + uint8_t requested_am = 0; mfm = fdc_is_mfm(); am_len = mfm ? 4 : 1; + requested_am = fdc_is_deleted() ? 0xF8 : 0xFB; if (d86f[drive].track_index) { @@ -2137,7 +2144,19 @@ void d86f_poll_find_nf(int drive, int side) { if ((d86f[drive].state == STATE_WRITE_FIND_SECTOR) && (d86f[drive].data_am_counter == (am_len - 1))) { - d86f_poll_write(drive, side, 0xFB, BYTE_DATAAM); + d86f_poll_write(drive, side, fdc_is_deleted() ? 0xF8 : 0xFB, BYTE_DATAAM); + } + else if ((d86f[drive].state != STATE_WRITE_FIND_SECTOR) && (d86f[drive].data_am_counter == (am_len - 1))) + { + if (d86f[drive].track_data_byte != requested_am) + { + fdc_set_wrong_am(); + if (fdc_is_sk()) + { + /* Read command in skip mode, invalidate the data AM counter in order to ignore the sector. */ + d86f[drive].data_am_counter = 0; + } + } } d86f[drive].data_am_counter++; @@ -2162,6 +2181,7 @@ void d86f_poll_find_nf(int drive, int side) } break; case BYTE_ID_CRC: + pclog("Last sector: %08X\n", d86f[drive].last_sector.dword); d86f[drive].id_pos = d86f_get_pos(drive); d86f[drive].track_crc.bytes[d86f[drive].id_pos ^ 1] = d86f[drive].track_data_byte; break; @@ -2251,6 +2271,7 @@ void d86f_poll_find_nf(int drive, int side) Therefore, ensuring the data address mark acounter is at a correct length is all we need to do. */ if (d86f[drive].data_am_counter == am_len) { + pclog("Changing state...\n"); d86f[drive].state++; } /* Data address mark counter always reset to 0. */ @@ -2508,6 +2529,8 @@ void d86f_poll_read_id(int drive, int side) void d86f_poll_find_am_fm(int drive, int side) { + uint16_t requested_am = fdc_is_deleted() ? 0x6AF5 : 0x6FF5; + switch (d86f[drive].track_data_word) { case 0x7EF5: /* ID address mark */ @@ -2527,7 +2550,21 @@ void d86f_poll_find_am_fm(int drive, int side) d86f[drive].calc_crc.word = 0xffff; if (d86f[drive].state == STATE_WRITE_FIND_SECTOR) { - d86f_write_byte_direct(drive, side, 0xFB); + d86f_write_byte_direct(drive, side, fdc_is_deleted() ? 0xF8 : 0xFB); + } + else + { + if (d86f[drive].track_data_word != requested_am) + { + fdc_set_wrong_am(); + if (fdc_is_sk()) + { + d86f[drive].datac = 0; + d86f_poll_advancebyte(drive, side); + d86f[drive].id_was_read = 0; /* Invalidate ID was read flag to avoid false positives after read. */ + return; + } + } } d86f_calccrc(drive, d86f[drive].track_data_byte); d86f[drive].datac = 0; @@ -2539,6 +2576,7 @@ void d86f_poll_find_am_fm(int drive, int side) case STATE_READ_FIND_NEXT_SECTOR: d86f[drive].state++; d86f_poll_advancebyte(drive, side); + d86f[drive].id_was_read = 0; /* Invalidate ID was read flag to avoid false positives after read. */ return; } } @@ -2554,6 +2592,8 @@ void d86f_poll_find_am_fm(int drive, int side) void d86f_poll_find_am_mfm(int drive, int side) { + uint16_t requested_am = fdc_is_deleted() ? 0x4A55 : 0x4555; + switch (d86f[drive].track_data_word) { case 0x8944: @@ -2580,7 +2620,21 @@ void d86f_poll_find_am_mfm(int drive, int side) d86f[drive].id_match = 0; /* Invalidate ID match to avoid false positives after read. */ if (d86f[drive].state == STATE_WRITE_FIND_SECTOR) { - d86f_write_byte_direct(drive, side, 0xFB); + d86f_write_byte_direct(drive, side, fdc_is_deleted() ? 0xF8 : 0xFB); + } + else + { + if (d86f[drive].track_data_word != requested_am) + { + fdc_set_wrong_am(); + if (fdc_is_sk()) + { + d86f[drive].datac = 0; + d86f_poll_advancebyte(drive, side); + d86f[drive].id_was_read = 0; /* Invalidate ID was read flag to avoid false positives after read. */ + return; + } + } } d86f_calccrc(drive, d86f[drive].track_data_byte); d86f[drive].datac = 0; @@ -2593,6 +2647,7 @@ void d86f_poll_find_am_mfm(int drive, int side) // pclog("Advancing state (%04X)...\n", d86f[drive].calc_crc); d86f[drive].state++; d86f_poll_advancebyte(drive, side); + d86f[drive].id_was_read = 0; /* Invalidate ID was read flag to avoid false positives after read. */ return; } } diff --git a/src/disc_imd.c b/src/disc_imd.c index 3aaeee32e..966401309 100644 --- a/src/disc_imd.c +++ b/src/disc_imd.c @@ -36,6 +36,7 @@ static struct imd_track_t tracks[256][2]; uint16_t current_side_flags[2]; uint8_t xdf_ordered_pos[256][2]; + uint8_t interleave_ordered_pos[256][2]; uint8_t *current_data[2]; uint8_t track_buffer[2][25000]; } imd[2]; @@ -70,7 +71,8 @@ void imd_load(int drive, char *fn) uint32_t track_total = 0; uint32_t raw_tsize = 0; uint32_t minimum_gap3 = 0; - uint32_t minimum_gap4 = 12; + // uint32_t minimum_gap4 = 12; + uint32_t minimum_gap4 = 0; d86f_unregister(drive); @@ -161,6 +163,7 @@ void imd_load(int drive, char *fn) if ((track_spt == 16) && (sector_size == 2)) imd[drive].tracks[track][side].side_flags |= 0x20; if ((track_spt == 17) && (sector_size == 2)) imd[drive].tracks[track][side].side_flags |= 0x20; if ((track_spt == 8) && (sector_size == 3)) imd[drive].tracks[track][side].side_flags |= 0x20; + if ((imd[drive].tracks[track][side].side_flags & 7) == 1) imd[drive].tracks[track][side].side_flags |= 0x20; imd[drive].tracks[track][side].is_present = 1; imd[drive].tracks[track][side].file_offs = (buffer2 - buffer); memcpy(imd[drive].tracks[track][side].params, buffer2, 5); @@ -229,15 +232,18 @@ void imd_load(int drive, char *fn) } buffer2 = buffer + last_offset; + /* Leaving even GAP4: 80 : 40 */ + /* Leaving only GAP1: 96 : 47 */ + /* Not leaving even GAP1: 146 : 73 */ raw_tsize = td0_get_raw_tsize(imd[drive].tracks[track][side].side_flags, 0); minimum_gap3 = 12 * track_spt; - if ((raw_tsize - track_total) < (minimum_gap3 + minimum_gap4)) + if ((raw_tsize - track_total + (mfm ? 146 : 73)) < (minimum_gap3 + minimum_gap4)) { /* If we can't fit the sectors with a reasonable minimum gap at perfect RPM, let's try 2% slower. */ raw_tsize = td0_get_raw_tsize(imd[drive].tracks[track][side].side_flags, 1); /* Set disk flags so that rotation speed is 2% slower. */ imd[drive].disk_flags |= (3 << 5); - if ((raw_tsize - track_total) < (minimum_gap3 + minimum_gap4)) + if ((raw_tsize - track_total + (mfm ? 146 : 73)) < (minimum_gap3 + minimum_gap4)) { /* If we can't fit the sectors with a reasonable minimum gap even at 2% slower RPM, abort. */ pclog("IMD: Unable to fit the %i sectors in a track\n", track_spt); @@ -245,7 +251,7 @@ void imd_load(int drive, char *fn) return; } } - imd[drive].tracks[track][side].gap3_len = (raw_tsize - track_total - minimum_gap4) / track_spt; + imd[drive].tracks[track][side].gap3_len = (raw_tsize - track_total - minimum_gap4 + (mfm ? 146 : 73)) / track_spt; imd[drive].track_count++; @@ -295,7 +301,10 @@ int imd_track_is_xdf(int drive, int side, int track) effective_sectors = xdf_sectors = high_sectors = low_sectors = 0; - memset(imd[drive].xdf_ordered_pos[side], 0, 256); + for (i = 0; i < 256; i++) + { + imd[drive].xdf_ordered_pos[i][side] = 0; + } if (imd[drive].tracks[track][side].params[2] & 0xC0) { @@ -384,6 +393,52 @@ int imd_track_is_xdf(int drive, int side, int track) } } +int imd_track_is_interleave(int drive, int side, int track) +{ + int i, effective_sectors; + uint8_t *r_map; + int track_spt; + + effective_sectors = 0; + + for (i = 0; i < 256; i++) + { + imd[drive].interleave_ordered_pos[i][side] = 0; + } + + track_spt = imd[drive].tracks[track][side].params[3]; + + r_map = imd[drive].buffer + imd[drive].tracks[track][side].r_map_offs; + + if (imd[drive].tracks[track][side].params[2] & 0xC0) + { + return 0; + } + if (track_spt != 21) + { + return 0; + } + if (imd[drive].tracks[track][side].params[4] != 2) + { + return 0; + } + + for (i = 0; i < track_spt; i++) + { + if ((r_map[i] >= 1) && (r_map[i] <= track_spt)) + { + effective_sectors++; + imd[drive].interleave_ordered_pos[r_map[i]][side] = i; + } + } + + if (effective_sectors == track_spt) + { + return 1; + } + return 0; +} + void imd_sector_to_buffer(int drive, int track, int side, uint8_t *buffer, int sector, int len) { int i = 0; @@ -426,6 +481,7 @@ void imd_seek(int drive, int track) int track_gap3 = 12; int xdf_type = 0; + int interleave_type = 0; int is_trackx = 0; @@ -434,6 +490,9 @@ void imd_seek(int drive, int track) int ordered_pos = 0; + int real_sector = 0; + int actual_sector = 0; + uint8_t *c_map; uint8_t *h_map; uint8_t *r_map; @@ -456,6 +515,8 @@ void imd_seek(int drive, int track) imd[drive].current_side_flags[0] = imd[drive].tracks[track][0].side_flags; imd[drive].current_side_flags[1] = imd[drive].tracks[track][1].side_flags; + // pclog("IMD Seek: %02X %02X (%02X)\n", imd[drive].current_side_flags[0], imd[drive].current_side_flags[1], imd[drive].disk_flags); + d86f_reset_index_hole_pos(drive, 0); d86f_reset_index_hole_pos(drive, 1); @@ -463,6 +524,7 @@ void imd_seek(int drive, int track) { track_rate = imd[drive].current_side_flags[side] & 7; if (!track_rate && (imd[drive].current_side_flags[side] & 0x20)) track_rate = 4; + if ((imd[drive].current_side_flags[side] & 27) == 0x21) track_rate = 2; r_map = imd[drive].buffer + imd[drive].tracks[track][side].r_map_offs; h = imd[drive].tracks[track][side].params[2]; @@ -495,26 +557,38 @@ void imd_seek(int drive, int track) xdf_type = imd_track_is_xdf(drive, side, track); + interleave_type = imd_track_is_interleave(drive, side, track); + current_pos = d86f_prepare_pretrack(drive, side, 0, 1); if (!xdf_type) { for (sector = 0; sector < imd[drive].tracks[track][side].params[3]; sector++) { - id[0] = (h & 0x80) ? c_map[sector] : c; - id[1] = (h & 0x40) ? h_map[sector] : (h & 1); - id[2] = r_map[sector]; - id[3] = (n == 0xFF) ? n_map[sector] : n; + if (interleave_type == 0) + { + real_sector = r_map[sector]; + actual_sector = sector; + } + else + { + real_sector = dmf_r[sector]; + actual_sector = imd[drive].interleave_ordered_pos[real_sector][side]; + } + id[0] = (h & 0x80) ? c_map[actual_sector] : c; + id[1] = (h & 0x40) ? h_map[actual_sector] : (h & 1); + id[2] = real_sector; + id[3] = (n == 0xFF) ? n_map[actual_sector] : n; ssize = 128 << ((uint32_t) id[3]); data = imd[drive].track_buffer[side] + track_buf_pos[side]; - type = imd[drive].buffer[imd[drive].tracks[track][side].sector_data_offs[sector]]; + type = imd[drive].buffer[imd[drive].tracks[track][side].sector_data_offs[actual_sector]]; type = (type >> 1) & 7; deleted = bad_crc = 0; if ((type == 2) || (type == 4)) deleted = 1; if ((type == 3) || (type == 4)) bad_crc = 1; // pclog("IMD: (%i %i) %i %i %i %i (%i %i) (GPL=%i)\n", track, side, id[0], id[1], id[2], id[3], deleted, bad_crc, track_gap3); - imd_sector_to_buffer(drive, track, side, data, sector, ssize); + imd_sector_to_buffer(drive, track, side, data, actual_sector, ssize); current_pos = d86f_prepare_sector(drive, side, current_pos, id, data, ssize, 1, 22, track_gap3, 0, deleted, bad_crc); track_buf_pos[side] += ssize; } diff --git a/src/disc_img_86box.c b/src/disc_img_86box.c index 963ff6a04..c254e0a35 100644 --- a/src/disc_img_86box.c +++ b/src/disc_img_86box.c @@ -29,7 +29,7 @@ static struct uint16_t current_sector_pos; } img[2]; -static uint8_t dmf_r[21] = { 12, 2, 13, 3, 14, 4, 15, 5, 16, 6, 17, 7, 18, 8, 19, 9, 20, 10, 21, 11, 1 }; +uint8_t dmf_r[21] = { 12, 2, 13, 3, 14, 4, 15, 5, 16, 6, 17, 7, 18, 8, 19, 9, 20, 10, 21, 11, 1 }; static uint8_t xdf_spt[2] = { 6, 8 }; static uint8_t xdf_logical_sectors[2][2] = { { 38, 6 }, { 46, 8 } }; uint8_t xdf_physical_sectors[2][2] = { { 16, 3 }, { 19, 4 } }; diff --git a/src/disc_td0.c b/src/disc_td0.c index bf64ae7e4..1e12a97a7 100644 --- a/src/disc_td0.c +++ b/src/disc_td0.c @@ -103,6 +103,7 @@ typedef struct int current_sector_index[2]; uint8_t calculated_gap3_lengths[256][2]; uint8_t xdf_ordered_pos[256][2]; + uint8_t interleave_ordered_pos[256][2]; } td0_t; td0_t td0[2]; @@ -654,7 +655,8 @@ int td0_initialize(int drive) uint32_t track_size = 0; uint32_t raw_tsize = 0; uint32_t minimum_gap3 = 0; - uint32_t minimum_gap4 = 12; + // uint32_t minimum_gap4 = 12; + uint32_t minimum_gap4 = 0; if (!td0[drive].f) { @@ -861,20 +863,20 @@ int td0_initialize(int drive) raw_tsize = td0_get_raw_tsize(td0[drive].side_flags[track][head], 0); minimum_gap3 = 12 * track_spt; - if ((raw_tsize - track_size) < (minimum_gap3 + minimum_gap4)) + if ((raw_tsize - track_size + (fm ? 73 : 146)) < (minimum_gap3 + minimum_gap4)) { /* If we can't fit the sectors with a reasonable minimum gap at perfect RPM, let's try 2% slower. */ raw_tsize = td0_get_raw_tsize(td0[drive].side_flags[track][head], 1); /* Set disk flags so that rotation speed is 2% slower. */ td0[drive].disk_flags |= (3 << 5); - if ((raw_tsize - track_size) < (minimum_gap3 + minimum_gap4)) + if ((raw_tsize - track_size + (fm ? 73 : 146)) < (minimum_gap3 + minimum_gap4)) { /* If we can't fit the sectors with a reasonable minimum gap even at 2% slower RPM, abort. */ pclog("TD0: Unable to fit the %i sectors in a track\n", track_spt); return 0; } } - td0[drive].calculated_gap3_lengths[track][head] = (raw_tsize - track_size - minimum_gap4) / track_spt; + td0[drive].calculated_gap3_lengths[track][head] = (raw_tsize - track_size - minimum_gap4 + (fm ? 73 : 146)) / track_spt; track_spt = imagebuf[offset]; } @@ -1008,6 +1010,41 @@ int td0_track_is_xdf(int drive, int side, int track) } } +int td0_track_is_interleave(int drive, int side, int track) +{ + int i, effective_sectors; + int track_spt; + + effective_sectors = 0; + + for (i = 0; i < 256; i++) + { + td0[drive].interleave_ordered_pos[i][side] = 0; + } + + track_spt = td0[drive].track_spt[track][side]; + + if (track_spt != 21) + { + return 0; + } + + for (i = 0; i < track_spt; i++) + { + if ((td0[drive].sects[track][side][i].track == track) && (td0[drive].sects[track][side][i].head == side) && (td0[drive].sects[track][side][i].sector >= 1) && (td0[drive].sects[track][side][i].sector <= track_spt) && (td0[drive].sects[track][side][i].size == 2)) + { + effective_sectors++; + td0[drive].interleave_ordered_pos[td0[drive].sects[track][side][i].sector][side] = i; + } + } + + if (effective_sectors == track_spt) + { + return 1; + } + return 0; +} + void td0_seek(int drive, int track) { int side; @@ -1024,6 +1061,7 @@ void td0_seek(int drive, int track) int track_gap3 = 12; int xdf_type = 0; + int interleave_type = 0; int is_trackx = 0; @@ -1031,6 +1069,9 @@ void td0_seek(int drive, int track) int xdf_sector = 0; int ordered_pos = 0; + + int real_sector = 0; + int actual_sector = 0; if (!td0[drive].f) return; @@ -1064,19 +1105,31 @@ void td0_seek(int drive, int track) xdf_type = td0_track_is_xdf(drive, side, track); + interleave_type = td0_track_is_interleave(drive, side, track); + current_pos = d86f_prepare_pretrack(drive, side, 0, 1); if (!xdf_type) { for (sector = 0; sector < td0[drive].track_spt[track][side]; sector++) { - id[0] = td0[drive].sects[track][side][sector].track; - id[1] = td0[drive].sects[track][side][sector].head; - id[2] = td0[drive].sects[track][side][sector].sector; - id[3] = td0[drive].sects[track][side][sector].size; - // pclog("TD0: %i %i %i %i (%i %i) (GPL=%i)\n", id[0], id[1], id[2], id[3], td0[drive].sects[track][side][sector].deleted, td0[drive].sects[track][side][sector].bad_crc, track_gap3); - ssize = 128 << ((uint32_t) td0[drive].sects[track][side][sector].size); - current_pos = d86f_prepare_sector(drive, side, current_pos, id, td0[drive].sects[track][side][sector].data, ssize, 1, track_gap2, track_gap3, 0, td0[drive].sects[track][side][sector].deleted, td0[drive].sects[track][side][sector].bad_crc); + if (interleave_type == 0) + { + real_sector = td0[drive].sects[track][side][sector].sector; + actual_sector = sector; + } + else + { + real_sector = dmf_r[sector]; + actual_sector = td0[drive].interleave_ordered_pos[real_sector][side]; + } + id[0] = td0[drive].sects[track][side][actual_sector].track; + id[1] = td0[drive].sects[track][side][actual_sector].head; + id[2] = real_sector; + id[3] = td0[drive].sects[track][side][actual_sector].size; + // pclog("TD0: %i %i %i %i (%i %i) (GPL=%i)\n", id[0], id[1], id[2], id[3], td0[drive].sects[track][side][actual_sector].deleted, td0[drive].sects[track][side][actual_sector].bad_crc, track_gap3); + ssize = 128 << ((uint32_t) td0[drive].sects[track][side][actual_sector].size); + current_pos = d86f_prepare_sector(drive, side, current_pos, id, td0[drive].sects[track][side][actual_sector].data, ssize, 1, track_gap2, track_gap3, 0, td0[drive].sects[track][side][actual_sector].deleted, td0[drive].sects[track][side][actual_sector].bad_crc); } } else diff --git a/src/fdc.c b/src/fdc.c index 215fd53f7..f545857a6 100644 --- a/src/fdc.c +++ b/src/fdc.c @@ -73,6 +73,11 @@ typedef struct FDC int max_track; int mfm; + + int deleted; + int wrong_am; + + int sc; } FDC; static FDC fdc; @@ -103,6 +108,21 @@ void fdc_reset() // pclog("Reset FDC\n"); } +int fdc_is_deleted() +{ + return fdc.deleted & 1; +} + +int fdc_is_sk() +{ + return (fdc.deleted & 0x20) ? 1 : 0; +} + +void fdc_set_wrong_am() +{ + fdc.wrong_am = 1; +} + int fdc_get_drive() { return fdc.drive; @@ -621,6 +641,8 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) break; case 2: /*Read track*/ + fdc.sc=0; + fdc.wrong_am=0; fdc.pnum=0; fdc.ptot=8; fdc.stat=0x90; @@ -638,6 +660,10 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) fdc.stat=0x90; break; case 5: /*Write data*/ + case 9: /*Write deleted data*/ + fdc.sc=0; + fdc.wrong_am=0; + fdc.deleted = ((fdc.command&0x1F) == 9) ? 1 : 0; // printf("Write data!\n"); fdc.pnum=0; fdc.ptot=8; @@ -647,6 +673,13 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) // readflash=1; break; case 6: /*Read data*/ + case 0xC: /*Read deleted data*/ + case 0x16: /*Verify*/ + fdc.sc=0; + fdc.wrong_am=0; + fdc.deleted = ((fdc.command&0x1F) == 0xC) ? 1 : 0; + if ((fdc.command&0x1F) == 0x16) fdc.deleted = 2; + fdc.deleted |= (fdc.command & 0x20); fdc.pnum=0; fdc.ptot=8; fdc.stat=0x90; @@ -822,6 +855,7 @@ bad_command: break; case 5: /*Write data*/ + case 9: /*Write deleted data*/ fdc_rate(fdc.drive); fdc.head=fdc.params[2]; fdd_set_head(fdc.drive, (fdc.params[0] & 4) ? 1 : 0); @@ -848,7 +882,10 @@ bad_command: // ioc_fiq(IOC_FIQ_DISC_DATA); break; + case 0x16: /*Verify*/ + if (fdc.params[0] & 0x80) fdc.sc = fdc.params[7]; case 6: /*Read data*/ + case 0xC: /*Read deleted data*/ fdc_rate(fdc.drive); fdc.head=fdc.params[2]; fdd_set_head(fdc.drive, (fdc.params[0] & 4) ? 1 : 0); @@ -1084,6 +1121,11 @@ void fdc_poll_readwrite_finish() fdc.stat=0xD0; fdc.res[4]=(fdd_get_head(fdc.drive ^ fdd_swap)?4:0)|fdc.drive; fdc.res[5]=fdc.res[6]=0; + if (fdc.wrong_am) + { + fdc.res[6] |= 0x40; + fdc.wrong_am = 0; + } fdc.res[7]=fdc.rw_track; fdc.res[8]=fdc.head; fdc.res[9]=fdc.sector; @@ -1100,6 +1142,11 @@ void fdc_no_dma_end() 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; + } fdc.res[7]=fdc.rw_track; fdc.res[8]=fdc.head; fdc.res[9]=fdc.sector; @@ -1162,14 +1209,45 @@ void fdc_callback() disctime = 0; return; case 5: /*Write data*/ + case 9: /*Write deleted data*/ case 6: /*Read data*/ + case 0xC: /*Read deleted data*/ + case 0x1C: /*Verify*/ // rpclog("Read data %i\n", fdc.tc); + if ((discint == 6) || (discint == 0xC)) + { + if (fdc.wrong_am && !(fdc.deleted & 0x20)) + { + /* Mismatching data address mark and no skip, set TC. */ + fdc.tc = 1; + } + } if (fdc.tc) { fdc_poll_readwrite_finish(); return; } readflash = 1; + if ((discint == 0x16) && (fdc.params[0] & 0x80)) + { + /* VERIFY command, EC set */ + fdc.sc--; + if (!fdc.sc) + { + fdc_poll_readwrite_finish(); + return; + } + /* The rest is processed normally per MT flag and EOT. */ + } + else if ((discint == 0x16) && !(fdc.params[0] & 0x80)) + { + /* VERIFY command, EC clear */ + if ((fdc.sector == fdc.params[5]) && (fdc.head == (fdc.command & 0x80) ? 1 : 0)) + { + fdc_poll_readwrite_finish(); + return; + } + } if (fdc.sector == fdc.params[5]) { /* Reached end of track, MT bit is clear */ @@ -1410,6 +1488,12 @@ void fdc_overrun() int fdc_data(uint8_t data) { + if (fdc.deleted & 2) + { + /* We're in a VERIFY command, so return with 0. */ + return 0; + } + if (fdc.tc) return 0; diff --git a/src/fdc.h b/src/fdc.h index be0af77ea..dd61dc0c9 100644 --- a/src/fdc.h +++ b/src/fdc.h @@ -31,6 +31,9 @@ void fdc_update_densel_force(int densel_force); void fdc_update_drvrate(int drive, int drvrate); void fdc_update_drv2en(int drv2en); +int fdc_is_deleted(); +int fdc_is_sk(); +void fdc_set_wrong_am(); int fdc_get_drive(); int fdc_get_perp(); int fdc_get_format_n();