OSDN Git Service

[VM][FM7] Add sounds; FDD Seeking and Relay.
[csp-qt/common_source_project-fm7.git] / source / src / vm / fm7 / fm7.cpp
index af2a5b2..80ec677 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * FM7 -> VM
  * (C) 2015 K.Ohta <whatisthis.sowhat _at_ gmail.com>
 #include "../device.h"
 #include "../event.h"
 #include "../memory.h"
+#include "../prnfile.h"
+
 #ifdef USE_DEBUGGER
 #include "../debugger.h"
 #endif
-#if defined(SUPPORT_DUMMY_DEVICE_LED)
-#include "../dummydevice.h"
-#else
-#define SIG_DUMMYDEVICE_BIT0 0
-#define SIG_DUMMYDEVICE_BIT1 1
-#define SIG_DUMMYDEVICE_BIT2 2
-#endif
 
 #include "../datarec.h"
 #include "../disk.h"
 #include "../ym2203.h"
 #if defined(_FM77AV_VARIANTS)
 #include "mb61vh010.h"
+#include "../beep.h"
+#endif
+#if defined(HAS_DMA)
+#include "hd6844.h"
+#endif
+#if defined(_FM8)
+#include "./bubblecasette.h"
 #endif
 
+#if defined(USE_LED_DEVICE)
+#include "./dummydevice.h"
+#else
+#define SIG_DUMMYDEVICE_BIT0 0
+#define SIG_DUMMYDEVICE_BIT1 1
+#define SIG_DUMMYDEVICE_BIT2 2
+#endif
+#if defined(USE_SOUND_FILES)
+#include "../wav_sounder.h"
+#endif
 #include "./fm7_mainio.h"
 #include "./fm7_mainmem.h"
 #include "./fm7_display.h"
