OSDN Git Service

[VM][General] Merge upstream 2015-12-23. OSD for Qt is WIP.
[csp-qt/common_source_project-fm7.git] / source / src / vm / pc8801 / pc8801.cpp
1 /*
2         NEC PC-8801MA Emulator 'ePC-8801MA'
3         NEC PC-8001mkIISR Emulator 'ePC-8001mkIISR'
4
5         Author : Takeda.Toshiya
6         Date   : 2012.02.16-
7
8         [ virtual machine ]
9 */
10
11 #include "pc8801.h"
12 #include "../../emu.h"
13 #include "../device.h"
14 #include "../event.h"
15
16 #include "../i8251.h"
17 #include "../i8255.h"
18 #include "../pcm1bit.h"
19 #include "../prnfile.h"
20 #include "../upd1990a.h"
21 #include "../ym2203.h"
22 #include "../z80.h"
23
24 #include "../disk.h"
25 #include "../pc80s31k.h"
26 #include "../upd765a.h"
27
28 #ifdef USE_DEBUGGER
29 #include "../debugger.h"
30 #endif
31
32 #ifdef SUPPORT_PC88_PCG8100
33 #include "../i8253.h"
34 #endif
35
36 #include "pc88.h"
37
38 // ----------------------------------------------------------------------------
39 // initialize
40 // ----------------------------------------------------------------------------
41
42 VM::VM(EMU* parent_emu) : emu(parent_emu)
43 {
44         // check configs
45         boot_mode = config.boot_mode;
46         
47         // create devices
48         first_device = last_device = NULL;
49         dummy = new DEVICE(this, emu);  // must be 1st device
50         
51         pc88event = new EVENT(this, emu);
52 //      pc88event->set_frames_per_sec(60);
53 //      pc88event->set_lines_per_frame(260);
54         
55         pc88 = new PC88(this, emu);
56 //      pc88->set_context_event_manager(pc88event);
57         pc88sio = new I8251(this, emu);
58 //      pc88sio->set_context_event_manager(pc88event);
59         pc88pio = new I8255(this, emu);
60 //      pc88pio->set_context_event_manager(pc88event);
61         pc88pcm = new PCM1BIT(this, emu);
62 //      pc88pcm->set_context_event_manager(pc88event);
63         pc88rtc = new UPD1990A(this, emu);
64 //      pc88rtc->set_context_event_manager(pc88event);
65         // config.sound_device_type
66         //      0: 44h:OPNA A4h:None            PC-8801FH/MH or later
67         //      1: 44h:OPN  A4h:None            PC-8801mkIISR/TR/MR/FR
68         //      2: 44h:OPN  A4h:OPNA            PC-8801mkIISR/TR/MR/FR + PC-8801-23
69         pc88opn = new YM2203(this, emu);
70 //      pc88opn->set_context_event_manager(pc88event);
71 #ifdef USE_SOUND_DEVICE_TYPE
72 #ifdef SUPPORT_PC88_OPNA
73         pc88opn->is_ym2608 = (config.sound_device_type == 0);
74 #endif
75 #ifdef SUPPORT_PC88_SB2
76         if(config.sound_device_type == 2) {
77                 pc88sb2 = new YM2203(this, emu);
78 #ifdef SUPPORT_PC88_OPNA
79                 pc88sb2->is_ym2608 = true;
80 #endif
81 //              pc88sb2->set_context_event_manager(pc88event);
82         } else {
83                 pc88sb2 = NULL;
84         }
85 #endif
86 #endif
87         if(config.printer_device_type == 0) {
88                 pc88prn = new PRNFILE(this, emu);
89 //              pc88prn->set_context_event_manager(pc88event);
90         } else {
91                 pc88prn = dummy;
92         }
93         pc88cpu = new Z80(this, emu);
94 //      pc88cpu->set_context_event_manager(pc88event);
95         dummycpu = new DEVICE(this, emu);
96         
97         pc88sub = new PC80S31K(this, emu);
98 //      pc88sub->set_context_event_manager(pc88event);
99         pc88pio_sub = new I8255(this, emu);
100 //      pc88pio_sub->set_context_event_manager(pc88event);
101         pc88fdc_sub = new UPD765A(this, emu);
102 //      pc88fdc_sub->set_context_event_manager(pc88event);
103         pc88cpu_sub = new Z80(this, emu);
104 //      pc88cpu_sub->set_context_event_manager(pc88event);
105         
106 #ifdef SUPPORT_PC88_PCG8100
107         pc88pit = new I8253(this, emu);
108 //      pc88pit->set_context_event_manager(pc88event);
109         pc88pcm0 = new PCM1BIT(this, emu);
110 //      pc88pcm->set_context_event_manager(pc88event);
111         pc88pcm1 = new PCM1BIT(this, emu);
112 //      pc88pcm->set_context_event_manager(pc88event);
113         pc88pcm2 = new PCM1BIT(this, emu);
114 //      pc88pcm->set_context_event_manager(pc88event);
115 #endif
116         
117 #ifdef SUPPORT_PC88_HIGH_CLOCK
118         pc88event->set_context_cpu(dummycpu, 7987248 / 8);
119         pc88event->set_context_cpu(pc88cpu, (config.cpu_type != 0) ? 3993624 : 7987248);
120 #else
121         pc88event->set_context_cpu(dummycpu, 3993624 / 4);
122         pc88event->set_context_cpu(pc88cpu, 3993624);
123 #endif
124         pc88event->set_context_cpu(pc88cpu_sub, 3993624);
125         pc88event->set_context_sound(pc88opn);
126 #ifdef SUPPORT_PC88_SB2
127         if(pc88sb2 != NULL) {
128                 pc88event->set_context_sound(pc88sb2);
129         }
130 #endif
131         pc88event->set_context_sound(pc88pcm);
132 #ifdef SUPPORT_PC88_PCG8100
133         pc88event->set_context_sound(pc88pcm0);
134         pc88event->set_context_sound(pc88pcm1);
135         pc88event->set_context_sound(pc88pcm2);
136 #endif
137         pc88->set_context_cpu(pc88cpu);
138         pc88->set_context_opn(pc88opn);
139 #ifdef SUPPORT_PC88_SB2
140         pc88->set_context_sb2(pc88sb2);
141 #endif
142         pc88->set_context_pcm(pc88pcm);
143         pc88->set_context_pio(pc88pio);
144         pc88->set_context_prn(pc88prn);
145         pc88->set_context_rtc(pc88rtc);
146         pc88->set_context_sio(pc88sio);
147 #ifdef SUPPORT_PC88_PCG8100
148         pc88->set_context_pcg_pit(pc88pit);
149         pc88->set_context_pcg_pcm0(pc88pcm0);
150         pc88->set_context_pcg_pcm1(pc88pcm1);
151         pc88->set_context_pcg_pcm2(pc88pcm2);
152 #endif
153         pc88cpu->set_context_mem(pc88);
154         pc88cpu->set_context_io(pc88);
155         pc88cpu->set_context_intr(pc88);
156 #ifdef USE_DEBUGGER
157         pc88cpu->set_context_debugger(new DEBUGGER(this, emu));
158 #endif
159         pc88opn->set_context_irq(pc88, SIG_PC88_SOUND_IRQ, 1);
160 #ifdef SUPPORT_PC88_SB2
161         if(pc88sb2 != NULL) {
162                 pc88sb2->set_context_irq(pc88, SIG_PC88_SB2_IRQ, 1);
163         }
164 #endif
165         pc88sio->set_context_rxrdy(pc88, SIG_PC88_USART_IRQ, 1);
166         pc88sio->set_context_out(pc88, SIG_PC88_USART_OUT);
167         
168         pc88sub->set_context_cpu(pc88cpu_sub);
169         pc88sub->set_context_fdc(pc88fdc_sub);
170         pc88sub->set_context_pio(pc88pio_sub);
171         pc88pio->set_context_port_a(pc88pio_sub, SIG_I8255_PORT_B, 0xff, 0);
172         pc88pio->set_context_port_b(pc88pio_sub, SIG_I8255_PORT_A, 0xff, 0);
173         pc88pio->set_context_port_c(pc88pio_sub, SIG_I8255_PORT_C, 0x0f, 4);
174         pc88pio->set_context_port_c(pc88pio_sub, SIG_I8255_PORT_C, 0xf0, -4);
175         pc88pio->clear_ports_by_cmdreg = true;
176         pc88pio_sub->set_context_port_a(pc88pio, SIG_I8255_PORT_B, 0xff, 0);
177         pc88pio_sub->set_context_port_b(pc88pio, SIG_I8255_PORT_A, 0xff, 0);
178         pc88pio_sub->set_context_port_c(pc88pio, SIG_I8255_PORT_C, 0x0f, 4);
179         pc88pio_sub->set_context_port_c(pc88pio, SIG_I8255_PORT_C, 0xf0, -4);
180         pc88pio_sub->clear_ports_by_cmdreg = true;
181         pc88fdc_sub->set_context_irq(pc88cpu_sub, SIG_CPU_IRQ, 1);
182         pc88cpu_sub->set_context_mem(pc88sub);
183         pc88cpu_sub->set_context_io(pc88sub);
184         pc88cpu_sub->set_context_intr(pc88sub);
185 #ifdef USE_DEBUGGER
186         pc88cpu_sub->set_context_debugger(new DEBUGGER(this, emu));
187 #endif
188         
189 #ifdef SUPPORT_PC88_PCG8100
190         pc88pit->set_context_ch0(pc88pcm0, SIG_PCM1BIT_SIGNAL, 1);
191         pc88pit->set_context_ch1(pc88pcm1, SIG_PCM1BIT_SIGNAL, 1);
192         pc88pit->set_context_ch2(pc88pcm2, SIG_PCM1BIT_SIGNAL, 1);
193         pc88pit->set_constant_clock(0, 3993624);
194         pc88pit->set_constant_clock(1, 3993624);
195         pc88pit->set_constant_clock(2, 3993624);
196 #endif
197         
198         // initialize all devices
199         for(DEVICE* device = first_device; device; device = device->next_device) {
200                 device->initialize();
201         }
202 }
203
204 VM::~VM()
205 {
206         // delete all devices
207         for(DEVICE* device = first_device; device;) {
208                 DEVICE *next_device = device->next_device;
209                 device->release();
210                 delete device;
211                 device = next_device;
212         }
213 }
214
215 DEVICE* VM::get_device(int id)
216 {
217         for(DEVICE* device = first_device; device; device = device->next_device) {
218                 if(device->this_device_id == id) {
219                         return device;
220                 }
221         }
222         return NULL;
223 }
224
225 // ----------------------------------------------------------------------------
226 // drive virtual machine
227 // ----------------------------------------------------------------------------
228
229 void VM::reset()
230 {
231         // reset all devices
232         for(DEVICE* device = first_device; device; device = device->next_device) {
233                 device->reset();
234         }
235         for(DEVICE* device = first_device; device; device = device->next_device) {
236                 device->reset();
237         }
238         
239         // initial device settings
240         pc88opn->SetReg(0x29, 3); // for Misty Blue
241         pc88pio->write_signal(SIG_I8255_PORT_C, 0, 0xff);
242         pc88pio_sub->write_signal(SIG_I8255_PORT_C, 0, 0xff);
243 }
244
245 void VM::run()
246 {
247         pc88event->drive();
248 }
249
250 double VM::frame_rate()
251 {
252         return pc88event->frame_rate();
253 }
254
255 // ----------------------------------------------------------------------------
256 // debugger
257 // ----------------------------------------------------------------------------
258
259 #ifdef USE_DEBUGGER
260 DEVICE *VM::get_cpu(int index)
261 {
262         if(index == 0) {
263                 return pc88cpu;
264         } else if(index == 1) {
265                 return pc88cpu_sub;
266         }
267         return NULL;
268 }
269 #endif
270
271 // ----------------------------------------------------------------------------
272 // draw screen
273 // ----------------------------------------------------------------------------
274
275 void VM::draw_screen()
276 {
277         pc88->draw_screen();
278 }
279
280 int VM::access_lamp()
281 {
282         return pc88fdc_sub->read_signal(0);
283 }
284
285 // ----------------------------------------------------------------------------
286 // soud manager
287 // ----------------------------------------------------------------------------
288
289 void VM::initialize_sound(int rate, int samples)
290 {
291         // init sound manager
292         pc88event->initialize_sound(rate, samples);
293         
294         // init sound gen
295 #ifdef SUPPORT_PC88_OPNA
296         if(pc88opn->is_ym2608) {
297                 pc88opn->init(rate, 7987248, samples, 0, 0);
298         } else
299 #endif
300         pc88opn->init(rate, 3993624, samples, 0, 0);
301 #ifdef SUPPORT_PC88_SB2
302         if(pc88sb2 != NULL) {
303 #ifdef SUPPORT_PC88_OPNA
304                 if(pc88sb2->is_ym2608) {
305                         pc88sb2->init(rate, 7987248, samples, 0, 0);
306                 } else
307 #endif
308                 pc88sb2->init(rate, 3993624, samples, 0, 0);
309         }
310 #endif
311         pc88pcm->init(rate, 8000);
312 #ifdef SUPPORT_PC88_PCG8100
313         pc88pcm0->init(rate, 8000);
314         pc88pcm1->init(rate, 8000);
315         pc88pcm2->init(rate, 8000);
316 #endif
317 }
318
319 uint16* VM::create_sound(int* extra_frames)
320 {
321         return pc88event->create_sound(extra_frames);
322 }
323
324 int VM::sound_buffer_ptr()
325 {
326         return pc88event->sound_buffer_ptr();
327 }
328
329 // ----------------------------------------------------------------------------
330 // notify key
331 // ----------------------------------------------------------------------------
332
333 void VM::key_down(int code, bool repeat)
334 {
335         pc88->key_down(code, repeat);
336 }
337
338 void VM::key_up(int code)
339 {
340 }
341
342 // ----------------------------------------------------------------------------
343 // user interface
344 // ----------------------------------------------------------------------------
345
346 void VM::open_disk(int drv, const _TCHAR* file_path, int bank)
347 {
348         pc88fdc_sub->open_disk(drv, file_path, bank);
349 }
350
351 void VM::close_disk(int drv)
352 {
353         pc88fdc_sub->close_disk(drv);
354 }
355
356 bool VM::disk_inserted(int drv)
357 {
358         return pc88fdc_sub->disk_inserted(drv);
359 }
360
361 void VM::set_disk_protected(int drv, bool value)
362 {
363         pc88fdc_sub->set_disk_protected(drv, value);
364 }
365
366 bool VM::get_disk_protected(int drv)
367 {
368         return pc88fdc_sub->get_disk_protected(drv);
369 }
370
371 void VM::play_tape(const _TCHAR* file_path)
372 {
373         pc88->play_tape(file_path);
374 }
375
376 void VM::rec_tape(const _TCHAR* file_path)
377 {
378         pc88->rec_tape(file_path);
379 }
380
381 void VM::close_tape()
382 {
383         pc88->close_tape();
384 }
385
386 bool VM::tape_inserted()
387 {
388         return pc88->tape_inserted();
389 }
390
391 bool VM::now_skip()
392 {
393 //      return event->now_skip();
394         return pc88->now_skip();
395 }
396
397 void VM::update_config()
398 {
399         int ii;
400         uint32 vol1, vol2;
401 #ifdef USE_MULTIPLE_SOUNDCARDS
402         vol1 = vol2 = (config.sound_device_level[1] + 32768) >> 8; // Card1
403         pc88opn->write_signal(SIG_YM2203_LVOLUME, vol1, 0xffffffff); // OPN: LEFT
404         pc88opn->write_signal(SIG_YM2203_RVOLUME, vol2, 0xffffffff); // OPN: RIGHT
405 # ifdef SUPPORT_PC88_SB2
406         if(pc88sb2 != NULL) {
407                 vol1 = vol2 = (config.sound_device_level[2] + 32768) >> 8; // Card2
408                 pc88sb2->write_signal(SIG_YM2203_LVOLUME, vol1, 0xffffffff); // OPN: LEFT
409                 pc88sb2->write_signal(SIG_YM2203_RVOLUME, vol2, 0xffffffff); // OPN: RIGHT
410         }
411 # endif
412 #endif
413         if(boot_mode != config.boot_mode) {
414                 // boot mode is changed !!!
415                 boot_mode = config.boot_mode;
416                 reset();
417         } else {
418                 for(DEVICE* device = first_device; device; device = device->next_device) {
419                         device->update_config();
420                 }
421         }
422 }
423
424 #define STATE_VERSION   5
425
426 void VM::save_state(FILEIO* state_fio)
427 {
428         state_fio->FputUint32(STATE_VERSION);
429         
430         for(DEVICE* device = first_device; device; device = device->next_device) {
431                 device->save_state(state_fio);
432         }
433         state_fio->FputInt32(boot_mode);
434 }
435
436 bool VM::load_state(FILEIO* state_fio)
437 {
438         if(state_fio->FgetUint32() != STATE_VERSION) {
439                 return false;
440         }
441         for(DEVICE* device = first_device; device; device = device->next_device) {
442                 if(!device->load_state(state_fio)) {
443                         return false;
444                 }
445         }
446         boot_mode = state_fio->FgetInt32();
447         return true;
448 }
449