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'
15 #include "../../emu.h"
16 #include "../device.h"
23 #include "../mc6847.h"
26 #include "../upd7752.h"
28 #include "../pc6031.h"
29 #include "../pc80s31k.h"
30 #include "../prnfile.h"
31 #include "../upd765a.h"
32 #include "../ym2203.h"
35 #include "../datarec.h"
39 #include "../debugger.h"
42 #if defined(_PC6601) || defined(_PC6601SR)
51 // ----------------------------------------------------------------------------
53 // ----------------------------------------------------------------------------
55 VM::VM(EMU* parent_emu) : emu(parent_emu)
57 support_pc80s31k = FILEIO::IsFileExisting(create_local_path(_T("DISK.ROM")));
59 support_sub_cpu = false;
61 support_sub_cpu = FILEIO::IsFileExisting(create_local_path(_T(SUB_CPU_ROM_FILE_NAME)));
65 first_device = last_device = NULL;
66 dummy = new DEVICE(this, emu); // must be 1st device
67 event = new EVENT(this, emu); // must be 2nd device
69 dummy->set_device_name(_T("1st Dummy"));
71 d_pc80s31k_seek = d_pc6031_seek = d_floppy_seek = NULL;
72 pio_sub = new I8255(this, emu);
73 io = new IO(this, emu);
74 psg = new YM2203(this, emu);
75 cpu = new Z80(this, emu);
78 pio_sub->set_device_name(_T("i8255 PIO(PRINTER/SOUND/SUB/VDP)"));
80 pio_sub->set_device_name(_T("i8255 PIO(PRINTER/SOUND/SUB)"));
82 #if defined(_PC6601SR) || defined(_PC6001MK2SR)
83 psg->set_device_name(_T("YM2203 OPN"));
85 psg->set_device_name(_T("AY-3-8910 PSG"));
87 cpu->set_device_name(_T("CPU(Z80)"));
90 if(config.printer_device_type == 0) {
91 printer = new PRNFILE(this, emu);
96 #if defined(_PC6601) || defined(_PC6601SR)
97 floppy = new FLOPPY(this, emu);
99 floppy->set_device_name(_T("FLOPPY I/F"));
102 joystick = new JOYSTICK(this, emu);
103 memory = new MEMORY(this, emu);
104 timer = new TIMER(this, emu);
106 joystick->set_device_name(_T("JOYSTICK I/F"));
107 memory->set_device_name(_T("MEMORY"));
108 timer->set_device_name(_T("TIMER"));
112 event->set_context_cpu(cpu);
113 event->set_context_sound(psg);
115 pio_sub->set_context_port_b(printer, SIG_PRINTER_DATA, 0xff, 0);
116 pio_sub->set_context_port_c(printer, SIG_PRINTER_STROBE, 0x01, 0);
117 pio_sub->set_context_port_c(memory, SIG_MEMORY_PIO_PORT_C, 0x06, 0); // CRTKILL,CGSWN
120 display = new DISPLAY(this, emu);
121 vdp = new MC6847(this, emu);
122 display->set_context_vdp(vdp);
123 display->set_vram_ptr(memory->get_vram());
124 display->set_context_timer(timer);
125 vdp->load_font_image(create_local_path(_T("CGROM60.60")));
126 vdp->set_context_cpu(cpu);
127 pio_sub->set_context_port_c(vdp, SIG_MC6847_ENABLE, 0x02, 0); // CRTKILL
129 display->set_device_name(_T("DISPLAY I/F"));
132 voice = new UPD7752(this, emu);
133 event->set_context_sound(voice);
134 memory->set_context_timer(timer);
136 memory->set_context_cpu(cpu);
137 joystick->set_context_psg(psg);
139 timer->set_context_cpu(cpu);
141 timer->set_context_memory(memory);
143 if(support_sub_cpu) {
144 cpu_sub = new MCS48(this, emu);
145 sub = new SUB(this, emu);
146 drec = new DATAREC(this, emu);
147 event->set_context_cpu(cpu_sub, 8000000);
148 event->set_context_sound(drec);
149 #if defined(USE_SOUND_FILES)
150 drec->load_sound_data(DATAREC_SNDFILE_RELAY_ON, _T("RELAY_ON.WAV"));
151 drec->load_sound_data(DATAREC_SNDFILE_RELAY_OFF, _T("RELAY_OFF.WAV"));
153 cpu_sub->set_context_mem(new MCS48MEM(this, emu));
154 cpu_sub->set_context_io(sub);
156 cpu_sub->set_context_debugger(new DEBUGGER(this, emu));
158 sub->set_context_pio(pio_sub);
159 sub->set_context_drec(drec);
160 sub->set_context_timer(timer);
161 pio_sub->set_context_port_c(cpu_sub, SIG_CPU_IRQ, 0x80, 0);
162 drec->set_context_ear(sub, SIG_SUB_DATAREC, 1);
163 timer->set_context_sub(sub);
165 psub = new PSUB(this, emu);
167 psub->set_device_name(_T("PSEUDO SUB SYSTEM"));
169 psub->set_context_pio(pio_sub);
170 psub->set_context_timer(timer);
171 timer->set_context_sub(psub);
174 if(support_pc80s31k) {
175 pio_fdd = new I8255(this, emu);
176 pio_pc80s31k = new I8255(this, emu);
177 pc80s31k = new PC80S31K(this, emu);
178 fdc_pc80s31k = new UPD765A(this, emu);
179 cpu_pc80s31k = new Z80(this, emu);
181 pio_fdd->set_device_name(_T("i8255 PIO(FDD)"));
182 pio_pc80s31k->set_device_name(_T("i8255 PIO(PC-80S31K)"));
183 pc80s31k->set_device_name(_T("PC-80S31K FDD"));
184 fdc_pc80s31k->set_device_name(_T("uPD765A FDC(PC-80S31K)"));
185 cpu_pc80s31k->set_device_name(_T("Z80 CPU(PC-80S31K)"));
187 #if defined(USE_SOUND_FILES)
188 if(fdc_pc80s31k->load_sound_data(UPD765A_SND_TYPE_SEEK, _T("FDDSEEK.WAV"))) {
189 event->set_context_sound(fdc_pc80s31k);
192 event->set_context_cpu(cpu_pc80s31k, 4000000);
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 cpu_pc80s31k->set_context_mem(pc80s31k);
208 cpu_pc80s31k->set_context_io(pc80s31k);
209 cpu_pc80s31k->set_context_intr(pc80s31k);
211 cpu_pc80s31k->set_context_debugger(new DEBUGGER(this, emu));
213 #if defined(_PC6601) || defined(_PC6601SR)
214 floppy->set_context_ext(pio_fdd);
217 pc6031 = new PC6031(this, emu);
218 #if defined(_PC6601) || defined(_PC6601SR)
219 floppy->set_context_ext(pc6031);
221 #if defined(USE_SOUND_FILES)
222 if(pc6031->load_sound_data(PC6031_SND_TYPE_SEEK, _T("FDDSEEK.WAV"))) {
223 event->set_context_sound(pc6031);
225 if(floppy->load_sound_data(FLOPPY_SND_TYPE_SEEK, _T("FDDSEEK.WAV"))) {
226 event->set_context_sound(floppy);
233 cpu->set_context_mem(memory);
234 cpu->set_context_io(io);
235 cpu->set_context_intr(timer);
237 cpu->set_context_debugger(new DEBUGGER(this, emu));
241 if(support_sub_cpu) {
242 io->set_iomap_range_rw(0x90, 0x93, sub);
244 io->set_iomap_range_rw(0x90, 0x93, psub);
246 io->set_iomap_alias_w(0xa0, psg, 0); // PSG ch
247 io->set_iomap_alias_w(0xa1, psg, 1); // PSG data
248 io->set_iomap_alias_r(0xa2, psg, 1); // PSG data
249 #if defined(_PC6601SR) || defined(_PC6001MK2SR)
250 io->set_iomap_alias_r(0xa3, psg, 0); // FM status
251 io->set_iomap_range_rw(0x40, 0x6f, memory); // VRAM addr
254 io->set_iomap_single_w(0xb0, display); // VRAM addr
255 io->set_iomap_single_w(0x00, memory); // MEMORY MAP
257 io->set_iomap_single_w(0xb0, memory); // VRAM addr
258 io->set_iomap_range_rw(0xc0, 0xcf, memory); // VRAM addr
259 io->set_iomap_range_rw(0xe0, 0xe3, voice); // VOICE
260 #if defined(_PC6601) || defined(_PC6601SR)
261 io->set_iomap_range_rw(0xb8, 0xbf, timer); // IRQ
262 io->set_iomap_range_rw(0xfa, 0xfb, timer); // IRQ
264 io->set_iomap_range_rw(0xf3, 0xf7, timer); // IRQ/Timer
267 #if defined(_PC6601) || defined(_PC6601SR)
268 io->set_iomap_range_rw(0xb1, 0xb3, floppy); // DISK DRIVE
269 io->set_iomap_range_rw(0xb5, 0xb7, floppy); // DISK DRIVE (Mirror)
270 io->set_iomap_range_rw(0xd0, 0xde, floppy); // DISK DRIVE
272 io->set_iovalue_single_r(0xb1, 0x01);
273 #if defined(_PC6601SR)
274 io->set_iovalue_single_r(0xb2, 0x02);
275 #elif defined(_PC6001MK2SR)
276 io->set_iovalue_single_r(0xb2, 0x00);
279 if(support_pc80s31k) {
280 io->set_iomap_range_rw(0xd0, 0xd2, pio_fdd);
281 io->set_iomap_single_w(0xd3, pio_fdd);
283 io->set_iomap_range_rw(0xd0, 0xd3, pc6031);
286 io->set_iomap_range_rw(0xf0, 0xf2, memory); // MEMORY MAP
288 // initialize all devices
289 for(DEVICE* device = first_device; device; device = device->next_device) {
290 device->initialize();
292 if(support_sub_cpu) {
293 // load rom images after cpustate is allocated
296 cpu_sub->load_rom_image(create_local_path(_T(SUB_CPU_ROM_FILE_NAME)));
300 #if defined(_PC6601) || defined(_PC6601SR)
301 floppy->get_disk_handler(0)->drive_num = drive_num++;
302 floppy->get_disk_handler(1)->drive_num = drive_num++;
304 if(support_pc80s31k) {
305 fdc_pc80s31k->get_disk_handler(0)->drive_num = drive_num++;
306 fdc_pc80s31k->get_disk_handler(1)->drive_num = drive_num++;
308 pc6031->get_disk_handler(0)->drive_num = drive_num++;
309 pc6031->get_disk_handler(1)->drive_num = drive_num++;
315 // delete all devices
316 for(DEVICE* device = first_device; device;) {
317 DEVICE *next_device = device->next_device;
320 device = next_device;
324 DEVICE* VM::get_device(int id)
326 for(DEVICE* device = first_device; device; device = device->next_device) {
327 if(device->this_device_id == id) {
334 // ----------------------------------------------------------------------------
335 // drive virtual machine
336 // ----------------------------------------------------------------------------
340 for(DEVICE* device = first_device; device; device = device->next_device) {
343 if(support_pc80s31k) {
344 pio_fdd->write_signal(SIG_I8255_PORT_C, 0, 0xff);
345 pio_pc80s31k->write_signal(SIG_I8255_PORT_C, 0, 0xff);
354 // ----------------------------------------------------------------------------
356 // ----------------------------------------------------------------------------
359 DEVICE *VM::get_cpu(int index)
363 } else if(index == 1) {
365 } else if(index == 2) {
372 // ----------------------------------------------------------------------------
374 // ----------------------------------------------------------------------------
376 void VM::draw_screen()
379 display->draw_screen();
381 memory->draw_screen();
384 // ----------------------------------------------------------------------------
386 // ----------------------------------------------------------------------------
388 void VM::initialize_sound(int rate, int samples)
390 // init sound manager
391 event->initialize_sound(rate, samples);
394 psg->initialize_sound(rate, 4000000, samples, 0, 0);
396 voice->initialize_sound(rate);
400 uint16_t* VM::create_sound(int* extra_frames)
402 return event->create_sound(extra_frames);
405 int VM::get_sound_buffer_ptr()
407 return event->get_sound_buffer_ptr();
410 #ifdef USE_SOUND_VOLUME
411 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
414 psg->set_volume(1, decibel_l, decibel_r);
415 #if !defined(_PC6001)
416 } else if(ch-- == 0) {
417 voice->set_volume(0, decibel_l, decibel_r);
419 } else if(ch-- == 0) {
420 if(support_sub_cpu) {
421 drec->set_volume(0, decibel_l, decibel_r);
424 #if defined(USE_SOUND_FILES)
426 if(support_pc80s31k) {
427 if(fdc_pc80s31k != NULL) fdc_pc80s31k->set_volume(0, decibel_l, decibel_r);
429 if(pc6031 != NULL) pc6031->set_volume(0, decibel_l, decibel_r);
430 if(floppy != NULL) floppy->set_volume(0, decibel_l, decibel_r);
437 // ----------------------------------------------------------------------------
439 // ----------------------------------------------------------------------------
441 void VM::key_down(int code, bool repeat)
443 if(!support_sub_cpu) {
444 psub->key_down(code);
448 void VM::key_up(int code)
450 if(!support_sub_cpu) {
455 // ----------------------------------------------------------------------------
457 // ----------------------------------------------------------------------------
459 void VM::open_cart(int drv, const _TCHAR* file_path)
462 memory->open_cart(file_path);
467 void VM::close_cart(int drv)
470 memory->close_cart();
475 bool VM::is_cart_inserted(int drv)
478 return memory->is_cart_inserted();
484 uint32_t VM::get_access_lamp_status()
486 uint32_t status = 0; /// fdc->read_signal(0);
487 #if defined(_PC6601) || defined(_PC6601SR)
488 status = floppy->read_signal(0);
490 if(support_pc80s31k) {
491 status |= fdc_pc80s31k->read_signal(0);
493 status |= pc6031->read_signal(0);
498 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
500 #if defined(_PC6601) || defined(_PC6601SR)
502 floppy->open_disk(drv, file_path, bank);
508 if(support_pc80s31k) {
509 fdc_pc80s31k->open_disk(drv, file_path, bank);
511 pc6031->open_disk(drv, file_path, bank);
515 void VM::close_floppy_disk(int drv)
517 #if defined(_PC6601) || defined(_PC6601SR)
519 floppy->close_disk(drv);
525 if(support_pc80s31k) {
526 fdc_pc80s31k->close_disk(drv);
528 pc6031->close_disk(drv);
532 bool VM::is_floppy_disk_inserted(int drv)
534 #if defined(_PC6601) || defined(_PC6601SR)
536 return floppy->is_disk_inserted(drv);
541 if(support_pc80s31k) {
542 return fdc_pc80s31k->is_disk_inserted(drv);
544 return pc6031->is_disk_inserted(drv);
548 void VM::is_floppy_disk_protected(int drv, bool value)
550 #if defined(_PC6601) || defined(_PC6601SR)
552 floppy->is_disk_protected(drv, value);
558 if(support_pc80s31k) {
559 fdc_pc80s31k->is_disk_protected(drv, value);
561 pc6031->is_disk_protected(drv, value);
565 bool VM::is_floppy_disk_protected(int drv)
567 #if defined(_PC6601) || defined(_PC6601SR)
569 return floppy->is_disk_protected(drv);
574 if(support_pc80s31k) {
575 return fdc_pc80s31k->is_disk_protected(drv);
577 return pc6031->is_disk_protected(drv);
581 void VM::play_tape(const _TCHAR* file_path)
583 if(support_sub_cpu) {
584 // support both p6/p6t and wav
585 drec->play_tape(file_path);
587 // support only p6/p6t
588 psub->play_tape(file_path);
592 void VM::rec_tape(const _TCHAR* file_path)
594 if(support_sub_cpu) {
595 // support both p6/p6t and wav
596 sub->rec_tape(file_path); // temporary
597 // drec->rec_tape(file_path);
599 // support both p6/p6t and wav
600 psub->rec_tape(file_path);
604 void VM::close_tape()
606 if(support_sub_cpu) {
607 if(sub->is_tape_inserted()) {
608 sub->close_tape(); // temporary
617 bool VM::is_tape_inserted()
619 if(support_sub_cpu) {
620 return drec->is_tape_inserted() || sub->is_tape_inserted();
622 return psub->is_tape_inserted();
626 bool VM::is_tape_playing()
628 if(support_sub_cpu) {
629 return drec->is_tape_playing();
635 bool VM::is_tape_recording()
637 if(support_sub_cpu) {
638 return drec->is_tape_recording();
644 int VM::get_tape_position()
646 if(support_sub_cpu) {
647 return drec->get_tape_position();
653 bool VM::is_frame_skippable()
655 return event->is_frame_skippable();
658 void VM::update_config()
660 for(DEVICE* device = first_device; device; device = device->next_device) {
661 device->update_config();
665 #define STATE_VERSION 3
667 void VM::save_state(FILEIO* state_fio)
669 state_fio->FputUint32(STATE_VERSION);
671 for(DEVICE* device = first_device; device; device = device->next_device) {
672 device->save_state(state_fio);
674 state_fio->FputInt32(sr_mode);
677 bool VM::load_state(FILEIO* state_fio)
679 if(state_fio->FgetUint32() != STATE_VERSION) {
682 for(DEVICE* device = first_device; device; device = device->next_device) {
683 if(!device->load_state(state_fio)) {
687 sr_mode = state_fio->FgetInt32();