OSDN Git Service

[VM][PCM1BIT][AY3_891x] Add LPF feature.See initialize_sound().
[csp-qt/common_source_project-fm7.git] / source / src / vm / mb8877.cpp
index a21d553..6dd9932 100644 (file)
 #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 DELAY_TIME             (disk[drvreg]->drive_type == DRIVE_TYPE_2HD ? 15000 : 30000)
+#define DELAY_AFTER_HLD                (disk[drvreg]->drive_type == DRIVE_TYPE_2HD ? 15000 : 30000)
 
 static const int seek_wait_hi[4] = {3000,  6000, 10000, 16000};        // 2MHz
 static const int seek_wait_lo[4] = {6000, 12000, 20000, 30000};        // 1MHz
@@ -58,39 +60,68 @@ 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);
        register_event(this, (event << 8) | (cmdtype & 0xff), usec, false, &register_id[event]);
 }
 
-void MB8877::register_seek_event()
+void MB8877::register_seek_event(bool first)
 {
        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]);
+               register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), seek_wait_hi[cmdreg & 3] - (first ? 250 : 0), false, &register_id[EVENT_SEEK]);
        } else {
-               register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), seek_wait_lo[cmdreg & 3], false, &register_id[EVENT_SEEK]);
+               register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), seek_wait_lo[cmdreg & 3] - (first ? 500 : 0), false, &register_id[EVENT_SEEK]);
        }
        now_seek = true;
 }
 
 void MB8877::register_drq_event(int bytes)
 {
-       double usec = disk[drvreg]->get_usec_per_bytes(bytes) - get_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(config.correct_disk_timing[drvreg]) {
+               nf = true;
+       }
        if(type_fm7) {
-               if((disk[drvreg]->is_special_disk == SPECIAL_DISK_FM7_GAMBLER) ||
-                  (disk[drvreg]->is_special_disk == SPECIAL_DISK_FM77AV_PSYOBLADE)) {
-                       usec = 4;
+               if((disk[drvreg]->is_special_disk == SPECIAL_DISK_FM7_GAMBLER)) {
+                  /* (disk[drvreg]->is_special_disk == SPECIAL_DISK_FM77AV_PSYOBLADE) || */
+                       nf = true;
                }
        }
-//#endif
+       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]);
 }
@@ -101,11 +132,43 @@ 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
-       _max_drive = osd->get_feature_int_value(_T("MAX_DRIVE"));
+       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);
@@ -115,9 +178,14 @@ void MB8877::initialize()
        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;
+       if(osd->check_feature(_T("MB8877_DELAY_AFTER_SEEK"))) {
+               mb8877_delay_after_seek = osd->get_feature_int_value(_T("MB8877_DELAY_AFTER_SEEK"));
        }
+       //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;
@@ -173,14 +241,15 @@ void MB8877::initialize()
                d_noise_head_up->set_mute(!config.sound_noise_fdd);
        }
        
-       // initialize timing
-       memset(fdc, 0, sizeof(fdc));
-       
        // initialize fdc
-       seektrk = 0;
-       seekvct = true;
-       status = cmdreg = trkreg = secreg = datareg = sidereg = cmdtype = 0;
-       drvreg = 0;
+       memset(fdc, 0, sizeof(fdc));
+       for(int i = 0; i < 16; i++) {
+               fdc[i].track = 40;  // OK?
+               fdc[i].count_immediate = false;
+       }
+//     drvreg = sidereg = 0;
+       cmdtype = 0;
+//     motor_on = drive_sel = false;
        prev_drq_clock = seekend_clock = 0;
 }
 
@@ -197,17 +266,34 @@ void MB8877::release()
 
 void MB8877::reset()
 {
-       for(int i = 0; i < _max_drive; i++) {
-               fdc[i].track = 0;
-               fdc[i].index = 0;
-               fdc[i].access = false;
-       }
+       // finish previous command
+       if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
+               // abort write sector command
+               if(sector_changed) {
+                       disk[drvreg]->set_data_crc_error(false);
+               }
+       } else if(cmdtype == FDC_CMD_WR_TRK) {
+               // abort write track command
+               if(!disk[drvreg]->write_protected) {
+                       if(fdc[drvreg].id_written && !fdc[drvreg].sector_found) {
+                               // data mark of last sector is not written
+                               disk[drvreg]->set_data_mark_missing();
+                       }
+                       disk[drvreg]->sync_buffer();
+               }
+       }
+       
+       // single events are automatically canceled in event manager
        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;
        
