OSDN Git Service

[VM][General] Merge upstream 2016-02-13. Still don't implement OSD/Gui part of joysti...
[csp-qt/common_source_project-fm7.git] / source / src / vm / pc6001 / pc6001.cpp
1 /*
2         NEC PC-6001 Emulator 'yaPC-6001'
3         NEC PC-6001mkII Emulator 'yaPC-6201'
4         NEC PC-6001mkIISR Emulator 'yaPC-6401'
5         NEC PC-6601 Emulator 'yaPC-6601'
6         NEC PC-6601SR Emulator 'yaPC-6801'
7
8         Author : tanam
9         Date   : 2013.07.15-
10
11         [ virtual machine ]
12 */
13
14 #include "pc6001.h"
15 #include "../../emu.h"
16 #include "../device.h"
17 #include "../event.h"
18
19 #include "../disk.h"
20 #include "../i8255.h"
21 #include "../io.h"
22 #ifdef _PC6001
23 #include "../mc6847.h"
24 #include "display.h"
25 #else
26 #include "../upd7752.h"
27 #endif
28 #include "../pc6031.h"
29 #include "../pc80s31k.h"
30 #include "../prnfile.h"
31 #include "../upd765a.h"
32 #include "../ym2203.h"
33 #include "../z80.h"
34
35 #include "../datarec.h"
36 #include "../mcs48.h"
37
38 #ifdef USE_DEBUGGER
39 #include "../debugger.h"
40 #endif
41
42 #if defined(_PC6601) || defined(_PC6601SR)
43 #include "floppy.h"
44 #endif
45 #include "joystick.h"
46 #include "memory.h"
47 #include "psub.h"
48 #include "sub.h"
49 #include "timer.h"
50
51 // ----------------------------------------------------------------------------
52 // initialize
53 // ----------------------------------------------------------------------------
54
55 VM::VM(EMU* parent_emu) : emu(parent_emu)
56 {
57         support_pc80s31k = FILEIO::IsFileExists(create_local_path(_T("DISK.ROM")));
58 #ifdef _PC6601SR
59         support_sub_cpu = false;
60 #else
61         support_sub_cpu = FILEIO::IsFileExists(create_local_path(_T(SUB_CPU_ROM_FILE_NAME)));
62 #endif
63         
64         // create devices
65         first_device = last_device = NULL;
66         dummy = new DEVICE(this, emu);  // must be 1st device
67         event = new EVENT(this, emu);   // must be 2nd device
68         
69         pio_sub = new I8255(this, emu);
70         io = new IO(this, emu);
71         psg = new YM2203(this, emu);
72         cpu = new Z80(this, emu);
73    
74         if(config.printer_device_type == 0) {
75                 printer = new PRNFILE(this, emu);
76         } else {
77                 printer = dummy;
78         }
79         
80 #if defined(_PC6601) || defined(_PC6601SR)
81         floppy = new FLOPPY(this, emu);
82 #endif
83         joystick = new JOYSTICK(this, emu);
84         memory = new MEMORY(this, emu);
85         timer = new TIMER(this, emu);
86         
87         // set contexts
88         event->set_context_cpu(cpu);
89         event->set_context_sound(psg);
90         
91         pio_sub->set_context_port_b(printer, SIG_PRINTER_DATA, 0xff, 0);
92         pio_sub->set_context_port_c(printer, SIG_PRINTER_STROBE, 0x01, 0);
93         pio_sub->set_context_port_c(memory, SIG_MEMORY_PIO_PORT_C, 0x06, 0);    // CRTKILL,CGSWN
94         
95 #ifdef _PC6001
96         display = new DISPLAY(this, emu);
97         vdp = new MC6847(this, emu);
98         display->set_context_vdp(vdp);
99         display->set_vram_ptr(memory->get_vram());
100         display->set_context_timer(timer);
101         vdp->load_font_image(create_local_path(_T("CGROM60.60")));
102         vdp->set_context_cpu(cpu);
103         pio_sub->set_context_port_c(vdp, SIG_MC6847_ENABLE, 0x02, 0);   // CRTKILL
104 #else
105         voice = new UPD7752(this, emu);
106         event->set_context_sound(voice);
107         memory->set_context_timer(timer);
108 #endif
109         memory->set_context_cpu(cpu);
110         joystick->set_context_psg(psg);
111         
112         timer->set_context_cpu(cpu);
113 #ifndef _PC6001
114         timer->set_context_memory(memory);
115 #endif
116         if(support_sub_cpu) {
117                 cpu_sub = new MCS48(this, emu);
118                 sub = new SUB(this, emu);
119                 drec = new DATAREC(this, emu);
120                 event->set_context_cpu(cpu_sub, 8000000);
121                 event->set_context_sound(drec);
122                 cpu_sub->set_context_mem(new MCS48MEM(this, emu));
123                 cpu_sub->set_context_io(sub);
124 #ifdef USE_DEBUGGER
125                 cpu_sub->set_context_debugger(new DEBUGGER(this, emu));
126 #endif
127 //#ifdef DATAREC_SOUND
128 //              event->set_context_sound(drec);
129 //#endif
130                 sub->set_context_pio(pio_sub);
131                 sub->set_context_drec(drec);
132                 sub->set_context_timer(timer);
133                 pio_sub->set_context_port_c(cpu_sub, SIG_CPU_IRQ, 0x80, 0);
134                 drec->set_context_ear(sub, SIG_SUB_DATAREC, 1);
135                 timer->set_context_sub(sub);
136         } else {
137                 psub = new PSUB(this, emu);
138                 psub->set_context_pio(pio_sub);
139                 psub->set_context_timer(timer);
140                 timer->set_context_sub(psub);
141                 cpu_sub = NULL;
142         }
143         if(support_pc80s31k) {
144                 pio_fdd = new I8255(this, emu);
145                 pio_pc80s31k = new I8255(this, emu);
146                 pc80s31k = new PC80S31K(this, emu);
147                 fdc_pc80s31k = new UPD765A(this, emu);
148                 cpu_pc80s31k = new Z80(this, emu);
149                 
150                 event->set_context_cpu(cpu_pc80s31k, 4000000);
151                 pc80s31k->set_context_cpu(cpu_pc80s31k);
152                 pc80s31k->set_context_fdc(fdc_pc80s31k);
153                 pc80s31k->set_context_pio(pio_pc80s31k);
154                 pio_fdd->set_context_port_a(pio_pc80s31k, SIG_I8255_PORT_B, 0xff, 0);
155                 pio_fdd->set_context_port_b(pio_pc80s31k, SIG_I8255_PORT_A, 0xff, 0);
156                 pio_fdd->set_context_port_c(pio_pc80s31k, SIG_I8255_PORT_C, 0x0f, 4);
157                 pio_fdd->set_context_port_c(pio_pc80s31k, SIG_I8255_PORT_C, 0xf0, -4);
158                 pio_fdd->clear_ports_by_cmdreg = true;
159                 pio_pc80s31k->set_context_port_a(pio_fdd, SIG_I8255_PORT_B, 0xff, 0);
160                 pio_pc80s31k->set_context_port_b(pio_fdd, SIG_I8255_PORT_A, 0xff, 0);
161                 pio_pc80s31k->set_context_port_c(pio_fdd, SIG_I8255_PORT_C, 0x0f, 4);
162                 pio_pc80s31k->set_context_port_c(pio_fdd, SIG_I8255_PORT_C, 0xf0, -4);
163                 pio_pc80s31k->clear_ports_by_cmdreg = true;
164                 fdc_pc80s31k->set_context_irq(cpu_pc80s31k, SIG_CPU_IRQ, 1);
165                 cpu_pc80s31k->set_context_mem(pc80s31k);
166                 cpu_pc80s31k->set_context_io(pc80s31k);
167                 cpu_pc80s31k->set_context_intr(pc80s31k);
168 #ifdef USE_DEBUGGER
169                 cpu_pc80s31k->set_context_debugger(new DEBUGGER(this, emu));
170 #endif
171 #if defined(_PC6601) || defined(_PC6601SR)
172                 floppy->set_context_ext(pio_fdd);
173 #endif
174         } else {
175                 pc6031 = new PC6031(this, emu);
176 #if defined(_PC6601) || defined(_PC6601SR)
177                 floppy->set_context_ext(pc6031);
178 #endif
179                 cpu_pc80s31k = NULL;
180         }
181         
182         // cpu bus
183         cpu->set_context_mem(memory);
184         cpu->set_context_io(io);
185         cpu->set_context_intr(timer);
186 #ifdef USE_DEBUGGER
187         cpu->set_context_debugger(new DEBUGGER(this, emu));
188 #endif
189         
190         // i/o bus
191         if(support_sub_cpu) {
192                 io->set_iomap_range_rw(0x90, 0x93, sub);
193         } else {
194                 io->set_iomap_range_rw(0x90, 0x93, psub);
195         }
196         io->set_iomap_alias_w(0xa0, psg, 0);                    // PSG ch
197         io->set_iomap_alias_w(0xa1, psg, 1);                    // PSG data
198         io->set_iomap_alias_r(0xa2, psg, 1);                    // PSG data
199 #if defined(_PC6601SR) || defined(_PC6001MK2SR)
200         io->set_iomap_alias_r(0xa3, psg, 0);                    // FM status
201         io->set_iomap_range_rw(0x40, 0x6f, memory);             // VRAM addr
202 #endif
203 #ifdef _PC6001
204         io->set_iomap_single_w(0xb0, display);                  // VRAM addr
205         io->set_iomap_single_w(0x00, memory);                   // MEMORY MAP
206 #else
207         io->set_iomap_single_w(0xb0, memory);                   // VRAM addr
208         io->set_iomap_range_rw(0xc0, 0xcf, memory);             // VRAM addr
209         io->set_iomap_range_rw(0xe0, 0xe3, voice);              // VOICE
210 #if defined(_PC6601) || defined(_PC6601SR)
211         io->set_iomap_range_rw(0xb8, 0xbf, timer);              // IRQ
212         io->set_iomap_range_rw(0xfa, 0xfb, timer);              // IRQ
213 #endif
214         io->set_iomap_range_rw(0xf3, 0xf7, timer);              // IRQ/Timer
215 #endif
216         
217 #if defined(_PC6601) || defined(_PC6601SR)
218         io->set_iomap_range_rw(0xb1, 0xb3, floppy);             // DISK DRIVE
219         io->set_iomap_range_rw(0xb5, 0xb7, floppy);             // DISK DRIVE (Mirror)
220         io->set_iomap_range_rw(0xd0, 0xde, floppy);             // DISK DRIVE
221 #else
222         io->set_iovalue_single_r(0xb1, 0x01);
223 #if defined(_PC6601SR)
224         io->set_iovalue_single_r(0xb2, 0x02);
225 #elif defined(_PC6001MK2SR)
226         io->set_iovalue_single_r(0xb2, 0x00);
227 #endif
228         
229         if(support_pc80s31k) {
230                 io->set_iomap_range_rw(0xd0, 0xd2, pio_fdd);
231                 io->set_iomap_single_w(0xd3, pio_fdd);
232         } else {
233                 io->set_iomap_range_rw(0xd0, 0xd3, pc6031);
234         }
235 #endif
236         io->set_iomap_range_rw(0xf0, 0xf2, memory);             // MEMORY MAP
237         
238         // initialize all devices
239         for(DEVICE* device = first_device; device; device = device->next_device) {
240                 device->initialize();
241         }
242         if(support_sub_cpu) {
243                 // load rom images after cpustate is allocated
244 #ifdef _PC6601SR
245 #else
246                 cpu_sub->load_rom_image(create_local_path(_T(SUB_CPU_ROM_FILE_NAME)));
247 #endif
248         }
249         int drive_num = 0;
250 #if defined(_PC6601) || defined(_PC6601SR)
251         floppy->get_disk_handler(0)->drive_num = drive_num++;
252         floppy->get_disk_handler(1)->drive_num = drive_num++;
253 #endif
254         if(support_pc80s31k) {
255                 fdc_pc80s31k->get_disk_handler(0)->drive_num = drive_num++;
256                 fdc_pc80s31k->get_disk_handler(1)->drive_num = drive_num++;
257         } else {
258                 pc6031->get_disk_handler(0)->drive_num = drive_num++;
259                 pc6031->get_disk_handler(1)->drive_num = drive_num++;
260         }
261 }
262
263 VM::~VM()
264 {
265         // delete all devices
266         for(DEVICE* device = first_device; device;) {
267                 DEVICE *next_device = device->next_device;
268                 device->release();
269                 delete device;
270                 device = next_device;
271         }
272 }
273
274 DEVICE* VM::get_device(int id)
275 {
276         for(DEVICE* device = first_device; device; device = device->next_device) {
277                 if(device->this_device_id == id) {
278                         return device;
279                 }
280         }
281         return NULL;
282 }
283
284 // ----------------------------------------------------------------------------
285 // drive virtual machine
286 // ----------------------------------------------------------------------------
287 void VM::reset()
288 {
289         // reset all devices
290         for(DEVICE* device = first_device; device; device = device->next_device) {
291                 device->reset();
292         }
293         if(support_pc80s31k) {
294                 pio_fdd->write_signal(SIG_I8255_PORT_C, 0, 0xff);
295                 pio_pc80s31k->write_signal(SIG_I8255_PORT_C, 0, 0xff);
296         }
297 }
298
299 void VM::run()
300 {
301         event->drive();
302 }
303
304 // ----------------------------------------------------------------------------
305 // debugger
306 // ----------------------------------------------------------------------------
307
308 #ifdef USE_DEBUGGER
309 DEVICE *VM::get_cpu(int index)
310 {
311         if(index == 0) {
312                 return cpu;
313         } else if(index == 1) {
314                 return cpu_sub;
315         } else if(index == 2) {
316                 return cpu_pc80s31k;
317         }
318         return NULL;
319 }
320 #endif
321
322 // ----------------------------------------------------------------------------
323 // draw screen
324 // ----------------------------------------------------------------------------
325
326 void VM::draw_screen()
327 {
328 #ifdef _PC6001
329         display->draw_screen();
330 #else
331         memory->draw_screen();
332 #endif
333 }
334 // ----------------------------------------------------------------------------
335 // soud manager
336 // ----------------------------------------------------------------------------
337
338 void VM::initialize_sound(int rate, int samples)
339 {
340         // init sound manager
341         event->initialize_sound(rate, samples);
342         
343         // init sound gen
344         psg->init(rate, 4000000, samples, 0, 0);
345 #ifndef _PC6001
346         voice->init(rate);
347 #endif
348 }
349
350 uint16* VM::create_sound(int* extra_frames)
351 {
352         return event->create_sound(extra_frames);
353 }
354
355 int VM::sound_buffer_ptr()
356 {
357         return event->sound_buffer_ptr();
358 }
359
360 #ifdef USE_SOUND_VOLUME
361 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
362 {
363         if(ch-- == 0) {
364                 psg->set_volume(1, decibel_l, decibel_r);
365 #if !defined(_PC6001)
366         } else if(ch-- == 0) {
367                 voice->set_volume(0, decibel_l, decibel_r);
368 #endif
369         } else if(ch-- == 0) {
370                 if(support_sub_cpu) {
371                         drec->set_volume(0, decibel_l, decibel_r);
372                 }
373         }
374 }
375 #endif
376
377 // ----------------------------------------------------------------------------
378 // notify key
379 // ----------------------------------------------------------------------------
380
381 void VM::key_down(int code, bool repeat)
382 {
383         if(!support_sub_cpu) {
384                 psub->key_down(code);
385         }
386 }
387
388 void VM::key_up(int code)
389 {
390         if(!support_sub_cpu) {
391                 psub->key_up(code);
392         }
393 }
394
395 // ----------------------------------------------------------------------------
396 // user interface
397 // ----------------------------------------------------------------------------
398
399 void VM::open_cart(int drv, const _TCHAR* file_path)
400 {
401         if(drv == 0) {
402                 memory->open_cart(file_path);
403                 reset();
404         }
405 }
406
407 void VM::close_cart(int drv)
408 {
409         if(drv == 0) {
410                 memory->close_cart();
411                 reset();
412         }
413 }
414
415 bool VM::cart_inserted(int drv)
416 {
417         if(drv == 0) {
418                 return memory->cart_inserted();
419         } else {
420                 return false;
421         }
422 }
423
424 int VM::access_lamp()
425 {
426         uint32 status = 0; /// fdc->read_signal(0);
427 #if defined(_PC6601) || defined(_PC6601SR)
428         status = floppy->read_signal(0);
429 #endif
430         if(support_pc80s31k) {
431                 status |= fdc_pc80s31k->read_signal(0);
432         } else {
433                 status |= pc6031->read_signal(0);
434         }
435         return status;
436 }
437
438 void VM::open_disk(int drv, const _TCHAR* file_path, int bank)
439 {
440 #if defined(_PC6601) || defined(_PC6601SR)
441         if(drv < 2) {
442                 floppy->open_disk(drv, file_path, bank);
443                 return;
444         } else {
445                 drv -= 2;
446         }
447 #endif
448         if(support_pc80s31k) {
449                 fdc_pc80s31k->open_disk(drv, file_path, bank);
450         } else {
451                 pc6031->open_disk(drv, file_path, bank);
452         }
453 }
454
455 void VM::close_disk(int drv)
456 {
457 #if defined(_PC6601) || defined(_PC6601SR)
458         if(drv < 2) {
459                 floppy->close_disk(drv);
460                 return;
461         } else {
462                 drv -= 2;
463         }
464 #endif
465         if(support_pc80s31k) {
466                 fdc_pc80s31k->close_disk(drv);
467         } else {
468                 pc6031->close_disk(drv);
469         }
470 }
471
472 bool VM::disk_inserted(int drv)
473 {
474 #if defined(_PC6601) || defined(_PC6601SR)
475         if(drv < 2) {
476                 return floppy->disk_inserted(drv);
477         } else {
478                 drv -= 2;
479         }
480 #endif
481         if(support_pc80s31k) {
482                 return fdc_pc80s31k->disk_inserted(drv);
483         } else {
484                 return pc6031->disk_inserted(drv);
485         }
486 }
487
488 void VM::set_disk_protected(int drv, bool value)
489 {
490 #if defined(_PC6601) || defined(_PC6601SR)
491         if(drv < 2) {
492                 floppy->set_disk_protected(drv, value);
493                 return;
494         } else {
495                 drv -= 2;
496         }
497 #endif
498         if(support_pc80s31k) {
499                 fdc_pc80s31k->set_disk_protected(drv, value);
500         } else {
501                 pc6031->set_disk_protected(drv, value);
502         }
503 }
504
505 bool VM::get_disk_protected(int drv)
506 {
507 #if defined(_PC6601) || defined(_PC6601SR)
508         if(drv < 2) {
509                 return floppy->get_disk_protected(drv);
510         } else {
511                 drv -= 2;
512         }
513 #endif
514         if(support_pc80s31k) {
515                 return fdc_pc80s31k->get_disk_protected(drv);
516         } else {
517                 return pc6031->get_disk_protected(drv);
518         }
519 }
520
521 void VM::play_tape(const _TCHAR* file_path)
522 {
523         if(support_sub_cpu) {
524                 // support both p6/p6t and wav
525                 drec->play_tape(file_path);
526         } else {
527                 // support only p6/p6t
528                 psub->play_tape(file_path);
529         }
530 }
531
532 void VM::rec_tape(const _TCHAR* file_path)
533 {
534         if(support_sub_cpu) {
535                 // support both p6/p6t and wav
536                 sub->rec_tape(file_path);       // temporary
537 //              drec->rec_tape(file_path);
538         } else {
539                 // support both p6/p6t and wav
540                 psub->rec_tape(file_path);
541         }
542 }
543
544 void VM::close_tape()
545 {
546         if(support_sub_cpu) {
547                 if(sub->tape_inserted()) {
548                         sub->close_tape();      // temporary
549                 } else {
550                         drec->close_tape();
551                 }
552         } else {
553                 psub->close_tape();
554         }
555 }
556
557 bool VM::tape_inserted()
558 {
559         if(support_sub_cpu) {
560                 return drec->tape_inserted() || sub->tape_inserted();
561         } else {
562                 return psub->tape_inserted();
563         }
564 }
565
566 bool VM::tape_playing()
567 {
568         if(support_sub_cpu) {
569                 return drec->tape_playing();
570         } else {
571                 return false;
572         }
573 }
574
575 bool VM::tape_recording()
576 {
577         if(support_sub_cpu) {
578                 return drec->tape_recording();
579         } else {
580                 return false;
581         }
582 }
583
584 int VM::tape_position()
585 {
586         if(support_sub_cpu) {
587                 return drec->tape_position();
588         } else {
589                 return 0;
590         }
591 }
592
593 bool VM::now_skip()
594 {
595         return event->now_skip();
596 }
597
598 void VM::update_config()
599 {
600         for(DEVICE* device = first_device; device; device = device->next_device) {
601                 device->update_config();
602         }
603 }
604
605 #define STATE_VERSION   3
606
607 void VM::save_state(FILEIO* state_fio)
608 {
609         state_fio->FputUint32(STATE_VERSION);
610         
611         for(DEVICE* device = first_device; device; device = device->next_device) {
612                 device->save_state(state_fio);
613         }
614         state_fio->FputInt32(sr_mode);
615 }
616
617 bool VM::load_state(FILEIO* state_fio)
618 {
619         if(state_fio->FgetUint32() != STATE_VERSION) {
620                 return false;
621         }
622         for(DEVICE* device = first_device; device; device = device->next_device) {
623                 if(!device->load_state(state_fio)) {
624                         return false;
625                 }
626         }
627         sr_mode = state_fio->FgetInt32();
628         return true;
629 }
630