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()
101 ignore_crc = config.ignore_crc;
103 // initialize d88 handler
104 for(int i = 0; i < MAX_DRIVE; i++) {
105 disk[i] = new DISK(emu);
109 memset(fdc, 0, sizeof(fdc));
114 status = cmdreg = trkreg = secreg = datareg = sidereg = cmdtype = 0;
118 void MB8877::release()
120 // release d88 handler
121 for(int i = 0; i < MAX_DRIVE; i++) {
131 for(int i = 0; i < MAX_DRIVE; i++) {
134 fdc[i].access = false;
136 for(int i = 0; i < array_length(register_id); i++) {
139 now_search = now_seek = after_seek = drive_sel = false;
143 void MB8877::update_config()
145 ignore_crc = config.ignore_crc;
148 void MB8877::write_io8(uint32 addr, uint32 data)
155 cmdreg = (~data) & 0xff;
165 trkreg = (~data) & 0xff;
169 if((status & FDC_ST_BUSY) && (fdc[drvreg].index == 0)) {
170 // track reg is written after command starts
171 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
179 secreg = (~data) & 0xff;
183 if((status & FDC_ST_BUSY) && (fdc[drvreg].index == 0)) {
184 // sector reg is written after command starts
185 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
193 datareg = (~data) & 0xff;
197 if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
198 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
199 // write or multisector write
200 if(fdc[drvreg].index < disk[drvreg]->sector_size.sd) {
201 if(!disk[drvreg]->write_protected) {
202 disk[drvreg]->sector[fdc[drvreg].index] = datareg;
204 disk[drvreg]->set_deleted((cmdreg & 1) != 0);
206 status |= FDC_ST_WRITEFAULT;
207 status &= ~FDC_ST_BUSY;
213 if(fdc[drvreg].index >= disk[drvreg]->sector_size.sd) {
214 if(cmdtype == FDC_CMD_WR_SEC) {
216 status &= ~FDC_ST_BUSY;
221 REGISTER_EVENT(EVENT_MULTI1, 30);
222 REGISTER_EVENT(EVENT_MULTI2, 60);
224 } else if(status & FDC_ST_DRQ) {
225 REGISTER_DRQ_EVENT();
227 status &= ~FDC_ST_DRQ;
228 } else if(cmdtype == FDC_CMD_WR_TRK) {
230 if(fdc[drvreg].index < disk[drvreg]->get_track_size()) {
231 if(!disk[drvreg]->write_protected) {
232 if(fdc[drvreg].index == 0) {
233 disk[drvreg]->format_track(fdc[drvreg].track, sidereg);
234 fdc[drvreg].id_written = false;
235 fdc[drvreg].side = sidereg;
236 fdc[drvreg].side_changed = false;
238 if(fdc[drvreg].side != sidereg) {
239 fdc[drvreg].side_changed = true;
241 if(fdc[drvreg].side_changed) {
242 // abort write track because disk side is changed
243 } else if(datareg == 0xf5) {
244 // write a1h in missing clock
245 } else if(datareg == 0xf6) {
246 // write c2h in missing clock
247 } else if(datareg == 0xf7) {
249 if(!fdc[drvreg].id_written) {
250 // insert new sector with crc error
251 fdc[drvreg].id_written = true;
252 fdc[drvreg].sector_found = false;
253 uint8 c = disk[drvreg]->track[fdc[drvreg].index - 4];
254 uint8 h = disk[drvreg]->track[fdc[drvreg].index - 3];
255 uint8 r = disk[drvreg]->track[fdc[drvreg].index - 2];
256 uint8 n = disk[drvreg]->track[fdc[drvreg].index - 1];
257 fdc[drvreg].sector_length = 0x80 << (n & 3);
258 fdc[drvreg].sector_index = 0;
259 disk[drvreg]->insert_sector(c, h, r, n, false, true, 0xe5, fdc[drvreg].sector_length);
261 // clear crc error if all sector data are written
262 if(fdc[drvreg].sector_found && fdc[drvreg].sector_index == fdc[drvreg].sector_length) {
263 disk[drvreg]->set_crc_error(false);
265 fdc[drvreg].id_written = false;
267 } else if(fdc[drvreg].id_written) {
268 if(fdc[drvreg].sector_found) {
270 if(fdc[drvreg].sector_index < fdc[drvreg].sector_length) {
271 disk[drvreg]->sector[fdc[drvreg].sector_index] = datareg;
273 fdc[drvreg].sector_index++;
274 } else if(datareg == 0xf8 || datareg == 0xfb) {
276 disk[drvreg]->set_deleted(datareg == 0xf8);
277 fdc[drvreg].sector_found = true;
280 disk[drvreg]->track[fdc[drvreg].index] = datareg;
282 status |= FDC_ST_WRITEFAULT;
283 status &= ~FDC_ST_BUSY;
284 status &= ~FDC_ST_DRQ;
290 if(fdc[drvreg].index >= disk[drvreg]->get_track_size()) {
291 status &= ~FDC_ST_BUSY;
294 } else if(status & FDC_ST_DRQ) {
295 REGISTER_DRQ_EVENT();
297 status &= ~FDC_ST_DRQ;
299 if(!(status & FDC_ST_DRQ)) {
300 CANCEL_EVENT(EVENT_LOST);
302 fdc[drvreg].access = true;
309 uint32 MB8877::read_io8(uint32 addr)
316 if(cmdtype == FDC_CMD_TYPE4) {
317 // now force interrupt
318 if(!disk[drvreg]->inserted || !motor_on) {
319 status = FDC_ST_NOTREADY;
321 // MZ-2500 RELICS invites STATUS = 0
325 } else if(now_search) {
329 // disk not inserted, motor stop
330 if(!disk[drvreg]->inserted || !motor_on) {
331 status |= FDC_ST_NOTREADY;
333 status &= ~FDC_ST_NOTREADY;
336 if(cmdtype == FDC_CMD_TYPE1 || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) {
337 if(disk[drvreg]->inserted && disk[drvreg]->write_protected) {
338 status |= FDC_ST_WRITEP;
340 status &= ~FDC_ST_WRITEP;
343 status &= ~FDC_ST_WRITEP;
345 // track0, index hole
346 if(cmdtype == FDC_CMD_TYPE1) {
347 if(fdc[drvreg].track == 0) {
348 status |= FDC_ST_TRACK00;
350 status &= ~FDC_ST_TRACK00;
352 if(!(status & FDC_ST_NOTREADY)) {
353 if(get_cur_position() == 0) {
354 status |= FDC_ST_INDEX;
356 status &= ~FDC_ST_INDEX;
360 // show busy a moment
362 if(cmdtype == FDC_CMD_TYPE1 && !now_seek) {
363 status &= ~FDC_ST_BUSY;
366 if(cmdtype == 0 && !(status & FDC_ST_NOTREADY)) {
367 // MZ-2000 HuBASIC invites NOT READY status
368 if(++no_command == 16) {
369 val |= FDC_ST_NOTREADY;
375 if(!(status & FDC_ST_DRQ)) {
379 #ifdef _FDC_DEBUG_LOG
380 //emu->out_debug_log(_T("FDC\tSTATUS=%2x\n"), val);
383 return (~val) & 0xff;
390 return (~trkreg) & 0xff;
397 return (~secreg) & 0xff;
403 if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
404 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC) {
405 // read or multisector read
406 if(fdc[drvreg].index < disk[drvreg]->sector_size.sd) {
407 datareg = disk[drvreg]->sector[fdc[drvreg].index];
410 if(fdc[drvreg].index >= disk[drvreg]->sector_size.sd) {
411 if(cmdtype == FDC_CMD_RD_SEC) {
413 #ifdef _FDC_DEBUG_LOG
414 emu->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
416 status &= ~FDC_ST_BUSY;
421 #ifdef _FDC_DEBUG_LOG
422 emu->out_debug_log(_T("FDC\tEND OF SECTOR (SEARCH NEXT)\n"));
424 REGISTER_EVENT(EVENT_MULTI1, 30);
425 REGISTER_EVENT(EVENT_MULTI2, 60);
428 REGISTER_DRQ_EVENT();
430 status &= ~FDC_ST_DRQ;
431 } else if(cmdtype == FDC_CMD_RD_ADDR) {
433 if(fdc[drvreg].index < 6) {
434 datareg = disk[drvreg]->id[fdc[drvreg].index];
437 if(fdc[drvreg].index >= 6) {
438 status &= ~FDC_ST_BUSY;
442 REGISTER_DRQ_EVENT();
444 status &= ~FDC_ST_DRQ;
445 } else if(cmdtype == FDC_CMD_RD_TRK) {
447 if(fdc[drvreg].index < disk[drvreg]->get_track_size()) {
448 datareg = disk[drvreg]->track[fdc[drvreg].index];
451 if(fdc[drvreg].index >= disk[drvreg]->get_track_size()) {
452 #ifdef _FDC_DEBUG_LOG
453 emu->out_debug_log(_T("FDC\tEND OF TRACK\n"));
455 status &= ~FDC_ST_BUSY;
456 status |= FDC_ST_LOSTDATA;
460 REGISTER_DRQ_EVENT();
462 status &= ~FDC_ST_DRQ;
464 if(!(status & FDC_ST_DRQ)) {
465 CANCEL_EVENT(EVENT_LOST);
467 fdc[drvreg].access = true;
470 #ifdef _FDC_DEBUG_LOG
471 //emu->out_debug_log(_T("FDC\tDATA=%2x\n"), datareg);
474 return (~datareg) & 0xff;
482 void MB8877::write_dma_io8(uint32 addr, uint32 data)
487 uint32 MB8877::read_dma_io8(uint32 addr)
492 void MB8877::write_signal(int id, uint32 data, uint32 mask)
494 if(id == SIG_MB8877_DRIVEREG) {
495 drvreg = data & DRIVE_MASK;
497 } else if(id == SIG_MB8877_SIDEREG) {
498 sidereg = (data & mask) ? 1 : 0;
499 } else if(id == SIG_MB8877_MOTOR) {
500 motor_on = ((data & mask) != 0);
504 uint32 MB8877::read_signal(int ch)
508 for(int i = 0; i < MAX_DRIVE; i++) {
512 fdc[i].access = false;
520 void MB8877::event_callback(int event_id, int err)
522 int event = event_id >> 8;
523 int cmd = event_id & 0xff;
524 register_id[event] = -1;
526 // cancel event if the command is finished or other command is executed
528 if(event == EVENT_SEEK) {
530 } else if(event == EVENT_SEARCH) {
538 if(seektrk > fdc[drvreg].track) {
540 } else if(seektrk < fdc[drvreg].track) {
543 if((cmdreg & 0x10) || ((cmdreg & 0xf0) == 0)) {
544 trkreg = fdc[drvreg].track;
546 if(seektrk == fdc[drvreg].track) {
548 if((cmdreg & 0xf0) == 0) {
551 status |= search_track();
555 REGISTER_SEEK_EVENT();
559 if(seektrk == fdc[drvreg].track) {
561 if((cmdreg & 0x10) || ((cmdreg & 0xf0) == 0)) {
562 trkreg = fdc[drvreg].track;
564 if((cmdreg & 0xf0) == 0) {
567 status |= search_track();
569 CANCEL_EVENT(EVENT_SEEK);
575 if(!(status_tmp & FDC_ST_RECNFND)) {
576 status = status_tmp | (FDC_ST_BUSY | FDC_ST_DRQ);
577 REGISTER_LOST_EVENT();
578 fdc[drvreg].cur_position = fdc[drvreg].next_trans_position;
579 fdc[drvreg].prev_clock = prev_drq_clock = current_clock();
583 #if defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
584 // for SHARP X1 Batten Tanuki
585 if(disk[drvreg]->is_special_disk == SPECIAL_DISK_X1_BATTEN && drive_sel) {
586 status_tmp &= ~FDC_ST_RECNFND;
589 status = status_tmp & ~(FDC_ST_BUSY | FDC_ST_DRQ);
593 cmdtype = FDC_CMD_TYPE4;
596 if(status & FDC_ST_BUSY) {
597 status |= FDC_ST_DRQ;
598 REGISTER_LOST_EVENT();
599 fdc[drvreg].cur_position = (fdc[drvreg].cur_position + 1) % disk[drvreg]->get_track_size();
600 fdc[drvreg].prev_clock = prev_drq_clock = current_clock();
608 if(cmdtype == FDC_CMD_RD_MSEC) {
610 } else if(cmdtype == FDC_CMD_WR_MSEC) {
615 if(status & FDC_ST_BUSY) {
616 #ifdef _FDC_DEBUG_LOG
617 emu->out_debug_log("FDC\tDATA LOST\n");
619 status |= FDC_ST_LOSTDATA;
620 status &= ~FDC_ST_BUSY;
621 //status &= ~FDC_ST_DRQ;
629 // ----------------------------------------------------------------------------
631 // ----------------------------------------------------------------------------
633 void MB8877::process_cmd()
635 #ifdef _FDC_DEBUG_LOG
636 static const _TCHAR *cmdstr[0x10] = {
637 _T("RESTORE "), _T("SEEK "), _T("STEP "), _T("STEP "),
638 _T("STEP IN "), _T("STEP IN "), _T("STEP OUT"), _T("STEP OUT"),
639 _T("RD DATA "), _T("RD DATA "), _T("RD DATA "), _T("WR DATA "),
640 _T("RD ADDR "), _T("FORCEINT"), _T("RD TRACK"), _T("WR TRACK")
642 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);
645 CANCEL_EVENT(EVENT_TYPE4);
648 switch(cmdreg & 0xf0) {
696 void MB8877::cmd_restore()
699 cmdtype = FDC_CMD_TYPE1;
700 status = FDC_ST_HEADENG | FDC_ST_BUSY;
706 REGISTER_SEEK_EVENT();
707 REGISTER_EVENT(EVENT_SEEKEND, 300);
710 void MB8877::cmd_seek()
713 cmdtype = FDC_CMD_TYPE1;
714 status = FDC_ST_HEADENG | FDC_ST_BUSY;
717 seektrk = fdc[drvreg].track + datareg - trkreg;
721 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
722 seekvct = !(datareg > trkreg);
724 REGISTER_SEEK_EVENT();
725 REGISTER_EVENT(EVENT_SEEKEND, 300);
728 void MB8877::cmd_step()
738 void MB8877::cmd_stepin()
741 cmdtype = FDC_CMD_TYPE1;
742 status = FDC_ST_HEADENG | FDC_ST_BUSY;
744 seektrk = (fdc[drvreg].track < 83) ? fdc[drvreg].track + 1 : 83;
747 REGISTER_SEEK_EVENT();
748 REGISTER_EVENT(EVENT_SEEKEND, 300);
751 void MB8877::cmd_stepout()
754 cmdtype = FDC_CMD_TYPE1;
755 status = FDC_ST_HEADENG | FDC_ST_BUSY;
757 seektrk = (fdc[drvreg].track > 0) ? fdc[drvreg].track - 1 : 0;
760 REGISTER_SEEK_EVENT();
761 REGISTER_EVENT(EVENT_SEEKEND, 300);
764 void MB8877::cmd_readdata()
767 cmdtype = (cmdreg & 0x10) ? FDC_CMD_RD_MSEC : FDC_CMD_RD_SEC;
768 int side = (cmdreg & 2) ? ((cmdreg & 8) ? 1 : 0) : sidereg;
769 status = FDC_ST_BUSY;
770 status_tmp = search_sector(fdc[drvreg].track, side, secreg, ((cmdreg & 2) != 0));
774 if(!(status_tmp & FDC_ST_RECNFND)) {
775 time = get_usec_to_start_trans();
777 time = disk[drvreg]->get_usec_per_bytes(disk[drvreg]->get_track_size());
779 REGISTER_EVENT(EVENT_SEARCH, time);
780 CANCEL_EVENT(EVENT_LOST);
783 void MB8877::cmd_writedata()
786 cmdtype = (cmdreg & 0x10) ? FDC_CMD_WR_MSEC : FDC_CMD_WR_SEC;
787 int side = (cmdreg & 2) ? ((cmdreg & 8) ? 1 : 0) : sidereg;
788 status = FDC_ST_BUSY;
789 status_tmp = search_sector(fdc[drvreg].track, side, secreg, ((cmdreg & 2) != 0)) & ~FDC_ST_RECTYPE;
793 if(!(status_tmp & FDC_ST_RECNFND)) {
794 time = get_usec_to_start_trans();
796 time = disk[drvreg]->get_usec_per_bytes(disk[drvreg]->get_track_size());
798 REGISTER_EVENT(EVENT_SEARCH, time);
799 CANCEL_EVENT(EVENT_LOST);
802 void MB8877::cmd_readaddr()
804 // type-3 read address
805 cmdtype = FDC_CMD_RD_ADDR;
806 status = FDC_ST_BUSY;
807 status_tmp = search_addr();
811 if(!(status_tmp & FDC_ST_RECNFND)) {
812 time = get_usec_to_start_trans();
814 time = disk[drvreg]->get_usec_per_bytes(disk[drvreg]->get_track_size());
816 REGISTER_EVENT(EVENT_SEARCH, time);
817 CANCEL_EVENT(EVENT_LOST);
820 void MB8877::cmd_readtrack()
823 cmdtype = FDC_CMD_RD_TRK;
824 status = FDC_ST_BUSY;
827 disk[drvreg]->make_track(fdc[drvreg].track, sidereg);
828 fdc[drvreg].index = 0;
831 int bytes = disk[drvreg]->get_track_size() - get_cur_position();
833 bytes += disk[drvreg]->get_track_size();
835 double time = disk[drvreg]->get_usec_per_bytes(bytes);
836 REGISTER_EVENT(EVENT_SEARCH, time);
837 CANCEL_EVENT(EVENT_LOST);
840 void MB8877::cmd_writetrack()
842 // type-3 write track
843 cmdtype = FDC_CMD_WR_TRK;
844 status = FDC_ST_BUSY;
847 fdc[drvreg].index = 0;
850 int bytes = disk[drvreg]->get_track_size() - get_cur_position();
852 bytes += disk[drvreg]->get_track_size();
854 double time = disk[drvreg]->get_usec_per_bytes(bytes);
855 REGISTER_EVENT(EVENT_SEARCH, time);
856 CANCEL_EVENT(EVENT_LOST);
859 void MB8877::cmd_forceint()
861 // type-4 force interrupt
863 if(!disk[drvreg]->inserted || !motor_on) {
864 status = FDC_ST_NOTREADY | FDC_ST_HEADENG;
866 status = FDC_ST_HEADENG;
868 cmdtype = FDC_CMD_TYPE4;
870 // if(cmdtype == 0 || cmdtype == 4) { // modified for mz-2800, why in the write sector command case?
871 if(cmdtype == 0 || cmdtype == FDC_CMD_TYPE4) { // is this correct?
873 cmdtype = FDC_CMD_TYPE1;
875 status &= ~FDC_ST_BUSY;
878 // force interrupt if bit0-bit3 is high
883 // finish current seeking
885 if(seektrk > fdc[drvreg].track) {
887 } else if(seektrk < fdc[drvreg].track) {
890 if((cmdreg_tmp & 0x10) || ((cmdreg_tmp & 0xf0) == 0)) {
891 trkreg = fdc[drvreg].track;
893 if(seektrk == fdc[drvreg].track) {
895 if((cmdreg_tmp & 0xf0) == 0) {
900 now_search = now_seek = false;
902 CANCEL_EVENT(EVENT_SEEK);
903 CANCEL_EVENT(EVENT_SEEKEND);
904 CANCEL_EVENT(EVENT_SEARCH);
905 CANCEL_EVENT(EVENT_TYPE4);
906 CANCEL_EVENT(EVENT_DRQ);
907 CANCEL_EVENT(EVENT_MULTI1);
908 CANCEL_EVENT(EVENT_MULTI2);
909 CANCEL_EVENT(EVENT_LOST);
910 REGISTER_EVENT(EVENT_TYPE4, 100);
913 // ----------------------------------------------------------------------------
915 // ----------------------------------------------------------------------------
917 uint8 MB8877::search_track()
919 int trk = fdc[drvreg].track;
921 if(!disk[drvreg]->get_track(trk, sidereg)) {
922 return FDC_ST_SEEKERR;
925 // verify track number
929 for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
930 disk[drvreg]->get_sector(trk, sidereg, i);
931 if(disk[drvreg]->id[0] == trkreg) {
935 return FDC_ST_SEEKERR;
938 uint8 MB8877::search_sector(int trk, int side, int sct, bool compare)
941 if(!disk[drvreg]->get_track(trk, side)) {
943 return FDC_ST_RECNFND;
946 // get current position
947 int sector_num = disk[drvreg]->sector_num.sd;
948 int position = get_cur_position();
950 if(position > disk[drvreg]->sync_position[sector_num - 1]) {
951 position -= disk[drvreg]->get_track_size();
954 // first scanned sector
955 int first_sector = 0;
956 for(int i = 0; i < sector_num; i++) {
957 if(position < disk[drvreg]->sync_position[i]) {
964 for(int i = 0; i < sector_num; i++) {
966 int index = (first_sector + i) % sector_num;
967 disk[drvreg]->get_sector(trk, side, index);
970 if((cmdreg & 2) && (disk[drvreg]->id[1] & 1) != ((cmdreg >> 3) & 1)) {
973 if(disk[drvreg]->id[2] != sct) {
978 fdc[drvreg].next_trans_position = disk[drvreg]->data_position[i];
979 fdc[drvreg].next_sync_position = disk[drvreg]->sync_position[i];
980 fdc[drvreg].index = 0;
981 return (disk[drvreg]->deleted ? FDC_ST_RECTYPE : 0) | ((disk[drvreg]->crc_error && !ignore_crc) ? FDC_ST_CRCERR : 0);
985 disk[drvreg]->sector_size.sd = 0;
987 return FDC_ST_RECNFND;
990 uint8 MB8877::search_addr()
992 int trk = fdc[drvreg].track;
995 if(!disk[drvreg]->get_track(trk, sidereg)) {
997 return FDC_ST_RECNFND;
1000 // get current position
1001 int sector_num = disk[drvreg]->sector_num.sd;
1002 int position = get_cur_position();
1004 if(position > disk[drvreg]->sync_position[sector_num - 1]) {
1005 position -= disk[drvreg]->get_track_size();
1008 // first scanned sector
1009 int first_sector = 0;
1010 for(int i = 0; i < sector_num; i++) {
1011 if(position < disk[drvreg]->sync_position[i]) {
1018 if(disk[drvreg]->get_sector(trk, sidereg, first_sector)) {
1019 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[first_sector];
1020 fdc[drvreg].next_sync_position = disk[drvreg]->sync_position[first_sector];
1021 fdc[drvreg].index = 0;
1022 secreg = disk[drvreg]->id[0];
1023 return (disk[drvreg]->crc_error && !ignore_crc) ? FDC_ST_CRCERR : 0;
1027 disk[drvreg]->sector_size.sd = 0;
1029 return FDC_ST_RECNFND;
1032 // ----------------------------------------------------------------------------
1034 // ----------------------------------------------------------------------------
1036 int MB8877::get_cur_position()
1038 return (int)(fdc[drvreg].cur_position + passed_usec(fdc[drvreg].prev_clock) / disk[drvreg]->get_usec_per_bytes(1)) % disk[drvreg]->get_track_size();
1041 double MB8877::get_usec_to_start_trans()
1043 #if defined(_X1TURBO) || defined(_X1TURBOZ)
1044 // FIXME: ugly patch for X1turbo ALPHA
1045 if(disk[drvreg]->is_special_disk == SPECIAL_DISK_X1_ALPHA) {
1049 if(disk[drvreg]->no_skew) {
1050 // XXX: this image may be a standard image or coverted from a standard image and skew may be incorrect,
1051 // so use the constant period to search the target sector
1055 // get time from current position
1056 int position = get_cur_position();
1057 int bytes = fdc[drvreg].next_trans_position - position;
1058 if(fdc[drvreg].next_sync_position < position) {
1059 bytes += disk[drvreg]->get_track_size();
1061 double time = disk[drvreg]->get_usec_per_bytes(bytes);
1063 // wait 70msec to read/write data just after seek command is done
1064 // if(time < 70000) {
1065 // time += disk[drvreg]->get_usec_per_bytes(disk[drvreg]->get_track_size());
1072 // ----------------------------------------------------------------------------
1074 // ----------------------------------------------------------------------------
1076 void MB8877::set_irq(bool val)
1078 write_signals(&outputs_irq, val ? 0xffffffff : 0);
1081 void MB8877::set_drq(bool val)
1083 write_signals(&outputs_drq, val ? 0xffffffff : 0);
1086 // ----------------------------------------------------------------------------
1088 // ----------------------------------------------------------------------------
1090 void MB8877::open_disk(int drv, _TCHAR path[], int bank)
1092 if(drv < MAX_DRIVE) {
1093 disk[drv]->open(path, bank);
1097 void MB8877::close_disk(int drv)
1099 if(drv < MAX_DRIVE) {
1105 bool MB8877::disk_inserted(int drv)
1107 if(drv < MAX_DRIVE) {
1108 return disk[drv]->inserted;
1113 void MB8877::set_drive_type(int drv, uint8 type)
1115 if(drv < MAX_DRIVE) {
1116 disk[drv]->drive_type = type;
1120 uint8 MB8877::get_drive_type(int drv)
1122 if(drv < MAX_DRIVE) {
1123 return disk[drv]->drive_type;
1125 return DRIVE_TYPE_UNK;
1128 void MB8877::set_drive_rpm(int drv, int rpm)
1130 if(drv < MAX_DRIVE) {
1131 disk[drv]->drive_rpm = rpm;
1135 void MB8877::set_drive_mfm(int drv, bool mfm)
1137 if(drv < MAX_DRIVE) {
1138 disk[drv]->drive_mfm = mfm;
1142 uint8 MB8877::fdc_status()
1144 // for each virtual machines
1145 #if defined(_FMR50) || defined(_FMR60)
1146 return disk[drvreg]->inserted ? 2 : 0;
1152 #define STATE_VERSION 2
1154 void MB8877::save_state(FILEIO* state_fio)
1156 state_fio->FputUint32(STATE_VERSION);
1157 state_fio->FputInt32(this_device_id);
1159 state_fio->FputBool(ignore_crc);
1160 state_fio->Fwrite(fdc, sizeof(fdc), 1);
1161 for(int i = 0; i < MAX_DRIVE; i++) {
1162 disk[i]->save_state(state_fio);
1164 state_fio->FputUint8(status);
1165 state_fio->FputUint8(status_tmp);
1166 state_fio->FputUint8(cmdreg);
1167 state_fio->FputUint8(cmdreg_tmp);
1168 state_fio->FputUint8(trkreg);
1169 state_fio->FputUint8(secreg);
1170 state_fio->FputUint8(datareg);
1171 state_fio->FputUint8(drvreg);
1172 state_fio->FputUint8(sidereg);
1173 state_fio->FputUint8(cmdtype);
1174 state_fio->Fwrite(register_id, sizeof(register_id), 1);
1175 state_fio->FputBool(now_search);
1176 state_fio->FputBool(now_seek);
1177 state_fio->FputBool(after_seek);
1178 state_fio->FputInt32(no_command);
1179 state_fio->FputInt32(seektrk);
1180 state_fio->FputBool(seekvct);
1181 state_fio->FputBool(motor_on);
1182 state_fio->FputBool(drive_sel);
1183 state_fio->FputUint32(prev_drq_clock);
1186 bool MB8877::load_state(FILEIO* state_fio)
1188 if(state_fio->FgetUint32() != STATE_VERSION) {
1191 if(state_fio->FgetInt32() != this_device_id) {
1194 ignore_crc = state_fio->FgetBool();
1195 state_fio->Fread(fdc, sizeof(fdc), 1);
1196 for(int i = 0; i < MAX_DRIVE; i++) {
1197 if(!disk[i]->load_state(state_fio)) {
1201 status = state_fio->FgetUint8();
1202 status_tmp = state_fio->FgetUint8();
1203 cmdreg = state_fio->FgetUint8();
1204 cmdreg_tmp = state_fio->FgetUint8();
1205 trkreg = state_fio->FgetUint8();
1206 secreg = state_fio->FgetUint8();
1207 datareg = state_fio->FgetUint8();
1208 drvreg = state_fio->FgetUint8();
1209 sidereg = state_fio->FgetUint8();
1210 cmdtype = state_fio->FgetUint8();
1211 state_fio->Fread(register_id, sizeof(register_id), 1);
1212 now_search = state_fio->FgetBool();
1213 now_seek = state_fio->FgetBool();
1214 after_seek = state_fio->FgetBool();
1215 no_command = state_fio->FgetInt32();
1216 seektrk = state_fio->FgetInt32();
1217 seekvct = state_fio->FgetBool();
1218 motor_on = state_fio->FgetBool();
1219 drive_sel = state_fio->FgetBool();
1220 prev_drq_clock = state_fio->FgetUint32();