2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
11 #include "../fileio.h"
14 #define local_path(x) create_local_path(x)
16 #define local_path(x) (x)
20 static const uint16_t crc_table[256] = {
21 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
22 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
23 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
24 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
25 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
26 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
27 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
28 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
29 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
30 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
31 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
32 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
33 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
34 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
35 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
36 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
39 static const int secsize[8] = {
40 128, 256, 512, 1024, 2048, 4096, 8192, 16384
43 static uint8_t tmp_buffer[DISK_BUFFER_SIZE];
45 // physical format table for solid image
48 int ncyl, nside, nsec, size;
55 static const fd_format_t fd_formats[] = {
57 { MEDIA_TYPE_2D, 40, 1, 16, 256, MFM }, // 1D 160KB
58 #elif defined(_SMC70) || defined(_SMC777)
59 { MEDIA_TYPE_2DD, 70, 1, 16, 256, MFM }, // 1DD 280KB
60 #elif defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
61 { MEDIA_TYPE_2D, 40, 2, 16, 256, MFM }, // 2D 320KB
63 { MEDIA_TYPE_2D, 40, 2, 18, 256, MFM }, // 2D 360KB
64 #elif defined(_MZ80B) || defined(_MZ2000) || defined(_MZ2200) || defined(_MZ2500)
65 { MEDIA_TYPE_2DD, 80, 2, 16, 256, MFM }, // 2DD 640KB
67 { MEDIA_TYPE_2D, 35, 1, 16, 128, FM }, // 1S 70KB
68 { MEDIA_TYPE_2D, 35, 2, 16, 128, FM }, // 2S 140KB
69 { MEDIA_TYPE_2DD, 77, 1, 26, 128, FM }, // 1S 250KB
70 { MEDIA_TYPE_2D, 40, 1, 8, 512, MFM }, // 1D 160KB
71 { MEDIA_TYPE_2D, 40, 1, 9, 512, MFM }, // 1D 180KB
72 { MEDIA_TYPE_2D, 40, 1, 10, 512, MFM }, // 1D 200KB
73 //#if defined(SUPPORT_MEDIA_TYPE_1DD)
74 // { MEDIA_TYPE_2DD, 70, 1, 8, 512, MFM }, // 1DD 280KB
75 // { MEDIA_TYPE_2DD, 70, 1, 9, 512, MFM }, // 1DD 315KB
76 // { MEDIA_TYPE_2DD, 70, 1, 10, 512, MFM }, // 1DD 350KB
77 // { MEDIA_TYPE_2DD, 80, 1, 8, 512, MFM }, // 1DD 320KB
78 // { MEDIA_TYPE_2DD, 80, 1, 9, 512, MFM }, // 1DD 360KB
79 // { MEDIA_TYPE_2DD, 80, 1, 10, 512, MFM }, // 1DD 400KB
81 { MEDIA_TYPE_2D, 35, 2, 8, 512, MFM }, // 2D 280KB
82 { MEDIA_TYPE_2D, 35, 2, 9, 512, MFM }, // 2D 315KB
83 { MEDIA_TYPE_2D, 35, 2, 10, 512, MFM }, // 2D 350KB
84 { MEDIA_TYPE_2D, 40, 2, 8, 512, MFM }, // 2D 320KB
85 { MEDIA_TYPE_2D, 40, 2, 9, 512, MFM }, // 2D 360KB
86 { MEDIA_TYPE_2D, 40, 2, 10, 512, MFM }, // 2D 400KB
88 { MEDIA_TYPE_2DD, 80, 2, 8, 512, MFM }, // 2DD 640KB
89 { MEDIA_TYPE_2DD, 80, 2, 9, 512, MFM }, // 2DD 720KB
90 { MEDIA_TYPE_2DD, 81, 2, 9, 512, MFM }, // 2DD 729KB, ASCII MSX
91 { MEDIA_TYPE_2DD, 80, 2, 10, 512, MFM }, // 2DD 800KB
92 { MEDIA_TYPE_2HD, 77, 2, 26, 256, MFM }, // 2HD 1001KB, MITSUBISHI/IBM
93 { MEDIA_TYPE_2HD, 80, 2, 15, 512, MFM }, // 2HC 1200KB, TOSHIBA/IBM
94 { MEDIA_TYPE_2HD, 77, 2, 8, 1024, MFM }, // 2HD 1232KB, NEC
95 { MEDIA_TYPE_144, 80, 2, 18, 512, MFM }, // 2HD 1440KB
96 { MEDIA_TYPE_144, 80, 2, 21, 512, MFM }, // 2HD 1680KB
97 { MEDIA_TYPE_144, 82, 2, 21, 512, MFM }, // 2HD 1722KB
98 { MEDIA_TYPE_144, 80, 2, 36, 512, MFM }, // 2ED 2880KB
102 #define IS_VALID_TRACK(offset) ((offset) >= 0x20 && (offset) < sizeof(buffer))
104 void DISK::open(const _TCHAR* file_path, int bank)
106 // check current disk image
108 if(_tcsicmp(orig_path, file_path) == 0 && file_bank == bank) {
116 memset(buffer, 0, sizeof(buffer));
118 write_protected = false;
119 media_type = MEDIA_TYPE_UNK;
121 is_solid_image = is_fdi_image = is_1dd_image = false;
122 trim_required = false;
123 track_mfm = drive_mfm;
126 FILEIO *fio = new FILEIO();
127 if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
128 my_tcscpy_s(orig_path, _MAX_PATH, file_path);
129 my_tcscpy_s(dest_path, _MAX_PATH, file_path);
131 this->out_debug_log("OPENed: %s", file_path);
133 file_size.d = fio->FileLength();
134 fio->Fseek(0, FILEIO_SEEK_SET);
136 if(check_file_extension(file_path, _T(".d88")) || check_file_extension(file_path, _T(".d77")) || check_file_extension(file_path, _T(".1dd"))) {
139 for(int i = 0; i < bank; i++) {
140 fio->Fseek(offset + 0x1c, SEEK_SET);
141 offset += fio->FgetUint32_LE();
143 fio->Fseek(offset + 0x1c, FILEIO_SEEK_SET);
144 file_size.d = fio->FgetUint32_LE();
145 fio->Fseek(offset, FILEIO_SEEK_SET);
146 fio->Fread(buffer, file_size.d, 1);
148 if(check_file_extension(file_path, _T(".1dd"))) {
150 media_type = MEDIA_TYPE_2DD;
152 inserted = changed = true;
153 // trim_required = true;
155 // fix sector number from big endian to little endian
156 for(int trkside = 0; trkside < 164; trkside++) {
158 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
160 if(!IS_VALID_TRACK(offset.d)) {
163 uint8_t* t = buffer + offset.d;
164 pair_t sector_num, data_size;
165 sector_num.read_2bytes_le_from(t + 4);
166 bool is_be = (sector_num.b.l == 0 && sector_num.b.h >= 4);
168 sector_num.read_2bytes_be_from(t + 4);
169 sector_num.write_2bytes_le_to(t + 4);
171 for(int i = 0; i < sector_num.sd; i++) {
173 sector_num.write_2bytes_le_to(t + 4);
175 data_size.read_2bytes_le_from(t + 14);
176 t += data_size.sd + 0x10;
179 } else if(check_file_extension(file_path, _T(".td0"))) {
182 inserted = changed = teledisk_to_d88(fio);
183 my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), file_path);
185 // failed to convert the disk image
187 } else if(check_file_extension(file_path, _T(".imd"))) {
190 inserted = changed = imagedisk_to_d88(fio);
191 my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), file_path);
193 // failed to convert the disk image
195 } else if(check_file_extension(file_path, _T(".dsk"))) {
198 inserted = changed = cpdread_to_d88(fio);
199 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(".2d")) && file_size.d == 40 * 2 * 16 * 256) {
204 // 2d image for SHARP X1 series
205 inserted = changed = is_solid_image = solid_to_d88(fio, MEDIA_TYPE_2D, 40, 2, 16, 256, true);
206 } else if(check_file_extension(file_path, _T(".img")) && file_size.d == 70 * 1 * 16 * 256) {
207 // img image for SONY SMC-70/777 series
208 inserted = changed = is_solid_image = solid_to_d88(fio, MEDIA_TYPE_2DD, 70, 1, 16, 256, true);
209 } else if(check_file_extension(file_path, _T(".sf7")) && file_size.d == 40 * 1 * 16 * 256) {
210 // sf7 image for SEGA SC-3000 + SF-7000
211 inserted = changed = is_solid_image = solid_to_d88(fio, MEDIA_TYPE_2D, 40, 1, 16, 256, true);
214 // check solid image file format
215 bool is_fdi_tmp = check_file_extension(file_path, _T(".fdi"));
216 for(int i = 0;; i++) {
217 const fd_format_t *p = &fd_formats[i];
221 int len = p->ncyl * p->nside * p->nsec * p->size;
222 // 4096 bytes: FDI header ???
223 if(file_size.d == len + (is_fdi_tmp ? 4096 : 0)) {
224 fio->Fseek(0, FILEIO_SEEK_SET);
227 fio->Fread(fdi_header, 4096, 1);
231 int nside = p->nside;
234 #if defined(SUPPORT_MEDIA_TYPE_1DD)
235 if(type == MEDIA_TYPE_2D && nside == 2 && p->mfm) {
236 type = MEDIA_TYPE_2DD;
240 #elif defined(_ANY2D88)
241 if(open_as_1dd && type == MEDIA_TYPE_2D && nside == 2 && p->mfm) {
242 type = MEDIA_TYPE_2DD;
246 if(open_as_256 && (size == 512 || size == 1024)) {
251 // if(solid_to_d88(fio, p->type, p->ncyl, p->nside, p->nsec, p->size, p->mfm)) {
252 if(solid_to_d88(fio, type, ncyl, nside, nsec, size, p->mfm)) {
253 inserted = changed = is_solid_image = true;
259 if(fio->IsOpened()) {
265 // check loaded image
268 if(media_type == MEDIA_TYPE_UNK) {
269 if((media_type = buffer[0x1b]) == MEDIA_TYPE_2HD) {
270 // check 1.2MB or 1.44MB
271 for(int trkside = 0; trkside < 164; trkside++) {
273 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
275 if(!IS_VALID_TRACK(offset.d)) {
279 uint8_t *t = buffer + offset.d;
280 pair_t sector_num, data_size;
281 sector_num.read_2bytes_le_from(t + 4);
282 data_size.read_2bytes_le_from(t + 14);
284 if(sector_num.sd >= 18 && data_size.sd == 512) {
285 media_type = MEDIA_TYPE_144;
292 // fix write protect flag
293 if(buffer[0x1a] != 0) {
295 write_protected = true;
298 // get crc32 for midification check
299 crc32 = get_crc32(buffer, file_size.d);
301 // check special disk image
302 #if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
303 // FIXME: ugly patch for FM-7 Gambler Jiko Chuushin Ha, DEATH FORCE and Psy-O-Blade
304 if(media_type == MEDIA_TYPE_2D) {
306 pair_t offset, sector_num, data_size;
307 offset.read_4bytes_le_from(buffer + 0x20);
308 if(IS_VALID_TRACK(offset.d)) {
309 // check the sector (c,h,r,n) = (0,0,7,1) or (0,0,f7,2)
310 uint8_t* t = buffer + offset.d;
311 sector_num.read_2bytes_le_from(t + 4);
312 for(int i = 0; i < sector_num.sd; i++) {
313 data_size.read_2bytes_le_from(t + 14);
314 if(is_special_disk == 0) {
315 if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 7 && t[3] == 1) {
316 static const uint8_t gambler[] = {0xb7, 0xde, 0xad, 0xdc, 0xdd, 0xcc, 0xde, 0xd7, 0xb1, 0x20, 0xbc, 0xde, 0xba, 0xc1, 0xad, 0xb3, 0xbc, 0xdd, 0xca};
317 if(memcmp((void *)(t + 0x30), gambler, sizeof(gambler)) == 0) {
318 is_special_disk = SPECIAL_DISK_FM7_GAMBLER;
321 } else if(data_size.sd == 0x200 && t[0] == 0 && t[1] == 0 && t[2] == 0xf7 && t[3] == 2) {
322 //"DEATHFORCE/77AV" + $f7*17 + $00 + $00
323 static const uint8_t deathforce[] ={
324 0x44, 0x45, 0x41, 0x54, 0x48, 0x46, 0x4f, 0x52,
325 0x43, 0x45, 0x2f, 0x37, 0x37, 0x41, 0x56, 0xf7,
326 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
327 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
330 if(memcmp((void *)(t + 0x10), deathforce, sizeof(deathforce)) == 0) {
331 this->out_debug_log("SPECIAL DISK: DEATH FORCE");
332 is_special_disk = SPECIAL_DISK_FM7_DEATHFORCE;
335 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 0x05 && t[3] == 1) {
336 //$00 * 16 + $00 + "Protected by N & A (SUPER HACKER COMBI)
337 //Can you found CHECK-ROUTINES ?Can you crack these protect ?
339 static const uint8_t xanadu2fm_d_1[] ={
340 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
341 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
343 static const uint8_t xanadu2fm_d_2[] = {
344 0x50, 0x72, 0x6F, 0x74, 0x65, 0x63, 0x74, 0x65,
345 0x64, 0x20, 0x62, 0x79, 0x20, 0x20, 0x4E, 0x20,
346 0x26, 0x20, 0x41, 0x20, 0x28, 0x53, 0x55, 0x50,
347 0x45, 0x52, 0x20, 0x48, 0x41, 0x43, 0x4B, 0x45,
348 0x52, 0x20, 0x43, 0x4F, 0x4D, 0x42, 0x49, 0x29,
349 0x43, 0x61, 0x6E, 0x20, 0x79, 0x6F, 0x75, 0x20,
350 0x66, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x43, 0x48,
351 0x45, 0x43, 0x4B, 0x2D, 0x52, 0x4F, 0x55, 0x54,
352 0x49, 0x4E, 0x45, 0x53, 0x20, 0x3F, 0x43, 0x61,
353 0x6E, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x63, 0x72,
354 0x61, 0x63, 0x6B, 0x20, 0x74, 0x68, 0x65, 0x73,
355 0x65, 0x20, 0x70, 0x72, 0x6F, 0x74, 0x65, 0x63,
356 0x74, 0x20, 0x3F, 0x67, 0x6F, 0x6F, 0x64, 0x20,
357 0x62, 0x79, 0x65, 0x20, 0x21, 0x6F, 0x75, 0x20,
359 if(memcmp((void *)(t + 0x10 + 0x60), xanadu2fm_d_1, sizeof(xanadu2fm_d_1)) == 0) {
360 if(memcmp((void *)(t + 0x10 + 0x70), xanadu2fm_d_2, sizeof(xanadu2fm_d_2)) == 0) {
361 is_special_disk = SPECIAL_DISK_FM7_XANADU2_D;
362 this->out_debug_log("SPECIAL DISK: Xanadu scenario 2 Disk D");
366 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 0x08 && t[3] == 0x01) {
370 static const uint8_t xanadu1fm_d_1[] = {
371 0xFF, 0x43, 0x6F, 0x6E, 0x74, 0x69, 0x6E, 0x75,
372 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x70,
373 0x72, 0x6F, 0x67, 0x72, 0x61 ,0x6D, 0x2E, 0x0D,
374 0xFF, 0x00, 0x34, 0x01, 0x1C ,0xAF, 0x6F, 0x8D,
375 0x01, 0x3F, 0x17, 0xFA, 0xE4, 0x27, 0xFB, 0x35,
376 0x81, 0x34, 0x13, 0xA6, 0x80, 0x81, 0xFF, 0x27,
377 0x04, 0x8D, 0x04, 0x20, 0xF6, 0x35, 0x93, 0x34,
378 0x15, 0xA7, 0x8D, 0x00, 0xB6, 0xC6, 0x05, 0x30,
379 0x8D, 0x00, 0xAC, 0x17, 0x00, 0xB6, 0x17, 0x00,
380 0xD6, 0x35, 0x95, 0x00, 0x00, 0x3F, 0x59, 0x41,
381 0x4D, 0x41, 0x55, 0x43, 0x48, 0x49, 0x91, 0xD3,
383 static const uint8_t xanadu1fm_d_2[] = {
384 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
385 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
386 0x00, 0x00, 0x00, 0x00, 0x3F, 0x59, 0x41, 0x4D,
387 0x41, 0x55, 0x43, 0x48, 0x49, 0x93, 0xD3, 0x8F,
390 if(memcmp((void *)(t + 0x10 + 0), xanadu1fm_d_1, sizeof(xanadu1fm_d_1)) == 0) {
391 if(memcmp((void *)(t + 0x10 + 0xb0), xanadu1fm_d_2, sizeof(xanadu1fm_d_2)) == 0) {
392 is_special_disk = SPECIAL_DISK_FM7_XANADU2_D; // Same issue as Xanadu2.
393 this->out_debug_log("SPECIAL DISK: Xanadu scenario 1 Disk A");
397 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 1 && t[3] == 1) {
398 //$03 + $2D + "PSY-O-BLADE Copyright 1988 by T&E SOFT Inc." + $B6 + $FD + $05
399 static const uint8_t psyoblade_ipl1[] ={
400 0x03, 0x2d, 0x50, 0x53, 0x59, 0xa5, 0x4f, 0xa5,
401 0x42, 0x4c, 0x41, 0x44, 0x45, 0x20, 0x20, 0x20,
402 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68,
403 0x74, 0x20, 0x31, 0x39, 0x38, 0x38, 0x20, 0x62,
404 0x79, 0x20, 0x54, 0x26, 0x45, 0x20, 0x53, 0x4f,
405 0x46, 0x54, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0xb6,
409 static const uint8_t psyoblade_disk_1[] ={
410 0xc3, 0x00, 0x01, 0x00, 0x1a, 0x50, 0x86, 0xff,
411 0xb7, 0xfd, 0x10, 0xb7, 0xfd, 0x0f, 0x30, 0x8c,
412 0x0e, 0x8d, 0x35, 0x30, 0x8c, 0x14, 0x8d, 0x30,
413 0x30, 0x8c, 0x14, 0x8d, 0x2b, 0x20, 0xfe, 0x0a,
415 //$00 + $00 + $03 + $14 + "PSY-O-BLADE DISK" + $B6 + $FD + $05
416 static const uint8_t psyoblade_disk_2[] ={
417 0x00, 0x00, 0x03, 0x14, 0x50, 0x53, 0x59, 0xa5,
418 0x4f, 0xa5, 0x42, 0x4c, 0x41, 0x44, 0x45, 0x20,
419 0x20, 0x20, 0x44, 0x49, 0x53, 0x4B, 0x20
421 if(memcmp((void *)(t + 0x58), psyoblade_ipl1, sizeof(psyoblade_ipl1)) == 0) {
422 is_special_disk = SPECIAL_DISK_FM77AV_PSYOBLADE;
423 this->out_debug_log("SPECIAL DISK: PSY-O-BLADE");
425 } else if(memcmp((void *)(t + 0x10), psyoblade_disk_1, sizeof(psyoblade_disk_1)) == 0) {
426 if(memcmp((void *)(t + 0x40), psyoblade_disk_2, sizeof(psyoblade_disk_2)) == 0) {
427 is_special_disk = SPECIAL_DISK_FM77AV_PSYOBLADE;
428 this->out_debug_log("SPECIAL DISK: PSY-O-BLADE");
432 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 3 && t[3] == 1) {
433 static const uint8_t taiyoufm1[] = {
434 0x10, 0xff, 0x04, 0x9f, 0x10, 0xce, 0xfc, 0xf4,
435 0x37, 0x20, 0x34, 0x20, 0x37, 0x36, 0x34, 0x36, //7 4 7646
436 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
437 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
438 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
439 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
440 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
441 0x10, 0xfe, 0x04, 0x9f, 0x1c, 0xef, 0x86, 0xff,
442 0xb7, 0xfc, 0xf8, 0x17, 0x03, 0x3d, 0x33, 0xc9,
443 0xdb, 0x9c, 0x35, 0x04, 0x5a, 0x26, 0xa0, 0xfe,
445 if(memcmp((void *)(t + 0x70), taiyoufm1, sizeof(taiyoufm1)) == 0) {
446 is_special_disk = SPECIAL_DISK_FM7_TAIYOU1;
447 this->out_debug_log("SPECIAL DISK: TAIYOU NO SHINDEN Disk 1");
450 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 2 && t[3] == 1) {
451 static const uint8_t taiyoufm2[] = {
452 0x3d, 0x02, 0xa3, 0xd6, 0x01, 0xc7, 0x06, 0x86,
453 0x07, 0x00, 0x00, 0xc7, 0x06, 0xd4, 0x01, 0x00,
454 0x00, 0xb4, 0x19, 0xcd, 0x21, 0xfe, 0xc0, 0xa2,
455 0xda, 0x01, 0x06, 0xb9, 0x10, 0x00, 0xbb, 0x40,
456 0x00, 0x8e, 0xc3, 0xbb, 0x00, 0x00, 0xfe, 0x06,
457 0xd9, 0x01, 0x26, 0x80, 0xbf, 0x6c, 0x02, 0x00,
458 0x74, 0x03, 0x43, 0xe2, 0xf1, 0x07, 0xc6, 0x06,
459 0xdb, 0x01, 0x00, 0xbb, 0x80, 0x00, 0x80, 0x3f,
461 if(memcmp((void *)(t + 0x00), taiyoufm2, sizeof(taiyoufm2)) == 0) {
462 is_special_disk = SPECIAL_DISK_FM7_TAIYOU2;
463 this->out_debug_log("SPECIAL DISK: TAIYOU NO SHINDEN Disk 2");
467 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 3 && t[3] == 1) {
468 static const uint8_t taiyoufm1[] = {
469 0x10, 0xff, 0x04, 0x9f, 0x10, 0xce, 0xfc, 0xf4,
470 0x37, 0x20, 0x34, 0x20, 0x37, 0x36, 0x34, 0x36, //7 4 7646
471 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
472 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
473 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
474 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
475 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
476 0x10, 0xfe, 0x04, 0x9f, 0x1c, 0xef, 0x86, 0xff,
477 0xb7, 0xfc, 0xf8, 0x17, 0x03, 0x3d, 0x33, 0xc9,
478 0xdb, 0x9c, 0x35, 0x04, 0x5a, 0x26, 0xa0, 0xfe,
480 if(memcmp((void *)(t + 0x70), taiyoufm1, sizeof(taiyoufm1)) == 0) {
481 is_special_disk = SPECIAL_DISK_FM7_TAIYOU1;
482 this->out_debug_log("SPECIAL DISK: TAIYOU NO SHINDEN Disk 1");
485 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 2 && t[3] == 1) {
486 static const uint8_t taiyoufm2[] = {
487 0x3d, 0x02, 0xa3, 0xd6, 0x01, 0xc7, 0x06, 0x86,
488 0x07, 0x00, 0x00, 0xc7, 0x06, 0xd4, 0x01, 0x00,
489 0x00, 0xb4, 0x19, 0xcd, 0x21, 0xfe, 0xc0, 0xa2,
490 0xda, 0x01, 0x06, 0xb9, 0x10, 0x00, 0xbb, 0x40,
491 0x00, 0x8e, 0xc3, 0xbb, 0x00, 0x00, 0xfe, 0x06,
492 0xd9, 0x01, 0x26, 0x80, 0xbf, 0x6c, 0x02, 0x00,
493 0x74, 0x03, 0x43, 0xe2, 0xf1, 0x07, 0xc6, 0x06,
494 0xdb, 0x01, 0x00, 0xbb, 0x80, 0x00, 0x80, 0x3f,
496 if(memcmp((void *)(t + 0x00), taiyoufm2, sizeof(taiyoufm2)) == 0) {
497 is_special_disk = SPECIAL_DISK_FM7_TAIYOU2;
498 this->out_debug_log("SPECIAL DISK: TAIYOU NO SHINDEN Disk 1");
502 t += data_size.sd + 0x10;
506 #elif defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
507 // FIXME: ugly patch for X1turbo ALPHA and X1 Batten Tanuki
508 if(media_type == MEDIA_TYPE_2D) {
511 offset.read_4bytes_le_from(buffer + 0x20);
512 if(IS_VALID_TRACK(offset.d)) {
513 // check first sector
514 static const uint8_t batten[] = {0xca, 0xde, 0xaf, 0xc3, 0xdd, 0x20, 0xc0, 0xc7, 0xb7};
515 uint8_t *t = buffer + offset.d;
516 #if defined(_X1TURBO) || defined(_X1TURBOZ)
517 // if(strncmp((char *)(t + 0x11), "turbo ALPHA", 11) == 0) {
518 // is_special_disk = SPECIAL_DISK_X1TURBO_ALPHA;
521 if(memcmp((void *)(t + 0x11), batten, sizeof(batten)) == 0) {
522 is_special_disk = SPECIAL_DISK_X1_BATTEN;
523 this->out_debug_log("SPECIAL DISK: BATTEN TANUKI NO DAI BOUKEN");
537 trim_required = false;
539 buffer[0x1a] = write_protected ? 0x10 : 0; // mey be changed
541 if(/*!write_protected &&*/ file_size.d && get_crc32(buffer, file_size.d) != crc32) {
543 FILEIO* fio = new FILEIO();
544 int pre_size = 0, post_size = 0;
545 uint8_t *pre_buffer = NULL, *post_buffer = NULL;
547 // is this d88 format ?
548 if(check_file_extension(dest_path, _T(".d88")) || check_file_extension(dest_path, _T(".d77")) || check_file_extension(dest_path, _T(".1dd"))) {
549 if(fio->Fopen(dest_path, FILEIO_READ_BINARY)) {
550 fio->Fseek(0, FILEIO_SEEK_END);
551 uint32_t total_size = fio->Ftell(), offset = 0;
552 for(int i = 0; i < file_bank; i++) {
553 fio->Fseek(offset + 0x1c, SEEK_SET);
554 offset += fio->FgetUint32_LE();
556 if((pre_size = offset) > 0) {
557 pre_buffer = (uint8_t *)malloc(pre_size);
558 fio->Fseek(0, FILEIO_SEEK_SET);
559 fio->Fread(pre_buffer, pre_size, 1);
561 fio->Fseek(offset + 0x1c, SEEK_SET);
562 offset += fio->FgetUint32_LE();
563 if((post_size = total_size - offset) > 0) {
564 post_buffer = (uint8_t *)malloc(post_size);
565 fio->Fseek(offset, FILEIO_SEEK_SET);
566 fio->Fread(post_buffer, post_size, 1);
572 // is this solid image and was physical formatted ?
574 bool formatted = false;
577 for(int trkside = 0; trkside < 164; trkside++) {
579 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
581 if(!IS_VALID_TRACK(offset.d)) {
584 if(solid_nside == 1 && (trkside & 1) == 1) {
589 uint8_t* t = buffer + offset.d;
590 pair_t sector_num, data_size;
591 sector_num.read_2bytes_le_from(t + 4);
593 if(sector_num.sd != solid_nsec) {
596 for(int i = 0; i < sector_num.sd; i++) {
597 data_size.read_2bytes_le_from(t + 14);
598 if(data_size.sd != solid_size) {
601 if(t[6] != (solid_mfm ? 0 : 0x40)) {
604 t += data_size.sd + 0x10;
607 if(tracks != (solid_ncyl * solid_nside)) {
611 my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), orig_path);
612 is_solid_image = false;
616 if((FILEIO::IsFileExisting(dest_path) && FILEIO::IsFileProtected(dest_path)) || !fio->Fopen(dest_path, FILEIO_WRITE_BINARY)) {
617 fio->Fopen(local_path(create_string(_T("temporary_saved_floppy_disk_#%d.d88"), drive_num)), FILEIO_WRITE_BINARY);
619 if(fio->IsOpened()) {
621 fio->Fwrite(pre_buffer, pre_size, 1);
625 fio->Fwrite(fdi_header, 4096, 1);
627 for(int trkside = 0; trkside < 164; trkside++) {
629 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
631 if(!IS_VALID_TRACK(offset.d)) {
634 uint8_t* t = buffer + offset.d;
635 pair_t sector_num, data_size;
636 sector_num.read_2bytes_le_from(t + 4);
638 for(int i = 0; i < sector_num.sd; i++) {
639 data_size.read_2bytes_le_from(t + 14);
640 fio->Fwrite(t + 0x10, data_size.sd, 1);
641 t += data_size.sd + 0x10;
645 fio->Fwrite(buffer, file_size.d, 1);
648 fio->Fwrite(post_buffer, post_size, 1);
659 this->out_debug_log("CLOSEd");
663 inserted = write_protected = false;
665 sector_size.sd = sector_num.sd = 0;
670 void DISK::save_as_d88(const _TCHAR* file_path)
673 FILEIO* fio = new FILEIO();
674 if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
676 memcpy(tmp_buffer, buffer + 0x20, 4 * 82);
677 for(int trk = 0; trk < 82; trk++) {
678 memcpy(buffer + 0x20 + (trk * 2 + 0) * 4, tmp_buffer + trk * 4, 4);
679 memset(buffer + 0x20 + (trk * 2 + 1) * 4, 0, 4);
681 buffer[0x1b] = MEDIA_TYPE_2DD;
683 fio->Fwrite(buffer, file_size.d, 1);
691 bool DISK::get_track(int trk, int side)
693 sector_size.sd = sector_num.sd = 0;
694 invalid_format = false;
697 // disk not inserted or invalid media type
698 if(!(inserted && check_media_type())) {
703 int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
704 if(!(0 <= trkside && trkside < 164)) {
711 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
713 if(!IS_VALID_TRACK(offset.d)) {
718 sector = buffer + offset.d;
719 sector_num.read_2bytes_le_from(sector + 4);
721 data_size.read_2bytes_le_from(sector + 14);
723 // create each sector position in track
725 if(sector_num.sd == 0) {
726 track_mfm = drive_mfm;
729 for(int i = 0; i < sector_num.sd; i++) {
730 data_size.read_2bytes_le_from(t + 14);
731 // t[6]: 0x00 = double-density, 0x40 = single-density
736 t += data_size.sd + 0x10;
739 int sync_size = track_mfm ? 12 : 6;
740 int am_size = track_mfm ? 3 : 0;
741 int gap0_size = track_mfm ? 80 : 40;
742 int gap1_size = track_mfm ? 50 : 26;
743 int gap2_size = track_mfm ? 22 : 11;
744 int gap3_size = 0, gap4_size;
746 if(media_type == MEDIA_TYPE_144 || media_type == MEDIA_TYPE_2HD) {
748 if(data_size.sd == 256 && sector_num.sd == 26) gap3_size = 54;
749 if(data_size.sd == 512 && sector_num.sd == 15) gap3_size = 84;
750 if(data_size.sd == 1024 && sector_num.sd == 8) gap3_size = 116;
752 if(data_size.sd == 128 && sector_num.sd == 26) gap3_size = 27;
753 if(data_size.sd == 256 && sector_num.sd == 15) gap3_size = 42;
754 if(data_size.sd == 512 && sector_num.sd == 8) gap3_size = 58;
758 if(data_size.sd == 256 && sector_num.sd == 16) gap3_size = 51;
759 if(data_size.sd == 512 && sector_num.sd == 9) gap3_size = 80;
760 if(data_size.sd == 1024 && sector_num.sd == 5) gap3_size = 116;
762 if(data_size.sd == 128 && sector_num.sd == 16) gap3_size = 27;
763 if(data_size.sd == 256 && sector_num.sd == 9) gap3_size = 42;
764 if(data_size.sd == 512 && sector_num.sd == 5) gap3_size = 58;
769 int total = 0, valid_sector_num = 0;
771 for(int i = 0; i < sector_num.sd; i++) {
772 data_size.read_2bytes_le_from(t + 14);
773 sync_position[i] = total; // for invalid format case
774 total += sync_size + (am_size + 1) + (4 + 2) + gap2_size;
775 if(data_size.sd > 0) {
776 total += sync_size + (am_size + 1);
777 total += data_size.sd + 2;
780 //if(t[2] != i + 1) {
783 t += data_size.sd + 0x10;
785 total += sync_size + (am_size + 1); // sync in preamble
788 gap3_size = (get_track_size() - total - gap0_size - gap1_size) / (valid_sector_num + 1);
790 gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * valid_sector_num;
792 if(gap3_size < 8 || gap4_size < 8) {
793 gap0_size = gap1_size = gap3_size = (get_track_size() - total) / (2 + valid_sector_num + 1);
794 gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * valid_sector_num;
796 //printf("GAP3=%d GAP4=%d\n", gap3_size, gap4_size);
797 if(gap3_size < 8 || gap4_size < 8) {
798 gap0_size = gap1_size = gap3_size = gap4_size = 8;
799 //gap0_size = gap1_size = gap3_size = gap4_size = 32;
800 invalid_format = true;
803 int preamble_size = gap0_size + sync_size + (am_size + 1) + gap1_size;
806 total -= sync_size + (am_size + 1);
807 for(int i = 0; i < sector_num.sd; i++) {
808 sync_position[i] *= get_track_size() - preamble_size - gap4_size;
809 sync_position[i] /= total;
813 total = preamble_size;
814 sync_position[array_length(sync_position) - 1] = gap0_size; // sync position in preamble
816 for(int i = 0; i < sector_num.sd; i++) {
817 data_size.read_2bytes_le_from(t + 14);
819 total = preamble_size + sync_position[i];
821 sync_position[i] = total;
823 am1_position[i] = total;
824 total += am_size + 1;
825 id_position[i] = total;
826 total += (4 + 2) + gap2_size;
827 if(data_size.sd > 0) {
828 total += sync_size + (am_size + 1);
829 data_position[i] = total;
830 total += data_size.sd + 2;
833 data_position[i] = total; // FIXME
835 t += data_size.sd + 0x10;
840 bool DISK::make_track(int trk, int side)
842 int track_size = get_track_size();
844 if(!get_track(trk, side)) {
845 // create a dummy track
846 for(int i = 0; i < track_size; i++) {
853 int sync_size = track_mfm ? 12 : 6;
854 int am_size = track_mfm ? 3 : 0;
855 int gap2_size = track_mfm ? 22 : 11;
856 uint8_t gap_data = track_mfm ? 0x4e : 0xff;
859 memset(track, gap_data, track_size);
860 int q = sync_position[array_length(sync_position) - 1];
863 for(int i = 0; i < sync_size; i++) {
867 for(int i = 0; i < am_size; i++) {
875 for(int i = 0; i < sector_num.sd; i++) {
877 data_size.read_2bytes_le_from(t + 14);
878 int p = sync_position[i];
881 for(int j = 0; j < sync_size; j++) {
882 if(p < track_size) track[p++] = 0x00;
885 for(int j = 0; j < am_size; j++) {
886 if(p < track_size) track[p++] = 0xa1;
888 if(p < track_size) track[p++] = 0xfe;
890 if(p < track_size) track[p++] = t[0];
891 if(p < track_size) track[p++] = t[1];
892 if(p < track_size) track[p++] = t[2];
893 if(p < track_size) track[p++] = t[3];
895 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0]]);
896 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[1]]);
897 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[2]]);
898 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[3]]);
899 if(p < track_size) track[p++] = (crc >> 8) & 0xff;
900 if(p < track_size) track[p++] = (crc >> 0) & 0xff;
902 for(int j = 0; j < gap2_size; j++) {
903 if(p < track_size) track[p++] = gap_data;
906 if(data_size.sd > 0) {
908 for(int j = 0; j < sync_size; j++) {
909 if(p < track_size) track[p++] = 0x00;
912 for(int j = 0; j < am_size; j++) {
913 if(p < track_size) track[p++] = 0xa1;
915 if(p < track_size) track[p++] = (t[7] != 0) ? 0xf8 : 0xfb;
918 for(int j = 0; j < data_size.sd; j++) {
919 if(p < track_size) track[p++] = t[0x10 + j];
920 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0x10 + j]]);
922 if(p < track_size) track[p++] = (crc >> 8) & 0xff;
923 if(p < track_size) track[p++] = (crc >> 0) & 0xff;
925 t += data_size.sd + 0x10;
930 bool DISK::get_sector(int trk, int side, int index)
932 sector_size.sd = sector_num.sd = 0;
935 // disk not inserted or invalid media type
936 if(!(inserted && check_media_type())) {
941 if(trk == -1 && side == -1) {
945 int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
946 if(!(0 <= trkside && trkside < 164)) {
950 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
952 if(!IS_VALID_TRACK(offset.d)) {
957 uint8_t* t = buffer + offset.d;
958 sector_num.read_2bytes_le_from(t + 4);
960 if(index >= sector_num.sd) {
965 for(int i = 0; i < index; i++) {
967 data_size.read_2bytes_le_from(t + 14);
968 t += data_size.sd + 0x10;
974 void DISK::set_sector_info(uint8_t *t)
982 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0]]);
983 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[1]]);
984 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[2]]);
985 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[3]]);
986 id[4] = (crc >> 8) & 0xff;
987 id[5] = (crc >> 0) & 0xff;
988 // http://www,gnu-darwin.or.jp/www001/src/ports/emulators/quasi88/work/quasi88-0.6.3/document/FORMAT.TXT
989 // t[6]: 0x00 = double-density, 0x40 = single-density
990 // t[7]: 0x00 = normal, 0x10 = deleted mark
991 // t[8]: 0x00 = valid, 0x10 = valid (deleted data), 0xa0 = id crc error, 0xb0 = data crc error, 0xe0 = address mark missing, 0xf0 = data mark missing
993 deleted = (t[7] != 0);
995 // if(ignore_crc()) {
996 // addr_crc_error = false;
997 // data_crc_error = false;
999 addr_crc_error = ((t[8] & 0xf0) == 0xa0);
1000 data_crc_error = ((t[8] & 0xf0) == 0xb0);
1003 sector_size.read_2bytes_le_from(t + 14);
1006 void DISK::set_deleted(bool value)
1008 if(sector != NULL) {
1009 uint8_t *t = sector - 0x10;
1010 t[7] = value ? 0x10 : 0;
1011 if((t[8] & 0xf0) == 0x00 || (t[8] & 0xf0) == 0x10) {
1012 t[8] = (t[8] & 0x0f) | t[7];
1018 void DISK::set_data_crc_error(bool value)
1020 if(sector != NULL) {
1021 uint8_t *t = sector - 0x10;
1022 t[8] = (t[8] & 0x0f) | (value ? 0xb0 : t[7]);
1024 data_crc_error = value;
1027 void DISK::set_data_mark_missing()
1029 if(sector != NULL) {
1030 uint8_t *t = sector - 0x10;
1031 t[8] = (t[8] & 0x0f) | 0xf0;
1035 //addr_crc_error = false;
1036 data_crc_error = false;
1039 bool DISK::format_track(int trk, int side)
1041 // disk not inserted or invalid media type
1042 if(!(inserted && check_media_type())) {
1047 int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
1048 if(!(0 <= trkside && trkside < 164)) {
1052 // create new empty track
1055 trim_required = false;
1057 memset(buffer + DISK_BUFFER_SIZE, 0, sizeof(buffer) - DISK_BUFFER_SIZE);
1059 offset.d = DISK_BUFFER_SIZE;
1060 offset.write_4bytes_le_to(buffer + 0x20 + trkside * 4);
1062 trim_required = true;
1064 track_mfm = drive_mfm;
1069 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)
1071 uint8_t* t = buffer + DISK_BUFFER_SIZE;
1074 for(int i = 0; i < (sector_num.sd - 1); i++) {
1075 t[4] = sector_num.b.l;
1076 t[5] = sector_num.b.h;
1078 data_size.read_2bytes_le_from(t + 14);
1079 t += data_size.sd + 0x10;
1085 t[4] = sector_num.b.l;
1086 t[5] = sector_num.b.h;
1087 t[6] = track_mfm ? 0 : 0x40;
1088 t[7] = deleted ? 0x10 : 0;
1089 t[8] = data_crc_error ? 0xb0 : t[7];
1090 t[14] = (length >> 0) & 0xff;
1091 t[15] = (length >> 8) & 0xff;
1092 memset(t + 16, fill_data, length);
1097 void DISK::sync_buffer()
1101 trim_required = false;
1105 void DISK::trim_buffer()
1107 int max_tracks = 164;
1108 int track_limit = 164;
1109 uint32_t dest_offset = 0x2b0;
1112 memset(tmp_buffer, 0, sizeof(tmp_buffer));
1113 memcpy(tmp_buffer, buffer, 0x20);
1115 if(media_type == MEDIA_TYPE_2D) {
1119 for(int trkside = 0; trkside < 164; trkside++) {
1120 pair_t src_trk_offset;
1121 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
1122 if(src_trk_offset.d != 0) {
1124 if(src_trk_offset.d < 0x2b0) {
1125 max_tracks = (src_trk_offset.d - 0x20) >> 2;
1126 if(max_tracks > track_limit) {
1127 max_tracks = track_limit;
1131 if(src_trk_offset.d != 0x2b0) {
1132 max_tracks = (src_trk_offset.d - 0x20) >> 2;
1133 if(max_tracks > 164) {
1134 dest_offset = 0x20 + max_tracks * 4);
1143 for(int trkside = 0; trkside < max_tracks; trkside++) {
1144 pair_t src_trk_offset;
1145 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
1147 pair_t dest_trk_offset;
1148 dest_trk_offset.d = 0;
1150 if(IS_VALID_TRACK(src_trk_offset.d)) {
1151 uint8_t* t = buffer + src_trk_offset.d;
1152 pair_t sector_num, data_size;
1153 sector_num.read_2bytes_le_from(t + 4);
1154 if(sector_num.sd != 0) {
1155 dest_trk_offset.d = dest_offset;
1156 for(int i = 0; i < sector_num.sd; i++) {
1157 data_size.read_2bytes_le_from(t + 14);
1158 memcpy(tmp_buffer + dest_offset, t, data_size.sd + 0x10);
1159 dest_offset += data_size.sd + 0x10;
1160 t += data_size.sd + 0x10;
1164 dest_trk_offset.write_4bytes_le_to(tmp_buffer + 0x20 + trkside * 4);
1168 file_size.d = dest_offset;
1169 file_size.write_4bytes_le_to(tmp_buffer + 0x1c);
1171 memset(buffer, 0, sizeof(buffer));
1172 memcpy(buffer, tmp_buffer, min(sizeof(buffer), file_size.d));
1177 if(drive_rpm != 0) {
1179 } else if(inserted) {
1180 return (media_type == MEDIA_TYPE_2HD) ? 360 : 300;
1182 return (drive_type == DRIVE_TYPE_2HD) ? 360 : 300;
1186 int DISK::get_track_size()
1189 return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : track_mfm ? 6250 : 3100;
1191 return drive_type == DRIVE_TYPE_144 ? 12500 : drive_type == DRIVE_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100;
1195 double DISK::get_usec_per_track()
1197 return 1000000.0 / (get_rpm() / 60.0);
1200 double DISK::get_usec_per_bytes(int bytes)
1202 return 1000000.0 / (get_track_size() * (get_rpm() / 60.0)) * bytes;
1205 int DISK::get_bytes_per_usec(double usec)
1207 return (int)(usec / get_usec_per_bytes(1) + 0.5);
1210 bool DISK::check_media_type()
1212 switch(drive_type) {
1214 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || \
1215 defined(_FM77AV20) || defined(_FM77AV20EX)
1216 return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
1218 return (media_type == MEDIA_TYPE_2D);
1220 case DRIVE_TYPE_2DD:
1221 return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
1222 case DRIVE_TYPE_2HD:
1223 return (media_type == MEDIA_TYPE_2HD);
1224 case DRIVE_TYPE_144:
1225 return (media_type == MEDIA_TYPE_144);
1226 case DRIVE_TYPE_UNK:
1227 return true; // always okay
1234 #define COPYBUFFER(src, size) { \
1235 if(file_size.d + (size) > DISK_BUFFER_SIZE) { \
1238 memcpy(buffer + file_size.d, (src), (size)); \
1239 file_size.d += (size); \
1248 uint32_t trkptr[164];
1254 uint8_t dens, del, stat;
1259 // teledisk image decoder
1262 this teledisk image decoder is based on:
1264 LZHUF.C English version 1.0 based on Japanese version 29-NOV-1988
1265 LZSS coded by Haruhiko OKUMURA
1266 Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
1267 Edited and translated to English by Kenji RIKITAKE
1271 #define STRING_BUFFER_SIZE 4096
1272 #define LOOKAHEAD_BUFFER_SIZE 60
1274 #define N_CHAR (256 - THRESHOLD + LOOKAHEAD_BUFFER_SIZE)
1275 #define TABLE_SIZE (N_CHAR * 2 - 1)
1276 #define ROOT_POSITION (TABLE_SIZE - 1)
1277 #define MAX_FREQ 0x8000
1279 static uint8_t td_text_buf[STRING_BUFFER_SIZE + LOOKAHEAD_BUFFER_SIZE - 1];
1280 static uint16_t td_ptr;
1281 static uint16_t td_bufcnt, td_bufndx, td_bufpos;
1282 static uint16_t td_ibufcnt, td_ibufndx;
1283 static uint8_t td_inbuf[512];
1284 static uint16_t td_freq[TABLE_SIZE + 1];
1285 static short td_prnt[TABLE_SIZE + N_CHAR];
1286 static short td_son[TABLE_SIZE];
1287 static uint16_t td_getbuf;
1288 static uint8_t td_getlen;
1290 static const uint8_t td_d_code[256] = {
1291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1293 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
1294 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
1295 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1296 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1297 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1298 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
1299 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
1300 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f,
1301 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
1302 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
1303 0x18, 0x18, 0x19, 0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, 0x1f, 0x1f,
1304 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
1305 0x28, 0x28, 0x29, 0x29, 0x2a, 0x2a, 0x2b, 0x2b, 0x2c, 0x2c, 0x2d, 0x2d, 0x2e, 0x2e, 0x2f, 0x2f,
1306 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f
1308 static const uint8_t td_d_len[256] = {
1309 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1310 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1311 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1312 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1313 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1314 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1315 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1316 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1317 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1318 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1319 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1320 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1321 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1322 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1323 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1324 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
1327 static int td_next_word(FILEIO* fio)
1329 if(td_ibufndx >= td_ibufcnt) {
1330 td_ibufndx = td_ibufcnt = 0;
1331 memset(td_inbuf, 0, 512);
1332 for(int i = 0; i < 512; i++) {
1333 int d = fio->Fgetc();
1344 while(td_getlen <= 8) {
1345 td_getbuf |= td_inbuf[td_ibufndx++] << (8 - td_getlen);
1351 static int td_get_bit(FILEIO* fio)
1353 if(td_next_word(fio) < 0) {
1356 short i = td_getbuf;
1359 return (i < 0) ? 1 : 0;
1362 static int td_get_byte(FILEIO* fio)
1364 if(td_next_word(fio) != 0) {
1367 uint16_t i = td_getbuf;
1374 static void td_start_huff()
1377 for(i = 0; i < N_CHAR; i++) {
1379 td_son[i] = i + TABLE_SIZE;
1380 td_prnt[i + TABLE_SIZE] = i;
1383 while(j <= ROOT_POSITION) {
1384 td_freq[j] = td_freq[i] + td_freq[i + 1];
1386 td_prnt[i] = td_prnt[i + 1] = j;
1389 td_freq[TABLE_SIZE] = 0xffff;
1390 td_prnt[ROOT_POSITION] = 0;
1393 static void td_reconst()
1397 for(i = 0; i < TABLE_SIZE; i++) {
1398 if(td_son[i] >= TABLE_SIZE) {
1399 td_freq[j] = (td_freq[i] + 1) / 2;
1400 td_son[j] = td_son[i];
1404 for(i = 0, j = N_CHAR; j < TABLE_SIZE; i += 2, j++) {
1406 f = td_freq[j] = td_freq[i] + td_freq[k];
1407 for(k = j - 1; f < td_freq[k]; k--);
1410 memmove(&td_freq[k + 1], &td_freq[k], l);
1412 memmove(&td_son[k + 1], &td_son[k], l);
1415 for(i = 0; i < TABLE_SIZE; i++) {
1416 if((k = td_son[i]) >= TABLE_SIZE) {
1419 td_prnt[k] = td_prnt[k + 1] = i;
1424 static void td_update(int c)
1427 if(td_freq[ROOT_POSITION] == MAX_FREQ) {
1430 c = td_prnt[c + TABLE_SIZE];
1433 if(k > td_freq[l = c + 1]) {
1434 while(k > td_freq[++l]);
1436 td_freq[c] = td_freq[l];
1440 if(i < TABLE_SIZE) {
1446 if(j < TABLE_SIZE) {
1453 while((c = td_prnt[c]) != 0);
1456 static short td_decode_char(FILEIO* fio)
1459 uint16_t c = td_son[ROOT_POSITION];
1460 while(c < TABLE_SIZE) {
1461 if((ret = td_get_bit(fio)) < 0) {
1472 static short td_decode_position(FILEIO* fio)
1476 if((bit = td_get_byte(fio)) < 0) {
1480 c = (uint16_t)td_d_code[i] << 6;
1481 j = td_d_len[i] - 2;
1483 if((bit = td_get_bit(fio)) < 0) {
1488 return (c | i & 0x3f);
1491 static void td_init_decode()
1493 td_ibufcnt= td_ibufndx = td_bufcnt = td_getbuf = 0;
1496 for(int i = 0; i < STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE; i++) {
1497 td_text_buf[i] = ' ';
1499 td_ptr = STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE;
1502 static int td_decode(FILEIO* fio, uint8_t *buf, int len)
1506 for(count = 0; count < len;) {
1507 if(td_bufcnt == 0) {
1508 if((c = td_decode_char(fio)) < 0) {
1512 *(buf++) = (uint8_t)c;
1513 td_text_buf[td_ptr++] = (uint8_t)c;
1514 td_ptr &= (STRING_BUFFER_SIZE - 1);
1517 if((pos = td_decode_position(fio)) < 0) {
1520 td_bufpos = (td_ptr - pos - 1) & (STRING_BUFFER_SIZE - 1);
1521 td_bufcnt = c - 255 + THRESHOLD;
1525 while(td_bufndx < td_bufcnt && count < len) {
1526 c = td_text_buf[(td_bufpos + td_bufndx) & (STRING_BUFFER_SIZE - 1)];
1527 *(buf++) = (uint8_t)c;
1529 td_text_buf[td_ptr++] = (uint8_t)c;
1530 td_ptr &= (STRING_BUFFER_SIZE - 1);
1533 if(td_bufndx >= td_bufcnt) {
1534 td_bufndx = td_bufcnt = 0;
1561 uint8_t nsec, trk, head;
1570 bool DISK::teledisk_to_d88(FILEIO *fio)
1577 bool temporary = false;
1579 // check teledisk header
1580 fio->Fseek(0, FILEIO_SEEK_SET);
1581 fio->Fread(&hdr, sizeof(td_hdr_t), 1);
1582 if(hdr.sig[0] == 't' && hdr.sig[1] == 'd') {
1583 // this image is compressed
1584 // decompress to the temporary file
1585 FILEIO* fio_tmp = new FILEIO();
1586 if(!fio_tmp->Fopen(local_path(_T("teledisk.$$$")), FILEIO_WRITE_BINARY)) {
1593 if((rd = td_decode(fio, obuf, 512)) > 0) {
1594 fio_tmp->Fwrite(obuf, rd, 1);
1602 // reopen the temporary file
1604 if(!fio->Fopen(_T("teledisk.$$$"), FILEIO_READ_BINARY)) {
1607 } else if(hdr.sig[0] == 'T' && hdr.sig[1] == 'D') {
1608 // this image is not compressed
1612 if(hdr.flag & 0x80) {
1614 fio->Fread(&cmt, sizeof(td_cmt_t), 1);
1615 fio->Fseek(cmt.len, FILEIO_SEEK_CUR);
1618 // create d88 header
1622 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1623 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "TELEDISK");
1624 d88_hdr.protect = 0; // non-protected
1627 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1630 int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
1631 fio->Fread(&trk, sizeof(td_trk_t), 1);
1632 while(trk.nsec != 0xff) {
1633 d88_hdr.trkptr[trkcnt++] = trkptr;
1634 if(hdr.sides == 1) {
1638 // read sectors in this track
1639 for(int i = 0; i < trk.nsec; i++) {
1640 uint8_t buf[2048], dst[2048];
1641 memset(buf, 0, sizeof(buf));
1642 memset(dst, 0, sizeof(dst));
1644 // read sector header
1645 fio->Fread(&sct, sizeof(td_sct_t), 1);
1647 // create d88 sector header
1648 memset(&d88_sct, 0, sizeof(d88_sct_t));
1653 d88_sct.nsec = trk.nsec;
1654 d88_sct.dens = (hdr.dens & 0x80) ? 0x40 : 0;
1655 d88_sct.del = (sct.ctrl & 4) ? 0x10 : 0;
1656 d88_sct.stat = (sct.ctrl & 2) ? 0xb0 : d88_sct.del;
1657 d88_sct.size = secsize[sct.n & 3];
1659 // create sector image
1660 if(sct.ctrl & 0x30) {
1661 d88_sct.stat = 0xf0; // data mark missing
1664 // read sector source
1665 int len = fio->Fgetc();
1666 len += fio->Fgetc() * 256 - 1;
1667 int flag = fio->Fgetc(), d = 0;
1668 fio->Fread(buf, len, 1);
1672 memcpy(dst, buf, len);
1673 } else if(flag == 1) {
1675 len2.read_2bytes_le_from(buf);
1680 } else if(flag == 2) {
1681 for(int s = 0; s < len;) {
1682 int type = buf[s++];
1683 int len2 = buf[s++];
1686 dst[d++] = buf[s++];
1688 } else if(type < 5) {
1694 for(int j = 0; j < n; j++) {
1698 for(int j = 0; j < n; j++) {
1703 break; // unknown type
1707 break; // unknown flag
1712 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1713 COPYBUFFER(dst, d88_sct.size);
1714 trkptr += sizeof(d88_sct_t) + d88_sct.size;
1717 fio->Fread(&trk, sizeof(td_trk_t), 1);
1719 d88_hdr.type = ((hdr.dens & 3) == 2) ? MEDIA_TYPE_2HD : ((trkcnt >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
1720 d88_hdr.size = trkptr;
1721 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1724 FILEIO::RemoveFile(_T("teledisk.$$$"));
1729 // imagedisk image decoder (from MESS formats/imd_dsk.c by Mr.Miodrag Milanovic)
1731 bool DISK::imagedisk_to_d88(FILEIO *fio)
1733 int size = fio->FileLength();
1734 fio->Fseek(0, FILEIO_SEEK_SET);
1735 fio->Fread(tmp_buffer, size, 1);
1737 if(memcmp(tmp_buffer, "IMD ", 4) != 0) {
1742 for(pos = 0; pos < size && tmp_buffer[pos] != 0x1a; pos++);
1749 // create d88 header
1753 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1754 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "IMAGEDISK");
1755 d88_hdr.protect = 0; // non-protected
1758 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1761 int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
1766 // check track header
1767 uint8_t mode = tmp_buffer[pos++];
1768 uint8_t track = tmp_buffer[pos++];
1769 uint8_t head = tmp_buffer[pos++];
1770 uint8_t sector_count = tmp_buffer[pos++];
1771 uint8_t ssize = tmp_buffer[pos++];
1773 if(sector_count == 0) {
1779 uint32_t actual_size = ssize < 7 ? 128 << ssize : 8192;
1782 const uint8_t *snum = &tmp_buffer[pos];
1783 pos += sector_count;
1784 const uint8_t *tnum = head & 0x80 ? &tmp_buffer[pos] : NULL;
1786 pos += sector_count;
1787 const uint8_t *hnum = head & 0x40 ? &tmp_buffer[pos] : NULL;
1789 pos += sector_count;
1793 int trkside = track * 2 + (head & 1);
1795 if(trkcnt < trkside) {
1798 d88_hdr.trkptr[trkside] = trkptr;
1800 if(img_mode == -1) {
1801 img_mode = mode & 3;
1804 // read sectors in this track
1805 for(int i = 0; i < sector_count; i++) {
1806 // create d88 sector header
1807 uint8_t stype = tmp_buffer[pos++];
1808 memset(&d88_sct, 0, sizeof(d88_sct_t));
1809 d88_sct.c = tnum ? tnum[i] : track;
1810 d88_sct.h = hnum ? hnum[i] : head;
1811 d88_sct.r = snum[i];
1813 d88_sct.nsec = sector_count;
1814 d88_sct.dens = (mode < 3) ? 0x40 : 0;
1816 if(stype == 0 || stype > 8) {
1817 d88_sct.stat = 0xf0; // data mark missing
1820 d88_sct.del = (stype == 3 || stype == 4 || stype == 7 || stype == 8) ? 0x10 : 0;
1821 d88_sct.stat = (stype == 5 || stype == 6 || stype == 7 || stype == 8) ? 0xb0 : d88_sct.del;
1822 d88_sct.size = actual_size;
1824 // create sector image
1825 if(stype == 2 || stype == 4 || stype == 6 || stype == 8) {
1826 memset(dst, tmp_buffer[pos++], actual_size);
1828 memcpy(dst, &tmp_buffer[pos], actual_size);
1829 pos += d88_sct.size;
1835 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1836 COPYBUFFER(dst, d88_sct.size);
1837 trkptr += sizeof(d88_sct_t) + d88_sct.size;
1841 d88_hdr.type = (img_mode == 0) ? MEDIA_TYPE_2HD : (((trkcnt + 1) >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
1842 d88_hdr.size = trkptr;
1843 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1847 // cpdread image decoder (from MESS formats/dsk_dsk.c by Mr.Olivier Galibert)
1849 #define DSK_FORMAT_HEADER "MV - CPC"
1850 #define EXT_FORMAT_HEADER "EXTENDED CPC DSK"
1853 struct track_header {
1854 uint8_t headertag[13];
1857 uint8_t track_number;
1858 uint8_t side_number;
1861 uint8_t sector_size_code;
1862 uint8_t number_of_sector;
1863 uint8_t gap3_length;
1864 uint8_t filler_byte;
1866 struct sector_header {
1870 uint8_t sector_size_code;
1871 uint8_t fdc_status_reg1;
1872 uint8_t fdc_status_reg2;
1873 uint16_t data_length;
1877 bool DISK::cpdread_to_d88(FILEIO *fio)
1879 bool extendformat = false;
1880 int image_size = fio->FileLength();
1882 fio->Fseek(0, FILEIO_SEEK_SET);
1883 fio->Fread(tmp_buffer, image_size, 1);
1885 if(memcmp(tmp_buffer, EXT_FORMAT_HEADER, 16) == 0) {
1886 extendformat = true;
1887 } else if(memcmp(tmp_buffer, DSK_FORMAT_HEADER, 8) == 0) {
1888 extendformat = false;
1893 int heads = tmp_buffer[0x31];
1898 int tracks = tmp_buffer[0x30];
1899 int track_offsets[84 * 2];
1900 bool track_offsets_error = false;
1902 int cnt = 0, tmp = 0x100;
1903 for(int i = 0; i < tracks * heads; i++) {
1904 if(track_offsets_error = (memcmp(tmp_buffer + tmp, "Track-Info", 10) != 0)) {
1907 track_offsets[cnt] = tmp;
1908 tmp += tmp_buffer[0x32] + tmp_buffer[0x33] * 256;
1912 int cnt = 0, tmp = 0x100;
1913 for(int i = 0; i < tracks * heads; i++) {
1914 int length = tmp_buffer[0x34 + i] << 8;
1916 if(track_offsets_error = (memcmp(tmp_buffer + tmp, "Track-Info", 10) != 0)) {
1919 track_offsets[cnt] = tmp;
1922 track_offsets[cnt] = image_size;
1927 if(track_offsets_error) {
1928 // I found the dsk image that the track size in table is 1100h, but the actual track size is 900h,
1929 // so I modified this code to search "Track-Info" at the top of track information block
1930 int cnt = 0, tmp = 0x100;
1931 for(int i = 0; i < tracks * heads; i++) {
1933 for(; tmp < image_size; tmp += 0x10) {
1934 if(found = (memcmp(tmp_buffer + tmp, "Track-Info", 10) == 0)) {
1939 track_offsets[cnt] = tmp;
1942 track_offsets[cnt] = image_size;
1948 // create d88 header
1952 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1953 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "CPDREAD");
1954 d88_hdr.protect = 0; // non-protected
1957 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1960 int total = 0, trkptr = sizeof(d88_hdr_t);
1962 for(int track = 0; track < tracks; track++) {
1963 for(int side = 0; side < heads; side++) {
1964 if(track_offsets[(track << 1) + side] >= image_size) {
1967 if((track << 1) + side < 164) {
1968 d88_hdr.trkptr[(track << 1) + side] = trkptr;
1972 memcpy(&tr, tmp_buffer + track_offsets[(track << 1) + side], sizeof(tr));
1973 int pos = track_offsets[(track << 1) + side] + 0x100;
1974 for(int j = 0; j < tr.number_of_sector; j++) {
1975 sector_header sector;
1976 memcpy(§or, tmp_buffer + track_offsets[(track << 1) + side] + sizeof(tr) + (sizeof(sector) * j), sizeof(sector));
1978 // create d88 sector header
1979 memset(&d88_sct, 0, sizeof(d88_sct_t));
1980 d88_sct.c = sector.track;
1981 d88_sct.h = sector.side;
1982 d88_sct.r = sector.sector_id;
1983 d88_sct.n = sector.sector_size_code;
1984 d88_sct.nsec = tr.number_of_sector;
1986 d88_sct.size = sector.data_length;
1987 d88_sct.dens = (tr.rec_mode == 1) ? 0x40 : 0;
1989 d88_sct.size = 128 << tr.sector_size_code;
1990 d88_sct.dens = (tr.sector_size_code == 0) ? 0x40 : 0; // FIXME
1992 d88_sct.del = (sector.fdc_status_reg1 == 0xb2) ? 0x10 : 0;
1993 d88_sct.stat = (d88_sct.size == 0) ? 0xf0 : (sector.fdc_status_reg1 == 0xb5) ? 0xb0 : d88_sct.del;
1996 if((track << 1) + side < 164) {
1997 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1998 COPYBUFFER(tmp_buffer + pos, d88_sct.size);
1999 trkptr += sizeof(d88_sct_t) + d88_sct.size;
2001 total += d88_sct.size;
2004 pos += sector.data_length;
2006 pos += 128 << tr.sector_size_code;
2011 d88_hdr.type = (total < (368640 + 655360) / 2) ? MEDIA_TYPE_2D : (total < (737280 + 1228800) / 2) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2HD;
2012 d88_hdr.size = trkptr;
2013 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
2017 // solid image decoder
2019 bool DISK::solid_to_d88(FILEIO *fio, int type, int ncyl, int nside, int nsec, int size, bool mfm)
2025 solid_nside = nside;
2030 // create d88 header
2034 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
2035 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "SOLID");
2036 d88_hdr.protect = 0; // non-protected
2039 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
2042 for(int i = 0; i < 8; i++) {
2043 if(size == (128 << i)) {
2050 int trkptr = sizeof(d88_hdr_t);
2052 for(int c = 0; c < ncyl; c++) {
2053 for(int h = 0; h < nside; h++) {
2054 d88_hdr.trkptr[t++] = trkptr;
2059 // read sectors in this track
2060 for(int s = 0; s < nsec; s++) {
2061 // create d88 sector header
2062 memset(&d88_sct, 0, sizeof(d88_sct_t));
2067 d88_sct.nsec = nsec;
2071 d88_sct.size = size;
2073 // create sector image
2075 memset(dst, 0xe5, sizeof(dst));
2076 fio->Fread(dst, size, 1);
2079 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
2080 COPYBUFFER(dst, size);
2081 trkptr += sizeof(d88_sct_t) + size;
2085 d88_hdr.type = (type == MEDIA_TYPE_144) ? MEDIA_TYPE_2HD : type;
2086 d88_hdr.size = trkptr;
2087 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
2091 #define STATE_VERSION 12
2093 void DISK::save_state(FILEIO* state_fio)
2095 state_fio->FputUint32(STATE_VERSION);
2097 state_fio->Fwrite(buffer, sizeof(buffer), 1);
2098 state_fio->Fwrite(orig_path, sizeof(orig_path), 1);
2099 state_fio->Fwrite(dest_path, sizeof(dest_path), 1);
2100 state_fio->FputUint32(file_size.d);
2101 state_fio->FputInt32(file_bank);
2102 state_fio->FputUint32(crc32);
2103 state_fio->FputBool(trim_required);
2104 state_fio->FputBool(is_1dd_image);
2105 state_fio->FputBool(is_solid_image);
2106 state_fio->FputBool(is_fdi_image);
2107 state_fio->Fwrite(fdi_header, sizeof(fdi_header), 1);
2108 state_fio->FputInt32(solid_ncyl);
2109 state_fio->FputInt32(solid_nside);
2110 state_fio->FputInt32(solid_nsec);
2111 state_fio->FputInt32(solid_size);
2112 state_fio->FputBool(solid_mfm);
2113 state_fio->FputBool(inserted);
2114 state_fio->FputBool(ejected);
2115 state_fio->FputBool(write_protected);
2116 state_fio->FputBool(changed);
2117 state_fio->FputUint8(media_type);
2118 state_fio->FputInt32(is_special_disk);
2119 state_fio->Fwrite(track, sizeof(track), 1);
2120 state_fio->FputInt32(sector_num.sd);
2121 state_fio->FputBool(track_mfm);
2122 state_fio->FputBool(invalid_format);
2123 //state_fio->FputBool(no_skew);
2124 state_fio->Fwrite(sync_position, sizeof(sync_position), 1);
2125 state_fio->Fwrite(am1_position, sizeof(am1_position), 1);
2126 state_fio->Fwrite(id_position, sizeof(id_position), 1);
2127 state_fio->Fwrite(data_position, sizeof(data_position), 1);
2128 // state_fio->FputInt32(gap3_size);
2129 state_fio->FputInt32(sector ? (int)(sector - buffer) : -1);
2130 state_fio->FputInt32(sector_size.sd);
2131 state_fio->Fwrite(id, sizeof(id), 1);
2132 state_fio->FputUint8(density);
2133 state_fio->FputBool(deleted);
2134 state_fio->FputBool(addr_crc_error);
2135 state_fio->FputBool(data_crc_error);
2136 state_fio->FputUint8(drive_type);
2137 state_fio->FputInt32(drive_rpm);
2138 state_fio->FputBool(drive_mfm);
2141 bool DISK::load_state(FILEIO* state_fio)
2143 if(state_fio->FgetUint32() != STATE_VERSION) {
2146 state_fio->Fread(buffer, sizeof(buffer), 1);
2147 state_fio->Fread(orig_path, sizeof(orig_path), 1);
2148 state_fio->Fread(dest_path, sizeof(dest_path), 1);
2149 file_size.d = state_fio->FgetUint32();
2150 file_bank = state_fio->FgetInt32();
2151 crc32 = state_fio->FgetUint32();
2152 trim_required = state_fio->FgetBool();
2153 is_1dd_image = state_fio->FgetBool();
2154 is_solid_image = state_fio->FgetBool();
2155 is_fdi_image = state_fio->FgetBool();
2156 state_fio->Fread(fdi_header, sizeof(fdi_header), 1);
2157 solid_ncyl = state_fio->FgetInt32();
2158 solid_nside = state_fio->FgetInt32();
2159 solid_nsec = state_fio->FgetInt32();
2160 solid_size = state_fio->FgetInt32();
2161 solid_mfm = state_fio->FgetBool();
2162 inserted = state_fio->FgetBool();
2163 ejected = state_fio->FgetBool();
2164 write_protected = state_fio->FgetBool();
2165 changed = state_fio->FgetBool();
2166 media_type = state_fio->FgetUint8();
2167 is_special_disk = state_fio->FgetInt32();
2168 state_fio->Fread(track, sizeof(track), 1);
2169 sector_num.sd = state_fio->FgetInt32();
2170 track_mfm = state_fio->FgetBool();
2171 invalid_format = state_fio->FgetBool();
2172 //no_skew = state_fio->FgetBool();
2173 state_fio->Fread(sync_position, sizeof(sync_position), 1);
2174 state_fio->Fread(am1_position, sizeof(am1_position), 1);
2175 state_fio->Fread(id_position, sizeof(id_position), 1);
2176 state_fio->Fread(data_position, sizeof(data_position), 1);
2177 // gap3_size = state_fio->FgetInt32();
2178 int offset = state_fio->FgetInt32();
2179 sector = (offset != -1) ? buffer + offset : NULL;
2180 sector_size.sd = state_fio->FgetInt32();
2181 state_fio->Fread(id, sizeof(id), 1);
2182 density = state_fio->FgetUint8();
2183 deleted = state_fio->FgetBool();
2184 addr_crc_error = state_fio->FgetBool();
2185 data_crc_error = state_fio->FgetBool();
2186 drive_type = state_fio->FgetUint8();
2187 drive_rpm = state_fio->FgetInt32();
2188 drive_mfm = state_fio->FgetBool();