OSDN Git Service

[VM][STATE][WIP] Apply process_state() to some devices.
[csp-qt/common_source_project-fm7.git] / source / src / vm / mb8877.cpp
index 565e67d..a41f211 100644 (file)
@@ -5,11 +5,12 @@
        Author : Takeda.Toshiya
        Date   : 2006.12.06 -
 
-       [ MB8877 / MB8876 / MB8866 ]
+       [ MB8877 / MB8876 / MB8866 / MB89311 ]
 */
 
 #include "mb8877.h"
 #include "disk.h"
+#include "noise.h"
 
 #define FDC_ST_BUSY            0x01    // busy
 #define FDC_ST_INDEX           0x02    // index hole
 #define FDC_CMD_RD_TRK         7
 #define FDC_CMD_WR_TRK         8
 
-#define EVENT_SEEK             0
-#define EVENT_SEEKEND          1
-#define EVENT_SEARCH           2
-#define EVENT_DRQ              3
-#define EVENT_MULTI1           4
-#define EVENT_MULTI2           5
-#define EVENT_LOST             6
+#define EVENT_SEEK                             0
+#define EVENT_SEEKEND_VERIFY   1
+#define EVENT_SEARCH                   2
+#define EVENT_DRQ                              3
+#define EVENT_MULTI1                   4
+#define EVENT_MULTI2                   5
+#define EVENT_LOST                             6
+#define EVENT_END_READ_SECTOR   7
+#define EVENT_CRC_ERROR         8
 
-#define DRIVE_MASK             (MAX_DRIVE - 1)
+//#define DRIVE_MASK           (MAX_DRIVE - 1)
 
 #define DELAY_TIME             (disk[drvreg]->drive_type == DRIVE_TYPE_2HD ? 15000 : 30000)
 
@@ -57,6 +60,13 @@ void MB8877::cancel_my_event(int event)
        }
 }
 
