OSDN Git Service

[VM][General][WIP] Syncing to UPSTREAM 2015-01-21 , work-in-progress.
[csp-qt/common_source_project-fm7.git] / source / src / vm / mz700 / mz700.cpp
1 /*\r
2         SHARP MZ-700 Emulator 'EmuZ-700'\r
3         SHARP MZ-800 Emulator 'EmuZ-800'\r
4         SHARP MZ-1500 Emulator 'EmuZ-1500'\r
5 \r
6         Author : Takeda.Toshiya\r
7         Date   : 2008.06.05 -\r
8 \r
9         [ virtual machine ]\r
10 */\r
11 \r
12 #include "mz700.h"\r
13 #include "../../emu.h"\r
14 #include "../device.h"\r
15 #include "../event.h"\r
16 \r
17 #include "../and.h"\r
18 #include "../datarec.h"\r
19 #include "../i8253.h"\r
20 #include "../i8255.h"\r
21 #include "../io.h"\r
22 #include "../pcm1bit.h"\r
23 #include "../z80.h"\r
24 \r
25 #ifdef USE_DEBUGGER\r
26 #include "../debugger.h"\r
27 #endif\r
28 \r
29 //#include "cmos.h"\r
30 #include "emm.h"\r
31 #include "kanji.h"\r
32 #include "keyboard.h"\r
33 #include "memory.h"\r
34 #include "ramfile.h"\r
35 \r
36 #if defined(_MZ800) || defined(_MZ1500)\r
37 #include "../disk.h"\r
38 #include "../mb8877.h"\r
39 #if defined(_MZ800)\r
40 #include "../not.h"\r
41 #endif\r
42 #include "../sn76489an.h"\r
43 #include "../z80pio.h"\r
44 #include "../z80sio.h"\r
45 #include "floppy.h"\r
46 #if defined(_MZ1500)\r
47 #include "psg.h"\r
48 #endif\r
49 #include "quickdisk.h"\r
50 #endif\r
51 \r
52 #include "../../fileio.h"\r
53 \r
54 // ----------------------------------------------------------------------------\r
55 // initialize\r
56 // ----------------------------------------------------------------------------\r
57 \r
58 VM::VM(EMU* parent_emu) : emu(parent_emu)\r
59 {\r
60 #if defined(_MZ800)\r
61         boot_mode = config.boot_mode;\r
62 #endif\r
63         \r
64         // create devices\r
65         first_device = last_device = NULL;\r
66         dummy = new DEVICE(this, emu);  // must be 1st device\r
67         event = new EVENT(this, emu);   // must be 2nd device\r
68         \r
69         and_int = new AND(this, emu);\r
70         drec = new DATAREC(this, emu);\r
71         pit = new I8253(this, emu);\r
72         pio = new I8255(this, emu);\r
73         io = new IO(this, emu);\r
74         pcm = new PCM1BIT(this, emu);\r
75         cpu = new Z80(this, emu);\r
76         \r
77 //      cmos = new CMOS(this, emu);\r
78         emm = new EMM(this, emu);\r
79         kanji = new KANJI(this, emu);\r
80         keyboard = new KEYBOARD(this, emu);\r
81         memory = new MEMORY(this, emu);\r
82         ramfile = new RAMFILE(this, emu);\r
83         \r
84 #if defined(_MZ800) || defined(_MZ1500)\r
85         and_snd = new AND(this, emu);\r
86         fdc = new MB8877(this, emu);    // mb8876\r
87 #if defined(_MZ800)\r
88         not_pit = new NOT(this, emu);\r
89         psg = new SN76489AN(this, emu);\r
90 #elif defined(_MZ1500)\r
91         psg_l = new SN76489AN(this, emu);\r
92         psg_r = new SN76489AN(this, emu);\r
93 #endif\r
94         pio_int = new Z80PIO(this, emu);\r
95         sio_rs = new Z80SIO(this, emu);\r
96         sio_qd = new Z80SIO(this, emu);\r
97         \r
98         floppy = new FLOPPY(this, emu);\r
99 #if defined(_MZ1500)\r
100         psg = new PSG(this, emu);\r
101 #endif\r
102         qd = new QUICKDISK(this, emu);\r
103 #endif\r
104         \r
105         // set contexts\r
106         event->set_context_cpu(cpu);\r
107         event->set_context_sound(pcm);\r
108 #if defined(_MZ800)\r
109         event->set_context_sound(psg);\r
110 #elif defined(_MZ1500)\r
111         event->set_context_sound(psg_l);\r
112         event->set_context_sound(psg_r);\r
113 #endif\r
114         \r
115         // VRAM/PCG wait\r
116         memory->set_context_cpu(cpu);\r
117         \r
118         // memory mapped I/O\r
119         memory->set_context_pio(pio);\r
120         memory->set_context_pit(pit);\r
121         \r
122 #if defined(_MZ1500)\r
123         // psg mixer\r
124         psg->set_context_psg_l(psg_l);\r
125         psg->set_context_psg_r(psg_r);\r
126 #endif\r
127         \r
128 #if defined(_MZ800)\r
129         // 8253:CLK#0 <- 1.10MHz\r
130         pit->set_constant_clock(0, 1100000);\r
131 #else\r
132         // 8253:CLK#0 <- 895KHz\r
133         pit->set_constant_clock(0, CPU_CLOCKS / 4);\r
134 #endif\r
135         \r
136 #if defined(_MZ800) || defined(_MZ1500)\r
137         // 8253:OUT#0 AND 8255:PC0 -> SPEAKER\r
138         pit->set_context_ch0(and_snd, SIG_AND_BIT_0, 1);\r
139         pio->set_context_port_c(and_snd, SIG_AND_BIT_1, 1, 0);\r
140         and_snd->set_context_out(pcm, SIG_PCM1BIT_SIGNAL, 1);\r
141         and_snd->set_mask(SIG_AND_BIT_0 | SIG_AND_BIT_1);\r
142 #else\r
143         // 8253:OUT#0 -> SPEAKER\r
144         pit->set_context_ch0(pcm, SIG_PCM1BIT_SIGNAL, 1);\r
145 #endif\r
146 #if defined(_MZ800)\r
147         // 8253:OUT#0 -> NOT -> Z80PIO:PA4\r
148         pit->set_context_ch0(not_pit, SIG_NOT_INPUT, 1);\r
149         not_pit->set_context_out(pio_int, SIG_Z80PIO_PORT_A, 0x10);\r
150 #elif defined(_MZ1500)\r
151         // 8253:OUT#0 -> Z80PIO:PA4\r
152         pit->set_context_ch0(pio_int, SIG_Z80PIO_PORT_A, 0x10);\r
153 #endif\r
154         \r
155         // 8253:CLK#1 <- 15.7KHz\r
156         pit->set_constant_clock(1, CPU_CLOCKS / 228);\r
157         \r
158         // 8253:OUT#1 -> 8253:CLK#2\r
159         pit->set_context_ch1(pit, SIG_I8253_CLOCK_2, 1);\r
160         \r
161         // 8253:OUT#2 (N)AND 8255:PC2 -> Z80:INT\r
162         pit->set_context_ch2(and_int, SIG_AND_BIT_0, 1);\r
163         pio->set_context_port_c(and_int, SIG_AND_BIT_1, 4, 0);\r
164         and_int->set_context_out(cpu, SIG_CPU_IRQ, 1);\r
165         and_int->set_mask(SIG_AND_BIT_0 | SIG_AND_BIT_1);\r
166         \r
167 #if defined(_MZ1500)\r
168         // 8253:OUT#2 -> Z80PIO:PA5\r
169         pit->set_context_ch2(pio_int, SIG_Z80PIO_PORT_A, 0x20);\r
170 #endif\r
171         \r
172         // 8255:PA0-3 -> KEYBOARD:STROBE\r
173         pio->set_context_port_a(keyboard, SIG_KEYBOARD_COLUMN, 0x0f, 0);\r
174 #if defined(_MZ800)\r
175         // 8255:PA4 -> JOYSTICK #1\r
176         // 8255:PA5 -> JOYSTICK #2\r
177 #endif\r
178         // 8255:PA7 -> 556 RESET\r
179         \r
180         // 8255:PB0-7 <- KEYBOARD:DATA\r
181         keyboard->set_context_pio(pio);\r
182         \r
183         // 8255:PC0 -> AND -> SPEAKER\r
184         // 8255:PC1 -> DATA RECORDER:WRITE DATA\r
185         pio->set_context_port_c(drec, SIG_DATAREC_OUT, 0x02, 0);\r
186         // 8255:PC2 -> (N)AND -> Z80:INT\r
187         // 8255:PC3 -> DATA RECORDER:MOTOR ON/OFF\r
188         pio->set_context_port_c(drec, SIG_DATAREC_TRIG, 0x08, 0);\r
189         // 8255:PC4 <- DATA RECORDER:MOTOR REMOTE\r
190         drec->set_context_remote(pio, SIG_I8255_PORT_C, 0x10);\r
191         // 8255:PC5 <- DATA RECORDER:READ DATA\r
192         drec->set_context_out(pio, SIG_I8255_PORT_C, 0x20);\r
193         // 8255:PC6 <- MEMORY:556 OUT (1.5KHz)\r
194         // 8255:PC7 <- MEMORY:VBLANK\r
195         \r
196 #if defined(_MZ800) || defined(_MZ1500)\r
197         // Z80PIO:PA0 <- PRINTER:RDA\r
198         // Z80PIO:PA1 <- PRINTER:STA\r
199         // Z80PIO:PA2 <- GND\r
200         // Z80PIO:PA3 <- GND\r
201 #if defined(_MZ800)\r
202         // Z80PIO:PA4 <- NOT <- 8253:OUT#0\r
203         // Z80PIO:PA5 <- HBLANK\r
204         memory->set_context_pio_int(pio_int);\r
205 #elif defined(_MZ1500)\r
206         // Z80PIO:PA4 <- 8253:OUT#0\r
207         // Z80PIO:PA5 <- 8253:OUT#2\r
208 #endif\r
209         // Z80PIO:PA6 -> PRINTER:IRT\r
210         // Z80PIO:PA7 -> PRINTER:RDP\r
211 #endif\r
212         \r
213 #if defined(_MZ800) || defined(_MZ1500)\r
214         // Z80SIO:RTSA -> QD:WRGA\r
215         sio_qd->set_context_rts(0, qd, QUICKDISK_SIO_RTSA, 1);\r
216         // Z80SIO:DTRB -> QD:MTON\r
217         sio_qd->set_context_dtr(1, qd, QUICKDISK_SIO_DTRB, 1);\r
218         // Z80SIO:SENDA -> QD:RECV\r
219         sio_qd->set_context_sync(0, qd, QUICKDISK_SIO_SYNC, 1);\r
220         sio_qd->set_context_rxdone(0, qd, QUICKDISK_SIO_RXDONE, 1);\r
221         sio_qd->set_context_send(0, qd, QUICKDISK_SIO_DATA);\r
222         sio_qd->set_context_break(0, qd, QUICKDISK_SIO_BREAK, 1);\r
223         // Z80SIO:CTSA <- QD:PROTECT\r
224         // Z80SIO:DCDA <- QD:INSERT\r
225         // Z80SIO:DCDB <- QD:HOE\r
226         qd->set_context_sio(sio_qd);\r
227         \r
228         sio_rs->set_tx_clock(0, 1200 * 16);     // 1200 baud\r
229         sio_rs->set_rx_clock(0, 1200 * 16);     // baud-rate can be changed by jumper pin\r
230         sio_rs->set_tx_clock(1, 1200 * 16);\r
231         sio_rs->set_rx_clock(1, 1200 * 16);\r
232         \r
233         sio_qd->set_tx_clock(0, 101562.5);\r
234         sio_qd->set_rx_clock(0, 101562.5);\r
235         sio_qd->set_tx_clock(1, 101562.5);\r
236         sio_qd->set_rx_clock(1, 101562.5);\r
237         \r
238         // floppy drives\r
239         floppy->set_context_cpu(cpu);\r
240         floppy->set_context_fdc(fdc);\r
241         fdc->set_context_drq(floppy, SIG_FLOPPY_DRQ, 1);\r
242 #endif\r
243         \r
244         // cpu bus\r
245         cpu->set_context_mem(memory);\r
246         cpu->set_context_io(io);\r
247 #if defined(_MZ800) || defined(_MZ1500)\r
248         cpu->set_context_intr(pio_int);\r
249         // z80 family daisy chain\r
250         // 0=8253:OUT2\r
251         pio_int->set_context_intr(cpu, 1);\r
252         pio_int->set_context_child(sio_rs);\r
253         sio_rs->set_context_intr(cpu, 2);\r
254         sio_rs->set_context_child(sio_qd);\r
255         sio_qd->set_context_intr(cpu, 3);\r
256 #else\r
257         cpu->set_context_intr(dummy);\r
258 #endif\r
259 #ifdef USE_DEBUGGER\r
260         cpu->set_context_debugger(new DEBUGGER(this, emu));\r
261 #endif\r
262         \r
263         // emm\r
264         io->set_iomap_range_rw(0x00, 0x03, emm);\r
265         // kanji\r
266         io->set_iomap_range_rw(0xb8, 0xb9, kanji);\r
267         // ramfile\r
268         io->set_iomap_range_rw(0xea, 0xeb, ramfile);\r
269         // cmos\r
270 //      io->set_iomap_range_rw(0xf8, 0xfa, cmos);\r
271         \r
272 #if defined(_MZ800)\r
273         // 8255/8253\r
274         io->set_iomap_range_rw(0xd0, 0xd3, pio);\r
275         io->set_iomap_range_rw(0xd4, 0xd7, pit);\r
276 #endif\r
277         \r
278 #if defined(_MZ800) || defined(_MZ1500)\r
279         // floppy drives\r
280         io->set_iomap_range_rw(0xd8, 0xdb, fdc);\r
281         io->set_iomap_range_w(0xdc, 0xdf, floppy);\r
282 #endif\r
283         \r
284         // memory mapper\r
285 #if defined(_MZ800)\r
286         io->set_iomap_range_r(0xe0, 0xe1, memory);\r
287         io->set_iomap_range_w(0xe0, 0xe6, memory);\r
288 #elif defined(_MZ1500)\r
289         io->set_iomap_range_w(0xe0, 0xe6, memory);\r
290 #else\r
291         io->set_iomap_range_w(0xe0, 0xe4, memory);\r
292 #endif\r
293         \r
294 #if defined(_MZ800)\r
295         // crtc\r
296         io->set_iomap_range_w(0xcc, 0xcf, memory);\r
297         io->set_iomap_single_r(0xce, memory);\r
298         // palette\r
299         io->set_iomap_single_w(0xf0, memory);\r
300 #elif defined(_MZ1500)\r
301         // palette\r
302         io->set_iomap_range_w(0xf0, 0xf1, memory);\r
303 #endif\r
304         \r
305 #if defined(_MZ800)\r
306         // joystick\r
307 //      io->set_iomap_range_r(0xf0, 0xf1, joystick);\r
308 #endif\r
309         \r
310         // psg\r
311 #if defined(_MZ800)\r
312         io->set_iomap_single_w(0xf2, psg);\r
313 #elif defined(_MZ1500)\r
314         io->set_iomap_single_w(0xe9, psg);\r
315         io->set_iomap_single_w(0xf2, psg_l);\r
316         io->set_iomap_single_w(0xf3, psg_r);\r
317 #endif\r
318         \r
319 #if defined(_MZ800) || defined(_MZ1500)\r
320         // z80pio/sio\r
321         // z80pio and z80sio*2\r
322         static const int z80_sio_addr[4] = {0, 2, 1, 3};\r
323         static const int z80_pio_addr[4] = {1, 3, 0, 2};\r
324         for(int i = 0; i < 4; i++) {\r
325                 io->set_iomap_alias_rw(0xb0 + i, sio_rs, z80_sio_addr[i]);\r
326                 io->set_iomap_alias_rw(0xf4 + i, sio_qd, z80_sio_addr[i]);\r
327                 io->set_iomap_alias_rw(0xfc + i, pio_int, z80_pio_addr[i]);\r
328         }\r
329 #else\r
330         // printer\r
331         io->set_iovalue_single_r(0xfe, 0xc0);\r
332 #endif\r
333 \r
334         // initialize all devices\r
335         for(DEVICE* device = first_device; device; device = device->next_device) {\r
336                 device->initialize();\r
337         }\r
338 #if defined(_MZ800) || defined(_MZ1500)\r
339         for(int i = 0; i < MAX_DRIVE; i++) {\r
340                 fdc->set_drive_type(i, DRIVE_TYPE_2DD);\r
341         }\r
342 #endif\r
343 }\r
344 \r
345 VM::~VM()\r
346 {\r
347         // delete all devices\r
348         for(DEVICE* device = first_device; device;) {\r
349                 DEVICE *next_device = device->next_device;\r
350                 device->release();\r
351                 delete device;\r
352                 device = next_device;\r
353         }\r
354 }\r
355 \r
356 DEVICE* VM::get_device(int id)\r
357 {\r
358         for(DEVICE* device = first_device; device; device = device->next_device) {\r
359                 if(device->this_device_id == id) {\r
360                         return device;\r
361                 }\r
362         }\r
363         return NULL;\r
364 }\r
365 \r
366 // ----------------------------------------------------------------------------\r
367 // drive virtual machine\r
368 // ----------------------------------------------------------------------------\r
369 \r
370 void VM::reset()\r
371 {\r
372         // reset all devices\r
373         for(DEVICE* device = first_device; device; device = device->next_device) {\r
374                 device->reset();\r
375         }\r
376         and_int->write_signal(SIG_AND_BIT_0, 0, 1);     // CLOCK = L\r
377         and_int->write_signal(SIG_AND_BIT_1, 1, 1);     // INTMASK = H\r
378 #if defined(_MZ800) || defined(_MZ1500)\r
379         and_snd->write_signal(SIG_AND_BIT_1, 1, 1);     // SNDMASK = H\r
380 #endif\r
381 }\r
382 \r
383 void VM::run()\r
384 {\r
385         event->drive();\r
386 }\r
387 \r
388 // ----------------------------------------------------------------------------\r
389 // debugger\r
390 // ----------------------------------------------------------------------------\r
391 \r
392 #ifdef USE_DEBUGGER\r
393 DEVICE *VM::get_cpu(int index)\r
394 {\r
395         if(index == 0) {\r
396                 return cpu;\r
397         }\r
398         return NULL;\r
399 }\r
400 #endif\r
401 \r
402 // ----------------------------------------------------------------------------\r
403 // draw screen\r
404 // ----------------------------------------------------------------------------\r
405 \r
406 void VM::draw_screen()\r
407 {\r
408         memory->draw_screen();\r
409 }\r
410 \r
411 #if defined(_MZ800) || defined(_MZ1500)\r
412 int VM::access_lamp()\r
413 {\r
414   uint32 status = fdc->read_signal(0) | qd->read_signal(0); // 4 + 1: Nagative\r
415   return (status & (1 | 4)) ? 1 : (status & (2 | 8)) ? 2 : 0;\r
416 }\r
417 #endif\r
418 \r
419 // ----------------------------------------------------------------------------\r
420 // soud manager\r
421 // ----------------------------------------------------------------------------\r
422 \r
423 void VM::initialize_sound(int rate, int samples)\r
424 {\r
425         // init sound manager\r
426         event->initialize_sound(rate, samples);\r
427         \r
428         // init sound gen\r
429         pcm->init(rate, 8000);\r
430 #if defined(_MZ800)\r
431         psg->init(rate, 3579545, 8000);\r
432 #elif defined(_MZ1500)\r
433         psg_l->init(rate, 3579545, 8000);\r
434         psg_r->init(rate, 3579545, 8000);\r
435 #endif\r
436 }\r
437 \r
438 uint16* VM::create_sound(int* extra_frames)\r
439 {\r
440         return event->create_sound(extra_frames);\r
441 }\r
442 \r
443 int VM::sound_buffer_ptr()\r
444 {\r
445         return event->sound_buffer_ptr();\r
446 }\r
447 \r
448 // ----------------------------------------------------------------------------\r
449 // user interface\r
450 // ----------------------------------------------------------------------------\r
451 \r
452 void VM::play_tape(_TCHAR* file_path)\r
453 {\r
454         drec->play_tape(file_path);\r
455         drec->write_signal(SIG_DATAREC_REMOTE, 1, 1);\r
456 }\r
457 \r
458 void VM::rec_tape(_TCHAR* file_path)\r
459 {\r
460         drec->rec_tape(file_path);\r
461         drec->write_signal(SIG_DATAREC_REMOTE, 1, 1);\r
462 }\r
463 \r
464 void VM::close_tape()\r
465 {\r
466         drec->close_tape();\r
467         drec->write_signal(SIG_DATAREC_REMOTE, 0, 0);\r
468 }\r
469 \r
470 bool VM::tape_inserted()\r
471 {\r
472         return drec->tape_inserted();\r
473 }\r
474 \r
475 int VM::get_tape_ptr()\r
476 {\r
477         return drec->get_tape_ptr();\r
478 }\r
479 \r
480 void VM::push_play()\r
481 {\r
482         drec->write_signal(SIG_DATAREC_REMOTE, 1, 1);\r
483 }\r
484 \r
485 void VM::push_stop()\r
486 {\r
487         drec->write_signal(SIG_DATAREC_REMOTE, 0, 0);\r
488 }\r
489 \r
490 #if defined(_MZ800) || defined(_MZ1500)\r
491 void VM::open_quickdisk(int drv, _TCHAR* file_path)\r
492 {\r
493         if(drv == 0) {\r
494                 qd->open_disk(file_path);\r
495         }\r
496 }\r
497 \r
498 void VM::close_quickdisk(int drv)\r
499 {\r
500         if(drv == 0) {\r
501                 qd->close_disk();\r
502         }\r
503 }\r
504 \r
505 bool VM::quickdisk_inserted(int drv)\r
506 {\r
507         if(drv == 0) {\r
508                 return qd->disk_inserted();\r
509         } else {\r
510                 return false;\r
511         }\r
512 }\r
513 \r
514 void VM::write_protect_fd(int drv, bool flag)\r
515 {\r
516         fdc->write_protect_fd(drv, flag);\r
517 }\r
518 \r
519 bool VM::is_write_protect_fd(int drv)\r
520 {\r
521         return fdc->is_write_protect_fd(drv);\r
522 }\r
523 \r
524 void VM::open_disk(int drv, _TCHAR* file_path, int offset)\r
525 {\r
526         fdc->open_disk(drv, file_path, offset);\r
527 }\r
528 \r
529 void VM::close_disk(int drv)\r
530 {\r
531         fdc->close_disk(drv);\r
532 }\r
533 \r
534 bool VM::disk_inserted(int drv)\r
535 {\r
536         return fdc->disk_inserted(drv);\r
537 }\r
538 \r
539 #endif\r
540 \r
541 bool VM::now_skip()\r
542 {\r
543         return event->now_skip();\r
544 }\r
545 \r
546 void VM::update_config()\r
547 {\r
548 #if defined(_MZ800)\r
549         if(boot_mode != config.boot_mode) {\r
550                 // boot mode is changed !!!\r
551                 boot_mode = config.boot_mode;\r
552                 reset();\r
553         } else {\r
554 #endif\r
555                 for(DEVICE* device = first_device; device; device = device->next_device) {\r
556                         device->update_config();\r
557                 }\r
558 #if defined(_MZ800)\r
559         }\r
560 #endif\r
561 }\r
562 \r
563 #define STATE_VERSION   1\r
564 \r
565 void VM::save_state(FILEIO* state_fio)\r
566 {\r
567         state_fio->FputUint32(STATE_VERSION);\r
568         \r
569         for(DEVICE* device = first_device; device; device = device->next_device) {\r
570                 device->save_state(state_fio);\r
571         }\r
572 #if defined(_MZ800)\r
573         state_fio->FputInt32(boot_mode);\r
574 #endif\r
575 }\r
576 \r
577 bool VM::load_state(FILEIO* state_fio)\r
578 {\r
579         if(state_fio->FgetUint32() != STATE_VERSION) {\r
580                 return false;\r
581         }\r
582         for(DEVICE* device = first_device; device; device = device->next_device) {\r
583                 if(!device->load_state(state_fio)) {\r
584                         return false;\r
585                 }\r
586         }\r
587 #if defined(_MZ800)\r
588         boot_mode = state_fio->FgetInt32();\r
589 #endif\r
590         return true;\r
591 }\r
592 \r