@@ -48,71 +59,146 @@ VM::VM(EMU* parent_emu): emu(parent_emu)
 {
        
        first_device = last_device = NULL;
-       connect_opn = false;
-       connect_whg = false;
-       connect_thg = false;
+#if defined(_FM8)
+       psg = NULL;
+#else  
+# if defined(_FM77AV_VARIANTS)
+       opn[0] = opn[1] = opn[2] = NULL;
+# else   
        opn[0] = opn[1] = opn[2] = psg = NULL; 
-   
+# endif
+#endif
        dummy = new DEVICE(this, emu);  // must be 1st device
        event = new EVENT(this, emu);   // must be 2nd device
        
        dummycpu = new DEVICE(this, emu);
-       // basic devices
-       kanjiclass1 = new KANJIROM(this, emu, false);
-#ifdef CAPABLE_KANJI_CLASS2
-       kanjiclass2 = new KANJIROM(this, emu, true);
+       maincpu = new MC6809(this, emu);
+       subcpu = new MC6809(this, emu);
+#ifdef WITH_Z80
+       z80cpu = new Z80(this, emu);
 #endif
-       joystick  = new JOYSTICK(this, emu);
-       
+       // basic devices
        // I/Os
-       drec = new DATAREC(this, emu);
-       pcm1bit = new PCM1BIT(this, emu);
-       fdc  = new MB8877(this, emu);
-       
+#if defined(HAS_DMA)
+       dmac = new HD6844(this, emu);
+#endif   
+#if defined(_FM8)
+       psg = new YM2203(this, emu);
+#else  
        opn[0] = new YM2203(this, emu); // OPN
        opn[1] = new YM2203(this, emu); // WHG
        opn[2] = new YM2203(this, emu); // THG
-   
-#if !defined(_FM77AV_VARIANTS)
+# if !defined(_FM77AV_VARIANTS)
        psg = new YM2203(this, emu);
+# endif
 #endif
-       keyboard = new KEYBOARD(this, emu);
+#if defined(_FM8)
+       for(int i = 0; i < 2; i++) bubble_casette[i] = new BUBBLECASETTE(this, emu);
+#endif 
+       drec = new DATAREC(this, emu);
+       pcm1bit = new PCM1BIT(this, emu);
+
+       connect_320kfdc = connect_1Mfdc = false;
+       fdc = NULL;
+#if defined(_FM8) || defined(_FM7) || defined(_FMNEW7)
+       if(((config.dipswitch & FM7_DIPSW_CONNECT_320KFDC) != 0) ||
+          ((config.dipswitch & FM7_DIPSW_CONNECT_1MFDC) != 0)) {
+#endif         
+               fdc = new MB8877(this, emu);
+#if defined(_FM8) || defined(_FM7) || defined(_FMNEW7)
+               if((config.dipswitch & FM7_DIPSW_CONNECT_320KFDC) != 0) {
+                       connect_320kfdc = true;
+               }
+               if((config.dipswitch & FM7_DIPSW_CONNECT_1MFDC) != 0) {
+                       connect_1Mfdc = true;
+               }
+#elif defined(_FM77_VARIANTS)
+               connect_320kfdc = true;
+               if((config.dipswitch & FM7_DIPSW_CONNECT_1MFDC) != 0) {
+                       connect_1Mfdc = true;
+               }
+#else  // AV or later.
+               connect_320kfdc = true;
+               // 1MFDD??
+#endif         
+#if defined(_FM8) || defined(_FM7) || defined(_FMNEW7)
+       }
+#endif 
+       joystick  = new JOYSTICK(this, emu);
+       printer = new PRNFILE(this, emu);
 #if defined(_FM77AV_VARIANTS)
        alu = new MB61VH010(this, emu);
+       keyboard_beep = new BEEP(this, emu);
 #endif 
-       display = new DISPLAY(this, emu);
+       keyboard = new KEYBOARD(this, emu);
+       display = new DISPLAY(this, emu);       
+
        mainio  = new FM7_MAINIO(this, emu);
        mainmem = new FM7_MAINMEM(this, emu);
-
-#if defined(SUPPORT_DUMMY_DEVICE_LED)
+       
+#if defined(_FM8) || defined(_FM7) || defined(_FMNEW7)
+       if((config.dipswitch & FM7_DIPSW_CONNECT_KANJIROM) != 0) {
+               kanjiclass1 = new KANJIROM(this, emu, false);
+       } else {
+               kanjiclass1 = NULL;
+       }
+#else
+       kanjiclass1 = new KANJIROM(this, emu, false);
+#endif 
+#ifdef CAPABLE_KANJI_CLASS2
+       kanjiclass2 = new KANJIROM(this, emu, true);
+#endif
+#if defined(USE_LED_DEVICE)
        led_terminate = new DUMMYDEVICE(this, emu);
 #else
        led_terminate = new DEVICE(this, emu);
 #endif
-       maincpu = new MC6809(this, emu);
-       subcpu = new MC6809(this, emu);
-#ifdef WITH_Z80
-       z80cpu = new Z80(this, emu);
-#endif
-       // MEMORIES must set before initialize().
-       maincpu->set_context_mem(mainmem);
-       subcpu->set_context_mem(display);
-#ifdef WITH_Z80
-       z80cpu->set_context_mem(mainmem);
-#endif
-#ifdef USE_DEBUGGER
-       maincpu->set_context_debugger(new DEBUGGER(this, emu));
-       subcpu->set_context_debugger(new DEBUGGER(this, emu));
-#ifdef WITH_Z80
-       z80cpu->set_context_debugger(new DEBUGGER(this, emu));
-#endif
+#if defined(USE_SOUND_FILES)
+       fdd_seek = new WAV_SOUNDER(this, emu);
+       cmt_relay_on = new WAV_SOUNDER(this, emu);
+       cmt_relay_off = new WAV_SOUNDER(this, emu);
+#endif 
+#if defined(_USE_QT)
+       event->set_device_name(_T("EVENT"));
+       dummy->set_device_name(_T("1st Dummy"));
+       
+       maincpu->set_device_name(_T("MAINCPU(MC6809)"));
+       subcpu->set_device_name(_T("SUBCPU(MC6809)"));
+       dummycpu->set_device_name(_T("DUMMY CPU"));
+# ifdef WITH_Z80
+       z80cpu->set_device_name(_T("Z80 CPU"));
+# endif
+       led_terminate->set_device_name(_T("LEDs"));
+       if(fdc != NULL) fdc->set_device_name(_T("MB8877 FDC(320KB)"));
+                                               
+       // basic devices
+       // I/Os
+# if defined(_FM8)
+       psg->set_device_name(_T("AY-3-8910 PSG"));
+# else 
+       opn[0]->set_device_name(_T("YM2203 OPN"));
+       opn[1]->set_device_name(_T("YM2203 WHG"));
+       opn[2]->set_device_name(_T("YM2203 THG"));
+#  if !defined(_FM77AV_VARIANTS)
+       psg->set_device_name(_T("AY-3-8910 PSG"));
+#  endif
+# endif
+       pcm1bit->set_device_name(_T("BEEP"));
+       printer->set_device_name(_T("PRINTER I/F"));
+# if defined(_FM77AV_VARIANTS)
+       keyboard_beep->set_device_name(_T("BEEP(KEYBOARD)"));
+# endif        
+       if(kanjiclass1 != NULL) kanjiclass1->set_device_name(_T("KANJI ROM CLASS1"));
+# ifdef CAPABLE_KANJI_CLASS2
+       if(kanjiclass2 != NULL) kanjiclass2->set_device_name(_T("KANJI ROM CLASS2"));
+# endif
+# if defined(_FM8)
+       bubble_casette[0]->set_device_name(_T("BUBBLE CASETTE #0"));
+       bubble_casette[1]->set_device_name(_T("BUBBLE CASETTE #1"));
+# endif        
 #endif
-
-       //for(DEVICE* device = first_device; device; device = device->next_device) {
-       //      device->initialize();
-       //}
-       connect_bus();
-       initialize();
+       this->connect_bus();
+       
 }
 
 VM::~VM()
@@ -136,23 +222,10 @@ DEVICE* VM::get_device(int id)
        return NULL;
 }
 