+bool MB8877::register_my_event_with_check(int event, double usec)
+{
+       if(register_id[event] >= 0) return false;
+       register_my_event(event, usec);
+       return true;
+}
+
 void MB8877::register_my_event(int event, double usec)
 {
        cancel_my_event(event);
@@ -67,7 +77,7 @@ void MB8877::register_seek_event()
 {
        cancel_my_event(EVENT_SEEK);
        if(fdc[drvreg].track == seektrk) {
-               register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), 1, false, &register_id[EVENT_SEEK]);
+               register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), 300, false, &register_id[EVENT_SEEK]); // From XM7 v3.4L77a Wait 300uS.
        } else if(disk[drvreg]->drive_type == DRIVE_TYPE_2HD) {
                register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), seek_wait_hi[cmdreg & 3], false, &register_id[EVENT_SEEK]);
        } else {
@@ -78,21 +88,40 @@ void MB8877::register_seek_event()
 
 void MB8877::register_drq_event(int bytes)
 {
-       double usec = disk[drvreg]->get_usec_per_bytes(bytes) - passed_usec(prev_drq_clock);
+       double nusec = disk[drvreg]->get_usec_per_bytes(bytes); // For debug
+       double usec = nusec - get_passed_usec(prev_drq_clock);
+       bool nf = false;
+       
+       if(usec > nusec) usec = nusec; 
        if(usec < 4) {
                usec = 4;
        }
-#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
-       if(disk[drvreg]->is_special_disk == SPECIAL_DISK_FM7_GAMBLER) {
-               usec = 4;
+       if(config.correct_disk_timing[drvreg]) {
+               nf = true;
        }
-#elif defined(_X1TURBO) || defined(_X1TURBOZ)
-//     if(disk[drvreg]->is_special_disk == SPECIAL_DISK_X1TURBO_ALPHA) {
-//             if(usec > 24) {
-//                     usec = 24;
-//             }
-//     }
-#endif
+       if(type_fm7) {
+               if((disk[drvreg]->is_special_disk == SPECIAL_DISK_FM7_GAMBLER)) {
+                  /* (disk[drvreg]->is_special_disk == SPECIAL_DISK_FM77AV_PSYOBLADE) || */
+                       nf = true;
+               }
+       }
+       if(nf) {
+               switch(disk[drvreg]->media_type) {
+               case MEDIA_TYPE_2D:
+               case MEDIA_TYPE_2DD:
+                       if(usec > 7.0) usec = 7.0;
+                       break;
+               case MEDIA_TYPE_2HD:
+               case MEDIA_TYPE_144:
+               case MEDIA_TYPE_UNK:
+                       usec = 4.0;
+                       break;
+               default:
+                       usec = 4.0;
+                       break;
+               }
+       }
+       if(fdc_debug_log) this->out_debug_log("DRQ REG: %dbytes %d:%d -> %f\n", bytes, get_current_clock(), prev_drq_clock, usec);
        cancel_my_event(EVENT_DRQ);
        register_event(this, (EVENT_DRQ << 8) | (cmdtype & 0xff), usec, false, &register_id[EVENT_DRQ]);
 }
@@ -103,16 +132,118 @@ void MB8877::register_lost_event(int bytes)
        register_event(this, (EVENT_LOST << 8) | (cmdtype & 0xff), disk[drvreg]->get_usec_per_bytes(bytes), false, &register_id[EVENT_LOST]);
 }
 
+bool MB8877::check_drive(void)
+{
+       if(drvreg >= _max_drive) {
+               status = FDC_ST_NOTREADY;
+               //set_drq(false);
+               set_irq(true);
+               return false;
+       }
+       return true;
+}
+
+bool MB8877::check_drive2(void)
+{
+       if(!check_drive()) {
+               return false;
+       }
+       if(!is_disk_inserted(drvreg & 0x7f)) {
+               status = FDC_ST_NOTREADY;
+               set_irq(true);
+               //set_drq(false);
+               return false;
+       }
+       return true;
+}
+
 void MB8877::initialize()
 {
+       DEVICE::initialize();
        // initialize d88 handler
-       for(int i = 0; i < MAX_DRIVE; i++) {
+       if(osd->check_feature(_T("MAX_DRIVE"))) {
+               _max_drive = osd->get_feature_int_value(_T("MAX_DRIVE"));
+       } else if(osd->check_feature(_T("MAX_FD"))) {
+               _max_drive = osd->get_feature_int_value(_T("MAX_FD"));
+       } else {
+               _max_drive = 1;
+       }
+
+       _drive_mask = _max_drive - 1;
+       for(int i = 0; i < _max_drive; i++) {
                disk[i] = new DISK(emu);
+               disk[i]->set_device_name(_T("%s/Disk #%d"), this_device_name, i + 1);
+       }
+       
+       if(osd->check_feature(_T("MB8877_NO_BUSY_AFTER_SEEK"))) {
+               mb8877_no_busy_after_seek = true;
+       }
+       //if(osd->check_feature(_T("_FDC_DEBUG_LOG"))) {
+       //      fdc_debug_log = true;
+       //}
+       fdc_debug_log = config.special_debug_fdc;
+       
+       if(osd->check_feature(_T("HAS_MB8866"))) {
+               type_mb8866 = true;
+               invert_registers = true;
+               set_device_name(_T("MB8866 FDC"));
+       }
+       if(osd->check_feature(_T("HAS_MB8876"))) {
+               invert_registers = true;
+               set_device_name(_T("MB8876 FDC"));
+       } else if(osd->check_feature(_T("HAS_MB89311"))) {
+               type_mb89311 = true;
+               set_device_name(_T("MB89311 FDC"));
+       } else {
+               set_device_name(_T("MB8877 FDC"));
+       }               
+       if(osd->check_feature(_T("_X1")) || osd->check_feature(_T("_X1TWIN")) ||
+               osd->check_feature(_T("_X1TURBO")) || osd->check_feature(_T("_X1TURBOZ"))) {
+               type_x1 = true;
+       }
+       if(osd->check_feature(_T("_FM7")) || osd->check_feature(_T("_FM8")) ||
+               osd->check_feature(_T("_FM77_VARIANTS")) || osd->check_feature(_T("_FM77AV_VARIANTS"))) {
+               type_fm7 = true;
+               if(osd->check_feature(_T("_FM77AV40")) || osd->check_feature(_T("_FM77AV40EX")) ||
+                  osd->check_feature(_T("_FM77AV40SX")) ||
+                  osd->check_feature(_T("_FM77AV20")) || osd->check_feature(_T("_FM77AV20EX"))) {
+                       type_fm77av_2dd = true;
+               }
+       }
+       if(osd->check_feature(_T("_FMR50"))) {
+               type_fmr50 = true;
+       }
+       if(osd->check_feature(_T("_FMR60"))) {
+               type_fmr60 = true;
+       }
+       
+       // initialize noise
+       if(d_noise_seek != NULL) {
+               d_noise_seek->set_device_name(_T("Noise Player (FDD Seek)"));
+               if(!d_noise_seek->load_wav_file(_T("FDDSEEK.WAV"))) {
+                       if(!d_noise_seek->load_wav_file(_T("FDDSEEK1.WAV"))) {
+                               d_noise_seek->load_wav_file(_T("SEEK.WAV"));
+                       }
+               }
+               d_noise_seek->set_mute(!config.sound_noise_fdd);
+       }
+       if(d_noise_head_down != NULL) {
+               d_noise_head_down->set_device_name(_T("Noise Player (FDD Head Load)"));
+               d_noise_head_down->load_wav_file(_T("HEADDOWN.WAV"));
+               d_noise_head_down->set_mute(!config.sound_noise_fdd);
+       }
+       if(d_noise_head_up != NULL) {
+               d_noise_head_up->set_device_name(_T("Noise Player (FDD Head Unload)"));
+               d_noise_head_up->load_wav_file(_T("HEADUP.WAV"));
+               d_noise_head_up->set_mute(!config.sound_noise_fdd);
        }
        
        // initialize timing
        memset(fdc, 0, sizeof(fdc));
-       
+       for(int i = 0; i < 16; i++) {
+               fdc[i].track = 40;  // OK?
+               fdc[i].count_immediate = false;
+       }
        // initialize fdc
        seektrk = 0;
        seekvct = true;
@@ -124,7 +255,7 @@ void MB8877::initialize()
 void MB8877::release()
 {
        // release d88 handler
-       for(int i = 0; i < MAX_DRIVE; i++) {
+       for(int i = 0; i < _max_drive; i++) {
                if(disk[i]) {
                        disk[i]->close();
                        delete disk[i];
@@ -134,39 +265,55 @@ void MB8877::release()
 
 void MB8877::reset()
 {
-       for(int i = 0; i < MAX_DRIVE; i++) {
-               fdc[i].track = 0;
+       for(int i = 0; i < _max_drive; i++) {
+               fdc[i].track = 0; // Not Hold to track 20180506 K.O
                fdc[i].index = 0;
                fdc[i].access = false;
        }
-       for(int i = 0; i < array_length(register_id); i++) {
+       for(int i = 0; i < (int)array_length(register_id); i++) {
                register_id[i] = -1;
        }
        now_search = now_seek = drive_sel = false;
        no_command = 0;
+       
+//#ifdef HAS_MB89311
+       if(type_mb89311) {
+               extended_mode = true;
+       } else {
+               extended_mode = false;
+       }
+//#endif
 }
 
-void MB8877::write_io8(uint32 addr, uint32 data)
+void MB8877::write_io8(uint32_t addr, uint32_t data)
 {
+       bool ready;
+       
        switch(addr & 3) {
        case 0:
                // command reg
                cmdreg_tmp = cmdreg;
-#if defined(HAS_MB8866) || defined(HAS_MB8876)
-               cmdreg = (~data) & 0xff;
-#else
-               cmdreg = data;
-#endif
+//#if defined(HAS_MB8866) || defined(HAS_MB8876)
+               if(invert_registers) {
+                       cmdreg = (~data) & 0xff;
+               } else {
+//#else
+                       cmdreg = data;
+               }
+//#endif
                process_cmd();
                no_command = 0;
                break;
        case 1:
                // track reg
-#if defined(HAS_MB8866) || defined(HAS_MB8876)
-               trkreg = (~data) & 0xff;
-#else
-               trkreg = data;
-#endif
+//#if defined(HAS_MB8866) || defined(HAS_MB8876)
+               if(invert_registers) {
+                       trkreg = (~data) & 0xff;
+               } else {
+//#else
+                       trkreg = data;
+               }
+//#endif
                if((status & FDC_ST_BUSY) && (fdc[drvreg].index == 0)) {
                        // track reg is written after command starts
                        if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
@@ -176,11 +323,14 @@ void MB8877::write_io8(uint32 addr, uint32 data)
                break;
        case 2:
                // sector reg
-#if defined(HAS_MB8866) || defined(HAS_MB8876)
-               secreg = (~data) & 0xff;
-#else
-               secreg = data;
-#endif
+//#if defined(HAS_MB8866) || defined(HAS_MB8876)
+               if(invert_registers) {
+                       secreg = (~data) & 0xff;
+               } else {
+//#else
+                       secreg = data;
+               }
+//#endif
                if((status & FDC_ST_BUSY) && (fdc[drvreg].index == 0)) {
                        // sector reg is written after command starts
                        if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
@@ -190,12 +340,30 @@ void MB8877::write_io8(uint32 addr, uint32 data)
                break;
        case 3:
                // data reg
-#if defined(HAS_MB8866) || defined(HAS_MB8876)
-               datareg = (~data) & 0xff;
-#else
-               datareg = data;
-#endif
-               if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
+//#if defined(HAS_MB8866) || defined(HAS_MB8876)
+               if(invert_registers) {
+                       datareg = (~data) & 0xff;
+               } else {
+//#else
+                       datareg = data;
+               }
+//#endif
+               ready = ((status & FDC_ST_DRQ) && !now_search);
+
+//#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
+               if(type_fm7) {
+                       if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
+                               if(!motor_on) ready = false;
+                       }
+                       if(!fdc[drvreg].head_load) ready = false;
+               } else 
+//#endif
+               {
+                       if(!motor_on) ready = false;
+                       if(!fdc[drvreg].head_load) ready = false;
+               }
+//             if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
+               if(ready) {
                        if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
                                // write or multisector write
                                if(fdc[drvreg].index < disk[drvreg]->sector_size.sd) {
@@ -217,13 +385,20 @@ void MB8877::write_io8(uint32 addr, uint32 data)
                                if((fdc[drvreg].index + 1) >= disk[drvreg]->sector_size.sd) {
                                        if(cmdtype == FDC_CMD_WR_SEC) {
                                                // single sector
+//#ifdef _FDC_DEBUG_LOG
+                                               if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
+//#endif
                                                status &= ~FDC_ST_BUSY;
                                                cmdtype = 0;
                                                set_irq(true);
                                        } else {
                                                // multisector
-                                               register_my_event(EVENT_MULTI1, 30);
-                                               register_my_event(EVENT_MULTI2, 60);
+//#ifdef _FDC_DEBUG_LOG
+                                               if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR (SEARCH NEXT)\n"));
+//#endif
+                                               // 2HD: 360rpm, 10410bytes/track -> 0.06246bytes/us
+                                               register_my_event(EVENT_MULTI1, 30); // 0.06246bytes/us * 30us = 1.8738bytes < GAP3
+                                               register_my_event(EVENT_MULTI2, 60); // 0.06246bytes/us * 60us = 3.7476bytes < GAP3
                                        }
                                        sector_changed = false;
                                } else if(status & FDC_ST_DRQ) {
@@ -232,6 +407,7 @@ void MB8877::write_io8(uint32 addr, uint32 data)
                                        } else {
                                                register_drq_event(1);
                                        }
+                                       if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
                                }
                                status &= ~FDC_ST_DRQ;
                        } else if(cmdtype == FDC_CMD_WR_TRK) {
@@ -258,7 +434,7 @@ void MB8877::write_io8(uint32 addr, uint32 data)
                                                        if(!fdc[drvreg].id_written) {
                                                                // insert new sector with data crc error
 write_id:
-                                                               uint8 c = 0, h = 0, r = 0, n = 0;
+                                                               uint8_t c = 0, h = 0, r = 0, n = 0;
                                                                fdc[drvreg].id_written = true;
                                                                fdc[drvreg].sector_found = false;
                                                                if(fdc[drvreg].index >= 4) {
@@ -321,6 +497,7 @@ write_id:
                                        } else {
                                                register_drq_event(1);
                                        }
+                                       if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
                                }
                                status &= ~FDC_ST_DRQ;
                        }
@@ -334,9 +511,11 @@ write_id:
        }
 }
 
-uint32 MB8877::read_io8(uint32 addr)
+uint32_t MB8877::read_io8(uint32_t addr)
 {
-       uint32 val;
+       uint32_t val;
+       bool not_ready = false;
+       bool ready;
        
        switch(addr & 3) {
        case 0:
@@ -346,7 +525,19 @@ uint32 MB8877::read_io8(uint32 addr)
                        val = FDC_ST_BUSY;
                } else {
                        // disk not inserted, motor stop
-                       if(!disk[drvreg]->inserted || !motor_on) {
+                       not_ready = !disk[drvreg]->inserted;
+//#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
+                       if(type_fm7){
+                               if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
+                                       if(!motor_on) not_ready = true;
+                               }
+                       } else
+//#endif
+                       {
+                               if(!motor_on) not_ready = true;
+                       }
+//                     if(!disk[drvreg]->inserted || !motor_on) {
+                       if(not_ready) {
                                status |= FDC_ST_NOTREADY;
                        } else {
                                status &= ~FDC_ST_NOTREADY;
@@ -379,11 +570,23 @@ uint32 MB8877::read_io8(uint32 addr)
                        val = status;
                        if(cmdtype == FDC_CMD_TYPE1 && !now_seek) {
                                status &= ~FDC_ST_BUSY;
-#ifdef MB8877_NO_BUSY_AFTER_SEEK
-                               val &= ~FDC_ST_BUSY;
-#endif
+//#ifdef MB8877_NO_BUSY_AFTER_SEEK
+                               if(mb8877_no_busy_after_seek) {
+                                       //#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
+                                       if(type_fm7) {
+                                               if(disk[0]->is_special_disk != SPECIAL_DISK_FM7_XANADU2_D) {
+                                                       val &= ~FDC_ST_BUSY;
+                                               }
+                                       } else
+                                               //#endif
+                                       {
+                                               val &= ~FDC_ST_BUSY;
+                                       }
+                               }
+//#endif
                        }
                }
+
                if(cmdtype == 0 && !(status & FDC_ST_NOTREADY)) {
                        // MZ-2000 HuBASIC invites NOT READY status
                        if(++no_command == 16) {
@@ -392,6 +595,7 @@ uint32 MB8877::read_io8(uint32 addr)
                } else {
                        no_command = 0;
                }
+
                // reset irq/drq
                if(!(status & FDC_ST_DRQ)) {
                        set_drq(false);
@@ -399,66 +603,97 @@ uint32 MB8877::read_io8(uint32 addr)
                if(!(status & FDC_ST_BUSY)) {
                        set_irq(false);
                }
-#ifdef _FDC_DEBUG_LOG
-               emu->out_debug_log(_T("FDC\tSTATUS=%2x\n"), val);
-#endif
-#if defined(HAS_MB8866) || defined(HAS_MB8876)
-               return (~val) & 0xff;
-#else
-               return val;
-#endif
+//#ifdef _FDC_DEBUG_LOG
+               if(fdc_debug_log) this->out_debug_log(_T("FDC\tSTATUS=%2x\n"), val);
+//#endif
+//#if defined(HAS_MB8866) || defined(HAS_MB8876)
+                       if(invert_registers) {
+                               return (~val) & 0xff;
+//#else
+                       } else {
+                               return val;
+                       }
+//#endif
        case 1:
                // track reg
-#if defined(HAS_MB8866) || defined(HAS_MB8876)
-               return (~trkreg) & 0xff;
-#else
-               return trkreg;
-#endif
+//#if defined(HAS_MB8866) || defined(HAS_MB8876)
+                       if(invert_registers) {
+                               return (~trkreg) & 0xff;
+                       } else {
+//#else
+                               return trkreg;
+                       }
+//#endif
        case 2:
                // sector reg
-#if defined(HAS_MB8866) || defined(HAS_MB8876)
-               return (~secreg) & 0xff;
-#else
-               return secreg;
-#endif
+//#if defined(HAS_MB8866) || defined(HAS_MB8876)
+                       if(invert_registers) {
+                               return (~secreg) & 0xff;
+                       } else {
+//#else
+                               return secreg;
+                       }
+//#endif
        case 3:
                // data reg
-               if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
+               ready = ((status & FDC_ST_DRQ) && !now_search);
+//#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
+               if(type_fm7) {
+                       if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
+                               if(!motor_on) ready = false;
+                       }
+                       if(!fdc[drvreg].head_load) ready = false;
+               } else
+//#endif
+               {
+                       if(!motor_on) ready = false;
+                       if(!fdc[drvreg].head_load) ready = false;
+               }
+//             if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
+               if(ready) {
                        if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC) {
                                // read or multisector read
                                if(fdc[drvreg].index < disk[drvreg]->sector_size.sd) {
                                        datareg = disk[drvreg]->sector[fdc[drvreg].index];
-                                       //fdc[drvreg].index++;
                                }
-                               if((fdc[drvreg].index + 1) >= disk[drvreg]->sector_size.sd) {
+                               if((fdc[drvreg].index + 1) >= disk[drvreg]->sector_size.sd) {  // Reading complete this sector.
 
                                        if(disk[drvreg]->data_crc_error && !disk[drvreg]->ignore_crc()) {
                                                // data crc error
-#ifdef _FDC_DEBUG_LOG
-                                               emu->out_debug_log(_T("FDC\tEND OF SECTOR (DATA CRC ERROR)\n"));
-#endif
+#if 0
+//#ifdef _FDC_DEBUG_LOG
+                                               if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR (DATA CRC ERROR)\n"));
+//#endif
                                                status |= FDC_ST_CRCERR;
                                                status &= ~FDC_ST_BUSY;
                                                cmdtype = 0;
                                                set_irq(true);
+#else
+                                               register_my_event_with_check(EVENT_CRC_ERROR, disk[drvreg]->get_usec_per_bytes(3));
+#endif
                                        } else if(cmdtype == FDC_CMD_RD_SEC) {
                                                // single sector
-#ifdef _FDC_DEBUG_LOG
-                                               emu->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
-#endif
+#if 0
+//#ifdef _FDC_DEBUG_LOG
+                                               if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
+//#endif
                                                status &= ~FDC_ST_BUSY;
                                                cmdtype = 0;
                                                set_irq(true);
+#else
+                                               register_my_event_with_check(EVENT_END_READ_SECTOR, disk[drvreg]->get_usec_per_bytes(3));
+#endif
                                        } else {
                                                // multisector
-#ifdef _FDC_DEBUG_LOG
-                                               emu->out_debug_log(_T("FDC\tEND OF SECTOR (SEARCH NEXT)\n"));
-#endif
+//#ifdef _FDC_DEBUG_LOG
+                                               if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR (SEARCH NEXT)\n"));
+//#endif
                                                register_my_event(EVENT_MULTI1, 30);
                                                register_my_event(EVENT_MULTI2, 60);
                                        }
-                               } else {
+                               } else { // Still data remain.
                                        register_drq_event(1);
+                                       if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
                                }
                                status &= ~FDC_ST_DRQ;
                        } else if(cmdtype == FDC_CMD_RD_ADDR) {
@@ -475,11 +710,12 @@ uint32 MB8877::read_io8(uint32 addr)
                                        status &= ~FDC_ST_BUSY;
                                        cmdtype = 0;
                                        set_irq(true);
-#ifdef _FDC_DEBUG_LOG
-                                       emu->out_debug_log(_T("FDC\tEND OF ID FIELD\n"));
-#endif
+//#ifdef _FDC_DEBUG_LOG
+                                       if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF ID FIELD\n"));
+//#endif
                                } else {
                                        register_drq_event(1);
+                                       if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
                                }
                                status &= ~FDC_ST_DRQ;
                        } else if(cmdtype == FDC_CMD_RD_TRK) {
@@ -489,15 +725,16 @@ uint32 MB8877::read_io8(uint32 addr)
                                        //fdc[drvreg].index++;
                                }
                                if((fdc[drvreg].index + 1) >= disk[drvreg]->get_track_size()) {
-#ifdef _FDC_DEBUG_LOG
-                                       emu->out_debug_log(_T("FDC\tEND OF TRACK\n"));
-#endif
+//#ifdef _FDC_DEBUG_LOG
+                                       if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF TRACK\n"));
+///#endif
                                        status &= ~FDC_ST_BUSY;
                                        status |= FDC_ST_LOSTDATA;
                                        cmdtype = 0;
                                        set_irq(true);
                                } else {
                                        register_drq_event(1);
+                                       if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
                                }
                                status &= ~FDC_ST_DRQ;
                        }
@@ -507,46 +744,57 @@ uint32 MB8877::read_io8(uint32 addr)
                                fdc[drvreg].access = true;
                        }
                }
-#ifdef _FDC_DEBUG_LOG
-               emu->out_debug_log(_T("FDC\tDATA=%2x\n"), datareg);
-#endif
-#if defined(HAS_MB8866) || defined(HAS_MB8876)
-               return (~datareg) & 0xff;
-#else
-               return datareg;
-#endif
+//#ifdef _FDC_DEBUG_LOG
+               if(fdc_debug_log) this->force_out_debug_log(_T("FDC\tDATA=%2x\n"), datareg); // emu->force_out_debug_log()
+//#endif
+//#if defined(HAS_MB8866) || defined(HAS_MB8876)
+               if(invert_registers) {
+                       return (~datareg) & 0xff;
+               } else {
+//#else
+                       return datareg;
+               }
+//#endif
        }
        return 0xff;
 }
 
-void MB8877::write_dma_io8(uint32 addr, uint32 data)
+void MB8877::write_dma_io8(uint32_t addr, uint32_t data)
 {
        write_io8(3, data);
 }
 
-uint32 MB8877::read_dma_io8(uint32 addr)
+uint32_t MB8877::read_dma_io8(uint32_t addr)
 {
        return read_io8(3);
 }
 
-void MB8877::write_signal(int id, uint32 data, uint32 mask)
+void MB8877::write_signal(int id, uint32_t data, uint32_t mask)
 {
        if(id == SIG_MB8877_DRIVEREG) {
-               drvreg = data & DRIVE_MASK;
+               drvreg = data & _drive_mask;
                drive_sel = true;
-               seekend_clock = current_clock();
+               seekend_clock = get_current_clock();
        } else if(id == SIG_MB8877_SIDEREG) {
                sidereg = (data & mask) ? 1 : 0;
        } else if(id == SIG_MB8877_MOTOR) {
                motor_on = ((data & mask) != 0);
-       }
+       } 
 }
 
-uint32 MB8877::read_signal(int ch)
+uint32_t MB8877::read_signal(int ch)
 {
+       if(ch == SIG_MB8877_DRIVEREG) {
+               return drvreg & _drive_mask;
+       } else if(ch == SIG_MB8877_SIDEREG) {
+               return sidereg & 1;
+       } else if(ch == SIG_MB8877_MOTOR) {
+               return motor_on ? 1 : 0;
+       }
+       
        // get access status
-       uint32 stat = 0;
-       for(int i = 0; i < MAX_DRIVE; i++) {
+       uint32_t stat = 0;
+       for(int i = 0; i < _max_drive; i++) {
                if(fdc[i].access) {
                        stat |= 1 << i;
                }
@@ -562,11 +810,12 @@ void MB8877::event_callback(int event_id, int err)
 {
        int event = event_id >> 8;
        int cmd = event_id & 0xff;
+       //bool need_after_irq = false;
        register_id[event] = -1;
        
        // cancel event if the command is finished or other command is executed
        if(cmd != cmdtype) {
-               if(event == EVENT_SEEK || event == EVENT_SEEKEND) {
+               if(event == EVENT_SEEK || event == EVENT_SEEKEND_VERIFY) {
                        now_seek = false;
                } else if(event == EVENT_SEARCH) {
                        now_search = false;
@@ -576,65 +825,118 @@ void MB8877::event_callback(int event_id, int err)
        
        switch(event) {
        case EVENT_SEEK:
-#ifdef _FDC_DEBUG_LOG
-               //emu->out_debug_log(_T("FDC\tSEEK START\n"));
-#endif
+//#ifdef _FDC_DEBUG_LOG
+               //this->out_debug_log(_T("FDC\tSEEK START\n"));
+//#endif
                if(seektrk > fdc[drvreg].track) {
                        fdc[drvreg].track++;
+                       if(d_noise_seek != NULL) d_noise_seek->play();
+                       //need_after_irq = true;
                } else if(seektrk < fdc[drvreg].track) {
                        fdc[drvreg].track--;
+                       if(d_noise_seek != NULL) d_noise_seek->play();
+                       //need_after_irq = true;
                }
-               if((cmdreg & 0x10) || ((cmdreg & 0xf0) == 0)) {
+               // Not update track register if "SEEK" command.Thanks to Haserin. 20180224 K.O.
+               if((((cmdreg & 0x10) != 0) && (cmdreg >= 0x20)) || ((cmdreg & 0xf0) == 0)) {
                        trkreg = fdc[drvreg].track;
                }
-               //emu->out_debug_log(_T("Track %d\n"), trkreg);
-               if(seektrk != fdc[drvreg].track) {
+               if((uint8_t)seektrk != (uint8_t)fdc[drvreg].track) {
+                       //if(need_after_irq) {
+                               //set_drq(false);
+                               //set_irq(true);  // 20180118 K.O Turn ON IRQ -> Turn OFF DRQ
+                       //}
                        register_seek_event();
                        break;
                }
-               seekend_clock = current_clock();
+#if 1
+               // Verify before execute command.
+               // Port from XM7.Thanks to Ryu Takegami.
+               if(cmdreg & 4) {
+               // verify
+                       if(trkreg != fdc[drvreg].track) {
+                               status |= FDC_ST_SEEKERR;
+                               trkreg = fdc[drvreg].track; // Reload track register when verify: Really OK? 20180224 K.O
+                       }
+               }
+#endif
+               seekend_clock = get_current_clock();
+//#ifdef HAS_MB89311
+               if(type_mb89311) {
+                       if(extended_mode) {
+                               if((cmdreg & 0xf4) == 0x44) {
+                                       // read-after-seek
+                                       cmd_readdata(true);
+                                       break;
+                               } else if((cmdreg & 0xf4) == 0x64) {
+                                       // write-after-seek
+                                       cmd_writedata(true);
+                                       break;
+                               }
+                       }
+               }
+//#endif
                status_tmp = status;
                if(cmdreg & 4) {
                        // verify
                        status_tmp |= search_track();
                        double time;
+#if 0                  
                        if(status_tmp & FDC_ST_SEEKERR) {
                                time = get_usec_to_detect_index_hole(5, true);
                        } else {
                                time = get_usec_to_next_trans_pos(true);
                        }
-                       register_my_event(EVENT_SEEKEND, time);
+#else
+                       // Verify wait is shorter than above at least FM-7 series's MB8877. 20180223 K.O.
+                       // Thanks to Ryu Takegami.
+                       time = (disk[drvreg]->drive_type == DRIVE_TYPE_2HD) ? 10000.0 : 20000.0;
+#endif
+                       // 20180128 K.O If seek completed, delay to make IRQ/DRQ at SEEKEND_VERIFY.
+                       register_my_event(EVENT_SEEKEND_VERIFY, time);
                        break;
                }
-       case EVENT_SEEKEND:
+//     case EVENT_SEEKEND: // Separate SEEK and SEEKEND when verifying. 20180128 K.O
                now_seek = false;
                status = status_tmp;
-               set_irq(true);
-#ifdef _FDC_DEBUG_LOG
-               //emu->out_debug_log(_T("FDC\tSEEK END\n"));
-#endif
+               status &= (uint8_t)(~FDC_ST_BUSY);      // 20180118 K.O Turn off BUSY flag.
+               set_drq(false);
+               set_irq(true);  // 20180118 K.O Turn ON IRQ -> Turn OFF DRQ
+               break;
+       case EVENT_SEEKEND_VERIFY: // Separate SEEK and SEEKEND when verifying. 20180128 K.O
+               now_seek = false;
+               status &= (uint8_t)(~FDC_ST_BUSY);      // 20180118 K.O Turn off BUSY flag.
+               set_drq(false);
+               set_irq(true);  // 20180118 K.O Turn ON IRQ -> Turn OFF DRQ
+//#ifdef _FDC_DEBUG_LOG
+               //this->out_debug_log(_T("FDC\tSEEK END\n"));
+//#endif
                break;
        case EVENT_SEARCH:
                now_search = false;
                if(status_tmp & FDC_ST_RECNFND) {
-#if defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
-                       // for SHARP X1 Batten Tanuki
-                       if(disk[drvreg]->is_special_disk == SPECIAL_DISK_X1_BATTEN && drive_sel) {
-                               status_tmp &= ~FDC_ST_RECNFND;
+//#if defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
+                       if(type_x1) {
+                               // for SHARP X1 Batten Tanuki
+                               if(disk[drvreg]->is_special_disk == SPECIAL_DISK_X1_BATTEN && drive_sel) {
+                                       status_tmp &= ~FDC_ST_RECNFND;
+                               }
                        }
-#endif
-#ifdef _FDC_DEBUG_LOG
-                       emu->out_debug_log(_T("FDC\tSEARCH NG\n"));
-#endif
+//#endif
+//#ifdef _FDC_DEBUG_LOG
+                       if(fdc_debug_log) this->out_debug_log(_T("FDC\tSEARCH NG\n"));
+//#endif
                        status = status_tmp & ~(FDC_ST_BUSY | FDC_ST_DRQ);
                        cmdtype = 0;
+                       set_drq(false);
                        set_irq(true);
                } else if(status_tmp & FDC_ST_WRITEFAULT) {
-#ifdef _FDC_DEBUG_LOG
-                       emu->out_debug_log(_T("FDC\tWRITE PROTECTED\n"));
-#endif
+//#ifdef _FDC_DEBUG_LOG
+                               if(fdc_debug_log) this->out_debug_log(_T("FDC\tWRITE PROTECTED\n"));
+//#endif
                        status = status_tmp & ~(FDC_ST_BUSY | FDC_ST_DRQ);
                        cmdtype = 0;
+                       set_drq(false);
                        set_irq(true);
                } else {
                        status = status_tmp | (FDC_ST_BUSY | FDC_ST_DRQ);
@@ -646,12 +948,13 @@ void MB8877::event_callback(int event_id, int err)
                                register_lost_event(1);
                        }
                        fdc[drvreg].cur_position = fdc[drvreg].next_trans_position;
-                       fdc[drvreg].prev_clock = prev_drq_clock = current_clock();
+                       fdc[drvreg].prev_clock = prev_drq_clock = get_current_clock();
                        set_drq(true);
                        drive_sel = false;
-#ifdef _FDC_DEBUG_LOG
-                       emu->out_debug_log(_T("FDC\tSEARCH OK\n"));
-#endif
+                       if(fdc_debug_log) this->out_debug_log("DRQ ON@SEARCH: %d\n", prev_drq_clock);
+//#ifdef _FDC_DEBUG_LOG
+                       if(fdc_debug_log) this->out_debug_log(_T("FDC\tSEARCH OK\n"));
+//#endif
                }
                break;
        case EVENT_DRQ:
@@ -667,13 +970,15 @@ void MB8877::event_callback(int event_id, int err)
                           cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC ||
                           cmdtype == FDC_CMD_RD_TRK || cmdtype == FDC_CMD_WR_TRK  ||
                           cmdtype == FDC_CMD_RD_ADDR) {
-                               fdc[drvreg].index++;
+                               if(!(fdc[drvreg].count_immediate)) fdc[drvreg].index++;
                        }
-                       fdc[drvreg].prev_clock = prev_drq_clock = current_clock();
+                       fdc[drvreg].prev_clock = prev_drq_clock = get_current_clock();
+
                        set_drq(true);
-#ifdef _FDC_DEBUG_LOG
-                       //emu->out_debug_log(_T("FDC\tDRQ!\n"));
-#endif
+                       if(fdc_debug_log) this->out_debug_log("DRQ ON@DRQ: %d\n", prev_drq_clock);
+//#ifdef _FDC_DEBUG_LOG
+                       //this->out_debug_log(_T("FDC\tDRQ!\n"));
+//#endif
                }
                break;
        case EVENT_MULTI1:
@@ -686,22 +991,54 @@ void MB8877::event_callback(int event_id, int err)
                        cmd_writedata(false);
                }
                break;
+       case EVENT_CRC_ERROR:
+               //#ifdef _FDC_DEBUG_LOG
+               if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR (DATA CRC ERROR)\n"));
+//#endif
+               status |= FDC_ST_CRCERR;
+               status &= ~FDC_ST_BUSY;
+               cmdtype = 0;
+               set_irq(true);
+               break;
+       case EVENT_END_READ_SECTOR:
+//#ifdef _FDC_DEBUG_LOG
+               if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
+//#endif
+               status &= ~FDC_ST_BUSY;
+               cmdtype = 0;
+               set_irq(true);
+               break;
        case EVENT_LOST:
                if(status & FDC_ST_BUSY) {
-#ifdef _FDC_DEBUG_LOG
-                       emu->out_debug_log("FDC\tDATA LOST\n");
-#endif
+//#ifdef _FDC_DEBUG_LOG
+                       if(fdc_debug_log) this->out_debug_log(_T("FDC\tDATA LOST\n"));
+//#endif
                        if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) {
-                               if(fdc[drvreg].index == 0) {
-                                       status &= ~FDC_ST_BUSY;
-                                       //status &= ~FDC_ST_DRQ;
+                               if(fdc[drvreg].index == 0) { // HEAD of REGION
                                        cmdtype = 0;
-                                       set_irq(true);
-                                       //set_drq(false);
-                               } else {
+                                       //if((status & FDC_ST_DRQ) != 0) { // 20180130 FORCE DOWN DRQ ON LOST-DATA.
+                                               status |= FDC_ST_LOSTDATA;
+                                               status &= (uint8_t)(~(FDC_ST_DRQ | FDC_ST_BUSY));
+                                               set_drq(false);
+                                               //}
+                                               set_irq(true);
+                               } else { // STILL WRITING
                                        write_io8(3, 0x00);
+                                       //if((status & FDC_ST_DRQ) != 0) {
+                                               status |= FDC_ST_LOSTDATA;
+                                               status &= (uint8_t)(~(FDC_ST_DRQ | FDC_ST_BUSY));
+                                               set_irq(true);
+                                               set_drq(false);
+                                               //cmdtype = 0;
+                                               //}
                                }
-                       } else {
+                       } else { // READ 
+                               //if((status & FDC_ST_DRQ) != 0) {
+                                       status |= FDC_ST_LOSTDATA;
+                                       status &= (uint8_t)(~(FDC_ST_DRQ | FDC_ST_BUSY));
+                                       set_irq(true);
+                                       set_drq(false);
+                                       //}
                                read_io8(3);
                        }
                        status |= FDC_ST_LOSTDATA;
@@ -714,62 +1051,148 @@ void MB8877::event_callback(int event_id, int err)
 // command
 // ----------------------------------------------------------------------------
 
+
 void MB8877::process_cmd()
 {
-#ifdef _FDC_DEBUG_LOG
-       static const _TCHAR *cmdstr[0x10] = {
-               _T("RESTORE "), _T("SEEK    "), _T("STEP    "), _T("STEP    "),
-               _T("STEP IN "), _T("STEP IN "), _T("STEP OUT"), _T("STEP OUT"),
-               _T("RD DATA "), _T("RD DATA "), _T("RD DATA "), _T("WR DATA "),
-               _T("RD ADDR "), _T("FORCEINT"), _T("RD TRACK"), _T("WR TRACK")
-       };
-       emu->out_debug_log(_T("FDC\tCMD=%2xh (%s) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, cmdstr[cmdreg >> 4], datareg, drvreg, trkreg, sidereg, secreg);
-#endif
        set_irq(false);
+       set_drq(false);
+       
+//#ifdef HAS_MB89311
+       // MB89311 mode commands
+       if(type_mb89311) {
+                               if(cmdreg == 0xfc) {
+                               // delay (may be only in extended mode)
+//#ifdef _FDC_DEBUG_LOG
+                               if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (DELAY   ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
+//#endif
+                               cmdtype = status = 0;
+                               return;
+                       } else if(cmdreg == 0xfd) {
+                               // assign parameter
+//#ifdef _FDC_DEBUG_LOG
+                               if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (ASGN PAR) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
+//#endif
+                               cmdtype = status = 0;
+                               return;
+                       } else if(cmdreg == 0xfe) {
+                               // assign mode
+//#ifdef _FDC_DEBUG_LOG
+                               if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (ASGN MOD) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
+//#endif
+                               extended_mode = !extended_mode;
+                               cmdtype = status = 0;
+                               return;
+                       } else if(cmdreg == 0xff) {
+                               // reset (may be only in extended mode)
+//#ifdef _FDC_DEBUG_LOG
+                               if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (RESET   ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
+//#endif
+                               cmd_forceint();
+                               extended_mode = true;
+                               return;
+                       } else if(extended_mode) {
+                               // type-1
+                               if((cmdreg & 0xeb) == 0x21) {
+//#ifdef _FDC_DEBUG_LOG
+                               if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (STEP IN ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
+//#endif
+                               cmd_stepin();
+                               return;
+                       } else if((cmdreg & 0xeb) == 0x22) {
+//#ifdef _FDC_DEBUG_LOG
+                               if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (STEP OUT) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
+//#endif
+                               cmd_stepout();
+                               return;
+                               // type-2
+                       } else if((cmdreg & 0xf4) == 0x44) {
+                               // read-after-seek
+//#ifdef _FDC_DEBUG_LOG
+                                       if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (RDaftSEK) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
+//#endif
+                                       cmd_seek();
+                                       return;
+                               } else if((cmdreg & 0xf4) == 0x64) {
+                                       // write-after-seek
+//#ifdef _FDC_DEBUG_LOG
+                               if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (WRaftSEK) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
+//#endif
+                               cmd_seek();
+                       return;
+                       // type-3
+                       } else if((cmdreg & 0xfb) == 0xf1) {
+                                       // format
+//#ifdef _FDC_DEBUG_LOG
+                               if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (FORMAT  ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
+//#endif
+                               cmd_format();
+                               return;
+                               }
+                               }
+       }
+//#endif
        
-       switch(cmdreg & 0xf0) {
+       // MB8877 mode commands
+       if(fdc_debug_log) {
+               _TCHAR tmps[512];
+               memset(tmps, 0x00, sizeof(tmps));
+               get_debug_regs_info(tmps, sizeof(tmps));
+               if(fdc_debug_log) this->out_debug_log(_T("%s"), tmps);
+       }
+       switch(cmdreg & 0xf8) {
        // type-1
-       case 0x00:
+       case 0x00: case 0x08:
                cmd_restore();
+               update_head_flag(drvreg, (cmdreg & 8) != 0);
                break;
-       case 0x10:
+       case 0x10: case 0x18:
                cmd_seek();
+               update_head_flag(drvreg, (cmdreg & 8) != 0);
                break;
-       case 0x20:
-       case 0x30:
+       case 0x20: case 0x28:
+       case 0x30: case 0x38:
                cmd_step();
+               update_head_flag(drvreg, (cmdreg & 8) != 0);
                break;
-       case 0x40:
-       case 0x50:
+       case 0x40: case 0x48:
+       case 0x50: case 0x58:
                cmd_stepin();
+               update_head_flag(drvreg, (cmdreg & 8) != 0);
                break;
-       case 0x60:
-       case 0x70:
+       case 0x60: case 0x68:
+       case 0x70: case 0x78:
                cmd_stepout();
+               update_head_flag(drvreg, (cmdreg & 8) != 0);
                break;
        // type-2
-       case 0x80:
-       case 0x90:
+       case 0x80: case 0x88:
+       case 0x90: case 0x98:
                cmd_readdata(true);
+               update_head_flag(drvreg, true);
                break;
-       case 0xa0:
-       case 0xb0:
+       case 0xa0:case 0xa8:
+       case 0xb0: case 0xb8:
                cmd_writedata(true);
+               update_head_flag(drvreg, true);
                break;
        // type-3
        case 0xc0:
                cmd_readaddr();
+               update_head_flag(drvreg, true);
                break;
        case 0xe0:
                cmd_readtrack();
+               update_head_flag(drvreg, true);
                break;
        case 0xf0:
                cmd_writetrack();
+               update_head_flag(drvreg, true);
                break;
        // type-4
-       case 0xd0:
+       case 0xd0: case 0xd8:
                cmd_forceint();
                break;
+       // unknown command
        default:
                break;
        }
@@ -779,8 +1202,26 @@ void MB8877::cmd_restore()
 {
        // type-1 restore
        cmdtype = FDC_CMD_TYPE1;
-       status = FDC_ST_HEADENG | FDC_ST_BUSY;
-       trkreg = 0xff;
+       if(!check_drive()) {
+               return;
+       }
+       if((cmdreg & 0x08) != 0) { // Head engage
+               status = FDC_ST_HEADENG | FDC_ST_BUSY;
+       } else {
+               status = FDC_ST_BUSY;
+       }
+       set_irq(false);
+       set_drq(false);
+
+       if(fdc[drvreg].track < 0) {
+               fdc[drvreg].track = 0;
+               trkreg = 0;
+       } else if(fdc[drvreg].track >= 80) {
+               fdc[drvreg].track = 80;
+               trkreg = 80;
+       } else {
+               trkreg = fdc[drvreg].track;
+       }
        datareg = 0;
        
        seektrk = 0;
@@ -793,13 +1234,30 @@ void MB8877::cmd_seek()
 {
        // type-1 seek
        cmdtype = FDC_CMD_TYPE1;
-       status = FDC_ST_HEADENG | FDC_ST_BUSY;
-       
-//     seektrk = (uint8)(fdc[drvreg].track + datareg - trkreg);
-       seektrk = datareg;
-       seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
-       seekvct = !(datareg > trkreg);
+       if(!check_drive()) {
+               return;
+       }
+       if((cmdreg & 0x08) != 0) { // Head engage
+               status = FDC_ST_HEADENG | FDC_ST_BUSY;
+       } else {
+               status = FDC_ST_BUSY;
+       }               
+
+       // revert below 20180225 K.O
+       //seektrk = (uint8_t)(fdc[drvreg].track + datareg - trkreg); // Seek target is differ when drive's track != trkreg.Thanks to Haserin and Ryu Takegami.
+       seektrk = (int)((int8_t)datareg);
+//#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
+       if(seektrk >= disk[drvreg]->get_max_tracks()) {
+               seektrk = disk[drvreg]->get_max_tracks() - 1;
+       } else if(seektrk < 0) {
+               seektrk = 0;
+       }
 
+       seekvct = !(seektrk > fdc[drvreg].track);
+       // Update track register by data register.Thanks to Ryu Takegami. 20180224 K.O
+       trkreg = datareg;
+       set_irq(false);
+       set_drq(false);
        register_seek_event();
 }
 
@@ -817,12 +1275,35 @@ void MB8877::cmd_stepin()
 {
        // type-1 step in
        cmdtype = FDC_CMD_TYPE1;
-       status = FDC_ST_HEADENG | FDC_ST_BUSY;
-       
+       if(!check_drive()) {
+               return;
+       }
+       if((cmdreg & 0x08) != 0) { // Head engage
+               status = FDC_ST_HEADENG | FDC_ST_BUSY;
+       } else {
+               status = FDC_ST_BUSY;
+       }
+
+       // Verify before execute command.
+       // Port from XM7.Thanks to Ryu Takegami.
+#if 1
+       if(cmdreg & 4) {
+               // verify
+               if(trkreg != fdc[drvreg].track) {
+                       status |= FDC_ST_SEEKERR;
+//                     trkreg = fdc[drvreg].track;
+               }
+       }
+#endif
        seektrk = fdc[drvreg].track + 1;
-       seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
+       if(seektrk >= disk[drvreg]->get_max_tracks()) {
+               seektrk = disk[drvreg]->get_max_tracks() - 1;
+       } else if(seektrk < 0) {
+               seektrk = 0;
+       }
        seekvct = false;
-       
+       set_irq(false);
+       set_drq(false);
        register_seek_event();
 }
 
@@ -830,12 +1311,33 @@ void MB8877::cmd_stepout()
 {
        // type-1 step out
        cmdtype = FDC_CMD_TYPE1;
-       status = FDC_ST_HEADENG | FDC_ST_BUSY;
-       
+       if(!check_drive()) {
+               return;
+       }
+       if((cmdreg & 0x08) != 0) { // Head engage
+               status = FDC_ST_HEADENG | FDC_ST_BUSY;
+       } else {
+               status = FDC_ST_BUSY;
+       }
+
+       // Verify before execute command.
+       // Port from XM7.Thanks to Ryu Takegami.
+#if 1
+       if(cmdreg & 4) {
+               // verify
+               if(trkreg != fdc[drvreg].track) {
+                       status |= FDC_ST_SEEKERR;
+//                     trkreg = fdc[drvreg].track;
+               }
+       }
+#endif
        seektrk = fdc[drvreg].track - 1;
-       seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
+       if(seektrk >= disk[drvreg]->get_max_tracks()) {
+               seektrk = disk[drvreg]->get_max_tracks() - 1;
+       } else if(seektrk < 0) {
+               seektrk = 0;
+       }
        seekvct = true;
-       
        register_seek_event();
 }
 
@@ -843,6 +1345,9 @@ void MB8877::cmd_readdata(bool first_sector)
 {
        // type-2 read data
        cmdtype = (cmdreg & 0x10) ? FDC_CMD_RD_MSEC : FDC_CMD_RD_SEC;
+       if(!check_drive2()) {
+               return;
+       }
        status = FDC_ST_BUSY;
        status_tmp = search_sector();
        now_search = true;
@@ -861,6 +1366,9 @@ void MB8877::cmd_writedata(bool first_sector)
 {
        // type-2 write data
        cmdtype = (cmdreg & 0x10) ? FDC_CMD_WR_MSEC : FDC_CMD_WR_SEC;
+       if(!check_drive2()) {
+               return;
+       }
        status = FDC_ST_BUSY;
        status_tmp = search_sector() & ~FDC_ST_RECTYPE;
        now_search = true;
@@ -882,6 +1390,9 @@ void MB8877::cmd_readaddr()
 {
        // type-3 read address
        cmdtype = FDC_CMD_RD_ADDR;
+       if(!check_drive2()) {
+               return;
+       }
        status = FDC_ST_BUSY;
        status_tmp = search_addr();
        now_search = true;
@@ -900,6 +1411,9 @@ void MB8877::cmd_readtrack()
 {
        // type-3 read track
        cmdtype = FDC_CMD_RD_TRK;
+       if(!check_drive2()) {
+               return;
+       }
        status = FDC_ST_BUSY;
        status_tmp = 0;
        
@@ -917,6 +1431,9 @@ void MB8877::cmd_writetrack()
 {
        // type-3 write track
        cmdtype = FDC_CMD_WR_TRK;
+       if(!check_drive2()) {
+               return;
+       }
        status = FDC_ST_BUSY;
        status_tmp = 0;
        
@@ -948,18 +1465,49 @@ void MB8877::cmd_writetrack()
        cancel_my_event(EVENT_LOST);
 }
 
+//#ifdef HAS_MB89311
+void MB8877::cmd_format()
+{
+       if(type_mb89311) {
+               // type-3 format (FIXME: need to implement)
+               cmdtype = FDC_CMD_WR_TRK;
+               status = FDC_ST_BUSY;
+               status_tmp = 0;
+               
+               fdc[drvreg].index = 0;
+               fdc[drvreg].id_written = false;
+               now_search = true;
+               
+               status_tmp = FDC_ST_WRITEFAULT;
+               double time = (cmdreg & 4) ? DELAY_TIME : 1;
+               
+               register_my_event(EVENT_SEARCH, time);
+               cancel_my_event(EVENT_LOST);
+       }
+}
+//#endif
+
 void MB8877::cmd_forceint()
 {
        // type-4 force interrupt
+       bool ready = (cmdtype == 0);
+       bool is_busy = ((status & FDC_ST_BUSY) != 0);
+       bool now_seek_bak = now_seek;
+       bool is_type1 = (cmdtype == FDC_CMD_TYPE1);
+       bool is_read = ((cmdtype == FDC_CMD_RD_SEC) || (cmdtype == FDC_CMD_RD_MSEC) || \
+                                 (cmdtype == FDC_CMD_RD_ADDR) || (cmdtype == FDC_CMD_RD_TRK));
+       bool is_trkwrite = (cmdtype == FDC_CMD_WR_TRK);
+       
        if(cmdtype == FDC_CMD_TYPE1) {
                // abort restore/seek/step command
                if(now_seek) {
                        if(seektrk > fdc[drvreg].track) {
-                               fdc[drvreg].track++;
+                               if((fdc[drvreg].track < 0xff) && (fdc[drvreg].track >= 0)) fdc[drvreg].track++;
                        } else if(seektrk < fdc[drvreg].track) {
-                               fdc[drvreg].track--;
+                               if((fdc[drvreg].track <= 0xff) && (fdc[drvreg].track > 0)) fdc[drvreg].track--;
                        }
-                       if((cmdreg_tmp & 0x10) || ((cmdreg_tmp & 0xf0) == 0)) {
+                       // Not update track register if "SEEK" command.Thanks to Haserin. 20180224 K.O.
+                       if((((cmdreg_tmp & 0x10) != 0) && (cmdreg_tmp >= 0x20)) || ((cmdreg_tmp & 0xf0) == 0)) {
                                trkreg = fdc[drvreg].track;
                        }
                }
@@ -980,19 +1528,43 @@ void MB8877::cmd_forceint()
        }
        now_search = now_seek = sector_changed = false;
        
-       if(cmdtype == 0 || !(status & FDC_ST_BUSY)) {
+//#ifdef HAS_MB89311
+       if((cmdreg == 0xff) && (type_mb89311)) {
+               // reset command
                cmdtype = FDC_CMD_TYPE1;
                status = FDC_ST_HEADENG;
+       } else {
+//#endif
+               if(cmdtype == 0 || !(status & FDC_ST_BUSY)) {
+                       cmdtype = FDC_CMD_TYPE1;
+                   if(!type_fm7) status = FDC_ST_HEADENG; // Hack for FUKUALL.d77 .
+               }
+               status &= ~FDC_ST_BUSY;
+               if((now_seek_bak) || (ready)) {// Refer from XM7, is this write implement? 20180210 K.O
+                       status = 0;
+                       if(((ready) || !(is_busy)) && (!type_fm7)) status = FDC_ST_HEADENG;
+                       // indexcount = 0;
+                       if(check_drive2()) {
+                               if(!(is_read) && (disk[drvreg]->write_protected)) status |= FDC_ST_WRITEP;
+                               if((is_trkwrite) && (disk[drvreg]->write_protected)) status |= FDC_ST_WRITEFAULT;
+                               if(is_type1) {
+                                       if(fdc[drvreg].track == 0) status |= FDC_ST_TRACK00;
+                                       if(get_cur_position() < disk[drvreg]->get_bytes_per_usec(5000)) {
+                                               status |= FDC_ST_INDEX;
+                                       }
+                               }
+                       }
+               }
+               // force interrupt if bit0-bit3 is high
+               if(cmdreg & 0x0f) {
+                       set_irq(true);
+               }
+//#ifdef HAS_MB89311
        }
-       status &= ~FDC_ST_BUSY;
-       
-       // force interrupt if bit0-bit3 is high
-       if(cmdreg & 0x0f) {
-               set_irq(true);
-       }
+//#endif
        
        cancel_my_event(EVENT_SEEK);
-       cancel_my_event(EVENT_SEEKEND);
+       cancel_my_event(EVENT_SEEKEND_VERIFY);
        cancel_my_event(EVENT_SEARCH);
        cancel_my_event(EVENT_DRQ);
        cancel_my_event(EVENT_MULTI1);
@@ -1000,14 +1572,27 @@ void MB8877::cmd_forceint()
        cancel_my_event(EVENT_LOST);
 }
 
+void MB8877::update_head_flag(int drv, bool head_load)
+{
+       if(fdc[drv].head_load != head_load) {
+               if(head_load) {
+                       if(d_noise_head_down != NULL) d_noise_head_down->play();
+               } else {
+                       if(d_noise_head_up != NULL) d_noise_head_up->play();
+               }
+               fdc[drv].head_load = head_load;
+       }
+}
+
 // ----------------------------------------------------------------------------
 // media handler
 // ----------------------------------------------------------------------------
 
-uint8 MB8877::search_track()
+uint8_t MB8877::search_track()
 {
        // get track
        int track = fdc[drvreg].track;
+
        if(!disk[drvreg]->get_track(track, sidereg)){
                return FDC_ST_SEEKERR;
        }
@@ -1041,7 +1626,7 @@ uint8 MB8877::search_track()
        return FDC_ST_SEEKERR;
 }
 
-uint8 MB8877::search_sector()
+uint8_t MB8877::search_sector()
 {
        // write protect
        if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
@@ -1052,15 +1637,8 @@ uint8 MB8877::search_sector()
        
        // get track
        int track = fdc[drvreg].track;
-#if defined(_FM77AV_VARIANTS)   
-       if(disk[drvreg]->media_type == MEDIA_TYPE_2D) {
-               if((disk[drvreg]->drive_type == DRIVE_TYPE_2DD) ||
-                  (disk[drvreg]->drive_type == DRIVE_TYPE_2HD) ||
-                  (disk[drvreg]->drive_type == DRIVE_TYPE_144)) {
-                       track >>= 1;
-               }
-       }
-#endif
+
+       
        if(!disk[drvreg]->get_track(track, sidereg)) {
                return FDC_ST_RECNFND;
        }
@@ -1092,11 +1670,13 @@ uint8 MB8877::search_sector()
                if(disk[drvreg]->id[0] != trkreg) {
                        continue;
                }
-#if !defined(HAS_MB8866)
-               if((cmdreg & 2) && (disk[drvreg]->id[1] & 1) != ((cmdreg >> 3) & 1)) {
-                       continue;
+//#if !defined(HAS_MB8866)
+               if(!type_mb8866) {
+                       if((cmdreg & 2) && (disk[drvreg]->id[1] & 1) != ((cmdreg >> 3) & 1)) {
+                               continue;
+                       }
                }
-#endif
+//#endif
                if(disk[drvreg]->id[2] != secreg) {
                        continue;
                }
@@ -1111,20 +1691,20 @@ uint8 MB8877::search_sector()
                
                // sector found
                if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
-                       fdc[drvreg].next_trans_position = disk[drvreg]->id_position[i] + 4 + 2;
-                       fdc[drvreg].bytes_before_2nd_drq = disk[drvreg]->data_position[i] - fdc[drvreg].next_trans_position;
+                       fdc[drvreg].next_trans_position = disk[drvreg]->id_position[index] + 4 + 2;
+                       fdc[drvreg].bytes_before_2nd_drq = disk[drvreg]->data_position[index] - fdc[drvreg].next_trans_position;
                } else {
-                       fdc[drvreg].next_trans_position = disk[drvreg]->data_position[i] + 1;
+                       fdc[drvreg].next_trans_position = disk[drvreg]->data_position[index] + 1;
                }
-               fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[i];
+               fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[index];
                fdc[drvreg].index = 0;
-#ifdef _FDC_DEBUG_LOG
-               emu->out_debug_log(_T("FDC\tSECTOR FOUND SIZE=$%04x ID=%02x %02x %02x %02x CRC=%02x %02x CRC_ERROR=%d\n"),
+//#ifdef _FDC_DEBUG_LOG
+           if(fdc_debug_log) this->out_debug_log(_T("FDC\tSECTOR FOUND SIZE=$%04x ID=%02x %02x %02x %02x CRC=%02x %02x CRC_ERROR=%d\n"),
                        disk[drvreg]->sector_size.sd,
                        disk[drvreg]->id[0], disk[drvreg]->id[1], disk[drvreg]->id[2], disk[drvreg]->id[3],
                        disk[drvreg]->id[4], disk[drvreg]->id[5],
                        disk[drvreg]->data_crc_error ? 1 : 0);
-#endif
+//#endif
                return (disk[drvreg]->deleted ? FDC_ST_RECTYPE : 0);
        }
        
@@ -1133,19 +1713,11 @@ uint8 MB8877::search_sector()
        return FDC_ST_RECNFND;
 }
 
-uint8 MB8877::search_addr()
+uint8_t MB8877::search_addr()
 {
        // get track
        int track = fdc[drvreg].track;
-#if defined(_FM77AV_VARIANTS)   
-       if(disk[drvreg]->media_type == MEDIA_TYPE_2D) {
-               if((disk[drvreg]->drive_type == DRIVE_TYPE_2DD) ||
-                  (disk[drvreg]->drive_type == DRIVE_TYPE_2HD) ||
-                  (disk[drvreg]->drive_type == DRIVE_TYPE_144)) {
-                       track >>= 1;
-               }
-       }
-#endif   
+       
        if(!disk[drvreg]->get_track(track, sidereg)) {
                return FDC_ST_RECNFND;
        }
@@ -1187,26 +1759,14 @@ uint8 MB8877::search_addr()
 
 int MB8877::get_cur_position()
 {
-       return (fdc[drvreg].cur_position + disk[drvreg]->get_bytes_per_usec(passed_usec(fdc[drvreg].prev_clock))) % disk[drvreg]->get_track_size();
+       return (fdc[drvreg].cur_position + disk[drvreg]->get_bytes_per_usec(get_passed_usec(fdc[drvreg].prev_clock))) % disk[drvreg]->get_track_size();
 }
 
 double MB8877::get_usec_to_start_trans(bool first_sector)
 {
-#if defined(_X1TURBO) || defined(_X1TURBOZ)
-       // FIXME: ugly patch for X1turbo ALPHA
-//     if(disk[drvreg]->is_special_disk == SPECIAL_DISK_X1TURBO_ALPHA) {
-//             return 100;
-//     } else
-#endif
-       if(/*disk[drvreg]->no_skew &&*/ !disk[drvreg]->correct_timing()) {
-               // XXX: this image may be a standard image or coverted from a standard image and skew may be incorrect,
-               // so use the constant period to search the target sector
-               return 50000;
-       }
-       
        // get time from current position
        double time = get_usec_to_next_trans_pos(first_sector && ((cmdreg & 4) != 0));
-       if(first_sector && time < 60000 - passed_usec(seekend_clock)) {
+       if(first_sector && time < 60000 - get_passed_usec(seekend_clock)) {
                time += disk[drvreg]->get_usec_per_track();
        }
        return time;
@@ -1215,17 +1775,45 @@ double MB8877::get_usec_to_start_trans(bool first_sector)
 double MB8877::get_usec_to_next_trans_pos(bool delay)
 {
        int position = get_cur_position();
+       
+       if(disk[drvreg]->invalid_format) {
+               // XXX: this track is invalid format and the calculated sector position may be incorrect.
+               // so use the constant period
+               return 50000;
+       } else if(/*disk[drvreg]->no_skew && */!disk[drvreg]->correct_timing()) {
+               // XXX: this image may be a standard image or coverted from a standard image and skew may be incorrect,
+               // so use the period to search the next sector from the current position
+               int sector_num = disk[drvreg]->sector_num.sd;
+               int bytes = -1;
+               
+               if(position > disk[drvreg]->am1_position[sector_num - 1]) {
+                       position -= disk[drvreg]->get_track_size();
+               }
+               for(int i = 0; i < sector_num; i++) {
+                       if(position < disk[drvreg]->am1_position[i]) {
+                               if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
+                                       bytes = (disk[drvreg]->id_position[i] + 4 + 2) - position;
+                               } else {
+                                       bytes = (disk[drvreg]->data_position[i] + 1) - position;
+                               }
+                               if(bytes < 0) {
+                                       bytes += disk[drvreg]->get_track_size(); // to make sure
+                               }
+                               break;
+                       }
+               }
+               if(bytes > 0) {
+                       return disk[drvreg]->get_usec_per_bytes(bytes);
+               }
+               return 50000;
+       }
        if(delay) {
                position = (position + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
        }
        int bytes = fdc[drvreg].next_trans_position - position;
-       // Is it right?
        if(fdc[drvreg].next_am1_position < position || bytes < 0) {
-               bytes += disk[drvreg]->get_track_size();
-       }
-       //if(bytes < 0) {
-       //      bytes += disk[drvreg]->get_track_size();
-       //}
+               bytes += disk[drvreg]->get_track_size();
+       }
        double time = disk[drvreg]->get_usec_per_bytes(bytes);
        if(delay) {
                time += DELAY_TIME;
@@ -1270,52 +1858,73 @@ void MB8877::set_drq(bool val)
 
 void MB8877::open_disk(int drv, const _TCHAR* file_path, int bank)
 {
-       if(drv < MAX_DRIVE) {
+       if(drv < _max_drive) {
                disk[drv]->open(file_path, bank);
+#if defined(_USE_QT)
+               if((disk[drv]->is_special_disk == SPECIAL_DISK_FM7_FLEX) || (config.disk_count_immediate[drv])) {
+#else
+               if(disk[drv]->is_special_disk == SPECIAL_DISK_FM7_FLEX) {
+#endif
+                       fdc[drv].count_immediate = true;
+               } else {
+                       fdc[drv].count_immediate = false;
+               }
        }
 }
 
 void MB8877::close_disk(int drv)
 {
-       if(drv < MAX_DRIVE) {
+       if(drv < _max_drive) {
                disk[drv]->close();
-               cmdtype = 0;
+               //cmdtype = 0;
+               update_head_flag(drvreg, false);
+               fdc[drv].count_immediate = false;
        }
 }
 
-bool MB8877::disk_inserted(int drv)
+bool MB8877::is_disk_inserted(int drv)
 {
-       if(drv < MAX_DRIVE) {
+       if(drv < _max_drive) {
                return disk[drv]->inserted;
        }
        return false;
 }
 
-void MB8877::set_disk_protected(int drv, bool value)
+void MB8877::is_disk_protected(int drv, bool value)
 {
-       if(drv < MAX_DRIVE) {
+       if(drv < _max_drive) {
                disk[drv]->write_protected = value;
        }
 }
 
-bool MB8877::get_disk_protected(int drv)
+bool MB8877::is_disk_protected(int drv)
 {
-       if(drv < MAX_DRIVE) {
+       if(drv < _max_drive) {
                return disk[drv]->write_protected;
        }
        return false;
 }
 
-void MB8877::set_drive_type(int drv, uint8 type)
+uint8_t MB8877::get_media_type(int drv)
+{
+       if(drv < _max_drive) {
+               if(disk[drv]->inserted) {
+                       return disk[drv]->media_type;
+               }
+       }
+       return MEDIA_TYPE_UNK;
+}
+
+void MB8877::set_drive_type(int drv, uint8_t type)
 {
-       if(drv < MAX_DRIVE) {
+       if(drv < _max_drive) {
                disk[drv]->drive_type = type;
        }
 }
 
-uint8 MB8877::get_drive_type(int drv)
+uint8_t MB8877::get_drive_type(int drv)
 {
-       if(drv < MAX_DRIVE) {
+       if(drv < _max_drive) {
                return disk[drv]->drive_type;
        }
        return DRIVE_TYPE_UNK;
@@ -1323,97 +1932,142 @@ uint8 MB8877::get_drive_type(int drv)
 
 void MB8877::set_drive_rpm(int drv, int rpm)
 {
-       if(drv < MAX_DRIVE) {
+       if(drv < _max_drive) {
                disk[drv]->drive_rpm = rpm;
        }
 }
 
 void MB8877::set_drive_mfm(int drv, bool mfm)
 {
-       if(drv < MAX_DRIVE) {
+       if(drv < _max_drive) {
                disk[drv]->drive_mfm = mfm;
        }
 }
 
-uint8 MB8877::fdc_status()
+void MB8877::set_track_size(int drv, int size)
+{
+       if(drv < _max_drive) {
+               disk[drv]->track_size = size;
+       }
+}
+
+uint8_t MB8877::fdc_status()
 {
        // for each virtual machines
-#if defined(_FMR50) || defined(_FMR60)
-       return disk[drvreg]->inserted ? 2 : 0;
-#else
+//#if defined(_FMR50) || defined(_FMR60)
+       if(type_fmr50 || type_fmr60) {
+               return disk[drvreg]->inserted ? 2 : 0;
+       }
+//#else
        return 0;
-#endif
+//#endif
 }
 
-#define STATE_VERSION  5
+void MB8877::update_config()
+{
+       if(d_noise_seek != NULL) {
+               d_noise_seek->set_mute(!config.sound_noise_fdd);
+       }
+       if(d_noise_head_down != NULL) {
+               d_noise_head_down->set_mute(!config.sound_noise_fdd);
+       }
+       if(d_noise_head_up != NULL) {
+               d_noise_head_up->set_mute(!config.sound_noise_fdd);
+       }
+       fdc_debug_log = config.special_debug_fdc;
+}
 
-void MB8877::save_state(FILEIO* state_fio)
+//#ifdef USE_DEBUGGER
+static const _TCHAR *cmdstr[0x10] = {
+               _T("RESTORE "), _T("SEEK    "), _T("STEP    "), _T("STEP    "),
+               _T("STEP IN "), _T("STEP IN "), _T("STEP OUT"), _T("STEP OUT"),
+               _T("RD DATA "), _T("RD DATA "), _T("RD DATA "), _T("WR DATA "),
+               _T("RD ADDR "), _T("FORCEINT"), _T("RD TRACK"), _T("WR TRACK")
+};
+void MB8877::get_debug_regs_info(_TCHAR *buffer, size_t buffer_len)
 {
-       state_fio->FputUint32(STATE_VERSION);
-       state_fio->FputInt32(this_device_id);
-       
-       state_fio->Fwrite(fdc, sizeof(fdc), 1);
-       for(int i = 0; i < MAX_DRIVE; i++) {
-               disk[i]->save_state(state_fio);
-       }
-       state_fio->FputUint8(status);
-       state_fio->FputUint8(status_tmp);
-       state_fio->FputUint8(cmdreg);
-       state_fio->FputUint8(cmdreg_tmp);
-       state_fio->FputUint8(trkreg);
-       state_fio->FputUint8(secreg);
-       state_fio->FputUint8(datareg);
-       state_fio->FputUint8(drvreg);
-       state_fio->FputUint8(sidereg);
-       state_fio->FputUint8(cmdtype);
-       state_fio->Fwrite(register_id, sizeof(register_id), 1);
-       state_fio->FputBool(now_search);
-       state_fio->FputBool(now_seek);
-       state_fio->FputBool(sector_changed);
-       state_fio->FputInt32(no_command);
-       state_fio->FputInt32(seektrk);
-       state_fio->FputBool(seekvct);
-       state_fio->FputBool(motor_on);
-       state_fio->FputBool(drive_sel);
-       state_fio->FputUint32(prev_drq_clock);
-       state_fio->FputUint32(seekend_clock);
+       my_stprintf_s(buffer, buffer_len,
+       _T("CMDREG=%02X (%s) DATAREG=%02X DRVREG=%02X TRKREG=%02X SIDEREG=%d SECREG=%02X\nUNIT: DRIVE=%d TRACK=%2d SIDE=%d SECTORS=%2d C=%02X H=%02X R=%02X N=%02X LENGTH=%d"),
+       cmdreg, cmdstr[cmdreg >> 4], datareg, drvreg, trkreg, sidereg, secreg,
+       drvreg, fdc[drvreg].track, sidereg, disk[drvreg]->sector_num.sd,
+       disk[drvreg]->id[0], disk[drvreg]->id[1], disk[drvreg]->id[2], disk[drvreg]->id[3],
+       disk[drvreg]->sector_size.sd);
 }
+//#endif
+
+#define STATE_VERSION  6
 
-bool MB8877::load_state(FILEIO* state_fio)
+bool MB8877::process_state(FILEIO* state_fio, bool loading)
 {
-       if(state_fio->FgetUint32() != STATE_VERSION) {
-               return false;
+       if(!state_fio->StateCheckUint32(STATE_VERSION)) {
+               return false;
+       }
+       if(!state_fio->StateCheckInt32(this_device_id)) {
+               return false;
+       }
+//
+//     state_fio->StateBuffer(fdc, sizeof(fdc), 1);
+       for(int ch = 0; ch < 16; ch++) { // ToDo
+               process_state_fdc(ch, state_fio, loading);
        }
-       if(state_fio->FgetInt32() != this_device_id) {
-               return false;
+       for(int i = 0; i < _max_drive; i++) {
+               if(!disk[i]->process_state(state_fio, loading)) {
+                       return false;
+               }
+       }
+       state_fio->StateUint8(status);
+       state_fio->StateUint8(status_tmp);
+       state_fio->StateUint8(cmdreg);
+       state_fio->StateUint8(cmdreg_tmp);
+       state_fio->StateUint8(trkreg);
+       state_fio->StateUint8(secreg);
+       state_fio->StateUint8(datareg);
+       state_fio->StateUint8(drvreg);
+       state_fio->StateUint8(sidereg);
+       state_fio->StateUint8(cmdtype);
+       //state_fio->StateBuffer(register_id, sizeof(register_id), 1);
+       for(int i = 0; i < (sizeof(register_id) / sizeof(register_id)); i++) {
+               state_fio->StateInt32(register_id[i]);
        }
-       state_fio->Fread(fdc, sizeof(fdc), 1);
-       for(int i = 0; i < MAX_DRIVE; i++) {
-               if(!disk[i]->load_state(state_fio)) {
-                       return false;
-               }
+
+       state_fio->StateBool(now_search);
+       state_fio->StateBool(now_seek);
+       state_fio->StateBool(sector_changed);
+       state_fio->StateInt32(no_command);
+       state_fio->StateInt32(seektrk);
+       state_fio->StateBool(seekvct);
+       state_fio->StateBool(motor_on);
+       state_fio->StateBool(drive_sel);
+       state_fio->StateUint32(prev_drq_clock);
+       state_fio->StateUint32(seekend_clock);
+       if(loading) {
+               fdc_debug_log = config.special_debug_fdc;
        }
-       status = state_fio->FgetUint8();
-       status_tmp = state_fio->FgetUint8();
-       cmdreg = state_fio->FgetUint8();
-       cmdreg_tmp = state_fio->FgetUint8();
-       trkreg = state_fio->FgetUint8();
-       secreg = state_fio->FgetUint8();
-       datareg = state_fio->FgetUint8();
-       drvreg = state_fio->FgetUint8();
-       sidereg = state_fio->FgetUint8();
-       cmdtype = state_fio->FgetUint8();
-       state_fio->Fread(register_id, sizeof(register_id), 1);
-       now_search = state_fio->FgetBool();
-       now_seek = state_fio->FgetBool();
-       sector_changed = state_fio->FgetBool();
-       no_command = state_fio->FgetInt32();
-       seektrk = state_fio->FgetInt32();
-       seekvct = state_fio->FgetBool();
-       motor_on = state_fio->FgetBool();
-       drive_sel = state_fio->FgetBool();
-       prev_drq_clock = state_fio->FgetUint32();
-       seekend_clock = state_fio->FgetUint32();
-       return true;
+       return true;
+}
+
+void MB8877::process_state_fdc(int ch, FILEIO* state_fio, bool loading)
+{
+       state_fio->StateInt32(fdc[ch].track);
+       state_fio->StateInt32(fdc[ch].index);
+       state_fio->StateBool(fdc[ch].access);
+       state_fio->StateBool(fdc[ch].head_load);
+       state_fio->StateBool(fdc[ch].id_written);
+       state_fio->StateBool(fdc[ch].sector_found);
+
+       state_fio->StateInt32(fdc[ch].sector_length);
+       state_fio->StateInt32(fdc[ch].sector_index);
+       
+       state_fio->StateInt32(fdc[ch].side);
+       state_fio->StateBool(fdc[ch].side_changed);
+       
+       state_fio->StateInt32(fdc[ch].cur_position);
+       state_fio->StateInt32(fdc[ch].next_trans_position);
+
+       state_fio->StateInt32(fdc[ch].bytes_before_2nd_drq);
+       state_fio->StateInt32(fdc[ch].next_am1_position);
+
+       state_fio->StateUint32(fdc[ch].prev_clock);
+       state_fio->StateBool(fdc[ch].count_immediate);
 }