OSDN Git Service

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