2 NEC PC-8801MA Emulator 'ePC-8801MA'
3 NEC PC-8001mkIISR Emulator 'ePC-8001mkIISR'
5 Author : Takeda.Toshiya
12 #include "../../emu.h"
13 #include "../device.h"
18 #include "../pcm1bit.h"
19 //#include "../pcpr201.h"
20 #include "../prnfile.h"
21 #include "../upd1990a.h"
22 #include "../ym2203.h"
27 #include "../pc80s31k.h"
28 #include "../upd765a.h"
31 #include "../debugger.h"
34 #ifdef SUPPORT_PC88_PCG8100
40 // ----------------------------------------------------------------------------
42 // ----------------------------------------------------------------------------
44 VM::VM(EMU* parent_emu) : emu(parent_emu)
47 boot_mode = config.boot_mode;
50 first_device = last_device = NULL;
51 dummy = new DEVICE(this, emu); // must be 1st device
53 pc88event = new EVENT(this, emu);
54 pc88event->set_device_name(_T("Event Manager (PC-8801)"));
55 // pc88event->set_frames_per_sec(60);
56 // pc88event->set_lines_per_frame(260);
57 dummy->set_device_name(_T("1st Dummy"));
58 pc88 = new PC88(this, emu);
60 #if defined(_PC8001) || defined(_PC8001MK2) || defined(_PC8001SR)
61 pc88->set_device_name(_T("PC8001 MAIN"));
63 pc88->set_device_name(_T("PC8801 MAIN"));
65 // pc88->set_context_event_manager(pc88event);
66 pc88sio = new I8251(this, emu);
67 // pc88sio->set_device_name(_T("8251 SIO (PC-8801)"));
68 // pc88sio->set_context_event_manager(pc88event);
69 pc88pio = new I8255(this, emu);
70 // pc88pio->set_device_name(_T("8255 PIO (PC-8801)"));
71 // pc88pio->set_context_event_manager(pc88event);
72 pc88pcm = new PCM1BIT(this, emu);
73 // pc88pcm->set_device_name(_T("1-Bit PCM Sound (PC-8801)"));
74 // pc88pcm->set_context_event_manager(pc88event);
75 pc88rtc = new UPD1990A(this, emu);
76 // pc88rtc->set_device_name(_T("uPD1990A RTC (PC-8801)"));
77 // pc88rtc->set_context_event_manager(pc88event);
79 // 0: 44h:OPNA A4h:None PC-8801FH/MH or later
80 // 1: 44h:OPN A4h:None PC-8801mkIISR/TR/MR/FR
81 // 2: 44h:OPN A4h:OPNA PC-8801mkIISR/TR/MR/FR + PC-8801-23
82 pc88opn = new YM2203(this, emu);
83 // pc88opn->set_context_event_manager(pc88event);
85 #ifdef SUPPORT_PC88_OPNA
86 if(config.sound_type == 0) {
87 pc88opn->set_device_name(_T("YM2608 OPNA"));
89 pc88opn->set_device_name(_T("YM2203 OPN"));
91 pc88opn->is_ym2608 = (config.sound_type == 0);
93 #ifdef SUPPORT_PC88_SB2
94 if(config.sound_type == 2) {
95 pc88sb2 = new YM2203(this, emu);
96 #ifdef SUPPORT_PC88_OPNA
97 pc88sb2->set_device_name(_T("YM2608 OPNA (SB2)"));
98 pc88sb2->is_ym2608 = true;
100 pc88sb2->set_device_name(_T("YM2203 OPN (SB2)"));
102 // pc88sb2->set_context_event_manager(pc88event);
108 if(config.printer_type == 0) {
109 pc88prn = new PRNFILE(this, emu);
110 // pc88prn->set_context_event_manager(pc88event);
111 // } else if(config.printer_type == 1) {
112 // pc88prn = new PCPR201(this, emu);
113 // pc88prn->set_context_event_manager(pc88event);
118 dummycpu = new DEVICE(this, emu);
119 pc88cpu = new Z80(this, emu);
120 // pc88cpu->set_context_event_manager(pc88event);
121 dummycpu->set_device_name(_T("DUMMY CPU"));
122 pc88cpu->set_device_name(_T("MAIN CPU(Z80)"));
124 pc88sub = new PC80S31K(this, emu);
125 pc88sub->set_device_name(_T("PC-80S31K (Sub)"));
126 // pc88sub->set_context_event_manager(pc88event);
127 pc88pio_sub = new I8255(this, emu);
128 pc88pio_sub->set_device_name(_T("8255 PIO (Sub)"));
129 // pc88pio_sub->set_context_event_manager(pc88event);
130 pc88fdc_sub = new UPD765A(this, emu);
131 pc88fdc_sub->set_device_name(_T("uPD765A FDC (Sub)"));
132 // pc88fdc_sub->set_context_event_manager(pc88event);
133 pc88noise_seek = new NOISE(this, emu);
134 // pc88noise_seek->set_context_event_manager(pc88event);
135 pc88noise_head_down = new NOISE(this, emu);
136 // pc88noise_head_down->set_context_event_manager(pc88event);
137 pc88noise_head_up = new NOISE(this, emu);
138 // pc88noise_head_up->set_context_event_manager(pc88event);
139 pc88cpu_sub = new Z80(this, emu);
140 pc88cpu_sub->set_device_name(_T("Z80 CPU (Sub)"));
141 // pc88cpu_sub->set_context_event_manager(pc88event);
143 #ifdef SUPPORT_PC88_PCG8100
144 pc88pit = new I8253(this, emu);
145 // pc88pit->set_context_event_manager(pc88event);
146 pc88pcm0 = new PCM1BIT(this, emu);
147 // pc88pcm0->set_context_event_manager(pc88event);
148 pc88pcm1 = new PCM1BIT(this, emu);
149 // pc88pcm1->set_context_event_manager(pc88event);
150 pc88pcm2 = new PCM1BIT(this, emu);
151 // pc88pcm2->set_context_event_manager(pc88event);
152 pc88pit->set_device_name(_T("i8253 PIT (PCG8100)"));
153 pc88pcm0->set_device_name(_T("SOUND #1 (PCG8100)"));
154 pc88pcm1->set_device_name(_T("SOUND #2 (PCG8100)"));
155 pc88pcm2->set_device_name(_T("SOUND #3 (PCG8100)"));
158 pc88event->set_context_cpu(dummycpu, 3993624 / 4);
159 #ifdef SUPPORT_PC88_HIGH_CLOCK
160 pc88event->set_context_cpu(pc88cpu, (config.cpu_type != 0) ? 3993624 : 7987248);
162 pc88event->set_context_cpu(pc88cpu, 3993624);
164 pc88event->set_context_cpu(pc88cpu_sub, 3993624);
165 pc88event->set_context_sound(pc88opn);
166 #ifdef SUPPORT_PC88_SB2
167 if(pc88sb2 != NULL) {
168 pc88event->set_context_sound(pc88sb2);
171 pc88event->set_context_sound(pc88pcm);
172 #ifdef SUPPORT_PC88_PCG8100
173 pc88event->set_context_sound(pc88pcm0);
174 pc88event->set_context_sound(pc88pcm1);
175 pc88event->set_context_sound(pc88pcm2);
177 pc88event->set_context_sound(pc88noise_seek);
178 pc88event->set_context_sound(pc88noise_head_down);
179 pc88event->set_context_sound(pc88noise_head_up);
180 pc88->set_context_cpu(pc88cpu);
181 pc88->set_context_opn(pc88opn);
182 #ifdef SUPPORT_PC88_SB2
183 pc88->set_context_sb2(pc88sb2);
185 pc88->set_context_pcm(pc88pcm);
186 pc88->set_context_pio(pc88pio);
187 pc88->set_context_prn(pc88prn);
188 pc88->set_context_rtc(pc88rtc);
189 pc88->set_context_sio(pc88sio);
190 #ifdef SUPPORT_PC88_PCG8100
191 pc88->set_context_pcg_pit(pc88pit);
192 pc88->set_context_pcg_pcm0(pc88pcm0);
193 pc88->set_context_pcg_pcm1(pc88pcm1);
194 pc88->set_context_pcg_pcm2(pc88pcm2);
196 pc88cpu->set_context_mem(pc88);
197 pc88cpu->set_context_io(pc88);
198 pc88cpu->set_context_intr(pc88);
200 pc88cpu->set_context_debugger(new DEBUGGER(this, emu));
202 pc88opn->set_context_irq(pc88, SIG_PC88_SOUND_IRQ, 1);
203 #ifdef SUPPORT_PC88_SB2
204 if(pc88sb2 != NULL) {
205 pc88sb2->set_context_irq(pc88, SIG_PC88_SB2_IRQ, 1);
208 pc88sio->set_context_rxrdy(pc88, SIG_PC88_USART_IRQ, 1);
209 pc88sio->set_context_out(pc88, SIG_PC88_USART_OUT);
211 pc88sub->set_context_cpu(pc88cpu_sub);
212 pc88sub->set_context_fdc(pc88fdc_sub);
213 pc88sub->set_context_pio(pc88pio_sub);
214 pc88pio->set_context_port_a(pc88pio_sub, SIG_I8255_PORT_B, 0xff, 0);
215 pc88pio->set_context_port_b(pc88pio_sub, SIG_I8255_PORT_A, 0xff, 0);
216 pc88pio->set_context_port_c(pc88pio_sub, SIG_I8255_PORT_C, 0x0f, 4);
217 pc88pio->set_context_port_c(pc88pio_sub, SIG_I8255_PORT_C, 0xf0, -4);
218 pc88pio->clear_ports_by_cmdreg = true;
219 pc88pio_sub->set_context_port_a(pc88pio, SIG_I8255_PORT_B, 0xff, 0);
220 pc88pio_sub->set_context_port_b(pc88pio, SIG_I8255_PORT_A, 0xff, 0);
221 pc88pio_sub->set_context_port_c(pc88pio, SIG_I8255_PORT_C, 0x0f, 4);
222 pc88pio_sub->set_context_port_c(pc88pio, SIG_I8255_PORT_C, 0xf0, -4);
223 pc88pio_sub->clear_ports_by_cmdreg = true;
224 pc88fdc_sub->set_context_irq(pc88cpu_sub, SIG_CPU_IRQ, 1);
225 pc88fdc_sub->set_context_noise_seek(pc88noise_seek);
226 pc88fdc_sub->set_context_noise_head_down(pc88noise_head_down);
227 pc88fdc_sub->set_context_noise_head_up(pc88noise_head_up);
228 pc88cpu_sub->set_context_mem(pc88sub);
229 pc88cpu_sub->set_context_io(pc88sub);
230 pc88cpu_sub->set_context_intr(pc88sub);
232 pc88cpu_sub->set_context_debugger(new DEBUGGER(this, emu));
235 #ifdef SUPPORT_PC88_PCG8100
236 pc88pit->set_context_ch0(pc88pcm0, SIG_PCM1BIT_SIGNAL, 1);
237 pc88pit->set_context_ch1(pc88pcm1, SIG_PCM1BIT_SIGNAL, 1);
238 pc88pit->set_context_ch2(pc88pcm2, SIG_PCM1BIT_SIGNAL, 1);
239 pc88pit->set_constant_clock(0, 3993624);
240 pc88pit->set_constant_clock(1, 3993624);
241 pc88pit->set_constant_clock(2, 3993624);
244 // initialize all devices
245 for(DEVICE* device = first_device; device; device = device->next_device) {
246 device->initialize();
252 // delete all devices
253 for(DEVICE* device = first_device; device;) {
254 DEVICE *next_device = device->next_device;
257 device = next_device;
261 DEVICE* VM::get_device(int id)
263 for(DEVICE* device = first_device; device; device = device->next_device) {
264 if(device->this_device_id == id) {
271 // ----------------------------------------------------------------------------
272 // drive virtual machine
273 // ----------------------------------------------------------------------------
278 for(DEVICE* device = first_device; device; device = device->next_device) {
281 for(DEVICE* device = first_device; device; device = device->next_device) {
285 // initial device settings
286 pc88opn->set_reg(0x29, 3); // for Misty Blue
287 pc88pio->write_signal(SIG_I8255_PORT_C, 0, 0xff);
288 pc88pio_sub->write_signal(SIG_I8255_PORT_C, 0, 0xff);
296 double VM::get_frame_rate()
298 return pc88event->get_frame_rate();
301 // ----------------------------------------------------------------------------
303 // ----------------------------------------------------------------------------
306 DEVICE *VM::get_cpu(int index)
310 } else if(index == 1) {
317 // ----------------------------------------------------------------------------
319 // ----------------------------------------------------------------------------
321 void VM::draw_screen()
326 // ----------------------------------------------------------------------------
328 // ----------------------------------------------------------------------------
330 void VM::initialize_sound(int rate, int samples)
332 // init sound manager
333 pc88event->initialize_sound(rate, samples);
336 #ifdef SUPPORT_PC88_OPNA
337 if(pc88opn->is_ym2608) {
338 pc88opn->initialize_sound(rate, 7987248, samples, 0, 0);
341 pc88opn->initialize_sound(rate, 3993624, samples, 0, 0);
342 #ifdef SUPPORT_PC88_SB2
343 if(pc88sb2 != NULL) {
344 #ifdef SUPPORT_PC88_OPNA
345 if(pc88sb2->is_ym2608) {
346 pc88sb2->initialize_sound(rate, 7987248, samples, 0, 0);
349 pc88sb2->initialize_sound(rate, 3993624, samples, 0, 0);
352 pc88pcm->initialize_sound(rate, 8000);
353 #ifdef SUPPORT_PC88_PCG8100
354 pc88pcm0->initialize_sound(rate, 8000);
355 pc88pcm1->initialize_sound(rate, 8000);
356 pc88pcm2->initialize_sound(rate, 8000);
360 uint16_t* VM::create_sound(int* extra_frames)
362 return pc88event->create_sound(extra_frames);
365 int VM::get_sound_buffer_ptr()
367 return pc88event->get_sound_buffer_ptr();
370 #ifdef USE_SOUND_VOLUME
371 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
374 pc88opn->set_volume(0, decibel_l, decibel_r);
375 } else if(ch-- == 0) {
376 pc88opn->set_volume(1, decibel_l, decibel_r);
377 #ifdef SUPPORT_PC88_OPNA
378 } else if(ch-- == 0) {
379 pc88opn->set_volume(2, decibel_l, decibel_r);
380 } else if(ch-- == 0) {
381 pc88opn->set_volume(3, decibel_l, decibel_r);
383 #ifdef SUPPORT_PC88_SB2
384 } else if(ch-- == 0) {
385 if(pc88sb2 != NULL) {
386 pc88sb2->set_volume(0, decibel_l, decibel_r);
388 } else if(ch-- == 0) {
389 if(pc88sb2 != NULL) {
390 pc88sb2->set_volume(1, decibel_l, decibel_r);
392 } else if(ch-- == 0) {
393 if(pc88sb2 != NULL) {
394 pc88sb2->set_volume(2, decibel_l, decibel_r);
396 } else if(ch-- == 0) {
397 if(pc88sb2 != NULL) {
398 pc88sb2->set_volume(3, decibel_l, decibel_r);
401 #ifdef SUPPORT_PC88_PCG8100
402 } else if(ch-- == 0) {
403 pc88pcm0->set_volume(0, decibel_l, decibel_r);
404 pc88pcm1->set_volume(0, decibel_l, decibel_r);
405 pc88pcm2->set_volume(0, decibel_l, decibel_r);
407 } else if(ch-- == 0) {
408 pc88pcm->set_volume(0, decibel_l, decibel_r);
409 } else if(ch-- == 0) {
410 pc88noise_seek->set_volume(0, decibel_l, decibel_r);
411 pc88noise_head_down->set_volume(0, decibel_l, decibel_r);
412 pc88noise_head_up->set_volume(0, decibel_l, decibel_r);
417 // ----------------------------------------------------------------------------
419 // ----------------------------------------------------------------------------
421 void VM::key_down(int code, bool repeat)
423 pc88->key_down(code, repeat);
426 void VM::key_up(int code)
430 bool VM::get_caps_locked()
432 return pc88->get_caps_locked();
435 bool VM::get_kana_locked()
437 return pc88->get_kana_locked();
440 // ----------------------------------------------------------------------------
442 // ----------------------------------------------------------------------------
444 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
446 pc88fdc_sub->open_disk(drv, file_path, bank);
449 void VM::close_floppy_disk(int drv)
451 pc88fdc_sub->close_disk(drv);
454 bool VM::is_floppy_disk_inserted(int drv)
456 return pc88fdc_sub->is_disk_inserted(drv);
459 void VM::is_floppy_disk_protected(int drv, bool value)
461 pc88fdc_sub->is_disk_protected(drv, value);
464 bool VM::is_floppy_disk_protected(int drv)
466 return pc88fdc_sub->is_disk_protected(drv);
469 uint32_t VM::is_floppy_disk_accessed()
471 return pc88fdc_sub->read_signal(0);
474 void VM::play_tape(int drv, const _TCHAR* file_path)
476 pc88->play_tape(file_path);
479 void VM::rec_tape(int drv, const _TCHAR* file_path)
481 pc88->rec_tape(file_path);
484 void VM::close_tape(int drv)
489 bool VM::is_tape_inserted(int drv)
491 return pc88->is_tape_inserted();
494 bool VM::is_frame_skippable()
496 // return event->is_frame_skippable();
497 return pc88->is_frame_skippable();
500 void VM::update_config()
502 if(boot_mode != config.boot_mode) {
503 // boot mode is changed !!!
504 boot_mode = config.boot_mode;
507 for(DEVICE* device = first_device; device; device = device->next_device) {
508 device->update_config();
513 #define STATE_VERSION 7
515 void VM::save_state(FILEIO* state_fio)
517 state_fio->FputUint32(STATE_VERSION);
519 for(DEVICE* device = first_device; device; device = device->next_device) {
520 device->save_state(state_fio);
522 state_fio->FputInt32(boot_mode);
525 bool VM::load_state(FILEIO* state_fio)
527 if(state_fio->FgetUint32() != STATE_VERSION) {
530 for(DEVICE* device = first_device; device; device = device->next_device) {
531 if(!device->load_state(state_fio)) {
535 boot_mode = state_fio->FgetInt32();