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 fad271c..6dd9932 100644 (file)
 #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,21 +60,28 @@ 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;
 }
@@ -159,6 +168,7 @@ void MB8877::initialize()
        } else {
                _max_drive = 1;
        }
+
        _drive_mask = _max_drive - 1;
        for(int i = 0; i < _max_drive; i++) {
                disk[i] = new DISK(emu);
@@ -168,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;
@@ -226,17 +241,15 @@ void MB8877::initialize()
                d_noise_head_up->set_mute(!config.sound_noise_fdd);
        }
        
-       // initialize timing
+       // initialize fdc
        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;
-       status = cmdreg = trkreg = secreg = datareg = sidereg = cmdtype = 0;
-       drvreg = 0;
+//     drvreg = sidereg = 0;
+       cmdtype = 0;
+//     motor_on = drive_sel = false;
        prev_drq_clock = seekend_clock = 0;
 }
 
@@ -253,17 +266,34 @@ void MB8877::release()
 
 void MB8877::reset()
 {
-       for(int i = 0; i < _max_drive; i++) {
-               //fdc[i].track = 0; // Hold to track
-               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;
@@ -337,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) {
@@ -499,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) {
@@ -571,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) {
@@ -579,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);
@@ -625,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) {
@@ -641,6 +678,7 @@ uint32_t MB8877::read_io8(uint32_t addr)
 
                                        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
@@ -648,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
@@ -810,17 +855,29 @@ void MB8877::event_callback(int event_id, int err)
                        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) {
+               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();
+                       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) {
@@ -842,11 +899,17 @@ 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);
                        }
+#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;
@@ -946,6 +1009,23 @@ 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
@@ -989,6 +1069,7 @@ void MB8877::event_callback(int event_id, int err)
 // command
 // ----------------------------------------------------------------------------
 
+
 void MB8877::process_cmd()
 {
        set_irq(false);
@@ -1070,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:
@@ -1168,7 +1245,7 @@ void MB8877::cmd_restore()
        seektrk = 0;
        seekvct = true;
        
-       register_seek_event();
+       register_seek_event(true);
 }
 
 void MB8877::cmd_seek()
@@ -1183,31 +1260,23 @@ void MB8877::cmd_seek()
        } else {
                status = FDC_ST_BUSY;
        }               
-       
-//     seektrk = (uint8_t)(fdc[drvreg].track + datareg - trkreg);
-       seektrk = datareg;
+
+       // 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(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;
-       } else {
-               seektrk = (seektrk > 41) ? 41 : (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 = !(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()
@@ -1231,21 +1300,11 @@ void MB8877::cmd_stepin()
                status = FDC_ST_HEADENG | FDC_ST_BUSY;
        } else {
                status = 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;
-       } else {
-               seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
-       }               
-       seekvct = false;
-       
+       }
+
+       // Verify before execute command.
+       // Port from XM7.Thanks to Ryu Takegami.
+#if 1
        if(cmdreg & 4) {
                // verify
                if(trkreg != fdc[drvreg].track) {
@@ -1253,7 +1312,17 @@ 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()
@@ -1267,22 +1336,11 @@ void MB8877::cmd_stepout()
                status = FDC_ST_HEADENG | FDC_ST_BUSY;
        } else {
                status = 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;
-       } else {
-               seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
-       }               
-       seekvct = true;
-       
+       }
+
+       // Verify before execute command.
+       // Port from XM7.Thanks to Ryu Takegami.
+#if 1
        if(cmdreg & 4) {
                // verify
                if(trkreg != fdc[drvreg].track) {
@@ -1290,7 +1348,15 @@ 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)
@@ -1330,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);
        }
@@ -1396,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();
@@ -1431,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);
@@ -1442,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;
                        }
                }
@@ -1483,7 +1558,21 @@ void MB8877::cmd_forceint()
                    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);
@@ -1521,24 +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;
-                       }
-               } else {        // OS-9 2DD Access fix by Ryu Takegami
-                       if((disk[drvreg]->media_type != MEDIA_TYPE_2D) &&
-                          (disk[drvreg]->media_type != MEDIA_TYPE_UNK)) {
-                               if(disk[drvreg]->drive_type == DRIVE_TYPE_2D) {
-                                       track <<= 1;
-                               }
-                       }
-               }
-       }
-//#endif
+
        if(!disk[drvreg]->get_track(track, sidereg)){
                return FDC_ST_SEEKERR;
        }
@@ -1583,24 +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;
-                       }
-               } else {        // OS-9 2DD Access fix by Ryu Takegami
-                       if((disk[drvreg]->media_type != MEDIA_TYPE_2D) &&
-                          (disk[drvreg]->media_type != MEDIA_TYPE_UNK)) {
-                               if(disk[drvreg]->drive_type == DRIVE_TYPE_2D) {
-                                       track <<= 1;
-                               }
-                       }
-               }
-       }
-//#endif
+
+       
        if(!disk[drvreg]->get_track(track, sidereg)) {
                return FDC_ST_RECNFND;
        }
@@ -1679,24 +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;
-                       }
-               } else {        // OS-9 2DD Access fix by Ryu Takegami
-                       if((disk[drvreg]->media_type != MEDIA_TYPE_2D) &&
-                          (disk[drvreg]->media_type != MEDIA_TYPE_UNK)) {
-                               if(disk[drvreg]->drive_type == DRIVE_TYPE_2D) {
-                                       track <<= 1;
-                               }
-                       }
-               }
-       }
-//#endif
+       
        if(!disk[drvreg]->get_track(track, sidereg)) {
                return FDC_ST_RECNFND;
        }
@@ -1745,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;
 }
@@ -1787,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) {
@@ -1795,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;
 }
@@ -1804,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) {
@@ -1812,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;
 }
@@ -1855,8 +1898,11 @@ 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;
        }
 }
@@ -1884,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) {
@@ -1943,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  6
+//#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;
 }