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);
89 if((disk[drvreg]->is_special_disk == SPECIAL_DISK_FM7_GAMBLER) ||
90 /* (disk[drvreg]->is_special_disk == SPECIAL_DISK_FM77AV_PSYOBLADE) || */
91 (config.correct_disk_timing[drvreg])) {
95 this->out_debug_log("DRQ REG: %dbytes %d:%d -> %f\n", bytes, get_current_clock(), prev_drq_clock, usec);
96 cancel_my_event(EVENT_DRQ);
97 register_event(this, (EVENT_DRQ << 8) | (cmdtype & 0xff), usec, false, ®ister_id[EVENT_DRQ]);
100 void MB8877::register_lost_event(int bytes)
102 cancel_my_event(EVENT_LOST);
103 register_event(this, (EVENT_LOST << 8) | (cmdtype & 0xff), disk[drvreg]->get_usec_per_bytes(bytes), false, ®ister_id[EVENT_LOST]);
106 bool MB8877::check_drive(void)
108 if(drvreg >= _max_drive) {
109 status = FDC_ST_NOTREADY;
117 bool MB8877::check_drive2(void)
122 if(!is_disk_inserted(drvreg & 0x7f)) {
123 status = FDC_ST_NOTREADY;
131 void MB8877::initialize()
133 DEVICE::initialize();
134 // initialize d88 handler
135 if(osd->check_feature(_T("MAX_DRIVE"))) {
136 _max_drive = osd->get_feature_int_value(_T("MAX_DRIVE"));
137 } else if(osd->check_feature(_T("MAX_FD"))) {
138 _max_drive = osd->get_feature_int_value(_T("MAX_FD"));
142 _drive_mask = _max_drive - 1;
143 for(int i = 0; i < _max_drive; i++) {
144 disk[i] = new DISK(emu);
145 disk[i]->set_device_name(_T("%s/Disk #%d"), this_device_name, i + 1);
148 if(osd->check_feature(_T("MB8877_NO_BUSY_AFTER_SEEK"))) {
149 mb8877_no_busy_after_seek = true;
151 if(osd->check_feature(_T("_FDC_DEBUG_LOG"))) {
152 fdc_debug_log = true;
154 if(osd->check_feature(_T("HAS_MB8866"))) {
156 invert_registers = true;
157 set_device_name(_T("MB8866 FDC"));
159 if(osd->check_feature(_T("HAS_MB8876"))) {
160 invert_registers = true;
161 set_device_name(_T("MB8876 FDC"));
162 } else if(osd->check_feature(_T("HAS_MB89311"))) {
164 set_device_name(_T("MB89311 FDC"));
166 set_device_name(_T("MB8877 FDC"));
168 if(osd->check_feature(_T("_X1")) || osd->check_feature(_T("_X1TWIN")) ||
169 osd->check_feature(_T("_X1TURBO")) || osd->check_feature(_T("_X1TURBOZ"))) {
172 if(osd->check_feature(_T("_FM7")) || osd->check_feature(_T("_FM8")) ||
173 osd->check_feature(_T("_FM77_VARIANTS")) || osd->check_feature(_T("_FM77AV_VARIANTS"))) {
175 if(osd->check_feature(_T("_FM77AV40")) || osd->check_feature(_T("_FM77AV40EX")) ||
176 osd->check_feature(_T("_FM77AV40SX")) ||
177 osd->check_feature(_T("_FM77AV20")) || osd->check_feature(_T("_FM77AV20EX"))) {
178 type_fm77av_2dd = true;
181 if(osd->check_feature(_T("_FMR50"))) {
184 if(osd->check_feature(_T("_FMR60"))) {
189 if(d_noise_seek != NULL) {
190 d_noise_seek->set_device_name(_T("Noise Player (FDD Seek)"));
191 if(!d_noise_seek->load_wav_file(_T("FDDSEEK.WAV"))) {
192 if(!d_noise_seek->load_wav_file(_T("FDDSEEK1.WAV"))) {
193 d_noise_seek->load_wav_file(_T("SEEK.WAV"));
196 d_noise_seek->set_mute(!config.sound_noise_fdd);
198 if(d_noise_head_down != NULL) {
199 d_noise_head_down->set_device_name(_T("Noise Player (FDD Head Load)"));
200 d_noise_head_down->load_wav_file(_T("HEADDOWN.WAV"));
201 d_noise_head_down->set_mute(!config.sound_noise_fdd);
203 if(d_noise_head_up != NULL) {
204 d_noise_head_up->set_device_name(_T("Noise Player (FDD Head Unload)"));
205 d_noise_head_up->load_wav_file(_T("HEADUP.WAV"));
206 d_noise_head_up->set_mute(!config.sound_noise_fdd);
210 memset(fdc, 0, sizeof(fdc));
211 for(int i = 0; i < 16; i++) {
212 fdc[i].track = 40; // OK?
213 fdc[i].count_immediate = false;
218 status = cmdreg = trkreg = secreg = datareg = sidereg = cmdtype = 0;
220 prev_drq_clock = seekend_clock = 0;
223 void MB8877::release()
225 // release d88 handler
226 for(int i = 0; i < _max_drive; i++) {
236 for(int i = 0; i < _max_drive; i++) {
237 //fdc[i].track = 0; // Hold to track
239 fdc[i].access = false;
241 for(int i = 0; i < (int)array_length(register_id); i++) {
244 now_search = now_seek = drive_sel = false;
249 extended_mode = true;
251 extended_mode = false;
256 void MB8877::write_io8(uint32_t addr, uint32_t data)
264 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
265 if(invert_registers) {
266 cmdreg = (~data) & 0xff;
277 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
278 if(invert_registers) {
279 trkreg = (~data) & 0xff;
285 if((status & FDC_ST_BUSY) && (fdc[drvreg].index == 0)) {
286 // track reg is written after command starts
287 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
294 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
295 if(invert_registers) {
296 secreg = (~data) & 0xff;
302 if((status & FDC_ST_BUSY) && (fdc[drvreg].index == 0)) {
303 // sector reg is written after command starts
304 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
311 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
312 if(invert_registers) {
313 datareg = (~data) & 0xff;
319 ready = ((status & FDC_ST_DRQ) && !now_search);
320 //#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
322 if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
323 if(!motor_on) ready = false;
328 if(!motor_on) ready = false;
330 // if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
332 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
333 // write or multisector write
334 if(fdc[drvreg].index < disk[drvreg]->sector_size.sd) {
335 if(!disk[drvreg]->write_protected) {
336 if(disk[drvreg]->sector[fdc[drvreg].index] != datareg) {
337 disk[drvreg]->sector[fdc[drvreg].index] = datareg;
338 sector_changed = true;
341 disk[drvreg]->set_deleted((cmdreg & 1) != 0);
343 status |= FDC_ST_WRITEFAULT;
344 status &= ~FDC_ST_BUSY;
348 //fdc[drvreg].index++;
350 if((fdc[drvreg].index + 1) >= disk[drvreg]->sector_size.sd) {
351 if(cmdtype == FDC_CMD_WR_SEC) {
353 //#ifdef _FDC_DEBUG_LOG
354 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
356 status &= ~FDC_ST_BUSY;
361 //#ifdef _FDC_DEBUG_LOG
362 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR (SEARCH NEXT)\n"));
364 // 2HD: 360rpm, 10410bytes/track -> 0.06246bytes/us
365 register_my_event(EVENT_MULTI1, 30); // 0.06246bytes/us * 30us = 1.8738bytes < GAP3
366 register_my_event(EVENT_MULTI2, 60); // 0.06246bytes/us * 60us = 3.7476bytes < GAP3
368 sector_changed = false;
369 } else if(status & FDC_ST_DRQ) {
370 if(fdc[drvreg].index == 0) {
371 register_drq_event(fdc[drvreg].bytes_before_2nd_drq);
373 register_drq_event(1);
375 if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
377 status &= ~FDC_ST_DRQ;
378 } else if(cmdtype == FDC_CMD_WR_TRK) {
380 if(fdc[drvreg].index < disk[drvreg]->get_track_size()) {
381 if(!disk[drvreg]->write_protected) {
382 if(fdc[drvreg].index == 0) {
383 disk[drvreg]->format_track(fdc[drvreg].track, sidereg);
384 fdc[drvreg].id_written = false;
385 fdc[drvreg].side = sidereg;
386 fdc[drvreg].side_changed = false;
388 if(fdc[drvreg].side != sidereg) {
389 fdc[drvreg].side_changed = true;
391 if(fdc[drvreg].side_changed) {
392 // abort write track because disk side is changed
393 } else if(datareg == 0xf5) {
394 // write a1h in missing clock
395 } else if(datareg == 0xf6) {
396 // write c2h in missing clock
397 } else if(datareg == 0xf7) {
399 if(!fdc[drvreg].id_written) {
400 // insert new sector with data crc error
402 uint8_t c = 0, h = 0, r = 0, n = 0;
403 fdc[drvreg].id_written = true;
404 fdc[drvreg].sector_found = false;
405 if(fdc[drvreg].index >= 4) {
406 c = disk[drvreg]->track[fdc[drvreg].index - 4];
407 h = disk[drvreg]->track[fdc[drvreg].index - 3];
408 r = disk[drvreg]->track[fdc[drvreg].index - 2];
409 n = disk[drvreg]->track[fdc[drvreg].index - 1];
411 fdc[drvreg].sector_length = 0x80 << (n & 3);
412 fdc[drvreg].sector_index = 0;
413 disk[drvreg]->insert_sector(c, h, r, n, false, true, 0xe5, fdc[drvreg].sector_length);
414 } else if(fdc[drvreg].sector_found) {
415 // clear data crc error if all sector data are written
416 if(fdc[drvreg].sector_index == fdc[drvreg].sector_length) {
417 disk[drvreg]->set_data_crc_error(false);
419 fdc[drvreg].id_written = false;
421 // data mark of current sector is not written
422 disk[drvreg]->set_data_mark_missing();
425 } else if(fdc[drvreg].id_written) {
426 if(fdc[drvreg].sector_found) {
428 if(fdc[drvreg].sector_index < fdc[drvreg].sector_length) {
429 disk[drvreg]->sector[fdc[drvreg].sector_index] = datareg;
431 fdc[drvreg].sector_index++;
432 } else if(datareg == 0xf8 || datareg == 0xfb) {
434 disk[drvreg]->set_deleted(datareg == 0xf8);
435 fdc[drvreg].sector_found = true;
438 disk[drvreg]->track[fdc[drvreg].index] = datareg;
440 status |= FDC_ST_WRITEFAULT;
441 status &= ~FDC_ST_BUSY;
442 status &= ~FDC_ST_DRQ;
446 //fdc[drvreg].index++;
448 if((fdc[drvreg].index + 1) >= disk[drvreg]->get_track_size()) {
449 if(!disk[drvreg]->write_protected) {
450 if(fdc[drvreg].id_written && !fdc[drvreg].sector_found) {
451 // data mark of last sector is not written
452 disk[drvreg]->set_data_mark_missing();
454 disk[drvreg]->sync_buffer();
456 status &= ~FDC_ST_BUSY;
459 } else if(status & FDC_ST_DRQ) {
460 if(fdc[drvreg].index == 0) {
461 register_drq_event(fdc[drvreg].bytes_before_2nd_drq);
463 register_drq_event(1);
465 if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
467 status &= ~FDC_ST_DRQ;
469 if(!(status & FDC_ST_DRQ)) {
470 cancel_my_event(EVENT_LOST);
472 fdc[drvreg].access = true;
479 uint32_t MB8877::read_io8(uint32_t addr)
492 // disk not inserted, motor stop
493 not_ready = !disk[drvreg]->inserted;
494 //#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
496 if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
497 if(!motor_on) not_ready = true;
502 if(!motor_on) not_ready = true;
504 // if(!disk[drvreg]->inserted || !motor_on) {
506 status |= FDC_ST_NOTREADY;
508 status &= ~FDC_ST_NOTREADY;
511 if(cmdtype == FDC_CMD_TYPE1 || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) {
512 if(disk[drvreg]->inserted && disk[drvreg]->write_protected) {
513 status |= FDC_ST_WRITEP;
515 status &= ~FDC_ST_WRITEP;
518 status &= ~FDC_ST_WRITEP;
520 // track0, index hole
521 if(cmdtype == FDC_CMD_TYPE1) {
522 if(fdc[drvreg].track == 0) {
523 status |= FDC_ST_TRACK00;
525 status &= ~FDC_ST_TRACK00;
527 // index hole signal width is 5msec (thanks Mr.Sato)
528 if(!(status & FDC_ST_NOTREADY) && get_cur_position() < disk[drvreg]->get_bytes_per_usec(5000)) {
529 status |= FDC_ST_INDEX;
531 status &= ~FDC_ST_INDEX;
534 // show busy a moment
536 if(cmdtype == FDC_CMD_TYPE1 && !now_seek) {
537 status &= ~FDC_ST_BUSY;
538 //#ifdef MB8877_NO_BUSY_AFTER_SEEK
539 if(mb8877_no_busy_after_seek) {
540 //#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
542 if(disk[0]->is_special_disk != SPECIAL_DISK_FM7_XANADU2_D) {
554 if(cmdtype == 0 && !(status & FDC_ST_NOTREADY)) {
555 // MZ-2000 HuBASIC invites NOT READY status
556 if(++no_command == 16) {
557 val |= FDC_ST_NOTREADY;
563 if(!(status & FDC_ST_DRQ)) {
566 if(!(status & FDC_ST_BUSY)) {
569 //#ifdef _FDC_DEBUG_LOG
570 if(fdc_debug_log) this->out_debug_log(_T("FDC\tSTATUS=%2x\n"), val);
572 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
573 if(invert_registers) {
574 return (~val) & 0xff;
582 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
583 if(invert_registers) {
584 return (~trkreg) & 0xff;
592 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
593 if(invert_registers) {
594 return (~secreg) & 0xff;
602 ready = ((status & FDC_ST_DRQ) && !now_search);
603 //#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
605 if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
606 if(!motor_on) ready = false;
611 if(!motor_on) ready = false;
613 // if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
615 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC) {
616 // read or multisector read
617 if(fdc[drvreg].index < disk[drvreg]->sector_size.sd) {
618 datareg = disk[drvreg]->sector[fdc[drvreg].index];
620 if((fdc[drvreg].index + 1) >= disk[drvreg]->sector_size.sd) { // Reading complete this sector.
622 if(disk[drvreg]->data_crc_error && !disk[drvreg]->ignore_crc()) {
624 //#ifdef _FDC_DEBUG_LOG
625 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR (DATA CRC ERROR)\n"));
627 status |= FDC_ST_CRCERR;
628 status &= ~FDC_ST_BUSY;
631 } else if(cmdtype == FDC_CMD_RD_SEC) {
633 //#ifdef _FDC_DEBUG_LOG
634 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
636 status &= ~FDC_ST_BUSY;
641 //#ifdef _FDC_DEBUG_LOG
642 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR (SEARCH NEXT)\n"));
644 register_my_event(EVENT_MULTI1, 30);
645 register_my_event(EVENT_MULTI2, 60);
647 } else { // Still data remain.
648 register_drq_event(1);
649 if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
651 status &= ~FDC_ST_DRQ;
652 } else if(cmdtype == FDC_CMD_RD_ADDR) {
654 if(fdc[drvreg].index < 6) {
655 datareg = disk[drvreg]->id[fdc[drvreg].index];
656 //fdc[drvreg].index++;
658 if((fdc[drvreg].index + 1) >= 6) {
659 if(disk[drvreg]->addr_crc_error && !disk[drvreg]->ignore_crc()) {
661 status |= FDC_ST_CRCERR;
663 status &= ~FDC_ST_BUSY;
666 //#ifdef _FDC_DEBUG_LOG
667 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF ID FIELD\n"));
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_TRK) {
676 if(fdc[drvreg].index < disk[drvreg]->get_track_size()) {
677 datareg = disk[drvreg]->track[fdc[drvreg].index];
678 //fdc[drvreg].index++;
680 if((fdc[drvreg].index + 1) >= disk[drvreg]->get_track_size()) {
681 //#ifdef _FDC_DEBUG_LOG
682 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF TRACK\n"));
684 status &= ~FDC_ST_BUSY;
685 status |= FDC_ST_LOSTDATA;
689 register_drq_event(1);
690 if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
692 status &= ~FDC_ST_DRQ;
694 if(!(status & FDC_ST_DRQ)) {
695 cancel_my_event(EVENT_LOST);
697 fdc[drvreg].access = true;
700 //#ifdef _FDC_DEBUG_LOG
701 if(fdc_debug_log) this->force_out_debug_log(_T("FDC\tDATA=%2x\n"), datareg); // emu->force_out_debug_log()
703 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
704 if(invert_registers) {
705 return (~datareg) & 0xff;
715 void MB8877::write_dma_io8(uint32_t addr, uint32_t data)
720 uint32_t MB8877::read_dma_io8(uint32_t addr)
725 void MB8877::write_signal(int id, uint32_t data, uint32_t mask)
727 if(id == SIG_MB8877_DRIVEREG) {
728 drvreg = data & _drive_mask;
730 seekend_clock = get_current_clock();
731 } else if(id == SIG_MB8877_SIDEREG) {
732 sidereg = (data & mask) ? 1 : 0;
733 } else if(id == SIG_MB8877_MOTOR) {
734 motor_on = ((data & mask) != 0);
738 uint32_t MB8877::read_signal(int ch)
740 if(ch == SIG_MB8877_DRIVEREG) {
741 return drvreg & _drive_mask;
742 } else if(ch == SIG_MB8877_SIDEREG) {
744 } else if(ch == SIG_MB8877_MOTOR) {
745 return motor_on ? 1 : 0;
750 for(int i = 0; i < _max_drive; i++) {
754 fdc[i].access = false;
762 void MB8877::event_callback(int event_id, int err)
764 int event = event_id >> 8;
765 int cmd = event_id & 0xff;
766 //bool need_after_irq = false;
767 register_id[event] = -1;
769 // cancel event if the command is finished or other command is executed
771 if(event == EVENT_SEEK || event == EVENT_SEEKEND_VERIFY) {
773 } else if(event == EVENT_SEARCH) {
781 //#ifdef _FDC_DEBUG_LOG
782 //this->out_debug_log(_T("FDC\tSEEK START\n"));
784 if(seektrk > fdc[drvreg].track) {
786 if(d_noise_seek != NULL) d_noise_seek->play();
787 //need_after_irq = true;
788 } else if(seektrk < fdc[drvreg].track) {
790 if(d_noise_seek != NULL) d_noise_seek->play();
791 //need_after_irq = true;
793 if((cmdreg & 0x10) || ((cmdreg & 0xf0) == 0)) {
794 trkreg = fdc[drvreg].track;
796 if(seektrk != fdc[drvreg].track) {
797 //if(need_after_irq) {
799 //set_irq(true); // 20180118 K.O Turn ON IRQ -> Turn OFF DRQ
801 register_seek_event();
804 seekend_clock = get_current_clock();
808 if((cmdreg & 0xf4) == 0x44) {
812 } else if((cmdreg & 0xf4) == 0x64) {
823 status_tmp |= search_track();
825 if(status_tmp & FDC_ST_SEEKERR) {
826 time = get_usec_to_detect_index_hole(5, true);
828 time = get_usec_to_next_trans_pos(true);
830 // 20180128 K.O If seek completed, delay to make IRQ/DRQ at SEEKEND_VERIFY.
831 register_my_event(EVENT_SEEKEND_VERIFY, time);
834 // case EVENT_SEEKEND: // Separate SEEK and SEEKEND when verifying. 20180128 K.O
837 status &= (uint8_t)(~FDC_ST_BUSY); // 20180118 K.O Turn off BUSY flag.
839 set_irq(true); // 20180118 K.O Turn ON IRQ -> Turn OFF DRQ
841 case EVENT_SEEKEND_VERIFY: // Separate SEEK and SEEKEND when verifying. 20180128 K.O
843 status &= (uint8_t)(~FDC_ST_BUSY); // 20180118 K.O Turn off BUSY flag.
845 set_irq(true); // 20180118 K.O Turn ON IRQ -> Turn OFF DRQ
846 //#ifdef _FDC_DEBUG_LOG
847 //this->out_debug_log(_T("FDC\tSEEK END\n"));
852 if(status_tmp & FDC_ST_RECNFND) {
853 //#if defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
855 // for SHARP X1 Batten Tanuki
856 if(disk[drvreg]->is_special_disk == SPECIAL_DISK_X1_BATTEN && drive_sel) {
857 status_tmp &= ~FDC_ST_RECNFND;
861 //#ifdef _FDC_DEBUG_LOG
862 if(fdc_debug_log) this->out_debug_log(_T("FDC\tSEARCH NG\n"));
864 status = status_tmp & ~(FDC_ST_BUSY | FDC_ST_DRQ);
868 } else if(status_tmp & FDC_ST_WRITEFAULT) {
869 //#ifdef _FDC_DEBUG_LOG
870 if(fdc_debug_log) this->out_debug_log(_T("FDC\tWRITE PROTECTED\n"));
872 status = status_tmp & ~(FDC_ST_BUSY | FDC_ST_DRQ);
877 status = status_tmp | (FDC_ST_BUSY | FDC_ST_DRQ);
878 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
879 register_lost_event(8);
880 } else if(cmdtype == FDC_CMD_WR_TRK) {
881 register_lost_event(3);
883 register_lost_event(1);
885 fdc[drvreg].cur_position = fdc[drvreg].next_trans_position;
886 fdc[drvreg].prev_clock = prev_drq_clock = get_current_clock();
889 this->out_debug_log("DRQ ON@SEARCH: %d\n", prev_drq_clock);
890 //#ifdef _FDC_DEBUG_LOG
891 if(fdc_debug_log) this->out_debug_log(_T("FDC\tSEARCH OK\n"));
896 if(status & FDC_ST_BUSY) {
897 status |= FDC_ST_DRQ;
898 register_lost_event(1);
899 if((cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) && fdc[drvreg].index == 0) {
900 fdc[drvreg].cur_position = (fdc[drvreg].cur_position + fdc[drvreg].bytes_before_2nd_drq) % disk[drvreg]->get_track_size();
902 fdc[drvreg].cur_position = (fdc[drvreg].cur_position + 1) % disk[drvreg]->get_track_size();
904 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC ||
905 cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC ||
906 cmdtype == FDC_CMD_RD_TRK || cmdtype == FDC_CMD_WR_TRK ||
907 cmdtype == FDC_CMD_RD_ADDR) {
908 if(!(fdc[drvreg].count_immediate)) fdc[drvreg].index++;
910 fdc[drvreg].prev_clock = prev_drq_clock = get_current_clock();
913 this->out_debug_log("DRQ ON@DRQ: %d\n", prev_drq_clock);
914 //#ifdef _FDC_DEBUG_LOG
915 //this->out_debug_log(_T("FDC\tDRQ!\n"));
923 if(cmdtype == FDC_CMD_RD_MSEC) {
925 } else if(cmdtype == FDC_CMD_WR_MSEC) {
926 cmd_writedata(false);
930 if(status & FDC_ST_BUSY) {
931 //#ifdef _FDC_DEBUG_LOG
932 if(fdc_debug_log) this->out_debug_log(_T("FDC\tDATA LOST\n"));
934 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) {
935 if(fdc[drvreg].index == 0) { // HEAD of REGION
937 //if((status & FDC_ST_DRQ) != 0) { // 20180130 FORCE DOWN DRQ ON LOST-DATA.
938 status |= FDC_ST_LOSTDATA;
939 status &= (uint8_t)(~(FDC_ST_DRQ | FDC_ST_BUSY));
943 } else { // STILL WRITING
945 //if((status & FDC_ST_DRQ) != 0) {
946 status |= FDC_ST_LOSTDATA;
947 status &= (uint8_t)(~(FDC_ST_DRQ | FDC_ST_BUSY));
954 //if((status & FDC_ST_DRQ) != 0) {
955 status |= FDC_ST_LOSTDATA;
956 status &= (uint8_t)(~(FDC_ST_DRQ | FDC_ST_BUSY));
962 status |= FDC_ST_LOSTDATA;
968 // ----------------------------------------------------------------------------
970 // ----------------------------------------------------------------------------
972 void MB8877::process_cmd()
978 // MB89311 mode commands
981 // delay (may be only in extended mode)
982 //#ifdef _FDC_DEBUG_LOG
983 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (DELAY ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
985 cmdtype = status = 0;
987 } else if(cmdreg == 0xfd) {
989 //#ifdef _FDC_DEBUG_LOG
990 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (ASGN PAR) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
992 cmdtype = status = 0;
994 } else if(cmdreg == 0xfe) {
996 //#ifdef _FDC_DEBUG_LOG
997 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (ASGN MOD) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
999 extended_mode = !extended_mode;
1000 cmdtype = status = 0;
1002 } else if(cmdreg == 0xff) {
1003 // reset (may be only in extended mode)
1004 //#ifdef _FDC_DEBUG_LOG
1005 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (RESET ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1008 extended_mode = true;
1010 } else if(extended_mode) {
1012 if((cmdreg & 0xeb) == 0x21) {
1013 //#ifdef _FDC_DEBUG_LOG
1014 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (STEP IN ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1018 } else if((cmdreg & 0xeb) == 0x22) {
1019 //#ifdef _FDC_DEBUG_LOG
1020 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (STEP OUT) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1025 } else if((cmdreg & 0xf4) == 0x44) {
1027 //#ifdef _FDC_DEBUG_LOG
1028 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (RDaftSEK) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1032 } else if((cmdreg & 0xf4) == 0x64) {
1034 //#ifdef _FDC_DEBUG_LOG
1035 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (WRaftSEK) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1040 } else if((cmdreg & 0xfb) == 0xf1) {
1042 //#ifdef _FDC_DEBUG_LOG
1043 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (FORMAT ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1052 // MB8877 mode commands
1053 //#ifdef _FDC_DEBUG_LOG
1054 static const _TCHAR *cmdstr[0x10] = {
1055 _T("RESTORE "), _T("SEEK "), _T("STEP "), _T("STEP "),
1056 _T("STEP IN "), _T("STEP IN "), _T("STEP OUT"), _T("STEP OUT"),
1057 _T("RD DATA "), _T("RD DATA "), _T("RD DATA "), _T("WR DATA "),
1058 _T("RD ADDR "), _T("FORCEINT"), _T("RD TRACK"), _T("WR TRACK")
1060 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (%s) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, cmdstr[cmdreg >> 4], datareg, drvreg, trkreg, sidereg, secreg);
1063 switch(cmdreg & 0xf8) {
1065 case 0x00: case 0x08:
1067 update_head_flag(drvreg, (cmdreg & 8) != 0);
1069 case 0x10: case 0x18:
1071 update_head_flag(drvreg, (cmdreg & 8) != 0);
1073 case 0x20: case 0x28:
1074 case 0x30: case 0x38:
1076 update_head_flag(drvreg, (cmdreg & 8) != 0);
1078 case 0x40: case 0x48:
1079 case 0x50: case 0x58:
1081 update_head_flag(drvreg, (cmdreg & 8) != 0);
1083 case 0x60: case 0x68:
1084 case 0x70: case 0x78:
1086 update_head_flag(drvreg, (cmdreg & 8) != 0);
1089 case 0x80: case 0x88:
1090 case 0x90: case 0x98:
1092 update_head_flag(drvreg, true);
1094 case 0xa0:case 0xa8:
1095 case 0xb0: case 0xb8:
1096 cmd_writedata(true);
1097 update_head_flag(drvreg, true);
1102 update_head_flag(drvreg, true);
1106 update_head_flag(drvreg, true);
1110 update_head_flag(drvreg, true);
1113 case 0xd0: case 0xd8:
1122 void MB8877::cmd_restore()
1125 cmdtype = FDC_CMD_TYPE1;
1126 if(!check_drive()) {
1129 if((cmdreg & 0x08) != 0) { // Head engage
1130 status = FDC_ST_HEADENG | FDC_ST_BUSY;
1132 status = FDC_ST_BUSY;
1137 if(fdc[drvreg].track < 0) {
1138 fdc[drvreg].track = 0;
1140 } else if(fdc[drvreg].track >= 80) {
1141 fdc[drvreg].track = 80;
1144 trkreg = fdc[drvreg].track;
1151 register_seek_event();
1154 void MB8877::cmd_seek()
1157 cmdtype = FDC_CMD_TYPE1;
1158 if(!check_drive()) {
1161 if((cmdreg & 0x08) != 0) { // Head engage
1162 status = FDC_ST_HEADENG | FDC_ST_BUSY;
1164 status = FDC_ST_BUSY;
1167 // seektrk = (uint8_t)(fdc[drvreg].track + datareg - trkreg);
1169 //#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
1170 if(type_fm77av_2dd) {
1171 if(disk[drvreg]->drive_type != DRIVE_TYPE_2D) {
1172 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1174 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1176 } else if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
1177 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1179 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1181 seekvct = !(seektrk > fdc[drvreg].track);
1185 if(trkreg != fdc[drvreg].track) {
1186 status |= FDC_ST_SEEKERR;
1187 trkreg = fdc[drvreg].track;
1190 register_seek_event();
1193 void MB8877::cmd_step()
1203 void MB8877::cmd_stepin()
1206 cmdtype = FDC_CMD_TYPE1;
1207 if(!check_drive()) {
1210 if((cmdreg & 0x08) != 0) { // Head engage
1211 status = FDC_ST_HEADENG | FDC_ST_BUSY;
1213 status = FDC_ST_BUSY;
1215 seektrk = fdc[drvreg].track + 1;
1216 if(type_fm77av_2dd) {
1217 if(disk[drvreg]->drive_type != DRIVE_TYPE_2D) {
1218 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1220 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1222 } else if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
1223 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1225 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1231 if(trkreg != fdc[drvreg].track) {
1232 status |= FDC_ST_SEEKERR;
1233 // trkreg = fdc[drvreg].track;
1236 register_seek_event();
1239 void MB8877::cmd_stepout()
1242 cmdtype = FDC_CMD_TYPE1;
1243 if(!check_drive()) {
1246 if((cmdreg & 0x08) != 0) { // Head engage
1247 status = FDC_ST_HEADENG | FDC_ST_BUSY;
1249 status = FDC_ST_BUSY;
1252 seektrk = fdc[drvreg].track - 1;
1253 if(type_fm77av_2dd) {
1254 if(disk[drvreg]->drive_type != DRIVE_TYPE_2D) {
1255 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1257 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1259 } else if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
1260 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1262 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1268 if(trkreg != fdc[drvreg].track) {
1269 status |= FDC_ST_SEEKERR;
1270 // trkreg = fdc[drvreg].track;
1273 register_seek_event();
1276 void MB8877::cmd_readdata(bool first_sector)
1279 cmdtype = (cmdreg & 0x10) ? FDC_CMD_RD_MSEC : FDC_CMD_RD_SEC;
1280 if(!check_drive2()) {
1283 status = FDC_ST_BUSY;
1284 status_tmp = search_sector();
1288 if(status_tmp & FDC_ST_RECNFND) {
1289 time = get_usec_to_detect_index_hole(5, first_sector && ((cmdreg & 4) != 0));
1291 time = get_usec_to_start_trans(first_sector);
1293 register_my_event(EVENT_SEARCH, time);
1294 cancel_my_event(EVENT_LOST);
1297 void MB8877::cmd_writedata(bool first_sector)
1299 // type-2 write data
1300 cmdtype = (cmdreg & 0x10) ? FDC_CMD_WR_MSEC : FDC_CMD_WR_SEC;
1301 if(!check_drive2()) {
1304 status = FDC_ST_BUSY;
1305 status_tmp = search_sector() & ~FDC_ST_RECTYPE;
1307 sector_changed = false;
1310 if(status_tmp & FDC_ST_RECNFND) {
1311 time = get_usec_to_detect_index_hole(5, first_sector && ((cmdreg & 4) != 0));
1312 } else if(status & FDC_ST_WRITEFAULT) {
1313 time = (cmdreg & 4) ? DELAY_TIME : 1;
1315 time = get_usec_to_start_trans(first_sector);
1317 register_my_event(EVENT_SEARCH, time);
1318 cancel_my_event(EVENT_LOST);
1321 void MB8877::cmd_readaddr()
1323 // type-3 read address
1324 cmdtype = FDC_CMD_RD_ADDR;
1325 if(!check_drive2()) {
1328 status = FDC_ST_BUSY;
1329 status_tmp = search_addr();
1333 if(status_tmp & FDC_ST_RECNFND) {
1334 time = get_usec_to_detect_index_hole(5, ((cmdreg & 4) != 0));
1336 time = get_usec_to_start_trans(true);
1338 register_my_event(EVENT_SEARCH, time);
1339 cancel_my_event(EVENT_LOST);
1342 void MB8877::cmd_readtrack()
1344 // type-3 read track
1345 cmdtype = FDC_CMD_RD_TRK;
1346 if(!check_drive2()) {
1349 status = FDC_ST_BUSY;
1352 disk[drvreg]->make_track(fdc[drvreg].track, sidereg);
1353 fdc[drvreg].index = 0;
1356 fdc[drvreg].next_trans_position = 1;
1357 double time = get_usec_to_detect_index_hole(1, ((cmdreg & 4) != 0));
1358 register_my_event(EVENT_SEARCH, time);
1359 cancel_my_event(EVENT_LOST);
1362 void MB8877::cmd_writetrack()
1364 // type-3 write track
1365 cmdtype = FDC_CMD_WR_TRK;
1366 if(!check_drive2()) {
1369 status = FDC_ST_BUSY;
1372 fdc[drvreg].index = 0;
1373 fdc[drvreg].id_written = false;
1377 if(disk[drvreg]->write_protected) {
1378 status_tmp = FDC_ST_WRITEFAULT;
1379 time = (cmdreg & 4) ? DELAY_TIME : 1;
1382 // wait 15msec before raise first drq
1383 fdc[drvreg].next_trans_position = (get_cur_position() + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
1386 // raise first drq soon
1387 fdc[drvreg].next_trans_position = (get_cur_position() + 1) % disk[drvreg]->get_track_size();
1388 time = disk[drvreg]->get_usec_per_bytes(1);
1390 // wait at least 3bytes before check index hole and raise second drq
1391 fdc[drvreg].bytes_before_2nd_drq = disk[drvreg]->get_track_size() - fdc[drvreg].next_trans_position;
1392 if(fdc[drvreg].bytes_before_2nd_drq < 3) {
1393 fdc[drvreg].bytes_before_2nd_drq += disk[drvreg]->get_track_size();
1396 register_my_event(EVENT_SEARCH, time);
1397 cancel_my_event(EVENT_LOST);
1400 //#ifdef HAS_MB89311
1401 void MB8877::cmd_format()
1404 // type-3 format (FIXME: need to implement)
1405 cmdtype = FDC_CMD_WR_TRK;
1406 status = FDC_ST_BUSY;
1409 fdc[drvreg].index = 0;
1410 fdc[drvreg].id_written = false;
1413 status_tmp = FDC_ST_WRITEFAULT;
1414 double time = (cmdreg & 4) ? DELAY_TIME : 1;
1416 register_my_event(EVENT_SEARCH, time);
1417 cancel_my_event(EVENT_LOST);
1422 void MB8877::cmd_forceint()
1424 // type-4 force interrupt
1425 if(cmdtype == FDC_CMD_TYPE1) {
1426 // abort restore/seek/step command
1428 if(seektrk > fdc[drvreg].track) {
1429 fdc[drvreg].track++;
1430 } else if(seektrk < fdc[drvreg].track) {
1431 fdc[drvreg].track--;
1433 if((cmdreg_tmp & 0x10) || ((cmdreg_tmp & 0xf0) == 0)) {
1434 trkreg = fdc[drvreg].track;
1437 } else if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1438 // abort write sector command
1439 if(sector_changed) {
1440 disk[drvreg]->set_data_crc_error(false);
1442 } else if(cmdtype == FDC_CMD_WR_TRK) {
1443 // abort write track command
1444 if(!disk[drvreg]->write_protected) {
1445 if(fdc[drvreg].id_written && !fdc[drvreg].sector_found) {
1446 // data mark of last sector is not written
1447 disk[drvreg]->set_data_mark_missing();
1449 disk[drvreg]->sync_buffer();
1452 now_search = now_seek = sector_changed = false;
1454 //#ifdef HAS_MB89311
1455 if((cmdreg == 0xff) && (type_mb89311)) {
1457 cmdtype = FDC_CMD_TYPE1;
1458 status = FDC_ST_HEADENG;
1461 if(cmdtype == 0 || !(status & FDC_ST_BUSY)) {
1462 cmdtype = FDC_CMD_TYPE1;
1463 if(!type_fm7) status = FDC_ST_HEADENG; // Hack for FUKUALL.d77 .
1465 status &= ~FDC_ST_BUSY;
1467 // force interrupt if bit0-bit3 is high
1471 //#ifdef HAS_MB89311
1475 cancel_my_event(EVENT_SEEK);
1476 cancel_my_event(EVENT_SEEKEND_VERIFY);
1477 cancel_my_event(EVENT_SEARCH);
1478 cancel_my_event(EVENT_DRQ);
1479 cancel_my_event(EVENT_MULTI1);
1480 cancel_my_event(EVENT_MULTI2);
1481 cancel_my_event(EVENT_LOST);
1484 void MB8877::update_head_flag(int drv, bool head_load)
1486 if(fdc[drv].head_load != head_load) {
1488 if(d_noise_head_down != NULL) d_noise_head_down->play();
1490 if(d_noise_head_up != NULL) d_noise_head_up->play();
1492 fdc[drv].head_load = head_load;
1496 // ----------------------------------------------------------------------------
1498 // ----------------------------------------------------------------------------
1500 uint8_t MB8877::search_track()
1503 int track = fdc[drvreg].track;
1504 //#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
1505 if(type_fm77av_2dd) {
1506 if(disk[drvreg]->media_type == MEDIA_TYPE_2D) {
1507 if((disk[drvreg]->drive_type == DRIVE_TYPE_2DD) ||
1508 (disk[drvreg]->drive_type == DRIVE_TYPE_2HD) ||
1509 (disk[drvreg]->drive_type == DRIVE_TYPE_144)) {
1512 } else { // OS-9 2DD Access fix by Ryu Takegami
1513 if((disk[drvreg]->media_type != MEDIA_TYPE_2D) &&
1514 (disk[drvreg]->media_type != MEDIA_TYPE_UNK)) {
1515 if(disk[drvreg]->drive_type == DRIVE_TYPE_2D) {
1522 if(!disk[drvreg]->get_track(track, sidereg)){
1523 return FDC_ST_SEEKERR;
1526 // verify track number
1527 if(disk[drvreg]->ignore_crc()) {
1528 for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
1529 disk[drvreg]->get_sector(-1, -1, i);
1530 if(disk[drvreg]->id[0] == trkreg) {
1531 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[i] + 4 + 2;
1532 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[i];
1537 for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
1538 disk[drvreg]->get_sector(-1, -1, i);
1539 if(disk[drvreg]->id[0] == trkreg && !disk[drvreg]->addr_crc_error) {
1540 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[i] + 4 + 2;
1541 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[i];
1545 for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
1546 disk[drvreg]->get_sector(-1, -1, i);
1547 if(disk[drvreg]->id[0] == trkreg) {
1548 return FDC_ST_SEEKERR | FDC_ST_CRCERR;
1552 return FDC_ST_SEEKERR;
1555 uint8_t MB8877::search_sector()
1558 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1559 if(disk[drvreg]->write_protected) {
1560 return FDC_ST_WRITEFAULT;
1565 int track = fdc[drvreg].track;
1566 //#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
1567 if(type_fm77av_2dd) {
1568 if(disk[drvreg]->media_type == MEDIA_TYPE_2D) {
1569 if((disk[drvreg]->drive_type == DRIVE_TYPE_2DD) ||
1570 (disk[drvreg]->drive_type == DRIVE_TYPE_2HD) ||
1571 (disk[drvreg]->drive_type == DRIVE_TYPE_144)) {
1574 } else { // OS-9 2DD Access fix by Ryu Takegami
1575 if((disk[drvreg]->media_type != MEDIA_TYPE_2D) &&
1576 (disk[drvreg]->media_type != MEDIA_TYPE_UNK)) {
1577 if(disk[drvreg]->drive_type == DRIVE_TYPE_2D) {
1584 if(!disk[drvreg]->get_track(track, sidereg)) {
1585 return FDC_ST_RECNFND;
1588 // get current position
1589 int sector_num = disk[drvreg]->sector_num.sd;
1590 int position = get_cur_position();
1592 if(position > disk[drvreg]->am1_position[sector_num - 1]) {
1593 position -= disk[drvreg]->get_track_size();
1596 // first scanned sector
1597 int first_sector = 0;
1598 for(int i = 0; i < sector_num; i++) {
1599 if(position < disk[drvreg]->am1_position[i]) {
1606 for(int i = 0; i < sector_num; i++) {
1608 int index = (first_sector + i) % sector_num;
1609 disk[drvreg]->get_sector(-1, -1, index);
1612 if(disk[drvreg]->id[0] != trkreg) {
1615 //#if !defined(HAS_MB8866)
1617 if((cmdreg & 2) && (disk[drvreg]->id[1] & 1) != ((cmdreg >> 3) & 1)) {
1622 if(disk[drvreg]->id[2] != secreg) {
1625 if(disk[drvreg]->sector_size.sd == 0) {
1628 if(disk[drvreg]->addr_crc_error && !disk[drvreg]->ignore_crc()) {
1630 disk[drvreg]->sector_size.sd = 0;
1631 return FDC_ST_RECNFND | FDC_ST_CRCERR;
1635 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1636 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[index] + 4 + 2;
1637 fdc[drvreg].bytes_before_2nd_drq = disk[drvreg]->data_position[index] - fdc[drvreg].next_trans_position;
1639 fdc[drvreg].next_trans_position = disk[drvreg]->data_position[index] + 1;
1641 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[index];
1642 fdc[drvreg].index = 0;
1643 //#ifdef _FDC_DEBUG_LOG
1644 if(fdc_debug_log) this->out_debug_log(_T("FDC\tSECTOR FOUND SIZE=$%04x ID=%02x %02x %02x %02x CRC=%02x %02x CRC_ERROR=%d\n"),
1645 disk[drvreg]->sector_size.sd,
1646 disk[drvreg]->id[0], disk[drvreg]->id[1], disk[drvreg]->id[2], disk[drvreg]->id[3],
1647 disk[drvreg]->id[4], disk[drvreg]->id[5],
1648 disk[drvreg]->data_crc_error ? 1 : 0);
1650 return (disk[drvreg]->deleted ? FDC_ST_RECTYPE : 0);
1654 disk[drvreg]->sector_size.sd = 0;
1655 return FDC_ST_RECNFND;
1658 uint8_t MB8877::search_addr()
1661 int track = fdc[drvreg].track;
1662 //#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
1663 if(type_fm77av_2dd) {
1664 if(disk[drvreg]->media_type == MEDIA_TYPE_2D) {
1665 if((disk[drvreg]->drive_type == DRIVE_TYPE_2DD) ||
1666 (disk[drvreg]->drive_type == DRIVE_TYPE_2HD) ||
1667 (disk[drvreg]->drive_type == DRIVE_TYPE_144)) {
1670 } else { // OS-9 2DD Access fix by Ryu Takegami
1671 if((disk[drvreg]->media_type != MEDIA_TYPE_2D) &&
1672 (disk[drvreg]->media_type != MEDIA_TYPE_UNK)) {
1673 if(disk[drvreg]->drive_type == DRIVE_TYPE_2D) {
1680 if(!disk[drvreg]->get_track(track, sidereg)) {
1681 return FDC_ST_RECNFND;
1684 // get current position
1685 int sector_num = disk[drvreg]->sector_num.sd;
1686 int position = get_cur_position();
1688 if(position > disk[drvreg]->am1_position[sector_num - 1]) {
1689 position -= disk[drvreg]->get_track_size();
1692 // first scanned sector
1693 int first_sector = 0;
1694 for(int i = 0; i < sector_num; i++) {
1695 if(position < disk[drvreg]->am1_position[i]) {
1702 if(disk[drvreg]->get_sector(-1, -1, first_sector)) {
1703 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[first_sector] + 1;
1704 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[first_sector];
1705 fdc[drvreg].index = 0;
1706 secreg = disk[drvreg]->id[0];
1711 disk[drvreg]->sector_size.sd = 0;
1712 return FDC_ST_RECNFND;
1715 // ----------------------------------------------------------------------------
1717 // ----------------------------------------------------------------------------
1719 int MB8877::get_cur_position()
1721 return (fdc[drvreg].cur_position + disk[drvreg]->get_bytes_per_usec(get_passed_usec(fdc[drvreg].prev_clock))) % disk[drvreg]->get_track_size();
1724 double MB8877::get_usec_to_start_trans(bool first_sector)
1726 // get time from current position
1727 double time = get_usec_to_next_trans_pos(first_sector && ((cmdreg & 4) != 0));
1728 if(first_sector && time < 60000 - get_passed_usec(seekend_clock)) {
1729 time += disk[drvreg]->get_usec_per_track();
1734 double MB8877::get_usec_to_next_trans_pos(bool delay)
1736 int position = get_cur_position();
1738 if(disk[drvreg]->invalid_format) {
1739 // XXX: this track is invalid format and the calculated sector position may be incorrect.
1740 // so use the constant period
1742 } else if(/*disk[drvreg]->no_skew && */!disk[drvreg]->correct_timing()) {
1743 // XXX: this image may be a standard image or coverted from a standard image and skew may be incorrect,
1744 // so use the period to search the next sector from the current position
1745 int sector_num = disk[drvreg]->sector_num.sd;
1748 if(position > disk[drvreg]->am1_position[sector_num - 1]) {
1749 position -= disk[drvreg]->get_track_size();
1751 for(int i = 0; i < sector_num; i++) {
1752 if(position < disk[drvreg]->am1_position[i]) {
1753 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1754 bytes = (disk[drvreg]->id_position[i] + 4 + 2) - position;
1756 bytes = (disk[drvreg]->data_position[i] + 1) - position;
1759 bytes += disk[drvreg]->get_track_size(); // to make sure
1765 return disk[drvreg]->get_usec_per_bytes(bytes);
1770 position = (position + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
1772 int bytes = fdc[drvreg].next_trans_position - position;
1773 if(fdc[drvreg].next_am1_position < position || bytes < 0) {
1774 bytes += disk[drvreg]->get_track_size();
1776 double time = disk[drvreg]->get_usec_per_bytes(bytes);
1783 double MB8877::get_usec_to_detect_index_hole(int count, bool delay)
1785 int position = get_cur_position();
1787 position = (position + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
1789 int bytes = disk[drvreg]->get_track_size() * count - position;
1791 bytes += disk[drvreg]->get_track_size();
1793 double time = disk[drvreg]->get_usec_per_bytes(bytes);
1800 // ----------------------------------------------------------------------------
1802 // ----------------------------------------------------------------------------
1804 void MB8877::set_irq(bool val)
1806 write_signals(&outputs_irq, val ? 0xffffffff : 0);
1809 void MB8877::set_drq(bool val)
1811 write_signals(&outputs_drq, val ? 0xffffffff : 0);
1814 // ----------------------------------------------------------------------------
1816 // ----------------------------------------------------------------------------
1818 void MB8877::open_disk(int drv, const _TCHAR* file_path, int bank)
1820 if(drv < _max_drive) {
1821 disk[drv]->open(file_path, bank);
1822 #if defined(_USE_QT)
1823 if((disk[drv]->is_special_disk == SPECIAL_DISK_FM7_FLEX) || (config.disk_count_immediate[drv])) {
1825 if(disk[drv]->is_special_disk == SPECIAL_DISK_FM7_FLEX) {
1827 fdc[drv].count_immediate = true;
1829 fdc[drv].count_immediate = false;
1834 void MB8877::close_disk(int drv)
1836 if(drv < _max_drive) {
1839 update_head_flag(drvreg, false);
1840 fdc[drv].count_immediate = false;
1844 bool MB8877::is_disk_inserted(int drv)
1846 if(drv < _max_drive) {
1847 return disk[drv]->inserted;
1852 void MB8877::is_disk_protected(int drv, bool value)
1854 if(drv < _max_drive) {
1855 disk[drv]->write_protected = value;
1859 bool MB8877::is_disk_protected(int drv)
1861 if(drv < _max_drive) {
1862 return disk[drv]->write_protected;
1867 void MB8877::set_drive_type(int drv, uint8_t type)
1869 if(drv < _max_drive) {
1870 disk[drv]->drive_type = type;
1874 uint8_t MB8877::get_drive_type(int drv)
1876 if(drv < _max_drive) {
1877 return disk[drv]->drive_type;
1879 return DRIVE_TYPE_UNK;
1882 void MB8877::set_drive_rpm(int drv, int rpm)
1884 if(drv < _max_drive) {
1885 disk[drv]->drive_rpm = rpm;
1889 void MB8877::set_drive_mfm(int drv, bool mfm)
1891 if(drv < _max_drive) {
1892 disk[drv]->drive_mfm = mfm;
1896 void MB8877::set_track_size(int drv, int size)
1898 if(drv < _max_drive) {
1899 disk[drv]->track_size = size;
1903 uint8_t MB8877::fdc_status()
1905 // for each virtual machines
1906 //#if defined(_FMR50) || defined(_FMR60)
1907 if(type_fmr50 || type_fmr60) {
1908 return disk[drvreg]->inserted ? 2 : 0;
1915 void MB8877::update_config()
1917 if(d_noise_seek != NULL) {
1918 d_noise_seek->set_mute(!config.sound_noise_fdd);
1920 if(d_noise_head_down != NULL) {
1921 d_noise_head_down->set_mute(!config.sound_noise_fdd);
1923 if(d_noise_head_up != NULL) {
1924 d_noise_head_up->set_mute(!config.sound_noise_fdd);
1928 #define STATE_VERSION 6
1930 void MB8877::save_state(FILEIO* state_fio)
1932 state_fio->FputUint32(STATE_VERSION);
1933 state_fio->FputInt32(this_device_id);
1935 state_fio->Fwrite(fdc, sizeof(fdc), 1);
1936 for(int i = 0; i < _max_drive; i++) {
1937 disk[i]->save_state(state_fio);
1939 state_fio->FputUint8(status);
1940 state_fio->FputUint8(status_tmp);
1941 state_fio->FputUint8(cmdreg);
1942 state_fio->FputUint8(cmdreg_tmp);
1943 state_fio->FputUint8(trkreg);
1944 state_fio->FputUint8(secreg);
1945 state_fio->FputUint8(datareg);
1946 state_fio->FputUint8(drvreg);
1947 state_fio->FputUint8(sidereg);
1948 state_fio->FputUint8(cmdtype);
1949 state_fio->Fwrite(register_id, sizeof(register_id), 1);
1950 state_fio->FputBool(now_search);
1951 state_fio->FputBool(now_seek);
1952 state_fio->FputBool(sector_changed);
1953 state_fio->FputInt32(no_command);
1954 state_fio->FputInt32(seektrk);
1955 state_fio->FputBool(seekvct);
1956 state_fio->FputBool(motor_on);
1957 state_fio->FputBool(drive_sel);
1958 state_fio->FputUint32(prev_drq_clock);
1959 state_fio->FputUint32(seekend_clock);
1962 bool MB8877::load_state(FILEIO* state_fio)
1964 if(state_fio->FgetUint32() != STATE_VERSION) {
1967 if(state_fio->FgetInt32() != this_device_id) {
1970 state_fio->Fread(fdc, sizeof(fdc), 1);
1971 for(int i = 0; i < _max_drive; i++) {
1972 if(!disk[i]->load_state(state_fio)) {
1976 status = state_fio->FgetUint8();
1977 status_tmp = state_fio->FgetUint8();
1978 cmdreg = state_fio->FgetUint8();
1979 cmdreg_tmp = state_fio->FgetUint8();
1980 trkreg = state_fio->FgetUint8();
1981 secreg = state_fio->FgetUint8();
1982 datareg = state_fio->FgetUint8();
1983 drvreg = state_fio->FgetUint8();
1984 sidereg = state_fio->FgetUint8();
1985 cmdtype = state_fio->FgetUint8();
1986 state_fio->Fread(register_id, sizeof(register_id), 1);
1987 now_search = state_fio->FgetBool();
1988 now_seek = state_fio->FgetBool();
1989 sector_changed = state_fio->FgetBool();
1990 no_command = state_fio->FgetInt32();
1991 seektrk = state_fio->FgetInt32();
1992 seekvct = state_fio->FgetBool();
1993 motor_on = state_fio->FgetBool();
1994 drive_sel = state_fio->FgetBool();
1995 prev_drq_clock = state_fio->FgetUint32();
1996 seekend_clock = state_fio->FgetUint32();