+       // reset fdc
+       memset(fdc, 0, sizeof(fdc));
+       status = status_tmp = cmdreg = cmdreg_tmp = trkreg = secreg = datareg = cmdtype = 0;
+       now_search = now_seek = sector_changed = false;
+       no_command = seektrk = 0;
+       seekvct = false;
 //#ifdef HAS_MB89311
        if(type_mb89311) {
                extended_mode = true;
@@ -281,15 +367,18 @@ void MB8877::write_io8(uint32_t addr, uint32_t 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) {
@@ -336,6 +425,7 @@ void MB8877::write_io8(uint32_t addr, uint32_t 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) {
@@ -425,6 +515,7 @@ write_id:
                                        } else {
                                                register_drq_event(1);
                                        }
+                                       if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
                                }
                                status &= ~FDC_ST_DRQ;
                        }
@@ -441,7 +532,7 @@ write_id:
 uint32_t MB8877::read_io8(uint32_t addr)
 {
        uint32_t val;
-       bool not_ready;
+       bool not_ready = false;
        bool ready;
        
        switch(addr & 3) {
@@ -513,6 +604,7 @@ uint32_t MB8877::read_io8(uint32_t addr)
 //#endif
                        }
                }
+
                if(cmdtype == 0 && !(status & FDC_ST_NOTREADY)) {
                        // MZ-2000 HuBASIC invites NOT READY status
                        if(++no_command == 16) {
@@ -521,6 +613,7 @@ uint32_t MB8877::read_io8(uint32_t addr)
                } else {
                        no_command = 0;
                }
+
                // reset irq/drq
                if(!(status & FDC_ST_DRQ)) {
                        set_drq(false);
@@ -567,10 +660,12 @@ uint32_t MB8877::read_io8(uint32_t addr)
                        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) {
@@ -578,12 +673,12 @@ uint32_t MB8877::read_io8(uint32_t addr)
                                // 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
+#if 0
 //#ifdef _FDC_DEBUG_LOG
                                                if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR (DATA CRC ERROR)\n"));
 //#endif
@@ -591,14 +686,21 @@ uint32_t MB8877::read_io8(uint32_t addr)
                                                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
+#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
@@ -607,8 +709,9 @@ uint32_t MB8877::read_io8(uint32_t addr)
                                                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) {
@@ -630,6 +733,7 @@ uint32_t MB8877::read_io8(uint32_t addr)
 //#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) {
@@ -648,6 +752,7 @@ uint32_t MB8877::read_io8(uint32_t addr)
                                        set_irq(true);
                                } else {
                                        register_drq_event(1);
+                                       if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
                                }
                                status &= ~FDC_ST_DRQ;
                        }
@@ -658,7 +763,7 @@ uint32_t MB8877::read_io8(uint32_t addr)
                        }
                }
 //#ifdef _FDC_DEBUG_LOG
-               if(fdc_debug_log) this->out_debug_log(_T("FDC\tDATA=%2x\n"), datareg);
+               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) {
@@ -692,7 +797,7 @@ void MB8877::write_signal(int id, uint32_t data, uint32_t mask)
                sidereg = (data & mask) ? 1 : 0;
        } else if(id == SIG_MB8877_MOTOR) {
                motor_on = ((data & mask) != 0);
-       }
+       } 
 }
 
 uint32_t MB8877::read_signal(int ch)
@@ -723,11 +828,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;
@@ -743,17 +849,35 @@ void MB8877::event_callback(int event_id, int err)
                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;
                }
-               if(seektrk != fdc[drvreg].track) {
-                       register_seek_event();
+               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(false);
                        break;
                }
+#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) {
@@ -775,18 +899,33 @@ void MB8877::event_callback(int event_id, int err)
                        // 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);
+               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
@@ -798,15 +937,16 @@ void MB8877::event_callback(int event_id, int err)
                        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;
