OSDN Git Service

[VM][STATE] Use namespace {VMNAME} to separate per VMs.
[csp-qt/common_source_project-fm7.git] / source / src / vm / pc6001 / pc6001.cpp
1 /*
2         NEC PC-6001 Emulator 'yaPC-6001'
3         NEC PC-6001mkII Emulator 'yaPC-6201'
4         NEC PC-6001mkIISR Emulator 'yaPC-6401'
5         NEC PC-6601 Emulator 'yaPC-6601'
6         NEC PC-6601SR Emulator 'yaPC-6801'
7
8         Author : tanam
9         Date   : 2013.07.15-
10
11         [ virtual machine ]
12 */
13
14 #include "pc6001.h"
15 #include "../../emu.h"
16 #include "../device.h"
17 #include "../event.h"
18
19 #include "../disk.h"
20 #include "../i8255.h"
21 #include "../io.h"
22 #ifdef _PC6001
23 #include "../mc6847.h"
24 #include "display.h"
25 #else
26 #include "../upd7752.h"
27 #endif
28 #include "../noise.h"
29 #include "../pc6031.h"
30 #include "../pc80s31k.h"
31 #include "../prnfile.h"
32 #include "../upd765a.h"
33 #if defined(_PC6001MK2SR) || defined(_PC6601SR)
34 #include "../ym2203.h"
35 #else
36 #include "../ay_3_891x.h"
37 #endif
38 #include "../z80.h"
39
40 #include "../datarec.h"
41 #include "../mcs48.h"
42
43 #ifdef USE_DEBUGGER
44 #include "../debugger.h"
45 #endif
46
47 #if defined(_PC6601) || defined(_PC6601SR)
48 #include "floppy.h"
49 #endif
50 #include "joystick.h"
51 #include "memory.h"
52 #include "psub.h"
53 #include "sub.h"
54 #include "timer.h"
55
56 #ifdef _PC6001
57 using PC6001::DISPLAY;
58 #endif
59 #if defined(_PC6601) || defined(_PC6601SR)
60 using PC6001::FLOPPY;
61 #endif
62
63 using PC6001::JOYSTICK;
64 using PC6001::MEMORY;
65 using PC6001::PSUB;
66 using PC6001::SUB;
67 using PC6001::TIMER;
68
69 // ----------------------------------------------------------------------------
70 // initialize
71 // ----------------------------------------------------------------------------
72
73 VM::VM(EMU* parent_emu) : VM_TEMPLATE(parent_emu)
74 {
75         support_pc80s31k = FILEIO::IsFileExisting(create_local_path(_T("DISK.ROM")));
76 #ifdef _PC6601SR
77         support_sub_cpu = false;
78 #else
79         support_sub_cpu = FILEIO::IsFileExisting(create_local_path(_T(SUB_CPU_ROM_FILE_NAME)));
80 #endif
81         
82         // create devices
83         first_device = last_device = NULL;
84         dummy = new DEVICE(this, emu);  // must be 1st device
85         event = new EVENT(this, emu);   // must be 2nd device
86         
87         pio_sub = new I8255(this, emu);
88         io = new IO(this, emu);
89         noise_seek = new NOISE(this, emu);
90         noise_head_down = new NOISE(this, emu);
91         noise_head_up = new NOISE(this, emu);
92 #if defined(_PC6001MK2SR) || defined(_PC6601SR)
93         psg = new YM2203(this, emu);
94 #else
95         psg = new AY_3_891X(this, emu);
96 #endif
97         cpu = new Z80(this, emu);
98         
99         if(config.printer_type == 0) {
100                 printer = new PRNFILE(this, emu);
101         } else {
102                 printer = dummy;
103         }
104         
105 #if defined(_PC6601) || defined(_PC6601SR)
106         floppy = new FLOPPY(this, emu);
107         floppy->set_context_noise_seek(noise_seek);
108 //      floppy->set_context_noise_head_down(noise_head_down);
109 //      floppy->set_context_noise_head_up(noise_head_up);
110 #endif
111         joystick = new JOYSTICK(this, emu);
112         memory = new MEMORY(this, emu);
113         timer = new TIMER(this, emu);
114         
115         // set contexts
116         event->set_context_cpu(cpu);
117         event->set_context_sound(psg);
118         event->set_context_sound(noise_seek);
119         event->set_context_sound(noise_head_down);
120         event->set_context_sound(noise_head_up);
121         
122         pio_sub->set_context_port_b(printer, SIG_PRINTER_DATA, 0xff, 0);
123         pio_sub->set_context_port_c(printer, SIG_PRINTER_STROBE, 0x01, 0);
124         pio_sub->set_context_port_c(memory, SIG_MEMORY_PIO_PORT_C, 0x06, 0);    // CRTKILL,CGSWN
125         
126 #ifdef _PC6001
127         display = new DISPLAY(this, emu);
128         vdp = new MC6847(this, emu);
129         display->set_context_vdp(vdp);
130         display->set_vram_ptr(memory->get_vram());
131         display->set_context_timer(timer);
132         vdp->load_font_image(create_local_path(_T("CGROM60.60")));
133         vdp->set_context_cpu(cpu);
134         pio_sub->set_context_port_c(vdp, SIG_MC6847_ENABLE, 0x02, 0);   // CRTKILL
135 #else
136         voice = new UPD7752(this, emu);
137         event->set_context_sound(voice);
138         memory->set_context_timer(timer);
139 #endif
140         memory->set_context_cpu(cpu);
141         joystick->set_context_psg(psg);
142         
143         timer->set_context_cpu(cpu);
144 #ifndef _PC6001
145         timer->set_context_memory(memory);
146 #endif
147         if(support_sub_cpu) {
148                 cpu_sub = new MCS48(this, emu);
149                 cpu_sub->set_device_name(_T("MCS48 MCU (Sub)"));
150                 sub = new SUB(this, emu);
151                 drec = new DATAREC(this, emu);
152                 drec->set_device_name(_T("Data Recorder (Sub)"));
153                 drec->set_context_noise_play(new NOISE(this, emu));
154                 drec->set_context_noise_stop(new NOISE(this, emu));
155                 drec->set_context_noise_fast(new NOISE(this, emu));
156                 event->set_context_cpu(cpu_sub, 8000000);
157                 event->set_context_sound(drec);
158                 event->set_context_sound(drec->get_context_noise_play());
159                 event->set_context_sound(drec->get_context_noise_stop());
160                 event->set_context_sound(drec->get_context_noise_fast());
161                 cpu_sub->set_context_mem(new MCS48MEM(this, emu));
162                 cpu_sub->set_context_io(sub);
163 #ifdef USE_DEBUGGER
164                 cpu_sub->set_context_debugger(new DEBUGGER(this, emu));
165 #endif
166                 sub->set_context_pio(pio_sub);
167                 sub->set_context_drec(drec);
168                 sub->set_context_timer(timer);
169                 pio_sub->set_context_port_c(cpu_sub, SIG_CPU_IRQ, 0x80, 0);
170                 drec->set_context_ear(sub, SIG_SUB_DATAREC, 1);
171                 timer->set_context_sub(sub);
172         } else {
173                 psub = new PSUB(this, emu);
174                 psub->set_context_pio(pio_sub);
175                 psub->set_context_timer(timer);
176                 timer->set_context_sub(psub);
177                 cpu_sub = NULL;
178         }
179         if(support_pc80s31k) {
180                 pio_fdd = new I8255(this, emu);
181                 pio_fdd->set_device_name(_T("8255 PIO (FDD I/F)"));
182                 pio_pc80s31k = new I8255(this, emu);
183                 pio_pc80s31k->set_device_name(_T("8255 PIO (320KB FDD)"));
184                 pc80s31k = new PC80S31K(this, emu);
185                 pc80s31k->set_device_name(_T("PC-80S31K (320KB FDD)"));
186                 fdc_pc80s31k = new UPD765A(this, emu);
187                 fdc_pc80s31k->set_device_name(_T("uPD765A FDC (320KB FDD)"));
188                 cpu_pc80s31k = new Z80(this, emu);
189                 cpu_pc80s31k->set_device_name(_T("Z80 CPU (320KB FDD)"));
190                 
191                 event->set_context_cpu(cpu_pc80s31k, 4000000);
192                 
193                 pc80s31k->set_context_cpu(cpu_pc80s31k);
194                 pc80s31k->set_context_fdc(fdc_pc80s31k);
195                 pc80s31k->set_context_pio(pio_pc80s31k);
196                 pio_fdd->set_context_port_a(pio_pc80s31k, SIG_I8255_PORT_B, 0xff, 0);
197                 pio_fdd->set_context_port_b(pio_pc80s31k, SIG_I8255_PORT_A, 0xff, 0);
198                 pio_fdd->set_context_port_c(pio_pc80s31k, SIG_I8255_PORT_C, 0x0f, 4);
199                 pio_fdd->set_context_port_c(pio_pc80s31k, SIG_I8255_PORT_C, 0xf0, -4);
200                 pio_fdd->clear_ports_by_cmdreg = true;
201                 pio_pc80s31k->set_context_port_a(pio_fdd, SIG_I8255_PORT_B, 0xff, 0);
202                 pio_pc80s31k->set_context_port_b(pio_fdd, SIG_I8255_PORT_A, 0xff, 0);
203                 pio_pc80s31k->set_context_port_c(pio_fdd, SIG_I8255_PORT_C, 0x0f, 4);
204                 pio_pc80s31k->set_context_port_c(pio_fdd, SIG_I8255_PORT_C, 0xf0, -4);
205                 pio_pc80s31k->clear_ports_by_cmdreg = true;
206                 fdc_pc80s31k->set_context_irq(cpu_pc80s31k, SIG_CPU_IRQ, 1);
207                 fdc_pc80s31k->set_context_noise_seek(noise_seek);
208                 fdc_pc80s31k->set_context_noise_head_down(noise_head_down);
209                 fdc_pc80s31k->set_context_noise_head_up(noise_head_up);
210                 cpu_pc80s31k->set_context_mem(pc80s31k);
211                 cpu_pc80s31k->set_context_io(pc80s31k);
212                 cpu_pc80s31k->set_context_intr(pc80s31k);
213 #ifdef USE_DEBUGGER
214                 cpu_pc80s31k->set_context_debugger(new DEBUGGER(this, emu));
215 #endif
216 #if defined(_PC6601) || defined(_PC6601SR)
217                 floppy->set_context_ext(pio_fdd);
218 #endif
219         } else {
220                 pc6031 = new PC6031(this, emu);
221                 pc6031->set_context_noise_seek(noise_seek);
222 //              pc6031->set_context_noise_head_down(noise_head_down);
223 //              pc6031->set_context_noise_head_up(noise_head_up);
224 #if defined(_PC6601) || defined(_PC6601SR)
225                 floppy->set_context_ext(pc6031);
226 #endif
227                 cpu_pc80s31k = NULL;
228         }
229         
230         // cpu bus
231         cpu->set_context_mem(memory);
232         cpu->set_context_io(io);
233         cpu->set_context_intr(timer);
234 #ifdef USE_DEBUGGER
235         cpu->set_context_debugger(new DEBUGGER(this, emu));
236 #endif
237         
238         // i/o bus
239         if(support_sub_cpu) {
240                 io->set_iomap_range_rw(0x90, 0x93, sub);
241         } else {
242                 io->set_iomap_range_rw(0x90, 0x93, psub);
243         }
244         io->set_iomap_alias_w(0xa0, psg, 0);                    // PSG ch
245         io->set_iomap_alias_w(0xa1, psg, 1);                    // PSG data
246         io->set_iomap_alias_r(0xa2, psg, 1);                    // PSG data
247 #if defined(_PC6601SR) || defined(_PC6001MK2SR)
248         io->set_iomap_alias_r(0xa3, psg, 0);                    // FM status
249         io->set_iomap_range_rw(0x40, 0x6f, memory);             // VRAM addr
250 #endif
251 #ifdef _PC6001
252         io->set_iomap_single_w(0xb0, display);                  // VRAM addr
253         io->set_iomap_single_w(0x00, memory);                   // MEMORY MAP
254 #else
255         io->set_iomap_single_w(0xb0, memory);                   // VRAM addr
256         io->set_iomap_range_rw(0xc0, 0xcf, memory);             // VRAM addr
257         io->set_iomap_range_rw(0xe0, 0xe3, voice);              // VOICE
258 #if defined(_PC6601) || defined(_PC6601SR)
259         io->set_iomap_range_rw(0xb8, 0xbf, timer);              // IRQ
260         io->set_iomap_range_rw(0xfa, 0xfb, timer);              // IRQ
261 #endif
262         io->set_iomap_range_rw(0xf3, 0xf7, timer);              // IRQ/Timer
263 #endif
264         
265 #if defined(_PC6601) || defined(_PC6601SR)
266         io->set_iomap_range_rw(0xb1, 0xb3, floppy);             // DISK DRIVE
267         io->set_iomap_range_rw(0xb5, 0xb7, floppy);             // DISK DRIVE (Mirror)
268         io->set_iomap_range_rw(0xd0, 0xde, floppy);             // DISK DRIVE
269 #else
270         io->set_iovalue_single_r(0xb1, 0x01);
271 #if defined(_PC6601SR)
272         io->set_iovalue_single_r(0xb2, 0x02);
273 #elif defined(_PC6001MK2SR)
274         io->set_iovalue_single_r(0xb2, 0x00);
275 #endif
276         
277         if(support_pc80s31k) {
278                 io->set_iomap_range_rw(0xd0, 0xd2, pio_fdd);
279                 io->set_iomap_single_w(0xd3, pio_fdd);
280         } else {
281                 io->set_iomap_range_rw(0xd0, 0xd3, pc6031);
282         }
283 #endif
284         io->set_iomap_range_rw(0xf0, 0xf2, memory);             // MEMORY MAP
285         
286         // initialize all devices
287 #if defined(__GIT_REPO_VERSION)
288         strncpy(_git_revision, __GIT_REPO_VERSION, sizeof(_git_revision) - 1);
289 #endif
290         for(DEVICE* device = first_device; device; device = device->next_device) {
291                 device->initialize();
292         }
293
294         if(support_sub_cpu) {
295                 // load rom images after cpustate is allocated
296 #ifdef _PC6601SR
297 #else
298                 cpu_sub->load_rom_image(create_local_path(_T(SUB_CPU_ROM_FILE_NAME)));
299 #endif
300         }
301         int drive_num = 0;
302 #if defined(_PC6601) || defined(_PC6601SR)
303         floppy->get_disk_handler(0)->drive_num = drive_num++;
304         floppy->get_disk_handler(1)->drive_num = drive_num++;
305 #endif
306         if(support_pc80s31k) {
307                 fdc_pc80s31k->get_disk_handler(0)->drive_num = drive_num++;
308                 fdc_pc80s31k->get_disk_handler(1)->drive_num = drive_num++;
309         } else {
310                 pc6031->get_disk_handler(0)->drive_num = drive_num++;
311                 pc6031->get_disk_handler(1)->drive_num = drive_num++;
312         }
313 }
314
315 VM::~VM()
316 {
317         // delete all devices
318         for(DEVICE* device = first_device; device;) {
319                 DEVICE *next_device = device->next_device;
320                 device->release();
321                 delete device;
322                 device = next_device;
323         }
324 }
325
326 DEVICE* VM::get_device(int id)
327 {
328         for(DEVICE* device = first_device; device; device = device->next_device) {
329                 if(device->this_device_id == id) {
330                         return device;
331                 }
332         }
333         return NULL;
334 }
335
336 // ----------------------------------------------------------------------------
337 // drive virtual machine
338 // ----------------------------------------------------------------------------
339 void VM::reset()
340 {
341         // reset all devices
342         for(DEVICE* device = first_device; device; device = device->next_device) {
343                 device->reset();
344         }
345         if(support_pc80s31k) {
346                 pio_fdd->write_signal(SIG_I8255_PORT_C, 0, 0xff);
347                 pio_pc80s31k->write_signal(SIG_I8255_PORT_C, 0, 0xff);
348         }
349 }
350
351 void VM::run()
352 {
353         event->drive();
354 }
355
356 // ----------------------------------------------------------------------------
357 // debugger
358 // ----------------------------------------------------------------------------
359
360 #ifdef USE_DEBUGGER
361 DEVICE *VM::get_cpu(int index)
362 {
363         if(index == 0) {
364                 return cpu;
365         } else if(index == 1) {
366                 return cpu_sub;
367         } else if(index == 2) {
368                 return cpu_pc80s31k;
369         }
370         return NULL;
371 }
372 #endif
373
374 // ----------------------------------------------------------------------------
375 // draw screen
376 // ----------------------------------------------------------------------------
377
378 void VM::draw_screen()
379 {
380 #ifdef _PC6001
381         display->draw_screen();
382 #else
383         memory->draw_screen();
384 #endif
385 }
386 // ----------------------------------------------------------------------------
387 // soud manager
388 // ----------------------------------------------------------------------------
389
390 void VM::initialize_sound(int rate, int samples)
391 {
392         // init sound manager
393         event->initialize_sound(rate, samples);
394         
395         // init sound gen
396         psg->initialize_sound(rate, 4000000, samples, 0, 0);
397 #ifndef _PC6001
398         voice->initialize_sound(rate);
399 #endif
400 }
401
402 uint16_t* VM::create_sound(int* extra_frames)
403 {
404         return event->create_sound(extra_frames);
405 }
406
407 int VM::get_sound_buffer_ptr()
408 {
409         return event->get_sound_buffer_ptr();
410 }
411
412 #ifdef USE_SOUND_VOLUME
413 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
414 {
415         if(ch-- == 0) {
416                 psg->set_volume(1, decibel_l, decibel_r);
417 #if !defined(_PC6001)
418         } else if(ch-- == 0) {
419                 voice->set_volume(0, decibel_l, decibel_r);
420 #endif
421         } else if(ch-- == 0) {
422                 if(support_sub_cpu) {
423                         drec->set_volume(0, decibel_l, decibel_r);
424                 }
425         } else if(ch-- == 0) {
426                 noise_seek->set_volume(0, decibel_l, decibel_r);
427                 noise_head_down->set_volume(0, decibel_l, decibel_r);
428                 noise_head_up->set_volume(0, decibel_l, decibel_r);
429         } else if(ch-- == 0) {
430                 if(support_sub_cpu) {
431                         drec->get_context_noise_play()->set_volume(0, decibel_l, decibel_r);
432                         drec->get_context_noise_stop()->set_volume(0, decibel_l, decibel_r);
433                         drec->get_context_noise_fast()->set_volume(0, decibel_l, decibel_r);
434                 }
435         }
436 }
437 #endif
438
439 // ----------------------------------------------------------------------------
440 // notify key
441 // ----------------------------------------------------------------------------
442
443 void VM::key_down(int code, bool repeat)
444 {
445         if(!support_sub_cpu) {
446                 psub->key_down(code);
447         }
448 }
449
450 void VM::key_up(int code)
451 {
452         if(!support_sub_cpu) {
453                 psub->key_up(code);
454         }
455 }
456
457 // ----------------------------------------------------------------------------
458 // user interface
459 // ----------------------------------------------------------------------------
460
461 void VM::open_cart(int drv, const _TCHAR* file_path)
462 {
463         if(drv == 0) {
464                 memory->open_cart(file_path);
465                 reset();
466         }
467 }
468
469 void VM::close_cart(int drv)
470 {
471         if(drv == 0) {
472                 memory->close_cart();
473                 reset();
474         }
475 }
476
477 bool VM::is_cart_inserted(int drv)
478 {
479         if(drv == 0) {
480                 return memory->is_cart_inserted();
481         } else {
482                 return false;
483         }
484 }
485
486 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
487 {
488 #if defined(_PC6601) || defined(_PC6601SR)
489         if(drv < 2) {
490                 floppy->open_disk(drv, file_path, bank);
491                 return;
492         } else {
493                 drv -= 2;
494         }
495 #endif
496         if(support_pc80s31k) {
497                 fdc_pc80s31k->open_disk(drv, file_path, bank);
498         } else {
499                 pc6031->open_disk(drv, file_path, bank);
500         }
501 }
502
503 void VM::close_floppy_disk(int drv)
504 {
505 #if defined(_PC6601) || defined(_PC6601SR)
506         if(drv < 2) {
507                 floppy->close_disk(drv);
508                 return;
509         } else {
510                 drv -= 2;
511         }
512 #endif
513         if(support_pc80s31k) {
514                 fdc_pc80s31k->close_disk(drv);
515         } else {
516                 pc6031->close_disk(drv);
517         }
518 }
519
520 bool VM::is_floppy_disk_inserted(int drv)
521 {
522 #if defined(_PC6601) || defined(_PC6601SR)
523         if(drv < 2) {
524                 return floppy->is_disk_inserted(drv);
525         } else {
526                 drv -= 2;
527         }
528 #endif
529         if(support_pc80s31k) {
530                 return fdc_pc80s31k->is_disk_inserted(drv);
531         } else {
532                 return pc6031->is_disk_inserted(drv);
533         }
534 }
535
536 void VM::is_floppy_disk_protected(int drv, bool value)
537 {
538 #if defined(_PC6601) || defined(_PC6601SR)
539         if(drv < 2) {
540                 floppy->is_disk_protected(drv, value);
541                 return;
542         } else {
543                 drv -= 2;
544         }
545 #endif
546         if(support_pc80s31k) {
547                 fdc_pc80s31k->is_disk_protected(drv, value);
548         } else {
549                 pc6031->is_disk_protected(drv, value);
550         }
551 }
552
553 bool VM::is_floppy_disk_protected(int drv)
554 {
555 #if defined(_PC6601) || defined(_PC6601SR)
556         if(drv < 2) {
557                 return floppy->is_disk_protected(drv);
558         } else {
559                 drv -= 2;
560         }
561 #endif
562         if(support_pc80s31k) {
563                 return fdc_pc80s31k->is_disk_protected(drv);
564         } else {
565                 return pc6031->is_disk_protected(drv);
566         }
567 }
568
569 uint32_t VM::is_floppy_disk_accessed()
570 {
571         uint32_t status = 0; /// fdc->read_signal(0);
572         if(support_pc80s31k) {
573                 status |= fdc_pc80s31k->read_signal(0);
574         } else {
575                 status |= pc6031->read_signal(0);
576         }
577 #if defined(_PC6601) || defined(_PC6601SR)
578         status <<= 2;
579         status |= floppy->read_signal(0);
580 #endif
581         return status;
582 }
583
584 void VM::play_tape(int drv, const _TCHAR* file_path)
585 {
586         if(support_sub_cpu) {
587                 // support both p6/p6t and wav
588                 drec->play_tape(file_path);
589 //              drec->set_remote(true);
590         } else {
591                 // support only p6/p6t
592                 psub->play_tape(file_path);
593         }
594 }
595
596 void VM::rec_tape(int drv, const _TCHAR* file_path)
597 {
598         if(support_sub_cpu) {
599                 // support both p6/p6t and wav
600                 sub->rec_tape(file_path);       // temporary
601 //              drec->rec_tape(file_path);
602 //              drec->set_remote(true);
603         } else {
604                 // support both p6/p6t and wav
605                 psub->rec_tape(file_path);
606         }
607 }
608
609 void VM::close_tape(int drv)
610 {
611         if(support_sub_cpu) {
612                 if(sub->is_tape_inserted()) {
613                         sub->close_tape();      // temporary
614                 } else {
615                         emu->lock_vm();
616                         drec->close_tape();
617                         emu->unlock_vm();
618 //                      drec->set_remote(false);
619                 }
620         } else {
621                 psub->close_tape();
622         }
623 }
624
625 bool VM::is_tape_inserted(int drv)
626 {
627         if(support_sub_cpu) {
628                 return drec->is_tape_inserted() || sub->is_tape_inserted();
629         } else {
630                 return psub->is_tape_inserted();
631         }
632 }
633
634 bool VM::is_tape_playing(int drv)
635 {
636         if(support_sub_cpu) {
637                 return drec->is_tape_playing();
638         } else {
639                 return false;
640         }
641 }
642
643 bool VM::is_tape_recording(int drv)
644 {
645         if(support_sub_cpu) {
646                 return drec->is_tape_recording();
647         } else {
648                 return false;
649         }
650 }
651
652 int VM::get_tape_position(int drv)
653 {
654         if(support_sub_cpu) {
655                 return drec->get_tape_position();
656         } else {
657                 return 0;
658         }
659 }
660
661 const _TCHAR* VM::get_tape_message(int drv)
662 {
663         if(support_sub_cpu) {
664                 return drec->get_message();
665         } else {
666                 return NULL;
667         }
668 }
669
670 void VM::push_play(int drv)
671 {
672         if(support_sub_cpu) {
673                 drec->set_ff_rew(0);
674                 drec->set_remote(true);
675         }
676 }
677
678 void VM::push_stop(int drv)
679 {
680         if(support_sub_cpu) {
681                 drec->set_remote(false);
682         }
683 }
684
685 void VM::push_fast_forward(int drv)
686 {
687         if(support_sub_cpu) {
688                 drec->set_ff_rew(1);
689                 drec->set_remote(true);
690         }
691 }
692
693 void VM::push_fast_rewind(int drv)
694 {
695         if(support_sub_cpu) {
696                 drec->set_ff_rew(-1);
697                 drec->set_remote(true);
698         }
699 }
700
701 bool VM::is_frame_skippable()
702 {
703         return event->is_frame_skippable();
704 }
705
706 void VM::update_config()
707 {
708         for(DEVICE* device = first_device; device; device = device->next_device) {
709                 device->update_config();
710         }
711 }
712
713 #define STATE_VERSION   6
714
715 bool VM::process_state(FILEIO* state_fio, bool loading)
716 {
717         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
718                 return false;
719         }
720         for(DEVICE* device = first_device; device; device = device->next_device) {
721                 // Note: typeid(foo).name is fixed by recent ABI.Not dec 6.
722                 // const char *name = typeid(*device).name();
723                 //       But, using get_device_name() instead of typeid(foo).name() 20181008 K.O
724                 const char *name = device->get_device_name();
725                 int len = strlen(name);
726                 
727                 if(!state_fio->StateCheckInt32(len)) {
728                         if(loading) {
729                                 printf("Class name len Error: DEVID=%d EXPECT=%s\n", device->this_device_id, name);
730                         }
731                         return false;
732                 }
733                 if(!state_fio->StateCheckBuffer(name, len, 1)) {
734                         if(loading) {
735                                 printf("Class name Error: DEVID=%d EXPECT=%s\n", device->this_device_id, name);
736                         }
737                         return false;
738                 }
739                 if(!device->process_state(state_fio, loading)) {
740                         if(loading) {
741                                 printf("Data loading Error: DEVID=%d\n", device->this_device_id);
742                         }
743                         return false;
744                 }
745         }
746         // Machine specified.
747         state_fio->StateInt32(sr_mode);
748         return true;
749 }