2 Skelton for retropc emulator
5 Author : Takeda.Toshiya
13 #include "../fileio.h"
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
37 #define FDC_CMD_TYPE4 0x80
40 #define EVENT_SEEKEND 1
41 #define EVENT_SEARCH 2
44 #define EVENT_MULTI1 5
45 #define EVENT_MULTI2 6
48 #define DRIVE_MASK (MAX_DRIVE - 1)
50 static const int seek_wait_hi[4] = {3000, 6000, 10000, 16000};
51 static const int seek_wait_lo[4] = {6000, 12000, 20000, 30000};
53 #define CANCEL_EVENT(event) { \
54 if(register_id[event] != -1) { \
55 cancel_event(this, register_id[event]); \
56 register_id[event] = -1; \
59 #define REGISTER_EVENT(event, usec) { \
60 if(register_id[event] != -1) { \
61 cancel_event(this, register_id[event]); \
62 register_id[event] = -1; \
64 register_event(this, (event << 8) | (cmdtype & 0xff), usec, false, ®ister_id[event]); \
66 #define REGISTER_SEEK_EVENT() { \
67 if(register_id[EVENT_SEEK] != -1) { \
68 cancel_event(this, register_id[EVENT_SEEK]); \
69 register_id[EVENT_SEEK] = -1; \
71 if(disk[drvreg]->drive_type == DRIVE_TYPE_2HD) { \
72 register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), seek_wait_hi[cmdreg & 3], false, ®ister_id[EVENT_SEEK]); \
74 register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), seek_wait_lo[cmdreg & 3], false, ®ister_id[EVENT_SEEK]); \
76 now_seek = after_seek = true; \
78 #define REGISTER_DRQ_EVENT() { \
79 double usec = disk[drvreg]->get_usec_per_bytes(1) - passed_usec(prev_drq_clock); \
82 } else if(usec > 24 && disk[drvreg]->is_special_disk == SPECIAL_DISK_X1_ALPHA) { \
85 if(register_id[EVENT_DRQ] != -1) { \
86 cancel_event(this, register_id[EVENT_DRQ]); \
87 register_id[EVENT_DRQ] = -1; \
89 register_event(this, (EVENT_DRQ << 8) | (cmdtype & 0xff), usec, false, ®ister_id[EVENT_DRQ]); \
91 #define REGISTER_LOST_EVENT() { \
92 if(register_id[EVENT_LOST] != -1) { \
93 cancel_event(this, register_id[EVENT_LOST]); \
94 register_id[EVENT_LOST] = -1; \
96 register_event(this, (EVENT_LOST << 8) | (cmdtype & 0xff), disk[drvreg]->get_usec_per_bytes(/*1*/2), false, ®ister_id[EVENT_LOST]); \
99 void MB8877::initialize()
102 ignore_crc = config.ignore_crc;
104 // initialize d88 handler
105 for(int i = 0; i < MAX_DRIVE; i++) {
106 disk[i] = new DISK(emu);
110 memset(fdc, 0, sizeof(fdc));
115 status = cmdreg = trkreg = secreg = datareg = sidereg = cmdtype = 0;
119 void MB8877::release()
121 // release d88 handler
122 for(int i = 0; i < MAX_DRIVE; i++) {
132 for(int i = 0; i < MAX_DRIVE; i++) {
135 fdc[i].access = false;
137 for(int i = 0; i < array_length(register_id); i++) {
140 now_search = now_seek = after_seek = drive_sel = false;
144 void MB8877::update_config()
146 ignore_crc = config.ignore_crc;
149 void MB8877::write_io8(uint32 addr, uint32 data)
156 cmdreg = (~data) & 0xff;
166 trkreg = (~data) & 0xff;
170 if((status & FDC_ST_BUSY) && (fdc[drvreg].index == 0)) {
171 // track reg is written after command starts
172 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
180 secreg = (~data) & 0xff;
184 if((status & FDC_ST_BUSY) && (fdc[drvreg].index == 0)) {
185 // sector reg is written after command starts
186 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
194 datareg = (~data) & 0xff;
198 if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
199 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
200 // write or multisector write
201 if(fdc[drvreg].index < disk[drvreg]->sector_size) {
202 if(!disk[drvreg]->write_protected) {
203 disk[drvreg]->sector[fdc[drvreg].index] = datareg;
205 disk[drvreg]->set_deleted((cmdreg & 1) != 0);
207 status |= FDC_ST_WRITEFAULT;
208 status &= ~FDC_ST_BUSY;
214 if(fdc[drvreg].index >= disk[drvreg]->sector_size) {
215 if(cmdtype == FDC_CMD_WR_SEC) {
217 status &= ~FDC_ST_BUSY;
222 REGISTER_EVENT(EVENT_MULTI1, 30);
223 REGISTER_EVENT(EVENT_MULTI2, 60);
225 } else if(status & FDC_ST_DRQ) {
226 REGISTER_DRQ_EVENT();
228 status &= ~FDC_ST_DRQ;
229 } else if(cmdtype == FDC_CMD_WR_TRK) {
231 if(fdc[drvreg].index < disk[drvreg]->get_track_size()) {
232 if(!disk[drvreg]->write_protected) {
233 if(fdc[drvreg].index == 0) {
234 disk[drvreg]->format_track(fdc[drvreg].track, sidereg);
235 fdc[drvreg].id_written = false;
236 fdc[drvreg].side = sidereg;
237 fdc[drvreg].side_changed = false;
239 if(fdc[drvreg].side != sidereg) {
240 fdc[drvreg].side_changed = true;
242 if(fdc[drvreg].side_changed) {
243 // abort write track because disk side is changed
244 } else if(datareg == 0xf5) {
245 // write a1h in missing clock
246 } else if(datareg == 0xf6) {
247 // write c2h in missing clock
248 } else if(datareg == 0xf7) {
250 if(!fdc[drvreg].id_written) {
251 // insert new sector with crc error
252 fdc[drvreg].id_written = true;
253 fdc[drvreg].sector_found = false;
254 uint8 c = disk[drvreg]->track[fdc[drvreg].index - 4];
255 uint8 h = disk[drvreg]->track[fdc[drvreg].index - 3];
256 uint8 r = disk[drvreg]->track[fdc[drvreg].index - 2];
257 uint8 n = disk[drvreg]->track[fdc[drvreg].index - 1];
258 fdc[drvreg].sector_length = 0x80 << (n & 3);
259 fdc[drvreg].sector_index = 0;
260 disk[drvreg]->insert_sector(c, h, r, n, false, true, 0xe5, fdc[drvreg].sector_length);
262 // clear crc error if all sector data are written
263 if(fdc[drvreg].sector_found && fdc[drvreg].sector_index == fdc[drvreg].sector_length) {
264 disk[drvreg]->set_crc_error(false);
266 fdc[drvreg].id_written = false;
268 } else if(fdc[drvreg].id_written) {
269 if(fdc[drvreg].sector_found) {
271 if(fdc[drvreg].sector_index < fdc[drvreg].sector_length) {
272 disk[drvreg]->sector[fdc[drvreg].sector_index] = datareg;
274 fdc[drvreg].sector_index++;
275 } else if(datareg == 0xf8 || datareg == 0xfb) {
277 disk[drvreg]->set_deleted(datareg == 0xf8);
278 fdc[drvreg].sector_found = true;
281 disk[drvreg]->track[fdc[drvreg].index] = datareg;
283 status |= FDC_ST_WRITEFAULT;
284 status &= ~FDC_ST_BUSY;
285 status &= ~FDC_ST_DRQ;
291 if(fdc[drvreg].index >= disk[drvreg]->get_track_size()) {
292 status &= ~FDC_ST_BUSY;
295 } else if(status & FDC_ST_DRQ) {
296 REGISTER_DRQ_EVENT();
298 status &= ~FDC_ST_DRQ;
300 if(!(status & FDC_ST_DRQ)) {
301 CANCEL_EVENT(EVENT_LOST);
303 fdc[drvreg].access = true;
310 uint32 MB8877::read_io8(uint32 addr)
317 if(cmdtype == FDC_CMD_TYPE4) {
318 // now force interrupt
319 if(!disk[drvreg]->inserted || !motor_on) {
320 status = FDC_ST_NOTREADY;
322 // MZ-2500 RELICS invites STATUS = 0
326 } else if(now_search) {
330 // disk not inserted, motor stop
331 if(!disk[drvreg]->inserted || !motor_on) {
332 status |= FDC_ST_NOTREADY;
334 status &= ~FDC_ST_NOTREADY;
337 if(cmdtype == FDC_CMD_TYPE1 || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) {
338 if(disk[drvreg]->inserted && disk[drvreg]->write_protected) {
339 status |= FDC_ST_WRITEP;
341 status &= ~FDC_ST_WRITEP;
344 status &= ~FDC_ST_WRITEP;
346 // track0, index hole
347 if(cmdtype == FDC_CMD_TYPE1) {
348 if(fdc[drvreg].track == 0) {
349 status |= FDC_ST_TRACK00;
351 status &= ~FDC_ST_TRACK00;
353 if(!(status & FDC_ST_NOTREADY)) {
354 if(get_cur_position() == 0) {
355 status |= FDC_ST_INDEX;
357 status &= ~FDC_ST_INDEX;
361 // show busy a moment
363 if(cmdtype == FDC_CMD_TYPE1 && !now_seek) {
364 status &= ~FDC_ST_BUSY;
367 if(cmdtype == 0 && !(status & FDC_ST_NOTREADY)) {
368 // MZ-2000 HuBASIC invites NOT READY status
369 if(++no_command == 16) {
370 val |= FDC_ST_NOTREADY;
376 if(!(status & FDC_ST_DRQ)) {
380 #ifdef _FDC_DEBUG_LOG
381 emu->out_debug_log(_T("FDC\tSTATUS=%2x\n"), val);
384 return (~val) & 0xff;
391 return (~trkreg) & 0xff;
398 return (~secreg) & 0xff;
404 if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
405 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC) {
406 // read or multisector read
407 if(fdc[drvreg].index < disk[drvreg]->sector_size) {
408 datareg = disk[drvreg]->sector[fdc[drvreg].index];
411 if(fdc[drvreg].index >= disk[drvreg]->sector_size) {
412 if(cmdtype == FDC_CMD_RD_SEC) {
414 #ifdef _FDC_DEBUG_LOG
415 emu->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
417 status &= ~FDC_ST_BUSY;
422 #ifdef _FDC_DEBUG_LOG
423 emu->out_debug_log(_T("FDC\tEND OF SECTOR (SEARCH NEXT)\n"));
425 REGISTER_EVENT(EVENT_MULTI1, 30);
426 REGISTER_EVENT(EVENT_MULTI2, 60);
429 REGISTER_DRQ_EVENT();
431 status &= ~FDC_ST_DRQ;
432 } else if(cmdtype == FDC_CMD_RD_ADDR) {
434 if(fdc[drvreg].index < 6) {
435 datareg = disk[drvreg]->id[fdc[drvreg].index];
438 if(fdc[drvreg].index >= 6) {
439 status &= ~FDC_ST_BUSY;
443 REGISTER_DRQ_EVENT();
445 status &= ~FDC_ST_DRQ;
446 } else if(cmdtype == FDC_CMD_RD_TRK) {
448 if(fdc[drvreg].index < disk[drvreg]->get_track_size()) {
449 datareg = disk[drvreg]->track[fdc[drvreg].index];
452 if(fdc[drvreg].index >= disk[drvreg]->get_track_size()) {
453 #ifdef _FDC_DEBUG_LOG
454 emu->out_debug_log(_T("FDC\tEND OF TRACK\n"));
456 status &= ~FDC_ST_BUSY;
457 status |= FDC_ST_LOSTDATA;
461 REGISTER_DRQ_EVENT();
463 status &= ~FDC_ST_DRQ;
465 if(!(status & FDC_ST_DRQ)) {
466 CANCEL_EVENT(EVENT_LOST);
468 fdc[drvreg].access = true;
471 #ifdef _FDC_DEBUG_LOG
472 emu->out_debug_log(_T("FDC\tDATA=%2x\n"), datareg);
475 return (~datareg) & 0xff;
483 void MB8877::write_dma_io8(uint32 addr, uint32 data)
488 uint32 MB8877::read_dma_io8(uint32 addr)
493 void MB8877::write_signal(int id, uint32 data, uint32 mask)
495 if(id == SIG_MB8877_DRIVEREG) {
496 drvreg = data & DRIVE_MASK;
498 } else if(id == SIG_MB8877_SIDEREG) {
499 sidereg = (data & mask) ? 1 : 0;
500 } else if(id == SIG_MB8877_MOTOR) {
501 motor_on = ((data & mask) != 0);
505 uint32 MB8877::read_signal(int ch)
509 for(int i = 0; i < MAX_DRIVE; i++) {
513 fdc[i].access = false;
521 void MB8877::event_callback(int event_id, int err)
523 int event = event_id >> 8;
524 int cmd = event_id & 0xff;
525 register_id[event] = -1;
527 // cancel event if the command is finished or other command is executed
529 if(event == EVENT_SEEK) {
531 } else if(event == EVENT_SEARCH) {
539 if(seektrk > fdc[drvreg].track) {
541 } else if(seektrk < fdc[drvreg].track) {
544 if((cmdreg & 0x10) || ((cmdreg & 0xf0) == 0)) {
545 trkreg = fdc[drvreg].track;
547 if(seektrk == fdc[drvreg].track) {
549 if((cmdreg & 0xf0) == 0) {
552 status |= search_track();
556 REGISTER_SEEK_EVENT();
560 if(seektrk == fdc[drvreg].track) {
562 if((cmdreg & 0x10) || ((cmdreg & 0xf0) == 0)) {
563 trkreg = fdc[drvreg].track;
565 if((cmdreg & 0xf0) == 0) {
568 status |= search_track();
570 CANCEL_EVENT(EVENT_SEEK);
576 if(!(status_tmp & FDC_ST_RECNFND)) {
577 status = status_tmp | (FDC_ST_BUSY | FDC_ST_DRQ);
578 REGISTER_LOST_EVENT();
579 fdc[drvreg].cur_position = fdc[drvreg].next_trans_position;
580 fdc[drvreg].prev_clock = prev_drq_clock = current_clock();
584 #if defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
585 // for SHARP X1 Batten Tanuki
586 if(disk[drvreg]->is_special_disk == SPECIAL_DISK_X1_BATTEN && drive_sel) {
587 status_tmp &= ~FDC_ST_RECNFND;
590 status = status_tmp & ~(FDC_ST_BUSY | FDC_ST_DRQ);
594 cmdtype = FDC_CMD_TYPE4;
597 if(status & FDC_ST_BUSY) {
598 status |= FDC_ST_DRQ;
599 REGISTER_LOST_EVENT();
600 fdc[drvreg].cur_position = (fdc[drvreg].cur_position + 1) % disk[drvreg]->get_track_size();
601 fdc[drvreg].prev_clock = prev_drq_clock = current_clock();
609 if(cmdtype == FDC_CMD_RD_MSEC) {
611 } else if(cmdtype == FDC_CMD_WR_MSEC) {
616 if(status & FDC_ST_BUSY) {
617 #ifdef _FDC_DEBUG_LOG
618 emu->out_debug_log("FDC\tDATA LOST\n");
620 status |= FDC_ST_LOSTDATA;
621 status &= ~FDC_ST_BUSY;
622 //status &= ~FDC_ST_DRQ;
630 // ----------------------------------------------------------------------------
632 // ----------------------------------------------------------------------------
634 void MB8877::process_cmd()
636 #ifdef _FDC_DEBUG_LOG
637 static const _TCHAR *cmdstr[0x10] = {
638 _T("RESTORE "), _T("SEEK "), _T("STEP "), _T("STEP "),
639 _T("STEP IN "), _T("STEP IN "), _T("STEP OUT"), _T("STEP OUT"),
640 _T("RD DATA "), _T("RD DATA "), _T("RD DATA "), _T("WR DATA "),
641 _T("RD ADDR "), _T("FORCEINT"), _T("RD TRACK"), _T("WR TRACK")
643 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);
646 CANCEL_EVENT(EVENT_TYPE4);
649 switch(cmdreg & 0xf0) {
697 void MB8877::cmd_restore()
700 cmdtype = FDC_CMD_TYPE1;
701 status = FDC_ST_HEADENG | FDC_ST_BUSY;
707 REGISTER_SEEK_EVENT();
708 REGISTER_EVENT(EVENT_SEEKEND, 300);
711 void MB8877::cmd_seek()
714 cmdtype = FDC_CMD_TYPE1;
715 status = FDC_ST_HEADENG | FDC_ST_BUSY;
718 seektrk = fdc[drvreg].track + datareg - trkreg;
722 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
723 seekvct = !(datareg > trkreg);
725 REGISTER_SEEK_EVENT();
726 REGISTER_EVENT(EVENT_SEEKEND, 300);
729 void MB8877::cmd_step()
739 void MB8877::cmd_stepin()
742 cmdtype = FDC_CMD_TYPE1;
743 status = FDC_ST_HEADENG | FDC_ST_BUSY;
745 seektrk = (fdc[drvreg].track < 83) ? fdc[drvreg].track + 1 : 83;
748 REGISTER_SEEK_EVENT();
749 REGISTER_EVENT(EVENT_SEEKEND, 300);
752 void MB8877::cmd_stepout()
755 cmdtype = FDC_CMD_TYPE1;
756 status = FDC_ST_HEADENG | FDC_ST_BUSY;
758 seektrk = (fdc[drvreg].track > 0) ? fdc[drvreg].track - 1 : 0;
761 REGISTER_SEEK_EVENT();
762 REGISTER_EVENT(EVENT_SEEKEND, 300);
765 void MB8877::cmd_readdata()
768 cmdtype = (cmdreg & 0x10) ? FDC_CMD_RD_MSEC : FDC_CMD_RD_SEC;
769 int side = (cmdreg & 2) ? ((cmdreg & 8) ? 1 : 0) : sidereg;
770 status = FDC_ST_BUSY;
771 status_tmp = search_sector(fdc[drvreg].track, side, secreg, ((cmdreg & 2) != 0));
775 if(!(status_tmp & FDC_ST_RECNFND)) {
776 time = get_usec_to_start_trans();
778 time = disk[drvreg]->get_usec_per_bytes(disk[drvreg]->get_track_size());
780 REGISTER_EVENT(EVENT_SEARCH, time);
781 CANCEL_EVENT(EVENT_LOST);
784 void MB8877::cmd_writedata()
787 cmdtype = (cmdreg & 0x10) ? FDC_CMD_WR_MSEC : FDC_CMD_WR_SEC;
788 int side = (cmdreg & 2) ? ((cmdreg & 8) ? 1 : 0) : sidereg;
789 status = FDC_ST_BUSY;
790 status_tmp = search_sector(fdc[drvreg].track, side, secreg, ((cmdreg & 2) != 0)) & ~FDC_ST_RECTYPE;
794 if(!(status_tmp & FDC_ST_RECNFND)) {
795 time = get_usec_to_start_trans();
797 time = disk[drvreg]->get_usec_per_bytes(disk[drvreg]->get_track_size());
799 REGISTER_EVENT(EVENT_SEARCH, time);
800 CANCEL_EVENT(EVENT_LOST);
803 void MB8877::cmd_readaddr()
805 // type-3 read address
806 cmdtype = FDC_CMD_RD_ADDR;
807 status = FDC_ST_BUSY;
808 status_tmp = search_addr();
812 if(!(status_tmp & FDC_ST_RECNFND)) {
813 time = get_usec_to_start_trans();
815 time = disk[drvreg]->get_usec_per_bytes(disk[drvreg]->get_track_size());
817 REGISTER_EVENT(EVENT_SEARCH, time);
818 CANCEL_EVENT(EVENT_LOST);
821 void MB8877::cmd_readtrack()
824 cmdtype = FDC_CMD_RD_TRK;
825 status = FDC_ST_BUSY;
828 disk[drvreg]->make_track(fdc[drvreg].track, sidereg);
829 fdc[drvreg].index = 0;
832 int bytes = disk[drvreg]->get_track_size() - get_cur_position();
834 bytes += disk[drvreg]->get_track_size();
836 double time = disk[drvreg]->get_usec_per_bytes(bytes);
837 REGISTER_EVENT(EVENT_SEARCH, time);
838 CANCEL_EVENT(EVENT_LOST);
841 void MB8877::cmd_writetrack()
843 // type-3 write track
844 cmdtype = FDC_CMD_WR_TRK;
845 status = FDC_ST_BUSY;
848 fdc[drvreg].index = 0;
851 int bytes = disk[drvreg]->get_track_size() - get_cur_position();
853 bytes += disk[drvreg]->get_track_size();
855 double time = disk[drvreg]->get_usec_per_bytes(bytes);
856 REGISTER_EVENT(EVENT_SEARCH, time);
857 CANCEL_EVENT(EVENT_LOST);
860 void MB8877::cmd_forceint()
862 // type-4 force interrupt
864 if(!disk[drvreg]->inserted || !motor_on) {
865 status = FDC_ST_NOTREADY | FDC_ST_HEADENG;
867 status = FDC_ST_HEADENG;
869 cmdtype = FDC_CMD_TYPE4;
871 // if(cmdtype == 0 || cmdtype == 4) { // modified for mz-2800, why in the write sector command case?
872 if(cmdtype == 0 || cmdtype == FDC_CMD_TYPE4) { // is this correct?
874 cmdtype = FDC_CMD_TYPE1;
876 status &= ~FDC_ST_BUSY;
879 // force interrupt if bit0-bit3 is high
884 // finish current seeking
886 if(seektrk > fdc[drvreg].track) {
888 } else if(seektrk < fdc[drvreg].track) {
891 if((cmdreg_tmp & 0x10) || ((cmdreg_tmp & 0xf0) == 0)) {
892 trkreg = fdc[drvreg].track;
894 if(seektrk == fdc[drvreg].track) {
896 if((cmdreg_tmp & 0xf0) == 0) {
901 now_search = now_seek = false;
903 CANCEL_EVENT(EVENT_SEEK);
904 CANCEL_EVENT(EVENT_SEEKEND);
905 CANCEL_EVENT(EVENT_SEARCH);
906 CANCEL_EVENT(EVENT_TYPE4);
907 CANCEL_EVENT(EVENT_DRQ);
908 CANCEL_EVENT(EVENT_MULTI1);
909 CANCEL_EVENT(EVENT_MULTI2);
910 CANCEL_EVENT(EVENT_LOST);
911 REGISTER_EVENT(EVENT_TYPE4, 100);
914 // ----------------------------------------------------------------------------
916 // ----------------------------------------------------------------------------
918 uint8 MB8877::search_track()
920 int trk = fdc[drvreg].track;
922 if(!disk[drvreg]->get_track(trk, sidereg)) {
923 return FDC_ST_SEEKERR;
926 // verify track number
930 for(int i = 0; i < disk[drvreg]->sector_num; i++) {
931 disk[drvreg]->get_sector(trk, sidereg, i);
932 if(disk[drvreg]->id[0] == trkreg) {
936 return FDC_ST_SEEKERR;
939 uint8 MB8877::search_sector(int trk, int side, int sct, bool compare)
942 if(!disk[drvreg]->get_track(trk, side)) {
944 return FDC_ST_RECNFND;
947 // get current position
948 int sector_num = disk[drvreg]->sector_num;
949 int position = get_cur_position();
951 if(position > disk[drvreg]->sync_position[sector_num - 1]) {
952 position -= disk[drvreg]->get_track_size();
955 // first scanned sector
956 int first_sector = 0;
957 for(int i = 0; i < sector_num; i++) {
958 if(position < disk[drvreg]->sync_position[i]) {
965 for(int i = 0; i < sector_num; i++) {
967 int index = (first_sector + i) % sector_num;
968 disk[drvreg]->get_sector(trk, side, index);
971 if((cmdreg & 2) && (disk[drvreg]->id[1] & 1) != ((cmdreg >> 3) & 1)) {
974 if(disk[drvreg]->id[2] != sct) {
979 fdc[drvreg].next_trans_position = disk[drvreg]->data_position[i];
980 fdc[drvreg].next_sync_position = disk[drvreg]->sync_position[i];
981 fdc[drvreg].index = 0;
982 return (disk[drvreg]->deleted ? FDC_ST_RECTYPE : 0) | ((disk[drvreg]->crc_error && !ignore_crc) ? FDC_ST_CRCERR : 0);
986 disk[drvreg]->sector_size = 0;
988 return FDC_ST_RECNFND;
991 uint8 MB8877::search_addr()
993 int trk = fdc[drvreg].track;
996 if(!disk[drvreg]->get_track(trk, sidereg)) {
998 return FDC_ST_RECNFND;
1001 // get current position
1002 int sector_num = disk[drvreg]->sector_num;
1003 int position = get_cur_position();
1005 if(position > disk[drvreg]->sync_position[sector_num - 1]) {
1006 position -= disk[drvreg]->get_track_size();
1009 // first scanned sector
1010 int first_sector = 0;
1011 for(int i = 0; i < sector_num; i++) {
1012 if(position < disk[drvreg]->sync_position[i]) {
1019 if(disk[drvreg]->get_sector(trk, sidereg, first_sector)) {
1020 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[first_sector];
1021 fdc[drvreg].next_sync_position = disk[drvreg]->sync_position[first_sector];
1022 fdc[drvreg].index = 0;
1023 secreg = disk[drvreg]->id[0];
1024 return (disk[drvreg]->crc_error && !ignore_crc) ? FDC_ST_CRCERR : 0;
1028 disk[drvreg]->sector_size = 0;
1030 return FDC_ST_RECNFND;
1033 // ----------------------------------------------------------------------------
1035 // ----------------------------------------------------------------------------
1037 int MB8877::get_cur_position()
1039 return (int)(fdc[drvreg].cur_position + passed_usec(fdc[drvreg].prev_clock) / disk[drvreg]->get_usec_per_bytes(1)) % disk[drvreg]->get_track_size();
1042 double MB8877::get_usec_to_start_trans()
1044 #if defined(_X1TURBO) || defined(_X1TURBOZ)
1045 // FIXME: ugly patch for X1turbo ALPHA
1046 if(disk[drvreg]->is_special_disk == SPECIAL_DISK_X1_ALPHA) {
1050 if(disk[drvreg]->no_skew) {
1051 // XXX: this image may be a standard image or coverted from a standard image and skew may be incorrect,
1052 // so use the constant period to search the target sector
1056 // get time from current position
1057 int position = get_cur_position();
1058 int bytes = fdc[drvreg].next_trans_position - position;
1059 if(fdc[drvreg].next_sync_position < position) {
1060 bytes += disk[drvreg]->get_track_size();
1062 double time = disk[drvreg]->get_usec_per_bytes(bytes);
1064 // wait 70msec to read/write data just after seek command is done
1065 // if(time < 70000) {
1066 // time += disk[drvreg]->get_usec_per_bytes(disk[drvreg]->get_track_size());
1073 // ----------------------------------------------------------------------------
1075 // ----------------------------------------------------------------------------
1077 void MB8877::set_irq(bool val)
1079 write_signals(&outputs_irq, val ? 0xffffffff : 0);
1082 void MB8877::set_drq(bool val)
1084 write_signals(&outputs_drq, val ? 0xffffffff : 0);
1087 // ----------------------------------------------------------------------------
1089 // ----------------------------------------------------------------------------
1091 void MB8877::open_disk(int drv, _TCHAR path[], int bank)
1093 if(drv < MAX_DRIVE) {
1094 disk[drv]->open(path, bank);
1098 void MB8877::close_disk(int drv)
1100 if(drv < MAX_DRIVE) {
1106 bool MB8877::disk_inserted(int drv)
1108 if(drv < MAX_DRIVE) {
1109 return disk[drv]->inserted;
1114 void MB8877::set_drive_type(int drv, uint8 type)
1116 if(drv < MAX_DRIVE) {
1117 disk[drv]->drive_type = type;
1121 uint8 MB8877::get_drive_type(int drv)
1123 if(drv < MAX_DRIVE) {
1124 return disk[drv]->drive_type;
1126 return DRIVE_TYPE_UNK;
1129 void MB8877::set_drive_rpm(int drv, int rpm)
1131 if(drv < MAX_DRIVE) {
1132 disk[drv]->drive_rpm = rpm;
1136 void MB8877::set_drive_mfm(int drv, bool mfm)
1138 if(drv < MAX_DRIVE) {
1139 disk[drv]->drive_mfm = mfm;
1143 uint8 MB8877::fdc_status()
1145 // for each virtual machines
1146 #if defined(_FMR50) || defined(_FMR60)
1147 return disk[drvreg]->inserted ? 2 : 0;
1153 #define STATE_VERSION 2
1155 void MB8877::save_state(FILEIO* state_fio)
1157 state_fio->FputUint32(STATE_VERSION);
1158 state_fio->FputInt32(this_device_id);
1160 state_fio->FputBool(ignore_crc);
1161 state_fio->Fwrite(fdc, sizeof(fdc), 1);
1162 for(int i = 0; i < MAX_DRIVE; i++) {
1163 disk[i]->save_state(state_fio);
1165 state_fio->FputUint8(status);
1166 state_fio->FputUint8(status_tmp);
1167 state_fio->FputUint8(cmdreg);
1168 state_fio->FputUint8(cmdreg_tmp);
1169 state_fio->FputUint8(trkreg);
1170 state_fio->FputUint8(secreg);
1171 state_fio->FputUint8(datareg);
1172 state_fio->FputUint8(drvreg);
1173 state_fio->FputUint8(sidereg);
1174 state_fio->FputUint8(cmdtype);
1175 state_fio->Fwrite(register_id, sizeof(register_id), 1);
1176 state_fio->FputBool(now_search);
1177 state_fio->FputBool(now_seek);
1178 state_fio->FputBool(after_seek);
1179 state_fio->FputInt32(no_command);
1180 state_fio->FputInt32(seektrk);
1181 state_fio->FputBool(seekvct);
1182 state_fio->FputBool(motor_on);
1183 state_fio->FputBool(drive_sel);
1184 state_fio->FputUint32(prev_drq_clock);
1187 bool MB8877::load_state(FILEIO* state_fio)
1189 if(state_fio->FgetUint32() != STATE_VERSION) {
1192 if(state_fio->FgetInt32() != this_device_id) {
1195 ignore_crc = state_fio->FgetBool();
1196 state_fio->Fread(fdc, sizeof(fdc), 1);
1197 for(int i = 0; i < MAX_DRIVE; i++) {
1198 if(!disk[i]->load_state(state_fio)) {
1202 status = state_fio->FgetUint8();
1203 status_tmp = state_fio->FgetUint8();
1204 cmdreg = state_fio->FgetUint8();
1205 cmdreg_tmp = state_fio->FgetUint8();
1206 trkreg = state_fio->FgetUint8();
1207 secreg = state_fio->FgetUint8();
1208 datareg = state_fio->FgetUint8();
1209 drvreg = state_fio->FgetUint8();
1210 sidereg = state_fio->FgetUint8();
1211 cmdtype = state_fio->FgetUint8();
1212 state_fio->Fread(register_id, sizeof(register_id), 1);
1213 now_search = state_fio->FgetBool();
1214 now_seek = state_fio->FgetBool();
1215 after_seek = state_fio->FgetBool();
1216 no_command = state_fio->FgetInt32();
1217 seektrk = state_fio->FgetInt32();
1218 seekvct = state_fio->FgetBool();
1219 motor_on = state_fio->FgetBool();
1220 drive_sel = state_fio->FgetBool();
1221 prev_drq_clock = state_fio->FgetUint32();