Author : Takeda.Toshiya
Date : 2006.12.06 -
- [ MB8877 / MB8876 ]
+ [ MB8877 / MB8876 / MB8866 / MB89311 ]
*/
#include "mb8877.h"
#include "disk.h"
+#include "noise.h"
#define FDC_ST_BUSY 0x01 // busy
#define FDC_ST_INDEX 0x02 // index hole
#define FDC_CMD_RD_ADDR 6
#define FDC_CMD_RD_TRK 7
#define FDC_CMD_WR_TRK 8
-#define FDC_CMD_TYPE4 0x80
-
-#define EVENT_SEEK 0
-#define EVENT_SEEKEND 1
-#define EVENT_SEARCH 2
-#define EVENT_TYPE4 3
-#define EVENT_DRQ 4
-#define EVENT_MULTI1 5
-#define EVENT_MULTI2 6
-#define EVENT_LOST 7
-
-#define DRIVE_MASK (MAX_DRIVE - 1)
-
-static const int seek_wait_hi[4] = {3000, 6000, 10000, 16000};
-static const int seek_wait_lo[4] = {6000, 12000, 20000, 30000};
-
-#define CANCEL_EVENT(event) { \
- if(register_id[event] != -1) { \
- cancel_event(this, register_id[event]); \
- register_id[event] = -1; \
- } \
+
+#define EVENT_SEEK 0
+#define EVENT_SEEKEND_VERIFY 1
+#define EVENT_SEARCH 2
+#define EVENT_DRQ 3
+#define EVENT_MULTI1 4
+#define EVENT_MULTI2 5
+#define EVENT_LOST 6
+#define EVENT_END_READ_SECTOR 7
+#define EVENT_CRC_ERROR 8
+
+//#define DRIVE_MASK (MAX_DRIVE - 1)
+
+#define DELAY_AFTER_HLD (disk[drvreg]->drive_type == DRIVE_TYPE_2HD ? 15000 : 30000)
+
+static const int seek_wait_hi[4] = {3000, 6000, 10000, 16000}; // 2MHz
+static const int seek_wait_lo[4] = {6000, 12000, 20000, 30000}; // 1MHz
+
+void MB8877::cancel_my_event(int event)
+{
+ if(register_id[event] != -1) {
+ cancel_event(this, register_id[event]);
+ register_id[event] = -1;
+ }
}
-#define REGISTER_EVENT(event, usec) { \
- if(register_id[event] != -1) { \
- cancel_event(this, register_id[event]); \
- register_id[event] = -1; \
- } \
- register_event(this, (event << 8) | (cmdtype & 0xff), usec, false, ®ister_id[event]); \
+
+bool MB8877::register_my_event_with_check(int event, double usec)
+{
+ if(register_id[event] >= 0) return false;
+ register_my_event(event, usec);
+ return true;
}
-#define REGISTER_SEEK_EVENT() { \
- if(register_id[EVENT_SEEK] != -1) { \
- cancel_event(this, register_id[EVENT_SEEK]); \
- register_id[EVENT_SEEK] = -1; \
- } \
- if(disk[drvreg]->drive_type == DRIVE_TYPE_2HD) { \
- register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), seek_wait_hi[cmdreg & 3], false, ®ister_id[EVENT_SEEK]); \
- } else { \
- register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), seek_wait_lo[cmdreg & 3], false, ®ister_id[EVENT_SEEK]); \
- } \
- now_seek = after_seek = true; \
+
+void MB8877::register_my_event(int event, double usec)
+{
+ cancel_my_event(event);
+ register_event(this, (event << 8) | (cmdtype & 0xff), usec, false, ®ister_id[event]);
}
-#define REGISTER_DRQ_EVENT() { \
- double usec = disk[drvreg]->get_usec_per_bytes(1) - passed_usec(prev_drq_clock); \
- if(usec < 4) { \
- usec = 4; \
- } else if(usec > 24 && disk[drvreg]->is_special_disk == SPECIAL_DISK_X1_ALPHA) { \
- usec = 24; \
- } \
- if(register_id[EVENT_DRQ] != -1) { \
- cancel_event(this, register_id[EVENT_DRQ]); \
- register_id[EVENT_DRQ] = -1; \
- } \
- register_event(this, (EVENT_DRQ << 8) | (cmdtype & 0xff), usec, false, ®ister_id[EVENT_DRQ]); \
+
+void MB8877::register_seek_event(bool first)
+{
+ cancel_my_event(EVENT_SEEK);
+ if(fdc[drvreg].track == seektrk) {
+ register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), 300, false, ®ister_id[EVENT_SEEK]); // From XM7 v3.4L77a Wait 300uS.
+ } else if(disk[drvreg]->drive_type == DRIVE_TYPE_2HD) {
+ register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), seek_wait_hi[cmdreg & 3] - (first ? 250 : 0), false, ®ister_id[EVENT_SEEK]);
+ } else {
+ register_event(this, (EVENT_SEEK << 8) | (cmdtype & 0xff), seek_wait_lo[cmdreg & 3] - (first ? 500 : 0), false, ®ister_id[EVENT_SEEK]);
+ }
+ now_seek = true;
}
-#define REGISTER_LOST_EVENT() { \
- if(register_id[EVENT_LOST] != -1) { \
- cancel_event(this, register_id[EVENT_LOST]); \
- register_id[EVENT_LOST] = -1; \
- } \
- register_event(this, (EVENT_LOST << 8) | (cmdtype & 0xff), disk[drvreg]->get_usec_per_bytes(/*1*/2), false, ®ister_id[EVENT_LOST]); \
+
+void MB8877::register_drq_event(int bytes)
+{
+ double nusec = disk[drvreg]->get_usec_per_bytes(bytes); // For debug
+ double usec = nusec - get_passed_usec(prev_drq_clock);
+ bool nf = false;
+
+ if(usec > nusec) usec = nusec;
+ if(usec < 4) {
+ usec = 4;
+ }
+ if(config.correct_disk_timing[drvreg]) {
+ nf = true;
+ }
+ if(type_fm7) {
+ if((disk[drvreg]->is_special_disk == SPECIAL_DISK_FM7_GAMBLER)) {
+ /* (disk[drvreg]->is_special_disk == SPECIAL_DISK_FM77AV_PSYOBLADE) || */
+ nf = true;
+ }
+ }
+ if(nf) {
+ switch(disk[drvreg]->media_type) {
+ case MEDIA_TYPE_2D:
+ case MEDIA_TYPE_2DD:
+ if(usec > 7.0) usec = 7.0;
+ break;
+ case MEDIA_TYPE_2HD:
+ case MEDIA_TYPE_144:
+ case MEDIA_TYPE_UNK:
+ usec = 4.0;
+ break;
+ default:
+ usec = 4.0;
+ break;
+ }
+ }
+ if(fdc_debug_log) this->out_debug_log("DRQ REG: %dbytes %d:%d -> %f\n", bytes, get_current_clock(), prev_drq_clock, usec);
+ cancel_my_event(EVENT_DRQ);
+ register_event(this, (EVENT_DRQ << 8) | (cmdtype & 0xff), usec, false, ®ister_id[EVENT_DRQ]);
+}
+
+void MB8877::register_lost_event(int bytes)
+{
+ cancel_my_event(EVENT_LOST);
+ register_event(this, (EVENT_LOST << 8) | (cmdtype & 0xff), disk[drvreg]->get_usec_per_bytes(bytes), false, ®ister_id[EVENT_LOST]);
+}
+
+bool MB8877::check_drive(void)
+{
+ if(drvreg >= _max_drive) {
+ status = FDC_ST_NOTREADY;
+ //set_drq(false);
+ set_irq(true);
+ return false;
+ }
+ return true;
+}
+
+bool MB8877::check_drive2(void)
+{
+ if(!check_drive()) {
+ return false;
+ }
+ if(!is_disk_inserted(drvreg & 0x7f)) {
+ status = FDC_ST_NOTREADY;
+ set_irq(true);
+ //set_drq(false);
+ return false;
+ }
+ return true;
}
void MB8877::initialize()
{
- // config
- ignore_crc = config.ignore_crc;
-
+ DEVICE::initialize();
// initialize d88 handler
- for(int i = 0; i < MAX_DRIVE; i++) {
+ if(osd->check_feature(_T("MAX_DRIVE"))) {
+ _max_drive = osd->get_feature_int_value(_T("MAX_DRIVE"));
+ } else if(osd->check_feature(_T("MAX_FD"))) {
+ _max_drive = osd->get_feature_int_value(_T("MAX_FD"));
+ } else {
+ _max_drive = 1;
+ }
+
+ _drive_mask = _max_drive - 1;
+ for(int i = 0; i < _max_drive; i++) {
disk[i] = new DISK(emu);
+ disk[i]->set_device_name(_T("%s/Disk #%d"), this_device_name, i + 1);
}
- // initialize timing
- memset(fdc, 0, sizeof(fdc));
+ if(osd->check_feature(_T("MB8877_NO_BUSY_AFTER_SEEK"))) {
+ mb8877_no_busy_after_seek = true;
+ }
+ if(osd->check_feature(_T("MB8877_DELAY_AFTER_SEEK"))) {
+ mb8877_delay_after_seek = osd->get_feature_int_value(_T("MB8877_DELAY_AFTER_SEEK"));
+ }
+ //if(osd->check_feature(_T("_FDC_DEBUG_LOG"))) {
+ // fdc_debug_log = true;
+ //}
+ fdc_debug_log = config.special_debug_fdc;
+
+ if(osd->check_feature(_T("HAS_MB8866"))) {
+ type_mb8866 = true;
+ invert_registers = true;
+ set_device_name(_T("MB8866 FDC"));
+ }
+ if(osd->check_feature(_T("HAS_MB8876"))) {
+ invert_registers = true;
+ set_device_name(_T("MB8876 FDC"));
+ } else if(osd->check_feature(_T("HAS_MB89311"))) {
+ type_mb89311 = true;
+ set_device_name(_T("MB89311 FDC"));
+ } else {
+ set_device_name(_T("MB8877 FDC"));
+ }
+ if(osd->check_feature(_T("_X1")) || osd->check_feature(_T("_X1TWIN")) ||
+ osd->check_feature(_T("_X1TURBO")) || osd->check_feature(_T("_X1TURBOZ"))) {
+ type_x1 = true;
+ }
+ if(osd->check_feature(_T("_FM7")) || osd->check_feature(_T("_FM8")) ||
+ osd->check_feature(_T("_FM77_VARIANTS")) || osd->check_feature(_T("_FM77AV_VARIANTS"))) {
+ type_fm7 = true;
+ if(osd->check_feature(_T("_FM77AV40")) || osd->check_feature(_T("_FM77AV40EX")) ||
+ osd->check_feature(_T("_FM77AV40SX")) ||
+ osd->check_feature(_T("_FM77AV20")) || osd->check_feature(_T("_FM77AV20EX"))) {
+ type_fm77av_2dd = true;
+ }
+ }
+ if(osd->check_feature(_T("_FMR50"))) {
+ type_fmr50 = true;
+ }
+ if(osd->check_feature(_T("_FMR60"))) {
+ type_fmr60 = true;
+ }
+
+ // initialize noise
+ if(d_noise_seek != NULL) {
+ d_noise_seek->set_device_name(_T("Noise Player (FDD Seek)"));
+ if(!d_noise_seek->load_wav_file(_T("FDDSEEK.WAV"))) {
+ if(!d_noise_seek->load_wav_file(_T("FDDSEEK1.WAV"))) {
+ d_noise_seek->load_wav_file(_T("SEEK.WAV"));
+ }
+ }
+ d_noise_seek->set_mute(!config.sound_noise_fdd);
+ }
+ if(d_noise_head_down != NULL) {
+ d_noise_head_down->set_device_name(_T("Noise Player (FDD Head Load)"));
+ d_noise_head_down->load_wav_file(_T("HEADDOWN.WAV"));
+ d_noise_head_down->set_mute(!config.sound_noise_fdd);
+ }
+ if(d_noise_head_up != NULL) {
+ d_noise_head_up->set_device_name(_T("Noise Player (FDD Head Unload)"));
+ d_noise_head_up->load_wav_file(_T("HEADUP.WAV"));
+ d_noise_head_up->set_mute(!config.sound_noise_fdd);
+ }
// initialize fdc
- seektrk = 0;
- seekvct = true;
- status = cmdreg = trkreg = secreg = datareg = sidereg = cmdtype = 0;
- drvreg = 0;
+ memset(fdc, 0, sizeof(fdc));
+ for(int i = 0; i < 16; i++) {
+ fdc[i].track = 40; // OK?
+ fdc[i].count_immediate = false;
+ }
+// drvreg = sidereg = 0;
+ cmdtype = 0;
+// motor_on = drive_sel = false;
+ prev_drq_clock = seekend_clock = 0;
}
void MB8877::release()
{
// release d88 handler
- for(int i = 0; i < MAX_DRIVE; i++) {
+ for(int i = 0; i < _max_drive; i++) {
if(disk[i]) {
disk[i]->close();
delete disk[i];
void MB8877::reset()
{
- for(int i = 0; i < MAX_DRIVE; i++) {
- fdc[i].track = 0;
- fdc[i].index = 0;
- fdc[i].access = false;
- }
- for(int i = 0; i < array_length(register_id); i++) {
+ // finish previous command
+ if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
+ // abort write sector command
+ if(sector_changed) {
+ disk[drvreg]->set_data_crc_error(false);
+ }
+ } else if(cmdtype == FDC_CMD_WR_TRK) {
+ // abort write track command
+ if(!disk[drvreg]->write_protected) {
+ if(fdc[drvreg].id_written && !fdc[drvreg].sector_found) {
+ // data mark of last sector is not written
+ disk[drvreg]->set_data_mark_missing();
+ }
+ disk[drvreg]->sync_buffer();
+ }
+ }
+
+ // single events are automatically canceled in event manager
+ for(int i = 0; i < (int)array_length(register_id); i++) {
register_id[i] = -1;
}
- now_search = now_seek = after_seek = drive_sel = false;
- no_command = 0;
-}
-
-void MB8877::update_config()
-{
- ignore_crc = config.ignore_crc;
+
+ // reset fdc
+ memset(fdc, 0, sizeof(fdc));
+ status = status_tmp = cmdreg = cmdreg_tmp = trkreg = secreg = datareg = cmdtype = 0;
+ now_search = now_seek = sector_changed = false;
+ no_command = seektrk = 0;
+ seekvct = false;
+//#ifdef HAS_MB89311
+ if(type_mb89311) {
+ extended_mode = true;
+ } else {
+ extended_mode = false;
+ }
+//#endif
}
-void MB8877::write_io8(uint32 addr, uint32 data)
+void MB8877::write_io8(uint32_t addr, uint32_t data)
{
+ bool ready;
+
switch(addr & 3) {
case 0:
// command reg
cmdreg_tmp = cmdreg;
-#ifdef HAS_MB8876
- cmdreg = (~data) & 0xff;
-#else
- cmdreg = data;
-#endif
+//#if defined(HAS_MB8866) || defined(HAS_MB8876)
+ if(invert_registers) {
+ cmdreg = (~data) & 0xff;
+ } else {
+//#else
+ cmdreg = data;
+ }
+//#endif
process_cmd();
no_command = 0;
break;
case 1:
// track reg
-#ifdef HAS_MB8876
- trkreg = (~data) & 0xff;
-#else
- trkreg = data;
-#endif
+//#if defined(HAS_MB8866) || defined(HAS_MB8876)
+ if(invert_registers) {
+ trkreg = (~data) & 0xff;
+ } else {
+//#else
+ trkreg = data;
+ }
+//#endif
if((status & FDC_ST_BUSY) && (fdc[drvreg].index == 0)) {
// track reg is written after command starts
if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
break;
case 2:
// sector reg
-#ifdef HAS_MB8876
- secreg = (~data) & 0xff;
-#else
- secreg = data;
-#endif
+//#if defined(HAS_MB8866) || defined(HAS_MB8876)
+ if(invert_registers) {
+ secreg = (~data) & 0xff;
+ } else {
+//#else
+ secreg = data;
+ }
+//#endif
if((status & FDC_ST_BUSY) && (fdc[drvreg].index == 0)) {
// sector reg is written after command starts
if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC || cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
break;
case 3:
// data reg
-#ifdef HAS_MB8876
- datareg = (~data) & 0xff;
-#else
- datareg = data;
-#endif
- if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
+//#if defined(HAS_MB8866) || defined(HAS_MB8876)
+ if(invert_registers) {
+ datareg = (~data) & 0xff;
+ } else {
+//#else
+ datareg = data;
+ }
+//#endif
+ ready = ((status & FDC_ST_DRQ) && !now_search);
+
+//#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
+ if(type_fm7) {
+ if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
+ if(!motor_on) ready = false;
+ }
+ if(!fdc[drvreg].head_load) ready = false;
+ } else
+//#endif
+ {
+ if(!motor_on) ready = false;
+ if(!fdc[drvreg].head_load) ready = false;
+ }
+// if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
+ if(ready) {
if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
// write or multisector write
if(fdc[drvreg].index < disk[drvreg]->sector_size.sd) {
if(!disk[drvreg]->write_protected) {
- disk[drvreg]->sector[fdc[drvreg].index] = datareg;
+ if(disk[drvreg]->sector[fdc[drvreg].index] != datareg) {
+ disk[drvreg]->sector[fdc[drvreg].index] = datareg;
+ sector_changed = true;
+ }
// dm, ddm
disk[drvreg]->set_deleted((cmdreg & 1) != 0);
} else {
cmdtype = 0;
set_irq(true);
}
- fdc[drvreg].index++;
+ //fdc[drvreg].index++;
}
- if(fdc[drvreg].index >= disk[drvreg]->sector_size.sd) {
+ if((fdc[drvreg].index + 1) >= disk[drvreg]->sector_size.sd) {
if(cmdtype == FDC_CMD_WR_SEC) {
// single sector
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
+//#endif
status &= ~FDC_ST_BUSY;
cmdtype = 0;
set_irq(true);
} else {
// multisector
- REGISTER_EVENT(EVENT_MULTI1, 30);
- REGISTER_EVENT(EVENT_MULTI2, 60);
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR (SEARCH NEXT)\n"));
+//#endif
+ // 2HD: 360rpm, 10410bytes/track -> 0.06246bytes/us
+ register_my_event(EVENT_MULTI1, 30); // 0.06246bytes/us * 30us = 1.8738bytes < GAP3
+ register_my_event(EVENT_MULTI2, 60); // 0.06246bytes/us * 60us = 3.7476bytes < GAP3
}
+ sector_changed = false;
} else if(status & FDC_ST_DRQ) {
- REGISTER_DRQ_EVENT();
+ if(fdc[drvreg].index == 0) {
+ register_drq_event(fdc[drvreg].bytes_before_2nd_drq);
+ } else {
+ register_drq_event(1);
+ }
+ if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
}
status &= ~FDC_ST_DRQ;
} else if(cmdtype == FDC_CMD_WR_TRK) {
} else if(datareg == 0xf7) {
// write crc
if(!fdc[drvreg].id_written) {
- // insert new sector with crc error
+ // insert new sector with data crc error
+write_id:
+ uint8_t c = 0, h = 0, r = 0, n = 0;
fdc[drvreg].id_written = true;
fdc[drvreg].sector_found = false;
- uint8 c = disk[drvreg]->track[fdc[drvreg].index - 4];
- uint8 h = disk[drvreg]->track[fdc[drvreg].index - 3];
- uint8 r = disk[drvreg]->track[fdc[drvreg].index - 2];
- uint8 n = disk[drvreg]->track[fdc[drvreg].index - 1];
+ if(fdc[drvreg].index >= 4) {
+ c = disk[drvreg]->track[fdc[drvreg].index - 4];
+ h = disk[drvreg]->track[fdc[drvreg].index - 3];
+ r = disk[drvreg]->track[fdc[drvreg].index - 2];
+ n = disk[drvreg]->track[fdc[drvreg].index - 1];
+ }
fdc[drvreg].sector_length = 0x80 << (n & 3);
fdc[drvreg].sector_index = 0;
disk[drvreg]->insert_sector(c, h, r, n, false, true, 0xe5, fdc[drvreg].sector_length);
- } else {
- // clear crc error if all sector data are written
- if(fdc[drvreg].sector_found && fdc[drvreg].sector_index == fdc[drvreg].sector_length) {
- disk[drvreg]->set_crc_error(false);
+ } else if(fdc[drvreg].sector_found) {
+ // clear data crc error if all sector data are written
+ if(fdc[drvreg].sector_index == fdc[drvreg].sector_length) {
+ disk[drvreg]->set_data_crc_error(false);
}
fdc[drvreg].id_written = false;
+ } else {
+ // data mark of current sector is not written
+ disk[drvreg]->set_data_mark_missing();
+ goto write_id;
}
} else if(fdc[drvreg].id_written) {
if(fdc[drvreg].sector_found) {
cmdtype = 0;
set_irq(true);
}
- fdc[drvreg].index++;
+ //fdc[drvreg].index++;
}
- if(fdc[drvreg].index >= disk[drvreg]->get_track_size()) {
+ if((fdc[drvreg].index + 1) >= disk[drvreg]->get_track_size()) {
+ if(!disk[drvreg]->write_protected) {
+ if(fdc[drvreg].id_written && !fdc[drvreg].sector_found) {
+ // data mark of last sector is not written
+ disk[drvreg]->set_data_mark_missing();
+ }
+ disk[drvreg]->sync_buffer();
+ }
status &= ~FDC_ST_BUSY;
cmdtype = 0;
set_irq(true);
} else if(status & FDC_ST_DRQ) {
- REGISTER_DRQ_EVENT();
+ if(fdc[drvreg].index == 0) {
+ register_drq_event(fdc[drvreg].bytes_before_2nd_drq);
+ } else {
+ register_drq_event(1);
+ }
+ if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
}
status &= ~FDC_ST_DRQ;
}
if(!(status & FDC_ST_DRQ)) {
- CANCEL_EVENT(EVENT_LOST);
+ cancel_my_event(EVENT_LOST);
set_drq(false);
fdc[drvreg].access = true;
}
}
}
-uint32 MB8877::read_io8(uint32 addr)
+uint32_t MB8877::read_io8(uint32_t addr)
{
- uint32 val;
+ uint32_t val;
+ bool not_ready = false;
+ bool ready;
switch(addr & 3) {
case 0:
// status reg
- if(cmdtype == FDC_CMD_TYPE4) {
- // now force interrupt
- if(!disk[drvreg]->inserted || !motor_on) {
- status = FDC_ST_NOTREADY;
- } else {
- // MZ-2500 RELICS invites STATUS = 0
- status = 0;
- }
- val = status;
- } else if(now_search) {
+ if(now_search) {
// now sector search
val = FDC_ST_BUSY;
} else {
// disk not inserted, motor stop
- if(!disk[drvreg]->inserted || !motor_on) {
+ not_ready = !disk[drvreg]->inserted;
+//#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
+ if(type_fm7){
+ if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
+ if(!motor_on) not_ready = true;
+ }
+ } else
+//#endif
+ {
+ if(!motor_on) not_ready = true;
+ }
+// if(!disk[drvreg]->inserted || !motor_on) {
+ if(not_ready) {
status |= FDC_ST_NOTREADY;
} else {
status &= ~FDC_ST_NOTREADY;
} else {
status &= ~FDC_ST_TRACK00;
}
- if(!(status & FDC_ST_NOTREADY)) {
- if(get_cur_position() == 0) {
- status |= FDC_ST_INDEX;
- } else {
- status &= ~FDC_ST_INDEX;
- }
+ // index hole signal width is 5msec (thanks Mr.Sato)
+ if(!(status & FDC_ST_NOTREADY) && get_cur_position() < disk[drvreg]->get_bytes_per_usec(5000)) {
+ status |= FDC_ST_INDEX;
+ } else {
+ status &= ~FDC_ST_INDEX;
}
}
// show busy a moment
val = status;
if(cmdtype == FDC_CMD_TYPE1 && !now_seek) {
status &= ~FDC_ST_BUSY;
+//#ifdef MB8877_NO_BUSY_AFTER_SEEK
+ if(mb8877_no_busy_after_seek) {
+ //#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
+ if(type_fm7) {
+ if(disk[0]->is_special_disk != SPECIAL_DISK_FM7_XANADU2_D) {
+ val &= ~FDC_ST_BUSY;
+ }
+ } else
+ //#endif
+ {
+ val &= ~FDC_ST_BUSY;
+ }
+ }
+//#endif
}
}
+
if(cmdtype == 0 && !(status & FDC_ST_NOTREADY)) {
// MZ-2000 HuBASIC invites NOT READY status
if(++no_command == 16) {
} else {
no_command = 0;
}
+
// reset irq/drq
if(!(status & FDC_ST_DRQ)) {
set_drq(false);
}
- set_irq(false);
-#ifdef _FDC_DEBUG_LOG
- emu->out_debug_log(_T("FDC\tSTATUS=%2x\n"), val);
-#endif
-#ifdef HAS_MB8876
- return (~val) & 0xff;
-#else
- return val;
-#endif
+ if(!(status & FDC_ST_BUSY)) {
+ set_irq(false);
+ }
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) this->out_debug_log(_T("FDC\tSTATUS=%2x\n"), val);
+//#endif
+//#if defined(HAS_MB8866) || defined(HAS_MB8876)
+ if(invert_registers) {
+ return (~val) & 0xff;
+//#else
+ } else {
+ return val;
+ }
+//#endif
case 1:
// track reg
-#ifdef HAS_MB8876
- return (~trkreg) & 0xff;
-#else
- return trkreg;
-#endif
+//#if defined(HAS_MB8866) || defined(HAS_MB8876)
+ if(invert_registers) {
+ return (~trkreg) & 0xff;
+ } else {
+//#else
+ return trkreg;
+ }
+//#endif
case 2:
// sector reg
-#ifdef HAS_MB8876
- return (~secreg) & 0xff;
-#else
- return secreg;
-#endif
+//#if defined(HAS_MB8866) || defined(HAS_MB8876)
+ if(invert_registers) {
+ return (~secreg) & 0xff;
+ } else {
+//#else
+ return secreg;
+ }
+//#endif
case 3:
// data reg
- if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
+ ready = ((status & FDC_ST_DRQ) && !now_search);
+//#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
+ if(type_fm7) {
+ if(disk[drvreg]->is_special_disk != SPECIAL_DISK_FM7_RIGLAS) {
+ if(!motor_on) ready = false;
+ }
+ if(!fdc[drvreg].head_load) ready = false;
+ } else
+//#endif
+ {
+ if(!motor_on) ready = false;
+ if(!fdc[drvreg].head_load) ready = false;
+ }
+// if(motor_on && (status & FDC_ST_DRQ) && !now_search) {
+ if(ready) {
if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC) {
// read or multisector read
if(fdc[drvreg].index < disk[drvreg]->sector_size.sd) {
datareg = disk[drvreg]->sector[fdc[drvreg].index];
- fdc[drvreg].index++;
}
- if(fdc[drvreg].index >= disk[drvreg]->sector_size.sd) {
- if(cmdtype == FDC_CMD_RD_SEC) {
- // single sector
-#ifdef _FDC_DEBUG_LOG
- emu->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
+ if((fdc[drvreg].index + 1) >= disk[drvreg]->sector_size.sd) { // Reading complete this sector.
+
+ if(disk[drvreg]->data_crc_error && !disk[drvreg]->ignore_crc()) {
+ // data crc error
+#if 0
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR (DATA CRC ERROR)\n"));
+//#endif
+ status |= FDC_ST_CRCERR;
+ status &= ~FDC_ST_BUSY;
+ cmdtype = 0;
+ set_irq(true);
+#else
+ register_my_event_with_check(EVENT_CRC_ERROR, disk[drvreg]->get_usec_per_bytes(3));
#endif
+ } else if(cmdtype == FDC_CMD_RD_SEC) {
+ // single sector
+#if 0
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
+//#endif
status &= ~FDC_ST_BUSY;
cmdtype = 0;
set_irq(true);
+#else
+ register_my_event_with_check(EVENT_END_READ_SECTOR, disk[drvreg]->get_usec_per_bytes(3));
+#endif
} else {
// multisector
-#ifdef _FDC_DEBUG_LOG
- emu->out_debug_log(_T("FDC\tEND OF SECTOR (SEARCH NEXT)\n"));
-#endif
- REGISTER_EVENT(EVENT_MULTI1, 30);
- REGISTER_EVENT(EVENT_MULTI2, 60);
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR (SEARCH NEXT)\n"));
+//#endif
+ register_my_event(EVENT_MULTI1, 30);
+ register_my_event(EVENT_MULTI2, 60);
}
- } else {
- REGISTER_DRQ_EVENT();
+ } else { // Still data remain.
+ register_drq_event(1);
+ if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
}
status &= ~FDC_ST_DRQ;
} else if(cmdtype == FDC_CMD_RD_ADDR) {
// read address
if(fdc[drvreg].index < 6) {
datareg = disk[drvreg]->id[fdc[drvreg].index];
- fdc[drvreg].index++;
+ //fdc[drvreg].index++;
}
- if(fdc[drvreg].index >= 6) {
+ if((fdc[drvreg].index + 1) >= 6) {
+ if(disk[drvreg]->addr_crc_error && !disk[drvreg]->ignore_crc()) {
+ // id crc error
+ status |= FDC_ST_CRCERR;
+ }
status &= ~FDC_ST_BUSY;
cmdtype = 0;
set_irq(true);
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF ID FIELD\n"));
+//#endif
} else {
- REGISTER_DRQ_EVENT();
+ register_drq_event(1);
+ if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
}
status &= ~FDC_ST_DRQ;
} else if(cmdtype == FDC_CMD_RD_TRK) {
// read track
if(fdc[drvreg].index < disk[drvreg]->get_track_size()) {
datareg = disk[drvreg]->track[fdc[drvreg].index];
- fdc[drvreg].index++;
+ //fdc[drvreg].index++;
}
- if(fdc[drvreg].index >= disk[drvreg]->get_track_size()) {
-#ifdef _FDC_DEBUG_LOG
- emu->out_debug_log(_T("FDC\tEND OF TRACK\n"));
-#endif
+ if((fdc[drvreg].index + 1) >= disk[drvreg]->get_track_size()) {
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF TRACK\n"));
+///#endif
status &= ~FDC_ST_BUSY;
status |= FDC_ST_LOSTDATA;
cmdtype = 0;
set_irq(true);
} else {
- REGISTER_DRQ_EVENT();
+ register_drq_event(1);
+ if(fdc[drvreg].count_immediate) fdc[drvreg].index++;
}
status &= ~FDC_ST_DRQ;
}
if(!(status & FDC_ST_DRQ)) {
- CANCEL_EVENT(EVENT_LOST);
+ cancel_my_event(EVENT_LOST);
set_drq(false);
fdc[drvreg].access = true;
}
}
-#ifdef _FDC_DEBUG_LOG
- emu->out_debug_log(_T("FDC\tDATA=%2x\n"), datareg);
-#endif
-#ifdef HAS_MB8876
- return (~datareg) & 0xff;
-#else
- return datareg;
-#endif
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) this->force_out_debug_log(_T("FDC\tDATA=%2x\n"), datareg); // emu->force_out_debug_log()
+//#endif
+//#if defined(HAS_MB8866) || defined(HAS_MB8876)
+ if(invert_registers) {
+ return (~datareg) & 0xff;
+ } else {
+//#else
+ return datareg;
+ }
+//#endif
}
return 0xff;
}
-void MB8877::write_dma_io8(uint32 addr, uint32 data)
+void MB8877::write_dma_io8(uint32_t addr, uint32_t data)
{
write_io8(3, data);
}
-uint32 MB8877::read_dma_io8(uint32 addr)
+uint32_t MB8877::read_dma_io8(uint32_t addr)
{
return read_io8(3);
}
-void MB8877::write_signal(int id, uint32 data, uint32 mask)
+void MB8877::write_signal(int id, uint32_t data, uint32_t mask)
{
if(id == SIG_MB8877_DRIVEREG) {
- drvreg = data & DRIVE_MASK;
+ drvreg = data & _drive_mask;
drive_sel = true;
+ seekend_clock = get_current_clock();
} else if(id == SIG_MB8877_SIDEREG) {
sidereg = (data & mask) ? 1 : 0;
} else if(id == SIG_MB8877_MOTOR) {
motor_on = ((data & mask) != 0);
- }
+ }
}
-uint32 MB8877::read_signal(int ch)
+uint32_t MB8877::read_signal(int ch)
{
+ if(ch == SIG_MB8877_DRIVEREG) {
+ return drvreg & _drive_mask;
+ } else if(ch == SIG_MB8877_SIDEREG) {
+ return sidereg & 1;
+ } else if(ch == SIG_MB8877_MOTOR) {
+ return motor_on ? 1 : 0;
+ }
+
// get access status
- uint32 stat = 0;
- for(int i = 0; i < MAX_DRIVE; i++) {
+ uint32_t stat = 0;
+ for(int i = 0; i < _max_drive; i++) {
if(fdc[i].access) {
stat |= 1 << i;
}
{
int event = event_id >> 8;
int cmd = event_id & 0xff;
+ //bool need_after_irq = false;
register_id[event] = -1;
// cancel event if the command is finished or other command is executed
if(cmd != cmdtype) {
- if(event == EVENT_SEEK) {
+ if(event == EVENT_SEEK || event == EVENT_SEEKEND_VERIFY) {
now_seek = false;
} else if(event == EVENT_SEARCH) {
now_search = false;
switch(event) {
case EVENT_SEEK:
+//#ifdef _FDC_DEBUG_LOG
+ //this->out_debug_log(_T("FDC\tSEEK START\n"));
+//#endif
if(seektrk > fdc[drvreg].track) {
fdc[drvreg].track++;
+ if(d_noise_seek != NULL) d_noise_seek->play();
+ //need_after_irq = true;
} else if(seektrk < fdc[drvreg].track) {
fdc[drvreg].track--;
+ if(d_noise_seek != NULL) d_noise_seek->play();
+ //need_after_irq = true;
}
- if((cmdreg & 0x10) || ((cmdreg & 0xf0) == 0)) {
+ // Not update track register if "SEEK" command.Thanks to Haserin. 20180224 K.O.
+ if((((cmdreg & 0x10) != 0) && (cmdreg >= 0x20)) || ((cmdreg & 0xf0) == 0)) {
trkreg = fdc[drvreg].track;
}
- if(seektrk == fdc[drvreg].track) {
- // auto update
- if((cmdreg & 0xf0) == 0) {
- datareg = 0;
+ if((uint8_t)seektrk != (uint8_t)fdc[drvreg].track) {
+ //if(need_after_irq) {
+ //set_drq(false);
+ //set_irq(true); // 20180118 K.O Turn ON IRQ -> Turn OFF DRQ
+ //}
+ register_seek_event(false);
+ break;
+ }
+#if 1
+ // Verify before execute command.
+ // Port from XM7.Thanks to Ryu Takegami.
+ if(cmdreg & 4) {
+ // verify
+ if(trkreg != fdc[drvreg].track) {
+ status |= FDC_ST_SEEKERR;
+ trkreg = fdc[drvreg].track; // Reload track register when verify: Really OK? 20180224 K.O
}
- status |= search_track();
- now_seek = false;
- set_irq(true);
- } else {
- REGISTER_SEEK_EVENT();
}
- break;
- case EVENT_SEEKEND:
- if(seektrk == fdc[drvreg].track) {
- // auto update
- if((cmdreg & 0x10) || ((cmdreg & 0xf0) == 0)) {
- trkreg = fdc[drvreg].track;
+#endif
+ seekend_clock = get_current_clock();
+//#ifdef HAS_MB89311
+ if(type_mb89311) {
+ if(extended_mode) {
+ if((cmdreg & 0xf4) == 0x44) {
+ // read-after-seek
+ cmd_readdata(true);
+ break;
+ } else if((cmdreg & 0xf4) == 0x64) {
+ // write-after-seek
+ cmd_writedata(true);
+ break;
+ }
}
- if((cmdreg & 0xf0) == 0) {
- datareg = 0;
+ }
+//#endif
+ status_tmp = status;
+ if(cmdreg & 4) {
+ // verify
+ status_tmp |= search_track();
+ double time;
+#if 0
+ if(status_tmp & FDC_ST_SEEKERR) {
+ time = get_usec_to_detect_index_hole(5, true);
+ } else {
+ time = get_usec_to_next_trans_pos(true);
}
- status |= search_track();
- now_seek = false;
- CANCEL_EVENT(EVENT_SEEK);
- set_irq(true);
+#else
+ // Verify wait is shorter than above at least FM-7 series's MB8877. 20180223 K.O.
+ // Thanks to Ryu Takegami.
+ time = (disk[drvreg]->drive_type == DRIVE_TYPE_2HD) ? 10000.0 : 20000.0;
+#endif
+ // 20180128 K.O If seek completed, delay to make IRQ/DRQ at SEEKEND_VERIFY.
+ register_my_event(EVENT_SEEKEND_VERIFY, time);
+ break;
}
+// case EVENT_SEEKEND: // Separate SEEK and SEEKEND when verifying. 20180128 K.O
+ now_seek = false;
+ status = status_tmp;
+ status &= (uint8_t)(~FDC_ST_BUSY); // 20180118 K.O Turn off BUSY flag.
+ set_drq(false);
+ set_irq(true); // 20180118 K.O Turn ON IRQ -> Turn OFF DRQ
+ break;
+ case EVENT_SEEKEND_VERIFY: // Separate SEEK and SEEKEND when verifying. 20180128 K.O
+ now_seek = false;
+ status &= (uint8_t)(~FDC_ST_BUSY); // 20180118 K.O Turn off BUSY flag.
+ set_drq(false);
+ set_irq(true); // 20180118 K.O Turn ON IRQ -> Turn OFF DRQ
+//#ifdef _FDC_DEBUG_LOG
+ //this->out_debug_log(_T("FDC\tSEEK END\n"));
+//#endif
break;
case EVENT_SEARCH:
now_search = false;
- if(!(status_tmp & FDC_ST_RECNFND)) {
+ if(status_tmp & FDC_ST_RECNFND) {
+//#if defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
+ if(type_x1) {
+ // for SHARP X1 Batten Tanuki
+ if(disk[drvreg]->is_special_disk == SPECIAL_DISK_X1_BATTEN && drive_sel) {
+ status_tmp &= ~FDC_ST_RECNFND;
+ }
+ }
+//#endif
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) this->out_debug_log(_T("FDC\tSEARCH NG\n"));
+//#endif
+ status = status_tmp & ~(FDC_ST_BUSY | FDC_ST_DRQ);
+ cmdtype = 0;
+ set_drq(false);
+ set_irq(true);
+ } else if(status_tmp & FDC_ST_WRITEFAULT) {
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) this->out_debug_log(_T("FDC\tWRITE PROTECTED\n"));
+//#endif
+ status = status_tmp & ~(FDC_ST_BUSY | FDC_ST_DRQ);
+ cmdtype = 0;
+ set_drq(false);
+ set_irq(true);
+ } else {
status = status_tmp | (FDC_ST_BUSY | FDC_ST_DRQ);
- REGISTER_LOST_EVENT();
+ if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
+ register_lost_event(8);
+ } else if(cmdtype == FDC_CMD_WR_TRK) {
+ register_lost_event(3);
+ } else {
+ register_lost_event(1);
+ }
fdc[drvreg].cur_position = fdc[drvreg].next_trans_position;
- fdc[drvreg].prev_clock = prev_drq_clock = current_clock();
+ fdc[drvreg].prev_clock = prev_drq_clock = get_current_clock();
set_drq(true);
drive_sel = false;
- } else {
-#if defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
- // for SHARP X1 Batten Tanuki
- if(disk[drvreg]->is_special_disk == SPECIAL_DISK_X1_BATTEN && drive_sel) {
- status_tmp &= ~FDC_ST_RECNFND;
- }
-#endif
- status = status_tmp & ~(FDC_ST_BUSY | FDC_ST_DRQ);
+ if(fdc_debug_log) this->out_debug_log("DRQ ON@SEARCH: %d\n", prev_drq_clock);
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) this->out_debug_log(_T("FDC\tSEARCH OK\n"));
+//#endif
}
break;
- case EVENT_TYPE4:
- cmdtype = FDC_CMD_TYPE4;
- break;
case EVENT_DRQ:
if(status & FDC_ST_BUSY) {
status |= FDC_ST_DRQ;
- REGISTER_LOST_EVENT();
- fdc[drvreg].cur_position = (fdc[drvreg].cur_position + 1) % disk[drvreg]->get_track_size();
- fdc[drvreg].prev_clock = prev_drq_clock = current_clock();
+ register_lost_event(1);
+ if((cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) && fdc[drvreg].index == 0) {
+ fdc[drvreg].cur_position = (fdc[drvreg].cur_position + fdc[drvreg].bytes_before_2nd_drq) % disk[drvreg]->get_track_size();
+ } else {
+ fdc[drvreg].cur_position = (fdc[drvreg].cur_position + 1) % disk[drvreg]->get_track_size();
+ }
+ if(cmdtype == FDC_CMD_RD_SEC || cmdtype == FDC_CMD_RD_MSEC ||
+ cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC ||
+ cmdtype == FDC_CMD_RD_TRK || cmdtype == FDC_CMD_WR_TRK ||
+ cmdtype == FDC_CMD_RD_ADDR) {
+ if(!(fdc[drvreg].count_immediate)) fdc[drvreg].index++;
+ }
+ fdc[drvreg].prev_clock = prev_drq_clock = get_current_clock();
+
set_drq(true);
+ if(fdc_debug_log) this->out_debug_log("DRQ ON@DRQ: %d\n", prev_drq_clock);
+//#ifdef _FDC_DEBUG_LOG
+ //this->out_debug_log(_T("FDC\tDRQ!\n"));
+//#endif
}
break;
case EVENT_MULTI1:
break;
case EVENT_MULTI2:
if(cmdtype == FDC_CMD_RD_MSEC) {
- cmd_readdata();
+ cmd_readdata(false);
} else if(cmdtype == FDC_CMD_WR_MSEC) {
- cmd_writedata();
+ cmd_writedata(false);
}
break;
+ case EVENT_CRC_ERROR:
+ //#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR (DATA CRC ERROR)\n"));
+//#endif
+ status |= FDC_ST_CRCERR;
+ status &= ~FDC_ST_BUSY;
+ cmdtype = 0;
+ set_irq(true);
+ break;
+ case EVENT_END_READ_SECTOR:
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) this->out_debug_log(_T("FDC\tEND OF SECTOR\n"));
+//#endif
+ status &= ~FDC_ST_BUSY;
+ cmdtype = 0;
+ set_irq(true);
+ break;
case EVENT_LOST:
if(status & FDC_ST_BUSY) {
-#ifdef _FDC_DEBUG_LOG
- emu->out_debug_log("FDC\tDATA LOST\n");
-#endif
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) this->out_debug_log(_T("FDC\tDATA LOST\n"));
+//#endif
+ if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC || cmdtype == FDC_CMD_WR_TRK) {
+ if(fdc[drvreg].index == 0) { // HEAD of REGION
+ cmdtype = 0;
+ //if((status & FDC_ST_DRQ) != 0) { // 20180130 FORCE DOWN DRQ ON LOST-DATA.
+ status |= FDC_ST_LOSTDATA;
+ status &= (uint8_t)(~(FDC_ST_DRQ | FDC_ST_BUSY));
+ set_drq(false);
+ //}
+ set_irq(true);
+ } else { // STILL WRITING
+ write_io8(3, 0x00);
+ //if((status & FDC_ST_DRQ) != 0) {
+ status |= FDC_ST_LOSTDATA;
+ status &= (uint8_t)(~(FDC_ST_DRQ | FDC_ST_BUSY));
+ set_irq(true);
+ set_drq(false);
+ //cmdtype = 0;
+ //}
+ }
+ } else { // READ
+ //if((status & FDC_ST_DRQ) != 0) {
+ status |= FDC_ST_LOSTDATA;
+ status &= (uint8_t)(~(FDC_ST_DRQ | FDC_ST_BUSY));
+ set_irq(true);
+ set_drq(false);
+ //}
+ read_io8(3);
+ }
status |= FDC_ST_LOSTDATA;
- status &= ~FDC_ST_BUSY;
- //status &= ~FDC_ST_DRQ;
- set_irq(true);
- //set_drq(false);
}
break;
}
// command
// ----------------------------------------------------------------------------
+
void MB8877::process_cmd()
{
-#ifdef _FDC_DEBUG_LOG
- static const _TCHAR *cmdstr[0x10] = {
- _T("RESTORE "), _T("SEEK "), _T("STEP "), _T("STEP "),
- _T("STEP IN "), _T("STEP IN "), _T("STEP OUT"), _T("STEP OUT"),
- _T("RD DATA "), _T("RD DATA "), _T("RD DATA "), _T("WR DATA "),
- _T("RD ADDR "), _T("FORCEINT"), _T("RD TRACK"), _T("WR TRACK")
- };
- emu->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);
-#endif
-
- CANCEL_EVENT(EVENT_TYPE4);
set_irq(false);
+ set_drq(false);
- switch(cmdreg & 0xf0) {
+//#ifdef HAS_MB89311
+ // MB89311 mode commands
+ if(type_mb89311) {
+ if(cmdreg == 0xfc) {
+ // delay (may be only in extended mode)
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) 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);
+//#endif
+ cmdtype = status = 0;
+ return;
+ } else if(cmdreg == 0xfd) {
+ // assign parameter
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) 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);
+//#endif
+ cmdtype = status = 0;
+ return;
+ } else if(cmdreg == 0xfe) {
+ // assign mode
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) 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);
+//#endif
+ extended_mode = !extended_mode;
+ cmdtype = status = 0;
+ return;
+ } else if(cmdreg == 0xff) {
+ // reset (may be only in extended mode)
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) 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);
+//#endif
+ cmd_forceint();
+ extended_mode = true;
+ return;
+ } else if(extended_mode) {
+ // type-1
+ if((cmdreg & 0xeb) == 0x21) {
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) 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);
+//#endif
+ cmd_stepin();
+ return;
+ } else if((cmdreg & 0xeb) == 0x22) {
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) 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);
+//#endif
+ cmd_stepout();
+ return;
+ // type-2
+ } else if((cmdreg & 0xf4) == 0x44) {
+ // read-after-seek
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) 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);
+//#endif
+ cmd_seek();
+ return;
+ } else if((cmdreg & 0xf4) == 0x64) {
+ // write-after-seek
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) 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);
+//#endif
+ cmd_seek();
+ return;
+ // type-3
+ } else if((cmdreg & 0xfb) == 0xf1) {
+ // format
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) 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);
+//#endif
+ cmd_format();
+ return;
+ }
+ }
+ }
+//#endif
+
+ // MB8877 mode commands
+ if(fdc_debug_log) {
+ _TCHAR tmps[512];
+ memset(tmps, 0x00, sizeof(tmps));
+ get_debug_regs_info(tmps, sizeof(tmps));
+ if(fdc_debug_log) this->out_debug_log(_T("%s"), tmps);
+ }
+ switch(cmdreg & 0xf8) {
// type-1
- case 0x00:
+ case 0x00: case 0x08:
cmd_restore();
+ update_head_flag(drvreg, (cmdreg & 8) != 0);
break;
- case 0x10:
+ case 0x10: case 0x18:
cmd_seek();
+ update_head_flag(drvreg, (cmdreg & 8) != 0);
break;
- case 0x20:
- case 0x30:
+ case 0x20: case 0x28:
+ case 0x30: case 0x38:
cmd_step();
+ update_head_flag(drvreg, (cmdreg & 8) != 0);
break;
- case 0x40:
- case 0x50:
+ case 0x40: case 0x48:
+ case 0x50: case 0x58:
cmd_stepin();
+ update_head_flag(drvreg, (cmdreg & 8) != 0);
break;
- case 0x60:
- case 0x70:
+ case 0x60: case 0x68:
+ case 0x70: case 0x78:
cmd_stepout();
+ update_head_flag(drvreg, (cmdreg & 8) != 0);
break;
// type-2
- case 0x80:
- case 0x90:
- cmd_readdata();
+ case 0x80: case 0x88:
+ case 0x90: case 0x98:
+ cmd_readdata(true);
+ update_head_flag(drvreg, true);
break;
- case 0xa0:
- case 0xb0:
- cmd_writedata();
+ case 0xa0:case 0xa8:
+ case 0xb0: case 0xb8:
+ cmd_writedata(true);
+ update_head_flag(drvreg, true);
break;
// type-3
case 0xc0:
cmd_readaddr();
+ update_head_flag(drvreg, true);
break;
case 0xe0:
cmd_readtrack();
+ update_head_flag(drvreg, true);
break;
case 0xf0:
cmd_writetrack();
+ update_head_flag(drvreg, true);
break;
// type-4
- case 0xd0:
+ case 0xd0: case 0xd8:
cmd_forceint();
break;
+ // unknown command
default:
break;
}
{
// type-1 restore
cmdtype = FDC_CMD_TYPE1;
- status = FDC_ST_HEADENG | FDC_ST_BUSY;
- trkreg = 0xff;
+ if(!check_drive()) {
+ return;
+ }
+ if((cmdreg & 0x08) != 0) { // Head engage
+ status = FDC_ST_HEADENG | FDC_ST_BUSY;
+ } else {
+ status = FDC_ST_BUSY;
+ }
+ set_irq(false);
+ set_drq(false);
+
+ if(fdc[drvreg].track < 0) {
+ fdc[drvreg].track = 0;
+ trkreg = 0;
+ } else if(fdc[drvreg].track >= 80) {
+ fdc[drvreg].track = 80;
+ trkreg = 80;
+ } else {
+ trkreg = fdc[drvreg].track;
+ }
+ datareg = 0;
seektrk = 0;
seekvct = true;
- REGISTER_SEEK_EVENT();
- REGISTER_EVENT(EVENT_SEEKEND, 300);
+ register_seek_event(true);
}
void MB8877::cmd_seek()
{
// type-1 seek
cmdtype = FDC_CMD_TYPE1;
- status = FDC_ST_HEADENG | FDC_ST_BUSY;
-
-#if 0
- seektrk = fdc[drvreg].track + datareg - trkreg;
-#else
- seektrk = datareg;
-#endif
- seektrk = (seektrk > 83) ? 83 : (seektrk < 0) ? 0 : seektrk;
- seekvct = !(datareg > trkreg);
-
- REGISTER_SEEK_EVENT();
- REGISTER_EVENT(EVENT_SEEKEND, 300);
+ if(!check_drive()) {
+ return;
+ }
+ if((cmdreg & 0x08) != 0) { // Head engage
+ status = FDC_ST_HEADENG | FDC_ST_BUSY;
+ } else {
+ status = FDC_ST_BUSY;
+ }
+
+ // revert below 20180225 K.O
+ //seektrk = (uint8_t)(fdc[drvreg].track + datareg - trkreg); // Seek target is differ when drive's track != trkreg.Thanks to Haserin and Ryu Takegami.
+ seektrk = (int)((int8_t)datareg);
+//#if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV20) || defined(_FM77AV20EX)
+ if(seektrk >= disk[drvreg]->get_max_tracks()) {
+ seektrk = disk[drvreg]->get_max_tracks() - 1;
+ } else if(seektrk < 0) {
+ seektrk = 0;
+ }
+
+ seekvct = !(seektrk > fdc[drvreg].track);
+ // Update track register by data register.Thanks to Ryu Takegami. 20180224 K.O
+ trkreg = datareg;
+ set_irq(false);
+ set_drq(false);
+ register_seek_event(true);
}
void MB8877::cmd_step()
{
// type-1 step in
cmdtype = FDC_CMD_TYPE1;
- status = FDC_ST_HEADENG | FDC_ST_BUSY;
-
- seektrk = (fdc[drvreg].track < 83) ? fdc[drvreg].track + 1 : 83;
+ if(!check_drive()) {
+ return;
+ }
+ if((cmdreg & 0x08) != 0) { // Head engage
+ status = FDC_ST_HEADENG | FDC_ST_BUSY;
+ } else {
+ status = FDC_ST_BUSY;
+ }
+
+ // Verify before execute command.
+ // Port from XM7.Thanks to Ryu Takegami.
+#if 1
+ if(cmdreg & 4) {
+ // verify
+ if(trkreg != fdc[drvreg].track) {
+ status |= FDC_ST_SEEKERR;
+// trkreg = fdc[drvreg].track;
+ }
+ }
+#endif
+ seektrk = fdc[drvreg].track + 1;
+ if(seektrk >= disk[drvreg]->get_max_tracks()) {
+ seektrk = disk[drvreg]->get_max_tracks() - 1;
+ } else if(seektrk < 0) {
+ seektrk = 0;
+ }
seekvct = false;
-
- REGISTER_SEEK_EVENT();
- REGISTER_EVENT(EVENT_SEEKEND, 300);
+ set_irq(false);
+ set_drq(false);
+ register_seek_event(true);
}
void MB8877::cmd_stepout()
{
// type-1 step out
cmdtype = FDC_CMD_TYPE1;
- status = FDC_ST_HEADENG | FDC_ST_BUSY;
-
- seektrk = (fdc[drvreg].track > 0) ? fdc[drvreg].track - 1 : 0;
+ if(!check_drive()) {
+ return;
+ }
+ if((cmdreg & 0x08) != 0) { // Head engage
+ status = FDC_ST_HEADENG | FDC_ST_BUSY;
+ } else {
+ status = FDC_ST_BUSY;
+ }
+
+ // Verify before execute command.
+ // Port from XM7.Thanks to Ryu Takegami.
+#if 1
+ if(cmdreg & 4) {
+ // verify
+ if(trkreg != fdc[drvreg].track) {
+ status |= FDC_ST_SEEKERR;
+// trkreg = fdc[drvreg].track;
+ }
+ }
+#endif
+ seektrk = fdc[drvreg].track - 1;
+ if(seektrk >= disk[drvreg]->get_max_tracks()) {
+ seektrk = disk[drvreg]->get_max_tracks() - 1;
+ } else if(seektrk < 0) {
+ seektrk = 0;
+ }
seekvct = true;
-
- REGISTER_SEEK_EVENT();
- REGISTER_EVENT(EVENT_SEEKEND, 300);
+ register_seek_event(true);
}
-void MB8877::cmd_readdata()
+void MB8877::cmd_readdata(bool first_sector)
{
// type-2 read data
cmdtype = (cmdreg & 0x10) ? FDC_CMD_RD_MSEC : FDC_CMD_RD_SEC;
- int side = (cmdreg & 2) ? ((cmdreg & 8) ? 1 : 0) : sidereg;
+ if(!check_drive2()) {
+ return;
+ }
status = FDC_ST_BUSY;
- status_tmp = search_sector(fdc[drvreg].track, side, secreg, ((cmdreg & 2) != 0));
+ status_tmp = search_sector();
now_search = true;
double time;
- if(!(status_tmp & FDC_ST_RECNFND)) {
- time = get_usec_to_start_trans();
+ if(status_tmp & FDC_ST_RECNFND) {
+ time = get_usec_to_detect_index_hole(5, first_sector && ((cmdreg & 4) != 0));
} else {
- time = disk[drvreg]->get_usec_per_bytes(disk[drvreg]->get_track_size());
+ time = get_usec_to_start_trans(first_sector);
}
- REGISTER_EVENT(EVENT_SEARCH, time);
- CANCEL_EVENT(EVENT_LOST);
+ register_my_event(EVENT_SEARCH, time);
+ cancel_my_event(EVENT_LOST);
}
-void MB8877::cmd_writedata()
+void MB8877::cmd_writedata(bool first_sector)
{
// type-2 write data
cmdtype = (cmdreg & 0x10) ? FDC_CMD_WR_MSEC : FDC_CMD_WR_SEC;
- int side = (cmdreg & 2) ? ((cmdreg & 8) ? 1 : 0) : sidereg;
+ if(!check_drive2()) {
+ return;
+ }
status = FDC_ST_BUSY;
- status_tmp = search_sector(fdc[drvreg].track, side, secreg, ((cmdreg & 2) != 0)) & ~FDC_ST_RECTYPE;
+ status_tmp = search_sector() & ~FDC_ST_RECTYPE;
now_search = true;
+ sector_changed = false;
double time;
- if(!(status_tmp & FDC_ST_RECNFND)) {
- time = get_usec_to_start_trans();
+ if(status_tmp & FDC_ST_RECNFND) {
+ time = get_usec_to_detect_index_hole(5, first_sector && ((cmdreg & 4) != 0));
+ } else if(status & FDC_ST_WRITEFAULT) {
+ time = (cmdreg & 4) ? DELAY_AFTER_HLD : 1;
} else {
- time = disk[drvreg]->get_usec_per_bytes(disk[drvreg]->get_track_size());
+ time = get_usec_to_start_trans(first_sector);
}
- REGISTER_EVENT(EVENT_SEARCH, time);
- CANCEL_EVENT(EVENT_LOST);
+ register_my_event(EVENT_SEARCH, time);
+ cancel_my_event(EVENT_LOST);
}
void MB8877::cmd_readaddr()
{
// type-3 read address
cmdtype = FDC_CMD_RD_ADDR;
+ if(!check_drive2()) {
+ return;
+ }
status = FDC_ST_BUSY;
status_tmp = search_addr();
now_search = true;
double time;
- if(!(status_tmp & FDC_ST_RECNFND)) {
- time = get_usec_to_start_trans();
+ if(status_tmp & FDC_ST_RECNFND) {
+ time = get_usec_to_detect_index_hole(5, ((cmdreg & 4) != 0));
} else {
- time = disk[drvreg]->get_usec_per_bytes(disk[drvreg]->get_track_size());
+ time = get_usec_to_start_trans(true);
}
- REGISTER_EVENT(EVENT_SEARCH, time);
- CANCEL_EVENT(EVENT_LOST);
+ register_my_event(EVENT_SEARCH, time);
+ cancel_my_event(EVENT_LOST);
}
void MB8877::cmd_readtrack()
{
// type-3 read track
cmdtype = FDC_CMD_RD_TRK;
+ if(!check_drive2()) {
+ return;
+ }
status = FDC_ST_BUSY;
status_tmp = 0;
fdc[drvreg].index = 0;
now_search = true;
- int bytes = disk[drvreg]->get_track_size() - get_cur_position();
- if(bytes < 12) {
- bytes += disk[drvreg]->get_track_size();
- }
- double time = disk[drvreg]->get_usec_per_bytes(bytes);
- REGISTER_EVENT(EVENT_SEARCH, time);
- CANCEL_EVENT(EVENT_LOST);
+ fdc[drvreg].next_trans_position = 1;
+ double time = get_usec_to_detect_index_hole(1, ((cmdreg & 4) != 0));
+ register_my_event(EVENT_SEARCH, time);
+ cancel_my_event(EVENT_LOST);
}
void MB8877::cmd_writetrack()
{
// type-3 write track
cmdtype = FDC_CMD_WR_TRK;
+ if(!check_drive2()) {
+ return;
+ }
status = FDC_ST_BUSY;
status_tmp = 0;
fdc[drvreg].index = 0;
+ fdc[drvreg].id_written = false;
now_search = true;
- int bytes = disk[drvreg]->get_track_size() - get_cur_position();
- if(bytes < 12) {
- bytes += disk[drvreg]->get_track_size();
+ double time;
+ if(disk[drvreg]->write_protected) {
+ status_tmp = FDC_ST_WRITEFAULT;
+ time = (cmdreg & 4) ? DELAY_AFTER_HLD : 1;
+ } else {
+ if(cmdreg & 4) {
+ // wait 15msec before raise first drq
+ fdc[drvreg].next_trans_position = (get_cur_position() + disk[drvreg]->get_bytes_per_usec(DELAY_AFTER_HLD)) % disk[drvreg]->get_track_size();
+ time = DELAY_AFTER_HLD;
+ } else {
+ // raise first drq soon
+ fdc[drvreg].next_trans_position = (get_cur_position() + 1) % disk[drvreg]->get_track_size();
+ time = disk[drvreg]->get_usec_per_bytes(1);
+ }
+ // wait at least 3bytes before check index hole and raise second drq
+ fdc[drvreg].bytes_before_2nd_drq = disk[drvreg]->get_track_size() - fdc[drvreg].next_trans_position;
+ if(fdc[drvreg].bytes_before_2nd_drq < 3) {
+ fdc[drvreg].bytes_before_2nd_drq += disk[drvreg]->get_track_size();
+ }
+ }
+ register_my_event(EVENT_SEARCH, time);
+ cancel_my_event(EVENT_LOST);
+}
+
+//#ifdef HAS_MB89311
+void MB8877::cmd_format()
+{
+ if(type_mb89311) {
+ // type-3 format (FIXME: need to implement)
+ cmdtype = FDC_CMD_WR_TRK;
+ status = FDC_ST_BUSY;
+ status_tmp = 0;
+
+ fdc[drvreg].index = 0;
+ fdc[drvreg].id_written = false;
+ now_search = true;
+
+ status_tmp = FDC_ST_WRITEFAULT;
+ double time = (cmdreg & 4) ? DELAY_AFTER_HLD : 1;
+
+ register_my_event(EVENT_SEARCH, time);
+ cancel_my_event(EVENT_LOST);
}
- double time = disk[drvreg]->get_usec_per_bytes(bytes);
- REGISTER_EVENT(EVENT_SEARCH, time);
- CANCEL_EVENT(EVENT_LOST);
}
+//#endif
void MB8877::cmd_forceint()
{
// type-4 force interrupt
-#if 0
- if(!disk[drvreg]->inserted || !motor_on) {
- status = FDC_ST_NOTREADY | FDC_ST_HEADENG;
- } else {
- status = FDC_ST_HEADENG;
- }
- cmdtype = FDC_CMD_TYPE4;
-#else
-// if(cmdtype == 0 || cmdtype == 4) { // modified for mz-2800, why in the write sector command case?
- if(cmdtype == 0 || cmdtype == FDC_CMD_TYPE4) { // is this correct?
- status = 0;
- cmdtype = FDC_CMD_TYPE1;
- }
- status &= ~FDC_ST_BUSY;
-#endif
+ bool ready = (cmdtype == 0);
+ bool is_busy = ((status & FDC_ST_BUSY) != 0);
+ bool now_seek_bak = now_seek;
+ bool is_type1 = (cmdtype == FDC_CMD_TYPE1);
+ bool is_read = ((cmdtype == FDC_CMD_RD_SEC) || (cmdtype == FDC_CMD_RD_MSEC) || \
+ (cmdtype == FDC_CMD_RD_ADDR) || (cmdtype == FDC_CMD_RD_TRK));
+ bool is_trkwrite = (cmdtype == FDC_CMD_WR_TRK);
- // force interrupt if bit0-bit3 is high
- if(cmdreg & 0x0f) {
- set_irq(true);
+ if(cmdtype == FDC_CMD_TYPE1) {
+ // abort restore/seek/step command
+ if(now_seek) {
+ if(seektrk > fdc[drvreg].track) {
+ if((fdc[drvreg].track < 0xff) && (fdc[drvreg].track >= 0)) fdc[drvreg].track++;
+ } else if(seektrk < fdc[drvreg].track) {
+ if((fdc[drvreg].track <= 0xff) && (fdc[drvreg].track > 0)) fdc[drvreg].track--;
+ }
+ // Not update track register if "SEEK" command.Thanks to Haserin. 20180224 K.O.
+ if((((cmdreg_tmp & 0x10) != 0) && (cmdreg_tmp >= 0x20)) || ((cmdreg_tmp & 0xf0) == 0)) {
+ trkreg = fdc[drvreg].track;
+ }
+ }
+ } else if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
+ // abort write sector command
+ if(sector_changed) {
+ disk[drvreg]->set_data_crc_error(false);
+ }
+ } else if(cmdtype == FDC_CMD_WR_TRK) {
+ // abort write track command
+ if(!disk[drvreg]->write_protected) {
+ if(fdc[drvreg].id_written && !fdc[drvreg].sector_found) {
+ // data mark of last sector is not written
+ disk[drvreg]->set_data_mark_missing();
+ }
+ disk[drvreg]->sync_buffer();
+ }
}
+ now_search = now_seek = sector_changed = false;
- // finish current seeking
- if(now_seek) {
- if(seektrk > fdc[drvreg].track) {
- fdc[drvreg].track++;
- } else if(seektrk < fdc[drvreg].track) {
- fdc[drvreg].track--;
- }
- if((cmdreg_tmp & 0x10) || ((cmdreg_tmp & 0xf0) == 0)) {
- trkreg = fdc[drvreg].track;
+//#ifdef HAS_MB89311
+ if((cmdreg == 0xff) && (type_mb89311)) {
+ // reset command
+ cmdtype = FDC_CMD_TYPE1;
+ status = FDC_ST_HEADENG;
+ } else {
+//#endif
+ if(cmdtype == 0 || !(status & FDC_ST_BUSY)) {
+ cmdtype = FDC_CMD_TYPE1;
+ if(!type_fm7) status = FDC_ST_HEADENG; // Hack for FUKUALL.d77 .
}
- if(seektrk == fdc[drvreg].track) {
- // auto update
- if((cmdreg_tmp & 0xf0) == 0) {
- datareg = 0;
+ status &= ~FDC_ST_BUSY;
+ if((now_seek_bak) || (ready)) {// Refer from XM7, is this write implement? 20180210 K.O
+ status = 0;
+ if(((ready) || !(is_busy)) && (!type_fm7)) status = FDC_ST_HEADENG;
+ // indexcount = 0;
+ if(check_drive2()) {
+ if(!(is_read) && (disk[drvreg]->write_protected)) status |= FDC_ST_WRITEP;
+ if((is_trkwrite) && (disk[drvreg]->write_protected)) status |= FDC_ST_WRITEFAULT;
+ if(is_type1) {
+ if(fdc[drvreg].track == 0) status |= FDC_ST_TRACK00;
+ if(get_cur_position() < disk[drvreg]->get_bytes_per_usec(5000)) {
+ status |= FDC_ST_INDEX;
+ }
+ }
}
}
+ // force interrupt if bit0-bit3 is high
+ if(cmdreg & 0x0f) {
+ set_irq(true);
+ }
+//#ifdef HAS_MB89311
}
- now_search = now_seek = false;
+//#endif
- CANCEL_EVENT(EVENT_SEEK);
- CANCEL_EVENT(EVENT_SEEKEND);
- CANCEL_EVENT(EVENT_SEARCH);
- CANCEL_EVENT(EVENT_TYPE4);
- CANCEL_EVENT(EVENT_DRQ);
- CANCEL_EVENT(EVENT_MULTI1);
- CANCEL_EVENT(EVENT_MULTI2);
- CANCEL_EVENT(EVENT_LOST);
- REGISTER_EVENT(EVENT_TYPE4, 100);
+ cancel_my_event(EVENT_SEEK);
+ cancel_my_event(EVENT_SEEKEND_VERIFY);
+ cancel_my_event(EVENT_SEARCH);
+ cancel_my_event(EVENT_DRQ);
+ cancel_my_event(EVENT_MULTI1);
+ cancel_my_event(EVENT_MULTI2);
+ cancel_my_event(EVENT_LOST);
+}
+
+void MB8877::update_head_flag(int drv, bool head_load)
+{
+ if(fdc[drv].head_load != head_load) {
+ if(head_load) {
+ if(d_noise_head_down != NULL) d_noise_head_down->play();
+ } else {
+ if(d_noise_head_up != NULL) d_noise_head_up->play();
+ }
+ fdc[drv].head_load = head_load;
+ }
}
// ----------------------------------------------------------------------------
// media handler
// ----------------------------------------------------------------------------
-uint8 MB8877::search_track()
+uint8_t MB8877::search_track()
{
- int trk = fdc[drvreg].track;
-
- if(!disk[drvreg]->get_track(trk, sidereg)) {
+ // get track
+ int track = fdc[drvreg].track;
+
+ if(!disk[drvreg]->get_track(track, sidereg)){
return FDC_ST_SEEKERR;
}
// verify track number
- if(!(cmdreg & 4)) {
- return 0;
- }
- for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
- disk[drvreg]->get_sector(trk, sidereg, i);
- if(disk[drvreg]->id[0] == trkreg) {
- return 0;
+ if(disk[drvreg]->ignore_crc()) {
+ for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
+ disk[drvreg]->get_sector(-1, -1, i);
+ if(disk[drvreg]->id[0] == trkreg) {
+ fdc[drvreg].next_trans_position = disk[drvreg]->id_position[i] + 4 + 2;
+ fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[i];
+ return 0;
+ }
+ }
+ } else {
+ for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
+ disk[drvreg]->get_sector(-1, -1, i);
+ if(disk[drvreg]->id[0] == trkreg && !disk[drvreg]->addr_crc_error) {
+ fdc[drvreg].next_trans_position = disk[drvreg]->id_position[i] + 4 + 2;
+ fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[i];
+ return 0;
+ }
+ }
+ for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
+ disk[drvreg]->get_sector(-1, -1, i);
+ if(disk[drvreg]->id[0] == trkreg) {
+ return FDC_ST_SEEKERR | FDC_ST_CRCERR;
+ }
}
}
return FDC_ST_SEEKERR;
}
-uint8 MB8877::search_sector(int trk, int side, int sct, bool compare)
+uint8_t MB8877::search_sector()
{
+ // write protect
+ if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
+ if(disk[drvreg]->write_protected) {
+ return FDC_ST_WRITEFAULT;
+ }
+ }
+
// get track
- if(!disk[drvreg]->get_track(trk, side)) {
- set_irq(true);
+ int track = fdc[drvreg].track;
+
+
+ if(!disk[drvreg]->get_track(track, sidereg)) {
return FDC_ST_RECNFND;
}
int sector_num = disk[drvreg]->sector_num.sd;
int position = get_cur_position();
- if(position > disk[drvreg]->sync_position[sector_num - 1]) {
+ if(position > disk[drvreg]->am1_position[sector_num - 1]) {
position -= disk[drvreg]->get_track_size();
}
// first scanned sector
int first_sector = 0;
for(int i = 0; i < sector_num; i++) {
- if(position < disk[drvreg]->sync_position[i]) {
+ if(position < disk[drvreg]->am1_position[i]) {
first_sector = i;
break;
}
for(int i = 0; i < sector_num; i++) {
// get sector
int index = (first_sector + i) % sector_num;
- disk[drvreg]->get_sector(trk, side, index);
+ disk[drvreg]->get_sector(-1, -1, index);
// check id
- if((cmdreg & 2) && (disk[drvreg]->id[1] & 1) != ((cmdreg >> 3) & 1)) {
+ if(disk[drvreg]->id[0] != trkreg) {
+ continue;
+ }
+//#if !defined(HAS_MB8866)
+ if(!type_mb8866) {
+ if((cmdreg & 2) && (disk[drvreg]->id[1] & 1) != ((cmdreg >> 3) & 1)) {
+ continue;
+ }
+ }
+//#endif
+ if(disk[drvreg]->id[2] != secreg) {
continue;
}
- if(disk[drvreg]->id[2] != sct) {
+ if(disk[drvreg]->sector_size.sd == 0) {
continue;
}
+ if(disk[drvreg]->addr_crc_error && !disk[drvreg]->ignore_crc()) {
+ // id crc error
+ disk[drvreg]->sector_size.sd = 0;
+ return FDC_ST_RECNFND | FDC_ST_CRCERR;
+ }
// sector found
- fdc[drvreg].next_trans_position = disk[drvreg]->data_position[i];
- fdc[drvreg].next_sync_position = disk[drvreg]->sync_position[i];
+ if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
+ fdc[drvreg].next_trans_position = disk[drvreg]->id_position[index] + 4 + 2;
+ fdc[drvreg].bytes_before_2nd_drq = disk[drvreg]->data_position[index] - fdc[drvreg].next_trans_position;
+ } else {
+ fdc[drvreg].next_trans_position = disk[drvreg]->data_position[index] + 1;
+ }
+ fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[index];
fdc[drvreg].index = 0;
- return (disk[drvreg]->deleted ? FDC_ST_RECTYPE : 0) | ((disk[drvreg]->crc_error && !ignore_crc) ? FDC_ST_CRCERR : 0);
+//#ifdef _FDC_DEBUG_LOG
+ if(fdc_debug_log) this->out_debug_log(_T("FDC\tSECTOR FOUND SIZE=$%04x ID=%02x %02x %02x %02x CRC=%02x %02x CRC_ERROR=%d\n"),
+ disk[drvreg]->sector_size.sd,
+ disk[drvreg]->id[0], disk[drvreg]->id[1], disk[drvreg]->id[2], disk[drvreg]->id[3],
+ disk[drvreg]->id[4], disk[drvreg]->id[5],
+ disk[drvreg]->data_crc_error ? 1 : 0);
+//#endif
+ return (disk[drvreg]->deleted ? FDC_ST_RECTYPE : 0);
}
// sector not found
disk[drvreg]->sector_size.sd = 0;
- set_irq(true);
return FDC_ST_RECNFND;
}
-uint8 MB8877::search_addr()
+uint8_t MB8877::search_addr()
{
- int trk = fdc[drvreg].track;
-
// get track
- if(!disk[drvreg]->get_track(trk, sidereg)) {
- set_irq(true);
+ int track = fdc[drvreg].track;
+
+ if(!disk[drvreg]->get_track(track, sidereg)) {
return FDC_ST_RECNFND;
}
int sector_num = disk[drvreg]->sector_num.sd;
int position = get_cur_position();
- if(position > disk[drvreg]->sync_position[sector_num - 1]) {
+ if(position > disk[drvreg]->am1_position[sector_num - 1]) {
position -= disk[drvreg]->get_track_size();
}
// first scanned sector
int first_sector = 0;
for(int i = 0; i < sector_num; i++) {
- if(position < disk[drvreg]->sync_position[i]) {
+ if(position < disk[drvreg]->am1_position[i]) {
first_sector = i;
break;
}
}
// get sector
- if(disk[drvreg]->get_sector(trk, sidereg, first_sector)) {
- fdc[drvreg].next_trans_position = disk[drvreg]->id_position[first_sector];
- fdc[drvreg].next_sync_position = disk[drvreg]->sync_position[first_sector];
+ if(disk[drvreg]->get_sector(-1, -1, first_sector)) {
+ fdc[drvreg].next_trans_position = disk[drvreg]->id_position[first_sector] + 1;
+ fdc[drvreg].next_am1_position = disk[drvreg]->am1_position[first_sector];
fdc[drvreg].index = 0;
secreg = disk[drvreg]->id[0];
- return (disk[drvreg]->crc_error && !ignore_crc) ? FDC_ST_CRCERR : 0;
+ return 0;
}
// sector not found
disk[drvreg]->sector_size.sd = 0;
- set_irq(true);
return FDC_ST_RECNFND;
}
int MB8877::get_cur_position()
{
- return (int)(fdc[drvreg].cur_position + passed_usec(fdc[drvreg].prev_clock) / disk[drvreg]->get_usec_per_bytes(1)) % disk[drvreg]->get_track_size();
+ return (fdc[drvreg].cur_position + disk[drvreg]->get_bytes_per_usec(get_passed_usec(fdc[drvreg].prev_clock))) % disk[drvreg]->get_track_size();
}
-double MB8877::get_usec_to_start_trans()
+double MB8877::get_usec_to_start_trans(bool first_sector)
{
-#if defined(_X1TURBO) || defined(_X1TURBOZ)
- // FIXME: ugly patch for X1turbo ALPHA
- if(disk[drvreg]->is_special_disk == SPECIAL_DISK_X1_ALPHA) {
- return 100;
- } else
-#endif
- if(disk[drvreg]->no_skew) {
+ // get time from current position
+ double time = get_usec_to_next_trans_pos(first_sector && ((cmdreg & 4) != 0));
+
+ if(mb8877_delay_after_seek > 0) {
+ // wait 60ms to start read/write after seek is finished (FM-Techknow, p.180)
+ if(first_sector && time < mb8877_delay_after_seek - get_passed_usec(seekend_clock)) {
+ time += disk[drvreg]->get_usec_per_track();
+ }
+ }
+ return time;
+}
+
+double MB8877::get_usec_to_next_trans_pos(bool delay)
+{
+ int position = get_cur_position();
+
+ if(disk[drvreg]->invalid_format) {
+ // XXX: this track is invalid format and the calculated sector position may be incorrect.
+ // so use the constant period
+ return 50000;
+ } else if(/*disk[drvreg]->no_skew && */!disk[drvreg]->correct_timing()) {
// XXX: this image may be a standard image or coverted from a standard image and skew may be incorrect,
- // so use the constant period to search the target sector
+ // so use the period to search the next sector from the current position
+ int sector_num = disk[drvreg]->sector_num.sd;
+ int bytes = -1;
+
+ if(position > disk[drvreg]->am1_position[sector_num - 1]) {
+ position -= disk[drvreg]->get_track_size();
+ }
+ for(int i = 0; i < sector_num; i++) {
+ if(position < disk[drvreg]->am1_position[i]) {
+ if(cmdtype == FDC_CMD_WR_SEC || cmdtype == FDC_CMD_WR_MSEC) {
+ bytes = (disk[drvreg]->id_position[i] + 4 + 2) - position;
+ } else {
+ bytes = (disk[drvreg]->data_position[i] + 1) - position;
+ }
+ if(bytes < 0) {
+ bytes += disk[drvreg]->get_track_size(); // to make sure
+ }
+ break;
+ }
+ }
+ if(bytes > 0) {
+ return disk[drvreg]->get_usec_per_bytes(bytes);
+ }
return 50000;
}
-
- // get time from current position
- int position = get_cur_position();
+ if(delay) {
+ position = (position + disk[drvreg]->get_bytes_per_usec(DELAY_AFTER_HLD)) % disk[drvreg]->get_track_size();
+ }
int bytes = fdc[drvreg].next_trans_position - position;
- if(fdc[drvreg].next_sync_position < position) {
+ if(fdc[drvreg].next_am1_position < position || bytes < 0) {
bytes += disk[drvreg]->get_track_size();
}
double time = disk[drvreg]->get_usec_per_bytes(bytes);
- if(after_seek) {
- // wait 70msec to read/write data just after seek command is done
-// if(time < 70000) {
-// time += disk[drvreg]->get_usec_per_bytes(disk[drvreg]->get_track_size());
-// }
- after_seek = false;
+ if(delay) {
+ time += DELAY_AFTER_HLD;
+ }
+ return time;
+}
+
+double MB8877::get_usec_to_detect_index_hole(int count, bool delay)
+{
+ int position = get_cur_position();
+ if(delay) {
+ position = (position + disk[drvreg]->get_bytes_per_usec(DELAY_AFTER_HLD)) % disk[drvreg]->get_track_size();
+ }
+ int bytes = disk[drvreg]->get_track_size() * count - position;
+ if(bytes < 0) {
+ bytes += disk[drvreg]->get_track_size();
+ }
+ double time = disk[drvreg]->get_usec_per_bytes(bytes);
+ if(delay) {
+ time += DELAY_AFTER_HLD;
}
return time;
}
// user interface
// ----------------------------------------------------------------------------
-void MB8877::open_disk(int drv, _TCHAR path[], int bank)
+void MB8877::open_disk(int drv, const _TCHAR* file_path, int bank)
{
- if(drv < MAX_DRIVE) {
- disk[drv]->open(path, bank);
+ if(drv < _max_drive) {
+ disk[drv]->open(file_path, bank);
+#if defined(_USE_QT)
+ if((disk[drv]->is_special_disk == SPECIAL_DISK_FM7_FLEX) || (config.disk_count_immediate[drv])) {
+#else
+ if(disk[drv]->is_special_disk == SPECIAL_DISK_FM7_FLEX) {
+#endif
+ fdc[drv].count_immediate = true;
+ } else {
+ fdc[drv].count_immediate = false;
+ }
}
}
void MB8877::close_disk(int drv)
{
- if(drv < MAX_DRIVE) {
+ if(drv < _max_drive) {
disk[drv]->close();
- cmdtype = 0;
+ //cmdtype = 0;
+ if(drv == drvreg) {
+ cmdtype = 0;
+ }
+ update_head_flag(drv, false);
+ fdc[drv].count_immediate = false;
}
}
-bool MB8877::disk_inserted(int drv)
+bool MB8877::is_disk_inserted(int drv)
{
- if(drv < MAX_DRIVE) {
+ if(drv < _max_drive) {
return disk[drv]->inserted;
}
return false;
}
-void MB8877::set_drive_type(int drv, uint8 type)
+void MB8877::is_disk_protected(int drv, bool value)
+{
+ if(drv < _max_drive) {
+ disk[drv]->write_protected = value;
+ }
+}
+
+bool MB8877::is_disk_protected(int drv)
+{
+ if(drv < _max_drive) {
+ return disk[drv]->write_protected;
+ }
+ return false;
+}
+
+uint8_t MB8877::get_media_type(int drv)
{
- if(drv < MAX_DRIVE) {
+ if(drv < _max_drive) {
+ if(disk[drv]->inserted) {
+ return disk[drv]->media_type;
+ }
+ }
+ return MEDIA_TYPE_UNK;
+}
+
+void MB8877::set_drive_type(int drv, uint8_t type)
+{
+ if(drv < _max_drive) {
disk[drv]->drive_type = type;
}
}
-uint8 MB8877::get_drive_type(int drv)
+uint8_t MB8877::get_drive_type(int drv)
{
- if(drv < MAX_DRIVE) {
+ if(drv < _max_drive) {
return disk[drv]->drive_type;
}
return DRIVE_TYPE_UNK;
void MB8877::set_drive_rpm(int drv, int rpm)
{
- if(drv < MAX_DRIVE) {
+ if(drv < _max_drive) {
disk[drv]->drive_rpm = rpm;
}
}
void MB8877::set_drive_mfm(int drv, bool mfm)
{
- if(drv < MAX_DRIVE) {
+ if(drv < _max_drive) {
disk[drv]->drive_mfm = mfm;
}
}
-uint8 MB8877::fdc_status()
+void MB8877::set_track_size(int drv, int size)
+{
+ if(drv < _max_drive) {
+ disk[drv]->track_size = size;
+ }
+}
+
+uint8_t MB8877::fdc_status()
{
// for each virtual machines
-#if defined(_FMR50) || defined(_FMR60)
- return disk[drvreg]->inserted ? 2 : 0;
-#else
+//#if defined(_FMR50) || defined(_FMR60)
+ if(type_fmr50 || type_fmr60) {
+ return disk[drvreg]->inserted ? 2 : 0;
+ }
+//#else
return 0;
-#endif
+//#endif
+}
+
+void MB8877::update_config()
+{
+ if(d_noise_seek != NULL) {
+ d_noise_seek->set_mute(!config.sound_noise_fdd);
+ }
+ if(d_noise_head_down != NULL) {
+ d_noise_head_down->set_mute(!config.sound_noise_fdd);
+ }
+ if(d_noise_head_up != NULL) {
+ d_noise_head_up->set_mute(!config.sound_noise_fdd);
+ }
+ fdc_debug_log = config.special_debug_fdc;
}
-#define STATE_VERSION 2
+//#ifdef USE_DEBUGGER
+static const _TCHAR *cmdstr[0x10] = {
+ _T("RESTORE "), _T("SEEK "), _T("STEP "), _T("STEP "),
+ _T("STEP IN "), _T("STEP IN "), _T("STEP OUT"), _T("STEP OUT"),
+ _T("RD DATA "), _T("RD DATA "), _T("RD DATA "), _T("WR DATA "),
+ _T("RD ADDR "), _T("FORCEINT"), _T("RD TRACK"), _T("WR TRACK")
+};
-void MB8877::save_state(FILEIO* state_fio)
+bool MB8877::get_debug_regs_info(_TCHAR *buffer, size_t buffer_len)
{
- state_fio->FputUint32(STATE_VERSION);
- state_fio->FputInt32(this_device_id);
+ int position = get_cur_position();
- state_fio->FputBool(ignore_crc);
- state_fio->Fwrite(fdc, sizeof(fdc), 1);
- for(int i = 0; i < MAX_DRIVE; i++) {
- disk[i]->save_state(state_fio);
- }
- state_fio->FputUint8(status);
- state_fio->FputUint8(status_tmp);
- state_fio->FputUint8(cmdreg);
- state_fio->FputUint8(cmdreg_tmp);
- state_fio->FputUint8(trkreg);
- state_fio->FputUint8(secreg);
- state_fio->FputUint8(datareg);
- state_fio->FputUint8(drvreg);
- state_fio->FputUint8(sidereg);
- state_fio->FputUint8(cmdtype);
- state_fio->Fwrite(register_id, sizeof(register_id), 1);
- state_fio->FputBool(now_search);
- state_fio->FputBool(now_seek);
- state_fio->FputBool(after_seek);
- state_fio->FputInt32(no_command);
- state_fio->FputInt32(seektrk);
- state_fio->FputBool(seekvct);
- state_fio->FputBool(motor_on);
- state_fio->FputBool(drive_sel);
- state_fio->FputUint32(prev_drq_clock);
+ my_stprintf_s(buffer, buffer_len,
+ _T("CMDREG=%02X (%s) DATAREG=%02X DRVREG=%02X TRKREG=%02X SIDEREG=%d SECREG=%02X\n")
+ _T("UNIT: DRIVE=%d TRACK=%2d SIDE=%d POSITION=%5d/%d"),
+ cmdreg, cmdstr[cmdreg >> 4], datareg, drvreg, trkreg, sidereg, secreg,
+ drvreg, fdc[drvreg].track, sidereg,
+ position, disk[drvreg]->get_track_size());
+
+ for(int i = 0; i < disk[drvreg]->sector_num.sd; i++) {
+ uint8_t c, h, r, n;
+ int length;
+ if(disk[drvreg]->get_sector_info(-1, -1, i, &c, &h, &r, &n, &length)) {
+ my_tcscat_s(buffer, buffer_len,
+ create_string(_T("\nSECTOR %2d: C=%02X H=%02X R=%02X N=%02X SIZE=%4d AM1=%5d DATA=%5d"), i + 1, c, h, r, n, length, disk[drvreg]->am1_position[i], disk[drvreg]->data_position[i]));
+ if(position >= disk[drvreg]->am1_position[i] && position < disk[drvreg]->data_position[i] + length) {
+ my_tcscat_s(buffer, buffer_len, _T(" <==="));
+ }
+ }
+ }
+ return true;
}
+//#endif
+
+#define STATE_VERSION 6
-bool MB8877::load_state(FILEIO* state_fio)
+bool MB8877::process_state(FILEIO* state_fio, bool loading)
{
- if(state_fio->FgetUint32() != STATE_VERSION) {
- return false;
+ if(!state_fio->StateCheckUint32(STATE_VERSION)) {
+ return false;
+ }
+ if(!state_fio->StateCheckInt32(this_device_id)) {
+ return false;
+ }
+//
+ for(int i = 0; i < array_length(fdc); i++) {
+ state_fio->StateValue(fdc[i].track);
+ state_fio->StateValue(fdc[i].index);
+ state_fio->StateValue(fdc[i].access);
+ state_fio->StateValue(fdc[i].head_load);
+ state_fio->StateValue(fdc[i].id_written);
+ state_fio->StateValue(fdc[i].sector_found);
+ state_fio->StateValue(fdc[i].sector_length);
+ state_fio->StateValue(fdc[i].sector_index);
+ state_fio->StateValue(fdc[i].side);
+ state_fio->StateValue(fdc[i].side_changed);
+ state_fio->StateValue(fdc[i].cur_position);
+ state_fio->StateValue(fdc[i].next_trans_position);
+ state_fio->StateValue(fdc[i].bytes_before_2nd_drq);
+ state_fio->StateValue(fdc[i].next_am1_position);
+ state_fio->StateValue(fdc[i].prev_clock);
}
- if(state_fio->FgetInt32() != this_device_id) {
- return false;
+ for(int i = 0; i < array_length(disk); i++) {
+ if(disk[i] == NULL) continue;
+ if(!disk[i]->process_state(state_fio, loading)) {
+ return false;
+ }
+ }
+ state_fio->StateValue(status);
+ state_fio->StateValue(status_tmp);
+ state_fio->StateValue(cmdreg);
+ state_fio->StateValue(cmdreg_tmp);
+ state_fio->StateValue(trkreg);
+ state_fio->StateValue(secreg);
+ state_fio->StateValue(datareg);
+ state_fio->StateValue(drvreg);
+ state_fio->StateValue(sidereg);
+ state_fio->StateValue(cmdtype);
+ state_fio->StateArray(register_id, sizeof(register_id), 1);
+ state_fio->StateValue(now_search);
+ state_fio->StateValue(now_seek);
+ state_fio->StateValue(sector_changed);
+ state_fio->StateValue(no_command);
+ state_fio->StateValue(seektrk);
+ state_fio->StateValue(seekvct);
+ state_fio->StateValue(motor_on);
+ state_fio->StateValue(drive_sel);
+ state_fio->StateValue(prev_drq_clock);
+ state_fio->StateValue(seekend_clock);
+ if(loading) {
+ fdc_debug_log = config.special_debug_fdc;
}
- ignore_crc = state_fio->FgetBool();
- state_fio->Fread(fdc, sizeof(fdc), 1);
- for(int i = 0; i < MAX_DRIVE; i++) {
- if(!disk[i]->load_state(state_fio)) {
- return false;
- }
- }
- status = state_fio->FgetUint8();
- status_tmp = state_fio->FgetUint8();
- cmdreg = state_fio->FgetUint8();
- cmdreg_tmp = state_fio->FgetUint8();
- trkreg = state_fio->FgetUint8();
- secreg = state_fio->FgetUint8();
- datareg = state_fio->FgetUint8();
- drvreg = state_fio->FgetUint8();
- sidereg = state_fio->FgetUint8();
- cmdtype = state_fio->FgetUint8();
- state_fio->Fread(register_id, sizeof(register_id), 1);
- now_search = state_fio->FgetBool();
- now_seek = state_fio->FgetBool();
- after_seek = state_fio->FgetBool();
- no_command = state_fio->FgetInt32();
- seektrk = state_fio->FgetInt32();
- seekvct = state_fio->FgetBool();
- motor_on = state_fio->FgetBool();
- drive_sel = state_fio->FgetBool();
- prev_drq_clock = state_fio->FgetUint32();
- return true;
+ return true;
}