diff options
Diffstat (limited to 'src/devices/machine/upd765.cpp')
-rw-r--r-- | src/devices/machine/upd765.cpp | 422 |
1 files changed, 330 insertions, 92 deletions
diff --git a/src/devices/machine/upd765.cpp b/src/devices/machine/upd765.cpp index 64739ff5a6e..694a32b0999 100644 --- a/src/devices/machine/upd765.cpp +++ b/src/devices/machine/upd765.cpp @@ -20,7 +20,7 @@ #define LOG_LIVE (1U << 12) // Live states #define LOG_DONE (1U << 13) // Command done -#define VERBOSE (LOG_GENERAL | LOG_WARN ) +#define VERBOSE (LOG_GENERAL | LOG_WARN) #include "logmacro.h" @@ -53,9 +53,11 @@ DEFINE_DEVICE_TYPE(N82077AA, n82077aa_device, "n82077aa", "Int DEFINE_DEVICE_TYPE(PC_FDC_SUPERIO, pc_fdc_superio_device, "pc_fdc_superio", "Winbond PC FDC Super I/O") DEFINE_DEVICE_TYPE(DP8473, dp8473_device, "dp8473", "National Semiconductor DP8473 FDC") DEFINE_DEVICE_TYPE(PC8477A, pc8477a_device, "pc8477a", "National Semiconductor PC8477A FDC") +DEFINE_DEVICE_TYPE(PC8477B, pc8477b_device, "pc8477b", "National Semiconductor PC8477B FDC") DEFINE_DEVICE_TYPE(WD37C65C, wd37c65c_device, "wd37c65c", "Western Digital WD37C65C FDC") DEFINE_DEVICE_TYPE(MCS3201, mcs3201_device, "mcs3201", "Motorola MCS3201 FDC") DEFINE_DEVICE_TYPE(TC8566AF, tc8566af_device, "tc8566af", "Toshiba TC8566AF FDC") +DEFINE_DEVICE_TYPE(HD63266F, hd63266f_device, "hd63266f", "Hitachi HD63266F FDC") void upd765a_device::map(address_map &map) { @@ -139,6 +141,19 @@ void pc8477a_device::map(address_map &map) map(0x7, 0x7).rw(FUNC(pc8477a_device::dir_r), FUNC(pc8477a_device::ccr_w)); } +void pc8477b_device::map(address_map &map) +{ + if(mode != mode_t::AT) { + map(0x0, 0x0).r(FUNC(pc8477b_device::sra_r)); + map(0x1, 0x1).r(FUNC(pc8477b_device::srb_r)); + } + map(0x2, 0x2).rw(FUNC(pc8477b_device::dor_r), FUNC(pc8477b_device::dor_w)); + map(0x3, 0x3).rw(FUNC(pc8477b_device::tdr_r), FUNC(pc8477b_device::tdr_w)); + map(0x4, 0x4).rw(FUNC(pc8477b_device::msr_r), FUNC(pc8477b_device::dsr_w)); + map(0x5, 0x5).rw(FUNC(pc8477b_device::fifo_r), FUNC(pc8477b_device::fifo_w)); + map(0x7, 0x7).rw(FUNC(pc8477b_device::dir_r), FUNC(pc8477b_device::ccr_w)); +} + void wd37c65c_device::map(address_map &map) { // NOTE: this map only covers registers defined by CS. @@ -201,22 +216,13 @@ void ps2_fdc_device::set_mode(mode_t _mode) mode = _mode; } -void upd765_family_device::device_resolve_objects() -{ - intrq_cb.resolve_safe(); - drq_cb.resolve_safe(); - hdl_cb.resolve_safe(); - idx_cb.resolve_safe(); - us_cb.resolve_safe(); -} - void upd765_family_device::device_start() { save_item(NAME(selected_drive)); for(int i=0; i != 4; i++) { char name[2]; - flopi[i].tm = timer_alloc(i); + flopi[i].tm = timer_alloc(FUNC(upd765_family_device::update_floppy), this); flopi[i].id = i; if(select_connected) { name[0] = '0'+i; @@ -257,7 +263,7 @@ void upd765_family_device::device_start() cur_live.fi = nullptr; if(ready_polled) { - poll_timer = timer_alloc(TIMER_DRIVE_READY_POLLING); + poll_timer = timer_alloc(FUNC(upd765_family_device::run_drive_ready_polling), this); poll_timer->adjust(attotime::from_usec(100), 0, attotime::from_usec(1024)); } else poll_timer = nullptr; @@ -286,8 +292,7 @@ void upd765_family_device::soft_reset() flopi[i].st0_filled = false; } clr_drive_busy(); - data_irq = false; - other_irq = false; + irq = false; internal_drq = false; fifo_pos = 0; command_pos = 0; @@ -343,7 +348,7 @@ bool upd765_family_device::get_ready(int fid) return !external_ready; } -WRITE_LINE_MEMBER(upd765_family_device::reset_w) +void upd765_family_device::reset_w(int state) { // This implementation is not valid for devices with DOR and possibly other extra registers. // The working assumption is that no need to manipulate the RESET line directly when software can use DOR instead. @@ -396,8 +401,7 @@ void upd765_family_device::set_floppy(floppy_image_device *flop) uint8_t ps2_fdc_device::sra_r() { uint8_t sra = 0; - int fid = dor & 3; - floppy_info &fi = flopi[fid]; + floppy_info &fi = flopi[dor & 3]; if(fi.dir) sra |= 0x01; if(fi.index) @@ -408,17 +412,38 @@ uint8_t ps2_fdc_device::sra_r() sra |= 0x10; if(fi.main_state == SEEK_WAIT_STEP_SIGNAL_TIME) sra |= 0x20; - sra |= 0x40; if(cur_irq) sra |= 0x80; if(mode == mode_t::M30) + { sra ^= 0x1f; + if(drq) + sra |= 0x40; + } + else + { + if(!flopi[1].dev) + sra |= 0x40; + } return sra; } uint8_t ps2_fdc_device::srb_r() { - return 0; + uint8_t srb = 0; + // TODO: rddata, wrdata, write enable bits + if(mode == mode_t::M30) + { + const uint8_t ds[4] = { 0x43, 0x23, 0x62, 0x61 }; + srb = ds[dor & 3]; + if(!flopi[1].dev) + srb |= 0x80; + } + else + { + srb = 0xc0 | ((dor & 1) << 6) | ((dor & 0x30) >> 4); + } + return srb; } uint8_t upd765_family_device::dor_r() @@ -458,7 +483,7 @@ void upd765_family_device::tdr_w(uint8_t data) uint8_t upd765_family_device::msr_r() { - uint32_t msr = 0; + uint8_t msr = 0; switch(main_phase) { case PHASE_CMD: msr |= MSR_RQM; @@ -487,11 +512,6 @@ uint8_t upd765_family_device::msr_r() } msr |= get_drive_busy(); - if(data_irq && !machine().side_effects_disabled()) { - data_irq = false; - check_irq(); - } - return msr; } @@ -512,13 +532,25 @@ void upd765_family_device::set_rate(int rate) uint8_t upd765_family_device::fifo_r() { uint8_t r = 0xff; + if(!machine().side_effects_disabled()) + { + irq = false; + check_irq(); + } switch(main_phase) { + case PHASE_CMD: + if(machine().side_effects_disabled()) + return 0xff; + if(command_pos) + fifo_w(0xff); + LOGFIFO("fifo_r in command phase\n"); + break; case PHASE_EXEC: if(machine().side_effects_disabled()) return fifo[0]; if(internal_drq) return fifo_pop(false); - LOGFIFO("fifo_r in phase %d\n", main_phase); + LOGFIFO("fifo_r in execution phase\n"); break; case PHASE_RESULT: @@ -550,11 +582,12 @@ void upd765_family_device::fifo_w(uint8_t data) if(!BIT(dor, 2)) LOGWARN("%s: fifo_w(%02x) in reset\n", machine().describe_context(), data); + irq = false; + check_irq(); + switch(main_phase) { case PHASE_CMD: { command[command_pos++] = data; - other_irq = false; - check_irq(); int cmd = check_command(); if(cmd == C_INCOMPLETE) break; @@ -574,7 +607,7 @@ void upd765_family_device::fifo_w(uint8_t data) fifo_push(data, false); return; } - LOGFIFO("fifo_w in phase %d\n", main_phase); + LOGFIFO("fifo_w in execution phase\n"); break; default: @@ -619,11 +652,10 @@ void upd765_family_device::enable_transfer() check_irq(); } - } else { - // DMA - if(!drq) - set_drq(true); } + // DMA + if(!drq) + set_drq(true); } void upd765_family_device::disable_transfer() @@ -631,8 +663,8 @@ void upd765_family_device::disable_transfer() if(spec & SPEC_ND) { internal_drq = false; check_irq(); - } else - set_drq(false); + } + set_drq(false); } void upd765_family_device::fifo_push(uint8_t data, bool internal) @@ -743,7 +775,7 @@ void upd765_family_device::live_delay(int state) { cur_live.next_state = state; if(cur_live.tm != machine().time()) - cur_live.fi->tm->adjust(cur_live.tm - machine().time()); + cur_live.fi->tm->adjust(cur_live.tm - machine().time(), cur_live.fi->id); else live_sync(); } @@ -807,7 +839,7 @@ void upd765_family_device::live_run(attotime limit) // infinity looking for data too. limit = machine().time() + attotime::from_msec(1); - cur_live.fi->tm->adjust(attotime::from_msec(1)); + cur_live.fi->tm->adjust(attotime::from_msec(1), cur_live.fi->id); } } @@ -1301,17 +1333,31 @@ int upd765_family_device::check_command() // MSDOS 6.22 format uses 0xcd to format a track, which makes one // think only the bottom 5 bits are decoded. + // The real 765 completely decodes the commands that don't have + // variable upper bits. Some later superio chips don't. + // The MCS Powerview depends on this. - switch(command[0] & 0x1f) { - case 0x02: - return command_pos == 9 ? C_READ_TRACK : C_INCOMPLETE; - + switch(command[0]) { case 0x03: return command_pos == 3 ? C_SPECIFY : C_INCOMPLETE; case 0x04: return command_pos == 2 ? C_SENSE_DRIVE_STATUS : C_INCOMPLETE; + case 0x07: + return command_pos == 2 ? C_RECALIBRATE : C_INCOMPLETE; + + case 0x08: + return C_SENSE_INTERRUPT_STATUS; + + case 0x0f: + return command_pos == 3 ? C_SEEK : C_INCOMPLETE; + } + + switch(command[0] & 0x1f) { + case 0x02: + return command_pos == 9 ? C_READ_TRACK : C_INCOMPLETE; + case 0x05: case 0x09: return command_pos == 9 ? C_WRITE_DATA : C_INCOMPLETE; @@ -1320,21 +1366,12 @@ int upd765_family_device::check_command() case 0x0c: return command_pos == 9 ? C_READ_DATA : C_INCOMPLETE; - case 0x07: - return command_pos == 2 ? C_RECALIBRATE : C_INCOMPLETE; - - case 0x08: - return C_SENSE_INTERRUPT_STATUS; - case 0x0a: return command_pos == 2 ? C_READ_ID : C_INCOMPLETE; case 0x0d: return command_pos == 6 ? C_FORMAT_TRACK : C_INCOMPLETE; - case 0x0f: - return command_pos == 3 ? C_SEEK : C_INCOMPLETE; - case 0x11: return command_pos == 9 ? C_SCAN_EQUAL : C_INCOMPLETE; @@ -1464,8 +1501,6 @@ void upd765_family_device::execute_command(int cmd) LOGCOMMAND("command sense interrupt status (fid=%d %02x %02x) (%s)\n", fid, result[0], result[1], machine().describe_context()); result_pos = 2; - other_irq = false; - check_irq(); break; } @@ -1549,12 +1584,9 @@ void upd765_family_device::command_end(floppy_info &fi, bool data_completion) { LOGDONE("command done (%s) - %s\n", data_completion ? "data" : "seek", results()); fi.main_state = fi.sub_state = IDLE; - if(data_completion) - data_irq = true; - else { - other_irq = true; + irq = true; + if(!data_completion) fi.st0_filled = true; - } check_irq(); } @@ -1594,9 +1626,9 @@ void upd765_family_device::seek_start(floppy_info &fi) seek_continue(fi); } -void upd765_family_device::delay_cycles(emu_timer *tm, int cycles) +void upd765_family_device::delay_cycles(floppy_info &fi, int cycles) { - tm->adjust(attotime::from_double(double(cycles)/cur_rate)); + fi.tm->adjust(attotime::from_double(double(cycles)/cur_rate), fi.id); } void upd765_family_device::seek_continue(floppy_info &fi) @@ -1610,7 +1642,7 @@ void upd765_family_device::seek_continue(floppy_info &fi) fi.dev->stp_w(0); } fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME; - fi.tm->adjust(attotime::from_nsec(2500)); + fi.tm->adjust(attotime::from_nsec(2500), fi.id); return; case SEEK_WAIT_STEP_SIGNAL_TIME: @@ -1629,7 +1661,7 @@ void upd765_family_device::seek_continue(floppy_info &fi) fi.pcn++; } fi.sub_state = SEEK_WAIT_STEP_TIME; - delay_cycles(fi.tm, 500*(16-(spec >> 12))); + delay_cycles(fi, 500*(16-(spec >> 12))); return; case SEEK_WAIT_STEP_TIME: @@ -1660,7 +1692,7 @@ void upd765_family_device::seek_continue(floppy_info &fi) if(done) { fi.sub_state = SEEK_WAIT_DONE; // recalibrate and seek takes some time, even if we don't move - fi.tm->adjust(attotime::from_nsec((fi.main_state == RECALIBRATE) ? 20000 : 10000)); + fi.tm->adjust(attotime::from_nsec((fi.main_state == RECALIBRATE) ? 20000 : 10000), fi.id); return; } fi.sub_state = SEEK_MOVE; @@ -1772,12 +1804,12 @@ void upd765_family_device::read_data_continue(floppy_info &fi) switch(fi.sub_state) { case HEAD_LOAD: LOGSTATE("HEAD_LOAD\n"); - delay_cycles(fi.tm, 500*(spec & 0x00fe)); + delay_cycles(fi, 500*(spec & 0x00fe)); fi.sub_state = HEAD_LOAD_DONE; break; case HEAD_LOAD_DONE: LOGSTATE("HEAD_LOAD_DONE\n"); - if(fi.pcn == command[2] || !(fifocfg & 0x40)) { + if(fi.pcn == command[2] || !(fifocfg & FIF_EIS)) { fi.sub_state = SEEK_DONE; break; } @@ -1787,7 +1819,7 @@ void upd765_family_device::read_data_continue(floppy_info &fi) fi.dev->stp_w(0); } fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME; - fi.tm->adjust(attotime::from_nsec(2500)); + fi.tm->adjust(attotime::from_nsec(2500), fi.id); return; case SEEK_WAIT_STEP_SIGNAL_TIME: @@ -1800,7 +1832,7 @@ void upd765_family_device::read_data_continue(floppy_info &fi) fi.dev->stp_w(1); fi.sub_state = SEEK_WAIT_STEP_TIME; - delay_cycles(fi.tm, 500*(16-(spec >> 12))); + delay_cycles(fi, 500*(16-(spec >> 12))); return; case SEEK_WAIT_STEP_TIME: @@ -1854,6 +1886,7 @@ void upd765_family_device::read_data_continue(floppy_info &fi) return; } st1 &= ~ST1_ND; + st2 &= ~ST2_WC; LOGRW("reading sector %02x %02x %02x %02x\n", cur_live.idbuf[0], cur_live.idbuf[1], @@ -1985,6 +2018,14 @@ void upd765_family_device::write_data_start(floppy_info &fi) write_data_continue(fi); return; } + else if(fi.dev && fi.dev->wpt_r()) { + fi.st0 |= ST0_FAIL; + fi.sub_state = COMMAND_DONE; + st1 = ST1_NW; + st2 = 0; + write_data_continue(fi); + return; + } write_data_continue(fi); } @@ -1995,7 +2036,7 @@ void upd765_family_device::write_data_continue(floppy_info &fi) switch(fi.sub_state) { case HEAD_LOAD: LOGSTATE("HEAD_LOAD\n"); - delay_cycles(fi.tm, 500*(spec & 0x00fe)); + delay_cycles(fi, 500*(spec & 0x00fe)); fi.sub_state = HEAD_LOAD_DONE; break; case HEAD_LOAD_DONE: @@ -2136,12 +2177,12 @@ void upd765_family_device::read_track_continue(floppy_info &fi) switch(fi.sub_state) { case HEAD_LOAD: LOGSTATE("HEAD_LOAD\n"); - delay_cycles(fi.tm, 500*(spec & 0x00fe)); + delay_cycles(fi, 500*(spec & 0x00fe)); fi.sub_state = HEAD_LOAD_DONE; break; case HEAD_LOAD_DONE: LOGSTATE("HEAD_LOAD_DONE\n"); - if(fi.pcn == command[2] || !(fifocfg & 0x40)) { + if(fi.pcn == command[2] || !(fifocfg & FIF_EIS)) { fi.sub_state = SEEK_DONE; break; } @@ -2151,7 +2192,7 @@ void upd765_family_device::read_track_continue(floppy_info &fi) fi.dev->stp_w(0); } fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME; - fi.tm->adjust(attotime::from_nsec(2500)); + fi.tm->adjust(attotime::from_nsec(2500), fi.id); return; case SEEK_WAIT_STEP_SIGNAL_TIME: @@ -2164,7 +2205,7 @@ void upd765_family_device::read_track_continue(floppy_info &fi) fi.dev->stp_w(1); fi.sub_state = SEEK_WAIT_STEP_TIME; - delay_cycles(fi.tm, 500*(16-(spec >> 12))); + delay_cycles(fi, 500*(16-(spec >> 12))); return; case SEEK_WAIT_STEP_TIME: @@ -2295,12 +2336,21 @@ void upd765_family_device::format_track_start(floppy_info &fi) set_ds(command[1] & 3); fi.ready = get_ready(command[1] & 3); + st1 = 0; + st2 = 0; if(!fi.ready) { fi.st0 = (command[1] & 7) | ST0_NR | ST0_FAIL; fi.sub_state = TRACK_DONE; format_track_continue(fi); return; } + else if(fi.dev && fi.dev->wpt_r()) { + fi.st0 = (command[1] & 7) | ST0_FAIL; + fi.sub_state = TRACK_DONE; + st1 = ST1_NW; + format_track_continue(fi); + return; + } fi.st0 = command[1] & 7; if(fi.dev) @@ -2316,7 +2366,7 @@ void upd765_family_device::format_track_continue(floppy_info &fi) switch(fi.sub_state) { case HEAD_LOAD: LOGSTATE("HEAD_LOAD\n"); - delay_cycles(fi.tm, 500*(spec & 0x00fe)); + delay_cycles(fi, 500*(spec & 0x00fe)); fi.sub_state = HEAD_LOAD_DONE; break; case HEAD_LOAD_DONE: @@ -2340,8 +2390,8 @@ void upd765_family_device::format_track_continue(floppy_info &fi) LOGSTATE("TRACK_DONE\n"); main_phase = PHASE_RESULT; result[0] = fi.st0; - result[1] = 0; - result[2] = 0; + result[1] = st1; + result[2] = st2; result[3] = 0; result[4] = 0; result[5] = 0; @@ -2401,7 +2451,7 @@ void upd765_family_device::read_id_continue(floppy_info &fi) switch(fi.sub_state) { case HEAD_LOAD: LOGSTATE("HEAD_LOAD\n"); - delay_cycles(fi.tm, 500*(spec & 0x00fe)); + delay_cycles(fi, 500*(spec & 0x00fe)); fi.sub_state = HEAD_LOAD_DONE; break; case HEAD_LOAD_DONE: @@ -2452,7 +2502,7 @@ void upd765_family_device::read_id_continue(floppy_info &fi) void upd765_family_device::check_irq() { bool old_irq = cur_irq; - cur_irq = data_irq || other_irq || internal_drq; + cur_irq = irq || internal_drq; cur_irq = cur_irq && (dor & 4) && (mode != mode_t::AT || (dor & 8)); if(cur_irq != old_irq) { LOGTCIRQ("irq = %d\n", cur_irq); @@ -2485,16 +2535,11 @@ std::string upd765_family_device::ttsn() const return machine().time().to_string(); } -void upd765_family_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +TIMER_CALLBACK_MEMBER(upd765_family_device::update_floppy) { - if(id == TIMER_DRIVE_READY_POLLING) { - run_drive_ready_polling(); - return; - } - live_sync(); - floppy_info &fi = flopi[id]; + floppy_info &fi = flopi[param]; switch(fi.sub_state) { case SEEK_WAIT_STEP_SIGNAL_TIME: fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME_DONE; @@ -2507,7 +2552,7 @@ void upd765_family_device::device_timer(emu_timer &timer, device_timer_id id, in general_continue(fi); } -void upd765_family_device::run_drive_ready_polling() +TIMER_CALLBACK_MEMBER(upd765_family_device::run_drive_ready_polling) { if(main_phase != PHASE_CMD || (fifocfg & FIF_POLL) || command_pos) return; @@ -2520,7 +2565,7 @@ void upd765_family_device::run_drive_ready_polling() if(!flopi[fid].st0_filled) { flopi[fid].st0 = ST0_ABRT | fid; flopi[fid].st0_filled = true; - other_irq = true; + irq = true; } } } @@ -3095,6 +3140,14 @@ dp8473_device::dp8473_device(const machine_config &mconfig, const char *tag, dev recalibrate_steps = 77; // TODO: 3917 in extended track range mode } +void dp8473_device::soft_reset() +{ + upd765_family_device::soft_reset(); + + // "interrupt is generated when ... Internal Ready signal changes state immediately after a hardware or software reset" + irq = true; +} + pc8477a_device::pc8477a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : ps2_fdc_device(mconfig, PC8477A, tag, owner, clock) { ready_polled = true; @@ -3104,6 +3157,15 @@ pc8477a_device::pc8477a_device(const machine_config &mconfig, const char *tag, d recalibrate_steps = 85; // TODO: may also be programmed as 255, 3925 or 4095 by (unemulated) mode command } +pc8477b_device::pc8477b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : ps2_fdc_device(mconfig, PC8477B, tag, owner, clock) +{ + ready_polled = true; + ready_connected = false; + select_connected = true; + select_multiplexed = false; + recalibrate_steps = 85; // TODO: may also be programmed as 255, 3925 or 4095 by (unemulated) mode command +} + wd37c65c_device::wd37c65c_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : upd765_family_device(mconfig, WD37C65C, tag, owner, clock), m_clock2(0) @@ -3129,7 +3191,7 @@ uint8_t wd37c65c_device::get_st3(floppy_info &fi) mcs3201_device::mcs3201_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : upd765_family_device(mconfig, MCS3201, tag, owner, clock), - m_input_handler(*this) + m_input_handler(*this, 0) { has_dor = true; ready_polled = false; @@ -3138,12 +3200,6 @@ mcs3201_device::mcs3201_device(const machine_config &mconfig, const char *tag, d select_multiplexed = false; } -void mcs3201_device::device_start() -{ - upd765_family_device::device_start(); - m_input_handler.resolve_safe(0); -} - uint8_t mcs3201_device::input_r() { return m_input_handler(); @@ -3223,3 +3279,185 @@ void upd72067_device::auxcmd_w(uint8_t data) break; } } + +void upd72069_device::auxcmd_w(uint8_t data) +{ + switch(data) { + case 0x36: // reset + soft_reset(); + break; + case 0x1e: // motor on, probably + for(unsigned i = 0; i < 4; i++) + if(flopi[i].dev) + flopi[i].dev->mon_w(!BIT(data, i + 4)); + main_phase = PHASE_RESULT; + result[0] = ST0_UNK; + result_pos = 1; + break; + } +} + + +hd63266f_device::hd63266f_device(const machine_config& mconfig, const char *tag, device_t *owner, uint32_t clock) + : upd765_family_device(mconfig, HD63266F, tag, owner, clock) + , inp_cb(*this, 0) +{ + has_dor = false; +} + +void hd63266f_device::map(address_map &map) +{ + map(0x0, 0x0).rw(FUNC(hd63266f_device::msr_r), FUNC(hd63266f_device::abort_w)); + map(0x1, 0x1).rw(FUNC(hd63266f_device::fifo_r), FUNC(hd63266f_device::fifo_w)); + map(0x2, 0x2).r(FUNC(hd63266f_device::extstat_r)); +} + +void hd63266f_device::soft_reset() +{ + upd765_family_device::soft_reset(); + delayed_command = 0; + motor_state = 0; + for(int i = 0; i < 4; i++) + if(flopi[i].dev) flopi[i].dev->mon_w(1); +} + +void hd63266f_device::abort_w(u8 data) +{ + if(data == 0xff) { + soft_reset(); + LOGCOMMAND("abort\n"); + } +} + +int hd63266f_device::check_command() +{ + switch(command[0]) { + case 0x0e: + return C_SLEEP; + case 0x0b: + case 0x2b: + return command_pos == 4 ? C_SPECIFY : C_INCOMPLETE; + case 0x4b: + case 0x6b: + return command_pos == 7 ? C_SPECIFY2 : C_INCOMPLETE; + } + return upd765_family_device::check_command(); +} + +void hd63266f_device::execute_command(int cmd) +{ + switch(cmd) + { + case C_SLEEP: + for(int i = 0; i < 4; i++) { + if(flopi[i].dev) flopi[i].dev->mon_w(1); + } + main_phase = PHASE_CMD; + motor_state = 0; + LOGCOMMAND("sleep\n"); + break; + case C_SPECIFY2: + spec = (command[1] << 8) | command[2]; + LOGCOMMAND("command specify2 %02x %02x: step_rate=%d ms, head_unload=%d ms, head_load=%d ms, non_dma=%s\n", + command[1], command[2], 16-(command[1]>>4), (command[1]&0x0f)<<4, command[2]&0xfe, ((command[2]&1)==1)? "true":"false"); + main_phase = PHASE_CMD; + break; + case C_SENSE_DRIVE_STATUS: + upd765_family_device::execute_command(cmd); + if(!inp_cb.isunset()) + result[0] = (result[0] & ~ST3_TS) | (inp_cb() ? 0 : 8); + break; + default: + upd765_family_device::execute_command(cmd); + break; + } +} + +u8 hd63266f_device::extstat_r() +{ + return (irq << 6) | motor_state; +} + +// no documentation for motor control so borrow some of 82072 +void hd63266f_device::start_command(int cmd) +{ + // check if the command specifies a target drive + switch(cmd) { + case C_READ_TRACK: + 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); + break; + default: + motor_on_counter = 0; + break; + } + + // execute the command immediately if there's no motor on delay + if(motor_on_counter == 0) { + upd765_family_device::start_command(cmd); + } else + delayed_command = cmd; +} + +void hd63266f_device::motor_control(int fid, bool start_motor) +{ + 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) { + LOGCOMMAND("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); + motor_on_counter = 3; + motor_state |= 1 << fid; + } + } else { + // motor off timer only applies to the selected drive + if(selected_drive != fid) + return; + + logerror("motor_on_counter %d\n", motor_on_counter); + // decrement motor on counter + if(motor_on_counter) + motor_on_counter--; + + // execute the command if the motor on counter has expired + if(motor_on_counter == 0 && main_phase == PHASE_CMD && delayed_command) { + upd765_family_device::start_command(delayed_command); + + delayed_command = 0; + + return; + } + } +} + +void hd63266f_device::index_callback(floppy_image_device *floppy, int state) +{ + if(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); +} + |