2 SHARP X1 Emulator 'eX1'
3 SHARP X1twin Emulator 'eX1twin'
4 SHARP X1turbo Emulator 'eX1turbo'
6 Author : Takeda.Toshiya
13 #include "../../emu.h"
14 #include "../device.h"
17 #include "../datarec.h"
19 #include "../hd46505.h"
22 #include "../mb8877.h"
23 #include "../mz1p17.h"
25 //#include "../pcpr201.h"
26 #include "../prnfile.h"
27 #include "../ym2151.h"
28 //#include "../ym2203.h"
29 #include "../ay_3_891x.h"
31 #include "../z80ctc.h"
32 #include "../z80sio.h"
33 #ifdef _X1TURBO_FEATURE
34 #include "../z80dma.h"
38 #include "../debugger.h"
51 #include "../upd1990a.h"
56 #include "../huc6280.h"
57 #include "../pcengine/pce.h"
60 DLL_PREFIX_I struct cur_time_s cur_time;
63 // ----------------------------------------------------------------------------
65 // ----------------------------------------------------------------------------
67 VM::VM(EMU* parent_emu) : emu(parent_emu)
69 pseudo_sub_cpu = !(FILEIO::IsFileExisting(create_local_path(SUB_ROM_FILE_NAME)) && FILEIO::IsFileExisting(create_local_path(KBD_ROM_FILE_NAME)));
71 sound_type = config.sound_type;
74 first_device = last_device = NULL;
75 dummy = new DEVICE(this, emu); // must be 1st device
76 event = new EVENT(this, emu); // must be 2nd device
77 dummy->set_device_name(_T("1st Dummy"));
79 drec = new DATAREC(this, emu);
80 drec->set_context_noise_play(new NOISE(this, emu));
81 drec->set_context_noise_stop(new NOISE(this, emu));
82 drec->set_context_noise_fast(new NOISE(this, emu));
83 crtc = new HD46505(this, emu);
84 pio = new I8255(this, emu);
85 io = new IO(this, emu);
86 fdc = new MB8877(this, emu);
87 fdc->set_context_noise_seek(new NOISE(this, emu));
88 fdc->set_context_noise_head_down(new NOISE(this, emu));
89 fdc->set_context_noise_head_up(new NOISE(this, emu));
90 // psg = new YM2203(this, emu);
91 psg = new AY_3_891X(this, emu);
92 cpu = new Z80(this, emu);
93 ctc = new Z80CTC(this, emu);
94 sio = new Z80SIO(this, emu);
96 opm1 = new YM2151(this, emu);
97 opm1->set_device_name(_T("YM2151 OPM (CZ-8BS1 #1)"));
98 ctc1 = new Z80CTC(this, emu);
99 ctc1->set_device_name(_T("Z80 CTC (CZ-8BS1 #1)"));
101 if(sound_type == 2) {
102 opm2 = new YM2151(this, emu);
103 opm2->set_device_name(_T("YM2151 OPM (CZ-8BS1 #2)"));
104 ctc2 = new Z80CTC(this, emu);
105 ctc2->set_device_name(_T("Z80 CTC (CZ-8BS1 #2)"));
107 if(config.printer_type == 0) {
108 printer = new PRNFILE(this, emu);
109 } else if(config.printer_type == 1) {
110 printer = new MZ1P17(this, emu);
111 // } else if(config.printer_type == 2) {
112 // printer = new PCPR201(this, emu);
116 #ifdef _X1TURBO_FEATURE
117 dma = new Z80DMA(this, emu);
120 display = new DISPLAY(this, emu);
121 emm = new EMM(this, emu);
122 floppy = new FLOPPY(this, emu);
123 iobus = new IOBUS(this, emu);
124 joy = new JOYSTICK(this, emu);
125 memory = new MEMORY(this, emu);
126 mouse = new MOUSE(this, emu);
129 psub = new PSUB(this, emu);
134 cpu_sub = new MCS48(this, emu);
135 cpu_sub->set_device_name(_T("MCS48 MCU (Sub)"));
136 pio_sub = new I8255(this, emu);
137 pio_sub->set_device_name(_T("i8255 PIO (Sub)"));
138 rtc_sub = new UPD1990A(this, emu);
139 rtc_sub->set_device_name(_T("uPD1990A RTC (Sub)"));
140 sub = new SUB(this, emu);
143 cpu_kbd = new MCS48(this, emu);
144 cpu_kbd->set_device_name(_T("MCS48 MCU (Keyboard)"));
145 kbd = new KEYBOARD(this, emu);
149 event->set_context_cpu(cpu);
150 if(!pseudo_sub_cpu) {
151 event->set_context_cpu(cpu_sub, 6000000);
152 event->set_context_cpu(cpu_kbd, 6000000);
154 if(sound_type >= 1) {
155 event->set_context_sound(opm1);
157 if(sound_type == 2) {
158 event->set_context_sound(opm2);
160 event->set_context_sound(psg);
161 event->set_context_sound(drec);
162 event->set_context_sound(fdc->get_context_noise_seek());
163 event->set_context_sound(fdc->get_context_noise_head_down());
164 event->set_context_sound(fdc->get_context_noise_head_up());
165 event->set_context_sound(drec->get_context_noise_play());
166 event->set_context_sound(drec->get_context_noise_stop());
167 event->set_context_sound(drec->get_context_noise_fast());
169 drec->set_context_ear(pio, SIG_I8255_PORT_B, 0x02);
170 crtc->set_context_vblank(display, SIG_DISPLAY_VBLANK, 1);
171 crtc->set_context_disp(display, SIG_DISPLAY_DISP, 1);
172 crtc->set_context_vblank(pio, SIG_I8255_PORT_B, 0x80);
173 crtc->set_context_vsync(pio, SIG_I8255_PORT_B, 0x04);
174 pio->set_context_port_a(printer, SIG_PRINTER_DATA, 0xff, 0);
175 pio->set_context_port_c(drec, SIG_DATAREC_MIC, 0x01, 0);
176 pio->set_context_port_c(display, SIG_DISPLAY_COLUMN40, 0x40, 0);
177 pio->set_context_port_c(iobus, SIG_IOBUS_MODE, 0x60, 0);
178 pio->set_context_port_c(printer, SIG_PRINTER_STROBE, 0x80, 0);
179 #ifdef _X1TURBO_FEATURE
180 fdc->set_context_drq(dma, SIG_Z80DMA_READY, 1);
182 ctc->set_context_zc0(ctc, SIG_Z80CTC_TRIG_3, 1);
183 ctc->set_context_zc1(sio, SIG_Z80SIO_TX_CLK_CH0, 1);
184 ctc->set_context_zc1(sio, SIG_Z80SIO_RX_CLK_CH0, 1);
185 ctc->set_context_zc2(sio, SIG_Z80SIO_TX_CLK_CH1, 1);
186 ctc->set_context_zc2(sio, SIG_Z80SIO_RX_CLK_CH1, 1);
187 ctc->set_constant_clock(1, CPU_CLOCKS >> 1);
188 ctc->set_constant_clock(2, CPU_CLOCKS >> 1);
189 sio->set_context_rts(1, mouse, SIG_MOUSE_RTS, 1);
190 // sio->set_tx_clock(0, 9600 * 16); // 9600 baud for RS-232C
191 // sio->set_rx_clock(0, 9600 * 16); // clock is from Z-80CTC ch1 (2MHz/13)
192 // sio->set_tx_clock(1, 4800 * 16); // 4800 baud for mouse
193 // sio->set_rx_clock(1, 4800 * 16); // clock is from Z-80CTC ch2 (2MHz/26)
195 if(sound_type >= 1) {
196 ctc1->set_context_zc0(ctc1, SIG_Z80CTC_TRIG_3, 1);
197 // ctc1->set_constant_clock(1, CPU_CLOCKS >> 1);
198 // ctc1->set_constant_clock(2, CPU_CLOCKS >> 1);
200 if(sound_type == 2) {
201 ctc2->set_context_zc0(ctc2, SIG_Z80CTC_TRIG_3, 1);
202 // ctc2->set_constant_clock(1, CPU_CLOCKS >> 1);
203 // ctc2->set_constant_clock(2, CPU_CLOCKS >> 1);
205 if(config.printer_type == 0) {
206 PRNFILE *prnfile = (PRNFILE *)printer;
207 prnfile->set_context_busy(pio, SIG_I8255_PORT_B, 0x08);
208 } else if(config.printer_type == 1) {
209 MZ1P17 *mz1p17 = (MZ1P17 *)printer;
210 mz1p17->mode = MZ1P17_MODE_X1;
211 mz1p17->set_context_busy(pio, SIG_I8255_PORT_B, 0x08);
212 // } else if(config.printer_type == 2) {
213 // PCPR201 *pcpr201 = (PCPR201 *)printer;
214 // pcpr201->set_context_busy(pio, SIG_I8255_PORT_B, 0x08);
216 #ifdef _X1TURBO_FEATURE
217 dma->set_context_memory(memory);
218 dma->set_context_io(iobus);
221 #ifdef _X1TURBO_FEATURE
222 display->set_context_cpu(cpu);
224 display->set_context_crtc(crtc);
225 display->set_vram_ptr(iobus->get_vram());
226 display->set_regs_ptr(crtc->get_regs());
227 floppy->set_context_fdc(fdc);
228 iobus->set_context_cpu(cpu);
229 iobus->set_context_display(display);
230 iobus->set_context_io(io);
231 joy->set_context_psg(psg);
232 #ifdef _X1TURBO_FEATURE
233 memory->set_context_pio(pio);
235 mouse->set_context_sio(sio);
238 drec->set_context_remote(psub, SIG_PSUB_TAPE_REMOTE, 1);
239 drec->set_context_end(psub, SIG_PSUB_TAPE_END, 1);
240 psub->set_context_pio(pio);
241 psub->set_context_drec(drec);
244 cpu_sub->set_context_mem(new MCS48MEM(this, emu));
245 cpu_sub->set_context_io(sub);
247 cpu_sub->set_context_debugger(new DEBUGGER(this, emu));
249 drec->set_context_end(sub, SIG_SUB_TAPE_END, 1);
250 drec->set_context_apss(sub, SIG_SUB_TAPE_APSS, 1);
251 pio_sub->set_context_port_c(sub, SIG_SUB_PIO_PORT_C, 0x80, 0);
252 // pc1:break -> pb0 of 8255(main)
253 pio_sub->set_context_port_c(pio, SIG_I8255_PORT_B, 0x02, -1);
254 // pc5:ibf -> pb6 of 8255(main)
255 pio_sub->set_context_port_c(pio, SIG_I8255_PORT_B, 0x20, 1);
256 // pc7:obf -> pb5 of 8255(main)
257 pio_sub->set_context_port_c(pio, SIG_I8255_PORT_B, 0x80, -2);
258 // pc7:obf -> pb7 of 8255(sub)
259 pio_sub->set_context_port_c(pio_sub, SIG_I8255_PORT_B, 0x80, 0);
261 sub->set_context_pio(pio_sub);
262 sub->set_context_rtc(rtc_sub);
263 sub->set_context_drec(drec);
266 cpu_kbd->set_context_mem(new MCS48MEM(this, emu));
267 cpu_kbd->set_context_io(kbd);
269 cpu_kbd->set_context_debugger(new DEBUGGER(this, emu));
271 kbd->set_context_cpu(cpu_sub);
275 cpu->set_context_mem(memory);
276 cpu->set_context_io(iobus);
277 #if defined(_X1TURBO_FEATURE) && defined(SINGLE_MODE_DMA)
278 cpu->set_context_dma(dma);
281 cpu->set_context_debugger(new DEBUGGER(this, emu));
284 // z80 family daisy chain
285 DEVICE* parent_dev = NULL;
288 #define Z80_DAISY_CHAIN(dev) { \
289 if(parent_dev == NULL) { \
290 cpu->set_context_intr(dev); \
292 parent_dev->set_context_child(dev); \
294 dev->set_context_intr(cpu, level++); \
297 #ifndef _X1TURBO_FEATURE
298 Z80_DAISY_CHAIN(sio); // CZ-8BM2
299 Z80_DAISY_CHAIN(ctc);
301 if(sound_type >= 1) {
302 Z80_DAISY_CHAIN(ctc1);
304 if(sound_type == 2) {
305 Z80_DAISY_CHAIN(ctc2);
307 #ifdef _X1TURBO_FEATURE
308 Z80_DAISY_CHAIN(sio);
309 Z80_DAISY_CHAIN(dma);
310 Z80_DAISY_CHAIN(ctc);
313 Z80_DAISY_CHAIN(psub);
315 Z80_DAISY_CHAIN(sub);
319 if(sound_type >= 1) {
320 io->set_iomap_single_w(0x700, opm1);
321 io->set_iovalue_single_r(0x700, 0x00);
322 io->set_iomap_single_rw(0x701, opm1);
324 io->set_flipflop_single_rw(0x704, 0x00);
326 io->set_iomap_range_rw(0x704, 0x707, ctc1);
329 if(sound_type == 2) {
330 io->set_iomap_single_w(0x708, opm2);
331 io->set_iovalue_single_r(0x708, 0x00);
332 io->set_iomap_single_rw(0x709, opm2);
333 io->set_iomap_range_rw(0x70c, 0x70f, ctc2);
335 #ifdef _X1TURBO_FEATURE
336 io->set_iomap_single_rw(0xb00, memory);
338 io->set_iomap_range_rw(0xd00, 0xd03, emm);
339 io->set_iomap_range_r(0xe80, 0xe81, display);
340 io->set_iomap_range_w(0xe80, 0xe82, display);
341 io->set_iomap_range_rw(0xff8, 0xffb, fdc);
342 io->set_iomap_single_w(0xffc, floppy);
343 #ifdef _X1TURBO_FEATURE
344 io->set_iomap_range_r(0xffc, 0xfff, floppy);
346 io->set_iomap_range_rw(0x1000, 0x17ff, display);
347 for(int i = 0x1800; i <= 0x18ff; i += 0x10) {
348 io->set_iomap_range_rw(i, i + 1, crtc);
351 io->set_iomap_range_rw(0x1900, 0x19ff, psub);
353 io->set_iomap_range_rw(0x1900, 0x19ff, sub);
355 for(int i = 0x1a00; i <= 0x1aff; i += 4) {
356 io->set_iomap_range_rw(i, i + 3, pio);
358 for(int i = 0x1b00; i <= 0x1bff; i++) {
359 io->set_iomap_alias_rw(i, psg, 1);
361 for(int i = 0x1c00; i <= 0x1cff; i++) {
362 io->set_iomap_alias_w(i, psg, 0);
364 io->set_iomap_range_r(0x1e00, 0x1eff, memory);
365 io->set_iomap_range_w(0x1d00, 0x1eff, memory);
366 #ifdef _X1TURBO_FEATURE
367 io->set_iomap_range_rw(0x1f80, 0x1f8f, dma);
368 io->set_iomap_range_rw(0x1f90, 0x1f93, sio);
369 io->set_iomap_range_rw(0x1fa0, 0x1fa3, ctc);
371 io->set_iomap_single_rw(0x1fb0, display);
372 io->set_iomap_range_rw(0x1fb9, 0x1fc5, display);
373 io->set_iomap_single_rw(0x1fd0, display);
374 io->set_iomap_single_rw(0x1fe0, display);
376 io->set_iomap_single_w(0x1fd0, display);
377 io->set_iomap_single_w(0x1fe0, display);
380 // io->set_iovalue_single_r(0x1ff0, 0x00);
383 io->set_iomap_range_rw(0x1f98, 0x1f9b, sio); // CZ-8BM2
384 io->set_iomap_range_rw(0x1fa8, 0x1fab, ctc);
386 io->set_iomap_range_rw(0x2000, 0x3fff, display); // tvram
390 pceevent = new EVENT(this, emu);
391 pceevent->set_frames_per_sec(PCE_FRAMES_PER_SEC);
392 pceevent->set_lines_per_frame(PCE_LINES_PER_FRAME);
393 pceevent->set_device_name(_T("EVENT (PC-ENGINE)"));
394 pcecpu = new HUC6280(this, emu);
395 pcecpu->set_device_name(_T("HuC6820 CPU (PC-ENGINE)"));
396 pcecpu->set_context_event_manager(pceevent);
397 pce = new PCE(this, emu);
398 pce->set_device_name(_T("SUB SYSTEM (PC-ENGINE)"));
399 pce->set_context_event_manager(pceevent);
401 pceevent->set_context_cpu(pcecpu, PCE_CPU_CLOCKS);
402 pceevent->set_context_sound(pce);
404 pcecpu->set_context_mem(pce);
405 pcecpu->set_context_io(pce);
407 pcecpu->set_context_debugger(new DEBUGGER(this, emu));
409 pce->set_context_cpu(pcecpu);
412 // initialize all devices
413 for(DEVICE* device = first_device; device; device = device->next_device) {
414 device->initialize();
416 if(!pseudo_sub_cpu) {
417 // load rom images after cpustate is allocated
418 cpu_sub->load_rom_image(create_local_path(SUB_ROM_FILE_NAME));
419 cpu_kbd->load_rom_image(create_local_path(KBD_ROM_FILE_NAME));
421 // patch to set the current year
422 uint8_t *rom = cpu_sub->get_rom_ptr();
423 sub->rom_crc32 = get_crc32(rom, 0x800); // 2KB
424 if(rom[0x23] == 0xb9 && rom[0x24] == 0x35 && rom[0x25] == 0xb1) {
425 //dll_cur_time_t cur_time;
427 get_host_time(&cur_time);
428 rom[0x26] = TO_BCD(cur_time.year);
431 for(int i = 0; i < MAX_DRIVE; i++) {
432 //#ifdef _X1TURBO_FEATURE
433 // fdc->set_drive_type(i, DRIVE_TYPE_2DD);
435 fdc->set_drive_type(i, DRIVE_TYPE_2D);
437 // fdc->set_drive_rpm(i, 300);
438 // fdc->set_drive_mfm(i, true);
444 // delete all devices
445 for(DEVICE* device = first_device; device;) {
446 DEVICE *next_device = device->next_device;
449 device = next_device;
453 DEVICE* VM::get_device(int id)
455 for(DEVICE* device = first_device; device; device = device->next_device) {
456 if(device->this_device_id == id) {
463 // ----------------------------------------------------------------------------
464 // drive virtual machine
465 // ----------------------------------------------------------------------------
470 for(DEVICE* device = first_device; device; device = device->next_device) {
473 pio->write_signal(SIG_I8255_PORT_B, 0x00, 0x08); // busy = low
474 psg->set_reg(0x2e, 0); // set prescaler
477 void VM::special_reset()
480 cpu->write_signal(SIG_CPU_NMI, 1, 1);
487 if(pce->is_cart_inserted()) {
493 double VM::get_frame_rate()
496 if(pce->is_cart_inserted()) {
497 return pceevent->get_frame_rate();
500 return event->get_frame_rate();
503 // ----------------------------------------------------------------------------
505 // ----------------------------------------------------------------------------
508 DEVICE *VM::get_cpu(int index)
512 } else if(index == 1) {
514 } else if(index == 2) {
517 } else if(index == 3 && pce->is_cart_inserted()) {
525 // ----------------------------------------------------------------------------
527 // ----------------------------------------------------------------------------
529 void VM::draw_screen()
531 display->draw_screen();
533 if(pce->is_cart_inserted()) {
539 // ----------------------------------------------------------------------------
541 // ----------------------------------------------------------------------------
543 void VM::initialize_sound(int rate, int samples)
545 // init sound manager
546 event->initialize_sound(rate, samples);
548 pceevent->initialize_sound(rate, samples);
552 if(sound_type >= 1) {
553 opm1->initialize_sound(rate, 4000000, samples, 0);
555 if(sound_type == 2) {
556 opm2->initialize_sound(rate, 4000000, samples, 0);
558 psg->initialize_sound(rate, 2000000, samples, 0, 0);
560 pce->initialize_sound(rate);
564 uint16_t* VM::create_sound(int* extra_frames)
567 if(pce->is_cart_inserted()) {
568 uint16_t* buffer = pceevent->create_sound(extra_frames);
569 for(int i = 0; i < *extra_frames; i++) {
575 return event->create_sound(extra_frames);
578 int VM::get_sound_buffer_ptr()
581 if(pce->is_cart_inserted()) {
582 return pceevent->get_sound_buffer_ptr();
585 return event->get_sound_buffer_ptr();
588 #ifdef USE_SOUND_VOLUME
589 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
592 psg->set_volume(1, decibel_l, decibel_r);
594 if(sound_type >= 1) {
595 opm1->set_volume(0, decibel_l, decibel_r);
598 if(sound_type >= 2) {
599 opm2->set_volume(0, decibel_l, decibel_r);
602 drec->set_volume(0, decibel_l, decibel_r);
604 fdc->get_context_noise_seek()->set_volume(0, decibel_l, decibel_r);
605 fdc->get_context_noise_head_down()->set_volume(0, decibel_l, decibel_r);
606 fdc->get_context_noise_head_up()->set_volume(0, decibel_l, decibel_r);
608 drec->get_context_noise_play()->set_volume(0, decibel_l, decibel_r);
609 drec->get_context_noise_stop()->set_volume(0, decibel_l, decibel_r);
610 drec->get_context_noise_fast()->set_volume(0, decibel_l, decibel_r);
613 pce->set_volume(0, decibel_l, decibel_r);
619 // ----------------------------------------------------------------------------
621 // ----------------------------------------------------------------------------
623 void VM::key_down(int code, bool repeat)
626 if(!repeat && !pce->is_cart_inserted()) {
631 psub->key_down(code, false);
633 kbd->key_down(code, false);
638 void VM::key_up(int code)
641 if(!pce->is_cart_inserted()) {
653 bool VM::get_caps_locked()
656 if(!pce->is_cart_inserted()) {
659 return psub->get_caps_locked();
661 return kbd->get_caps_locked();
669 bool VM::get_kana_locked()
672 if(!pce->is_cart_inserted()) {
675 return psub->get_kana_locked();
677 return kbd->get_kana_locked();
685 // ----------------------------------------------------------------------------
687 // ----------------------------------------------------------------------------
689 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
691 fdc->open_disk(drv, file_path, bank);
694 void VM::close_floppy_disk(int drv)
696 fdc->close_disk(drv);
699 bool VM::is_floppy_disk_inserted(int drv)
701 return fdc->is_disk_inserted(drv);
704 void VM::is_floppy_disk_protected(int drv, bool value)
706 fdc->is_disk_protected(drv, value);
709 bool VM::is_floppy_disk_protected(int drv)
711 return fdc->is_disk_protected(drv);
714 uint32_t VM::is_floppy_disk_accessed()
716 return fdc->read_signal(0);
719 void VM::play_tape(int drv, const _TCHAR* file_path)
721 bool value = drec->play_tape(file_path);
724 psub->play_tape(value);
727 sub->play_tape(value);
731 void VM::rec_tape(int drv, const _TCHAR* file_path)
733 bool value = drec->rec_tape(file_path);
736 psub->rec_tape(value);
739 sub->rec_tape(value);
743 void VM::close_tape(int drv)
755 bool VM::is_tape_inserted(int drv)
757 return drec->is_tape_inserted();
760 bool VM::is_tape_playing(int drv)
762 return drec->is_tape_playing();
765 bool VM::is_tape_recording(int drv)
767 return drec->is_tape_recording();
770 int VM::get_tape_position(int drv)
772 return drec->get_tape_position();
775 const _TCHAR* VM::get_tape_message(int drv)
777 return drec->get_message();
780 void VM::push_play(int drv)
783 drec->set_remote(true);
786 void VM::push_stop(int drv)
788 drec->set_remote(false);
791 void VM::push_fast_forward(int drv)
794 drec->set_remote(true);
797 void VM::push_fast_rewind(int drv)
799 drec->set_ff_rew(-1);
800 drec->set_remote(true);
803 void VM::push_apss_forward(int drv)
808 void VM::push_apss_rewind(int drv)
813 bool VM::is_frame_skippable()
816 if(pce->is_cart_inserted()) {
817 return pceevent->is_frame_skippable();
820 return event->is_frame_skippable();
824 void VM::open_cart(int drv, const _TCHAR* file_path)
827 pce->open_cart(file_path);
833 void VM::close_cart(int drv)
842 bool VM::is_cart_inserted(int drv)
845 return pce->is_cart_inserted();
852 void VM::update_config()
854 for(DEVICE* device = first_device; device; device = device->next_device) {
855 device->update_config();
857 #ifdef _X1TURBO_FEATURE
862 #ifdef _X1TURBO_FEATURE
863 void VM::update_dipswitch()
865 // bit0 0=High 1=Standard
866 // bit1-3 000=5"2D 001=5"2DD 010=5"2HD
867 io->set_iovalue_single_r(0x1ff0, (config.monitor_type & 1) | ((config.drive_type & 7) << 1));
871 #define STATE_VERSION 9
873 void VM::save_state(FILEIO* state_fio)
875 state_fio->FputUint32(STATE_VERSION);
877 for(DEVICE* device = first_device; device; device = device->next_device) {
878 const char *name = typeid(*device).name() + 6; // skip "class "
880 state_fio->FputInt32(strlen(name));
881 state_fio->Fwrite(name, strlen(name), 1);
882 device->save_state(state_fio);
884 state_fio->FputBool(pseudo_sub_cpu);
885 state_fio->FputInt32(sound_type);
888 bool VM::load_state(FILEIO* state_fio)
890 if(state_fio->FgetUint32() != STATE_VERSION) {
893 for(DEVICE* device = first_device; device; device = device->next_device) {
894 const char *name = typeid(*device).name() + 6; // skip "class "
896 if(!(state_fio->FgetInt32() == strlen(name) && state_fio->Fcompare(name, strlen(name)))) {
899 if(!device->load_state(state_fio)) {
903 pseudo_sub_cpu = state_fio->FgetBool();
904 sound_type = state_fio->FgetInt32();
906 #ifdef _X1TURBO_FEATURE