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"
29 #include "../pc6031.h"
30 #include "../pc80s31k.h"
31 #include "../prnfile.h"
32 #include "../upd765a.h"
33 #if defined(_PC6001MK2SR) || defined(_PC6601SR)
34 #include "../ym2203.h"
36 #include "../ay_3_891x.h"
40 #include "../datarec.h"
44 #include "../debugger.h"
47 #if defined(_PC6601) || defined(_PC6601SR)
56 // ----------------------------------------------------------------------------
58 // ----------------------------------------------------------------------------
60 VM::VM(EMU* parent_emu) : VM_TEMPLATE(parent_emu)
62 support_pc80s31k = FILEIO::IsFileExisting(create_local_path(_T("DISK.ROM")));
64 support_sub_cpu = false;
66 support_sub_cpu = FILEIO::IsFileExisting(create_local_path(_T(SUB_CPU_ROM_FILE_NAME)));
70 first_device = last_device = NULL;
71 dummy = new DEVICE(this, emu); // must be 1st device
72 event = new EVENT(this, emu); // must be 2nd device
74 pio_sub = new I8255(this, emu);
75 io = new IO(this, emu);
76 noise_seek = new NOISE(this, emu);
77 noise_head_down = new NOISE(this, emu);
78 noise_head_up = new NOISE(this, emu);
79 #if defined(_PC6001MK2SR) || defined(_PC6601SR)
80 psg = new YM2203(this, emu);
82 psg = new AY_3_891X(this, emu);
84 cpu = new Z80(this, emu);
86 if(config.printer_type == 0) {
87 printer = new PRNFILE(this, emu);
92 #if defined(_PC6601) || defined(_PC6601SR)
93 floppy = new FLOPPY(this, emu);
94 floppy->set_context_noise_seek(noise_seek);
95 // floppy->set_context_noise_head_down(noise_head_down);
96 // floppy->set_context_noise_head_up(noise_head_up);
98 joystick = new JOYSTICK(this, emu);
99 memory = new MEMORY(this, emu);
100 timer = new TIMER(this, emu);
103 event->set_context_cpu(cpu);
104 event->set_context_sound(psg);
105 event->set_context_sound(noise_seek);
106 event->set_context_sound(noise_head_down);
107 event->set_context_sound(noise_head_up);
109 pio_sub->set_context_port_b(printer, SIG_PRINTER_DATA, 0xff, 0);
110 pio_sub->set_context_port_c(printer, SIG_PRINTER_STROBE, 0x01, 0);
111 pio_sub->set_context_port_c(memory, SIG_MEMORY_PIO_PORT_C, 0x06, 0); // CRTKILL,CGSWN
114 display = new DISPLAY(this, emu);
115 vdp = new MC6847(this, emu);
116 display->set_context_vdp(vdp);
117 display->set_vram_ptr(memory->get_vram());
118 display->set_context_timer(timer);
119 vdp->load_font_image(create_local_path(_T("CGROM60.60")));
120 vdp->set_context_cpu(cpu);
121 pio_sub->set_context_port_c(vdp, SIG_MC6847_ENABLE, 0x02, 0); // CRTKILL
123 voice = new UPD7752(this, emu);
124 event->set_context_sound(voice);
125 memory->set_context_timer(timer);
127 memory->set_context_cpu(cpu);
128 joystick->set_context_psg(psg);
130 timer->set_context_cpu(cpu);
132 timer->set_context_memory(memory);
134 if(support_sub_cpu) {
135 cpu_sub = new MCS48(this, emu);
136 cpu_sub->set_device_name(_T("MCS48 MCU (Sub)"));
137 sub = new SUB(this, emu);
138 drec = new DATAREC(this, emu);
139 drec->set_device_name(_T("Data Recorder (Sub)"));
140 drec->set_context_noise_play(new NOISE(this, emu));
141 drec->set_context_noise_stop(new NOISE(this, emu));
142 drec->set_context_noise_fast(new NOISE(this, emu));
143 event->set_context_cpu(cpu_sub, 8000000);
144 event->set_context_sound(drec);
145 event->set_context_sound(drec->get_context_noise_play());
146 event->set_context_sound(drec->get_context_noise_stop());
147 event->set_context_sound(drec->get_context_noise_fast());
148 cpu_sub->set_context_mem(new MCS48MEM(this, emu));
149 cpu_sub->set_context_io(sub);
151 cpu_sub->set_context_debugger(new DEBUGGER(this, emu));
153 sub->set_context_pio(pio_sub);
154 sub->set_context_drec(drec);
155 sub->set_context_timer(timer);
156 pio_sub->set_context_port_c(cpu_sub, SIG_CPU_IRQ, 0x80, 0);
157 drec->set_context_ear(sub, SIG_SUB_DATAREC, 1);
158 timer->set_context_sub(sub);
160 psub = new PSUB(this, emu);
161 psub->set_context_pio(pio_sub);
162 psub->set_context_timer(timer);
163 timer->set_context_sub(psub);
166 if(support_pc80s31k) {
167 pio_fdd = new I8255(this, emu);
168 pio_fdd->set_device_name(_T("8255 PIO (FDD I/F)"));
169 pio_pc80s31k = new I8255(this, emu);
170 pio_pc80s31k->set_device_name(_T("8255 PIO (320KB FDD)"));
171 pc80s31k = new PC80S31K(this, emu);
172 pc80s31k->set_device_name(_T("PC-80S31K (320KB FDD)"));
173 fdc_pc80s31k = new UPD765A(this, emu);
174 fdc_pc80s31k->set_device_name(_T("uPD765A FDC (320KB FDD)"));
175 cpu_pc80s31k = new Z80(this, emu);
176 cpu_pc80s31k->set_device_name(_T("Z80 CPU (320KB FDD)"));
178 event->set_context_cpu(cpu_pc80s31k, 4000000);
180 pc80s31k->set_context_cpu(cpu_pc80s31k);
181 pc80s31k->set_context_fdc(fdc_pc80s31k);
182 pc80s31k->set_context_pio(pio_pc80s31k);
183 pio_fdd->set_context_port_a(pio_pc80s31k, SIG_I8255_PORT_B, 0xff, 0);
184 pio_fdd->set_context_port_b(pio_pc80s31k, SIG_I8255_PORT_A, 0xff, 0);
185 pio_fdd->set_context_port_c(pio_pc80s31k, SIG_I8255_PORT_C, 0x0f, 4);
186 pio_fdd->set_context_port_c(pio_pc80s31k, SIG_I8255_PORT_C, 0xf0, -4);
187 pio_fdd->clear_ports_by_cmdreg = true;
188 pio_pc80s31k->set_context_port_a(pio_fdd, SIG_I8255_PORT_B, 0xff, 0);
189 pio_pc80s31k->set_context_port_b(pio_fdd, SIG_I8255_PORT_A, 0xff, 0);
190 pio_pc80s31k->set_context_port_c(pio_fdd, SIG_I8255_PORT_C, 0x0f, 4);
191 pio_pc80s31k->set_context_port_c(pio_fdd, SIG_I8255_PORT_C, 0xf0, -4);
192 pio_pc80s31k->clear_ports_by_cmdreg = true;
193 fdc_pc80s31k->set_context_irq(cpu_pc80s31k, SIG_CPU_IRQ, 1);
194 fdc_pc80s31k->set_context_noise_seek(noise_seek);
195 fdc_pc80s31k->set_context_noise_head_down(noise_head_down);
196 fdc_pc80s31k->set_context_noise_head_up(noise_head_up);
197 cpu_pc80s31k->set_context_mem(pc80s31k);
198 cpu_pc80s31k->set_context_io(pc80s31k);
199 cpu_pc80s31k->set_context_intr(pc80s31k);
201 cpu_pc80s31k->set_context_debugger(new DEBUGGER(this, emu));
203 #if defined(_PC6601) || defined(_PC6601SR)
204 floppy->set_context_ext(pio_fdd);
207 pc6031 = new PC6031(this, emu);
208 pc6031->set_context_noise_seek(noise_seek);
209 // pc6031->set_context_noise_head_down(noise_head_down);
210 // pc6031->set_context_noise_head_up(noise_head_up);
211 #if defined(_PC6601) || defined(_PC6601SR)
212 floppy->set_context_ext(pc6031);
218 cpu->set_context_mem(memory);
219 cpu->set_context_io(io);
220 cpu->set_context_intr(timer);
222 cpu->set_context_debugger(new DEBUGGER(this, emu));
226 if(support_sub_cpu) {
227 io->set_iomap_range_rw(0x90, 0x93, sub);
229 io->set_iomap_range_rw(0x90, 0x93, psub);
231 io->set_iomap_alias_w(0xa0, psg, 0); // PSG ch
232 io->set_iomap_alias_w(0xa1, psg, 1); // PSG data
233 io->set_iomap_alias_r(0xa2, psg, 1); // PSG data
234 #if defined(_PC6601SR) || defined(_PC6001MK2SR)
235 io->set_iomap_alias_r(0xa3, psg, 0); // FM status
236 io->set_iomap_range_rw(0x40, 0x6f, memory); // VRAM addr
239 io->set_iomap_single_w(0xb0, display); // VRAM addr
240 io->set_iomap_single_w(0x00, memory); // MEMORY MAP
242 io->set_iomap_single_w(0xb0, memory); // VRAM addr
243 io->set_iomap_range_rw(0xc0, 0xcf, memory); // VRAM addr
244 io->set_iomap_range_rw(0xe0, 0xe3, voice); // VOICE
245 #if defined(_PC6601) || defined(_PC6601SR)
246 io->set_iomap_range_rw(0xb8, 0xbf, timer); // IRQ
247 io->set_iomap_range_rw(0xfa, 0xfb, timer); // IRQ
249 io->set_iomap_range_rw(0xf3, 0xf7, timer); // IRQ/Timer
252 #if defined(_PC6601) || defined(_PC6601SR)
253 io->set_iomap_range_rw(0xb1, 0xb3, floppy); // DISK DRIVE
254 io->set_iomap_range_rw(0xb5, 0xb7, floppy); // DISK DRIVE (Mirror)
255 io->set_iomap_range_rw(0xd0, 0xde, floppy); // DISK DRIVE
257 io->set_iovalue_single_r(0xb1, 0x01);
258 #if defined(_PC6601SR)
259 io->set_iovalue_single_r(0xb2, 0x02);
260 #elif defined(_PC6001MK2SR)
261 io->set_iovalue_single_r(0xb2, 0x00);
264 if(support_pc80s31k) {
265 io->set_iomap_range_rw(0xd0, 0xd2, pio_fdd);
266 io->set_iomap_single_w(0xd3, pio_fdd);
268 io->set_iomap_range_rw(0xd0, 0xd3, pc6031);
271 io->set_iomap_range_rw(0xf0, 0xf2, memory); // MEMORY MAP
273 // initialize all devices
274 for(DEVICE* device = first_device; device; device = device->next_device) {
275 device->initialize();
278 if(support_sub_cpu) {
279 // load rom images after cpustate is allocated
282 cpu_sub->load_rom_image(create_local_path(_T(SUB_CPU_ROM_FILE_NAME)));
286 #if defined(_PC6601) || defined(_PC6601SR)
287 floppy->get_disk_handler(0)->drive_num = drive_num++;
288 floppy->get_disk_handler(1)->drive_num = drive_num++;
290 if(support_pc80s31k) {
291 fdc_pc80s31k->get_disk_handler(0)->drive_num = drive_num++;
292 fdc_pc80s31k->get_disk_handler(1)->drive_num = drive_num++;
294 pc6031->get_disk_handler(0)->drive_num = drive_num++;
295 pc6031->get_disk_handler(1)->drive_num = drive_num++;
302 // delete all devices
303 for(DEVICE* device = first_device; device;) {
304 DEVICE *next_device = device->next_device;
307 device = next_device;
311 DEVICE* VM::get_device(int id)
313 for(DEVICE* device = first_device; device; device = device->next_device) {
314 if(device->this_device_id == id) {
321 // ----------------------------------------------------------------------------
322 // drive virtual machine
323 // ----------------------------------------------------------------------------
327 for(DEVICE* device = first_device; device; device = device->next_device) {
330 if(support_pc80s31k) {
331 pio_fdd->write_signal(SIG_I8255_PORT_C, 0, 0xff);
332 pio_pc80s31k->write_signal(SIG_I8255_PORT_C, 0, 0xff);
341 // ----------------------------------------------------------------------------
343 // ----------------------------------------------------------------------------
346 DEVICE *VM::get_cpu(int index)
350 } else if(index == 1) {
352 } else if(index == 2) {
359 // ----------------------------------------------------------------------------
361 // ----------------------------------------------------------------------------
363 void VM::draw_screen()
366 display->draw_screen();
368 memory->draw_screen();
371 // ----------------------------------------------------------------------------
373 // ----------------------------------------------------------------------------
375 void VM::initialize_sound(int rate, int samples)
377 // init sound manager
378 event->initialize_sound(rate, samples);
381 psg->initialize_sound(rate, 4000000, samples, 0, 0);
383 voice->initialize_sound(rate);
387 uint16_t* VM::create_sound(int* extra_frames)
389 return event->create_sound(extra_frames);
392 int VM::get_sound_buffer_ptr()
394 return event->get_sound_buffer_ptr();
397 #ifdef USE_SOUND_VOLUME
398 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
401 psg->set_volume(1, decibel_l, decibel_r);
402 #if !defined(_PC6001)
403 } else if(ch-- == 0) {
404 voice->set_volume(0, decibel_l, decibel_r);
406 } else if(ch-- == 0) {
407 if(support_sub_cpu) {
408 drec->set_volume(0, decibel_l, decibel_r);
410 } else if(ch-- == 0) {
411 noise_seek->set_volume(0, decibel_l, decibel_r);
412 noise_head_down->set_volume(0, decibel_l, decibel_r);
413 noise_head_up->set_volume(0, decibel_l, decibel_r);
414 } else if(ch-- == 0) {
415 if(support_sub_cpu) {
416 drec->get_context_noise_play()->set_volume(0, decibel_l, decibel_r);
417 drec->get_context_noise_stop()->set_volume(0, decibel_l, decibel_r);
418 drec->get_context_noise_fast()->set_volume(0, decibel_l, decibel_r);
424 // ----------------------------------------------------------------------------
426 // ----------------------------------------------------------------------------
428 void VM::key_down(int code, bool repeat)
430 if(!support_sub_cpu) {
431 psub->key_down(code);
435 void VM::key_up(int code)
437 if(!support_sub_cpu) {
442 // ----------------------------------------------------------------------------
444 // ----------------------------------------------------------------------------
446 void VM::open_cart(int drv, const _TCHAR* file_path)
449 memory->open_cart(file_path);
454 void VM::close_cart(int drv)
457 memory->close_cart();
462 bool VM::is_cart_inserted(int drv)
465 return memory->is_cart_inserted();
471 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
473 #if defined(_PC6601) || defined(_PC6601SR)
475 floppy->open_disk(drv, file_path, bank);
481 if(support_pc80s31k) {
482 fdc_pc80s31k->open_disk(drv, file_path, bank);
484 pc6031->open_disk(drv, file_path, bank);
488 void VM::close_floppy_disk(int drv)
490 #if defined(_PC6601) || defined(_PC6601SR)
492 floppy->close_disk(drv);
498 if(support_pc80s31k) {
499 fdc_pc80s31k->close_disk(drv);
501 pc6031->close_disk(drv);
505 bool VM::is_floppy_disk_inserted(int drv)
507 #if defined(_PC6601) || defined(_PC6601SR)
509 return floppy->is_disk_inserted(drv);
514 if(support_pc80s31k) {
515 return fdc_pc80s31k->is_disk_inserted(drv);
517 return pc6031->is_disk_inserted(drv);
521 void VM::is_floppy_disk_protected(int drv, bool value)
523 #if defined(_PC6601) || defined(_PC6601SR)
525 floppy->is_disk_protected(drv, value);
531 if(support_pc80s31k) {
532 fdc_pc80s31k->is_disk_protected(drv, value);
534 pc6031->is_disk_protected(drv, value);
538 bool VM::is_floppy_disk_protected(int drv)
540 #if defined(_PC6601) || defined(_PC6601SR)
542 return floppy->is_disk_protected(drv);
547 if(support_pc80s31k) {
548 return fdc_pc80s31k->is_disk_protected(drv);
550 return pc6031->is_disk_protected(drv);
554 uint32_t VM::is_floppy_disk_accessed()
556 uint32_t status = 0; /// fdc->read_signal(0);
557 if(support_pc80s31k) {
558 status |= fdc_pc80s31k->read_signal(0);
560 status |= pc6031->read_signal(0);
562 #if defined(_PC6601) || defined(_PC6601SR)
564 status |= floppy->read_signal(0);
569 void VM::play_tape(int drv, const _TCHAR* file_path)
571 if(support_sub_cpu) {
572 // support both p6/p6t and wav
573 drec->play_tape(file_path);
574 // drec->set_remote(true);
576 // support only p6/p6t
577 psub->play_tape(file_path);
581 void VM::rec_tape(int drv, const _TCHAR* file_path)
583 if(support_sub_cpu) {
584 // support both p6/p6t and wav
585 sub->rec_tape(file_path); // temporary
586 // drec->rec_tape(file_path);
587 // drec->set_remote(true);
589 // support both p6/p6t and wav
590 psub->rec_tape(file_path);
594 void VM::close_tape(int drv)
596 if(support_sub_cpu) {
597 if(sub->is_tape_inserted()) {
598 sub->close_tape(); // temporary
603 // drec->set_remote(false);
610 bool VM::is_tape_inserted(int drv)
612 if(support_sub_cpu) {
613 return drec->is_tape_inserted() || sub->is_tape_inserted();
615 return psub->is_tape_inserted();
619 bool VM::is_tape_playing(int drv)
621 if(support_sub_cpu) {
622 return drec->is_tape_playing();
628 bool VM::is_tape_recording(int drv)
630 if(support_sub_cpu) {
631 return drec->is_tape_recording();
637 int VM::get_tape_position(int drv)
639 if(support_sub_cpu) {
640 return drec->get_tape_position();
646 const _TCHAR* VM::get_tape_message(int drv)
648 if(support_sub_cpu) {
649 return drec->get_message();
655 void VM::push_play(int drv)
657 if(support_sub_cpu) {
659 drec->set_remote(true);
663 void VM::push_stop(int drv)
665 if(support_sub_cpu) {
666 drec->set_remote(false);
670 void VM::push_fast_forward(int drv)
672 if(support_sub_cpu) {
674 drec->set_remote(true);
678 void VM::push_fast_rewind(int drv)
680 if(support_sub_cpu) {
681 drec->set_ff_rew(-1);
682 drec->set_remote(true);
686 bool VM::is_frame_skippable()
688 return event->is_frame_skippable();
691 void VM::update_config()
693 for(DEVICE* device = first_device; device; device = device->next_device) {
694 device->update_config();
698 #define STATE_VERSION 6
700 #include "../../statesub.h"
701 #include "../../qt/gui/csp_logger.h"
702 extern CSP_Logger DLL_PREFIX_I *csp_logger;
704 void VM::decl_state(void)
707 state_entry = new csp_state_utils(STATE_VERSION, 0, (_TCHAR *)(_T("CSP::PC_6001_HEAD")), csp_logger);
708 #elif defined(_PC6001MK2)
709 state_entry = new csp_state_utils(STATE_VERSION, 0, (_TCHAR *)(_T("CSP::PC_6001_MK2_HEAD")), csp_logger);
710 #elif defined(_PC6001MK2SR)
711 state_entry = new csp_state_utils(STATE_VERSION, 0, (_TCHAR *)(_T("CSP::PC_6001_MK2_SR_HEAD")), csp_logger);
712 #elif defined(_PC6601)
713 state_entry = new csp_state_utils(STATE_VERSION, 0, (_TCHAR *)(_T("CSP::PC_6601_HEAD")), csp_logger);
714 #elif defined(_PC601SR)
715 state_entry = new csp_state_utils(STATE_VERSION, 0, (_TCHAR *)(_T("CSP::PC_6601_SR_HEAD")), csp_logger);
717 state_entry = new csp_state_utils(STATE_VERSION, 0, (_TCHAR *)(_T("CSP::PC_6001_SERIES_HEAD")), csp_logger);
719 DECL_STATE_ENTRY_INT32(sr_mode);
720 for(DEVICE* device = first_device; device; device = device->next_device) {
721 device->decl_state();
725 void VM::save_state(FILEIO* state_fio)
727 //state_fio->FputUint32(STATE_VERSION);
729 if(state_entry != NULL) {
730 state_entry->save_state(state_fio);
732 for(DEVICE* device = first_device; device; device = device->next_device) {
733 device->save_state(state_fio);
735 //state_fio->FputInt32(sr_mode);
738 bool VM::load_state(FILEIO* state_fio)
740 //if(state_fio->FgetUint32() != STATE_VERSION) {
744 if(state_entry != NULL) {
745 mb = state_entry->load_state(state_fio);
748 emu->out_debug_log("INFO: HEADER DATA ERROR");
751 for(DEVICE* device = first_device; device; device = device->next_device) {
752 if(!device->load_state(state_fio)) {
756 //sr_mode = state_fio->FgetInt32();