3 NEC PC-8801MA Emulator 'ePC-8801MA'
4 NEC PC-8001mkIISR Emulator 'ePC-8001mkIISR'
6 Author : Takeda.Toshiya
13 #include "../../emu.h"
14 #include "../device.h"
19 #include "../pcm1bit.h"
20 //#include "../pcpr201.h"
21 #include "../prnfile.h"
22 #include "../upd1990a.h"
23 #include "../ym2203.h"
28 #include "../pc80s31k.h"
29 #include "../upd765a.h"
32 #include "../debugger.h"
35 #ifdef SUPPORT_PC88_CDROM
36 #include "../scsi_cdrom.h"
37 #include "../scsi_host.h"
40 #ifdef SUPPORT_PC88_HMB20
41 #include "../ym2151.h"
44 #ifdef SUPPORT_PC88_PCG8100
51 // ----------------------------------------------------------------------------
53 // ----------------------------------------------------------------------------
55 VM::VM(EMU* parent_emu) : VM_TEMPLATE(parent_emu)
58 boot_mode = config.boot_mode;
61 first_device = last_device = NULL;
62 dummy = new DEVICE(this, emu); // must be 1st device
64 pc88event = new EVENT(this, emu);
65 // pc88event->set_device_name(_T("Event Manager (PC-8801)"));
66 // pc88event->set_frames_per_sec(60);
67 // pc88event->set_lines_per_frame(260);
69 pc88 = new PC88(this, emu);
70 // pc88->set_context_event_manager(pc88event);
71 pc88sio = new I8251(this, emu);
72 // pc88sio->set_device_name(_T("8251 SIO (PC-8801)"));
73 // pc88sio->set_context_event_manager(pc88event);
74 pc88pio = new I8255(this, emu);
75 // pc88pio->set_device_name(_T("8255 PIO (PC-8801)"));
76 // pc88pio->set_context_event_manager(pc88event);
77 pc88pcm = new PCM1BIT(this, emu);
78 // pc88pcm->set_device_name(_T("1-Bit PCM Sound (PC-8801)"));
79 // pc88pcm->set_context_event_manager(pc88event);
80 pc88rtc = new UPD1990A(this, emu);
81 // pc88rtc->set_device_name(_T("uPD1990A RTC (PC-8801)"));
82 // pc88rtc->set_context_event_manager(pc88event);
84 // 0: 44h:OPNA A4h:None PC-8801FH/MH or later
85 // 1: 44h:OPN A4h:None PC-8801mkIISR/TR/FR/MR
86 // 2: 44h:OPN A4h:OPNA PC-8801mkIISR/TR/FR/MR + PC-8801-23
87 // 3: 44h:OPN A4h:OPN PC-8801mkIISR/TR/FR/MR + PC-8801-11
88 // 4: 44h:OPNA A4h:OPNA PC-8801FH/MH or later + PC-8801-24
89 // 5: 44h:OPNA A4h:OPN PC-8801FH/MH or later + PC-8801-11
90 pc88opn = new YM2203(this, emu);
91 // pc88opn->set_context_event_manager(pc88event);
93 #ifdef SUPPORT_PC88_OPNA
94 if(config.sound_type == 0 || config.sound_type == 4 || config.sound_type == 5) {
95 pc88opn->is_ym2608 = true;
96 pc88opn->set_device_name(_T("YM2608 OPNA"));
99 pc88opn->is_ym2608 = false;
100 pc88opn->set_device_name(_T("YM2203 OPN"));
101 #ifdef SUPPORT_PC88_OPNA
104 #ifdef SUPPORT_PC88_SB2
105 if(config.sound_type >= 2) {
106 pc88sb2 = new YM2203(this, emu);
107 // pc88sb2->set_context_event_manager(pc88event);
108 #ifdef SUPPORT_PC88_OPNA
109 if(config.sound_type == 2 || config.sound_type == 4) {
110 pc88sb2->is_ym2608 = true;
111 pc88sb2->set_device_name(_T("YM2608 OPNA (SB2)"));
114 pc88sb2->is_ym2608 = false;
115 pc88sb2->set_device_name(_T("YM2203 OPN (SB2)"));
116 #ifdef SUPPORT_PC88_OPNA
124 if(config.printer_type == 0) {
125 pc88prn = new PRNFILE(this, emu);
126 // pc88prn->set_context_event_manager(pc88event);
127 // } else if(config.printer_type == 1) {
128 // pc88prn = new PCPR201(this, emu);
129 // pc88prn->set_context_event_manager(pc88event);
133 pc88cpu = new Z80(this, emu);
134 // pc88cpu->set_context_event_manager(pc88event);
136 pc88sub = new PC80S31K(this, emu);
137 pc88sub->set_device_name(_T("PC-80S31K (Sub)"));
138 // pc88sub->set_context_event_manager(pc88event);
139 pc88pio_sub = new I8255(this, emu);
140 pc88pio_sub->set_device_name(_T("8255 PIO (Sub)"));
141 // pc88pio_sub->set_context_event_manager(pc88event);
142 pc88fdc_sub = new UPD765A(this, emu);
143 pc88fdc_sub->set_device_name(_T("uPD765A FDC (Sub)"));
144 // pc88fdc_sub->set_context_event_manager(pc88event);
145 pc88noise_seek = new NOISE(this, emu);
146 // pc88noise_seek->set_context_event_manager(pc88event);
147 pc88noise_head_down = new NOISE(this, emu);
148 // pc88noise_head_down->set_context_event_manager(pc88event);
149 pc88noise_head_up = new NOISE(this, emu);
150 // pc88noise_head_up->set_context_event_manager(pc88event);
151 pc88cpu_sub = new Z80(this, emu);
152 pc88cpu_sub->set_device_name(_T("Z80 CPU (Sub)"));
153 // pc88cpu_sub->set_context_event_manager(pc88event);
155 #ifdef SUPPORT_PC88_CDROM
156 pc88scsi_host = new SCSI_HOST(this, emu);
157 // pc88scsi_host->set_context_event_manager(pc88event);
158 pc88scsi_cdrom = new SCSI_CDROM(this, emu);
159 // pc88scsi_cdrom->set_context_event_manager(pc88event);
162 #ifdef SUPPORT_PC88_HMB20
163 pc88opm = new YM2151(this, emu);
164 pc88opm->set_device_name(_T("YM2151 OPM (HMB20)"));
165 // pc88opm->set_context_event_manager(pc88event);
168 #ifdef SUPPORT_PC88_PCG8100
169 pc88pit = new I8253(this, emu);
170 pc88pit->set_device_name(_T("8253 PIT (PCG8100)"));
171 // pc88pit->set_context_event_manager(pc88event);
172 pc88pcm0 = new PCM1BIT(this, emu);
173 pc88pcm0->set_device_name(_T("1-Bit PCM Sound (PCG8100 #1)"));
174 // pc88pcm0->set_context_event_manager(pc88event);
175 pc88pcm1 = new PCM1BIT(this, emu);
176 pc88pcm1->set_device_name(_T("1-Bit PCM Sound (PCG8100 #2)"));
177 // pc88pcm1->set_context_event_manager(pc88event);
178 pc88pcm2 = new PCM1BIT(this, emu);
179 pc88pcm2->set_device_name(_T("1-Bit PCM Sound (PCG8100 #3)"));
180 // pc88pcm2->set_context_event_manager(pc88event);
183 #ifdef SUPPORT_PC88_HIGH_CLOCK
184 pc88event->set_context_cpu(pc88cpu, (config.cpu_type == 1) ? 3993624 : 7987248);
186 pc88event->set_context_cpu(pc88cpu, 3993624);
188 pc88event->set_context_cpu(pc88cpu_sub, 3993624);
189 pc88event->set_context_sound(pc88opn);
190 #ifdef SUPPORT_PC88_SB2
191 if(pc88sb2 != NULL) {
192 pc88event->set_context_sound(pc88sb2);
195 pc88event->set_context_sound(pc88pcm);
196 #ifdef SUPPORT_PC88_CDROM
197 pc88event->set_context_sound(pc88scsi_cdrom);
199 #ifdef SUPPORT_PC88_HMB20
200 pc88event->set_context_sound(pc88opm);
202 #ifdef SUPPORT_PC88_PCG8100
203 pc88event->set_context_sound(pc88pcm0);
204 pc88event->set_context_sound(pc88pcm1);
205 pc88event->set_context_sound(pc88pcm2);
207 pc88event->set_context_sound(pc88noise_seek);
208 pc88event->set_context_sound(pc88noise_head_down);
209 pc88event->set_context_sound(pc88noise_head_up);
211 pc88->set_context_cpu(pc88cpu);
212 pc88->set_context_opn(pc88opn);
213 #ifdef SUPPORT_PC88_SB2
214 pc88->set_context_sb2(pc88sb2);
216 pc88->set_context_pcm(pc88pcm);
217 pc88->set_context_pio(pc88pio);
218 pc88->set_context_prn(pc88prn);
219 pc88->set_context_rtc(pc88rtc);
220 pc88->set_context_sio(pc88sio);
221 #ifdef SUPPORT_PC88_CDROM
222 pc88->set_context_scsi_host(pc88scsi_host);
223 pc88->set_context_scsi_cdrom(pc88scsi_cdrom);
225 #ifdef SUPPORT_PC88_HMB20
226 pc88->set_context_opm(pc88opm);
228 #ifdef SUPPORT_PC88_PCG8100
229 pc88->set_context_pcg_pit(pc88pit);
230 pc88->set_context_pcg_pcm0(pc88pcm0);
231 pc88->set_context_pcg_pcm1(pc88pcm1);
232 pc88->set_context_pcg_pcm2(pc88pcm2);
234 pc88cpu->set_context_mem(pc88);
235 pc88cpu->set_context_io(pc88);
236 pc88cpu->set_context_intr(pc88);
238 pc88cpu->set_context_debugger(new DEBUGGER(this, emu));
240 pc88opn->set_context_irq(pc88, SIG_PC88_SOUND_IRQ, 1);
241 #ifdef SUPPORT_PC88_SB2
242 if(pc88sb2 != NULL) {
243 pc88sb2->set_context_irq(pc88, SIG_PC88_SB2_IRQ, 1);
246 pc88sio->set_context_rxrdy(pc88, SIG_PC88_USART_IRQ, 1);
247 pc88sio->set_context_out(pc88, SIG_PC88_USART_OUT);
249 pc88sub->set_context_cpu(pc88cpu_sub);
250 pc88sub->set_context_fdc(pc88fdc_sub);
251 pc88sub->set_context_pio(pc88pio_sub);
252 pc88pio->set_context_port_a(pc88pio_sub, SIG_I8255_PORT_B, 0xff, 0);
253 pc88pio->set_context_port_b(pc88pio_sub, SIG_I8255_PORT_A, 0xff, 0);
254 pc88pio->set_context_port_c(pc88pio_sub, SIG_I8255_PORT_C, 0x0f, 4);
255 pc88pio->set_context_port_c(pc88pio_sub, SIG_I8255_PORT_C, 0xf0, -4);
256 pc88pio->clear_ports_by_cmdreg = true;
257 pc88pio_sub->set_context_port_a(pc88pio, SIG_I8255_PORT_B, 0xff, 0);
258 pc88pio_sub->set_context_port_b(pc88pio, SIG_I8255_PORT_A, 0xff, 0);
259 pc88pio_sub->set_context_port_c(pc88pio, SIG_I8255_PORT_C, 0x0f, 4);
260 pc88pio_sub->set_context_port_c(pc88pio, SIG_I8255_PORT_C, 0xf0, -4);
261 pc88pio_sub->clear_ports_by_cmdreg = true;
262 pc88fdc_sub->set_context_irq(pc88cpu_sub, SIG_CPU_IRQ, 1);
263 pc88fdc_sub->set_context_noise_seek(pc88noise_seek);
264 pc88fdc_sub->set_context_noise_head_down(pc88noise_head_down);
265 pc88fdc_sub->set_context_noise_head_up(pc88noise_head_up);
266 pc88cpu_sub->set_context_mem(pc88sub);
267 pc88cpu_sub->set_context_io(pc88sub);
268 pc88cpu_sub->set_context_intr(pc88sub);
270 pc88cpu_sub->set_context_debugger(new DEBUGGER(this, emu));
273 #ifdef SUPPORT_PC88_CDROM
274 pc88scsi_cdrom->scsi_id = 0;
275 pc88scsi_cdrom->set_context_interface(pc88scsi_host);
276 pc88scsi_host->set_context_target(pc88scsi_cdrom);
277 pc88scsi_host->set_context_drq(pc88, SIG_PC88_SCSI_DRQ, 1);
279 #ifdef SUPPORT_PC88_PCG8100
280 pc88pit->set_context_ch0(pc88pcm0, SIG_PCM1BIT_SIGNAL, 1);
281 pc88pit->set_context_ch1(pc88pcm1, SIG_PCM1BIT_SIGNAL, 1);
282 pc88pit->set_context_ch2(pc88pcm2, SIG_PCM1BIT_SIGNAL, 1);
283 pc88pit->set_constant_clock(0, 3993624);
284 pc88pit->set_constant_clock(1, 3993624);
285 pc88pit->set_constant_clock(2, 3993624);
288 // initialize all devices
289 for(DEVICE* device = first_device; device; device = device->next_device) {
290 device->initialize();
296 // delete all devices
297 for(DEVICE* device = first_device; device;) {
298 DEVICE *next_device = device->next_device;
301 device = next_device;
305 DEVICE* VM::get_device(int id)
307 for(DEVICE* device = first_device; device; device = device->next_device) {
308 if(device->this_device_id == id) {
315 // ----------------------------------------------------------------------------
316 // drive virtual machine
317 // ----------------------------------------------------------------------------
322 for(DEVICE* device = first_device; device; device = device->next_device) {
325 for(DEVICE* device = first_device; device; device = device->next_device) {
329 // initial device settings
330 pc88opn->set_reg(0x29, 3); // for Misty Blue
331 pc88pio->write_signal(SIG_I8255_PORT_C, 0, 0xff);
332 pc88pio_sub->write_signal(SIG_I8255_PORT_C, 0, 0xff);
340 double VM::get_frame_rate()
342 return pc88event->get_frame_rate();
345 // ----------------------------------------------------------------------------
347 // ----------------------------------------------------------------------------
350 DEVICE *VM::get_cpu(int index)
354 } else if(index == 1) {
361 // ----------------------------------------------------------------------------
363 // ----------------------------------------------------------------------------
365 void VM::draw_screen()
370 // ----------------------------------------------------------------------------
372 // ----------------------------------------------------------------------------
374 void VM::initialize_sound(int rate, int samples)
376 // init sound manager
377 pc88event->initialize_sound(rate, samples);
380 if(pc88opn->is_ym2608) {
381 pc88opn->initialize_sound(rate, 7987248, samples, 0, 0);
383 pc88opn->initialize_sound(rate, 3993624, samples, 0, 0);
385 #ifdef SUPPORT_PC88_SB2
386 if(pc88sb2 != NULL) {
387 if(pc88sb2->is_ym2608) {
388 pc88sb2->initialize_sound(rate, 7987248, samples, 0, 0);
390 pc88sb2->initialize_sound(rate, 3993624, samples, 0, 0);
394 pc88pcm->initialize_sound(rate, 8000);
395 #ifdef SUPPORT_PC88_HMB20
396 pc88opm->initialize_sound(rate, 4000000, samples, 0);
398 #ifdef SUPPORT_PC88_PCG8100
399 pc88pcm0->initialize_sound(rate, 8000);
400 pc88pcm1->initialize_sound(rate, 8000);
401 pc88pcm2->initialize_sound(rate, 8000);
405 uint16_t* VM::create_sound(int* extra_frames)
407 return pc88event->create_sound(extra_frames);
410 int VM::get_sound_buffer_ptr()
412 return pc88event->get_sound_buffer_ptr();
415 #ifdef USE_SOUND_VOLUME
416 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
419 pc88opn->set_volume(0, decibel_l, decibel_r);
420 } else if(ch-- == 0) {
421 pc88opn->set_volume(1, decibel_l, decibel_r);
422 #ifdef SUPPORT_PC88_OPNA
423 } else if(ch-- == 0) {
424 pc88opn->set_volume(2, decibel_l, decibel_r);
425 } else if(ch-- == 0) {
426 pc88opn->set_volume(3, decibel_l, decibel_r);
428 #ifdef SUPPORT_PC88_SB2
429 } else if(ch-- == 0) {
430 if(pc88sb2 != NULL) {
431 pc88sb2->set_volume(0, decibel_l, decibel_r);
433 } else if(ch-- == 0) {
434 if(pc88sb2 != NULL) {
435 pc88sb2->set_volume(1, decibel_l, decibel_r);
437 #ifdef SUPPORT_PC88_OPNA
438 } else if(ch-- == 0) {
439 if(pc88sb2 != NULL) {
440 pc88sb2->set_volume(2, decibel_l, decibel_r);
442 } else if(ch-- == 0) {
443 if(pc88sb2 != NULL) {
444 pc88sb2->set_volume(3, decibel_l, decibel_r);
448 #ifdef SUPPORT_PC88_CDROM
449 } else if(ch-- == 0) {
450 pc88scsi_cdrom->set_volume(0, decibel_l, decibel_r);
452 #ifdef SUPPORT_PC88_HMB20
453 } else if(ch-- == 0) {
454 pc88opm->set_volume(0, decibel_l, decibel_r);
456 #ifdef SUPPORT_PC88_PCG8100
457 } else if(ch-- == 0) {
458 pc88pcm0->set_volume(0, decibel_l, decibel_r);
459 pc88pcm1->set_volume(0, decibel_l, decibel_r);
460 pc88pcm2->set_volume(0, decibel_l, decibel_r);
462 } else if(ch-- == 0) {
463 pc88pcm->set_volume(0, decibel_l, decibel_r);
464 } else if(ch-- == 0) {
465 pc88noise_seek->set_volume(0, decibel_l, decibel_r);
466 pc88noise_head_down->set_volume(0, decibel_l, decibel_r);
467 pc88noise_head_up->set_volume(0, decibel_l, decibel_r);
472 // ----------------------------------------------------------------------------
474 // ----------------------------------------------------------------------------
476 void VM::key_down(int code, bool repeat)
478 pc88->key_down(code, repeat);
481 void VM::key_up(int code)
485 bool VM::get_caps_locked()
487 return pc88->get_caps_locked();
490 bool VM::get_kana_locked()
492 return pc88->get_kana_locked();
495 // ----------------------------------------------------------------------------
497 // ----------------------------------------------------------------------------
499 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
501 pc88fdc_sub->open_disk(drv, file_path, bank);
504 void VM::close_floppy_disk(int drv)
506 pc88fdc_sub->close_disk(drv);
509 bool VM::is_floppy_disk_inserted(int drv)
511 return pc88fdc_sub->is_disk_inserted(drv);
514 void VM::is_floppy_disk_protected(int drv, bool value)
516 pc88fdc_sub->is_disk_protected(drv, value);
519 bool VM::is_floppy_disk_protected(int drv)
521 return pc88fdc_sub->is_disk_protected(drv);
524 uint32_t VM::is_floppy_disk_accessed()
526 return pc88fdc_sub->read_signal(0);
529 void VM::play_tape(int drv, const _TCHAR* file_path)
531 pc88->play_tape(file_path);
534 void VM::rec_tape(int drv, const _TCHAR* file_path)
536 pc88->rec_tape(file_path);
539 void VM::close_tape(int drv)
544 bool VM::is_tape_inserted(int drv)
546 return pc88->is_tape_inserted();
549 #ifdef SUPPORT_PC88_CDROM
550 void VM::open_compact_disc(int drv, const _TCHAR* file_path)
552 pc88scsi_cdrom->open(file_path);
555 void VM::close_compact_disc(int drv)
557 pc88scsi_cdrom->close();
560 bool VM::is_compact_disc_inserted(int drv)
562 return pc88scsi_cdrom->mounted();
565 uint32_t VM::is_compact_disc_accessed()
567 return pc88scsi_cdrom->accessed();
571 bool VM::is_frame_skippable()
573 // return event->is_frame_skippable();
574 return pc88->is_frame_skippable();
577 void VM::update_config()
579 if(boot_mode != config.boot_mode) {
580 // boot mode is changed !!!
581 boot_mode = config.boot_mode;
584 for(DEVICE* device = first_device; device; device = device->next_device) {
585 device->update_config();
590 #define STATE_VERSION 10
592 bool VM::process_state(FILEIO* state_fio, bool loading)
594 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
597 for(DEVICE* device = first_device; device; device = device->next_device) {
598 // Note: typeid(foo).name is fixed by recent ABI.Not decr. 6.
599 // const char *name = typeid(*device).name();
600 // But, using get_device_name() instead of typeid(foo).name() 20181008 K.O
601 const char *name = device->get_device_name();
602 int len = strlen(name);
603 if(!state_fio->StateCheckInt32(len)) {
606 if(!state_fio->StateCheckBuffer(name, len, 1)) {
609 if(!device->process_state(state_fio, loading)) {
611 printf("Data loading Error: DEVID=%d\n", device->this_device_id);
616 // Machine specified.
617 state_fio->StateValue(boot_mode);