OSDN Git Service

[VM][General][Qt] Merge upstream 2015-12-31.
[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 // ----------------------------------------------------------------------------
361 // user interface
362 // ----------------------------------------------------------------------------
363
364 void VM::open_cart(int drv, const _TCHAR* file_path)
365 {
366         if(drv == 0) {
367                 memory->open_cart(file_path);
368                 reset();
369         }
370 }
371
372 void VM::close_cart(int drv)
373 {
374         if(drv == 0) {
375                 memory->close_cart();
376                 reset();
377         }
378 }
379
380 bool VM::cart_inserted(int drv)
381 {
382         if(drv == 0) {
383                 return memory->cart_inserted();
384         } else {
385                 return false;
386         }
387 }
388
389 int VM::access_lamp()
390 {
391         uint32 status = 0; /// fdc->read_signal(0);
392 #if defined(_PC6601) || defined(_PC6601SR)
393         status = floppy->read_signal(0);
394 #endif
395         if(support_pc80s31k) {
396                 status |= fdc_pc80s31k->read_signal(0);
397         } else {
398                 status |= pc6031->read_signal(0);
399         }
400         return status;
401 }
402
403 void VM::open_disk(int drv, const _TCHAR* file_path, int bank)
404 {
405 #if defined(_PC6601) || defined(_PC6601SR)
406         if(drv < 2) {
407                 floppy->open_disk(drv, file_path, bank);
408                 return;
409         } else {
410                 drv -= 2;
411         }
412 #endif
413         if(support_pc80s31k) {
414                 fdc_pc80s31k->open_disk(drv, file_path, bank);
415         } else {
416                 pc6031->open_disk(drv, file_path, bank);
417         }
418 }
419
420 void VM::close_disk(int drv)
421 {
422 #if defined(_PC6601) || defined(_PC6601SR)
423         if(drv < 2) {
424                 floppy->close_disk(drv);
425                 return;
426         } else {
427                 drv -= 2;
428         }
429 #endif
430         if(support_pc80s31k) {
431                 fdc_pc80s31k->close_disk(drv);
432         } else {
433                 pc6031->close_disk(drv);
434         }
435 }
436
437 bool VM::disk_inserted(int drv)
438 {
439 #if defined(_PC6601) || defined(_PC6601SR)
440         if(drv < 2) {
441                 return floppy->disk_inserted(drv);
442         } else {
443                 drv -= 2;
444         }
445 #endif
446         if(support_pc80s31k) {
447                 return fdc_pc80s31k->disk_inserted(drv);
448         } else {
449                 return pc6031->disk_inserted(drv);
450         }
451 }
452
453 void VM::set_disk_protected(int drv, bool value)
454 {
455 #if defined(_PC6601) || defined(_PC6601SR)
456         if(drv < 2) {
457                 floppy->set_disk_protected(drv, value);
458                 return;
459         } else {
460                 drv -= 2;
461         }
462 #endif
463         if(support_pc80s31k) {
464                 fdc_pc80s31k->set_disk_protected(drv, value);
465         } else {
466                 pc6031->set_disk_protected(drv, value);
467         }
468 }
469
470 bool VM::get_disk_protected(int drv)
471 {
472 #if defined(_PC6601) || defined(_PC6601SR)
473         if(drv < 2) {
474                 return floppy->get_disk_protected(drv);
475         } else {
476                 drv -= 2;
477         }
478 #endif
479         if(support_pc80s31k) {
480                 return fdc_pc80s31k->get_disk_protected(drv);
481         } else {
482                 return pc6031->get_disk_protected(drv);
483         }
484 }
485
486 void VM::play_tape(const _TCHAR* file_path)
487 {
488         if(support_sub_cpu) {
489                 // support both p6/p6t and wav
490                 drec->play_tape(file_path);
491         } else {
492                 // support only p6/p6t
493                 psub->play_tape(file_path);
494         }
495 }
496
497 void VM::rec_tape(const _TCHAR* file_path)
498 {
499         if(support_sub_cpu) {
500                 // support both p6/p6t and wav
501                 sub->rec_tape(file_path);       // temporary
502 //              drec->rec_tape(file_path);
503         } else {
504                 // support both p6/p6t and wav
505                 psub->rec_tape(file_path);
506         }
507 }
508
509 void VM::close_tape()
510 {
511         if(support_sub_cpu) {
512                 if(sub->tape_inserted()) {
513                         sub->close_tape();      // temporary
514                 } else {
515                         drec->close_tape();
516                 }
517         } else {
518                 psub->close_tape();
519         }
520 }
521
522 bool VM::tape_inserted()
523 {
524         if(support_sub_cpu) {
525                 return drec->tape_inserted() || sub->tape_inserted();
526         } else {
527                 return psub->tape_inserted();
528         }
529 }
530
531 bool VM::tape_playing()
532 {
533         if(support_sub_cpu) {
534                 return drec->tape_playing();
535         } else {
536                 return false;
537         }
538 }
539
540 bool VM::tape_recording()
541 {
542         if(support_sub_cpu) {
543                 return drec->tape_recording();
544         } else {
545                 return false;
546         }
547 }
548
549 int VM::tape_position()
550 {
551         if(support_sub_cpu) {
552                 return drec->tape_position();
553         } else {
554                 return 0;
555         }
556 }
557
558 bool VM::now_skip()
559 {
560         return event->now_skip();
561 }
562
563 void VM::update_config()
564 {
565         for(DEVICE* device = first_device; device; device = device->next_device) {
566                 device->update_config();
567         }
568 }
569
570 #define STATE_VERSION   3
571
572 void VM::save_state(FILEIO* state_fio)
573 {
574         state_fio->FputUint32(STATE_VERSION);
575         
576         for(DEVICE* device = first_device; device; device = device->next_device) {
577                 device->save_state(state_fio);
578         }
579         state_fio->FputInt32(sr_mode);
580 }
581
582 bool VM::load_state(FILEIO* state_fio)
583 {
584         if(state_fio->FgetUint32() != STATE_VERSION) {
585                 return false;
586         }
587         for(DEVICE* device = first_device; device; device = device->next_device) {
588                 if(!device->load_state(state_fio)) {
589                         return false;
590                 }
591         }
592         sr_mode = state_fio->FgetInt32();
593         return true;
594 }
595