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)
57 using PC6001::DISPLAY;
59 #if defined(_PC6601) || defined(_PC6601SR)
63 using PC6001::JOYSTICK;
69 // ----------------------------------------------------------------------------
71 // ----------------------------------------------------------------------------
73 VM::VM(EMU* parent_emu) : VM_TEMPLATE(parent_emu)
75 support_pc80s31k = FILEIO::IsFileExisting(create_local_path(_T("DISK.ROM")));
77 support_sub_cpu = false;
79 support_sub_cpu = FILEIO::IsFileExisting(create_local_path(_T(SUB_CPU_ROM_FILE_NAME)));
83 first_device = last_device = NULL;
84 dummy = new DEVICE(this, emu); // must be 1st device
85 event = new EVENT(this, emu); // must be 2nd device
87 pio_sub = new I8255(this, emu);
88 io = new IO(this, emu);
89 noise_seek = new NOISE(this, emu);
90 noise_head_down = new NOISE(this, emu);
91 noise_head_up = new NOISE(this, emu);
92 #if defined(_PC6001MK2SR) || defined(_PC6601SR)
93 psg = new YM2203(this, emu);
95 psg = new AY_3_891X(this, emu);
97 cpu = new Z80(this, emu);
99 if(config.printer_type == 0) {
100 printer = new PRNFILE(this, emu);
105 #if defined(_PC6601) || defined(_PC6601SR)
106 floppy = new FLOPPY(this, emu);
107 floppy->set_context_noise_seek(noise_seek);
108 // floppy->set_context_noise_head_down(noise_head_down);
109 // floppy->set_context_noise_head_up(noise_head_up);
111 joystick = new JOYSTICK(this, emu);
112 memory = new MEMORY(this, emu);
113 timer = new TIMER(this, emu);
116 event->set_context_cpu(cpu);
117 event->set_context_sound(psg);
118 event->set_context_sound(noise_seek);
119 event->set_context_sound(noise_head_down);
120 event->set_context_sound(noise_head_up);
122 pio_sub->set_context_port_b(printer, SIG_PRINTER_DATA, 0xff, 0);
123 pio_sub->set_context_port_c(printer, SIG_PRINTER_STROBE, 0x01, 0);
124 pio_sub->set_context_port_c(memory, SIG_MEMORY_PIO_PORT_C, 0x06, 0); // CRTKILL,CGSWN
127 display = new DISPLAY(this, emu);
128 vdp = new MC6847(this, emu);
129 display->set_context_vdp(vdp);
130 display->set_vram_ptr(memory->get_vram());
131 display->set_context_timer(timer);
132 vdp->load_font_image(create_local_path(_T("CGROM60.60")));
133 vdp->set_context_cpu(cpu);
134 pio_sub->set_context_port_c(vdp, SIG_MC6847_ENABLE, 0x02, 0); // CRTKILL
136 voice = new UPD7752(this, emu);
137 event->set_context_sound(voice);
138 memory->set_context_timer(timer);
140 memory->set_context_cpu(cpu);
141 joystick->set_context_psg(psg);
143 timer->set_context_cpu(cpu);
145 timer->set_context_memory(memory);
147 if(support_sub_cpu) {
148 cpu_sub = new MCS48(this, emu);
149 cpu_sub->set_device_name(_T("MCS48 MCU (Sub)"));
150 sub = new SUB(this, emu);
151 drec = new DATAREC(this, emu);
152 drec->set_device_name(_T("Data Recorder (Sub)"));
153 drec->set_context_noise_play(new NOISE(this, emu));
154 drec->set_context_noise_stop(new NOISE(this, emu));
155 drec->set_context_noise_fast(new NOISE(this, emu));
156 event->set_context_cpu(cpu_sub, 8000000);
157 event->set_context_sound(drec);
158 event->set_context_sound(drec->get_context_noise_play());
159 event->set_context_sound(drec->get_context_noise_stop());
160 event->set_context_sound(drec->get_context_noise_fast());
161 cpu_sub->set_context_mem(new MCS48MEM(this, emu));
162 cpu_sub->set_context_io(sub);
164 cpu_sub->set_context_debugger(new DEBUGGER(this, emu));
166 sub->set_context_pio(pio_sub);
167 sub->set_context_drec(drec);
168 sub->set_context_timer(timer);
169 pio_sub->set_context_port_c(cpu_sub, SIG_CPU_IRQ, 0x80, 0);
170 drec->set_context_ear(sub, SIG_SUB_DATAREC, 1);
171 timer->set_context_sub(sub);
173 psub = new PSUB(this, emu);
174 psub->set_context_pio(pio_sub);
175 psub->set_context_timer(timer);
176 timer->set_context_sub(psub);
179 if(support_pc80s31k) {
180 pio_fdd = new I8255(this, emu);
181 pio_fdd->set_device_name(_T("8255 PIO (FDD I/F)"));
182 pio_pc80s31k = new I8255(this, emu);
183 pio_pc80s31k->set_device_name(_T("8255 PIO (320KB FDD)"));
184 pc80s31k = new PC80S31K(this, emu);
185 pc80s31k->set_device_name(_T("PC-80S31K (320KB FDD)"));
186 fdc_pc80s31k = new UPD765A(this, emu);
187 fdc_pc80s31k->set_device_name(_T("uPD765A FDC (320KB FDD)"));
188 cpu_pc80s31k = new Z80(this, emu);
189 cpu_pc80s31k->set_device_name(_T("Z80 CPU (320KB FDD)"));
191 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 fdc_pc80s31k->set_context_noise_seek(noise_seek);
208 fdc_pc80s31k->set_context_noise_head_down(noise_head_down);
209 fdc_pc80s31k->set_context_noise_head_up(noise_head_up);
210 cpu_pc80s31k->set_context_mem(pc80s31k);
211 cpu_pc80s31k->set_context_io(pc80s31k);
212 cpu_pc80s31k->set_context_intr(pc80s31k);
214 cpu_pc80s31k->set_context_debugger(new DEBUGGER(this, emu));
216 #if defined(_PC6601) || defined(_PC6601SR)
217 floppy->set_context_ext(pio_fdd);
220 pc6031 = new PC6031(this, emu);
221 pc6031->set_context_noise_seek(noise_seek);
222 // pc6031->set_context_noise_head_down(noise_head_down);
223 // pc6031->set_context_noise_head_up(noise_head_up);
224 #if defined(_PC6601) || defined(_PC6601SR)
225 floppy->set_context_ext(pc6031);
231 cpu->set_context_mem(memory);
232 cpu->set_context_io(io);
233 cpu->set_context_intr(timer);
235 cpu->set_context_debugger(new DEBUGGER(this, emu));
239 if(support_sub_cpu) {
240 io->set_iomap_range_rw(0x90, 0x93, sub);
242 io->set_iomap_range_rw(0x90, 0x93, psub);
244 io->set_iomap_alias_w(0xa0, psg, 0); // PSG ch
245 io->set_iomap_alias_w(0xa1, psg, 1); // PSG data
246 io->set_iomap_alias_r(0xa2, psg, 1); // PSG data
247 #if defined(_PC6601SR) || defined(_PC6001MK2SR)
248 io->set_iomap_alias_r(0xa3, psg, 0); // FM status
249 io->set_iomap_range_rw(0x40, 0x6f, memory); // VRAM addr
252 io->set_iomap_single_w(0xb0, display); // VRAM addr
253 io->set_iomap_single_w(0x00, memory); // MEMORY MAP
255 io->set_iomap_single_w(0xb0, memory); // VRAM addr
256 io->set_iomap_range_rw(0xc0, 0xcf, memory); // VRAM addr
257 io->set_iomap_range_rw(0xe0, 0xe3, voice); // VOICE
258 #if defined(_PC6601) || defined(_PC6601SR)
259 io->set_iomap_range_rw(0xb8, 0xbf, timer); // IRQ
260 io->set_iomap_range_rw(0xfa, 0xfb, timer); // IRQ
262 io->set_iomap_range_rw(0xf3, 0xf7, timer); // IRQ/Timer
265 #if defined(_PC6601) || defined(_PC6601SR)
266 io->set_iomap_range_rw(0xb1, 0xb3, floppy); // DISK DRIVE
267 io->set_iomap_range_rw(0xb5, 0xb7, floppy); // DISK DRIVE (Mirror)
268 io->set_iomap_range_rw(0xd0, 0xde, floppy); // DISK DRIVE
270 io->set_iovalue_single_r(0xb1, 0x01);
271 #if defined(_PC6601SR)
272 io->set_iovalue_single_r(0xb2, 0x02);
273 #elif defined(_PC6001MK2SR)
274 io->set_iovalue_single_r(0xb2, 0x00);
277 if(support_pc80s31k) {
278 io->set_iomap_range_rw(0xd0, 0xd2, pio_fdd);
279 io->set_iomap_single_w(0xd3, pio_fdd);
281 io->set_iomap_range_rw(0xd0, 0xd3, pc6031);
284 io->set_iomap_range_rw(0xf0, 0xf2, memory); // MEMORY MAP
286 // initialize all devices
287 #if defined(__GIT_REPO_VERSION)
288 strncpy(_git_revision, __GIT_REPO_VERSION, sizeof(_git_revision) - 1);
290 for(DEVICE* device = first_device; device; device = device->next_device) {
291 device->initialize();
294 if(support_sub_cpu) {
295 // load rom images after cpustate is allocated
298 cpu_sub->load_rom_image(create_local_path(_T(SUB_CPU_ROM_FILE_NAME)));
302 #if defined(_PC6601) || defined(_PC6601SR)
303 floppy->get_disk_handler(0)->drive_num = drive_num++;
304 floppy->get_disk_handler(1)->drive_num = drive_num++;
306 if(support_pc80s31k) {
307 fdc_pc80s31k->get_disk_handler(0)->drive_num = drive_num++;
308 fdc_pc80s31k->get_disk_handler(1)->drive_num = drive_num++;
310 pc6031->get_disk_handler(0)->drive_num = drive_num++;
311 pc6031->get_disk_handler(1)->drive_num = drive_num++;
317 // delete all devices
318 for(DEVICE* device = first_device; device;) {
319 DEVICE *next_device = device->next_device;
322 device = next_device;
326 DEVICE* VM::get_device(int id)
328 for(DEVICE* device = first_device; device; device = device->next_device) {
329 if(device->this_device_id == id) {
336 // ----------------------------------------------------------------------------
337 // drive virtual machine
338 // ----------------------------------------------------------------------------
342 for(DEVICE* device = first_device; device; device = device->next_device) {
345 if(support_pc80s31k) {
346 pio_fdd->write_signal(SIG_I8255_PORT_C, 0, 0xff);
347 pio_pc80s31k->write_signal(SIG_I8255_PORT_C, 0, 0xff);
356 // ----------------------------------------------------------------------------
358 // ----------------------------------------------------------------------------
361 DEVICE *VM::get_cpu(int index)
365 } else if(index == 1) {
367 } else if(index == 2) {
374 // ----------------------------------------------------------------------------
376 // ----------------------------------------------------------------------------
378 void VM::draw_screen()
381 display->draw_screen();
383 memory->draw_screen();
386 // ----------------------------------------------------------------------------
388 // ----------------------------------------------------------------------------
390 void VM::initialize_sound(int rate, int samples)
392 // init sound manager
393 event->initialize_sound(rate, samples);
396 psg->initialize_sound(rate, 4000000, samples, 0, 0);
398 voice->initialize_sound(rate);
402 uint16_t* VM::create_sound(int* extra_frames)
404 return event->create_sound(extra_frames);
407 int VM::get_sound_buffer_ptr()
409 return event->get_sound_buffer_ptr();
412 #ifdef USE_SOUND_VOLUME
413 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
416 psg->set_volume(1, decibel_l, decibel_r);
417 #if !defined(_PC6001)
418 } else if(ch-- == 0) {
419 voice->set_volume(0, decibel_l, decibel_r);
421 } else if(ch-- == 0) {
422 if(support_sub_cpu) {
423 drec->set_volume(0, decibel_l, decibel_r);
425 } else if(ch-- == 0) {
426 noise_seek->set_volume(0, decibel_l, decibel_r);
427 noise_head_down->set_volume(0, decibel_l, decibel_r);
428 noise_head_up->set_volume(0, decibel_l, decibel_r);
429 } else if(ch-- == 0) {
430 if(support_sub_cpu) {
431 drec->get_context_noise_play()->set_volume(0, decibel_l, decibel_r);
432 drec->get_context_noise_stop()->set_volume(0, decibel_l, decibel_r);
433 drec->get_context_noise_fast()->set_volume(0, decibel_l, decibel_r);
439 // ----------------------------------------------------------------------------
441 // ----------------------------------------------------------------------------
443 void VM::key_down(int code, bool repeat)
445 if(!support_sub_cpu) {
446 psub->key_down(code);
450 void VM::key_up(int code)
452 if(!support_sub_cpu) {
457 // ----------------------------------------------------------------------------
459 // ----------------------------------------------------------------------------
461 void VM::open_cart(int drv, const _TCHAR* file_path)
464 memory->open_cart(file_path);
469 void VM::close_cart(int drv)
472 memory->close_cart();
477 bool VM::is_cart_inserted(int drv)
480 return memory->is_cart_inserted();
486 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
488 #if defined(_PC6601) || defined(_PC6601SR)
490 floppy->open_disk(drv, file_path, bank);
496 if(support_pc80s31k) {
497 fdc_pc80s31k->open_disk(drv, file_path, bank);
499 pc6031->open_disk(drv, file_path, bank);
503 void VM::close_floppy_disk(int drv)
505 #if defined(_PC6601) || defined(_PC6601SR)
507 floppy->close_disk(drv);
513 if(support_pc80s31k) {
514 fdc_pc80s31k->close_disk(drv);
516 pc6031->close_disk(drv);
520 bool VM::is_floppy_disk_inserted(int drv)
522 #if defined(_PC6601) || defined(_PC6601SR)
524 return floppy->is_disk_inserted(drv);
529 if(support_pc80s31k) {
530 return fdc_pc80s31k->is_disk_inserted(drv);
532 return pc6031->is_disk_inserted(drv);
536 void VM::is_floppy_disk_protected(int drv, bool value)
538 #if defined(_PC6601) || defined(_PC6601SR)
540 floppy->is_disk_protected(drv, value);
546 if(support_pc80s31k) {
547 fdc_pc80s31k->is_disk_protected(drv, value);
549 pc6031->is_disk_protected(drv, value);
553 bool VM::is_floppy_disk_protected(int drv)
555 #if defined(_PC6601) || defined(_PC6601SR)
557 return floppy->is_disk_protected(drv);
562 if(support_pc80s31k) {
563 return fdc_pc80s31k->is_disk_protected(drv);
565 return pc6031->is_disk_protected(drv);
569 uint32_t VM::is_floppy_disk_accessed()
571 uint32_t status = 0; /// fdc->read_signal(0);
572 if(support_pc80s31k) {
573 status |= fdc_pc80s31k->read_signal(0);
575 status |= pc6031->read_signal(0);
577 #if defined(_PC6601) || defined(_PC6601SR)
579 status |= floppy->read_signal(0);
584 void VM::play_tape(int drv, const _TCHAR* file_path)
586 if(support_sub_cpu) {
587 // support both p6/p6t and wav
588 drec->play_tape(file_path);
589 // drec->set_remote(true);
591 // support only p6/p6t
592 psub->play_tape(file_path);
596 void VM::rec_tape(int drv, const _TCHAR* file_path)
598 if(support_sub_cpu) {
599 // support both p6/p6t and wav
600 sub->rec_tape(file_path); // temporary
601 // drec->rec_tape(file_path);
602 // drec->set_remote(true);
604 // support both p6/p6t and wav
605 psub->rec_tape(file_path);
609 void VM::close_tape(int drv)
611 if(support_sub_cpu) {
612 if(sub->is_tape_inserted()) {
613 sub->close_tape(); // temporary
618 // drec->set_remote(false);
625 bool VM::is_tape_inserted(int drv)
627 if(support_sub_cpu) {
628 return drec->is_tape_inserted() || sub->is_tape_inserted();
630 return psub->is_tape_inserted();
634 bool VM::is_tape_playing(int drv)
636 if(support_sub_cpu) {
637 return drec->is_tape_playing();
643 bool VM::is_tape_recording(int drv)
645 if(support_sub_cpu) {
646 return drec->is_tape_recording();
652 int VM::get_tape_position(int drv)
654 if(support_sub_cpu) {
655 return drec->get_tape_position();
661 const _TCHAR* VM::get_tape_message(int drv)
663 if(support_sub_cpu) {
664 return drec->get_message();
670 void VM::push_play(int drv)
672 if(support_sub_cpu) {
674 drec->set_remote(true);
678 void VM::push_stop(int drv)
680 if(support_sub_cpu) {
681 drec->set_remote(false);
685 void VM::push_fast_forward(int drv)
687 if(support_sub_cpu) {
689 drec->set_remote(true);
693 void VM::push_fast_rewind(int drv)
695 if(support_sub_cpu) {
696 drec->set_ff_rew(-1);
697 drec->set_remote(true);
701 bool VM::is_frame_skippable()
703 return event->is_frame_skippable();
706 void VM::update_config()
708 for(DEVICE* device = first_device; device; device = device->next_device) {
709 device->update_config();
713 #define STATE_VERSION 6
715 bool VM::process_state(FILEIO* state_fio, bool loading)
717 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
720 for(DEVICE* device = first_device; device; device = device->next_device) {
721 // Note: typeid(foo).name is fixed by recent ABI.Not dec 6.
722 // const char *name = typeid(*device).name();
723 // But, using get_device_name() instead of typeid(foo).name() 20181008 K.O
724 const char *name = device->get_device_name();
725 int len = strlen(name);
727 if(!state_fio->StateCheckInt32(len)) {
729 printf("Class name len Error: DEVID=%d EXPECT=%s\n", device->this_device_id, name);
733 if(!state_fio->StateCheckBuffer(name, len, 1)) {
735 printf("Class name Error: DEVID=%d EXPECT=%s\n", device->this_device_id, name);
739 if(!device->process_state(state_fio, loading)) {
741 printf("Data loading Error: DEVID=%d\n", device->this_device_id);
746 // Machine specified.
747 state_fio->StateInt32(sr_mode);