-                       }
+                                       status_tmp &= ~FDC_ST_RECNFND;
+                               }
                        }
 //#endif
 //#ifdef _FDC_DEBUG_LOG
-                               if(fdc_debug_log) this->out_debug_log(_T("FDC\tSEARCH NG\n"));
+                       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
@@ -814,6 +954,7 @@ void MB8877::event_callback(int event_id, int err)
 //#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);
@@ -828,6 +969,7 @@ void MB8877::event_callback(int event_id, int err)
                        fdc[drvreg].prev_clock = prev_drq_clock = get_current_clock();
                        set_drq(true);
                        drive_sel = false;
+                       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
@@ -846,10 +988,12 @@ 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 = get_current_clock();
+
                        set_drq(true);
+                       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
@@ -865,22 +1009,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
-                               if(fdc_debug_log) this->out_debug_log(_T("FDC\tDATA LOST\n"));
+                       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;
@@ -893,6 +1069,7 @@ void MB8877::event_callback(int event_id, int err)
 // command
 // ----------------------------------------------------------------------------
 
+
 void MB8877::process_cmd()
 {
        set_irq(false);
@@ -974,16 +1151,12 @@ void MB8877::process_cmd()
 //#endif
        
        // MB8877 mode commands
-//#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")
-       };
-       if(fdc_debug_log) this->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
-       
+       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 0x08:
@@ -1047,54 +1220,63 @@ 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;
        seekvct = true;
        
-       register_seek_event();
+       register_seek_event(true);
 }
 
 void MB8877::cmd_seek()
 {
        // type-1 seek
        cmdtype = FDC_CMD_TYPE1;
-       status = FDC_ST_HEADENG | FDC_ST_BUSY;
-       
-//     seektrk = (uint8_t)(fdc[drvreg].track + datareg - trkreg);
-       seektrk = datareg;
-//#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
-       if(type_fm77av_2dd) {
-               if(disk[drvreg]->drive_type != DRIVE_TYPE_2D) {
-                       seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
-               } else {
-                       seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
-               }
-       } else  if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
-               seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
+       if(!check_drive()) {
+               return;
+       }
+       if((cmdreg & 0x08) != 0) { // Head engage
+               status = FDC_ST_HEADENG | FDC_ST_BUSY;
        } else {
-               seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
+               status = FDC_ST_BUSY;
        }               
-//#else
-//     if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
-//#endif
-//             seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
-//     } else {
-//             seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
-//     }
-//     seekvct = !(datareg > trkreg);
+
+       // 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);
-       
-       if(cmdreg & 4) {
-               // verify
-               if(trkreg != fdc[drvreg].track) {
-                       status |= FDC_ST_SEEKERR;
-                       trkreg = fdc[drvreg].track;
-               }
-       }
-       register_seek_event();
+       // Update track register by data register.Thanks to Ryu Takegami. 20180224 K.O
+       trkreg = datareg;
+       set_irq(false);
+       set_drq(false);
+       register_seek_event(true);
 }
 
 void MB8877::cmd_step()
@@ -1111,31 +1293,18 @@ void MB8877::cmd_stepin()
 {
        // type-1 step in
        cmdtype = FDC_CMD_TYPE1;
-       status = FDC_ST_HEADENG | FDC_ST_BUSY;
-       
-       seektrk = fdc[drvreg].track + 1;
-//#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
-//     if(disk[drvreg]->drive_type != DRIVE_TYPE_2D) {
-//#else
-//     if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
-//#endif
-//             seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
-//     } else {
-//             seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
-//     }
-       if(type_fm77av_2dd) {
-               if(disk[drvreg]->drive_type != DRIVE_TYPE_2D) {
-                       seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
-               } else {
-                       seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
-               }
-       } else  if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
-               seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
+       if(!check_drive()) {
+               return;
+       }
+       if((cmdreg & 0x08) != 0) { // Head engage
+               status = FDC_ST_HEADENG | FDC_ST_BUSY;
        } else {
-               seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
-       }               
-       seekvct = false;
-       
+               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) {
@@ -1143,38 +1312,35 @@ void MB8877::cmd_stepin()
 //                     trkreg = fdc[drvreg].track;
                }
        }
