2 Skelton for retropc emulator
5 Author : Takeda.Toshiya
17 #define EVENT_RESULT7 3
29 #define PHASE_RESULT 8
40 #define ST0_NR 0x000008
41 #define ST0_EC 0x000010
42 #define ST0_SE 0x000020
43 #define ST0_AT 0x000040
44 #define ST0_IC 0x000080
45 #define ST0_AI 0x0000c0
47 #define ST1_MA 0x000100
48 #define ST1_NW 0x000200
49 #define ST1_ND 0x000400
50 #define ST1_OR 0x001000
51 #define ST1_DE 0x002000
52 #define ST1_EN 0x008000
54 #define ST2_MD 0x010000
55 #define ST2_BC 0x020000
56 #define ST2_SN 0x040000
57 #define ST2_SH 0x080000
58 #define ST2_NC 0x100000
59 #define ST2_DD 0x200000
60 #define ST2_CM 0x400000
71 #define REGISTER_PHASE_EVENT(phs, usec) { \
72 if(phase_id != -1) { \
73 cancel_event(this, phase_id); \
76 register_event(this, EVENT_PHASE, 100, false, &phase_id); \
79 #define REGISTER_PHASE_EVENT_NEW(phs, usec) { \
80 if(phase_id != -1) { \
81 cancel_event(this, phase_id); \
84 register_event(this, EVENT_PHASE, usec, false, &phase_id); \
87 #define REGISTER_DRQ_EVENT() { \
88 double usec = disk[hdu & DRIVE_MASK]->get_usec_per_bytes(1) - passed_usec(prev_drq_clock); \
92 register_event(this, EVENT_DRQ, usec, false, &drq_id); \
95 #define CANCEL_EVENT() { \
96 if(phase_id != -1) { \
97 cancel_event(this, phase_id); \
101 cancel_event(this, drq_id); \
104 if(lost_id != -1) { \
105 cancel_event(this, lost_id); \
108 if(result7_id != -1) { \
109 cancel_event(this, result7_id); \
112 for(int d = 0; d < 4; d++) { \
113 if(seek_id[d] != -1) { \
114 cancel_event(this, seek_id[d]); \
120 void UPD765A::initialize()
122 // initialize d88 handler
123 for(int i = 0; i < 4; i++) {
124 disk[i] = new DISK(emu);
128 memset(fdc, 0, sizeof(fdc));
129 memset(buffer, 0, sizeof(buffer));
131 phase = prevphase = PHASE_IDLE;
134 bufptr = buffer; // temporary
135 phase_id = drq_id = lost_id = result7_id = -1;
136 seek_id[0] = seek_id[1] = seek_id[2] = seek_id[3] = -1;
138 motor_on = false; // motor off
140 irq_masked = drq_masked = false;
144 #ifdef UPD765A_EXT_DRVSEL
151 if(outputs_index.count) {
152 register_event(this, EVENT_INDEX, 4, true, NULL);
157 void UPD765A::release()
159 for(int i = 0; i < 4; i++) {
167 void UPD765A::reset()
171 phase_id = drq_id = lost_id = result7_id = -1;
172 seek_id[0] = seek_id[1] = seek_id[2] = seek_id[3] = -1;
178 void UPD765A::write_io8(uint32 addr, uint32 data)
182 if((status & (S_RQM | S_DIO)) == S_RQM) {
187 #ifdef _FDC_DEBUG_LOG
188 switch(data & 0x1f) {
190 emu->out_debug_log("FDC: CMD=%2x READ DIAGNOSTIC\n", data);
193 emu->out_debug_log("FDC: CMD=%2x SPECIFY\n", data);
196 emu->out_debug_log("FDC: CMD=%2x SENCE DEVSTAT\n", data);
200 emu->out_debug_log("FDC: CMD=%2x WRITE DATA\n", data);
204 emu->out_debug_log("FDC: CMD=%2x READ DATA\n", data);
207 emu->out_debug_log("FDC: CMD=%2x RECALIB\n", data);
210 emu->out_debug_log("FDC: CMD=%2x SENCE INTSTAT\n", data);
213 emu->out_debug_log("FDC: CMD=%2x READ ID\n", data);
216 emu->out_debug_log("FDC: CMD=%2x WRITE ID\n", data);
219 emu->out_debug_log("FDC: CMD=%2x SEEK\n", data);
224 emu->out_debug_log("FDC: CMD=%2x SCAN\n", data);
227 emu->out_debug_log("FDC: CMD=%2x INVALID\n", data);
232 process_cmd(command & 0x1f);
236 #ifdef _FDC_DEBUG_LOG
237 emu->out_debug_log("FDC: PARAM=%2x\n", data);
243 process_cmd(command & 0x1f);
248 #ifdef _FDC_DEBUG_LOG
249 emu->out_debug_log("FDC: WRITE=%2x\n", data);
254 REGISTER_DRQ_EVENT();
256 process_cmd(command & 0x1f);
258 fdc[hdu & DRIVE_MASK].access = true;
263 if(((command & 0x1f) == 0x11 && *bufptr != data) ||
264 ((command & 0x1f) == 0x19 && *bufptr > data) ||
265 ((command & 0x1f) == 0x1d && *bufptr < data)) {
272 REGISTER_DRQ_EVENT();
276 fdc[hdu & DRIVE_MASK].access = true;
283 uint32 UPD765A::read_io8(uint32 addr)
287 if((status & (S_RQM | S_DIO)) == (S_RQM | S_DIO)) {
294 #ifdef _FDC_DEBUG_LOG
295 emu->out_debug_log("FDC: RESULT=%2x\n", data);
300 // EPSON QC-10 CP/M Plus
301 bool clear_irq = true;
302 if((command & 0x1f) == 0x08) {
303 for(int i = 0; i < 4; i++) {
319 #ifdef _FDC_DEBUG_LOG
320 emu->out_debug_log("FDC: READ=%2x\n", data);
324 REGISTER_DRQ_EVENT();
326 process_cmd(command & 0x1f);
328 fdc[hdu & DRIVE_MASK].access = true;
334 // FIXME: dirty patch for PC-8801 Kimochi Disk 2
335 if(phase_id != -1 && event_phase == PHASE_EXEC) {
336 cancel_event(this, phase_id);
339 process_cmd(command & 0x1f);
342 #ifdef _FDC_DEBUG_LOG
343 // emu->out_debug_log(_T("FDC: STATUS=%2x\n"), seekstat | status);
345 return seekstat | status;
349 void UPD765A::write_dma_io8(uint32 addr, uint32 data)
351 #ifdef UPD765A_DMA_MODE
352 // EPSON QC-10 CP/M Plus
353 dma_data_lost = false;
358 uint32 UPD765A::read_dma_io8(uint32 addr)
360 #ifdef UPD765A_DMA_MODE
361 // EPSON QC-10 CP/M Plus
362 dma_data_lost = false;
367 void UPD765A::write_signal(int id, uint32 data, uint32 mask)
369 if(id == SIG_UPD765A_RESET) {
370 bool next = ((data & mask) != 0);
371 if(!reset_signal && next) {
375 } else if(id == SIG_UPD765A_TC) {
376 if(phase == PHASE_READ || phase == PHASE_WRITE || phase == PHASE_SCAN || (phase == PHASE_RESULT && count == 7)) {
380 process_cmd(command & 0x1f);
383 } else if(id == SIG_UPD765A_MOTOR) {
384 motor_on = ((data & mask) != 0);
385 } else if(id == SIG_UPD765A_MOTOR_NEG) {
386 motor_on = ((data & mask) == 0);
387 #ifdef UPD765A_EXT_DRVSEL
388 } else if(id == SIG_UPD765A_DRVSEL) {
389 hdu = (hdu & 4) | (data & DRIVE_MASK);
390 write_signals(&outputs_hdu, hdu);
392 } else if(id == SIG_UPD765A_IRQ_MASK) {
393 if(!(irq_masked = ((data & mask) != 0))) {
394 write_signals(&outputs_irq, 0);
396 } else if(id == SIG_UPD765A_DRQ_MASK) {
397 if(!(drq_masked = ((data & mask) != 0))) {
398 write_signals(&outputs_drq, 0);
400 } else if(id == SIG_UPD765A_FREADY) {
401 // for NEC PC-98x1 series
402 force_ready = ((data & mask) != 0);
406 uint32 UPD765A::read_signal(int ch)
410 for(int i = 0; i < 4; i++) {
414 fdc[i].access = false;
419 void UPD765A::event_callback(int event_id, int err)
421 if(event_id == EVENT_PHASE) {
424 process_cmd(command & 0x1f);
425 } else if(event_id == EVENT_DRQ) {
429 int drv = hdu & DRIVE_MASK;
430 fdc[drv].cur_position = (fdc[drv].cur_position + 1) % disk[drv]->get_track_size();
431 fdc[drv].prev_clock = prev_drq_clock = current_clock();
433 } else if(event_id == EVENT_LOST) {
434 #ifdef _FDC_DEBUG_LOG
435 emu->out_debug_log("FDC: DATA LOST\n");
441 } else if(event_id == EVENT_RESULT7) {
443 shift_to_result7_event();
444 } else if(event_id == EVENT_INDEX) {
445 // index hole signal width is 5msec (thanks Mr.Sato)
446 int drv = hdu & DRIVE_MASK;
447 bool now_index = (disk[drv]->inserted && get_cur_position(drv) < disk[drv]->get_bytes_per_usec(5000));
448 if(prev_index != now_index) {
449 write_signals(&outputs_index, now_index ? 0xffffffff : 0);
450 prev_index = now_index;
452 } else if(event_id >= EVENT_SEEK && event_id < EVENT_SEEK + 4) {
453 int drv = event_id - EVENT_SEEK;
459 void UPD765A::set_irq(bool val)
461 #ifdef _FDC_DEBUG_LOG
462 // emu->out_debug_log("FDC: IRQ=%d\n", val ? 1 : 0);
464 write_signals(&outputs_irq, (val && !irq_masked) ? 0xffffffff : 0);
467 void UPD765A::set_drq(bool val)
469 #ifdef _FDC_DEBUG_LOG
470 // emu->out_debug_log("FDC: DRQ=%d\n", val ? 1 : 0);
472 // cancel next drq and data lost events
474 cancel_event(this, drq_id);
477 cancel_event(this, lost_id);
479 drq_id = lost_id = -1;
480 // register data lost event if data exists
482 #ifdef UPD765A_DMA_MODE
483 // EPSON QC-10 CP/M Plus
484 dma_data_lost = true;
486 if((command & 0x1f) != 0x0d) {
487 register_event(this, EVENT_LOST, disk[hdu & DRIVE_MASK]->get_usec_per_bytes(1), false, &lost_id);
490 register_event(this, EVENT_LOST, 30000, false, &lost_id);
495 write_signals(&outputs_irq, (val && !irq_masked) ? 0xffffffff : 0);
497 write_signals(&outputs_drq, (val && !drq_masked) ? 0xffffffff : 0);
498 #ifdef UPD765A_DMA_MODE
499 // EPSON QC-10 CP/M Plus
500 if(val && dma_data_lost) {
501 #ifdef _FDC_DEBUG_LOG
502 emu->out_debug_log("FDC: DATA LOST (DMA)\n");
505 write_signals(&outputs_drq, 0);
512 void UPD765A::set_hdu(uint8 val)
514 #ifdef UPD765A_EXT_DRVSEL
515 hdu = (hdu & 3) | (val & 4);
519 write_signals(&outputs_hdu, hdu);
522 // ----------------------------------------------------------------------------
524 // ----------------------------------------------------------------------------
526 void UPD765A::process_cmd(int cmd)
530 cmd_read_diagnostic();
572 void UPD765A::cmd_sence_devstat()
580 buffer[0] = get_devstat(buffer[0] & DRIVE_MASK);
586 void UPD765A::cmd_sence_intstat()
588 for(int i = 0; i < 4; i++) {
590 buffer[0] = (uint8)fdc[i].result;
591 buffer[1] = (uint8)fdc[i].track;
597 #ifdef UPD765A_SENCE_INTSTAT_RESULT
599 buffer[0] = (uint8)ST0_AI;
601 buffer[0] = (uint8)ST0_IC;
607 uint8 UPD765A::get_devstat(int drv)
609 if(drv >= MAX_DRIVE) {
613 if(!force_ready && !disk[drv]->inserted) {
616 return 0x28 | drv | (fdc[drv].track ? 0 : 0x10) | ((fdc[drv].track & 1) ? 0x04 : 0) | (disk[drv]->write_protected ? 0x40 : 0);
619 void UPD765A::cmd_seek()
626 seek(buffer[0] & DRIVE_MASK, buffer[1]);
632 void UPD765A::cmd_recalib()
639 seek(buffer[0] & DRIVE_MASK, 0);
645 void UPD765A::seek(int drv, int trk)
648 int seektime = 32 - 2 * step_rate_time;
649 if(disk[drv]->drive_type == DRIVE_TYPE_2HD) {
652 seektime = (trk == fdc[drv].track) ? 120 : seektime * abs(trk - fdc[drv].track) + 500; //usec
654 if(drv >= MAX_DRIVE) {
655 // invalid drive number
656 fdc[drv].result = (drv & DRIVE_MASK) | ST0_SE | ST0_NR | ST0_AT;
659 fdc[drv].track = trk;
660 #ifdef UPD765A_DONT_WAIT_SEEK
663 if(seek_id[drv] != -1) {
664 cancel_event(this, seek_id[drv]);
666 register_event(this, EVENT_SEEK + drv, seektime, false, &seek_id[drv]);
667 seekstat |= 1 << drv;
672 void UPD765A::seek_event(int drv)
674 int trk = fdc[drv].track;
676 if(drv >= MAX_DRIVE) {
677 fdc[drv].result = (drv & DRIVE_MASK) | ST0_SE | ST0_NR | ST0_AT;
678 } else if(force_ready || disk[drv]->inserted) {
679 fdc[drv].result = (drv & DRIVE_MASK) | ST0_SE;
681 #ifdef UPD765A_NO_ST0_AT_FOR_SEEK
683 fdc[drv].result = (drv & DRIVE_MASK) | ST0_SE | ST0_NR;
685 fdc[drv].result = (drv & DRIVE_MASK) | ST0_SE | ST0_NR | ST0_AT;
689 seekstat &= ~(1 << drv);
692 disk[drv]->changed = false;
695 void UPD765A::cmd_read_data()
703 REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase());
707 if(force_ready && !disk[hdu & DRIVE_MASK]->inserted) {
708 REGISTER_PHASE_EVENT(PHASE_EXEC, 1000000);
711 read_data((command & 0x1f) == 12, false);
719 REGISTER_PHASE_EVENT(PHASE_TIMER, 2000);
722 REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase());
729 // result = ST0_AT | ST1_EN;
736 void UPD765A::cmd_write_data()
744 REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase());
748 if(force_ready && !disk[hdu & DRIVE_MASK]->inserted) {
749 REGISTER_PHASE_EVENT(PHASE_EXEC, 1000000);
752 result = check_cond(true);
753 if(result & ST1_MA) {
754 REGISTER_PHASE_EVENT(PHASE_EXEC, 1000000); // retry
763 int length = 0x80 << (id[3] & 7);
765 length = __min(dtl, 0x80);
766 memset(buffer + length, 0, 0x80 - length);
768 shift_to_write(length);
772 write_data((command & 0x1f) == 9);
779 REGISTER_PHASE_EVENT(PHASE_TIMER, 2000);
782 REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase());
785 // result = ST0_AT | ST1_EN;
791 if(prevphase == PHASE_WRITE && bufptr != buffer) {
792 // terminate while transfer ?
793 memset(bufptr, 0, count);
794 write_data((command & 0x1f) == 9);
801 void UPD765A::cmd_scan()
810 REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase());
814 if(force_ready && !disk[hdu & DRIVE_MASK]->inserted) {
815 REGISTER_PHASE_EVENT(PHASE_EXEC, 1000000);
818 read_data(false, true);
827 REGISTER_PHASE_EVENT(PHASE_TIMER, 2000);
830 REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase());
837 // result = ST0_AT | ST1_EN;
844 void UPD765A::cmd_read_diagnostic()
852 REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase());
856 if(force_ready && !disk[hdu & DRIVE_MASK]->inserted) {
857 REGISTER_PHASE_EVENT(PHASE_EXEC, 1000000);
868 REGISTER_PHASE_EVENT(PHASE_TIMER, 2000);
871 REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase());
878 // result = ST0_AT | ST1_EN;
885 void UPD765A::read_data(bool deleted, bool scan)
887 result = check_cond(false);
888 if(result & ST1_MA) {
889 REGISTER_PHASE_EVENT(PHASE_EXEC, 10000);
896 result = read_sector();
900 if((result & ~ST2_CM) && !(result & ST2_DD)) {
904 if((result & ST2_CM) && (command & 0x20)) {
905 REGISTER_PHASE_EVENT(PHASE_TIMER, 100000);
908 int length = (id[3] & 7) ? (0x80 << (id[3] & 7)) : (__min(dtl, 0x80));
910 shift_to_read(length);
912 shift_to_scan(length);
917 void UPD765A::write_data(bool deleted)
919 if((result = check_cond(true)) != 0) {
923 result = write_sector(deleted);
927 void UPD765A::read_diagnostic()
929 int drv = hdu & DRIVE_MASK;
930 int trk = fdc[drv].track;
931 int side = (hdu >> 2) & 1;
933 result = check_cond(false);
934 if(result & ST1_MA) {
935 REGISTER_PHASE_EVENT(PHASE_EXEC, 10000);
942 if(!disk[drv]->make_track(trk, side)) {
948 // FIXME: we need to consider the case that the first sector does not have a data field
949 // start reading at the first sector data
950 memcpy(buffer, disk[drv]->track + disk[drv]->data_position[0], disk[drv]->get_track_size() - disk[drv]->data_position[0]);
951 memcpy(buffer + disk[drv]->get_track_size() - disk[drv]->data_position[0], disk[drv]->track, disk[drv]->data_position[0]);
952 fdc[drv].next_trans_position = disk[drv]->data_position[0];
954 shift_to_read(0x80 << (id[3] & 7));
958 uint32 UPD765A::read_sector()
960 int drv = hdu & DRIVE_MASK;
961 int trk = fdc[drv].track;
962 int side = (hdu >> 2) & 1;
964 // get sector counts in the current track
965 if(!disk[drv]->make_track(trk, side)) {
966 #ifdef _FDC_DEBUG_LOG
967 emu->out_debug_log("FDC: TRACK NOT FOUND (TRK=%d SIDE=%d)\n", trk, side);
969 return ST0_AT | ST1_MA;
971 int secnum = disk[drv]->sector_num.sd;
973 #ifdef _FDC_DEBUG_LOG
974 emu->out_debug_log("FDC: NO SECTORS IN TRACK (TRK=%d SIDE=%d)\n", trk, side);
976 return ST0_AT | ST1_MA;
979 for(int i = 0; i < secnum; i++) {
980 if(!disk[drv]->get_sector(trk, side, i)) {
983 cy = disk[drv]->id[0];
985 if(disk[drv]->id[0] != id[0] || disk[drv]->id[1] != id[1] || disk[drv]->id[2] != id[2] /*|| disk[drv]->id[3] != id[3]*/) {
987 if(disk[drv]->id[0] != id[0] || disk[drv]->id[1] != id[1] || disk[drv]->id[2] != id[2] || disk[drv]->id[3] != id[3]) {
991 if(disk[drv]->sector_size.sd == 0) {
994 // sector number is matched
995 if(disk[drv]->invalid_format) {
996 memset(buffer, disk[drv]->drive_mfm ? 0x4e : 0xff, sizeof(buffer));
997 memcpy(buffer, disk[drv]->sector, disk[drv]->sector_size.sd);
999 memcpy(buffer, disk[drv]->track + disk[drv]->data_position[i], disk[drv]->get_track_size() - disk[drv]->data_position[i]);
1000 memcpy(buffer + disk[drv]->get_track_size() - disk[drv]->data_position[i], disk[drv]->track, disk[drv]->data_position[i]);
1002 fdc[drv].next_trans_position = disk[drv]->data_position[i];
1004 if((disk[drv]->addr_crc_error || disk[drv]->data_crc_error) && !disk[drv]->ignore_crc()) {
1005 return ST0_AT | ST1_DE | (disk[drv]->data_crc_error ? ST2_DD : 0);
1007 if(disk[drv]->deleted) {
1012 #ifdef _FDC_DEBUG_LOG
1013 emu->out_debug_log("FDC: SECTOR NOT FOUND (TRK=%d SIDE=%d ID=%2x,%2x,%2x,%2x)\n", trk, side, id[0], id[1], id[2], id[3]);
1015 if(cy != id[0] && cy != -1) {
1017 return ST0_AT | ST1_ND | ST2_BC;
1019 return ST0_AT | ST1_ND | ST2_NC;
1022 return ST0_AT | ST1_ND;
1025 uint32 UPD765A::write_sector(bool deleted)
1027 int drv = hdu & DRIVE_MASK;
1028 int trk = fdc[drv].track;
1029 int side = (hdu >> 2) & 1;
1031 if(disk[drv]->write_protected) {
1032 return ST0_AT | ST1_NW;
1034 // get sector counts in the current track
1035 if(!disk[drv]->get_track(trk, side)) {
1036 return ST0_AT | ST1_MA;
1038 int secnum = disk[drv]->sector_num.sd;
1040 return ST0_AT | ST1_MA;
1043 for(int i = 0; i < secnum; i++) {
1044 if(!disk[drv]->get_sector(trk, side, i)) {
1047 cy = disk[drv]->id[0];
1048 if(disk[drv]->id[0] != id[0] || disk[drv]->id[1] != id[1] || disk[drv]->id[2] != id[2] /*|| disk[drv]->id[3] != id[3]*/) {
1051 if(disk[drv]->sector_size.sd == 0) {
1054 // sector number is matched
1055 int size = 0x80 << (id[3] & 7);
1056 memcpy(disk[drv]->sector, buffer, __min(size, disk[drv]->sector_size.sd));
1057 disk[drv]->set_deleted(deleted);
1060 if(cy != id[0] && cy != -1) {
1062 return ST0_AT | ST1_ND | ST2_BC;
1064 return ST0_AT | ST1_ND | ST2_NC;
1067 return ST0_AT | ST1_ND;
1070 uint32 UPD765A::find_id()
1072 int drv = hdu & DRIVE_MASK;
1073 int trk = fdc[drv].track;
1074 int side = (hdu >> 2) & 1;
1076 // get sector counts in the current track
1077 if(!disk[drv]->get_track(trk, side)) {
1078 return ST0_AT | ST1_MA;
1080 int secnum = disk[drv]->sector_num.sd;
1082 return ST0_AT | ST1_MA;
1085 for(int i = 0; i < secnum; i++) {
1086 if(!disk[drv]->get_sector(trk, side, i)) {
1089 cy = disk[drv]->id[0];
1090 if(disk[drv]->id[0] != id[0] || disk[drv]->id[1] != id[1] || disk[drv]->id[2] != id[2] /*|| disk[drv]->id[3] != id[3]*/) {
1093 if(disk[drv]->sector_size.sd == 0) {
1096 // sector number is matched
1097 fdc[drv].next_trans_position = disk[drv]->data_position[i];
1100 if(cy != id[0] && cy != -1) {
1102 return ST0_AT | ST1_ND | ST2_BC;
1104 return ST0_AT | ST1_ND | ST2_NC;
1107 return ST0_AT | ST1_ND;
1110 uint32 UPD765A::check_cond(bool write)
1112 int drv = hdu & DRIVE_MASK;
1114 if(drv >= MAX_DRIVE) {
1115 return ST0_AT | ST0_NR;
1117 if(!disk[drv]->inserted) {
1118 return ST0_AT | ST1_MA;
1123 void UPD765A::get_sector_params()
1136 bool UPD765A::id_incr()
1138 if((command & 19) == 17) {
1140 if((dtl & 0xff) == 0x02) {
1144 if(id[2]++ != eot) {
1148 if(command & 0x80) {
1159 void UPD765A::cmd_read_id()
1170 if(force_ready && !disk[hdu & DRIVE_MASK]->inserted) {
1171 REGISTER_PHASE_EVENT(PHASE_EXEC, 1000000);
1174 if(check_cond(false) & ST1_MA) {
1175 // REGISTER_PHASE_EVENT(PHASE_EXEC, 1000000);
1178 if((result = read_id()) == 0) {
1179 int drv = hdu & DRIVE_MASK;
1180 int bytes = fdc[drv].next_trans_position - get_cur_position(drv);
1182 bytes += disk[drv]->get_track_size();
1184 REGISTER_PHASE_EVENT_NEW(PHASE_TIMER, disk[drv]->get_usec_per_bytes(bytes));
1186 REGISTER_PHASE_EVENT(PHASE_TIMER, 5000);
1195 void UPD765A::cmd_write_id()
1206 dtl = buffer[4]; // temporary
1208 REGISTER_PHASE_EVENT(PHASE_TIMER, 1000000);
1211 fdc[hdu & DRIVE_MASK].next_trans_position = get_cur_position(hdu & DRIVE_MASK);
1212 shift_to_write(4 * eot);
1216 REGISTER_PHASE_EVENT(PHASE_TIMER, 4000000);
1220 if(force_ready && !disk[hdu & DRIVE_MASK]->inserted) {
1221 REGISTER_PHASE_EVENT(PHASE_TIMER, 1000000);
1224 result = write_id();
1230 uint32 UPD765A::read_id()
1232 int drv = hdu & DRIVE_MASK;
1233 int trk = fdc[drv].track;
1234 int side = (hdu >> 2) & 1;
1236 // get sector counts in the current track
1237 if(!disk[drv]->get_track(trk, side)) {
1238 return ST0_AT | ST1_MA;
1240 int secnum = disk[drv]->sector_num.sd;
1242 return ST0_AT | ST1_MA;
1245 // first found sector
1246 int position = get_cur_position(drv), first_sector = 0;
1247 if(position > disk[drv]->sync_position[secnum - 1]) {
1248 position -= disk[drv]->get_track_size();
1250 for(int i = 0; i < secnum; i++) {
1251 if(position < disk[drv]->sync_position[i]) {
1256 for(int i = 0; i < secnum; i++) {
1257 int index = (first_sector + i) % secnum;
1258 if(disk[drv]->get_sector(trk, side, index)) {
1259 id[0] = disk[drv]->id[0];
1260 id[1] = disk[drv]->id[1];
1261 id[2] = disk[drv]->id[2];
1262 id[3] = disk[drv]->id[3];
1263 fdc[drv].next_trans_position = disk[drv]->id_position[index] + 6;
1267 return ST0_AT | ST1_ND;
1270 uint32 UPD765A::write_id()
1272 int drv = hdu & DRIVE_MASK;
1273 int trk = fdc[drv].track;
1274 int side = (hdu >> 2) & 1;
1275 int length = 0x80 << (id[3] & 7);
1277 if((result = check_cond(true)) != 0) {
1280 if(disk[drv]->write_protected) {
1281 return ST0_AT | ST1_NW;
1284 disk[drv]->format_track(trk, side);
1285 for(int i = 0; i < eot && i < 256; i++) {
1286 for(int j = 0; j < 4; j++) {
1287 id[j] = buffer[4 * i + j];
1289 disk[drv]->insert_sector(id[0], id[1], id[2], id[3], false, false, dtl, length);
1294 void UPD765A::cmd_specify()
1301 step_rate_time = buffer[0] >> 4;
1302 no_dma_mode = ((buffer[1] & 1) != 0);
1304 status = 0x80;//0xff;
1309 void UPD765A::cmd_invalid()
1311 buffer[0] = (uint8)ST0_IC;
1315 void UPD765A::shift_to_idle()
1321 void UPD765A::shift_to_cmd(int length)
1324 status = S_RQM | S_CB;
1329 void UPD765A::shift_to_exec()
1332 process_cmd(command & 0x1f);
1335 void UPD765A::shift_to_read(int length)
1338 status = S_RQM | S_DIO | S_NDM | S_CB;
1342 int drv = hdu & DRIVE_MASK;
1343 fdc[drv].cur_position = fdc[drv].next_trans_position;
1344 fdc[drv].prev_clock = prev_drq_clock = current_clock();
1348 void UPD765A::shift_to_write(int length)
1350 phase = PHASE_WRITE;
1351 status = S_RQM | S_NDM | S_CB;
1355 int drv = hdu & DRIVE_MASK;
1356 fdc[drv].cur_position = fdc[drv].next_trans_position;
1357 fdc[drv].prev_clock = prev_drq_clock = current_clock();
1361 void UPD765A::shift_to_scan(int length)
1364 status = S_RQM | S_NDM | S_CB;
1369 int drv = hdu & DRIVE_MASK;
1370 fdc[drv].cur_position = fdc[drv].next_trans_position;
1371 fdc[drv].prev_clock = prev_drq_clock = current_clock();
1375 void UPD765A::shift_to_result(int length)
1377 phase = PHASE_RESULT;
1378 status = S_RQM | S_CB | S_DIO;
1383 void UPD765A::shift_to_result7()
1385 #ifdef UPD765A_WAIT_RESULT7
1386 if(result7_id != -1) {
1387 cancel_event(this, result7_id);
1390 if(phase != PHASE_TIMER) {
1391 register_event(this, EVENT_RESULT7, 100, false, &result7_id);
1394 shift_to_result7_event();
1397 void UPD765A::shift_to_result7_event()
1399 #ifdef UPD765A_NO_ST1_EN_OR_FOR_RESULT7
1400 // for NEC PC-9801 (XANADU)
1401 result &= ~(ST1_EN | ST1_OR);
1403 buffer[0] = (result & 0xf8) | (hdue & 7);
1404 buffer[1] = uint8(result >> 8);
1405 buffer[2] = uint8(result >> 16);
1414 // ----------------------------------------------------------------------------
1416 // ----------------------------------------------------------------------------
1418 int UPD765A::get_cur_position(int drv)
1420 return (fdc[drv].cur_position + disk[drv]->get_bytes_per_usec(passed_usec(fdc[drv].prev_clock))) % disk[drv]->get_track_size();
1423 double UPD765A::get_usec_to_exec_phase()
1425 int drv = hdu & DRIVE_MASK;
1426 int trk = fdc[drv].track;
1427 int side = (hdu >> 2) & 1;
1429 if(/*disk[drv]->no_skew &&*/ !disk[drv]->correct_timing()) {
1430 // XXX: this image may be a standard image or coverted from a standard image and skew may be incorrect,
1431 // so use the constant period to go to exec phase
1435 // search target sector
1436 int position = get_cur_position(drv);
1437 int trans_position = -1, sync_position;
1439 if(disk[drv]->get_track(trk, side) && disk[drv]->sector_num.sd != 0) {
1440 if((command & 0x1f) == 0x02) {
1442 trans_position = disk[drv]->data_position[0];
1443 sync_position = disk[drv]->sync_position[0];
1445 for(int i = 0; i < disk[drv]->sector_num.sd; i++) {
1446 if(!disk[drv]->get_sector(trk, side, i)) {
1449 if(disk[drv]->id[0] != id[0] || disk[drv]->id[1] != id[1] || disk[drv]->id[2] != id[2] /*|| disk[drv]->id[3] != id[3]*/) {
1452 // sector number is matched
1453 trans_position = disk[drv]->data_position[i];
1454 sync_position = disk[drv]->sync_position[i];
1459 if(trans_position == -1) {
1464 // get current position
1465 int bytes = trans_position - position;
1466 if(sync_position < position) {
1467 bytes += disk[drv]->get_track_size();
1469 return disk[drv]->get_usec_per_bytes(bytes);
1472 // ----------------------------------------------------------------------------
1474 // ----------------------------------------------------------------------------
1476 void UPD765A::open_disk(int drv, const _TCHAR* file_path, int bank)
1478 if(drv < MAX_DRIVE) {
1479 disk[drv]->open(file_path, bank);
1480 if(disk[drv]->changed) {
1481 #ifdef _FDC_DEBUG_LOG
1482 emu->out_debug_log("FDC: Disk Changed (Drive=%d)\n", drv);
1484 if(raise_irq_when_media_changed) {
1485 fdc[drv].result = (drv & DRIVE_MASK) | ST0_AI;
1492 void UPD765A::close_disk(int drv)
1494 if(drv < MAX_DRIVE && disk[drv]->inserted) {
1496 #ifdef _FDC_DEBUG_LOG
1497 emu->out_debug_log("FDC: Disk Ejected (Drive=%d)\n", drv);
1499 if(raise_irq_when_media_changed) {
1500 fdc[drv].result = (drv & DRIVE_MASK) | ST0_AI;
1506 bool UPD765A::disk_inserted(int drv)
1508 if(drv < MAX_DRIVE) {
1509 return disk[drv]->inserted;
1514 bool UPD765A::disk_inserted()
1516 int drv = hdu & DRIVE_MASK;
1517 return disk_inserted(drv);
1520 bool UPD765A::disk_ejected(int drv)
1522 if(drv < MAX_DRIVE) {
1523 return disk[drv]->ejected;
1528 bool UPD765A::disk_ejected()
1530 int drv = hdu & DRIVE_MASK;
1531 return disk_ejected(drv);
1534 void UPD765A::set_disk_protected(int drv, bool value)
1536 if(drv < MAX_DRIVE) {
1537 disk[drv]->write_protected = value;
1541 bool UPD765A::get_disk_protected(int drv)
1543 if(drv < MAX_DRIVE) {
1544 return disk[drv]->write_protected;
1549 uint8 UPD765A::media_type(int drv)
1551 if(drv < MAX_DRIVE && disk[drv]->inserted) {
1552 return disk[drv]->media_type;
1554 return MEDIA_TYPE_UNK;
1557 void UPD765A::set_drive_type(int drv, uint8 type)
1559 if(drv < MAX_DRIVE) {
1560 disk[drv]->drive_type = type;
1564 uint8 UPD765A::get_drive_type(int drv)
1566 if(drv < MAX_DRIVE) {
1567 return disk[drv]->drive_type;
1569 return DRIVE_TYPE_UNK;
1572 void UPD765A::set_drive_rpm(int drv, int rpm)
1574 if(drv < MAX_DRIVE) {
1575 disk[drv]->drive_rpm = rpm;
1579 void UPD765A::set_drive_mfm(int drv, bool mfm)
1581 if(drv < MAX_DRIVE) {
1582 disk[drv]->drive_mfm = mfm;
1586 #define STATE_VERSION 1
1588 void UPD765A::save_state(FILEIO* state_fio)
1590 state_fio->FputUint32(STATE_VERSION);
1591 state_fio->FputInt32(this_device_id);
1593 state_fio->Fwrite(fdc, sizeof(fdc), 1);
1594 for(int i = 0; i < 4; i++) {
1595 disk[i]->save_state(state_fio);
1597 state_fio->FputUint8(hdu);
1598 state_fio->FputUint8(hdue);
1599 state_fio->Fwrite(id, sizeof(id), 1);
1600 state_fio->FputUint8(eot);
1601 state_fio->FputUint8(gpl);
1602 state_fio->FputUint8(dtl);
1603 state_fio->FputInt32(phase);
1604 state_fio->FputInt32(prevphase);
1605 state_fio->FputUint8(status);
1606 state_fio->FputUint8(seekstat);
1607 state_fio->FputUint8(command);
1608 state_fio->FputUint32(result);
1609 state_fio->FputInt32(step_rate_time);
1610 state_fio->FputBool(no_dma_mode);
1611 state_fio->FputBool(motor_on);
1612 #ifdef UPD765A_DMA_MODE
1613 state_fio->FputBool(dma_data_lost);
1615 state_fio->FputBool(irq_masked);
1616 state_fio->FputBool(drq_masked);
1617 state_fio->FputInt32((int)(bufptr - buffer));
1618 state_fio->Fwrite(buffer, sizeof(buffer), 1);
1619 state_fio->FputInt32(count);
1620 state_fio->FputInt32(event_phase);
1621 state_fio->FputInt32(phase_id);
1622 state_fio->FputInt32(drq_id);
1623 state_fio->FputInt32(lost_id);
1624 state_fio->FputInt32(result7_id);
1625 state_fio->Fwrite(seek_id, sizeof(seek_id), 1);
1626 state_fio->FputBool(force_ready);
1627 state_fio->FputBool(reset_signal);
1628 state_fio->FputBool(prev_index);
1629 state_fio->FputUint32(prev_drq_clock);
1632 bool UPD765A::load_state(FILEIO* state_fio)
1634 if(state_fio->FgetUint32() != STATE_VERSION) {
1637 if(state_fio->FgetInt32() != this_device_id) {
1640 state_fio->Fread(fdc, sizeof(fdc), 1);
1641 for(int i = 0; i < 4; i++) {
1642 if(!disk[i]->load_state(state_fio)) {
1646 hdu = state_fio->FgetUint8();
1647 hdue = state_fio->FgetUint8();
1648 state_fio->Fread(id, sizeof(id), 1);
1649 eot = state_fio->FgetUint8();
1650 gpl = state_fio->FgetUint8();
1651 dtl = state_fio->FgetUint8();
1652 phase = state_fio->FgetInt32();
1653 prevphase = state_fio->FgetInt32();
1654 status = state_fio->FgetUint8();
1655 seekstat = state_fio->FgetUint8();
1656 command = state_fio->FgetUint8();
1657 result = state_fio->FgetUint32();
1658 step_rate_time = state_fio->FgetInt32();
1659 no_dma_mode = state_fio->FgetBool();
1660 motor_on = state_fio->FgetBool();
1661 #ifdef UPD765A_DMA_MODE
1662 dma_data_lost = state_fio->FgetBool();
1664 irq_masked = state_fio->FgetBool();
1665 drq_masked = state_fio->FgetBool();
1666 bufptr = buffer + state_fio->FgetInt32();
1667 state_fio->Fread(buffer, sizeof(buffer), 1);
1668 count = state_fio->FgetInt32();
1669 event_phase = state_fio->FgetInt32();
1670 phase_id = state_fio->FgetInt32();
1671 drq_id = state_fio->FgetInt32();
1672 lost_id = state_fio->FgetInt32();
1673 result7_id = state_fio->FgetInt32();
1674 state_fio->Fread(seek_id, sizeof(seek_id), 1);
1675 force_ready = state_fio->FgetBool();
1676 reset_signal = state_fio->FgetBool();
1677 prev_index = state_fio->FgetBool();
1678 prev_drq_clock = state_fio->FgetUint32();