OSDN Git Service

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