OSDN Git Service

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