2 Skelton for retropc emulator
5 Author : Takeda.Toshiya
14 #define FDC_ST_BUSY 0x01 // busy
15 #define FDC_ST_INDEX 0x02 // index hole
16 #define FDC_ST_DRQ 0x02 // data request
17 #define FDC_ST_TRACK00 0x04 // track0
18 #define FDC_ST_LOSTDATA 0x04 // data lost
19 #define FDC_ST_CRCERR 0x08 // crc error
20 #define FDC_ST_SEEKERR 0x10 // seek error
21 #define FDC_ST_RECNFND 0x10 // sector not found
22 #define FDC_ST_HEADENG 0x20 // head engage
23 #define FDC_ST_RECTYPE 0x20 // record type
24 #define FDC_ST_WRITEFAULT 0x20 // write fault
25 #define FDC_ST_WRITEP 0x40 // write protectdc
26 #define FDC_ST_NOTREADY 0x80 // media not inserted
28 #define FDC_CMD_TYPE1 1
29 #define FDC_CMD_RD_SEC 2
30 #define FDC_CMD_RD_MSEC 3
31 #define FDC_CMD_WR_SEC 4
32 #define FDC_CMD_WR_MSEC 5
33 #define FDC_CMD_RD_ADDR 6
34 #define FDC_CMD_RD_TRK 7
35 #define FDC_CMD_WR_TRK 8
36 #define FDC_CMD_TYPE4 0x80
39 #define EVENT_SEEKEND 1
40 #define EVENT_SEARCH 2
43 #define EVENT_MULTI1 5
44 #define EVENT_MULTI2 6
47 #define DRIVE_MASK (MAX_DRIVE - 1)
49 static const int seek_wait_hi[4] = {3000, 6000, 10000, 16000};
50 static const int seek_wait_lo[4] = {6000, 12000, 20000, 30000};
52 #define CANCEL_EVENT(event) { \
53 if(register_id[event] != -1) { \
54 cancel_event(this, register_id[event]); \
55 register_id[event] = -1; \
58 #define REGISTER_EVENT(event, usec) { \
59 if(register_id[event] != -1) { \
60 cancel_event(this, register_id[event]); \
61 register_id[event] = -1; \
63 register_event(this, (event << 8) | (cmdtype & 0xff), usec, false, ®ister_id[event]); \
65 #define REGISTER_SEEK_EVENT() { \
66 if(register_id[EVENT_SEEK] != -1) { \
67 cancel_event(this, register_id[EVENT_SEEK]); \
68 register_id[EVENT_SEEK] = -1; \
70 if(disk[drvreg]->drive_type == DRIVE_TYPE_2HD) { \
71 register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), seek_wait_hi[cmdreg & 3], false, ®ister_id[EVENT_SEEK]); \
73 register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), seek_wait_lo[cmdreg & 3], false, ®ister_id[EVENT_SEEK]); \
75 now_seek = after_seek = true; \
77 #define REGISTER_DRQ_EVENT() { \
78 double usec = disk[drvreg]->get_usec_per_bytes(1) - passed_usec(prev_drq_clock); \
81 } else if(usec > 24 && disk[drvreg]->is_special_disk == SPECIAL_DISK_X1_ALPHA) { \
84 if(register_id[EVENT_DRQ] != -1) { \
85 cancel_event(this, register_id[EVENT_DRQ]); \
86 register_id[EVENT_DRQ] = -1; \
88 register_event(this, (EVENT_DRQ << 8) | (cmdtype & 0xff), usec, false, ®ister_id[EVENT_DRQ]); \
90 #define REGISTER_LOST_EVENT() { \
91 if(register_id[EVENT_LOST] != -1) { \
92 cancel_event(this, register_id[EVENT_LOST]); \
93 register_id[EVENT_LOST] = -1; \
95 register_event(this, (EVENT_LOST << 8) | (cmdtype & 0xff), disk[drvreg]->get_usec_per_bytes(/*1*/2), false, ®ister_id[EVENT_LOST]); \
98 void MB8877::initialize()
100 // initialize d88 handler
101 for(int i = 0; i < MAX_DRIVE; i++) {
102 disk[i] = new DISK(emu);
106 memset(fdc, 0, sizeof(fdc));
111 status = cmdreg = trkreg = secreg = datareg = sidereg = cmdtype = 0;
115 void MB8877::release()
117 // release d88 handler
118 for(int i = 0; i < MAX_DRIVE; i++) {
128 for(int i = 0; i < MAX_DRIVE; i++) {
131 fdc[i].access = false;
133 for(int i = 0; i < array_length(register_id); i++) {
136 now_search = now_seek = after_seek = drive_sel = false;
140 void MB8877::write_io8(uint32 addr, uint32 data)
147 cmdreg = (~data) & 0xff;
157 trkreg = (~data) & 0xff;
161 if((status & FDC_ST_BUSY) && (fdc[drvreg].index == 0)) {
162 // track reg is written after command starts
163 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
171 secreg = (~data) & 0xff;
175 if((status & FDC_ST_BUSY) && (fdc[drvreg].index == 0)) {
176 // sector reg is written after command starts
177 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
185 datareg = (~data) & 0xff;
189 if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
190 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
191 // write or multisector write
192 if(fdc[drvreg].index < disk[drvreg]->sector_size.sd) {
193 if(!disk[drvreg]->write_protected) {
194 disk[drvreg]->sector[fdc[drvreg].index] = datareg;
196 disk[drvreg]->set_deleted((cmdreg & 1) != 0);
198 status |= FDC_ST_WRITEFAULT;
199 status &= ~FDC_ST_BUSY;
205 if(fdc[drvreg].index >= disk[drvreg]->sector_size.sd) {
206 if(cmdtype == FDC_CMD_WR_SEC) {
208 status &= ~FDC_ST_BUSY;
213 REGISTER_EVENT(EVENT_MULTI1, 30);
214 REGISTER_EVENT(EVENT_MULTI2, 60);
216 } else if(status & FDC_ST_DRQ) {
217 REGISTER_DRQ_EVENT();
219 status &= ~FDC_ST_DRQ;
220 } else if(cmdtype == FDC_CMD_WR_TRK) {
222 if(fdc[drvreg].index < disk[drvreg]->get_track_size()) {
223 if(!disk[drvreg]->write_protected) {
224 if(fdc[drvreg].index == 0) {
225 disk[drvreg]->format_track(fdc[drvreg].track, sidereg);
226 fdc[drvreg].id_written = false;
227 fdc[drvreg].side = sidereg;
228 fdc[drvreg].side_changed = false;
230 if(fdc[drvreg].side != sidereg) {
231 fdc[drvreg].side_changed = true;
233 if(fdc[drvreg].side_changed) {
234 // abort write track because disk side is changed
235 } else if(datareg == 0xf5) {
236 // write a1h in missing clock
237 } else if(datareg == 0xf6) {
238 // write c2h in missing clock
239 } else if(datareg == 0xf7) {
241 if(!fdc[drvreg].id_written) {
244 // insert new sector with crc error
245 fdc[drvreg].id_written = true;
246 fdc[drvreg].sector_found = false;
247 if (fdc[drvreg].index >= 4) {
248 c = disk[drvreg]->track[fdc[drvreg].index - 4];
249 h = disk[drvreg]->track[fdc[drvreg].index - 3];
250 r = disk[drvreg]->track[fdc[drvreg].index - 2];
251 n = disk[drvreg]->track[fdc[drvreg].index - 1];
253 fdc[drvreg].sector_length = 0x80 << (n & 3);
254 fdc[drvreg].sector_index = 0;
255 disk[drvreg]->insert_sector(c, h, r, n, false, true, 0xe5, fdc[drvreg].sector_length);
257 // clear crc error if all sector data are written
258 if(fdc[drvreg].sector_found && fdc[drvreg].sector_index == fdc[drvreg].sector_length) {
259 disk[drvreg]->set_crc_error(false);
261 fdc[drvreg].id_written = false;
263 } else if(fdc[drvreg].id_written) {
264 if(fdc[drvreg].sector_found) {
266 if(fdc[drvreg].sector_index < fdc[drvreg].sector_length) {
267 disk[drvreg]->sector[fdc[drvreg].sector_index] = datareg;
269 fdc[drvreg].sector_index++;
270 } else if(datareg == 0xf8 || datareg == 0xfb) {
272 disk[drvreg]->set_deleted(datareg == 0xf8);
273 fdc[drvreg].sector_found = true;
276 disk[drvreg]->track[fdc[drvreg].index] = datareg;
278 status |= FDC_ST_WRITEFAULT;
279 status &= ~FDC_ST_BUSY;
280 status &= ~FDC_ST_DRQ;
286 if(fdc[drvreg].index >= disk[drvreg]->get_track_size()) {
287 status &= ~FDC_ST_BUSY;
289 if(!disk[drvreg]->write_protected) {
290 disk[drvreg]->sync_buffer();
293 } else if(status & FDC_ST_DRQ) {
294 REGISTER_DRQ_EVENT();
296 status &= ~FDC_ST_DRQ;
298 if(!(status & FDC_ST_DRQ)) {
299 CANCEL_EVENT(EVENT_LOST);
301 fdc[drvreg].access = true;
308 uint32 MB8877::read_io8(uint32 addr)
315 if(cmdtype == FDC_CMD_TYPE4) {
316 // now force interrupt
317 if(!disk[drvreg]->inserted || !motor_on) {
318 status = FDC_ST_NOTREADY;
320 // MZ-2500 RELICS invites STATUS = 0
324 } else if(now_search) {
328 // disk not inserted, motor stop
329 if(!disk[drvreg]->inserted || !motor_on) {
330 status |= FDC_ST_NOTREADY;
332 status &= ~FDC_ST_NOTREADY;
335 if(cmdtype == FDC_CMD_TYPE1 || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) {
336 if(disk[drvreg]->inserted && disk[drvreg]->write_protected) {
337 status |= FDC_ST_WRITEP;
339 status &= ~FDC_ST_WRITEP;
342 status &= ~FDC_ST_WRITEP;
344 // track0, index hole
345 if(cmdtype == FDC_CMD_TYPE1) {
346 if(fdc[drvreg].track == 0) {
347 status |= FDC_ST_TRACK00;
349 status &= ~FDC_ST_TRACK00;
351 if(!(status & FDC_ST_NOTREADY)) {
352 if(get_cur_position() == 0) {
353 status |= FDC_ST_INDEX;
355 status &= ~FDC_ST_INDEX;
359 // show busy a moment
361 if(cmdtype == FDC_CMD_TYPE1 && !now_seek) {
362 status &= ~FDC_ST_BUSY;
365 if(cmdtype == 0 && !(status & FDC_ST_NOTREADY)) {
366 // MZ-2000 HuBASIC invites NOT READY status
367 if(++no_command == 16) {
368 val |= FDC_ST_NOTREADY;
374 if(!(status & FDC_ST_DRQ)) {
378 #ifdef _FDC_DEBUG_LOG
379 emu->out_debug_log(_T("FDC\tSTATUS=%2x\n"), val);
382 return (~val) & 0xff;
389 return (~trkreg) & 0xff;
396 return (~secreg) & 0xff;
402 if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
403 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC) {
404 // read or multisector read
405 if(fdc[drvreg].index < disk[drvreg]->sector_size.sd) {
406 datareg = disk[drvreg]->sector[fdc[drvreg].index];
409 if(fdc[drvreg].index >= disk[drvreg]->sector_size.sd) {
410 if(cmdtype == FDC_CMD_RD_SEC) {
412 #ifdef _FDC_DEBUG_LOG
413 emu->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
415 status &= ~FDC_ST_BUSY;
420 #ifdef _FDC_DEBUG_LOG
421 emu->out_debug_log(_T("FDC\tEND OF SECTOR (SEARCH NEXT)\n"));
423 REGISTER_EVENT(EVENT_MULTI1, 30);
424 REGISTER_EVENT(EVENT_MULTI2, 60);
427 REGISTER_DRQ_EVENT();
429 status &= ~FDC_ST_DRQ;
430 } else if(cmdtype == FDC_CMD_RD_ADDR) {
432 if(fdc[drvreg].index < 6) {
433 datareg = disk[drvreg]->id[fdc[drvreg].index];
436 if(fdc[drvreg].index >= 6) {
437 status &= ~FDC_ST_BUSY;
441 REGISTER_DRQ_EVENT();
443 status &= ~FDC_ST_DRQ;
444 } else if(cmdtype == FDC_CMD_RD_TRK) {
446 if(fdc[drvreg].index < disk[drvreg]->get_track_size()) {
447 datareg = disk[drvreg]->track[fdc[drvreg].index];
450 if(fdc[drvreg].index >= disk[drvreg]->get_track_size()) {
451 #ifdef _FDC_DEBUG_LOG
452 emu->out_debug_log(_T("FDC\tEND OF TRACK\n"));
454 status &= ~FDC_ST_BUSY;
455 status |= FDC_ST_LOSTDATA;
459 REGISTER_DRQ_EVENT();
461 status &= ~FDC_ST_DRQ;
463 if(!(status & FDC_ST_DRQ)) {
464 CANCEL_EVENT(EVENT_LOST);
466 fdc[drvreg].access = true;
469 #ifdef _FDC_DEBUG_LOG
470 emu->out_debug_log(_T("FDC\tDATA=%2x\n"), datareg);
473 return (~datareg) & 0xff;
481 void MB8877::write_dma_io8(uint32 addr, uint32 data)
486 uint32 MB8877::read_dma_io8(uint32 addr)
491 void MB8877::write_signal(int id, uint32 data, uint32 mask)
493 if(id == SIG_MB8877_DRIVEREG) {
494 drvreg = data & DRIVE_MASK;
496 } else if(id == SIG_MB8877_SIDEREG) {
497 sidereg = (data & mask) ? 1 : 0;
498 } else if(id == SIG_MB8877_MOTOR) {
499 motor_on = ((data & mask) != 0);
503 uint32 MB8877::read_signal(int ch)
507 for(int i = 0; i < MAX_DRIVE; i++) {
511 fdc[i].access = false;
519 void MB8877::event_callback(int event_id, int err)
521 int event = event_id >> 8;
522 int cmd = event_id & 0xff;
523 register_id[event] = -1;
525 // cancel event if the command is finished or other command is executed
527 if(event == EVENT_SEEK) {
529 } else if(event == EVENT_SEARCH) {
537 if(seektrk > fdc[drvreg].track) {
539 } else if(seektrk < fdc[drvreg].track) {
542 if((cmdreg & 0x10) || ((cmdreg & 0xf0) == 0)) {
543 trkreg = fdc[drvreg].track;
545 if(seektrk == fdc[drvreg].track) {
547 if((cmdreg & 0xf0) == 0) {
550 status |= search_track();
554 REGISTER_SEEK_EVENT();
558 if(seektrk == fdc[drvreg].track) {
560 if((cmdreg & 0x10) || ((cmdreg & 0xf0) == 0)) {
561 trkreg = fdc[drvreg].track;
563 if((cmdreg & 0xf0) == 0) {
566 status |= search_track();
568 CANCEL_EVENT(EVENT_SEEK);
574 if(!(status_tmp & FDC_ST_RECNFND)) {
575 status = status_tmp | (FDC_ST_BUSY | FDC_ST_DRQ);
576 REGISTER_LOST_EVENT();
577 fdc[drvreg].cur_position = fdc[drvreg].next_trans_position;
578 fdc[drvreg].prev_clock = prev_drq_clock = current_clock();
582 #if defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
583 // for SHARP X1 Batten Tanuki
584 if(disk[drvreg]->is_special_disk == SPECIAL_DISK_X1_BATTEN && drive_sel) {
585 status_tmp &= ~FDC_ST_RECNFND;
588 status = status_tmp & ~(FDC_ST_BUSY | FDC_ST_DRQ);
592 cmdtype = FDC_CMD_TYPE4;
595 if(status & FDC_ST_BUSY) {
596 status |= FDC_ST_DRQ;
597 REGISTER_LOST_EVENT();
598 fdc[drvreg].cur_position = (fdc[drvreg].cur_position + 1) % disk[drvreg]->get_track_size();
599 fdc[drvreg].prev_clock = prev_drq_clock = current_clock();
607 if(cmdtype == FDC_CMD_RD_MSEC) {
609 } else if(cmdtype == FDC_CMD_WR_MSEC) {
614 if(status & FDC_ST_BUSY) {
615 #ifdef _FDC_DEBUG_LOG
616 emu->out_debug_log("FDC\tDATA LOST\n");
618 status |= FDC_ST_LOSTDATA;
619 status &= ~FDC_ST_BUSY;
620 //status &= ~FDC_ST_DRQ;
628 // ----------------------------------------------------------------------------
630 // ----------------------------------------------------------------------------
632 void MB8877::process_cmd()
634 #ifdef _FDC_DEBUG_LOG
635 static const _TCHAR *cmdstr[0x10] = {
636 _T("RESTORE "), _T("SEEK "), _T("STEP "), _T("STEP "),
637 _T("STEP IN "), _T("STEP IN "), _T("STEP OUT"), _T("STEP OUT"),
638 _T("RD DATA "), _T("RD DATA "), _T("RD DATA "), _T("WR DATA "),
639 _T("RD ADDR "), _T("FORCEINT"), _T("RD TRACK"), _T("WR TRACK")
641 emu->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);
644 CANCEL_EVENT(EVENT_TYPE4);
647 switch(cmdreg & 0xf0) {
695 void MB8877::cmd_restore()
698 cmdtype = FDC_CMD_TYPE1;
699 status = FDC_ST_HEADENG | FDC_ST_BUSY;
705 REGISTER_SEEK_EVENT();
706 REGISTER_EVENT(EVENT_SEEKEND, 300);
709 void MB8877::cmd_seek()
712 cmdtype = FDC_CMD_TYPE1;
713 status = FDC_ST_HEADENG | FDC_ST_BUSY;
716 seektrk = fdc[drvreg].track + datareg - trkreg;
720 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
721 seekvct = !(datareg > trkreg);
723 REGISTER_SEEK_EVENT();
724 REGISTER_EVENT(EVENT_SEEKEND, 300);
727 void MB8877::cmd_step()
737 void MB8877::cmd_stepin()
740 cmdtype = FDC_CMD_TYPE1;
741 status = FDC_ST_HEADENG | FDC_ST_BUSY;
743 seektrk = (fdc[drvreg].track < 83) ? fdc[drvreg].track + 1 : 83;
746 REGISTER_SEEK_EVENT();
747 REGISTER_EVENT(EVENT_SEEKEND, 300);
750 void MB8877::cmd_stepout()
753 cmdtype = FDC_CMD_TYPE1;
754 status = FDC_ST_HEADENG | FDC_ST_BUSY;
756 seektrk = (fdc[drvreg].track > 0) ? fdc[drvreg].track - 1 : 0;
759 REGISTER_SEEK_EVENT();
760 REGISTER_EVENT(EVENT_SEEKEND, 300);
763 void MB8877::cmd_readdata()
766 cmdtype = (cmdreg & 0x10) ? FDC_CMD_RD_MSEC : FDC_CMD_RD_SEC;
767 int side = (cmdreg & 2) ? ((cmdreg & 8) ? 1 : 0) : sidereg;
768 status = FDC_ST_BUSY;
769 status_tmp = search_sector(fdc[drvreg].track, side, secreg, ((cmdreg & 2) != 0));
773 if(!(status_tmp & FDC_ST_RECNFND)) {
774 time = get_usec_to_start_trans();
776 time = disk[drvreg]->get_usec_per_bytes(disk[drvreg]->get_track_size());
778 REGISTER_EVENT(EVENT_SEARCH, time);
779 CANCEL_EVENT(EVENT_LOST);
782 void MB8877::cmd_writedata()
785 cmdtype = (cmdreg & 0x10) ? FDC_CMD_WR_MSEC : FDC_CMD_WR_SEC;
786 int side = (cmdreg & 2) ? ((cmdreg & 8) ? 1 : 0) : sidereg;
787 status = FDC_ST_BUSY;
788 status_tmp = search_sector(fdc[drvreg].track, side, secreg, ((cmdreg & 2) != 0)) & ~FDC_ST_RECTYPE;
792 if(!(status_tmp & FDC_ST_RECNFND)) {
793 time = get_usec_to_start_trans();
795 time = disk[drvreg]->get_usec_per_bytes(disk[drvreg]->get_track_size());
797 REGISTER_EVENT(EVENT_SEARCH, time);
798 CANCEL_EVENT(EVENT_LOST);
801 void MB8877::cmd_readaddr()
803 // type-3 read address
804 cmdtype = FDC_CMD_RD_ADDR;
805 status = FDC_ST_BUSY;
806 status_tmp = search_addr();
810 if(!(status_tmp & FDC_ST_RECNFND)) {
811 time = get_usec_to_start_trans();
813 time = disk[drvreg]->get_usec_per_bytes(disk[drvreg]->get_track_size());
815 REGISTER_EVENT(EVENT_SEARCH, time);
816 CANCEL_EVENT(EVENT_LOST);
819 void MB8877::cmd_readtrack()
822 cmdtype = FDC_CMD_RD_TRK;
823 status = FDC_ST_BUSY;
826 disk[drvreg]->make_track(fdc[drvreg].track, sidereg);
827 fdc[drvreg].index = 0;
830 int bytes = disk[drvreg]->get_track_size() - get_cur_position();
832 bytes += disk[drvreg]->get_track_size();
834 double time = disk[drvreg]->get_usec_per_bytes(bytes);
835 REGISTER_EVENT(EVENT_SEARCH, time);
836 CANCEL_EVENT(EVENT_LOST);
839 void MB8877::cmd_writetrack()
841 // type-3 write track
842 cmdtype = FDC_CMD_WR_TRK;
843 status = FDC_ST_BUSY;
846 fdc[drvreg].index = 0;
849 int bytes = disk[drvreg]->get_track_size() - get_cur_position();
851 bytes += disk[drvreg]->get_track_size();
853 double time = disk[drvreg]->get_usec_per_bytes(bytes);
854 REGISTER_EVENT(EVENT_SEARCH, time);
855 CANCEL_EVENT(EVENT_LOST);
858 void MB8877::cmd_forceint()
860 // type-4 force interrupt
862 if(!disk[drvreg]->inserted || !motor_on) {
863 status = FDC_ST_NOTREADY | FDC_ST_HEADENG;
865 status = FDC_ST_HEADENG;
867 cmdtype = FDC_CMD_TYPE4;
869 // if(cmdtype == 0 || cmdtype == 4) { // modified for mz-2800, why in the write sector command case?
870 if(cmdtype == 0 || cmdtype == FDC_CMD_TYPE4) { // is this correct?
872 cmdtype = FDC_CMD_TYPE1;
874 status &= ~FDC_ST_BUSY;
877 // force interrupt if bit0-bit3 is high
882 // finish current seeking
884 if(seektrk > fdc[drvreg].track) {
886 } else if(seektrk < fdc[drvreg].track) {
889 if((cmdreg_tmp & 0x10) || ((cmdreg_tmp & 0xf0) == 0)) {
890 trkreg = fdc[drvreg].track;
892 if(seektrk == fdc[drvreg].track) {
894 if((cmdreg_tmp & 0xf0) == 0) {
899 now_search = now_seek = false;
901 CANCEL_EVENT(EVENT_SEEK);
902 CANCEL_EVENT(EVENT_SEEKEND);
903 CANCEL_EVENT(EVENT_SEARCH);
904 CANCEL_EVENT(EVENT_TYPE4);
905 CANCEL_EVENT(EVENT_DRQ);
906 CANCEL_EVENT(EVENT_MULTI1);
907 CANCEL_EVENT(EVENT_MULTI2);
908 CANCEL_EVENT(EVENT_LOST);
909 REGISTER_EVENT(EVENT_TYPE4, 100);
912 // ----------------------------------------------------------------------------
914 // ----------------------------------------------------------------------------
916 uint8 MB8877::search_track()
918 int trk = fdc[drvreg].track;
919 int trkside = trk * 2 + (sidereg & 1);
921 if(!(disk[drvreg]->inserted && disk[drvreg]->check_media_type())) {
922 return FDC_ST_SEEKERR;
924 if(!(0 <= trkside && trkside < 164)) {
925 return FDC_ST_SEEKERR;
928 // verify track number
929 disk[drvreg]->get_track(trk, sidereg);
933 for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
934 disk[drvreg]->get_sector(trk, sidereg, i);
935 if(disk[drvreg]->id[0] == trkreg) {
939 return FDC_ST_SEEKERR;
942 uint8 MB8877::search_sector(int trk, int side, int sct, bool compare)
945 if(!disk[drvreg]->get_track(trk, side)) {
947 return FDC_ST_RECNFND;
950 // get current position
951 int sector_num = disk[drvreg]->sector_num.sd;
952 int position = get_cur_position();
954 if(position > disk[drvreg]->sync_position[sector_num - 1]) {
955 position -= disk[drvreg]->get_track_size();
958 // first scanned sector
959 int first_sector = 0;
960 for(int i = 0; i < sector_num; i++) {
961 if(position < disk[drvreg]->sync_position[i]) {
968 for(int i = 0; i < sector_num; i++) {
970 int index = (first_sector + i) % sector_num;
971 disk[drvreg]->get_sector(trk, side, index);
974 if((cmdreg & 2) && (disk[drvreg]->id[1] & 1) != ((cmdreg >> 3) & 1)) {
977 if(disk[drvreg]->id[2] != sct) {
982 fdc[drvreg].next_trans_position = disk[drvreg]->data_position[i];
983 fdc[drvreg].next_sync_position = disk[drvreg]->sync_position[i];
984 fdc[drvreg].index = 0;
985 return (disk[drvreg]->deleted ? FDC_ST_RECTYPE : 0) | ((disk[drvreg]->crc_error && !config.ignore_crc[drvreg]) ? FDC_ST_CRCERR : 0);
989 disk[drvreg]->sector_size.sd = 0;
991 return FDC_ST_RECNFND;
994 uint8 MB8877::search_addr()
996 int trk = fdc[drvreg].track;
999 if(!disk[drvreg]->get_track(trk, sidereg)) {
1001 return FDC_ST_RECNFND;
1004 // get current position
1005 int sector_num = disk[drvreg]->sector_num.sd;
1006 int position = get_cur_position();
1008 if(position > disk[drvreg]->sync_position[sector_num - 1]) {
1009 position -= disk[drvreg]->get_track_size();
1012 // first scanned sector
1013 int first_sector = 0;
1014 for(int i = 0; i < sector_num; i++) {
1015 if(position < disk[drvreg]->sync_position[i]) {
1022 if(disk[drvreg]->get_sector(trk, sidereg, first_sector)) {
1023 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[first_sector];
1024 fdc[drvreg].next_sync_position = disk[drvreg]->sync_position[first_sector];
1025 fdc[drvreg].index = 0;
1026 secreg = disk[drvreg]->id[0];
1027 return (disk[drvreg]->crc_error && !config.ignore_crc[drvreg]) ? FDC_ST_CRCERR : 0;
1031 disk[drvreg]->sector_size.sd = 0;
1033 return FDC_ST_RECNFND;
1036 // ----------------------------------------------------------------------------
1038 // ----------------------------------------------------------------------------
1040 int MB8877::get_cur_position()
1042 return (int)(fdc[drvreg].cur_position + passed_usec(fdc[drvreg].prev_clock) / disk[drvreg]->get_usec_per_bytes(1)) % disk[drvreg]->get_track_size();
1045 double MB8877::get_usec_to_start_trans()
1047 #if defined(_X1TURBO) || defined(_X1TURBOZ)
1048 // FIXME: ugly patch for X1turbo ALPHA
1049 if(disk[drvreg]->is_special_disk == SPECIAL_DISK_X1_ALPHA) {
1053 if(disk[drvreg]->no_skew) {
1054 // XXX: this image may be a standard image or coverted from a standard image and skew may be incorrect,
1055 // so use the constant period to search the target sector
1059 // get time from current position
1060 int position = get_cur_position();
1061 int bytes = fdc[drvreg].next_trans_position - position;
1062 if(fdc[drvreg].next_sync_position < position) {
1063 bytes += disk[drvreg]->get_track_size();
1065 double time = disk[drvreg]->get_usec_per_bytes(bytes);
1067 // wait 70msec to read/write data just after seek command is done
1068 // if(time < 70000) {
1069 // time += disk[drvreg]->get_usec_per_bytes(disk[drvreg]->get_track_size());
1076 // ----------------------------------------------------------------------------
1078 // ----------------------------------------------------------------------------
1080 void MB8877::set_irq(bool val)
1082 write_signals(&outputs_irq, val ? 0xffffffff : 0);
1085 void MB8877::set_drq(bool val)
1087 write_signals(&outputs_drq, val ? 0xffffffff : 0);
1090 // ----------------------------------------------------------------------------
1092 // ----------------------------------------------------------------------------
1094 void MB8877::open_disk(int drv, _TCHAR path[], int bank)
1096 if(drv < MAX_DRIVE) {
1097 disk[drv]->open(path, bank);
1101 void MB8877::close_disk(int drv)
1103 if(drv < MAX_DRIVE) {
1109 bool MB8877::disk_inserted(int drv)
1111 if(drv < MAX_DRIVE) {
1112 return disk[drv]->inserted;
1117 void MB8877::set_drive_type(int drv, uint8 type)
1119 if(drv < MAX_DRIVE) {
1120 disk[drv]->drive_type = type;
1124 uint8 MB8877::get_drive_type(int drv)
1126 if(drv < MAX_DRIVE) {
1127 return disk[drv]->drive_type;
1129 return DRIVE_TYPE_UNK;
1132 void MB8877::set_drive_rpm(int drv, int rpm)
1134 if(drv < MAX_DRIVE) {
1135 disk[drv]->drive_rpm = rpm;
1139 void MB8877::set_drive_mfm(int drv, bool mfm)
1141 if(drv < MAX_DRIVE) {
1142 disk[drv]->drive_mfm = mfm;
1146 uint8 MB8877::fdc_status()
1148 // for each virtual machines
1149 #if defined(_FMR50) || defined(_FMR60)
1150 return disk[drvreg]->inserted ? 2 : 0;
1156 #define STATE_VERSION 3
1158 void MB8877::save_state(FILEIO* state_fio)
1160 state_fio->FputUint32(STATE_VERSION);
1161 state_fio->FputInt32(this_device_id);
1163 state_fio->Fwrite(fdc, sizeof(fdc), 1);
1164 for(int i = 0; i < MAX_DRIVE; i++) {
1165 disk[i]->save_state(state_fio);
1167 state_fio->FputUint8(status);
1168 state_fio->FputUint8(status_tmp);
1169 state_fio->FputUint8(cmdreg);
1170 state_fio->FputUint8(cmdreg_tmp);
1171 state_fio->FputUint8(trkreg);
1172 state_fio->FputUint8(secreg);
1173 state_fio->FputUint8(datareg);
1174 state_fio->FputUint8(drvreg);
1175 state_fio->FputUint8(sidereg);
1176 state_fio->FputUint8(cmdtype);
1177 state_fio->Fwrite(register_id, sizeof(register_id), 1);
1178 state_fio->FputBool(now_search);
1179 state_fio->FputBool(now_seek);
1180 state_fio->FputBool(after_seek);
1181 state_fio->FputInt32(no_command);
1182 state_fio->FputInt32(seektrk);
1183 state_fio->FputBool(seekvct);
1184 state_fio->FputBool(motor_on);
1185 state_fio->FputBool(drive_sel);
1186 state_fio->FputUint32(prev_drq_clock);
1189 bool MB8877::load_state(FILEIO* state_fio)
1191 if(state_fio->FgetUint32() != STATE_VERSION) {
1194 if(state_fio->FgetInt32() != this_device_id) {
1197 state_fio->Fread(fdc, sizeof(fdc), 1);
1198 for(int i = 0; i < MAX_DRIVE; i++) {
1199 if(!disk[i]->load_state(state_fio)) {
1203 status = state_fio->FgetUint8();
1204 status_tmp = state_fio->FgetUint8();
1205 cmdreg = state_fio->FgetUint8();
1206 cmdreg_tmp = state_fio->FgetUint8();
1207 trkreg = state_fio->FgetUint8();
1208 secreg = state_fio->FgetUint8();
1209 datareg = state_fio->FgetUint8();
1210 drvreg = state_fio->FgetUint8();
1211 sidereg = state_fio->FgetUint8();
1212 cmdtype = state_fio->FgetUint8();
1213 state_fio->Fread(register_id, sizeof(register_id), 1);
1214 now_search = state_fio->FgetBool();
1215 now_seek = state_fio->FgetBool();
1216 after_seek = state_fio->FgetBool();
1217 no_command = state_fio->FgetInt32();
1218 seektrk = state_fio->FgetInt32();
1219 seekvct = state_fio->FgetBool();
1220 motor_on = state_fio->FgetBool();
1221 drive_sel = state_fio->FgetBool();
1222 prev_drq_clock = state_fio->FgetUint32();