OSDN Git Service

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