OSDN Git Service

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