-
-void VM::initialize(void)
-{
-#if defined(_FM8) || defined(_FM7)
-       cycle_steal = false;
-#else
-       cycle_steal = true;
-#endif
-       clock_low = false;
-       
-}
-
-
 void VM::connect_bus(void)
 {
-       uint32 mainclock;
-       uint32 subclock;
+       uint32_t mainclock;
+       uint32_t subclock;
 
        /*
         * CLASS CONSTRUCTION
@@ -174,9 +247,11 @@ void VM::connect_bus(void)
         */
        event->set_frames_per_sec(FRAMES_PER_SEC);
        event->set_lines_per_frame(LINES_PER_FRAME);
-       event->set_context_cpu(dummycpu, CPU_CLOCKS / 3);
-       //event->set_context_cpu(dummycpu, SUBCLOCK_SLOW);
-       
+       //event->set_context_cpu(dummycpu, (CPU_CLOCKS * 3) / 8); // MAYBE FIX With eFM77AV40/20.
+       // With slow clock (for dummycpu), some softwares happen troubles,
+       // Use faster clock for dummycpu. 20160319 K.Ohta
+       event->set_context_cpu(dummycpu, SUBCLOCK_NORMAL);
+
 #if defined(_FM8)
        mainclock = MAINCLOCK_SLOW;
        subclock = SUBCLOCK_SLOW;
@@ -190,6 +265,7 @@ void VM::connect_bus(void)
                mainclock = MAINCLOCK_SLOW;
                subclock = SUBCLOCK_SLOW;
        }
+       //if((config.dipswitch & FM7_DIPSW_CYCLESTEAL) != 0) subclock = subclock / 3;
 #endif
        event->set_context_cpu(maincpu, mainclock);
        event->set_context_cpu(subcpu,  subclock);
@@ -200,55 +276,92 @@ void VM::connect_bus(void)
 #endif
 
        event->set_context_sound(pcm1bit);
-#if !defined(_FM77AV_VARIANTS)
-       mainio->set_context_psg(psg);
+#if defined(_FM8)
        event->set_context_sound(psg);
-#endif
+       event->set_context_sound(drec);
+#else
        event->set_context_sound(opn[0]);
        event->set_context_sound(opn[1]);
        event->set_context_sound(opn[2]);
+# if !defined(_FM77AV_VARIANTS)
+       event->set_context_sound(psg);
+# endif
        event->set_context_sound(drec);
-   
-       event->register_frame_event(display);
+#if defined(USE_SOUND_FILES)
+       fdd_seek->load_data(_T("FDDSEEK.WAV"));
+       event->set_context_sound(fdd_seek);
+       
+       cmt_relay_on->load_data(_T("RELAY_ON.WAV"));
+       cmt_relay_off->load_data(_T("RELAYOFF.WAV"));
+       event->set_context_sound(cmt_relay_on);
+       event->set_context_sound(cmt_relay_off);
+#endif
+# if defined(_FM77AV_VARIANTS)
+       event->set_context_sound(keyboard_beep);
+# endif
+#endif   
+#if !defined(_FM77AV_VARIANTS) && !defined(_FM77L4)
        event->register_vline_event(display);
-       event->register_vline_event(mainio);
-   
+       event->register_frame_event(display);
+#endif 
        mainio->set_context_maincpu(maincpu);
        mainio->set_context_subcpu(subcpu);
        
        mainio->set_context_display(display);
+#if defined(_FM8) || defined(_FM7) || defined(_FMNEW7)
+       if((config.dipswitch & FM7_DIPSW_CONNECT_KANJIROM) != 0) {
+               mainio->set_context_kanjirom_class1(kanjiclass1);
+       }
+#else
        mainio->set_context_kanjirom_class1(kanjiclass1);
+#endif 
        mainio->set_context_mainmem(mainmem);
        mainio->set_context_keyboard(keyboard);
-   
+       mainio->set_context_printer(printer);
+       mainio->set_context_printer_reset(printer, SIG_PRINTER_RESET, 0xffffffff);
+       mainio->set_context_printer_strobe(printer, SIG_PRINTER_STROBE, 0xffffffff);
+       mainio->set_context_printer_select(printer, SIG_PRINTER_SELECT, 0xffffffff);
 #if defined(CAPABLE_KANJI_CLASS2)
-        mainio->set_context_kanjirom_class2(kanjiclass2);
+       mainio->set_context_kanjirom_class2(kanjiclass2);
 #endif
-
+#if defined(_FM8)
+       for(int i = 0; i < 2; i++) mainio->set_context_bubble(bubble_casette[i], i);
+#endif 
        keyboard->set_context_break_line(mainio, FM7_MAINIO_PUSH_BREAK, 0xffffffff);
        keyboard->set_context_int_line(mainio, FM7_MAINIO_KEYBOARDIRQ, 0xffffffff);
        keyboard->set_context_int_line(display, SIG_FM7_SUB_KEY_FIRQ, 0xffffffff);
-       
+#if defined(_FM77AV_VARIANTS)
+       keyboard->set_context_beep(keyboard_beep);
+#endif 
        keyboard->set_context_rxrdy(display, SIG_FM7KEY_RXRDY, 0x01);
        keyboard->set_context_key_ack(display, SIG_FM7KEY_ACK, 0x01);
        keyboard->set_context_ins_led( led_terminate, SIG_DUMMYDEVICE_BIT0, 0xffffffff);
        keyboard->set_context_caps_led(led_terminate, SIG_DUMMYDEVICE_BIT1, 0xffffffff);
        keyboard->set_context_kana_led(led_terminate, SIG_DUMMYDEVICE_BIT2, 0xffffffff);
    
