OSDN Git Service

[UI][VM][MB8877][T3444][uPD765A] Add ON/OFF debug logging for FDCs.
[csp-qt/common_source_project-fm7.git] / source / src / vm / mb8877.cpp
1 /*
2         Skelton for retropc emulator
3
4         Origin : XM7
5         Author : Takeda.Toshiya
6         Date   : 2006.12.06 -
7
8         [ MB8877 / MB8876 / MB8866 / MB89311 ]
9 */
10
11 #include "mb8877.h"
12 #include "disk.h"
13 #include "noise.h"
14
15 #define FDC_ST_BUSY             0x01    // busy
16 #define FDC_ST_INDEX            0x02    // index hole
17 #define FDC_ST_DRQ              0x02    // data request
18 #define FDC_ST_TRACK00          0x04    // track0
19 #define FDC_ST_LOSTDATA         0x04    // data lost
20 #define FDC_ST_CRCERR           0x08    // crc error
21 #define FDC_ST_SEEKERR          0x10    // seek error
22 #define FDC_ST_RECNFND          0x10    // sector not found
23 #define FDC_ST_HEADENG          0x20    // head engage
24 #define FDC_ST_RECTYPE          0x20    // record type
25 #define FDC_ST_WRITEFAULT       0x20    // write fault
26 #define FDC_ST_WRITEP           0x40    // write protectdc
27 #define FDC_ST_NOTREADY         0x80    // media not inserted
28
29 #define FDC_CMD_TYPE1           1
30 #define FDC_CMD_RD_SEC          2
31 #define FDC_CMD_RD_MSEC         3
32 #define FDC_CMD_WR_SEC          4
33 #define FDC_CMD_WR_MSEC         5
34 #define FDC_CMD_RD_ADDR         6
35 #define FDC_CMD_RD_TRK          7
36 #define FDC_CMD_WR_TRK          8
37
38 #define EVENT_SEEK                              0
39 #define EVENT_SEEKEND_VERIFY    1
40 #define EVENT_SEARCH                    2
41 #define EVENT_DRQ                               3
42 #define EVENT_MULTI1                    4
43 #define EVENT_MULTI2                    5
44 #define EVENT_LOST                              6
45
46 //#define DRIVE_MASK            (MAX_DRIVE - 1)
47
48 #define DELAY_TIME              (disk[drvreg]->drive_type == DRIVE_TYPE_2HD ? 15000 : 30000)
49
50 static const int seek_wait_hi[4] = {3000,  6000, 10000, 16000}; // 2MHz
51 static const int seek_wait_lo[4] = {6000, 12000, 20000, 30000}; // 1MHz
52
53 void MB8877::cancel_my_event(int event)
54 {
55         if(register_id[event] != -1) {
56                 cancel_event(this, register_id[event]);
57                 register_id[event] = -1;
58         }
59 }
60
61 void MB8877::register_my_event(int event, double usec)
62 {
63         cancel_my_event(event);
64         register_event(this, (event << 8) | (cmdtype & 0xff), usec, false, &register_id[event]);
65 }
66
67 void MB8877::register_seek_event()
68 {
69         cancel_my_event(EVENT_SEEK);
70         if(fdc[drvreg].track == seektrk) {
71                 register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), 1, false, &register_id[EVENT_SEEK]);
72         } else if(disk[drvreg]->drive_type == DRIVE_TYPE_2HD) {
73                 register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), seek_wait_hi[cmdreg & 3], false, &register_id[EVENT_SEEK]);
74         } else {
75                 register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), seek_wait_lo[cmdreg & 3], false, &register_id[EVENT_SEEK]);
76         }
77         now_seek = true;
78 }
79
80 void MB8877::register_drq_event(int bytes)
81 {
82         double nusec = disk[drvreg]->get_usec_per_bytes(bytes); // For debug
83         double usec = nusec - get_passed_usec(prev_drq_clock);
84         bool nf = false;
85         
86         if(usec > nusec) usec = nusec; 
87         if(usec < 4) {
88                 usec = 4;
89         }
90         if(config.correct_disk_timing[drvreg]) {
91                 nf = true;
92         }
93         if(type_fm7) {
94                 if((disk[drvreg]->is_special_disk == SPECIAL_DISK_FM7_GAMBLER)) {
95                    /* (disk[drvreg]->is_special_disk == SPECIAL_DISK_FM77AV_PSYOBLADE) || */
96                         nf = true;
97                 }
98         }
99         if(nf) {
100                 switch(disk[drvreg]->media_type) {
101                 case MEDIA_TYPE_2D:
102                 case MEDIA_TYPE_2DD:
103                         if(usec > 7.0) usec = 7.0;
104                         break;
105                 case MEDIA_TYPE_2HD:
106                 case MEDIA_TYPE_144:
107                 case MEDIA_TYPE_UNK:
108                         usec = 4.0;
109                         break;
110                 default:
111                         usec = 4.0;
112                         break;
113                 }
114         }
115         if(fdc_debug_log) this->out_debug_log("DRQ REG: %dbytes %d:%d -> %f\n", bytes, get_current_clock(), prev_drq_clock, usec);
116         cancel_my_event(EVENT_DRQ);
117         register_event(this, (EVENT_DRQ << 8) | (cmdtype & 0xff), usec, false, &register_id[EVENT_DRQ]);
118 }
119
120 void MB8877::register_lost_event(int bytes)
121 {
122         cancel_my_event(EVENT_LOST);
123         register_event(this, (EVENT_LOST << 8) | (cmdtype & 0xff), disk[drvreg]->get_usec_per_bytes(bytes), false, &register_id[EVENT_LOST]);
124 }
125
126 bool MB8877::check_drive(void)
127 {
128         if(drvreg >= _max_drive) {
129                 status = FDC_ST_NOTREADY;
130                 //set_drq(false);
131                 set_irq(true);
132                 return false;
133         }
134         return true;
135 }
136
137 bool MB8877::check_drive2(void)
138 {
139         if(!check_drive()) {
140                 return false;
141         }
142         if(!is_disk_inserted(drvreg & 0x7f)) {
143                 status = FDC_ST_NOTREADY;
144                 set_irq(true);
145                 //set_drq(false);
146                 return false;
147         }
148         return true;
149 }
150
151 void MB8877::initialize()
152 {
153         DEVICE::initialize();
154         // initialize d88 handler
155         if(osd->check_feature(_T("MAX_DRIVE"))) {
156                 _max_drive = osd->get_feature_int_value(_T("MAX_DRIVE"));
157         } else if(osd->check_feature(_T("MAX_FD"))) {
158                 _max_drive = osd->get_feature_int_value(_T("MAX_FD"));
159         } else {
160                 _max_drive = 1;
161         }
162         _drive_mask = _max_drive - 1;
163         for(int i = 0; i < _max_drive; i++) {
164                 disk[i] = new DISK(emu);
165                 disk[i]->set_device_name(_T("%s/Disk #%d"), this_device_name, i + 1);
166         }
167         
168         if(osd->check_feature(_T("MB8877_NO_BUSY_AFTER_SEEK"))) {
169                 mb8877_no_busy_after_seek = true;
170         }
171         //if(osd->check_feature(_T("_FDC_DEBUG_LOG"))) {
172         //      fdc_debug_log = true;
173         //}
174         fdc_debug_log = config.special_debug_fdc;
175         
176         if(osd->check_feature(_T("HAS_MB8866"))) {
177                 type_mb8866 = true;
178                 invert_registers = true;
179                 set_device_name(_T("MB8866 FDC"));
180         }
181         if(osd->check_feature(_T("HAS_MB8876"))) {
182                 invert_registers = true;
183                 set_device_name(_T("MB8876 FDC"));
184         } else if(osd->check_feature(_T("HAS_MB89311"))) {
185                 type_mb89311 = true;
186                 set_device_name(_T("MB89311 FDC"));
187         } else {
188                 set_device_name(_T("MB8877 FDC"));
189         }               
190         if(osd->check_feature(_T("_X1")) || osd->check_feature(_T("_X1TWIN")) ||
191                 osd->check_feature(_T("_X1TURBO")) || osd->check_feature(_T("_X1TURBOZ"))) {
192                 type_x1 = true;
193         }
194         if(osd->check_feature(_T("_FM7")) || osd->check_feature(_T("_FM8")) ||
195                 osd->check_feature(_T("_FM77_VARIANTS")) || osd->check_feature(_T("_FM77AV_VARIANTS"))) {
196                 type_fm7 = true;
197                 if(osd->check_feature(_T("_FM77AV40")) || osd->check_feature(_T("_FM77AV40EX")) ||
198                    osd->check_feature(_T("_FM77AV40SX")) ||
199                    osd->check_feature(_T("_FM77AV20")) || osd->check_feature(_T("_FM77AV20EX"))) {
200                         type_fm77av_2dd = true;
201                 }
202         }
203         if(osd->check_feature(_T("_FMR50"))) {
204                 type_fmr50 = true;
205         }
206         if(osd->check_feature(_T("_FMR60"))) {
207                 type_fmr60 = true;
208         }
209         
210         // initialize noise
211         if(d_noise_seek != NULL) {
212                 d_noise_seek->set_device_name(_T("Noise Player (FDD Seek)"));
213                 if(!d_noise_seek->load_wav_file(_T("FDDSEEK.WAV"))) {
214                         if(!d_noise_seek->load_wav_file(_T("FDDSEEK1.WAV"))) {
215                                 d_noise_seek->load_wav_file(_T("SEEK.WAV"));
216                         }
217                 }
218                 d_noise_seek->set_mute(!config.sound_noise_fdd);
219         }
220         if(d_noise_head_down != NULL) {
221                 d_noise_head_down->set_device_name(_T("Noise Player (FDD Head Load)"));
222                 d_noise_head_down->load_wav_file(_T("HEADDOWN.WAV"));
223                 d_noise_head_down->set_mute(!config.sound_noise_fdd);
224         }
225         if(d_noise_head_up != NULL) {
226                 d_noise_head_up->set_device_name(_T("Noise Player (FDD Head Unload)"));
227                 d_noise_head_up->load_wav_file(_T("HEADUP.WAV"));
228                 d_noise_head_up->set_mute(!config.sound_noise_fdd);
229         }
230         
231         // initialize timing
232         memset(fdc, 0, sizeof(fdc));
233         for(int i = 0; i < 16; i++) {
234                 fdc[i].track = 40;  // OK?
235                 fdc[i].count_immediate = false;
236         }
237         // initialize fdc
238         seektrk = 0;
239         seekvct = true;
240         status = cmdreg = trkreg = secreg = datareg = sidereg = cmdtype = 0;
241         drvreg = 0;
242         prev_drq_clock = seekend_clock = 0;
243 }
244
245 void MB8877::release()
246 {
247         // release d88 handler
248         for(int i = 0; i < _max_drive; i++) {
249                 if(disk[i]) {
250                         disk[i]->close();
251                         delete disk[i];
252                 }
253         }
254 }
255
256 void MB8877::reset()
257 {
258         for(int i = 0; i < _max_drive; i++) {
259                 //fdc[i].track = 0; // Hold to track
260                 fdc[i].index = 0;
261                 fdc[i].access = false;
262         }
263         for(int i = 0; i < (int)array_length(register_id); i++) {
264                 register_id[i] = -1;
265         }
266         now_search = now_seek = drive_sel = false;
267         no_command = 0;
268         
269 //#ifdef HAS_MB89311
270         if(type_mb89311) {
271                 extended_mode = true;
272         } else {
273                 extended_mode = false;
274         }
275 //#endif
276 }
277
278 void MB8877::write_io8(uint32_t addr, uint32_t data)
279 {
280         bool ready;
281         
282         switch(addr & 3) {
283         case 0:
284                 // command reg
285                 cmdreg_tmp = cmdreg;
286 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
287                 if(invert_registers) {
288                         cmdreg = (~data) & 0xff;
289                 } else {
290 //#else
291                         cmdreg = data;
292                 }
293 //#endif
294                 process_cmd();
295                 no_command = 0;
296                 break;
297         case 1:
298                 // track reg
299 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
300                 if(invert_registers) {
301                         trkreg = (~data) & 0xff;
302                 } else {
303 //#else
304                         trkreg = data;
305                 }
306 //#endif
307                 if((status & FDC_ST_BUSY) && (fdc[drvreg].index == 0)) {
308                         // track reg is written after command starts
309                         if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
310                                 process_cmd();
311                         }
312                 }
313                 break;
314         case 2:
315                 // sector reg
316 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
317                 if(invert_registers) {
318                         secreg = (~data) & 0xff;
319                 } else {
320 //#else
321                         secreg = data;
322                 }
323 //#endif
324                 if((status & FDC_ST_BUSY) && (fdc[drvreg].index == 0)) {
325                         // sector reg is written after command starts
326                         if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
327                                 process_cmd();
328                         }
329                 }
330                 break;
331         case 3:
332                 // data reg
333 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
334                 if(invert_registers) {
335                         datareg = (~data) & 0xff;
336                 } else {
337 //#else
338                         datareg = data;
339                 }
340 //#endif
341                 ready = ((status & FDC_ST_DRQ) && !now_search);
342 //#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
343                 if(type_fm7) {
344                         if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
345                                 if(!motor_on) ready = false;
346                         }
347                 } else 
348 //#endif
349                 {
350                         if(!motor_on) ready = false;
351                 }
352 //              if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
353                 if(ready) {
354                         if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
355                                 // write or multisector write
356                                 if(fdc[drvreg].index < disk[drvreg]->sector_size.sd) {
357                                         if(!disk[drvreg]->write_protected) {
358                                                 if(disk[drvreg]->sector[fdc[drvreg].index] != datareg) {
359                                                         disk[drvreg]->sector[fdc[drvreg].index] = datareg;
360                                                         sector_changed = true;
361                                                 }
362                                                 // dm, ddm
363                                                 disk[drvreg]->set_deleted((cmdreg & 1) != 0);
364                                         } else {
365                                                 status |= FDC_ST_WRITEFAULT;
366                                                 status &= ~FDC_ST_BUSY;
367                                                 cmdtype = 0;
368                                                 set_irq(true);
369                                         }
370                                         //fdc[drvreg].index++;
371                                 }
372                                 if((fdc[drvreg].index + 1) >= disk[drvreg]->sector_size.sd) {
373                                         if(cmdtype == FDC_CMD_WR_SEC) {
374                                                 // single sector
375 //#ifdef _FDC_DEBUG_LOG
376                                                 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
377 //#endif
378                                                 status &= ~FDC_ST_BUSY;
379                                                 cmdtype = 0;
380                                                 set_irq(true);
381                                         } else {
382                                                 // multisector
383 //#ifdef _FDC_DEBUG_LOG
384                                                 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR (SEARCH NEXT)\n"));
385 //#endif
386                                                 // 2HD: 360rpm, 10410bytes/track -> 0.06246bytes/us
387                                                 register_my_event(EVENT_MULTI1, 30); // 0.06246bytes/us * 30us = 1.8738bytes < GAP3
388                                                 register_my_event(EVENT_MULTI2, 60); // 0.06246bytes/us * 60us = 3.7476bytes < GAP3
389                                         }
390                                         sector_changed = false;
391                                 } else if(status & FDC_ST_DRQ) {
392                                         if(fdc[drvreg].index == 0) {
393                                                 register_drq_event(fdc[drvreg].bytes_before_2nd_drq);
394                                         } else {
395                                                 register_drq_event(1);
396                                         }
397                                         if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
398                                 }
399                                 status &= ~FDC_ST_DRQ;
400                         } else if(cmdtype == FDC_CMD_WR_TRK) {
401                                 // write track
402                                 if(fdc[drvreg].index < disk[drvreg]->get_track_size()) {
403                                         if(!disk[drvreg]->write_protected) {
404                                                 if(fdc[drvreg].index == 0) {
405                                                         disk[drvreg]->format_track(fdc[drvreg].track, sidereg);
406                                                         fdc[drvreg].id_written = false;
407                                                         fdc[drvreg].side = sidereg;
408                                                         fdc[drvreg].side_changed = false;
409                                                 }
410                                                 if(fdc[drvreg].side != sidereg) {
411                                                         fdc[drvreg].side_changed = true;
412                                                 }
413                                                 if(fdc[drvreg].side_changed) {
414                                                         // abort write track because disk side is changed
415                                                 } else if(datareg == 0xf5) {
416                                                         // write a1h in missing clock
417                                                 } else if(datareg == 0xf6) {
418                                                         // write c2h in missing clock
419                                                 } else if(datareg == 0xf7) {
420                                                         // write crc
421                                                         if(!fdc[drvreg].id_written) {
422                                                                 // insert new sector with data crc error
423 write_id:
424                                                                 uint8_t c = 0, h = 0, r = 0, n = 0;
425                                                                 fdc[drvreg].id_written = true;
426                                                                 fdc[drvreg].sector_found = false;
427                                                                 if(fdc[drvreg].index >= 4) {
428                                                                         c = disk[drvreg]->track[fdc[drvreg].index - 4];
429                                                                         h = disk[drvreg]->track[fdc[drvreg].index - 3];
430                                                                         r = disk[drvreg]->track[fdc[drvreg].index - 2];
431                                                                         n = disk[drvreg]->track[fdc[drvreg].index - 1];
432                                                                 }
433                                                                 fdc[drvreg].sector_length = 0x80 << (n & 3);
434                                                                 fdc[drvreg].sector_index = 0;
435                                                                 disk[drvreg]->insert_sector(c, h, r, n, false, true, 0xe5, fdc[drvreg].sector_length);
436                                                         } else if(fdc[drvreg].sector_found) {
437                                                                 // clear data crc error if all sector data are written
438                                                                 if(fdc[drvreg].sector_index == fdc[drvreg].sector_length) {
439                                                                         disk[drvreg]->set_data_crc_error(false);
440                                                                 }
441                                                                 fdc[drvreg].id_written = false;
442                                                         } else {
443                                                                 // data mark of current sector is not written
444                                                                 disk[drvreg]->set_data_mark_missing();
445                                                                 goto write_id;
446                                                         }
447                                                 } else if(fdc[drvreg].id_written) {
448                                                         if(fdc[drvreg].sector_found) {
449                                                                 // sector data
450                                                                 if(fdc[drvreg].sector_index < fdc[drvreg].sector_length) {
451                                                                         disk[drvreg]->sector[fdc[drvreg].sector_index] = datareg;
452                                                                 }
453                                                                 fdc[drvreg].sector_index++;
454                                                         } else if(datareg == 0xf8 || datareg == 0xfb) {
455                                                                 // data mark
456                                                                 disk[drvreg]->set_deleted(datareg == 0xf8);
457                                                                 fdc[drvreg].sector_found = true;
458                                                         }
459                                                 }
460                                                 disk[drvreg]->track[fdc[drvreg].index] = datareg;
461                                         } else {
462                                                 status |= FDC_ST_WRITEFAULT;
463                                                 status &= ~FDC_ST_BUSY;
464                                                 status &= ~FDC_ST_DRQ;
465                                                 cmdtype = 0;
466                                                 set_irq(true);
467                                         }
468                                         //fdc[drvreg].index++;
469                                 }
470                                 if((fdc[drvreg].index + 1) >= disk[drvreg]->get_track_size()) {
471                                         if(!disk[drvreg]->write_protected) {
472                                                 if(fdc[drvreg].id_written && !fdc[drvreg].sector_found) {
473                                                         // data mark of last sector is not written
474                                                         disk[drvreg]->set_data_mark_missing();
475                                                 }
476                                                 disk[drvreg]->sync_buffer();
477                                         }
478                                         status &= ~FDC_ST_BUSY;
479                                         cmdtype = 0;
480                                         set_irq(true);
481                                 } else if(status & FDC_ST_DRQ) {
482                                         if(fdc[drvreg].index == 0) {
483                                                 register_drq_event(fdc[drvreg].bytes_before_2nd_drq);
484                                         } else {
485                                                 register_drq_event(1);
486                                         }
487                                         if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
488                                 }
489                                 status &= ~FDC_ST_DRQ;
490                         }
491                         if(!(status & FDC_ST_DRQ)) {
492                                 cancel_my_event(EVENT_LOST);
493                                 set_drq(false);
494                                 fdc[drvreg].access = true;
495                         }
496                 }
497                 break;
498         }
499 }
500
501 uint32_t MB8877::read_io8(uint32_t addr)
502 {
503         uint32_t val;
504         bool not_ready;
505         bool ready;
506         
507         switch(addr & 3) {
508         case 0:
509                 // status reg
510                 if(now_search) {
511                         // now sector search
512                         val = FDC_ST_BUSY;
513                 } else {
514                         // disk not inserted, motor stop
515                         not_ready = !disk[drvreg]->inserted;
516 //#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
517                         if(type_fm7){
518                                 if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
519                                         if(!motor_on) not_ready = true;
520                                 }
521                         } else
522 //#endif
523                         {
524                                 if(!motor_on) not_ready = true;
525                         }
526 //                      if(!disk[drvreg]->inserted || !motor_on) {
527                         if(not_ready) {
528                                 status |= FDC_ST_NOTREADY;
529                         } else {
530                                 status &= ~FDC_ST_NOTREADY;
531                         }
532                         // write protected
533                         if(cmdtype == FDC_CMD_TYPE1 || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) {
534                                 if(disk[drvreg]->inserted && disk[drvreg]->write_protected) {
535                                         status |= FDC_ST_WRITEP;
536                                 } else {
537                                         status &= ~FDC_ST_WRITEP;
538                                 }
539                         } else {
540                                 status &= ~FDC_ST_WRITEP;
541                         }
542                         // track0, index hole
543                         if(cmdtype == FDC_CMD_TYPE1) {
544                                 if(fdc[drvreg].track == 0) {
545                                         status |= FDC_ST_TRACK00;
546                                 } else {
547                                         status &= ~FDC_ST_TRACK00;
548                                 }
549                                 // index hole signal width is 5msec (thanks Mr.Sato)
550                                 if(!(status & FDC_ST_NOTREADY) && get_cur_position() < disk[drvreg]->get_bytes_per_usec(5000)) {
551                                         status |= FDC_ST_INDEX;
552                                 } else {
553                                         status &= ~FDC_ST_INDEX;
554                                 }
555                         }
556                         // show busy a moment
557                         val = status;
558                         if(cmdtype == FDC_CMD_TYPE1 && !now_seek) {
559                                 status &= ~FDC_ST_BUSY;
560 //#ifdef MB8877_NO_BUSY_AFTER_SEEK
561                                 if(mb8877_no_busy_after_seek) {
562                                         //#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
563                                         if(type_fm7) {
564                                                 if(disk[0]->is_special_disk != SPECIAL_DISK_FM7_XANADU2_D) {
565                                                         val &= ~FDC_ST_BUSY;
566                                                 }
567                                         } else
568                                                 //#endif
569                                         {
570                                                 val &= ~FDC_ST_BUSY;
571                                         }
572                                 }
573 //#endif
574                         }
575                 }
576                 if(cmdtype == 0 && !(status & FDC_ST_NOTREADY)) {
577                         // MZ-2000 HuBASIC invites NOT READY status
578                         if(++no_command == 16) {
579                                 val |= FDC_ST_NOTREADY;
580                         }
581                 } else {
582                         no_command = 0;
583                 }
584                 // reset irq/drq
585                 if(!(status & FDC_ST_DRQ)) {
586                         set_drq(false);
587                 }
588                 if(!(status & FDC_ST_BUSY)) {
589                         set_irq(false);
590                 }
591 //#ifdef _FDC_DEBUG_LOG
592                 if(fdc_debug_log) this->out_debug_log(_T("FDC\tSTATUS=%2x\n"), val);
593 //#endif
594 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
595                         if(invert_registers) {
596                                 return (~val) & 0xff;
597 //#else
598                         } else {
599                                 return val;
600                         }
601 //#endif
602         case 1:
603                 // track reg
604 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
605                         if(invert_registers) {
606                                 return (~trkreg) & 0xff;
607                         } else {
608 //#else
609                                 return trkreg;
610                         }
611 //#endif
612         case 2:
613                 // sector reg
614 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
615                         if(invert_registers) {
616                                 return (~secreg) & 0xff;
617                         } else {
618 //#else
619                                 return secreg;
620                         }
621 //#endif
622         case 3:
623                 // data reg
624                 ready = ((status & FDC_ST_DRQ) && !now_search);
625 //#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
626                 if(type_fm7) {
627                         if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
628                                 if(!motor_on) ready = false;
629                         }
630                 } else
631 //#endif
632                 {
633                         if(!motor_on) ready = false;
634                 }
635 //              if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
636                 if(ready) {
637                         if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC) {
638                                 // read or multisector read
639                                 if(fdc[drvreg].index < disk[drvreg]->sector_size.sd) {
640                                         datareg = disk[drvreg]->sector[fdc[drvreg].index];
641                                 }
642                                 if((fdc[drvreg].index + 1) >= disk[drvreg]->sector_size.sd) {  // Reading complete this sector.
643
644                                         if(disk[drvreg]->data_crc_error && !disk[drvreg]->ignore_crc()) {
645                                                 // data crc error
646 //#ifdef _FDC_DEBUG_LOG
647                                                 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR (DATA CRC ERROR)\n"));
648 //#endif
649                                                 status |= FDC_ST_CRCERR;
650                                                 status &= ~FDC_ST_BUSY;
651                                                 cmdtype = 0;
652                                                 set_irq(true);
653                                         } else if(cmdtype == FDC_CMD_RD_SEC) {
654                                                 // single sector
655 //#ifdef _FDC_DEBUG_LOG
656                                                 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
657 //#endif
658                                                 status &= ~FDC_ST_BUSY;
659                                                 cmdtype = 0;
660                                                 set_irq(true);
661                                         } else {
662                                                 // multisector
663 //#ifdef _FDC_DEBUG_LOG
664                                                 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR (SEARCH NEXT)\n"));
665 //#endif
666                                                 register_my_event(EVENT_MULTI1, 30);
667                                                 register_my_event(EVENT_MULTI2, 60);
668                                         }
669                                 } else { // Still data remain.
670                                         register_drq_event(1);
671                                         if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
672                                 }
673                                 status &= ~FDC_ST_DRQ;
674                         } else if(cmdtype == FDC_CMD_RD_ADDR) {
675                                 // read address
676                                 if(fdc[drvreg].index < 6) {
677                                         datareg = disk[drvreg]->id[fdc[drvreg].index];
678                                         //fdc[drvreg].index++;
679                                 }
680                                 if((fdc[drvreg].index + 1) >= 6) {
681                                         if(disk[drvreg]->addr_crc_error && !disk[drvreg]->ignore_crc()) {
682                                                 // id crc error
683                                                 status |= FDC_ST_CRCERR;
684                                         }
685                                         status &= ~FDC_ST_BUSY;
686                                         cmdtype = 0;
687                                         set_irq(true);
688 //#ifdef _FDC_DEBUG_LOG
689                                         if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF ID FIELD\n"));
690 //#endif
691                                 } else {
692                                         register_drq_event(1);
693                                         if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
694                                 }
695                                 status &= ~FDC_ST_DRQ;
696                         } else if(cmdtype == FDC_CMD_RD_TRK) {
697                                 // read track
698                                 if(fdc[drvreg].index < disk[drvreg]->get_track_size()) {
699                                         datareg = disk[drvreg]->track[fdc[drvreg].index];
700                                         //fdc[drvreg].index++;
701                                 }
702                                 if((fdc[drvreg].index + 1) >= disk[drvreg]->get_track_size()) {
703 //#ifdef _FDC_DEBUG_LOG
704                                         if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF TRACK\n"));
705 ///#endif
706                                         status &= ~FDC_ST_BUSY;
707                                         status |= FDC_ST_LOSTDATA;
708                                         cmdtype = 0;
709                                         set_irq(true);
710                                 } else {
711                                         register_drq_event(1);
712                                         if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
713                                 }
714                                 status &= ~FDC_ST_DRQ;
715                         }
716                         if(!(status & FDC_ST_DRQ)) {
717                                 cancel_my_event(EVENT_LOST);
718                                 set_drq(false);
719                                 fdc[drvreg].access = true;
720                         }
721                 }
722 //#ifdef _FDC_DEBUG_LOG
723                 if(fdc_debug_log) this->force_out_debug_log(_T("FDC\tDATA=%2x\n"), datareg); // emu->force_out_debug_log()
724 //#endif
725 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
726                 if(invert_registers) {
727                         return (~datareg) & 0xff;
728                 } else {
729 //#else
730                         return datareg;
731                 }
732 //#endif
733         }
734         return 0xff;
735 }
736
737 void MB8877::write_dma_io8(uint32_t addr, uint32_t data)
738 {
739         write_io8(3, data);
740 }
741
742 uint32_t MB8877::read_dma_io8(uint32_t addr)
743 {
744         return read_io8(3);
745 }
746
747 void MB8877::write_signal(int id, uint32_t data, uint32_t mask)
748 {
749         if(id == SIG_MB8877_DRIVEREG) {
750                 drvreg = data & _drive_mask;
751                 drive_sel = true;
752                 seekend_clock = get_current_clock();
753         } else if(id == SIG_MB8877_SIDEREG) {
754                 sidereg = (data & mask) ? 1 : 0;
755         } else if(id == SIG_MB8877_MOTOR) {
756                 motor_on = ((data & mask) != 0);
757         } 
758 }
759
760 uint32_t MB8877::read_signal(int ch)
761 {
762         if(ch == SIG_MB8877_DRIVEREG) {
763                 return drvreg & _drive_mask;
764         } else if(ch == SIG_MB8877_SIDEREG) {
765                 return sidereg & 1;
766         } else if(ch == SIG_MB8877_MOTOR) {
767                 return motor_on ? 1 : 0;
768         }
769         
770         // get access status
771         uint32_t stat = 0;
772         for(int i = 0; i < _max_drive; i++) {
773                 if(fdc[i].access) {
774                         stat |= 1 << i;
775                 }
776                 fdc[i].access = false;
777         }
778         if(now_search) {
779                 stat |= 1 << drvreg;
780         }
781         return stat;
782 }
783
784 void MB8877::event_callback(int event_id, int err)
785 {
786         int event = event_id >> 8;
787         int cmd = event_id & 0xff;
788         //bool need_after_irq = false;
789         register_id[event] = -1;
790         
791         // cancel event if the command is finished or other command is executed
792         if(cmd != cmdtype) {
793                 if(event == EVENT_SEEK || event == EVENT_SEEKEND_VERIFY) {
794                         now_seek = false;
795                 } else if(event == EVENT_SEARCH) {
796                         now_search = false;
797                 }
798                 return;
799         }
800         
801         switch(event) {
802         case EVENT_SEEK:
803 //#ifdef _FDC_DEBUG_LOG
804                 //this->out_debug_log(_T("FDC\tSEEK START\n"));
805 //#endif
806                 if(seektrk > fdc[drvreg].track) {
807                         fdc[drvreg].track++;
808                         if(d_noise_seek != NULL) d_noise_seek->play();
809                         //need_after_irq = true;
810                 } else if(seektrk < fdc[drvreg].track) {
811                         fdc[drvreg].track--;
812                         if(d_noise_seek != NULL) d_noise_seek->play();
813                         //need_after_irq = true;
814                 }
815                 if((cmdreg & 0x10) || ((cmdreg & 0xf0) == 0)) {
816                         trkreg = fdc[drvreg].track;
817                 }
818                 if(seektrk != fdc[drvreg].track) {
819                         //if(need_after_irq) {
820                                 //set_drq(false);
821                                 //set_irq(true);  // 20180118 K.O Turn ON IRQ -> Turn OFF DRQ
822                         //}
823                         register_seek_event();
824                         break;
825                 }
826                 seekend_clock = get_current_clock();
827 //#ifdef HAS_MB89311
828                 if(type_mb89311) {
829                         if(extended_mode) {
830                                 if((cmdreg & 0xf4) == 0x44) {
831                                         // read-after-seek
832                                         cmd_readdata(true);
833                                         break;
834                                 } else if((cmdreg & 0xf4) == 0x64) {
835                                         // write-after-seek
836                                         cmd_writedata(true);
837                                         break;
838                                 }
839                         }
840                 }
841 //#endif
842                 status_tmp = status;
843                 if(cmdreg & 4) {
844                         // verify
845                         status_tmp |= search_track();
846                         double time;
847                         if(status_tmp & FDC_ST_SEEKERR) {
848                                 time = get_usec_to_detect_index_hole(5, true);
849                         } else {
850                                 time = get_usec_to_next_trans_pos(true);
851                         }
852                         // 20180128 K.O If seek completed, delay to make IRQ/DRQ at SEEKEND_VERIFY.
853                         register_my_event(EVENT_SEEKEND_VERIFY, time);
854                         break;
855                 }
856 //      case EVENT_SEEKEND: // Separate SEEK and SEEKEND when verifying. 20180128 K.O
857                 now_seek = false;
858                 status = status_tmp;
859                 status &= (uint8_t)(~FDC_ST_BUSY);      // 20180118 K.O Turn off BUSY flag.
860                 set_drq(false);
861                 set_irq(true);  // 20180118 K.O Turn ON IRQ -> Turn OFF DRQ
862                 break;
863         case EVENT_SEEKEND_VERIFY: // Separate SEEK and SEEKEND when verifying. 20180128 K.O
864                 now_seek = false;
865                 status &= (uint8_t)(~FDC_ST_BUSY);      // 20180118 K.O Turn off BUSY flag.
866                 set_drq(false);
867                 set_irq(true);  // 20180118 K.O Turn ON IRQ -> Turn OFF DRQ
868 //#ifdef _FDC_DEBUG_LOG
869                 //this->out_debug_log(_T("FDC\tSEEK END\n"));
870 //#endif
871                 break;
872         case EVENT_SEARCH:
873                 now_search = false;
874                 if(status_tmp & FDC_ST_RECNFND) {
875 //#if defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
876                         if(type_x1) {
877                                 // for SHARP X1 Batten Tanuki
878                                 if(disk[drvreg]->is_special_disk == SPECIAL_DISK_X1_BATTEN && drive_sel) {
879                                         status_tmp &= ~FDC_ST_RECNFND;
880                                 }
881                         }
882 //#endif
883 //#ifdef _FDC_DEBUG_LOG
884                         if(fdc_debug_log) this->out_debug_log(_T("FDC\tSEARCH NG\n"));
885 //#endif
886                         status = status_tmp & ~(FDC_ST_BUSY | FDC_ST_DRQ);
887                         cmdtype = 0;
888                         set_drq(false);
889                         set_irq(true);
890                 } else if(status_tmp & FDC_ST_WRITEFAULT) {
891 //#ifdef _FDC_DEBUG_LOG
892                                 if(fdc_debug_log) this->out_debug_log(_T("FDC\tWRITE PROTECTED\n"));
893 //#endif
894                         status = status_tmp & ~(FDC_ST_BUSY | FDC_ST_DRQ);
895                         cmdtype = 0;
896                         set_drq(false);
897                         set_irq(true);
898                 } else {
899                         status = status_tmp | (FDC_ST_BUSY | FDC_ST_DRQ);
900                         if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
901                                 register_lost_event(8);
902                         } else if(cmdtype == FDC_CMD_WR_TRK) {
903                                 register_lost_event(3);
904                         } else {
905                                 register_lost_event(1);
906                         }
907                         fdc[drvreg].cur_position = fdc[drvreg].next_trans_position;
908                         fdc[drvreg].prev_clock = prev_drq_clock = get_current_clock();
909                         set_drq(true);
910                         drive_sel = false;
911                         if(fdc_debug_log) this->out_debug_log("DRQ ON@SEARCH: %d\n", prev_drq_clock);
912 //#ifdef _FDC_DEBUG_LOG
913                         if(fdc_debug_log) this->out_debug_log(_T("FDC\tSEARCH OK\n"));
914 //#endif
915                 }
916                 break;
917         case EVENT_DRQ:
918                 if(status & FDC_ST_BUSY) {
919                         status |= FDC_ST_DRQ;
920                         register_lost_event(1);
921                         if((cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) && fdc[drvreg].index == 0) {
922                                 fdc[drvreg].cur_position = (fdc[drvreg].cur_position + fdc[drvreg].bytes_before_2nd_drq) % disk[drvreg]->get_track_size();
923                         } else {
924                                 fdc[drvreg].cur_position = (fdc[drvreg].cur_position + 1) % disk[drvreg]->get_track_size();
925                         }
926                         if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC ||
927                            cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC ||
928                            cmdtype == FDC_CMD_RD_TRK || cmdtype == FDC_CMD_WR_TRK  ||
929                            cmdtype == FDC_CMD_RD_ADDR) {
930                                 if(!(fdc[drvreg].count_immediate)) fdc[drvreg].index++;
931                         }
932                         fdc[drvreg].prev_clock = prev_drq_clock = get_current_clock();
933
934                         set_drq(true);
935                         if(fdc_debug_log) this->out_debug_log("DRQ ON@DRQ: %d\n", prev_drq_clock);
936 //#ifdef _FDC_DEBUG_LOG
937                         //this->out_debug_log(_T("FDC\tDRQ!\n"));
938 //#endif
939                 }
940                 break;
941         case EVENT_MULTI1:
942                 secreg++;
943                 break;
944         case EVENT_MULTI2:
945                 if(cmdtype == FDC_CMD_RD_MSEC) {
946                         cmd_readdata(false);
947                 } else if(cmdtype == FDC_CMD_WR_MSEC) {
948                         cmd_writedata(false);
949                 }
950                 break;
951         case EVENT_LOST:
952                 if(status & FDC_ST_BUSY) {
953 //#ifdef _FDC_DEBUG_LOG
954                         if(fdc_debug_log) this->out_debug_log(_T("FDC\tDATA LOST\n"));
955 //#endif
956                         if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) {
957                                 if(fdc[drvreg].index == 0) { // HEAD of REGION
958                                         cmdtype = 0;
959                                         //if((status & FDC_ST_DRQ) != 0) { // 20180130 FORCE DOWN DRQ ON LOST-DATA.
960                                                 status |= FDC_ST_LOSTDATA;
961                                                 status &= (uint8_t)(~(FDC_ST_DRQ | FDC_ST_BUSY));
962                                                 set_drq(false);
963                                                 //}
964                                                 set_irq(true);
965                                 } else { // STILL WRITING
966                                         write_io8(3, 0x00);
967                                         //if((status & FDC_ST_DRQ) != 0) {
968                                                 status |= FDC_ST_LOSTDATA;
969                                                 status &= (uint8_t)(~(FDC_ST_DRQ | FDC_ST_BUSY));
970                                                 set_irq(true);
971                                                 set_drq(false);
972                                                 //cmdtype = 0;
973                                                 //}
974                                 }
975                         } else { // READ 
976                                 //if((status & FDC_ST_DRQ) != 0) {
977                                         status |= FDC_ST_LOSTDATA;
978                                         status &= (uint8_t)(~(FDC_ST_DRQ | FDC_ST_BUSY));
979                                         set_irq(true);
980                                         set_drq(false);
981                                         //}
982                                 read_io8(3);
983                         }
984                         status |= FDC_ST_LOSTDATA;
985                 }
986                 break;
987         }
988 }
989
990 // ----------------------------------------------------------------------------
991 // command
992 // ----------------------------------------------------------------------------
993
994 void MB8877::process_cmd()
995 {
996         set_irq(false);
997         set_drq(false);
998         
999 //#ifdef HAS_MB89311
1000         // MB89311 mode commands
1001         if(type_mb89311) {
1002                                 if(cmdreg == 0xfc) {
1003                                 // delay (may be only in extended mode)
1004 //#ifdef _FDC_DEBUG_LOG
1005                                 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (DELAY   ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1006 //#endif
1007                                 cmdtype = status = 0;
1008                                 return;
1009                         } else if(cmdreg == 0xfd) {
1010                                 // assign parameter
1011 //#ifdef _FDC_DEBUG_LOG
1012                                 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (ASGN PAR) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1013 //#endif
1014                                 cmdtype = status = 0;
1015                                 return;
1016                         } else if(cmdreg == 0xfe) {
1017                                 // assign mode
1018 //#ifdef _FDC_DEBUG_LOG
1019                                 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (ASGN MOD) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1020 //#endif
1021                                 extended_mode = !extended_mode;
1022                                 cmdtype = status = 0;
1023                                 return;
1024                         } else if(cmdreg == 0xff) {
1025                                 // reset (may be only in extended mode)
1026 //#ifdef _FDC_DEBUG_LOG
1027                                 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (RESET   ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1028 //#endif
1029                                 cmd_forceint();
1030                                 extended_mode = true;
1031                                 return;
1032                         } else if(extended_mode) {
1033                                 // type-1
1034                                 if((cmdreg & 0xeb) == 0x21) {
1035 //#ifdef _FDC_DEBUG_LOG
1036                                 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (STEP IN ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1037 //#endif
1038                                 cmd_stepin();
1039                                 return;
1040                         } else if((cmdreg & 0xeb) == 0x22) {
1041 //#ifdef _FDC_DEBUG_LOG
1042                                 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (STEP OUT) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1043 //#endif
1044                                 cmd_stepout();
1045                                 return;
1046                                 // type-2
1047                         } else if((cmdreg & 0xf4) == 0x44) {
1048                                 // read-after-seek
1049 //#ifdef _FDC_DEBUG_LOG
1050                                         if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (RDaftSEK) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1051 //#endif
1052                                         cmd_seek();
1053                                         return;
1054                                 } else if((cmdreg & 0xf4) == 0x64) {
1055                                         // write-after-seek
1056 //#ifdef _FDC_DEBUG_LOG
1057                                 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (WRaftSEK) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1058 //#endif
1059                                 cmd_seek();
1060                         return;
1061                         // type-3
1062                         } else if((cmdreg & 0xfb) == 0xf1) {
1063                                         // format
1064 //#ifdef _FDC_DEBUG_LOG
1065                                 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (FORMAT  ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1066 //#endif
1067                                 cmd_format();
1068                                 return;
1069                                 }
1070                                 }
1071         }
1072 //#endif
1073         
1074         // MB8877 mode commands
1075 //#ifdef _FDC_DEBUG_LOG
1076         static const _TCHAR *cmdstr[0x10] = {
1077                 _T("RESTORE "), _T("SEEK    "), _T("STEP    "), _T("STEP    "),
1078                 _T("STEP IN "), _T("STEP IN "), _T("STEP OUT"), _T("STEP OUT"),
1079                 _T("RD DATA "), _T("RD DATA "), _T("RD DATA "), _T("WR DATA "),
1080                 _T("RD ADDR "), _T("FORCEINT"), _T("RD TRACK"), _T("WR TRACK")
1081         };
1082         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);
1083 //#endif
1084         
1085         switch(cmdreg & 0xf8) {
1086         // type-1
1087         case 0x00: case 0x08:
1088                 cmd_restore();
1089                 update_head_flag(drvreg, (cmdreg & 8) != 0);
1090                 break;
1091         case 0x10: case 0x18:
1092                 cmd_seek();
1093                 update_head_flag(drvreg, (cmdreg & 8) != 0);
1094                 break;
1095         case 0x20: case 0x28:
1096         case 0x30: case 0x38:
1097                 cmd_step();
1098                 update_head_flag(drvreg, (cmdreg & 8) != 0);
1099                 break;
1100         case 0x40: case 0x48:
1101         case 0x50: case 0x58:
1102                 cmd_stepin();
1103                 update_head_flag(drvreg, (cmdreg & 8) != 0);
1104                 break;
1105         case 0x60: case 0x68:
1106         case 0x70: case 0x78:
1107                 cmd_stepout();
1108                 update_head_flag(drvreg, (cmdreg & 8) != 0);
1109                 break;
1110         // type-2
1111         case 0x80: case 0x88:
1112         case 0x90: case 0x98:
1113                 cmd_readdata(true);
1114                 update_head_flag(drvreg, true);
1115                 break;
1116         case 0xa0:case 0xa8:
1117         case 0xb0: case 0xb8:
1118                 cmd_writedata(true);
1119                 update_head_flag(drvreg, true);
1120                 break;
1121         // type-3
1122         case 0xc0:
1123                 cmd_readaddr();
1124                 update_head_flag(drvreg, true);
1125                 break;
1126         case 0xe0:
1127                 cmd_readtrack();
1128                 update_head_flag(drvreg, true);
1129                 break;
1130         case 0xf0:
1131                 cmd_writetrack();
1132                 update_head_flag(drvreg, true);
1133                 break;
1134         // type-4
1135         case 0xd0: case 0xd8:
1136                 cmd_forceint();
1137                 break;
1138         // unknown command
1139         default:
1140                 break;
1141         }
1142 }
1143
1144 void MB8877::cmd_restore()
1145 {
1146         // type-1 restore
1147         cmdtype = FDC_CMD_TYPE1;
1148         if(!check_drive()) {
1149                 return;
1150         }
1151         if((cmdreg & 0x08) != 0) { // Head engage
1152                 status = FDC_ST_HEADENG | FDC_ST_BUSY;
1153         } else {
1154                 status = FDC_ST_BUSY;
1155         }
1156         set_irq(false);
1157         set_drq(false);
1158
1159         if(fdc[drvreg].track < 0) {
1160                 fdc[drvreg].track = 0;
1161                 trkreg = 0;
1162         } else if(fdc[drvreg].track >= 80) {
1163                 fdc[drvreg].track = 80;
1164                 trkreg = 80;
1165         } else {
1166                 trkreg = fdc[drvreg].track;
1167         }
1168         datareg = 0;
1169         
1170         seektrk = 0;
1171         seekvct = true;
1172         
1173         register_seek_event();
1174 }
1175
1176 void MB8877::cmd_seek()
1177 {
1178         // type-1 seek
1179         cmdtype = FDC_CMD_TYPE1;
1180         if(!check_drive()) {
1181                 return;
1182         }
1183         if((cmdreg & 0x08) != 0) { // Head engage
1184                 status = FDC_ST_HEADENG | FDC_ST_BUSY;
1185         } else {
1186                 status = FDC_ST_BUSY;
1187         }               
1188         
1189 //      seektrk = (uint8_t)(fdc[drvreg].track + datareg - trkreg);
1190         seektrk = datareg;
1191 //#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
1192         if(type_fm77av_2dd) {
1193                 if(disk[drvreg]->drive_type != DRIVE_TYPE_2D) {
1194                         seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1195                 } else {
1196                         seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1197                 }
1198         } else  if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
1199                 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1200         } else {
1201                 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1202         }               
1203         seekvct = !(seektrk > fdc[drvreg].track);
1204         
1205         if(cmdreg & 4) {
1206                 // verify
1207                 if(trkreg != fdc[drvreg].track) {
1208                         status |= FDC_ST_SEEKERR;
1209                         trkreg = fdc[drvreg].track;
1210                 }
1211         }
1212         register_seek_event();
1213 }
1214
1215 void MB8877::cmd_step()
1216 {
1217         // type-1 step
1218         if(seekvct) {
1219                 cmd_stepout();
1220         } else {
1221                 cmd_stepin();
1222         }
1223 }
1224
1225 void MB8877::cmd_stepin()
1226 {
1227         // type-1 step in
1228         cmdtype = FDC_CMD_TYPE1;
1229         if(!check_drive()) {
1230                 return;
1231         }
1232         if((cmdreg & 0x08) != 0) { // Head engage
1233                 status = FDC_ST_HEADENG | FDC_ST_BUSY;
1234         } else {
1235                 status = FDC_ST_BUSY;
1236         }               
1237         seektrk = fdc[drvreg].track + 1;
1238         if(type_fm77av_2dd) {
1239                 if(disk[drvreg]->drive_type != DRIVE_TYPE_2D) {
1240                         seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1241                 } else {
1242                         seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1243                 }
1244         } else  if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
1245                 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1246         } else {
1247                 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1248         }               
1249         seekvct = false;
1250         
1251         if(cmdreg & 4) {
1252                 // verify
1253                 if(trkreg != fdc[drvreg].track) {
1254                         status |= FDC_ST_SEEKERR;
1255 //                      trkreg = fdc[drvreg].track;
1256                 }
1257         }
1258         register_seek_event();
1259 }
1260
1261 void MB8877::cmd_stepout()
1262 {
1263         // type-1 step out
1264         cmdtype = FDC_CMD_TYPE1;
1265         if(!check_drive()) {
1266                 return;
1267         }
1268         if((cmdreg & 0x08) != 0) { // Head engage
1269                 status = FDC_ST_HEADENG | FDC_ST_BUSY;
1270         } else {
1271                 status = FDC_ST_BUSY;
1272         }               
1273         
1274         seektrk = fdc[drvreg].track - 1;
1275         if(type_fm77av_2dd) {
1276                 if(disk[drvreg]->drive_type != DRIVE_TYPE_2D) {
1277                         seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1278                 } else {
1279                         seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1280                 }
1281         } else  if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
1282                 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1283         } else {
1284                 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1285         }               
1286         seekvct = true;
1287         
1288         if(cmdreg & 4) {
1289                 // verify
1290                 if(trkreg != fdc[drvreg].track) {
1291                         status |= FDC_ST_SEEKERR;
1292 //                      trkreg = fdc[drvreg].track;
1293                 }
1294         }
1295         register_seek_event();
1296 }
1297
1298 void MB8877::cmd_readdata(bool first_sector)
1299 {
1300         // type-2 read data
1301         cmdtype = (cmdreg & 0x10) ? FDC_CMD_RD_MSEC : FDC_CMD_RD_SEC;
1302         if(!check_drive2()) {
1303                 return;
1304         }
1305         status = FDC_ST_BUSY;
1306         status_tmp = search_sector();
1307         now_search = true;
1308         
1309         double time;
1310         if(status_tmp & FDC_ST_RECNFND) {
1311                 time = get_usec_to_detect_index_hole(5, first_sector && ((cmdreg & 4) != 0));
1312         } else {
1313                 time = get_usec_to_start_trans(first_sector);
1314         }
1315         register_my_event(EVENT_SEARCH, time);
1316         cancel_my_event(EVENT_LOST);
1317 }
1318
1319 void MB8877::cmd_writedata(bool first_sector)
1320 {
1321         // type-2 write data
1322         cmdtype = (cmdreg & 0x10) ? FDC_CMD_WR_MSEC : FDC_CMD_WR_SEC;
1323         if(!check_drive2()) {
1324                 return;
1325         }
1326         status = FDC_ST_BUSY;
1327         status_tmp = search_sector() & ~FDC_ST_RECTYPE;
1328         now_search = true;
1329         sector_changed = false;
1330         
1331         double time;
1332         if(status_tmp & FDC_ST_RECNFND) {
1333                 time = get_usec_to_detect_index_hole(5, first_sector && ((cmdreg & 4) != 0));
1334         } else if(status & FDC_ST_WRITEFAULT) {
1335                 time = (cmdreg & 4) ? DELAY_TIME : 1;
1336         } else {
1337                 time = get_usec_to_start_trans(first_sector);
1338         }
1339         register_my_event(EVENT_SEARCH, time);
1340         cancel_my_event(EVENT_LOST);
1341 }
1342
1343 void MB8877::cmd_readaddr()
1344 {
1345         // type-3 read address
1346         cmdtype = FDC_CMD_RD_ADDR;
1347         if(!check_drive2()) {
1348                 return;
1349         }
1350         status = FDC_ST_BUSY;
1351         status_tmp = search_addr();
1352         now_search = true;
1353         
1354         double time;
1355         if(status_tmp & FDC_ST_RECNFND) {
1356                 time = get_usec_to_detect_index_hole(5, ((cmdreg & 4) != 0));
1357         } else {
1358                 time = get_usec_to_start_trans(true);
1359         }
1360         register_my_event(EVENT_SEARCH, time);
1361         cancel_my_event(EVENT_LOST);
1362 }
1363
1364 void MB8877::cmd_readtrack()
1365 {
1366         // type-3 read track
1367         cmdtype = FDC_CMD_RD_TRK;
1368         if(!check_drive2()) {
1369                 return;
1370         }
1371         status = FDC_ST_BUSY;
1372         status_tmp = 0;
1373         
1374         disk[drvreg]->make_track(fdc[drvreg].track, sidereg);
1375         fdc[drvreg].index = 0;
1376         now_search = true;
1377         
1378         fdc[drvreg].next_trans_position = 1;
1379         double time = get_usec_to_detect_index_hole(1, ((cmdreg & 4) != 0));
1380         register_my_event(EVENT_SEARCH, time);
1381         cancel_my_event(EVENT_LOST);
1382 }
1383
1384 void MB8877::cmd_writetrack()
1385 {
1386         // type-3 write track
1387         cmdtype = FDC_CMD_WR_TRK;
1388         if(!check_drive2()) {
1389                 return;
1390         }
1391         status = FDC_ST_BUSY;
1392         status_tmp = 0;
1393         
1394         fdc[drvreg].index = 0;
1395         fdc[drvreg].id_written = false;
1396         now_search = true;
1397         
1398         double time;
1399         if(disk[drvreg]->write_protected) {
1400                 status_tmp = FDC_ST_WRITEFAULT;
1401                 time = (cmdreg & 4) ? DELAY_TIME : 1;
1402         } else {
1403                 if(cmdreg & 4) {
1404                         // wait 15msec before raise first drq
1405                         fdc[drvreg].next_trans_position = (get_cur_position() + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
1406                         time = DELAY_TIME;
1407                 } else {
1408                         // raise first drq soon
1409                         fdc[drvreg].next_trans_position = (get_cur_position() + 1) % disk[drvreg]->get_track_size();
1410                         time = disk[drvreg]->get_usec_per_bytes(1);
1411                 }
1412                 // wait at least 3bytes before check index hole and raise second drq
1413                 fdc[drvreg].bytes_before_2nd_drq = disk[drvreg]->get_track_size() - fdc[drvreg].next_trans_position;
1414                 if(fdc[drvreg].bytes_before_2nd_drq < 3) {
1415                         fdc[drvreg].bytes_before_2nd_drq += disk[drvreg]->get_track_size();
1416                 }
1417         }
1418         register_my_event(EVENT_SEARCH, time);
1419         cancel_my_event(EVENT_LOST);
1420 }
1421
1422 //#ifdef HAS_MB89311
1423 void MB8877::cmd_format()
1424 {
1425         if(type_mb89311) {
1426                 // type-3 format (FIXME: need to implement)
1427                 cmdtype = FDC_CMD_WR_TRK;
1428                 status = FDC_ST_BUSY;
1429                 status_tmp = 0;
1430                 
1431                 fdc[drvreg].index = 0;
1432                 fdc[drvreg].id_written = false;
1433                 now_search = true;
1434                 
1435                 status_tmp = FDC_ST_WRITEFAULT;
1436                 double time = (cmdreg & 4) ? DELAY_TIME : 1;
1437                 
1438                 register_my_event(EVENT_SEARCH, time);
1439                 cancel_my_event(EVENT_LOST);
1440         }
1441 }
1442 //#endif
1443
1444 void MB8877::cmd_forceint()
1445 {
1446         // type-4 force interrupt
1447         if(cmdtype == FDC_CMD_TYPE1) {
1448                 // abort restore/seek/step command
1449                 if(now_seek) {
1450                         if(seektrk > fdc[drvreg].track) {
1451                                 fdc[drvreg].track++;
1452                         } else if(seektrk < fdc[drvreg].track) {
1453                                 fdc[drvreg].track--;
1454                         }
1455                         if((cmdreg_tmp & 0x10) || ((cmdreg_tmp & 0xf0) == 0)) {
1456                                 trkreg = fdc[drvreg].track;
1457                         }
1458                 }
1459         } else if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1460                 // abort write sector command
1461                 if(sector_changed) {
1462                         disk[drvreg]->set_data_crc_error(false);
1463                 }
1464         } else if(cmdtype == FDC_CMD_WR_TRK) {
1465                 // abort write track command
1466                 if(!disk[drvreg]->write_protected) {
1467                         if(fdc[drvreg].id_written && !fdc[drvreg].sector_found) {
1468                                 // data mark of last sector is not written
1469                                 disk[drvreg]->set_data_mark_missing();
1470                         }
1471                         disk[drvreg]->sync_buffer();
1472                 }
1473         }
1474         now_search = now_seek = sector_changed = false;
1475         
1476 //#ifdef HAS_MB89311
1477         if((cmdreg == 0xff) && (type_mb89311)) {
1478                 // reset command
1479                 cmdtype = FDC_CMD_TYPE1;
1480                 status = FDC_ST_HEADENG;
1481         } else {
1482 //#endif
1483                 if(cmdtype == 0 || !(status & FDC_ST_BUSY)) {
1484                         cmdtype = FDC_CMD_TYPE1;
1485                     if(!type_fm7) status = FDC_ST_HEADENG; // Hack for FUKUALL.d77 .
1486                 }
1487                 status &= ~FDC_ST_BUSY;
1488                 
1489                 // force interrupt if bit0-bit3 is high
1490                 if(cmdreg & 0x0f) {
1491                         set_irq(true);
1492                 }
1493 //#ifdef HAS_MB89311
1494         }
1495 //#endif
1496         
1497         cancel_my_event(EVENT_SEEK);
1498         cancel_my_event(EVENT_SEEKEND_VERIFY);
1499         cancel_my_event(EVENT_SEARCH);
1500         cancel_my_event(EVENT_DRQ);
1501         cancel_my_event(EVENT_MULTI1);
1502         cancel_my_event(EVENT_MULTI2);
1503         cancel_my_event(EVENT_LOST);
1504 }
1505
1506 void MB8877::update_head_flag(int drv, bool head_load)
1507 {
1508         if(fdc[drv].head_load != head_load) {
1509                 if(head_load) {
1510                         if(d_noise_head_down != NULL) d_noise_head_down->play();
1511                 } else {
1512                         if(d_noise_head_up != NULL) d_noise_head_up->play();
1513                 }
1514                 fdc[drv].head_load = head_load;
1515         }
1516 }
1517
1518 // ----------------------------------------------------------------------------
1519 // media handler
1520 // ----------------------------------------------------------------------------
1521
1522 uint8_t MB8877::search_track()
1523 {
1524         // get track
1525         int track = fdc[drvreg].track;
1526 //#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
1527         if(type_fm77av_2dd) {
1528                 if(disk[drvreg]->media_type == MEDIA_TYPE_2D) {
1529                         if((disk[drvreg]->drive_type == DRIVE_TYPE_2DD) ||
1530                            (disk[drvreg]->drive_type == DRIVE_TYPE_2HD) ||
1531                            (disk[drvreg]->drive_type == DRIVE_TYPE_144)) {
1532                                 track >>= 1;
1533                         }
1534                 } else {        // OS-9 2DD Access fix by Ryu Takegami
1535                         if((disk[drvreg]->media_type != MEDIA_TYPE_2D) &&
1536                            (disk[drvreg]->media_type != MEDIA_TYPE_UNK)) {
1537                                 if(disk[drvreg]->drive_type == DRIVE_TYPE_2D) {
1538                                         track <<= 1;
1539                                 }
1540                         }
1541                 }
1542         }
1543 //#endif
1544         if(!disk[drvreg]->get_track(track, sidereg)){
1545                 return FDC_ST_SEEKERR;
1546         }
1547         
1548         // verify track number
1549         if(disk[drvreg]->ignore_crc()) {
1550                 for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
1551                         disk[drvreg]->get_sector(-1, -1, i);
1552                         if(disk[drvreg]->id[0] == trkreg) {
1553                                 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[i] + 4 + 2;
1554                                 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[i];
1555                                 return 0;
1556                         }
1557                 }
1558         } else {
1559                 for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
1560                         disk[drvreg]->get_sector(-1, -1, i);
1561                         if(disk[drvreg]->id[0] == trkreg && !disk[drvreg]->addr_crc_error) {
1562                                 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[i] + 4 + 2;
1563                                 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[i];
1564                                 return 0;
1565                         }
1566                 }
1567                 for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
1568                         disk[drvreg]->get_sector(-1, -1, i);
1569                         if(disk[drvreg]->id[0] == trkreg) {
1570                                 return FDC_ST_SEEKERR | FDC_ST_CRCERR;
1571                         }
1572                 }
1573         }
1574         return FDC_ST_SEEKERR;
1575 }
1576
1577 uint8_t MB8877::search_sector()
1578 {
1579         // write protect
1580         if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1581                 if(disk[drvreg]->write_protected) {
1582                         return FDC_ST_WRITEFAULT;
1583                 }
1584         }
1585         
1586         // get track
1587         int track = fdc[drvreg].track;
1588 //#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
1589         if(type_fm77av_2dd) {
1590                 if(disk[drvreg]->media_type == MEDIA_TYPE_2D) {
1591                         if((disk[drvreg]->drive_type == DRIVE_TYPE_2DD) ||
1592                            (disk[drvreg]->drive_type == DRIVE_TYPE_2HD) ||
1593                            (disk[drvreg]->drive_type == DRIVE_TYPE_144)) {
1594                                 track >>= 1;
1595                         }
1596                 } else {        // OS-9 2DD Access fix by Ryu Takegami
1597                         if((disk[drvreg]->media_type != MEDIA_TYPE_2D) &&
1598                            (disk[drvreg]->media_type != MEDIA_TYPE_UNK)) {
1599                                 if(disk[drvreg]->drive_type == DRIVE_TYPE_2D) {
1600                                         track <<= 1;
1601                                 }
1602                         }
1603                 }
1604         }
1605 //#endif
1606         if(!disk[drvreg]->get_track(track, sidereg)) {
1607                 return FDC_ST_RECNFND;
1608         }
1609         
1610         // get current position
1611         int sector_num = disk[drvreg]->sector_num.sd;
1612         int position = get_cur_position();
1613         
1614         if(position > disk[drvreg]->am1_position[sector_num - 1]) {
1615                 position -= disk[drvreg]->get_track_size();
1616         }
1617         
1618         // first scanned sector
1619         int first_sector = 0;
1620         for(int i = 0; i < sector_num; i++) {
1621                 if(position < disk[drvreg]->am1_position[i]) {
1622                         first_sector = i;
1623                         break;
1624                 }
1625         }
1626         
1627         // scan sectors
1628         for(int i = 0; i < sector_num; i++) {
1629                 // get sector
1630                 int index = (first_sector + i) % sector_num;
1631                 disk[drvreg]->get_sector(-1, -1, index);
1632                 
1633                 // check id
1634                 if(disk[drvreg]->id[0] != trkreg) {
1635                         continue;
1636                 }
1637 //#if !defined(HAS_MB8866)
1638                 if(!type_mb8866) {
1639                         if((cmdreg & 2) && (disk[drvreg]->id[1] & 1) != ((cmdreg >> 3) & 1)) {
1640                                 continue;
1641                         }
1642                 }
1643 //#endif
1644                 if(disk[drvreg]->id[2] != secreg) {
1645                         continue;
1646                 }
1647                 if(disk[drvreg]->sector_size.sd == 0) {
1648                         continue;
1649                 }
1650                 if(disk[drvreg]->addr_crc_error && !disk[drvreg]->ignore_crc()) {
1651                         // id crc error
1652                         disk[drvreg]->sector_size.sd = 0;
1653                         return FDC_ST_RECNFND | FDC_ST_CRCERR;
1654                 }
1655                 
1656                 // sector found
1657                 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1658                         fdc[drvreg].next_trans_position = disk[drvreg]->id_position[index] + 4 + 2;
1659                         fdc[drvreg].bytes_before_2nd_drq = disk[drvreg]->data_position[index] - fdc[drvreg].next_trans_position;
1660                 } else {
1661                         fdc[drvreg].next_trans_position = disk[drvreg]->data_position[index] + 1;
1662                 }
1663                 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[index];
1664                 fdc[drvreg].index = 0;
1665 //#ifdef _FDC_DEBUG_LOG
1666             if(fdc_debug_log) this->out_debug_log(_T("FDC\tSECTOR FOUND SIZE=$%04x ID=%02x %02x %02x %02x CRC=%02x %02x CRC_ERROR=%d\n"),
1667                         disk[drvreg]->sector_size.sd,
1668                         disk[drvreg]->id[0], disk[drvreg]->id[1], disk[drvreg]->id[2], disk[drvreg]->id[3],
1669                         disk[drvreg]->id[4], disk[drvreg]->id[5],
1670                         disk[drvreg]->data_crc_error ? 1 : 0);
1671 //#endif
1672                 return (disk[drvreg]->deleted ? FDC_ST_RECTYPE : 0);
1673         }
1674         
1675         // sector not found
1676         disk[drvreg]->sector_size.sd = 0;
1677         return FDC_ST_RECNFND;
1678 }
1679
1680 uint8_t MB8877::search_addr()
1681 {
1682         // get track
1683         int track = fdc[drvreg].track;
1684 //#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
1685         if(type_fm77av_2dd) {
1686                 if(disk[drvreg]->media_type == MEDIA_TYPE_2D) {
1687                         if((disk[drvreg]->drive_type == DRIVE_TYPE_2DD) ||
1688                            (disk[drvreg]->drive_type == DRIVE_TYPE_2HD) ||
1689                            (disk[drvreg]->drive_type == DRIVE_TYPE_144)) {
1690                                 track >>= 1;
1691                         }
1692                 } else {        // OS-9 2DD Access fix by Ryu Takegami
1693                         if((disk[drvreg]->media_type != MEDIA_TYPE_2D) &&
1694                            (disk[drvreg]->media_type != MEDIA_TYPE_UNK)) {
1695                                 if(disk[drvreg]->drive_type == DRIVE_TYPE_2D) {
1696                                         track <<= 1;
1697                                 }
1698                         }
1699                 }
1700         }
1701 //#endif
1702         if(!disk[drvreg]->get_track(track, sidereg)) {
1703                 return FDC_ST_RECNFND;
1704         }
1705         
1706         // get current position
1707         int sector_num = disk[drvreg]->sector_num.sd;
1708         int position = get_cur_position();
1709         
1710         if(position > disk[drvreg]->am1_position[sector_num - 1]) {
1711                 position -= disk[drvreg]->get_track_size();
1712         }
1713         
1714         // first scanned sector
1715         int first_sector = 0;
1716         for(int i = 0; i < sector_num; i++) {
1717                 if(position < disk[drvreg]->am1_position[i]) {
1718                         first_sector = i;
1719                         break;
1720                 }
1721         }
1722         
1723         // get sector
1724         if(disk[drvreg]->get_sector(-1, -1, first_sector)) {
1725                 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[first_sector] + 1;
1726                 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[first_sector];
1727                 fdc[drvreg].index = 0;
1728                 secreg = disk[drvreg]->id[0];
1729                 return 0;
1730         }
1731         
1732         // sector not found
1733         disk[drvreg]->sector_size.sd = 0;
1734         return FDC_ST_RECNFND;
1735 }
1736
1737 // ----------------------------------------------------------------------------
1738 // timing
1739 // ----------------------------------------------------------------------------
1740
1741 int MB8877::get_cur_position()
1742 {
1743         return (fdc[drvreg].cur_position + disk[drvreg]->get_bytes_per_usec(get_passed_usec(fdc[drvreg].prev_clock))) % disk[drvreg]->get_track_size();
1744 }
1745
1746 double MB8877::get_usec_to_start_trans(bool first_sector)
1747 {
1748         // get time from current position
1749         double time = get_usec_to_next_trans_pos(first_sector && ((cmdreg & 4) != 0));
1750         if(first_sector && time < 60000 - get_passed_usec(seekend_clock)) {
1751                 time += disk[drvreg]->get_usec_per_track();
1752         }
1753         return time;
1754 }
1755
1756 double MB8877::get_usec_to_next_trans_pos(bool delay)
1757 {
1758         int position = get_cur_position();
1759         
1760         if(disk[drvreg]->invalid_format) {
1761                 // XXX: this track is invalid format and the calculated sector position may be incorrect.
1762                 // so use the constant period
1763                 return 50000;
1764         } else if(/*disk[drvreg]->no_skew && */!disk[drvreg]->correct_timing()) {
1765                 // XXX: this image may be a standard image or coverted from a standard image and skew may be incorrect,
1766                 // so use the period to search the next sector from the current position
1767                 int sector_num = disk[drvreg]->sector_num.sd;
1768                 int bytes = -1;
1769                 
1770                 if(position > disk[drvreg]->am1_position[sector_num - 1]) {
1771                         position -= disk[drvreg]->get_track_size();
1772                 }
1773                 for(int i = 0; i < sector_num; i++) {
1774                         if(position < disk[drvreg]->am1_position[i]) {
1775                                 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1776                                         bytes = (disk[drvreg]->id_position[i] + 4 + 2) - position;
1777                                 } else {
1778                                         bytes = (disk[drvreg]->data_position[i] + 1) - position;
1779                                 }
1780                                 if(bytes < 0) {
1781                                         bytes += disk[drvreg]->get_track_size(); // to make sure
1782                                 }
1783                                 break;
1784                         }
1785                 }
1786                 if(bytes > 0) {
1787                         return disk[drvreg]->get_usec_per_bytes(bytes);
1788                 }
1789                 return 50000;
1790         }
1791         if(delay) {
1792                 position = (position + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
1793         }
1794         int bytes = fdc[drvreg].next_trans_position - position;
1795         if(fdc[drvreg].next_am1_position < position || bytes < 0) {
1796                 bytes += disk[drvreg]->get_track_size();
1797         }
1798         double time = disk[drvreg]->get_usec_per_bytes(bytes);
1799         if(delay) {
1800                 time += DELAY_TIME;
1801         }
1802         return time;
1803 }
1804
1805 double MB8877::get_usec_to_detect_index_hole(int count, bool delay)
1806 {
1807         int position = get_cur_position();
1808         if(delay) {
1809                 position = (position + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
1810         }
1811         int bytes = disk[drvreg]->get_track_size() * count - position;
1812         if(bytes < 0) {
1813                 bytes += disk[drvreg]->get_track_size();
1814         }
1815         double time = disk[drvreg]->get_usec_per_bytes(bytes);
1816         if(delay) {
1817                 time += DELAY_TIME;
1818         }
1819         return time;
1820 }
1821
1822 // ----------------------------------------------------------------------------
1823 // irq / drq
1824 // ----------------------------------------------------------------------------
1825
1826 void MB8877::set_irq(bool val)
1827 {
1828         write_signals(&outputs_irq, val ? 0xffffffff : 0);
1829 }
1830
1831 void MB8877::set_drq(bool val)
1832 {
1833         write_signals(&outputs_drq, val ? 0xffffffff : 0);
1834 }
1835
1836 // ----------------------------------------------------------------------------
1837 // user interface
1838 // ----------------------------------------------------------------------------
1839
1840 void MB8877::open_disk(int drv, const _TCHAR* file_path, int bank)
1841 {
1842         if(drv < _max_drive) {
1843                 disk[drv]->open(file_path, bank);
1844 #if defined(_USE_QT)
1845                 if((disk[drv]->is_special_disk == SPECIAL_DISK_FM7_FLEX) || (config.disk_count_immediate[drv])) {
1846 #else
1847                 if(disk[drv]->is_special_disk == SPECIAL_DISK_FM7_FLEX) {
1848 #endif
1849                         fdc[drv].count_immediate = true;
1850                 } else {
1851                         fdc[drv].count_immediate = false;
1852                 }
1853         }
1854 }
1855
1856 void MB8877::close_disk(int drv)
1857 {
1858         if(drv < _max_drive) {
1859                 disk[drv]->close();
1860                 cmdtype = 0;
1861                 update_head_flag(drvreg, false);
1862                 fdc[drv].count_immediate = false;
1863         }
1864 }
1865
1866 bool MB8877::is_disk_inserted(int drv)
1867 {
1868         if(drv < _max_drive) {
1869                 return disk[drv]->inserted;
1870         }
1871         return false;
1872 }
1873
1874 void MB8877::is_disk_protected(int drv, bool value)
1875 {
1876         if(drv < _max_drive) {
1877                 disk[drv]->write_protected = value;
1878         }
1879 }
1880
1881 bool MB8877::is_disk_protected(int drv)
1882 {
1883         if(drv < _max_drive) {
1884                 return disk[drv]->write_protected;
1885         }
1886         return false;
1887 }
1888
1889 void MB8877::set_drive_type(int drv, uint8_t type)
1890 {
1891         if(drv < _max_drive) {
1892                 disk[drv]->drive_type = type;
1893         }
1894 }
1895
1896 uint8_t MB8877::get_drive_type(int drv)
1897 {
1898         if(drv < _max_drive) {
1899                 return disk[drv]->drive_type;
1900         }
1901         return DRIVE_TYPE_UNK;
1902 }
1903
1904 void MB8877::set_drive_rpm(int drv, int rpm)
1905 {
1906         if(drv < _max_drive) {
1907                 disk[drv]->drive_rpm = rpm;
1908         }
1909 }
1910
1911 void MB8877::set_drive_mfm(int drv, bool mfm)
1912 {
1913         if(drv < _max_drive) {
1914                 disk[drv]->drive_mfm = mfm;
1915         }
1916 }
1917
1918 void MB8877::set_track_size(int drv, int size)
1919 {
1920         if(drv < _max_drive) {
1921                 disk[drv]->track_size = size;
1922         }
1923 }
1924
1925 uint8_t MB8877::fdc_status()
1926 {
1927         // for each virtual machines
1928 //#if defined(_FMR50) || defined(_FMR60)
1929         if(type_fmr50 || type_fmr60) {
1930                 return disk[drvreg]->inserted ? 2 : 0;
1931         }
1932 //#else
1933         return 0;
1934 //#endif
1935 }
1936
1937 void MB8877::update_config()
1938 {
1939         if(d_noise_seek != NULL) {
1940                 d_noise_seek->set_mute(!config.sound_noise_fdd);
1941         }
1942         if(d_noise_head_down != NULL) {
1943                 d_noise_head_down->set_mute(!config.sound_noise_fdd);
1944         }
1945         if(d_noise_head_up != NULL) {
1946                 d_noise_head_up->set_mute(!config.sound_noise_fdd);
1947         }
1948         fdc_debug_log = config.special_debug_fdc;
1949 }
1950
1951 #define STATE_VERSION   6
1952
1953 void MB8877::save_state(FILEIO* state_fio)
1954 {
1955         state_fio->FputUint32(STATE_VERSION);
1956         state_fio->FputInt32(this_device_id);
1957         
1958         state_fio->Fwrite(fdc, sizeof(fdc), 1);
1959         for(int i = 0; i < _max_drive; i++) {
1960                 disk[i]->save_state(state_fio);
1961         }
1962         state_fio->FputUint8(status);
1963         state_fio->FputUint8(status_tmp);
1964         state_fio->FputUint8(cmdreg);
1965         state_fio->FputUint8(cmdreg_tmp);
1966         state_fio->FputUint8(trkreg);
1967         state_fio->FputUint8(secreg);
1968         state_fio->FputUint8(datareg);
1969         state_fio->FputUint8(drvreg);
1970         state_fio->FputUint8(sidereg);
1971         state_fio->FputUint8(cmdtype);
1972         state_fio->Fwrite(register_id, sizeof(register_id), 1);
1973         state_fio->FputBool(now_search);
1974         state_fio->FputBool(now_seek);
1975         state_fio->FputBool(sector_changed);
1976         state_fio->FputInt32(no_command);
1977         state_fio->FputInt32(seektrk);
1978         state_fio->FputBool(seekvct);
1979         state_fio->FputBool(motor_on);
1980         state_fio->FputBool(drive_sel);
1981         state_fio->FputUint32(prev_drq_clock);
1982         state_fio->FputUint32(seekend_clock);
1983 }
1984
1985 bool MB8877::load_state(FILEIO* state_fio)
1986 {
1987         if(state_fio->FgetUint32() != STATE_VERSION) {
1988                 return false;
1989         }
1990         if(state_fio->FgetInt32() != this_device_id) {
1991                 return false;
1992         }
1993         state_fio->Fread(fdc, sizeof(fdc), 1);
1994         for(int i = 0; i < _max_drive; i++) {
1995                 if(!disk[i]->load_state(state_fio)) {
1996                         return false;
1997                 }
1998         }
1999         status = state_fio->FgetUint8();
2000         status_tmp = state_fio->FgetUint8();
2001         cmdreg = state_fio->FgetUint8();
2002         cmdreg_tmp = state_fio->FgetUint8();
2003         trkreg = state_fio->FgetUint8();
2004         secreg = state_fio->FgetUint8();
2005         datareg = state_fio->FgetUint8();
2006         drvreg = state_fio->FgetUint8();
2007         sidereg = state_fio->FgetUint8();
2008         cmdtype = state_fio->FgetUint8();
2009         state_fio->Fread(register_id, sizeof(register_id), 1);
2010         now_search = state_fio->FgetBool();
2011         now_seek = state_fio->FgetBool();
2012         sector_changed = state_fio->FgetBool();
2013         no_command = state_fio->FgetInt32();
2014         seektrk = state_fio->FgetInt32();
2015         seekvct = state_fio->FgetBool();
2016         motor_on = state_fio->FgetBool();
2017         drive_sel = state_fio->FgetBool();
2018         prev_drq_clock = state_fio->FgetUint32();
2019         seekend_clock = state_fio->FgetUint32();
2020
2021         fdc_debug_log = config.special_debug_fdc;
2022         return true;
2023 }
2024