OSDN Git Service

[General] Merge upstream : 2015-02-21.
[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 "../upd1990a.h"
20 #include "../ym2203.h"
21 #include "../z80.h"
22
23 #include "../disk.h"
24 #include "../pc80s31k.h"
25 #include "../upd765a.h"
26
27 #ifdef USE_DEBUGGER
28 #include "../debugger.h"
29 #endif
30
31 #ifdef SUPPORT_PC88_PCG8100
32 #include "../i8253.h"
33 #endif
34
35 #include "pc88.h"
36
37 #include "../../fileio.h"
38
39 // ----------------------------------------------------------------------------
40 // initialize
41 // ----------------------------------------------------------------------------
42
43 VM::VM(EMU* parent_emu) : emu(parent_emu)
44 {
45         // check configs
46         boot_mode = config.boot_mode;
47         
48         // create devices
49         first_device = last_device = NULL;
50         dummy = new DEVICE(this, emu);  // must be 1st device
51         
52         pc88event = new EVENT(this, emu);
53 //      pc88event->set_frames_per_sec(60);
54 //      pc88event->set_lines_per_frame(260);
55         
56         pc88 = new PC88(this, emu);
57 //      pc88->set_context_event_manager(pc88event);
58         pc88sio = new I8251(this, emu);
59 //      pc88sio->set_context_event_manager(pc88event);
60         pc88pio = new I8255(this, emu);
61 //      pc88pio->set_context_event_manager(pc88event);
62         pc88pcm = new PCM1BIT(this, emu);
63 //      pc88pcm->set_context_event_manager(pc88event);
64         pc88rtc = new UPD1990A(this, emu);
65 //      pc88rtc->set_context_event_manager(pc88event);
66         pc88opn = new YM2203(this, emu);
67 #ifdef SUPPORT_PC88_OPNA
68         pc88opn->is_ym2608 = (config.sound_device_type == 0);
69 #endif
70 //      pc88opn->set_context_event_manager(pc88event);
71         pc88cpu = new Z80(this, emu);
72 //      pc88cpu->set_context_event_manager(pc88event);
73         
74         pc88sub = new PC80S31K(this, emu);
75 //      pc88sub->set_context_event_manager(pc88event);
76         pc88pio_sub = new I8255(this, emu);
77 //      pc88pio_sub->set_context_event_manager(pc88event);
78         pc88fdc_sub = new UPD765A(this, emu);
79 //      pc88fdc_sub->set_context_event_manager(pc88event);
80         pc88cpu_sub = new Z80(this, emu);
81 //      pc88cpu_sub->set_context_event_manager(pc88event);
82         
83 #ifdef SUPPORT_PC88_PCG8100
84         pc88pit = new I8253(this, emu);
85 //      pc88pit->set_context_event_manager(pc88event);
86         pc88pcm0 = new PCM1BIT(this, emu);
87 //      pc88pcm->set_context_event_manager(pc88event);
88         pc88pcm1 = new PCM1BIT(this, emu);
89 //      pc88pcm->set_context_event_manager(pc88event);
90         pc88pcm2 = new PCM1BIT(this, emu);
91 //      pc88pcm->set_context_event_manager(pc88event);
92 #endif
93         
94 #ifdef SUPPORT_PC88_HIGH_CLOCK
95         pc88event->set_context_cpu(pc88cpu, (config.cpu_type != 0) ? 3993624 : 7987248);
96 #else
97         pc88event->set_context_cpu(pc88cpu, 3993624);
98 #endif
99         pc88event->set_context_cpu(pc88cpu_sub, 3993624);
100         pc88event->set_context_sound(pc88opn);
101         pc88event->set_context_sound(pc88pcm);
102 #ifdef SUPPORT_PC88_PCG8100
103         pc88event->set_context_sound(pc88pcm0);
104         pc88event->set_context_sound(pc88pcm1);
105         pc88event->set_context_sound(pc88pcm2);
106 #endif
107         
108         pc88->set_context_cpu(pc88cpu);
109         pc88->set_context_opn(pc88opn);
110         pc88->set_context_pcm(pc88pcm);
111         pc88->set_context_pio(pc88pio);
112         pc88->set_context_rtc(pc88rtc);
113         pc88->set_context_sio(pc88sio);
114 #ifdef SUPPORT_PC88_PCG8100
115         pc88->set_context_pcg_pit(pc88pit);
116         pc88->set_context_pcg_pcm0(pc88pcm0);
117         pc88->set_context_pcg_pcm1(pc88pcm1);
118         pc88->set_context_pcg_pcm2(pc88pcm2);
119 #endif
120         pc88cpu->set_context_mem(pc88);
121         pc88cpu->set_context_io(pc88);
122         pc88cpu->set_context_intr(pc88);
123 #ifdef USE_DEBUGGER
124         pc88cpu->set_context_debugger(new DEBUGGER(this, emu));
125 #endif
126         pc88opn->set_context_irq(pc88, SIG_PC88_SOUND_IRQ, 1);
127         pc88sio->set_context_rxrdy(pc88, SIG_PC88_USART_IRQ, 1);
128         pc88sio->set_context_out(pc88, SIG_PC88_USART_OUT);
129         
130         pc88sub->set_context_cpu(pc88cpu_sub);
131         pc88sub->set_context_fdc(pc88fdc_sub);
132         pc88sub->set_context_pio(pc88pio_sub);
133         pc88pio->set_context_port_a(pc88pio_sub, SIG_I8255_PORT_B, 0xff, 0);
134         pc88pio->set_context_port_b(pc88pio_sub, SIG_I8255_PORT_A, 0xff, 0);
135         pc88pio->set_context_port_c(pc88pio_sub, SIG_I8255_PORT_C, 0x0f, 4);
136         pc88pio->set_context_port_c(pc88pio_sub, SIG_I8255_PORT_C, 0xf0, -4);
137         pc88pio->clear_ports_by_cmdreg = true;
138         pc88pio_sub->set_context_port_a(pc88pio, SIG_I8255_PORT_B, 0xff, 0);
139         pc88pio_sub->set_context_port_b(pc88pio, SIG_I8255_PORT_A, 0xff, 0);
140         pc88pio_sub->set_context_port_c(pc88pio, SIG_I8255_PORT_C, 0x0f, 4);
141         pc88pio_sub->set_context_port_c(pc88pio, SIG_I8255_PORT_C, 0xf0, -4);
142         pc88pio_sub->clear_ports_by_cmdreg = true;
143         pc88fdc_sub->set_context_irq(pc88cpu_sub, SIG_CPU_IRQ, 1);
144         pc88cpu_sub->set_context_mem(pc88sub);
145         pc88cpu_sub->set_context_io(pc88sub);
146         pc88cpu_sub->set_context_intr(pc88sub);
147 #ifdef USE_DEBUGGER
148         pc88cpu_sub->set_context_debugger(new DEBUGGER(this, emu));
149 #endif
150         
151 #ifdef SUPPORT_PC88_PCG8100
152         pc88pit->set_context_ch0(pc88pcm0, SIG_PCM1BIT_SIGNAL, 1);
153         pc88pit->set_context_ch1(pc88pcm1, SIG_PCM1BIT_SIGNAL, 1);
154         pc88pit->set_context_ch2(pc88pcm2, SIG_PCM1BIT_SIGNAL, 1);
155         pc88pit->set_constant_clock(0, 3993624);
156         pc88pit->set_constant_clock(1, 3993624);
157         pc88pit->set_constant_clock(2, 3993624);
158 #endif
159         
160         // initialize all devices
161         for(DEVICE* device = first_device; device; device = device->next_device) {
162                 device->initialize();
163         }
164 }
165
166 VM::~VM()
167 {
168         // delete all devices
169         for(DEVICE* device = first_device; device;) {
170                 DEVICE *next_device = device->next_device;
171                 device->release();
172                 delete device;
173                 device = next_device;
174         }
175 }
176
177 DEVICE* VM::get_device(int id)
178 {
179         for(DEVICE* device = first_device; device; device = device->next_device) {
180                 if(device->this_device_id == id) {
181                         return device;
182                 }
183         }
184         return NULL;
185 }
186
187 // ----------------------------------------------------------------------------
188 // drive virtual machine
189 // ----------------------------------------------------------------------------
190
191 void VM::reset()
192 {
193         // reset all devices
194         for(DEVICE* device = first_device; device; device = device->next_device) {
195                 device->reset();
196         }
197         for(DEVICE* device = first_device; device; device = device->next_device) {
198                 device->reset();
199         }
200         
201         // initial device settings
202         pc88opn->SetReg(0x29, 3); // for Misty Blue
203         pc88pio->write_signal(SIG_I8255_PORT_C, 0, 0xff);
204         pc88pio_sub->write_signal(SIG_I8255_PORT_C, 0, 0xff);
205 }
206
207 void VM::run()
208 {
209         pc88event->drive();
210 }
211
212 double VM::frame_rate()
213 {
214         return pc88event->frame_rate();
215 }
216
217 // ----------------------------------------------------------------------------
218 // debugger
219 // ----------------------------------------------------------------------------
220
221 #ifdef USE_DEBUGGER
222 DEVICE *VM::get_cpu(int index)
223 {
224         if(index == 0) {
225                 return pc88cpu;
226         } else if(index == 1) {
227                 return pc88cpu_sub;
228         }
229         return NULL;
230 }
231 #endif
232
233 // ----------------------------------------------------------------------------
234 // draw screen
235 // ----------------------------------------------------------------------------
236
237 void VM::draw_screen()
238 {
239         pc88->draw_screen();
240 }
241
242 int VM::access_lamp()
243 {
244         return pc88fdc_sub->read_signal(0);
245 }
246
247 // ----------------------------------------------------------------------------
248 // soud manager
249 // ----------------------------------------------------------------------------
250
251 void VM::initialize_sound(int rate, int samples)
252 {
253         // init sound manager
254         pc88event->initialize_sound(rate, samples);
255         
256         // init sound gen
257 #ifdef SUPPORT_PC88_OPNA
258         if(pc88opn->is_ym2608) {
259                 pc88opn->init(rate, 7987248, samples, 0, 0);
260         } else
261 #endif
262         pc88opn->init(rate, 3993624, samples, 0, 0);
263         pc88pcm->init(rate, 8000);
264 #ifdef SUPPORT_PC88_PCG8100
265         pc88pcm0->init(rate, 8000);
266         pc88pcm1->init(rate, 8000);
267         pc88pcm2->init(rate, 8000);
268 #endif
269 }
270
271 uint16* VM::create_sound(int* extra_frames)
272 {
273         return pc88event->create_sound(extra_frames);
274 }
275
276 int VM::sound_buffer_ptr()
277 {
278         return pc88event->sound_buffer_ptr();
279 }
280
281 // ----------------------------------------------------------------------------
282 // notify key
283 // ----------------------------------------------------------------------------
284
285 void VM::key_down(int code, bool repeat)
286 {
287         pc88->key_down(code, repeat);
288 }
289
290 void VM::key_up(int code)
291 {
292 }
293
294 // ----------------------------------------------------------------------------
295 // user interface
296 // ----------------------------------------------------------------------------
297
298 void VM::open_disk(int drv, _TCHAR* file_path, int bank)
299 {
300         pc88fdc_sub->open_disk(drv, file_path, bank);
301 }
302
303 void VM::close_disk(int drv)
304 {
305         pc88fdc_sub->close_disk(drv);
306 }
307
308 bool VM::disk_inserted(int drv)
309 {
310         return pc88fdc_sub->disk_inserted(drv);
311 }
312
313 void VM::write_protect_fd(int drv, bool flag)
314 {
315         pc88fdc_sub->write_protect_fd(drv, flag);
316 }
317
318 bool VM::is_write_protect_fd(int drv)
319 {
320         return pc88fdc_sub->is_write_protect_fd(drv);
321 }
322
323 void VM::play_tape(_TCHAR* file_path)
324 {
325         pc88->play_tape(file_path);
326 }
327
328 void VM::rec_tape(_TCHAR* file_path)
329 {
330         pc88->rec_tape(file_path);
331 }
332
333 void VM::close_tape()
334 {
335         pc88->close_tape();
336 }
337
338 bool VM::tape_inserted()
339 {
340         return pc88->tape_inserted();
341 }
342
343 int VM::get_tape_ptr()
344 {
345         return pc88->get_tape_ptr();
346 }
347
348 bool VM::now_skip()
349 {
350 //      return event->now_skip();
351         return pc88->now_skip();
352 }
353
354 void VM::update_config()
355 {
356         if(boot_mode != config.boot_mode) {
357                 // boot mode is changed !!!
358                 boot_mode = config.boot_mode;
359                 reset();
360         } else {
361                 for(DEVICE* device = first_device; device; device = device->next_device) {
362                         device->update_config();
363                 }
364         }
365 }
366
367 #define STATE_VERSION   3
368
369 void VM::save_state(FILEIO* state_fio)
370 {
371         state_fio->FputUint32(STATE_VERSION);
372         
373         for(DEVICE* device = first_device; device; device = device->next_device) {
374                 device->save_state(state_fio);
375         }
376         state_fio->FputInt32(boot_mode);
377 }
378
379 bool VM::load_state(FILEIO* state_fio)
380 {
381         if(state_fio->FgetUint32() != STATE_VERSION) {
382                 return false;
383         }
384         for(DEVICE* device = first_device; device; device = device->next_device) {
385                 if(!device->load_state(state_fio)) {
386                         return false;
387                 }
388         }
389         boot_mode = state_fio->FgetInt32();
390         return true;
391 }
392