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 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 usec = disk[drvreg]->get_usec_per_bytes(bytes) - get_passed_usec(prev_drq_clock);
86 //#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
88 if((disk[drvreg]->is_special_disk == SPECIAL_DISK_FM7_GAMBLER) ||
89 (disk[drvreg]->is_special_disk == SPECIAL_DISK_FM77AV_PSYOBLADE) ||
90 (config.correct_disk_timing[drvreg])) {
95 cancel_my_event(EVENT_DRQ);
96 register_event(this, (EVENT_DRQ << 8) | (cmdtype & 0xff), usec, false, ®ister_id[EVENT_DRQ]);
99 void MB8877::register_lost_event(int bytes)
101 cancel_my_event(EVENT_LOST);
102 register_event(this, (EVENT_LOST << 8) | (cmdtype & 0xff), disk[drvreg]->get_usec_per_bytes(bytes), false, ®ister_id[EVENT_LOST]);
105 bool MB8877::check_drive(void)
107 if(drvreg >= _max_drive) {
108 status = FDC_ST_NOTREADY;
116 bool MB8877::check_drive2(void)
121 if(!is_disk_inserted(drvreg & 0x7f)) {
122 status = FDC_ST_NOTREADY;
130 void MB8877::initialize()
132 DEVICE::initialize();
133 // initialize d88 handler
134 if(osd->check_feature(_T("MAX_DRIVE"))) {
135 _max_drive = osd->get_feature_int_value(_T("MAX_DRIVE"));
136 } else if(osd->check_feature(_T("MAX_FD"))) {
137 _max_drive = osd->get_feature_int_value(_T("MAX_FD"));
141 _drive_mask = _max_drive - 1;
142 for(int i = 0; i < _max_drive; i++) {
143 disk[i] = new DISK(emu);
144 disk[i]->set_device_name(_T("%s/Disk #%d"), this_device_name, i + 1);
147 if(osd->check_feature(_T("MB8877_NO_BUSY_AFTER_SEEK"))) {
148 mb8877_no_busy_after_seek = true;
150 if(osd->check_feature(_T("_FDC_DEBUG_LOG"))) {
151 fdc_debug_log = true;
153 if(osd->check_feature(_T("HAS_MB8866"))) {
155 invert_registers = true;
156 set_device_name(_T("MB8866 FDC"));
158 if(osd->check_feature(_T("HAS_MB8876"))) {
159 invert_registers = true;
160 set_device_name(_T("MB8876 FDC"));
161 } else if(osd->check_feature(_T("HAS_MB89311"))) {
163 set_device_name(_T("MB89311 FDC"));
165 set_device_name(_T("MB8877 FDC"));
167 if(osd->check_feature(_T("_X1")) || osd->check_feature(_T("_X1TWIN")) ||
168 osd->check_feature(_T("_X1TURBO")) || osd->check_feature(_T("_X1TURBOZ"))) {
171 if(osd->check_feature(_T("_FM7")) || osd->check_feature(_T("_FM8")) ||
172 osd->check_feature(_T("_FM77_VARIANTS")) || osd->check_feature(_T("_FM77AV_VARIANTS"))) {
174 if(osd->check_feature(_T("_FM77AV40")) || osd->check_feature(_T("_FM77AV40EX")) ||
175 osd->check_feature(_T("_FM77AV40SX")) ||
176 osd->check_feature(_T("_FM77AV20")) || osd->check_feature(_T("_FM77AV20EX"))) {
177 type_fm77av_2dd = true;
180 if(osd->check_feature(_T("_FMR50"))) {
183 if(osd->check_feature(_T("_FMR60"))) {
188 if(d_noise_seek != NULL) {
189 d_noise_seek->set_device_name(_T("Noise Player (FDD Seek)"));
190 if(!d_noise_seek->load_wav_file(_T("FDDSEEK.WAV"))) {
191 if(!d_noise_seek->load_wav_file(_T("FDDSEEK1.WAV"))) {
192 d_noise_seek->load_wav_file(_T("SEEK.WAV"));
195 d_noise_seek->set_mute(!config.sound_noise_fdd);
197 if(d_noise_head_down != NULL) {
198 d_noise_head_down->set_device_name(_T("Noise Player (FDD Head Load)"));
199 d_noise_head_down->load_wav_file(_T("HEADDOWN.WAV"));
200 d_noise_head_down->set_mute(!config.sound_noise_fdd);
202 if(d_noise_head_up != NULL) {
203 d_noise_head_up->set_device_name(_T("Noise Player (FDD Head Unload)"));
204 d_noise_head_up->load_wav_file(_T("HEADUP.WAV"));
205 d_noise_head_up->set_mute(!config.sound_noise_fdd);
209 memset(fdc, 0, sizeof(fdc));
210 for(int i = 0; i < 16; i++) {
211 fdc[i].track = 40; // OK?
216 status = cmdreg = trkreg = secreg = datareg = sidereg = cmdtype = 0;
218 prev_drq_clock = seekend_clock = 0;
221 void MB8877::release()
223 // release d88 handler
224 for(int i = 0; i < _max_drive; i++) {
234 for(int i = 0; i < _max_drive; i++) {
235 //fdc[i].track = 0; // Hold to track
237 fdc[i].access = false;
239 for(int i = 0; i < (int)array_length(register_id); i++) {
242 now_search = now_seek = drive_sel = false;
247 extended_mode = true;
249 extended_mode = false;
254 void MB8877::write_io8(uint32_t addr, uint32_t data)
262 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
263 if(invert_registers) {
264 cmdreg = (~data) & 0xff;
275 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
276 if(invert_registers) {
277 trkreg = (~data) & 0xff;
283 if((status & FDC_ST_BUSY) && (fdc[drvreg].index == 0)) {
284 // track reg is written after command starts
285 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
292 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
293 if(invert_registers) {
294 secreg = (~data) & 0xff;
300 if((status & FDC_ST_BUSY) && (fdc[drvreg].index == 0)) {
301 // sector reg is written after command starts
302 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
309 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
310 if(invert_registers) {
311 datareg = (~data) & 0xff;
317 ready = ((status & FDC_ST_DRQ) && !now_search);
318 //#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
320 if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
321 if(!motor_on) ready = false;
326 if(!motor_on) ready = false;
328 // if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
330 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
331 // write or multisector write
332 if(fdc[drvreg].index < disk[drvreg]->sector_size.sd) {
333 if(!disk[drvreg]->write_protected) {
334 if(disk[drvreg]->sector[fdc[drvreg].index] != datareg) {
335 disk[drvreg]->sector[fdc[drvreg].index] = datareg;
336 sector_changed = true;
339 disk[drvreg]->set_deleted((cmdreg & 1) != 0);
341 status |= FDC_ST_WRITEFAULT;
342 status &= ~FDC_ST_BUSY;
346 //fdc[drvreg].index++;
348 if((fdc[drvreg].index + 1) >= disk[drvreg]->sector_size.sd) {
349 if(cmdtype == FDC_CMD_WR_SEC) {
351 //#ifdef _FDC_DEBUG_LOG
352 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
354 status &= ~FDC_ST_BUSY;
359 //#ifdef _FDC_DEBUG_LOG
360 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR (SEARCH NEXT)\n"));
362 // 2HD: 360rpm, 10410bytes/track -> 0.06246bytes/us
363 register_my_event(EVENT_MULTI1, 30); // 0.06246bytes/us * 30us = 1.8738bytes < GAP3
364 register_my_event(EVENT_MULTI2, 60); // 0.06246bytes/us * 60us = 3.7476bytes < GAP3
366 sector_changed = false;
367 } else if(status & FDC_ST_DRQ) {
368 if(fdc[drvreg].index == 0) {
369 register_drq_event(fdc[drvreg].bytes_before_2nd_drq);
371 register_drq_event(1);
374 status &= ~FDC_ST_DRQ;
375 } else if(cmdtype == FDC_CMD_WR_TRK) {
377 if(fdc[drvreg].index < disk[drvreg]->get_track_size()) {
378 if(!disk[drvreg]->write_protected) {
379 if(fdc[drvreg].index == 0) {
380 disk[drvreg]->format_track(fdc[drvreg].track, sidereg);
381 fdc[drvreg].id_written = false;
382 fdc[drvreg].side = sidereg;
383 fdc[drvreg].side_changed = false;
385 if(fdc[drvreg].side != sidereg) {
386 fdc[drvreg].side_changed = true;
388 if(fdc[drvreg].side_changed) {
389 // abort write track because disk side is changed
390 } else if(datareg == 0xf5) {
391 // write a1h in missing clock
392 } else if(datareg == 0xf6) {
393 // write c2h in missing clock
394 } else if(datareg == 0xf7) {
396 if(!fdc[drvreg].id_written) {
397 // insert new sector with data crc error
399 uint8_t c = 0, h = 0, r = 0, n = 0;
400 fdc[drvreg].id_written = true;
401 fdc[drvreg].sector_found = false;
402 if(fdc[drvreg].index >= 4) {
403 c = disk[drvreg]->track[fdc[drvreg].index - 4];
404 h = disk[drvreg]->track[fdc[drvreg].index - 3];
405 r = disk[drvreg]->track[fdc[drvreg].index - 2];
406 n = disk[drvreg]->track[fdc[drvreg].index - 1];
408 fdc[drvreg].sector_length = 0x80 << (n & 3);
409 fdc[drvreg].sector_index = 0;
410 disk[drvreg]->insert_sector(c, h, r, n, false, true, 0xe5, fdc[drvreg].sector_length);
411 } else if(fdc[drvreg].sector_found) {
412 // clear data crc error if all sector data are written
413 if(fdc[drvreg].sector_index == fdc[drvreg].sector_length) {
414 disk[drvreg]->set_data_crc_error(false);
416 fdc[drvreg].id_written = false;
418 // data mark of current sector is not written
419 disk[drvreg]->set_data_mark_missing();
422 } else if(fdc[drvreg].id_written) {
423 if(fdc[drvreg].sector_found) {
425 if(fdc[drvreg].sector_index < fdc[drvreg].sector_length) {
426 disk[drvreg]->sector[fdc[drvreg].sector_index] = datareg;
428 fdc[drvreg].sector_index++;
429 } else if(datareg == 0xf8 || datareg == 0xfb) {
431 disk[drvreg]->set_deleted(datareg == 0xf8);
432 fdc[drvreg].sector_found = true;
435 disk[drvreg]->track[fdc[drvreg].index] = datareg;
437 status |= FDC_ST_WRITEFAULT;
438 status &= ~FDC_ST_BUSY;
439 status &= ~FDC_ST_DRQ;
443 //fdc[drvreg].index++;
445 if((fdc[drvreg].index + 1) >= disk[drvreg]->get_track_size()) {
446 if(!disk[drvreg]->write_protected) {
447 if(fdc[drvreg].id_written && !fdc[drvreg].sector_found) {
448 // data mark of last sector is not written
449 disk[drvreg]->set_data_mark_missing();
451 disk[drvreg]->sync_buffer();
453 status &= ~FDC_ST_BUSY;
456 } else if(status & FDC_ST_DRQ) {
457 if(fdc[drvreg].index == 0) {
458 register_drq_event(fdc[drvreg].bytes_before_2nd_drq);
460 register_drq_event(1);
463 status &= ~FDC_ST_DRQ;
465 if(!(status & FDC_ST_DRQ)) {
466 cancel_my_event(EVENT_LOST);
468 fdc[drvreg].access = true;
475 uint32_t MB8877::read_io8(uint32_t addr)
488 // disk not inserted, motor stop
489 not_ready = !disk[drvreg]->inserted;
490 //#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
492 if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
493 if(!motor_on) not_ready = true;
498 if(!motor_on) not_ready = true;
500 // if(!disk[drvreg]->inserted || !motor_on) {
502 status |= FDC_ST_NOTREADY;
504 status &= ~FDC_ST_NOTREADY;
507 if(cmdtype == FDC_CMD_TYPE1 || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) {
508 if(disk[drvreg]->inserted && disk[drvreg]->write_protected) {
509 status |= FDC_ST_WRITEP;
511 status &= ~FDC_ST_WRITEP;
514 status &= ~FDC_ST_WRITEP;
516 // track0, index hole
517 if(cmdtype == FDC_CMD_TYPE1) {
518 if(fdc[drvreg].track == 0) {
519 status |= FDC_ST_TRACK00;
521 status &= ~FDC_ST_TRACK00;
523 // index hole signal width is 5msec (thanks Mr.Sato)
524 if(!(status & FDC_ST_NOTREADY) && get_cur_position() < disk[drvreg]->get_bytes_per_usec(5000)) {
525 status |= FDC_ST_INDEX;
527 status &= ~FDC_ST_INDEX;
530 // show busy a moment
532 if(cmdtype == FDC_CMD_TYPE1 && !now_seek) {
533 status &= ~FDC_ST_BUSY;
534 //#ifdef MB8877_NO_BUSY_AFTER_SEEK
535 if(mb8877_no_busy_after_seek) {
536 //#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
538 if(disk[0]->is_special_disk != SPECIAL_DISK_FM7_XANADU2_D) {
550 if(cmdtype == 0 && !(status & FDC_ST_NOTREADY)) {
551 // MZ-2000 HuBASIC invites NOT READY status
552 if(++no_command == 16) {
553 val |= FDC_ST_NOTREADY;
559 if(!(status & FDC_ST_DRQ)) {
562 if(!(status & FDC_ST_BUSY)) {
565 //#ifdef _FDC_DEBUG_LOG
566 if(fdc_debug_log) this->out_debug_log(_T("FDC\tSTATUS=%2x\n"), val);
568 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
569 if(invert_registers) {
570 return (~val) & 0xff;
578 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
579 if(invert_registers) {
580 return (~trkreg) & 0xff;
588 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
589 if(invert_registers) {
590 return (~secreg) & 0xff;
598 ready = ((status & FDC_ST_DRQ) && !now_search);
599 //#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
601 if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
602 if(!motor_on) ready = false;
607 if(!motor_on) ready = false;
609 // if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
611 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC) {
612 // read or multisector read
613 if(fdc[drvreg].index < disk[drvreg]->sector_size.sd) {
614 datareg = disk[drvreg]->sector[fdc[drvreg].index];
615 //fdc[drvreg].index++;
617 if((fdc[drvreg].index + 1) >= disk[drvreg]->sector_size.sd) {
619 if(disk[drvreg]->data_crc_error && !disk[drvreg]->ignore_crc()) {
621 //#ifdef _FDC_DEBUG_LOG
622 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR (DATA CRC ERROR)\n"));
624 status |= FDC_ST_CRCERR;
625 status &= ~FDC_ST_BUSY;
628 } else if(cmdtype == FDC_CMD_RD_SEC) {
630 //#ifdef _FDC_DEBUG_LOG
631 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
633 status &= ~FDC_ST_BUSY;
638 //#ifdef _FDC_DEBUG_LOG
639 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR (SEARCH NEXT)\n"));
641 register_my_event(EVENT_MULTI1, 30);
642 register_my_event(EVENT_MULTI2, 60);
645 register_drq_event(1);
647 status &= ~FDC_ST_DRQ;
648 } else if(cmdtype == FDC_CMD_RD_ADDR) {
650 if(fdc[drvreg].index < 6) {
651 datareg = disk[drvreg]->id[fdc[drvreg].index];
652 //fdc[drvreg].index++;
654 if((fdc[drvreg].index + 1) >= 6) {
655 if(disk[drvreg]->addr_crc_error && !disk[drvreg]->ignore_crc()) {
657 status |= FDC_ST_CRCERR;
659 status &= ~FDC_ST_BUSY;
662 //#ifdef _FDC_DEBUG_LOG
663 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF ID FIELD\n"));
666 register_drq_event(1);
668 status &= ~FDC_ST_DRQ;
669 } else if(cmdtype == FDC_CMD_RD_TRK) {
671 if(fdc[drvreg].index < disk[drvreg]->get_track_size()) {
672 datareg = disk[drvreg]->track[fdc[drvreg].index];
673 //fdc[drvreg].index++;
675 if((fdc[drvreg].index + 1) >= disk[drvreg]->get_track_size()) {
676 //#ifdef _FDC_DEBUG_LOG
677 if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF TRACK\n"));
679 status &= ~FDC_ST_BUSY;
680 status |= FDC_ST_LOSTDATA;
684 register_drq_event(1);
686 status &= ~FDC_ST_DRQ;
688 if(!(status & FDC_ST_DRQ)) {
689 cancel_my_event(EVENT_LOST);
691 fdc[drvreg].access = true;
694 //#ifdef _FDC_DEBUG_LOG
695 if(fdc_debug_log) this->force_out_debug_log(_T("FDC\tDATA=%2x\n"), datareg); // emu->force_out_debug_log()
697 //#if defined(HAS_MB8866) || defined(HAS_MB8876)
698 if(invert_registers) {
699 return (~datareg) & 0xff;
709 void MB8877::write_dma_io8(uint32_t addr, uint32_t data)
714 uint32_t MB8877::read_dma_io8(uint32_t addr)
719 void MB8877::write_signal(int id, uint32_t data, uint32_t mask)
721 if(id == SIG_MB8877_DRIVEREG) {
722 drvreg = data & _drive_mask;
724 seekend_clock = get_current_clock();
725 } else if(id == SIG_MB8877_SIDEREG) {
726 sidereg = (data & mask) ? 1 : 0;
727 } else if(id == SIG_MB8877_MOTOR) {
728 motor_on = ((data & mask) != 0);
732 uint32_t MB8877::read_signal(int ch)
734 if(ch == SIG_MB8877_DRIVEREG) {
735 return drvreg & _drive_mask;
736 } else if(ch == SIG_MB8877_SIDEREG) {
738 } else if(ch == SIG_MB8877_MOTOR) {
739 return motor_on ? 1 : 0;
744 for(int i = 0; i < _max_drive; i++) {
748 fdc[i].access = false;
756 void MB8877::event_callback(int event_id, int err)
758 int event = event_id >> 8;
759 int cmd = event_id & 0xff;
760 //bool need_after_irq = false;
761 register_id[event] = -1;
763 // cancel event if the command is finished or other command is executed
765 if(event == EVENT_SEEK || event == EVENT_SEEKEND) {
767 } else if(event == EVENT_SEARCH) {
775 //#ifdef _FDC_DEBUG_LOG
776 //this->out_debug_log(_T("FDC\tSEEK START\n"));
778 if(seektrk > fdc[drvreg].track) {
780 if(d_noise_seek != NULL) d_noise_seek->play();
781 //need_after_irq = true;
782 } else if(seektrk < fdc[drvreg].track) {
784 if(d_noise_seek != NULL) d_noise_seek->play();
785 //need_after_irq = true;
787 if((cmdreg & 0x10) || ((cmdreg & 0xf0) == 0)) {
788 trkreg = fdc[drvreg].track;
790 if(seektrk != fdc[drvreg].track) {
791 //if(need_after_irq) {
793 //set_irq(true); // 20180118 K.O Turn ON IRQ -> Turn OFF DRQ
795 register_seek_event();
798 // 20180118 K.O If seek completed, IRQ/DRQ make at EVENT_SEEKEND.
799 seekend_clock = get_current_clock();
803 if((cmdreg & 0xf4) == 0x44) {
807 } else if((cmdreg & 0xf4) == 0x64) {
818 status_tmp |= search_track();
820 if(status_tmp & FDC_ST_SEEKERR) {
821 time = get_usec_to_detect_index_hole(5, true);
823 time = get_usec_to_next_trans_pos(true);
825 register_my_event(EVENT_SEEKEND, time);
831 status &= (uint8_t)(~FDC_ST_BUSY); // 20180118 K.O Turn off BUSY flag.
833 set_irq(true); // 20180118 K.O Turn ON IRQ -> Turn OFF DRQ
834 //#ifdef _FDC_DEBUG_LOG
835 //this->out_debug_log(_T("FDC\tSEEK END\n"));
840 if(status_tmp & FDC_ST_RECNFND) {
841 //#if defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
843 // for SHARP X1 Batten Tanuki
844 if(disk[drvreg]->is_special_disk == SPECIAL_DISK_X1_BATTEN && drive_sel) {
845 status_tmp &= ~FDC_ST_RECNFND;
849 //#ifdef _FDC_DEBUG_LOG
850 if(fdc_debug_log) this->out_debug_log(_T("FDC\tSEARCH NG\n"));
852 status = status_tmp & ~(FDC_ST_BUSY | FDC_ST_DRQ);
855 } else if(status_tmp & FDC_ST_WRITEFAULT) {
856 //#ifdef _FDC_DEBUG_LOG
857 if(fdc_debug_log) this->out_debug_log(_T("FDC\tWRITE PROTECTED\n"));
859 status = status_tmp & ~(FDC_ST_BUSY | FDC_ST_DRQ);
863 status = status_tmp | (FDC_ST_BUSY | FDC_ST_DRQ);
864 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
865 register_lost_event(8);
866 } else if(cmdtype == FDC_CMD_WR_TRK) {
867 register_lost_event(3);
869 register_lost_event(1);
871 fdc[drvreg].cur_position = fdc[drvreg].next_trans_position;
872 fdc[drvreg].prev_clock = prev_drq_clock = get_current_clock();
875 //#ifdef _FDC_DEBUG_LOG
876 if(fdc_debug_log) this->out_debug_log(_T("FDC\tSEARCH OK\n"));
881 if(status & FDC_ST_BUSY) {
882 status |= FDC_ST_DRQ;
883 register_lost_event(1);
884 if((cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) && fdc[drvreg].index == 0) {
885 fdc[drvreg].cur_position = (fdc[drvreg].cur_position + fdc[drvreg].bytes_before_2nd_drq) % disk[drvreg]->get_track_size();
887 fdc[drvreg].cur_position = (fdc[drvreg].cur_position + 1) % disk[drvreg]->get_track_size();
889 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC ||
890 cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC ||
891 cmdtype == FDC_CMD_RD_TRK || cmdtype == FDC_CMD_WR_TRK ||
892 cmdtype == FDC_CMD_RD_ADDR) {
895 fdc[drvreg].prev_clock = prev_drq_clock = get_current_clock();
897 //#ifdef _FDC_DEBUG_LOG
898 //this->out_debug_log(_T("FDC\tDRQ!\n"));
906 if(cmdtype == FDC_CMD_RD_MSEC) {
908 } else if(cmdtype == FDC_CMD_WR_MSEC) {
909 cmd_writedata(false);
913 if(status & FDC_ST_BUSY) {
914 //#ifdef _FDC_DEBUG_LOG
915 if(fdc_debug_log) this->out_debug_log(_T("FDC\tDATA LOST\n"));
917 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) {
918 if(fdc[drvreg].index == 0) {
919 status &= ~FDC_ST_BUSY;
920 //status &= ~FDC_ST_DRQ;
922 if((status & FDC_ST_DRQ) != 0) {
923 status |= FDC_ST_LOSTDATA;
924 status &= (uint8_t)(~(FDC_ST_DRQ | FDC_ST_BUSY));
930 if((status & FDC_ST_DRQ) != 0) {
931 status |= FDC_ST_LOSTDATA;
932 status &= (uint8_t)(~(FDC_ST_DRQ | FDC_ST_BUSY));
938 if((status & FDC_ST_DRQ) != 0) {
939 status |= FDC_ST_LOSTDATA;
940 status &= (uint8_t)(~(FDC_ST_DRQ | FDC_ST_BUSY));
946 status |= FDC_ST_LOSTDATA;
952 // ----------------------------------------------------------------------------
954 // ----------------------------------------------------------------------------
956 void MB8877::process_cmd()
962 // MB89311 mode commands
965 // delay (may be only in extended mode)
966 //#ifdef _FDC_DEBUG_LOG
967 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (DELAY ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
969 cmdtype = status = 0;
971 } else if(cmdreg == 0xfd) {
973 //#ifdef _FDC_DEBUG_LOG
974 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (ASGN PAR) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
976 cmdtype = status = 0;
978 } else if(cmdreg == 0xfe) {
980 //#ifdef _FDC_DEBUG_LOG
981 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (ASGN MOD) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
983 extended_mode = !extended_mode;
984 cmdtype = status = 0;
986 } else if(cmdreg == 0xff) {
987 // reset (may be only in extended mode)
988 //#ifdef _FDC_DEBUG_LOG
989 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (RESET ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
992 extended_mode = true;
994 } else if(extended_mode) {
996 if((cmdreg & 0xeb) == 0x21) {
997 //#ifdef _FDC_DEBUG_LOG
998 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (STEP IN ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1002 } else if((cmdreg & 0xeb) == 0x22) {
1003 //#ifdef _FDC_DEBUG_LOG
1004 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (STEP OUT) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1009 } else if((cmdreg & 0xf4) == 0x44) {
1011 //#ifdef _FDC_DEBUG_LOG
1012 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (RDaftSEK) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1016 } else if((cmdreg & 0xf4) == 0x64) {
1018 //#ifdef _FDC_DEBUG_LOG
1019 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (WRaftSEK) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1024 } else if((cmdreg & 0xfb) == 0xf1) {
1026 //#ifdef _FDC_DEBUG_LOG
1027 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (FORMAT ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
1036 // MB8877 mode commands
1037 //#ifdef _FDC_DEBUG_LOG
1038 static const _TCHAR *cmdstr[0x10] = {
1039 _T("RESTORE "), _T("SEEK "), _T("STEP "), _T("STEP "),
1040 _T("STEP IN "), _T("STEP IN "), _T("STEP OUT"), _T("STEP OUT"),
1041 _T("RD DATA "), _T("RD DATA "), _T("RD DATA "), _T("WR DATA "),
1042 _T("RD ADDR "), _T("FORCEINT"), _T("RD TRACK"), _T("WR TRACK")
1044 if(fdc_debug_log) this->out_debug_log(_T("FDC\tCMD=%2xh (%s) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, cmdstr[cmdreg >> 4], datareg, drvreg, trkreg, sidereg, secreg);
1047 switch(cmdreg & 0xf8) {
1049 case 0x00: case 0x08:
1051 update_head_flag(drvreg, (cmdreg & 8) != 0);
1053 case 0x10: case 0x18:
1055 update_head_flag(drvreg, (cmdreg & 8) != 0);
1057 case 0x20: case 0x28:
1058 case 0x30: case 0x38:
1060 update_head_flag(drvreg, (cmdreg & 8) != 0);
1062 case 0x40: case 0x48:
1063 case 0x50: case 0x58:
1065 update_head_flag(drvreg, (cmdreg & 8) != 0);
1067 case 0x60: case 0x68:
1068 case 0x70: case 0x78:
1070 update_head_flag(drvreg, (cmdreg & 8) != 0);
1073 case 0x80: case 0x88:
1074 case 0x90: case 0x98:
1076 update_head_flag(drvreg, true);
1078 case 0xa0:case 0xa8:
1079 case 0xb0: case 0xb8:
1080 cmd_writedata(true);
1081 update_head_flag(drvreg, true);
1086 update_head_flag(drvreg, true);
1090 update_head_flag(drvreg, true);
1094 update_head_flag(drvreg, true);
1097 case 0xd0: case 0xd8:
1106 void MB8877::cmd_restore()
1109 cmdtype = FDC_CMD_TYPE1;
1110 if(!check_drive()) {
1113 if((cmdreg & 0x08) != 0) { // Head engage
1114 status = FDC_ST_HEADENG | FDC_ST_BUSY;
1116 status = FDC_ST_BUSY;
1121 if(fdc[drvreg].track < 0) {
1122 fdc[drvreg].track = 0;
1124 } else if(fdc[drvreg].track >= 80) {
1125 fdc[drvreg].track = 80;
1128 trkreg = fdc[drvreg].track;
1135 register_seek_event();
1138 void MB8877::cmd_seek()
1141 cmdtype = FDC_CMD_TYPE1;
1142 if(!check_drive()) {
1145 if((cmdreg & 0x08) != 0) { // Head engage
1146 status = FDC_ST_HEADENG | FDC_ST_BUSY;
1148 status = FDC_ST_BUSY;
1151 // seektrk = (uint8_t)(fdc[drvreg].track + datareg - trkreg);
1153 //#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
1154 if(type_fm77av_2dd) {
1155 if(disk[drvreg]->drive_type != DRIVE_TYPE_2D) {
1156 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1158 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1160 } else if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
1161 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1163 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1165 seekvct = !(seektrk > fdc[drvreg].track);
1169 if(trkreg != fdc[drvreg].track) {
1170 status |= FDC_ST_SEEKERR;
1171 trkreg = fdc[drvreg].track;
1174 register_seek_event();
1177 void MB8877::cmd_step()
1187 void MB8877::cmd_stepin()
1190 cmdtype = FDC_CMD_TYPE1;
1191 if(!check_drive()) {
1194 if((cmdreg & 0x08) != 0) { // Head engage
1195 status = FDC_ST_HEADENG | FDC_ST_BUSY;
1197 status = FDC_ST_BUSY;
1199 seektrk = fdc[drvreg].track + 1;
1200 if(type_fm77av_2dd) {
1201 if(disk[drvreg]->drive_type != DRIVE_TYPE_2D) {
1202 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1204 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1206 } else if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
1207 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1209 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1215 if(trkreg != fdc[drvreg].track) {
1216 status |= FDC_ST_SEEKERR;
1217 // trkreg = fdc[drvreg].track;
1220 register_seek_event();
1223 void MB8877::cmd_stepout()
1226 cmdtype = FDC_CMD_TYPE1;
1227 if(!check_drive()) {
1230 if((cmdreg & 0x08) != 0) { // Head engage
1231 status = FDC_ST_HEADENG | FDC_ST_BUSY;
1233 status = FDC_ST_BUSY;
1236 seektrk = fdc[drvreg].track - 1;
1237 if(type_fm77av_2dd) {
1238 if(disk[drvreg]->drive_type != DRIVE_TYPE_2D) {
1239 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1241 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1243 } else if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
1244 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1246 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1252 if(trkreg != fdc[drvreg].track) {
1253 status |= FDC_ST_SEEKERR;
1254 // trkreg = fdc[drvreg].track;
1257 register_seek_event();
1260 void MB8877::cmd_readdata(bool first_sector)
1263 cmdtype = (cmdreg & 0x10) ? FDC_CMD_RD_MSEC : FDC_CMD_RD_SEC;
1264 if(!check_drive2()) {
1267 status = FDC_ST_BUSY;
1268 status_tmp = search_sector();
1272 if(status_tmp & FDC_ST_RECNFND) {
1273 time = get_usec_to_detect_index_hole(5, first_sector && ((cmdreg & 4) != 0));
1275 time = get_usec_to_start_trans(first_sector);
1277 register_my_event(EVENT_SEARCH, time);
1278 cancel_my_event(EVENT_LOST);
1281 void MB8877::cmd_writedata(bool first_sector)
1283 // type-2 write data
1284 cmdtype = (cmdreg & 0x10) ? FDC_CMD_WR_MSEC : FDC_CMD_WR_SEC;
1285 if(!check_drive2()) {
1288 status = FDC_ST_BUSY;
1289 status_tmp = search_sector() & ~FDC_ST_RECTYPE;
1291 sector_changed = false;
1294 if(status_tmp & FDC_ST_RECNFND) {
1295 time = get_usec_to_detect_index_hole(5, first_sector && ((cmdreg & 4) != 0));
1296 } else if(status & FDC_ST_WRITEFAULT) {
1297 time = (cmdreg & 4) ? DELAY_TIME : 1;
1299 time = get_usec_to_start_trans(first_sector);
1301 register_my_event(EVENT_SEARCH, time);
1302 cancel_my_event(EVENT_LOST);
1305 void MB8877::cmd_readaddr()
1307 // type-3 read address
1308 cmdtype = FDC_CMD_RD_ADDR;
1309 if(!check_drive2()) {
1312 status = FDC_ST_BUSY;
1313 status_tmp = search_addr();
1317 if(status_tmp & FDC_ST_RECNFND) {
1318 time = get_usec_to_detect_index_hole(5, ((cmdreg & 4) != 0));
1320 time = get_usec_to_start_trans(true);
1322 register_my_event(EVENT_SEARCH, time);
1323 cancel_my_event(EVENT_LOST);
1326 void MB8877::cmd_readtrack()
1328 // type-3 read track
1329 cmdtype = FDC_CMD_RD_TRK;
1330 if(!check_drive2()) {
1333 status = FDC_ST_BUSY;
1336 disk[drvreg]->make_track(fdc[drvreg].track, sidereg);
1337 fdc[drvreg].index = 0;
1340 fdc[drvreg].next_trans_position = 1;
1341 double time = get_usec_to_detect_index_hole(1, ((cmdreg & 4) != 0));
1342 register_my_event(EVENT_SEARCH, time);
1343 cancel_my_event(EVENT_LOST);
1346 void MB8877::cmd_writetrack()
1348 // type-3 write track
1349 cmdtype = FDC_CMD_WR_TRK;
1350 if(!check_drive2()) {
1353 status = FDC_ST_BUSY;
1356 fdc[drvreg].index = 0;
1357 fdc[drvreg].id_written = false;
1361 if(disk[drvreg]->write_protected) {
1362 status_tmp = FDC_ST_WRITEFAULT;
1363 time = (cmdreg & 4) ? DELAY_TIME : 1;
1366 // wait 15msec before raise first drq
1367 fdc[drvreg].next_trans_position = (get_cur_position() + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
1370 // raise first drq soon
1371 fdc[drvreg].next_trans_position = (get_cur_position() + 1) % disk[drvreg]->get_track_size();
1372 time = disk[drvreg]->get_usec_per_bytes(1);
1374 // wait at least 3bytes before check index hole and raise second drq
1375 fdc[drvreg].bytes_before_2nd_drq = disk[drvreg]->get_track_size() - fdc[drvreg].next_trans_position;
1376 if(fdc[drvreg].bytes_before_2nd_drq < 3) {
1377 fdc[drvreg].bytes_before_2nd_drq += disk[drvreg]->get_track_size();
1380 register_my_event(EVENT_SEARCH, time);
1381 cancel_my_event(EVENT_LOST);
1384 //#ifdef HAS_MB89311
1385 void MB8877::cmd_format()
1388 // type-3 format (FIXME: need to implement)
1389 cmdtype = FDC_CMD_WR_TRK;
1390 status = FDC_ST_BUSY;
1393 fdc[drvreg].index = 0;
1394 fdc[drvreg].id_written = false;
1397 status_tmp = FDC_ST_WRITEFAULT;
1398 double time = (cmdreg & 4) ? DELAY_TIME : 1;
1400 register_my_event(EVENT_SEARCH, time);
1401 cancel_my_event(EVENT_LOST);
1406 void MB8877::cmd_forceint()
1408 // type-4 force interrupt
1409 if(cmdtype == FDC_CMD_TYPE1) {
1410 // abort restore/seek/step command
1412 if(seektrk > fdc[drvreg].track) {
1413 fdc[drvreg].track++;
1414 } else if(seektrk < fdc[drvreg].track) {
1415 fdc[drvreg].track--;
1417 if((cmdreg_tmp & 0x10) || ((cmdreg_tmp & 0xf0) == 0)) {
1418 trkreg = fdc[drvreg].track;
1421 } else if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1422 // abort write sector command
1423 if(sector_changed) {
1424 disk[drvreg]->set_data_crc_error(false);
1426 } else if(cmdtype == FDC_CMD_WR_TRK) {
1427 // abort write track command
1428 if(!disk[drvreg]->write_protected) {
1429 if(fdc[drvreg].id_written && !fdc[drvreg].sector_found) {
1430 // data mark of last sector is not written
1431 disk[drvreg]->set_data_mark_missing();
1433 disk[drvreg]->sync_buffer();
1436 now_search = now_seek = sector_changed = false;
1438 //#ifdef HAS_MB89311
1439 if((cmdreg == 0xff) && (type_mb89311)) {
1441 cmdtype = FDC_CMD_TYPE1;
1442 status = FDC_ST_HEADENG;
1445 if(cmdtype == 0 || !(status & FDC_ST_BUSY)) {
1446 cmdtype = FDC_CMD_TYPE1;
1447 if(!type_fm7) status = FDC_ST_HEADENG; // Hack for FUKUALL.d77 .
1449 status &= ~FDC_ST_BUSY;
1451 // force interrupt if bit0-bit3 is high
1455 //#ifdef HAS_MB89311
1459 cancel_my_event(EVENT_SEEK);
1460 cancel_my_event(EVENT_SEEKEND);
1461 cancel_my_event(EVENT_SEARCH);
1462 cancel_my_event(EVENT_DRQ);
1463 cancel_my_event(EVENT_MULTI1);
1464 cancel_my_event(EVENT_MULTI2);
1465 cancel_my_event(EVENT_LOST);
1468 void MB8877::update_head_flag(int drv, bool head_load)
1470 if(fdc[drv].head_load != head_load) {
1472 if(d_noise_head_down != NULL) d_noise_head_down->play();
1474 if(d_noise_head_up != NULL) d_noise_head_up->play();
1476 fdc[drv].head_load = head_load;
1480 // ----------------------------------------------------------------------------
1482 // ----------------------------------------------------------------------------
1484 uint8_t MB8877::search_track()
1487 int track = fdc[drvreg].track;
1488 //#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
1489 if(type_fm77av_2dd) {
1490 if(disk[drvreg]->media_type == MEDIA_TYPE_2D) {
1491 if((disk[drvreg]->drive_type == DRIVE_TYPE_2DD) ||
1492 (disk[drvreg]->drive_type == DRIVE_TYPE_2HD) ||
1493 (disk[drvreg]->drive_type == DRIVE_TYPE_144)) {
1496 } else { // OS-9 2DD Access fix by Ryu Takegami
1497 if((disk[drvreg]->media_type != MEDIA_TYPE_2D) &&
1498 (disk[drvreg]->media_type != MEDIA_TYPE_UNK)) {
1499 if(disk[drvreg]->drive_type == DRIVE_TYPE_2D) {
1506 if(!disk[drvreg]->get_track(track, sidereg)){
1507 return FDC_ST_SEEKERR;
1510 // verify track number
1511 if(disk[drvreg]->ignore_crc()) {
1512 for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
1513 disk[drvreg]->get_sector(-1, -1, i);
1514 if(disk[drvreg]->id[0] == trkreg) {
1515 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[i] + 4 + 2;
1516 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[i];
1521 for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
1522 disk[drvreg]->get_sector(-1, -1, i);
1523 if(disk[drvreg]->id[0] == trkreg && !disk[drvreg]->addr_crc_error) {
1524 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[i] + 4 + 2;
1525 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[i];
1529 for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
1530 disk[drvreg]->get_sector(-1, -1, i);
1531 if(disk[drvreg]->id[0] == trkreg) {
1532 return FDC_ST_SEEKERR | FDC_ST_CRCERR;
1536 return FDC_ST_SEEKERR;
1539 uint8_t MB8877::search_sector()
1542 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1543 if(disk[drvreg]->write_protected) {
1544 return FDC_ST_WRITEFAULT;
1549 int track = fdc[drvreg].track;
1550 //#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
1551 if(type_fm77av_2dd) {
1552 if(disk[drvreg]->media_type == MEDIA_TYPE_2D) {
1553 if((disk[drvreg]->drive_type == DRIVE_TYPE_2DD) ||
1554 (disk[drvreg]->drive_type == DRIVE_TYPE_2HD) ||
1555 (disk[drvreg]->drive_type == DRIVE_TYPE_144)) {
1558 } else { // OS-9 2DD Access fix by Ryu Takegami
1559 if((disk[drvreg]->media_type != MEDIA_TYPE_2D) &&
1560 (disk[drvreg]->media_type != MEDIA_TYPE_UNK)) {
1561 if(disk[drvreg]->drive_type == DRIVE_TYPE_2D) {
1568 if(!disk[drvreg]->get_track(track, sidereg)) {
1569 return FDC_ST_RECNFND;
1572 // get current position
1573 int sector_num = disk[drvreg]->sector_num.sd;
1574 int position = get_cur_position();
1576 if(position > disk[drvreg]->am1_position[sector_num - 1]) {
1577 position -= disk[drvreg]->get_track_size();
1580 // first scanned sector
1581 int first_sector = 0;
1582 for(int i = 0; i < sector_num; i++) {
1583 if(position < disk[drvreg]->am1_position[i]) {
1590 for(int i = 0; i < sector_num; i++) {
1592 int index = (first_sector + i) % sector_num;
1593 disk[drvreg]->get_sector(-1, -1, index);
1596 if(disk[drvreg]->id[0] != trkreg) {
1599 //#if !defined(HAS_MB8866)
1601 if((cmdreg & 2) && (disk[drvreg]->id[1] & 1) != ((cmdreg >> 3) & 1)) {
1606 if(disk[drvreg]->id[2] != secreg) {
1609 if(disk[drvreg]->sector_size.sd == 0) {
1612 if(disk[drvreg]->addr_crc_error && !disk[drvreg]->ignore_crc()) {
1614 disk[drvreg]->sector_size.sd = 0;
1615 return FDC_ST_RECNFND | FDC_ST_CRCERR;
1619 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1620 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[index] + 4 + 2;
1621 fdc[drvreg].bytes_before_2nd_drq = disk[drvreg]->data_position[index] - fdc[drvreg].next_trans_position;
1623 fdc[drvreg].next_trans_position = disk[drvreg]->data_position[index] + 1;
1625 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[index];
1626 fdc[drvreg].index = 0;
1627 //#ifdef _FDC_DEBUG_LOG
1628 if(fdc_debug_log) this->out_debug_log(_T("FDC\tSECTOR FOUND SIZE=$%04x ID=%02x %02x %02x %02x CRC=%02x %02x CRC_ERROR=%d\n"),
1629 disk[drvreg]->sector_size.sd,
1630 disk[drvreg]->id[0], disk[drvreg]->id[1], disk[drvreg]->id[2], disk[drvreg]->id[3],
1631 disk[drvreg]->id[4], disk[drvreg]->id[5],
1632 disk[drvreg]->data_crc_error ? 1 : 0);
1634 return (disk[drvreg]->deleted ? FDC_ST_RECTYPE : 0);
1638 disk[drvreg]->sector_size.sd = 0;
1639 return FDC_ST_RECNFND;
1642 uint8_t MB8877::search_addr()
1645 int track = fdc[drvreg].track;
1646 //#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
1647 if(type_fm77av_2dd) {
1648 if(disk[drvreg]->media_type == MEDIA_TYPE_2D) {
1649 if((disk[drvreg]->drive_type == DRIVE_TYPE_2DD) ||
1650 (disk[drvreg]->drive_type == DRIVE_TYPE_2HD) ||
1651 (disk[drvreg]->drive_type == DRIVE_TYPE_144)) {
1654 } else { // OS-9 2DD Access fix by Ryu Takegami
1655 if((disk[drvreg]->media_type != MEDIA_TYPE_2D) &&
1656 (disk[drvreg]->media_type != MEDIA_TYPE_UNK)) {
1657 if(disk[drvreg]->drive_type == DRIVE_TYPE_2D) {
1664 if(!disk[drvreg]->get_track(track, sidereg)) {
1665 return FDC_ST_RECNFND;
1668 // get current position
1669 int sector_num = disk[drvreg]->sector_num.sd;
1670 int position = get_cur_position();
1672 if(position > disk[drvreg]->am1_position[sector_num - 1]) {
1673 position -= disk[drvreg]->get_track_size();
1676 // first scanned sector
1677 int first_sector = 0;
1678 for(int i = 0; i < sector_num; i++) {
1679 if(position < disk[drvreg]->am1_position[i]) {
1686 if(disk[drvreg]->get_sector(-1, -1, first_sector)) {
1687 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[first_sector] + 1;
1688 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[first_sector];
1689 fdc[drvreg].index = 0;
1690 secreg = disk[drvreg]->id[0];
1695 disk[drvreg]->sector_size.sd = 0;
1696 return FDC_ST_RECNFND;
1699 // ----------------------------------------------------------------------------
1701 // ----------------------------------------------------------------------------
1703 int MB8877::get_cur_position()
1705 return (fdc[drvreg].cur_position + disk[drvreg]->get_bytes_per_usec(get_passed_usec(fdc[drvreg].prev_clock))) % disk[drvreg]->get_track_size();
1708 double MB8877::get_usec_to_start_trans(bool first_sector)
1710 // get time from current position
1711 double time = get_usec_to_next_trans_pos(first_sector && ((cmdreg & 4) != 0));
1712 if(first_sector && time < 60000 - get_passed_usec(seekend_clock)) {
1713 time += disk[drvreg]->get_usec_per_track();
1718 double MB8877::get_usec_to_next_trans_pos(bool delay)
1720 int position = get_cur_position();
1722 if(disk[drvreg]->invalid_format) {
1723 // XXX: this track is invalid format and the calculated sector position may be incorrect.
1724 // so use the constant period
1726 } else if(/*disk[drvreg]->no_skew && */!disk[drvreg]->correct_timing()) {
1727 // XXX: this image may be a standard image or coverted from a standard image and skew may be incorrect,
1728 // so use the period to search the next sector from the current position
1729 int sector_num = disk[drvreg]->sector_num.sd;
1732 if(position > disk[drvreg]->am1_position[sector_num - 1]) {
1733 position -= disk[drvreg]->get_track_size();
1735 for(int i = 0; i < sector_num; i++) {
1736 if(position < disk[drvreg]->am1_position[i]) {
1737 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1738 bytes = (disk[drvreg]->id_position[i] + 4 + 2) - position;
1740 bytes = (disk[drvreg]->data_position[i] + 1) - position;
1743 bytes += disk[drvreg]->get_track_size(); // to make sure
1749 return disk[drvreg]->get_usec_per_bytes(bytes);
1754 position = (position + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
1756 int bytes = fdc[drvreg].next_trans_position - position;
1757 if(fdc[drvreg].next_am1_position < position || bytes < 0) {
1758 bytes += disk[drvreg]->get_track_size();
1760 double time = disk[drvreg]->get_usec_per_bytes(bytes);
1767 double MB8877::get_usec_to_detect_index_hole(int count, bool delay)
1769 int position = get_cur_position();
1771 position = (position + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
1773 int bytes = disk[drvreg]->get_track_size() * count - position;
1775 bytes += disk[drvreg]->get_track_size();
1777 double time = disk[drvreg]->get_usec_per_bytes(bytes);
1784 // ----------------------------------------------------------------------------
1786 // ----------------------------------------------------------------------------
1788 void MB8877::set_irq(bool val)
1790 write_signals(&outputs_irq, val ? 0xffffffff : 0);
1793 void MB8877::set_drq(bool val)
1795 write_signals(&outputs_drq, val ? 0xffffffff : 0);
1798 // ----------------------------------------------------------------------------
1800 // ----------------------------------------------------------------------------
1802 void MB8877::open_disk(int drv, const _TCHAR* file_path, int bank)
1804 if(drv < _max_drive) {
1805 disk[drv]->open(file_path, bank);
1809 void MB8877::close_disk(int drv)
1811 if(drv < _max_drive) {
1814 update_head_flag(drvreg, false);
1818 bool MB8877::is_disk_inserted(int drv)
1820 if(drv < _max_drive) {
1821 return disk[drv]->inserted;
1826 void MB8877::is_disk_protected(int drv, bool value)
1828 if(drv < _max_drive) {
1829 disk[drv]->write_protected = value;
1833 bool MB8877::is_disk_protected(int drv)
1835 if(drv < _max_drive) {
1836 return disk[drv]->write_protected;
1841 void MB8877::set_drive_type(int drv, uint8_t type)
1843 if(drv < _max_drive) {
1844 disk[drv]->drive_type = type;
1848 uint8_t MB8877::get_drive_type(int drv)
1850 if(drv < _max_drive) {
1851 return disk[drv]->drive_type;
1853 return DRIVE_TYPE_UNK;
1856 void MB8877::set_drive_rpm(int drv, int rpm)
1858 if(drv < _max_drive) {
1859 disk[drv]->drive_rpm = rpm;
1863 void MB8877::set_drive_mfm(int drv, bool mfm)
1865 if(drv < _max_drive) {
1866 disk[drv]->drive_mfm = mfm;
1870 void MB8877::set_track_size(int drv, int size)
1872 if(drv < _max_drive) {
1873 disk[drv]->track_size = size;
1877 uint8_t MB8877::fdc_status()
1879 // for each virtual machines
1880 //#if defined(_FMR50) || defined(_FMR60)
1881 if(type_fmr50 || type_fmr60) {
1882 return disk[drvreg]->inserted ? 2 : 0;
1889 void MB8877::update_config()
1891 if(d_noise_seek != NULL) {
1892 d_noise_seek->set_mute(!config.sound_noise_fdd);
1894 if(d_noise_head_down != NULL) {
1895 d_noise_head_down->set_mute(!config.sound_noise_fdd);
1897 if(d_noise_head_up != NULL) {
1898 d_noise_head_up->set_mute(!config.sound_noise_fdd);
1902 #define STATE_VERSION 5
1904 void MB8877::save_state(FILEIO* state_fio)
1906 state_fio->FputUint32(STATE_VERSION);
1907 state_fio->FputInt32(this_device_id);
1909 state_fio->Fwrite(fdc, sizeof(fdc), 1);
1910 for(int i = 0; i < _max_drive; i++) {
1911 disk[i]->save_state(state_fio);
1913 state_fio->FputUint8(status);
1914 state_fio->FputUint8(status_tmp);
1915 state_fio->FputUint8(cmdreg);
1916 state_fio->FputUint8(cmdreg_tmp);
1917 state_fio->FputUint8(trkreg);
1918 state_fio->FputUint8(secreg);
1919 state_fio->FputUint8(datareg);
1920 state_fio->FputUint8(drvreg);
1921 state_fio->FputUint8(sidereg);
1922 state_fio->FputUint8(cmdtype);
1923 state_fio->Fwrite(register_id, sizeof(register_id), 1);
1924 state_fio->FputBool(now_search);
1925 state_fio->FputBool(now_seek);
1926 state_fio->FputBool(sector_changed);
1927 state_fio->FputInt32(no_command);
1928 state_fio->FputInt32(seektrk);
1929 state_fio->FputBool(seekvct);
1930 state_fio->FputBool(motor_on);
1931 state_fio->FputBool(drive_sel);
1932 state_fio->FputUint32(prev_drq_clock);
1933 state_fio->FputUint32(seekend_clock);
1936 bool MB8877::load_state(FILEIO* state_fio)
1938 if(state_fio->FgetUint32() != STATE_VERSION) {
1941 if(state_fio->FgetInt32() != this_device_id) {
1944 state_fio->Fread(fdc, sizeof(fdc), 1);
1945 for(int i = 0; i < _max_drive; i++) {
1946 if(!disk[i]->load_state(state_fio)) {
1950 status = state_fio->FgetUint8();
1951 status_tmp = state_fio->FgetUint8();
1952 cmdreg = state_fio->FgetUint8();
1953 cmdreg_tmp = state_fio->FgetUint8();
1954 trkreg = state_fio->FgetUint8();
1955 secreg = state_fio->FgetUint8();
1956 datareg = state_fio->FgetUint8();
1957 drvreg = state_fio->FgetUint8();
1958 sidereg = state_fio->FgetUint8();
1959 cmdtype = state_fio->FgetUint8();
1960 state_fio->Fread(register_id, sizeof(register_id), 1);
1961 now_search = state_fio->FgetBool();
1962 now_seek = state_fio->FgetBool();
1963 sector_changed = state_fio->FgetBool();
1964 no_command = state_fio->FgetInt32();
1965 seektrk = state_fio->FgetInt32();
1966 seekvct = state_fio->FgetBool();
1967 motor_on = state_fio->FgetBool();
1968 drive_sel = state_fio->FgetBool();
1969 prev_drq_clock = state_fio->FgetUint32();
1970 seekend_clock = state_fio->FgetUint32();