-       register_seek_event();
+#endif
+       seektrk = fdc[drvreg].track + 1;
+       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(true);
 }
 
 void MB8877::cmd_stepout()
 {
        // type-1 step out
        cmdtype = FDC_CMD_TYPE1;
-       status = FDC_ST_HEADENG | FDC_ST_BUSY;
-       
-       seektrk = fdc[drvreg].track - 1;
-       if(type_fm77av_2dd) {
-               if(disk[drvreg]->drive_type != DRIVE_TYPE_2D) {
-                       seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
-               } else {
-                       seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
-               }
-       } else  if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
-               seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
+       if(!check_drive()) {
+               return;
+       }
+       if((cmdreg & 0x08) != 0) { // Head engage
+               status = FDC_ST_HEADENG | FDC_ST_BUSY;
        } else {
-               seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
-       }               
-//#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
-//     if(disk[drvreg]->drive_type != DRIVE_TYPE_2D) {
-//#else
-//     if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
-//#endif
-//             seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
-//     } else {
-//             seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
-//     }
-       seekvct = true;
-       
+               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) {
@@ -1182,13 +1348,24 @@ void MB8877::cmd_stepout()
 //                     trkreg = fdc[drvreg].track;
                }
        }
-       register_seek_event();
+#endif
+       seektrk = fdc[drvreg].track - 1;
+       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(true);
 }
 
 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;
@@ -1207,6 +1384,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;
@@ -1216,7 +1396,7 @@ void MB8877::cmd_writedata(bool first_sector)
        if(status_tmp & FDC_ST_RECNFND) {
                time = get_usec_to_detect_index_hole(5, first_sector && ((cmdreg & 4) != 0));
        } else if(status & FDC_ST_WRITEFAULT) {
-               time = (cmdreg & 4) ? DELAY_TIME : 1;
+               time = (cmdreg & 4) ? DELAY_AFTER_HLD : 1;
        } else {
                time = get_usec_to_start_trans(first_sector);
        }
@@ -1228,6 +1408,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;
@@ -1246,6 +1429,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;
        
@@ -1263,6 +1449,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;
        
