C64: support GCR mode.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
15
user_io.cpp
15
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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user