-       drec->set_context_out(mainio, FM7_MAINIO_CMT_RECV, 0xffffffff);
+       drec->set_context_ear(mainio, FM7_MAINIO_CMT_RECV, 0xffffffff);
        //drec->set_context_remote(mainio, FM7_MAINIO_CMT_REMOTE, 0xffffffff);
        mainio->set_context_datarec(drec);
+       
        mainmem->set_context_mainio(mainio);
        mainmem->set_context_display(display);
        mainmem->set_context_maincpu(maincpu);
-  
+#if defined(CAPABLE_DICTROM)
+       mainmem->set_context_kanjirom_class1(kanjiclass1);
+#endif  
        display->set_context_mainio(mainio);
        display->set_context_subcpu(subcpu);
        display->set_context_keyboard(keyboard);
+
+       mainio->set_context_clock_status(mainmem, FM7_MAINIO_CLOCKMODE, 0xffffffff);
+       mainio->set_context_clock_status(display, SIG_DISPLAY_CLOCK, 0xffffffff);
+       
        subcpu->set_context_bus_halt(display, SIG_FM7_SUB_HALT, 0xffffffff);
        subcpu->set_context_bus_halt(mainmem, SIG_FM7_SUB_HALT, 0xffffffff);
 
+#if defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
        display->set_context_kanjiclass1(kanjiclass1);
+#endif 
 #if defined(CAPABLE_KANJI_CLASS2)
        display->set_context_kanjiclass2(kanjiclass2);
 #endif   
@@ -258,14 +371,29 @@ void VM::connect_bus(void)
 #endif 
        // Palette, VSYNC, HSYNC, Multi-page, display mode. 
        mainio->set_context_display(display);
-       
-       //FDC
-       mainio->set_context_fdc(fdc);
-       fdc->set_context_irq(mainio, FM7_MAINIO_FDC_IRQ, 0x1);
-       fdc->set_context_drq(mainio, FM7_MAINIO_FDC_DRQ, 0x1);
+#if defined(_FM8) || (_FM7) || (_FMNEW7)
+       if(connect_320kfdc || connect_1Mfdc) {
+#endif         
+               //FDC
+               fdc->set_context_irq(mainio, FM7_MAINIO_FDC_IRQ, 0x1);
+               fdc->set_context_drq(mainio, FM7_MAINIO_FDC_DRQ, 0x1);
+               mainio->set_context_fdc(fdc);
+#if defined(USE_SOUND_FILES)
+               fdc->set_context_seek(fdd_seek);
+               mainio->set_context_relay_on(cmt_relay_on);
+               mainio->set_context_relay_off(cmt_relay_off);
+#endif
+#if defined(_FM8) || (_FM7) || (_FMNEW7)
+       }
+#endif 
        // SOUND
        mainio->set_context_beep(pcm1bit);
-       
+#if defined(_FM8)      
+       mainio->set_context_psg(psg);
+#else
+# if !defined(_FM77AV_VARIANTS)
+       mainio->set_context_psg(psg);
+# endif
        opn[0]->set_context_irq(mainio, FM7_MAINIO_OPN_IRQ, 0xffffffff);
        mainio->set_context_opn(opn[0], 0);
        //joystick->set_context_opn(opn[0]);
@@ -276,101 +404,75 @@ void VM::connect_bus(void)
        mainio->set_context_opn(opn[1], 1);
        opn[2]->set_context_irq(mainio, FM7_MAINIO_THG_IRQ, 0xffffffff);
        mainio->set_context_opn(opn[2], 2);
-   
+#endif   
        subcpu->set_context_bus_halt(display, SIG_FM7_SUB_HALT, 0xffffffff);
        subcpu->set_context_bus_clr(display, SIG_FM7_SUB_USE_CLR, 0x0000000f);
    
        event->register_frame_event(joystick);
-               
+#if defined(HAS_DMA)
+       dmac->set_context_src(fdc, 0);
+       dmac->set_context_dst(mainmem, 0);
+       dmac->set_context_int_line(mainio, 0, FM7_MAINIO_DMA_INT, 0xffffffff);
+       dmac->set_context_drq_line(maincpu, 1, SIG_CPU_BUSREQ, 0xffffffff);
+       mainio->set_context_dmac(dmac);
+#endif
+       
+       // MEMORIES must set before initialize().
+       maincpu->set_context_mem(mainmem);
+       subcpu->set_context_mem(display);
+#ifdef WITH_Z80
+       z80cpu->set_context_mem(mainmem);
+#endif
+#ifdef USE_DEBUGGER
+       maincpu->set_context_debugger(new DEBUGGER(this, emu));
+       subcpu->set_context_debugger(new DEBUGGER(this, emu));
+# ifdef WITH_Z80
+       z80cpu->set_context_debugger(new DEBUGGER(this, emu));
+# endif
+#endif
        for(DEVICE* device = first_device; device; device = device->next_device) {
                device->initialize();
        }
