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);
78 // config.sound_device_type
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 pc88opn->is_ym2608 = (config.sound_type == 0);
88 #ifdef SUPPORT_PC88_SB2
89 if(config.sound_type == 2) {
90 pc88sb2 = new YM2203(this, emu);
91 #ifdef SUPPORT_PC88_OPNA
92 pc88sb2->is_ym2608 = true;
94 #ifdef SUPPORT_PC88_OPNA
95 pc88sb2->set_device_name(_T("YM2608 OPNA(SB2)"));
97 pc88sb2->set_device_name(_T("YM2203 OPN(SB2)"));
99 // pc88sb2->set_context_event_manager(pc88event);
105 if(config.printer_type == 0) {
106 pc88prn = new PRNFILE(this, emu);
107 // pc88prn->set_context_event_manager(pc88event);
108 // } else if(config.printer_type == 1) {
109 // pc88prn = new PCPR201(this, emu);
110 // pc88prn->set_context_event_manager(pc88event);
115 dummycpu = new DEVICE(this, emu);
116 pc88cpu = new Z80(this, emu);
117 // pc88cpu->set_context_event_manager(pc88event);
118 dummycpu->set_device_name(_T("DUMMY CPU"));
119 pc88cpu->set_device_name(_T("MAIN CPU(Z80)"));
121 pc88sub = new PC80S31K(this, emu);
122 // pc88sub->set_context_event_manager(pc88event);
123 pc88pio_sub = new I8255(this, emu);
124 // pc88pio_sub->set_context_event_manager(pc88event);
125 pc88fdc_sub = new UPD765A(this, emu);
126 // pc88fdc_sub->set_context_event_manager(pc88event);
127 pc88noise_seek = new NOISE(this, emu);
128 // pc88noise_seek->set_context_event_manager(pc88event);
129 pc88noise_head_down = new NOISE(this, emu);
130 // pc88noise_head_down->set_context_event_manager(pc88event);
131 pc88noise_head_up = new NOISE(this, emu);
132 // pc88noise_head_up->set_context_event_manager(pc88event);
133 pc88cpu_sub = new Z80(this, emu);
134 // pc88cpu_sub->set_context_event_manager(pc88event);
136 pc88sub->set_device_name(_T("PC-80S31K FDD I/F"));
137 pc88pio_sub->set_device_name(_T("i8255 PIO(FDD)"));
138 pc88fdc_sub->set_device_name(_T("uPD765A FDC(FDD)"));
139 pc88cpu_sub->set_device_name(_T("Z80 CPU(FDD)"));
140 #ifdef SUPPORT_PC88_PCG8100
141 pc88pit = new I8253(this, emu);
142 // pc88pit->set_context_event_manager(pc88event);
143 pc88pcm0 = new PCM1BIT(this, emu);
144 // pc88pcm->set_context_event_manager(pc88event);
145 pc88pcm1 = new PCM1BIT(this, emu);
146 // pc88pcm->set_context_event_manager(pc88event);
147 pc88pcm2 = new PCM1BIT(this, emu);
148 // pc88pcm->set_context_event_manager(pc88event);
149 pc88pit->set_device_name(_T("i8253 PIT (PCG8100)"));
150 pc88pcm0->set_device_name(_T("SOUND #1 (PCG8100)"));
151 pc88pcm1->set_device_name(_T("SOUND #2 (PCG8100)"));
152 pc88pcm2->set_device_name(_T("SOUND #3 (PCG8100)"));
154 pc88event->set_context_sound(pc88noise_seek);
155 pc88event->set_context_sound(pc88noise_head_down);
156 pc88event->set_context_sound(pc88noise_head_up);
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 pc88->set_context_cpu(pc88cpu);
178 pc88->set_context_opn(pc88opn);
179 #ifdef SUPPORT_PC88_SB2
180 pc88->set_context_sb2(pc88sb2);
182 pc88->set_context_pcm(pc88pcm);
183 pc88->set_context_pio(pc88pio);
184 pc88->set_context_prn(pc88prn);
185 pc88->set_context_rtc(pc88rtc);
186 pc88->set_context_sio(pc88sio);
187 #ifdef SUPPORT_PC88_PCG8100
188 pc88->set_context_pcg_pit(pc88pit);
189 pc88->set_context_pcg_pcm0(pc88pcm0);
190 pc88->set_context_pcg_pcm1(pc88pcm1);
191 pc88->set_context_pcg_pcm2(pc88pcm2);
193 pc88cpu->set_context_mem(pc88);
194 pc88cpu->set_context_io(pc88);
195 pc88cpu->set_context_intr(pc88);
197 pc88cpu->set_context_debugger(new DEBUGGER(this, emu));
199 pc88opn->set_context_irq(pc88, SIG_PC88_SOUND_IRQ, 1);
200 #ifdef SUPPORT_PC88_SB2
201 if(pc88sb2 != NULL) {
202 pc88sb2->set_context_irq(pc88, SIG_PC88_SB2_IRQ, 1);
205 pc88sio->set_context_rxrdy(pc88, SIG_PC88_USART_IRQ, 1);
206 pc88sio->set_context_out(pc88, SIG_PC88_USART_OUT);
208 pc88sub->set_context_cpu(pc88cpu_sub);
209 pc88sub->set_context_fdc(pc88fdc_sub);
210 pc88sub->set_context_pio(pc88pio_sub);
211 pc88pio->set_context_port_a(pc88pio_sub, SIG_I8255_PORT_B, 0xff, 0);
212 pc88pio->set_context_port_b(pc88pio_sub, SIG_I8255_PORT_A, 0xff, 0);
213 pc88pio->set_context_port_c(pc88pio_sub, SIG_I8255_PORT_C, 0x0f, 4);
214 pc88pio->set_context_port_c(pc88pio_sub, SIG_I8255_PORT_C, 0xf0, -4);
215 pc88pio->clear_ports_by_cmdreg = true;
216 pc88pio_sub->set_context_port_a(pc88pio, SIG_I8255_PORT_B, 0xff, 0);
217 pc88pio_sub->set_context_port_b(pc88pio, SIG_I8255_PORT_A, 0xff, 0);
218 pc88pio_sub->set_context_port_c(pc88pio, SIG_I8255_PORT_C, 0x0f, 4);
219 pc88pio_sub->set_context_port_c(pc88pio, SIG_I8255_PORT_C, 0xf0, -4);
220 pc88pio_sub->clear_ports_by_cmdreg = true;
221 pc88fdc_sub->set_context_irq(pc88cpu_sub, SIG_CPU_IRQ, 1);
222 pc88fdc_sub->set_context_noise_seek(pc88noise_seek);
223 pc88fdc_sub->set_context_noise_head_down(pc88noise_head_down);
224 pc88fdc_sub->set_context_noise_head_up(pc88noise_head_up);
225 pc88cpu_sub->set_context_mem(pc88sub);
226 pc88cpu_sub->set_context_io(pc88sub);
227 pc88cpu_sub->set_context_intr(pc88sub);
229 pc88cpu_sub->set_context_debugger(new DEBUGGER(this, emu));
232 #ifdef SUPPORT_PC88_PCG8100
233 pc88pit->set_context_ch0(pc88pcm0, SIG_PCM1BIT_SIGNAL, 1);
234 pc88pit->set_context_ch1(pc88pcm1, SIG_PCM1BIT_SIGNAL, 1);
235 pc88pit->set_context_ch2(pc88pcm2, SIG_PCM1BIT_SIGNAL, 1);
236 pc88pit->set_constant_clock(0, 3993624);
237 pc88pit->set_constant_clock(1, 3993624);
238 pc88pit->set_constant_clock(2, 3993624);
241 // initialize all devices
242 for(DEVICE* device = first_device; device; device = device->next_device) {
243 device->initialize();
249 // delete all devices
250 for(DEVICE* device = first_device; device;) {
251 DEVICE *next_device = device->next_device;
254 device = next_device;
258 DEVICE* VM::get_device(int id)
260 for(DEVICE* device = first_device; device; device = device->next_device) {
261 if(device->this_device_id == id) {
268 // ----------------------------------------------------------------------------
269 // drive virtual machine
270 // ----------------------------------------------------------------------------
275 for(DEVICE* device = first_device; device; device = device->next_device) {
278 for(DEVICE* device = first_device; device; device = device->next_device) {
282 // initial device settings
283 pc88opn->set_reg(0x29, 3); // for Misty Blue
284 pc88pio->write_signal(SIG_I8255_PORT_C, 0, 0xff);
285 pc88pio_sub->write_signal(SIG_I8255_PORT_C, 0, 0xff);
293 double VM::get_frame_rate()
295 return pc88event->get_frame_rate();
298 // ----------------------------------------------------------------------------
300 // ----------------------------------------------------------------------------
303 DEVICE *VM::get_cpu(int index)
307 } else if(index == 1) {
314 // ----------------------------------------------------------------------------
316 // ----------------------------------------------------------------------------
318 void VM::draw_screen()
323 // ----------------------------------------------------------------------------
325 // ----------------------------------------------------------------------------
327 void VM::initialize_sound(int rate, int samples)
329 // init sound manager
330 pc88event->initialize_sound(rate, samples);
333 #ifdef SUPPORT_PC88_OPNA
334 if(pc88opn->is_ym2608) {
335 pc88opn->initialize_sound(rate, 7987248, samples, 0, 0);
338 pc88opn->initialize_sound(rate, 3993624, samples, 0, 0);
339 #ifdef SUPPORT_PC88_SB2
340 if(pc88sb2 != NULL) {
341 #ifdef SUPPORT_PC88_OPNA
342 if(pc88sb2->is_ym2608) {
343 pc88sb2->initialize_sound(rate, 7987248, samples, 0, 0);
346 pc88sb2->initialize_sound(rate, 3993624, samples, 0, 0);
349 pc88pcm->initialize_sound(rate, 8000);
350 #ifdef SUPPORT_PC88_PCG8100
351 pc88pcm0->initialize_sound(rate, 8000);
352 pc88pcm1->initialize_sound(rate, 8000);
353 pc88pcm2->initialize_sound(rate, 8000);
357 uint16_t* VM::create_sound(int* extra_frames)
359 return pc88event->create_sound(extra_frames);
362 int VM::get_sound_buffer_ptr()
364 return pc88event->get_sound_buffer_ptr();
367 #ifdef USE_SOUND_VOLUME
368 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
371 pc88opn->set_volume(0, decibel_l, decibel_r);
372 } else if(ch-- == 0) {
373 pc88opn->set_volume(1, decibel_l, decibel_r);
374 #ifdef SUPPORT_PC88_OPNA
375 } else if(ch-- == 0) {
376 pc88opn->set_volume(2, decibel_l, decibel_r);
377 } else if(ch-- == 0) {
378 pc88opn->set_volume(3, decibel_l, decibel_r);
380 #ifdef SUPPORT_PC88_SB2
381 } else if(ch-- == 0) {
382 if(pc88sb2 != NULL) {
383 pc88sb2->set_volume(0, decibel_l, decibel_r);
385 } else if(ch-- == 0) {
386 if(pc88sb2 != NULL) {
387 pc88sb2->set_volume(1, decibel_l, decibel_r);
389 } else if(ch-- == 0) {
390 if(pc88sb2 != NULL) {
391 pc88sb2->set_volume(2, decibel_l, decibel_r);
393 } else if(ch-- == 0) {
394 if(pc88sb2 != NULL) {
395 pc88sb2->set_volume(3, decibel_l, decibel_r);
398 #ifdef SUPPORT_PC88_PCG8100
399 } else if(ch-- == 0) {
400 pc88pcm0->set_volume(0, decibel_l, decibel_r);
401 pc88pcm1->set_volume(0, decibel_l, decibel_r);
402 pc88pcm2->set_volume(0, decibel_l, decibel_r);
404 } else if(ch-- == 0) {
405 pc88pcm->set_volume(0, decibel_l, decibel_r);
406 } else if(ch-- == 0) {
407 pc88noise_seek->set_volume(0, decibel_l, decibel_r);
408 pc88noise_head_down->set_volume(0, decibel_l, decibel_r);
409 pc88noise_head_up->set_volume(0, decibel_l, decibel_r);
414 // ----------------------------------------------------------------------------
416 // ----------------------------------------------------------------------------
418 void VM::key_down(int code, bool repeat)
420 pc88->key_down(code, repeat);
423 void VM::key_up(int code)
427 // ----------------------------------------------------------------------------
429 // ----------------------------------------------------------------------------
431 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
433 pc88fdc_sub->open_disk(drv, file_path, bank);
436 void VM::close_floppy_disk(int drv)
438 pc88fdc_sub->close_disk(drv);
441 bool VM::is_floppy_disk_inserted(int drv)
443 return pc88fdc_sub->is_disk_inserted(drv);
446 void VM::is_floppy_disk_protected(int drv, bool value)
448 pc88fdc_sub->is_disk_protected(drv, value);
451 bool VM::is_floppy_disk_protected(int drv)
453 return pc88fdc_sub->is_disk_protected(drv);
456 uint32_t VM::is_floppy_disk_accessed()
458 return pc88fdc_sub->read_signal(0);
461 void VM::play_tape(int drv, const _TCHAR* file_path)
463 pc88->play_tape(file_path);
466 void VM::rec_tape(int drv, const _TCHAR* file_path)
468 pc88->rec_tape(file_path);
471 void VM::close_tape(int drv)
476 bool VM::is_tape_inserted(int drv)
478 return pc88->is_tape_inserted();
481 bool VM::is_frame_skippable()
483 // return event->is_frame_skippable();
484 return pc88->is_frame_skippable();
487 void VM::update_config()
489 if(boot_mode != config.boot_mode) {
490 // boot mode is changed !!!
491 boot_mode = config.boot_mode;
494 for(DEVICE* device = first_device; device; device = device->next_device) {
495 device->update_config();
500 #define STATE_VERSION 7
502 void VM::save_state(FILEIO* state_fio)
504 state_fio->FputUint32(STATE_VERSION);
506 for(DEVICE* device = first_device; device; device = device->next_device) {
507 device->save_state(state_fio);
509 state_fio->FputInt32(boot_mode);
512 bool VM::load_state(FILEIO* state_fio)
514 if(state_fio->FgetUint32() != STATE_VERSION) {
517 for(DEVICE* device = first_device; device; device = device->next_device) {
518 if(!device->load_state(state_fio)) {
522 boot_mode = state_fio->FgetInt32();