2 Skelton for retropc emulator
5 Author : Takeda.Toshiya
8 [ MB8877 / MB8876 / MB8866 / MB89311 ]
14 #define FDC_ST_BUSY 0x01 // busy
15 #define FDC_ST_INDEX 0x02 // index hole
16 #define FDC_ST_DRQ 0x02 // data request
17 #define FDC_ST_TRACK00 0x04 // track0
18 #define FDC_ST_LOSTDATA 0x04 // data lost
19 #define FDC_ST_CRCERR 0x08 // crc error
20 #define FDC_ST_SEEKERR 0x10 // seek error
21 #define FDC_ST_RECNFND 0x10 // sector not found
22 #define FDC_ST_HEADENG 0x20 // head engage
23 #define FDC_ST_RECTYPE 0x20 // record type
24 #define FDC_ST_WRITEFAULT 0x20 // write fault
25 #define FDC_ST_WRITEP 0x40 // write protectdc
26 #define FDC_ST_NOTREADY 0x80 // media not inserted
28 #define FDC_CMD_TYPE1 1
29 #define FDC_CMD_RD_SEC 2
30 #define FDC_CMD_RD_MSEC 3
31 #define FDC_CMD_WR_SEC 4
32 #define FDC_CMD_WR_MSEC 5
33 #define FDC_CMD_RD_ADDR 6
34 #define FDC_CMD_RD_TRK 7
35 #define FDC_CMD_WR_TRK 8
38 #define EVENT_SEEKEND 1
39 #define EVENT_SEARCH 2
41 #define EVENT_MULTI1 4
42 #define EVENT_MULTI2 5
46 #define DRIVE_MASK (MAX_DRIVE - 1)
48 #define DELAY_TIME (disk[drvreg]->drive_type == DRIVE_TYPE_2HD ? 15000 : 30000)
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
53 void MB8877::cancel_my_event(int event)
55 if(register_id[event] != -1) {
56 cancel_event(this, register_id[event]);
57 register_id[event] = -1;
61 void MB8877::register_my_event(int event, double usec)
63 cancel_my_event(event);
64 register_event(this, (event << 8) | (cmdtype & 0xff), usec, false, ®ister_id[event]);
67 void MB8877::register_seek_event()
70 cancel_my_event(EVENT_SEEK);
71 if(fdc[drvreg].track == seektrk) {
72 register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), 1, false, ®ister_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, ®ister_id[EVENT_SEEK]);
76 register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), seek_wait_lo[cmdreg & 3], false, ®ister_id[EVENT_SEEK]);
81 void MB8877::register_drq_event(int bytes)
83 double usec = disk[drvreg]->get_usec_per_bytes(bytes) - get_passed_usec(prev_drq_clock);
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)) {
93 cancel_my_event(EVENT_DRQ);
94 register_event(this, (EVENT_DRQ << 8) | (cmdtype & 0xff), usec, false, ®ister_id[EVENT_DRQ]);
97 void MB8877::register_lost_event(int bytes)
99 cancel_my_event(EVENT_LOST);
100 register_event(this, (EVENT_LOST << 8) | (cmdtype & 0xff), disk[drvreg]->get_usec_per_bytes(bytes), false, ®ister_id[EVENT_LOST]);
105 void MB8877::initialize()
107 // initialize d88 handler
108 for(int i = 0; i < MAX_DRIVE; i++) {
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);
118 memset(fdc, 0, sizeof(fdc));
123 status = cmdreg = trkreg = secreg = datareg = sidereg = cmdtype = 0;
125 prev_drq_clock = seekend_clock = 0;
128 void MB8877::release()
130 // release d88 handler
131 for(int i = 0; i < MAX_DRIVE; i++) {
142 for(int i = 0; i < MAX_DRIVE; i++) {
145 fdc[i].access = false;
147 for(int i = 0; i < (int)array_length(register_id); i++) {
150 now_search = now_seek = drive_sel = false;
153 extended_mode = true;
157 void MB8877::write_io8(uint32_t addr, uint32_t data)
164 //printf("WRITE: CMDREG to %02x\n", data);
165 #if defined(HAS_MB8866) || defined(HAS_MB8876)
166 cmdreg = (~data) & 0xff;
175 //printf("WRITE: TRKREG to %02x\n", data);
176 #if defined(HAS_MB8866) || defined(HAS_MB8876)
177 trkreg = (~data) & 0xff;
181 if((status & FDC_ST_BUSY) && (fdc[drvreg].index == 0)) {
182 // track reg is written after command starts
183 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
190 #if defined(HAS_MB8866) || defined(HAS_MB8876)
191 secreg = (~data) & 0xff;
195 if((status & FDC_ST_BUSY) && (fdc[drvreg].index == 0)) {
196 // sector reg is written after command starts
197 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
204 #if defined(HAS_MB8866) || defined(HAS_MB8876)
205 datareg = (~data) & 0xff;
210 _stat = ((status & FDC_ST_DRQ) && !now_search);
211 if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
212 _stat = (_stat && motor_on);
215 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
216 // write or multisector write
217 if(fdc[drvreg].index < disk[drvreg]->sector_size.sd) {
218 if(!disk[drvreg]->write_protected) {
219 if(disk[drvreg]->sector[fdc[drvreg].index] != datareg) {
220 disk[drvreg]->sector[fdc[drvreg].index] = datareg;
221 sector_changed = true;
224 disk[drvreg]->set_deleted((cmdreg & 1) != 0);
226 status |= FDC_ST_WRITEFAULT;
227 status &= ~FDC_ST_BUSY;
231 //fdc[drvreg].index++;
233 if((fdc[drvreg].index + 1) >= disk[drvreg]->sector_size.sd) {
234 if(cmdtype == FDC_CMD_WR_SEC) {
236 #ifdef _FDC_DEBUG_LOG
237 this->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
239 status &= ~FDC_ST_BUSY;
244 #ifdef _FDC_DEBUG_LOG
245 this->out_debug_log(_T("FDC\tEND OF SECTOR (SEARCH NEXT)\n"));
247 // 2HD: 360rpm, 10410bytes/track -> 0.06246bytes/us
248 register_my_event(EVENT_MULTI1, 30); // 0.06246bytes/us * 30us = 1.8738bytes < GAP3
249 register_my_event(EVENT_MULTI2, 60); // 0.06246bytes/us * 60us = 3.7476bytes < GAP3
251 sector_changed = false;
252 } else if(status & FDC_ST_DRQ) {
253 if(fdc[drvreg].index == 0) {
254 register_drq_event(fdc[drvreg].bytes_before_2nd_drq);
256 register_drq_event(1);
259 status &= ~FDC_ST_DRQ;
260 } else if(cmdtype == FDC_CMD_WR_TRK) {
262 if(fdc[drvreg].index < disk[drvreg]->get_track_size()) {
263 if(!disk[drvreg]->write_protected) {
264 if(fdc[drvreg].index == 0) {
265 disk[drvreg]->format_track(fdc[drvreg].track, sidereg);
266 fdc[drvreg].id_written = false;
267 fdc[drvreg].side = sidereg;
268 fdc[drvreg].side_changed = false;
270 if(fdc[drvreg].side != sidereg) {
271 fdc[drvreg].side_changed = true;
273 if(fdc[drvreg].side_changed) {
274 // abort write track because disk side is changed
275 } else if(datareg == 0xf5) {
276 // write a1h in missing clock
277 } else if(datareg == 0xf6) {
278 // write c2h in missing clock
279 } else if(datareg == 0xf7) {
281 if(!fdc[drvreg].id_written) {
282 // insert new sector with data crc error
284 uint8_t c = 0, h = 0, r = 0, n = 0;
285 fdc[drvreg].id_written = true;
286 fdc[drvreg].sector_found = false;
287 if(fdc[drvreg].index >= 4) {
288 c = disk[drvreg]->track[fdc[drvreg].index - 4];
289 h = disk[drvreg]->track[fdc[drvreg].index - 3];
290 r = disk[drvreg]->track[fdc[drvreg].index - 2];
291 n = disk[drvreg]->track[fdc[drvreg].index - 1];
293 fdc[drvreg].sector_length = 0x80 << (n & 3);
294 fdc[drvreg].sector_index = 0;
295 disk[drvreg]->insert_sector(c, h, r, n, false, true, 0xe5, fdc[drvreg].sector_length);
296 } else if(fdc[drvreg].sector_found) {
297 // clear data crc error if all sector data are written
298 if(fdc[drvreg].sector_index == fdc[drvreg].sector_length) {
299 disk[drvreg]->set_data_crc_error(false);
301 fdc[drvreg].id_written = false;
303 // data mark of current sector is not written
304 disk[drvreg]->set_data_mark_missing();
307 } else if(fdc[drvreg].id_written) {
308 if(fdc[drvreg].sector_found) {
310 if(fdc[drvreg].sector_index < fdc[drvreg].sector_length) {
311 disk[drvreg]->sector[fdc[drvreg].sector_index] = datareg;
313 fdc[drvreg].sector_index++;
314 } else if(datareg == 0xf8 || datareg == 0xfb) {
316 disk[drvreg]->set_deleted(datareg == 0xf8);
317 fdc[drvreg].sector_found = true;
320 disk[drvreg]->track[fdc[drvreg].index] = datareg;
322 status |= FDC_ST_WRITEFAULT;
323 status &= ~FDC_ST_BUSY;
324 status &= ~FDC_ST_DRQ;
328 //fdc[drvreg].index++;
330 if((fdc[drvreg].index + 1) >= disk[drvreg]->get_track_size()) {
331 if(!disk[drvreg]->write_protected) {
332 if(fdc[drvreg].id_written && !fdc[drvreg].sector_found) {
333 // data mark of last sector is not written
334 disk[drvreg]->set_data_mark_missing();
336 disk[drvreg]->sync_buffer();
338 status &= ~FDC_ST_BUSY;
341 } else if(status & FDC_ST_DRQ) {
342 if(fdc[drvreg].index == 0) {
343 register_drq_event(fdc[drvreg].bytes_before_2nd_drq);
345 register_drq_event(1);
348 status &= ~FDC_ST_DRQ;
350 if(!(status & FDC_ST_DRQ)) {
351 cancel_my_event(EVENT_LOST);
353 fdc[drvreg].access = true;
360 uint32_t MB8877::read_io8(uint32_t addr)
371 // disk not inserted, motor stop
372 _stat = !disk[drvreg]->inserted;
373 if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
374 _stat = (_stat || !motor_on);
377 status |= FDC_ST_NOTREADY;
379 status &= ~FDC_ST_NOTREADY;
382 if(cmdtype == FDC_CMD_TYPE1 || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) {
383 if(disk[drvreg]->inserted && disk[drvreg]->write_protected) {
384 status |= FDC_ST_WRITEP;
386 status &= ~FDC_ST_WRITEP;
389 status &= ~FDC_ST_WRITEP;
391 // track0, index hole
392 if(cmdtype == FDC_CMD_TYPE1) {
393 if(fdc[drvreg].track == 0) {
394 status |= FDC_ST_TRACK00;
396 status &= ~FDC_ST_TRACK00;
398 // index hole signal width is 5msec (thanks Mr.Sato)
399 if(!(status & FDC_ST_NOTREADY) && get_cur_position() < disk[drvreg]->get_bytes_per_usec(5000)) {
400 status |= FDC_ST_INDEX;
402 status &= ~FDC_ST_INDEX;
405 // show busy a moment
407 if(cmdtype == FDC_CMD_TYPE1 && !now_seek) {
408 status &= ~FDC_ST_BUSY;
409 #ifdef MB8877_NO_BUSY_AFTER_SEEK
410 #if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
411 if(disk[0]->is_special_disk != SPECIAL_DISK_FM7_XANADU2_D) {
420 if(cmdtype == 0 && !(status & FDC_ST_NOTREADY)) {
421 // MZ-2000 HuBASIC invites NOT READY status
422 if(++no_command == 16) {
423 val |= FDC_ST_NOTREADY;
429 if(!(status & FDC_ST_DRQ)) {
432 if(!(status & FDC_ST_BUSY)) {
436 #ifdef _FDC_DEBUG_LOG
437 this->out_debug_log(_T("FDC\tSTATUS=%2x\n"), val);
439 #if defined(HAS_MB8866) || defined(HAS_MB8876)
440 return (~val) & 0xff;
446 #if defined(HAS_MB8866) || defined(HAS_MB8876)
447 return (~trkreg) & 0xff;
453 #if defined(HAS_MB8866) || defined(HAS_MB8876)
454 return (~secreg) & 0xff;
460 _stat = ((status & FDC_ST_DRQ) && !now_search);
461 if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
462 _stat = (_stat && motor_on);
465 //if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
466 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC) {
467 // read or multisector read
468 if(fdc[drvreg].index < disk[drvreg]->sector_size.sd) {
469 datareg = disk[drvreg]->sector[fdc[drvreg].index];
470 //fdc[drvreg].index++;
472 if((fdc[drvreg].index + 1) >= disk[drvreg]->sector_size.sd) {
474 if(disk[drvreg]->data_crc_error && !disk[drvreg]->ignore_crc()) {
476 #ifdef _FDC_DEBUG_LOG
477 this->out_debug_log(_T("FDC\tEND OF SECTOR (DATA CRC ERROR)\n"));
479 status |= FDC_ST_CRCERR;
480 status &= ~FDC_ST_BUSY;
483 } else if(cmdtype == FDC_CMD_RD_SEC) {
485 #ifdef _FDC_DEBUG_LOG
486 this->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
488 status &= ~FDC_ST_BUSY;
493 #ifdef _FDC_DEBUG_LOG
494 this->out_debug_log(_T("FDC\tEND OF SECTOR (SEARCH NEXT)\n"));
496 register_my_event(EVENT_MULTI1, 30);
497 register_my_event(EVENT_MULTI2, 60);
500 register_drq_event(1);
502 status &= ~FDC_ST_DRQ;
503 } else if(cmdtype == FDC_CMD_RD_ADDR) {
505 if(fdc[drvreg].index < 6) {
506 datareg = disk[drvreg]->id[fdc[drvreg].index];
507 //fdc[drvreg].index++;
509 if((fdc[drvreg].index + 1) >= 6) {
510 if(disk[drvreg]->addr_crc_error && !disk[drvreg]->ignore_crc()) {
512 status |= FDC_ST_CRCERR;
514 status &= ~FDC_ST_BUSY;
517 #ifdef _FDC_DEBUG_LOG
518 this->out_debug_log(_T("FDC\tEND OF ID FIELD\n"));
521 register_drq_event(1);
523 status &= ~FDC_ST_DRQ;
524 } else if(cmdtype == FDC_CMD_RD_TRK) {
526 if(fdc[drvreg].index < disk[drvreg]->get_track_size()) {
527 datareg = disk[drvreg]->track[fdc[drvreg].index];
528 //fdc[drvreg].index++;
530 if((fdc[drvreg].index + 1) >= disk[drvreg]->get_track_size()) {
531 #ifdef _FDC_DEBUG_LOG
532 this->out_debug_log(_T("FDC\tEND OF TRACK\n"));
534 status &= ~FDC_ST_BUSY;
535 status |= FDC_ST_LOSTDATA;
539 register_drq_event(1);
541 status &= ~FDC_ST_DRQ;
543 if(!(status & FDC_ST_DRQ)) {
544 cancel_my_event(EVENT_LOST);
546 fdc[drvreg].access = true;
549 #ifdef _FDC_DEBUG_LOG
550 this->out_debug_log(_T("FDC\tDATA=%2x\n"), datareg);
552 #if defined(HAS_MB8866) || defined(HAS_MB8876)
553 return (~datareg) & 0xff;
561 void MB8877::write_dma_io8(uint32_t addr, uint32_t data)
566 uint32_t MB8877::read_dma_io8(uint32_t addr)
571 void MB8877::write_signal(int id, uint32_t data, uint32_t mask)
573 if(id == SIG_MB8877_DRIVEREG) {
574 drvreg = data & DRIVE_MASK;
576 seekend_clock = get_current_clock();
577 } else if(id == SIG_MB8877_SIDEREG) {
578 sidereg = (data & mask) ? 1 : 0;
579 } else if(id == SIG_MB8877_MOTOR) {
580 motor_on = ((data & mask) != 0);
582 #if defined(USE_SOUND_FILES)
583 else if((id >= SIG_SOUNDER_MUTE) && (id < (SIG_SOUNDER_MUTE + 2))) {
584 snd_mute = ((data & mask) != 0);
585 } else if((id >= SIG_SOUNDER_RELOAD) && (id < (SIG_SOUNDER_RELOAD + 2))) {
586 reload_sound_data(id - SIG_SOUNDER_RELOAD);
591 uint32_t MB8877::read_signal(int ch)
595 if(ch == SIG_MB8877_DRIVEREG) {
596 return drvreg & DRIVE_MASK;
597 } else if(ch == SIG_MB8877_SIDEREG) {
599 } else if(ch == SIG_MB8877_MOTOR) {
600 return motor_on ? 1 : 0;
602 for(int i = 0; i < MAX_DRIVE; i++) {
606 fdc[i].access = false;
614 void MB8877::event_callback(int event_id, int err)
616 int event = event_id >> 8;
617 int cmd = event_id & 0xff;
618 register_id[event] = -1;
620 // cancel event if the command is finished or other command is executed
622 if(event == EVENT_SEEK || event == EVENT_SEEKEND) {
624 } else if(event == EVENT_SEARCH) {
631 #ifdef _FDC_DEBUG_LOG
632 //this->out_debug_log(_T("FDC\tSEEK START\n"));
634 if(seektrk > fdc[drvreg].track) {
636 #if defined(USE_SOUND_FILES)
637 add_sound(MB8877_SND_TYPE_SEEK);
639 } else if(seektrk < fdc[drvreg].track) {
641 #if defined(USE_SOUND_FILES)
642 add_sound(MB8877_SND_TYPE_SEEK);
645 //printf("TRK: %d\n", fdc[drvreg].track);
646 if((cmdreg & 0x10) || ((cmdreg & 0xf0) == 0)) {
647 trkreg = fdc[drvreg].track;
649 if(seektrk != fdc[drvreg].track) {
650 register_seek_event();
653 seekend_clock = get_current_clock();
656 if((cmdreg & 0xf4) == 0x44) {
660 } else if((cmdreg & 0xf4) == 0x64) {
670 status_tmp |= search_track();
672 if(status_tmp & FDC_ST_SEEKERR) {
673 time = get_usec_to_detect_index_hole(5, true);
675 time = get_usec_to_next_trans_pos(true);
677 register_my_event(EVENT_SEEKEND, time);
684 #ifdef _FDC_DEBUG_LOG
685 //this->out_debug_log(_T("FDC\tSEEK END\n"));
690 if(status_tmp & FDC_ST_RECNFND) {
691 #if defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
692 // for SHARP X1 Batten Tanuki
693 if(disk[drvreg]->is_special_disk == SPECIAL_DISK_X1_BATTEN && drive_sel) {
694 status_tmp &= ~FDC_ST_RECNFND;
697 #ifdef _FDC_DEBUG_LOG
698 this->out_debug_log(_T("FDC\tSEARCH NG\n"));
700 status = status_tmp & ~(FDC_ST_BUSY | FDC_ST_DRQ);
703 } else if(status_tmp & FDC_ST_WRITEFAULT) {
704 #ifdef _FDC_DEBUG_LOG
705 this->out_debug_log(_T("FDC\tWRITE PROTECTED\n"));
707 status = status_tmp & ~(FDC_ST_BUSY | FDC_ST_DRQ);
711 status = status_tmp | (FDC_ST_BUSY | FDC_ST_DRQ);
712 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
713 register_lost_event(8);
714 } else if(cmdtype == FDC_CMD_WR_TRK) {
715 register_lost_event(3);
717 register_lost_event(1);
719 fdc[drvreg].cur_position = fdc[drvreg].next_trans_position;
720 fdc[drvreg].prev_clock = prev_drq_clock = get_current_clock();
723 #ifdef _FDC_DEBUG_LOG
724 this->out_debug_log(_T("FDC\tSEARCH OK\n"));
729 if(status & FDC_ST_BUSY) {
730 status |= FDC_ST_DRQ;
731 register_lost_event(1);
732 if((cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) && fdc[drvreg].index == 0) {
733 fdc[drvreg].cur_position = (fdc[drvreg].cur_position + fdc[drvreg].bytes_before_2nd_drq) % disk[drvreg]->get_track_size();
735 fdc[drvreg].cur_position = (fdc[drvreg].cur_position + 1) % disk[drvreg]->get_track_size();
737 if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC ||
738 cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC ||
739 cmdtype == FDC_CMD_RD_TRK || cmdtype == FDC_CMD_WR_TRK ||
740 cmdtype == FDC_CMD_RD_ADDR) {
743 fdc[drvreg].prev_clock = prev_drq_clock = get_current_clock();
745 #ifdef _FDC_DEBUG_LOG
746 //this->out_debug_log(_T("FDC\tDRQ!\n"));
754 if(cmdtype == FDC_CMD_RD_MSEC) {
756 } else if(cmdtype == FDC_CMD_WR_MSEC) {
757 cmd_writedata(false);
761 if(status & FDC_ST_BUSY) {
762 #ifdef _FDC_DEBUG_LOG
763 this->out_debug_log(_T("FDC\tDATA LOST\n"));
765 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) {
766 if(fdc[drvreg].index == 0) {
767 status &= ~FDC_ST_BUSY;
768 //status &= ~FDC_ST_DRQ;
778 status |= FDC_ST_LOSTDATA;
784 // ----------------------------------------------------------------------------
786 // ----------------------------------------------------------------------------
788 void MB8877::process_cmd()
794 // MB89311 mode commands
796 // delay (may be only in extended mode)
797 #ifdef _FDC_DEBUG_LOG
798 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);
800 cmdtype = status = 0;
802 } else if(cmdreg == 0xfd) {
804 #ifdef _FDC_DEBUG_LOG
805 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);
807 cmdtype = status = 0;
809 } else if(cmdreg == 0xfe) {
811 #ifdef _FDC_DEBUG_LOG
812 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);
814 extended_mode = !extended_mode;
815 cmdtype = status = 0;
817 } else if(cmdreg == 0xff) {
818 // reset (may be only in extended mode)
819 #ifdef _FDC_DEBUG_LOG
820 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);
823 extended_mode = true;
825 } else if(extended_mode) {
827 if((cmdreg & 0xeb) == 0x21) {
828 #ifdef _FDC_DEBUG_LOG
829 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);
833 } else if((cmdreg & 0xeb) == 0x22) {
834 #ifdef _FDC_DEBUG_LOG
835 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);
840 } else if((cmdreg & 0xf4) == 0x44) {
842 #ifdef _FDC_DEBUG_LOG
843 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);
847 } else if((cmdreg & 0xf4) == 0x64) {
849 #ifdef _FDC_DEBUG_LOG
850 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);
855 } else if((cmdreg & 0xfb) == 0xf1) {
857 #ifdef _FDC_DEBUG_LOG
858 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);
866 // MB8877 mode commands
867 #ifdef _FDC_DEBUG_LOG
868 static const _TCHAR *cmdstr[0x10] = {
869 _T("RESTORE "), _T("SEEK "), _T("STEP "), _T("STEP "),
870 _T("STEP IN "), _T("STEP IN "), _T("STEP OUT"), _T("STEP OUT"),
871 _T("RD DATA "), _T("RD DATA "), _T("RD DATA "), _T("WR DATA "),
872 _T("RD ADDR "), _T("FORCEINT"), _T("RD TRACK"), _T("WR TRACK")
874 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);
877 switch(cmdreg & 0xf8) {
879 case 0x00: case 0x08:
882 case 0x10: case 0x18:
885 case 0x20: case 0x28:
886 case 0x30: case 0x38:
889 case 0x40: case 0x48:
890 case 0x50: case 0x58:
893 case 0x60: case 0x68:
894 case 0x70: case 0x78:
898 case 0x80: case 0x88:
899 case 0x90: case 0x98:
903 case 0xb0: case 0xb8:
917 case 0xd0: case 0xd8:
926 void MB8877::cmd_restore()
929 cmdtype = FDC_CMD_TYPE1;
930 status = FDC_ST_HEADENG | FDC_ST_BUSY;
937 register_seek_event();
940 void MB8877::cmd_seek()
943 cmdtype = FDC_CMD_TYPE1;
944 status = FDC_ST_HEADENG | FDC_ST_BUSY;
947 //printf("SEEK %d -> %d\n", trkreg, seektrk);
948 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || \
949 defined(_FM77AV20) || defined(_FM77AV20EX)
950 if(disk[drvreg]->drive_type != DRIVE_TYPE_2D) {
951 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
953 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
956 if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
957 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
959 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
962 // seekvct = !(datareg > trkreg);
963 seekvct = !(seektrk > fdc[drvreg].track);
966 if(trkreg != fdc[drvreg].track) {
967 status |= FDC_ST_SEEKERR;
968 trkreg = fdc[drvreg].track;
972 register_seek_event();
975 void MB8877::cmd_step()
985 void MB8877::cmd_stepin()
988 cmdtype = FDC_CMD_TYPE1;
989 status = FDC_ST_HEADENG | FDC_ST_BUSY;
991 seektrk = fdc[drvreg].track + 1;
992 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || \
993 defined(_FM77AV20) || defined(_FM77AV20EX)
994 if(disk[drvreg]->drive_type != DRIVE_TYPE_2D) {
995 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
997 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1000 if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
1001 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1003 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1009 if(trkreg != fdc[drvreg].track) {
1010 status |= FDC_ST_SEEKERR;
1011 //trkreg = fdc[drvreg].track;
1014 register_seek_event();
1017 void MB8877::cmd_stepout()
1020 cmdtype = FDC_CMD_TYPE1;
1021 status = FDC_ST_HEADENG | FDC_ST_BUSY;
1023 seektrk = fdc[drvreg].track - 1;
1024 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || \
1025 defined(_FM77AV20) || defined(_FM77AV20EX)
1026 if(disk[drvreg]->drive_type != DRIVE_TYPE_2D) {
1027 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1029 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1032 if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
1033 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1035 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1041 if(trkreg != fdc[drvreg].track) {
1042 status |= FDC_ST_SEEKERR;
1043 //trkreg = fdc[drvreg].track;
1046 register_seek_event();
1049 void MB8877::cmd_readdata(bool first_sector)
1052 cmdtype = (cmdreg & 0x10) ? FDC_CMD_RD_MSEC : FDC_CMD_RD_SEC;
1053 status = FDC_ST_BUSY;
1054 status_tmp = search_sector();
1058 if(status_tmp & FDC_ST_RECNFND) {
1059 time = get_usec_to_detect_index_hole(5, first_sector && ((cmdreg & 4) != 0));
1061 time = get_usec_to_start_trans(first_sector);
1063 register_my_event(EVENT_SEARCH, time);
1064 cancel_my_event(EVENT_LOST);
1067 void MB8877::cmd_writedata(bool first_sector)
1069 // type-2 write data
1070 cmdtype = (cmdreg & 0x10) ? FDC_CMD_WR_MSEC : FDC_CMD_WR_SEC;
1071 status = FDC_ST_BUSY;
1072 status_tmp = search_sector() & ~FDC_ST_RECTYPE;
1074 sector_changed = false;
1077 if(status_tmp & FDC_ST_RECNFND) {
1078 time = get_usec_to_detect_index_hole(5, first_sector && ((cmdreg & 4) != 0));
1079 } else if(status & FDC_ST_WRITEFAULT) {
1080 time = (cmdreg & 4) ? DELAY_TIME : 1;
1082 time = get_usec_to_start_trans(first_sector);
1084 register_my_event(EVENT_SEARCH, time);
1085 cancel_my_event(EVENT_LOST);
1088 void MB8877::cmd_readaddr()
1090 // type-3 read address
1091 cmdtype = FDC_CMD_RD_ADDR;
1092 status = FDC_ST_BUSY;
1093 status_tmp = search_addr();
1097 if(status_tmp & FDC_ST_RECNFND) {
1098 time = get_usec_to_detect_index_hole(5, ((cmdreg & 4) != 0));
1100 time = get_usec_to_start_trans(true);
1102 register_my_event(EVENT_SEARCH, time);
1103 cancel_my_event(EVENT_LOST);
1106 void MB8877::cmd_readtrack()
1108 // type-3 read track
1109 cmdtype = FDC_CMD_RD_TRK;
1110 status = FDC_ST_BUSY;
1113 disk[drvreg]->make_track(fdc[drvreg].track, sidereg);
1114 fdc[drvreg].index = 0;
1117 fdc[drvreg].next_trans_position = 1;
1118 double time = get_usec_to_detect_index_hole(1, ((cmdreg & 4) != 0));
1119 register_my_event(EVENT_SEARCH, time);
1120 cancel_my_event(EVENT_LOST);
1123 void MB8877::cmd_writetrack()
1125 // type-3 write track
1126 cmdtype = FDC_CMD_WR_TRK;
1127 status = FDC_ST_BUSY;
1130 fdc[drvreg].index = 0;
1131 fdc[drvreg].id_written = false;
1135 if(disk[drvreg]->write_protected) {
1136 status_tmp = FDC_ST_WRITEFAULT;
1137 time = (cmdreg & 4) ? DELAY_TIME : 1;
1140 // wait 15msec before raise first drq
1141 fdc[drvreg].next_trans_position = (get_cur_position() + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
1144 // raise first drq soon
1145 fdc[drvreg].next_trans_position = (get_cur_position() + 1) % disk[drvreg]->get_track_size();
1146 time = disk[drvreg]->get_usec_per_bytes(1);
1148 // wait at least 3bytes before check index hole and raise second drq
1149 fdc[drvreg].bytes_before_2nd_drq = disk[drvreg]->get_track_size() - fdc[drvreg].next_trans_position;
1150 if(fdc[drvreg].bytes_before_2nd_drq < 3) {
1151 fdc[drvreg].bytes_before_2nd_drq += disk[drvreg]->get_track_size();
1154 register_my_event(EVENT_SEARCH, time);
1155 cancel_my_event(EVENT_LOST);
1159 void MB8877::cmd_format()
1161 // type-3 format (FIXME: need to implement)
1162 cmdtype = FDC_CMD_WR_TRK;
1163 status = FDC_ST_BUSY;
1166 fdc[drvreg].index = 0;
1167 fdc[drvreg].id_written = false;
1170 status_tmp = FDC_ST_WRITEFAULT;
1171 double time = (cmdreg & 4) ? DELAY_TIME : 1;
1173 register_my_event(EVENT_SEARCH, time);
1174 cancel_my_event(EVENT_LOST);
1178 void MB8877::cmd_forceint()
1180 // type-4 force interrupt
1181 if(cmdtype == FDC_CMD_TYPE1) {
1182 // abort restore/seek/step command
1184 if(seektrk > fdc[drvreg].track) {
1185 fdc[drvreg].track++;
1186 } else if(seektrk < fdc[drvreg].track) {
1187 fdc[drvreg].track--;
1189 if((cmdreg_tmp & 0x10) || ((cmdreg_tmp & 0xf0) == 0)) {
1190 trkreg = fdc[drvreg].track;
1193 } else if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1194 // abort write sector command
1195 if(sector_changed) {
1196 disk[drvreg]->set_data_crc_error(false);
1198 } else if(cmdtype == FDC_CMD_WR_TRK) {
1199 // abort write track command
1200 if(!disk[drvreg]->write_protected) {
1201 if(fdc[drvreg].id_written && !fdc[drvreg].sector_found) {
1202 // data mark of last sector is not written
1203 disk[drvreg]->set_data_mark_missing();
1205 disk[drvreg]->sync_buffer();
1208 now_search = now_seek = sector_changed = false;
1211 if(cmdreg == 0xff) {
1213 cmdtype = FDC_CMD_TYPE1;
1214 status = FDC_ST_HEADENG;
1217 if(cmdtype == 0 || !(status & FDC_ST_BUSY)) {
1218 cmdtype = FDC_CMD_TYPE1;
1219 status = FDC_ST_HEADENG;
1221 status &= ~FDC_ST_BUSY;
1223 // force interrupt if bit0-bit3 is high
1231 cancel_my_event(EVENT_SEEK);
1232 cancel_my_event(EVENT_SEEKEND);
1233 cancel_my_event(EVENT_SEARCH);
1234 cancel_my_event(EVENT_DRQ);
1235 cancel_my_event(EVENT_MULTI1);
1236 cancel_my_event(EVENT_MULTI2);
1237 cancel_my_event(EVENT_LOST);
1240 // ----------------------------------------------------------------------------
1242 // ----------------------------------------------------------------------------
1244 uint8_t MB8877::search_track()
1247 int track = fdc[drvreg].track;
1248 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || \
1249 defined(_FM77AV20) || defined(_FM77AV20EX)
1250 if(disk[drvreg]->media_type == MEDIA_TYPE_2D) {
1251 if((disk[drvreg]->drive_type == DRIVE_TYPE_2DD) ||
1252 (disk[drvreg]->drive_type == DRIVE_TYPE_2HD) ||
1253 (disk[drvreg]->drive_type == DRIVE_TYPE_144)) {
1258 if(!disk[drvreg]->get_track(track, sidereg)){
1259 return FDC_ST_SEEKERR;
1262 // verify track number
1263 if(disk[drvreg]->ignore_crc()) {
1264 for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
1265 disk[drvreg]->get_sector(-1, -1, i);
1266 if(disk[drvreg]->id[0] == trkreg) {
1267 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[i] + 4 + 2;
1268 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[i];
1273 for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
1274 disk[drvreg]->get_sector(-1, -1, i);
1275 if(disk[drvreg]->id[0] == trkreg && !disk[drvreg]->addr_crc_error) {
1276 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[i] + 4 + 2;
1277 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[i];
1281 for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
1282 disk[drvreg]->get_sector(-1, -1, i);
1283 if(disk[drvreg]->id[0] == trkreg) {
1284 return FDC_ST_SEEKERR | FDC_ST_CRCERR;
1288 return FDC_ST_SEEKERR;
1291 uint8_t MB8877::search_sector()
1294 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1295 if(disk[drvreg]->write_protected) {
1296 return FDC_ST_WRITEFAULT;
1301 int track = fdc[drvreg].track;
1302 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || \
1303 defined(_FM77AV20) || defined(_FM77AV20EX)
1304 if(disk[drvreg]->media_type == MEDIA_TYPE_2D) {
1305 if((disk[drvreg]->drive_type == DRIVE_TYPE_2DD) ||
1306 (disk[drvreg]->drive_type == DRIVE_TYPE_2HD) ||
1307 (disk[drvreg]->drive_type == DRIVE_TYPE_144)) {
1312 if(!disk[drvreg]->get_track(track, sidereg)) {
1313 return FDC_ST_RECNFND;
1316 // get current position
1317 int sector_num = disk[drvreg]->sector_num.sd;
1318 int position = get_cur_position();
1320 if(position > disk[drvreg]->am1_position[sector_num - 1]) {
1321 position -= disk[drvreg]->get_track_size();
1324 // first scanned sector
1325 int first_sector = 0;
1326 for(int i = 0; i < sector_num; i++) {
1327 if(position < disk[drvreg]->am1_position[i]) {
1334 for(int i = 0; i < sector_num; i++) {
1336 int index = (first_sector + i) % sector_num;
1337 disk[drvreg]->get_sector(-1, -1, index);
1338 //printf("CHRN=%02x %02x %02x %02x\n", disk[drvreg]->id[0], disk[drvreg]->id[1], disk[drvreg]->id[2], disk[drvreg]->id[3]);
1340 if(disk[drvreg]->id[0] != trkreg) {
1343 #if !defined(HAS_MB8866)
1344 if((cmdreg & 2) && (disk[drvreg]->id[1] & 1) != ((cmdreg >> 3) & 1)) {
1348 if(disk[drvreg]->id[2] != secreg) {
1351 if(disk[drvreg]->sector_size.sd == 0) {
1354 if(disk[drvreg]->addr_crc_error && !disk[drvreg]->ignore_crc()) {
1356 disk[drvreg]->sector_size.sd = 0;
1357 return FDC_ST_RECNFND | FDC_ST_CRCERR;
1361 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1362 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[index] + 4 + 2;
1363 fdc[drvreg].bytes_before_2nd_drq = disk[drvreg]->data_position[index] - fdc[drvreg].next_trans_position;
1365 fdc[drvreg].next_trans_position = disk[drvreg]->data_position[index] + 1;
1367 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[index];
1368 fdc[drvreg].index = 0;
1369 #ifdef _FDC_DEBUG_LOG
1370 this->out_debug_log(_T("FDC\tSECTOR FOUND SIZE=$%04x ID=%02x %02x %02x %02x CRC=%02x %02x CRC_ERROR=%d\n"),
1371 disk[drvreg]->sector_size.sd,
1372 disk[drvreg]->id[0], disk[drvreg]->id[1], disk[drvreg]->id[2], disk[drvreg]->id[3],
1373 disk[drvreg]->id[4], disk[drvreg]->id[5],
1374 disk[drvreg]->data_crc_error ? 1 : 0);
1376 return (disk[drvreg]->deleted ? FDC_ST_RECTYPE : 0);
1380 disk[drvreg]->sector_size.sd = 0;
1381 return FDC_ST_RECNFND;
1384 uint8_t MB8877::search_addr()
1387 int track = fdc[drvreg].track;
1388 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || \
1389 defined(_FM77AV20) || defined(_FM77AV20EX)
1390 if(disk[drvreg]->media_type == MEDIA_TYPE_2D) {
1391 if((disk[drvreg]->drive_type == DRIVE_TYPE_2DD) ||
1392 (disk[drvreg]->drive_type == DRIVE_TYPE_2HD) ||
1393 (disk[drvreg]->drive_type == DRIVE_TYPE_144)) {
1398 if(!disk[drvreg]->get_track(track, sidereg)) {
1399 return FDC_ST_RECNFND;
1402 // get current position
1403 int sector_num = disk[drvreg]->sector_num.sd;
1404 int position = get_cur_position();
1406 if(position > disk[drvreg]->am1_position[sector_num - 1]) {
1407 position -= disk[drvreg]->get_track_size();
1410 // first scanned sector
1411 int first_sector = 0;
1412 for(int i = 0; i < sector_num; i++) {
1413 if(position < disk[drvreg]->am1_position[i]) {
1420 if(disk[drvreg]->get_sector(-1, -1, first_sector)) {
1421 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[first_sector] + 1;
1422 fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[first_sector];
1423 fdc[drvreg].index = 0;
1424 secreg = disk[drvreg]->id[0];
1429 disk[drvreg]->sector_size.sd = 0;
1430 return FDC_ST_RECNFND;
1433 // ----------------------------------------------------------------------------
1435 // ----------------------------------------------------------------------------
1437 int MB8877::get_cur_position()
1439 return (fdc[drvreg].cur_position + disk[drvreg]->get_bytes_per_usec(get_passed_usec(fdc[drvreg].prev_clock))) % disk[drvreg]->get_track_size();
1442 double MB8877::get_usec_to_start_trans(bool first_sector)
1444 // get time from current position
1445 double time = get_usec_to_next_trans_pos(first_sector && ((cmdreg & 4) != 0));
1446 if(first_sector && time < 60000 - get_passed_usec(seekend_clock)) {
1447 time += disk[drvreg]->get_usec_per_track();
1452 double MB8877::get_usec_to_next_trans_pos(bool delay)
1454 int position = get_cur_position();
1456 if(disk[drvreg]->invalid_format) {
1457 // XXX: this track is invalid format and the calculated sector position may be incorrect.
1458 // so use the constant period
1460 } else if(/*disk[drvreg]->no_skew && */!disk[drvreg]->correct_timing()) {
1461 // XXX: this image may be a standard image or coverted from a standard image and skew may be incorrect,
1462 // so use the period to search the next sector from the current position
1463 int sector_num = disk[drvreg]->sector_num.sd;
1466 if(position > disk[drvreg]->am1_position[sector_num - 1]) {
1467 position -= disk[drvreg]->get_track_size();
1469 for(int i = 0; i < sector_num; i++) {
1470 if(position < disk[drvreg]->am1_position[i]) {
1471 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1472 bytes = (disk[drvreg]->id_position[i] + 4 + 2) - position;
1474 bytes = (disk[drvreg]->data_position[i] + 1) - position;
1477 bytes += disk[drvreg]->get_track_size(); // to make sure
1483 return disk[drvreg]->get_usec_per_bytes(bytes);
1488 position = (position + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
1490 int bytes = fdc[drvreg].next_trans_position - position;
1491 if(fdc[drvreg].next_am1_position < position || bytes < 0) {
1492 bytes += disk[drvreg]->get_track_size();
1494 double time = disk[drvreg]->get_usec_per_bytes(bytes);
1501 double MB8877::get_usec_to_detect_index_hole(int count, bool delay)
1503 int position = get_cur_position();
1505 position = (position + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
1507 int bytes = disk[drvreg]->get_track_size() * count - position;
1509 bytes += disk[drvreg]->get_track_size();
1511 double time = disk[drvreg]->get_usec_per_bytes(bytes);
1518 // ----------------------------------------------------------------------------
1520 // ----------------------------------------------------------------------------
1522 void MB8877::set_irq(bool val)
1524 write_signals(&outputs_irq, val ? 0xffffffff : 0);
1527 void MB8877::set_drq(bool val)
1529 write_signals(&outputs_drq, val ? 0xffffffff : 0);
1532 // ----------------------------------------------------------------------------
1534 // ----------------------------------------------------------------------------
1536 void MB8877::open_disk(int drv, const _TCHAR* file_path, int bank)
1538 if(drv < MAX_DRIVE) {
1539 disk[drv]->open(file_path, bank);
1543 void MB8877::close_disk(int drv)
1545 if(drv < MAX_DRIVE) {
1551 bool MB8877::is_disk_inserted(int drv)
1553 if(drv < MAX_DRIVE) {
1554 return disk[drv]->inserted;
1559 void MB8877::is_disk_protected(int drv, bool value)
1561 if(drv < MAX_DRIVE) {
1562 disk[drv]->write_protected = value;
1566 bool MB8877::is_disk_protected(int drv)
1568 if(drv < MAX_DRIVE) {
1569 return disk[drv]->write_protected;
1574 void MB8877::set_drive_type(int drv, uint8_t type)
1576 if(drv < MAX_DRIVE) {
1577 disk[drv]->drive_type = type;
1581 uint8_t MB8877::get_drive_type(int drv)
1583 if(drv < MAX_DRIVE) {
1584 return disk[drv]->drive_type;
1586 return DRIVE_TYPE_UNK;
1589 void MB8877::set_drive_rpm(int drv, int rpm)
1591 if(drv < MAX_DRIVE) {
1592 disk[drv]->drive_rpm = rpm;
1596 void MB8877::set_drive_mfm(int drv, bool mfm)
1598 if(drv < MAX_DRIVE) {
1599 disk[drv]->drive_mfm = mfm;
1603 uint8_t MB8877::fdc_status()
1605 // for each virtual machines
1606 #if defined(_FMR50) || defined(_FMR60)
1607 return disk[drvreg]->inserted ? 2 : 0;
1616 // 1: HEAD ENGAGE (Optional?)
1617 #if defined(USE_SOUND_FILES)
1618 void MB8877::add_sound(int type)
1621 if(type == MB8877_SND_TYPE_SEEK) {
1622 p = snd_seek_mix_tbl;
1623 } else if(type == MB8877_SND_TYPE_HEAD) {
1624 p = snd_head_mix_tbl;
1629 for(int i = 0; i < MB8877_SND_TBL_MAX; i++) {
1637 bool MB8877::load_sound_data(int type, const _TCHAR *pathname)
1639 if((type < 0) || (type > 1)) return false;
1640 int16_t *data = NULL;
1642 int id = (this_device_id << 8) + type;
1644 sp = create_local_path(pathname);
1645 emu->load_sound_file(id, sp, &data, &dst_size);
1646 if((dst_size <= 0) || (data == NULL)) { // Failed
1647 this->out_debug_log("ID=%d : Failed to load SOUND FILE for %s:%s", id, (type == 0) ? _T("SEEK") : _T("HEAD") ,pathname);
1650 int utl_size = dst_size * 2 * sizeof(int16_t);
1651 int alloc_size = utl_size + 64;
1653 case MB8877_SND_TYPE_SEEK: // SEEK
1654 snd_seek_data = (int16_t *)malloc(alloc_size);
1655 memcpy(snd_seek_data, data, utl_size);
1656 strncpy(snd_seek_name, pathname, 511);
1657 snd_seek_samples_size = dst_size;
1659 case MB8877_SND_TYPE_HEAD: // HEAD
1660 snd_head_data = (int16_t *)malloc(alloc_size);
1661 memcpy(snd_head_data, data, utl_size);
1662 strncpy(snd_head_name, pathname, 511);
1663 snd_head_samples_size = dst_size;
1666 this->out_debug_log("ID=%d : Illegal type (%d): 0 (SEEK SOUND) or 1 (HEAD SOUND) is available.",
1670 this->out_debug_log("ID=%d : Success to load SOUND FILE for %s:%s",
1671 id, (type == 0) ? _T("SEEK") : _T("HEAD") ,
1677 void MB8877::release_sound_data(int type)
1680 case MB8877_SND_TYPE_SEEK: // SEEK
1681 if(snd_seek_data != NULL) free(snd_seek_data);
1682 memset(snd_seek_name, 0x00, sizeof(snd_seek_name));
1683 snd_seek_data = NULL;
1685 case MB8877_SND_TYPE_HEAD: // HEAD
1686 if(snd_head_data != NULL) free(snd_head_data);
1687 memset(snd_head_name, 0x00, sizeof(snd_head_name));
1688 snd_head_data = NULL;
1695 bool MB8877::reload_sound_data(int type)
1698 case MB8877_SND_TYPE_SEEK: // SEEK
1699 if(snd_seek_data != NULL) free(snd_seek_data);
1701 case MB8877_SND_TYPE_HEAD:
1702 if(snd_head_data != NULL) free(snd_head_data);
1708 _TCHAR *p = (type == MB8877_SND_TYPE_SEEK) ? snd_seek_name : snd_head_name;
1710 strncpy(tmps, p, 511);
1711 return load_sound_data(type, tmps);
1714 void MB8877::mix_main(int32_t *dst, int count, int16_t *src, int *table, int samples)
1720 if((dst == NULL) || (src == NULL)) return;
1721 if((count <= 0) || (samples <= 0)) return;
1722 for(i=0; i < MB8877_SND_TBL_MAX; i++) {
1726 if(!snd_mute && (config.sound_fdd != 0)) {
1730 for(j = 0; j < count; j++) {
1731 if(ptr >= samples) {
1734 data[0] = (int32_t)src[pp + 0];
1735 data[1] = (int32_t)src[pp + 1];
1736 dst_tmp[k + 0] += apply_volume((int32_t)data[0], snd_level_l);
1737 dst_tmp[k + 1] += apply_volume((int32_t)data[1], snd_level_r);
1746 if(ptr >= samples) {
1755 void MB8877::mix(int32_t *buffer, int cnt)
1757 if(snd_seek_data != NULL) mix_main(buffer, cnt, snd_seek_data, snd_seek_mix_tbl, snd_seek_samples_size);
1758 if(snd_head_data != NULL) mix_main(buffer, cnt, snd_head_data, snd_head_mix_tbl, snd_head_samples_size);
1761 void MB8877::set_volume(int ch, int decibel_l, int decibel_r)
1763 snd_level_l = decibel_to_volume(decibel_l);
1764 snd_level_r = decibel_to_volume(decibel_r);
1768 #define STATE_VERSION 7
1770 void MB8877::save_state(FILEIO* state_fio)
1772 state_fio->FputUint32(STATE_VERSION);
1773 state_fio->FputInt32(this_device_id);
1775 state_fio->Fwrite(fdc, sizeof(fdc), 1);
1776 for(int i = 0; i < MAX_DRIVE; i++) {
1777 disk[i]->save_state(state_fio);
1779 state_fio->FputUint8(status);
1780 state_fio->FputUint8(status_tmp);
1781 state_fio->FputUint8(cmdreg);
1782 state_fio->FputUint8(cmdreg_tmp);
1783 state_fio->FputUint8(trkreg);
1784 state_fio->FputUint8(secreg);
1785 state_fio->FputUint8(datareg);
1786 state_fio->FputUint8(drvreg);
1787 state_fio->FputUint8(sidereg);
1788 state_fio->FputUint8(cmdtype);
1789 state_fio->Fwrite(register_id, sizeof(register_id), 1);
1790 state_fio->FputBool(now_search);
1791 state_fio->FputBool(now_seek);
1792 state_fio->FputBool(sector_changed);
1793 state_fio->FputInt32(no_command);
1794 state_fio->FputInt32(seektrk);
1795 state_fio->FputBool(seekvct);
1796 state_fio->FputBool(motor_on);
1797 state_fio->FputBool(drive_sel);
1798 state_fio->FputUint32(prev_drq_clock);
1799 state_fio->FputUint32(seekend_clock);
1800 #if defined(USE_SOUND_FILES)
1801 state_fio->Fwrite(snd_seek_name, sizeof(snd_seek_name), 1);
1802 state_fio->Fwrite(snd_head_name, sizeof(snd_head_name), 1);
1803 for(int i = 0; i < MB8877_SND_TBL_MAX; i++) {
1804 state_fio->FputInt32(snd_seek_mix_tbl[i]);
1806 for(int i = 0; i < MB8877_SND_TBL_MAX; i++) {
1807 state_fio->FputInt32(snd_head_mix_tbl[i]);
1809 state_fio->FputBool(snd_mute);
1810 state_fio->FputInt32(snd_level_l);
1811 state_fio->FputInt32(snd_level_r);
1815 bool MB8877::load_state(FILEIO* state_fio)
1817 uint32_t s_version = state_fio->FgetUint32();
1818 //uint32_t desired_version = STATE_VERSION;
1819 bool pending = false;
1820 if(s_version != STATE_VERSION) {
1821 if(s_version == 5) {
1827 if(state_fio->FgetInt32() != this_device_id) {
1830 state_fio->Fread(fdc, sizeof(fdc), 1);
1831 for(int i = 0; i < MAX_DRIVE; i++) {
1832 if(!disk[i]->load_state(state_fio)) {
1836 status = state_fio->FgetUint8();
1837 status_tmp = state_fio->FgetUint8();
1838 cmdreg = state_fio->FgetUint8();
1839 cmdreg_tmp = state_fio->FgetUint8();
1840 trkreg = state_fio->FgetUint8();
1841 secreg = state_fio->FgetUint8();
1842 datareg = state_fio->FgetUint8();
1843 drvreg = state_fio->FgetUint8();
1844 sidereg = state_fio->FgetUint8();
1845 cmdtype = state_fio->FgetUint8();
1846 state_fio->Fread(register_id, sizeof(register_id), 1);
1847 now_search = state_fio->FgetBool();
1848 now_seek = state_fio->FgetBool();
1849 sector_changed = state_fio->FgetBool();
1850 no_command = state_fio->FgetInt32();
1851 seektrk = state_fio->FgetInt32();
1852 seekvct = state_fio->FgetBool();
1853 motor_on = state_fio->FgetBool();
1854 drive_sel = state_fio->FgetBool();
1855 prev_drq_clock = state_fio->FgetUint32();
1856 seekend_clock = state_fio->FgetUint32();
1857 #if defined(USE_SOUND_FILES)
1859 state_fio->Fread(snd_seek_name, sizeof(snd_seek_name), 1);
1860 state_fio->Fread(snd_head_name, sizeof(snd_head_name), 1);
1861 for(int i = 0; i < MB8877_SND_TBL_MAX; i++) {
1862 snd_seek_mix_tbl[i] = state_fio->FgetInt32();
1864 for(int i = 0; i < MB8877_SND_TBL_MAX; i++) {
1865 snd_head_mix_tbl[i] = state_fio->FgetInt32();
1867 snd_mute = state_fio->FgetBool();
1868 snd_level_l = state_fio->FgetInt32();
1869 snd_level_r = state_fio->FgetInt32();
1870 if(snd_seek_data != NULL) free(snd_seek_data);
1871 if(snd_head_data != NULL) free(snd_head_data);
1872 if(strlen(snd_seek_name) > 0) {
1874 strncpy(tmps, snd_seek_name, 511);
1875 load_sound_data(MB8877_SND_TYPE_SEEK, (const _TCHAR *)tmps);
1877 if(strlen(snd_head_name) > 0) {
1879 strncpy(tmps, snd_head_name, 511);
1880 load_sound_data(MB8877_SND_TYPE_HEAD, (const _TCHAR *)tmps);