-       for(int i = 0; i < 2; i++) {
-#if defined(_FM77AV20) || defined(_FM77AV40SX) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
-               fdc->set_drive_type(i, DRIVE_TYPE_2DD);
+
+       // Disks
+#if defined(_FM8) || (_FM7) || (_FMNEW7)
+       if(connect_320kfdc) {
+#endif         
+               for(int i = 0; i < 4; i++) {
+#if defined(_FM77AV20) || defined(_FM77AV20EX) || \
+       defined(_FM77AV40SX) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
+                       fdc->set_drive_type(i, DRIVE_TYPE_2DD);
 #else
-               fdc->set_drive_type(i, DRIVE_TYPE_2D);
+                       fdc->set_drive_type(i, DRIVE_TYPE_2D);
 #endif
-               //fdc->set_drive_rpm(i, 380);
-               fdc->set_drive_rpm(i, 0);
-               fdc->set_drive_mfm(i, true);
-       }
-#if defined(_FM77) || defined(_FM77L4)
-       for(int i = 2; i < 4; i++) {
-               fdc->set_drive_type(i, DRIVE_TYPE_2HD);
-               fdc->set_drive_rpm(i, 360);
-               fdc->set_drive_mfm(i, true);
+                       fdc->set_drive_rpm(i, 360);
+                       fdc->set_drive_mfm(i, true);
+               }
+#if defined(_FM8) || (_FM7) || (_FMNEW7)
        }
-#endif
+#endif 
        
+#if defined(_FM8) || (_FM7) || (_FMNEW7)
+       if(connect_1Mfdc) {
+#endif
+// 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.
+//#if defined(_FM77) || defined(_FM77L4)
+//             for(int i = 0; i < 4; i++) {
+//                     fdc->set_drive_type(i, DRIVE_TYPE_2HD);
+//                     fdc->set_drive_rpm(i, 360);
+//                     fdc->set_drive_mfm(i, true);
+//             }
+//#endif
+#if defined(_FM8) || (_FM7) || (_FMNEW7)
+       }
+#endif 
 }  
 
 void VM::update_config()
 {
-       uint32 vol1, vol2, tmpv;
+       uint32_t vol1, vol2, tmpv;
        int ii, i_limit;
-#if !defined(_FM8)
-       switch(config.cpu_type){
-               case 0:
-                       event->set_secondary_cpu_clock(maincpu, MAINCLOCK_NORMAL);
-                       break;
-               case 1:
-                       event->set_secondary_cpu_clock(maincpu, MAINCLOCK_SLOW);
-                       break;
-       }
-#endif
 
-#if defined(SIG_YM2203_LVOLUME) && defined(SIG_YM2203_RVOLUME)
-# if defined(USE_MULTIPLE_SOUNDCARDS)
-       i_limit = USE_MULTIPLE_SOUNDCARDS - 1;
-# else
-#  if !defined(_FM77AV_VARIANTS) && !defined(_FM8)
-       i_limit = 4;
-#  elif defined(_FM8)
-       i_limit = 1; // PSG Only
-#  else
-       i_limit = 3;
-#  endif
-# endif
-       
-       for(ii = 0; ii < i_limit; ii++) {
-               if(config.multiple_speakers) { //
-# if defined(USE_MULTIPLE_SOUNDCARDS)
-                       vol1 = (config.sound_device_level[ii] + 32768) >> 8;
-# else
-                       vol1 = 256;
-# endif //
-
-                       vol2 = vol1 >> 2;
-               } else {
-# if defined(USE_MULTIPLE_SOUNDCARDS)
-                       vol1 = vol2 = (config.sound_device_level[ii] + 32768) >> 8;
-# else
-                       vol1 = vol2 = 256;
-# endif
-               }
-               switch(ii) {
-               case 0: // OPN
-                       break;
-               case 1: // WHG
-               case 3: // PSG
-                       tmpv = vol1;
-                       vol1 = vol2;
-                       vol2 = tmpv;
-                       break;
-               case 2: // THG
-                       vol2 = vol1;
-                       break;
-               default:
-                       break;
-               }
-               opn[ii]->write_signal(SIG_YM2203_LVOLUME, vol1, 0xffffffff); // OPN: LEFT
-               opn[ii]->write_signal(SIG_YM2203_RVOLUME, vol2, 0xffffffff); // OPN: RIGHT
-       }
-#endif   
-#if defined(USE_MULTIPLE_SOUNDCARDS) && defined(DATAREC_SOUND)
-       drec->write_signal(SIG_DATAREC_VOLUME, (config.sound_device_level[USE_MULTIPLE_SOUNDCARDS - 1] + 32768) >> 3, 0xffffffff); 
-#endif
        for(DEVICE* device = first_device; device; device = device->next_device) {
                device->update_config();
        }
@@ -383,24 +485,18 @@ void VM::reset()
        for(DEVICE* device = first_device; device; device = device->next_device) {
                device->reset();
        }
-       //subcpu->reset();
-       //maincpu->reset();
-       
-       opn[0]->SetReg(0x2e, 0);        // set prescaler
-       opn[1]->SetReg(0x2e, 0);        // set prescaler
-       opn[2]->SetReg(0x2e, 0);        // set prescaler
-
-       // Init OPN/PSG.
-       // Parameters from XM7.
-       opn[0]->write_signal(SIG_YM2203_MUTE, 0x00, 0x01); // Okay?
-       opn[1]->write_signal(SIG_YM2203_MUTE, 0x00, 0x01); // Okay?
-       opn[2]->write_signal(SIG_YM2203_MUTE, 0x00, 0x01); // Okay?
-
-#if !defined(_FM77AV_VARIANTS)
-       psg->SetReg(0x27, 0); // stop timer
-       psg->SetReg(0x2e, 0);   // set prescaler
+#if !defined(_FM77AV_VARIANTS) || defined(_FM8)
+       psg->set_reg(0x27, 0); // stop timer
+       psg->set_reg(0x2e, 0);  // set prescaler
        psg->write_signal(SIG_YM2203_MUTE, 0x00, 0x01); // Okay?
-#endif 
+#endif
+#if !defined(_FM8)
+       for(int i = 0; i < 3; i++) {
+               opn[i]->set_reg(0x27, 0); // stop timer
+               opn[i]->set_reg(0x2e, 0);       // set prescaler
+               opn[i]->write_signal(SIG_YM2203_MUTE, 0x00, 0x01); // Okay?
+       }
+#endif
 }
 
 void VM::special_reset()
