OSDN Git Service

[VM][FM7] Add Japanese communication board (日本語通信カード) .
[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 #include "../memory.h"
14 #include "../prnfile.h"
15
16 #ifdef USE_DEBUGGER
17 #include "../debugger.h"
18 #endif
19
20 #include "../datarec.h"
21 #include "../disk.h"
22
23 #include "../mc6809.h"
24 #include "../z80.h"
25 #include "../mb8877.h"
26 #include "../noise.h"
27
28 #include "../pcm1bit.h"
29 #include "../ym2203.h"
30 #include "../ay_3_891x.h"
31 #include "../and.h"
32 #include "../or.h"
33
34 #if defined(_FM77AV_VARIANTS)
35 #include "mb61vh010.h"
36 #include "../beep.h"
37 #endif
38 #if defined(HAS_DMA)
39 #include "hd6844.h"
40 #endif
41 #if defined(_FM8)
42 #include "./bubblecasette.h"
43 #endif
44
45 #include "./fm7_mainio.h"
46 #include "./fm7_mainmem.h"
47 #include "./fm7_display.h"
48 #include "./fm7_keyboard.h"
49 #include "./joystick.h"
50
51 #include "./kanjirom.h"
52 #if defined(CAPABLE_JCOMMCARD)
53 #include "./jcommcard.h"
54 #endif
55
56 VM::VM(EMU* parent_emu): emu(parent_emu)
57 {
58         
59         first_device = last_device = NULL;
60 #if defined(_FM8)
61         psg = NULL;
62 #else   
63 # if defined(_FM77AV_VARIANTS)
64         opn[0] = opn[1] = opn[2] = NULL;
65 # else   
66         opn[0] = opn[1] = opn[2] = NULL;
67         psg = NULL; 
68 # endif
69 #endif
70         dummy = new DEVICE(this, emu);  // must be 1st device
71         event = new EVENT(this, emu);   // must be 2nd device
72         
73         dummycpu = new DEVICE(this, emu);
74         maincpu = new MC6809(this, emu);
75         subcpu = new MC6809(this, emu);
76         g_substat_display = new AND(this, emu);
77         g_substat_mainhalt = new AND(this, emu);
78         
79 #ifdef WITH_Z80
80         if((config.dipswitch & FM7_DIPSW_Z80CARD_ON) != 0) {
81                 z80cpu = new Z80(this, emu);
82         } else {
83                 z80cpu = NULL;
84         }
85         g_mainstat = new AND(this, emu);
86         g_intr = new OR(this, emu);
87
88         g_intr_irq = new AND(this, emu);
89         g_intr_firq = new AND(this, emu);
90         g_nmi = new AND(this, emu);
91 #endif
92 #if defined(CAPABLE_JCOMMCARD)
93         if((config.dipswitch & FM7_DIPSW_JSUBCARD_ON) != 0) {
94                 jsubcpu = new MC6809(this, parent_emu);
95                 jcommcard = new FM7_JCOMMCARD(this, parent_emu);
96         } else {
97                 jsubcpu = NULL;
98                 jcommcard = NULL;
99         }
100 #endif
101                 
102         // basic devices
103         // I/Os
104 #if defined(HAS_DMA)
105         dmac = new HD6844(this, emu);
106 #endif   
107 #if defined(_FM8)
108 #  if defined(USE_AY_3_8910_AS_PSG)
109         psg = new AY_3_891X(this, emu);
110 #  else
111         psg = new YM2203(this, emu);
112 #  endif
113 #else   
114         opn[0] = new YM2203(this, emu); // OPN
115         opn[1] = new YM2203(this, emu); // WHG
116         opn[2] = new YM2203(this, emu); // THG
117 # if !defined(_FM77AV_VARIANTS)
118 #  if defined(USE_AY_3_8910_AS_PSG)
119         psg = new AY_3_891X(this, emu);
120 #  else
121         psg = new YM2203(this, emu);
122 #  endif
123 # endif 
124 #endif
125 #if defined(_FM8)
126         for(int i = 0; i < 2; i++) bubble_casette[i] = new BUBBLECASETTE(this, emu);
127 #endif
128         drec = NULL;
129         drec = new DATAREC(this, emu);
130         drec->set_context_noise_play(new NOISE(this, emu));
131         drec->set_context_noise_stop(new NOISE(this, emu));
132         drec->set_context_noise_fast(new NOISE(this, emu));
133         pcm1bit = new PCM1BIT(this, emu);
134
135         connect_320kfdc = connect_1Mfdc = false;
136         fdc = NULL;
137 #if defined(_FM8) || defined(_FM7) || defined(_FMNEW7)
138         if(((config.dipswitch & FM7_DIPSW_CONNECT_320KFDC) != 0) ||
139            ((config.dipswitch & FM7_DIPSW_CONNECT_1MFDC) != 0)) {
140 #endif          
141                 fdc = new MB8877(this, emu);
142                 fdc->set_context_noise_seek(new NOISE(this, emu));
143                 fdc->set_context_noise_head_down(new NOISE(this, emu));
144                 fdc->set_context_noise_head_up(new NOISE(this, emu));
145 #if defined(_FM8) || defined(_FM7) || defined(_FMNEW7)
146                 if((config.dipswitch & FM7_DIPSW_CONNECT_320KFDC) != 0) {
147                         connect_320kfdc = true;
148                 }
149                 if((config.dipswitch & FM7_DIPSW_CONNECT_1MFDC) != 0) {
150                         connect_1Mfdc = true;
151                 }
152 #elif defined(_FM77_VARIANTS)
153                 connect_320kfdc = true;
154                 if((config.dipswitch & FM7_DIPSW_CONNECT_1MFDC) != 0) {
155                         connect_1Mfdc = true;
156                 }
157 #else   // AV or later.
158                 connect_320kfdc = true;
159                 // 1MFDD??
160 #endif          
161 #if defined(_FM8) || defined(_FM7) || defined(_FMNEW7)
162         }
163 #endif  
164         joystick  = new JOYSTICK(this, emu);
165         printer = new PRNFILE(this, emu);
166 #if defined(_FM77AV_VARIANTS)
167         alu = new MB61VH010(this, emu);
168         keyboard_beep = new BEEP(this, emu);
169 #endif  
170         keyboard = new KEYBOARD(this, emu);
171         display = new DISPLAY(this, emu);       
172
173         mainio  = new FM7_MAINIO(this, emu);
174         mainmem = new FM7_MAINMEM(this, emu);
175         
176 #if defined(_FM8) || defined(_FM7) || defined(_FMNEW7)
177         if((config.dipswitch & FM7_DIPSW_CONNECT_KANJIROM) != 0) {
178                 kanjiclass1 = new KANJIROM(this, emu, false);
179         } else {
180                 kanjiclass1 = NULL;
181         }
182 #else
183         kanjiclass1 = new KANJIROM(this, emu, false);
184 #endif  
185 #ifdef CAPABLE_KANJI_CLASS2
186         kanjiclass2 = new KANJIROM(this, emu, true);
187 #endif
188 #ifdef WITH_Z80
189         g_mainstat->set_mask(SIG_AND_BIT_0);
190         g_mainstat->set_mask(SIG_AND_BIT_1);
191         maincpu->set_context_bus_ba(g_mainstat, SIG_AND_BIT_0, 0xffffffff);
192         maincpu->set_context_bus_bs(g_mainstat, SIG_AND_BIT_1, 0xffffffff);
193         g_mainstat->set_context_out(mainio, FM7_MAINIO_RUN_Z80, 0xffffffff);
194
195         if(z80cpu != NULL) {
196                 z80cpu->set_context_busack(mainio, FM7_MAINIO_RUN_6809, 0xffffffff);
197                 mainio->set_context_z80cpu(z80cpu);
198         }
199 #endif
200 #if defined(_USE_QT)
201         event->set_device_name(_T("EVENT"));
202         dummy->set_device_name(_T("1st Dummy"));
203         
204         maincpu->set_device_name(_T("MAINCPU(MC6809)"));
205         subcpu->set_device_name(_T("SUBCPU(MC6809)"));
206         dummycpu->set_device_name(_T("DUMMY CPU"));
207 # ifdef WITH_Z80
208         if(z80cpu != NULL) z80cpu->set_device_name(_T("Z80 CPU"));
209 # endif
210         if(fdc != NULL) fdc->set_device_name(_T("MB8877 FDC(320KB)"));
211                                                 
212         // basic devices
213         // I/Os
214 # if defined(_FM8)
215         psg->set_device_name(_T("AY-3-8910 PSG"));
216 # else  
217         opn[0]->set_device_name(_T("YM2203 OPN"));
218         opn[1]->set_device_name(_T("YM2203 WHG"));
219         opn[2]->set_device_name(_T("YM2203 THG"));
220 #  if !defined(_FM77AV_VARIANTS)
221         psg->set_device_name(_T("AY-3-8910 PSG"));
222 #  endif
223 # endif
224         pcm1bit->set_device_name(_T("BEEP"));
225         printer->set_device_name(_T("PRINTER I/F"));
226 # if defined(_FM77AV_VARIANTS)
227         keyboard_beep->set_device_name(_T("BEEP(KEYBOARD)"));
228 # endif 
229         if(kanjiclass1 != NULL) kanjiclass1->set_device_name(_T("KANJI ROM CLASS1"));
230 # ifdef CAPABLE_KANJI_CLASS2
231         if(kanjiclass2 != NULL) kanjiclass2->set_device_name(_T("KANJI ROM CLASS2"));
232 # endif
233 # if defined(_FM8)
234         bubble_casette[0]->set_device_name(_T("BUBBLE CASETTE #0"));
235         bubble_casette[1]->set_device_name(_T("BUBBLE CASETTE #1"));
236 # endif 
237 #endif
238         this->connect_bus();
239         
240 }
241
242 VM::~VM()
243 {
244         // delete all devices
245         for(DEVICE* device = first_device; device;) {
246                 DEVICE *next_device = device->next_device;
247                 device->release();
248                 delete device;
249                 device = next_device;
250         }
251 }
252
253 DEVICE* VM::get_device(int id)
254 {
255         for(DEVICE* device = first_device; device; device = device->next_device) {
256                 if(device->this_device_id == id) {
257                         return device;
258                 }
259         }
260         return NULL;
261 }
262
263 void VM::connect_bus(void)
264 {
265         uint32_t mainclock;
266         uint32_t subclock;
267
268         /*
269          * CLASS CONSTRUCTION
270          *
271          * VM 
272          *  |-> MAINCPU -> MAINMEM -> MAINIO -> MAIN DEVICES
273          *  |             |        |      
274          *  | -> SUBCPU  -> SUBMEM  -> SUBIO -> SUB DEVICES
275          *  | -> DISPLAY
276          *  | -> KEYBOARD
277          *
278          *  MAINMEM can access SUBMEM/IO, when SUBCPU is halted.
279          *  MAINMEM and SUBMEM can access DISPLAY and KEYBOARD with exclusive.
280          *  MAINCPU can access MAINMEM.
281          *  SUBCPU  can access SUBMEM.
282          *  DISPLAY : R/W from MAINCPU and SUBCPU.
283          *  KEYBOARD : R/W
284          *
285          */
286         event->set_frames_per_sec(FRAMES_PER_SEC);
287         event->set_lines_per_frame(LINES_PER_FRAME);
288         //event->set_context_cpu(dummycpu, (CPU_CLOCKS * 3) / 8); // MAYBE FIX With eFM77AV40/20.
289         // With slow clock (for dummycpu), some softwares happen troubles,
290         // Use faster clock for dummycpu. 20160319 K.Ohta
291         event->set_context_cpu(dummycpu, SUBCLOCK_NORMAL);
292
293 #if defined(_FM8)
294         mainclock = MAINCLOCK_SLOW;
295         subclock = SUBCLOCK_SLOW;
296 #else
297         if(config.cpu_type == 0) {
298                 // 2MHz
299                 subclock = SUBCLOCK_NORMAL;
300                 mainclock = MAINCLOCK_NORMAL;
301         } else {
302                 // 1.2MHz
303                 mainclock = MAINCLOCK_SLOW;
304                 subclock = SUBCLOCK_SLOW;
305         }
306         //if((config.dipswitch & FM7_DIPSW_CYCLESTEAL) != 0) subclock = subclock / 3;
307 #endif
308         event->set_context_cpu(maincpu, mainclock);
309         event->set_context_cpu(subcpu,  subclock);
310    
311 #ifdef WITH_Z80
312         if(z80cpu != NULL) {
313                 event->set_context_cpu(z80cpu,  4000000);
314                 z80cpu->write_signal(SIG_CPU_BUSREQ, 1, 1);
315         }
316         maincpu->write_signal(SIG_CPU_HALTREQ, 0, 1);
317
318         g_intr_irq->set_mask(SIG_AND_BIT_0);
319         g_intr_irq->set_mask(SIG_AND_BIT_1);
320         
321         g_intr_firq->set_mask(SIG_AND_BIT_0);
322         g_intr_firq->set_mask(SIG_AND_BIT_1);
323         
324         g_nmi->set_mask(SIG_AND_BIT_0);
325         g_nmi->set_mask(SIG_AND_BIT_1);
326
327         mainio->set_context_irq(g_intr_irq, SIG_AND_BIT_1, 0xffffffff);
328         g_intr_irq->set_context_out(g_intr, SIG_OR_BIT_0, 0xffffffff);
329         
330         mainio->set_context_firq(g_intr_firq, SIG_AND_BIT_1, 0xffffffff);
331         g_intr_firq->set_context_out(g_intr, SIG_OR_BIT_0, 0xffffffff);
332         
333         if(z80cpu != NULL) g_intr->set_context_out(z80cpu, SIG_CPU_IRQ, 0xffffffff);
334
335         mainio->set_context_nmi(g_nmi, SIG_AND_BIT_1, 0xffffffff);
336         if(z80cpu != NULL) g_nmi->set_context_out(z80cpu, SIG_CPU_NMI, 0xffffffff);
337 #endif
338 #if defined(CAPABLE_JCOMMCARD)
339         if((jsubcpu != NULL) && (jcommcard != NULL)) {
340                 event->set_context_cpu(jsubcpu,  JCOMMCARD_CLOCK);
341                 jcommcard->set_context_cpu(jsubcpu);
342                 jsubcpu->set_context_bus_ba(jcommcard, FM7_JCOMMCARD_BUS_BA, 0x00000001);
343                 jsubcpu->set_context_bus_bs(jcommcard, FM7_JCOMMCARD_BUS_BS, 0x00000001);
344                 mainio->set_context_jcommcard(jcommcard);
345         }
346 #endif
347         event->set_context_sound(pcm1bit);
348 #if defined(_FM8)
349         event->set_context_sound(psg);
350         if(drec != NULL) event->set_context_sound(drec);
351 #else
352         event->set_context_sound(opn[0]);
353         event->set_context_sound(opn[1]);
354         event->set_context_sound(opn[2]);
355 # if !defined(_FM77AV_VARIANTS)
356         event->set_context_sound(psg);
357 # endif
358         event->set_context_sound(drec);
359         if(fdc != NULL) {
360                 event->set_context_sound(fdc->get_context_noise_seek());
361                 event->set_context_sound(fdc->get_context_noise_head_down());
362                 event->set_context_sound(fdc->get_context_noise_head_up());
363         }
364         if(drec != NULL) {
365                 event->set_context_sound(drec->get_context_noise_play());
366                 event->set_context_sound(drec->get_context_noise_stop());
367                 event->set_context_sound(drec->get_context_noise_fast());
368         }
369 # if defined(_FM77AV_VARIANTS)
370         event->set_context_sound(keyboard_beep);
371 # endif
372 #endif   
373 #if !defined(_FM77AV_VARIANTS) && !defined(_FM77L4)
374         event->register_vline_event(display);
375         event->register_frame_event(display);
376 #endif  
377         mainio->set_context_maincpu(maincpu);
378         mainio->set_context_subcpu(subcpu);
379         
380         mainio->set_context_display(display);
381         mainio->set_context_irq(maincpu, SIG_CPU_IRQ, 0xffffffff);
382         mainio->set_context_firq(maincpu, SIG_CPU_FIRQ, 0xffffffff);
383         mainio->set_context_nmi(maincpu, SIG_CPU_NMI, 0xffffffff);
384 #if defined(_FM8) || defined(_FM7) || defined(_FMNEW7)
385         if((config.dipswitch & FM7_DIPSW_CONNECT_KANJIROM) != 0) {
386                 mainio->set_context_kanjirom_class1(kanjiclass1);
387         }
388 #else
389         mainio->set_context_kanjirom_class1(kanjiclass1);
390 #endif  
391         mainio->set_context_mainmem(mainmem);
392         mainio->set_context_keyboard(keyboard);
393         mainio->set_context_printer(printer);
394         mainio->set_context_printer_reset(printer, SIG_PRINTER_RESET, 0xffffffff);
395         mainio->set_context_printer_strobe(printer, SIG_PRINTER_STROBE, 0xffffffff);
396         mainio->set_context_printer_select(printer, SIG_PRINTER_SELECT, 0xffffffff);
397 #if defined(CAPABLE_KANJI_CLASS2)
398         mainio->set_context_kanjirom_class2(kanjiclass2);
399 #endif
400 #if defined(_FM8)
401         for(int i = 0; i < 2; i++) mainio->set_context_bubble(bubble_casette[i], i);
402 #endif  
403         keyboard->set_context_break_line(mainio, FM7_MAINIO_PUSH_BREAK, 0xffffffff);
404         keyboard->set_context_int_line(mainio, FM7_MAINIO_KEYBOARDIRQ, 0xffffffff);
405         keyboard->set_context_int_line(display, SIG_FM7_SUB_KEY_FIRQ, 0xffffffff);
406 #if defined(_FM77AV_VARIANTS)
407         keyboard->set_context_beep(keyboard_beep);
408 #endif  
409         keyboard->set_context_rxrdy(display, SIG_FM7KEY_RXRDY, 0x01);
410         keyboard->set_context_key_ack(display, SIG_FM7KEY_ACK, 0x01);
411    
412         if(drec != NULL) {
413                 drec->set_context_ear(mainio, FM7_MAINIO_CMT_RECV, 0xffffffff);
414                 //drec->set_context_remote(mainio, FM7_MAINIO_CMT_REMOTE, 0xffffffff);
415                 mainio->set_context_datarec(drec);
416         }
417         mainmem->set_context_mainio(mainio);
418         mainmem->set_context_display(display);
419         mainmem->set_context_maincpu(maincpu);
420 #if defined(CAPABLE_DICTROM)
421         mainmem->set_context_kanjirom_class1(kanjiclass1);
422 #endif  
423         display->set_context_mainio(mainio);
424         display->set_context_subcpu(subcpu);
425         display->set_context_keyboard(keyboard);
426
427         mainio->set_context_clock_status(mainmem, FM7_MAINIO_CLOCKMODE, 0xffffffff);
428         mainio->set_context_clock_status(display, SIG_DISPLAY_CLOCK, 0xffffffff);
429
430         g_substat_display->set_mask(SIG_AND_BIT_0);
431         g_substat_display->set_mask(SIG_AND_BIT_1);
432         subcpu->set_context_bus_ba(g_substat_display, SIG_AND_BIT_0, 0xffffffff);
433         subcpu->set_context_bus_bs(g_substat_display, SIG_AND_BIT_1, 0xffffffff);
434         g_substat_display->set_context_out(display, SIG_FM7_SUB_HALT, 0xffffffff);
435
436         g_substat_mainhalt->set_mask(SIG_AND_BIT_0);
437         g_substat_mainhalt->set_mask(SIG_AND_BIT_1);
438         subcpu->set_context_bus_ba(g_substat_mainhalt, SIG_AND_BIT_0, 0xffffffff);
439         subcpu->set_context_bus_bs(g_substat_mainhalt, SIG_AND_BIT_1, 0xffffffff);
440         g_substat_mainhalt->set_context_out(mainmem, SIG_FM7_SUB_HALT, 0xffffffff);
441
442 #if defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
443         display->set_context_kanjiclass1(kanjiclass1);
444 #endif  
445 #if defined(CAPABLE_KANJI_CLASS2)
446         display->set_context_kanjiclass2(kanjiclass2);
447 #endif   
448 #if defined(_FM77AV_VARIANTS)
449         display->set_context_alu(alu);
450         alu->set_context_memory(display);
451         alu->set_direct_access_offset(DISPLAY_VRAM_DIRECT_ACCESS);
452 #endif  
453         // Palette, VSYNC, HSYNC, Multi-page, display mode. 
454         mainio->set_context_display(display);
455 #if defined(_FM8) || (_FM7) || (_FMNEW7)
456         if(connect_320kfdc || connect_1Mfdc) {
457 #endif          
458                 //FDC
459                 fdc->set_context_irq(mainio, FM7_MAINIO_FDC_IRQ, 0x1);
460                 fdc->set_context_drq(mainio, FM7_MAINIO_FDC_DRQ, 0x1);
461                 mainio->set_context_fdc(fdc);
462 #if defined(_FM8) || (_FM7) || (_FMNEW7)
463         }
464 #endif  
465         // SOUND
466         mainio->set_context_beep(pcm1bit);
467 #if defined(_FM8)       
468         mainio->set_context_psg(psg);
469 #else
470 # if !defined(_FM77AV_VARIANTS)
471         mainio->set_context_psg(psg);
472 # endif
473         opn[0]->set_context_irq(mainio, FM7_MAINIO_OPN_IRQ, 0xffffffff);
474         mainio->set_context_opn(opn[0], 0);
475         joystick->set_context_opn(opn[0]);
476         mainio->set_context_joystick(joystick);
477         opn[0]->set_context_port_b(joystick, FM7_JOYSTICK_MOUSE_STROBE, 0xff, 0);
478         
479         opn[1]->set_context_irq(mainio, FM7_MAINIO_WHG_IRQ, 0xffffffff);
480         mainio->set_context_opn(opn[1], 1);
481         opn[2]->set_context_irq(mainio, FM7_MAINIO_THG_IRQ, 0xffffffff);
482         mainio->set_context_opn(opn[2], 2);
483 #endif   
484         subcpu->set_context_bus_clr(display, SIG_FM7_SUB_USE_CLR, 0x0000000f);
485    
486         event->register_frame_event(joystick);
487 #if defined(HAS_DMA)
488         dmac->set_context_src(fdc, 0);
489         dmac->set_context_dst(mainmem, 0);
490         dmac->set_context_int_line(mainio, 0, FM7_MAINIO_DMA_INT, 0xffffffff);
491         dmac->set_context_drq_line(maincpu, 1, SIG_CPU_BUSREQ, 0xffffffff);
492         mainio->set_context_dmac(dmac);
493 #endif
494         
495         // MEMORIES must set before initialize().
496         maincpu->set_context_mem(mainmem);
497         subcpu->set_context_mem(display);
498 #ifdef WITH_Z80
499         if(z80cpu != NULL) z80cpu->set_context_mem(mainmem);
500 #endif
501 #if defined(CAPABLE_JCOMMCARD)
502         if((jsubcpu != NULL) && (jcommcard != NULL)) {
503                 jsubcpu->set_context_mem(jcommcard);
504         }
505 #endif
506 #ifdef USE_DEBUGGER
507         maincpu->set_context_debugger(new DEBUGGER(this, emu));
508         subcpu->set_context_debugger(new DEBUGGER(this, emu));
509 # ifdef WITH_Z80
510         if(z80cpu != NULL) z80cpu->set_context_debugger(new DEBUGGER(this, emu));
511 # endif
512 # if defined(CAPABLE_JCOMMCARD)
513         if(jsubcpu != NULL) {
514                 jsubcpu->set_context_debugger(new DEBUGGER(this, emu));
515         }
516 # endif
517 #endif
518         for(DEVICE* device = first_device; device; device = device->next_device) {
519                 device->initialize();
520         }
521
522 #if defined(WITH_Z80)
523         g_intr_irq->write_signal(SIG_AND_BIT_0, ((config.dipswitch & FM7_DIPSW_Z80_IRQ_ON) != 0) ? 1 : 0, 1);
524         g_intr_firq->write_signal(SIG_AND_BIT_0, ((config.dipswitch & FM7_DIPSW_Z80_FIRQ_ON) != 0) ? 1 : 0, 1);
525         g_nmi->write_signal(SIG_AND_BIT_0, ((config.dipswitch & FM7_DIPSW_Z80_NMI_ON) != 0) ? 1 : 0, 1);
526 #endif
527         // Disks
528 #if defined(_FM8) || (_FM7) || (_FMNEW7)
529         if(connect_320kfdc) {
530 #endif          
531                 for(int i = 0; i < 4; i++) {
532 #if defined(_FM77AV20) || defined(_FM77AV20EX) || \
533         defined(_FM77AV40SX) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
534                         fdc->set_drive_type(i, DRIVE_TYPE_2DD);
535 #else
536                         fdc->set_drive_type(i, DRIVE_TYPE_2D);
537 #endif
538                         fdc->set_drive_rpm(i, 360);
539                         fdc->set_drive_mfm(i, true);
540                 }
541 #if defined(_FM8) || (_FM7) || (_FMNEW7)
542         }
543 #endif  
544         
545 #if defined(_FM8) || (_FM7) || (_FMNEW7)
546         if(connect_1Mfdc) {
547 #endif
548 // ToDo: Implement another FDC for 1MB (2HD or 8''), this is used by FM-8 to FM-77? Not FM77AV or later? I still know this.
549 //#if defined(_FM77) || defined(_FM77L4)
550 //              for(int i = 0; i < 4; i++) {
551 //                      fdc->set_drive_type(i, DRIVE_TYPE_2HD);
552 //                      fdc->set_drive_rpm(i, 360);
553 //                      fdc->set_drive_mfm(i, true);
554 //              }
555 //#endif
556 #if defined(_FM8) || (_FM7) || (_FMNEW7)
557         }
558 #endif  
559 }  
560
561 void VM::update_config()
562 {
563         for(DEVICE* device = first_device; device; device = device->next_device) {
564                 device->update_config();
565         }
566         update_dipswitch();
567 }
568
569 void VM::reset()
570 {
571         // reset all devices
572         for(DEVICE* device = first_device; device; device = device->next_device) {
573                 device->reset();
574         }
575 #if !defined(_FM77AV_VARIANTS) || defined(_FM8)
576 # if defined(USE_AY_3_8910_AS_PSG)
577         psg->set_reg(0x2e, 0);  // set prescaler
578         psg->write_signal(SIG_AY_3_891X_MUTE, 0x00, 0x01); // Okay?
579 # else  
580         psg->set_reg(0x27, 0); // stop timer
581         psg->set_reg(0x2e, 0);  // set prescaler
582         psg->write_signal(SIG_YM2203_MUTE, 0x00, 0x01); // Okay?
583 #endif
584 #endif
585 #if !defined(_FM8)
586         for(int i = 0; i < 3; i++) {
587                 opn[i]->set_reg(0x27, 0); // stop timer
588                 opn[i]->set_reg(0x2e, 0);       // set prescaler
589                 opn[i]->write_signal(SIG_YM2203_MUTE, 0x00, 0x01); // Okay?
590         }
591 #endif
592 }
593
594 void VM::special_reset()
595 {
596         // BREAK + RESET
597         mainio->write_signal(FM7_MAINIO_PUSH_BREAK, 1, 1);
598         mainio->reset();
599         mainmem->reset();
600         
601 #if defined(FM77AV_VARIANTS)    
602         mainio->write_signal(FM7_MAINIO_HOT_RESET, 1, 1);
603 #endif  
604         display->reset();
605         subcpu->reset();
606         mainio->write_signal(FM7_MAINIO_PUSH_BREAK, 1, 1);
607         maincpu->reset();
608         event->register_event(mainio, EVENT_UP_BREAK, 10000.0 * 1000.0, false, NULL);
609 }
610
611 void VM::run()
612 {
613         event->drive();
614 }
615
616 double VM::get_frame_rate()
617 {
618         return event->get_frame_rate();
619 }
620
621
622
623 // ----------------------------------------------------------------------------
624 // debugger
625 // ----------------------------------------------------------------------------
626
627 #ifdef USE_DEBUGGER
628 DEVICE *VM::get_cpu(int index)
629 {
630         if(index == 0) {
631                 return maincpu;
632         } else if(index == 1) {
633                 return subcpu;
634         }
635 #if defined(WITH_Z80)
636         else if(index == 2) {
637 # if defined(CAPABLE_JCOMMCARD)
638                 if(z80cpu == NULL) {
639                         return jsubcpu;
640                 }
641 # endif
642                 return z80cpu;
643         }
644 # if defined(CAPABLE_JCOMMCARD)
645         else if(index == 3) {
646                 return jsubcpu;
647         }
648 # endif
649 #else
650 # if defined(CAPABLE_JCOMMCARD)
651         else if(index == 2) {
652                 return jsubcpu;
653         }
654 # endif
655 #endif
656         return NULL;
657 }
658 #endif
659
660 // ----------------------------------------------------------------------------
661 // draw screen
662 // ----------------------------------------------------------------------------
663
664 void VM::draw_screen()
665 {
666         display->draw_screen();
667 }
668
669 void VM::initialize_sound(int rate, int samples)
670 {
671         // init sound manager
672         event->initialize_sound(rate, samples);
673         // init sound gen
674 #if defined(_FM8)
675         psg->initialize_sound(rate, (int)(4.9152 * 1000.0 * 1000.0 / 4.0), samples, 0, 0);
676 #else   
677         opn[0]->initialize_sound(rate, (int)(4.9152 * 1000.0 * 1000.0 / 4.0), samples, 0, 0);
678         opn[1]->initialize_sound(rate, (int)(4.9152 * 1000.0 * 1000.0 / 4.0), samples, 0, 0);
679         opn[2]->initialize_sound(rate, (int)(4.9152 * 1000.0 * 1000.0 / 4.0), samples, 0, 0);
680 # if !defined(_FM77AV_VARIANTS)   
681         psg->initialize_sound(rate, (int)(4.9152 * 1000.0 * 1000.0 / 4.0), samples, 0, 0);
682 # endif
683 # if defined(_FM77AV_VARIANTS)
684         keyboard_beep->initialize_sound(rate, 2400.0, 512);
685 # endif
686 #endif  
687         pcm1bit->initialize_sound(rate, 2000);
688         //drec->initialize_sound(rate, 0);
689 }
690
691 uint16_t* VM::create_sound(int* extra_frames)
692 {
693         uint16_t* p = event->create_sound(extra_frames);
694         return p;
695 }
696
697 int VM::get_sound_buffer_ptr()
698 {
699         int pos = event->get_sound_buffer_ptr();
700         return pos; 
701 }
702
703 #ifdef USE_SOUND_VOLUME
704 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
705 {
706 #if !defined(_FM77AV_VARIANTS)
707         if(ch-- == 0) {
708                 psg->set_volume(0, decibel_l, decibel_r);
709                 psg->set_volume(1, decibel_l, decibel_r);
710         } else
711 #endif
712 #if !defined(_FM8)              
713         if(ch-- == 0) {
714                 opn[0]->set_volume(0, decibel_l, decibel_r);
715         } else if(ch-- == 0) {
716                 opn[0]->set_volume(1, decibel_l, decibel_r);
717         } else if(ch-- == 0) {
718                 opn[1]->set_volume(0, decibel_l, decibel_r);
719         } else if(ch-- == 0) {
720                 opn[1]->set_volume(1, decibel_l, decibel_r);
721         } else if(ch-- == 0) {
722                 opn[2]->set_volume(0, decibel_l, decibel_r);
723         } else if(ch-- == 0) {
724                 opn[2]->set_volume(1, decibel_l, decibel_r);
725         } else
726 #endif  
727         if(ch-- == 0) {
728                 pcm1bit->set_volume(0, decibel_l, decibel_r);
729         } else if(ch-- == 0) {
730                 if(drec != NULL) drec->set_volume(0, decibel_l, decibel_r);
731         }
732 #if defined(_FM77AV_VARIANTS)
733         else if(ch-- == 0) {
734                 keyboard_beep->set_volume(0, decibel_l, decibel_r);
735         }
736 #endif
737         else if(ch-- == 0) {
738                 if(fdc != NULL) {
739                         fdc->get_context_noise_seek()->set_volume(0, decibel_l, decibel_r);
740                         fdc->get_context_noise_head_down()->set_volume(0, decibel_l, decibel_r);
741                         fdc->get_context_noise_head_up()->set_volume(0, decibel_l, decibel_r);
742                 }
743         } else if(ch-- == 0) {
744                 if(drec != NULL) {
745                         drec->get_context_noise_play()->set_volume(0, decibel_l, decibel_r);
746                         drec->get_context_noise_stop()->set_volume(0, decibel_l, decibel_r);
747                         drec->get_context_noise_fast()->set_volume(0, decibel_l, decibel_r);
748                 }
749         }
750 }
751 #endif
752
753 // ----------------------------------------------------------------------------
754 // notify key
755 // ----------------------------------------------------------------------------
756
757 void VM::key_down(int code, bool repeat)
758 {
759         if(!repeat) {
760                 keyboard->key_down(code);
761         }
762 }
763
764 void VM::key_up(int code)
765 {
766         keyboard->key_up(code);
767 }
768
769 bool VM::get_caps_locked()
770 {
771         return keyboard->get_caps_locked();
772 }
773
774 bool VM::get_kana_locked()
775 {
776         return keyboard->get_kana_locked();
777 }
778
779 // Get INS status.Important with FM-7 series (^_^;
780 uint32_t VM::get_extra_leds()
781 {
782         return keyboard->read_signal(SIG_FM7KEY_LED_STATUS);
783 }
784
785
786 // ----------------------------------------------------------------------------
787 // user interface
788 // ----------------------------------------------------------------------------
789
790 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
791 {
792         if(fdc != NULL) {
793                 fdc->open_disk(drv, file_path, bank);
794         }
795 }
796
797 void VM::close_floppy_disk(int drv)
798 {
799         if(fdc != NULL) {
800                 fdc->close_disk(drv);
801         }
802 }
803
804 bool VM::is_floppy_disk_inserted(int drv)
805 {
806         if(fdc != NULL) {
807                 return fdc->is_disk_inserted(drv);
808         } else {
809                 return false;
810         }
811 }
812
813 void VM::is_floppy_disk_protected(int drv, bool value)
814 {
815         if(fdc != NULL) {
816                 fdc->is_disk_protected(drv, value);
817         }
818 }
819
820 bool VM::is_floppy_disk_protected(int drv)
821 {
822         if(fdc != NULL) {
823                 return fdc->is_disk_protected(drv);
824         } else {
825                 return false;
826         }
827 }
828
829 uint32_t VM::is_floppy_disk_accessed()
830 {
831         // WILLFIX : Multiple FDC for 1M FD.
832 #if defined(_FM8) || (_FM7) || (_FMNEW7)
833         if(connect_320kfdc || connect_1Mfdc) {
834 #endif          
835                 return fdc->read_signal(0);
836 #if defined(_FM8) || (_FM7) || (_FMNEW7)
837         } else {
838                 return 0x00000000;
839         }
840 #endif  
841 }
842
843 void VM::play_tape(int drv, const _TCHAR* file_path)
844 {
845         if(drec != NULL) drec->play_tape(file_path);
846 }
847
848 void VM::rec_tape(int drv, const _TCHAR* file_path)
849 {
850         if(drec != NULL) drec->rec_tape(file_path);
851 }
852
853 void VM::close_tape(int drv)
854 {
855         emu->lock_vm();
856         if(drec != NULL) drec->close_tape();
857         emu->unlock_vm();
858 }
859
860 bool VM::is_tape_inserted(int drv)
861 {
862         if(drec != NULL) {
863                 return drec->is_tape_inserted();
864         }
865         return false;
866 }
867
868 bool VM::is_tape_playing(int drv)
869 {
870         if(drec != NULL) {
871                 return drec->is_tape_playing();
872         }
873         return false;
874 }
875
876 bool VM::is_tape_recording(int drv)
877 {
878         if(drec != NULL) {
879                 return drec->is_tape_recording();
880         }
881         return false;
882 }
883
884 int VM::get_tape_position(int drv)
885 {
886         if(drec != NULL) {
887                 return drec->get_tape_position();
888         }
889         return 0;
890 }
891
892 const _TCHAR* VM::get_tape_message(int drv)
893 {
894         if(drec != NULL) {
895                 return drec->get_message();
896         }
897         return NULL;
898 }
899
900 void VM::push_play(int drv)
901 {
902         if(drec != NULL) {
903                 drec->set_ff_rew(0);
904                 drec->set_remote(true);
905         }
906 }
907
908
909 void VM::push_stop(int drv)
910 {
911         if(drec != NULL) {
912                 drec->set_remote(false);
913         }
914 }
915
916 void VM::push_fast_forward(int drv)
917 {
918         if(drec != NULL) {
919                 drec->set_ff_rew(1);
920                 drec->set_remote(true);
921         }
922 }
923
924 void VM::push_fast_rewind(int drv)
925 {
926         if(drec != NULL) {
927                 drec->set_ff_rew(-1);
928                 drec->set_remote(true);
929         }
930 }
931
932 void VM::push_apss_forward(int drv)
933 {
934         if(drec != NULL) {
935                 drec->do_apss(1);
936         }
937 }
938
939 void VM::push_apss_rewind(int drv)
940 {
941         if(drec != NULL) {
942                 drec->do_apss(-1);
943         }
944 }
945
946 bool VM::is_frame_skippable()
947 {
948         return event->is_frame_skippable();
949 }
950
951 void VM::update_dipswitch()
952 {
953 #if defined(WITH_Z80)
954         g_intr_irq->write_signal(SIG_AND_BIT_0, ((config.dipswitch & FM7_DIPSW_Z80_IRQ_ON) != 0) ? 1 : 0, 1);
955         g_intr_firq->write_signal(SIG_AND_BIT_0, ((config.dipswitch & FM7_DIPSW_Z80_FIRQ_ON) != 0) ? 1 : 0, 1);
956         g_nmi->write_signal(SIG_AND_BIT_0, ((config.dipswitch & FM7_DIPSW_Z80_NMI_ON) != 0) ? 1 : 0, 1);
957 #endif
958 }
959
960 void VM::set_cpu_clock(DEVICE *cpu, uint32_t clocks) {
961         event->set_secondary_cpu_clock(cpu, clocks);
962 }
963
964 #if defined(USE_BUBBLE1)
965 void VM::open_bubble_casette(int drv, const _TCHAR *path, int bank)
966 {
967         if((drv >= 2) || (drv < 0)) return;
968         if(bubble_casette[drv] == NULL) return;
969         bubble_casette[drv]->open((_TCHAR *)path, bank);
970 }
971
972 void VM::close_bubble_casette(int drv)
973 {
974         if((drv >= 2) || (drv < 0)) return;
975         if(bubble_casette[drv] == NULL) return;
976         bubble_casette[drv]->close();
977 }
978
979 bool VM::is_bubble_casette_inserted(int drv)
980 {
981         if((drv >= 2) || (drv < 0)) return false;
982         if(bubble_casette[drv] == NULL) return false;
983         return bubble_casette[drv]->is_bubble_inserted();
984 }
985
986 bool VM::is_bubble_casette_protected(int drv)
987 {
988         if((drv >= 2) || (drv < 0)) return false;
989         if(bubble_casette[drv] == NULL) return false;
990         return bubble_casette[drv]->is_bubble_protected();
991 }
992
993 void VM::is_bubble_casette_protected(int drv, bool flag)
994 {
995         if((drv >= 2) || (drv < 0)) return;
996         if(bubble_casette[drv] == NULL) return;
997         bubble_casette[drv]->set_bubble_protect(flag);
998 }
999 #endif
1000
1001
1002 #define STATE_VERSION   8
1003 void VM::save_state(FILEIO* state_fio)
1004 {
1005         state_fio->FputUint32_BE(STATE_VERSION);
1006         state_fio->FputBool(connect_320kfdc);
1007         state_fio->FputBool(connect_1Mfdc);
1008         for(DEVICE* device = first_device; device; device = device->next_device) {
1009                 const char *name = typeid(*device).name() + 6; // skip "class "
1010                 
1011                 state_fio->FputInt32(strlen(name));
1012                 state_fio->Fwrite(name, strlen(name), 1);
1013                 device->save_state(state_fio);
1014         }
1015 }
1016
1017 bool VM::load_state(FILEIO* state_fio)
1018 {
1019         uint32_t version = state_fio->FgetUint32_BE();
1020         if(version != STATE_VERSION) {
1021                 return false;
1022         }
1023         connect_320kfdc = state_fio->FgetBool();
1024         connect_1Mfdc = state_fio->FgetBool();
1025         for(DEVICE* device = first_device; device; device = device->next_device) {
1026                 const char *name = typeid(*device).name() + 6; // skip "class "
1027                 
1028                 if(!(state_fio->FgetInt32() == strlen(name) && state_fio->Fcompare(name, strlen(name)))) {
1029                         printf("Load Error: DEVID=%d\n", device->this_device_id);
1030                         return false;
1031                 }
1032                 if(!device->load_state(state_fio)) {
1033                         printf("Load Error: DEVID=%d\n", device->this_device_id);
1034                         return false;
1035                 }
1036         }
1037         return true;
1038 }
1039
1040 #ifdef USE_DIG_RESOLUTION
1041 void VM::get_screen_resolution(int *w, int *h)
1042 {
1043         switch(display->get_screen_mode()) {
1044         case DISPLAY_MODE_8_200L:
1045         case DISPLAY_MODE_8_200L_TEXT:
1046                 *w = 640;
1047                 *h = 200;
1048                 break;
1049         case DISPLAY_MODE_8_400L:
1050         case DISPLAY_MODE_8_400L_TEXT:
1051                 *w = 640;
1052                 *h = 400;
1053                 break;
1054         case DISPLAY_MODE_4096:
1055         case DISPLAY_MODE_256k:
1056                 *w = 320;
1057                 *h = 200;
1058                 break;
1059         default:
1060                 *w = 640;
1061                 *h = 200;
1062                 break;
1063         }
1064 }
1065 #endif
1066
1067 bool VM::is_screen_changed()
1068 {
1069         bool f = true;
1070 #if defined(USE_MINIMUM_RENDERING)
1071         f = display->screen_update();
1072         display->reset_screen_update();
1073 #endif  
1074         return f;
1075 }