C64: support GCR mode.

This commit is contained in:
sorgelig
2021-06-16 05:42:44 +08:00
parent b4f581f5ef
commit a20997df31
3 changed files with 372 additions and 1 deletions

View File

@@ -7,8 +7,12 @@
#include <vector>
#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);
}

View File

@@ -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

View File

@@ -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);