OSDN Git Service

[DOC] For release 2017-01-24.
[csp-qt/common_source_project-fm7.git] / source / src / vm / mb8877.cpp
1 /*
2         Skelton for retropc emulator
3
4         Origin : XM7
5         Author : Takeda.Toshiya
6         Date   : 2006.12.06 -
7
8         [ MB8877 / MB8876 / MB8866 / MB89311 ]
9 */
10
11 #include "mb8877.h"
12 #include "disk.h"
13
14 #define FDC_ST_BUSY             0x01    // busy
15 #define FDC_ST_INDEX            0x02    // index hole
16 #define FDC_ST_DRQ              0x02    // data request
17 #define FDC_ST_TRACK00          0x04    // track0
18 #define FDC_ST_LOSTDATA         0x04    // data lost
19 #define FDC_ST_CRCERR           0x08    // crc error
20 #define FDC_ST_SEEKERR          0x10    // seek error
21 #define FDC_ST_RECNFND          0x10    // sector not found
22 #define FDC_ST_HEADENG          0x20    // head engage
23 #define FDC_ST_RECTYPE          0x20    // record type
24 #define FDC_ST_WRITEFAULT       0x20    // write fault
25 #define FDC_ST_WRITEP           0x40    // write protectdc
26 #define FDC_ST_NOTREADY         0x80    // media not inserted
27
28 #define FDC_CMD_TYPE1           1
29 #define FDC_CMD_RD_SEC          2
30 #define FDC_CMD_RD_MSEC         3
31 #define FDC_CMD_WR_SEC          4
32 #define FDC_CMD_WR_MSEC         5
33 #define FDC_CMD_RD_ADDR         6
34 #define FDC_CMD_RD_TRK          7
35 #define FDC_CMD_WR_TRK          8
36
37 #define EVENT_SEEK              0
38 #define EVENT_SEEKEND           1
39 #define EVENT_SEARCH            2
40 #define EVENT_DRQ               3
41 #define EVENT_MULTI1            4
42 #define EVENT_MULTI2            5
43 #define EVENT_LOST              6
44 #define EVENT_MOTOR 7
45
46 #define DRIVE_MASK              (MAX_DRIVE - 1)
47
48 #define DELAY_TIME              (disk[drvreg]->drive_type == DRIVE_TYPE_2HD ? 15000 : 30000)
49
50 static const int seek_wait_hi[4] = {3000,  6000, 10000, 16000}; // 2MHz
51 static const int seek_wait_lo[4] = {6000, 12000, 20000, 30000}; // 1MHz
52
53 void MB8877::cancel_my_event(int event)
54 {
55         if(register_id[event] != -1) {
56                 cancel_event(this, register_id[event]);
57                 register_id[event] = -1;
58         }
59 }
60
61 void MB8877::register_my_event(int event, double usec)
62 {
63         cancel_my_event(event);
64         register_event(this, (event << 8) | (cmdtype & 0xff), usec, false, &register_id[event]);
65 }
66
67 void MB8877::register_seek_event()
68 {
69
70         cancel_my_event(EVENT_SEEK);
71         if(fdc[drvreg].track == seektrk) {
72                 register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), 1, false, &register_id[EVENT_SEEK]);
73         } else if(disk[drvreg]->drive_type == DRIVE_TYPE_2HD) {
74                 register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), seek_wait_hi[cmdreg & 3], false, &register_id[EVENT_SEEK]);
75         } else {
76                 register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), seek_wait_lo[cmdreg & 3], false, &register_id[EVENT_SEEK]);
77         }
78         now_seek = true;
79 }
80
81 void MB8877::register_drq_event(int bytes)
82 {
83         double usec = disk[drvreg]->get_usec_per_bytes(bytes) - get_passed_usec(prev_drq_clock);
84         if(usec < 4) {
85                 usec = 4;
86         }
87 #if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
88         if((disk[drvreg]->is_special_disk == SPECIAL_DISK_FM7_GAMBLER) ||
89            (disk[drvreg]->is_special_disk == SPECIAL_DISK_FM77AV_PSYOBLADE)) {
90                 usec = 4;
91         }
92 #endif
93         cancel_my_event(EVENT_DRQ);
94         register_event(this, (EVENT_DRQ << 8) | (cmdtype & 0xff), usec, false, &register_id[EVENT_DRQ]);
95 }
96
97 void MB8877::register_lost_event(int bytes)
98 {
99         cancel_my_event(EVENT_LOST);
100         register_event(this, (EVENT_LOST << 8) | (cmdtype & 0xff), disk[drvreg]->get_usec_per_bytes(bytes), false, &register_id[EVENT_LOST]);
101 }
102
103
104
105 void MB8877::initialize()
106 {
107         // initialize d88 handler
108         for(int i = 0; i < MAX_DRIVE; i++) {
109                 _TCHAR strbuf[128];
110                 _TCHAR strbuf2[128];
111                 disk[i] = new DISK(emu);
112                 strncpy(strbuf, (_TCHAR *)this->get_device_name(), 128);
113                 snprintf(strbuf2, 128, "%s/DRIVE%d", strbuf, i + 1);
114                 disk[i]->set_device_name((const _TCHAR *)strbuf2);
115         }
116         
117         // initialize timing
118         memset(fdc, 0, sizeof(fdc));
119         
120         // initialize fdc
121         seektrk = 0;
122         seekvct = true;
123         status = cmdreg = trkreg = secreg = datareg = sidereg = cmdtype = 0;
124         drvreg = 0;
125         prev_drq_clock = seekend_clock = 0;
126 }
127
128 void MB8877::release()
129 {
130         // release d88 handler
131         for(int i = 0; i < MAX_DRIVE; i++) {
132                 if(disk[i]) {
133                         disk[i]->close();
134                         delete disk[i];
135                 }
136         }
137 }
138
139 void MB8877::reset()
140 {
141         touch_sound();
142         for(int i = 0; i < MAX_DRIVE; i++) {
143                 fdc[i].track = 0;
144                 fdc[i].index = 0;
145                 fdc[i].access = false;
146         }
147         for(int i = 0; i < array_length(register_id); i++) {
148                 register_id[i] = -1;
149         }
150         now_search = now_seek = drive_sel = false;
151         no_command = 0;
152 #ifdef HAS_MB89311
153         extended_mode = true;
154 #endif
155 }
156
157 void MB8877::write_io8(uint32_t addr, uint32_t data)
158 {
159         bool _stat;
160         switch(addr & 3) {
161         case 0:
162                 // command reg
163                 cmdreg_tmp = cmdreg;
164 #if defined(HAS_MB8866) || defined(HAS_MB8876)
165                 cmdreg = (~data) & 0xff;
166 #else
167                 cmdreg = data;
168 #endif
169                 process_cmd();
170                 no_command = 0;
171                 break;
172         case 1:
173                 // track reg
174 #if defined(HAS_MB8866) || defined(HAS_MB8876)
175                 trkreg = (~data) & 0xff;
176 #else
177                 trkreg = data;
178 #endif
179                 if((status & FDC_ST_BUSY) && (fdc[drvreg].index == 0)) {
180                         // track reg is written after command starts
181                         if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
182                                 process_cmd();
183                         }
184                 }
185                 break;
186         case 2:
187                 // sector reg
188 #if defined(HAS_MB8866) || defined(HAS_MB8876)
189                 secreg = (~data) & 0xff;
190 #else
191                 secreg = data;
192 #endif
193                 if((status & FDC_ST_BUSY) && (fdc[drvreg].index == 0)) {
194                         // sector reg is written after command starts
195                         if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
196                                 process_cmd();
197                         }
198                 }
199                 break;
200         case 3:
201                 // data reg
202 #if defined(HAS_MB8866) || defined(HAS_MB8876)
203                 datareg = (~data) & 0xff;
204 #else
205                 datareg = data;
206 #endif
207
208                 _stat = ((status & FDC_ST_DRQ) && !now_search);
209                 if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
210                         _stat = (_stat && motor_on);
211                 }
212                 if(_stat) {
213                         if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
214                                 // write or multisector write
215                                 if(fdc[drvreg].index < disk[drvreg]->sector_size.sd) {
216                                         if(!disk[drvreg]->write_protected) {
217                                                 if(disk[drvreg]->sector[fdc[drvreg].index] != datareg) {
218                                                         disk[drvreg]->sector[fdc[drvreg].index] = datareg;
219                                                         sector_changed = true;
220                                                 }
221                                                 // dm, ddm
222                                                 disk[drvreg]->set_deleted((cmdreg & 1) != 0);
223                                         } else {
224                                                 status |= FDC_ST_WRITEFAULT;
225                                                 status &= ~FDC_ST_BUSY;
226                                                 cmdtype = 0;
227                                                 set_irq(true);
228                                         }
229                                         //fdc[drvreg].index++;
230                                 }
231                                 if((fdc[drvreg].index + 1) >= disk[drvreg]->sector_size.sd) {
232                                         if(cmdtype == FDC_CMD_WR_SEC) {
233                                                 // single sector
234 #ifdef _FDC_DEBUG_LOG
235                                                 this->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
236 #endif
237                                                 status &= ~FDC_ST_BUSY;
238                                                 cmdtype = 0;
239                                                 set_irq(true);
240                                         } else {
241                                                 // multisector
242 #ifdef _FDC_DEBUG_LOG
243                                                 this->out_debug_log(_T("FDC\tEND OF SECTOR (SEARCH NEXT)\n"));
244 #endif
245                                                 // 2HD: 360rpm, 10410bytes/track -> 0.06246bytes/us
246                                                 register_my_event(EVENT_MULTI1, 30); // 0.06246bytes/us * 30us = 1.8738bytes < GAP3
247                                                 register_my_event(EVENT_MULTI2, 60); // 0.06246bytes/us * 60us = 3.7476bytes < GAP3
248                                         }
249                                         sector_changed = false;
250                                 } else if(status & FDC_ST_DRQ) {
251                                         if(fdc[drvreg].index == 0) {
252                                                 register_drq_event(fdc[drvreg].bytes_before_2nd_drq);
253                                         } else {
254                                                 register_drq_event(1);
255                                         }
256                                 }
257                                 status &= ~FDC_ST_DRQ;
258                         } else if(cmdtype == FDC_CMD_WR_TRK) {
259                                 // write track
260                                 if(fdc[drvreg].index < disk[drvreg]->get_track_size()) {
261                                         if(!disk[drvreg]->write_protected) {
262                                                 if(fdc[drvreg].index == 0) {
263                                                         disk[drvreg]->format_track(fdc[drvreg].track, sidereg);
264                                                         fdc[drvreg].id_written = false;
265                                                         fdc[drvreg].side = sidereg;
266                                                         fdc[drvreg].side_changed = false;
267                                                 }
268                                                 if(fdc[drvreg].side != sidereg) {
269                                                         fdc[drvreg].side_changed = true;
270                                                 }
271                                                 if(fdc[drvreg].side_changed) {
272                                                         // abort write track because disk side is changed
273                                                 } else if(datareg == 0xf5) {
274                                                         // write a1h in missing clock
275                                                 } else if(datareg == 0xf6) {
276                                                         // write c2h in missing clock
277                                                 } else if(datareg == 0xf7) {
278                                                         // write crc
279                                                         if(!fdc[drvreg].id_written) {
280                                                                 // insert new sector with data crc error
281 write_id:
282                                                                 uint8_t c = 0, h = 0, r = 0, n = 0;
283                                                                 fdc[drvreg].id_written = true;
284                                                                 fdc[drvreg].sector_found = false;
285                                                                 if(fdc[drvreg].index >= 4) {
286                                                                         c = disk[drvreg]->track[fdc[drvreg].index - 4];
287                                                                         h = disk[drvreg]->track[fdc[drvreg].index - 3];
288                                                                         r = disk[drvreg]->track[fdc[drvreg].index - 2];
289                                                                         n = disk[drvreg]->track[fdc[drvreg].index - 1];
290                                                                 }
291                                                                 fdc[drvreg].sector_length = 0x80 << (n & 3);
292                                                                 fdc[drvreg].sector_index = 0;
293                                                                 disk[drvreg]->insert_sector(c, h, r, n, false, true, 0xe5, fdc[drvreg].sector_length);
294                                                         } else if(fdc[drvreg].sector_found) {
295                                                                 // clear data crc error if all sector data are written
296                                                                 if(fdc[drvreg].sector_index == fdc[drvreg].sector_length) {
297                                                                         disk[drvreg]->set_data_crc_error(false);
298                                                                 }
299                                                                 fdc[drvreg].id_written = false;
300                                                         } else {
301                                                                 // data mark of current sector is not written
302                                                                 disk[drvreg]->set_data_mark_missing();
303                                                                 goto write_id;
304                                                         }
305                                                 } else if(fdc[drvreg].id_written) {
306                                                         if(fdc[drvreg].sector_found) {
307                                                                 // sector data
308                                                                 if(fdc[drvreg].sector_index < fdc[drvreg].sector_length) {
309                                                                         disk[drvreg]->sector[fdc[drvreg].sector_index] = datareg;
310                                                                 }
311                                                                 fdc[drvreg].sector_index++;
312                                                         } else if(datareg == 0xf8 || datareg == 0xfb) {
313                                                                 // data mark
314                                                                 disk[drvreg]->set_deleted(datareg == 0xf8);
315                                                                 fdc[drvreg].sector_found = true;
316                                                         }
317                                                 }
318                                                 disk[drvreg]->track[fdc[drvreg].index] = datareg;
319                                         } else {
320                                                 status |= FDC_ST_WRITEFAULT;
321                                                 status &= ~FDC_ST_BUSY;
322                                                 status &= ~FDC_ST_DRQ;
323                                                 cmdtype = 0;
324                                                 set_irq(true);
325                                         }
326                                         //fdc[drvreg].index++;
327                                 }
328                                 if((fdc[drvreg].index + 1) >= disk[drvreg]->get_track_size()) {
329                                         if(!disk[drvreg]->write_protected) {
330                                                 if(fdc[drvreg].id_written && !fdc[drvreg].sector_found) {
331                                                         // data mark of last sector is not written
332                                                         disk[drvreg]->set_data_mark_missing();
333                                                 }
334                                                 disk[drvreg]->sync_buffer();
335                                         }
336                                         status &= ~FDC_ST_BUSY;
337                                         cmdtype = 0;
338                                         set_irq(true);
339                                 } else if(status & FDC_ST_DRQ) {
340                                         if(fdc[drvreg].index == 0) {
341                                                 register_drq_event(fdc[drvreg].bytes_before_2nd_drq);
342                                         } else {
343                                                 register_drq_event(1);
344                                         }
345                                 }
346                                 status &= ~FDC_ST_DRQ;
347                         }
348                         if(!(status & FDC_ST_DRQ)) {
349                                 cancel_my_event(EVENT_LOST);
350                                 set_drq(false);
351                                 fdc[drvreg].access = true;
352                         }
353                 }
354                 break;
355         }
356 }
357
358 uint32_t MB8877::read_io8(uint32_t addr)
359 {
360         uint32_t val;
361         bool _stat;
362         switch(addr & 3) {
363         case 0:
364                 // status reg
365                 if(now_search) {
366                         // now sector search
367                         val = FDC_ST_BUSY;
368                 } else {
369                         // disk not inserted, motor stop
370                         _stat = !disk[drvreg]->inserted;
371                         if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
372                                 _stat = (_stat || !motor_on);
373                         }
374                         if(_stat) {
375                                 status |= FDC_ST_NOTREADY;
376                         } else {
377                                 status &= ~FDC_ST_NOTREADY;
378                         }
379                         // write protected
380                         if(cmdtype == FDC_CMD_TYPE1 || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) {
381                                 if(disk[drvreg]->inserted && disk[drvreg]->write_protected) {
382                                         status |= FDC_ST_WRITEP;
383                                 } else {
384                                         status &= ~FDC_ST_WRITEP;
385                                 }
386                         } else {
387                                 status &= ~FDC_ST_WRITEP;
388                         }
389                         // track0, index hole
390                         if(cmdtype == FDC_CMD_TYPE1) {
391                                 if(fdc[drvreg].track == 0) {
392                                         status |= FDC_ST_TRACK00;
393                                 } else {
394                                         status &= ~FDC_ST_TRACK00;
395                                 }
396                                 // index hole signal width is 5msec (thanks Mr.Sato)
397                                 if(!(status & FDC_ST_NOTREADY) && get_cur_position() < disk[drvreg]->get_bytes_per_usec(5000)) {
398                                         status |= FDC_ST_INDEX;
399                                 } else {
400                                         status &= ~FDC_ST_INDEX;
401                                 }
402                         }
403                         // show busy a moment
404                         val = status;
405                         if(cmdtype == FDC_CMD_TYPE1 && !now_seek) {
406                                 status &= ~FDC_ST_BUSY;
407 #ifdef MB8877_NO_BUSY_AFTER_SEEK
408         #if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
409                                 if(disk[0]->is_special_disk != SPECIAL_DISK_FM7_XANADU2_D) {
410                                         val &= ~FDC_ST_BUSY;
411                                 }
412         #else                   
413                                 val &= ~FDC_ST_BUSY;
414         #endif
415 #endif
416                         }
417                 }
418                 if(cmdtype == 0 && !(status & FDC_ST_NOTREADY)) {
419                         // MZ-2000 HuBASIC invites NOT READY status
420                         if(++no_command == 16) {
421                                 val |= FDC_ST_NOTREADY;
422                         }
423                 } else {
424                         no_command = 0;
425                 }
426                 // reset irq/drq
427                 if(!(status & FDC_ST_DRQ)) {
428                         set_drq(false);
429                 }
430                 if(!(status & FDC_ST_BUSY)) {
431                         set_irq(false);
432                 }
433
434 #ifdef _FDC_DEBUG_LOG
435                 this->out_debug_log(_T("FDC\tSTATUS=%2x\n"), val);
436 #endif
437 #if defined(HAS_MB8866) || defined(HAS_MB8876)
438                 return (~val) & 0xff;
439 #else
440                 return val;
441 #endif
442         case 1:
443                 // track reg
444 #if defined(HAS_MB8866) || defined(HAS_MB8876)
445                 return (~trkreg) & 0xff;
446 #else
447                 return trkreg;
448 #endif
449         case 2:
450                 // sector reg
451 #if defined(HAS_MB8866) || defined(HAS_MB8876)
452                 return (~secreg) & 0xff;
453 #else
454                 return secreg;
455 #endif
456         case 3:
457                 // data reg
458                 _stat = ((status & FDC_ST_DRQ) && !now_search);
459                 if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
460                         _stat = (_stat && motor_on);
461                 }
462                 if(_stat) {
463                 //if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
464                         if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC) {
465                                 // read or multisector read
466                                 if(fdc[drvreg].index < disk[drvreg]->sector_size.sd) {
467                                         datareg = disk[drvreg]->sector[fdc[drvreg].index];
468                                         //fdc[drvreg].index++;
469                                 }
470                                 if((fdc[drvreg].index + 1) >= disk[drvreg]->sector_size.sd) {
471
472                                         if(disk[drvreg]->data_crc_error && !disk[drvreg]->ignore_crc()) {
473                                                 // data crc error
474 #ifdef _FDC_DEBUG_LOG
475                                                 this->out_debug_log(_T("FDC\tEND OF SECTOR (DATA CRC ERROR)\n"));
476 #endif
477                                                 status |= FDC_ST_CRCERR;
478                                                 status &= ~FDC_ST_BUSY;
479                                                 cmdtype = 0;
480                                                 set_irq(true);
481                                         } else if(cmdtype == FDC_CMD_RD_SEC) {
482                                                 // single sector
483 #ifdef _FDC_DEBUG_LOG
484                                                 this->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
485 #endif
486                                                 status &= ~FDC_ST_BUSY;
487                                                 cmdtype = 0;
488                                                 set_irq(true);
489                                         } else {
490                                                 // multisector
491 #ifdef _FDC_DEBUG_LOG
492                                                 this->out_debug_log(_T("FDC\tEND OF SECTOR (SEARCH NEXT)\n"));
493 #endif
494                                                 register_my_event(EVENT_MULTI1, 30);
495                                                 register_my_event(EVENT_MULTI2, 60);
496                                         }
497                                 } else {
498                                         register_drq_event(1);
499                                 }
500                                 status &= ~FDC_ST_DRQ;
501                         } else if(cmdtype == FDC_CMD_RD_ADDR) {
502                                 // read address
503                                 if(fdc[drvreg].index < 6) {
504                                         datareg = disk[drvreg]->id[fdc[drvreg].index];
505                                         //fdc[drvreg].index++;
506                                 }
507                                 if((fdc[drvreg].index + 1) >= 6) {
508                                         if(disk[drvreg]->addr_crc_error && !disk[drvreg]->ignore_crc()) {
509                                                 // id crc error
510                                                 status |= FDC_ST_CRCERR;
511                                         }
512                                         status &= ~FDC_ST_BUSY;
513                                         cmdtype = 0;
514                                         set_irq(true);
515 #ifdef _FDC_DEBUG_LOG
516                                         this->out_debug_log(_T("FDC\tEND OF ID FIELD\n"));
517 #endif
518                                 } else {
519                                         register_drq_event(1);
520                                 }
521                                 status &= ~FDC_ST_DRQ;
522                         } else if(cmdtype == FDC_CMD_RD_TRK) {
523                                 // read track
524                                 if(fdc[drvreg].index < disk[drvreg]->get_track_size()) {
525                                         datareg = disk[drvreg]->track[fdc[drvreg].index];
526                                         //fdc[drvreg].index++;
527                                 }
528                                 if((fdc[drvreg].index + 1) >= disk[drvreg]->get_track_size()) {
529 #ifdef _FDC_DEBUG_LOG
530                                         this->out_debug_log(_T("FDC\tEND OF TRACK\n"));
531 #endif
532                                         status &= ~FDC_ST_BUSY;
533                                         status |= FDC_ST_LOSTDATA;
534                                         cmdtype = 0;
535                                         set_irq(true);
536                                 } else {
537                                         register_drq_event(1);
538                                 }
539                                 status &= ~FDC_ST_DRQ;
540                         }
541                         if(!(status & FDC_ST_DRQ)) {
542                                 cancel_my_event(EVENT_LOST);
543                                 set_drq(false);
544                                 fdc[drvreg].access = true;
545                         }
546                 }
547 #ifdef _FDC_DEBUG_LOG
548                 this->out_debug_log(_T("FDC\tDATA=%2x\n"), datareg);
549 #endif
550 #if defined(HAS_MB8866) || defined(HAS_MB8876)
551                 return (~datareg) & 0xff;
552 #else
553                 return datareg;
554 #endif
555         }
556         return 0xff;
557 }
558
559 void MB8877::write_dma_io8(uint32_t addr, uint32_t data)
560 {
561         write_io8(3, data);
562 }
563
564 uint32_t MB8877::read_dma_io8(uint32_t addr)
565 {
566         return read_io8(3);
567 }
568
569 void MB8877::write_signal(int id, uint32_t data, uint32_t mask)
570 {
571         if(id == SIG_MB8877_DRIVEREG) {
572                 drvreg = data & DRIVE_MASK;
573                 drive_sel = true;
574                 seekend_clock = get_current_clock();
575         } else if(id == SIG_MB8877_SIDEREG) {
576                 sidereg = (data & mask) ? 1 : 0;
577         } else if(id == SIG_MB8877_MOTOR) {
578                 motor_on = ((data & mask) != 0);
579         }
580 #if defined(USE_SOUND_FILES)
581         else if((id >= SIG_SOUNDER_MUTE) && (id < (SIG_SOUNDER_MUTE + 2))) {
582                 snd_mute = ((data & mask) != 0);
583         } else if((id >= SIG_SOUNDER_RELOAD) && (id < (SIG_SOUNDER_RELOAD + 2))) {
584                 reload_sound_data(id - SIG_SOUNDER_RELOAD);
585         }
586 #endif
587 }
588
589 uint32_t MB8877::read_signal(int ch)
590 {
591         // get access status
592         uint32_t stat = 0;
593         if(ch == SIG_MB8877_DRIVEREG) {
594                 return drvreg & DRIVE_MASK;
595         } else if(ch == SIG_MB8877_SIDEREG) {
596                 return sidereg & 1;
597         } else if(ch == SIG_MB8877_MOTOR) {
598                 return motor_on ? 1 : 0;
599         }
600         for(int i = 0; i < MAX_DRIVE; i++) {
601                 if(fdc[i].access) {
602                         stat |= 1 << i;
603                 }
604                 fdc[i].access = false;
605         }
606         if(now_search) {
607                 stat |= 1 << drvreg;
608         }
609         return stat;
610 }
611
612 void MB8877::event_callback(int event_id, int err)
613 {
614         int event = event_id >> 8;
615         int cmd = event_id & 0xff;
616         register_id[event] = -1;
617         
618         // cancel event if the command is finished or other command is executed
619         if(cmd != cmdtype) {
620                 if(event == EVENT_SEEK || event == EVENT_SEEKEND) {
621                         now_seek = false;
622                 } else if(event == EVENT_SEARCH) {
623                         now_search = false;
624                 }
625                 return;
626         }
627         switch(event) {
628         case EVENT_SEEK:
629 #ifdef _FDC_DEBUG_LOG
630                 //this->out_debug_log(_T("FDC\tSEEK START\n"));
631 #endif
632                 if(seektrk > fdc[drvreg].track) {
633                         fdc[drvreg].track++;
634 #if defined(USE_SOUND_FILES)
635                         add_sound(MB8877_SND_TYPE_SEEK);
636 #endif                  
637                 } else if(seektrk < fdc[drvreg].track) {
638                         fdc[drvreg].track--;
639 #if defined(USE_SOUND_FILES)
640                         add_sound(MB8877_SND_TYPE_SEEK);
641 #endif                  
642                 }
643                 if((cmdreg & 0x10) || ((cmdreg & 0xf0) == 0)) {
644                         trkreg = fdc[drvreg].track;
645                 }
646                 if(seektrk != fdc[drvreg].track) {
647                         register_seek_event();
648                         break;
649                 }
650                 seekend_clock = get_current_clock();
651 #ifdef HAS_MB89311
652                 if(extended_mode) {
653                         if((cmdreg & 0xf4) == 0x44) {
654                                 // read-after-seek
655                                 cmd_readdata(true);
656                                 break;
657                         } else if((cmdreg & 0xf4) == 0x64) {
658                                 // write-after-seek
659                                 cmd_writedata(true);
660                                 break;
661                         }
662                 }
663 #endif
664                 status_tmp = status;
665                 if(cmdreg & 4) {
666                         // verify
667                         status_tmp |= search_track();
668                         double time;
669                         if(status_tmp & FDC_ST_SEEKERR) {
670                                 time = get_usec_to_detect_index_hole(5, true);
671                         } else {
672                                 time = get_usec_to_next_trans_pos(true);
673                         }
674                         register_my_event(EVENT_SEEKEND, time);
675                         break;
676                 }
677         case EVENT_SEEKEND:
678                 now_seek = false;
679                 status = status_tmp;
680                 set_irq(true);
681 #ifdef _FDC_DEBUG_LOG
682                 //this->out_debug_log(_T("FDC\tSEEK END\n"));
683 #endif
684                 break;
685         case EVENT_SEARCH:
686                 now_search = false;
687                 if(status_tmp & FDC_ST_RECNFND) {
688 #if defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
689                         // for SHARP X1 Batten Tanuki
690                         if(disk[drvreg]->is_special_disk == SPECIAL_DISK_X1_BATTEN && drive_sel) {
691                                 status_tmp &= ~FDC_ST_RECNFND;
692                         }
693 #endif
694 #ifdef _FDC_DEBUG_LOG
695                         this->out_debug_log(_T("FDC\tSEARCH NG\n"));
696 #endif
697                         status = status_tmp & ~(FDC_ST_BUSY | FDC_ST_DRQ);
698                         cmdtype = 0;
699                         set_irq(true);
700                 } else if(status_tmp & FDC_ST_WRITEFAULT) {
701 #ifdef _FDC_DEBUG_LOG
702                         this->out_debug_log(_T("FDC\tWRITE PROTECTED\n"));
703 #endif
704                         status = status_tmp & ~(FDC_ST_BUSY | FDC_ST_DRQ);
705                         cmdtype = 0;
706                         set_irq(true);
707                 } else {
708                         status = status_tmp | (FDC_ST_BUSY | FDC_ST_DRQ);
709                         if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
710                                 register_lost_event(8);
711                         } else if(cmdtype == FDC_CMD_WR_TRK) {
712                                 register_lost_event(3);
713                         } else {
714                                 register_lost_event(1);
715                         }
716                         fdc[drvreg].cur_position = fdc[drvreg].next_trans_position;
717                         fdc[drvreg].prev_clock = prev_drq_clock = get_current_clock();
718                         set_drq(true);
719                         drive_sel = false;
720 #ifdef _FDC_DEBUG_LOG
721                         this->out_debug_log(_T("FDC\tSEARCH OK\n"));
722 #endif
723                 }
724                 break;
725         case EVENT_DRQ:
726                 if(status & FDC_ST_BUSY) {
727                         status |= FDC_ST_DRQ;
728                         register_lost_event(1);
729                         if((cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) && fdc[drvreg].index == 0) {
730                                 fdc[drvreg].cur_position = (fdc[drvreg].cur_position + fdc[drvreg].bytes_before_2nd_drq) % disk[drvreg]->get_track_size();
731                         } else {
732                                 fdc[drvreg].cur_position = (fdc[drvreg].cur_position + 1) % disk[drvreg]->get_track_size();
733                         }
734                         if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC ||
735                            cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC ||
736                            cmdtype == FDC_CMD_RD_TRK || cmdtype == FDC_CMD_WR_TRK  ||
737                            cmdtype == FDC_CMD_RD_ADDR) {
738                                 fdc[drvreg].index++;
739                         }
740                         fdc[drvreg].prev_clock = prev_drq_clock = get_current_clock();
741                         set_drq(true);
742 #ifdef _FDC_DEBUG_LOG
743                         //this->out_debug_log(_T("FDC\tDRQ!\n"));
744 #endif
745                 }
746                 break;
747         case EVENT_MULTI1:
748                 secreg++;
749                 break;
750         case EVENT_MULTI2:
751                 if(cmdtype == FDC_CMD_RD_MSEC) {
752                         cmd_readdata(false);
753                 } else if(cmdtype == FDC_CMD_WR_MSEC) {
754                         cmd_writedata(false);
755                 }
756                 break;
757         case EVENT_LOST:
758                 if(status & FDC_ST_BUSY) {
759 #ifdef _FDC_DEBUG_LOG
760                         this->out_debug_log(_T("FDC\tDATA LOST\n"));
761 #endif
762                         if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) {
763                                 if(fdc[drvreg].index == 0) {
764                                         status &= ~FDC_ST_BUSY;
765                                         //status &= ~FDC_ST_DRQ;
766                                         cmdtype = 0;
767                                         set_irq(true);
768                                         //set_drq(false);
769                                 } else {
770                                         write_io8(3, 0x00);
771                                 }
772                         } else {
773                                 read_io8(3);
774                         }
775                         status |= FDC_ST_LOSTDATA;
776                 }
777                 break;
778         }
779 }
780
781 // ----------------------------------------------------------------------------
782 // command
783 // ----------------------------------------------------------------------------
784
785 void MB8877::process_cmd()
786 {
787         set_irq(false);
788         set_drq(false);
789         
790 #ifdef HAS_MB89311
791         // MB89311 mode commands
792         if(cmdreg == 0xfc) {
793                 // delay (may be only in extended mode)
794                 #ifdef _FDC_DEBUG_LOG
795                         this->out_debug_log(_T("FDC\tCMD=%2xh (DELAY   ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
796                 #endif
797                 cmdtype = status = 0;
798                 return;
799         } else if(cmdreg == 0xfd) {
800                 // assign parameter
801                 #ifdef _FDC_DEBUG_LOG
802                         this->out_debug_log(_T("FDC\tCMD=%2xh (ASGN PAR) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
803                 #endif
804                 cmdtype = status = 0;
805                 return;
806         } else if(cmdreg == 0xfe) {
807                 // assign mode
808                 #ifdef _FDC_DEBUG_LOG
809                         this->out_debug_log(_T("FDC\tCMD=%2xh (ASGN MOD) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
810                 #endif
811                 extended_mode = !extended_mode;
812                 cmdtype = status = 0;
813                 return;
814         } else if(cmdreg == 0xff) {
815                 // reset (may be only in extended mode)
816                 #ifdef _FDC_DEBUG_LOG
817                         this->out_debug_log(_T("FDC\tCMD=%2xh (RESET   ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
818                 #endif
819                 cmd_forceint();
820                 extended_mode = true;
821                 return;
822         } else if(extended_mode) {
823                 // type-1
824                 if((cmdreg & 0xeb) == 0x21) {
825                         #ifdef _FDC_DEBUG_LOG
826                                 this->out_debug_log(_T("FDC\tCMD=%2xh (STEP IN ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
827                         #endif
828                         cmd_stepin();
829                         return;
830                 } else if((cmdreg & 0xeb) == 0x22) {
831                         #ifdef _FDC_DEBUG_LOG
832                                 this->out_debug_log(_T("FDC\tCMD=%2xh (STEP OUT) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
833                         #endif
834                         cmd_stepout();
835                         return;
836                 // type-2
837                 } else if((cmdreg & 0xf4) == 0x44) {
838                         // read-after-seek
839                         #ifdef _FDC_DEBUG_LOG
840                                 this->out_debug_log(_T("FDC\tCMD=%2xh (RDaftSEK) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
841                         #endif
842                         cmd_seek();
843                         return;
844                 } else if((cmdreg & 0xf4) == 0x64) {
845                         // write-after-seek
846                         #ifdef _FDC_DEBUG_LOG
847                                 this->out_debug_log(_T("FDC\tCMD=%2xh (WRaftSEK) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
848                         #endif
849                         cmd_seek();
850                         return;
851                 // type-3
852                 } else if((cmdreg & 0xfb) == 0xf1) {
853                         // format
854                         #ifdef _FDC_DEBUG_LOG
855                                 this->out_debug_log(_T("FDC\tCMD=%2xh (FORMAT  ) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, datareg, drvreg, trkreg, sidereg, secreg);
856                         #endif
857                         cmd_format();
858                         return;
859                 }
860         }
861 #endif
862         
863         // MB8877 mode commands
864 #ifdef _FDC_DEBUG_LOG
865         static const _TCHAR *cmdstr[0x10] = {
866                 _T("RESTORE "), _T("SEEK    "), _T("STEP    "), _T("STEP    "),
867                 _T("STEP IN "), _T("STEP IN "), _T("STEP OUT"), _T("STEP OUT"),
868                 _T("RD DATA "), _T("RD DATA "), _T("RD DATA "), _T("WR DATA "),
869                 _T("RD ADDR "), _T("FORCEINT"), _T("RD TRACK"), _T("WR TRACK")
870         };
871         this->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);
872 #endif
873         
874         switch(cmdreg & 0xf8) {
875         // type-1
876         case 0x00: case 0x08:
877                 cmd_restore();
878                 break;
879         case 0x10: case 0x18:
880                 cmd_seek();
881                 break;
882         case 0x20: case 0x28:
883         case 0x30: case 0x38:
884                 cmd_step();
885                 break;
886         case 0x40: case 0x48:
887         case 0x50: case 0x58:
888                 cmd_stepin();
889                 break;
890         case 0x60: case 0x68:
891         case 0x70: case 0x78:
892                 cmd_stepout();
893                 break;
894         // type-2
895         case 0x80: case 0x88:
896         case 0x90: case 0x98:
897                 cmd_readdata(true);
898                 break;
899         case 0xa0:case 0xa8:
900         case 0xb0: case 0xb8:
901                 cmd_writedata(true);
902                 break;
903         // type-3
904         case 0xc0:
905                 cmd_readaddr();
906                 break;
907         case 0xe0:
908                 cmd_readtrack();
909                 break;
910         case 0xf0:
911                 cmd_writetrack();
912                 break;
913         // type-4
914         case 0xd0: case 0xd8:
915                 cmd_forceint();
916                 break;
917         // unknown command
918         default:
919                 break;
920         }
921 }
922
923 void MB8877::cmd_restore()
924 {
925         // type-1 restore
926         cmdtype = FDC_CMD_TYPE1;
927         status = FDC_ST_HEADENG | FDC_ST_BUSY;
928         trkreg = 0xff;
929         datareg = 0;
930         
931         seektrk = 0;
932         seekvct = true;
933         
934         register_seek_event();
935 }
936
937 void MB8877::cmd_seek()
938 {
939         // type-1 seek
940         cmdtype = FDC_CMD_TYPE1;
941         status = FDC_ST_HEADENG | FDC_ST_BUSY;
942         
943         seektrk = datareg;
944         if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
945                 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
946         } else {
947                 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
948         }               
949 //      seekvct = !(datareg > trkreg);
950         seekvct = !(seektrk > fdc[drvreg].track);       
951         if(cmdreg & 4) {
952                 // verify
953                 if(trkreg != fdc[drvreg].track) {
954                         status |= FDC_ST_SEEKERR;
955                         trkreg = fdc[drvreg].track;
956                 }
957         }
958         trkreg  = datareg;
959         register_seek_event();
960 }
961
962 void MB8877::cmd_step()
963 {
964         // type-1 step
965         if(seekvct) {
966                 cmd_stepout();
967         } else {
968                 cmd_stepin();
969         }
970 }
971
972 void MB8877::cmd_stepin()
973 {
974         // type-1 step in
975         cmdtype = FDC_CMD_TYPE1;
976         status = FDC_ST_HEADENG | FDC_ST_BUSY;
977         
978         seektrk = fdc[drvreg].track + 1;
979         if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
980                 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
981         } else {
982                 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
983         }               
984         seekvct = false;
985         if(cmdreg & 4) {
986                 // verify
987                 if(trkreg != fdc[drvreg].track) {
988                         status |= FDC_ST_SEEKERR;
989                         //trkreg = fdc[drvreg].track;
990                 }
991         }
992         register_seek_event();
993 }
994
995 void MB8877::cmd_stepout()
996 {
997         // type-1 step out
998         cmdtype = FDC_CMD_TYPE1;
999         status = FDC_ST_HEADENG | FDC_ST_BUSY;
1000         
1001         seektrk = fdc[drvreg].track - 1;
1002         if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
1003                 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1004         } else {
1005                 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1006         }               
1007         seekvct = true;
1008         if(cmdreg & 4) {
1009                 // verify
1010                 if(trkreg != fdc[drvreg].track) {
1011                         status |= FDC_ST_SEEKERR;
1012                         //trkreg = fdc[drvreg].track;
1013                 }
1014         }
1015         register_seek_event();
1016 }
1017
1018 void MB8877::cmd_readdata(bool first_sector)
1019 {
1020         // type-2 read data
1021         cmdtype = (cmdreg & 0x10) ? FDC_CMD_RD_MSEC : FDC_CMD_RD_SEC;
1022         status = FDC_ST_BUSY;
1023         status_tmp = search_sector();
1024         now_search = true;
1025         
1026         double time;
1027         if(status_tmp & FDC_ST_RECNFND) {
1028                 time = get_usec_to_detect_index_hole(5, first_sector && ((cmdreg & 4) != 0));
1029         } else {
1030                 time = get_usec_to_start_trans(first_sector);
1031         }
1032         register_my_event(EVENT_SEARCH, time);
1033         cancel_my_event(EVENT_LOST);
1034 }
1035
1036 void MB8877::cmd_writedata(bool first_sector)
1037 {
1038         // type-2 write data
1039         cmdtype = (cmdreg & 0x10) ? FDC_CMD_WR_MSEC : FDC_CMD_WR_SEC;
1040         status = FDC_ST_BUSY;
1041         status_tmp = search_sector() & ~FDC_ST_RECTYPE;
1042         now_search = true;
1043         sector_changed = false;
1044         
1045         double time;
1046         if(status_tmp & FDC_ST_RECNFND) {
1047                 time = get_usec_to_detect_index_hole(5, first_sector && ((cmdreg & 4) != 0));
1048         } else if(status & FDC_ST_WRITEFAULT) {
1049                 time = (cmdreg & 4) ? DELAY_TIME : 1;
1050         } else {
1051                 time = get_usec_to_start_trans(first_sector);
1052         }
1053         register_my_event(EVENT_SEARCH, time);
1054         cancel_my_event(EVENT_LOST);
1055 }
1056
1057 void MB8877::cmd_readaddr()
1058 {
1059         // type-3 read address
1060         cmdtype = FDC_CMD_RD_ADDR;
1061         status = FDC_ST_BUSY;
1062         status_tmp = search_addr();
1063         now_search = true;
1064         
1065         double time;
1066         if(status_tmp & FDC_ST_RECNFND) {
1067                 time = get_usec_to_detect_index_hole(5, ((cmdreg & 4) != 0));
1068         } else {
1069                 time = get_usec_to_start_trans(true);
1070         }
1071         register_my_event(EVENT_SEARCH, time);
1072         cancel_my_event(EVENT_LOST);
1073 }
1074
1075 void MB8877::cmd_readtrack()
1076 {
1077         // type-3 read track
1078         cmdtype = FDC_CMD_RD_TRK;
1079         status = FDC_ST_BUSY;
1080         status_tmp = 0;
1081         
1082         disk[drvreg]->make_track(fdc[drvreg].track, sidereg);
1083         fdc[drvreg].index = 0;
1084         now_search = true;
1085         
1086         fdc[drvreg].next_trans_position = 1;
1087         double time = get_usec_to_detect_index_hole(1, ((cmdreg & 4) != 0));
1088         register_my_event(EVENT_SEARCH, time);
1089         cancel_my_event(EVENT_LOST);
1090 }
1091
1092 void MB8877::cmd_writetrack()
1093 {
1094         // type-3 write track
1095         cmdtype = FDC_CMD_WR_TRK;
1096         status = FDC_ST_BUSY;
1097         status_tmp = 0;
1098         
1099         fdc[drvreg].index = 0;
1100         fdc[drvreg].id_written = false;
1101         now_search = true;
1102         
1103         double time;
1104         if(disk[drvreg]->write_protected) {
1105                 status_tmp = FDC_ST_WRITEFAULT;
1106                 time = (cmdreg & 4) ? DELAY_TIME : 1;
1107         } else {
1108                 if(cmdreg & 4) {
1109                         // wait 15msec before raise first drq
1110                         fdc[drvreg].next_trans_position = (get_cur_position() + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
1111                         time = DELAY_TIME;
1112                 } else {
1113                         // raise first drq soon
1114                         fdc[drvreg].next_trans_position = (get_cur_position() + 1) % disk[drvreg]->get_track_size();
1115                         time = disk[drvreg]->get_usec_per_bytes(1);
1116                 }
1117                 // wait at least 3bytes before check index hole and raise second drq
1118                 fdc[drvreg].bytes_before_2nd_drq = disk[drvreg]->get_track_size() - fdc[drvreg].next_trans_position;
1119                 if(fdc[drvreg].bytes_before_2nd_drq < 3) {
1120                         fdc[drvreg].bytes_before_2nd_drq += disk[drvreg]->get_track_size();
1121                 }
1122         }
1123         register_my_event(EVENT_SEARCH, time);
1124         cancel_my_event(EVENT_LOST);
1125 }
1126
1127 #ifdef HAS_MB89311
1128 void MB8877::cmd_format()
1129 {
1130         // type-3 format (FIXME: need to implement)
1131         cmdtype = FDC_CMD_WR_TRK;
1132         status = FDC_ST_BUSY;
1133         status_tmp = 0;
1134         
1135         fdc[drvreg].index = 0;
1136         fdc[drvreg].id_written = false;
1137         now_search = true;
1138         
1139         status_tmp = FDC_ST_WRITEFAULT;
1140         double time = (cmdreg & 4) ? DELAY_TIME : 1;
1141         
1142         register_my_event(EVENT_SEARCH, time);
1143         cancel_my_event(EVENT_LOST);
1144 }
1145 #endif
1146
1147 void MB8877::cmd_forceint()
1148 {
1149         // type-4 force interrupt
1150         if(cmdtype == FDC_CMD_TYPE1) {
1151                 // abort restore/seek/step command
1152                 if(now_seek) {
1153                         if(seektrk > fdc[drvreg].track) {
1154                                 fdc[drvreg].track++;
1155                         } else if(seektrk < fdc[drvreg].track) {
1156                                 fdc[drvreg].track--;
1157                         }
1158                         if((cmdreg_tmp & 0x10) || ((cmdreg_tmp & 0xf0) == 0)) {
1159                                 trkreg = fdc[drvreg].track;
1160                         }
1161                 }
1162         } else if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1163                 // abort write sector command
1164                 if(sector_changed) {
1165                         disk[drvreg]->set_data_crc_error(false);
1166                 }
1167         } else if(cmdtype == FDC_CMD_WR_TRK) {
1168                 // abort write track command
1169                 if(!disk[drvreg]->write_protected) {
1170                         if(fdc[drvreg].id_written && !fdc[drvreg].sector_found) {
1171                                 // data mark of last sector is not written
1172                                 disk[drvreg]->set_data_mark_missing();
1173                         }
1174                         disk[drvreg]->sync_buffer();
1175                 }
1176         }
1177         now_search = now_seek = sector_changed = false;
1178         
1179 #ifdef HAS_MB89311
1180         if(cmdreg == 0xff) {
1181                 // reset command
1182                 cmdtype = FDC_CMD_TYPE1;
1183                 status = FDC_ST_HEADENG;
1184         } else {
1185 #endif
1186                 if(cmdtype == 0 || !(status & FDC_ST_BUSY)) {
1187                         cmdtype = FDC_CMD_TYPE1;
1188                         status = FDC_ST_HEADENG;
1189                 }
1190                 status &= ~FDC_ST_BUSY;
1191                 
1192                 // force interrupt if bit0-bit3 is high
1193                 if(cmdreg & 0x0f) {
1194                         set_irq(true);
1195                 }
1196 #ifdef HAS_MB89311
1197         }
1198 #endif
1199         
1200         cancel_my_event(EVENT_SEEK);
1201         cancel_my_event(EVENT_SEEKEND);
1202         cancel_my_event(EVENT_SEARCH);
1203         cancel_my_event(EVENT_DRQ);
1204         cancel_my_event(EVENT_MULTI1);
1205         cancel_my_event(EVENT_MULTI2);
1206         cancel_my_event(EVENT_LOST);
1207 }
1208
1209 // ----------------------------------------------------------------------------
1210 // media handler
1211 // ----------------------------------------------------------------------------
1212
1213 uint8_t MB8877::search_track()
1214 {
1215         // get track
1216         int track = fdc[drvreg].track;
1217         if(!disk[drvreg]->get_track(track, sidereg)){
1218                 return FDC_ST_SEEKERR;
1219         }
1220         
1221         // verify track number
1222         if(disk[drvreg]->ignore_crc()) {
1223                 for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
1224                         disk[drvreg]->get_sector(-1, -1, i);
1225                         if(disk[drvreg]->id[0] == trkreg) {
1226                                 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[i] + 4 + 2;
1227                                 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[i];
1228                                 return 0;
1229                         }
1230                 }
1231         } else {
1232                 for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
1233                         disk[drvreg]->get_sector(-1, -1, i);
1234                         if(disk[drvreg]->id[0] == trkreg && !disk[drvreg]->addr_crc_error) {
1235                                 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[i] + 4 + 2;
1236                                 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[i];
1237                                 return 0;
1238                         }
1239                 }
1240                 for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
1241                         disk[drvreg]->get_sector(-1, -1, i);
1242                         if(disk[drvreg]->id[0] == trkreg) {
1243                                 return FDC_ST_SEEKERR | FDC_ST_CRCERR;
1244                         }
1245                 }
1246         }
1247         return FDC_ST_SEEKERR;
1248 }
1249
1250 uint8_t MB8877::search_sector()
1251 {
1252         // write protect
1253         if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1254                 if(disk[drvreg]->write_protected) {
1255                         return FDC_ST_WRITEFAULT;
1256                 }
1257         }
1258         
1259         // get track
1260         int track = fdc[drvreg].track;
1261 #if defined(_FM77AV_VARIANTS)   
1262         if(disk[drvreg]->media_type == MEDIA_TYPE_2D) {
1263                 if((disk[drvreg]->drive_type == DRIVE_TYPE_2DD) ||
1264                    (disk[drvreg]->drive_type == DRIVE_TYPE_2HD) ||
1265                    (disk[drvreg]->drive_type == DRIVE_TYPE_144)) {
1266                         track >>= 1;
1267                 }
1268         }
1269 #endif
1270         if(!disk[drvreg]->get_track(track, sidereg)) {
1271                 return FDC_ST_RECNFND;
1272         }
1273         
1274         // get current position
1275         int sector_num = disk[drvreg]->sector_num.sd;
1276         int position = get_cur_position();
1277         
1278         if(position > disk[drvreg]->am1_position[sector_num - 1]) {
1279                 position -= disk[drvreg]->get_track_size();
1280         }
1281         
1282         // first scanned sector
1283         int first_sector = 0;
1284         for(int i = 0; i < sector_num; i++) {
1285                 if(position < disk[drvreg]->am1_position[i]) {
1286                         first_sector = i;
1287                         break;
1288                 }
1289         }
1290         
1291         // scan sectors
1292         for(int i = 0; i < sector_num; i++) {
1293                 // get sector
1294                 int index = (first_sector + i) % sector_num;
1295                 disk[drvreg]->get_sector(-1, -1, index);
1296                 
1297                 // check id
1298                 if(disk[drvreg]->id[0] != trkreg) {
1299                         continue;
1300                 }
1301 #if !defined(HAS_MB8866)
1302                 if((cmdreg & 2) && (disk[drvreg]->id[1] & 1) != ((cmdreg >> 3) & 1)) {
1303                         continue;
1304                 }
1305 #endif
1306                 if(disk[drvreg]->id[2] != secreg) {
1307                         continue;
1308                 }
1309                 if(disk[drvreg]->sector_size.sd == 0) {
1310                         continue;
1311                 }
1312                 if(disk[drvreg]->addr_crc_error && !disk[drvreg]->ignore_crc()) {
1313                         // id crc error
1314                         disk[drvreg]->sector_size.sd = 0;
1315                         return FDC_ST_RECNFND | FDC_ST_CRCERR;
1316                 }
1317                 
1318                 // sector found
1319                 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1320                         fdc[drvreg].next_trans_position = disk[drvreg]->id_position[index] + 4 + 2;
1321                         fdc[drvreg].bytes_before_2nd_drq = disk[drvreg]->data_position[index] - fdc[drvreg].next_trans_position;
1322                 } else {
1323                         fdc[drvreg].next_trans_position = disk[drvreg]->data_position[index] + 1;
1324                 }
1325                 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[index];
1326                 fdc[drvreg].index = 0;
1327 #ifdef _FDC_DEBUG_LOG
1328                 this->out_debug_log(_T("FDC\tSECTOR FOUND SIZE=$%04x ID=%02x %02x %02x %02x CRC=%02x %02x CRC_ERROR=%d\n"),
1329                         disk[drvreg]->sector_size.sd,
1330                         disk[drvreg]->id[0], disk[drvreg]->id[1], disk[drvreg]->id[2], disk[drvreg]->id[3],
1331                         disk[drvreg]->id[4], disk[drvreg]->id[5],
1332                         disk[drvreg]->data_crc_error ? 1 : 0);
1333 #endif
1334                 return (disk[drvreg]->deleted ? FDC_ST_RECTYPE : 0);
1335         }
1336         
1337         // sector not found
1338         disk[drvreg]->sector_size.sd = 0;
1339         return FDC_ST_RECNFND;
1340 }
1341
1342 uint8_t MB8877::search_addr()
1343 {
1344         // get track
1345         int track = fdc[drvreg].track;
1346 #if defined(_FM77AV_VARIANTS)   
1347         if(disk[drvreg]->media_type == MEDIA_TYPE_2D) {
1348                 if((disk[drvreg]->drive_type == DRIVE_TYPE_2DD) ||
1349                    (disk[drvreg]->drive_type == DRIVE_TYPE_2HD) ||
1350                    (disk[drvreg]->drive_type == DRIVE_TYPE_144)) {
1351                         track >>= 1;
1352                 }
1353         }
1354 #endif
1355         if(!disk[drvreg]->get_track(track, sidereg)) {
1356                 return FDC_ST_RECNFND;
1357         }
1358         
1359         // get current position
1360         int sector_num = disk[drvreg]->sector_num.sd;
1361         int position = get_cur_position();
1362         
1363         if(position > disk[drvreg]->am1_position[sector_num - 1]) {
1364                 position -= disk[drvreg]->get_track_size();
1365         }
1366         
1367         // first scanned sector
1368         int first_sector = 0;
1369         for(int i = 0; i < sector_num; i++) {
1370                 if(position < disk[drvreg]->am1_position[i]) {
1371                         first_sector = i;
1372                         break;
1373                 }
1374         }
1375         
1376         // get sector
1377         if(disk[drvreg]->get_sector(-1, -1, first_sector)) {
1378                 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[first_sector] + 1;
1379                 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[first_sector];
1380                 fdc[drvreg].index = 0;
1381                 secreg = disk[drvreg]->id[0];
1382                 return 0;
1383         }
1384         
1385         // sector not found
1386         disk[drvreg]->sector_size.sd = 0;
1387         return FDC_ST_RECNFND;
1388 }
1389
1390 // ----------------------------------------------------------------------------
1391 // timing
1392 // ----------------------------------------------------------------------------
1393
1394 int MB8877::get_cur_position()
1395 {
1396         return (fdc[drvreg].cur_position + disk[drvreg]->get_bytes_per_usec(get_passed_usec(fdc[drvreg].prev_clock))) % disk[drvreg]->get_track_size();
1397 }
1398
1399 double MB8877::get_usec_to_start_trans(bool first_sector)
1400 {
1401         // get time from current position
1402         double time = get_usec_to_next_trans_pos(first_sector && ((cmdreg & 4) != 0));
1403         if(first_sector && time < 60000 - get_passed_usec(seekend_clock)) {
1404                 time += disk[drvreg]->get_usec_per_track();
1405         }
1406         return time;
1407 }
1408
1409 double MB8877::get_usec_to_next_trans_pos(bool delay)
1410 {
1411         int position = get_cur_position();
1412         
1413         if(disk[drvreg]->invalid_format) {
1414                 // XXX: this track is invalid format and the calculated sector position may be incorrect.
1415                 // so use the constant period
1416                 return 50000;
1417         } else if(/*disk[drvreg]->no_skew && */!disk[drvreg]->correct_timing()) {
1418                 // XXX: this image may be a standard image or coverted from a standard image and skew may be incorrect,
1419                 // so use the period to search the next sector from the current position
1420                 int sector_num = disk[drvreg]->sector_num.sd;
1421                 int bytes = -1;
1422                 
1423                 if(position > disk[drvreg]->am1_position[sector_num - 1]) {
1424                         position -= disk[drvreg]->get_track_size();
1425                 }
1426                 for(int i = 0; i < sector_num; i++) {
1427                         if(position < disk[drvreg]->am1_position[i]) {
1428                                 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1429                                         bytes = (disk[drvreg]->id_position[i] + 4 + 2) - position;
1430                                 } else {
1431                                         bytes = (disk[drvreg]->data_position[i] + 1) - position;
1432                                 }
1433                                 if(bytes < 0) {
1434                                         bytes += disk[drvreg]->get_track_size(); // to make sure
1435                                 }
1436                                 break;
1437                         }
1438                 }
1439                 if(bytes > 0) {
1440                         return disk[drvreg]->get_usec_per_bytes(bytes);
1441                 }
1442                 return 50000;
1443         }
1444         if(delay) {
1445                 position = (position + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
1446         }
1447         int bytes = fdc[drvreg].next_trans_position - position;
1448         if(fdc[drvreg].next_am1_position < position || bytes < 0) {
1449                 bytes += disk[drvreg]->get_track_size();
1450         }
1451         double time = disk[drvreg]->get_usec_per_bytes(bytes);
1452         if(delay) {
1453                 time += DELAY_TIME;
1454         }
1455         return time;
1456 }
1457
1458 double MB8877::get_usec_to_detect_index_hole(int count, bool delay)
1459 {
1460         int position = get_cur_position();
1461         if(delay) {
1462                 position = (position + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
1463         }
1464         int bytes = disk[drvreg]->get_track_size() * count - position;
1465         if(bytes < 0) {
1466                 bytes += disk[drvreg]->get_track_size();
1467         }
1468         double time = disk[drvreg]->get_usec_per_bytes(bytes);
1469         if(delay) {
1470                 time += DELAY_TIME;
1471         }
1472         return time;
1473 }
1474
1475 // ----------------------------------------------------------------------------
1476 // irq / drq
1477 // ----------------------------------------------------------------------------
1478
1479 void MB8877::set_irq(bool val)
1480 {
1481         write_signals(&outputs_irq, val ? 0xffffffff : 0);
1482 }
1483
1484 void MB8877::set_drq(bool val)
1485 {
1486         write_signals(&outputs_drq, val ? 0xffffffff : 0);
1487 }
1488
1489 // ----------------------------------------------------------------------------
1490 // user interface
1491 // ----------------------------------------------------------------------------
1492
1493 void MB8877::open_disk(int drv, const _TCHAR* file_path, int bank)
1494 {
1495         if(drv < MAX_DRIVE) {
1496                 disk[drv]->open(file_path, bank);
1497         }
1498 }
1499
1500 void MB8877::close_disk(int drv)
1501 {
1502         if(drv < MAX_DRIVE) {
1503                 disk[drv]->close();
1504                 cmdtype = 0;
1505         }
1506 }
1507
1508 bool MB8877::is_disk_inserted(int drv)
1509 {
1510         if(drv < MAX_DRIVE) {
1511                 return disk[drv]->inserted;
1512         }
1513         return false;
1514 }
1515
1516 void MB8877::is_disk_protected(int drv, bool value)
1517 {
1518         if(drv < MAX_DRIVE) {
1519                 disk[drv]->write_protected = value;
1520         }
1521 }
1522
1523 bool MB8877::is_disk_protected(int drv)
1524 {
1525         if(drv < MAX_DRIVE) {
1526                 return disk[drv]->write_protected;
1527         }
1528         return false;
1529 }
1530
1531 void MB8877::set_drive_type(int drv, uint8_t type)
1532 {
1533         if(drv < MAX_DRIVE) {
1534                 disk[drv]->drive_type = type;
1535         }
1536 }
1537
1538 uint8_t MB8877::get_drive_type(int drv)
1539 {
1540         if(drv < MAX_DRIVE) {
1541                 return disk[drv]->drive_type;
1542         }
1543         return DRIVE_TYPE_UNK;
1544 }
1545
1546 void MB8877::set_drive_rpm(int drv, int rpm)
1547 {
1548         if(drv < MAX_DRIVE) {
1549                 disk[drv]->drive_rpm = rpm;
1550         }
1551 }
1552
1553 void MB8877::set_drive_mfm(int drv, bool mfm)
1554 {
1555         if(drv < MAX_DRIVE) {
1556                 disk[drv]->drive_mfm = mfm;
1557         }
1558 }
1559
1560 uint8_t MB8877::fdc_status()
1561 {
1562         // for each virtual machines
1563 #if defined(_FMR50) || defined(_FMR60)
1564         return disk[drvreg]->inserted ? 2 : 0;
1565 #else
1566         return 0;
1567 #endif
1568 }
1569
1570 // Set sound data.
1571 // TYPE=
1572 //     0: FDD SEEK
1573 //     1: HEAD ENGAGE (Optional?)
1574 #if defined(USE_SOUND_FILES)
1575 void MB8877::add_sound(int type)
1576 {
1577         int *p;
1578         if(type == MB8877_SND_TYPE_SEEK) {
1579                 p = snd_seek_mix_tbl;
1580         } else if(type == MB8877_SND_TYPE_HEAD) {
1581                 p = snd_head_mix_tbl;
1582         } else {
1583                 return;
1584         }
1585         touch_sound();
1586         for(int i = 0; i < MB8877_SND_TBL_MAX; i++) {
1587                 if(p[i] < 0) {
1588                         p[i] = 0;
1589                         break;
1590                 }
1591         }
1592 }
1593
1594 bool MB8877::load_sound_data(int type, const _TCHAR *pathname)
1595 {
1596         if((type < 0) || (type > 1)) return false;
1597         int16_t *data = NULL;
1598         int dst_size = 0;
1599         int id = (this_device_id << 8) + type;
1600         const _TCHAR *sp;
1601         sp = create_local_path(pathname);
1602         emu->load_sound_file(id, sp, &data, &dst_size);
1603         if((dst_size <= 0) || (data == NULL)) { // Failed
1604                 this->out_debug_log("ID=%d : Failed to load SOUND FILE for %s:%s", id, (type == 0) ? _T("SEEK") : _T("HEAD") ,pathname);
1605                 return false;
1606         } else {
1607                 int utl_size = dst_size * 2 * sizeof(int16_t);
1608                 int alloc_size = utl_size + 64;
1609                 switch(type) {
1610                 case MB8877_SND_TYPE_SEEK: // SEEK
1611                         snd_seek_data = (int16_t *)malloc(alloc_size);
1612                         memcpy(snd_seek_data, data, utl_size);
1613                         strncpy(snd_seek_name, pathname, 511);
1614                         snd_seek_samples_size = dst_size;
1615                         break;
1616                 case MB8877_SND_TYPE_HEAD: // HEAD
1617                         snd_seek_data = (int16_t *)malloc(alloc_size);
1618                         memcpy(snd_head_data, data, utl_size);
1619                         strncpy(snd_head_name, pathname, 511);
1620                         snd_head_samples_size = dst_size;
1621                         break;
1622                 default:
1623                         this->out_debug_log("ID=%d : Illegal type (%d): 0 (SEEK SOUND) or 1 (HEAD SOUND) is available.",
1624                                                                 id, type);
1625                         return false;
1626                 }
1627                 this->out_debug_log("ID=%d : Success to load SOUND FILE for %s:%s",
1628                                                         id, (type == 0) ? _T("SEEK") : _T("HEAD") ,
1629                                                         pathname);
1630         }
1631         return true;
1632 }
1633
1634 void MB8877::release_sound_data(int type)
1635 {
1636         switch(type) {
1637         case MB8877_SND_TYPE_SEEK: // SEEK
1638                 if(snd_seek_data != NULL) free(snd_seek_data);
1639                 memset(snd_seek_name, 0x00, sizeof(snd_seek_name));
1640                 snd_seek_data = NULL;
1641                 break;
1642         case MB8877_SND_TYPE_HEAD: // HEAD
1643                 if(snd_head_data != NULL) free(snd_head_data);
1644                 memset(snd_head_name, 0x00, sizeof(snd_head_name));
1645                 snd_head_data = NULL;
1646                         break;
1647         default:
1648                 break;
1649         }
1650 }
1651
1652 bool MB8877::reload_sound_data(int type)
1653 {
1654         switch(type) {
1655         case MB8877_SND_TYPE_SEEK: // SEEK
1656                 if(snd_seek_data != NULL) free(snd_seek_data);
1657                 break;
1658         case MB8877_SND_TYPE_HEAD:
1659                 if(snd_seek_data != NULL) free(snd_seek_data);
1660                 break;
1661         default:
1662                 return false;
1663                 break;
1664         }
1665         _TCHAR *p = (type == MB8877_SND_TYPE_SEEK) ? snd_seek_name : snd_head_name;
1666     _TCHAR tmps[512];
1667         strncpy(tmps, p, 511);
1668         return load_sound_data(type, tmps);
1669 }
1670
1671 void MB8877::mix_main(int32_t *dst, int count, int16_t *src, int *table, int samples)
1672 {
1673         int ptr, pp;
1674         int i, j, k;
1675         int32_t data[2];
1676         int32_t *dst_tmp;
1677         for(i=0; i < MB8877_SND_TBL_MAX; i++) {
1678                 ptr = table[i];
1679                 if(ptr >= 0) {
1680                         if(ptr < samples) {
1681                                 if(!snd_mute && (config.sound_fdd != 0)) {
1682                                         pp = ptr << 1;
1683                                         dst_tmp = dst;
1684                                         k = 0;
1685                                         for(j = 0; j < count; j++) {
1686                                                 if(ptr >= samples) {
1687                                                         break;
1688                                                 }
1689                                                 data[0] = (int32_t)src[pp + 0];
1690                                                 data[1] = (int32_t)src[pp + 1];
1691                                                 dst_tmp[k + 0] += apply_volume((int32_t)data[0], snd_level_l);
1692                                                 dst_tmp[k + 1] += apply_volume((int32_t)data[1], snd_level_r);
1693                                                 k += 2;
1694                                                 pp += 2;
1695                                                 ptr++;
1696                                         }
1697                                 } else {
1698                                         ptr += count;
1699                                 }
1700                         }
1701                         if(ptr >= samples) {
1702                                 table[i] = -1;
1703                         } else {
1704                                 table[i] = ptr;
1705                         }
1706                 }
1707         }
1708 }
1709
1710 void MB8877::mix(int32_t *buffer, int cnt)
1711 {
1712         if(snd_seek_data != NULL) mix_main(buffer, cnt, snd_seek_data, snd_seek_mix_tbl, snd_seek_samples_size);
1713         if(snd_head_data != NULL) mix_main(buffer, cnt, snd_head_data, snd_head_mix_tbl, snd_head_samples_size);
1714 }
1715
1716 void MB8877::set_volume(int ch, int decibel_l, int decibel_r)
1717 {
1718         snd_level_l = decibel_to_volume(decibel_l);
1719         snd_level_r = decibel_to_volume(decibel_r);
1720 }
1721 #endif
1722
1723 #define STATE_VERSION   7
1724
1725 void MB8877::save_state(FILEIO* state_fio)
1726 {
1727         state_fio->FputUint32(STATE_VERSION);
1728         state_fio->FputInt32(this_device_id);
1729         
1730         state_fio->Fwrite(fdc, sizeof(fdc), 1);
1731         for(int i = 0; i < MAX_DRIVE; i++) {
1732                 disk[i]->save_state(state_fio);
1733         }
1734         state_fio->FputUint8(status);
1735         state_fio->FputUint8(status_tmp);
1736         state_fio->FputUint8(cmdreg);
1737         state_fio->FputUint8(cmdreg_tmp);
1738         state_fio->FputUint8(trkreg);
1739         state_fio->FputUint8(secreg);
1740         state_fio->FputUint8(datareg);
1741         state_fio->FputUint8(drvreg);
1742         state_fio->FputUint8(sidereg);
1743         state_fio->FputUint8(cmdtype);
1744         state_fio->Fwrite(register_id, sizeof(register_id), 1);
1745         state_fio->FputBool(now_search);
1746         state_fio->FputBool(now_seek);
1747         state_fio->FputBool(sector_changed);
1748         state_fio->FputInt32(no_command);
1749         state_fio->FputInt32(seektrk);
1750         state_fio->FputBool(seekvct);
1751         state_fio->FputBool(motor_on);
1752         state_fio->FputBool(drive_sel);
1753         state_fio->FputUint32(prev_drq_clock);
1754         state_fio->FputUint32(seekend_clock);
1755 #if defined(USE_SOUND_FILES)
1756         state_fio->Fwrite(snd_seek_name, sizeof(snd_seek_name), 1);
1757         state_fio->Fwrite(snd_head_name, sizeof(snd_head_name), 1);
1758         for(int i = 0; i < MB8877_SND_TBL_MAX; i++) {
1759                 state_fio->FputInt32(snd_seek_mix_tbl[i]);
1760         }
1761         for(int i = 0; i < MB8877_SND_TBL_MAX; i++) {
1762                 state_fio->FputInt32(snd_head_mix_tbl[i]);
1763         }
1764         state_fio->FputBool(snd_mute);
1765         state_fio->FputInt32(snd_level_l);
1766         state_fio->FputInt32(snd_level_r);
1767 #endif
1768 }
1769
1770 bool MB8877::load_state(FILEIO* state_fio)
1771 {
1772         uint32_t s_version = state_fio->FgetUint32();
1773         uint32_t desired_version = STATE_VERSION;
1774         bool pending = false;
1775         if(s_version != STATE_VERSION) {
1776                 if(s_version == 5) {
1777                         pending = true;
1778                 } else {
1779                         return false;
1780                 }
1781         }
1782         if(state_fio->FgetInt32() != this_device_id) {
1783                 return false;
1784         }
1785         state_fio->Fread(fdc, sizeof(fdc), 1);
1786         for(int i = 0; i < MAX_DRIVE; i++) {
1787                 if(!disk[i]->load_state(state_fio)) {
1788                         return false;
1789                 }
1790         }
1791         status = state_fio->FgetUint8();
1792         status_tmp = state_fio->FgetUint8();
1793         cmdreg = state_fio->FgetUint8();
1794         cmdreg_tmp = state_fio->FgetUint8();
1795         trkreg = state_fio->FgetUint8();
1796         secreg = state_fio->FgetUint8();
1797         datareg = state_fio->FgetUint8();
1798         drvreg = state_fio->FgetUint8();
1799         sidereg = state_fio->FgetUint8();
1800         cmdtype = state_fio->FgetUint8();
1801         state_fio->Fread(register_id, sizeof(register_id), 1);
1802         now_search = state_fio->FgetBool();
1803         now_seek = state_fio->FgetBool();
1804         sector_changed = state_fio->FgetBool();
1805         no_command = state_fio->FgetInt32();
1806         seektrk = state_fio->FgetInt32();
1807         seekvct = state_fio->FgetBool();
1808         motor_on = state_fio->FgetBool();
1809         drive_sel = state_fio->FgetBool();
1810         prev_drq_clock = state_fio->FgetUint32();
1811         seekend_clock = state_fio->FgetUint32();
1812 #if defined(USE_SOUND_FILES)
1813         if(!pending) {
1814                 state_fio->Fread(snd_seek_name, sizeof(snd_seek_name), 1);
1815                 state_fio->Fread(snd_head_name, sizeof(snd_head_name), 1);
1816                 for(int i = 0; i < MB8877_SND_TBL_MAX; i++) {
1817                         snd_seek_mix_tbl[i] = state_fio->FgetInt32();
1818                 }
1819                 for(int i = 0; i < MB8877_SND_TBL_MAX; i++) {
1820                         snd_head_mix_tbl[i] = state_fio->FgetInt32();
1821                 }
1822                 snd_mute = state_fio->FgetBool();
1823                 snd_level_l = state_fio->FgetInt32();
1824                 snd_level_r = state_fio->FgetInt32();
1825                 if(snd_seek_data != NULL) free(snd_seek_data);
1826                 if(snd_head_data != NULL) free(snd_head_data);
1827                 if(strlen(snd_seek_name) > 0) {
1828                         _TCHAR tmps[512];
1829                         strncpy(tmps, snd_seek_name, 511);
1830                         load_sound_data(MB8877_SND_TYPE_SEEK, (const _TCHAR *)tmps);
1831                 }
1832                 if(strlen(snd_head_name) > 0) {
1833                         _TCHAR tmps[512];
1834                         strncpy(tmps, snd_head_name, 511);
1835                         load_sound_data(MB8877_SND_TYPE_HEAD, (const _TCHAR *)tmps);
1836                 }
1837         }
1838 #endif
1839         //touch_sound();
1840         return true;
1841 }
1842