2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
11 #include "../fileio.h"
14 #include "../qt/gui/csp_logger.h"
18 #define local_path(x) create_local_path(x)
20 #define local_path(x) (x)
24 static const uint16_t crc_table[256] = {
25 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
26 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
27 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
28 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
29 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
30 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
31 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
32 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
33 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
34 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
35 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
36 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
37 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
38 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
39 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
40 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
43 static const int secsize[8] = {
44 128, 256, 512, 1024, 2048, 4096, 8192, 16384
47 static uint8_t tmp_buffer[DISK_BUFFER_SIZE];
49 // physical format table for solid image
52 int ncyl, nside, nsec, size;
59 static const fd_format_t fd_formats[] = {
61 { MEDIA_TYPE_2D, 40, 1, 16, 256, MFM }, // 1D 160KB
62 #elif defined(_SMC70) || defined(_SMC777)
63 { MEDIA_TYPE_2DD, 70, 1, 16, 256, MFM }, // 1DD 280KB
64 #elif defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
65 { MEDIA_TYPE_2D, 40, 2, 16, 256, MFM }, // 2D 320KB
67 { MEDIA_TYPE_2D, 40, 2, 18, 256, MFM }, // 2D 360KB
68 #elif defined(_MZ80B) || defined(_MZ2000) || defined(_MZ2200) || defined(_MZ2500)
69 { MEDIA_TYPE_2DD, 80, 2, 16, 256, MFM }, // 2DD 640KB
71 { MEDIA_TYPE_2D, 35, 1, 16, 128, FM }, // 1S 70KB
72 { MEDIA_TYPE_2D, 35, 2, 16, 128, FM }, // 2S 140KB
73 { MEDIA_TYPE_2DD, 77, 1, 26, 128, FM }, // 1S 250KB
74 { MEDIA_TYPE_2D, 40, 1, 8, 512, MFM }, // 1D 160KB
75 { MEDIA_TYPE_2D, 40, 1, 9, 512, MFM }, // 1D 180KB
76 { MEDIA_TYPE_2D, 40, 1, 10, 512, MFM }, // 1D 200KB
77 //#if defined(SUPPORT_MEDIA_TYPE_1DD)
78 // { MEDIA_TYPE_2DD, 70, 1, 8, 512, MFM }, // 1DD 280KB
79 // { MEDIA_TYPE_2DD, 70, 1, 9, 512, MFM }, // 1DD 315KB
80 // { MEDIA_TYPE_2DD, 70, 1, 10, 512, MFM }, // 1DD 350KB
81 // { MEDIA_TYPE_2DD, 80, 1, 8, 512, MFM }, // 1DD 320KB
82 // { MEDIA_TYPE_2DD, 80, 1, 9, 512, MFM }, // 1DD 360KB
83 // { MEDIA_TYPE_2DD, 80, 1, 10, 512, MFM }, // 1DD 400KB
85 { MEDIA_TYPE_2D, 35, 2, 8, 512, MFM }, // 2D 280KB
86 { MEDIA_TYPE_2D, 35, 2, 9, 512, MFM }, // 2D 315KB
87 { MEDIA_TYPE_2D, 35, 2, 10, 512, MFM }, // 2D 350KB
88 { MEDIA_TYPE_2D, 40, 2, 8, 512, MFM }, // 2D 320KB
89 { MEDIA_TYPE_2D, 40, 2, 9, 512, MFM }, // 2D 360KB
90 { MEDIA_TYPE_2D, 40, 2, 10, 512, MFM }, // 2D 400KB
92 { MEDIA_TYPE_2DD, 80, 2, 8, 512, MFM }, // 2DD 640KB
93 { MEDIA_TYPE_2DD, 80, 2, 9, 512, MFM }, // 2DD 720KB
94 { MEDIA_TYPE_2DD, 81, 2, 9, 512, MFM }, // 2DD 729KB, ASCII MSX
95 { MEDIA_TYPE_2DD, 80, 2, 10, 512, MFM }, // 2DD 800KB
96 { MEDIA_TYPE_2HD, 77, 2, 26, 256, MFM }, // 2HD 1001KB, MITSUBISHI/IBM
97 { MEDIA_TYPE_2HD, 80, 2, 15, 512, MFM }, // 2HC 1200KB, TOSHIBA/IBM
98 { MEDIA_TYPE_2HD, 77, 2, 8, 1024, MFM }, // 2HD 1232KB, NEC
99 { MEDIA_TYPE_144, 80, 2, 18, 512, MFM }, // 2HD 1440KB
100 { MEDIA_TYPE_144, 80, 2, 21, 512, MFM }, // 2HD 1680KB
101 { MEDIA_TYPE_144, 82, 2, 21, 512, MFM }, // 2HD 1722KB
102 { MEDIA_TYPE_144, 80, 2, 36, 512, MFM }, // 2ED 2880KB
106 #define IS_VALID_TRACK(offset) ((offset) >= 0x20 && (offset) < sizeof(buffer))
108 void DISK::open(const _TCHAR* file_path, int bank)
110 // check current disk image
112 if(_tcsicmp(orig_path, file_path) == 0 && file_bank == bank) {
120 memset(buffer, 0, sizeof(buffer));
122 write_protected = false;
123 media_type = MEDIA_TYPE_UNK;
125 is_solid_image = is_fdi_image = is_1dd_image = false;
126 trim_required = false;
127 track_mfm = drive_mfm;
130 FILEIO *fio = new FILEIO();
131 if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
132 my_tcscpy_s(orig_path, _MAX_PATH, file_path);
133 my_tcscpy_s(dest_path, _MAX_PATH, file_path);
135 this->out_debug_log("OPENed: %s", file_path);
137 file_size.d = fio->FileLength();
138 fio->Fseek(0, FILEIO_SEEK_SET);
140 if(check_file_extension(file_path, _T(".d88")) || check_file_extension(file_path, _T(".d77")) || check_file_extension(file_path, _T(".1dd"))) {
143 for(int i = 0; i < bank; i++) {
144 fio->Fseek(offset + 0x1c, SEEK_SET);
145 offset += fio->FgetUint32_LE();
147 fio->Fseek(offset + 0x1c, FILEIO_SEEK_SET);
148 file_size.d = fio->FgetUint32_LE();
149 fio->Fseek(offset, FILEIO_SEEK_SET);
150 fio->Fread(buffer, file_size.d, 1);
152 if(check_file_extension(file_path, _T(".1dd"))) {
154 media_type = MEDIA_TYPE_2DD;
156 inserted = changed = true;
157 // trim_required = true;
159 // fix sector number from big endian to little endian
160 for(int trkside = 0; trkside < 164; trkside++) {
162 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
164 if(!IS_VALID_TRACK(offset.d)) {
167 uint8_t* t = buffer + offset.d;
168 pair_t sector_num, data_size;
169 sector_num.read_2bytes_le_from(t + 4);
170 bool is_be = (sector_num.b.l == 0 && sector_num.b.h >= 4);
172 sector_num.read_2bytes_be_from(t + 4);
173 sector_num.write_2bytes_le_to(t + 4);
175 for(int i = 0; i < sector_num.sd; i++) {
177 sector_num.write_2bytes_le_to(t + 4);
179 data_size.read_2bytes_le_from(t + 14);
180 t += data_size.sd + 0x10;
183 } else if(check_file_extension(file_path, _T(".td0"))) {
186 if(teledisk_to_d88(fio)) {
187 inserted = changed = true;
188 my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), file_path);
191 // failed to convert the disk image
193 } else if(check_file_extension(file_path, _T(".imd"))) {
196 if(imagedisk_to_d88(fio)) {
197 inserted = changed = true;
198 my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), file_path);
201 // failed to convert the disk image
203 } else if(check_file_extension(file_path, _T(".dsk"))) {
206 if(cpdread_to_d88(fio)) {
207 inserted = changed = true;
208 my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), file_path);
211 // failed to convert the disk image
213 } else if(check_file_extension(file_path, _T(".2d")) && file_size.d == 40 * 2 * 16 * 256) {
214 // 2d image for SHARP X1 series
216 if(solid_to_d88(fio, MEDIA_TYPE_2D, 40, 2, 16, 256, true)) {
217 inserted = changed = is_solid_image = true;
220 // failed to convert the disk image
222 } else if(check_file_extension(file_path, _T(".img")) && file_size.d == 70 * 1 * 16 * 256) {
223 // img image for SONY SMC-70/777 series
225 if(solid_to_d88(fio, MEDIA_TYPE_2DD, 70, 1, 16, 256, true)) {
226 inserted = changed = is_solid_image = true;
229 // failed to convert the disk image
231 } else if(check_file_extension(file_path, _T(".sf7")) && file_size.d == 40 * 1 * 16 * 256) {
232 // sf7 image for SEGA SC-3000 + SF-7000
234 if(solid_to_d88(fio, MEDIA_TYPE_2D, 40, 1, 16, 256, true)) {
235 inserted = changed = is_solid_image = true;
238 // failed to convert the disk image
242 // check solid image file format
243 bool is_fdi_tmp = check_file_extension(file_path, _T(".fdi"));
244 for(int i = 0;; i++) {
245 const fd_format_t *p = &fd_formats[i];
249 int len = p->ncyl * p->nside * p->nsec * p->size;
250 // 4096 bytes: FDI header ???
251 if(file_size.d == (uint32_t)(len + (is_fdi_tmp ? 4096 : 0))) {
252 fio->Fseek(0, FILEIO_SEEK_SET);
255 fio->Fread(fdi_header, 4096, 1);
259 int nside = p->nside;
262 #if defined(SUPPORT_MEDIA_TYPE_1DD)
263 if(type == MEDIA_TYPE_2D && nside == 2 && p->mfm) {
264 type = MEDIA_TYPE_2DD;
268 #elif defined(_ANY2D88)
269 if(open_as_1dd && type == MEDIA_TYPE_2D && nside == 2 && p->mfm) {
270 type = MEDIA_TYPE_2DD;
274 if(open_as_256 && (size == 512 || size == 1024)) {
280 // if(solid_to_d88(fio, p->type, p->ncyl, p->nside, p->nsec, p->size, p->mfm)) {
281 if(solid_to_d88(fio, type, ncyl, nside, nsec, size, p->mfm)) {
282 inserted = changed = is_solid_image = true;
285 // failed to convert the disk image
293 if(fio->IsOpened()) {
299 // check loaded image
302 if(media_type == MEDIA_TYPE_UNK) {
303 if((media_type = buffer[0x1b]) == MEDIA_TYPE_2HD) {
304 // check 1.2MB or 1.44MB
305 for(int trkside = 0; trkside < 164; trkside++) {
307 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
309 if(!IS_VALID_TRACK(offset.d)) {
313 uint8_t *t = buffer + offset.d;
314 pair_t sector_num, data_size;
315 sector_num.read_2bytes_le_from(t + 4);
316 data_size.read_2bytes_le_from(t + 14);
318 if(sector_num.sd >= 18 && data_size.sd == 512) {
319 media_type = MEDIA_TYPE_144;
326 // fix write protect flag
327 if(buffer[0x1a] != 0) {
329 write_protected = true;
332 // get crc32 for midification check
333 orig_file_size = file_size.d;
334 orig_crc32 = get_crc32(buffer, file_size.d);
336 // check special disk image
337 #if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
338 // FIXME: ugly patch for FM-7 Gambler Jiko Chuushin Ha, DEATH FORCE and Psy-O-Blade
339 if(media_type == MEDIA_TYPE_2D) {
341 pair_t offset, sector_num, data_size;
342 offset.read_4bytes_le_from(buffer + 0x20);
343 if(IS_VALID_TRACK(offset.d)) {
344 // check the sector (c,h,r,n) = (0,0,7,1) or (0,0,f7,2)
345 uint8_t* t = buffer + offset.d;
346 sector_num.read_2bytes_le_from(t + 4);
347 for(int i = 0; i < sector_num.sd; i++) {
348 data_size.read_2bytes_le_from(t + 14);
349 if(is_special_disk == 0) {
350 if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 7 && t[3] == 1) {
351 static const uint8_t gambler[] = {0xb7, 0xde, 0xad, 0xdc, 0xdd, 0xcc, 0xde, 0xd7, 0xb1, 0x20, 0xbc, 0xde, 0xba, 0xc1, 0xad, 0xb3, 0xbc, 0xdd, 0xca};
352 if(memcmp((void *)(t + 0x30), gambler, sizeof(gambler)) == 0) {
353 is_special_disk = SPECIAL_DISK_FM7_GAMBLER;
356 } else if(data_size.sd == 0x200 && t[0] == 0 && t[1] == 0 && t[2] == 0xf7 && t[3] == 2) {
357 //"DEATHFORCE/77AV" + $f7*17 + $00 + $00
358 static const uint8_t deathforce[] ={
359 0x44, 0x45, 0x41, 0x54, 0x48, 0x46, 0x4f, 0x52,
360 0x43, 0x45, 0x2f, 0x37, 0x37, 0x41, 0x56, 0xf7,
361 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
362 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
365 if(memcmp((void *)(t + 0x10), deathforce, sizeof(deathforce)) == 0) {
366 this->out_debug_log("SPECIAL DISK: DEATH FORCE");
367 is_special_disk = SPECIAL_DISK_FM7_DEATHFORCE;
370 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 0x05 && t[3] == 1) {
371 //$00 * 16 + $00 + "Protected by N & A (SUPER HACKER COMBI)
372 //Can you found CHECK-ROUTINES ?Can you crack these protect ?
374 static const uint8_t xanadu2fm_d_1[] ={
375 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
376 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
378 static const uint8_t xanadu2fm_d_2[] = {
379 0x50, 0x72, 0x6F, 0x74, 0x65, 0x63, 0x74, 0x65,
380 0x64, 0x20, 0x62, 0x79, 0x20, 0x20, 0x4E, 0x20,
381 0x26, 0x20, 0x41, 0x20, 0x28, 0x53, 0x55, 0x50,
382 0x45, 0x52, 0x20, 0x48, 0x41, 0x43, 0x4B, 0x45,
383 0x52, 0x20, 0x43, 0x4F, 0x4D, 0x42, 0x49, 0x29,
384 0x43, 0x61, 0x6E, 0x20, 0x79, 0x6F, 0x75, 0x20,
385 0x66, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x43, 0x48,
386 0x45, 0x43, 0x4B, 0x2D, 0x52, 0x4F, 0x55, 0x54,
387 0x49, 0x4E, 0x45, 0x53, 0x20, 0x3F, 0x43, 0x61,
388 0x6E, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x63, 0x72,
389 0x61, 0x63, 0x6B, 0x20, 0x74, 0x68, 0x65, 0x73,
390 0x65, 0x20, 0x70, 0x72, 0x6F, 0x74, 0x65, 0x63,
391 0x74, 0x20, 0x3F, 0x67, 0x6F, 0x6F, 0x64, 0x20,
392 0x62, 0x79, 0x65, 0x20, 0x21, 0x6F, 0x75, 0x20,
394 if(memcmp((void *)(t + 0x10 + 0x60), xanadu2fm_d_1, sizeof(xanadu2fm_d_1)) == 0) {
395 if(memcmp((void *)(t + 0x10 + 0x70), xanadu2fm_d_2, sizeof(xanadu2fm_d_2)) == 0) {
396 is_special_disk = SPECIAL_DISK_FM7_XANADU2_D;
397 this->out_debug_log("SPECIAL DISK: Xanadu scenario 2 Disk D");
401 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 0x08 && t[3] == 0x01) {
405 static const uint8_t xanadu1fm_d_1[] = {
406 0xFF, 0x43, 0x6F, 0x6E, 0x74, 0x69, 0x6E, 0x75,
407 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x70,
408 0x72, 0x6F, 0x67, 0x72, 0x61 ,0x6D, 0x2E, 0x0D,
409 0xFF, 0x00, 0x34, 0x01, 0x1C ,0xAF, 0x6F, 0x8D,
410 0x01, 0x3F, 0x17, 0xFA, 0xE4, 0x27, 0xFB, 0x35,
411 0x81, 0x34, 0x13, 0xA6, 0x80, 0x81, 0xFF, 0x27,
412 0x04, 0x8D, 0x04, 0x20, 0xF6, 0x35, 0x93, 0x34,
413 0x15, 0xA7, 0x8D, 0x00, 0xB6, 0xC6, 0x05, 0x30,
414 0x8D, 0x00, 0xAC, 0x17, 0x00, 0xB6, 0x17, 0x00,
415 0xD6, 0x35, 0x95, 0x00, 0x00, 0x3F, 0x59, 0x41,
416 0x4D, 0x41, 0x55, 0x43, 0x48, 0x49, 0x91, 0xD3,
418 static const uint8_t xanadu1fm_d_2[] = {
419 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
420 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
421 0x00, 0x00, 0x00, 0x00, 0x3F, 0x59, 0x41, 0x4D,
422 0x41, 0x55, 0x43, 0x48, 0x49, 0x93, 0xD3, 0x8F,
425 if(memcmp((void *)(t + 0x10 + 0), xanadu1fm_d_1, sizeof(xanadu1fm_d_1)) == 0) {
426 if(memcmp((void *)(t + 0x10 + 0xb0), xanadu1fm_d_2, sizeof(xanadu1fm_d_2)) == 0) {
427 is_special_disk = SPECIAL_DISK_FM7_XANADU2_D; // Same issue as Xanadu2.
428 this->out_debug_log("SPECIAL DISK: Xanadu scenario 1 Disk A");
432 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 1 && t[3] == 1) {
433 //$03 + $2D + "PSY-O-BLADE Copyright 1988 by T&E SOFT Inc." + $B6 + $FD + $05
434 static const uint8_t psyoblade_ipl1[] ={
435 0x03, 0x2d, 0x50, 0x53, 0x59, 0xa5, 0x4f, 0xa5,
436 0x42, 0x4c, 0x41, 0x44, 0x45, 0x20, 0x20, 0x20,
437 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68,
438 0x74, 0x20, 0x31, 0x39, 0x38, 0x38, 0x20, 0x62,
439 0x79, 0x20, 0x54, 0x26, 0x45, 0x20, 0x53, 0x4f,
440 0x46, 0x54, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0xb6,
444 static const uint8_t psyoblade_disk_1[] ={
445 0xc3, 0x00, 0x01, 0x00, 0x1a, 0x50, 0x86, 0xff,
446 0xb7, 0xfd, 0x10, 0xb7, 0xfd, 0x0f, 0x30, 0x8c,
447 0x0e, 0x8d, 0x35, 0x30, 0x8c, 0x14, 0x8d, 0x30,
448 0x30, 0x8c, 0x14, 0x8d, 0x2b, 0x20, 0xfe, 0x0a,
450 //$00 + $00 + $03 + $14 + "PSY-O-BLADE DISK" + $B6 + $FD + $05
451 static const uint8_t psyoblade_disk_2[] ={
452 0x00, 0x00, 0x03, 0x14, 0x50, 0x53, 0x59, 0xa5,
453 0x4f, 0xa5, 0x42, 0x4c, 0x41, 0x44, 0x45, 0x20,
454 0x20, 0x20, 0x44, 0x49, 0x53, 0x4B, 0x20
456 //RIGLAS/FM: $3E - $7D
457 static const uint8_t riglas_fm[] = {
458 0x0d, 0x56, /* $3e-$3f */
459 0x44, 0x53, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, /* $40-$47 */
460 0x43, 0x4d, 0x44, 0x00, 0x00, 0x02, 0x1b, 0x02, /* $48-$4f */
461 0x1e, 0x00, 0x04, 0x00, 0x00, 0x03, 0x0d, 0x56, /* $50-$57 */
462 0x43, 0x4f, 0x50, 0x59, 0x00, 0x00, 0x00, 0x00, /* $58-$5f */
463 0x43, 0x4d, 0x44, 0x00, 0x00, 0x02, 0x1f, 0x03, /* $60-$67 */
464 0x03, 0x00, 0x05, 0x00, 0x00, 0x03, 0x0d, 0x56, /* $68-$6f */
465 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x00, 0x00, /* $70-$77 */
466 0x43, 0x4d, 0x44, 0x00, 0x00, 0x03 /* $78-$7d */
469 if(memcmp((void *)(t + 0x58), psyoblade_ipl1, sizeof(psyoblade_ipl1)) == 0) {
470 is_special_disk = SPECIAL_DISK_FM77AV_PSYOBLADE;
471 this->out_debug_log("SPECIAL DISK: PSY-O-BLADE");
473 } else if(memcmp((void *)(t + 0x10), psyoblade_disk_1, sizeof(psyoblade_disk_1)) == 0) {
474 if(memcmp((void *)(t + 0x40), psyoblade_disk_2, sizeof(psyoblade_disk_2)) == 0) {
475 is_special_disk = SPECIAL_DISK_FM77AV_PSYOBLADE;
476 this->out_debug_log("SPECIAL DISK: PSY-O-BLADE");
479 } else if(memcmp((void *)(t + 0x3e + 0x10), riglas_fm, sizeof(riglas_fm)) == 0) {
480 is_special_disk = SPECIAL_DISK_FM7_RIGLAS;
481 this->out_debug_log("SPECIAL DISK: RIGLAS FM-7/77/AV");
484 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 3 && t[3] == 1) {
485 static const uint8_t taiyoufm1[] = {
486 0x10, 0xff, 0x04, 0x9f, 0x10, 0xce, 0xfc, 0xf4,
487 0x37, 0x20, 0x34, 0x20, 0x37, 0x36, 0x34, 0x36, //7 4 7646
488 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
489 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
490 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
491 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
492 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
493 0x10, 0xfe, 0x04, 0x9f, 0x1c, 0xef, 0x86, 0xff,
494 0xb7, 0xfc, 0xf8, 0x17, 0x03, 0x3d, 0x33, 0xc9,
495 0xdb, 0x9c, 0x35, 0x04, 0x5a, 0x26, 0xa0, 0xfe,
497 if(memcmp((void *)(t + 0x70), taiyoufm1, sizeof(taiyoufm1)) == 0) {
498 is_special_disk = SPECIAL_DISK_FM7_TAIYOU1;
499 this->out_debug_log("SPECIAL DISK: TAIYOU NO SHINDEN Disk 1");
502 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 2 && t[3] == 1) {
503 static const uint8_t taiyoufm2[] = {
504 0x3d, 0x02, 0xa3, 0xd6, 0x01, 0xc7, 0x06, 0x86,
505 0x07, 0x00, 0x00, 0xc7, 0x06, 0xd4, 0x01, 0x00,
506 0x00, 0xb4, 0x19, 0xcd, 0x21, 0xfe, 0xc0, 0xa2,
507 0xda, 0x01, 0x06, 0xb9, 0x10, 0x00, 0xbb, 0x40,
508 0x00, 0x8e, 0xc3, 0xbb, 0x00, 0x00, 0xfe, 0x06,
509 0xd9, 0x01, 0x26, 0x80, 0xbf, 0x6c, 0x02, 0x00,
510 0x74, 0x03, 0x43, 0xe2, 0xf1, 0x07, 0xc6, 0x06,
511 0xdb, 0x01, 0x00, 0xbb, 0x80, 0x00, 0x80, 0x3f,
513 if(memcmp((void *)(t + 0x00), taiyoufm2, sizeof(taiyoufm2)) == 0) {
514 is_special_disk = SPECIAL_DISK_FM7_TAIYOU2;
515 this->out_debug_log("SPECIAL DISK: TAIYOU NO SHINDEN Disk 2");
520 t += data_size.sd + 0x10;
524 #elif defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
525 // FIXME: ugly patch for X1turbo ALPHA and X1 Batten Tanuki
526 if(media_type == MEDIA_TYPE_2D) {
529 offset.read_4bytes_le_from(buffer + 0x20);
530 if(IS_VALID_TRACK(offset.d)) {
531 // check first sector
532 static const uint8_t batten[] = {0xca, 0xde, 0xaf, 0xc3, 0xdd, 0x20, 0xc0, 0xc7, 0xb7};
533 uint8_t *t = buffer + offset.d;
534 #if defined(_X1TURBO) || defined(_X1TURBOZ)
535 // if(strncmp((char *)(t + 0x11), "turbo ALPHA", 11) == 0) {
536 // is_special_disk = SPECIAL_DISK_X1TURBO_ALPHA;
539 if(memcmp((void *)(t + 0x11), batten, sizeof(batten)) == 0) {
540 is_special_disk = SPECIAL_DISK_X1_BATTEN;
541 this->out_debug_log("SPECIAL DISK: BATTEN TANUKI NO DAI BOUKEN");
555 trim_required = false;
557 buffer[0x1a] = write_protected ? 0x10 : 0; // mey be changed
559 if(/*!write_protected &&*/ !(file_size.d == orig_file_size && get_crc32(buffer, file_size.d) == orig_crc32)) {
561 FILEIO* fio = new FILEIO();
562 int pre_size = 0, post_size = 0;
563 uint8_t *pre_buffer = NULL, *post_buffer = NULL;
565 // is this d88 format ?
566 if(check_file_extension(dest_path, _T(".d88")) || check_file_extension(dest_path, _T(".d77")) || check_file_extension(dest_path, _T(".1dd"))) {
567 if(fio->Fopen(dest_path, FILEIO_READ_BINARY)) {
568 fio->Fseek(0, FILEIO_SEEK_END);
569 uint32_t total_size = fio->Ftell(), offset = 0;
570 for(int i = 0; i < file_bank; i++) {
571 fio->Fseek(offset + 0x1c, SEEK_SET);
572 offset += fio->FgetUint32_LE();
574 if((pre_size = offset) > 0) {
575 pre_buffer = (uint8_t *)malloc(pre_size);
576 fio->Fseek(0, FILEIO_SEEK_SET);
577 fio->Fread(pre_buffer, pre_size, 1);
579 fio->Fseek(offset + 0x1c, SEEK_SET);
580 offset += fio->FgetUint32_LE();
581 if((post_size = total_size - offset) > 0) {
582 post_buffer = (uint8_t *)malloc(post_size);
583 fio->Fseek(offset, FILEIO_SEEK_SET);
584 fio->Fread(post_buffer, post_size, 1);
590 // is this solid image and was physical formatted ?
592 bool formatted = false;
595 for(int trkside = 0; trkside < 164; trkside++) {
597 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
599 if(!IS_VALID_TRACK(offset.d)) {
602 if(solid_nside == 1 && (trkside & 1) == 1) {
607 uint8_t* t = buffer + offset.d;
608 pair_t sector_num, data_size;
609 sector_num.read_2bytes_le_from(t + 4);
611 if(sector_num.sd != solid_nsec) {
614 for(int i = 0; i < sector_num.sd; i++) {
615 data_size.read_2bytes_le_from(t + 14);
616 if(data_size.sd != solid_size) {
619 if(t[6] != (solid_mfm ? 0 : 0x40)) {
622 t += data_size.sd + 0x10;
625 if(tracks != (solid_ncyl * solid_nside)) {
629 my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), orig_path);
630 is_solid_image = false;
634 if((FILEIO::IsFileExisting(dest_path) && FILEIO::IsFileProtected(dest_path)) || !fio->Fopen(dest_path, FILEIO_WRITE_BINARY)) {
635 fio->Fopen(local_path(create_string(_T("temporary_saved_floppy_disk_#%d.d88"), drive_num)), FILEIO_WRITE_BINARY);
637 if(fio->IsOpened()) {
639 fio->Fwrite(pre_buffer, pre_size, 1);
643 fio->Fwrite(fdi_header, 4096, 1);
645 for(int trkside = 0; trkside < 164; trkside++) {
647 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
649 if(!IS_VALID_TRACK(offset.d)) {
652 uint8_t* t = buffer + offset.d;
653 pair_t sector_num, data_size;
654 sector_num.read_2bytes_le_from(t + 4);
656 for(int i = 0; i < sector_num.sd; i++) {
657 data_size.read_2bytes_le_from(t + 14);
658 fio->Fwrite(t + 0x10, data_size.sd, 1);
659 t += data_size.sd + 0x10;
663 fio->Fwrite(buffer, file_size.d, 1);
666 fio->Fwrite(post_buffer, post_size, 1);
677 this->out_debug_log("CLOSEd");
681 inserted = write_protected = false;
683 sector_size.sd = sector_num.sd = 0;
688 void DISK::save_as_d88(const _TCHAR* file_path)
691 FILEIO* fio = new FILEIO();
692 if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
694 memcpy(tmp_buffer, buffer + 0x20, 4 * 82);
695 for(int trk = 0; trk < 82; trk++) {
696 memcpy(buffer + 0x20 + (trk * 2 + 0) * 4, tmp_buffer + trk * 4, 4);
697 memset(buffer + 0x20 + (trk * 2 + 1) * 4, 0, 4);
699 buffer[0x1b] = MEDIA_TYPE_2DD;
701 fio->Fwrite(buffer, file_size.d, 1);
709 bool DISK::get_track(int trk, int side)
711 sector_size.sd = sector_num.sd = 0;
712 invalid_format = false;
715 // disk not inserted or invalid media type
716 if(!(inserted && check_media_type())) {
720 //printf("disk[foo]->get_track(trk=%d ,side=%d)\n", trk, side);
722 int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
723 if(!(0 <= trkside && trkside < 164)) {
730 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
732 if(!IS_VALID_TRACK(offset.d)) {
737 sector = buffer + offset.d;
738 sector_num.read_2bytes_le_from(sector + 4);
740 data_size.read_2bytes_le_from(sector + 14);
742 // create each sector position in track
744 if(sector_num.sd == 0) {
745 track_mfm = drive_mfm;
748 for(int i = 0; i < sector_num.sd; i++) {
749 data_size.read_2bytes_le_from(t + 14);
750 // t[6]: 0x00 = double-density, 0x40 = single-density
755 t += data_size.sd + 0x10;
758 int sync_size = track_mfm ? 12 : 6;
759 int am_size = track_mfm ? 3 : 0;
760 int gap0_size = track_mfm ? 80 : 40;
761 int gap1_size = track_mfm ? 50 : 26;
762 int gap2_size = track_mfm ? 22 : 11;
763 int gap3_size = 0, gap4_size;
765 if(media_type == MEDIA_TYPE_144 || media_type == MEDIA_TYPE_2HD) {
767 if(data_size.sd == 256 && sector_num.sd == 26) gap3_size = 54;
768 if(data_size.sd == 512 && sector_num.sd == 15) gap3_size = 84;
769 if(data_size.sd == 1024 && sector_num.sd == 8) gap3_size = 116;
771 if(data_size.sd == 128 && sector_num.sd == 26) gap3_size = 27;
772 if(data_size.sd == 256 && sector_num.sd == 15) gap3_size = 42;
773 if(data_size.sd == 512 && sector_num.sd == 8) gap3_size = 58;
777 if(data_size.sd == 256 && sector_num.sd == 16) gap3_size = 51;
778 if(data_size.sd == 512 && sector_num.sd == 9) gap3_size = 80;
779 if(data_size.sd == 1024 && sector_num.sd == 5) gap3_size = 116;
781 if(data_size.sd == 128 && sector_num.sd == 16) gap3_size = 27;
782 if(data_size.sd == 256 && sector_num.sd == 9) gap3_size = 42;
783 if(data_size.sd == 512 && sector_num.sd == 5) gap3_size = 58;
788 int total = 0, valid_sector_num = 0;
790 for(int i = 0; i < sector_num.sd; i++) {
791 data_size.read_2bytes_le_from(t + 14);
792 sync_position[i] = total; // for invalid format case
793 total += sync_size + (am_size + 1) + (4 + 2) + gap2_size;
794 if(data_size.sd > 0) {
795 total += sync_size + (am_size + 1);
796 total += data_size.sd + 2;
799 //if(t[2] != i + 1) {
802 t += data_size.sd + 0x10;
804 total += sync_size + (am_size + 1); // sync in preamble
807 gap3_size = (get_track_size() - total - gap0_size - gap1_size) / (valid_sector_num + 1);
809 gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * valid_sector_num;
811 if(gap3_size < 8 || gap4_size < 8) {
812 gap0_size = gap1_size = gap3_size = (get_track_size() - total) / (2 + valid_sector_num + 1);
813 gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * valid_sector_num;
815 //printf("GAP3=%d GAP4=%d\n", gap3_size, gap4_size);
816 if(gap3_size < 8 || gap4_size < 8) {
817 gap0_size = gap1_size = gap3_size = gap4_size = 8;
818 //gap0_size = gap1_size = gap3_size = gap4_size = 32;
819 invalid_format = true;
822 int preamble_size = gap0_size + sync_size + (am_size + 1) + gap1_size;
825 total -= sync_size + (am_size + 1);
826 for(int i = 0; i < sector_num.sd; i++) {
827 sync_position[i] *= get_track_size() - preamble_size - gap4_size;
828 sync_position[i] /= total;
832 total = preamble_size;
833 sync_position[array_length(sync_position) - 1] = gap0_size; // sync position in preamble
835 for(int i = 0; i < sector_num.sd; i++) {
836 data_size.read_2bytes_le_from(t + 14);
838 total = preamble_size + sync_position[i];
840 sync_position[i] = total;
842 am1_position[i] = total;
843 total += am_size + 1;
844 id_position[i] = total;
845 total += (4 + 2) + gap2_size;
846 if(data_size.sd > 0) {
847 total += sync_size + (am_size + 1);
848 data_position[i] = total;
849 total += data_size.sd + 2;
852 data_position[i] = total; // FIXME
854 t += data_size.sd + 0x10;
859 bool DISK::make_track(int trk, int side)
861 int track_size = get_track_size();
863 if(!get_track(trk, side)) {
864 // create a dummy track
865 for(int i = 0; i < track_size; i++) {
872 int sync_size = track_mfm ? 12 : 6;
873 int am_size = track_mfm ? 3 : 0;
874 int gap2_size = track_mfm ? 22 : 11;
875 uint8_t gap_data = track_mfm ? 0x4e : 0xff;
878 memset(track, gap_data, track_size);
879 int q = sync_position[array_length(sync_position) - 1];
882 for(int i = 0; i < sync_size; i++) {
886 for(int i = 0; i < am_size; i++) {
894 for(int i = 0; i < sector_num.sd; i++) {
896 data_size.read_2bytes_le_from(t + 14);
897 int p = sync_position[i];
900 for(int j = 0; j < sync_size; j++) {
901 if(p < track_size) track[p++] = 0x00;
904 for(int j = 0; j < am_size; j++) {
905 if(p < track_size) track[p++] = 0xa1;
907 if(p < track_size) track[p++] = 0xfe;
909 if(p < track_size) track[p++] = t[0];
910 if(p < track_size) track[p++] = t[1];
911 if(p < track_size) track[p++] = t[2];
912 if(p < track_size) track[p++] = t[3];
914 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0]]);
915 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[1]]);
916 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[2]]);
917 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[3]]);
918 if(p < track_size) track[p++] = (crc >> 8) & 0xff;
919 if(p < track_size) track[p++] = (crc >> 0) & 0xff;
921 for(int j = 0; j < gap2_size; j++) {
922 if(p < track_size) track[p++] = gap_data;
925 if(data_size.sd > 0) {
927 for(int j = 0; j < sync_size; j++) {
928 if(p < track_size) track[p++] = 0x00;
931 for(int j = 0; j < am_size; j++) {
932 if(p < track_size) track[p++] = 0xa1;
934 if(p < track_size) track[p++] = (t[7] != 0) ? 0xf8 : 0xfb;
937 for(int j = 0; j < data_size.sd; j++) {
938 if(p < track_size) track[p++] = t[0x10 + j];
939 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0x10 + j]]);
941 if(p < track_size) track[p++] = (crc >> 8) & 0xff;
942 if(p < track_size) track[p++] = (crc >> 0) & 0xff;
944 t += data_size.sd + 0x10;
949 bool DISK::get_sector(int trk, int side, int index)
951 sector_size.sd = sector_num.sd = 0;
954 // disk not inserted or invalid media type
955 if(!(inserted && check_media_type())) {
960 if(trk == -1 && side == -1) {
964 int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
965 if(!(0 <= trkside && trkside < 164)) {
969 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
971 if(!IS_VALID_TRACK(offset.d)) {
976 uint8_t* t = buffer + offset.d;
977 sector_num.read_2bytes_le_from(t + 4);
979 if(index >= sector_num.sd) {
984 for(int i = 0; i < index; i++) {
986 data_size.read_2bytes_le_from(t + 14);
987 t += data_size.sd + 0x10;
993 void DISK::set_sector_info(uint8_t *t)
1001 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0]]);
1002 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[1]]);
1003 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[2]]);
1004 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[3]]);
1005 id[4] = (crc >> 8) & 0xff;
1006 id[5] = (crc >> 0) & 0xff;
1007 // http://www,gnu-darwin.or.jp/www001/src/ports/emulators/quasi88/work/quasi88-0.6.3/document/FORMAT.TXT
1008 // t[6]: 0x00 = double-density, 0x40 = single-density
1009 // t[7]: 0x00 = normal, 0x10 = deleted mark
1010 // t[8]: 0x00 = valid, 0x10 = valid (deleted data), 0xa0 = id crc error, 0xb0 = data crc error, 0xe0 = address mark missing, 0xf0 = data mark missing
1012 deleted = (t[7] != 0);
1014 // if(ignore_crc()) {
1015 // addr_crc_error = false;
1016 // data_crc_error = false;
1018 addr_crc_error = ((t[8] & 0xf0) == 0xa0);
1019 data_crc_error = ((t[8] & 0xf0) == 0xb0);
1022 sector_size.read_2bytes_le_from(t + 14);
1025 void DISK::set_deleted(bool value)
1027 if(sector != NULL) {
1028 uint8_t *t = sector - 0x10;
1029 t[7] = value ? 0x10 : 0;
1030 if((t[8] & 0xf0) == 0x00 || (t[8] & 0xf0) == 0x10) {
1031 t[8] = (t[8] & 0x0f) | t[7];
1037 void DISK::set_data_crc_error(bool value)
1039 if(sector != NULL) {
1040 uint8_t *t = sector - 0x10;
1041 t[8] = (t[8] & 0x0f) | (value ? 0xb0 : t[7]);
1043 data_crc_error = value;
1046 void DISK::set_data_mark_missing()
1048 if(sector != NULL) {
1049 uint8_t *t = sector - 0x10;
1050 t[8] = (t[8] & 0x0f) | 0xf0;
1054 //addr_crc_error = false;
1055 data_crc_error = false;
1058 bool DISK::format_track(int trk, int side)
1060 // disk not inserted or invalid media type
1061 if(!(inserted && check_media_type())) {
1066 int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
1067 if(!(0 <= trkside && trkside < 164)) {
1071 // create new empty track
1074 trim_required = false;
1076 memset(buffer + DISK_BUFFER_SIZE, 0, sizeof(buffer) - DISK_BUFFER_SIZE);
1078 offset.d = DISK_BUFFER_SIZE;
1079 offset.write_4bytes_le_to(buffer + 0x20 + trkside * 4);
1081 trim_required = true;
1083 track_mfm = drive_mfm;
1088 void DISK::insert_sector(uint8_t c, uint8_t h, uint8_t r, uint8_t n, bool deleted, bool data_crc_error, uint8_t fill_data, int length)
1090 uint8_t* t = buffer + DISK_BUFFER_SIZE;
1093 for(int i = 0; i < (sector_num.sd - 1); i++) {
1094 t[4] = sector_num.b.l;
1095 t[5] = sector_num.b.h;
1097 data_size.read_2bytes_le_from(t + 14);
1098 t += data_size.sd + 0x10;
1104 t[4] = sector_num.b.l;
1105 t[5] = sector_num.b.h;
1106 t[6] = track_mfm ? 0 : 0x40;
1107 t[7] = deleted ? 0x10 : 0;
1108 t[8] = data_crc_error ? 0xb0 : t[7];
1109 t[14] = (length >> 0) & 0xff;
1110 t[15] = (length >> 8) & 0xff;
1111 memset(t + 16, fill_data, length);
1116 void DISK::sync_buffer()
1120 trim_required = false;
1124 void DISK::trim_buffer()
1126 int max_tracks = 164;
1127 int track_limit = 164;
1128 uint32_t dest_offset = 0x2b0;
1131 memset(tmp_buffer, 0, sizeof(tmp_buffer));
1132 memcpy(tmp_buffer, buffer, 0x20);
1134 if(media_type == MEDIA_TYPE_2D) {
1138 for(int trkside = 0; trkside < 164; trkside++) {
1139 pair_t src_trk_offset;
1140 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
1141 if(src_trk_offset.d != 0) {
1143 if(src_trk_offset.d < 0x2b0) {
1144 max_tracks = (src_trk_offset.d - 0x20) >> 2;
1145 if(max_tracks > track_limit) {
1146 max_tracks = track_limit;
1150 if(src_trk_offset.d != 0x2b0) {
1151 max_tracks = (src_trk_offset.d - 0x20) >> 2;
1152 if(max_tracks > 164) {
1153 dest_offset = 0x20 + max_tracks * 4);
1162 for(int trkside = 0; trkside < max_tracks; trkside++) {
1163 pair_t src_trk_offset;
1164 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
1166 pair_t dest_trk_offset;
1167 dest_trk_offset.d = 0;
1169 if(IS_VALID_TRACK(src_trk_offset.d)) {
1170 uint8_t* t = buffer + src_trk_offset.d;
1171 pair_t sector_num, data_size;
1172 sector_num.read_2bytes_le_from(t + 4);
1173 if(sector_num.sd != 0) {
1174 dest_trk_offset.d = dest_offset;
1175 for(int i = 0; i < sector_num.sd; i++) {
1176 data_size.read_2bytes_le_from(t + 14);
1177 memcpy(tmp_buffer + dest_offset, t, data_size.sd + 0x10);
1178 dest_offset += data_size.sd + 0x10;
1179 t += data_size.sd + 0x10;
1183 dest_trk_offset.write_4bytes_le_to(tmp_buffer + 0x20 + trkside * 4);
1187 file_size.d = dest_offset;
1188 file_size.write_4bytes_le_to(tmp_buffer + 0x1c);
1190 memset(buffer, 0, sizeof(buffer));
1191 memcpy(buffer, tmp_buffer, min(sizeof(buffer), file_size.d));
1196 if(drive_rpm != 0) {
1198 } else if(inserted) {
1199 return (media_type == MEDIA_TYPE_2HD) ? 360 : 300;
1201 return (drive_type == DRIVE_TYPE_2HD) ? 360 : 300;
1205 int DISK::get_track_size()
1208 return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : track_mfm ? 6250 : 3100;
1210 return drive_type == DRIVE_TYPE_144 ? 12500 : drive_type == DRIVE_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100;
1214 double DISK::get_usec_per_track()
1216 return 1000000.0 / (get_rpm() / 60.0);
1219 double DISK::get_usec_per_bytes(int bytes)
1221 return 1000000.0 / (get_track_size() * (get_rpm() / 60.0)) * bytes;
1224 int DISK::get_bytes_per_usec(double usec)
1226 return (int)(usec / get_usec_per_bytes(1) + 0.5);
1229 bool DISK::check_media_type()
1231 switch(drive_type) {
1233 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || \
1234 defined(_FM77AV20) || defined(_FM77AV20EX)
1235 return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
1237 return (media_type == MEDIA_TYPE_2D);
1239 case DRIVE_TYPE_2DD:
1240 return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
1241 case DRIVE_TYPE_2HD:
1242 return (media_type == MEDIA_TYPE_2HD);
1243 case DRIVE_TYPE_144:
1244 return (media_type == MEDIA_TYPE_144);
1245 case DRIVE_TYPE_UNK:
1246 return true; // always okay
1253 #define COPYBUFFER(src, size) { \
1254 if(file_size.d + (size) > DISK_BUFFER_SIZE) { \
1257 memcpy(buffer + file_size.d, (src), (size)); \
1258 file_size.d += (size); \
1267 uint32_t trkptr[164];
1273 uint8_t dens, del, stat;
1278 // teledisk image decoder
1281 this teledisk image decoder is based on:
1283 LZHUF.C English version 1.0 based on Japanese version 29-NOV-1988
1284 LZSS coded by Haruhiko OKUMURA
1285 Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
1286 Edited and translated to English by Kenji RIKITAKE
1290 #define STRING_BUFFER_SIZE 4096
1291 #define LOOKAHEAD_BUFFER_SIZE 60
1293 #define N_CHAR (256 - THRESHOLD + LOOKAHEAD_BUFFER_SIZE)
1294 #define TABLE_SIZE (N_CHAR * 2 - 1)
1295 #define ROOT_POSITION (TABLE_SIZE - 1)
1296 #define MAX_FREQ 0x8000
1298 static uint8_t td_text_buf[STRING_BUFFER_SIZE + LOOKAHEAD_BUFFER_SIZE - 1];
1299 static uint16_t td_ptr;
1300 static uint16_t td_bufcnt, td_bufndx, td_bufpos;
1301 static uint16_t td_ibufcnt, td_ibufndx;
1302 static uint8_t td_inbuf[512];
1303 static uint16_t td_freq[TABLE_SIZE + 1];
1304 static short td_prnt[TABLE_SIZE + N_CHAR];
1305 static short td_son[TABLE_SIZE];
1306 static uint16_t td_getbuf;
1307 static uint8_t td_getlen;
1309 static const uint8_t td_d_code[256] = {
1310 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1311 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1312 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
1313 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
1314 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1315 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1316 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1317 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
1318 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
1319 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f,
1320 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
1321 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
1322 0x18, 0x18, 0x19, 0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, 0x1f, 0x1f,
1323 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
1324 0x28, 0x28, 0x29, 0x29, 0x2a, 0x2a, 0x2b, 0x2b, 0x2c, 0x2c, 0x2d, 0x2d, 0x2e, 0x2e, 0x2f, 0x2f,
1325 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f
1327 static const uint8_t td_d_len[256] = {
1328 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1329 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1330 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1331 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1332 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1333 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1334 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1335 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1336 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1337 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1338 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1339 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1340 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1341 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1342 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1343 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
1346 static int td_next_word(FILEIO* fio)
1348 if(td_ibufndx >= td_ibufcnt) {
1349 td_ibufndx = td_ibufcnt = 0;
1350 memset(td_inbuf, 0, 512);
1351 for(int i = 0; i < 512; i++) {
1352 int d = fio->Fgetc();
1363 while(td_getlen <= 8) {
1364 td_getbuf |= td_inbuf[td_ibufndx++] << (8 - td_getlen);
1370 static int td_get_bit(FILEIO* fio)
1372 if(td_next_word(fio) < 0) {
1375 short i = td_getbuf;
1378 return (i < 0) ? 1 : 0;
1381 static int td_get_byte(FILEIO* fio)
1383 if(td_next_word(fio) != 0) {
1386 uint16_t i = td_getbuf;
1393 static void td_start_huff()
1396 for(i = 0; i < N_CHAR; i++) {
1398 td_son[i] = i + TABLE_SIZE;
1399 td_prnt[i + TABLE_SIZE] = i;
1402 while(j <= ROOT_POSITION) {
1403 td_freq[j] = td_freq[i] + td_freq[i + 1];
1405 td_prnt[i] = td_prnt[i + 1] = j;
1408 td_freq[TABLE_SIZE] = 0xffff;
1409 td_prnt[ROOT_POSITION] = 0;
1412 static void td_reconst()
1416 for(i = 0; i < TABLE_SIZE; i++) {
1417 if(td_son[i] >= TABLE_SIZE) {
1418 td_freq[j] = (td_freq[i] + 1) / 2;
1419 td_son[j] = td_son[i];
1423 for(i = 0, j = N_CHAR; j < TABLE_SIZE; i += 2, j++) {
1425 f = td_freq[j] = td_freq[i] + td_freq[k];
1426 for(k = j - 1; f < td_freq[k]; k--);
1429 memmove(&td_freq[k + 1], &td_freq[k], l);
1431 memmove(&td_son[k + 1], &td_son[k], l);
1434 for(i = 0; i < TABLE_SIZE; i++) {
1435 if((k = td_son[i]) >= TABLE_SIZE) {
1438 td_prnt[k] = td_prnt[k + 1] = i;
1443 static void td_update(int c)
1446 if(td_freq[ROOT_POSITION] == MAX_FREQ) {
1449 c = td_prnt[c + TABLE_SIZE];
1452 if(k > td_freq[l = c + 1]) {
1453 while(k > td_freq[++l]);
1455 td_freq[c] = td_freq[l];
1459 if(i < TABLE_SIZE) {
1465 if(j < TABLE_SIZE) {
1472 while((c = td_prnt[c]) != 0);
1475 static short td_decode_char(FILEIO* fio)
1478 uint16_t c = td_son[ROOT_POSITION];
1479 while(c < TABLE_SIZE) {
1480 if((ret = td_get_bit(fio)) < 0) {
1491 static short td_decode_position(FILEIO* fio)
1495 if((bit = td_get_byte(fio)) < 0) {
1499 c = (uint16_t)td_d_code[i] << 6;
1500 j = td_d_len[i] - 2;
1502 if((bit = td_get_bit(fio)) < 0) {
1507 return (c | (i & 0x3f));
1510 static void td_init_decode()
1512 td_ibufcnt= td_ibufndx = td_bufcnt = td_getbuf = 0;
1515 for(int i = 0; i < STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE; i++) {
1516 td_text_buf[i] = ' ';
1518 td_ptr = STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE;
1521 static int td_decode(FILEIO* fio, uint8_t *buf, int len)
1525 for(count = 0; count < len;) {
1526 if(td_bufcnt == 0) {
1527 if((c = td_decode_char(fio)) < 0) {
1531 *(buf++) = (uint8_t)c;
1532 td_text_buf[td_ptr++] = (uint8_t)c;
1533 td_ptr &= (STRING_BUFFER_SIZE - 1);
1536 if((pos = td_decode_position(fio)) < 0) {
1539 td_bufpos = (td_ptr - pos - 1) & (STRING_BUFFER_SIZE - 1);
1540 td_bufcnt = c - 255 + THRESHOLD;
1544 while(td_bufndx < td_bufcnt && count < len) {
1545 c = td_text_buf[(td_bufpos + td_bufndx) & (STRING_BUFFER_SIZE - 1)];
1546 *(buf++) = (uint8_t)c;
1548 td_text_buf[td_ptr++] = (uint8_t)c;
1549 td_ptr &= (STRING_BUFFER_SIZE - 1);
1552 if(td_bufndx >= td_bufcnt) {
1553 td_bufndx = td_bufcnt = 0;
1580 uint8_t nsec, trk, head;
1589 bool DISK::teledisk_to_d88(FILEIO *fio)
1596 bool temporary = false;
1598 // check teledisk header
1599 fio->Fseek(0, FILEIO_SEEK_SET);
1600 fio->Fread(&hdr, sizeof(td_hdr_t), 1);
1601 if(hdr.sig[0] == 't' && hdr.sig[1] == 'd') {
1602 // this image is compressed
1603 // decompress to the temporary file
1604 FILEIO* fio_tmp = new FILEIO();
1605 if(!fio_tmp->Fopen(local_path(_T("teledisk.$$$")), FILEIO_WRITE_BINARY)) {
1612 if((rd = td_decode(fio, obuf, 512)) > 0) {
1613 fio_tmp->Fwrite(obuf, rd, 1);
1621 // reopen the temporary file
1623 if(!fio->Fopen(_T("teledisk.$$$"), FILEIO_READ_BINARY)) {
1626 } else if(hdr.sig[0] == 'T' && hdr.sig[1] == 'D') {
1627 // this image is not compressed
1631 if(hdr.flag & 0x80) {
1633 fio->Fread(&cmt, sizeof(td_cmt_t), 1);
1634 fio->Fseek(cmt.len, FILEIO_SEEK_CUR);
1637 // create d88 header
1641 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1642 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "TELEDISK");
1643 d88_hdr.protect = 0; // non-protected
1646 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1649 int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
1650 fio->Fread(&trk, sizeof(td_trk_t), 1);
1651 while(trk.nsec != 0xff) {
1652 d88_hdr.trkptr[trkcnt++] = trkptr;
1653 if(hdr.sides == 1) {
1657 // read sectors in this track
1658 for(int i = 0; i < trk.nsec; i++) {
1659 uint8_t buf[2048], dst[2048];
1660 memset(buf, 0, sizeof(buf));
1661 memset(dst, 0, sizeof(dst));
1663 // read sector header
1664 fio->Fread(&sct, sizeof(td_sct_t), 1);
1666 // create d88 sector header
1667 memset(&d88_sct, 0, sizeof(d88_sct_t));
1672 d88_sct.nsec = trk.nsec;
1673 d88_sct.dens = (hdr.dens & 0x80) ? 0x40 : 0;
1674 d88_sct.del = (sct.ctrl & 4) ? 0x10 : 0;
1675 d88_sct.stat = (sct.ctrl & 2) ? 0xb0 : d88_sct.del;
1676 d88_sct.size = secsize[sct.n & 3];
1678 // create sector image
1679 if(sct.ctrl & 0x30) {
1680 d88_sct.stat = 0xf0; // data mark missing
1683 // read sector source
1684 int len = fio->Fgetc();
1685 len += fio->Fgetc() * 256 - 1;
1686 int flag = fio->Fgetc(), d = 0;
1687 fio->Fread(buf, len, 1);
1691 memcpy(dst, buf, len);
1692 } else if(flag == 1) {
1694 len2.read_2bytes_le_from(buf);
1699 } else if(flag == 2) {
1700 for(int s = 0; s < len;) {
1701 int type = buf[s++];
1702 int len2 = buf[s++];
1705 dst[d++] = buf[s++];
1707 } else if(type < 5) {
1713 for(int j = 0; j < n; j++) {
1717 for(int j = 0; j < n; j++) {
1722 break; // unknown type
1726 break; // unknown flag
1731 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1732 COPYBUFFER(dst, d88_sct.size);
1733 trkptr += sizeof(d88_sct_t) + d88_sct.size;
1736 fio->Fread(&trk, sizeof(td_trk_t), 1);
1738 d88_hdr.type = ((hdr.dens & 3) == 2) ? MEDIA_TYPE_2HD : ((trkcnt >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
1739 d88_hdr.size = trkptr;
1740 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1743 FILEIO::RemoveFile(_T("teledisk.$$$"));
1748 // imagedisk image decoder (from MESS formats/imd_dsk.c by Mr.Miodrag Milanovic)
1750 bool DISK::imagedisk_to_d88(FILEIO *fio)
1752 int size = fio->FileLength();
1753 fio->Fseek(0, FILEIO_SEEK_SET);
1754 fio->Fread(tmp_buffer, size, 1);
1756 if(memcmp(tmp_buffer, "IMD ", 4) != 0) {
1761 for(pos = 0; pos < size && tmp_buffer[pos] != 0x1a; pos++);
1768 // create d88 header
1772 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1773 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "IMAGEDISK");
1774 d88_hdr.protect = 0; // non-protected
1777 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1780 int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
1785 // check track header
1786 uint8_t mode = tmp_buffer[pos++];
1787 uint8_t track = tmp_buffer[pos++];
1788 uint8_t head = tmp_buffer[pos++];
1789 uint8_t sector_count = tmp_buffer[pos++];
1790 uint8_t ssize = tmp_buffer[pos++];
1792 if(sector_count == 0) {
1798 uint32_t actual_size = ssize < 7 ? 128 << ssize : 8192;
1801 const uint8_t *snum = &tmp_buffer[pos];
1802 pos += sector_count;
1803 const uint8_t *tnum = head & 0x80 ? &tmp_buffer[pos] : NULL;
1805 pos += sector_count;
1806 const uint8_t *hnum = head & 0x40 ? &tmp_buffer[pos] : NULL;
1808 pos += sector_count;
1812 int trkside = track * 2 + (head & 1);
1814 if(trkcnt < trkside) {
1817 d88_hdr.trkptr[trkside] = trkptr;
1819 if(img_mode == -1) {
1820 img_mode = mode & 3;
1823 // read sectors in this track
1824 for(int i = 0; i < sector_count; i++) {
1825 // create d88 sector header
1826 uint8_t stype = tmp_buffer[pos++];
1827 memset(&d88_sct, 0, sizeof(d88_sct_t));
1828 d88_sct.c = tnum ? tnum[i] : track;
1829 d88_sct.h = hnum ? hnum[i] : head;
1830 d88_sct.r = snum[i];
1832 d88_sct.nsec = sector_count;
1833 d88_sct.dens = (mode < 3) ? 0x40 : 0;
1835 if(stype == 0 || stype > 8) {
1836 d88_sct.stat = 0xf0; // data mark missing
1839 d88_sct.del = (stype == 3 || stype == 4 || stype == 7 || stype == 8) ? 0x10 : 0;
1840 d88_sct.stat = (stype == 5 || stype == 6 || stype == 7 || stype == 8) ? 0xb0 : d88_sct.del;
1841 d88_sct.size = actual_size;
1843 // create sector image
1844 if(stype == 2 || stype == 4 || stype == 6 || stype == 8) {
1845 memset(dst, tmp_buffer[pos++], actual_size);
1847 memcpy(dst, &tmp_buffer[pos], actual_size);
1848 pos += d88_sct.size;
1854 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1855 COPYBUFFER(dst, d88_sct.size);
1856 trkptr += sizeof(d88_sct_t) + d88_sct.size;
1860 d88_hdr.type = (img_mode == 0) ? MEDIA_TYPE_2HD : (((trkcnt + 1) >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
1861 d88_hdr.size = trkptr;
1862 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1866 // cpdread image decoder (from MESS formats/dsk_dsk.c by Mr.Olivier Galibert)
1868 #define DSK_FORMAT_HEADER "MV - CPC"
1869 #define EXT_FORMAT_HEADER "EXTENDED CPC DSK"
1872 struct track_header {
1873 uint8_t headertag[13];
1876 uint8_t track_number;
1877 uint8_t side_number;
1880 uint8_t sector_size_code;
1881 uint8_t number_of_sector;
1882 uint8_t gap3_length;
1883 uint8_t filler_byte;
1885 struct sector_header {
1889 uint8_t sector_size_code;
1890 uint8_t fdc_status_reg1;
1891 uint8_t fdc_status_reg2;
1892 uint16_t data_length;
1896 bool DISK::cpdread_to_d88(FILEIO *fio)
1898 bool extendformat = false;
1899 int image_size = fio->FileLength();
1901 fio->Fseek(0, FILEIO_SEEK_SET);
1902 fio->Fread(tmp_buffer, image_size, 1);
1904 if(memcmp(tmp_buffer, EXT_FORMAT_HEADER, 16) == 0) {
1905 extendformat = true;
1906 } else if(memcmp(tmp_buffer, DSK_FORMAT_HEADER, 8) == 0) {
1907 extendformat = false;
1912 int heads = tmp_buffer[0x31];
1917 int tracks = tmp_buffer[0x30];
1918 int track_offsets[84 * 2];
1919 bool track_offsets_error = false;
1921 int cnt = 0, tmp = 0x100;
1922 for(int i = 0; i < tracks * heads; i++) {
1923 track_offsets_error = (memcmp(tmp_buffer + tmp, "Track-Info", 10) != 0);
1924 if(track_offsets_error) {
1927 track_offsets[cnt] = tmp;
1928 tmp += tmp_buffer[0x32] + tmp_buffer[0x33] * 256;
1932 int cnt = 0, tmp = 0x100;
1933 for(int i = 0; i < tracks * heads; i++) {
1934 int length = tmp_buffer[0x34 + i] << 8;
1936 track_offsets_error = (memcmp(tmp_buffer + tmp, "Track-Info", 10) != 0);
1937 if(track_offsets_error) {
1940 track_offsets[cnt] = tmp;
1943 track_offsets[cnt] = image_size;
1948 if(track_offsets_error) {
1949 // I found the dsk image that the track size in table is 1100h, but the actual track size is 900h,
1950 // so I modified this code to search "Track-Info" at the top of track information block
1951 int cnt = 0, tmp = 0x100;
1952 for(int i = 0; i < tracks * heads; i++) {
1954 for(; tmp < image_size; tmp += 0x10) {
1955 found = (memcmp(tmp_buffer + tmp, "Track-Info", 10) == 0);
1961 track_offsets[cnt] = tmp;
1964 track_offsets[cnt] = image_size;
1970 // create d88 header
1974 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1975 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "CPDREAD");
1976 d88_hdr.protect = 0; // non-protected
1979 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1982 int total = 0, trkptr = sizeof(d88_hdr_t);
1984 for(int track = 0; track < tracks; track++) {
1985 for(int side = 0; side < heads; side++) {
1986 if(track_offsets[(track << 1) + side] >= image_size) {
1989 if((track << 1) + side < 164) {
1990 d88_hdr.trkptr[(track << 1) + side] = trkptr;
1994 memcpy(&tr, tmp_buffer + track_offsets[(track << 1) + side], sizeof(tr));
1995 int pos = track_offsets[(track << 1) + side] + 0x100;
1996 for(int j = 0; j < tr.number_of_sector; j++) {
1997 sector_header sector;
1998 memcpy(§or, tmp_buffer + track_offsets[(track << 1) + side] + sizeof(tr) + (sizeof(sector) * j), sizeof(sector));
2000 // create d88 sector header
2001 memset(&d88_sct, 0, sizeof(d88_sct_t));
2002 d88_sct.c = sector.track;
2003 d88_sct.h = sector.side;
2004 d88_sct.r = sector.sector_id;
2005 d88_sct.n = sector.sector_size_code;
2006 d88_sct.nsec = tr.number_of_sector;
2008 d88_sct.size = sector.data_length;
2009 d88_sct.dens = (tr.rec_mode == 1) ? 0x40 : 0;
2011 d88_sct.size = 128 << tr.sector_size_code;
2012 d88_sct.dens = (tr.sector_size_code == 0) ? 0x40 : 0; // FIXME
2014 d88_sct.del = (sector.fdc_status_reg1 == 0xb2) ? 0x10 : 0;
2015 d88_sct.stat = (d88_sct.size == 0) ? 0xf0 : (sector.fdc_status_reg1 == 0xb5) ? 0xb0 : d88_sct.del;
2018 if((track << 1) + side < 164) {
2019 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
2020 COPYBUFFER(tmp_buffer + pos, d88_sct.size);
2021 trkptr += sizeof(d88_sct_t) + d88_sct.size;
2023 total += d88_sct.size;
2026 pos += sector.data_length;
2028 pos += 128 << tr.sector_size_code;
2033 d88_hdr.type = (total < (368640 + 655360) / 2) ? MEDIA_TYPE_2D : (total < (737280 + 1228800) / 2) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2HD;
2034 d88_hdr.size = trkptr;
2035 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
2039 // solid image decoder
2041 bool DISK::solid_to_d88(FILEIO *fio, int type, int ncyl, int nside, int nsec, int size, bool mfm)
2047 solid_nside = nside;
2052 // create d88 header
2056 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
2057 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "SOLID");
2058 d88_hdr.protect = 0; // non-protected
2061 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
2064 for(int i = 0; i < 8; i++) {
2065 if(size == (128 << i)) {
2072 int trkptr = sizeof(d88_hdr_t);
2074 for(int c = 0; c < ncyl; c++) {
2075 for(int h = 0; h < nside; h++) {
2076 d88_hdr.trkptr[t++] = trkptr;
2081 // read sectors in this track
2082 for(int s = 0; s < nsec; s++) {
2083 // create d88 sector header
2084 memset(&d88_sct, 0, sizeof(d88_sct_t));
2089 d88_sct.nsec = nsec;
2093 d88_sct.size = size;
2095 // create sector image
2097 memset(dst, 0xe5, sizeof(dst));
2098 fio->Fread(dst, size, 1);
2101 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
2102 COPYBUFFER(dst, size);
2103 trkptr += sizeof(d88_sct_t) + size;
2107 d88_hdr.type = (type == MEDIA_TYPE_144) ? MEDIA_TYPE_2HD : type;
2108 d88_hdr.size = trkptr;
2109 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
2113 #define STATE_VERSION 13
2115 void DISK::save_state(FILEIO* state_fio)
2117 state_fio->FputUint32(STATE_VERSION);
2119 state_fio->Fwrite(buffer, sizeof(buffer), 1);
2120 state_fio->Fwrite(orig_path, sizeof(orig_path), 1);
2121 state_fio->Fwrite(dest_path, sizeof(dest_path), 1);
2122 state_fio->FputUint32(file_size.d);
2123 state_fio->FputInt32(file_bank);
2124 state_fio->FputUint32(orig_file_size);
2125 state_fio->FputUint32(orig_crc32);
2126 state_fio->FputBool(trim_required);
2127 state_fio->FputBool(is_1dd_image);
2128 state_fio->FputBool(is_solid_image);
2129 state_fio->FputBool(is_fdi_image);
2130 state_fio->Fwrite(fdi_header, sizeof(fdi_header), 1);
2131 state_fio->FputInt32(solid_ncyl);
2132 state_fio->FputInt32(solid_nside);
2133 state_fio->FputInt32(solid_nsec);
2134 state_fio->FputInt32(solid_size);
2135 state_fio->FputBool(solid_mfm);
2136 state_fio->FputBool(inserted);
2137 state_fio->FputBool(ejected);
2138 state_fio->FputBool(write_protected);
2139 state_fio->FputBool(changed);
2140 state_fio->FputUint8(media_type);
2141 state_fio->FputInt32(is_special_disk);
2142 state_fio->Fwrite(track, sizeof(track), 1);
2143 state_fio->FputInt32(sector_num.sd);
2144 state_fio->FputBool(track_mfm);
2145 state_fio->FputBool(invalid_format);
2146 //state_fio->FputBool(no_skew);
2147 state_fio->Fwrite(sync_position, sizeof(sync_position), 1);
2148 state_fio->Fwrite(am1_position, sizeof(am1_position), 1);
2149 state_fio->Fwrite(id_position, sizeof(id_position), 1);
2150 state_fio->Fwrite(data_position, sizeof(data_position), 1);
2151 // state_fio->FputInt32(gap3_size);
2152 state_fio->FputInt32(sector ? (int)(sector - buffer) : -1);
2153 state_fio->FputInt32(sector_size.sd);
2154 state_fio->Fwrite(id, sizeof(id), 1);
2155 state_fio->FputUint8(density);
2156 state_fio->FputBool(deleted);
2157 state_fio->FputBool(addr_crc_error);
2158 state_fio->FputBool(data_crc_error);
2159 state_fio->FputUint8(drive_type);
2160 state_fio->FputInt32(drive_rpm);
2161 state_fio->FputBool(drive_mfm);
2164 bool DISK::load_state(FILEIO* state_fio)
2166 if(state_fio->FgetUint32() != STATE_VERSION) {
2169 state_fio->Fread(buffer, sizeof(buffer), 1);
2170 state_fio->Fread(orig_path, sizeof(orig_path), 1);
2171 state_fio->Fread(dest_path, sizeof(dest_path), 1);
2172 file_size.d = state_fio->FgetUint32();
2173 file_bank = state_fio->FgetInt32();
2174 orig_file_size = state_fio->FgetUint32();
2175 orig_crc32 = state_fio->FgetUint32();
2176 trim_required = state_fio->FgetBool();
2177 is_1dd_image = state_fio->FgetBool();
2178 is_solid_image = state_fio->FgetBool();
2179 is_fdi_image = state_fio->FgetBool();
2180 state_fio->Fread(fdi_header, sizeof(fdi_header), 1);
2181 solid_ncyl = state_fio->FgetInt32();
2182 solid_nside = state_fio->FgetInt32();
2183 solid_nsec = state_fio->FgetInt32();
2184 solid_size = state_fio->FgetInt32();
2185 solid_mfm = state_fio->FgetBool();
2186 inserted = state_fio->FgetBool();
2187 ejected = state_fio->FgetBool();
2188 write_protected = state_fio->FgetBool();
2189 changed = state_fio->FgetBool();
2190 media_type = state_fio->FgetUint8();
2191 is_special_disk = state_fio->FgetInt32();
2192 state_fio->Fread(track, sizeof(track), 1);
2193 sector_num.sd = state_fio->FgetInt32();
2194 track_mfm = state_fio->FgetBool();
2195 invalid_format = state_fio->FgetBool();
2196 //no_skew = state_fio->FgetBool();
2197 state_fio->Fread(sync_position, sizeof(sync_position), 1);
2198 state_fio->Fread(am1_position, sizeof(am1_position), 1);
2199 state_fio->Fread(id_position, sizeof(id_position), 1);
2200 state_fio->Fread(data_position, sizeof(data_position), 1);
2201 // gap3_size = state_fio->FgetInt32();
2202 int offset = state_fio->FgetInt32();
2203 sector = (offset != -1) ? buffer + offset : NULL;
2204 sector_size.sd = state_fio->FgetInt32();
2205 state_fio->Fread(id, sizeof(id), 1);
2206 density = state_fio->FgetUint8();
2207 deleted = state_fio->FgetBool();
2208 addr_crc_error = state_fio->FgetBool();
2209 data_crc_error = state_fio->FgetBool();
2210 drive_type = state_fio->FgetUint8();
2211 drive_rpm = state_fio->FgetInt32();
2212 drive_mfm = state_fio->FgetBool();