OSDN Git Service

[OSD][Qt] Add displaying futures on status bar.
[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_rts0(qd, QUICKDISK_SIO_RTSA, 1);\r
216         // Z80SIO:DTRB -> QD:MTON\r
217         sio_qd->set_context_dtr1(qd, QUICKDISK_SIO_DTRB, 1);\r
218         // Z80SIO:SENDA -> QD:RECV\r
219         sio_qd->set_context_sync0(qd, QUICKDISK_SIO_SYNC, 1);\r
220         sio_qd->set_context_rxdone0(qd, QUICKDISK_SIO_RXDONE, 1);\r
221         sio_qd->set_context_send0(qd, QUICKDISK_SIO_DATA);\r
222         sio_qd->set_context_break0(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         // floppy drives\r
229         floppy->set_context_cpu(cpu);\r
230         floppy->set_context_fdc(fdc);\r
231         fdc->set_context_drq(floppy, SIG_FLOPPY_DRQ, 1);\r
232 #endif\r
233         \r
234         // cpu bus\r
235         cpu->set_context_mem(memory);\r
236         cpu->set_context_io(io);\r
237 #if defined(_MZ800) || defined(_MZ1500)\r
238         cpu->set_context_intr(pio_int);\r
239         // z80 family daisy chain\r
240         // 0=8253:OUT2\r
241         pio_int->set_context_intr(cpu, 1);\r
242         pio_int->set_context_child(sio_rs);\r
243         sio_rs->set_context_intr(cpu, 2);\r
244         sio_rs->set_context_child(sio_qd);\r
245         sio_qd->set_context_intr(cpu, 3);\r
246 #else\r
247         cpu->set_context_intr(dummy);\r
248 #endif\r
249 #ifdef USE_DEBUGGER\r
250         cpu->set_context_debugger(new DEBUGGER(this, emu));\r
251 #endif\r
252         \r
253         // emm\r
254         io->set_iomap_range_rw(0x00, 0x03, emm);\r
255         // kanji\r
256         io->set_iomap_range_rw(0xb8, 0xb9, kanji);\r
257         // ramfile\r
258         io->set_iomap_range_rw(0xea, 0xeb, ramfile);\r
259         // cmos\r
260 //      io->set_iomap_range_rw(0xf8, 0xfa, cmos);\r
261         \r
262 #if defined(_MZ800)\r
263         // 8255/8253\r
264         io->set_iomap_range_rw(0xd0, 0xd3, pio);\r
265         io->set_iomap_range_rw(0xd4, 0xd7, pit);\r
266 #endif\r
267         \r
268 #if defined(_MZ800) || defined(_MZ1500)\r
269         // floppy drives\r
270         io->set_iomap_range_rw(0xd8, 0xdb, fdc);\r
271         io->set_iomap_range_w(0xdc, 0xdf, floppy);\r
272 #endif\r
273         \r
274         // memory mapper\r
275 #if defined(_MZ800)\r
276         io->set_iomap_range_r(0xe0, 0xe1, memory);\r
277         io->set_iomap_range_w(0xe0, 0xe6, memory);\r
278 #elif defined(_MZ1500)\r
279         io->set_iomap_range_w(0xe0, 0xe6, memory);\r
280 #else\r
281         io->set_iomap_range_w(0xe0, 0xe4, memory);\r
282 #endif\r
283         \r
284 #if defined(_MZ800)\r
285         // crtc\r
286         io->set_iomap_range_w(0xcc, 0xcf, memory);\r
287         io->set_iomap_single_r(0xce, memory);\r
288         // palette\r
289         io->set_iomap_single_w(0xf0, memory);\r
290 #elif defined(_MZ1500)\r
291         // palette\r
292         io->set_iomap_range_w(0xf0, 0xf1, memory);\r
293 #endif\r
294         \r
295 #if defined(_MZ800)\r
296         // joystick\r
297 //      io->set_iomap_range_r(0xf0, 0xf1, joystick);\r
298 #endif\r
299         \r
300         // psg\r
301 #if defined(_MZ800)\r
302         io->set_iomap_single_w(0xf2, psg);\r
303 #elif defined(_MZ1500)\r
304         io->set_iomap_single_w(0xe9, psg);\r
305         io->set_iomap_single_w(0xf2, psg_l);\r
306         io->set_iomap_single_w(0xf3, psg_r);\r
307 #endif\r
308         \r
309 #if defined(_MZ800) || defined(_MZ1500)\r
310         // z80pio/sio\r
311         // z80pio and z80sio*2\r
312         static const int z80_sio_addr[4] = {0, 2, 1, 3};\r
313         static const int z80_pio_addr[4] = {1, 3, 0, 2};\r
314         for(int i = 0; i < 4; i++) {\r
315                 io->set_iomap_alias_rw(0xb0 + i, sio_rs, z80_sio_addr[i]);\r
316                 io->set_iomap_alias_rw(0xf4 + i, sio_qd, z80_sio_addr[i]);\r
317                 io->set_iomap_alias_rw(0xfc + i, pio_int, z80_pio_addr[i]);\r
318         }\r
319 #else\r
320         // printer\r
321         io->set_iovalue_single_r(0xfe, 0xc0);\r
322 #endif\r
323 \r
324         // initialize all devices\r
325         for(DEVICE* device = first_device; device; device = device->next_device) {\r
326                 device->initialize();\r
327         }\r
328 #if defined(_MZ800) || defined(_MZ1500)\r
329         for(int i = 0; i < MAX_DRIVE; i++) {\r
330                 fdc->set_drive_type(i, DRIVE_TYPE_2DD);\r
331         }\r
332 #endif\r
333 }\r
334 \r
335 VM::~VM()\r
336 {\r
337         // delete all devices\r
338         for(DEVICE* device = first_device; device;) {\r
339                 DEVICE *next_device = device->next_device;\r
340                 device->release();\r
341                 delete device;\r
342                 device = next_device;\r
343         }\r
344 }\r
345 \r
346 DEVICE* VM::get_device(int id)\r
347 {\r
348         for(DEVICE* device = first_device; device; device = device->next_device) {\r
349                 if(device->this_device_id == id) {\r
350                         return device;\r
351                 }\r
352         }\r
353         return NULL;\r
354 }\r
355 \r
356 // ----------------------------------------------------------------------------\r
357 // drive virtual machine\r
358 // ----------------------------------------------------------------------------\r
359 \r
360 void VM::reset()\r
361 {\r
362         // reset all devices\r
363         for(DEVICE* device = first_device; device; device = device->next_device) {\r
364                 device->reset();\r
365         }\r
366         and_int->write_signal(SIG_AND_BIT_0, 0, 1);     // CLOCK = L\r
367         and_int->write_signal(SIG_AND_BIT_1, 1, 1);     // INTMASK = H\r
368 #if defined(_MZ800) || defined(_MZ1500)\r
369         and_snd->write_signal(SIG_AND_BIT_1, 1, 1);     // SNDMASK = H\r
370 #endif\r
371 }\r
372 \r
373 void VM::run()\r
374 {\r
375         event->drive();\r
376 }\r
377 \r
378 // ----------------------------------------------------------------------------\r
379 // debugger\r
380 // ----------------------------------------------------------------------------\r
381 \r
382 #ifdef USE_DEBUGGER\r
383 DEVICE *VM::get_cpu(int index)\r
384 {\r
385         if(index == 0) {\r
386                 return cpu;\r
387         }\r
388         return NULL;\r
389 }\r
390 #endif\r
391 \r
392 // ----------------------------------------------------------------------------\r
393 // draw screen\r
394 // ----------------------------------------------------------------------------\r
395 \r
396 void VM::draw_screen()\r
397 {\r
398         memory->draw_screen();\r
399 }\r
400 \r
401 #if defined(_MZ800) || defined(_MZ1500)\r
402 int VM::access_lamp()\r
403 {\r
404   uint32 status = fdc->read_signal(0) | qd->read_signal(0); // 4 + 1: Nagative\r
405   return (status & (1 | 4)) ? 1 : (status & (2 | 8)) ? 2 : 0;\r
406 }\r
407 #endif\r
408 \r
409 // ----------------------------------------------------------------------------\r
410 // soud manager\r
411 // ----------------------------------------------------------------------------\r
412 \r
413 void VM::initialize_sound(int rate, int samples)\r
414 {\r
415         // init sound manager\r
416         event->initialize_sound(rate, samples);\r
417         \r
418         // init sound gen\r
419         pcm->init(rate, 8000);\r
420 #if defined(_MZ800)\r
421         psg->init(rate, 3579545, 8000);\r
422 #elif defined(_MZ1500)\r
423         psg_l->init(rate, 3579545, 8000);\r
424         psg_r->init(rate, 3579545, 8000);\r
425 #endif\r
426 }\r
427 \r
428 uint16* VM::create_sound(int* extra_frames)\r
429 {\r
430         return event->create_sound(extra_frames);\r
431 }\r
432 \r
433 int VM::sound_buffer_ptr()\r
434 {\r
435         return event->sound_buffer_ptr();\r
436 }\r
437 \r
438 // ----------------------------------------------------------------------------\r
439 // user interface\r
440 // ----------------------------------------------------------------------------\r
441 \r
442 void VM::play_tape(_TCHAR* file_path)\r
443 {\r
444         drec->play_tape(file_path);\r
445         drec->write_signal(SIG_DATAREC_REMOTE, 1, 1);\r
446 }\r
447 \r
448 void VM::rec_tape(_TCHAR* file_path)\r
449 {\r
450         drec->rec_tape(file_path);\r
451         drec->write_signal(SIG_DATAREC_REMOTE, 1, 1);\r
452 }\r
453 \r
454 void VM::close_tape()\r
455 {\r
456         drec->close_tape();\r
457         drec->write_signal(SIG_DATAREC_REMOTE, 0, 0);\r
458 }\r
459 \r
460 bool VM::tape_inserted()\r
461 {\r
462         return drec->tape_inserted();\r
463 }\r
464 \r
465 int VM::get_tape_ptr()\r
466 {\r
467         return drec->tape_inserted();\r
468 }\r
469 \r
470 void VM::push_play()\r
471 {\r
472         drec->write_signal(SIG_DATAREC_REMOTE, 1, 1);\r
473 }\r
474 \r
475 void VM::push_stop()\r
476 {\r
477         drec->write_signal(SIG_DATAREC_REMOTE, 0, 0);\r
478 }\r
479 \r
480 #if defined(_MZ800) || defined(_MZ1500)\r
481 void VM::open_quickdisk(int drv, _TCHAR* file_path)\r
482 {\r
483         if(drv == 0) {\r
484                 qd->open_disk(file_path);\r
485         }\r
486 }\r
487 \r
488 void VM::close_quickdisk(int drv)\r
489 {\r
490         if(drv == 0) {\r
491                 qd->close_disk();\r
492         }\r
493 }\r
494 \r
495 bool VM::quickdisk_inserted(int drv)\r
496 {\r
497         if(drv == 0) {\r
498                 return qd->disk_inserted();\r
499         } else {\r
500                 return false;\r
501         }\r
502 }\r
503 \r
504 void VM::write_protect_fd(int drv, bool flag)\r
505 {\r
506         fdc->write_protect_fd(drv, flag);\r
507 }\r
508 \r
509 bool VM::is_write_protect_fd(int drv)\r
510 {\r
511         return fdc->is_write_protect_fd(drv);\r
512 }\r
513 \r
514 void VM::open_disk(int drv, _TCHAR* file_path, int offset)\r
515 {\r
516         fdc->open_disk(drv, file_path, offset);\r
517 }\r
518 \r
519 void VM::close_disk(int drv)\r
520 {\r
521         fdc->close_disk(drv);\r
522 }\r
523 \r
524 bool VM::disk_inserted(int drv)\r
525 {\r
526         return fdc->disk_inserted(drv);\r
527 }\r
528 \r
529 #endif\r
530 \r
531 bool VM::now_skip()\r
532 {\r
533         return event->now_skip();\r
534 }\r
535 \r
536 void VM::update_config()\r
537 {\r
538 #if defined(_MZ800)\r
539         if(boot_mode != config.boot_mode) {\r
540                 // boot mode is changed !!!\r
541                 boot_mode = config.boot_mode;\r
542                 reset();\r
543         } else {\r
544 #endif\r
545                 for(DEVICE* device = first_device; device; device = device->next_device) {\r
546                         device->update_config();\r
547                 }\r
548 #if defined(_MZ800)\r
549         }\r
550 #endif\r
551 }\r
552 \r
553 #define STATE_VERSION   1\r
554 \r
555 void VM::save_state(FILEIO* state_fio)\r
556 {\r
557         state_fio->FputUint32(STATE_VERSION);\r
558         \r
559         for(DEVICE* device = first_device; device; device = device->next_device) {\r
560                 device->save_state(state_fio);\r
561         }\r
562 #if defined(_MZ800)\r
563         state_fio->FputInt32(boot_mode);\r
564 #endif\r
565 }\r
566 \r
567 bool VM::load_state(FILEIO* state_fio)\r
568 {\r
569         if(state_fio->FgetUint32() != STATE_VERSION) {\r
570                 return false;\r
571         }\r
572         for(DEVICE* device = first_device; device; device = device->next_device) {\r
573                 if(!device->load_state(state_fio)) {\r
574                         return false;\r
575                 }\r
576         }\r
577 #if defined(_MZ800)\r
578         boot_mode = state_fio->FgetInt32();\r
579 #endif\r
580         return true;\r
581 }\r
582 \r