@@ -1273,12 +1462,12 @@ void MB8877::cmd_writetrack()
        double time;
        if(disk[drvreg]->write_protected) {
                status_tmp = FDC_ST_WRITEFAULT;
-               time = (cmdreg & 4) ? DELAY_TIME : 1;
+               time = (cmdreg & 4) ? DELAY_AFTER_HLD : 1;
        } else {
                if(cmdreg & 4) {
                        // wait 15msec before raise first drq
-                       fdc[drvreg].next_trans_position = (get_cur_position() + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
-                       time = DELAY_TIME;
+                       fdc[drvreg].next_trans_position = (get_cur_position() + disk[drvreg]->get_bytes_per_usec(DELAY_AFTER_HLD)) % disk[drvreg]->get_track_size();
+                       time = DELAY_AFTER_HLD;
                } else {
                        // raise first drq soon
                        fdc[drvreg].next_trans_position = (get_cur_position() + 1) % disk[drvreg]->get_track_size();
@@ -1308,7 +1497,7 @@ void MB8877::cmd_format()
                now_search = true;
                
                status_tmp = FDC_ST_WRITEFAULT;
-               double time = (cmdreg & 4) ? DELAY_TIME : 1;
+               double time = (cmdreg & 4) ? DELAY_AFTER_HLD : 1;
                
                register_my_event(EVENT_SEARCH, time);
                cancel_my_event(EVENT_LOST);
@@ -1319,15 +1508,24 @@ void MB8877::cmd_format()
 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;
                        }
                }
@@ -1357,10 +1555,24 @@ void MB8877::cmd_forceint()
 //#endif
                if(cmdtype == 0 || !(status & FDC_ST_BUSY)) {
                        cmdtype = FDC_CMD_TYPE1;
-                       status = FDC_ST_HEADENG;
+                   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);
@@ -1370,7 +1582,7 @@ void MB8877::cmd_forceint()
 //#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);
@@ -1398,17 +1610,7 @@ uint8_t MB8877::search_track()
 {
        // get track
        int track = fdc[drvreg].track;
-//#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
-       if(type_fm77av_2dd) {
-               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_SEEKERR;
        }
@@ -1453,17 +1655,8 @@ uint8_t MB8877::search_sector()
        
        // get track
        int track = fdc[drvreg].track;
-//#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
-       if(type_fm77av_2dd) {
-               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;
        }
@@ -1542,17 +1735,7 @@ uint8_t MB8877::search_addr()
 {
        // get track
        int track = fdc[drvreg].track;
-//#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
-       if(type_fm77av_2dd) {
-               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;
        }
@@ -1601,8 +1784,12 @@ double MB8877::get_usec_to_start_trans(bool first_sector)
 {
        // get time from current position
        double time = get_usec_to_next_trans_pos(first_sector && ((cmdreg & 4) != 0));
-       if(first_sector && time < 60000 - get_passed_usec(seekend_clock)) {
-               time += disk[drvreg]->get_usec_per_track();
+       
+       if(mb8877_delay_after_seek > 0) {
+       // wait 60ms to start read/write after seek is finished (FM-Techknow, p.180)
+               if(first_sector && time < mb8877_delay_after_seek - get_passed_usec(seekend_clock)) {
+                       time += disk[drvreg]->get_usec_per_track();
+               }
        }
        return time;
 }
@@ -1643,7 +1830,7 @@ double MB8877::get_usec_to_next_trans_pos(bool delay)
                return 50000;
        }
        if(delay) {
-               position = (position + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
+               position = (position + disk[drvreg]->get_bytes_per_usec(DELAY_AFTER_HLD)) % disk[drvreg]->get_track_size();
        }
        int bytes = fdc[drvreg].next_trans_position - position;
        if(fdc[drvreg].next_am1_position < position || bytes < 0) {
@@ -1651,7 +1838,7 @@ double MB8877::get_usec_to_next_trans_pos(bool delay)
        }
        double time = disk[drvreg]->get_usec_per_bytes(bytes);
        if(delay) {
-               time += DELAY_TIME;
+               time += DELAY_AFTER_HLD;
        }
        return time;
 }
@@ -1660,7 +1847,7 @@ double MB8877::get_usec_to_detect_index_hole(int count, bool delay)
 {
        int position = get_cur_position();
        if(delay) {
-               position = (position + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
+               position = (position + disk[drvreg]->get_bytes_per_usec(DELAY_AFTER_HLD)) % disk[drvreg]->get_track_size();
        }
        int bytes = disk[drvreg]->get_track_size() * count - position;
        if(bytes < 0) {
@@ -1668,7 +1855,7 @@ double MB8877::get_usec_to_detect_index_hole(int count, bool delay)
        }
        double time = disk[drvreg]->get_usec_per_bytes(bytes);
        if(delay) {
-               time += DELAY_TIME;
+               time += DELAY_AFTER_HLD;
        }
        return time;
 }
@@ -1695,6 +1882,15 @@ void MB8877::open_disk(int drv, const _TCHAR* file_path, int bank)
 {
        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;
+               }
        }
 }
 
@@ -1702,8 +1898,12 @@ void MB8877::close_disk(int drv)
 {
        if(drv < _max_drive) {
                disk[drv]->close();
-               cmdtype = 0;
-               update_head_flag(drvreg, false);
+               //cmdtype = 0;
+               if(drv == drvreg) {
+                       cmdtype = 0;
+               }
+               update_head_flag(drv, false);
+               fdc[drv].count_immediate = false;
        }
 }
 
@@ -1730,6 +1930,16 @@ bool MB8877::is_disk_protected(int drv)
        return false;
 }
 
+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) {
@@ -1789,77 +1999,101 @@ void MB8877::update_config()
        if(d_noise_head_up != NULL) {
                d_noise_head_up->set_mute(!config.sound_noise_fdd);
        }
+       fdc_debug_log = config.special_debug_fdc;
 }
 
