OSDN Git Service

[General][CMake] Merge upstream 2016-02-26.
[csp-qt/common_source_project-fm7.git] / source / src / vm / x1 / x1.cpp
1 /*
2         SHARP X1 Emulator 'eX1'
3         SHARP X1twin Emulator 'eX1twin'
4         SHARP X1turbo Emulator 'eX1turbo'
5
6         Author : Takeda.Toshiya
7         Date   : 2009.03.11-
8
9         [ virtual machine ]
10 */
11
12 #include "x1.h"
13 #include "../../emu.h"
14 #include "../device.h"
15 #include "../event.h"
16
17 #include "../datarec.h"
18 #include "../disk.h"
19 #include "../hd46505.h"
20 #include "../i8255.h"
21 #include "../io.h"
22 #include "../mb8877.h"
23 #include "../mz1p17.h"
24 //#include "../pcpr201.h"
25 #include "../prnfile.h"
26 #include "../ym2151.h"
27 #include "../ym2203.h"
28 #include "../z80.h"
29 #include "../z80ctc.h"
30 #include "../z80sio.h"
31 #ifdef _X1TURBO_FEATURE
32 #include "../z80dma.h"
33 #endif
34
35 #ifdef USE_DEBUGGER
36 #include "../debugger.h"
37 #endif
38
39 #include "display.h"
40 #include "emm.h"
41 #include "floppy.h"
42 #include "iobus.h"
43 #include "joystick.h"
44 #include "memory.h"
45 #include "mouse.h"
46 #include "psub.h"
47
48 #include "../mcs48.h"
49 #include "../upd1990a.h"
50 #include "sub.h"
51 #include "keyboard.h"
52
53 #ifdef _X1TWIN
54 #include "../huc6280.h"
55 #include "../pcengine/pce.h"
56 #endif
57
58 // ----------------------------------------------------------------------------
59 // initialize
60 // ----------------------------------------------------------------------------
61
62 VM::VM(EMU* parent_emu) : emu(parent_emu)
63 {
64         pseudo_sub_cpu = !(FILEIO::IsFileExists(create_local_path(SUB_ROM_FILE_NAME)) && FILEIO::IsFileExists(create_local_path(KBD_ROM_FILE_NAME)));
65         
66         sound_device_type = config.sound_device_type;
67         
68         // create devices
69         first_device = last_device = NULL;
70         dummy = new DEVICE(this, emu);  // must be 1st device
71         event = new EVENT(this, emu);   // must be 2nd device
72         
73         drec = new DATAREC(this, emu);
74         crtc = new HD46505(this, emu);
75         pio = new I8255(this, emu);
76         io = new IO(this, emu);
77         fdc = new MB8877(this, emu);
78         psg = new YM2203(this, emu);
79         cpu = new Z80(this, emu);
80         ctc = new Z80CTC(this, emu);
81         sio = new Z80SIO(this, emu);
82         if(sound_device_type >= 1) {
83                 opm1 = new YM2151(this, emu);
84                 ctc1 = new Z80CTC(this, emu);
85         }
86         if(sound_device_type == 2) {
87                 opm2 = new YM2151(this, emu);
88                 ctc2 = new Z80CTC(this, emu);
89         }
90         if(config.printer_device_type == 0) {
91                 printer = new PRNFILE(this, emu);
92         } else if(config.printer_device_type == 1) {
93                 printer = new MZ1P17(this, emu);
94 //      } else if(config.printer_device_type == 2) {
95 //              printer = new PCPR201(this, emu);
96         } else {
97                 printer = dummy;
98         }
99 #ifdef _X1TURBO_FEATURE
100         dma = new Z80DMA(this, emu);
101 #endif
102         
103         display = new DISPLAY(this, emu);
104         emm = new EMM(this, emu);
105         floppy = new FLOPPY(this, emu);
106         iobus = new IOBUS(this, emu);
107         joy = new JOYSTICK(this, emu);
108         memory = new MEMORY(this, emu);
109         mouse = new MOUSE(this, emu);
110         
111         if(pseudo_sub_cpu) {
112                 psub = new PSUB(this, emu);
113                 cpu_sub = NULL;
114                 cpu_kbd = NULL;
115         } else {
116                 // sub cpu
117                 cpu_sub = new MCS48(this, emu);
118                 pio_sub = new I8255(this, emu);
119                 rtc_sub = new UPD1990A(this, emu);
120                 sub = new SUB(this, emu);
121                 
122                 // keyboard
123                 cpu_kbd = new MCS48(this, emu);
124                 kbd = new KEYBOARD(this, emu);
125         }
126         
127         // set contexts
128         event->set_context_cpu(cpu);
129         if(!pseudo_sub_cpu) {
130                 event->set_context_cpu(cpu_sub, 6000000);
131                 event->set_context_cpu(cpu_kbd, 6000000);
132         }
133         if(sound_device_type >= 1) {
134                 event->set_context_sound(opm1);
135         }
136         if(sound_device_type == 2) {
137                 event->set_context_sound(opm2);
138         }
139         event->set_context_sound(psg);
140         event->set_context_sound(drec);
141         
142         drec->set_context_ear(pio, SIG_I8255_PORT_B, 0x02);
143         crtc->set_context_vblank(display, SIG_DISPLAY_VBLANK, 1);
144         crtc->set_context_vblank(pio, SIG_I8255_PORT_B, 0x80);
145         crtc->set_context_vsync(pio, SIG_I8255_PORT_B, 0x04);
146         pio->set_context_port_a(printer, SIG_PRINTER_DATA, 0xff, 0);
147         pio->set_context_port_c(drec, SIG_DATAREC_MIC, 0x01, 0);
148         pio->set_context_port_c(display, SIG_DISPLAY_COLUMN40, 0x40, 0);
149         pio->set_context_port_c(iobus, SIG_IOBUS_MODE, 0x60, 0);
150         pio->set_context_port_c(printer, SIG_PRINTER_STROBE, 0x80, 0);
151 #ifdef _X1TURBO_FEATURE
152         fdc->set_context_drq(dma, SIG_Z80DMA_READY, 1);
153 #endif
154         ctc->set_context_zc0(ctc, SIG_Z80CTC_TRIG_3, 1);
155         ctc->set_context_zc1(sio, SIG_Z80SIO_TX_CLK_CH0, 1);
156         ctc->set_context_zc1(sio, SIG_Z80SIO_RX_CLK_CH0, 1);
157         ctc->set_context_zc2(sio, SIG_Z80SIO_TX_CLK_CH1, 1);
158         ctc->set_context_zc2(sio, SIG_Z80SIO_RX_CLK_CH1, 1);
159         ctc->set_constant_clock(1, CPU_CLOCKS >> 1);
160         ctc->set_constant_clock(2, CPU_CLOCKS >> 1);
161         sio->set_context_rts(1, mouse, SIG_MOUSE_RTS, 1);
162 //      sio->set_tx_clock(0, 9600 * 16);        // 9600 baud for RS-232C
163 //      sio->set_rx_clock(0, 9600 * 16);        // clock is from Z-80CTC ch1 (2MHz/13)
164 //      sio->set_tx_clock(1, 4800 * 16);        // 4800 baud for mouse
165 //      sio->set_rx_clock(1, 4800 * 16);        // clock is from Z-80CTC ch2 (2MHz/26)
166         
167         if(sound_device_type >= 1) {
168                 ctc1->set_context_zc0(ctc1, SIG_Z80CTC_TRIG_3, 1);
169 //              ctc1->set_constant_clock(1, CPU_CLOCKS >> 1);
170 //              ctc1->set_constant_clock(2, CPU_CLOCKS >> 1);
171         }
172         if(sound_device_type == 2) {
173                 ctc2->set_context_zc0(ctc2, SIG_Z80CTC_TRIG_3, 1);
174 //              ctc2->set_constant_clock(1, CPU_CLOCKS >> 1);
175 //              ctc2->set_constant_clock(2, CPU_CLOCKS >> 1);
176         }
177         if(config.printer_device_type == 0) {
178                 PRNFILE *prnfile = (PRNFILE *)printer;
179                 prnfile->set_context_busy(pio, SIG_I8255_PORT_B, 0x08);
180         } else if(config.printer_device_type == 1) {
181                 MZ1P17 *mz1p17 = (MZ1P17 *)printer;
182                 mz1p17->mode = MZ1P17_MODE_X1;
183                 mz1p17->set_context_busy(pio, SIG_I8255_PORT_B, 0x08);
184 //      } else if(config.printer_device_type == 2) {
185 //              PCPR201 *pcpr201 = (PCPR201 *)printer;
186 //              pcpr201->set_context_busy(pio, SIG_I8255_PORT_B, 0x08);
187         }
188 #ifdef _X1TURBO_FEATURE
189         dma->set_context_memory(memory);
190         dma->set_context_io(iobus);
191 #endif
192         
193 #ifdef _X1TURBO_FEATURE
194         display->set_context_cpu(cpu);
195 #endif
196         display->set_context_crtc(crtc);
197         display->set_vram_ptr(iobus->get_vram());
198         display->set_regs_ptr(crtc->get_regs());
199         floppy->set_context_fdc(fdc);
200         iobus->set_context_cpu(cpu);
201         iobus->set_context_display(display);
202         iobus->set_context_io(io);
203         joy->set_context_psg(psg);
204 #ifdef _X1TURBO_FEATURE
205         memory->set_context_pio(pio);
206 #endif
207         mouse->set_context_sio(sio);
208         
209         if(pseudo_sub_cpu) {
210                 drec->set_context_remote(psub, SIG_PSUB_TAPE_REMOTE, 1);
211                 drec->set_context_end(psub, SIG_PSUB_TAPE_END, 1);
212                 psub->set_context_pio(pio);
213                 psub->set_context_drec(drec);
214         } else {
215                 // sub cpu
216                 cpu_sub->set_context_mem(new MCS48MEM(this, emu));
217                 cpu_sub->set_context_io(sub);
218 #ifdef USE_DEBUGGER
219                 cpu_sub->set_context_debugger(new DEBUGGER(this, emu));
220 #endif
221                 drec->set_context_end(sub, SIG_SUB_TAPE_END, 1);
222                 drec->set_context_apss(sub, SIG_SUB_TAPE_APSS, 1);
223                 pio_sub->set_context_port_c(sub, SIG_SUB_PIO_PORT_C, 0x80, 0);
224                 // pc1:break -> pb0 of 8255(main)
225                 pio_sub->set_context_port_c(pio, SIG_I8255_PORT_B, 0x02, -1);
226                 // pc5:ibf -> pb6 of 8255(main)
227                 pio_sub->set_context_port_c(pio, SIG_I8255_PORT_B, 0x20, 1);
228                 // pc7:obf -> pb5 of 8255(main)
229                 pio_sub->set_context_port_c(pio, SIG_I8255_PORT_B, 0x80, -2);
230                 // pc7:obf -> pb7 of 8255(sub)
231                 pio_sub->set_context_port_c(pio_sub, SIG_I8255_PORT_B, 0x80, 0);
232                 
233                 sub->set_context_pio(pio_sub);
234                 sub->set_context_rtc(rtc_sub);
235                 sub->set_context_drec(drec);
236                 
237                 // keyboard
238                 cpu_kbd->set_context_mem(new MCS48MEM(this, emu));
239                 cpu_kbd->set_context_io(kbd);
240 #ifdef USE_DEBUGGER
241                 cpu_kbd->set_context_debugger(new DEBUGGER(this, emu));
242 #endif
243                 kbd->set_context_cpu(cpu_sub);
244         }
245         
246         // cpu bus
247         cpu->set_context_mem(memory);
248         cpu->set_context_io(iobus);
249 #if defined(_X1TURBO_FEATURE) && defined(SINGLE_MODE_DMA)
250         cpu->set_context_dma(dma);
251 #endif
252 #ifdef USE_DEBUGGER
253         cpu->set_context_debugger(new DEBUGGER(this, emu));
254 #endif
255         
256         // z80 family daisy chain
257         DEVICE* parent_dev = NULL;
258         int level = 0;
259         
260         #define Z80_DAISY_CHAIN(dev) { \
261                 if(parent_dev == NULL) { \
262                         cpu->set_context_intr(dev); \
263                 } else { \
264                         parent_dev->set_context_child(dev); \
265                 } \
266                 dev->set_context_intr(cpu, level++); \
267                 parent_dev = dev; \
268         }
269 #ifndef _X1TURBO_FEATURE
270         Z80_DAISY_CHAIN(sio);   // CZ-8BM2
271         Z80_DAISY_CHAIN(ctc);
272 #endif
273         if(sound_device_type >= 1) {
274                 Z80_DAISY_CHAIN(ctc1);
275         }
276         if(sound_device_type == 2) {
277                 Z80_DAISY_CHAIN(ctc2);
278         }
279 #ifdef _X1TURBO_FEATURE
280         Z80_DAISY_CHAIN(sio);
281         Z80_DAISY_CHAIN(dma);
282         Z80_DAISY_CHAIN(ctc);
283 #endif
284         if(pseudo_sub_cpu) {
285                 Z80_DAISY_CHAIN(psub);
286         } else {
287                 Z80_DAISY_CHAIN(sub);
288         }
289         
290         // i/o bus
291         if(sound_device_type >= 1) {
292                 io->set_iomap_single_w(0x700, opm1);
293                 io->set_iovalue_single_r(0x700, 0x00);
294                 io->set_iomap_single_rw(0x701, opm1);
295 #ifdef _X1TURBOZ
296                 io->set_flipflop_single_rw(0x704, 0x00);
297 #else
298                 io->set_iomap_range_rw(0x704, 0x707, ctc1);
299 #endif
300         }
301         if(sound_device_type == 2) {
302                 io->set_iomap_single_w(0x708, opm2);
303                 io->set_iovalue_single_r(0x708, 0x00);
304                 io->set_iomap_single_rw(0x709, opm2);
305                 io->set_iomap_range_rw(0x70c, 0x70f, ctc2);
306         }
307 #ifdef _X1TURBO_FEATURE
308         io->set_iomap_single_rw(0xb00, memory);
309 #endif
310         io->set_iomap_range_rw(0xd00, 0xd03, emm);
311         io->set_iomap_range_r(0xe80, 0xe81, display);
312         io->set_iomap_range_w(0xe80, 0xe82, display);
313         io->set_iomap_range_rw(0xff8, 0xffb, fdc);
314         io->set_iomap_single_w(0xffc, floppy);
315 #ifdef _X1TURBO_FEATURE
316         io->set_iomap_range_r(0xffc, 0xfff, floppy);
317 #endif
318         io->set_iomap_range_rw(0x1000, 0x17ff, display);
319         for(int i = 0x1800; i <= 0x18ff; i += 0x10) {
320                 io->set_iomap_range_rw(i, i + 1, crtc);
321         }
322         if(pseudo_sub_cpu) {
323                 io->set_iomap_range_rw(0x1900, 0x19ff, psub);
324         } else {
325                 io->set_iomap_range_rw(0x1900, 0x19ff, sub);
326         }
327         for(int i = 0x1a00; i <= 0x1aff; i += 4) {
328                 io->set_iomap_range_rw(i, i + 3, pio);
329         }
330         for(int i = 0x1b00; i <= 0x1bff; i++) {
331                 io->set_iomap_alias_rw(i, psg, 1);
332         }
333         for(int i = 0x1c00; i <= 0x1cff; i++) {
334                 io->set_iomap_alias_w(i, psg, 0);
335         }
336         io->set_iomap_range_w(0x1d00, 0x1eff, memory);
337 #ifndef _X1TURBO_FEATURE
338         io->set_iomap_range_rw(0x1f98, 0x1f9b, sio);    // CZ-8BM2
339         io->set_iomap_range_rw(0x1fa8, 0x1fab, ctc);
340 #else
341         io->set_iomap_range_rw(0x1f80, 0x1f8f, dma);
342         io->set_iomap_range_rw(0x1f90, 0x1f93, sio);
343         io->set_iomap_range_rw(0x1fa0, 0x1fa3, ctc);
344 #ifdef _X1TURBOZ
345         io->set_iomap_single_rw(0x1fd0, display);
346         io->set_iomap_single_rw(0x1fe0, display);
347 #else
348         io->set_iomap_single_w(0x1fd0, display);
349         io->set_iomap_single_w(0x1fe0, display);
350 #endif
351         // 0x1ff0: dipswitch
352         //io->set_iovalue_single_r(0x1ff0, 0x00);
353         update_dipswitch();
354 #endif
355         io->set_iomap_range_rw(0x2000, 0x3fff, display);        // tvram
356         
357 #ifdef _X1TWIN
358         // init PC Engine
359         pceevent = new EVENT(this, emu);
360         pceevent->set_frames_per_sec(PCE_FRAMES_PER_SEC);
361         pceevent->set_lines_per_frame(PCE_LINES_PER_FRAME);
362         
363         pcecpu = new HUC6280(this, emu);
364         pcecpu->set_context_event_manager(pceevent);
365         pce = new PCE(this, emu);
366         pce->set_context_event_manager(pceevent);
367         
368         pceevent->set_context_cpu(pcecpu, PCE_CPU_CLOCKS);
369         pceevent->set_context_sound(pce);
370         
371         pcecpu->set_context_mem(pce);
372         pcecpu->set_context_io(pce);
373 #ifdef USE_DEBUGGER
374         pcecpu->set_context_debugger(new DEBUGGER(this, emu));
375 #endif
376         pce->set_context_cpu(pcecpu);
377 #endif
378         
379         // initialize all devices
380         for(DEVICE* device = first_device; device; device = device->next_device) {
381                 device->initialize();
382         }
383         if(!pseudo_sub_cpu) {
384                 // load rom images after cpustate is allocated
385                 cpu_sub->load_rom_image(create_local_path(SUB_ROM_FILE_NAME));
386                 cpu_kbd->load_rom_image(create_local_path(KBD_ROM_FILE_NAME));
387                 
388                 // patch to set the current year
389                 uint8 *rom = cpu_sub->get_rom_ptr();
390                 sub->rom_crc32 = get_crc32(rom, 0x800); // 2KB
391                 if(rom[0x23] == 0xb9 && rom[0x24] == 0x35 && rom[0x25] == 0xb1) {
392                         cur_time_t cur_time;
393                         get_host_time(&cur_time);
394                         rom[0x26] = TO_BCD(cur_time.year);
395                 }
396         }
397         for(int i = 0; i < MAX_DRIVE; i++) {
398 #ifdef _X1TURBO_FEATURE
399                 fdc->set_drive_type(i, DRIVE_TYPE_2DD);
400 #else
401                 fdc->set_drive_type(i, DRIVE_TYPE_2D);
402 #endif
403 //              fdc->set_drive_rpm(i, 300);
404 //              fdc->set_drive_mfm(i, true);
405         }
406 }
407
408 VM::~VM()
409 {
410         // delete all devices
411         for(DEVICE* device = first_device; device;) {
412                 DEVICE *next_device = device->next_device;
413                 device->release();
414                 delete device;
415                 device = next_device;
416         }
417 }
418
419 DEVICE* VM::get_device(int id)
420 {
421         for(DEVICE* device = first_device; device; device = device->next_device) {
422                 if(device->this_device_id == id) {
423                         return device;
424                 }
425         }
426         return NULL;
427 }
428
429 // ----------------------------------------------------------------------------
430 // drive virtual machine
431 // ----------------------------------------------------------------------------
432
433 void VM::reset()
434 {
435         // reset all devices
436         for(DEVICE* device = first_device; device; device = device->next_device) {
437                 device->reset();
438         }
439         pio->write_signal(SIG_I8255_PORT_B, 0x00, 0x08);        // busy = low
440         psg->SetReg(0x2e, 0);   // set prescaler
441 }
442
443 void VM::special_reset()
444 {
445         // nmi reset
446         cpu->write_signal(SIG_CPU_NMI, 1, 1);
447 }
448
449 void VM::run()
450 {
451         event->drive();
452 #ifdef _X1TWIN
453         if(pce->is_cart_inserted()) {
454                 pceevent->drive();
455         }
456 #endif
457 }
458
459 double VM::get_frame_rate()
460 {
461 #ifdef _X1TWIN
462         if(pce->is_cart_inserted()) {
463                 return pceevent->get_frame_rate();
464         }
465 #endif
466         return event->get_frame_rate();
467 }
468
469 // ----------------------------------------------------------------------------
470 // debugger
471 // ----------------------------------------------------------------------------
472
473 #ifdef USE_DEBUGGER
474 DEVICE *VM::get_cpu(int index)
475 {
476         if(index == 0) {
477                 return cpu;
478         } else if(index == 1) {
479                 return cpu_sub;
480         } else if(index == 2) {
481                 return cpu_kbd;
482 #ifdef _X1TWIN
483         } else if(index == 3 && pce->is_cart_inserted()) {
484                 return pcecpu;
485 #endif
486         }
487         return NULL;
488 }
489 #endif
490
491 // ----------------------------------------------------------------------------
492 // draw screen
493 // ----------------------------------------------------------------------------
494
495 void VM::draw_screen()
496 {
497         display->draw_screen();
498 #ifdef _X1TWIN
499         if(pce->is_cart_inserted()) {
500                 pce->draw_screen();
501         }
502 #endif
503 }
504
505 int VM::get_access_lamp_status()
506 {
507         uint32 status = fdc->read_signal(0);
508         return (status & (1 | 4)) ? 1 : (status & (2 | 8)) ? 2 : 0;
509 }
510
511 // ----------------------------------------------------------------------------
512 // soud manager
513 // ----------------------------------------------------------------------------
514
515 void VM::initialize_sound(int rate, int samples)
516 {
517         // init sound manager
518         event->initialize_sound(rate, samples);
519 #ifdef _X1TWIN
520         pceevent->initialize_sound(rate, samples);
521 #endif
522         
523         // init sound gen
524         if(sound_device_type >= 1) {
525                 opm1->initialize_sound(rate, 4000000, samples, 0);
526         }
527         if(sound_device_type == 2) {
528                 opm2->initialize_sound(rate, 4000000, samples, 0);
529         }
530         psg->initialize_sound(rate, 2000000, samples, 0, 0);
531 #ifdef _X1TWIN
532         pce->initialize_sound(rate);
533 #endif
534 }
535
536 uint16* VM::create_sound(int* extra_frames)
537 {
538 #ifdef _X1TWIN
539         if(pce->is_cart_inserted()) {
540                 uint16* buffer = pceevent->create_sound(extra_frames);
541                 for(int i = 0; i < *extra_frames; i++) {
542                         event->drive();
543                 }
544                 return buffer;
545         }
546 #endif
547         return event->create_sound(extra_frames);
548 }
549
550 int VM::get_sound_buffer_ptr()
551 {
552 #ifdef _X1TWIN
553         if(pce->is_cart_inserted()) {
554                 return pceevent->get_sound_buffer_ptr();
555         }
556 #endif
557         return event->get_sound_buffer_ptr();
558 }
559
560 #ifdef USE_SOUND_VOLUME
561 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
562 {
563         if(ch == 0) {
564                 psg->set_volume(1, decibel_l, decibel_r);
565         } else if(ch == 1) {
566                 if(sound_device_type >= 1) {
567                         opm1->set_volume(0, decibel_l, decibel_r);
568                 }
569         } else if(ch == 2) {
570                 if(sound_device_type >= 2) {
571                         opm2->set_volume(0, decibel_l, decibel_r);
572                 }
573         } else if(ch == 3) {
574                 drec->set_volume(0, decibel_l, decibel_r);
575 #if defined(_X1TWIN)
576         } else if(ch == 4) {
577                 pce->set_volume(0, decibel_l, decibel_r);
578 #endif
579         }
580 }
581 #endif
582
583 // ----------------------------------------------------------------------------
584 // notify key
585 // ----------------------------------------------------------------------------
586
587 void VM::key_down(int code, bool repeat)
588 {
589 #ifdef _X1TWIN
590         if(!repeat && !pce->is_cart_inserted()) {
591 #else
592         if(!repeat) {
593 #endif
594                 if(pseudo_sub_cpu) {
595                         psub->key_down(code, false);
596                 } else {
597                         kbd->key_down(code, false);
598                 }
599         }
600 }
601
602 void VM::key_up(int code)
603 {
604 #ifdef _X1TWIN
605         if(!pce->is_cart_inserted()) {
606 #endif
607                 if(pseudo_sub_cpu) {
608                         psub->key_up(code);
609                 } else {
610                         //kbd->key_up(code);
611                 }
612 #ifdef _X1TWIN
613         }
614 #endif
615 }
616
617 // ----------------------------------------------------------------------------
618 // user interface
619 // ----------------------------------------------------------------------------
620
621 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
622 {
623         fdc->open_disk(drv, file_path, bank);
624 }
625
626 void VM::close_floppy_disk(int drv)
627 {
628         fdc->close_disk(drv);
629 }
630
631 bool VM::is_floppy_disk_inserted(int drv)
632 {
633         return fdc->is_disk_inserted(drv);
634 }
635
636 void VM::is_floppy_disk_protected(int drv, bool value)
637 {
638         fdc->is_disk_protected(drv, value);
639 }
640
641 bool VM::is_floppy_disk_protected(int drv)
642 {
643         return fdc->is_disk_protected(drv);
644 }
645  
646 void VM::play_tape(const _TCHAR* file_path)
647 {
648         bool value = drec->play_tape(file_path);
649         if(pseudo_sub_cpu) {
650                 psub->close_tape();
651                 psub->play_tape(value);
652         } else {
653                 sub->close_tape();
654                 sub->play_tape(value);
655         }
656 }
657
658 void VM::rec_tape(const _TCHAR* file_path)
659 {
660         bool value = drec->rec_tape(file_path);
661         if(pseudo_sub_cpu) {
662                 psub->close_tape();
663                 psub->rec_tape(value);
664         } else {
665                 sub->close_tape();
666                 sub->rec_tape(value);
667         }
668 }
669
670 void VM::close_tape()
671 {
672         drec->close_tape();
673         if(pseudo_sub_cpu) {
674                 psub->close_tape();
675         } else {
676                 sub->close_tape();
677         }
678 }
679
680 bool VM::is_tape_inserted()
681 {
682         return drec->is_tape_inserted();
683 }
684
685 bool VM::is_tape_playing()
686 {
687         return drec->is_tape_playing();
688 }
689
690 bool VM::is_tape_recording()
691 {
692         return drec->is_tape_recording();
693 }
694
695 int VM::get_tape_position()
696 {
697         return drec->get_tape_position();
698 }
699
700 void VM::push_play()
701 {
702         drec->set_ff_rew(0);
703         drec->set_remote(true);
704 }
705
706 void VM::push_stop()
707 {
708         drec->set_remote(false);
709 }
710
711 void VM::push_fast_forward()
712 {
713         drec->set_ff_rew(1);
714         drec->set_remote(true);
715 }
716
717 void VM::push_fast_rewind()
718 {
719         drec->set_ff_rew(-1);
720         drec->set_remote(true);
721 }
722
723 void VM::push_apss_forward()
724 {
725         drec->do_apss(1);
726 }
727
728 void VM::push_apss_rewind()
729 {
730         drec->do_apss(-1);
731 }
732
733 bool VM::is_frame_skippable()
734 {
735 #ifdef _X1TWIN
736         if(pce->is_cart_inserted()) {
737                 return pceevent->is_frame_skippable();
738         }
739 #endif
740         return event->is_frame_skippable();
741 }
742
743 #ifdef _X1TWIN
744 void VM::open_cart(int drv, const _TCHAR* file_path)
745 {
746         if(drv == 0) {
747                 pce->open_cart(file_path);
748                 pce->reset();
749                 pcecpu->reset();
750         }
751 }
752
753 void VM::close_cart(int drv)
754 {
755         if(drv == 0) {
756                 pce->close_cart();
757                 pce->reset();
758                 pcecpu->reset();
759         }
760 }
761
762 bool VM::is_cart_inserted(int drv)
763 {
764         if(drv == 0) {
765                 return pce->is_cart_inserted();
766         } else {
767                 return false;
768         }
769 }
770 #endif
771
772 void VM::update_config()
773 {
774         for(DEVICE* device = first_device; device; device = device->next_device) {
775                 device->update_config();
776         }
777 #ifdef _X1TURBO_FEATURE
778         update_dipswitch();
779 #endif
780 }
781
782 #ifdef _X1TURBO_FEATURE
783 void VM::update_dipswitch()
784 {
785         // bit0         0=High 1=Standard
786         // bit2         0=5"2D 1=5"2HD
787         io->set_iovalue_single_r(0x1ff0, (config.monitor_type & 1) | ((config.drive_type & 1) << 2));
788 }
789 #endif
790
791 #define STATE_VERSION   6
792
793 void VM::save_state(FILEIO* state_fio)
794 {
795         state_fio->FputUint32(STATE_VERSION);
796         
797         for(DEVICE* device = first_device; device; device = device->next_device) {
798                 device->save_state(state_fio);
799         }
800         state_fio->FputBool(pseudo_sub_cpu);
801         state_fio->FputInt32(sound_device_type);
802 }
803
804 bool VM::load_state(FILEIO* state_fio)
805 {
806         if(state_fio->FgetUint32() != STATE_VERSION) {
807                 return false;
808         }
809         for(DEVICE* device = first_device; device; device = device->next_device) {
810                 if(!device->load_state(state_fio)) {
811                         return false;
812                 }
813         }
814         pseudo_sub_cpu = state_fio->FgetBool();
815         sound_device_type = state_fio->FgetInt32();
816         
817 #ifdef _X1TURBO_FEATURE
818         // post process
819         update_dipswitch();
820 #endif
821         return true;
822 }
823