2 SHARP X1 Emulator 'eX1'
3 SHARP X1twin Emulator 'eX1twin'
4 SHARP X1turbo Emulator 'eX1turbo'
5 SHARP X1turboZ Emulator 'eX1turboZ'
7 Author : Takeda.Toshiya
14 #include "../../emu.h"
15 #include "../device.h"
18 #include "../datarec.h"
20 #include "../harddisk.h"
21 #include "../hd46505.h"
24 #include "../mb8877.h"
25 #include "../mz1p17.h"
27 //#include "../pcpr201.h"
28 #include "../pcm8bit.h"
29 #include "../prnfile.h"
30 #include "../scsi_hdd.h"
31 #include "../scsi_host.h"
32 #include "../ym2151.h"
33 //#include "../ym2203.h"
34 #include "../ay_3_891x.h"
36 #include "../z80ctc.h"
37 #include "../z80sio.h"
38 #ifdef _X1TURBO_FEATURE
39 #include "../z80dma.h"
43 #include "../debugger.h"
58 #include "../upd1990a.h"
63 #include "../huc6280.h"
64 #include "../pcengine/pce.h"
67 DLL_PREFIX_I struct cur_time_s cur_time;
85 // ----------------------------------------------------------------------------
87 // ----------------------------------------------------------------------------
89 VM::VM(EMU_TEMPLATE* parent_emu) : VM_TEMPLATE(parent_emu)
91 pseudo_sub_cpu = !(FILEIO::IsFileExisting(create_local_path(SUB_ROM_FILE_NAME)) && FILEIO::IsFileExisting(create_local_path(KBD_ROM_FILE_NAME)));
93 sound_type = config.sound_type;
96 first_device = last_device = NULL;
97 dummy = new DEVICE(this, emu); // must be 1st device
98 event = new EVENT(this, emu); // must be 2nd device
99 dummy->set_device_name(_T("1st Dummy"));
101 drec = new DATAREC(this, emu);
102 drec->set_context_noise_play(new NOISE(this, emu));
103 drec->set_context_noise_stop(new NOISE(this, emu));
104 drec->set_context_noise_fast(new NOISE(this, emu));
105 crtc = new HD46505(this, emu);
106 pio = new I8255(this, emu);
107 io = new IO(this, emu);
109 fdc = new MB8877(this, emu);
110 fdc->set_context_noise_seek(new NOISE(this, emu));
111 fdc->set_context_noise_head_down(new NOISE(this, emu));
112 fdc->set_context_noise_head_up(new NOISE(this, emu));
113 sasi_host = new SCSI_HOST(this, emu);
114 for(int i = 0; i < array_length(sasi_hdd); i++) {
115 sasi_hdd[i] = new SASI_HDD(this, emu);
116 sasi_hdd[i]->set_device_name(_T("SASI Hard Disk Drive #%d"), i + 1);
117 sasi_hdd[i]->scsi_id = i;
118 // sasi_hdd[i]->bytes_per_sec = 32 * 1024; // 32KB/s
119 sasi_hdd[i]->bytes_per_sec = 3600 / 60 * 256 * 33; // 3600rpm, 256bytes x 33sectors in track (thanks Mr.Sato)
120 sasi_hdd[i]->data_req_delay = 0; // thanks Mr.Sato
121 sasi_hdd[i]->set_context_interface(sasi_host);
122 sasi_host->set_context_target(sasi_hdd[i]);
124 for(int drv = 0; drv < USE_HARD_DISK; drv++) {
125 sasi_hdd[drv >> 1]->set_disk_handler(drv & 1, new HARDDISK(emu));
127 psg = new AY_3_891X(this, emu);
129 psg->set_context_debugger(new DEBUGGER(this, emu));
131 cpu = new Z80(this, emu);
132 ctc = new Z80CTC(this, emu);
133 sio = new Z80SIO(this, emu);
134 if(sound_type >= 1) {
135 opm1 = new YM2151(this, emu);
136 opm1->set_device_name(_T("YM2151 OPM (CZ-8BS1 #1)"));
138 opm1->set_context_debugger(new DEBUGGER(this, emu));
140 ctc1 = new Z80CTC(this, emu);
141 ctc1->set_device_name(_T("Z80 CTC (CZ-8BS1 #1)"));
143 if(sound_type == 2) {
144 opm2 = new YM2151(this, emu);
145 opm2->set_device_name(_T("YM2151 OPM (CZ-8BS1 #2)"));
147 opm2->set_context_debugger(new DEBUGGER(this, emu));
149 ctc2 = new Z80CTC(this, emu);
150 ctc2->set_device_name(_T("Z80 CTC (CZ-8BS1 #2)"));
152 if(config.printer_type == 0) {
153 printer = new PRNFILE(this, emu);
154 } else if(config.printer_type == 1) {
155 printer = new MZ1P17(this, emu);
156 // } else if(config.printer_type == 2) {
157 // printer = new PCPR201(this, emu);
158 } else if(config.printer_type == 3) {
159 printer = new PCM8BIT(this, emu);
163 #ifdef _X1TURBO_FEATURE
164 dma = new Z80DMA(this, emu);
166 dma->set_context_debugger(new DEBUGGER(this, emu));
170 display = new DISPLAY(this, emu);
171 emm = new EMM(this, emu);
172 floppy = new FLOPPY(this, emu);
173 iobus = new IOBUS(this, emu);
174 joy = new JOYSTICK(this, emu);
175 memory = new MEMORY(this, emu);
176 mouse = new MOUSE(this, emu);
177 sasi = new SASI(this, emu);
178 cz8rb = new CZ8RB(this, emu);
181 psub = new PSUB(this, emu);
186 cpu_sub = new MCS48(this, emu);
187 cpu_sub->set_device_name(_T("MCS48 MCU (Sub)"));
188 pio_sub = new I8255(this, emu);
189 pio_sub->set_device_name(_T("i8255 PIO (Sub)"));
190 rtc_sub = new UPD1990A(this, emu);
191 rtc_sub->set_device_name(_T("uPD1990A RTC (Sub)"));
192 sub = new SUB(this, emu);
195 cpu_kbd = new MCS48(this, emu);
196 cpu_kbd->set_device_name(_T("MCS48 MCU (Keyboard)"));
197 kbd = new KEYBOARD(this, emu);
201 event->set_context_cpu(cpu);
202 if(!pseudo_sub_cpu) {
203 event->set_context_cpu(cpu_sub, 6000000);
204 event->set_context_cpu(cpu_kbd, 6000000);
206 if(sound_type >= 1) {
207 event->set_context_sound(opm1);
209 if(sound_type == 2) {
210 event->set_context_sound(opm2);
212 if(config.printer_type == 3) {
213 event->set_context_sound(printer);
215 event->set_context_sound(psg);
216 event->set_context_sound(drec);
217 event->set_context_sound(fdc->get_context_noise_seek());
218 event->set_context_sound(fdc->get_context_noise_head_down());
219 event->set_context_sound(fdc->get_context_noise_head_up());
220 event->set_context_sound(drec->get_context_noise_play());
221 event->set_context_sound(drec->get_context_noise_stop());
222 event->set_context_sound(drec->get_context_noise_fast());
224 drec->set_context_ear(pio, SIG_I8255_PORT_B, 0x02);
225 crtc->set_context_vblank(display, SIG_DISPLAY_VBLANK, 1);
226 crtc->set_context_disp(display, SIG_DISPLAY_DISP, 1);
227 crtc->set_context_vblank(pio, SIG_I8255_PORT_B, 0x80);
228 crtc->set_context_vsync(pio, SIG_I8255_PORT_B, 0x04);
229 pio->set_context_port_a(printer, SIG_PRINTER_DATA, 0xff, 0);
230 pio->set_context_port_c(drec, SIG_DATAREC_MIC, 0x01, 0);
231 pio->set_context_port_c(display, SIG_DISPLAY_COLUMN40, 0x40, 0);
232 pio->set_context_port_c(iobus, SIG_IOBUS_MODE, 0x60, 0);
233 pio->set_context_port_c(printer, SIG_PRINTER_STROBE, 0x80, 0);
234 #ifdef _X1TURBO_FEATURE
235 fdc->set_context_drq(dma, SIG_Z80DMA_READY, 1);
237 sasi_host->set_context_irq(sasi, SIG_SASI_IRQ, 1);
238 sasi_host->set_context_drq(sasi, SIG_SASI_DRQ, 1);
239 ctc->set_context_zc0(ctc, SIG_Z80CTC_TRIG_3, 1);
240 ctc->set_context_zc1(sio, SIG_Z80SIO_TX_CLK_CH0, 1);
241 ctc->set_context_zc1(sio, SIG_Z80SIO_RX_CLK_CH0, 1);
242 ctc->set_context_zc2(sio, SIG_Z80SIO_TX_CLK_CH1, 1);
243 ctc->set_context_zc2(sio, SIG_Z80SIO_RX_CLK_CH1, 1);
244 ctc->set_constant_clock(1, CPU_CLOCKS >> 1);
245 ctc->set_constant_clock(2, CPU_CLOCKS >> 1);
246 sio->set_context_rts(1, mouse, SIG_MOUSE_RTS, 1);
247 // sio->set_tx_clock(0, 9600 * 16); // 9600 baud for RS-232C
248 // sio->set_rx_clock(0, 9600 * 16); // clock is from Z-80CTC ch1 (2MHz/13)
249 // sio->set_tx_clock(1, 4800 * 16); // 4800 baud for mouse
250 // sio->set_rx_clock(1, 4800 * 16); // clock is from Z-80CTC ch2 (2MHz/26)
252 if(sound_type >= 1) {
253 ctc1->set_context_zc0(ctc1, SIG_Z80CTC_TRIG_3, 1);
254 // ctc1->set_constant_clock(1, CPU_CLOCKS >> 1);
255 // ctc1->set_constant_clock(2, CPU_CLOCKS >> 1);
257 if(sound_type == 2) {
258 ctc2->set_context_zc0(ctc2, SIG_Z80CTC_TRIG_3, 1);
259 // ctc2->set_constant_clock(1, CPU_CLOCKS >> 1);
260 // ctc2->set_constant_clock(2, CPU_CLOCKS >> 1);
262 if(config.printer_type == 0) {
263 PRNFILE *prnfile = (PRNFILE *)printer;
264 prnfile->set_context_busy(pio, SIG_I8255_PORT_B, 0x08);
265 } else if(config.printer_type == 1) {
266 MZ1P17 *mz1p17 = (MZ1P17 *)printer;
267 mz1p17->mode = MZ1P17_MODE_X1;
268 mz1p17->set_context_busy(pio, SIG_I8255_PORT_B, 0x08);
269 // } else if(config.printer_type == 2) {
270 // PCPR201 *pcpr201 = (PCPR201 *)printer;
271 // pcpr201->set_context_busy(pio, SIG_I8255_PORT_B, 0x08);
273 #ifdef _X1TURBO_FEATURE
274 dma->set_context_memory(memory);
275 dma->set_context_io(iobus);
278 #ifdef _X1TURBO_FEATURE
279 display->set_context_cpu(cpu);
281 display->set_context_crtc(crtc);
282 display->set_vram_ptr(iobus->get_vram());
283 display->set_regs_ptr(crtc->get_regs());
284 floppy->set_context_fdc(fdc);
285 iobus->set_context_cpu(cpu);
286 iobus->set_context_display(display);
287 iobus->set_context_io(io);
289 iobus->set_context_debugger(new DEBUGGER(this, emu));
291 joy->set_context_psg(psg);
292 #ifdef _X1TURBO_FEATURE
293 memory->set_context_pio(pio);
295 mouse->set_context_sio(sio);
296 sasi->set_context_host(sasi_host);
297 #ifdef _X1TURBO_FEATURE
298 sasi->set_context_dma(dma);
302 drec->set_context_remote(psub, SIG_PSUB_TAPE_REMOTE, 1);
303 drec->set_context_end(psub, SIG_PSUB_TAPE_END, 1);
304 psub->set_context_pio(pio);
305 psub->set_context_drec(drec);
308 cpu_sub->set_context_mem(new MCS48MEM(this, emu));
309 cpu_sub->set_context_io(sub);
311 cpu_sub->set_context_debugger(new DEBUGGER(this, emu));
313 drec->set_context_end(sub, SIG_SUB_TAPE_END, 1);
314 drec->set_context_apss(sub, SIG_SUB_TAPE_APSS, 1);
315 pio_sub->set_context_port_c(sub, SIG_SUB_PIO_PORT_C, 0x80, 0);
316 // pc1:break -> pb0 of 8255(main)
317 pio_sub->set_context_port_c(pio, SIG_I8255_PORT_B, 0x02, -1);
318 // pc5:ibf -> pb6 of 8255(main)
319 pio_sub->set_context_port_c(pio, SIG_I8255_PORT_B, 0x20, 1);
320 // pc7:obf -> pb5 of 8255(main)
321 pio_sub->set_context_port_c(pio, SIG_I8255_PORT_B, 0x80, -2);
322 // pc7:obf -> pb7 of 8255(sub)
323 pio_sub->set_context_port_c(pio_sub, SIG_I8255_PORT_B, 0x80, 0);
325 sub->set_context_pio(pio_sub);
326 sub->set_context_rtc(rtc_sub);
327 sub->set_context_drec(drec);
330 cpu_kbd->set_context_mem(new MCS48MEM(this, emu));
331 cpu_kbd->set_context_io(kbd);
333 cpu_kbd->set_context_debugger(new DEBUGGER(this, emu));
335 kbd->set_context_cpu(cpu_sub);
339 cpu->set_context_mem(memory);
340 cpu->set_context_io(iobus);
341 #if defined(_X1TURBO_FEATURE) && defined(SINGLE_MODE_DMA)
342 cpu->set_context_dma(dma);
345 cpu->set_context_debugger(new DEBUGGER(this, emu));
348 // z80 family daisy chain
349 DEVICE* parent_dev = NULL;
352 #define Z80_DAISY_CHAIN(dev) { \
353 if(parent_dev == NULL) { \
354 cpu->set_context_intr(dev); \
356 parent_dev->set_context_child(dev); \
358 dev->set_context_intr(cpu, level++); \
361 #ifndef _X1TURBO_FEATURE
362 Z80_DAISY_CHAIN(sio); // CZ-8BM2
363 Z80_DAISY_CHAIN(ctc);
365 if(sound_type >= 1) {
366 Z80_DAISY_CHAIN(ctc1);
368 if(sound_type == 2) {
369 Z80_DAISY_CHAIN(ctc2);
371 #ifdef _X1TURBO_FEATURE
372 Z80_DAISY_CHAIN(sio);
373 Z80_DAISY_CHAIN(dma);
374 Z80_DAISY_CHAIN(ctc);
377 Z80_DAISY_CHAIN(psub);
379 Z80_DAISY_CHAIN(sub);
383 if(sound_type >= 1) {
384 io->set_iomap_single_w(0x700, opm1);
385 io->set_iovalue_single_r(0x700, 0x00);
386 io->set_iomap_single_rw(0x701, opm1);
388 io->set_flipflop_single_rw(0x704, 0x00);
390 io->set_iomap_range_rw(0x704, 0x707, ctc1);
393 if(sound_type == 2) {
394 io->set_iomap_single_w(0x708, opm2);
395 io->set_iovalue_single_r(0x708, 0x00);
396 io->set_iomap_single_rw(0x709, opm2);
397 io->set_iomap_range_rw(0x70c, 0x70f, ctc2);
399 #ifdef _X1TURBO_FEATURE
400 io->set_iomap_single_rw(0xb00, memory);
402 io->set_iomap_range_rw(0xd00, 0xd03, emm);
403 io->set_iomap_range_rw(0xe00, 0xe03, cz8rb);
404 io->set_iomap_range_r(0xe80, 0xe81, display);
405 io->set_iomap_range_w(0xe80, 0xe82, display);
406 io->set_iomap_range_rw(0xfd0, 0xfd3, sasi);
407 io->set_iomap_range_rw(0xff8, 0xffb, fdc);
408 io->set_iomap_single_w(0xffc, floppy);
409 #ifdef _X1TURBO_FEATURE
410 io->set_iomap_range_r(0xffc, 0xfff, floppy);
412 io->set_iomap_range_rw(0x1000, 0x17ff, display);
413 for(int i = 0x1800; i <= 0x18ff; i += 0x10) {
414 io->set_iomap_range_rw(i, i + 1, crtc);
417 io->set_iomap_range_rw(0x1900, 0x19ff, psub);
419 io->set_iomap_range_rw(0x1900, 0x19ff, sub);
421 for(int i = 0x1a00; i <= 0x1aff; i += 4) {
422 io->set_iomap_range_rw(i, i + 3, pio);
424 for(int i = 0x1b00; i <= 0x1bff; i++) {
425 io->set_iomap_alias_rw(i, psg, 1);
427 for(int i = 0x1c00; i <= 0x1cff; i++) {
428 io->set_iomap_alias_w(i, psg, 0);
430 io->set_iomap_range_r(0x1e00, 0x1eff, memory);
431 io->set_iomap_range_w(0x1d00, 0x1eff, memory);
432 #ifdef _X1TURBO_FEATURE
433 io->set_iomap_range_rw(0x1f80, 0x1f8f, dma);
434 io->set_iomap_range_rw(0x1f90, 0x1f93, sio);
435 io->set_iomap_range_rw(0x1fa0, 0x1fa3, ctc);
437 io->set_iomap_single_rw(0x1fb0, display);
438 io->set_iomap_range_rw(0x1fb9, 0x1fc5, display);
439 io->set_iomap_single_rw(0x1fd0, display);
440 io->set_iomap_single_rw(0x1fe0, display);
442 io->set_iomap_single_w(0x1fd0, display);
443 io->set_iomap_single_w(0x1fe0, display);
446 // io->set_iovalue_single_r(0x1ff0, 0x00);
449 io->set_iomap_range_rw(0x1f98, 0x1f9b, sio); // CZ-8BM2
450 io->set_iomap_range_rw(0x1fa8, 0x1fab, ctc);
452 io->set_iomap_range_rw(0x2000, 0x3fff, display); // tvram
456 pceevent = new EVENT(this, emu);
457 pceevent->set_frames_per_sec(PCE_FRAMES_PER_SEC);
458 pceevent->set_lines_per_frame(PCE_LINES_PER_FRAME);
459 pceevent->set_device_name(_T("EVENT (PC-ENGINE)"));
460 pcecpu = new HUC6280(this, emu);
461 pcecpu->set_device_name(_T("HuC6820 CPU (PC-ENGINE)"));
462 pcecpu->set_context_event_manager(pceevent);
463 pce = new PCE(this, emu);
464 pce->set_device_name(_T("SUB SYSTEM (PC-ENGINE)"));
465 pce->set_context_event_manager(pceevent);
467 pceevent->set_context_cpu(pcecpu, PCE_CPU_CLOCKS);
468 pceevent->set_context_sound(pce);
470 pcecpu->set_context_mem(pce);
471 pcecpu->set_context_io(pce);
473 pcecpu->set_context_debugger(new DEBUGGER(this, emu));
475 pce->set_context_cpu(pcecpu);
478 // initialize all devices
479 #if defined(__GIT_REPO_VERSION)
480 set_git_repo_version(__GIT_REPO_VERSION);
482 initialize_devices();
484 if(!pseudo_sub_cpu) {
485 // load rom images after cpustate is allocated
486 cpu_sub->load_rom_image(create_local_path(SUB_ROM_FILE_NAME));
487 cpu_kbd->load_rom_image(create_local_path(KBD_ROM_FILE_NAME));
489 // patch to set the current year
490 uint8_t *rom = cpu_sub->get_rom_ptr();
491 sub->rom_crc32 = get_crc32(rom, 0x800); // 2KB
492 if(rom[0x23] == 0xb9 && rom[0x24] == 0x35 && rom[0x25] == 0xb1) {
493 //dll_cur_time_t cur_time;
495 get_host_time(&cur_time);
496 rom[0x26] = TO_BCD(cur_time.year);
499 for(int drv = 0; drv < MAX_DRIVE; drv++) {
500 //#ifdef _X1TURBO_FEATURE
501 // if(config.drive_type == 2) {
502 // fdc->set_drive_type(drv, DRIVE_TYPE_2HD);
505 fdc->set_drive_type(drv, DRIVE_TYPE_2D);
506 // fdc->set_drive_rpm(drv, 300);
507 // fdc->set_drive_mfm(drv, true);
509 for(int drv = 0; drv < USE_HARD_DISK; drv++) {
510 if(!(config.last_hard_disk_path[drv][0] != _T('\0') && FILEIO::IsFileExisting(config.last_hard_disk_path[drv]))) {
511 create_local_path(config.last_hard_disk_path[drv], _MAX_PATH, _T("SASI%d.DAT"), drv);
518 // delete all devices
519 for(DEVICE* device = first_device; device;) {
520 DEVICE *next_device = device->next_device;
523 device = next_device;
527 DEVICE* VM::get_device(int id)
529 for(DEVICE* device = first_device; device; device = device->next_device) {
530 if(device->this_device_id == id) {
537 // ----------------------------------------------------------------------------
538 // drive virtual machine
539 // ----------------------------------------------------------------------------
544 for(DEVICE* device = first_device; device; device = device->next_device) {
548 // hack to force reset iei/oei
550 for(DEVICE* device = cpu; device; device = device->get_context_child()) {
554 cpu->get_context_child()->notify_intr_reti();
558 pio->write_signal(SIG_I8255_PORT_B, 0x00, 0x08); // busy = low
559 psg->set_reg(0x2e, 0); // set prescaler
562 void VM::special_reset(int num)
565 cpu->write_signal(SIG_CPU_NMI, 1, 1);
572 if(pce->is_cart_inserted()) {
578 double VM::get_frame_rate()
581 if(pce->is_cart_inserted()) {
582 return pceevent->get_frame_rate();
585 return event->get_frame_rate();
588 // ----------------------------------------------------------------------------
590 // ----------------------------------------------------------------------------
593 DEVICE *VM::get_cpu(int index)
597 } else if(index == 1) {
599 } else if(index == 2) {
602 } else if(index == 3 && pce->is_cart_inserted()) {
610 // ----------------------------------------------------------------------------
612 // ----------------------------------------------------------------------------
614 void VM::draw_screen()
616 display->draw_screen();
618 if(pce->is_cart_inserted()) {
624 // ----------------------------------------------------------------------------
626 // ----------------------------------------------------------------------------
628 void VM::initialize_sound(int rate, int samples)
630 // init sound manager
631 event->initialize_sound(rate, samples);
633 pceevent->initialize_sound(rate, samples);
637 if(sound_type >= 1) {
638 opm1->initialize_sound(rate, 4000000, samples, 0);
640 if(sound_type == 2) {
641 opm2->initialize_sound(rate, 4000000, samples, 0);
643 if(config.printer_type == 3) {
644 PCM8BIT *pcm8 = (PCM8BIT *)printer;
645 pcm8->initialize_sound(rate, 32000);
647 psg->initialize_sound(rate, 2000000, samples, 0, 0);
649 pce->initialize_sound(rate);
653 uint16_t* VM::create_sound(int* extra_frames)
656 if(pce->is_cart_inserted()) {
657 uint16_t* buffer = pceevent->create_sound(extra_frames);
658 for(int i = 0; i < *extra_frames; i++) {
664 return event->create_sound(extra_frames);
667 int VM::get_sound_buffer_ptr()
670 if(pce->is_cart_inserted()) {
671 return pceevent->get_sound_buffer_ptr();
674 return event->get_sound_buffer_ptr();
677 #ifdef USE_SOUND_VOLUME
678 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
681 psg->set_volume(1, decibel_l, decibel_r);
683 if(sound_type >= 1) {
684 opm1->set_volume(0, decibel_l, decibel_r);
687 if(sound_type >= 2) {
688 opm2->set_volume(0, decibel_l, decibel_r);
691 if(config.printer_type == 3) {
692 PCM8BIT *pcm8 = (PCM8BIT *)printer;
693 pcm8->set_volume(0, decibel_l, decibel_r);
696 drec->set_volume(0, decibel_l, decibel_r);
698 fdc->get_context_noise_seek()->set_volume(0, decibel_l, decibel_r);
699 fdc->get_context_noise_head_down()->set_volume(0, decibel_l, decibel_r);
700 fdc->get_context_noise_head_up()->set_volume(0, decibel_l, decibel_r);
702 drec->get_context_noise_play()->set_volume(0, decibel_l, decibel_r);
703 drec->get_context_noise_stop()->set_volume(0, decibel_l, decibel_r);
704 drec->get_context_noise_fast()->set_volume(0, decibel_l, decibel_r);
707 pce->set_volume(0, decibel_l, decibel_r);
713 // ----------------------------------------------------------------------------
715 // ----------------------------------------------------------------------------
717 void VM::key_down(int code, bool repeat)
720 if(!repeat && !pce->is_cart_inserted()) {
725 psub->key_down(code, false);
727 kbd->key_down(code, false);
732 void VM::key_up(int code)
735 if(!pce->is_cart_inserted()) {
747 bool VM::get_caps_locked()
750 if(!pce->is_cart_inserted()) {
753 return psub->get_caps_locked();
755 return kbd->get_caps_locked();
763 bool VM::get_kana_locked()
766 if(!pce->is_cart_inserted()) {
769 return psub->get_kana_locked();
771 return kbd->get_kana_locked();
779 // ----------------------------------------------------------------------------
781 // ----------------------------------------------------------------------------
783 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
785 fdc->open_disk(drv, file_path, bank);
787 #ifdef _X1TURBO_FEATURE
788 if(fdc->get_media_type(drv) == MEDIA_TYPE_2DD) {
789 if(fdc->get_drive_type(drv) == DRIVE_TYPE_2D) {
790 fdc->set_drive_type(drv, DRIVE_TYPE_2DD);
792 } else if(fdc->get_media_type(drv) == MEDIA_TYPE_2D) {
793 if(fdc->get_drive_type(drv) == DRIVE_TYPE_2DD) {
794 fdc->set_drive_type(drv, DRIVE_TYPE_2D);
800 void VM::close_floppy_disk(int drv)
802 fdc->close_disk(drv);
805 bool VM::is_floppy_disk_inserted(int drv)
807 return fdc->is_disk_inserted(drv);
810 void VM::is_floppy_disk_protected(int drv, bool value)
812 fdc->is_disk_protected(drv, value);
815 bool VM::is_floppy_disk_protected(int drv)
817 return fdc->is_disk_protected(drv);
820 uint32_t VM::is_floppy_disk_accessed()
822 if(floppy->get_motor_on()) {
823 int drv = fdc->read_signal(SIG_MB8877_DRIVEREG);
829 uint32_t VM::floppy_disk_indicator_color()
831 #ifdef _X1TURBO_FEATURE
832 if(floppy->get_motor_on()) {
833 int drv = fdc->read_signal(SIG_MB8877_DRIVEREG);
834 if(fdc->get_drive_type(drv) == DRIVE_TYPE_2HD) {
842 void VM::open_hard_disk(int drv, const _TCHAR* file_path)
844 if(drv < USE_HARD_DISK) {
845 sasi_hdd[drv >> 1]->open(drv & 1, file_path, 256);
849 void VM::close_hard_disk(int drv)
851 if(drv < USE_HARD_DISK) {
852 sasi_hdd[drv >> 1]->close(drv & 1);
856 bool VM::is_hard_disk_inserted(int drv)
858 if(drv < USE_HARD_DISK) {
859 return sasi_hdd[drv >> 1]->mounted(drv & 1);
864 uint32_t VM::is_hard_disk_accessed()
868 for(int drv = 0; drv < USE_HARD_DISK; drv++) {
869 if(sasi_hdd[drv >> 1]->accessed(drv & 1)) {
876 void VM::play_tape(int drv, const _TCHAR* file_path)
878 bool remote = drec->get_remote();
879 bool opened = drec->play_tape(file_path);
881 if(opened && remote) {
882 // if machine already sets remote on, start playing now
887 psub->play_tape(opened);
890 sub->play_tape(opened);
894 void VM::rec_tape(int drv, const _TCHAR* file_path)
896 bool remote = drec->get_remote();
897 bool opened = drec->rec_tape(file_path);
899 if(opened && remote) {
900 // if machine already sets remote on, start recording now
905 psub->rec_tape(opened);
908 sub->rec_tape(opened);
912 void VM::close_tape(int drv)
917 drec->set_remote(false);
926 bool VM::is_tape_inserted(int drv)
928 return drec->is_tape_inserted();
931 bool VM::is_tape_playing(int drv)
933 return drec->is_tape_playing();
936 bool VM::is_tape_recording(int drv)
938 return drec->is_tape_recording();
941 int VM::get_tape_position(int drv)
943 return drec->get_tape_position();
946 const _TCHAR* VM::get_tape_message(int drv)
948 return drec->get_message();
951 void VM::push_play(int drv)
953 drec->set_remote(false);
955 drec->set_remote(true);
958 void VM::push_stop(int drv)
960 drec->set_remote(false);
963 void VM::push_fast_forward(int drv)
965 drec->set_remote(false);
967 drec->set_remote(true);
970 void VM::push_fast_rewind(int drv)
972 drec->set_remote(false);
973 drec->set_ff_rew(-1);
974 drec->set_remote(true);
977 void VM::push_apss_forward(int drv)
982 void VM::push_apss_rewind(int drv)
987 bool VM::is_frame_skippable()
990 if(pce->is_cart_inserted()) {
991 return pceevent->is_frame_skippable();
994 return event->is_frame_skippable();
998 void VM::open_cart(int drv, const _TCHAR* file_path)
1001 pce->open_cart(file_path);
1007 void VM::close_cart(int drv)
1016 bool VM::is_cart_inserted(int drv)
1019 return pce->is_cart_inserted();
1026 void VM::update_config()
1028 for(DEVICE* device = first_device; device; device = device->next_device) {
1029 device->update_config();
1031 #ifdef _X1TURBO_FEATURE
1036 #ifdef _X1TURBO_FEATURE
1037 void VM::update_dipswitch()
1039 // bit0 0=High 1=Standard
1040 // bit1-3 000=5"2D 001=5"2DD 010=5"2HD 110=8"1S 111=SASI
1041 io->set_iovalue_single_r(0x1ff0, (config.monitor_type & 1) | ((config.drive_type & 7) << 1));
1045 double VM::get_current_usec()
1047 if(event == NULL) return 0.0;
1048 return event->get_current_usec();
1051 uint64_t VM::get_current_clock_uint64()
1053 if(event == NULL) return (uint64_t)0;
1054 return event->get_current_clock_uint64();
1057 #define STATE_VERSION 12
1059 bool VM::process_state(FILEIO* state_fio, bool loading)
1061 if(!(VM_TEMPLATE::process_state_core(state_fio, loading, STATE_VERSION))) {
1064 state_fio->StateValue(pseudo_sub_cpu);
1065 state_fio->StateValue(sound_type);
1067 #ifdef _X1TURBO_FEATURE