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 < 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 #if defined(HAS_MB8866) || defined(HAS_MB8876)
165 cmdreg = (~data) & 0xff;
174 #if defined(HAS_MB8866) || defined(HAS_MB8876)
175 trkreg = (~data) & 0xff;
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) {
188 #if defined(HAS_MB8866) || defined(HAS_MB8876)
189 secreg = (~data) & 0xff;
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) {
202 #if defined(HAS_MB8866) || defined(HAS_MB8876)
203 datareg = (~data) & 0xff;
208 _stat = ((status & FDC_ST_DRQ) && !now_search);
209 if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
210 _stat = (_stat && motor_on);
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;
222 disk[drvreg]->set_deleted((cmdreg & 1) != 0);
224 status |= FDC_ST_WRITEFAULT;
225 status &= ~FDC_ST_BUSY;
229 //fdc[drvreg].index++;
231 if((fdc[drvreg].index + 1) >= disk[drvreg]->sector_size.sd) {
232 if(cmdtype == FDC_CMD_WR_SEC) {
234 #ifdef _FDC_DEBUG_LOG
235 this->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
237 status &= ~FDC_ST_BUSY;
242 #ifdef _FDC_DEBUG_LOG
243 this->out_debug_log(_T("FDC\tEND OF SECTOR (SEARCH NEXT)\n"));
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
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);
254 register_drq_event(1);
257 status &= ~FDC_ST_DRQ;
258 } else if(cmdtype == FDC_CMD_WR_TRK) {
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;
268 if(fdc[drvreg].side != sidereg) {
269 fdc[drvreg].side_changed = true;
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) {
279 if(!fdc[drvreg].id_written) {
280 // insert new sector with data crc error
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];
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);
299 fdc[drvreg].id_written = false;
301 // data mark of current sector is not written
302 disk[drvreg]->set_data_mark_missing();
305 } else if(fdc[drvreg].id_written) {
306 if(fdc[drvreg].sector_found) {
308 if(fdc[drvreg].sector_index < fdc[drvreg].sector_length) {
309 disk[drvreg]->sector[fdc[drvreg].sector_index] = datareg;
311 fdc[drvreg].sector_index++;
312 } else if(datareg == 0xf8 || datareg == 0xfb) {
314 disk[drvreg]->set_deleted(datareg == 0xf8);
315 fdc[drvreg].sector_found = true;
318 disk[drvreg]->track[fdc[drvreg].index] = datareg;
320 status |= FDC_ST_WRITEFAULT;
321 status &= ~FDC_ST_BUSY;
322 status &= ~FDC_ST_DRQ;
326 //fdc[drvreg].index++;
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();
334 disk[drvreg]->sync_buffer();
336 status &= ~FDC_ST_BUSY;
339 } else if(status & FDC_ST_DRQ) {
340 if(fdc[drvreg].index == 0) {
341 register_drq_event(fdc[drvreg].bytes_before_2nd_drq);
343 register_drq_event(1);
346 status &= ~FDC_ST_DRQ;
348 if(!(status & FDC_ST_DRQ)) {
349 cancel_my_event(EVENT_LOST);
351 fdc[drvreg].access = true;
358 uint32_t MB8877::read_io8(uint32_t addr)
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);
375 status |= FDC_ST_NOTREADY;
377 status &= ~FDC_ST_NOTREADY;
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;
384 status &= ~FDC_ST_WRITEP;
387 status &= ~FDC_ST_WRITEP;
389 // track0, index hole
390 if(cmdtype == FDC_CMD_TYPE1) {
391 if(fdc[drvreg].track == 0) {
392 status |= FDC_ST_TRACK00;
394 status &= ~FDC_ST_TRACK00;
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;
400 status &= ~FDC_ST_INDEX;
403 // show busy a moment
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) {
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;
427 if(!(status & FDC_ST_DRQ)) {
430 if(!(status & FDC_ST_BUSY)) {
434 #ifdef _FDC_DEBUG_LOG
435 this->out_debug_log(_T("FDC\tSTATUS=%2x\n"), val);
437 #if defined(HAS_MB8866) || defined(HAS_MB8876)
438 return (~val) & 0xff;
444 #if defined(HAS_MB8866) || defined(HAS_MB8876)
445 return (~trkreg) & 0xff;
451 #if defined(HAS_MB8866) || defined(HAS_MB8876)
452 return (~secreg) & 0xff;
458 _stat = ((status & FDC_ST_DRQ) && !now_search);
459 if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
460 _stat = (_stat && motor_on);
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++;
470 if((fdc[drvreg].index + 1) >= disk[drvreg]->sector_size.sd) {
472 if(disk[drvreg]->data_crc_error && !disk[drvreg]->ignore_crc()) {
474 #ifdef _FDC_DEBUG_LOG
475 this->out_debug_log(_T("FDC\tEND OF SECTOR (DATA CRC ERROR)\n"));
477 status |= FDC_ST_CRCERR;
478 status &= ~FDC_ST_BUSY;
481 } else if(cmdtype == FDC_CMD_RD_SEC) {
483 #ifdef _FDC_DEBUG_LOG
484 this->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
486 status &= ~FDC_ST_BUSY;
491 #ifdef _FDC_DEBUG_LOG
492 this->out_debug_log(_T("FDC\tEND OF SECTOR (SEARCH NEXT)\n"));
494 register_my_event(EVENT_MULTI1, 30);
495 register_my_event(EVENT_MULTI2, 60);
498 register_drq_event(1);
500 status &= ~FDC_ST_DRQ;
501 } else if(cmdtype == FDC_CMD_RD_ADDR) {
503 if(fdc[drvreg].index < 6) {
504 datareg = disk[drvreg]->id[fdc[drvreg].index];
505 //fdc[drvreg].index++;
507 if((fdc[drvreg].index + 1) >= 6) {
508 if(disk[drvreg]->addr_crc_error && !disk[drvreg]->ignore_crc()) {
510 status |= FDC_ST_CRCERR;
512 status &= ~FDC_ST_BUSY;
515 #ifdef _FDC_DEBUG_LOG
516 this->out_debug_log(_T("FDC\tEND OF ID FIELD\n"));
519 register_drq_event(1);
521 status &= ~FDC_ST_DRQ;
522 } else if(cmdtype == FDC_CMD_RD_TRK) {
524 if(fdc[drvreg].index < disk[drvreg]->get_track_size()) {
525 datareg = disk[drvreg]->track[fdc[drvreg].index];
526 //fdc[drvreg].index++;
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"));
532 status &= ~FDC_ST_BUSY;
533 status |= FDC_ST_LOSTDATA;
537 register_drq_event(1);
539 status &= ~FDC_ST_DRQ;
541 if(!(status & FDC_ST_DRQ)) {
542 cancel_my_event(EVENT_LOST);
544 fdc[drvreg].access = true;
547 #ifdef _FDC_DEBUG_LOG
548 this->out_debug_log(_T("FDC\tDATA=%2x\n"), datareg);
550 #if defined(HAS_MB8866) || defined(HAS_MB8876)
551 return (~datareg) & 0xff;
559 void MB8877::write_dma_io8(uint32_t addr, uint32_t data)
564 uint32_t MB8877::read_dma_io8(uint32_t addr)
569 void MB8877::write_signal(int id, uint32_t data, uint32_t mask)
571 if(id == SIG_MB8877_DRIVEREG) {
572 drvreg = data & DRIVE_MASK;
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);
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);
589 uint32_t MB8877::read_signal(int ch)
593 if(ch == SIG_MB8877_DRIVEREG) {
594 return drvreg & DRIVE_MASK;
595 } else if(ch == SIG_MB8877_SIDEREG) {
597 } else if(ch == SIG_MB8877_MOTOR) {
598 return motor_on ? 1 : 0;
600 for(int i = 0; i < MAX_DRIVE; i++) {
604 fdc[i].access = false;
612 void MB8877::event_callback(int event_id, int err)
614 int event = event_id >> 8;
615 int cmd = event_id & 0xff;
616 register_id[event] = -1;
618 // cancel event if the command is finished or other command is executed
620 if(event == EVENT_SEEK || event == EVENT_SEEKEND) {
622 } else if(event == EVENT_SEARCH) {
629 #ifdef _FDC_DEBUG_LOG
630 //this->out_debug_log(_T("FDC\tSEEK START\n"));
632 if(seektrk > fdc[drvreg].track) {
634 #if defined(USE_SOUND_FILES)
635 add_sound(MB8877_SND_TYPE_SEEK);
637 } else if(seektrk < fdc[drvreg].track) {
639 #if defined(USE_SOUND_FILES)
640 add_sound(MB8877_SND_TYPE_SEEK);
643 if((cmdreg & 0x10) || ((cmdreg & 0xf0) == 0)) {
644 trkreg = fdc[drvreg].track;
646 if(seektrk != fdc[drvreg].track) {
647 register_seek_event();
650 seekend_clock = get_current_clock();
653 if((cmdreg & 0xf4) == 0x44) {
657 } else if((cmdreg & 0xf4) == 0x64) {
667 status_tmp |= search_track();
669 if(status_tmp & FDC_ST_SEEKERR) {
670 time = get_usec_to_detect_index_hole(5, true);
672 time = get_usec_to_next_trans_pos(true);
674 register_my_event(EVENT_SEEKEND, time);
681 #ifdef _FDC_DEBUG_LOG
682 //this->out_debug_log(_T("FDC\tSEEK END\n"));
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;
694 #ifdef _FDC_DEBUG_LOG
695 this->out_debug_log(_T("FDC\tSEARCH NG\n"));
697 status = status_tmp & ~(FDC_ST_BUSY | FDC_ST_DRQ);
700 } else if(status_tmp & FDC_ST_WRITEFAULT) {
701 #ifdef _FDC_DEBUG_LOG
702 this->out_debug_log(_T("FDC\tWRITE PROTECTED\n"));
704 status = status_tmp & ~(FDC_ST_BUSY | FDC_ST_DRQ);
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);
714 register_lost_event(1);
716 fdc[drvreg].cur_position = fdc[drvreg].next_trans_position;
717 fdc[drvreg].prev_clock = prev_drq_clock = get_current_clock();
720 #ifdef _FDC_DEBUG_LOG
721 this->out_debug_log(_T("FDC\tSEARCH OK\n"));
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();
732 fdc[drvreg].cur_position = (fdc[drvreg].cur_position + 1) % disk[drvreg]->get_track_size();
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) {
740 fdc[drvreg].prev_clock = prev_drq_clock = get_current_clock();
742 #ifdef _FDC_DEBUG_LOG
743 //this->out_debug_log(_T("FDC\tDRQ!\n"));
751 if(cmdtype == FDC_CMD_RD_MSEC) {
753 } else if(cmdtype == FDC_CMD_WR_MSEC) {
754 cmd_writedata(false);
758 if(status & FDC_ST_BUSY) {
759 #ifdef _FDC_DEBUG_LOG
760 this->out_debug_log(_T("FDC\tDATA LOST\n"));
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;
775 status |= FDC_ST_LOSTDATA;
781 // ----------------------------------------------------------------------------
783 // ----------------------------------------------------------------------------
785 void MB8877::process_cmd()
791 // MB89311 mode commands
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);
797 cmdtype = status = 0;
799 } else if(cmdreg == 0xfd) {
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);
804 cmdtype = status = 0;
806 } else if(cmdreg == 0xfe) {
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);
811 extended_mode = !extended_mode;
812 cmdtype = status = 0;
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);
820 extended_mode = true;
822 } else if(extended_mode) {
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);
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);
837 } else if((cmdreg & 0xf4) == 0x44) {
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);
844 } else if((cmdreg & 0xf4) == 0x64) {
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);
852 } else if((cmdreg & 0xfb) == 0xf1) {
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);
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")
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);
874 switch(cmdreg & 0xf8) {
876 case 0x00: case 0x08:
879 case 0x10: case 0x18:
882 case 0x20: case 0x28:
883 case 0x30: case 0x38:
886 case 0x40: case 0x48:
887 case 0x50: case 0x58:
890 case 0x60: case 0x68:
891 case 0x70: case 0x78:
895 case 0x80: case 0x88:
896 case 0x90: case 0x98:
900 case 0xb0: case 0xb8:
914 case 0xd0: case 0xd8:
923 void MB8877::cmd_restore()
926 cmdtype = FDC_CMD_TYPE1;
927 status = FDC_ST_HEADENG | FDC_ST_BUSY;
934 register_seek_event();
937 void MB8877::cmd_seek()
940 cmdtype = FDC_CMD_TYPE1;
941 status = FDC_ST_HEADENG | FDC_ST_BUSY;
944 if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
945 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
947 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
949 // seekvct = !(datareg > trkreg);
950 seekvct = !(seektrk > fdc[drvreg].track);
953 if(trkreg != fdc[drvreg].track) {
954 status |= FDC_ST_SEEKERR;
955 trkreg = fdc[drvreg].track;
959 register_seek_event();
962 void MB8877::cmd_step()
972 void MB8877::cmd_stepin()
975 cmdtype = FDC_CMD_TYPE1;
976 status = FDC_ST_HEADENG | FDC_ST_BUSY;
978 seektrk = fdc[drvreg].track + 1;
979 if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
980 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
982 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
987 if(trkreg != fdc[drvreg].track) {
988 status |= FDC_ST_SEEKERR;
989 //trkreg = fdc[drvreg].track;
992 register_seek_event();
995 void MB8877::cmd_stepout()
998 cmdtype = FDC_CMD_TYPE1;
999 status = FDC_ST_HEADENG | FDC_ST_BUSY;
1001 seektrk = fdc[drvreg].track - 1;
1002 if(disk[drvreg]->media_type != MEDIA_TYPE_2D){
1003 seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
1005 seektrk = (seektrk > 41) ? 41 : (seektrk < 0) ? 0 : seektrk;
1010 if(trkreg != fdc[drvreg].track) {
1011 status |= FDC_ST_SEEKERR;
1012 //trkreg = fdc[drvreg].track;
1015 register_seek_event();
1018 void MB8877::cmd_readdata(bool first_sector)
1021 cmdtype = (cmdreg & 0x10) ? FDC_CMD_RD_MSEC : FDC_CMD_RD_SEC;
1022 status = FDC_ST_BUSY;
1023 status_tmp = search_sector();
1027 if(status_tmp & FDC_ST_RECNFND) {
1028 time = get_usec_to_detect_index_hole(5, first_sector && ((cmdreg & 4) != 0));
1030 time = get_usec_to_start_trans(first_sector);
1032 register_my_event(EVENT_SEARCH, time);
1033 cancel_my_event(EVENT_LOST);
1036 void MB8877::cmd_writedata(bool first_sector)
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;
1043 sector_changed = false;
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;
1051 time = get_usec_to_start_trans(first_sector);
1053 register_my_event(EVENT_SEARCH, time);
1054 cancel_my_event(EVENT_LOST);
1057 void MB8877::cmd_readaddr()
1059 // type-3 read address
1060 cmdtype = FDC_CMD_RD_ADDR;
1061 status = FDC_ST_BUSY;
1062 status_tmp = search_addr();
1066 if(status_tmp & FDC_ST_RECNFND) {
1067 time = get_usec_to_detect_index_hole(5, ((cmdreg & 4) != 0));
1069 time = get_usec_to_start_trans(true);
1071 register_my_event(EVENT_SEARCH, time);
1072 cancel_my_event(EVENT_LOST);
1075 void MB8877::cmd_readtrack()
1077 // type-3 read track
1078 cmdtype = FDC_CMD_RD_TRK;
1079 status = FDC_ST_BUSY;
1082 disk[drvreg]->make_track(fdc[drvreg].track, sidereg);
1083 fdc[drvreg].index = 0;
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);
1092 void MB8877::cmd_writetrack()
1094 // type-3 write track
1095 cmdtype = FDC_CMD_WR_TRK;
1096 status = FDC_ST_BUSY;
1099 fdc[drvreg].index = 0;
1100 fdc[drvreg].id_written = false;
1104 if(disk[drvreg]->write_protected) {
1105 status_tmp = FDC_ST_WRITEFAULT;
1106 time = (cmdreg & 4) ? DELAY_TIME : 1;
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();
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);
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();
1123 register_my_event(EVENT_SEARCH, time);
1124 cancel_my_event(EVENT_LOST);
1128 void MB8877::cmd_format()
1130 // type-3 format (FIXME: need to implement)
1131 cmdtype = FDC_CMD_WR_TRK;
1132 status = FDC_ST_BUSY;
1135 fdc[drvreg].index = 0;
1136 fdc[drvreg].id_written = false;
1139 status_tmp = FDC_ST_WRITEFAULT;
1140 double time = (cmdreg & 4) ? DELAY_TIME : 1;
1142 register_my_event(EVENT_SEARCH, time);
1143 cancel_my_event(EVENT_LOST);
1147 void MB8877::cmd_forceint()
1149 // type-4 force interrupt
1150 if(cmdtype == FDC_CMD_TYPE1) {
1151 // abort restore/seek/step command
1153 if(seektrk > fdc[drvreg].track) {
1154 fdc[drvreg].track++;
1155 } else if(seektrk < fdc[drvreg].track) {
1156 fdc[drvreg].track--;
1158 if((cmdreg_tmp & 0x10) || ((cmdreg_tmp & 0xf0) == 0)) {
1159 trkreg = fdc[drvreg].track;
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);
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();
1174 disk[drvreg]->sync_buffer();
1177 now_search = now_seek = sector_changed = false;
1180 if(cmdreg == 0xff) {
1182 cmdtype = FDC_CMD_TYPE1;
1183 status = FDC_ST_HEADENG;
1186 if(cmdtype == 0 || !(status & FDC_ST_BUSY)) {
1187 cmdtype = FDC_CMD_TYPE1;
1188 status = FDC_ST_HEADENG;
1190 status &= ~FDC_ST_BUSY;
1192 // force interrupt if bit0-bit3 is high
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);
1209 // ----------------------------------------------------------------------------
1211 // ----------------------------------------------------------------------------
1213 uint8_t MB8877::search_track()
1216 int track = fdc[drvreg].track;
1217 if(!disk[drvreg]->get_track(track, sidereg)){
1218 return FDC_ST_SEEKERR;
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];
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];
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;
1247 return FDC_ST_SEEKERR;
1250 uint8_t MB8877::search_sector()
1253 if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
1254 if(disk[drvreg]->write_protected) {
1255 return FDC_ST_WRITEFAULT;
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)) {
1270 if(!disk[drvreg]->get_track(track, sidereg)) {
1271 return FDC_ST_RECNFND;
1274 // get current position
1275 int sector_num = disk[drvreg]->sector_num.sd;
1276 int position = get_cur_position();
1278 if(position > disk[drvreg]->am1_position[sector_num - 1]) {
1279 position -= disk[drvreg]->get_track_size();
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]) {
1292 for(int i = 0; i < sector_num; i++) {
1294 int index = (first_sector + i) % sector_num;
1295 disk[drvreg]->get_sector(-1, -1, index);
1298 if(disk[drvreg]->id[0] != trkreg) {
1301 #if !defined(HAS_MB8866)
1302 if((cmdreg & 2) && (disk[drvreg]->id[1] & 1) != ((cmdreg >> 3) & 1)) {
1306 if(disk[drvreg]->id[2] != secreg) {
1309 if(disk[drvreg]->sector_size.sd == 0) {
1312 if(disk[drvreg]->addr_crc_error && !disk[drvreg]->ignore_crc()) {
1314 disk[drvreg]->sector_size.sd = 0;
1315 return FDC_ST_RECNFND | FDC_ST_CRCERR;
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;
1323 fdc[drvreg].next_trans_position = disk[drvreg]->data_position[index] + 1;
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);
1334 return (disk[drvreg]->deleted ? FDC_ST_RECTYPE : 0);
1338 disk[drvreg]->sector_size.sd = 0;
1339 return FDC_ST_RECNFND;
1342 uint8_t MB8877::search_addr()
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)) {
1355 if(!disk[drvreg]->get_track(track, sidereg)) {
1356 return FDC_ST_RECNFND;
1359 // get current position
1360 int sector_num = disk[drvreg]->sector_num.sd;
1361 int position = get_cur_position();
1363 if(position > disk[drvreg]->am1_position[sector_num - 1]) {
1364 position -= disk[drvreg]->get_track_size();
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]) {
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];
1386 disk[drvreg]->sector_size.sd = 0;
1387 return FDC_ST_RECNFND;
1390 // ----------------------------------------------------------------------------
1392 // ----------------------------------------------------------------------------
1394 int MB8877::get_cur_position()
1396 return (fdc[drvreg].cur_position + disk[drvreg]->get_bytes_per_usec(get_passed_usec(fdc[drvreg].prev_clock))) % disk[drvreg]->get_track_size();
1399 double MB8877::get_usec_to_start_trans(bool first_sector)
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();
1409 double MB8877::get_usec_to_next_trans_pos(bool delay)
1411 int position = get_cur_position();
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
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;
1423 if(position > disk[drvreg]->am1_position[sector_num - 1]) {
1424 position -= disk[drvreg]->get_track_size();
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;
1431 bytes = (disk[drvreg]->data_position[i] + 1) - position;
1434 bytes += disk[drvreg]->get_track_size(); // to make sure
1440 return disk[drvreg]->get_usec_per_bytes(bytes);
1445 position = (position + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
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();
1451 double time = disk[drvreg]->get_usec_per_bytes(bytes);
1458 double MB8877::get_usec_to_detect_index_hole(int count, bool delay)
1460 int position = get_cur_position();
1462 position = (position + disk[drvreg]->get_bytes_per_usec(DELAY_TIME)) % disk[drvreg]->get_track_size();
1464 int bytes = disk[drvreg]->get_track_size() * count - position;
1466 bytes += disk[drvreg]->get_track_size();
1468 double time = disk[drvreg]->get_usec_per_bytes(bytes);
1475 // ----------------------------------------------------------------------------
1477 // ----------------------------------------------------------------------------
1479 void MB8877::set_irq(bool val)
1481 write_signals(&outputs_irq, val ? 0xffffffff : 0);
1484 void MB8877::set_drq(bool val)
1486 write_signals(&outputs_drq, val ? 0xffffffff : 0);
1489 // ----------------------------------------------------------------------------
1491 // ----------------------------------------------------------------------------
1493 void MB8877::open_disk(int drv, const _TCHAR* file_path, int bank)
1495 if(drv < MAX_DRIVE) {
1496 disk[drv]->open(file_path, bank);
1500 void MB8877::close_disk(int drv)
1502 if(drv < MAX_DRIVE) {
1508 bool MB8877::is_disk_inserted(int drv)
1510 if(drv < MAX_DRIVE) {
1511 return disk[drv]->inserted;
1516 void MB8877::is_disk_protected(int drv, bool value)
1518 if(drv < MAX_DRIVE) {
1519 disk[drv]->write_protected = value;
1523 bool MB8877::is_disk_protected(int drv)
1525 if(drv < MAX_DRIVE) {
1526 return disk[drv]->write_protected;
1531 void MB8877::set_drive_type(int drv, uint8_t type)
1533 if(drv < MAX_DRIVE) {
1534 disk[drv]->drive_type = type;
1538 uint8_t MB8877::get_drive_type(int drv)
1540 if(drv < MAX_DRIVE) {
1541 return disk[drv]->drive_type;
1543 return DRIVE_TYPE_UNK;
1546 void MB8877::set_drive_rpm(int drv, int rpm)
1548 if(drv < MAX_DRIVE) {
1549 disk[drv]->drive_rpm = rpm;
1553 void MB8877::set_drive_mfm(int drv, bool mfm)
1555 if(drv < MAX_DRIVE) {
1556 disk[drv]->drive_mfm = mfm;
1560 uint8_t MB8877::fdc_status()
1562 // for each virtual machines
1563 #if defined(_FMR50) || defined(_FMR60)
1564 return disk[drvreg]->inserted ? 2 : 0;
1573 // 1: HEAD ENGAGE (Optional?)
1574 #if defined(USE_SOUND_FILES)
1575 void MB8877::add_sound(int type)
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;
1586 for(int i = 0; i < MB8877_SND_TBL_MAX; i++) {
1594 bool MB8877::load_sound_data(int type, const _TCHAR *pathname)
1596 if((type < 0) || (type > 1)) return false;
1597 int16_t *data = NULL;
1599 int id = (this_device_id << 8) + type;
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);
1607 int utl_size = dst_size * 2 * sizeof(int16_t);
1608 int alloc_size = utl_size + 64;
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;
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;
1623 this->out_debug_log("ID=%d : Illegal type (%d): 0 (SEEK SOUND) or 1 (HEAD SOUND) is available.",
1627 this->out_debug_log("ID=%d : Success to load SOUND FILE for %s:%s",
1628 id, (type == 0) ? _T("SEEK") : _T("HEAD") ,
1634 void MB8877::release_sound_data(int 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;
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;
1652 bool MB8877::reload_sound_data(int type)
1655 case MB8877_SND_TYPE_SEEK: // SEEK
1656 if(snd_seek_data != NULL) free(snd_seek_data);
1658 case MB8877_SND_TYPE_HEAD:
1659 if(snd_seek_data != NULL) free(snd_seek_data);
1665 _TCHAR *p = (type == MB8877_SND_TYPE_SEEK) ? snd_seek_name : snd_head_name;
1667 strncpy(tmps, p, 511);
1668 return load_sound_data(type, tmps);
1671 void MB8877::mix_main(int32_t *dst, int count, int16_t *src, int *table, int samples)
1677 for(i=0; i < MB8877_SND_TBL_MAX; i++) {
1681 if(!snd_mute && (config.sound_fdd != 0)) {
1685 for(j = 0; j < count; j++) {
1686 if(ptr >= samples) {
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);
1701 if(ptr >= samples) {
1710 void MB8877::mix(int32_t *buffer, int cnt)
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);
1716 void MB8877::set_volume(int ch, int decibel_l, int decibel_r)
1718 snd_level_l = decibel_to_volume(decibel_l);
1719 snd_level_r = decibel_to_volume(decibel_r);
1723 #define STATE_VERSION 7
1725 void MB8877::save_state(FILEIO* state_fio)
1727 state_fio->FputUint32(STATE_VERSION);
1728 state_fio->FputInt32(this_device_id);
1730 state_fio->Fwrite(fdc, sizeof(fdc), 1);
1731 for(int i = 0; i < MAX_DRIVE; i++) {
1732 disk[i]->save_state(state_fio);
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]);
1761 for(int i = 0; i < MB8877_SND_TBL_MAX; i++) {
1762 state_fio->FputInt32(snd_head_mix_tbl[i]);
1764 state_fio->FputBool(snd_mute);
1765 state_fio->FputInt32(snd_level_l);
1766 state_fio->FputInt32(snd_level_r);
1770 bool MB8877::load_state(FILEIO* state_fio)
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) {
1782 if(state_fio->FgetInt32() != this_device_id) {
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)) {
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)
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();
1819 for(int i = 0; i < MB8877_SND_TBL_MAX; i++) {
1820 snd_head_mix_tbl[i] = state_fio->FgetInt32();
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) {
1829 strncpy(tmps, snd_seek_name, 511);
1830 load_sound_data(MB8877_SND_TYPE_SEEK, (const _TCHAR *)tmps);
1832 if(strlen(snd_head_name) > 0) {
1834 strncpy(tmps, snd_head_name, 511);
1835 load_sound_data(MB8877_SND_TYPE_HEAD, (const _TCHAR *)tmps);