@@ -414,8 +510,9 @@ void VM::special_reset()
        mainio->write_signal(FM7_MAINIO_HOT_RESET, 1, 1);
 #endif 
        display->reset();
-       maincpu->reset();
+       subcpu->reset();
        mainio->write_signal(FM7_MAINIO_PUSH_BREAK, 1, 1);
+       maincpu->reset();
        event->register_event(mainio, EVENT_UP_BREAK, 10000.0 * 1000.0, false, NULL);
 }
 
@@ -424,17 +521,17 @@ void VM::run()
        event->drive();
 }
 
-double VM::frame_rate()
+double VM::get_frame_rate()
 {
-       return event->frame_rate();
+       return event->get_frame_rate();
 }
 
-#if defined(SUPPORT_DUMMY_DEVICE_LED)
-uint32 VM::get_led_status()
+#if defined(USE_LED_DEVICE)
+uint32_t VM::get_led_status()
 {
        return led_terminate->read_signal(SIG_DUMMYDEVICE_READWRITE);
 }
-#endif // SUPPORT_DUMMY_DEVICE_LED
+#endif // USE_LED_DEVICE
 
 
 // ----------------------------------------------------------------------------
@@ -467,10 +564,19 @@ void VM::draw_screen()
        display->draw_screen();
 }
 
-int VM::access_lamp()
+uint32_t VM::get_access_lamp_status()
 {
-       uint32 status = fdc->read_signal(0);
-       return (status & (1 | 4)) ? 1 : (status & (2 | 8)) ? 2 : 0;
+       // WILLFIX : Multiple FDC for 1M FD.
+#if defined(_FM8) || (_FM7) || (_FMNEW7)
+       if(connect_320kfdc || connect_1Mfdc) {
+#endif         
+               uint32_t status = fdc->read_signal(0xff);
+               return (status & (1 | 4)) ? 1 : (status & (2 | 8)) ? 2 : 0;
+#if defined(_FM8) || (_FM7) || (_FMNEW7)
+       } else {
+               return 0x00000000;
+       }
+#endif         
 }
 
 void VM::initialize_sound(int rate, int samples)
@@ -478,28 +584,80 @@ void VM::initialize_sound(int rate, int samples)
        // init sound manager
        event->initialize_sound(rate, samples);
        // init sound gen
-       opn[0]->init(rate, (int)(4.9152 * 1000.0 * 1000.0 / 4.0), samples, 0, 0);
-       opn[1]->init(rate, (int)(4.9152 * 1000.0 * 1000.0 / 4.0), samples, 0, 0);
-       opn[2]->init(rate, (int)(4.9152 * 1000.0 * 1000.0 / 4.0), samples, 0, 0);
-#if !defined(_FM77AV_VARIANTS)   
-       psg->init(rate, (int)(4.9152 * 1000.0 * 1000.0 / 4.0), samples, 0, 0);
-#endif   
-       pcm1bit->init(rate, 2000);
-       //drec->init_pcm(rate, 0);
+#if defined(_FM8)
+       psg->initialize_sound(rate, (int)(4.9152 * 1000.0 * 1000.0 / 4.0), samples, 0, 0);
+#else  
+       opn[0]->initialize_sound(rate, (int)(4.9152 * 1000.0 * 1000.0 / 4.0), samples, 0, 0);
+       opn[1]->initialize_sound(rate, (int)(4.9152 * 1000.0 * 1000.0 / 4.0), samples, 0, 0);
+       opn[2]->initialize_sound(rate, (int)(4.9152 * 1000.0 * 1000.0 / 4.0), samples, 0, 0);
+# if !defined(_FM77AV_VARIANTS)   
+       psg->initialize_sound(rate, (int)(4.9152 * 1000.0 * 1000.0 / 4.0), samples, 0, 0);
+# endif
+# if defined(_FM77AV_VARIANTS)
+       keyboard_beep->initialize_sound(rate, 2400.0, 512);
+# endif
+#endif 
+       pcm1bit->initialize_sound(rate, 2000);
+       //drec->initialize_sound(rate, 0);
 }
 
