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"
24 //#include "../pcpr201.h"
25 #include "../prnfile.h"
26 #include "../ym2151.h"
27 #include "../ym2203.h"
29 #include "../z80ctc.h"
30 #include "../z80sio.h"
31 #ifdef _X1TURBO_FEATURE
32 #include "../z80dma.h"
36 #include "../debugger.h"
49 #include "../upd1990a.h"
54 #include "../huc6280.h"
55 #include "../pcengine/pce.h"
58 // ----------------------------------------------------------------------------
60 // ----------------------------------------------------------------------------
62 VM::VM(EMU* parent_emu) : emu(parent_emu)
64 pseudo_sub_cpu = !(FILEIO::IsFileExists(create_local_path(SUB_ROM_FILE_NAME)) && FILEIO::IsFileExists(create_local_path(KBD_ROM_FILE_NAME)));
66 sound_device_type = config.sound_device_type;
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
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);
86 if(sound_device_type == 2) {
87 opm2 = new YM2151(this, emu);
88 ctc2 = new Z80CTC(this, emu);
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);
99 #ifdef _X1TURBO_FEATURE
100 dma = new Z80DMA(this, emu);
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);
112 psub = new PSUB(this, emu);
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);
123 cpu_kbd = new MCS48(this, emu);
124 kbd = new KEYBOARD(this, emu);
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);
133 if(sound_device_type >= 1) {
134 event->set_context_sound(opm1);
136 if(sound_device_type == 2) {
137 event->set_context_sound(opm2);
139 event->set_context_sound(psg);
140 event->set_context_sound(drec);
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);
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)
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);
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);
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);
188 #ifdef _X1TURBO_FEATURE
189 dma->set_context_memory(memory);
190 dma->set_context_io(iobus);
193 #ifdef _X1TURBO_FEATURE
194 display->set_context_cpu(cpu);
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);
207 mouse->set_context_sio(sio);
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);
216 cpu_sub->set_context_mem(new MCS48MEM(this, emu));
217 cpu_sub->set_context_io(sub);
219 cpu_sub->set_context_debugger(new DEBUGGER(this, emu));
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);
233 sub->set_context_pio(pio_sub);
234 sub->set_context_rtc(rtc_sub);
235 sub->set_context_drec(drec);
238 cpu_kbd->set_context_mem(new MCS48MEM(this, emu));
239 cpu_kbd->set_context_io(kbd);
241 cpu_kbd->set_context_debugger(new DEBUGGER(this, emu));
243 kbd->set_context_cpu(cpu_sub);
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);
253 cpu->set_context_debugger(new DEBUGGER(this, emu));
256 // z80 family daisy chain
257 DEVICE* parent_dev = NULL;
260 #define Z80_DAISY_CHAIN(dev) { \
261 if(parent_dev == NULL) { \
262 cpu->set_context_intr(dev); \
264 parent_dev->set_context_child(dev); \
266 dev->set_context_intr(cpu, level++); \
269 #ifndef _X1TURBO_FEATURE
270 Z80_DAISY_CHAIN(sio); // CZ-8BM2
271 Z80_DAISY_CHAIN(ctc);
273 if(sound_device_type >= 1) {
274 Z80_DAISY_CHAIN(ctc1);
276 if(sound_device_type == 2) {
277 Z80_DAISY_CHAIN(ctc2);
279 #ifdef _X1TURBO_FEATURE
280 Z80_DAISY_CHAIN(sio);
281 Z80_DAISY_CHAIN(dma);
282 Z80_DAISY_CHAIN(ctc);
285 Z80_DAISY_CHAIN(psub);
287 Z80_DAISY_CHAIN(sub);
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);
296 io->set_flipflop_single_rw(0x704, 0x00);
298 io->set_iomap_range_rw(0x704, 0x707, ctc1);
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);
307 #ifdef _X1TURBO_FEATURE
308 io->set_iomap_single_rw(0xb00, memory);
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);
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);
323 io->set_iomap_range_rw(0x1900, 0x19ff, psub);
325 io->set_iomap_range_rw(0x1900, 0x19ff, sub);
327 for(int i = 0x1a00; i <= 0x1aff; i += 4) {
328 io->set_iomap_range_rw(i, i + 3, pio);
330 for(int i = 0x1b00; i <= 0x1bff; i++) {
331 io->set_iomap_alias_rw(i, psg, 1);
333 for(int i = 0x1c00; i <= 0x1cff; i++) {
334 io->set_iomap_alias_w(i, psg, 0);
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);
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);
345 io->set_iomap_single_rw(0x1fd0, display);
346 io->set_iomap_single_rw(0x1fe0, display);
348 io->set_iomap_single_w(0x1fd0, display);
349 io->set_iomap_single_w(0x1fe0, display);
352 //io->set_iovalue_single_r(0x1ff0, 0x00);
355 io->set_iomap_range_rw(0x2000, 0x3fff, display); // tvram
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);
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);
368 pceevent->set_context_cpu(pcecpu, PCE_CPU_CLOCKS);
369 pceevent->set_context_sound(pce);
371 pcecpu->set_context_mem(pce);
372 pcecpu->set_context_io(pce);
374 pcecpu->set_context_debugger(new DEBUGGER(this, emu));
376 pce->set_context_cpu(pcecpu);
379 // initialize all devices
380 for(DEVICE* device = first_device; device; device = device->next_device) {
381 device->initialize();
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));
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) {
393 get_host_time(&cur_time);
394 rom[0x26] = TO_BCD(cur_time.year);
397 for(int i = 0; i < MAX_DRIVE; i++) {
398 #ifdef _X1TURBO_FEATURE
399 fdc->set_drive_type(i, DRIVE_TYPE_2DD);
401 fdc->set_drive_type(i, DRIVE_TYPE_2D);
403 // fdc->set_drive_rpm(i, 300);
404 // fdc->set_drive_mfm(i, true);
410 // delete all devices
411 for(DEVICE* device = first_device; device;) {
412 DEVICE *next_device = device->next_device;
415 device = next_device;
419 DEVICE* VM::get_device(int id)
421 for(DEVICE* device = first_device; device; device = device->next_device) {
422 if(device->this_device_id == id) {
429 // ----------------------------------------------------------------------------
430 // drive virtual machine
431 // ----------------------------------------------------------------------------
436 for(DEVICE* device = first_device; device; device = device->next_device) {
439 pio->write_signal(SIG_I8255_PORT_B, 0x00, 0x08); // busy = low
440 psg->SetReg(0x2e, 0); // set prescaler
443 void VM::special_reset()
446 cpu->write_signal(SIG_CPU_NMI, 1, 1);
453 if(pce->is_cart_inserted()) {
459 double VM::get_frame_rate()
462 if(pce->is_cart_inserted()) {
463 return pceevent->get_frame_rate();
466 return event->get_frame_rate();
469 // ----------------------------------------------------------------------------
471 // ----------------------------------------------------------------------------
474 DEVICE *VM::get_cpu(int index)
478 } else if(index == 1) {
480 } else if(index == 2) {
483 } else if(index == 3 && pce->is_cart_inserted()) {
491 // ----------------------------------------------------------------------------
493 // ----------------------------------------------------------------------------
495 void VM::draw_screen()
497 display->draw_screen();
499 if(pce->is_cart_inserted()) {
505 int VM::get_access_lamp_status()
507 uint32 status = fdc->read_signal(0);
508 return (status & (1 | 4)) ? 1 : (status & (2 | 8)) ? 2 : 0;
511 // ----------------------------------------------------------------------------
513 // ----------------------------------------------------------------------------
515 void VM::initialize_sound(int rate, int samples)
517 // init sound manager
518 event->initialize_sound(rate, samples);
520 pceevent->initialize_sound(rate, samples);
524 if(sound_device_type >= 1) {
525 opm1->initialize_sound(rate, 4000000, samples, 0);
527 if(sound_device_type == 2) {
528 opm2->initialize_sound(rate, 4000000, samples, 0);
530 psg->initialize_sound(rate, 2000000, samples, 0, 0);
532 pce->initialize_sound(rate);
536 uint16* VM::create_sound(int* extra_frames)
539 if(pce->is_cart_inserted()) {
540 uint16* buffer = pceevent->create_sound(extra_frames);
541 for(int i = 0; i < *extra_frames; i++) {
547 return event->create_sound(extra_frames);
550 int VM::get_sound_buffer_ptr()
553 if(pce->is_cart_inserted()) {
554 return pceevent->get_sound_buffer_ptr();
557 return event->get_sound_buffer_ptr();
560 #ifdef USE_SOUND_VOLUME
561 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
564 psg->set_volume(1, decibel_l, decibel_r);
566 if(sound_device_type >= 1) {
567 opm1->set_volume(0, decibel_l, decibel_r);
570 if(sound_device_type >= 2) {
571 opm2->set_volume(0, decibel_l, decibel_r);
574 drec->set_volume(0, decibel_l, decibel_r);
577 pce->set_volume(0, decibel_l, decibel_r);
583 // ----------------------------------------------------------------------------
585 // ----------------------------------------------------------------------------
587 void VM::key_down(int code, bool repeat)
590 if(!repeat && !pce->is_cart_inserted()) {
595 psub->key_down(code, false);
597 kbd->key_down(code, false);
602 void VM::key_up(int code)
605 if(!pce->is_cart_inserted()) {
617 // ----------------------------------------------------------------------------
619 // ----------------------------------------------------------------------------
621 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
623 fdc->open_disk(drv, file_path, bank);
626 void VM::close_floppy_disk(int drv)
628 fdc->close_disk(drv);
631 bool VM::is_floppy_disk_inserted(int drv)
633 return fdc->is_disk_inserted(drv);
636 void VM::is_floppy_disk_protected(int drv, bool value)
638 fdc->is_disk_protected(drv, value);
641 bool VM::is_floppy_disk_protected(int drv)
643 return fdc->is_disk_protected(drv);
646 void VM::play_tape(const _TCHAR* file_path)
648 bool value = drec->play_tape(file_path);
651 psub->play_tape(value);
654 sub->play_tape(value);
658 void VM::rec_tape(const _TCHAR* file_path)
660 bool value = drec->rec_tape(file_path);
663 psub->rec_tape(value);
666 sub->rec_tape(value);
670 void VM::close_tape()
680 bool VM::is_tape_inserted()
682 return drec->is_tape_inserted();
685 bool VM::is_tape_playing()
687 return drec->is_tape_playing();
690 bool VM::is_tape_recording()
692 return drec->is_tape_recording();
695 int VM::get_tape_position()
697 return drec->get_tape_position();
703 drec->set_remote(true);
708 drec->set_remote(false);
711 void VM::push_fast_forward()
714 drec->set_remote(true);
717 void VM::push_fast_rewind()
719 drec->set_ff_rew(-1);
720 drec->set_remote(true);
723 void VM::push_apss_forward()
728 void VM::push_apss_rewind()
733 bool VM::is_frame_skippable()
736 if(pce->is_cart_inserted()) {
737 return pceevent->is_frame_skippable();
740 return event->is_frame_skippable();
744 void VM::open_cart(int drv, const _TCHAR* file_path)
747 pce->open_cart(file_path);
753 void VM::close_cart(int drv)
762 bool VM::is_cart_inserted(int drv)
765 return pce->is_cart_inserted();
772 void VM::update_config()
774 for(DEVICE* device = first_device; device; device = device->next_device) {
775 device->update_config();
777 #ifdef _X1TURBO_FEATURE
782 #ifdef _X1TURBO_FEATURE
783 void VM::update_dipswitch()
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));
791 #define STATE_VERSION 6
793 void VM::save_state(FILEIO* state_fio)
795 state_fio->FputUint32(STATE_VERSION);
797 for(DEVICE* device = first_device; device; device = device->next_device) {
798 device->save_state(state_fio);
800 state_fio->FputBool(pseudo_sub_cpu);
801 state_fio->FputInt32(sound_device_type);
804 bool VM::load_state(FILEIO* state_fio)
806 if(state_fio->FgetUint32() != STATE_VERSION) {
809 for(DEVICE* device = first_device; device; device = device->next_device) {
810 if(!device->load_state(state_fio)) {
814 pseudo_sub_cpu = state_fio->FgetBool();
815 sound_device_type = state_fio->FgetInt32();
817 #ifdef _X1TURBO_FEATURE