diff options
author | 2017-09-13 15:44:02 +0700 | |
---|---|---|
committer | 2017-09-13 18:44:02 +1000 | |
commit | 5a3081ed8ebf74e10942e0382b106ad6a2d459fb (patch) | |
tree | 2e81fe7ace106f1feace87fe4adfc4ae3faf0523 | |
parent | 0fa8819b12091aeb64ea995dd0aa5893691d3cc6 (diff) |
upd765: sense interrupt status and i82072 changes (#2632)
Yet another attempt at implementing the i82072 sense interrupt status logic. This time, I've separated the logic into the derived class, so it won't affect the other devices. Also included motor on/off logic (unique to i82072) - motor on delay is incomplete.
-rw-r--r-- | src/devices/machine/upd765.cpp | 352 | ||||
-rw-r--r-- | src/devices/machine/upd765.h | 36 |
2 files changed, 304 insertions, 84 deletions
diff --git a/src/devices/machine/upd765.cpp b/src/devices/machine/upd765.cpp index 39cc69d8c9b..af54ea69ce2 100644 --- a/src/devices/machine/upd765.cpp +++ b/src/devices/machine/upd765.cpp @@ -5,7 +5,8 @@ #include "upd765.h" #include "debugger.h" -#define LOG 0 +#define VERBOSE 0 +#include "logmacro.h" DEFINE_DEVICE_TYPE(UPD765A, upd765a_device, "upd765a", "NEC uPD765A FDC") DEFINE_DEVICE_TYPE(UPD765B, upd765b_device, "upd765b", "NEC uPD765B FDC") @@ -148,6 +149,9 @@ void upd765_family_device::set_mode(int _mode) void upd765_family_device::device_start() { + save_item(NAME(motorcfg)); + save_item(NAME(selected_drive)); + intrq_cb.resolve_safe(); drq_cb.resolve_safe(); hdl_cb.resolve_safe(); @@ -162,7 +166,7 @@ void upd765_family_device::device_start() floppy_connector *con = subdevice<floppy_connector>(name); if(con) { flopi[i].dev = con->get_device(); - if (flopi[i].dev != nullptr) + if(flopi[i].dev != nullptr) flopi[i].dev->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(&upd765_family_device::index_callback, this)); } else flopi[i].dev = nullptr; @@ -182,6 +186,7 @@ void upd765_family_device::device_start() } cur_rate = 250000; tc = false; + selected_drive = -1; // reset at upper levels may cause a write to tc ending up with // live_sync, which will crash if the live structure isn't @@ -236,6 +241,7 @@ void upd765_family_device::soft_reset() cur_live.fi = nullptr; tc_done = false; st1 = st2 = st3 = 0x00; + selected_drive = -1; check_irq(); if(ready_polled) @@ -244,7 +250,7 @@ void upd765_family_device::soft_reset() void upd765_family_device::tc_w(bool _tc) { - if (LOG) logerror("tc=%d\n", _tc); + LOG("tc=%d\n", _tc); if(tc != _tc && _tc) { live_sync(); tc_done = true; @@ -267,19 +273,23 @@ bool upd765_family_device::get_ready(int fid) return !external_ready; } -void upd765_family_device::set_ds(int state) +void upd765_family_device::set_ds(int fid) { - for(int i = 0; i < 4; i++) - { - floppy_info &fi = flopi[i]; - if (fi.dev) - fi.dev->ds_w(state); - } + if(selected_drive == fid) + return; + + // pass drive select to connected drives + for(floppy_info &fi : flopi) + if(fi.dev) + fi.dev->ds_w(fid); + + // record selected drive + selected_drive = fid; } void upd765_family_device::set_floppy(floppy_image_device *flop) { - for(auto & elem : flopi) { + for(floppy_info & elem : flopi) { if(elem.dev) elem.dev->setup_index_pulse_cb(floppy_image_device::index_pulse_cb()); elem.dev = flop; @@ -323,7 +333,7 @@ READ8_MEMBER(upd765_family_device::dor_r) WRITE8_MEMBER(upd765_family_device::dor_w) { - if (LOG) logerror("dor = %02x\n", data); + LOG("dor = %02x\n", data); uint8_t diff = dor ^ data; dor = data; if(diff & 4) @@ -386,7 +396,7 @@ READ8_MEMBER(upd765_family_device::msr_r) WRITE8_MEMBER(upd765_family_device::dsr_w) { - if (LOG) logerror("dsr_w %02x\n", data); + LOG("dsr_w %02x (%s)\n", data, machine().describe_context()); if(data & 0x80) soft_reset(); dsr = data & 0x7f; @@ -405,7 +415,7 @@ READ8_MEMBER(upd765_family_device::fifo_r) case PHASE_EXEC: if(internal_drq) return fifo_pop(false); - if (LOG) logerror("fifo_r in phase %d\n", main_phase); + LOG("fifo_r in phase %d\n", main_phase); break; case PHASE_RESULT: @@ -414,9 +424,15 @@ READ8_MEMBER(upd765_family_device::fifo_r) memmove(result, result+1, result_pos); if(!result_pos) main_phase = PHASE_CMD; + else if(result_pos == 1) { + // clear drive busy bit after the first sense interrupt status result byte is read + for(floppy_info &fi : flopi) + if((fi.main_state == RECALIBRATE || fi.main_state == SEEK) && fi.sub_state == IDLE && fi.st0_filled == false) + fi.main_state = IDLE; + } break; default: - if (LOG) logerror("fifo_r in phase %d\n", main_phase); + LOG("fifo_r in phase %d\n", main_phase); break; } @@ -434,7 +450,7 @@ WRITE8_MEMBER(upd765_family_device::fifo_w) if(cmd == C_INCOMPLETE) break; if(cmd == C_INVALID) { - if (LOG) logerror("Invalid on %02x\n", command[0]); + LOG("Invalid on %02x\n", command[0]); main_phase = PHASE_RESULT; result[0] = ST0_UNK; result_pos = 1; @@ -449,11 +465,11 @@ WRITE8_MEMBER(upd765_family_device::fifo_w) fifo_push(data, false); return; } - if (LOG) logerror("fifo_w in phase %d\n", main_phase); + LOG("fifo_w in phase %d\n", main_phase); break; default: - if (LOG) logerror("fifo_w in phase %d\n", main_phase); + LOG("fifo_w in phase %d\n", main_phase); break; } } @@ -520,7 +536,7 @@ void upd765_family_device::fifo_push(uint8_t data, bool internal) if(fifo_pos == 16) { if(internal) { if(!(st1 & ST1_OR)) - if (LOG) logerror("Fifo overrun\n"); + LOG("Fifo overrun\n"); st1 |= ST1_OR; } return; @@ -541,7 +557,7 @@ uint8_t upd765_family_device::fifo_pop(bool internal) if(!fifo_pos) { if(internal) { if(!(st1 & ST1_OR)) - if (LOG) logerror("Fifo underrun\n"); + LOG("Fifo underrun\n"); st1 |= ST1_OR; } return 0; @@ -1050,7 +1066,7 @@ void upd765_family_device::live_run(attotime limit) command[12+cur_live.byte_counter-16] = byte; live_write_mfm(byte); if(cur_live.byte_counter == 19) - if (LOG) logerror("formatting sector %02x %02x %02x %02x\n", + LOG("formatting sector %02x %02x %02x %02x\n", command[12], command[13], command[14], command[15]); } else if(cur_live.byte_counter < 22) live_write_mfm(cur_live.crc >> 8); @@ -1086,7 +1102,7 @@ void upd765_family_device::live_run(attotime limit) command[12+cur_live.byte_counter-7] = byte; live_write_fm(byte); if(cur_live.byte_counter == 10) - if (LOG) logerror("formatting sector %02x %02x %02x %02x\n", + LOG("formatting sector %02x %02x %02x %02x\n", command[12], command[13], command[14], command[15]); } else if(cur_live.byte_counter < 13) live_write_fm(cur_live.crc >> 8); @@ -1138,7 +1154,7 @@ void upd765_family_device::live_run(attotime limit) break; default: - if (LOG) logerror("%s: Unknown live state %d\n", tts(cur_live.tm).c_str(), cur_live.state); + LOG("%s: Unknown live state %d\n", tts(cur_live.tm).c_str(), cur_live.state); return; } } @@ -1243,18 +1259,25 @@ void upd765_family_device::start_command(int cmd) result_pos = 0; main_phase = PHASE_EXEC; tc_done = false; + + execute_command(cmd); +} + +void upd765_family_device::execute_command(int cmd) +{ switch(cmd) { case C_CONFIGURE: - if (LOG) logerror("command configure %02x %02x %02x\n", + LOG("command configure %02x %02x %02x\n", command[1], command[2], command[3]); // byte 1 is ignored, byte 3 is precompensation-related + motorcfg = command[1]; fifocfg = command[2]; precomp = command[3]; main_phase = PHASE_CMD; break; case C_DUMP_REG: - if (LOG) logerror("command dump regs\n"); + LOG("command dump regs\n"); main_phase = PHASE_RESULT; result[0] = flopi[0].pcn; result[1] = flopi[1].pcn; @@ -1279,11 +1302,11 @@ void upd765_family_device::start_command(int cmd) main_phase = PHASE_RESULT; result[0] = locked ? 0x10 : 0x00; result_pos = 1; - if (LOG) logerror("command lock (%s)\n", locked ? "on" : "off"); + LOG("command lock (%s)\n", locked ? "on" : "off"); break; case C_PERPENDICULAR: - if (LOG) logerror("command perpendicular\n"); + LOG("command perpendicular\n"); perpmode = command[1]; main_phase = PHASE_CMD; break; @@ -1327,7 +1350,7 @@ void upd765_family_device::start_command(int cmd) (fi.dev->wpt_r() ? ST3_WP : 0x00) | (fi.dev->trk00_r() ? 0x00 : ST3_T0) | (fi.dev->twosid_r() ? 0x00 : ST3_TS); - if (LOG) logerror("command sense drive status %d (%02x)\n", fi.id, result[0]); + LOG("command sense drive status %d (%02x)\n", fi.id, result[0]); result_pos = 1; break; } @@ -1357,7 +1380,7 @@ void upd765_family_device::start_command(int cmd) if(fid == 4) { result[0] = ST0_UNK; result_pos = 1; - if (LOG) logerror("command sense interrupt status (%02x)\n", result[0]); + LOG("command sense interrupt status (%02x) (%s)\n", result[0], machine().describe_context()); break; } @@ -1367,7 +1390,7 @@ void upd765_family_device::start_command(int cmd) result[0] = fi.st0; result[1] = fi.pcn; - if (LOG) logerror("command sense interrupt status (fid=%d %02x %02x)\n", fid, result[0], result[1]); + LOG("command sense interrupt status (fid=%d %02x %02x) (%s)\n", fid, result[0], result[1], machine().describe_context()); result_pos = 2; other_irq = false; @@ -1376,7 +1399,7 @@ void upd765_family_device::start_command(int cmd) } case C_SPECIFY: - if (LOG) logerror("command specify %02x %02x\n", + LOG("command specify %02x %02x\n", command[1], command[2]); spec = (command[1] << 8) | command[2]; main_phase = PHASE_CMD; @@ -1394,15 +1417,15 @@ void upd765_family_device::start_command(int cmd) void upd765_family_device::command_end(floppy_info &fi, bool data_completion) { - if (LOG) logerror("command done (%s) -", data_completion ? "data" : "seek"); + LOG("command done (%s) -", data_completion ? "data" : "seek"); for(int i=0; i != result_pos; i++) - if (LOG) logerror(" %02x", result[i]); - if (LOG) logerror("\n"); - fi.main_state = fi.sub_state = IDLE; - if(data_completion) + LOG(" %02x", result[i]); + LOG("\n"); + fi.sub_state = IDLE; + if(data_completion) { + fi.main_state = IDLE; data_irq = true; - else - { + } else { other_irq = true; fi.st0_filled = true; } @@ -1411,7 +1434,7 @@ void upd765_family_device::command_end(floppy_info &fi, bool data_completion) void upd765_family_device::recalibrate_start(floppy_info &fi) { - if (LOG) logerror("command recalibrate\n"); + LOG("command recalibrate %d\n", command[1] & 3); fi.main_state = RECALIBRATE; fi.sub_state = SEEK_WAIT_STEP_TIME_DONE; fi.dir = 1; @@ -1423,7 +1446,7 @@ void upd765_family_device::recalibrate_start(floppy_info &fi) void upd765_family_device::seek_start(floppy_info &fi) { - if (LOG) logerror("command %sseek %d\n", command[0] & 0x80 ? "relative " : "", command[2]); + LOG("command %sseek %d\n", command[0] & 0x80 ? "relative " : "", command[2]); fi.main_state = SEEK; fi.sub_state = SEEK_WAIT_STEP_TIME_DONE; fi.dir = fi.pcn > command[2] ? 1 : 0; @@ -1513,7 +1536,7 @@ void upd765_family_device::read_data_start(floppy_info &fi) fi.sub_state = HEAD_LOAD_DONE; mfm = command[0] & 0x40; - if (LOG) logerror("command read%s data%s%s%s%s cmd=%02x sel=%x chrn=(%d, %d, %d, %d) eot=%02x gpl=%02x dtl=%02x rate=%d\n", + LOG("command read%s data%s%s%s%s cmd=%02x sel=%x chrn=(%d, %d, %d, %d) eot=%02x gpl=%02x dtl=%02x rate=%d\n", command[0] & 0x08 ? " deleted" : "", command[0] & 0x80 ? " mt" : "", command[0] & 0x40 ? " mfm" : "", @@ -1537,8 +1560,7 @@ void upd765_family_device::read_data_start(floppy_info &fi) set_ds(command[1] & 3); fi.ready = get_ready(command[1] & 3); - if(!fi.ready) - { + if(!fi.ready) { fi.st0 |= ST0_NR | ST0_FAIL; fi.sub_state = COMMAND_DONE; st1 = 0; @@ -1558,7 +1580,7 @@ void upd765_family_device::scan_start(floppy_info &fi) fi.sub_state = HEAD_LOAD_DONE; mfm = command[0] & 0x40; - if (LOG) logerror("command scan%s data%s%s%s%s cmd=%02x sel=%x chrn=(%d, %d, %d, %d) eot=%02x gpl=%02x stp=%02x rate=%d\n", + LOG("command scan%s data%s%s%s%s cmd=%02x sel=%x chrn=(%d, %d, %d, %d) eot=%02x gpl=%02x stp=%02x rate=%d\n", command[0] & 0x08 ? " deleted" : "", command[0] & 0x80 ? " mt" : "", command[0] & 0x40 ? " mfm" : "", @@ -1583,8 +1605,7 @@ void upd765_family_device::scan_start(floppy_info &fi) set_ds(command[1] & 3); fi.ready = get_ready(command[1] & 3); - if(!fi.ready) - { + if(!fi.ready) { fi.st0 |= ST0_NR | ST0_FAIL; fi.sub_state = COMMAND_DONE; st1 = 0; @@ -1662,7 +1683,7 @@ void upd765_family_device::read_data_continue(floppy_info &fi) live_start(fi, SEARCH_ADDRESS_MARK_HEADER); return; } - if (LOG) logerror("reading sector %02x %02x %02x %02x\n", + LOG("reading sector %02x %02x %02x %02x\n", cur_live.idbuf[0], cur_live.idbuf[1], cur_live.idbuf[2], @@ -1737,7 +1758,7 @@ void upd765_family_device::read_data_continue(floppy_info &fi) return; default: - if (LOG) logerror("%s: read sector unknown sub-state %d\n", ttsn().c_str(), fi.sub_state); + LOG("%s: read sector unknown sub-state %d\n", ttsn().c_str(), fi.sub_state); return; } } @@ -1748,7 +1769,7 @@ void upd765_family_device::write_data_start(floppy_info &fi) fi.main_state = WRITE_DATA; fi.sub_state = HEAD_LOAD_DONE; mfm = command[0] & 0x40; - if (LOG) logerror("command write%s data%s%s cmd=%02x sel=%x chrn=(%d, %d, %d, %d) eot=%02x gpl=%02x dtl=%02x rate=%d\n", + LOG("command write%s data%s%s cmd=%02x sel=%x chrn=(%d, %d, %d, %d) eot=%02x gpl=%02x dtl=%02x rate=%d\n", command[0] & 0x08 ? " deleted" : "", command[0] & 0x80 ? " mt" : "", command[0] & 0x40 ? " mfm" : "", @@ -1773,8 +1794,7 @@ void upd765_family_device::write_data_start(floppy_info &fi) set_ds(command[1] & 3); fi.ready = get_ready(command[1] & 3); - if(!fi.ready) - { + if(!fi.ready) { fi.st0 |= ST0_NR | ST0_FAIL; fi.sub_state = COMMAND_DONE; st1 = 0; @@ -1863,7 +1883,7 @@ void upd765_family_device::write_data_continue(floppy_info &fi) return; default: - if (LOG) logerror("%s: write sector unknown sub-state %d\n", ttsn().c_str(), fi.sub_state); + LOG("%s: write sector unknown sub-state %d\n", ttsn().c_str(), fi.sub_state); return; } } @@ -1876,7 +1896,7 @@ void upd765_family_device::read_track_start(floppy_info &fi) mfm = command[0] & 0x40; sectors_read = 0; - if (LOG) logerror("command read track%s cmd=%02x sel=%x chrn=(%d, %d, %d, %d) eot=%02x gpl=%02x dtl=%02x rate=%d\n", + LOG("command read track%s cmd=%02x sel=%x chrn=(%d, %d, %d, %d) eot=%02x gpl=%02x dtl=%02x rate=%d\n", command[0] & 0x40 ? " mfm" : "", command[0], command[1], @@ -1895,8 +1915,7 @@ void upd765_family_device::read_track_start(floppy_info &fi) set_ds(command[1] & 3); fi.ready = get_ready(command[1] & 3); - if(!fi.ready) - { + if(!fi.ready) { fi.st0 |= ST0_NR | ST0_FAIL; fi.sub_state = COMMAND_DONE; st1 = 0; @@ -1959,7 +1978,7 @@ void upd765_family_device::read_track_continue(floppy_info &fi) return; case WAIT_INDEX_DONE: - if (LOG) logerror("index found, reading track\n"); + LOG("index found, reading track\n"); fi.sub_state = SCAN_ID; live_start(fi, SEARCH_ADDRESS_MARK_HEADER); return; @@ -1969,7 +1988,7 @@ void upd765_family_device::read_track_continue(floppy_info &fi) st1 |= ST1_DE; } st1 &= ~ST1_MA; - if (LOG) logerror("reading sector %02x %02x %02x %02x\n", + LOG("reading sector %02x %02x %02x %02x\n", cur_live.idbuf[0], cur_live.idbuf[1], cur_live.idbuf[2], @@ -2032,7 +2051,7 @@ void upd765_family_device::read_track_continue(floppy_info &fi) return; default: - if (LOG) logerror("%s: read track unknown sub-state %d\n", ttsn().c_str(), fi.sub_state); + LOG("%s: read track unknown sub-state %d\n", ttsn().c_str(), fi.sub_state); return; } } @@ -2049,7 +2068,7 @@ void upd765_family_device::format_track_start(floppy_info &fi) fi.sub_state = HEAD_LOAD_DONE; mfm = command[0] & 0x40; - if (LOG) logerror("command format track %s h=%02x n=%02x sc=%02x gpl=%02x d=%02x\n", + LOG("command format track %s h=%02x n=%02x sc=%02x gpl=%02x d=%02x\n", command[0] & 0x40 ? "mfm" : "fm", command[1], command[2], command[3], command[4], command[5]); @@ -2057,8 +2076,7 @@ void upd765_family_device::format_track_start(floppy_info &fi) set_ds(command[1] & 3); fi.ready = get_ready(command[1] & 3); - if(!fi.ready) - { + if(!fi.ready) { fi.st0 = (command[1] & 7) | ST0_NR | ST0_FAIL; fi.sub_state = TRACK_DONE; format_track_continue(fi); @@ -2085,7 +2103,7 @@ void upd765_family_device::format_track_continue(floppy_info &fi) return; case WAIT_INDEX_DONE: - if (LOG) logerror("index found, writing track\n"); + LOG("index found, writing track\n"); fi.sub_state = TRACK_DONE; cur_live.pll.start_writing(machine().time()); live_start(fi, WRITE_TRACK_PRE_SECTORS); @@ -2105,7 +2123,7 @@ void upd765_family_device::format_track_continue(floppy_info &fi) return; default: - if (LOG) logerror("%s: format track unknown sub-state %d\n", ttsn().c_str(), fi.sub_state); + LOG("%s: format track unknown sub-state %d\n", ttsn().c_str(), fi.sub_state); return; } } @@ -2117,8 +2135,9 @@ void upd765_family_device::read_id_start(floppy_info &fi) fi.sub_state = HEAD_LOAD_DONE; mfm = command[0] & 0x40; - if (LOG) logerror("command read id%s, rate=%d\n", + LOG("command read id%s %d, rate=%d\n", command[0] & 0x40 ? " mfm" : "", + command[1] & 3, cur_rate); if(fi.dev) @@ -2135,8 +2154,7 @@ void upd765_family_device::read_id_start(floppy_info &fi) set_ds(command[1] & 3); fi.ready = get_ready(command[1] & 3); - if(!fi.ready) - { + if(!fi.ready) { fi.st0 |= ST0_NR | ST0_FAIL; fi.sub_state = COMMAND_DONE; read_id_continue(fi); @@ -2184,7 +2202,7 @@ void upd765_family_device::read_id_continue(floppy_info &fi) return; default: - if (LOG) logerror("%s: read id unknown sub-state %d\n", ttsn().c_str(), fi.sub_state); + LOG("%s: read id unknown sub-state %d\n", ttsn().c_str(), fi.sub_state); return; } } @@ -2196,7 +2214,7 @@ void upd765_family_device::check_irq() cur_irq = data_irq || other_irq || internal_drq; cur_irq = cur_irq && (dor & 4) && (mode != MODE_AT || (dor & 8)); if(cur_irq != old_irq) { - if (LOG) logerror("irq = %d\n", cur_irq); + LOG("irq = %d\n", cur_irq); intrq_cb(cur_irq); } } @@ -2254,7 +2272,7 @@ void upd765_family_device::run_drive_ready_polling() for(int fid=0; fid<4; fid++) { bool ready = get_ready(fid); if(ready != flopi[fid].ready) { - if (LOG) logerror("polled %d : %d -> %d\n", fid, flopi[fid].ready, ready); + LOG("polled %d : %d -> %d\n", fid, flopi[fid].ready, ready); flopi[fid].ready = ready; if(!flopi[fid].st0_filled) { flopi[fid].st0 = ST0_ABRT | fid; @@ -2269,7 +2287,7 @@ void upd765_family_device::run_drive_ready_polling() void upd765_family_device::index_callback(floppy_image_device *floppy, int state) { - for(auto & fi : flopi) { + for(floppy_info & fi : flopi) { if(fi.dev != floppy) continue; @@ -2311,7 +2329,7 @@ void upd765_family_device::index_callback(floppy_image_device *floppy, int state break; default: - if (LOG) logerror("%s: Index pulse on unknown sub-state %d\n", ttsn().c_str(), fi.sub_state); + LOG("%s: Index pulse on unknown sub-state %d\n", ttsn().c_str(), fi.sub_state); break; } @@ -2359,7 +2377,7 @@ void upd765_family_device::general_continue(floppy_info &fi) break; default: - if (LOG) logerror("%s: general_continue on unknown main-state %d\n", ttsn().c_str(), fi.main_state); + LOG("%s: general_continue on unknown main-state %d\n", ttsn().c_str(), fi.main_state); break; } } @@ -2400,7 +2418,7 @@ bool upd765_family_device::write_one_bit(const attotime &limit) void upd765_family_device::live_write_raw(uint16_t raw) { - // if (LOG) logerror("write %04x %04x\n", raw, cur_live.crc); + // LOG("write %04x %04x\n", raw, cur_live.crc); cur_live.shift_reg = raw; cur_live.data_bit_context = raw & 1; } @@ -2420,7 +2438,7 @@ void upd765_family_device::live_write_mfm(uint8_t mfm) cur_live.data_reg = mfm; cur_live.shift_reg = raw; cur_live.data_bit_context = context; - // if (LOG) logerror("write %02x %04x %04x\n", mfm, cur_live.crc, raw); + // LOG("write %02x %04x %04x\n", mfm, cur_live.crc, raw); } void upd765_family_device::live_write_fm(uint8_t fm) @@ -2432,13 +2450,13 @@ void upd765_family_device::live_write_fm(uint8_t fm) cur_live.data_reg = fm; cur_live.shift_reg = raw; cur_live.data_bit_context = fm & 1; - // if (LOG) logerror("write %02x %04x %04x\n", fm, cur_live.crc, raw); + // LOG("write %02x %04x %04x\n", fm, cur_live.crc, raw); } bool upd765_family_device::sector_matches() const { if(0) - if (LOG) logerror("matching %02x %02x %02x %02x - %02x %02x %02x %02x\n", + LOG("matching %02x %02x %02x %02x - %02x %02x %02x %02x\n", cur_live.idbuf[0], cur_live.idbuf[1], cur_live.idbuf[2], cur_live.idbuf[3], command[2], command[3], command[4], command[5]); return @@ -2473,6 +2491,185 @@ i82072_device::i82072_device(const machine_config &mconfig, const char *tag, dev dor_reset = 0x0c; } +void i82072_device::device_start() +{ + upd765_family_device::device_start(); + + save_item(NAME(motor_off_counter)); + save_item(NAME(motor_on_counter)); +} + +void i82072_device::soft_reset() +{ + motorcfg = 0x60; + + upd765_family_device::soft_reset(); +} + +int i82072_device::check_command() +{ + // ...01011 motor on/off + switch(command[0] & 0x1f) { + case 0x0b: + return C_MOTOR_ONOFF; + } + + return upd765_family_device::check_command(); +} + +void i82072_device::start_command(int cmd) +{ + // check if the command specifies a target drive + switch(cmd) { + case C_READ_TRACK: + case C_SENSE_DRIVE_STATUS: + case C_WRITE_DATA: + case C_READ_DATA: + case C_RECALIBRATE: + //case C_WRITE_DELETED_DATA: + case C_READ_ID: + //case C_READ_DELETED_DATA: + case C_FORMAT_TRACK: + case C_SEEK: + // start the motor + motor_control(command[1] & 0x3, true); + + // TODO: motor on delay + //if(motor_on_counter > 0) + break; + } + + upd765_family_device::start_command(cmd); +} + +void i82072_device::execute_command(int cmd) +{ + switch(cmd) { + case C_DUMP_REG: + upd765_family_device::execute_command(cmd); + + // i82072 dumps motor configuration at offset 7 + result[7] = motorcfg; + break; + + case C_MOTOR_ONOFF: { + bool motor_on = command[0] & 0x80; + floppy_info &fi = flopi[(command[0] >> 5) & 0x3]; + + LOG("command motor %s drive %d\n", motor_on ? "on" : "off", fi.id); + + // select the drive + if(motor_on) + set_ds(fi.id); + + // start the motor + if(fi.dev) + fi.dev->mon_w(motor_on ? 0 : 1); + + main_phase = PHASE_CMD; + break; + } + + case C_SPECIFY: + /* + * The InterPro 2000 expects the sense interrupt status command to return + * the status of a completed recalibrate or seek operation instead of a + * pending drive poll status after a soft reset. This behaviour does not + * seem to match any of the other upd765 devices, and without hardware, + * it's difficult to know exactly how it works at this point. + * + * For now, reproduce the expected behaviour by clearing pending drive + * poll results in the specify command, giving two different result + * pathways (both present in InterPro boot code): + * + * 1. reset, poll, sense interrupt status -> drive poll status + * 2. reset, poll, specify, recalibrate, sense interrupt status -> recalibrate status + * + * Possible alternatives include: + * + * 1. Clearing pending status during all command execution. + * 2. Returning results in LIFO order. + * 3. Returning results in priority order (where recalibrate/seek is "higher" priority than poll) + */ + + // clear pending interrupts and fall through + for(floppy_info &fi : flopi) + fi.st0_filled = false; + + default: + upd765_family_device::execute_command(cmd); + break; + } +} + +void i82072_device::motor_control(int fid, bool start_motor) +{ + // check if motor control is enabled + if(motorcfg == 0) + return; + + floppy_info &fi = flopi[fid]; + + if(start_motor) { + // if we are selecting a different drive, stop the motor on the previously selected drive + if(selected_drive != fid && flopi[selected_drive].dev && flopi[selected_drive].dev->mon_r() == 0) + flopi[selected_drive].dev->mon_w(1); + + // start the motor on the selected drive + if(fi.dev && fi.dev->mon_r() == 1) { + LOG("motor_control: switching on motor for drive %d\n", fid); + + // select the drive and enable the motor + set_ds(fid); + fi.dev->mon_w(0); + + // set motor on counter + motor_on_counter = (motorcfg & MON) << (motorcfg & HSDA ? 1 : 0); + } + + // FIXME: reset motor off timer on command end, not start + motor_off_counter = (2 + ((motorcfg & MOFF) >> 4)) << (motorcfg & HSDA ? 1 : 0); + } else { + // motor off timer only applies to the selected drive + if(selected_drive != fid) + return; + + // decrement motor on counter + if(motor_on_counter) + motor_on_counter--; + + // ignore motor off timer while drive is busy + if(fi.main_state == SEEK || fi.main_state == RECALIBRATE) + return; + + // check if the motor is already off + if(motor_off_counter == 0 || (fi.dev && fi.dev->mon_r() == 1)) + return; + + // decrement the counter + motor_off_counter--; + + // if the motor off timer has expired, stop the motor + if(motor_off_counter == 0 && fi.dev) { + LOG("motor_control: switching off motor for drive %d\n", fid); + fi.dev->mon_w(1); + } + } +} + +void i82072_device::index_callback(floppy_image_device *floppy, int state) +{ + for(floppy_info &fi : flopi) { + if(fi.dev != floppy) + continue; + + // update motor on/off counters and stop motor if necessary + motor_control(fi.id, false); + } + + upd765_family_device::index_callback(floppy, state); +} + smc37c78_device::smc37c78_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : upd765_family_device(mconfig, SMC37C78, tag, owner, clock) { ready_connected = false; @@ -2553,8 +2750,7 @@ WRITE8_MEMBER(tc8566af_device::cr1_w) { m_cr1 = data; - if (m_cr1 & 0x02) - { + if(m_cr1 & 0x02) { // Not sure if this inverted or not tc_w((m_cr1 & 0x01) ? true : false); } diff --git a/src/devices/machine/upd765.h b/src/devices/machine/upd765.h index 067551dbe8f..149f956c38b 100644 --- a/src/devices/machine/upd765.h +++ b/src/devices/machine/upd765.h @@ -142,7 +142,7 @@ public: void set_ready_line_connected(bool ready); void set_select_lines_connected(bool select); void set_floppy(floppy_image_device *image); - void soft_reset(); + virtual void soft_reset(); protected: upd765_family_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); @@ -332,11 +332,12 @@ protected: bool fifo_write; uint8_t dor, dsr, msr, fifo[16], command[16], result[16]; uint8_t st1, st2, st3; - uint8_t fifocfg, dor_reset; + uint8_t fifocfg, motorcfg, dor_reset; uint8_t precomp, perpmode; uint16_t spec; int sector_size; int cur_rate; + int selected_drive; emu_timer *poll_timer; @@ -361,6 +362,7 @@ protected: C_SCAN_EQUAL, C_SCAN_LOW, C_SCAN_HIGH, + C_MOTOR_ONOFF, C_INVALID, C_INCOMPLETE @@ -373,7 +375,7 @@ protected: uint8_t fifo_pop(bool internal); void set_drq(bool state); bool get_ready(int fid); - void set_ds(int state); + void set_ds(int fid); void enable_transfer(); void disable_transfer(); @@ -381,8 +383,9 @@ protected: void run_drive_ready_polling(); - int check_command(); - void start_command(int cmd); + virtual int check_command(); + virtual void start_command(int cmd); + virtual void execute_command(int cmd); void command_end(floppy_info &fi, bool data_completion); void recalibrate_start(floppy_info &fi); @@ -407,7 +410,7 @@ protected: void scan_start(floppy_info &fi); void general_continue(floppy_info &fi); - void index_callback(floppy_image_device *floppy, int state); + virtual void index_callback(floppy_image_device *floppy, int state); bool sector_matches() const; void live_start(floppy_info &fi, int live_state); @@ -451,6 +454,27 @@ public: i82072_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); virtual DECLARE_ADDRESS_MAP(map, 8) override; + +protected: + virtual void device_start() override; + + enum motorcfg_mask + { + MON = 0x0f, // motor on delay + MOFF = 0x70, // motor off delay + HSDA = 0x80 // high speed disk adjust + }; + + virtual void soft_reset() override; + virtual int check_command() override; + virtual void start_command(int cmd) override; + virtual void execute_command(int cmd) override; + virtual void index_callback(floppy_image_device *floppy, int state) override; + + void motor_control(int fid, bool start_motor); + + u8 motor_off_counter; + u8 motor_on_counter; }; class smc37c78_device : public upd765_family_device { |