-uint16* VM::create_sound(int* extra_frames)
+uint16_t* VM::create_sound(int* extra_frames)
 {
-       uint16* p = event->create_sound(extra_frames);
+       uint16_t* p = event->create_sound(extra_frames);
        return p;
 }
 
-int VM::sound_buffer_ptr()
+int VM::get_sound_buffer_ptr()
 {
-       int pos = event->sound_buffer_ptr();
+       int pos = event->get_sound_buffer_ptr();
        return pos; 
 }
 
+#ifdef USE_SOUND_VOLUME
+void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
+{
+#if !defined(_FM77AV_VARIANTS)
+       if(ch-- == 0) {
+               psg->set_volume(0, decibel_l, decibel_r);
+               psg->set_volume(1, decibel_l, decibel_r);
+       } else
+#endif
+#if !defined(_FM8)             
+       if(ch-- == 0) {
+               opn[0]->set_volume(0, decibel_l, decibel_r);
+       } else if(ch-- == 0) {
+               opn[0]->set_volume(1, decibel_l, decibel_r);
+       } else if(ch-- == 0) {
+               opn[1]->set_volume(0, decibel_l, decibel_r);
+       } else if(ch-- == 0) {
+               opn[1]->set_volume(1, decibel_l, decibel_r);
+       } else if(ch-- == 0) {
+               opn[2]->set_volume(0, decibel_l, decibel_r);
+       } else if(ch-- == 0) {
+               opn[2]->set_volume(1, decibel_l, decibel_r);
+       } else
+#endif 
+       if(ch-- == 0) {
+               pcm1bit->set_volume(0, decibel_l, decibel_r);
+       } else if(ch-- == 0) {
+               drec->set_volume(0, decibel_l, decibel_r);
+       }
+#if defined(_FM77AV_VARIANTS)
+        else if(ch-- == 0) {
+               keyboard_beep->set_volume(0, decibel_l, decibel_r);
+       }
+#endif
+#if defined(USE_SOUND_FILES)
+        else if(ch-- == 0) {
+                fdd_seek->set_volume(0, decibel_l, decibel_r);
+        } else if(ch-- == 0) {
+                cmt_relay_on->set_volume(0, decibel_l, decibel_r);
+                cmt_relay_off->set_volume(0, decibel_l, decibel_r);
+        }
+#endif
+}
+#endif
+
 // ----------------------------------------------------------------------------
 // notify key
 // ----------------------------------------------------------------------------
@@ -520,39 +678,53 @@ void VM::key_up(int code)
 // user interface
 // ----------------------------------------------------------------------------
 
-void VM::open_disk(int drv, _TCHAR* file_path, int bank)
+void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
 {
-       fdc->open_disk(drv, file_path, bank);
+       if(fdc != NULL) {
+               fdc->open_disk(drv, file_path, bank);
+       }
 }
 
-void VM::close_disk(int drv)
+void VM::close_floppy_disk(int drv)
 {
-       fdc->close_disk(drv);
+       if(fdc != NULL) {
+               fdc->close_disk(drv);
+       }
 }
 
-bool VM::disk_inserted(int drv)
+bool VM::is_floppy_disk_inserted(int drv)
 {
-       return fdc->disk_inserted(drv);
+       if(fdc != NULL) {
+               return fdc->is_disk_inserted(drv);
+       } else {
+               return false;
+       }
 }
 
-void VM::set_disk_protected(int drv, bool value)
+void VM::is_floppy_disk_protected(int drv, bool value)
 {
-       fdc->set_disk_protected(drv, value);
+       if(fdc != NULL) {
+               fdc->is_disk_protected(drv, value);
+       }
 }
 
-bool VM::get_disk_protected(int drv)
+bool VM::is_floppy_disk_protected(int drv)
 {
-       return fdc->get_disk_protected(drv);
+       if(fdc != NULL) {
+               return fdc->is_disk_protected(drv);
+       } else {
+               return false;
+       }
 }
 
-void VM::play_tape(_TCHAR* file_path)
+void VM::play_tape(const _TCHAR* file_path)
 {
-       bool value = drec->play_tape(file_path);
+       drec->play_tape(file_path);
 }
 
-void VM::rec_tape(_TCHAR* file_path)
+void VM::rec_tape(const _TCHAR* file_path)
 {
-       bool value = drec->rec_tape(file_path);
+       drec->rec_tape(file_path);
 }
 
 void VM::close_tape()
@@ -560,21 +732,63 @@ void VM::close_tape()
        drec->close_tape();
 }
 
-bool VM::tape_inserted()
+bool VM::is_tape_inserted()
 {
-       return drec->tape_inserted();
+       return drec->is_tape_inserted();
 }
 
