2 ASCII MSX1 Emulator 'yaMSX1'
3 ASCII MSX2 Emulator 'yaMSX2'
4 Pioneer PX-7 Emulator 'ePX-7'
6 Author : Takeda.Toshiya
18 #include "../tms9918a.h"
27 #define SET_BANK(s, e, w, r) { \
28 int sb = (s) >> 13, eb = (e) >> 13; \
29 for(int i = sb; i <= eb; i++) { \
30 if(((uintptr_t)w) == (uintptr_t)wdmy) { \
33 wbank[i] = (w) + 0x2000 * (i - sb); \
35 if(((uintptr_t)r) == (uintptr_t)rdmy) { \
38 rbank[i] = (r) + 0x2000 * (i - sb); \
46 uint8_t heads, names, per_track, per_fat, per_cluster;
48 { 720, 1, 112, 9, 2, 2 },
49 { 1440, 2, 112, 9, 3, 2 },
50 { 640, 1, 112, 8, 1, 2 },
51 { 1280, 2, 112, 8, 2, 2 },
52 { 360, 1, 64, 9, 2, 1 },
53 { 720, 2, 112, 9, 2, 2 },
54 { 320, 1, 64, 8, 1, 1 },
55 { 640, 2, 112, 8, 1, 2 }
58 static const uint8_t boot_block[] = {
59 0xeb, 0xfe, 0x90, 0x56, 0x46, 0x42, 0x2d, 0x31, 0x39, 0x38, 0x39, 0x00, 0x02, 0x02, 0x01, 0x00,
60 0x02, 0x70, 0x00, 0xa0, 0x05, 0xf9, 0x03, 0x00, 0x09, 0x00, 0x02, 0x00, 0x00, 0x00, 0xd0, 0xed,
61 0x53, 0x58, 0xc0, 0x32, 0xc2, 0xc0, 0x36, 0x55, 0x23, 0x36, 0xc0, 0x31, 0x1f, 0xf5, 0x11, 0x9d,
62 0xc0, 0x0e, 0x0f, 0xcd, 0x7d, 0xf3, 0x3c, 0x28, 0x28, 0x11, 0x00, 0x01, 0x0e, 0x1a, 0xcd, 0x7d,
63 0xf3, 0x21, 0x01, 0x00, 0x22, 0xab, 0xc0, 0x21, 0x00, 0x3f, 0x11, 0x9d, 0xc0, 0x0e, 0x27, 0xcd,
64 0x7d, 0xf3, 0xc3, 0x00, 0x01, 0x57, 0xc0, 0xcd, 0x00, 0x00, 0x79, 0xe6, 0xfe, 0xfe, 0x02, 0x20,
65 0x07, 0x3a, 0xc2, 0xc0, 0xa7, 0xca, 0x22, 0x40, 0x11, 0x77, 0xc0, 0x0e, 0x09, 0xcd, 0x7d, 0xf3,
66 0x0e, 0x07, 0xcd, 0x7d, 0xf3, 0x18, 0xb4, 0x42, 0x6f, 0x6f, 0x74, 0x20, 0x65, 0x72, 0x72, 0x6f,
67 0x72, 0x0d, 0x0a, 0x50, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x6b, 0x65, 0x79,
68 0x20, 0x66, 0x6f, 0x72, 0x20, 0x72, 0x65, 0x74, 0x72, 0x79, 0x0d, 0x0a, 0x24, 0x00, 0x4d, 0x53,
69 0x58, 0x44, 0x4f, 0x53, 0x20, 0x20, 0x53, 0x59, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x2a,
72 0x51, 0xf3, 0x11, 0x00, 0x01, 0x19, 0x01, 0x00, 0x01, 0x11, 0x00, 0xc1, 0xed, 0xb0, 0x3a, 0xee,
73 0xc0, 0x47, 0x11, 0xef, 0xc0, 0x21, 0x00, 0x00, 0xcd, 0x51, 0x52, 0xf3, 0x76, 0xc9, 0x18, 0x64,
74 0x3a, 0xaf, 0x80, 0xf9, 0xca, 0x6d, 0x48, 0xd3, 0xa5, 0x0c, 0x8c, 0x2f, 0x9c, 0xcb, 0xe9, 0x89,
75 0xd2, 0x00, 0x32, 0x26, 0x40, 0x94, 0x61, 0x19, 0x20, 0xe6, 0x80, 0x6d, 0x8a, 0x00, 0x00, 0x00,
76 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
81 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
85 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
86 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
87 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
88 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
89 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
90 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
93 static int DSKIO = -1, DSKCHG = -1, GETDPB = -1, DSKFMT = -1;
96 static bool load_cart(const _TCHAR *file_path, uint8_t *rom)
99 FILEIO* fio = new FILEIO();
100 if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
101 memset(rom, 0xff, 0x10000);
103 fio->Fseek(0, FILEIO_SEEK_END);
104 int file_size = fio->Ftell();
105 fio->Fseek(0, FILEIO_SEEK_SET);
107 if(file_size <= 0x2000) {
109 fio->Fread(rom, 0x2000, 1);
110 memcpy(rom + 0x2000, rom, 0x2000);
111 memcpy(rom + 0x4000, rom, 0x4000);
112 memcpy(rom + 0x8000, rom, 0x8000);
113 } else if(file_size <= 0x4000) {
115 fio->Fread(rom, 0x4000, 1);
116 memcpy(rom + 0x4000, rom, 0x4000);
117 memcpy(rom + 0x8000, rom, 0x8000);
118 } else if(file_size <= 0x8000) {
120 fio->Fread(rom + 0x4000, 0x8000, 1);
121 memcpy(rom + 0x0000, rom + 0x4000, 0x4000);
122 memcpy(rom + 0xc000, rom + 0x8000, 0x4000);
125 fio->Fread(rom, 0x10000, 1);
136 void SLOT0::initialize()
138 memset(rom, 0xff, sizeof(rom));
140 memset(ram, 0, sizeof(ram));
142 FILEIO* fio = new FILEIO();
144 if(fio->Fopen(create_local_path(_T("MSX2J.ROM")), FILEIO_READ_BINARY) ||
145 fio->Fopen(create_local_path(_T("MSX2.ROM" )), FILEIO_READ_BINARY) ||
147 if(fio->Fopen(create_local_path(_T("MSXJ.ROM")), FILEIO_READ_BINARY) ||
148 fio->Fopen(create_local_path(_T("MSX.ROM" )), FILEIO_READ_BINARY) ||
150 fio->Fopen(create_local_path(_T("BASIC.ROM")), FILEIO_READ_BINARY)) {
151 fio->Fread(rom, sizeof(rom), 1);
156 SET_BANK(0x0000, 0x7fff, wdmy, rom);
158 SET_BANK(0x8000, 0xffff, ram, ram);
160 SET_BANK(0x8000, 0xffff, wdmy, rdmy);
164 void SLOT0::write_data8(uint32_t addr, uint32_t data)
166 wbank[addr >> 13][addr & 0x1fff] = data;
169 uint32_t SLOT0::read_data8(uint32_t addr)
171 return rbank[addr >> 13][addr & 0x1fff];
174 #define SLOT0_STATE_VERSION 1
176 bool SLOT0::process_state(FILEIO* state_fio, bool loading)
178 if(!state_fio->StateCheckUint32(SLOT0_STATE_VERSION)) {
181 if(!state_fio->StateCheckInt32(this_device_id)) {
185 state_fio->StateArray(ram, sizeof(ram), 1);
192 void SLOT1::initialize()
194 memset(rdmy, 0xff, sizeof(rdmy));
198 void SLOT1::write_data8(uint32_t addr, uint32_t data)
201 if(addr >= 0x4000 && addr < 0xc000 && mapper[0] < 4) {
205 if(mapper[addr] != data) {
207 SET_BANK(addr * 0x4000 + 0x4000, addr * 0x4000 + 0x7fff, wdmy, rom + data * 0x4000);
212 wbank[addr >> 13][addr & 0x1fff] = data;
215 uint32_t SLOT1::read_data8(uint32_t addr)
217 return rbank[addr >> 13][addr & 0x1fff];
220 void SLOT1::open_cart(const _TCHAR *file_path)
222 if(load_cart(file_path, rom)) {
223 SET_BANK(0x0000, 0xffff, wdmy, rom);
226 mapper[0] = mapper[1] = 4;
231 void SLOT1::close_cart()
233 SET_BANK(0x0000, 0xffff, wdmy, rdmy);
236 mapper[0] = mapper[1] = 4;
237 FILEIO* fio = new FILEIO();
238 if(fio->Fopen(create_local_path(_T("MSXDOS2.ROM")), FILEIO_READ_BINARY)) {
239 fio->Fread(rom, sizeof(rom), 1);
243 SET_BANK(0x4000, 0x7fff, wdmy, rom + mapper[0] * 0x4000);
244 SET_BANK(0x8000, 0xbfff, wdmy, rom + mapper[1] * 0x4000);
250 #define SLOT1_STATE_VERSION 1
252 bool SLOT1::process_state(FILEIO* state_fio, bool loading)
254 if(!state_fio->StateCheckUint32(SLOT1_STATE_VERSION)) {
257 if(!state_fio->StateCheckInt32(this_device_id)) {
260 state_fio->StateValue(inserted);
262 state_fio->StateArray(mapper, sizeof(mapper), 1);
268 SET_BANK(0x0000, 0xffff, wdmy, rom);
270 } else if(mapper[0] < 4) {
271 SET_BANK(0x0000, 0x3fff, wdmy, rdmy);
272 SET_BANK(0x4000, 0x7fff, wdmy, rom + mapper[0] * 0x4000);
273 SET_BANK(0x8000, 0xbfff, wdmy, rom + mapper[1] * 0x4000);
274 SET_BANK(0xc000, 0xffff, wdmy, rdmy);
277 SET_BANK(0x0000, 0xffff, wdmy, rdmy);
286 void SLOT2::initialize()
288 memset(rom, 0xff, sizeof(rom));
289 memset(rdmy, 0xff, sizeof(rdmy));
291 FILEIO* fio = new FILEIO();
292 if(fio->Fopen(create_local_path(_T("PX7EXT.ROM")), FILEIO_READ_BINARY) ||
293 fio->Fopen(create_local_path(_T("EXT.ROM") ), FILEIO_READ_BINARY)) {
294 fio->Fread(rom, sizeof(rom), 1);
299 SET_BANK(0x0000, 0x3fff, wdmy, rdmy);
300 SET_BANK(0x4000, 0x5fff, wdmy, rom);
301 SET_BANK(0x6000, 0xffff, wdmy, rdmy);
303 clock = exv = ack = false;
305 register_event(this, EVENT_CLOCK, 1000000.0 / 7812.5, true, NULL);
310 super_impose = false;
313 mute_l = mute_r = true;
315 d_ldp->write_signal(SIG_LD700_MUTE_L, 1, 1);
316 d_ldp->write_signal(SIG_LD700_MUTE_R, 1, 1);
317 d_vdp->write_signal(SIG_TMS9918A_SUPER_IMPOSE, 0, 0);
320 void SLOT2::write_data8(uint32_t addr, uint32_t data)
323 d_ldp->write_signal(SIG_LD700_REMOTE, data, 1);
324 } else if(addr == 0x7fff) {
326 bool prev_super_impose = super_impose;
327 super_impose = ((data & 1) == 0);
329 if(req_intr && !prev_super_impose) {
330 d_cpu->write_signal(SIG_CPU_IRQ, 1, 1);
333 d_cpu->write_signal(SIG_CPU_IRQ, 0, 0);
335 d_vdp->write_signal(SIG_TMS9918A_SUPER_IMPOSE, super_impose ? 1 : 0, 1);
338 bool prev_mute_l = mute_l;
339 mute_l = ((data & 0x80) == 0);
340 if(!prev_mute_l && mute_l) {
343 d_ldp->write_signal(SIG_LD700_MUTE_L, mute_l ? 1 : 0, 1);
344 d_ldp->write_signal(SIG_LD700_MUTE_R, mute_r ? 1 : 0, 1);
346 wbank[addr >> 13][addr & 0x1fff] = data;
350 uint32_t SLOT2::read_data8(uint32_t addr)
353 return (clock ? 0 : 1) | (ack ? 0 : 0x80) | 0x7e;
354 } else if(addr == 0x7fff) {
355 uint32_t data = (req_intr ? 1 : 0) | (exv ? 0 : 0x80) | 0x7e;
357 d_cpu->write_signal(SIG_CPU_IRQ, 0, 0);
360 return rbank[addr >> 13][addr & 0x1fff];
364 void SLOT2::write_signal(int id, uint32_t data, uint32_t mask)
366 if(id == SIG_SLOT2_EXV) {
368 exv = ((data & mask) != 0);
372 d_cpu->write_signal(SIG_CPU_IRQ, 1, 1);
375 } else if(id == SIG_SLOT2_ACK) {
376 ack = ((data & mask) != 0);
377 } else if(id == SIG_SLOT2_MUTE) {
378 pc4 = ((data & mask) != 0);
382 void SLOT2::event_callback(int event_id, int err)
384 if(event_id == EVENT_CLOCK) {
389 #define SLOT2_STATE_VERSION 1
391 bool SLOT2::process_state(FILEIO* state_fio, bool loading)
393 if(!state_fio->StateCheckUint32(SLOT2_STATE_VERSION)) {
396 if(!state_fio->StateCheckInt32(this_device_id)) {
399 state_fio->StateValue(clock);
400 state_fio->StateValue(exv);
401 state_fio->StateValue(ack);
402 state_fio->StateValue(super_impose);
403 state_fio->StateValue(req_intr);
404 state_fio->StateValue(pc4);
405 state_fio->StateValue(mute_l);
406 state_fio->StateValue(mute_r);
410 void SLOT2::initialize()
412 memset(rom, 0xff, sizeof(rom));
413 memset(rdmy, 0xff, sizeof(rdmy));
415 FILEIO* fio = new FILEIO();
417 if(fio->Fopen(create_local_path(_T("MSX2JEXT.ROM")), FILEIO_READ_BINARY) ||
418 fio->Fopen(create_local_path(_T("MSX2EXT.ROM" )), FILEIO_READ_BINARY)) {
419 fio->Fread(rom, sizeof(rom), 1);
423 if(fio->Fopen(create_local_path(_T("DISK.ROM")), FILEIO_READ_BINARY)) {
424 fio->Fread(rom + 0x4000, sizeof(rom) - 0x4000, 1);
429 // patch for pseudo disk bios
430 if(rom[0x4010] == 0xc3) {
431 rom[DSKIO = rom[0x4011] + (int)rom[0x4012] * 256] = 0xc9;
433 if(rom[0x4013] == 0xc3) {
434 rom[DSKCHG = rom[0x4014] + (int)rom[0x4015] * 256] = 0xc9;
436 if(rom[0x4016] == 0xc3) {
437 rom[GETDPB = rom[0x4017] + (int)rom[0x4018] * 256] = 0xc9;
439 if(rom[0x401c] == 0xc3) {
440 rom[DSKFMT = rom[0x401d] + (int)rom[0x401e] * 256] = 0xc9;
442 if(rom[0x401f] == 0xc3) {
443 rom[ rom[0x4020] + (int)rom[0x4021] * 256] = 0xc9;
445 SET_BANK(0x0000, 0x7fff, wdmy, rom);
446 SET_BANK(0x8000, 0xffff, wdmy, rdmy);
449 void SLOT2::write_data8(uint32_t addr, uint32_t data)
451 wbank[addr >> 13][addr & 0x1fff] = data;
454 uint32_t SLOT2::read_data8(uint32_t addr)
456 return rbank[addr >> 13][addr & 0x1fff];
462 void SLOT3::initialize()
464 memset(ram, 0xff, sizeof(ram));
468 void SLOT3::write_data8(uint32_t addr, uint32_t data)
470 wbank[addr >> 13][addr & 0x1fff] = data;
473 uint32_t SLOT3::read_data8(uint32_t addr)
475 return rbank[addr >> 13][addr & 0x1fff];
478 void SLOT3::write_io8(uint32_t addr, uint32_t data)
480 switch(addr & 0xff) {
488 if(mapper[addr] != data) {
490 SET_BANK(addr * 0x4000, addr * 0x4000 + 0x3fff, ram + data * 0x4000, ram + data * 0x4000);
497 void SLOT3::open_cart(const _TCHAR *file_path)
499 if(load_cart(file_path, rom)) {
500 SET_BANK(0x0000, 0xffff, wdmy, rom);
505 void SLOT3::close_cart()
507 for(int i = 0; i < 4; i++) {
510 SET_BANK(0x0000, 0xffff, ram, ram);
515 #define SLOT3_STATE_VERSION 1
517 bool SLOT3::process_state(FILEIO* state_fio, bool loading)
519 if(!state_fio->StateCheckUint32(SLOT3_STATE_VERSION)) {
522 if(!state_fio->StateCheckInt32(this_device_id)) {
525 state_fio->StateArray(ram, sizeof(ram), 1);
526 state_fio->StateValue(inserted);
527 state_fio->StateArray(mapper, sizeof(mapper), 1);
532 SET_BANK(0x0000, 0xffff, wdmy, rom);
534 SET_BANK(0x0000, 0x3fff, ram + mapper[0] * 0x4000, ram + mapper[0] * 0x4000);
535 SET_BANK(0x4000, 0x7fff, ram + mapper[1] * 0x4000, ram + mapper[1] * 0x4000);
536 SET_BANK(0x8000, 0xbfff, ram + mapper[2] * 0x4000, ram + mapper[2] * 0x4000);
537 SET_BANK(0xc000, 0xffff, ram + mapper[3] * 0x4000, ram + mapper[3] * 0x4000);
546 void MEMORY::initialize()
548 for(int i = 0; i < MAX_DRIVE; i++) {
549 disk[i] = new DISK(emu);
550 disk[i]->set_device_name(_T("%s/Disk #%d"), this_device_name, i + 1);
551 disk[i]->drive_type = DRIVE_TYPE_2DD;
555 void MEMORY::release()
557 for(int i = 0; i < MAX_DRIVE; i++) {
569 for(int i = 0; i < MAX_DRIVE; i++) {
573 update_map((0 << 0) | (1 << 2) | (2 << 4) | (3 << 6));
576 void MEMORY::write_data8(uint32_t addr, uint32_t data)
579 d_map[addr >> 14]->write_data8(addr, data);
582 uint32_t MEMORY::read_data8(uint32_t addr)
585 return d_map[addr >> 14]->read_data8(addr);
588 uint32_t MEMORY::fetch_op(uint32_t addr, int* wait)
591 return read_data8(addr);
594 void MEMORY::write_io8(uint32_t addr, uint32_t data)
597 // if(d_map[3] == d_slot[3]) {
598 d_slot[3]->write_io8(addr, data);
603 void MEMORY::write_signal(int id, uint32_t data, uint32_t mask)
605 if(id == SIG_MEMORY_SEL) {
606 if(slot_select != (data & mask)) {
607 update_map(data & mask);
612 void MEMORY::update_map(uint32_t val)
614 d_map[0] = d_slot[(val >> 0) & 3];
615 d_map[1] = d_slot[(val >> 2) & 3];
616 d_map[2] = d_slot[(val >> 4) & 3];
617 d_map[3] = d_slot[(val >> 6) & 3];
622 static int get_track_number(int desc, int sector)
624 int trkside = sector / info[desc].per_track;
625 return trkside >> (info[desc].heads - 1);
628 static int get_side_number(int desc, int sector)
630 int trkside = sector / info[desc].per_track;
631 return trkside & (info[desc].heads - 1);
634 static bool get_track(DISK *disk, int desc, int sector)
636 return disk->get_track(get_track_number(desc, sector), get_side_number(desc, sector));
639 static bool get_sector(DISK *disk, int desc, int sector)
641 if(get_track(disk, desc, sector)) {
642 for(int i = 0; i < disk->sector_num.sd; i++) {
643 disk->get_sector(-1, -1, i);
644 if(disk->id[2] == (sector % info[desc].per_track) + 1) {
652 static bool get_boot_sector(DISK *disk)
654 if(disk->get_track(0, 0)) {
655 for(int i = 0; i < disk->sector_num.sd; i++) {
656 disk->get_sector(0, 0, i);
657 if(disk->id[2] == 1) {
665 uint32_t MEMORY::read_signal(int id)
668 for(int i = 0; i < MAX_DRIVE; i++) {
677 bool MEMORY::bios_ret_z80(uint16_t PC, pair32_t* af, pair32_t* bc, pair32_t* de, pair32_t* hl, pair32_t* ix, pair32_t* iy, uint8_t* iff1)
694 if(d_map[1] == d_slot[2]) {
695 // pseudo disk bios from fMSX
697 // read/write sectors
702 if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
703 AF = 0x0201; // not ready
707 if(disk[drv]->write_protected) {
708 AF = 0x0001; // write protected
711 for(int sector = DE; B != 0; sector++) {
712 if(!get_sector(disk[drv], desc, sector)) {
713 AF = 0x0801; // record not found
718 if(disk[drv]->addr_crc_error && !disk[drv]->ignore_crc()) {
719 AF = 0x0801; // record not found
722 if(addr + 512/*disk[drv]->sector_size.sd*/ > 0xffff) {
726 d_map[1] = d_slot[read_data8(0xf342) & 3];
727 for(int i = 0; i < 512/*disk[drv]->sector_size.sd*/; i++) {
728 disk[drv]->sector[i] = read_data8(addr++);
730 d_map[1] = d_slot[2];
734 for(int sector = DE; B != 0; sector++) {
735 if(!get_sector(disk[drv], desc, sector)) {
736 AF = 0x0801; // record not found
741 if(disk[drv]->addr_crc_error && !disk[drv]->ignore_crc()) {
742 AF = 0x0801; // record not found
745 if(addr + 512/*disk[drv]->sector_size.sd*/ > 0xffff) {
749 d_map[1] = d_slot[read_data8(0xf342) & 3];
750 for(int i = 0; i < 512/*disk[drv]->sector_size.sd*/; i++) {
751 write_data8(addr++, disk[drv]->sector[i]);
753 d_map[1] = d_slot[2];
755 if(disk[drv]->data_crc_error && !disk[drv]->ignore_crc()) {
756 AF = 0x0401; // data crc error
763 } else if(PC == DSKCHG) {
764 // detect disk changed
767 if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
768 AF = 0x0201; // not ready
771 B = disk[drv]->changed ? 0xff : 0x01;
772 disk[drv]->changed = false;
775 } else if(PC == GETDPB) {
776 // get drive parameter block
778 if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
779 AF = 0x0201; // not ready
782 if(!get_boot_sector(disk[drv])) {
783 AF = 0x0c01; // other error
788 if(disk[drv]->data_crc_error && !disk[drv]->ignore_crc()) {
789 AF = 0x0401; // data crc error
792 int bytes_per_sector = (int)disk[drv]->sector[0x0c] * 256 + disk[drv]->sector[0x0b];
793 int sectors_per_disk = (int)disk[drv]->sector[0x14] * 256 + disk[drv]->sector[0x13];
794 int sectors_per_fat = (int)disk[drv]->sector[0x17] * 256 + disk[drv]->sector[0x16];
795 int reserved_sectors = (int)disk[drv]->sector[0x0f] * 256 + disk[drv]->sector[0x0e];
796 int addr = HL + 1, num, bits;
797 d_map[1] = d_slot[read_data8(0xf342) & 3];
798 write_data8(addr++, disk[drv]->sector[0x15]); // format id [f8h-ffh]
799 write_data8(addr++, disk[drv]->sector[0x0b]); // sector size
800 write_data8(addr++, disk[drv]->sector[0x0c]);
801 num = (bytes_per_sector >> 5) - 1;
802 for(bits = 0; num & (1 << bits); bits++);
803 write_data8(addr++, num); // directory mask/shft
804 write_data8(addr++, bits);
805 num = disk[drv]->sector[0x0d] - 1;
806 for(bits = 0; num & (1 << bits); bits++);
807 write_data8(addr++, num); // cluster mask/shift
808 write_data8(addr++, bits + 1);
809 write_data8(addr++, disk[drv]->sector[0x0e]); // sector # of 1st fat
810 write_data8(addr++, disk[drv]->sector[0x0f]);
811 write_data8(addr++, disk[drv]->sector[0x10]); // number of fats
812 write_data8(addr++, disk[drv]->sector[0x11]); // number of dirent-s
813 num = reserved_sectors + disk[drv]->sector[0x10] * sectors_per_fat;
814 num += 32 * disk[drv]->sector[0x11] / bytes_per_sector;
815 write_data8(addr++, num & 0xff); // sector # of data
816 write_data8(addr++, (num >> 8) & 0xff);
817 num = (sectors_per_disk - num) / disk[drv]->sector[0x0d];
818 write_data8(addr++, num & 0xff); // number of clusters
819 write_data8(addr++, (num >> 8) & 0xff);
820 write_data8(addr++, disk[drv]->sector[0x16]); // sectors per fat
821 num = reserved_sectors + disk[drv]->sector[0x10] * sectors_per_fat;
822 write_data8(addr++, num & 0xff); // sector # of dir.
823 write_data8(addr, (num >> 8) & 0xff);
824 d_map[1] = d_slot[2];
827 } else if(PC == DSKFMT) {
831 int desc = A - 1; // A: 1=single-side 2=double-side
833 if(desc != 0 && desc != 1) {
834 AF = 0x0c01; // bad parameter
837 if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
838 AF = 0x0201; // not ready
841 if(disk[drv]->write_protected) {
842 AF = 0x0001; // write protected
848 int max_trkside = info[desc].sectors / info[desc].per_track;
849 for(int trkside = 0; trkside < max_trkside; trkside++) {
850 int trk = trkside >> (info[desc].heads - 1);
851 int side = trkside & (info[desc].heads - 1);
852 disk[drv]->format_track(trk, side);
853 for(int sct = 0; sct < info[desc].per_track; sct++) {
854 disk[drv]->insert_sector(trk, side, sct + 1, 2, false, false, 0, 512);
857 // fill boot block with data:
859 get_sector(disk[drv], desc, sector++);
860 memcpy(disk[drv]->sector, boot_block, 512);
861 uint8_t *ptr = disk[drv]->sector + 3;
862 memcpy(ptr, "fMSXdisk", 8); ptr += 10; // manufacturer's id
863 *ptr = info[desc].per_cluster; ptr += 4; // sectors per cluster
864 *ptr++ = info[desc].names; *ptr++ = 0x00; // number of names
865 *ptr++ = info[desc].sectors & 0xff; // number of sectors
866 *ptr++ = (info[desc].sectors >> 8) & 0xff;
867 *ptr++ = desc + 0xf8; // format id [f8h-ffh]
868 *ptr++ = info[desc].per_fat; *ptr++ = 0x00; // sectors per fat
869 *ptr++ = info[desc].per_track; *ptr++ = 0x00; // sectors per track
870 *ptr++ = info[desc].heads; *ptr = 0x00; // number of heads
872 for(int j = 0; j < 2; j++) {
873 get_sector(disk[drv], desc, sector++);
874 memset(disk[drv]->sector, 0x00, 512);
875 disk[drv]->sector[0] = desc + 0xf8;
876 disk[drv]->sector[1] = disk[drv]->sector[2] = 0xff;
877 for(int i = info[desc].per_fat; i > 1; i--) {
878 get_sector(disk[drv], desc, sector++);
879 memset(disk[drv]->sector, 0x00, 512);
882 for(int i = info[desc].names / 16; i; i--) {
883 get_sector(disk[drv], desc, sector++);
884 memset(disk[drv]->sector, 0x00, 512);
886 for(int i = info[desc].sectors - 2 * info[desc].per_fat - info[desc].names / 16 - 1; i; i--) {
887 get_sector(disk[drv], desc, sector++);
888 memset(disk[drv]->sector, 0xff, 512);
897 void MEMORY::open_disk(int drv, const _TCHAR* file_path, int bank)
899 if(drv < MAX_DRIVE) {
900 disk[drv]->open(file_path, bank);
904 void MEMORY::close_disk(int drv)
906 if(drv < MAX_DRIVE && disk[drv]->inserted) {
911 bool MEMORY::is_disk_inserted(int drv)
913 if(drv < MAX_DRIVE) {
914 return disk[drv]->inserted;
919 void MEMORY::is_disk_protected(int drv, bool value)
921 if(drv < MAX_DRIVE) {
922 disk[drv]->write_protected = value;
926 bool MEMORY::is_disk_protected(int drv)
928 if(drv < MAX_DRIVE) {
929 return disk[drv]->write_protected;
936 #define STATE_VERSION 1
938 bool MEMORY::process_state(FILEIO* state_fio, bool loading)
940 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
943 if(!state_fio->StateCheckInt32(this_device_id)) {
947 for(int i = 0; i < MAX_DRIVE; i++) {
948 if(!disk[i]->process_state(state_fio, loading)) {
953 state_fio->StateValue(slot_select);
957 update_map(slot_select);