-#define STATE_VERSION  5
+//#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::save_state(FILEIO* state_fio)
+bool MB8877::get_debug_regs_info(_TCHAR *buffer, size_t buffer_len)
 {
-       state_fio->FputUint32(STATE_VERSION);
-       state_fio->FputInt32(this_device_id);
+       int position = get_cur_position();
        
-       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\n")
+       _T("UNIT: DRIVE=%d TRACK=%2d SIDE=%d POSITION=%5d/%d"),
+       cmdreg, cmdstr[cmdreg >> 4], datareg, drvreg, trkreg, sidereg, secreg,
+       drvreg, fdc[drvreg].track, sidereg,
+       position, disk[drvreg]->get_track_size());
+       
+       for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
+               uint8_t c, h, r, n;
+               int length;
+               if(disk[drvreg]->get_sector_info(-1, -1, i, &c, &h, &r, &n, &length)) {
+                       my_tcscat_s(buffer, buffer_len,
+                       create_string(_T("\nSECTOR %2d: C=%02X H=%02X R=%02X N=%02X SIZE=%4d AM1=%5d DATA=%5d"), i + 1, c, h, r, n, length, disk[drvreg]->am1_position[i], disk[drvreg]->data_position[i]));
+                       if(position >= disk[drvreg]->am1_position[i] && position < disk[drvreg]->data_position[i] + length) {
+                               my_tcscat_s(buffer, buffer_len, _T(" <==="));
+                       }
+               }
+       }
+       return true;
 }
+//#endif
 
-bool MB8877::load_state(FILEIO* state_fio)
+#define STATE_VERSION  6
+
+bool MB8877::process_state(FILEIO* state_fio, bool loading)
 {
-       if(state_fio->FgetUint32() != STATE_VERSION) {
-               return false;
-       }
-       if(state_fio->FgetInt32() != this_device_id) {
-               return false;
-       }
-       state_fio->Fread(fdc, sizeof(fdc), 1);
-       for(int i = 0; i < _max_drive; i++) {
-               if(!disk[i]->load_state(state_fio)) {
-                       return false;
-               }
-       }
-       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;
+       if(!state_fio->StateCheckUint32(STATE_VERSION)) {
+               return false;
+       }
+       if(!state_fio->StateCheckInt32(this_device_id)) {
+               return false;
+       }
+//
+       for(int i = 0; i < array_length(fdc); i++) {
+               state_fio->StateValue(fdc[i].track);
+               state_fio->StateValue(fdc[i].index);
+               state_fio->StateValue(fdc[i].access);
+               state_fio->StateValue(fdc[i].head_load);
+               state_fio->StateValue(fdc[i].id_written);
+               state_fio->StateValue(fdc[i].sector_found);
+               state_fio->StateValue(fdc[i].sector_length);
+               state_fio->StateValue(fdc[i].sector_index);
+               state_fio->StateValue(fdc[i].side);
+               state_fio->StateValue(fdc[i].side_changed);
+               state_fio->StateValue(fdc[i].cur_position);
+               state_fio->StateValue(fdc[i].next_trans_position);
+               state_fio->StateValue(fdc[i].bytes_before_2nd_drq);
+               state_fio->StateValue(fdc[i].next_am1_position);
+               state_fio->StateValue(fdc[i].prev_clock);
+       }
+       for(int i = 0; i < array_length(disk); i++) {
+               if(disk[i] == NULL) continue;
+               if(!disk[i]->process_state(state_fio, loading)) {
+                       return false;
+               }
+       }
+       state_fio->StateValue(status);
+       state_fio->StateValue(status_tmp);
+       state_fio->StateValue(cmdreg);
+       state_fio->StateValue(cmdreg_tmp);
+       state_fio->StateValue(trkreg);
+       state_fio->StateValue(secreg);
+       state_fio->StateValue(datareg);
+       state_fio->StateValue(drvreg);
+       state_fio->StateValue(sidereg);
+       state_fio->StateValue(cmdtype);
+       state_fio->StateArray(register_id, sizeof(register_id), 1);
+       state_fio->StateValue(now_search);
+       state_fio->StateValue(now_seek);
+       state_fio->StateValue(sector_changed);
+       state_fio->StateValue(no_command);
+       state_fio->StateValue(seektrk);
+       state_fio->StateValue(seekvct);
+       state_fio->StateValue(motor_on);
+       state_fio->StateValue(drive_sel);
+       state_fio->StateValue(prev_drq_clock);
+       state_fio->StateValue(seekend_clock);
+       if(loading) {
+               fdc_debug_log = config.special_debug_fdc;
+       }
+       return true;
 }