From a20997df31aecfdcf0664840b56a6c8b5f187495 Mon Sep 17 00:00:00 2001 From: sorgelig Date: Wed, 16 Jun 2021 05:42:44 +0800 Subject: [PATCH] C64: support GCR mode. --- support/c64/c64.cpp | 352 ++++++++++++++++++++++++++++++++++++++++++++ support/c64/c64.h | 6 + user_io.cpp | 15 +- 3 files changed, 372 insertions(+), 1 deletion(-) diff --git a/support/c64/c64.cpp b/support/c64/c64.cpp index e63b620..0e2313c 100644 --- a/support/c64/c64.cpp +++ b/support/c64/c64.cpp @@ -7,8 +7,12 @@ #include #include "../../file_io.h" +#include "../../user_io.h" #include "../../hardware.h" +//#define dbgprintf printf +#define dbgprintf(...) + #define CBM_PRG 0x82 #define T64_BYTE_PER_HEADER 32U @@ -297,3 +301,351 @@ int c64_openT64(const char *path, fileTYPE* f) return ret; } + +// ----------------------------------------------------------------------------------------- + +struct img_info +{ + fileTYPE *f; + int type; + uint8_t id[2]; + int32_t trk_sz; + uint32_t trk_map[84]; +}; + +static img_info gcr_info[16] = {}; + +int c64_openGCR(const char *path, fileTYPE *f, int idx) +{ + gcr_info[idx].f = f; + if (!strcasecmp(path + strlen(path) - 4, ".g64")) + { + char str[16]; + FileReadAdv(f, str, 12); + if (memcmp(str, "GCR-1541", 8)) + { + printf("Not a G64 format!\n"); + return 0; + } + else + { + 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); + } + } + else + { + gcr_info[idx].type = 1; + 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]); + } + + return 1; +} + +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, + 0x09, 0x19, 0x1a, 0x1b, + 0x0d, 0x1d, 0x1e, 0x15 +}; + +static const uint8_t bin_lut[32] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 8, 0, 1, 0, 12, 4, 5, + 0, 0, 2, 3, 0, 15, 6, 7, + 0, 9, 10, 11, 0, 13, 14, 0 +}; + +static uint8_t *gcrptr; +static int gcrcnt = 0; + +void bin2gcr(uint8_t bin) +{ + static uint64_t gcr = 0; + + gcr <<= 5; + gcr |= gcr_lut[(bin >> 4) & 0xF]; + gcr <<= 5; + gcr |= gcr_lut[bin & 0xF]; + + gcrcnt++; + if (gcrcnt == 4) + { + gcrcnt = 0; + *gcrptr++ = (uint8_t)(gcr >> 32); + *gcrptr++ = (uint8_t)(gcr >> 24); + *gcrptr++ = (uint8_t)(gcr >> 16); + *gcrptr++ = (uint8_t)(gcr >> 8); + *gcrptr++ = (uint8_t)(gcr); + } +} + +void gcr2bin(uint8_t *gcr, uint8_t *bin) +{ + // from VICE + register uint32_t tmp = *gcr; + tmp <<= 13; + + for (int i = 5; i < 13; i += 2, bin++) + { + gcr++; + tmp |= ((uint32_t)(*gcr)) << i; + *bin = bin_lut[(tmp >> 16) & 0x1f] << 4; + tmp <<= 5; + *bin |= bin_lut[(tmp >> 16) & 0x1f]; + tmp <<= 5; + } +} + +void c64_readGCR(int idx, uint8_t track) +{ + if (!gcr_info[idx].type) return; + + if (gcr_info[idx].type == 2) + { + if (!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" : ""); + } + 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, (track & 1) ? ".5" : "", gcr_info[idx].trk_sz); + gcr_info[idx].trk_sz += 2; + } + } + 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); + } + else + { + track >>= 1; + + 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); + + 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++) + { + bt = trk_buf[ptr + i]; + cs ^= bt; + bin2gcr(bt); + } + bin2gcr(cs); + bin2gcr(0); + bin2gcr(0); + + int gap = (track < 18) ? 8 : (track < 25) ? 17 : (track < 31) ? 12 : 9; + while (gap--) *gcrptr++ = 0x55; + sec++; + } + + 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); + + EnableIO(); + spi_w(UIO_SECTOR_RD | (idx << 8)); + spi_block_write(gcr_buf, user_io_get_width(), gcr_info[idx].trk_sz); + DisableIO(); +} + +static uint8_t* align(uint8_t* src, int size) +{ + static uint8_t buf[512]; + memcpy(buf, src, size); + + int rol = 0; + while (buf[0] & 0x80) + { + rol++; + uint8_t c = 0, t; + for (int i = size - 1; i >= 0; i--) + { + t = buf[i] & 0x80; + buf[i] = (buf[i] << 1) | c; + c = t ? 1 : 0; + } + } + + if (rol) + { + dbgprintf("** ROL = %d ** ", rol); + } + return buf; +} + +void c64_writeGCR(int idx, uint8_t track) +{ + 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); + DisableIO(); + + if (gcr_info[idx].type == 2) + { + printf("Write to G64 is not supported.\n"); + return; + } + + if (track & 1) + { + dbgprintf("Discard data between tracks!\n"); + return; + } + + track >>= 1; + + dbgprintf("\n\nTrack = %d\n", track + 1); + //hexdump(gcr_buf, 8192); + + int sec_cnt = start_sectors[track + 1] - start_sectors[track]; + + int sync = 0; + uint8_t prev = 0, started = 0; + int 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); + memset(trk_buf, 0, sizeof(trk_buf)); + + while(ptr < gcr_info[idx].trk_sz) + { + if (prev == 0xFF && gcr_buf[ptr + off] == 0xFF) + { + sync = 1; + } + + if (gcr_buf[ptr + off] != 0xFF && sync) + { + uint8_t *hdr = align(gcr_buf + ptr + off, 11); + + uint32_t bin; + gcr2bin(hdr, (uint8_t*)&bin); + if (!started && (bin & 0xFF) == 8) + { + off = ptr - 2; + ptr = 2; + started = 1; + dbgprintf("Start at %d\n\n", off); + } + + dbgprintf("Sync = %08X: ", bin); + + if ((bin & 0xFF) == 8) + { + sec = (uint8_t)(bin >> 16); + gcr2bin(hdr + 5, (uint8_t*)&bin); + gcr_info[idx].id[1] = (uint8_t)(bin); + gcr_info[idx].id[0] = (uint8_t)(bin >> 8); + + dbgprintf("sec = %d, id1 = %02X, id2 = %02X\n", sec, gcr_info[idx].id[0], gcr_info[idx].id[1]); + } + else if ((bin & 0xFF) == 7) + { + if (sec < sec_cnt) + { + dbgprintf("data...\n\n"); + uint8_t *data = align(gcr_buf + ptr + off, 330); + + int dst = 0; + int src = 0; + for (; dst < 260; src += 5, dst += 4) + { + gcr2bin(data + src, sec_buf + dst); + } + + memcpy(trk_buf + (sec * 256), sec_buf + 1, 256); + /* + printf("Sec data:\n"); + hexdump(trk_buf + (sec * 256), 256); + printf("\n"); + */ + } + else + { + dbgprintf("nothing here.\n\n"); + sec = 0xFF; + } + + ptr += 256; // a little before the end + } + else + { + /* + printf("\noff %X\n", ptr + off - 20); + hexdump(gcr_buf + ptr + off - 20, 256); + */ + } + sync = 0; + } + else + { + prev = gcr_buf[ptr + off]; + ptr++; + } + } + + FileSeek(gcr_info[idx].f, start_sectors[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 24e67fc..e1c0d70 100644 --- a/support/c64/c64.h +++ b/support/c64/c64.h @@ -3,4 +3,10 @@ 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); + #endif diff --git a/user_io.cpp b/user_io.cpp index 2058848..c9dd6c0 100644 --- a/user_io.cpp +++ b/user_io.cpp @@ -1508,11 +1508,17 @@ int user_io_file_mount(const char *name, unsigned char index, char pre) { writable = 0; ret = c64_openT64(name, sd_image + index); + if (ret) ret = c64_openGCR(name, sd_image + index, index); } else { writable = FileCanWrite(name); ret = FileOpenEx(&sd_image[index], name, writable ? (O_RDWR | O_SYNC) : O_RDONLY); + if (ret && is_c64() && len > 4 && (!strcasecmp(name + len - 4, ".d64") || !strcasecmp(name + len - 4, ".g64"))) + { + ret = c64_openGCR(name, sd_image + index, index); + if(!ret) FileClose(&sd_image[index]); + } } } @@ -1524,6 +1530,7 @@ int user_io_file_mount(const char *name, unsigned char index, char pre) else { FileClose(&sd_image[index]); + c64_closeGCR(index); } buffer_lba[index] = -1; @@ -2662,7 +2669,13 @@ void user_io_poll() } DisableIO(); - if (op == 2) + if ((blksz == 32) && is_c64()) + { + if (op == 2) c64_writeGCR(disk, lba); + else if (op & 1) c64_readGCR(disk, lba); + else break; + } + else if (op == 2) { //printf("SD WR %d on %d\n", lba, disk);