OSDN Git Service

[General] Tracking to upstream, rev 2015-01-14.
[csp-qt/common_source_project-fm7.git] / source / src / vm / pc6001 / pc6001.cpp
1 /*\r
2         NEC PC-6001 Emulator 'yaPC-6001'\r
3         NEC PC-6001mkII Emulator 'yaPC-6201'\r
4         NEC PC-6001mkIISR Emulator 'yaPC-6401'\r
5         NEC PC-6601 Emulator 'yaPC-6601'\r
6         NEC PC-6601SR Emulator 'yaPC-6801'\r
7 \r
8         Author : tanam\r
9         Date   : 2013.07.15-\r
10 \r
11         [ virtual machine ]\r
12 */\r
13 \r
14 #include "pc6001.h"\r
15 #include "../../emu.h"\r
16 #include "../device.h"\r
17 #include "../event.h"\r
18 \r
19 #include "../i8255.h"\r
20 #include "../io.h"\r
21 #ifdef _PC6001\r
22 #include "../mc6847.h"\r
23 #include "display.h"\r
24 #else\r
25 #include "../upd7752.h"\r
26 #endif\r
27 #include "../pc6031.h"\r
28 #include "../pc80s31k.h"\r
29 #include "../upd765a.h"\r
30 #include "../ym2203.h"\r
31 #include "../z80.h"\r
32 \r
33 #include "../datarec.h"\r
34 #include "../mcs48.h"\r
35 \r
36 #ifdef USE_DEBUGGER\r
37 #include "../debugger.h"\r
38 #endif\r
39 \r
40 #if defined(_PC6601) || defined(_PC6601SR)\r
41 #include "floppy.h"\r
42 #endif\r
43 #include "joystick.h"\r
44 #include "memory.h"\r
45 #include "printer.h"\r
46 #include "psub.h"\r
47 #include "sub.h"\r
48 #include "timer.h"\r
49 \r
50 #include "../../fileio.h"\r
51 \r
52 // ----------------------------------------------------------------------------\r
53 // initialize\r
54 // ----------------------------------------------------------------------------\r
55 \r
56 VM::VM(EMU* parent_emu) : emu(parent_emu)\r
57 {\r
58         support_pc80s31k = FILEIO::IsFileExists(emu->bios_path(_T("DISK.ROM")));\r
59 #ifdef _PC6601SR\r
60         support_sub_cpu = false;\r
61 #else\r
62         support_sub_cpu = FILEIO::IsFileExists(emu->bios_path(_T(SUB_CPU_ROM_FILE_NAME)));\r
63 #endif\r
64         \r
65         // create devices\r
66         first_device = last_device = NULL;\r
67         dummy = new DEVICE(this, emu);  // must be 1st device\r
68         event = new EVENT(this, emu);   // must be 2nd device\r
69         \r
70         pio_sub = new I8255(this, emu);\r
71         io = new IO(this, emu);\r
72         psg = new YM2203(this, emu);\r
73         cpu = new Z80(this, emu);\r
74         \r
75 #if defined(_PC6601) || defined(_PC6601SR)\r
76         floppy = new FLOPPY(this, emu);\r
77 #endif\r
78         joystick = new JOYSTICK(this, emu);\r
79         memory = new MEMORY(this, emu);\r
80 //      printer = new PRINTER(this, emu);\r
81         timer = new TIMER(this, emu);\r
82         \r
83         // set contexts\r
84         event->set_context_cpu(cpu);\r
85         event->set_context_sound(psg);\r
86         \r
87 //      pio_sub->set_context_port_b(printer, SIG_PRINTER_OUT, 0xff, 0);\r
88 //      pio_sub->set_context_port_c(printer, SIG_PRINTER_STB, 0x01, 0);\r
89         pio_sub->set_context_port_c(memory, SIG_MEMORY_PIO_PORT_C, 0x06, 0);    // CRTKILL,CGSWN\r
90         \r
91 #ifdef _PC6001\r
92         display = new DISPLAY(this, emu);\r
93         vdp = new MC6847(this, emu);\r
94         display->set_context_vdp(vdp);\r
95         display->set_vram_ptr(memory->get_vram());\r
96         display->set_context_timer(timer);\r
97         vdp->load_font_image(emu->bios_path(_T("CGROM60.60")));\r
98         vdp->set_context_cpu(cpu);\r
99         pio_sub->set_context_port_c(vdp, SIG_MC6847_ENABLE, 0x02, 0);   // CRTKILL\r
100 #else\r
101         voice = new UPD7752(this, emu);\r
102         event->set_context_sound(voice);\r
103         memory->set_context_timer(timer);\r
104 #endif\r
105         memory->set_context_cpu(cpu);\r
106         joystick->set_context_psg(psg);\r
107         \r
108         timer->set_context_cpu(cpu);\r
109 #ifndef _PC6001\r
110         timer->set_context_memory(memory);\r
111 #endif\r
112         if(support_sub_cpu) {\r
113                 cpu_sub = new MCS48(this, emu);\r
114                 sub = new SUB(this, emu);\r
115                 drec = new DATAREC(this, emu);\r
116                 event->set_context_cpu(cpu_sub, 8000000);\r
117                 cpu_sub->set_context_mem(new MCS48MEM(this, emu));\r
118                 cpu_sub->set_context_io(sub);\r
119 #ifdef USE_DEBUGGER\r
120                 cpu_sub->set_context_debugger(new DEBUGGER(this, emu));\r
121 #endif\r
122                 sub->set_context_pio(pio_sub);\r
123                 sub->set_context_drec(drec);\r
124                 sub->set_context_timer(timer);\r
125                 pio_sub->set_context_port_c(cpu_sub, SIG_CPU_IRQ, 0x80, 0);\r
126                 drec->set_context_out(sub, SIG_SUB_DATAREC, 1);\r
127                 timer->set_context_sub(sub);\r
128         } else {\r
129                 psub = new PSUB(this, emu);\r
130                 psub->set_context_pio(pio_sub);\r
131                 psub->set_context_timer(timer);\r
132                 timer->set_context_sub(psub);\r
133                 cpu_sub = NULL;\r
134         }\r
135         if(support_pc80s31k) {\r
136                 pio_fdd = new I8255(this, emu);\r
137                 pio_pc80s31k = new I8255(this, emu);\r
138                 pc80s31k = new PC80S31K(this, emu);\r
139                 fdc_pc80s31k = new UPD765A(this, emu);\r
140                 cpu_pc80s31k = new Z80(this, emu);\r
141                 \r
142                 event->set_context_cpu(cpu_pc80s31k, 4000000);\r
143                 pc80s31k->set_context_cpu(cpu_pc80s31k);\r
144                 pc80s31k->set_context_fdc(fdc_pc80s31k);\r
145                 pc80s31k->set_context_pio(pio_pc80s31k);\r
146                 pio_fdd->set_context_port_a(pio_pc80s31k, SIG_I8255_PORT_A, 0xff, 0);\r
147                 pio_fdd->set_context_port_b(pio_pc80s31k, SIG_I8255_PORT_A, 0xff, 0);\r
148                 pio_fdd->set_context_port_c(pio_pc80s31k, SIG_I8255_PORT_C, 0x0f, 4);\r
149                 pio_fdd->set_context_port_c(pio_pc80s31k, SIG_I8255_PORT_C, 0xf0, -4);\r
150                 pio_fdd->clear_ports_by_cmdreg = true;\r
151                 pio_pc80s31k->set_context_port_a(pio_fdd, SIG_I8255_PORT_B, 0xff, 0);\r
152                 pio_pc80s31k->set_context_port_b(pio_fdd, SIG_I8255_PORT_A, 0xff, 0);\r
153                 pio_pc80s31k->set_context_port_c(pio_fdd, SIG_I8255_PORT_C, 0x0f, 4);\r
154                 pio_pc80s31k->set_context_port_c(pio_fdd, SIG_I8255_PORT_C, 0xf0, -4);\r
155                 pio_pc80s31k->clear_ports_by_cmdreg = true;\r
156                 fdc_pc80s31k->set_context_irq(cpu_pc80s31k, SIG_CPU_IRQ, 1);\r
157                 cpu_pc80s31k->set_context_mem(pc80s31k);\r
158                 cpu_pc80s31k->set_context_io(pc80s31k);\r
159                 cpu_pc80s31k->set_context_intr(pc80s31k);\r
160 #ifdef USE_DEBUGGER\r
161                 cpu_pc80s31k->set_context_debugger(new DEBUGGER(this, emu));\r
162 #endif\r
163 #if defined(_PC6601) || defined(_PC6601SR)\r
164                 floppy->set_context_ext(pio_fdd);\r
165 #endif\r
166         } else {\r
167                 pc6031 = new PC6031(this, emu);\r
168 #if defined(_PC6601) || defined(_PC6601SR)\r
169                 floppy->set_context_ext(pc6031);\r
170 #endif\r
171                 cpu_pc80s31k = NULL;\r
172         }\r
173         \r
174         // cpu bus\r
175         cpu->set_context_mem(memory);\r
176         cpu->set_context_io(io);\r
177         cpu->set_context_intr(timer);\r
178 #ifdef USE_DEBUGGER\r
179         cpu->set_context_debugger(new DEBUGGER(this, emu));\r
180 #endif\r
181         \r
182         // i/o bus\r
183         if(support_sub_cpu) {\r
184                 io->set_iomap_range_rw(0x90, 0x93, sub);\r
185         } else {\r
186                 io->set_iomap_range_rw(0x90, 0x93, psub);\r
187         }\r
188         io->set_iomap_alias_w(0xa0, psg, 0);                    // PSG ch\r
189         io->set_iomap_alias_w(0xa1, psg, 1);                    // PSG data\r
190         io->set_iomap_alias_r(0xa2, psg, 1);                    // PSG data\r
191 #if defined(_PC6601SR) || defined(_PC6001MK2SR)\r
192         io->set_iomap_alias_r(0xa3, psg, 0);                    // FM status\r
193         io->set_iomap_range_rw(0x40, 0x6f, memory);             // VRAM addr\r
194 #endif\r
195 #ifdef _PC6001\r
196         io->set_iomap_single_w(0xb0, display);                  // VRAM addr\r
197         io->set_iomap_single_w(0x00, memory);                   // MEMORY MAP\r
198 #else\r
199         io->set_iomap_single_w(0xb0, memory);                   // VRAM addr\r
200         io->set_iomap_range_rw(0xc0, 0xcf, memory);             // VRAM addr\r
201         io->set_iomap_range_rw(0xe0, 0xe3, voice);              // VOICE\r
202 #if defined(_PC6601) || defined(_PC6601SR)\r
203         io->set_iomap_range_rw(0xb8, 0xbf, timer);              // IRQ\r
204         io->set_iomap_range_rw(0xfa, 0xfb, timer);              // IRQ\r
205 #endif\r
206         io->set_iomap_range_rw(0xf3, 0xf7, timer);              // IRQ/Timer\r
207 #endif\r
208         \r
209 #if defined(_PC6601) || defined(_PC6601SR)\r
210         io->set_iomap_range_rw(0xb1, 0xb3, floppy);             // DISK DRIVE\r
211         io->set_iomap_range_rw(0xb5, 0xb7, floppy);             // DISK DRIVE (Mirror)\r
212         io->set_iomap_range_rw(0xd0, 0xde, floppy);             // DISK DRIVE\r
213 #else\r
214         io->set_iovalue_single_r(0xb1, 0x01);\r
215 #if defined(_PC6601SR)\r
216         io->set_iovalue_single_r(0xb2, 0x02);\r
217 #elif defined(_PC6001MK2SR)\r
218         io->set_iovalue_single_r(0xb2, 0x00);\r
219 #endif\r
220         \r
221         if(support_pc80s31k) {\r
222                 io->set_iomap_range_rw(0xd0, 0xd2, pio_fdd);\r
223                 io->set_iomap_single_w(0xd3, pio_fdd);\r
224         } else {\r
225                 io->set_iomap_range_rw(0xd0, 0xd3, pc6031);\r
226         }\r
227 #endif\r
228         io->set_iomap_range_rw(0xf0, 0xf2, memory);             // MEMORY MAP\r
229         \r
230         // initialize all devices\r
231         for(DEVICE* device = first_device; device; device = device->next_device) {\r
232                 device->initialize();\r
233         }\r
234         if(support_sub_cpu) {\r
235                 // load rom images after cpustate is allocated\r
236 #ifdef _PC6601SR\r
237 #else\r
238                 cpu_sub->load_rom_image(emu->bios_path(SUB_CPU_ROM_FILE_NAME));\r
239 #endif\r
240         }\r
241 }\r
242 \r
243 VM::~VM()\r
244 {\r
245         // delete all devices\r
246         for(DEVICE* device = first_device; device;) {\r
247                 DEVICE *next_device = device->next_device;\r
248                 device->release();\r
249                 delete device;\r
250                 device = next_device;\r
251         }\r
252 }\r
253 \r
254 DEVICE* VM::get_device(int id)\r
255 {\r
256         for(DEVICE* device = first_device; device; device = device->next_device) {\r
257                 if(device->this_device_id == id) {\r
258                         return device;\r
259                 }\r
260         }\r
261         return NULL;\r
262 }\r
263 \r
264 // ----------------------------------------------------------------------------\r
265 // drive virtual machine\r
266 // ----------------------------------------------------------------------------\r
267 void VM::reset()\r
268 {\r
269         // reset all devices\r
270         for(DEVICE* device = first_device; device; device = device->next_device) {\r
271                 device->reset();\r
272         }\r
273         if(support_pc80s31k) {\r
274                 pio_fdd->write_signal(SIG_I8255_PORT_C, 0, 0xff);\r
275                 pio_pc80s31k->write_signal(SIG_I8255_PORT_C, 0, 0xff);\r
276         }\r
277 }\r
278 \r
279 void VM::run()\r
280 {\r
281         event->drive();\r
282 }\r
283 \r
284 // ----------------------------------------------------------------------------\r
285 // debugger\r
286 // ----------------------------------------------------------------------------\r
287 \r
288 #ifdef USE_DEBUGGER\r
289 DEVICE *VM::get_cpu(int index)\r
290 {\r
291         if(index == 0) {\r
292                 return cpu;\r
293         } else if(index == 1) {\r
294                 return cpu_sub;\r
295         } else if(index == 2) {\r
296                 return cpu_pc80s31k;\r
297         }\r
298         return NULL;\r
299 }\r
300 #endif\r
301 \r
302 // ----------------------------------------------------------------------------\r
303 // draw screen\r
304 // ----------------------------------------------------------------------------\r
305 \r
306 void VM::draw_screen()\r
307 {\r
308 #ifdef _PC6001\r
309         display->draw_screen();\r
310 #else\r
311         memory->draw_screen();\r
312 #endif\r
313 }\r
314 // ----------------------------------------------------------------------------\r
315 // soud manager\r
316 // ----------------------------------------------------------------------------\r
317 \r
318 void VM::initialize_sound(int rate, int samples)\r
319 {\r
320         // init sound manager\r
321         event->initialize_sound(rate, samples);\r
322         \r
323         // init sound gen\r
324         psg->init(rate, 4000000, samples, 0, 0);\r
325 }\r
326 \r
327 uint16* VM::create_sound(int* extra_frames)\r
328 {\r
329         return event->create_sound(extra_frames);\r
330 }\r
331 \r
332 int VM::sound_buffer_ptr()\r
333 {\r
334         return event->sound_buffer_ptr();\r
335 }\r
336 \r
337 // ----------------------------------------------------------------------------\r
338 // user interface\r
339 // ----------------------------------------------------------------------------\r
340 \r
341 void VM::open_cart(int drv, _TCHAR* file_path)\r
342 {\r
343         if(drv == 0) {\r
344                 memory->open_cart(file_path);\r
345                 reset();\r
346         }\r
347 }\r
348 \r
349 void VM::close_cart(int drv)\r
350 {\r
351         if(drv == 0) {\r
352                 memory->close_cart();\r
353                 reset();\r
354         }\r
355 }\r
356 \r
357 bool VM::cart_inserted(int drv)\r
358 {\r
359         if(drv == 0) {\r
360                 return memory->cart_inserted();\r
361         } else {\r
362                 return false;\r
363         }\r
364 }\r
365 \r
366 int VM::access_lamp()\r
367 {\r
368         uint32 status = 0; /// fdc->read_signal(0);\r
369 #if defined(_PC6601) || defined(_PC6601SR)\r
370         status = floppy->read_signal(0);\r
371 #endif\r
372         if(support_pc80s31k) {\r
373                 status |= fdc_pc80s31k->read_signal(0);\r
374         } else {\r
375                 status |= pc6031->read_signal(0);\r
376         }\r
377         return status;\r
378 }\r
379 \r
380 void VM::open_disk(int drv, _TCHAR* file_path, int offset)\r
381 {\r
382 #if defined(_PC6601) || defined(_PC6601SR)\r
383         if(drv < 2) {\r
384                 floppy->open_disk(drv, file_path, offset);\r
385                 return;\r
386         } else {\r
387                 drv -= 2;\r
388         }\r
389 #endif\r
390         if(support_pc80s31k) {\r
391                 fdc_pc80s31k->open_disk(drv, file_path, offset);\r
392         } else {\r
393                 pc6031->open_disk(drv, file_path, offset);\r
394         }\r
395 }\r
396 \r
397 void VM::close_disk(int drv)\r
398 {\r
399 #if defined(_PC6601) || defined(_PC6601SR)\r
400         if(drv < 2) {\r
401                 floppy->close_disk(drv);\r
402                 return;\r
403         } else {\r
404                 drv -= 2;\r
405         }\r
406 #endif\r
407         if(support_pc80s31k) {\r
408                 fdc_pc80s31k->close_disk(drv);\r
409         } else {\r
410                 pc6031->close_disk(drv);\r
411         }\r
412 }\r
413 \r
414 bool VM::disk_inserted(int drv)\r
415 {\r
416 #if defined(_PC6601) || defined(_PC6601SR)\r
417         if(drv < 2) {\r
418                 return floppy->disk_inserted(drv);\r
419         } else {\r
420                 drv -= 2;\r
421         }\r
422 #endif\r
423         if(support_pc80s31k) {\r
424                 return fdc_pc80s31k->disk_inserted(drv);\r
425         } else {\r
426                 return pc6031->disk_inserted(drv);\r
427         }\r
428 }\r
429 \r
430 void VM::play_tape(_TCHAR* file_path)\r
431 {\r
432         if(support_sub_cpu) {\r
433                 // support both p6/p6t and wav\r
434                 drec->play_tape(file_path);\r
435         } else {\r
436                 // support only p6/p6t\r
437                 psub->play_tape(file_path);\r
438         }\r
439 }\r
440 \r
441 void VM::rec_tape(_TCHAR* file_path)\r
442 {\r
443         if(support_sub_cpu) {\r
444                 // support both p6/p6t and wav\r
445                 sub->rec_tape(file_path);       // temporary\r
446 //              drec->rec_tape(file_path);\r
447         } else {\r
448                 // support both p6/p6t and wav\r
449                 psub->rec_tape(file_path);\r
450         }\r
451 }\r
452 \r
453 void VM::close_tape()\r
454 {\r
455         if(support_sub_cpu) {\r
456                 if(sub->tape_inserted()) {\r
457                         sub->close_tape();      // temporary\r
458                 } else {\r
459                         drec->close_tape();\r
460                 }\r
461         } else {\r
462                 psub->close_tape();\r
463         }\r
464 }\r
465 \r
466 bool VM::tape_inserted()\r
467 {\r
468         if(support_sub_cpu) {\r
469                 return drec->tape_inserted() || sub->tape_inserted();\r
470         } else {\r
471                 return psub->tape_inserted();\r
472         }\r
473 }\r
474 \r
475 bool VM::now_skip()\r
476 {\r
477         return event->now_skip();\r
478 }\r
479 \r
480 void VM::update_config()\r
481 {\r
482         for(DEVICE* device = first_device; device; device = device->next_device) {\r
483                 device->update_config();\r
484         }\r
485 }\r