2 Skelton for retropc emulator
5 Author : Takeda.Toshiya
8 [ MB8877 / MB8876 / MB8866 / MB89311 ]
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
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
39 #define EVENT_SEEKEND_VERIFY 1
40 #define EVENT_SEARCH 2
42 #define EVENT_MULTI1 4
43 #define EVENT_MULTI2 5
46 //#define DRIVE_MASK (MAX_DRIVE - 1)
48 #define DELAY_TIME (disk[drvreg]->drive_type == DRIVE_TYPE_2HD ? 15000 : 30000)
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
53 void MB8877::cancel_my_event(int event)
55 if(register_id[event] != -1) {
56 cancel_event(this, register_id[event]);
57 register_id[event] = -1;
61 void MB8877::register_my_event(int event, double usec)
63 cancel_my_event(event);
64 register_event(this, (event << 8) | (cmdtype & 0xff), usec, false, ®ister_id[event]);
67 void MB8877::register_seek_event()
69 cancel_my_event(EVENT_SEEK);
70 if(fdc[drvreg].track == seektrk) {
71 register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), 1, false, ®ister_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, ®ister_id[EVENT_SEEK]);
75 register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), seek_wait_lo[cmdreg & 3], false, ®ister_id[EVENT_SEEK]);
80 void MB8877::register_drq_event(int bytes)
82 double nusec = disk[drvreg]->get_usec_per_bytes(bytes); // For debug
83 double usec = nusec - get_passed_usec(prev_drq_clock);
86 if(usec > nusec) usec = nusec;
90 if(config.correct_disk_timing[drvreg]) {
94 if((disk[drvreg]->is_special_disk == SPECIAL_DISK_FM7_GAMBLER)) {
95 /* (disk[drvreg]->is_special_disk == SPECIAL_DISK_FM77AV_PSYOBLADE) || */
100 switch(disk[drvreg]->media_type) {
103 if(usec > 7.0) usec = 7.0;
115 if(fdc_debug_log) this->out_debug_log("DRQ REG: %dbytes %d:%d -> %f\n", bytes, get_current_clock(), prev_drq_clock, usec);
116 cancel_my_event(EVENT_DRQ);
117 register_event(this, (EVENT_DRQ << 8) | (cmdtype & 0xff), usec, false, ®ister_id[EVENT_DRQ]);
120 void MB8877::register_lost_event(int bytes)
122 cancel_my_event(EVENT_LOST);
123 register_event(this, (EVENT_LOST << 8) | (cmdtype & 0xff), disk[drvreg]->get_usec_per_bytes(bytes), false, ®ister_id[EVENT_LOST]);
126 bool MB8877::check_drive(void)
128 if(drvreg >= _max_drive) {
129 status = FDC_ST_NOTREADY;
137 bool MB8877::check_drive2(void)
142 if(!is_disk_inserted(drvreg & 0x7f)) {
143 status = FDC_ST_NOTREADY;
151 void MB8877::initialize()
153 DEVICE::initialize();
154 // initialize d88 handler
155 if(osd->check_feature(_T("MAX_DRIVE"))) {
156 _max_drive = osd->get_feature_int_value(_T("MAX_DRIVE"));
157 } else if(osd->check_feature(_T("MAX_FD"))) {
158 _max_drive = osd->get_feature_int_value(_T("MAX_FD"));
162 _drive_mask = _max_drive - 1;
163 for(int i = 0; i < _max_drive; i++) {
164 disk[i] = new DISK(emu);
165 disk[i]->set_device_name(_T("%s/Disk #%d"), this_device_name, i + 1);
168 if(osd->check_feature(_T("MB8877_NO_BUSY_AFTER_SEEK"))) {
169 mb8877_no_busy_after_seek = true;
171 //if(osd->check_feature(_T("_FDC_DEBUG_LOG"))) {
172 // fdc_debug_log = true;
174 fdc_debug_log = config.special_debug_fdc;
176 if(osd->check_feature(_T("HAS_MB8866"))) {
178 invert_registers = true;
179 set_device_name(_T("MB8866 FDC"));
181 if(osd->check_feature(_T("HAS_MB8876"))) {
182 invert_registers = true;
183 set_device_name(_T("MB8876 FDC"));
184 } else if(osd->check_feature(_T("HAS_MB89311"))) {
186 set_device_name(_T("MB89311 FDC"));
188 set_device_name(_T("MB8877 FDC"));
190 if(osd->check_feature(_T("_X1")) || osd->check_feature(_T("_X1TWIN")) ||
191 osd->check_feature(_T("_X1TURBO")) || osd->check_feature(_T("_X1TURBOZ"))) {
194 if(osd->check_feature(_T("_FM7")) || osd->check_feature(_T("_FM8")) ||
195 osd->check_feature(_T("_FM77_VARIANTS")) || osd->check_feature(_T("_FM77AV_VARIANTS"))) {
197 if(osd->check_feature(_T("_FM77AV40")) || osd->check_feature(_T("_FM77AV40EX")) ||
198 osd->check_feature(_T("_FM77AV40SX")) ||
199 osd->check_feature(_T("_FM77AV20")) || osd->check_feature(_T("_FM77AV20EX"))) {
200 type_fm77av_2dd = true;
203 if(osd->check_feature(_T("_FMR50"))) {
206 if(osd->check_feature(_T("_FMR60"))) {
211 if(d_noise_seek != NULL) {
212 d_noise_seek->set_device_name(_T("Noise Player (FDD Seek)"));
213 if(!d_noise_seek->load_wav_file(_T("FDDSEEK.WAV"))) {
214 if(!d_noise_seek->load_wav_file(_T("FDDSEEK1.WAV"))) {
215 d_noise_seek->load_wav_file(_T("SEEK.WAV"));
218 d_noise_seek->set_mute(!config.sound_noise_fdd);
220 if(d_noise_head_down != NULL) {
221 d_noise_head_down->set_device_name(_T("Noise Player (FDD Head Load)"));
222 d_noise_head_down->load_wav_file(_T("HEADDOWN.WAV"));
223 d_noise_head_down->set_mute(!config.sound_noise_fdd);
225 if(d_noise_head_up != NULL) {
226 d_noise_head_up->set_device_name(_T("Noise Player (FDD Head Unload)"));
227 d_noise_head_up->load_wav_file(_T("HEADUP.WAV"));
228 d_noise_head_up->set_mute(!config.sound_noise_fdd);
232 memset(fdc, 0, sizeof(fdc));
233 for(int i = 0; i < 16; i++) {
234 fdc[i].track = 40; // OK?
235 fdc[i].count_immediate = false;
240 status = cmdreg = trkreg = secreg = datareg = sidereg = cmdtype = 0;
242 prev_drq_clock = seekend_clock = 0;
245 void MB8877::release()
247 // release d88 handler
248 for(int i = 0; i < _max_drive; i++) {
258 for(int i = 0; i < _max_drive; i++) {
259 //fdc[i].track = 0; // Hold to track
261 fdc[i].access = false;
263 for(int i = 0; i < (int)array_length(register_id); i++) {
266 now_search = now_seek = drive_sel = false;
271 extended_mode = true;
273 extended_mode = false;
278 void MB8877::write_io8(uint32_t addr, uint32_t data)
286 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
287 if(invert_registers) {
288 cmdreg = (~data) & 0xff;
299 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
300 if(invert_registers) {
301 trkreg = (~data) & 0xff;
307 if((status & FDC_ST_BUSY) && (fdc[drvreg].index == 0)) {
308 // track reg is written after command starts
309 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
316 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
317 if(invert_registers) {
318 secreg = (~data) & 0xff;
324 if((status & FDC_ST_BUSY) && (fdc[drvreg].index == 0)) {
325 // sector reg is written after command starts
326 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
333 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
334 if(invert_registers) {
335 datareg = (~data) & 0xff;
341 ready = ((status & FDC_ST_DRQ) && !now_search);
342 //#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
344 if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
345 if(!motor_on) ready = false;
350 if(!motor_on) ready = false;
352 // if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
354 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
355 // write or multisector write
356 if(fdc[drvreg].index < disk[drvreg]->sector_size.sd) {
357 if(!disk[drvreg]->write_protected) {
358 if(disk[drvreg]->sector[fdc[drvreg].index] != datareg) {
359 disk[drvreg]->sector[fdc[drvreg].index] = datareg;
360 sector_changed = true;
363 disk[drvreg]->set_deleted((cmdreg & 1) != 0);
365 status |= FDC_ST_WRITEFAULT;
366 status &= ~FDC_ST_BUSY;
370 //fdc[drvreg].index++;
372 if((fdc[drvreg].index + 1) >= disk[drvreg]->sector_size.sd) {
373 if(cmdtype == FDC_CMD_WR_SEC) {
375 //#ifdef _FDC_DEBUG_LOG
376 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
378 status &= ~FDC_ST_BUSY;
383 //#ifdef _FDC_DEBUG_LOG
384 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR (SEARCH NEXT)\n"));
386 // 2HD: 360rpm, 10410bytes/track -> 0.06246bytes/us
387 register_my_event(EVENT_MULTI1, 30); // 0.06246bytes/us * 30us = 1.8738bytes < GAP3
388 register_my_event(EVENT_MULTI2, 60); // 0.06246bytes/us * 60us = 3.7476bytes < GAP3
390 sector_changed = false;
391 } else if(status & FDC_ST_DRQ) {
392 if(fdc[drvreg].index == 0) {
393 register_drq_event(fdc[drvreg].bytes_before_2nd_drq);
395 register_drq_event(1);
397 if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
399 status &= ~FDC_ST_DRQ;
400 } else if(cmdtype == FDC_CMD_WR_TRK) {
402 if(fdc[drvreg].index < disk[drvreg]->get_track_size()) {
403 if(!disk[drvreg]->write_protected) {
404 if(fdc[drvreg].index == 0) {
405 disk[drvreg]->format_track(fdc[drvreg].track, sidereg);
406 fdc[drvreg].id_written = false;
407 fdc[drvreg].side = sidereg;
408 fdc[drvreg].side_changed = false;
410 if(fdc[drvreg].side != sidereg) {
411 fdc[drvreg].side_changed = true;
413 if(fdc[drvreg].side_changed) {
414 // abort write track because disk side is changed
415 } else if(datareg == 0xf5) {
416 // write a1h in missing clock
417 } else if(datareg == 0xf6) {
418 // write c2h in missing clock
419 } else if(datareg == 0xf7) {
421 if(!fdc[drvreg].id_written) {
422 // insert new sector with data crc error
424 uint8_t c = 0, h = 0, r = 0, n = 0;
425 fdc[drvreg].id_written = true;
426 fdc[drvreg].sector_found = false;
427 if(fdc[drvreg].index >= 4) {
428 c = disk[drvreg]->track[fdc[drvreg].index - 4];
429 h = disk[drvreg]->track[fdc[drvreg].index - 3];
430 r = disk[drvreg]->track[fdc[drvreg].index - 2];
431 n = disk[drvreg]->track[fdc[drvreg].index - 1];
433 fdc[drvreg].sector_length = 0x80 << (n & 3);
434 fdc[drvreg].sector_index = 0;
435 disk[drvreg]->insert_sector(c, h, r, n, false, true, 0xe5, fdc[drvreg].sector_length);
436 } else if(fdc[drvreg].sector_found) {
437 // clear data crc error if all sector data are written
438 if(fdc[drvreg].sector_index == fdc[drvreg].sector_length) {
439 disk[drvreg]->set_data_crc_error(false);
441 fdc[drvreg].id_written = false;
443 // data mark of current sector is not written
444 disk[drvreg]->set_data_mark_missing();
447 } else if(fdc[drvreg].id_written) {
448 if(fdc[drvreg].sector_found) {
450 if(fdc[drvreg].sector_index < fdc[drvreg].sector_length) {
451 disk[drvreg]->sector[fdc[drvreg].sector_index] = datareg;
453 fdc[drvreg].sector_index++;
454 } else if(datareg == 0xf8 || datareg == 0xfb) {
456 disk[drvreg]->set_deleted(datareg == 0xf8);
457 fdc[drvreg].sector_found = true;
460 disk[drvreg]->track[fdc[drvreg].index] = datareg;
462 status |= FDC_ST_WRITEFAULT;
463 status &= ~FDC_ST_BUSY;
464 status &= ~FDC_ST_DRQ;
468 //fdc[drvreg].index++;
470 if((fdc[drvreg].index + 1) >= disk[drvreg]->get_track_size()) {
471 if(!disk[drvreg]->write_protected) {
472 if(fdc[drvreg].id_written && !fdc[drvreg].sector_found) {
473 // data mark of last sector is not written
474 disk[drvreg]->set_data_mark_missing();
476 disk[drvreg]->sync_buffer();
478 status &= ~FDC_ST_BUSY;
481 } else if(status & FDC_ST_DRQ) {
482 if(fdc[drvreg].index == 0) {
483 register_drq_event(fdc[drvreg].bytes_before_2nd_drq);
485 register_drq_event(1);
487 if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
489 status &= ~FDC_ST_DRQ;
491 if(!(status & FDC_ST_DRQ)) {
492 cancel_my_event(EVENT_LOST);
494 fdc[drvreg].access = true;
501 uint32_t MB8877::read_io8(uint32_t addr)
504 bool not_ready = false;
514 // disk not inserted, motor stop
515 not_ready = !disk[drvreg]->inserted;
516 //#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
518 if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
519 if(!motor_on) not_ready = true;
524 if(!motor_on) not_ready = true;
526 // if(!disk[drvreg]->inserted || !motor_on) {
528 status |= FDC_ST_NOTREADY;
530 status &= ~FDC_ST_NOTREADY;
533 if(cmdtype == FDC_CMD_TYPE1 || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) {
534 if(disk[drvreg]->inserted && disk[drvreg]->write_protected) {
535 status |= FDC_ST_WRITEP;
537 status &= ~FDC_ST_WRITEP;
540 status &= ~FDC_ST_WRITEP;
542 // track0, index hole
543 if(cmdtype == FDC_CMD_TYPE1) {
544 if(fdc[drvreg].track == 0) {
545 status |= FDC_ST_TRACK00;
547 status &= ~FDC_ST_TRACK00;
549 // index hole signal width is 5msec (thanks Mr.Sato)
550 if(!(status & FDC_ST_NOTREADY) && get_cur_position() < disk[drvreg]->get_bytes_per_usec(5000)) {
551 status |= FDC_ST_INDEX;
553 status &= ~FDC_ST_INDEX;
556 // show busy a moment
558 if(cmdtype == FDC_CMD_TYPE1 && !now_seek) {
559 status &= ~FDC_ST_BUSY;
560 //#ifdef MB8877_NO_BUSY_AFTER_SEEK
561 if(mb8877_no_busy_after_seek) {
562 //#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
564 if(disk[0]->is_special_disk != SPECIAL_DISK_FM7_XANADU2_D) {
576 if(cmdtype == 0 && !(status & FDC_ST_NOTREADY)) {
577 // MZ-2000 HuBASIC invites NOT READY status
578 if(++no_command == 16) {
579 val |= FDC_ST_NOTREADY;
585 if(!(status & FDC_ST_DRQ)) {
588 if(!(status & FDC_ST_BUSY)) {
591 //#ifdef _FDC_DEBUG_LOG
592 if(fdc_debug_log) this->out_debug_log(_T("FDC\tSTATUS=%2x\n"), val);
594 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
595 if(invert_registers) {
596 return (~val) & 0xff;
604 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
605 if(invert_registers) {
606 return (~trkreg) & 0xff;
614 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
615 if(invert_registers) {
616 return (~secreg) & 0xff;
624 ready = ((status & FDC_ST_DRQ) && !now_search);
625 //#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
627 if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
628 if(!motor_on) ready = false;
633 if(!motor_on) ready = false;
635 // if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
637 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC) {
638 // read or multisector read
639 if(fdc[drvreg].index < disk[drvreg]->sector_size.sd) {
640 datareg = disk[drvreg]->sector[fdc[drvreg].index];
642 if((fdc[drvreg].index + 1) >= disk[drvreg]->sector_size.sd) { // Reading complete this sector.
644 if(disk[drvreg]->data_crc_error && !disk[drvreg]->ignore_crc()) {
646 //#ifdef _FDC_DEBUG_LOG
647 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR (DATA CRC ERROR)\n"));
649 status |= FDC_ST_CRCERR;
650 status &= ~FDC_ST_BUSY;
653 } else if(cmdtype == FDC_CMD_RD_SEC) {
655 //#ifdef _FDC_DEBUG_LOG
656 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
658 status &= ~FDC_ST_BUSY;
663 //#ifdef _FDC_DEBUG_LOG
664 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR (SEARCH NEXT)\n"));
666 register_my_event(EVENT_MULTI1, 30);
667 register_my_event(EVENT_MULTI2, 60);
669 } else { // Still data remain.
670 register_drq_event(1);
671 if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
673 status &= ~FDC_ST_DRQ;
674 } else if(cmdtype == FDC_CMD_RD_ADDR) {
676 if(fdc[drvreg].index < 6) {
677 datareg = disk[drvreg]->id[fdc[drvreg].index];
678 //fdc[drvreg].index++;
680 if((fdc[drvreg].index + 1) >= 6) {
681 if(disk[drvreg]->addr_crc_error && !disk[drvreg]->ignore_crc()) {
683 status |= FDC_ST_CRCERR;
685 status &= ~FDC_ST_BUSY;
688 //#ifdef _FDC_DEBUG_LOG
689 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF ID FIELD\n"));
692 register_drq_event(1);
693 if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
695 status &= ~FDC_ST_DRQ;
696 } else if(cmdtype == FDC_CMD_RD_TRK) {
698 if(fdc[drvreg].index < disk[drvreg]->get_track_size()) {
699 datareg = disk[drvreg]->track[fdc[drvreg].index];
700 //fdc[drvreg].index++;
702 if((fdc[drvreg].index + 1) >= disk[drvreg]->get_track_size()) {
703 //#ifdef _FDC_DEBUG_LOG
704 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF TRACK\n"));
706 status &= ~FDC_ST_BUSY;
707 status |= FDC_ST_LOSTDATA;
711 register_drq_event(1);
712 if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
714 status &= ~FDC_ST_DRQ;
716 if(!(status & FDC_ST_DRQ)) {
717 cancel_my_event(EVENT_LOST);
719 fdc[drvreg].access = true;
722 //#ifdef _FDC_DEBUG_LOG
723 if(fdc_debug_log) this->force_out_debug_log(_T("FDC\tDATA=%2x\n"), datareg); // emu->force_out_debug_log()
725 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
726 if(invert_registers) {
727 return (~datareg) & 0xff;
737 void MB8877::write_dma_io8(uint32_t addr, uint32_t data)
742 uint32_t MB8877::read_dma_io8(uint32_t addr)
747 void MB8877::write_signal(int id, uint32_t data, uint32_t mask)
749 if(id == SIG_MB8877_DRIVEREG) {
750 drvreg = data & _drive_mask;
752 seekend_clock = get_current_clock();
753 } else if(id == SIG_MB8877_SIDEREG) {
754 sidereg = (data & mask) ? 1 : 0;
755 } else if(id == SIG_MB8877_MOTOR) {
756 motor_on = ((data & mask) != 0);
760 uint32_t MB8877::read_signal(int ch)
762 if(ch == SIG_MB8877_DRIVEREG) {
763 return drvreg & _drive_mask;
764 } else if(ch == SIG_MB8877_SIDEREG) {
766 } else if(ch == SIG_MB8877_MOTOR) {
767 return motor_on ? 1 : 0;
772 for(int i = 0; i < _max_drive; i++) {
776 fdc[i].access = false;
784 void MB8877::event_callback(int event_id, int err)
786 int event = event_id >> 8;
787 int cmd = event_id & 0xff;
788 //bool need_after_irq = false;
789 register_id[event] = -1;
791 // cancel event if the command is finished or other command is executed
793 if(event == EVENT_SEEK || event == EVENT_SEEKEND_VERIFY) {
795 } else if(event == EVENT_SEARCH) {
803 //#ifdef _FDC_DEBUG_LOG
804 //this->out_debug_log(_T("FDC\tSEEK START\n"));
806 if(seektrk > fdc[drvreg].track) {
808 if(d_noise_seek != NULL) d_noise_seek->play();
809 //need_after_irq = true;
810 } else if(seektrk < fdc[drvreg].track) {
812 if(d_noise_seek != NULL) d_noise_seek->play();
813 //need_after_irq = true;
815 if((cmdreg & 0x10) || ((cmdreg & 0xf0) == 0)) {
816 trkreg = fdc[drvreg].track;
818 if(seektrk != fdc[drvreg].track) {
819 //if(need_after_irq) {
821 //set_irq(true); // 20180118 K.O Turn ON IRQ -> Turn OFF DRQ
823 register_seek_event();
826 seekend_clock = get_current_clock();
830 if((cmdreg & 0xf4) == 0x44) {
834 } else if((cmdreg & 0xf4) == 0x64) {
845 status_tmp |= search_track();
847 if(status_tmp & FDC_ST_SEEKERR) {
848 time = get_usec_to_detect_index_hole(5, true);
850 time = get_usec_to_next_trans_pos(true);
852 // 20180128 K.O If seek completed, delay to make IRQ/DRQ at SEEKEND_VERIFY.
853 register_my_event(EVENT_SEEKEND_VERIFY, time);
856 // case EVENT_SEEKEND: // Separate SEEK and SEEKEND when verifying. 20180128 K.O
859 status &= (uint8_t)(~FDC_ST_BUSY); // 20180118 K.O Turn off BUSY flag.
861 set_irq(true); // 20180118 K.O Turn ON IRQ -> Turn OFF DRQ
863 case EVENT_SEEKEND_VERIFY: // Separate SEEK and SEEKEND when verifying. 20180128 K.O
865 status &= (uint8_t)(~FDC_ST_BUSY); // 20180118 K.O Turn off BUSY flag.
867 set_irq(true); // 20180118 K.O Turn ON IRQ -> Turn OFF DRQ
868 //#ifdef _FDC_DEBUG_LOG
869 //this->out_debug_log(_T("FDC\tSEEK END\n"));
874 if(status_tmp & FDC_ST_RECNFND) {
875 //#if defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
877 // for SHARP X1 Batten Tanuki
878 if(disk[drvreg]->is_special_disk == SPECIAL_DISK_X1_BATTEN && drive_sel) {
879 status_tmp &= ~FDC_ST_RECNFND;
883 //#ifdef _FDC_DEBUG_LOG
884 if(fdc_debug_log) this->out_debug_log(_T("FDC\tSEARCH NG\n"));
886 status = status_tmp & ~(FDC_ST_BUSY | FDC_ST_DRQ);
890 } else if(status_tmp & FDC_ST_WRITEFAULT) {
891 //#ifdef _FDC_DEBUG_LOG
892 if(fdc_debug_log) this->out_debug_log(_T("FDC\tWRITE PROTECTED\n"));
894 status = status_tmp & ~(FDC_ST_BUSY | FDC_ST_DRQ);
899 status = status_tmp | (FDC_ST_BUSY | FDC_ST_DRQ);
900 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
901 register_lost_event(8);
902 } else if(cmdtype == FDC_CMD_WR_TRK) {
903 register_lost_event(3);
905 register_lost_event(1);
907 fdc[drvreg].cur_position = fdc[drvreg].next_trans_position;
908 fdc[drvreg].prev_clock = prev_drq_clock = get_current_clock();
911 if(fdc_debug_log) this->out_debug_log("DRQ ON@SEARCH: %d\n", prev_drq_clock);
912 //#ifdef _FDC_DEBUG_LOG
913 if(fdc_debug_log) this->out_debug_log(_T("FDC\tSEARCH OK\n"));
918 if(status & FDC_ST_BUSY) {
919 status |= FDC_ST_DRQ;
920 register_lost_event(1);
921 if((cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) && fdc[drvreg].index == 0) {
922 fdc[drvreg].cur_position = (fdc[drvreg].cur_position + fdc[drvreg].bytes_before_2nd_drq) % disk[drvreg]->get_track_size();
924 fdc[drvreg].cur_position = (fdc[drvreg].cur_position + 1) % disk[drvreg]->get_track_size();
926 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC ||
927 cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC ||
928 cmdtype == FDC_CMD_RD_TRK || cmdtype == FDC_CMD_WR_TRK ||
929 cmdtype == FDC_CMD_RD_ADDR) {
930 if(!(fdc[drvreg].count_immediate)) fdc[drvreg].index++;
932 fdc[drvreg].prev_clock = prev_drq_clock = get_current_clock();
935 if(fdc_debug_log) this->out_debug_log("DRQ ON@DRQ: %d\n", prev_drq_clock);
936 //#ifdef _FDC_DEBUG_LOG
937 //this->out_debug_log(_T("FDC\tDRQ!\n"));
945 if(cmdtype == FDC_CMD_RD_MSEC) {
947 } else if(cmdtype == FDC_CMD_WR_MSEC) {
948 cmd_writedata(false);
952 if(status & FDC_ST_BUSY) {
953 //#ifdef _FDC_DEBUG_LOG
954 if(fdc_debug_log) this->out_debug_log(_T("FDC\tDATA LOST\n"));
956 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) {
957 if(fdc[drvreg].index == 0) { // HEAD of REGION
959 //if((status & FDC_ST_DRQ) != 0) { // 20180130 FORCE DOWN DRQ ON LOST-DATA.
960 status |= FDC_ST_LOSTDATA;
961 status &= (uint8_t)(~(FDC_ST_DRQ | FDC_ST_BUSY));
965 } else { // STILL WRITING
967 //if((status & FDC_ST_DRQ) != 0) {
968 status |= FDC_ST_LOSTDATA;
969 status &= (uint8_t)(~(FDC_ST_DRQ | FDC_ST_BUSY));
976 //if((status & FDC_ST_DRQ) != 0) {
977 status |= FDC_ST_LOSTDATA;
978 status &= (uint8_t)(~(FDC_ST_DRQ | FDC_ST_BUSY));
984 status |= FDC_ST_LOSTDATA;
990 // ----------------------------------------------------------------------------
992 // ----------------------------------------------------------------------------
994 void MB8877::process_cmd()
1000 // MB89311 mode commands
1002 if(cmdreg == 0xfc) {
1003 // delay (may be only in extended mode)
1004 //#ifdef _FDC_DEBUG_LOG
1005 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (DELAY ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1007 cmdtype = status = 0;
1009 } else if(cmdreg == 0xfd) {
1011 //#ifdef _FDC_DEBUG_LOG
1012 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (ASGN PAR) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1014 cmdtype = status = 0;
1016 } else if(cmdreg == 0xfe) {
1018 //#ifdef _FDC_DEBUG_LOG
1019 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (ASGN MOD) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1021 extended_mode = !extended_mode;
1022 cmdtype = status = 0;
1024 } else if(cmdreg == 0xff) {
1025 // reset (may be only in extended mode)
1026 //#ifdef _FDC_DEBUG_LOG
1027 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (RESET ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1030 extended_mode = true;
1032 } else if(extended_mode) {
1034 if((cmdreg & 0xeb) == 0x21) {
1035 //#ifdef _FDC_DEBUG_LOG
1036 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (STEP IN ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1040 } else if((cmdreg & 0xeb) == 0x22) {
1041 //#ifdef _FDC_DEBUG_LOG
1042 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (STEP OUT) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1047 } else if((cmdreg & 0xf4) == 0x44) {
1049 //#ifdef _FDC_DEBUG_LOG
1050 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (RDaftSEK) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1054 } else if((cmdreg & 0xf4) == 0x64) {
1056 //#ifdef _FDC_DEBUG_LOG
1057 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (WRaftSEK) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1062 } else if((cmdreg & 0xfb) == 0xf1) {
1064 //#ifdef _FDC_DEBUG_LOG
1065 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (FORMAT ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1074 // MB8877 mode commands
1075 //#ifdef _FDC_DEBUG_LOG
1076 static const _TCHAR *cmdstr[0x10] = {
1077 _T("RESTORE "), _T("SEEK "), _T("STEP "), _T("STEP "),
1078 _T("STEP IN "), _T("STEP IN "), _T("STEP OUT"), _T("STEP OUT"),
1079 _T("RD DATA "), _T("RD DATA "), _T("RD DATA "), _T("WR DATA "),
1080 _T("RD ADDR "), _T("FORCEINT"), _T("RD TRACK"), _T("WR TRACK")
1082 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (%s) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, cmdstr[cmdreg >> 4], datareg, drvreg, trkreg, sidereg, secreg);
1085 switch(cmdreg & 0xf8) {
1087 case 0x00: case 0x08:
1089 update_head_flag(drvreg, (cmdreg & 8) != 0);
1091 case 0x10: case 0x18:
1093 update_head_flag(drvreg, (cmdreg & 8) != 0);
1095 case 0x20: case 0x28:
1096 case 0x30: case 0x38:
1098 update_head_flag(drvreg, (cmdreg & 8) != 0);
1100 case 0x40: case 0x48:
1101 case 0x50: case 0x58:
1103 update_head_flag(drvreg, (cmdreg & 8) != 0);
1105 case 0x60: case 0x68:
1106 case 0x70: case 0x78:
1108 update_head_flag(drvreg, (cmdreg & 8) != 0);
1111 case 0x80: case 0x88:
1112 case 0x90: case 0x98:
1114 update_head_flag(drvreg, true);
1116 case 0xa0:case 0xa8:
1117 case 0xb0: case 0xb8:
1118 cmd_writedata(true);
1119 update_head_flag(drvreg, true);
1124 update_head_flag(drvreg, true);
1128 update_head_flag(drvreg, true);
1132 update_head_flag(drvreg, true);
1135 case 0xd0: case 0xd8:
1144 void MB8877::cmd_restore()
1147 cmdtype = FDC_CMD_TYPE1;
1148 if(!check_drive()) {
1151 if((cmdreg & 0x08) != 0) { // Head engage
1152 status = FDC_ST_HEADENG | FDC_ST_BUSY;
1154 status = FDC_ST_BUSY;
1159 if(fdc[drvreg].track < 0) {
1160 fdc[drvreg].track = 0;
1162 } else if(fdc[drvreg].track >= 80) {
1163 fdc[drvreg].track = 80;
1166 trkreg = fdc[drvreg].track;
1173 register_seek_event();
1176 void MB8877::cmd_seek()
1179 cmdtype = FDC_CMD_TYPE1;
1180 if(!check_drive()) {
1183 if((cmdreg & 0x08) != 0) { // Head engage
1184 status = FDC_ST_HEADENG | FDC_ST_BUSY;
1186 status = FDC_ST_BUSY;
1189 // seektrk = (uint8_t)(fdc[drvreg].track + datareg - trkreg);
1191 //#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
1192 if(type_fm77av_2dd) {
1193 if(disk[drvreg]->drive_type != DRIVE_TYPE_2D) {
1194 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1196 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1198 } else if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
1199 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1201 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1203 seekvct = !(seektrk > fdc[drvreg].track);
1207 if(trkreg != fdc[drvreg].track) {
1208 status |= FDC_ST_SEEKERR;
1209 trkreg = fdc[drvreg].track;
1212 register_seek_event();
1215 void MB8877::cmd_step()
1225 void MB8877::cmd_stepin()
1228 cmdtype = FDC_CMD_TYPE1;
1229 if(!check_drive()) {
1232 if((cmdreg & 0x08) != 0) { // Head engage
1233 status = FDC_ST_HEADENG | FDC_ST_BUSY;
1235 status = FDC_ST_BUSY;
1237 seektrk = fdc[drvreg].track + 1;
1238 if(type_fm77av_2dd) {
1239 if(disk[drvreg]->drive_type != DRIVE_TYPE_2D) {
1240 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1242 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1244 } else if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
1245 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1247 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1253 if(trkreg != fdc[drvreg].track) {
1254 status |= FDC_ST_SEEKERR;
1255 // trkreg = fdc[drvreg].track;
1258 register_seek_event();
1261 void MB8877::cmd_stepout()
1264 cmdtype = FDC_CMD_TYPE1;
1265 if(!check_drive()) {
1268 if((cmdreg & 0x08) != 0) { // Head engage
1269 status = FDC_ST_HEADENG | FDC_ST_BUSY;
1271 status = FDC_ST_BUSY;
1274 seektrk = fdc[drvreg].track - 1;
1275 if(type_fm77av_2dd) {
1276 if(disk[drvreg]->drive_type != DRIVE_TYPE_2D) {
1277 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1279 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1281 } else if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
1282 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1284 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1290 if(trkreg != fdc[drvreg].track) {
1291 status |= FDC_ST_SEEKERR;
1292 // trkreg = fdc[drvreg].track;
1295 register_seek_event();
1298 void MB8877::cmd_readdata(bool first_sector)
1301 cmdtype = (cmdreg & 0x10) ? FDC_CMD_RD_MSEC : FDC_CMD_RD_SEC;
1302 if(!check_drive2()) {
1305 status = FDC_ST_BUSY;
1306 status_tmp = search_sector();
1310 if(status_tmp & FDC_ST_RECNFND) {
1311 time = get_usec_to_detect_index_hole(5, first_sector && ((cmdreg & 4) != 0));
1313 time = get_usec_to_start_trans(first_sector);
1315 register_my_event(EVENT_SEARCH, time);
1316 cancel_my_event(EVENT_LOST);
1319 void MB8877::cmd_writedata(bool first_sector)
1321 // type-2 write data
1322 cmdtype = (cmdreg & 0x10) ? FDC_CMD_WR_MSEC : FDC_CMD_WR_SEC;
1323 if(!check_drive2()) {
1326 status = FDC_ST_BUSY;
1327 status_tmp = search_sector() & ~FDC_ST_RECTYPE;
1329 sector_changed = false;
1332 if(status_tmp & FDC_ST_RECNFND) {
1333 time = get_usec_to_detect_index_hole(5, first_sector && ((cmdreg & 4) != 0));
1334 } else if(status & FDC_ST_WRITEFAULT) {
1335 time = (cmdreg & 4) ? DELAY_TIME : 1;
1337 time = get_usec_to_start_trans(first_sector);
1339 register_my_event(EVENT_SEARCH, time);
1340 cancel_my_event(EVENT_LOST);
1343 void MB8877::cmd_readaddr()
1345 // type-3 read address
1346 cmdtype = FDC_CMD_RD_ADDR;
1347 if(!check_drive2()) {
1350 status = FDC_ST_BUSY;
1351 status_tmp = search_addr();
1355 if(status_tmp & FDC_ST_RECNFND) {
1356 time = get_usec_to_detect_index_hole(5, ((cmdreg & 4) != 0));
1358 time = get_usec_to_start_trans(true);
1360 register_my_event(EVENT_SEARCH, time);
1361 cancel_my_event(EVENT_LOST);
1364 void MB8877::cmd_readtrack()
1366 // type-3 read track
1367 cmdtype = FDC_CMD_RD_TRK;
1368 if(!check_drive2()) {
1371 status = FDC_ST_BUSY;
1374 disk[drvreg]->make_track(fdc[drvreg].track, sidereg);
1375 fdc[drvreg].index = 0;
1378 fdc[drvreg].next_trans_position = 1;
1379 double time = get_usec_to_detect_index_hole(1, ((cmdreg & 4) != 0));
1380 register_my_event(EVENT_SEARCH, time);
1381 cancel_my_event(EVENT_LOST);
1384 void MB8877::cmd_writetrack()
1386 // type-3 write track
1387 cmdtype = FDC_CMD_WR_TRK;
1388 if(!check_drive2()) {
1391 status = FDC_ST_BUSY;
1394 fdc[drvreg].index = 0;
1395 fdc[drvreg].id_written = false;
1399 if(disk[drvreg]->write_protected) {
1400 status_tmp = FDC_ST_WRITEFAULT;
1401 time = (cmdreg & 4) ? DELAY_TIME : 1;
1404 // wait 15msec before raise first drq
1405 fdc[drvreg].next_trans_position = (get_cur_position() + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
1408 // raise first drq soon
1409 fdc[drvreg].next_trans_position = (get_cur_position() + 1) % disk[drvreg]->get_track_size();
1410 time = disk[drvreg]->get_usec_per_bytes(1);
1412 // wait at least 3bytes before check index hole and raise second drq
1413 fdc[drvreg].bytes_before_2nd_drq = disk[drvreg]->get_track_size() - fdc[drvreg].next_trans_position;
1414 if(fdc[drvreg].bytes_before_2nd_drq < 3) {
1415 fdc[drvreg].bytes_before_2nd_drq += disk[drvreg]->get_track_size();
1418 register_my_event(EVENT_SEARCH, time);
1419 cancel_my_event(EVENT_LOST);
1422 //#ifdef HAS_MB89311
1423 void MB8877::cmd_format()
1426 // type-3 format (FIXME: need to implement)
1427 cmdtype = FDC_CMD_WR_TRK;
1428 status = FDC_ST_BUSY;
1431 fdc[drvreg].index = 0;
1432 fdc[drvreg].id_written = false;
1435 status_tmp = FDC_ST_WRITEFAULT;
1436 double time = (cmdreg & 4) ? DELAY_TIME : 1;
1438 register_my_event(EVENT_SEARCH, time);
1439 cancel_my_event(EVENT_LOST);
1444 void MB8877::cmd_forceint()
1446 // type-4 force interrupt
1447 bool ready = (cmdtype == 0);
1448 bool is_busy = ((status & FDC_ST_BUSY) != 0);
1449 bool now_seek_bak = now_seek;
1450 bool is_type1 = (cmdtype == FDC_CMD_TYPE1);
1451 bool is_read = ((cmdtype == FDC_CMD_RD_SEC) || (cmdtype == FDC_CMD_RD_MSEC) || \
1452 (cmdtype == FDC_CMD_RD_ADDR) || (cmdtype == FDC_CMD_RD_TRK));
1453 bool is_trkwrite = (cmdtype == FDC_CMD_WR_TRK);
1455 if(cmdtype == FDC_CMD_TYPE1) {
1456 // abort restore/seek/step command
1458 if(seektrk > fdc[drvreg].track) {
1459 fdc[drvreg].track++;
1460 } else if(seektrk < fdc[drvreg].track) {
1461 fdc[drvreg].track--;
1463 if((cmdreg_tmp & 0x10) || ((cmdreg_tmp & 0xf0) == 0)) {
1464 trkreg = fdc[drvreg].track;
1467 } else if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1468 // abort write sector command
1469 if(sector_changed) {
1470 disk[drvreg]->set_data_crc_error(false);
1472 } else if(cmdtype == FDC_CMD_WR_TRK) {
1473 // abort write track command
1474 if(!disk[drvreg]->write_protected) {
1475 if(fdc[drvreg].id_written && !fdc[drvreg].sector_found) {
1476 // data mark of last sector is not written
1477 disk[drvreg]->set_data_mark_missing();
1479 disk[drvreg]->sync_buffer();
1482 now_search = now_seek = sector_changed = false;
1484 //#ifdef HAS_MB89311
1485 if((cmdreg == 0xff) && (type_mb89311)) {
1487 cmdtype = FDC_CMD_TYPE1;
1488 status = FDC_ST_HEADENG;
1491 if(cmdtype == 0 || !(status & FDC_ST_BUSY)) {
1492 cmdtype = FDC_CMD_TYPE1;
1493 if(!type_fm7) status = FDC_ST_HEADENG; // Hack for FUKUALL.d77 .
1495 status &= ~FDC_ST_BUSY;
1496 if((now_seek_bak) || (ready)) {// Refer from XM7, is this write implement? 20180210 K.O
1498 if(((ready) || !(is_busy)) && (!type_fm7)) status = FDC_ST_HEADENG;
1500 if(check_drive2()) {
1501 if(!(is_read) && (disk[drvreg]->write_protected)) status |= FDC_ST_WRITEP;
1502 if((is_trkwrite) && (disk[drvreg]->write_protected)) status |= FDC_ST_WRITEFAULT;
1504 if(fdc[drvreg].track == 0) status |= FDC_ST_TRACK00;
1505 if(get_cur_position() < disk[drvreg]->get_bytes_per_usec(5000)) {
1506 status |= FDC_ST_INDEX;
1511 // force interrupt if bit0-bit3 is high
1515 //#ifdef HAS_MB89311
1519 cancel_my_event(EVENT_SEEK);
1520 cancel_my_event(EVENT_SEEKEND_VERIFY);
1521 cancel_my_event(EVENT_SEARCH);
1522 cancel_my_event(EVENT_DRQ);
1523 cancel_my_event(EVENT_MULTI1);
1524 cancel_my_event(EVENT_MULTI2);
1525 cancel_my_event(EVENT_LOST);
1528 void MB8877::update_head_flag(int drv, bool head_load)
1530 if(fdc[drv].head_load != head_load) {
1532 if(d_noise_head_down != NULL) d_noise_head_down->play();
1534 if(d_noise_head_up != NULL) d_noise_head_up->play();
1536 fdc[drv].head_load = head_load;
1540 // ----------------------------------------------------------------------------
1542 // ----------------------------------------------------------------------------
1544 uint8_t MB8877::search_track()
1547 int track = fdc[drvreg].track;
1548 //#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
1549 if(type_fm77av_2dd) {
1550 if(disk[drvreg]->media_type == MEDIA_TYPE_2D) {
1551 if((disk[drvreg]->drive_type == DRIVE_TYPE_2DD) ||
1552 (disk[drvreg]->drive_type == DRIVE_TYPE_2HD) ||
1553 (disk[drvreg]->drive_type == DRIVE_TYPE_144)) {
1556 } else { // OS-9 2DD Access fix by Ryu Takegami
1557 if((disk[drvreg]->media_type != MEDIA_TYPE_2D) &&
1558 (disk[drvreg]->media_type != MEDIA_TYPE_UNK)) {
1559 if(disk[drvreg]->drive_type == DRIVE_TYPE_2D) {
1566 if(!disk[drvreg]->get_track(track, sidereg)){
1567 return FDC_ST_SEEKERR;
1570 // verify track number
1571 if(disk[drvreg]->ignore_crc()) {
1572 for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
1573 disk[drvreg]->get_sector(-1, -1, i);
1574 if(disk[drvreg]->id[0] == trkreg) {
1575 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[i] + 4 + 2;
1576 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[i];
1581 for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
1582 disk[drvreg]->get_sector(-1, -1, i);
1583 if(disk[drvreg]->id[0] == trkreg && !disk[drvreg]->addr_crc_error) {
1584 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[i] + 4 + 2;
1585 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[i];
1589 for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
1590 disk[drvreg]->get_sector(-1, -1, i);
1591 if(disk[drvreg]->id[0] == trkreg) {
1592 return FDC_ST_SEEKERR | FDC_ST_CRCERR;
1596 return FDC_ST_SEEKERR;
1599 uint8_t MB8877::search_sector()
1602 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1603 if(disk[drvreg]->write_protected) {
1604 return FDC_ST_WRITEFAULT;
1609 int track = fdc[drvreg].track;
1610 //#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
1611 if(type_fm77av_2dd) {
1612 if(disk[drvreg]->media_type == MEDIA_TYPE_2D) {
1613 if((disk[drvreg]->drive_type == DRIVE_TYPE_2DD) ||
1614 (disk[drvreg]->drive_type == DRIVE_TYPE_2HD) ||
1615 (disk[drvreg]->drive_type == DRIVE_TYPE_144)) {
1618 } else { // OS-9 2DD Access fix by Ryu Takegami
1619 if((disk[drvreg]->media_type != MEDIA_TYPE_2D) &&
1620 (disk[drvreg]->media_type != MEDIA_TYPE_UNK)) {
1621 if(disk[drvreg]->drive_type == DRIVE_TYPE_2D) {
1628 if(!disk[drvreg]->get_track(track, sidereg)) {
1629 return FDC_ST_RECNFND;
1632 // get current position
1633 int sector_num = disk[drvreg]->sector_num.sd;
1634 int position = get_cur_position();
1636 if(position > disk[drvreg]->am1_position[sector_num - 1]) {
1637 position -= disk[drvreg]->get_track_size();
1640 // first scanned sector
1641 int first_sector = 0;
1642 for(int i = 0; i < sector_num; i++) {
1643 if(position < disk[drvreg]->am1_position[i]) {
1650 for(int i = 0; i < sector_num; i++) {
1652 int index = (first_sector + i) % sector_num;
1653 disk[drvreg]->get_sector(-1, -1, index);
1656 if(disk[drvreg]->id[0] != trkreg) {
1659 //#if !defined(HAS_MB8866)
1661 if((cmdreg & 2) && (disk[drvreg]->id[1] & 1) != ((cmdreg >> 3) & 1)) {
1666 if(disk[drvreg]->id[2] != secreg) {
1669 if(disk[drvreg]->sector_size.sd == 0) {
1672 if(disk[drvreg]->addr_crc_error && !disk[drvreg]->ignore_crc()) {
1674 disk[drvreg]->sector_size.sd = 0;
1675 return FDC_ST_RECNFND | FDC_ST_CRCERR;
1679 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1680 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[index] + 4 + 2;
1681 fdc[drvreg].bytes_before_2nd_drq = disk[drvreg]->data_position[index] - fdc[drvreg].next_trans_position;
1683 fdc[drvreg].next_trans_position = disk[drvreg]->data_position[index] + 1;
1685 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[index];
1686 fdc[drvreg].index = 0;
1687 //#ifdef _FDC_DEBUG_LOG
1688 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"),
1689 disk[drvreg]->sector_size.sd,
1690 disk[drvreg]->id[0], disk[drvreg]->id[1], disk[drvreg]->id[2], disk[drvreg]->id[3],
1691 disk[drvreg]->id[4], disk[drvreg]->id[5],
1692 disk[drvreg]->data_crc_error ? 1 : 0);
1694 return (disk[drvreg]->deleted ? FDC_ST_RECTYPE : 0);
1698 disk[drvreg]->sector_size.sd = 0;
1699 return FDC_ST_RECNFND;
1702 uint8_t MB8877::search_addr()
1705 int track = fdc[drvreg].track;
1706 //#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
1707 if(type_fm77av_2dd) {
1708 if(disk[drvreg]->media_type == MEDIA_TYPE_2D) {
1709 if((disk[drvreg]->drive_type == DRIVE_TYPE_2DD) ||
1710 (disk[drvreg]->drive_type == DRIVE_TYPE_2HD) ||
1711 (disk[drvreg]->drive_type == DRIVE_TYPE_144)) {
1714 } else { // OS-9 2DD Access fix by Ryu Takegami
1715 if((disk[drvreg]->media_type != MEDIA_TYPE_2D) &&
1716 (disk[drvreg]->media_type != MEDIA_TYPE_UNK)) {
1717 if(disk[drvreg]->drive_type == DRIVE_TYPE_2D) {
1724 if(!disk[drvreg]->get_track(track, sidereg)) {
1725 return FDC_ST_RECNFND;
1728 // get current position
1729 int sector_num = disk[drvreg]->sector_num.sd;
1730 int position = get_cur_position();
1732 if(position > disk[drvreg]->am1_position[sector_num - 1]) {
1733 position -= disk[drvreg]->get_track_size();
1736 // first scanned sector
1737 int first_sector = 0;
1738 for(int i = 0; i < sector_num; i++) {
1739 if(position < disk[drvreg]->am1_position[i]) {
1746 if(disk[drvreg]->get_sector(-1, -1, first_sector)) {
1747 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[first_sector] + 1;
1748 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[first_sector];
1749 fdc[drvreg].index = 0;
1750 secreg = disk[drvreg]->id[0];
1755 disk[drvreg]->sector_size.sd = 0;
1756 return FDC_ST_RECNFND;
1759 // ----------------------------------------------------------------------------
1761 // ----------------------------------------------------------------------------
1763 int MB8877::get_cur_position()
1765 return (fdc[drvreg].cur_position + disk[drvreg]->get_bytes_per_usec(get_passed_usec(fdc[drvreg].prev_clock))) % disk[drvreg]->get_track_size();
1768 double MB8877::get_usec_to_start_trans(bool first_sector)
1770 // get time from current position
1771 double time = get_usec_to_next_trans_pos(first_sector && ((cmdreg & 4) != 0));
1772 if(first_sector && time < 60000 - get_passed_usec(seekend_clock)) {
1773 time += disk[drvreg]->get_usec_per_track();
1778 double MB8877::get_usec_to_next_trans_pos(bool delay)
1780 int position = get_cur_position();
1782 if(disk[drvreg]->invalid_format) {
1783 // XXX: this track is invalid format and the calculated sector position may be incorrect.
1784 // so use the constant period
1786 } else if(/*disk[drvreg]->no_skew && */!disk[drvreg]->correct_timing()) {
1787 // XXX: this image may be a standard image or coverted from a standard image and skew may be incorrect,
1788 // so use the period to search the next sector from the current position
1789 int sector_num = disk[drvreg]->sector_num.sd;
1792 if(position > disk[drvreg]->am1_position[sector_num - 1]) {
1793 position -= disk[drvreg]->get_track_size();
1795 for(int i = 0; i < sector_num; i++) {
1796 if(position < disk[drvreg]->am1_position[i]) {
1797 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1798 bytes = (disk[drvreg]->id_position[i] + 4 + 2) - position;
1800 bytes = (disk[drvreg]->data_position[i] + 1) - position;
1803 bytes += disk[drvreg]->get_track_size(); // to make sure
1809 return disk[drvreg]->get_usec_per_bytes(bytes);
1814 position = (position + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
1816 int bytes = fdc[drvreg].next_trans_position - position;
1817 if(fdc[drvreg].next_am1_position < position || bytes < 0) {
1818 bytes += disk[drvreg]->get_track_size();
1820 double time = disk[drvreg]->get_usec_per_bytes(bytes);
1827 double MB8877::get_usec_to_detect_index_hole(int count, bool delay)
1829 int position = get_cur_position();
1831 position = (position + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
1833 int bytes = disk[drvreg]->get_track_size() * count - position;
1835 bytes += disk[drvreg]->get_track_size();
1837 double time = disk[drvreg]->get_usec_per_bytes(bytes);
1844 // ----------------------------------------------------------------------------
1846 // ----------------------------------------------------------------------------
1848 void MB8877::set_irq(bool val)
1850 write_signals(&outputs_irq, val ? 0xffffffff : 0);
1853 void MB8877::set_drq(bool val)
1855 write_signals(&outputs_drq, val ? 0xffffffff : 0);
1858 // ----------------------------------------------------------------------------
1860 // ----------------------------------------------------------------------------
1862 void MB8877::open_disk(int drv, const _TCHAR* file_path, int bank)
1864 if(drv < _max_drive) {
1865 disk[drv]->open(file_path, bank);
1866 #if defined(_USE_QT)
1867 if((disk[drv]->is_special_disk == SPECIAL_DISK_FM7_FLEX) || (config.disk_count_immediate[drv])) {
1869 if(disk[drv]->is_special_disk == SPECIAL_DISK_FM7_FLEX) {
1871 fdc[drv].count_immediate = true;
1873 fdc[drv].count_immediate = false;
1878 void MB8877::close_disk(int drv)
1880 if(drv < _max_drive) {
1883 update_head_flag(drvreg, false);
1884 fdc[drv].count_immediate = false;
1888 bool MB8877::is_disk_inserted(int drv)
1890 if(drv < _max_drive) {
1891 return disk[drv]->inserted;
1896 void MB8877::is_disk_protected(int drv, bool value)
1898 if(drv < _max_drive) {
1899 disk[drv]->write_protected = value;
1903 bool MB8877::is_disk_protected(int drv)
1905 if(drv < _max_drive) {
1906 return disk[drv]->write_protected;
1911 void MB8877::set_drive_type(int drv, uint8_t type)
1913 if(drv < _max_drive) {
1914 disk[drv]->drive_type = type;
1918 uint8_t MB8877::get_drive_type(int drv)
1920 if(drv < _max_drive) {
1921 return disk[drv]->drive_type;
1923 return DRIVE_TYPE_UNK;
1926 void MB8877::set_drive_rpm(int drv, int rpm)
1928 if(drv < _max_drive) {
1929 disk[drv]->drive_rpm = rpm;
1933 void MB8877::set_drive_mfm(int drv, bool mfm)
1935 if(drv < _max_drive) {
1936 disk[drv]->drive_mfm = mfm;
1940 void MB8877::set_track_size(int drv, int size)
1942 if(drv < _max_drive) {
1943 disk[drv]->track_size = size;
1947 uint8_t MB8877::fdc_status()
1949 // for each virtual machines
1950 //#if defined(_FMR50) || defined(_FMR60)
1951 if(type_fmr50 || type_fmr60) {
1952 return disk[drvreg]->inserted ? 2 : 0;
1959 void MB8877::update_config()
1961 if(d_noise_seek != NULL) {
1962 d_noise_seek->set_mute(!config.sound_noise_fdd);
1964 if(d_noise_head_down != NULL) {
1965 d_noise_head_down->set_mute(!config.sound_noise_fdd);
1967 if(d_noise_head_up != NULL) {
1968 d_noise_head_up->set_mute(!config.sound_noise_fdd);
1970 fdc_debug_log = config.special_debug_fdc;
1973 #define STATE_VERSION 6
1975 void MB8877::save_state(FILEIO* state_fio)
1977 state_fio->FputUint32(STATE_VERSION);
1978 state_fio->FputInt32(this_device_id);
1980 state_fio->Fwrite(fdc, sizeof(fdc), 1);
1981 for(int i = 0; i < _max_drive; i++) {
1982 disk[i]->save_state(state_fio);
1984 state_fio->FputUint8(status);
1985 state_fio->FputUint8(status_tmp);
1986 state_fio->FputUint8(cmdreg);
1987 state_fio->FputUint8(cmdreg_tmp);
1988 state_fio->FputUint8(trkreg);
1989 state_fio->FputUint8(secreg);
1990 state_fio->FputUint8(datareg);
1991 state_fio->FputUint8(drvreg);
1992 state_fio->FputUint8(sidereg);
1993 state_fio->FputUint8(cmdtype);
1994 state_fio->Fwrite(register_id, sizeof(register_id), 1);
1995 state_fio->FputBool(now_search);
1996 state_fio->FputBool(now_seek);
1997 state_fio->FputBool(sector_changed);
1998 state_fio->FputInt32(no_command);
1999 state_fio->FputInt32(seektrk);
2000 state_fio->FputBool(seekvct);
2001 state_fio->FputBool(motor_on);
2002 state_fio->FputBool(drive_sel);
2003 state_fio->FputUint32(prev_drq_clock);
2004 state_fio->FputUint32(seekend_clock);
2007 bool MB8877::load_state(FILEIO* state_fio)
2009 if(state_fio->FgetUint32() != STATE_VERSION) {
2012 if(state_fio->FgetInt32() != this_device_id) {
2015 state_fio->Fread(fdc, sizeof(fdc), 1);
2016 for(int i = 0; i < _max_drive; i++) {
2017 if(!disk[i]->load_state(state_fio)) {
2021 status = state_fio->FgetUint8();
2022 status_tmp = state_fio->FgetUint8();
2023 cmdreg = state_fio->FgetUint8();
2024 cmdreg_tmp = state_fio->FgetUint8();
2025 trkreg = state_fio->FgetUint8();
2026 secreg = state_fio->FgetUint8();
2027 datareg = state_fio->FgetUint8();
2028 drvreg = state_fio->FgetUint8();
2029 sidereg = state_fio->FgetUint8();
2030 cmdtype = state_fio->FgetUint8();
2031 state_fio->Fread(register_id, sizeof(register_id), 1);
2032 now_search = state_fio->FgetBool();
2033 now_seek = state_fio->FgetBool();
2034 sector_changed = state_fio->FgetBool();
2035 no_command = state_fio->FgetInt32();
2036 seektrk = state_fio->FgetInt32();
2037 seekvct = state_fio->FgetBool();
2038 motor_on = state_fio->FgetBool();
2039 drive_sel = state_fio->FgetBool();
2040 prev_drq_clock = state_fio->FgetUint32();
2041 seekend_clock = state_fio->FgetUint32();
2043 fdc_debug_log = config.special_debug_fdc;