OSDN Git Service

[FM7][DISPLAY] Force SYNC submemory and mainmemory to SUBCPU.
[csp-qt/common_source_project-fm7.git] / source / src / vm / fm7 / fm7.cpp
1 /*
2  * FM7 -> VM
3  * (C) 2015 K.Ohta <whatisthis.sowhat _at_ gmail.com>
4  * History:
5  *   Feb 27, 2015 : Initial
6  */
7
8 #include "fm7.h"
9 #include "../../emu.h"
10 #include "../../config.h"
11 #include "../device.h"
12 #include "../event.h"
13
14 #include "../datarec.h"
15 #include "../disk.h"
16
17 #include "../mc6809.h"
18 #include "../z80.h"
19 #include "../ym2203.h"
20 #include "../mb8877.h"
21
22 #include "./fm7_mainio.h"
23 #include "./fm7_mainmem.h"
24 #include "./fm7_display.h"
25 #include "./fm7_keyboard.h"
26
27 #include "./kanjirom.h"
28
29 VM::VM(EMU* parent_emu): emu(parent_emu)
30 {
31         
32         first_device = last_device = NULL;
33         connect_opn = false;
34         connect_whg = false;
35         connect_thg = false;
36         opn[0] = opn[1] = opn[2] = psg = NULL; 
37    
38         dummy = new DEVICE(this, emu);  // must be 1st device
39         event = new EVENT(this, emu);   // must be 2nd device
40         
41         dummycpu = new DEVICE(this, emu);
42         maincpu = new MC6809(this, emu);
43         subcpu = new MC6809(this, emu);
44 #ifdef WITH_Z80
45         z80cpu = new Z80(this, emu);
46 #endif
47         // basic devices
48         mainmem = new FM7_MAINMEM(this, emu);
49         mainio  = new FM7_MAINIO(this, emu);
50         
51         display = new DISPLAY(this, emu);
52         keyboard = new KEYBOARD(this, emu);
53
54         // I/Os
55         drec = new DATAREC(this, emu);
56         pcm1bit = new PCM1BIT(this, emu);
57         fdc  = new MB8877(this, emu);
58         
59         opn[0] = new YM2203(this, emu); // OPN
60         opn[1] = new YM2203(this, emu); // WHG
61         opn[2] = new YM2203(this, emu); // THG
62    
63 #if !defined(_FM77AV_VARIANTS)
64         psg = new YM2203(this, emu);
65 #endif
66         kanjiclass1 = new KANJIROM(this, emu, false);
67 #ifdef CAPABLE_KANJI_CLASS2
68         kanjiclass2 = new KANJIROM(this, emu, true);
69 #endif
70         connect_bus();
71         initialize();
72 }
73
74 VM::~VM()
75 {
76         // delete all devices
77         for(DEVICE* device = first_device; device;) {
78                 DEVICE *next_device = device->next_device;
79                 device->release();
80                 delete device;
81                 device = next_device;
82         }
83 }
84
85 DEVICE* VM::get_device(int id)
86 {
87         for(DEVICE* device = first_device; device; device = device->next_device) {
88                 if(device->this_device_id == id) {
89                         return device;
90                 }
91         }
92         return NULL;
93 }
94
95
96 void VM::initialize(void)
97 {
98 #if defined(_FM8) || defined(_FM7)
99         cycle_steal = false;
100 #else
101         cycle_steal = true;
102 #endif
103         clock_low = false;
104
105 }
106
107
108 void VM::connect_bus(void)
109 {
110         int i;
111         
112         /*
113          * CLASS CONSTRUCTION
114          *
115          * VM 
116          *  |-> MAINCPU -> MAINMEM -> MAINIO -> MAIN DEVICES
117          *  |             |        |      
118          *  | -> SUBCPU  -> SUBMEM  -> SUBIO -> SUB DEVICES
119          *  | -> DISPLAY
120          *  | -> KEYBOARD
121          *
122          *  MAINMEM can access SUBMEM/IO, when SUBCPU is halted.
123          *  MAINMEM and SUBMEM can access DISPLAY and KEYBOARD with exclusive.
124          *  MAINCPU can access MAINMEM.
125          *  SUBCPU  can access SUBMEM.
126          *  DISPLAY : R/W from MAINCPU and SUBCPU.
127          *  KEYBOARD : R/W
128          *
129          */
130         event->set_frames_per_sec(60.00);
131         event->set_lines_per_frame(400);
132         event->set_context_cpu(dummycpu, 8000000);
133 #if defined(_FM8)
134         event->set_context_cpu(maincpu, MAINCLOCK_SLOW);
135         event->set_context_cpu(subcpu,  SUBCLOCK_SLOW);
136 #else
137         if(config.cpu_type == 0) {
138                 // 2MHz
139                 event->set_context_cpu(maincpu, MAINCLOCK_NORMAL);
140                 event->set_context_cpu(subcpu,  SUBCLOCK_NORMAL);
141         } else {
142                 // 1.2MHz
143                 event->set_context_cpu(maincpu, MAINCLOCK_SLOW);
144                 event->set_context_cpu(subcpu,  SUBCLOCK_SLOW);
145         }
146 #endif
147 #ifdef WITH_Z80
148         event->set_context_cpu(z80cpu,  4000000);
149         z80cpu->write_signal(SIG_CPU_BUSREQ, 1, 1);
150 #endif
151
152         event->set_context_sound(pcm1bit);
153 #if !defined(_FM77AV_VARIANTS)
154         //if(psg != NULL) {
155                 mainio->set_context_psg(psg);
156                 //psg->is_ym2608 = false; 
157                 event->set_context_sound(psg);
158                 //}
159 #endif
160         event->set_context_sound(opn[0]);
161         event->set_context_sound(opn[1]);
162         event->set_context_sound(opn[2]);
163 #ifdef DATAREC_SOUND
164         event->set_context_sound(drec);
165 #endif
166    
167         mainio->set_context_maincpu(maincpu);
168         mainio->set_context_subcpu(subcpu);
169         
170         mainio->set_context_display(display);
171         mainio->set_context_kanjirom_class1(kanjiclass1);
172         mainio->set_context_mainmem(mainmem);
173    
174 #if defined(_FM77AV_VARIANTS)
175         mainio->set_context_kanjirom_class2(kanjiclass2);
176 #endif
177
178         keyboard->set_context_break_line(mainio, FM7_MAINIO_PUSH_BREAK, 0xffffffff);
179         keyboard->set_context_mainio(mainio);
180         keyboard->set_context_display(display);
181    
182         drec->set_context_out(mainio, FM7_MAINIO_CMT_RECV, 0xffffffff);
183         //drec->set_context_remote(mainio, FM7_MAINIO_CMT_REMOTE, 0xffffffff);
184         mainio->set_context_datarec(drec);
185   
186         display->set_context_mainio(mainio);
187         display->set_context_subcpu(subcpu);
188         display->set_context_keyboard(keyboard);
189         subcpu->set_context_bus_halt(display, SIG_FM7_SUB_HALT, 0xffffffff);
190
191         display->set_context_kanjiclass1(kanjiclass1);
192 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
193         display->set_context_kanjiclass2(kanjiclass2);
194 #endif   
195         // Palette, VSYNC, HSYNC, Multi-page, display mode. 
196         mainio->set_context_display(display);
197         
198         //FDC
199         mainio->set_context_fdc(fdc);
200         fdc->set_context_irq(mainio, FM7_MAINIO_FDC_IRQ, 0x1);
201         fdc->set_context_drq(mainio, FM7_MAINIO_FDC_DRQ, 0x1);
202         // SOUND
203         mainio->set_context_beep(pcm1bit);
204         
205         opn[0]->set_context_irq(mainio, FM7_MAINIO_OPN_IRQ, 0xffffffff);
206         //opn[0]->set_context_port_a(mainio, FM7_MAINIO_OPNPORTA_CHANGED, 0xff, 0);
207         //opn[0]->set_context_port_b(mainio, FM7_MAINIO_OPNPORTB_CHANGED, 0xff, 0);
208         mainio->set_context_opn(opn[0], 0);
209         opn[1]->set_context_irq(mainio, FM7_MAINIO_WHG_IRQ, 0xffffffff);
210         mainio->set_context_opn(opn[1], 1);
211         opn[2]->set_context_irq(mainio, FM7_MAINIO_THG_IRQ, 0xffffffff);
212         mainio->set_context_opn(opn[2], 2);
213    
214         mainmem->set_context_mainio(mainio);
215         mainmem->set_context_display(display);
216         subcpu->set_context_bus_halt(mainmem, SIG_FM7_SUB_HALT, 0xffffffff);
217    
218         maincpu->set_context_mem(mainmem);
219         subcpu->set_context_mem(display);
220
221         for(DEVICE* device = first_device; device; device = device->next_device) {
222                 device->initialize();
223         }
224         maincpu->write_signal(SIG_CPU_BUSREQ, 0, 1);
225         subcpu->write_signal(SIG_CPU_BUSREQ, 0, 1);
226    
227         for(int i = 0; i < 2; i++) {
228 #if defined(_FM77AV20) || defined(_FM77AV40SX) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
229                 fdc->set_drive_type(i, DRIVE_TYPE_2DD);
230 #else
231                 fdc->set_drive_type(i, DRIVE_TYPE_2D);
232 #endif
233 //              fdc->set_drive_rpm(i, 300);
234 //              fdc->set_drive_mfm(i, true);
235         }
236 #if defined(_FM77) || defined(_FM77L4)
237         for(int i = 2; i < 4; i++) {
238                 fdc->set_drive_type(i, DRIVE_TYPE_2HD);
239 //              fdc->set_drive_rpm(i, 300);
240 //              fdc->set_drive_mfm(i, true);
241         }
242 #endif
243         
244 }  
245
246 void VM::update_config()
247 {
248 #if !defined(_FM8)
249         switch(config.cpu_type){
250                 case 0:
251                         event->set_secondary_cpu_clock(maincpu, MAINCLOCK_NORMAL);
252                         if((config.dipswitch & 0x01) == 0) {
253                                 event->set_secondary_cpu_clock(subcpu,  SUBCLOCK_NORMAL / 3);
254                         } else {
255                                 event->set_secondary_cpu_clock(subcpu,  SUBCLOCK_NORMAL);
256                         }
257                         break;
258                 case 1:
259                         event->set_secondary_cpu_clock(maincpu, MAINCLOCK_SLOW);
260                         if((config.dipswitch & 0x01) == 0) {
261                                 event->set_secondary_cpu_clock(subcpu,  SUBCLOCK_SLOW / 3);
262                         } else {
263                                 event->set_secondary_cpu_clock(subcpu,  SUBCLOCK_SLOW);
264                         }
265                         break;
266         }
267 #endif
268
269         for(DEVICE* device = first_device; device; device = device->next_device) {
270                 device->update_config();
271         }
272         //update_dipswitch();
273 }
274
275 void VM::reset()
276 {
277         int i, j;
278         uint8 data;
279         // reset all devices
280         for(DEVICE* device = first_device; device; device = device->next_device) {
281                 device->reset();
282         }
283         //      psg->SetReg(0x2e, 0);   // set prescaler
284         //opn[0]->SetReg(0x2e, 0);      // set prescaler
285         //opn[1]->SetReg(0x2e, 0);      // set prescaler
286         //opn[2]->SetReg(0x2e, 0);      // set prescaler
287 #if 1
288         if(psg != NULL) {
289                 for(i = 0; i < 0x0e; i++) {
290                         psg->write_io8(0, i);
291                         data = (i == 7) ? 0xff : 0x00;
292                         psg->write_io8(1, data);
293                 }
294         }
295         for(i = 0; i < 0x0e; i++) {
296                 data = (i == 7) ? 0xff : 0x00;
297                 for(j = 0; j < 3; j++) {
298                         opn[j]->write_io8(0, i);
299                         opn[j]->write_io8(1, data);
300                 }
301         }
302         for(i = 0x30; i < 0x40; i++) {
303                 if((i & 0x03) < 3) {
304                         for(j = 0; j < 3; j++) {
305                                 opn[j]->write_io8(0, i);
306                                 opn[j]->write_io8(1, 0x00);
307                         }
308                 }
309         }
310         for(i = 0x40; i < 0x50; i++) {
311                 if((i & 0x03) < 3) {
312                         for(j = 0; j < 3; j++) {
313                                 opn[j]->write_io8(0, i);
314                                 opn[j]->write_io8(1, 0x7f);
315                         }
316                 }
317         }
318         for(i = 0x50; i < 0x60; i++) {
319                 if((i & 0x03) < 3) {
320                         for(j = 0; j < 3; j++) {
321                                 opn[j]->write_io8(0, i);
322                                 opn[j]->write_io8(1, 0x1f);
323                         }
324                 }
325         }
326         for(i = 0x60; i < 0xb4; i++) {
327                 if((i & 0x03) < 3) {
328                         for(j = 0; j < 3; j++) {
329                                 opn[j]->write_io8(0, i);
330                                 opn[j]->write_io8(1, 0x00);
331                         }
332                 }
333         }
334         for(i = 0x80; i < 0x90; i++) {
335                 if((i & 0x03) < 3) {
336                         for(j = 0; j < 3; j++) {
337                                 opn[j]->write_io8(0, i);
338                                 opn[j]->write_io8(1, 0xff);
339                         }
340                 }
341         }
342         for(i = 0; i < 3; i++) {
343                 for(j = 0; j < 3; j++) {
344                         opn[j]->write_io8(0, 0x28);
345                         opn[j]->write_io8(1, i);
346                 }
347         }
348         for(j = 0; j < 3; j++) {
349                 opn[j]->write_io8(0, 0x27);
350                 opn[j]->write_io8(1, 0);
351         }
352         psg->write_signal(SIG_YM2203_MUTE, 0x00, 0x01); // Okay?
353         opn[0]->write_signal(SIG_YM2203_MUTE, 0x00, 0x01); // Okay?
354         opn[1]->write_signal(SIG_YM2203_MUTE, 0x00, 0x01); // Okay?
355         opn[2]->write_signal(SIG_YM2203_MUTE, 0x00, 0x01); // Okay?
356
357         
358         //      for(i = 0; i < 3; i++) {
359         //      opn_data[i] = 0;
360         //      opn_cmdreg[i] = 0;
361         //      opn_address[i] = 0x27;
362         //}
363 #endif
364 }
365
366 void VM::special_reset()
367 {
368         // BREAK + RESET
369         mainio->write_signal(FM7_MAINIO_PUSH_BREAK, 1, 1);
370         mainio->reset();
371         display->reset();
372         subcpu->reset();   
373         maincpu->reset();
374         mainio->write_signal(FM7_MAINIO_PUSH_BREAK, 1, 1);
375         event->register_event(mainio, EVENT_UP_BREAK, 10000.0 * 1000.0, false, NULL);
376 }
377
378 void VM::run()
379 {
380         event->drive();
381 }
382
383 double VM::frame_rate()
384 {
385         return event->frame_rate();
386 }
387
388 // ----------------------------------------------------------------------------
389 // debugger
390 // ----------------------------------------------------------------------------
391
392 #ifdef USE_DEBUGGER
393 DEVICE *VM::get_cpu(int index)
394 {
395         if(index == 0) {
396                 return maincpu;
397         } else if(index == 1) {
398                 return subcpu;
399         }
400 #if defined(_WITH_Z80)
401         else if(index == 2) {
402                 return z80cpu;
403         }
404 #endif
405         return NULL;
406 }
407 #endif
408
409 // ----------------------------------------------------------------------------
410 // draw screen
411 // ----------------------------------------------------------------------------
412
413 void VM::draw_screen()
414 {
415         display->draw_screen();
416 }
417
418 int VM::access_lamp()
419 {
420         uint32 status = fdc->read_signal(0);
421         return (status & (1 | 4)) ? 1 : (status & (2 | 8)) ? 2 : 0;
422 }
423
424 void VM::initialize_sound(int rate, int samples)
425 {
426         // init sound manager
427         event->initialize_sound(rate, samples);
428         // init sound gen
429         opn[0]->init(rate, 1228800, samples, 0, 0);
430         opn[1]->init(rate, 1228800, samples, 0, 0);
431         opn[2]->init(rate, 1228800, samples, 0, 0);
432 #if !defined(_FM77AV_VARIANTS)   
433         psg->init(rate, 1228800, samples, 0, 0);
434 #endif   
435         pcm1bit->init(rate, 2000);
436         //drec->init_pcm(rate, 0);
437 }
438
439 uint16* VM::create_sound(int* extra_frames)
440 {
441         uint16* p = event->create_sound(extra_frames);
442         return p;
443 }
444
445 int VM::sound_buffer_ptr()
446 {
447         int pos = event->sound_buffer_ptr();
448         return pos; 
449 }
450
451 // ----------------------------------------------------------------------------
452 // notify key
453 // ----------------------------------------------------------------------------
454
455 void VM::key_down(int code, bool repeat)
456 {
457         if(!repeat) {
458                 keyboard->key_down(code);
459         }
460 }
461
462 void VM::key_up(int code)
463 {
464         keyboard->key_up(code);
465 }
466
467 // ----------------------------------------------------------------------------
468 // user interface
469 // ----------------------------------------------------------------------------
470
471 void VM::open_disk(int drv, _TCHAR* file_path, int bank)
472 {
473         fdc->open_disk(drv, file_path, bank);
474 }
475
476 void VM::close_disk(int drv)
477 {
478         fdc->close_disk(drv);
479 }
480
481 bool VM::disk_inserted(int drv)
482 {
483         return fdc->disk_inserted(drv);
484 }
485  
486 void VM::write_protect_fd(int drv, bool flag)
487 {
488         fdc->write_protect_fd(drv, flag);
489 }
490
491 bool VM::is_write_protect_fd(int drv)
492 {
493         return fdc->is_write_protect_fd(drv);
494 }
495
496 void VM::play_tape(_TCHAR* file_path)
497 {
498         bool value = drec->play_tape(file_path);
499 }
500
501 void VM::rec_tape(_TCHAR* file_path)
502 {
503         bool value = drec->rec_tape(file_path);
504 }
505
506 void VM::close_tape()
507 {
508         drec->close_tape();
509 }
510
511 bool VM::tape_inserted()
512 {
513         return drec->tape_inserted();
514 }
515
516 int VM::get_tape_ptr(void)
517 {
518         return drec->get_tape_ptr();
519 }
520
521 bool VM::now_skip()
522 {
523         return event->now_skip();
524 }
525
526 void VM::update_dipswitch()
527 {
528         // bit0         0=High 1=Standard
529         // bit2         0=5"2D 1=5"2HD
530   //    io->set_iovalue_single_r(0x1ff0, (config.monitor_type & 1) | ((config.drive_type & 1) << 2));
531 }
532
533 void VM::set_cpu_clock(DEVICE *cpu, uint32 clocks) {
534         event->set_cpu_clock(cpu, clocks);
535 }
536
537 #define STATE_VERSION   1
538