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
This commit is contained in:
@@ -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<gcr_info[idx].tracks; t++)
|
||||
{
|
||||
if (gcr_info[idx].trk_map[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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
51
user_io.cpp
51
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)
|
||||
|
||||
Reference in New Issue
Block a user