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 "../ym2151.h"
24 #include "../ym2203.h"
26 #include "../z80ctc.h"
27 #include "../z80sio.h"
28 #ifdef _X1TURBO_FEATURE
29 #include "../z80dma.h"
33 #include "../debugger.h"
47 #include "../upd1990a.h"
52 #include "../huc6280.h"
53 #include "../pcengine/pce.h"
56 // ----------------------------------------------------------------------------
58 // ----------------------------------------------------------------------------
60 VM::VM(EMU* parent_emu) : emu(parent_emu)
62 pseudo_sub_cpu = !(FILEIO::IsFileExists(emu->bios_path(SUB_ROM_FILE_NAME)) && FILEIO::IsFileExists(emu->bios_path(KBD_ROM_FILE_NAME)));
64 sound_device_type = config.sound_device_type;
67 first_device = last_device = NULL;
68 dummy = new DEVICE(this, emu); // must be 1st device
69 event = new EVENT(this, emu); // must be 2nd device
71 drec = new DATAREC(this, emu);
72 crtc = new HD46505(this, emu);
73 pio = new I8255(this, emu);
74 io = new IO(this, emu);
75 fdc = new MB8877(this, emu);
76 psg = new YM2203(this, emu);
77 cpu = new Z80(this, emu);
78 ctc = new Z80CTC(this, emu);
79 sio = new Z80SIO(this, emu);
80 if(sound_device_type >= 1) {
81 opm1 = new YM2151(this, emu);
82 ctc1 = new Z80CTC(this, emu);
84 if(sound_device_type == 2) {
85 opm2 = new YM2151(this, emu);
86 ctc2 = new Z80CTC(this, emu);
88 #ifdef _X1TURBO_FEATURE
89 dma = new Z80DMA(this, emu);
92 display = new DISPLAY(this, emu);
93 emm = new EMM(this, emu);
94 floppy = new FLOPPY(this, emu);
95 iobus = new IOBUS(this, emu);
96 joy = new JOYSTICK(this, emu);
97 memory = new MEMORY(this, emu);
98 mouse = new MOUSE(this, emu);
99 printer = new PRINTER(this, emu);
102 psub = new PSUB(this, emu);
107 cpu_sub = new MCS48(this, emu);
108 pio_sub = new I8255(this, emu);
109 rtc_sub = new UPD1990A(this, emu);
110 sub = new SUB(this, emu);
113 cpu_kbd = new MCS48(this, emu);
114 kbd = new KEYBOARD(this, emu);
118 event->set_context_cpu(cpu);
119 if(!pseudo_sub_cpu) {
120 event->set_context_cpu(cpu_sub, 6000000);
121 event->set_context_cpu(cpu_kbd, 6000000);
123 if(sound_device_type >= 1) {
124 event->set_context_sound(opm1);
126 if(sound_device_type == 2) {
127 event->set_context_sound(opm2);
129 event->set_context_sound(psg);
130 event->set_context_sound(drec);
132 drec->set_context_out(pio, SIG_I8255_PORT_B, 0x02);
133 crtc->set_context_vblank(display, SIG_DISPLAY_VBLANK, 1);
134 crtc->set_context_vblank(pio, SIG_I8255_PORT_B, 0x80);
135 crtc->set_context_vsync(pio, SIG_I8255_PORT_B, 0x04);
136 pio->set_context_port_a(printer, SIG_PRINTER_OUT, 0xff, 0);
137 pio->set_context_port_c(drec, SIG_DATAREC_OUT, 0x01, 0);
138 pio->set_context_port_c(display, SIG_DISPLAY_COLUMN40, 0x40, 0);
139 pio->set_context_port_c(iobus, SIG_IOBUS_MODE, 0x60, 0);
140 pio->set_context_port_c(printer, SIG_PRINTER_STB, 0x80, 0);
141 #ifdef _X1TURBO_FEATURE
142 fdc->set_context_drq(dma, SIG_Z80DMA_READY, 1);
144 ctc->set_context_zc0(ctc, SIG_Z80CTC_TRIG_3, 1);
145 ctc->set_context_zc1(sio, SIG_Z80SIO_TX_CLK_CH0, 1);
146 ctc->set_context_zc1(sio, SIG_Z80SIO_RX_CLK_CH0, 1);
147 ctc->set_context_zc2(sio, SIG_Z80SIO_TX_CLK_CH1, 1);
148 ctc->set_context_zc2(sio, SIG_Z80SIO_RX_CLK_CH1, 1);
149 ctc->set_constant_clock(1, CPU_CLOCKS >> 1);
150 ctc->set_constant_clock(2, CPU_CLOCKS >> 1);
151 sio->set_context_rts(1, mouse, SIG_MOUSE_RTS, 1);
152 // sio->set_tx_clock(0, 9600 * 16); // 9600 baud for RS-232C
153 // sio->set_rx_clock(0, 9600 * 16); // clock is from Z-80CTC ch1 (2MHz/13)
154 // sio->set_tx_clock(1, 4800 * 16); // 4800 baud for mouse
155 // sio->set_rx_clock(1, 4800 * 16); // clock is from Z-80CTC ch2 (2MHz/26)
157 if(sound_device_type >= 1) {
158 ctc1->set_context_zc0(ctc1, SIG_Z80CTC_TRIG_3, 1);
159 // ctc1->set_constant_clock(1, CPU_CLOCKS >> 1);
160 // ctc1->set_constant_clock(2, CPU_CLOCKS >> 1);
162 if(sound_device_type == 2) {
163 ctc2->set_context_zc0(ctc2, SIG_Z80CTC_TRIG_3, 1);
164 // ctc2->set_constant_clock(1, CPU_CLOCKS >> 1);
165 // ctc2->set_constant_clock(2, CPU_CLOCKS >> 1);
167 #ifdef _X1TURBO_FEATURE
168 dma->set_context_memory(memory);
169 dma->set_context_io(iobus);
172 #ifdef _X1TURBO_FEATURE
173 display->set_context_cpu(cpu);
174 display->set_context_crtc(crtc);
176 display->set_vram_ptr(iobus->get_vram());
177 display->set_regs_ptr(crtc->get_regs());
178 floppy->set_context_fdc(fdc);
179 iobus->set_context_cpu(cpu);
180 iobus->set_context_display(display);
181 iobus->set_context_io(io);
182 joy->set_context_psg(psg);
183 #ifdef _X1TURBO_FEATURE
184 memory->set_context_pio(pio);
186 mouse->set_context_sio(sio);
189 drec->set_context_remote(psub, SIG_PSUB_TAPE_REMOTE, 1);
190 drec->set_context_end(psub, SIG_PSUB_TAPE_END, 1);
191 psub->set_context_pio(pio);
192 psub->set_context_drec(drec);
195 cpu_sub->set_context_mem(new MCS48MEM(this, emu));
196 cpu_sub->set_context_io(sub);
198 cpu_sub->set_context_debugger(new DEBUGGER(this, emu));
200 drec->set_context_end(sub, SIG_SUB_TAPE_END, 1);
201 drec->set_context_apss(sub, SIG_SUB_TAPE_APSS, 1);
202 pio_sub->set_context_port_c(sub, SIG_SUB_PIO_PORT_C, 0x80, 0);
203 // pc1:break -> pb0 of 8255(main)
204 pio_sub->set_context_port_c(pio, SIG_I8255_PORT_B, 0x02, -1);
205 // pc5:ibf -> pb6 of 8255(main)
206 pio_sub->set_context_port_c(pio, SIG_I8255_PORT_B, 0x20, 1);
207 // pc7:obf -> pb5 of 8255(main)
208 pio_sub->set_context_port_c(pio, SIG_I8255_PORT_B, 0x80, -2);
209 // pc7:obf -> pb7 of 8255(sub)
210 pio_sub->set_context_port_c(pio_sub, SIG_I8255_PORT_B, 0x80, 0);
212 sub->set_context_pio(pio_sub);
213 sub->set_context_rtc(rtc_sub);
214 sub->set_context_drec(drec);
217 cpu_kbd->set_context_mem(new MCS48MEM(this, emu));
218 cpu_kbd->set_context_io(kbd);
220 cpu_kbd->set_context_debugger(new DEBUGGER(this, emu));
222 kbd->set_context_cpu(cpu_sub);
226 cpu->set_context_mem(memory);
227 cpu->set_context_io(iobus);
228 #if defined(_X1TURBO_FEATURE) && defined(SINGLE_MODE_DMA)
229 cpu->set_context_dma(dma);
232 cpu->set_context_debugger(new DEBUGGER(this, emu));
235 // z80 family daisy chain
236 DEVICE* parent_dev = NULL;
239 #define Z80_DAISY_CHAIN(dev) { \
240 if(parent_dev == NULL) { \
241 cpu->set_context_intr(dev); \
243 parent_dev->set_context_child(dev); \
245 dev->set_context_intr(cpu, level++); \
248 #ifndef _X1TURBO_FEATURE
249 Z80_DAISY_CHAIN(sio); // CZ-8BM2
250 Z80_DAISY_CHAIN(ctc);
252 if(sound_device_type >= 1) {
253 Z80_DAISY_CHAIN(ctc1);
255 if(sound_device_type == 2) {
256 Z80_DAISY_CHAIN(ctc2);
258 #ifdef _X1TURBO_FEATURE
259 Z80_DAISY_CHAIN(sio);
260 Z80_DAISY_CHAIN(dma);
261 Z80_DAISY_CHAIN(ctc);
264 Z80_DAISY_CHAIN(psub);
266 Z80_DAISY_CHAIN(sub);
270 if(sound_device_type >= 1) {
271 io->set_iomap_single_w(0x700, opm1);
272 io->set_iovalue_single_r(0x700, 0x00);
273 io->set_iomap_single_rw(0x701, opm1);
275 io->set_flipflop_single_rw(0x704, 0x00);
277 io->set_iomap_range_rw(0x704, 0x707, ctc1);
280 if(sound_device_type == 2) {
281 io->set_iomap_single_w(0x708, opm2);
282 io->set_iovalue_single_r(0x708, 0x00);
283 io->set_iomap_single_rw(0x709, opm2);
284 io->set_iomap_range_rw(0x70c, 0x70f, ctc2);
286 #ifdef _X1TURBO_FEATURE
287 io->set_iomap_single_rw(0xb00, memory);
289 io->set_iomap_range_rw(0xd00, 0xd03, emm);
290 io->set_iomap_range_r(0xe80, 0xe81, display);
291 io->set_iomap_range_w(0xe80, 0xe82, display);
292 io->set_iomap_range_rw(0xff8, 0xffb, fdc);
293 io->set_iomap_single_w(0xffc, floppy);
294 #ifdef _X1TURBO_FEATURE
295 io->set_iomap_range_r(0xffc, 0xfff, floppy);
297 io->set_iomap_range_rw(0x1000, 0x17ff, display);
298 for(int i = 0x1800; i <= 0x18ff; i += 0x10) {
299 io->set_iomap_range_rw(i, i + 1, crtc);
302 io->set_iomap_range_rw(0x1900, 0x19ff, psub);
304 io->set_iomap_range_rw(0x1900, 0x19ff, sub);
306 for(int i = 0x1a00; i <= 0x1aff; i += 4) {
307 io->set_iomap_range_rw(i, i + 3, pio);
309 for(int i = 0x1b00; i <= 0x1bff; i++) {
310 io->set_iomap_alias_rw(i, psg, 1);
312 for(int i = 0x1c00; i <= 0x1cff; i++) {
313 io->set_iomap_alias_w(i, psg, 0);
315 io->set_iomap_range_w(0x1d00, 0x1eff, memory);
316 #ifndef _X1TURBO_FEATURE
317 io->set_iomap_range_rw(0x1f98, 0x1f9b, sio); // CZ-8BM2
318 io->set_iomap_range_rw(0x1fa8, 0x1fab, ctc);
320 io->set_iomap_range_rw(0x1f80, 0x1f8f, dma);
321 io->set_iomap_range_rw(0x1f90, 0x1f93, sio);
322 io->set_iomap_range_rw(0x1fa0, 0x1fa3, ctc);
324 io->set_iomap_single_rw(0x1fd0, display);
325 io->set_iomap_single_rw(0x1fe0, display);
327 io->set_iomap_single_w(0x1fd0, display);
328 io->set_iomap_single_w(0x1fe0, display);
331 // io->set_iovalue_single_r(0x1ff0, 0x00);
334 io->set_iomap_range_rw(0x2000, 0x3fff, display); // tvram
338 pceevent = new EVENT(this, emu);
339 pceevent->set_frames_per_sec(PCE_FRAMES_PER_SEC);
340 pceevent->set_lines_per_frame(PCE_LINES_PER_FRAME);
342 pcecpu = new HUC6280(this, emu);
343 pcecpu->set_context_event_manager(pceevent);
344 pce = new PCE(this, emu);
345 pce->set_context_event_manager(pceevent);
347 pceevent->set_context_cpu(pcecpu, PCE_CPU_CLOCKS);
348 pceevent->set_context_sound(pce);
350 pcecpu->set_context_mem(pce);
351 pcecpu->set_context_io(pce);
353 pcecpu->set_context_debugger(new DEBUGGER(this, emu));
355 pce->set_context_cpu(pcecpu);
358 // initialize all devices
359 for(DEVICE* device = first_device; device; device = device->next_device) {
360 device->initialize();
362 if(!pseudo_sub_cpu) {
363 // load rom images after cpustate is allocated
364 cpu_sub->load_rom_image(emu->bios_path(SUB_ROM_FILE_NAME));
365 cpu_kbd->load_rom_image(emu->bios_path(KBD_ROM_FILE_NAME));
367 // patch to set the current year
368 uint8 *rom = cpu_sub->get_rom_ptr();
369 sub->rom_crc32 = getcrc32(rom, 0x800); // 2KB
370 if(rom[0x23] == 0xb9 && rom[0x24] == 0x35 && rom[0x25] == 0xb1) {
372 emu->get_host_time(&cur_time);
373 rom[0x26] = TO_BCD(cur_time.year);
376 for(int i = 0; i < MAX_DRIVE; i++) {
377 #ifdef _X1TURBO_FEATURE
378 fdc->set_drive_type(i, DRIVE_TYPE_2DD);
380 fdc->set_drive_type(i, DRIVE_TYPE_2D);
382 // fdc->set_drive_rpm(i, 300);
383 // fdc->set_drive_mfm(i, true);
389 // delete all devices
390 for(DEVICE* device = first_device; device;) {
391 DEVICE *next_device = device->next_device;
394 device = next_device;
398 DEVICE* VM::get_device(int id)
400 for(DEVICE* device = first_device; device; device = device->next_device) {
401 if(device->this_device_id == id) {
408 // ----------------------------------------------------------------------------
409 // drive virtual machine
410 // ----------------------------------------------------------------------------
415 for(DEVICE* device = first_device; device; device = device->next_device) {
418 psg->SetReg(0x2e, 0); // set prescaler
421 void VM::special_reset()
424 cpu->write_signal(SIG_CPU_NMI, 1, 1);
431 if(pce->cart_inserted()) {
437 double VM::frame_rate()
440 if(pce->cart_inserted()) {
441 return pceevent->frame_rate();
444 return event->frame_rate();
447 // ----------------------------------------------------------------------------
449 // ----------------------------------------------------------------------------
452 DEVICE *VM::get_cpu(int index)
456 } else if(index == 1) {
458 } else if(index == 2) {
461 } else if(index == 3 && pce->cart_inserted()) {
469 // ----------------------------------------------------------------------------
471 // ----------------------------------------------------------------------------
473 void VM::draw_screen()
475 display->draw_screen();
477 if(pce->cart_inserted()) {
483 int VM::access_lamp()
485 uint32 status = fdc->read_signal(0);
486 return (status & (1 | 4)) ? 1 : (status & (2 | 8)) ? 2 : 0;
489 // ----------------------------------------------------------------------------
491 // ----------------------------------------------------------------------------
493 void VM::initialize_sound(int rate, int samples)
495 // init sound manager
496 event->initialize_sound(rate, samples);
498 pceevent->initialize_sound(rate, samples);
502 if(sound_device_type >= 1) {
503 opm1->init(rate, 4000000, samples, 0);
505 if(sound_device_type == 2) {
506 opm2->init(rate, 4000000, samples, 0);
508 psg->init(rate, 2000000, samples, 0, 0);
510 pce->initialize_sound(rate);
514 uint16* VM::create_sound(int* extra_frames)
517 if(pce->cart_inserted()) {
518 uint16* buffer = pceevent->create_sound(extra_frames);
519 for(int i = 0; i < *extra_frames; i++) {
525 return event->create_sound(extra_frames);
528 int VM::sound_buffer_ptr()
531 if(pce->cart_inserted()) {
532 return pceevent->sound_buffer_ptr();
535 return event->sound_buffer_ptr();
538 // ----------------------------------------------------------------------------
540 // ----------------------------------------------------------------------------
542 void VM::key_down(int code, bool repeat)
545 if(!repeat && !pce->cart_inserted()) {
550 psub->key_down(code, false);
552 kbd->key_down(code, false);
557 void VM::key_up(int code)
560 if(!pce->cart_inserted()) {
572 // ----------------------------------------------------------------------------
574 // ----------------------------------------------------------------------------
576 void VM::open_disk(int drv, const _TCHAR* file_path, int bank)
578 fdc->open_disk(drv, file_path, bank);
581 void VM::close_disk(int drv)
583 fdc->close_disk(drv);
586 bool VM::disk_inserted(int drv)
588 return fdc->disk_inserted(drv);
591 void VM::set_disk_protected(int drv, bool value)
593 fdc->set_disk_protected(drv, value);
596 bool VM::get_disk_protected(int drv)
598 return fdc->get_disk_protected(drv);
601 void VM::play_tape(const _TCHAR* file_path)
603 bool value = drec->play_tape(file_path);
606 psub->play_tape(value);
609 sub->play_tape(value);
613 void VM::rec_tape(const _TCHAR* file_path)
615 bool value = drec->rec_tape(file_path);
618 psub->rec_tape(value);
621 sub->rec_tape(value);
625 void VM::close_tape()
635 bool VM::tape_inserted()
637 return drec->tape_inserted();
640 #if defined(USE_TAPE_PTR)
641 int VM::get_tape_ptr(void)
643 return drec->get_tape_ptr();
650 drec->set_remote(true);
653 bool VM::get_tape_play(void)
655 return drec->get_tape_play();
660 drec->set_remote(false);
663 void VM::push_fast_forward()
666 drec->set_remote(true);
669 void VM::push_fast_rewind()
671 drec->set_ff_rew(-1);
672 drec->set_remote(true);
675 void VM::push_apss_forward()
680 void VM::push_apss_rewind()
688 if(pce->cart_inserted()) {
689 return pceevent->now_skip();
692 return event->now_skip();
696 void VM::open_cart(int drv, const _TCHAR* file_path)
699 pce->open_cart(file_path);
705 void VM::close_cart(int drv)
714 bool VM::cart_inserted(int drv)
717 return pce->cart_inserted();
724 void VM::update_config()
726 for(DEVICE* device = first_device; device; device = device->next_device) {
727 device->update_config();
729 #ifdef _X1TURBO_FEATURE
734 #ifdef _X1TURBO_FEATURE
735 void VM::update_dipswitch()
737 // bit0 0=High 1=Standard
738 // bit2 0=5"2D 1=5"2HD
739 io->set_iovalue_single_r(0x1ff0, (config.monitor_type & 1) | ((config.drive_type & 1) << 2));
743 #define STATE_VERSION 4
745 void VM::save_state(FILEIO* state_fio)
747 state_fio->FputUint32(STATE_VERSION);
749 for(DEVICE* device = first_device; device; device = device->next_device) {
750 device->save_state(state_fio);
752 state_fio->FputBool(pseudo_sub_cpu);
753 state_fio->FputInt32(sound_device_type);
756 bool VM::load_state(FILEIO* state_fio)
758 if(state_fio->FgetUint32() != STATE_VERSION) {
761 for(DEVICE* device = first_device; device; device = device->next_device) {
762 if(!device->load_state(state_fio)) {
766 pseudo_sub_cpu = state_fio->FgetBool();
767 sound_device_type = state_fio->FgetInt32();
769 #ifdef _X1TURBO_FEATURE