OSDN Git Service

[VM][Qt] Add SANYOPHC-20, PHC-25 and SEIKO MAP-1010 .
[csp-qt/common_source_project-fm7.git] / source / src / vm / upd765a.cpp
1 /*
2         Skelton for retropc emulator
3
4         Origin : M88
5         Author : Takeda.Toshiya
6         Date   : 2006.09.17-
7
8         [ uPD765A ]
9 */
10
11 #include "upd765a.h"
12 #include "disk.h"
13
14 #define EVENT_PHASE     0
15 #define EVENT_DRQ       1
16 #define EVENT_LOST      2
17 #define EVENT_RESULT7   3
18 #define EVENT_INDEX     4
19 #define EVENT_SEEK      5
20
21 #define PHASE_IDLE      0
22 #define PHASE_CMD       1
23 #define PHASE_EXEC      2
24 #define PHASE_READ      3
25 #define PHASE_WRITE     4
26 #define PHASE_SCAN      5
27 #define PHASE_TC        6
28 #define PHASE_TIMER     7
29 #define PHASE_RESULT    8
30
31 #define S_D0B   0x01
32 #define S_D1B   0x02
33 #define S_D2B   0x04
34 #define S_D3B   0x08
35 #define S_CB    0x10
36 #define S_NDM   0x20
37 #define S_DIO   0x40
38 #define S_RQM   0x80
39
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
46
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
53
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
61
62 #define ST3_HD  0x04
63 #define ST3_TS  0x08
64 #define ST3_T0  0x10
65 #define ST3_RY  0x20
66 #define ST3_WP  0x40
67 #define ST3_FT  0x80
68
69 #define DRIVE_MASK      3
70
71 #define REGISTER_PHASE_EVENT(phs, usec) { \
72         if(phase_id != -1) { \
73                 cancel_event(this, phase_id); \
74         } \
75         event_phase = phs; \
76         register_event(this, EVENT_PHASE, 100, false, &phase_id); \
77 }
78
79 #define REGISTER_PHASE_EVENT_NEW(phs, usec) { \
80         if(phase_id != -1) { \
81                 cancel_event(this, phase_id); \
82         } \
83         event_phase = phs; \
84         register_event(this, EVENT_PHASE, usec, false, &phase_id); \
85 }
86
87 #define REGISTER_DRQ_EVENT() { \
88         double usec = disk[hdu & DRIVE_MASK]->get_usec_per_bytes(1) - passed_usec(prev_drq_clock); \
89         if(usec < 4) { \
90                 usec = 4; \
91         } \
92         register_event(this, EVENT_DRQ, usec, false, &drq_id); \
93 }
94
95 #define CANCEL_EVENT() { \
96         if(phase_id != -1) { \
97                 cancel_event(this, phase_id); \
98                 phase_id = -1; \
99         } \
100         if(drq_id != -1) { \
101                 cancel_event(this, drq_id); \
102                 drq_id = -1; \
103         } \
104         if(lost_id != -1) { \
105                 cancel_event(this, lost_id); \
106                 lost_id = -1; \
107         } \
108         if(result7_id != -1) { \
109                 cancel_event(this, result7_id); \
110                 result7_id = -1; \
111         } \
112         for(int d = 0; d < 4; d++) { \
113                 if(seek_id[d] != -1) { \
114                         cancel_event(this, seek_id[d]); \
115                         seek_id[d] = -1; \
116                 } \
117         } \
118 }
119
120 void UPD765A::initialize()
121 {
122         // initialize d88 handler
123         for(int i = 0; i < 4; i++) {
124                 disk[i] = new DISK(emu);
125         }
126         
127         // initialize fdc
128         memset(fdc, 0, sizeof(fdc));
129         memset(buffer, 0, sizeof(buffer));
130         
131         phase = prevphase = PHASE_IDLE;
132         status = S_RQM;
133         seekstat = 0;
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;
137         no_dma_mode = false;
138         motor_on = false;       // motor off
139         reset_signal = true;
140         irq_masked = drq_masked = false;
141         
142         set_irq(false);
143         set_drq(false);
144 #ifdef UPD765A_EXT_DRVSEL
145         hdu = 0;
146 #else
147         set_hdu(0);
148 #endif
149         
150         // index hole event
151         if(outputs_index.count) {
152                 register_event(this, EVENT_INDEX, 4, true, NULL);
153                 prev_index = false;
154         }
155 }
156
157 void UPD765A::release()
158 {
159         for(int i = 0; i < 4; i++) {
160                 if(disk[i]) {
161                         disk[i]->close();
162                         delete disk[i];
163                 }
164         }
165 }
166
167 void UPD765A::reset()
168 {
169         shift_to_idle();
170 //      CANCEL_EVENT();
171         phase_id = drq_id = lost_id = result7_id = -1;
172         seek_id[0] = seek_id[1] = seek_id[2] = seek_id[3] = -1;
173         
174         set_irq(false);
175         set_drq(false);
176 }
177
178 void UPD765A::write_io8(uint32 addr, uint32 data)
179 {
180         if(addr & 1) {
181                 // fdc data
182                 if((status & (S_RQM | S_DIO)) == S_RQM) {
183                         status &= ~S_RQM;
184                         
185                         switch(phase) {
186                         case PHASE_IDLE:
187 #ifdef _FDC_DEBUG_LOG
188                                 switch(data & 0x1f) {
189                                 case 0x02:
190                                         emu->out_debug_log("FDC: CMD=%2x READ DIAGNOSTIC\n", data);
191                                         break;
192                                 case 0x03:
193                                         emu->out_debug_log("FDC: CMD=%2x SPECIFY\n", data);
194                                         break;
195                                 case 0x04:
196                                         emu->out_debug_log("FDC: CMD=%2x SENCE DEVSTAT\n", data);
197                                         break;
198                                 case 0x05:
199                                 case 0x09:
200                                         emu->out_debug_log("FDC: CMD=%2x WRITE DATA\n", data);
201                                         break;
202                                 case 0x06:
203                                 case 0x0c:
204                                         emu->out_debug_log("FDC: CMD=%2x READ DATA\n", data);
205                                         break;
206                                 case 0x07:
207                                         emu->out_debug_log("FDC: CMD=%2x RECALIB\n", data);
208                                         break;
209                                 case 0x08:
210                                         emu->out_debug_log("FDC: CMD=%2x SENCE INTSTAT\n", data);
211                                         break;
212                                 case 0x0a:
213                                         emu->out_debug_log("FDC: CMD=%2x READ ID\n", data);
214                                         break;
215                                 case 0x0d:
216                                         emu->out_debug_log("FDC: CMD=%2x WRITE ID\n", data);
217                                         break;
218                                 case 0x0f:
219                                         emu->out_debug_log("FDC: CMD=%2x SEEK\n", data);
220                                         break;
221                                 case 0x11:
222                                 case 0x19:
223                                 case 0x1d:
224                                         emu->out_debug_log("FDC: CMD=%2x SCAN\n", data);
225                                         break;
226                                 default:
227                                         emu->out_debug_log("FDC: CMD=%2x INVALID\n", data);
228                                         break;
229                                 }
230 #endif
231                                 command = data;
232                                 process_cmd(command & 0x1f);
233                                 break;
234                                 
235                         case PHASE_CMD:
236 #ifdef _FDC_DEBUG_LOG
237                                 emu->out_debug_log("FDC: PARAM=%2x\n", data);
238 #endif
239                                 *bufptr++ = data;
240                                 if(--count) {
241                                         status |= S_RQM;
242                                 } else {
243                                         process_cmd(command & 0x1f);
244                                 }
245                                 break;
246                                 
247                         case PHASE_WRITE:
248 #ifdef _FDC_DEBUG_LOG
249                                 emu->out_debug_log("FDC: WRITE=%2x\n", data);
250 #endif
251                                 *bufptr++ = data;
252                                 set_drq(false);
253                                 if(--count) {
254                                         REGISTER_DRQ_EVENT();
255                                 } else {
256                                         process_cmd(command & 0x1f);
257                                 }
258                                 fdc[hdu & DRIVE_MASK].access = true;
259                                 break;
260                                 
261                         case PHASE_SCAN:
262                                 if(data != 0xff) {
263                                         if(((command & 0x1f) == 0x11 && *bufptr != data) ||
264                                            ((command & 0x1f) == 0x19 && *bufptr >  data) ||
265                                            ((command & 0x1f) == 0x1d && *bufptr <  data)) {
266                                                 result &= ~ST2_SH;
267                                         }
268                                 }
269                                 bufptr++;
270                                 set_drq(false);
271                                 if(--count) {
272                                         REGISTER_DRQ_EVENT();
273                                 } else {
274                                         cmd_scan();
275                                 }
276                                 fdc[hdu & DRIVE_MASK].access = true;
277                                 break;
278                         }
279                 }
280         }
281 }
282
283 uint32 UPD765A::read_io8(uint32 addr)
284 {
285         if(addr & 1) {
286                 // fdc data
287                 if((status & (S_RQM | S_DIO)) == (S_RQM | S_DIO)) {
288                         uint8 data;
289                         status &= ~S_RQM;
290                         
291                         switch(phase) {
292                         case PHASE_RESULT:
293                                 data = *bufptr++;
294 #ifdef _FDC_DEBUG_LOG
295                                 emu->out_debug_log("FDC: RESULT=%2x\n", data);
296 #endif
297                                 if(--count) {
298                                         status |= S_RQM;
299                                 } else {
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++) {
304                                                         if(fdc[i].result) {
305                                                                 clear_irq = false;
306                                                                 break;
307                                                         }
308                                                 }
309                                         }
310                                         if(clear_irq) {
311                                                 set_irq(false);
312                                         }
313                                         shift_to_idle();
314                                 }
315                                 return data;
316                                 
317                         case PHASE_READ:
318                                 data = *bufptr++;
319 #ifdef _FDC_DEBUG_LOG
320                                 emu->out_debug_log("FDC: READ=%2x\n", data);
321 #endif
322                                 set_drq(false);
323                                 if(--count) {
324                                         REGISTER_DRQ_EVENT();
325                                 } else {
326                                         process_cmd(command & 0x1f);
327                                 }
328                                 fdc[hdu & DRIVE_MASK].access = true;
329                                 return data;
330                         }
331                 }
332                 return 0xff;
333         } else {
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);
337                         phase_id = -1;
338                         phase = event_phase;
339                         process_cmd(command & 0x1f);
340                 }
341                 // fdc status
342 #ifdef _FDC_DEBUG_LOG
343 //              emu->out_debug_log(_T("FDC: STATUS=%2x\n"), seekstat | status);
344 #endif
345                 return seekstat | status;
346         }
347 }
348
349 void UPD765A::write_dma_io8(uint32 addr, uint32 data)
350 {
351 #ifdef UPD765A_DMA_MODE
352         // EPSON QC-10 CP/M Plus
353         dma_data_lost = false;
354 #endif
355         write_io8(1, data);
356 }
357
358 uint32 UPD765A::read_dma_io8(uint32 addr)
359 {
360 #ifdef UPD765A_DMA_MODE
361         // EPSON QC-10 CP/M Plus
362         dma_data_lost = false;
363 #endif
364         return read_io8(1);
365 }
366
367 void UPD765A::write_signal(int id, uint32 data, uint32 mask)
368 {
369         if(id == SIG_UPD765A_RESET) {
370                 bool next = ((data & mask) != 0);
371                 if(!reset_signal && next) {
372                         reset();
373                 }
374                 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)) {
377                         if(data & mask) {
378                                 prevphase = phase;
379                                 phase = PHASE_TC;
380                                 process_cmd(command & 0x1f);
381                         }
382                 }
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);
391 #endif
392         } else if(id == SIG_UPD765A_IRQ_MASK) {
393                 if(!(irq_masked = ((data & mask) != 0))) {
394                         write_signals(&outputs_irq, 0);
395                 }
396         } else if(id == SIG_UPD765A_DRQ_MASK) {
397                 if(!(drq_masked = ((data & mask) != 0))) {
398                         write_signals(&outputs_drq, 0);
399                 }
400         } else if(id == SIG_UPD765A_FREADY) {
401                 // for NEC PC-98x1 series
402                 force_ready = ((data & mask) != 0);
403         }
404 }
405
406 uint32 UPD765A::read_signal(int ch)
407 {
408         // get access status
409         uint32 stat = 0;
410         for(int i = 0; i < 4; i++) {
411                 if(fdc[i].access) {
412                         stat |= 1 << i;
413                 }
414                 fdc[i].access = false;
415         }
416         return stat;
417 }
418
419 void UPD765A::event_callback(int event_id, int err)
420 {
421         if(event_id == EVENT_PHASE) {
422                 phase_id = -1;
423                 phase = event_phase;
424                 process_cmd(command & 0x1f);
425         } else if(event_id == EVENT_DRQ) {
426                 drq_id = -1;
427                 status |= S_RQM;
428                 
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();
432                 set_drq(true);
433         } else if(event_id == EVENT_LOST) {
434 #ifdef _FDC_DEBUG_LOG
435                 emu->out_debug_log("FDC: DATA LOST\n");
436 #endif
437                 lost_id = -1;
438                 result = ST1_OR;
439                 set_drq(false);
440                 shift_to_result7();
441         } else if(event_id == EVENT_RESULT7) {
442                 result7_id = -1;
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;
451                 }
452         } else if(event_id >= EVENT_SEEK && event_id < EVENT_SEEK + 4) {
453                 int drv = event_id - EVENT_SEEK;
454                 seek_id[drv] = -1;
455                 seek_event(drv);
456         }
457 }
458
459 void UPD765A::set_irq(bool val)
460 {
461 #ifdef _FDC_DEBUG_LOG
462 //      emu->out_debug_log("FDC: IRQ=%d\n", val ? 1 : 0);
463 #endif
464         write_signals(&outputs_irq, (val && !irq_masked) ? 0xffffffff : 0);
465 }
466
467 void UPD765A::set_drq(bool val)
468 {
469 #ifdef _FDC_DEBUG_LOG
470 //      emu->out_debug_log("FDC: DRQ=%d\n", val ? 1 : 0);
471 #endif
472         // cancel next drq and data lost events
473         if(drq_id != -1) {
474                 cancel_event(this, drq_id);
475         }
476         if(lost_id != -1) {
477                 cancel_event(this, lost_id);
478         }
479         drq_id = lost_id = -1;
480         // register data lost event if data exists
481         if(val) {
482 #ifdef UPD765A_DMA_MODE
483                 // EPSON QC-10 CP/M Plus
484                 dma_data_lost = true;
485 #else
486                 if((command & 0x1f) != 0x0d) {
487                         register_event(this, EVENT_LOST, disk[hdu & DRIVE_MASK]->get_usec_per_bytes(1), false, &lost_id);
488                 } else {
489                         // FIXME: write id
490                         register_event(this, EVENT_LOST, 30000, false, &lost_id);
491                 }
492 #endif
493         }
494         if(no_dma_mode) {
495                 write_signals(&outputs_irq, (val && !irq_masked) ? 0xffffffff : 0);
496         } else {
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");
503 #endif
504                         result = ST1_OR;
505                         write_signals(&outputs_drq, 0);
506                         shift_to_result7();
507                 }
508 #endif
509         }
510 }
511
512 void UPD765A::set_hdu(uint8 val)
513 {
514 #ifdef UPD765A_EXT_DRVSEL
515         hdu = (hdu & 3) | (val & 4);
516 #else
517         hdu = val;
518 #endif
519         write_signals(&outputs_hdu, hdu);
520 }
521
522 // ----------------------------------------------------------------------------
523 // command
524 // ----------------------------------------------------------------------------
525
526 void UPD765A::process_cmd(int cmd)
527 {
528         switch(cmd & 0x1f) {
529         case 0x02:
530                 cmd_read_diagnostic();
531                 break;
532         case 0x03:
533                 cmd_specify();
534                 break;
535         case 0x04:
536                 cmd_sence_devstat();
537                 break;
538         case 0x05:
539         case 0x09:
540                 cmd_write_data();
541                 break;
542         case 0x06:
543         case 0x0c:
544                 cmd_read_data();
545                 break;
546         case 0x07:
547                 cmd_recalib();
548                 break;
549         case 0x08:
550                 cmd_sence_intstat();
551                 break;
552         case 0x0a:
553                 cmd_read_id();
554                 break;
555         case 0x0d:
556                 cmd_write_id();
557                 break;
558         case 0x0f:
559                 cmd_seek();
560                 break;
561         case 0x11:
562         case 0x19:
563         case 0x1d:
564                 cmd_scan();
565                 break;
566         default:
567                 cmd_invalid();
568                 break;
569         }
570 }
571
572 void UPD765A::cmd_sence_devstat()
573 {
574         switch(phase) {
575         case PHASE_IDLE:
576                 shift_to_cmd(1);
577                 break;
578         case PHASE_CMD:
579                 set_hdu(buffer[0]);
580                 buffer[0] = get_devstat(buffer[0] & DRIVE_MASK);
581                 shift_to_result(1);
582                 break;
583         }
584 }
585
586 void UPD765A::cmd_sence_intstat()
587 {
588         for(int i = 0; i < 4; i++) {
589                 if(fdc[i].result) {
590                         buffer[0] = (uint8)fdc[i].result;
591                         buffer[1] = (uint8)fdc[i].track;
592                         fdc[i].result = 0;
593                         shift_to_result(2);
594                         return;
595                 }
596         }
597 #ifdef UPD765A_SENCE_INTSTAT_RESULT
598         // IBM PC/JX
599         buffer[0] = (uint8)ST0_AI;
600 #else
601         buffer[0] = (uint8)ST0_IC;
602 #endif
603         shift_to_result(1);
604 //      status &= ~S_CB;
605 }
606
607 uint8 UPD765A::get_devstat(int drv)
608 {
609         if(drv >= MAX_DRIVE) {
610                 return 0x80 | drv;
611         }
612         // XM8 version 1.20
613         if(!force_ready && !disk[drv]->inserted) {
614                 return drv;
615         }
616         return 0x28 | drv | (fdc[drv].track ? 0 : 0x10) | ((fdc[drv].track & 1) ? 0x04 : 0) | (disk[drv]->write_protected ? 0x40 : 0);
617 }
618
619 void UPD765A::cmd_seek()
620 {
621         switch(phase) {
622         case PHASE_IDLE:
623                 shift_to_cmd(2);
624                 break;
625         case PHASE_CMD:
626                 seek(buffer[0] & DRIVE_MASK, buffer[1]);
627                 shift_to_idle();
628                 break;
629         }
630 }
631
632 void UPD765A::cmd_recalib()
633 {
634         switch(phase) {
635         case PHASE_IDLE:
636                 shift_to_cmd(1);
637                 break;
638         case PHASE_CMD:
639                 seek(buffer[0] & DRIVE_MASK, 0);
640                 shift_to_idle();
641                 break;
642         }
643 }
644
645 void UPD765A::seek(int drv, int trk)
646 {
647         // get distance
648         int seektime = 32 - 2 * step_rate_time;
649         if(disk[drv]->drive_type == DRIVE_TYPE_2HD) {
650                 seektime /= 2;
651         }
652         seektime = (trk == fdc[drv].track) ? 120 : seektime * abs(trk - fdc[drv].track) + 500; //usec
653         
654         if(drv >= MAX_DRIVE) {
655                 // invalid drive number
656                 fdc[drv].result = (drv & DRIVE_MASK) | ST0_SE | ST0_NR | ST0_AT;
657                 set_irq(true);
658         } else {
659                 fdc[drv].track = trk;
660 #ifdef UPD765A_DONT_WAIT_SEEK
661                 seek_event(drv);
662 #else
663                 if(seek_id[drv] != -1) {
664                         cancel_event(this, seek_id[drv]);
665                 }
666                 register_event(this, EVENT_SEEK + drv, seektime, false, &seek_id[drv]);
667                 seekstat |= 1 << drv;
668 #endif
669         }
670 }
671
672 void UPD765A::seek_event(int drv)
673 {
674         int trk = fdc[drv].track;
675         
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;
680         } else {
681 #ifdef UPD765A_NO_ST0_AT_FOR_SEEK
682                 // for NEC PC-100
683                 fdc[drv].result = (drv & DRIVE_MASK) | ST0_SE | ST0_NR;
684 #else
685                 fdc[drv].result = (drv & DRIVE_MASK) | ST0_SE | ST0_NR | ST0_AT;
686 #endif
687         }
688         set_irq(true);
689         seekstat &= ~(1 << drv);
690         
691         // reset dsch flag
692         disk[drv]->changed = false;
693 }
694
695 void UPD765A::cmd_read_data()
696 {
697         switch(phase) {
698         case PHASE_IDLE:
699                 shift_to_cmd(8);
700                 break;
701         case PHASE_CMD:
702                 get_sector_params();
703                 REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase());
704                 break;
705         case PHASE_EXEC:
706                 // XM8 version 1.20
707                 if(force_ready && !disk[hdu & DRIVE_MASK]->inserted) {
708                         REGISTER_PHASE_EVENT(PHASE_EXEC, 1000000);
709                         break;
710                 }
711                 read_data((command & 0x1f) == 12, false);
712                 break;
713         case PHASE_READ:
714                 if(result) {
715                         shift_to_result7();
716                         break;
717                 }
718                 if(!id_incr()) {
719                         REGISTER_PHASE_EVENT(PHASE_TIMER, 2000);
720                         break;
721                 }
722                 REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase());
723                 break;
724         case PHASE_TC:
725                 CANCEL_EVENT();
726                 shift_to_result7();
727                 break;
728         case PHASE_TIMER:
729 //              result = ST0_AT | ST1_EN;
730                 result = ST1_EN;
731                 shift_to_result7();
732                 break;
733         }
734 }
735
736 void UPD765A::cmd_write_data()
737 {
738         switch(phase) {
739         case PHASE_IDLE:
740                 shift_to_cmd(8);
741                 break;
742         case PHASE_CMD:
743                 get_sector_params();
744                 REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase());
745                 break;
746         case PHASE_EXEC:
747                 // XM8 version 1.20
748                 if(force_ready && !disk[hdu & DRIVE_MASK]->inserted) {
749                         REGISTER_PHASE_EVENT(PHASE_EXEC, 1000000);
750                         break;
751                 }
752                 result = check_cond(true);
753                 if(result & ST1_MA) {
754                         REGISTER_PHASE_EVENT(PHASE_EXEC, 1000000);      // retry
755                         break;
756                 }
757                 if(!result) {
758                         result = find_id();
759                 }
760                 if(result) {
761                         shift_to_result7();
762                 } else {
763                         int length = 0x80 << (id[3] & 7);
764                         if(!(id[3] & 7)) {
765                                 length = __min(dtl, 0x80);
766                                 memset(buffer + length, 0, 0x80 - length);
767                         }
768                         shift_to_write(length);
769                 }
770                 break;
771         case PHASE_WRITE:
772                 write_data((command & 0x1f) == 9);
773                 if(result) {
774                         shift_to_result7();
775                         break;
776                 }
777                 phase = PHASE_EXEC;
778                 if(!id_incr()) {
779                         REGISTER_PHASE_EVENT(PHASE_TIMER, 2000);
780                         break;
781                 }
782                 REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase());
783                 break;
784         case PHASE_TIMER:
785 //              result = ST0_AT | ST1_EN;
786                 result = ST1_EN;
787                 shift_to_result7();
788                 break;
789         case PHASE_TC:
790                 CANCEL_EVENT();
791                 if(prevphase == PHASE_WRITE && bufptr != buffer) {
792                         // terminate while transfer ?
793                         memset(bufptr, 0, count);
794                         write_data((command & 0x1f) == 9);
795                 }
796                 shift_to_result7();
797                 break;
798         }
799 }
800
801 void UPD765A::cmd_scan()
802 {
803         switch(phase) {
804         case PHASE_IDLE:
805                 shift_to_cmd(9);
806                 break;
807         case PHASE_CMD:
808                 get_sector_params();
809                 dtl = dtl | 0x100;
810                 REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase());
811                 break;
812         case PHASE_EXEC:
813                 // XM8 version 1.20
814                 if(force_ready && !disk[hdu & DRIVE_MASK]->inserted) {
815                         REGISTER_PHASE_EVENT(PHASE_EXEC, 1000000);
816                         break;
817                 }
818                 read_data(false, true);
819                 break;
820         case PHASE_SCAN:
821                 if(result) {
822                         shift_to_result7();
823                         break;
824                 }
825                 phase = PHASE_EXEC;
826                 if(!id_incr()) {
827                         REGISTER_PHASE_EVENT(PHASE_TIMER, 2000);
828                         break;
829                 }
830                 REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase());
831                 break;
832         case PHASE_TC:
833                 CANCEL_EVENT();
834                 shift_to_result7();
835                 break;
836         case PHASE_TIMER:
837 //              result = ST0_AT | ST1_EN;
838                 result = ST1_EN;
839                 shift_to_result7();
840                 break;
841         }
842 }
843
844 void UPD765A::cmd_read_diagnostic()
845 {
846         switch(phase) {
847         case PHASE_IDLE:
848                 shift_to_cmd(8);
849                 break;
850         case PHASE_CMD:
851                 get_sector_params();
852                 REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase());
853                 break;
854         case PHASE_EXEC:
855                 // XM8 version 1.20
856                 if(force_ready && !disk[hdu & DRIVE_MASK]->inserted) {
857                         REGISTER_PHASE_EVENT(PHASE_EXEC, 1000000);
858                         break;
859                 }
860                 read_diagnostic();
861                 break;
862         case PHASE_READ:
863                 if(result) {
864                         shift_to_result7();
865                         break;
866                 }
867                 if(!id_incr()) {
868                         REGISTER_PHASE_EVENT(PHASE_TIMER, 2000);
869                         break;
870                 }
871                 REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase());
872                 break;
873         case PHASE_TC:
874                 CANCEL_EVENT();
875                 shift_to_result7();
876                 break;
877         case PHASE_TIMER:
878 //              result = ST0_AT | ST1_EN;
879                 result = ST1_EN;
880                 shift_to_result7();
881                 break;
882         }
883 }
884
885 void UPD765A::read_data(bool deleted, bool scan)
886 {
887         result = check_cond(false);
888         if(result & ST1_MA) {
889                 REGISTER_PHASE_EVENT(PHASE_EXEC, 10000);
890                 return;
891         }
892         if(result) {
893                 shift_to_result7();
894                 return;
895         }
896         result = read_sector();
897         if(deleted) {
898                 result ^= ST2_CM;
899         }
900         if((result & ~ST2_CM) && !(result & ST2_DD)) {
901                 shift_to_result7();
902                 return;
903         }
904         if((result & ST2_CM) && (command & 0x20)) {
905                 REGISTER_PHASE_EVENT(PHASE_TIMER, 100000);
906                 return;
907         }
908         int length = (id[3] & 7) ? (0x80 << (id[3] & 7)) : (__min(dtl, 0x80));
909         if(!scan) {
910                 shift_to_read(length);
911         } else {
912                 shift_to_scan(length);
913         }
914         return;
915 }
916
917 void UPD765A::write_data(bool deleted)
918 {
919         if((result = check_cond(true)) != 0) {
920                 shift_to_result7();
921                 return;
922         }
923         result = write_sector(deleted);
924         return;
925 }
926
927 void UPD765A::read_diagnostic()
928 {
929         int drv = hdu & DRIVE_MASK;
930         int trk = fdc[drv].track;
931         int side = (hdu >> 2) & 1;
932         
933         result = check_cond(false);
934         if(result & ST1_MA) {
935                 REGISTER_PHASE_EVENT(PHASE_EXEC, 10000);
936                 return;
937         }
938         if(result) {
939                 shift_to_result7();
940                 return;
941         }
942         if(!disk[drv]->make_track(trk, side)) {
943                 result = ST1_ND;
944                 shift_to_result7();
945                 return;
946         }
947         
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];
953         
954         shift_to_read(0x80 << (id[3] & 7));
955         return;
956 }
957
958 uint32 UPD765A::read_sector()
959 {
960         int drv = hdu & DRIVE_MASK;
961         int trk = fdc[drv].track;
962         int side = (hdu >> 2) & 1;
963         
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);
968 #endif
969                 return ST0_AT | ST1_MA;
970         }
971         int secnum = disk[drv]->sector_num.sd;
972         if(!secnum) {
973 #ifdef _FDC_DEBUG_LOG
974                 emu->out_debug_log("FDC: NO SECTORS IN TRACK (TRK=%d SIDE=%d)\n", trk, side);
975 #endif
976                 return ST0_AT | ST1_MA;
977         }
978         int cy = -1;
979         for(int i = 0; i < secnum; i++) {
980                 if(!disk[drv]->get_sector(trk, side, i)) {
981                         continue;
982                 }
983                 cy = disk[drv]->id[0];
984 #if 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]*/) {
986 #else
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]) {
988 #endif
989                         continue;
990                 }
991                 if(disk[drv]->sector_size.sd == 0) {
992                         continue;
993                 }
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);
998                 } else {
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]);
1001                 }
1002                 fdc[drv].next_trans_position = disk[drv]->data_position[i];
1003                 
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);
1006                 }
1007                 if(disk[drv]->deleted) {
1008                         return ST2_CM;
1009                 }
1010                 return 0;
1011         }
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]);
1014 #endif
1015         if(cy != id[0] && cy != -1) {
1016                 if(cy == 0xff) {
1017                         return ST0_AT | ST1_ND | ST2_BC;
1018                 } else {
1019                         return ST0_AT | ST1_ND | ST2_NC;
1020                 }
1021         }
1022         return ST0_AT | ST1_ND;
1023 }
1024
1025 uint32 UPD765A::write_sector(bool deleted)
1026 {
1027         int drv = hdu & DRIVE_MASK;
1028         int trk = fdc[drv].track;
1029         int side = (hdu >> 2) & 1;
1030         
1031         if(disk[drv]->write_protected) {
1032                 return ST0_AT | ST1_NW;
1033         }
1034         // get sector counts in the current track
1035         if(!disk[drv]->get_track(trk, side)) {
1036                 return ST0_AT | ST1_MA;
1037         }
1038         int secnum = disk[drv]->sector_num.sd;
1039         if(!secnum) {
1040                 return ST0_AT | ST1_MA;
1041         }
1042         int cy = -1;
1043         for(int i = 0; i < secnum; i++) {
1044                 if(!disk[drv]->get_sector(trk, side, i)) {
1045                         continue;
1046                 }
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]*/) {
1049                         continue;
1050                 }
1051                 if(disk[drv]->sector_size.sd == 0) {
1052                         continue;
1053                 }
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);
1058                 return 0;
1059         }
1060         if(cy != id[0] && cy != -1) {
1061                 if(cy == 0xff) {
1062                         return ST0_AT | ST1_ND | ST2_BC;
1063                 } else {
1064                         return ST0_AT | ST1_ND | ST2_NC;
1065                 }
1066         }
1067         return ST0_AT | ST1_ND;
1068 }
1069
1070 uint32 UPD765A::find_id()
1071 {
1072         int drv = hdu & DRIVE_MASK;
1073         int trk = fdc[drv].track;
1074         int side = (hdu >> 2) & 1;
1075         
1076         // get sector counts in the current track
1077         if(!disk[drv]->get_track(trk, side)) {
1078                 return ST0_AT | ST1_MA;
1079         }
1080         int secnum = disk[drv]->sector_num.sd;
1081         if(!secnum) {
1082                 return ST0_AT | ST1_MA;
1083         }
1084         int cy = -1;
1085         for(int i = 0; i < secnum; i++) {
1086                 if(!disk[drv]->get_sector(trk, side, i)) {
1087                         continue;
1088                 }
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]*/) {
1091                         continue;
1092                 }
1093                 if(disk[drv]->sector_size.sd == 0) {
1094                         continue;
1095                 }
1096                 // sector number is matched
1097                 fdc[drv].next_trans_position = disk[drv]->data_position[i];
1098                 return 0;
1099         }
1100         if(cy != id[0] && cy != -1) {
1101                 if(cy == 0xff) {
1102                         return ST0_AT | ST1_ND | ST2_BC;
1103                 } else {
1104                         return ST0_AT | ST1_ND | ST2_NC;
1105                 }
1106         }
1107         return ST0_AT | ST1_ND;
1108 }
1109
1110 uint32 UPD765A::check_cond(bool write)
1111 {
1112         int drv = hdu & DRIVE_MASK;
1113         hdue = hdu;
1114         if(drv >= MAX_DRIVE) {
1115                 return ST0_AT | ST0_NR;
1116         }
1117         if(!disk[drv]->inserted) {
1118                 return ST0_AT | ST1_MA;
1119         }
1120         return 0;
1121 }
1122
1123 void UPD765A::get_sector_params()
1124 {
1125         set_hdu(buffer[0]);
1126         hdue = buffer[0];
1127         id[0] = buffer[1];
1128         id[1] = buffer[2];
1129         id[2] = buffer[3];
1130         id[3] = buffer[4];
1131         eot = buffer[5];
1132         gpl = buffer[6];
1133         dtl = buffer[7];
1134 }
1135
1136 bool UPD765A::id_incr()
1137 {
1138         if((command & 19) == 17) {
1139                 // scan equal
1140                 if((dtl & 0xff) == 0x02) {
1141                         id[2]++;
1142                 }
1143         }
1144         if(id[2]++ != eot) {
1145                 return true;
1146         }
1147         id[2] = 1;
1148         if(command & 0x80) {
1149                 set_hdu(hdu ^ 4);
1150                 id[1] ^= 1;
1151                 if(id[1] & 1) {
1152                         return true;
1153                 }
1154         }
1155         id[0]++;
1156         return false;
1157 }
1158
1159 void UPD765A::cmd_read_id()
1160 {
1161         switch(phase) {
1162         case PHASE_IDLE:
1163                 shift_to_cmd(1);
1164                 break;
1165         case PHASE_CMD:
1166                 set_hdu(buffer[0]);
1167 //              break;
1168         case PHASE_EXEC:
1169                 // XM8 version 1.20
1170                 if(force_ready && !disk[hdu & DRIVE_MASK]->inserted) {
1171                         REGISTER_PHASE_EVENT(PHASE_EXEC, 1000000);
1172                         break;
1173                 }
1174                 if(check_cond(false) & ST1_MA) {
1175 //                      REGISTER_PHASE_EVENT(PHASE_EXEC, 1000000);
1176 //                      break;
1177                 }
1178                 if((result = read_id()) == 0) {
1179                         int drv = hdu & DRIVE_MASK;
1180                         int bytes = fdc[drv].next_trans_position - get_cur_position(drv);
1181                         if(bytes < 0) {
1182                                 bytes += disk[drv]->get_track_size();
1183                         }
1184                         REGISTER_PHASE_EVENT_NEW(PHASE_TIMER, disk[drv]->get_usec_per_bytes(bytes));
1185                 } else {
1186                         REGISTER_PHASE_EVENT(PHASE_TIMER, 5000);
1187                 }
1188                 break;
1189         case PHASE_TIMER:
1190                 shift_to_result7();
1191                 break;
1192         }
1193 }
1194
1195 void UPD765A::cmd_write_id()
1196 {
1197         switch(phase) {
1198         case PHASE_IDLE:
1199                 shift_to_cmd(5);
1200                 break;
1201         case PHASE_CMD:
1202                 set_hdu(buffer[0]);
1203                 id[3] = buffer[1];
1204                 eot = buffer[2];
1205                 gpl = buffer[3];
1206                 dtl = buffer[4]; // temporary
1207                 if(!eot) {
1208                         REGISTER_PHASE_EVENT(PHASE_TIMER, 1000000);
1209                         break;
1210                 }
1211                 fdc[hdu & DRIVE_MASK].next_trans_position = get_cur_position(hdu & DRIVE_MASK);
1212                 shift_to_write(4 * eot);
1213                 break;
1214         case PHASE_TC:
1215         case PHASE_WRITE:
1216                 REGISTER_PHASE_EVENT(PHASE_TIMER, 4000000);
1217                 break;
1218         case PHASE_TIMER:
1219                 // XM8 version 1.20
1220                 if(force_ready && !disk[hdu & DRIVE_MASK]->inserted) {
1221                         REGISTER_PHASE_EVENT(PHASE_TIMER, 1000000);
1222                         break;
1223                 }
1224                 result =  write_id();
1225                 shift_to_result7();
1226                 break;
1227         }
1228 }
1229
1230 uint32 UPD765A::read_id()
1231 {
1232         int drv = hdu & DRIVE_MASK;
1233         int trk = fdc[drv].track;
1234         int side = (hdu >> 2) & 1;
1235         
1236         // get sector counts in the current track
1237         if(!disk[drv]->get_track(trk, side)) {
1238                 return ST0_AT | ST1_MA;
1239         }
1240         int secnum = disk[drv]->sector_num.sd;
1241         if(!secnum) {
1242                 return ST0_AT | ST1_MA;
1243         }
1244         
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();
1249         }
1250         for(int i = 0; i < secnum; i++) {
1251                 if(position < disk[drv]->sync_position[i]) {
1252                         first_sector = i;
1253                         break;
1254                 }
1255         }
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;
1264                         return 0;
1265                 }
1266         }
1267         return ST0_AT | ST1_ND;
1268 }
1269
1270 uint32 UPD765A::write_id()
1271 {
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);
1276         
1277         if((result = check_cond(true)) != 0) {
1278                 return result;
1279         }
1280         if(disk[drv]->write_protected) {
1281                 return ST0_AT | ST1_NW;
1282         }
1283         
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];
1288                 }
1289                 disk[drv]->insert_sector(id[0], id[1], id[2], id[3], false, false, dtl, length);
1290         }
1291         return 0;
1292 }
1293
1294 void UPD765A::cmd_specify()
1295 {
1296         switch(phase) {
1297         case PHASE_IDLE:
1298                 shift_to_cmd(2);
1299                 break;
1300         case PHASE_CMD:
1301                 step_rate_time = buffer[0] >> 4;
1302                 no_dma_mode = ((buffer[1] & 1) != 0);
1303                 shift_to_idle();
1304                 status = 0x80;//0xff;
1305                 break;
1306         }
1307 }
1308
1309 void UPD765A::cmd_invalid()
1310 {
1311         buffer[0] = (uint8)ST0_IC;
1312         shift_to_result(1);
1313 }
1314
1315 void UPD765A::shift_to_idle()
1316 {
1317         phase = PHASE_IDLE;
1318         status = S_RQM;
1319 }
1320
1321 void UPD765A::shift_to_cmd(int length)
1322 {
1323         phase = PHASE_CMD;
1324         status = S_RQM | S_CB;
1325         bufptr = buffer;
1326         count = length;
1327 }
1328
1329 void UPD765A::shift_to_exec()
1330 {
1331         phase = PHASE_EXEC;
1332         process_cmd(command & 0x1f);
1333 }
1334
1335 void UPD765A::shift_to_read(int length)
1336 {
1337         phase = PHASE_READ;
1338         status = S_RQM | S_DIO | S_NDM | S_CB;
1339         bufptr = buffer;
1340         count = length;
1341         
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();
1345         set_drq(true);
1346 }
1347
1348 void UPD765A::shift_to_write(int length)
1349 {
1350         phase = PHASE_WRITE;
1351         status = S_RQM | S_NDM | S_CB;
1352         bufptr = buffer;
1353         count = length;
1354         
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();
1358         set_drq(true);
1359 }
1360
1361 void UPD765A::shift_to_scan(int length)
1362 {
1363         phase = PHASE_SCAN;
1364         status = S_RQM | S_NDM | S_CB;
1365         result = ST2_SH;
1366         bufptr = buffer;
1367         count = length;
1368         
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();
1372         set_drq(true);
1373 }
1374
1375 void UPD765A::shift_to_result(int length)
1376 {
1377         phase = PHASE_RESULT;
1378         status = S_RQM | S_CB | S_DIO;
1379         bufptr = buffer;
1380         count = length;
1381 }
1382
1383 void UPD765A::shift_to_result7()
1384 {
1385 #ifdef UPD765A_WAIT_RESULT7
1386         if(result7_id != -1) {
1387                 cancel_event(this, result7_id);
1388                 result7_id = -1;
1389         }
1390         if(phase != PHASE_TIMER) {
1391                 register_event(this, EVENT_RESULT7, 100, false, &result7_id);
1392         } else
1393 #endif
1394         shift_to_result7_event();
1395 }
1396
1397 void UPD765A::shift_to_result7_event()
1398 {
1399 #ifdef UPD765A_NO_ST1_EN_OR_FOR_RESULT7
1400         // for NEC PC-9801 (XANADU)
1401         result &= ~(ST1_EN | ST1_OR);
1402 #endif
1403         buffer[0] = (result & 0xf8) | (hdue & 7);
1404         buffer[1] = uint8(result >>  8);
1405         buffer[2] = uint8(result >> 16);
1406         buffer[3] = id[0];
1407         buffer[4] = id[1];
1408         buffer[5] = id[2];
1409         buffer[6] = id[3];
1410         set_irq(true);
1411         shift_to_result(7);
1412 }
1413
1414 // ----------------------------------------------------------------------------
1415 // timing
1416 // ----------------------------------------------------------------------------
1417
1418 int UPD765A::get_cur_position(int drv)
1419 {
1420         return (fdc[drv].cur_position + disk[drv]->get_bytes_per_usec(passed_usec(fdc[drv].prev_clock))) % disk[drv]->get_track_size();
1421 }
1422
1423 double UPD765A::get_usec_to_exec_phase()
1424 {
1425         int drv = hdu & DRIVE_MASK;
1426         int trk = fdc[drv].track;
1427         int side = (hdu >> 2) & 1;
1428         
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
1432                 return 100;
1433         }
1434         
1435         // search target sector
1436         int position = get_cur_position(drv);
1437         int trans_position = -1, sync_position;
1438         
1439         if(disk[drv]->get_track(trk, side) && disk[drv]->sector_num.sd != 0) {
1440                 if((command & 0x1f) == 0x02) {
1441                         // read diagnotics
1442                         trans_position = disk[drv]->data_position[0];
1443                         sync_position = disk[drv]->sync_position[0];
1444                 } else {
1445                         for(int i = 0; i < disk[drv]->sector_num.sd; i++) {
1446                                 if(!disk[drv]->get_sector(trk, side, i)) {
1447                                         continue;
1448                                 }
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]*/) {
1450                                         continue;
1451                                 }
1452                                 // sector number is matched
1453                                 trans_position = disk[drv]->data_position[i];
1454                                 sync_position = disk[drv]->sync_position[i];
1455                                 break;
1456                         }
1457                 }
1458         }
1459         if(trans_position == -1) {
1460                 // sector not found
1461                 return 100;
1462         }
1463         
1464         // get current position
1465         int bytes = trans_position - position;
1466         if(sync_position < position) {
1467                 bytes += disk[drv]->get_track_size();
1468         }
1469         return disk[drv]->get_usec_per_bytes(bytes);
1470 }
1471
1472 // ----------------------------------------------------------------------------
1473 // user interface
1474 // ----------------------------------------------------------------------------
1475
1476 void UPD765A::open_disk(int drv, const _TCHAR* file_path, int bank)
1477 {
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);
1483 #endif
1484                         if(raise_irq_when_media_changed) {
1485                                 fdc[drv].result = (drv & DRIVE_MASK) | ST0_AI;
1486                                 set_irq(true);
1487                         }
1488                 }
1489         }
1490 }
1491
1492 void UPD765A::close_disk(int drv)
1493 {
1494         if(drv < MAX_DRIVE && disk[drv]->inserted) {
1495                 disk[drv]->close();
1496 #ifdef _FDC_DEBUG_LOG
1497                 emu->out_debug_log("FDC: Disk Ejected (Drive=%d)\n", drv);
1498 #endif
1499                 if(raise_irq_when_media_changed) {
1500                         fdc[drv].result = (drv & DRIVE_MASK) | ST0_AI;
1501                         set_irq(true);
1502                 }
1503         }
1504 }
1505
1506 bool UPD765A::disk_inserted(int drv)
1507 {
1508         if(drv < MAX_DRIVE) {
1509                 return disk[drv]->inserted;
1510         }
1511         return false;
1512 }
1513
1514 bool UPD765A::disk_inserted()
1515 {
1516         int drv = hdu & DRIVE_MASK;
1517         return disk_inserted(drv);
1518 }
1519
1520 bool UPD765A::disk_ejected(int drv)
1521 {
1522         if(drv < MAX_DRIVE) {
1523                 return disk[drv]->ejected;
1524         }
1525         return false;
1526 }
1527
1528 bool UPD765A::disk_ejected()
1529 {
1530         int drv = hdu & DRIVE_MASK;
1531         return disk_ejected(drv);
1532 }
1533
1534 void UPD765A::set_disk_protected(int drv, bool value)
1535 {
1536         if(drv < MAX_DRIVE) {
1537                 disk[drv]->write_protected = value;
1538         }
1539 }
1540
1541 bool UPD765A::get_disk_protected(int drv)
1542 {
1543         if(drv < MAX_DRIVE) {
1544                 return disk[drv]->write_protected;
1545         }
1546         return false;
1547 }
1548
1549 uint8 UPD765A::media_type(int drv)
1550 {
1551         if(drv < MAX_DRIVE && disk[drv]->inserted) {
1552                 return disk[drv]->media_type;
1553         }
1554         return MEDIA_TYPE_UNK;
1555 }
1556
1557 void UPD765A::set_drive_type(int drv, uint8 type)
1558 {
1559         if(drv < MAX_DRIVE) {
1560                 disk[drv]->drive_type = type;
1561         }
1562 }
1563
1564 uint8 UPD765A::get_drive_type(int drv)
1565 {
1566         if(drv < MAX_DRIVE) {
1567                 return disk[drv]->drive_type;
1568         }
1569         return DRIVE_TYPE_UNK;
1570 }
1571
1572 void UPD765A::set_drive_rpm(int drv, int rpm)
1573 {
1574         if(drv < MAX_DRIVE) {
1575                 disk[drv]->drive_rpm = rpm;
1576         }
1577 }
1578
1579 void UPD765A::set_drive_mfm(int drv, bool mfm)
1580 {
1581         if(drv < MAX_DRIVE) {
1582                 disk[drv]->drive_mfm = mfm;
1583         }
1584 }
1585
1586 #define STATE_VERSION   1
1587
1588 void UPD765A::save_state(FILEIO* state_fio)
1589 {
1590         state_fio->FputUint32(STATE_VERSION);
1591         state_fio->FputInt32(this_device_id);
1592         
1593         state_fio->Fwrite(fdc, sizeof(fdc), 1);
1594         for(int i = 0; i < 4; i++) {
1595                 disk[i]->save_state(state_fio);
1596         }
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);
1614 #endif
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);
1630 }
1631
1632 bool UPD765A::load_state(FILEIO* state_fio)
1633 {
1634         if(state_fio->FgetUint32() != STATE_VERSION) {
1635                 return false;
1636         }
1637         if(state_fio->FgetInt32() != this_device_id) {
1638                 return false;
1639         }
1640         state_fio->Fread(fdc, sizeof(fdc), 1);
1641         for(int i = 0; i < 4; i++) {
1642                 if(!disk[i]->load_state(state_fio)) {
1643                         return false;
1644                 }
1645         }
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();
1663 #endif
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();
1679         return true;
1680 }
1681