-#if defined(USE_TAPE_PTR)
-int VM::get_tape_ptr(void)
+bool VM::is_tape_playing()
 {
-        return drec->get_tape_ptr();
+       return drec->is_tape_playing();
 }
-#endif
 
-bool VM::now_skip()
+bool VM::is_tape_recording()
+{
+       return drec->is_tape_recording();
+}
+
+int VM::get_tape_position()
+{
+       return drec->get_tape_position();
+}
+
+void VM::push_play()
+{
+       drec->set_ff_rew(0);
+       drec->set_remote(true);
+}
+
+
+void VM::push_stop()
 {
-       return event->now_skip();
+       drec->set_remote(false);
+}
+
+void VM::push_fast_forward()
+{
+       drec->set_ff_rew(1);
+       drec->set_remote(true);
+}
+
+void VM::push_fast_rewind()
+{
+       drec->set_ff_rew(-1);
+       drec->set_remote(true);
+}
+
+void VM::push_apss_forward()
+{
+       drec->do_apss(1);
+}
+
+void VM::push_apss_rewind()
+{
+       drec->do_apss(-1);
+}
+
+bool VM::is_frame_skippable()
+{
+       return event->is_frame_skippable();
 }
 
 void VM::update_dipswitch()
@@ -584,9 +798,110 @@ void VM::update_dipswitch()
   //   io->set_iovalue_single_r(0x1ff0, (config.monitor_type & 1) | ((config.drive_type & 1) << 2));
 }
 
-void VM::set_cpu_clock(DEVICE *cpu, uint32 clocks) {
+void VM::set_cpu_clock(DEVICE *cpu, uint32_t clocks) {
        event->set_secondary_cpu_clock(cpu, clocks);
 }
 
-#define STATE_VERSION  1
+#if defined(USE_BUBBLE1)
+void VM::open_bubble_casette(int drv, _TCHAR *path, int bank)
+{
+       if((drv >= 2) || (drv < 0)) return;
+       if(bubble_casette[drv] == NULL) return;
+       bubble_casette[drv]->open(path, bank);
+}
 
+void VM::close_bubble_casette(int drv)
+{
+       if((drv >= 2) || (drv < 0)) return;
+       if(bubble_casette[drv] == NULL) return;
+       bubble_casette[drv]->close();
+}
+
+bool VM::is_bubble_casette_inserted(int drv)
+{
+       if((drv >= 2) || (drv < 0)) return false;
+       if(bubble_casette[drv] == NULL) return false;
+       return bubble_casette[drv]->is_bubble_inserted();
+}
+
+bool VM::is_bubble_casette_protected(int drv)
+{
+       if((drv >= 2) || (drv < 0)) return false;
+       if(bubble_casette[drv] == NULL) return false;
+       return bubble_casette[drv]->is_bubble_protected();
+}
+
+void VM::is_bubble_casette_protected(int drv, bool flag)
+{
+       if((drv >= 2) || (drv < 0)) return;
+       if(bubble_casette[drv] == NULL) return;
+       bubble_casette[drv]->set_bubble_protect(flag);
+}
+#endif
+
+
+#define STATE_VERSION  4
+void VM::save_state(FILEIO* state_fio)
+{
+       state_fio->FputUint32_BE(STATE_VERSION);
+       state_fio->FputBool(connect_320kfdc);
+       state_fio->FputBool(connect_1Mfdc);
+       for(DEVICE* device = first_device; device; device = device->next_device) {
+               device->save_state(state_fio);
+       }
+}
+
+bool VM::load_state(FILEIO* state_fio)
+{
+       uint32_t version = state_fio->FgetUint32_BE();
+       int i = 1;
+       if(version != STATE_VERSION) {
+               return false;
+       }
+       connect_320kfdc = state_fio->FgetBool();
+       connect_1Mfdc = state_fio->FgetBool();
+       for(DEVICE* device = first_device; device; device = device->next_device) {
+               if(!device->load_state(state_fio)) {
+                       printf("Load Error: DEVID=%d\n", device->this_device_id);
+                       return false;
+               }
+       }
+       return true;
+}
+
+#ifdef USE_DIG_RESOLUTION
+void VM::get_screen_resolution(int *w, int *h)
+{
+       switch(display->get_screen_mode()) {
+       case DISPLAY_MODE_8_200L:
+       case DISPLAY_MODE_8_200L_TEXT:
+               *w = 640;
+               *h = 200;
+               break;
+       case DISPLAY_MODE_8_400L:
+       case DISPLAY_MODE_8_400L_TEXT:
+               *w = 640;
+               *h = 400;
+               break;
+       case DISPLAY_MODE_4096:
+       case DISPLAY_MODE_256k:
+               *w = 320;
+               *h = 200;
+               break;
+       default:
+               *w = 640;
+               *h = 200;
+               break;
+       }
+}
+#endif
+
+bool VM::is_screen_changed()
+{
+       bool f = true;
+#if defined(USE_MINIMUM_RENDERING)
+       f = display->screen_update();
+       display->reset_screen_update();
+#endif 
+       return f;
+}