OSDN Git Service

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