From 52237c4d36cf69f87d38de8a72c9f9784c328de2 Mon Sep 17 00:00:00 2001 From: Erik Scheffers Date: Wed, 15 Feb 2023 15:49:01 +0100 Subject: [PATCH] C128: Extend C64 disk routines to support 1571 drive (dual-sided disks and MFM formats) (#742) * C128: add support for .d71 and .g71 disk images * C128: add creating or resizing tracks in .g64/.g71 images * C128: change "1571" flag from bit 8 of lba to bit 10 * C128: fix second side of d71 images * C128: small fix for gcr track end position detection * C128: set track speed to 8 for MFM tracks * C128: provide detected disk image type to core * C128: add bit to indicate disk image GCR support --- support/c64/c64.cpp | 405 ++++++++++++++++++++++++++++++++++---------- support/c64/c64.h | 12 +- user_io.cpp | 51 +++++- 3 files changed, 364 insertions(+), 104 deletions(-) diff --git a/support/c64/c64.cpp b/support/c64/c64.cpp index 61e3c4c..ba7a411 100644 --- a/support/c64/c64.cpp +++ b/support/c64/c64.cpp @@ -10,6 +10,8 @@ #include "../../user_io.h" #include "../../hardware.h" +#include "c64.h" + //#define dbgprintf printf #define dbgprintf(...) @@ -42,6 +44,13 @@ #define D64_FILL_VALUE 0xA0 #define D64_INIT_VALUE 0x00 // DIR relies on 0x00 initial value +#define G64_MAX_TRACK_LEN (G64_BLOCK_COUNT_1571 * 256) +#define G64_TRACK_SPACE_GCR 7930 +#define G64_TRACK_SPACE_MFM 12500 + +// Define EXTEND_1541 to enable creating new tracks in G64 images on the 1541 in the C64/C16/VIC20 cores +// #define EXTEND_1541 + struct FileRecord { char name[D64_BYTE_PER_STRING]; unsigned char cbm; @@ -308,43 +317,119 @@ struct img_info { fileTYPE *f; int type; + uint8_t tracks; uint8_t id[2]; - int32_t trk_sz; - uint32_t trk_map[84]; + uint32_t trk_map[168]; + uint32_t spd_map[168]; + int *sector_map; }; static img_info gcr_info[16] = {}; +static uint8_t trk_buf[8192]; +static uint8_t gcr_buf[G64_MAX_TRACK_LEN*2]; +static uint8_t track_count[4] = {35, 40, 42, 70}; +static int start_sectors[4][85] = { + { // single sided, 35 tracks + 0, 21, 42, 63, 84, 105, 126, 147, 168, 189, 210, 231, 252, 273, 294, 315, 336, 357, 376, 395, 414, + 433, 452, 471, 490, 508, 526, 544, 562, 580, 598, 615, 632, 649, 666, 683, 683, 683, 683, 683, 683, 683, + 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, + 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, + 683 + }, + { // single sided, 40 tracks + 0, 21, 42, 63, 84, 105, 126, 147, 168, 189, 210, 231, 252, 273, 294, 315, 336, 357, 376, 395, 414, + 433, 452, 471, 490, 508, 526, 544, 562, 580, 598, 615, 632, 649, 666, 683, 700, 717, 734, 751, 768, 768, + 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, + 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, + 768 + }, + { // single sided, 42 tracks + 0, 21, 42, 63, 84, 105, 126, 147, 168, 189, 210, 231, 252, 273, 294, 315, 336, 357, 376, 395, 414, + 433, 452, 471, 490, 508, 526, 544, 562, 580, 598, 615, 632, 649, 666, 683, 700, 717, 734, 751, 768, 785, + 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, + 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, 802, + 802, + }, + { // double sided, 35 tracks per side + 0, 21, 42, 63, 84, 105, 126, 147, 168, 189, 210, 231, 252, 273, 294, 315, 336, 357, 376, 395, 414, + 433, 452, 471, 490, 508, 526, 544, 562, 580, 598, 615, 632, 649, 666, 683, 683, 683, 683, 683, 683, 683, + 683, 704, 725, 746, 767, 788, 809, 830, 851, 872, 893, 914, 935, 956, 977, 998, 1019, 1040, 1059, 1078, 1097, + 1116, 1135, 1154, 1173, 1191, 1209, 1227, 1245, 1263, 1281, 1298, 1315, 1332, 1349, 1366, 1366, 1366, 1366, 1366, 1366, 1366, + 1366 + } + // { // double sided, 40 tracks per side + // 0, 21, 42, 63, 84, 105, 126, 147, 168, 189, 210, 231, 252, 273, 294, 315, 336, 357, 376, 395, 414, + // 433, 452, 471, 490, 508, 526, 544, 562, 580, 598, 615, 632, 649, 666, 683, 700, 717, 734, 751, 768, 768, + // 768, 789, 810, 831, 852, 873, 894, 915, 936, 957, 978, 999, 1020, 1041, 1062, 1083, 1104, 1125, 1144, 1163, 1182, + // 1201, 1220, 1239, 1258, 1276, 1294, 1312, 1330, 1348, 1366, 1383, 1400, 1417, 1434, 1451, 1468, 1485, 1502, 1519, 1536, 1536, + // 1536 + // }, + // { // double sided, 42 tracks per side + // 0, 21, 42, 63, 84, 105, 126, 147, 168, 189, 210, 231, 252, 273, 294, 315, 336, 357, 376, 395, 414, + // 433, 452, 471, 490, 508, 526, 544, 562, 580, 598, 615, 632, 649, 666, 683, 700, 717, 734, 751, 768, 785, + // 802, 823, 844, 865, 886, 907, 928, 949, 970, 991, 1012, 1033, 1054, 1075, 1096, 1117, 1138, 1159, 1178, 1197, 1216, + // 1235, 1254, 1273, 1292, 1310, 1328, 1346, 1364, 1382, 1400, 1417, 1434, 1451, 1468, 1485, 1502, 1519, 1536, 1553, 1570, 1587, + // 1587 + // } +}; + int c64_openGCR(const char *path, fileTYPE *f, int idx) { + // Return value: + // + // negative value: + // error + // + // positive value: + // bit 0=dual sided (G64_SUPPORT_DS) + // 1=raw GCR supported (G64_SUPPORT_GCR) + // 2=raw MFM supported (G64_SUPPORT_MFM) + gcr_info[idx].f = f; - if (!strcasecmp(path + strlen(path) - 4, ".g64")) + if (!strcasecmp(path + strlen(path) - 4, ".g64") || !strcasecmp(path + strlen(path) - 4, ".g71")) { char str[16]; FileReadAdv(f, str, 12); - if (memcmp(str, "GCR-1541", 8)) + if (memcmp(str, "GCR-1541", 8) == 0 && memcmp(str, "GCR-1571", 8) == 0) { - printf("Not a G64 format!\n"); - return 0; + printf("Not valid G64 or G71 format: missing marker\n"); + return -1; } - else + + gcr_info[idx].type = 2; + gcr_info[idx].tracks = str[9]; + gcr_info[idx].sector_map = 0; + if (gcr_info[idx].tracks != 84 && gcr_info[idx].tracks != 168) { - gcr_info[idx].type = 2; - memset(gcr_info[idx].trk_map, 0, sizeof(gcr_info[idx].trk_map)); - FileReadAdv(f, gcr_info[idx].trk_map, 84 * 4); + gcr_info[idx].type = 0; + printf("Not valid G64 or G71 format: invalid track count %d\n", gcr_info[idx].tracks); + return -1; } + memset(gcr_info[idx].trk_map, 0, sizeof(gcr_info[idx].trk_map)); + FileReadAdv(f, gcr_info[idx].trk_map, gcr_info[idx].tracks*4); + memset(gcr_info[idx].spd_map, 0, sizeof(gcr_info[idx].spd_map)); + FileReadAdv(f, gcr_info[idx].spd_map, gcr_info[idx].tracks*4); + printf("G64/G71 disk tracks=%d\n", gcr_info[idx].tracks); + + return G64_SUPPORT_GCR | G64_SUPPORT_MFM | (gcr_info[idx].tracks > 84 ? G64_SUPPORT_DS : 0); } else { gcr_info[idx].type = 1; + for (int i = 0; i < 4 ; i++) { + gcr_info[idx].tracks = track_count[i]; + gcr_info[idx].sector_map = &start_sectors[i][0]; + if (f->size <= gcr_info[idx].sector_map[84] * 257) break; + } FileSeek(f, 0x165a2, SEEK_SET); gcr_info[idx].id[0] = 0; gcr_info[idx].id[1] = 0; FileReadAdv(f, gcr_info[idx].id, 2); - printf("D64 disk id1=%02X, id2=%02X\n", gcr_info[idx].id[0], gcr_info[idx].id[1]); - } + printf("D64/D71 disk id1=%02X, id2=%02X, tracks=%d, sectors=%d\n", gcr_info[idx].id[0], gcr_info[idx].id[1], gcr_info[idx].tracks, gcr_info[idx].sector_map[84]); - return 1; + return G64_SUPPORT_GCR | (gcr_info[idx].tracks > 42 ? G64_SUPPORT_DS : 0); + } } void c64_closeGCR(int idx) @@ -352,15 +437,6 @@ void c64_closeGCR(int idx) gcr_info[idx].type = 0; } -static uint8_t trk_buf[8192]; -static uint8_t gcr_buf[8192*2]; - -static int start_sectors[41] = { - 0, 21, 42, 63, 84, 105, 126, 147, 168, 189, 210, 231, 252, 273, 294, 315, 336, 357, 376, 395, - 414, 433, 452, 471, 490, 508, 526, 544, 562, 580, 598, 615, 632, 649, 666, 683, 700, 717, 734, 751, - 768 -}; - static const uint8_t gcr_lut[16] = { 0x0a, 0x0b, 0x12, 0x13, 0x0e, 0x0f, 0x16, 0x17, @@ -416,93 +492,119 @@ void gcr2bin(uint8_t *gcr, uint8_t *bin) } } -void c64_readGCR(int idx, uint8_t track) +void c64_readGCR(int idx, uint64_t lba, uint32_t blks) { + // dbgprintf("c64_readGCR: idx=%d, lba=%04llx, blks=%d\n", idx, lba, blks); + bool is_1571 = (lba & 0x400) != 0; + + uint8_t track = (uint8_t)lba; + uint8_t track_f = track >> 1; + + uint32_t track_size; + if (!gcr_info[idx].type) return; if (gcr_info[idx].type == 2) { - if (!gcr_info[idx].trk_map[track]) + if (track >= gcr_info[idx].tracks || !gcr_info[idx].trk_map[track]) { - gcr_info[idx].trk_sz = 4096; - memset(gcr_buf, 0, gcr_info[idx].trk_sz); - dbgprintf("Track %d%s: no data\n", track >> 1, (track & 1) ? ".5" : ""); + track_size = 0; + dbgprintf("Track %d%s: no data, size %d\n", (track >> 1) + 1, (track & 1) ? ".5" : "", track_size); } else { FileSeek(gcr_info[idx].f, gcr_info[idx].trk_map[track], SEEK_SET); - FileReadAdv(gcr_info[idx].f, gcr_buf, 8192); - gcr_info[idx].trk_sz = (gcr_buf[1] << 8) | gcr_buf[0]; - dbgprintf("Track %d%s: size %d\n", (track >> 1) + 1, (track & 1) ? ".5" : "", gcr_info[idx].trk_sz); - gcr_info[idx].trk_sz += 2; + FileReadAdv(gcr_info[idx].f, gcr_buf, blks * 256); + track_size = (gcr_buf[1] << 8) | gcr_buf[0]; + dbgprintf("Track %d%s: read ok, size %d\n", (track >> 1) + 1, (track & 1) ? ".5" : "", track_size); } } else if (track & 1) { - track >>= 1; - gcr_info[idx].trk_sz = (start_sectors[track + 1] - start_sectors[track]) * 256; - memset(gcr_buf, 0, gcr_info[idx].trk_sz); - - track++; - dbgprintf("\nBetween tracks %d <|> %d.\n", track, track+1); + track_size = 0; + dbgprintf("\nBetween tracks %d <|> %d.\n", track_f, track_f+1); } else { - track >>= 1; + uint8_t track_h = ((track_f >= 42) ? track_f%42 + gcr_info[idx].tracks/2 : track_f) + 1; + int size = track_f < 84 ? (gcr_info[idx].sector_map[track_f + 1] - gcr_info[idx].sector_map[track_f]) * 256 : 0; - int size = (start_sectors[track + 1] - start_sectors[track]) * 256; - FileSeek(gcr_info[idx].f, start_sectors[track] * 256, SEEK_SET); - FileReadAdv(gcr_info[idx].f, trk_buf, size); + // dbgprintf("GCR physical track=%d%s, logical track=%d, size=%d\n", (track >> 1) + 1, (track & 1) ? ".5" : "", track_h, size); + if (size) { + FileSeek(gcr_info[idx].f, gcr_info[idx].sector_map[track_f] * 256, SEEK_SET); + FileReadAdv(gcr_info[idx].f, trk_buf, size); - track++; - uint8_t sec = 0; - gcrptr = gcr_buf + 2; - for (int ptr = 0; ptr < size; ptr += 256) - { - gcrcnt = 0; - *gcrptr++ = 0xFF; *gcrptr++ = 0xFF; *gcrptr++ = 0xFF; *gcrptr++ = 0xFF; *gcrptr++ = 0xFF; - bin2gcr(0x08); - bin2gcr(sec ^ track ^ gcr_info[idx].id[0] ^ gcr_info[idx].id[1]); - bin2gcr(sec); - bin2gcr(track); - bin2gcr(gcr_info[idx].id[1]); - bin2gcr(gcr_info[idx].id[0]); - bin2gcr(0x0F); - bin2gcr(0x0F); - *gcrptr++ = 0x55; *gcrptr++ = 0x55; *gcrptr++ = 0x55; *gcrptr++ = 0x55; *gcrptr++ = 0x55; - *gcrptr++ = 0x55; *gcrptr++ = 0x55; *gcrptr++ = 0x55; *gcrptr++ = 0x55; - - uint8_t cs = 0; - uint8_t bt; - - *gcrptr++ = 0xFF; *gcrptr++ = 0xFF; *gcrptr++ = 0xFF; *gcrptr++ = 0xFF; *gcrptr++ = 0xFF; - bin2gcr(0x07); - for (int i = 0; i < 256; i++) + uint8_t sec = 0; + gcrptr = gcr_buf + 2; + for (int ptr = 0; ptr < size; ptr += 256) { - bt = trk_buf[ptr + i]; - cs ^= bt; - bin2gcr(bt); + gcrcnt = 0; + *gcrptr++ = 0xFF; *gcrptr++ = 0xFF; *gcrptr++ = 0xFF; *gcrptr++ = 0xFF; *gcrptr++ = 0xFF; + bin2gcr(0x08); + bin2gcr(sec ^ track_h ^ gcr_info[idx].id[0] ^ gcr_info[idx].id[1]); + bin2gcr(sec); + bin2gcr(track_h); + bin2gcr(gcr_info[idx].id[1]); + bin2gcr(gcr_info[idx].id[0]); + bin2gcr(0x0F); + bin2gcr(0x0F); + *gcrptr++ = 0x55; *gcrptr++ = 0x55; *gcrptr++ = 0x55; *gcrptr++ = 0x55; *gcrptr++ = 0x55; + *gcrptr++ = 0x55; *gcrptr++ = 0x55; *gcrptr++ = 0x55; *gcrptr++ = 0x55; + + uint8_t cs = 0; + uint8_t bt; + + *gcrptr++ = 0xFF; *gcrptr++ = 0xFF; *gcrptr++ = 0xFF; *gcrptr++ = 0xFF; *gcrptr++ = 0xFF; + bin2gcr(0x07); + for (int i = 0; i < 256; i++) + { + bt = trk_buf[ptr + i]; + cs ^= bt; + bin2gcr(bt); + } + bin2gcr(cs); + bin2gcr(0); + bin2gcr(0); + + int gap = (track_h < 18) ? 8 : (track_h < 25) ? 17 : (track_h < 31) ? 12 : 9; + while (gap--) *gcrptr++ = 0x55; + sec++; } - bin2gcr(cs); - bin2gcr(0); - bin2gcr(0); - int gap = (track < 18) ? 8 : (track < 25) ? 17 : (track < 31) ? 12 : 9; - while (gap--) *gcrptr++ = 0x55; - sec++; + track_size = gcrptr - gcr_buf - 2; + dbgprintf("Read GCR track %d: bin_size = %d, gcr_size = %d\n", track_f+1, size, track_size); + } + else { + track_size = 0; + dbgprintf("Read non-existant GCR track %d: bin_size = %d, gcr_size = %d\n", track_f+1, size, track_size); } - - gcr_info[idx].trk_sz = gcrptr - gcr_buf; - dbgprintf("Read GCR track %d: bin_size = %d, gcr_size = %d\n", track, size, gcr_info[idx].trk_sz); } - uint16_t sz = gcr_info[idx].trk_sz - 1; - gcr_buf[0] = (uint8_t)sz; - gcr_buf[1] = (uint8_t)(sz >> 8); + if (track_size > (blks * 256) - 2) + track_size = (blks * 256) - 2; + + uint32_t buffer_size = track_size + 2; + if (track_size == 0) { + if (is_1571) { + buffer_size = 12502U; + } + else { +#ifdef EXTEND_1541 + track_size = (track_h < 18) ? 7692U : (track_h < 25) ? 7142U : (track_h < 31) ? 6666U : 6250U; +#else + track_size = 4096; +#endif + buffer_size = track_size + 2; + } + memset(gcr_buf, 0, buffer_size); + } + + gcr_buf[0] = (uint8_t)track_size; + gcr_buf[1] = (uint8_t)(track_size >> 8); EnableIO(); spi_w(UIO_SECTOR_RD | (idx << 8)); - spi_block_write(gcr_buf, user_io_get_width(), gcr_info[idx].trk_sz); + spi_block_write(gcr_buf, user_io_get_width(), buffer_size); DisableIO(); } @@ -531,25 +633,136 @@ static uint8_t* align(uint8_t* src, int size) return buf; } -void c64_writeGCR(int idx, uint8_t track) +uint32_t c64_get_track_speed(int idx, uint64_t lba, uint32_t track_size){ + uint32_t freq; + uint8_t track = (uint8_t)lba; + + if (track_size > G64_TRACK_SPACE_GCR) { + freq = 8; + dbgprintf("Track %d%s: freq=%d (mfm)\n", (track >> 1) + 1, (track & 1) ? ".5" : "", freq); + } + else if (lba & 0x400) { + freq = (lba & 0x300) >> 8; + dbgprintf("Track %d%s: freq=%d (gcr, provided)\n", (track >> 1) + 1, (track & 1) ? ".5" : "", freq); + } + else { + uint8_t track_f = track >> 1; + uint8_t track_h = ((track_f > 42) ? track_f%42 + gcr_info[idx].tracks/2 : track_f) + 1; + freq = (track_h < 18) ? 3U : (track_h < 25) ? 2U : (track_h < 31) ? 1U : 0U; + dbgprintf("Track %d%s: freq=%d (gcr, calculated)\n", (track >> 1) + 1, (track & 1) ? ".5" : "", freq); + } + + return freq; +} + +void c64_writeGCR(int idx, uint64_t lba, uint32_t blks) { + // dbgprintf("c64_writeGCR: idx=%d, lba=%04llx, blks=%d\n", idx, lba, blks); + + uint8_t track = (uint8_t)lba; +#ifdef EXTEND_1541 + bool allow_new_track = true; +#else + bool allow_new_track = (lba & 0x400) != 0; +#endif + if (!gcr_info[idx].type) return; static uint8_t sec_buf[260]; EnableIO(); spi_w(UIO_SECTOR_WR | (idx << 8)); - spi_block_read(gcr_buf, user_io_get_width(), 8192); + spi_block_read(gcr_buf, user_io_get_width(), blks * 256); DisableIO(); + uint32_t track_size = (gcr_buf[1] << 8) | gcr_buf[0]; + if (gcr_info[idx].type == 2) { - if (gcr_info[idx].trk_map[track]) + if (track >= gcr_info[idx].tracks) { - FileSeek(gcr_info[idx].f, gcr_info[idx].trk_map[track]+2, SEEK_SET); - FileWriteAdv(gcr_info[idx].f, gcr_buf + 2, gcr_info[idx].trk_sz - 2); - dbgprintf("Write Track %d%s: size %d\n", (track >> 1) + 1, (track & 1) ? ".5" : "", gcr_info[idx].trk_sz - 2); + dbgprintf("Ignore track %d%s: out of range\n", (track >> 1) + 1, (track & 1) ? ".5" : ""); + return; } + + uint32_t track_pos = gcr_info[idx].trk_map[track]; + if (track_pos == 0 && !allow_new_track) { + return; + } + + uint32_t track_end = 0; + uint32_t file_end = gcr_info[idx].f->size; + + if (track_pos > 0) { + // find track end position + track_end = file_end; + for (uint8_t t=0; t track_pos && gcr_info[idx].trk_map[t] < track_end) + track_end = gcr_info[idx].trk_map[t]; + if (gcr_info[idx].spd_map[t] > track_pos && gcr_info[idx].spd_map[t] < track_end) + track_end = gcr_info[idx].spd_map[t]; + } + } + + uint32_t track_space = track_end - track_pos; + + if (track_size + 2 > track_space) { + if (!allow_new_track) { + return; + } + + // TODO reclaim unused space + if (track_space > 0) { + dbgprintf("Write Track %d%s: not enough space, relocating to end of file\n", (track >> 1) + 1, (track & 1) ? ".5" : ""); + } + else { + dbgprintf("Write Track %d%s: new track, saving to end of file\n", (track >> 1) + 1, (track & 1) ? ".5" : ""); + } + + FileSeek(gcr_info[idx].f, 0, SEEK_END); + FileWriteAdv(gcr_info[idx].f, gcr_buf, track_size + 2); + + // update track map entry + gcr_info[idx].trk_map[track] = file_end; + FileSeek(gcr_info[idx].f, 12+track*4, SEEK_SET); + FileWriteAdv(gcr_info[idx].f, &gcr_info[idx].trk_map[track], 4); + + // update speed map entry + uint32_t spd = c64_get_track_speed(idx, lba, track_size); + if (gcr_info[idx].spd_map[track] != spd) { + gcr_info[idx].spd_map[track] = spd; + FileSeek(gcr_info[idx].f, 12+(gcr_info[idx].tracks+track)*4, SEEK_SET); + FileWriteAdv(gcr_info[idx].f, &gcr_info[idx].spd_map[track], 4); + } + + if (track_space > 0) { + // clear old space + memset(gcr_buf, 0xff, track_space); + FileSeek(gcr_info[idx].f, track_pos, SEEK_SET); + FileWriteAdv(gcr_info[idx].f, gcr_buf, track_space); + } + + FileSeek(gcr_info[idx].f, 0, SEEK_END); + track_space = ( + (track_size <= G64_TRACK_SPACE_GCR) ? G64_TRACK_SPACE_GCR + : (track_size <= G64_TRACK_SPACE_MFM) ? G64_TRACK_SPACE_MFM : track_size + ) + 2; + } + else { + FileSeek(gcr_info[idx].f, track_pos, SEEK_SET); + FileWriteAdv(gcr_info[idx].f, gcr_buf, track_size + 2); + } + + // fill unused space + int unused = track_space - track_size - 2; + if (unused > 0) { + if (unused > G64_MAX_TRACK_LEN * 2) unused = G64_MAX_TRACK_LEN * 2; + memset(gcr_buf, 0xff, unused); + FileWriteAdv(gcr_info[idx].f, gcr_buf, unused); + } + + dbgprintf("Write Track %d%s: size %d, unused %d\n", (track >> 1) + 1, (track & 1) ? ".5" : "", track_size, unused); return; } @@ -561,20 +774,26 @@ void c64_writeGCR(int idx, uint8_t track) track >>= 1; - dbgprintf("\n\nTrack = %d\n", track + 1); //hexdump(gcr_buf, 8192); - int sec_cnt = start_sectors[track + 1] - start_sectors[track]; + int sec_cnt = track < 84 ? gcr_info[idx].sector_map[track + 1] - gcr_info[idx].sector_map[track] : 0; + if (sec_cnt == 0) + { + dbgprintf("Ignore track %d: invalid\n", track+1); + return; + } + + dbgprintf("\n\nGCR track = %d\n", track + 1); int sync = 0; uint8_t prev = 0, started = 0; - int off = 0, ptr = 2; + uint32_t off = 0, ptr = 2; uint8_t sec = 0xFF; - memcpy(gcr_buf + gcr_info[idx].trk_sz, gcr_buf + 2, gcr_info[idx].trk_sz - 2); + memcpy(gcr_buf + track_size + 2, gcr_buf + 2, track_size); memset(trk_buf, 0, sizeof(trk_buf)); - while(ptr < gcr_info[idx].trk_sz) + while(ptr < track_size + 2) { if (prev == 0xFF && gcr_buf[ptr + off] == 0xFF) { @@ -651,6 +870,6 @@ void c64_writeGCR(int idx, uint8_t track) } } - FileSeek(gcr_info[idx].f, start_sectors[track] * 256, SEEK_SET); + FileSeek(gcr_info[idx].f, gcr_info[idx].sector_map[track] * 256, SEEK_SET); FileWriteAdv(gcr_info[idx].f, trk_buf, sec_cnt * 256); } diff --git a/support/c64/c64.h b/support/c64/c64.h index e1c0d70..224a55b 100644 --- a/support/c64/c64.h +++ b/support/c64/c64.h @@ -1,12 +1,20 @@ #ifndef C64_H #define C64_H +#define G64_BLOCK_COUNT_1541 31 +#define G64_BLOCK_COUNT_1571 52 + +#define G64_SUPPORT_DS 1 +#define G64_SUPPORT_GCR 2 +#define G64_SUPPORT_MFM 4 +#define G64_SUPPORT_HD 8 + int c64_openT64(const char *path, fileTYPE* f); int c64_openGCR(const char *path, fileTYPE *f, int idx); void c64_closeGCR(int idx); -void c64_readGCR(int idx, uint8_t track); -void c64_writeGCR(int idx, uint8_t track); +void c64_readGCR(int idx, uint64_t lba, uint32_t blks); +void c64_writeGCR(int idx, uint64_t lba, uint32_t blks); #endif diff --git a/user_io.cpp b/user_io.cpp index 4c24b54..50fc48f 100644 --- a/user_io.cpp +++ b/user_io.cpp @@ -277,6 +277,13 @@ char is_c64() return (is_c64_type == 1); } +static int is_c128_type = 0; +char is_c128() +{ + if (!is_c128_type) is_c128_type = strcasecmp(orig_name, "C128") ? 2 : 1; + return (is_c128_type == 1); +} + static int is_psx_type = 0; char is_psx() { @@ -337,6 +344,7 @@ void user_io_read_core_name() is_archie_type = 0; is_gba_type = 0; is_c64_type = 0; + is_c128_type = 0; is_st_type = 0; is_pcxt_type = 0; core_name[0] = 0; @@ -852,7 +860,8 @@ static void parse_config() } else { - user_io_set_index(user_io_ext_idx(str, ext) << 6 | idx); + if (!is_c128()) + user_io_set_index(user_io_ext_idx(str, ext) << 6 | idx); user_io_file_mount(str, idx); } } @@ -1901,6 +1910,7 @@ int user_io_file_mount(const char *name, unsigned char index, char pre, int pre_ int writable = 0; int ret = 0; int len = strlen(name); + int img_type = 0; // disk image type (for C128 core): bit 0=dual sided, 1=raw GCR supported, 2=raw MFM supported, 3=high density sd_image_cangrow[index] = (pre != 0); sd_type[index] = 0; @@ -1924,20 +1934,43 @@ int user_io_file_mount(const char *name, unsigned char index, char pre, int pre_ ret = c64_openT64(name, sd_image + index); if (ret) { - ret = c64_openGCR(name, sd_image + index, index); + img_type = c64_openGCR(name, sd_image + index, index); + ret = img_type < 0 ? 0 : 1; sd_type[index] = 1; if (!ret) FileClose(&sd_image[index]); + + if (ret && is_c128()) + { + printf("Disk image type: %d\n", img_type); + user_io_set_aindex(img_type << 6 | index); + } } } else { writable = FileCanWrite(name); ret = FileOpenEx(&sd_image[index], name, writable ? (O_RDWR | O_SYNC) : O_RDONLY); - if (ret && len > 4 && (!strcasecmp(name + len - 4, ".d64") || !strcasecmp(name + len - 4, ".g64"))) + if (ret && len > 4) { + if (!strcasecmp(name + len - 4, ".d64") + || !strcasecmp(name + len - 4, ".g64") + || !strcasecmp(name + len - 4, ".d71") + || !strcasecmp(name + len - 4, ".g71")) + { + img_type = c64_openGCR(name, sd_image + index, index); + ret = img_type < 0 ? 0 : 1; + sd_type[index] = 1; + if(!ret) FileClose(&sd_image[index]); + } + else if (!strcasecmp(name + len - 4, ".d81")) + { + img_type = G64_SUPPORT_HD | G64_SUPPORT_DS; + } + } + + if (ret && is_c128()) { - ret = c64_openGCR(name, sd_image + index, index); - sd_type[index] = 1; - if(!ret) FileClose(&sd_image[index]); + printf("Disk image type: %d\n", img_type); + user_io_set_aindex(img_type << 6 | index); } } } @@ -2941,10 +2974,10 @@ void user_io_poll() } DisableIO(); - if ((blks == 32) && sd_type[disk]) + if ((blks == G64_BLOCK_COUNT_1541+1 || blks == G64_BLOCK_COUNT_1571+1) && sd_type[disk]) { - if (op == 2) c64_writeGCR(disk, lba); - else if (op & 1) c64_readGCR(disk, lba); + if (op == 2) c64_writeGCR(disk, lba, blks-1); + else if (op & 1) c64_readGCR(disk, lba, blks-1); else break; } else if (op == 2)