summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/upd765.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/upd765.cpp')
-rw-r--r--src/devices/machine/upd765.cpp811
1 files changed, 595 insertions, 216 deletions
diff --git a/src/devices/machine/upd765.cpp b/src/devices/machine/upd765.cpp
index 37a71638dca..51f6d0de63d 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"
@@ -48,14 +48,16 @@ DEFINE_DEVICE_TYPE(UPD72065, upd72065_device, "upd72065", "NEC
DEFINE_DEVICE_TYPE(UPD72067, upd72067_device, "upd72067", "NEC uPD72067 FDC")
DEFINE_DEVICE_TYPE(UPD72069, upd72069_device, "upd72069", "NEC uPD72069 FDC")
DEFINE_DEVICE_TYPE(I82072, i82072_device, "i82072", "Intel 82072 FDC")
-DEFINE_DEVICE_TYPE(SMC37C78, smc37c78_device, "smc37c78", "SMC FDC73C78 FDC")
+DEFINE_DEVICE_TYPE(SMC37C78, smc37c78_device, "smc37c78", "SMC FDC37C78 FDC")
DEFINE_DEVICE_TYPE(N82077AA, n82077aa_device, "n82077aa", "Intel N82077AA FDC")
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)
{
@@ -98,8 +100,10 @@ void smc37c78_device::map(address_map &map)
void n82077aa_device::map(address_map &map)
{
- map(0x0, 0x0).r(FUNC(n82077aa_device::sra_r));
- map(0x1, 0x1).r(FUNC(n82077aa_device::srb_r));
+ if(mode != mode_t::AT) {
+ map(0x0, 0x0).r(FUNC(n82077aa_device::sra_r));
+ map(0x1, 0x1).r(FUNC(n82077aa_device::srb_r));
+ }
map(0x2, 0x2).rw(FUNC(n82077aa_device::dor_r), FUNC(n82077aa_device::dor_w));
map(0x3, 0x3).rw(FUNC(n82077aa_device::tdr_r), FUNC(n82077aa_device::tdr_w));
map(0x4, 0x4).rw(FUNC(n82077aa_device::msr_r), FUNC(n82077aa_device::dsr_w));
@@ -109,30 +113,27 @@ void n82077aa_device::map(address_map &map)
void pc_fdc_superio_device::map(address_map &map)
{
- map(0x0, 0x0).r(FUNC(pc_fdc_superio_device::sra_r));
- map(0x1, 0x1).r(FUNC(pc_fdc_superio_device::srb_r));
- map(0x2, 0x2).rw(FUNC(pc_fdc_superio_device::dor_r), FUNC(pc_fdc_superio_device::dor_w));
- map(0x3, 0x3).rw(FUNC(pc_fdc_superio_device::tdr_r), FUNC(pc_fdc_superio_device::tdr_w));
- map(0x4, 0x4).rw(FUNC(pc_fdc_superio_device::msr_r), FUNC(pc_fdc_superio_device::dsr_w));
+ map(0x2, 0x2).w(FUNC(pc_fdc_superio_device::dor_w));
+ map(0x3, 0x3).w(FUNC(pc_fdc_superio_device::tdr_w));
+ map(0x4, 0x4).r(FUNC(pc_fdc_superio_device::msr_r));
map(0x5, 0x5).rw(FUNC(pc_fdc_superio_device::fifo_r), FUNC(pc_fdc_superio_device::fifo_w));
map(0x7, 0x7).rw(FUNC(pc_fdc_superio_device::dir_r), FUNC(pc_fdc_superio_device::ccr_w));
}
void dp8473_device::map(address_map &map)
{
- map(0x0, 0x0).r(FUNC(dp8473_device::sra_r));
- map(0x1, 0x1).r(FUNC(dp8473_device::srb_r));
- map(0x2, 0x2).rw(FUNC(dp8473_device::dor_r), FUNC(dp8473_device::dor_w));
- map(0x3, 0x3).rw(FUNC(dp8473_device::tdr_r), FUNC(dp8473_device::tdr_w));
- map(0x4, 0x4).rw(FUNC(dp8473_device::msr_r), FUNC(dp8473_device::dsr_w));
+ map(0x2, 0x2).w(FUNC(dp8473_device::dor_w));
+ map(0x4, 0x4).r(FUNC(dp8473_device::msr_r));
map(0x5, 0x5).rw(FUNC(dp8473_device::fifo_r), FUNC(dp8473_device::fifo_w));
map(0x7, 0x7).rw(FUNC(dp8473_device::dir_r), FUNC(dp8473_device::ccr_w));
}
void pc8477a_device::map(address_map &map)
{
- map(0x0, 0x0).r(FUNC(pc8477a_device::sra_r));
- map(0x1, 0x1).r(FUNC(pc8477a_device::srb_r));
+ if(mode != mode_t::AT) {
+ map(0x0, 0x0).r(FUNC(pc8477a_device::sra_r));
+ map(0x1, 0x1).r(FUNC(pc8477a_device::srb_r));
+ }
map(0x2, 0x2).rw(FUNC(pc8477a_device::dor_r), FUNC(pc8477a_device::dor_w));
map(0x3, 0x3).rw(FUNC(pc8477a_device::tdr_r), FUNC(pc8477a_device::tdr_w));
map(0x4, 0x4).rw(FUNC(pc8477a_device::msr_r), FUNC(pc8477a_device::dsr_w));
@@ -140,8 +141,24 @@ 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.
+ // LDOR and LDCR must be mapped separately, since their addresses are
+ // defined only by external decoding circuits. LDIR (optional) is also separate.
map(0x0, 0x0).r(FUNC(wd37c65c_device::msr_r));
map(0x1, 0x1).rw(FUNC(wd37c65c_device::fifo_r), FUNC(wd37c65c_device::fifo_w));
}
@@ -167,19 +184,20 @@ void tc8566af_device::map(address_map &map)
constexpr int upd765_family_device::rates[4];
upd765_family_device::upd765_family_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
- pc_fdc_interface(mconfig, type, tag, owner, clock),
+ device_t(mconfig, type, tag, owner, clock),
ready_connected(true),
ready_polled(true),
select_connected(true),
select_multiplexed(true),
+ has_dor(true),
external_ready(false),
+ recalibrate_steps(77),
mode(mode_t::AT),
intrq_cb(*this),
drq_cb(*this),
hdl_cb(*this),
idx_cb(*this),
- us_cb(*this),
- dor_reset(0x00)
+ us_cb(*this)
{
}
@@ -193,28 +211,18 @@ void upd765_family_device::set_select_lines_connected(bool _select)
select_connected = _select;
}
-void upd765_family_device::set_mode(mode_t _mode)
+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(motorcfg));
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;
@@ -243,6 +251,7 @@ void upd765_family_device::device_start()
cur_rate = 250000;
tc = false;
selected_drive = -1;
+ dor = 0x0c;
// reset at upper levels may cause a write to tc ending up with
// live_sync, which will crash if the live structure isn't
@@ -254,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;
@@ -265,7 +274,8 @@ void upd765_family_device::device_start()
void upd765_family_device::device_reset()
{
- dor = dor_reset;
+ if(has_dor)
+ dor = 0x00;
locked = false;
soft_reset();
}
@@ -282,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;
@@ -302,6 +311,14 @@ void upd765_family_device::soft_reset()
set_ds(select_multiplexed ? 0 : -1);
check_irq();
+ if(BIT(dor, 2))
+ end_reset();
+ else if(ready_polled)
+ poll_timer->adjust(attotime::never);
+}
+
+void upd765_family_device::end_reset()
+{
if(ready_polled)
poll_timer->adjust(attotime::from_usec(100), 0, attotime::from_usec(1024));
}
@@ -331,6 +348,25 @@ bool upd765_family_device::get_ready(int fid)
return !external_ready;
}
+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.
+ assert(!has_dor);
+ if(bool(state) == !BIT(dor, 2))
+ return;
+
+ LOGREGS("reset = %d\n", state);
+ if(state) {
+ dor &= 0xfb;
+ soft_reset();
+ }
+ else {
+ dor |= 0x04;
+ end_reset();
+ }
+}
+
void upd765_family_device::set_ds(int fid)
{
if(selected_drive == fid)
@@ -362,11 +398,10 @@ void upd765_family_device::set_floppy(floppy_image_device *flop)
idx_cb(0);
}
-uint8_t upd765_family_device::sra_r()
+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)
@@ -377,17 +412,38 @@ uint8_t upd765_family_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 upd765_family_device::srb_r()
+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()
@@ -397,11 +453,16 @@ uint8_t upd765_family_device::dor_r()
void upd765_family_device::dor_w(uint8_t data)
{
+ assert(has_dor);
LOGREGS("dor = %02x\n", data);
uint8_t diff = dor ^ data;
dor = data;
- if(diff & 4)
- soft_reset();
+ if(BIT(diff, 2)) {
+ if(BIT(data, 2))
+ end_reset();
+ else
+ soft_reset();
+ }
for(int i=0; i<4; i++) {
floppy_info &fi = flopi[i];
@@ -451,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;
}
@@ -476,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 0x00;
+ 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:
@@ -511,11 +579,15 @@ uint8_t upd765_family_device::fifo_r()
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;
@@ -535,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:
@@ -580,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()
@@ -592,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)
@@ -640,8 +711,8 @@ uint8_t upd765_family_device::fifo_pop(bool internal)
memmove(fifo, fifo+1, fifo_pos);
if(!fifo_write && !fifo_pos)
disable_transfer();
- int thr = fifocfg & 15;
- if(fifo_write && fifo_expected && (fifo_pos <= thr || (fifocfg & 0x20)))
+ int thr = fifocfg & FIF_THR;
+ if(fifo_write && fifo_expected && (fifo_pos <= thr || (fifocfg & FIF_DIS)))
enable_transfer();
return r;
}
@@ -704,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();
}
@@ -768,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);
}
}
@@ -778,7 +849,7 @@ void upd765_family_device::live_run(attotime limit)
if(read_one_bit(limit))
return;
- LOGSHIFT("%s: shift = %04x data=%02x c=%d\n", tts(cur_live.tm), cur_live.shift_reg,
+ LOGSHIFT("%s: shift = %04x data=%02x c=%d\n", cur_live.tm.to_string(), cur_live.shift_reg,
(cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) |
(cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) |
(cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) |
@@ -794,7 +865,7 @@ void upd765_family_device::live_run(attotime limit)
cur_live.data_separator_phase = false;
cur_live.bit_counter = 0;
cur_live.state = READ_HEADER_BLOCK_HEADER;
- LOGLIVE("%s: Found A1\n", tts(cur_live.tm));
+ LOGLIVE("%s: Found A1\n", cur_live.tm.to_string());
}
if(!mfm && cur_live.shift_reg == 0xf57e) {
@@ -802,7 +873,7 @@ void upd765_family_device::live_run(attotime limit)
cur_live.data_separator_phase = false;
cur_live.bit_counter = 0;
cur_live.state = READ_ID_BLOCK;
- LOGLIVE("%s: Found IDAM\n", tts(cur_live.tm));
+ LOGLIVE("%s: Found IDAM\n", cur_live.tm.to_string());
}
break;
@@ -810,7 +881,7 @@ void upd765_family_device::live_run(attotime limit)
if(read_one_bit(limit))
return;
- LOGSHIFT("%s: shift = %04x data=%02x counter=%d\n", tts(cur_live.tm), cur_live.shift_reg,
+ LOGSHIFT("%s: shift = %04x data=%02x counter=%d\n", cur_live.tm.to_string(), cur_live.shift_reg,
(cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) |
(cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) |
(cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) |
@@ -830,11 +901,11 @@ void upd765_family_device::live_run(attotime limit)
if(cur_live.shift_reg != 0x4489)
cur_live.state = SEARCH_ADDRESS_MARK_HEADER;
else
- LOGLIVE("%s: Found A1\n", tts(cur_live.tm));
+ LOGLIVE("%s: Found A1\n", cur_live.tm.to_string());
break;
}
if(cur_live.data_reg != 0xfe) {
- LOGLIVE("%s: No ident byte found after triple-A1, continue search\n", tts(cur_live.tm));
+ LOGLIVE("%s: No ident byte found after triple-A1, continue search\n", cur_live.tm.to_string());
cur_live.state = SEARCH_ADDRESS_MARK_HEADER;
break;
}
@@ -852,7 +923,7 @@ void upd765_family_device::live_run(attotime limit)
break;
int slot = (cur_live.bit_counter >> 4)-1;
- LOGLIVE("%s: slot=%d data=%02x crc=%04x\n", tts(cur_live.tm), slot, cur_live.data_reg, cur_live.crc);
+ LOGLIVE("%s: slot=%d data=%02x crc=%04x\n", cur_live.tm.to_string(), slot, cur_live.data_reg, cur_live.crc);
cur_live.idbuf[slot] = cur_live.data_reg;
if(slot == 5) {
live_delay(IDLE);
@@ -865,7 +936,7 @@ void upd765_family_device::live_run(attotime limit)
if(read_one_bit(limit))
return;
- LOGSHIFT("%s: shift = %04x data=%02x c=%d.%x\n", tts(cur_live.tm), cur_live.shift_reg,
+ LOGSHIFT("%s: shift = %04x data=%02x c=%d.%x\n", cur_live.tm.to_string(), cur_live.shift_reg,
(cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) |
(cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) |
(cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) |
@@ -910,7 +981,7 @@ void upd765_family_device::live_run(attotime limit)
if(read_one_bit(limit))
return;
- LOGSHIFT("%s: shift = %04x data=%02x counter=%d\n", tts(cur_live.tm), cur_live.shift_reg,
+ LOGSHIFT("%s: shift = %04x data=%02x counter=%d\n", cur_live.tm.to_string(), cur_live.shift_reg,
(cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) |
(cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) |
(cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) |
@@ -938,6 +1009,13 @@ void upd765_family_device::live_run(attotime limit)
return;
}
+ if (
+ ((command[0] & 0x08) == 0 && cur_live.data_reg == 0xf8) // Encountered deleted sector during read data
+ || ((command[0] & 0x08) != 0 && cur_live.data_reg == 0xfb) // Encountered normal sector during read deleted data
+ ) {
+ st2 |= ST2_CM;
+ }
+
cur_live.bit_counter = 0;
cur_live.state = READ_SECTOR_DATA;
break;
@@ -1216,7 +1294,7 @@ void upd765_family_device::live_run(attotime limit)
break;
default:
- LOGWARN("%s: Unknown live state %d\n", tts(cur_live.tm), cur_live.state);
+ LOGWARN("%s: Unknown live state %d\n", cur_live.tm.to_string(), cur_live.state);
return;
}
}
@@ -1255,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;
@@ -1274,26 +1366,34 @@ 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 0x11:
+ return command_pos == 9 ? C_SCAN_EQUAL : C_INCOMPLETE;
+
+ case 0x19:
+ return command_pos == 9 ? C_SCAN_LOW : C_INCOMPLETE;
+
+ case 0x1d:
+ return command_pos == 9 ? C_SCAN_HIGH : C_INCOMPLETE;
+
+ default:
+ return C_INVALID;
+ }
+}
+
+int ps2_fdc_device::check_command()
+{
+ switch(command[0] & 0x1f) {
case 0x0e:
return C_DUMP_REG;
- case 0x0f:
- return command_pos == 3 ? C_SEEK : C_INCOMPLETE;
-
- case 0x11:
- return command_pos == 9 ? C_SCAN_EQUAL : C_INCOMPLETE;
+ case 0x10:
+ return C_VERSION;
case 0x12:
return command_pos == 2 ? C_PERPENDICULAR : C_INCOMPLETE;
@@ -1304,14 +1404,8 @@ int upd765_family_device::check_command()
case 0x14:
return C_LOCK;
- case 0x19:
- return command_pos == 9 ? C_SCAN_LOW : C_INCOMPLETE;
-
- case 0x1d:
- return command_pos == 9 ? C_SCAN_HIGH : C_INCOMPLETE;
-
default:
- return C_INVALID;
+ return upd765_family_device::check_command();
}
}
@@ -1328,51 +1422,10 @@ void upd765_family_device::start_command(int cmd)
void upd765_family_device::execute_command(int cmd)
{
switch(cmd) {
- case C_CONFIGURE:
- LOGCOMMAND("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:
- LOGCOMMAND("command dump regs\n");
- main_phase = PHASE_RESULT;
- result[0] = flopi[0].pcn;
- result[1] = flopi[1].pcn;
- result[2] = flopi[2].pcn;
- result[3] = flopi[3].pcn;
- result[4] = (spec & 0xff00) >> 8;
- result[5] = (spec & 0x00ff);
- result[6] = sector_size;
- result[7] = locked ? 0x80 : 0x00;
- result[7] |= (perpmode & 0x30);
- result[8] = fifocfg;
- result[9] = precomp;
- result_pos = 10;
- break;
-
case C_FORMAT_TRACK:
format_track_start(flopi[command[1] & 3]);
break;
- case C_LOCK:
- locked = command[0] & 0x80;
- main_phase = PHASE_RESULT;
- result[0] = locked ? 0x10 : 0x00;
- result_pos = 1;
- LOGCOMMAND("command lock (%s)\n", locked ? "on" : "off");
- break;
-
- case C_PERPENDICULAR:
- LOGCOMMAND("command perpendicular\n");
- perpmode = command[1];
- main_phase = PHASE_CMD;
- break;
-
case C_READ_DATA:
read_data_start(flopi[command[1] & 3]);
break;
@@ -1404,14 +1457,7 @@ void upd765_family_device::execute_command(int cmd)
case C_SENSE_DRIVE_STATUS: {
floppy_info &fi = flopi[command[1] & 3];
main_phase = PHASE_RESULT;
- result[0] = command[1] & 7;
- if(fi.ready)
- result[0] |= ST3_RY;
- if(fi.dev)
- result[0] |=
- (fi.dev->wpt_r() ? ST3_WP : 0x00) |
- (fi.dev->trk00_r() ? 0x00 : ST3_T0) |
- (fi.dev->twosid_r() ? 0x00 : ST3_TS);
+ result[0] = get_st3(fi);
LOGCOMMAND("command sense drive status %d (%02x)\n", fi.id, result[0]);
result_pos = 1;
break;
@@ -1455,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;
}
@@ -1477,26 +1521,95 @@ void upd765_family_device::execute_command(int cmd)
}
}
+void ps2_fdc_device::execute_command(int cmd)
+{
+ switch(cmd) {
+ case C_CONFIGURE:
+ LOGCOMMAND("command configure %02x %02x %02x\n",
+ command[1], command[2], command[3]);
+ // byte 1 is ignored, byte 3 is precompensation-related
+ fifocfg = command[2];
+ precomp = command[3];
+ main_phase = PHASE_CMD;
+ break;
+
+ case C_DUMP_REG:
+ LOGCOMMAND("command dump regs\n");
+ main_phase = PHASE_RESULT;
+ result[0] = flopi[0].pcn;
+ result[1] = flopi[1].pcn;
+ result[2] = flopi[2].pcn;
+ result[3] = flopi[3].pcn;
+ result[4] = (spec & 0xff00) >> 8;
+ result[5] = (spec & 0x00ff);
+ result[6] = sector_size;
+ result[7] = locked ? 0x80 : 0x00;
+ result[7] |= (perpmode & 0x3f);
+ result[8] = fifocfg;
+ result[9] = precomp;
+ result_pos = 10;
+ break;
+
+ case C_VERSION:
+ LOGCOMMAND("command version\n");
+ main_phase = PHASE_RESULT;
+ result[0] = 0x90;
+ result_pos = 1;
+ break;
+
+ case C_LOCK:
+ locked = command[0] & 0x80;
+ main_phase = PHASE_RESULT;
+ result[0] = locked ? 0x10 : 0x00;
+ result_pos = 1;
+ LOGCOMMAND("command lock (%s)\n", locked ? "on" : "off");
+ break;
+
+ case C_PERPENDICULAR:
+ LOGCOMMAND("command perpendicular\n");
+ if(BIT(command[1], 7))
+ perpmode = command[1] & 0x3f;
+ else
+ perpmode = (perpmode & 0x3c) | (command[1] & 3);
+ main_phase = PHASE_CMD;
+ break;
+
+ default:
+ upd765_family_device::execute_command(cmd);
+ break;
+ }
+}
+
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();
}
+uint8_t upd765_family_device::get_st3(floppy_info &fi)
+{
+ uint8_t st3 = command[1] & 7;
+ if(fi.ready)
+ st3 |= ST3_RY;
+ if(fi.dev)
+ st3 |=
+ (fi.dev->wpt_r() ? ST3_WP : 0x00) |
+ (fi.dev->trk00_r() ? 0x00 : ST3_T0) |
+ (fi.dev->twosid_r() ? 0x00 : ST3_TS);
+ return st3;
+}
+
void upd765_family_device::recalibrate_start(floppy_info &fi)
{
LOGCOMMAND("command recalibrate %d\n", command[1] & 3);
fi.main_state = RECALIBRATE;
fi.sub_state = SEEK_WAIT_STEP_TIME_DONE;
fi.dir = 1;
- fi.counter = 77;
+ fi.counter = recalibrate_steps;
fi.ready = get_ready(command[1] & 3);
fi.st0 = (fi.ready ? 0 : ST0_NR);
seek_continue(fi);
@@ -1513,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)
@@ -1529,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:
@@ -1548,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:
@@ -1579,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;
@@ -1691,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;
}
@@ -1706,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:
@@ -1719,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:
@@ -1773,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],
@@ -1804,10 +1918,19 @@ void upd765_family_device::read_data_continue(floppy_info &fi)
if(cur_live.crc) {
fi.st0 |= ST0_FAIL;
st1 |= ST1_DE;
- st2 |= ST2_CM;
+ st2 |= ST2_DD;
+ fi.sub_state = COMMAND_DONE;
+ break;
+ }
+
+ if ((st2 & ST2_CM) && !(command[0] & 0x20)) {
+ // Encountered terminating sector while in non-skip mode.
+ // This will stop reading when a normal data sector is encountered during read deleted data,
+ // or when a deleted sector is encountered during a read data command.
fi.sub_state = COMMAND_DONE;
break;
}
+
bool done = tc_done;
if(command[4] == command[6]) {
if(command[0] & 0x80) {
@@ -1895,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);
}
@@ -1905,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:
@@ -2046,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;
}
@@ -2061,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:
@@ -2074,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:
@@ -2123,7 +2254,7 @@ void upd765_family_device::read_track_continue(floppy_info &fi)
else
st1 &= ~ST1_ND;
- sector_size = calc_sector_size(cur_live.idbuf[3]);
+ sector_size = calc_sector_size(command[5]);
fifo_expect(sector_size, false);
fi.sub_state = SECTOR_READ;
LOGSTATE("SEARCH_ADDRESS_MARK_DATA\n");
@@ -2146,7 +2277,7 @@ void upd765_family_device::read_track_continue(floppy_info &fi)
}
if(cur_live.crc) {
st1 |= ST1_DE;
- st2 |= ST2_CM;
+ st2 |= ST2_DD;
}
bool done = tc_done;
sectors_read++;
@@ -2205,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)
@@ -2226,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:
@@ -2250,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;
@@ -2311,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:
@@ -2362,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);
@@ -2375,17 +2515,6 @@ bool upd765_family_device::get_irq() const
return cur_irq;
}
-std::string upd765_family_device::tts(attotime t)
-{
- const char *sign = "";
- if(t.seconds() < 0) {
- t = attotime::zero - t;
- sign = "-";
- }
- int const nsec = t.attoseconds() / ATTOSECONDS_PER_NANOSECOND;
- return util::string_format("%s%04d.%03d,%03d,%03d", sign, int(t.seconds()), nsec/1000000, (nsec/1000)%1000, nsec % 1000);
-}
-
std::string upd765_family_device::results() const
{
std::ostringstream stream;
@@ -2403,19 +2532,14 @@ std::string upd765_family_device::results() const
std::string upd765_family_device::ttsn() const
{
- return tts(machine().time());
+ 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;
@@ -2428,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;
@@ -2441,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;
}
}
}
@@ -2586,7 +2710,7 @@ bool upd765_family_device::write_one_bit(const attotime &limit)
void upd765_family_device::live_write_raw(uint16_t raw)
{
- LOGLIVE("%s: write %04x %04x\n", tts(cur_live.tm), raw, cur_live.crc);
+ LOGLIVE("%s: write %04x %04x\n", cur_live.tm.to_string(), raw, cur_live.crc);
cur_live.shift_reg = raw;
cur_live.data_bit_context = raw & 1;
}
@@ -2606,7 +2730,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;
- LOGLIVE("%s: write %02x %04x %04x\n", tts(cur_live.tm), mfm, cur_live.crc, raw);
+ LOGLIVE("%s: write %02x %04x %04x\n", cur_live.tm.to_string(), mfm, cur_live.crc, raw);
}
void upd765_family_device::live_write_fm(uint8_t fm)
@@ -2618,7 +2742,7 @@ 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;
- LOGLIVE("%s: write %02x %04x %04x\n", tts(cur_live.tm), fm, cur_live.crc, raw);
+ LOGLIVE("%s: write %02x %04x %04x\n", cur_live.tm.to_string(), fm, cur_live.crc, raw);
}
bool upd765_family_device::sector_matches() const
@@ -2635,17 +2759,17 @@ bool upd765_family_device::sector_matches() const
upd765a_device::upd765a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : upd765_family_device(mconfig, UPD765A, tag, owner, clock)
{
- dor_reset = 0x0c;
+ has_dor = false;
}
upd765b_device::upd765b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : upd765_family_device(mconfig, UPD765B, tag, owner, clock)
{
- dor_reset = 0x0c;
+ has_dor = false;
}
i8272a_device::i8272a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : upd765_family_device(mconfig, I8272A, tag, owner, clock)
{
- dor_reset = 0x0c;
+ has_dor = false;
}
upd72065_device::upd72065_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : upd72065_device(mconfig, UPD72065, tag, owner, clock)
@@ -2654,7 +2778,8 @@ upd72065_device::upd72065_device(const machine_config &mconfig, const char *tag,
upd72065_device::upd72065_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : upd765_family_device(mconfig, type, tag, owner, clock)
{
- dor_reset = 0x0c;
+ has_dor = false;
+ recalibrate_steps = 255;
}
upd72067_device::upd72067_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : upd72065_device(mconfig, UPD72067, tag, owner, clock)
@@ -2675,13 +2800,15 @@ upd72069_device::upd72069_device(const machine_config &mconfig, const char *tag,
i82072_device::i82072_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : upd765_family_device(mconfig, I82072, tag, owner, clock)
{
- dor_reset = 0x0c;
+ has_dor = false;
+ recalibrate_steps = 255;
}
void i82072_device::device_start()
{
upd765_family_device::device_start();
+ save_item(NAME(motorcfg));
save_item(NAME(motor_off_counter));
save_item(NAME(motor_on_counter));
save_item(NAME(drive_busy));
@@ -2794,11 +2921,30 @@ void i82072_device::start_command(int cmd)
void i82072_device::execute_command(int cmd)
{
switch(cmd) {
- case C_DUMP_REG:
- upd765_family_device::execute_command(cmd);
+ case C_CONFIGURE:
+ LOGCOMMAND("command configure %02x %02x %02x\n",
+ command[1], command[2], command[3]);
+ motorcfg = command[1];
+ fifocfg = command[2];
+ precomp = command[3];
+ main_phase = PHASE_CMD;
+ break;
+ case C_DUMP_REG:
+ LOGCOMMAND("command dump regs\n");
+ main_phase = PHASE_RESULT;
+ result[0] = flopi[0].pcn;
+ result[1] = flopi[1].pcn;
+ result[2] = flopi[2].pcn;
+ result[3] = flopi[3].pcn;
+ result[4] = (spec & 0xff00) >> 8;
+ result[5] = (spec & 0x00ff);
+ result[6] = sector_size;
// i82072 dumps motor configuration at offset 7
result[7] = motorcfg;
+ result[8] = fifocfg;
+ result[9] = precomp;
+ result_pos = 10;
break;
case C_MOTOR_ONOFF: {
@@ -2937,14 +3083,40 @@ void i82072_device::index_callback(floppy_image_device *floppy, int state)
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)
+ps2_fdc_device::ps2_fdc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : upd765_family_device(mconfig, type, tag, owner, clock)
+{
+}
+
+void ps2_fdc_device::device_start()
+{
+ upd765_family_device::device_start();
+
+ save_item(NAME(perpmode));
+}
+
+void ps2_fdc_device::device_reset()
+{
+ upd765_family_device::device_reset();
+
+ perpmode = 0;
+}
+
+void ps2_fdc_device::soft_reset()
+{
+ upd765_family_device::soft_reset();
+
+ perpmode &= 0x3c;
+}
+
+smc37c78_device::smc37c78_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : ps2_fdc_device(mconfig, SMC37C78, tag, owner, clock)
{
ready_connected = false;
select_connected = true;
select_multiplexed = false;
+ recalibrate_steps = 80;
}
-n82077aa_device::n82077aa_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : upd765_family_device(mconfig, N82077AA, tag, owner, clock)
+n82077aa_device::n82077aa_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : ps2_fdc_device(mconfig, N82077AA, tag, owner, clock)
{
ready_connected = false;
select_connected = true;
@@ -2965,14 +3137,33 @@ dp8473_device::dp8473_device(const machine_config &mconfig, const char *tag, dev
ready_connected = false;
select_connected = true;
select_multiplexed = false;
+ recalibrate_steps = 77; // TODO: 3917 in extended track range mode
}
-pc8477a_device::pc8477a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : upd765_family_device(mconfig, PC8477A, tag, owner, clock)
+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;
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
+}
+
+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) :
@@ -2987,23 +3178,28 @@ wd37c65c_device::wd37c65c_device(const machine_config &mconfig, const char *tag,
(void)m_clock2; // TODO
}
+uint8_t wd37c65c_device::get_st3(floppy_info &fi)
+{
+ uint8_t st3 = command[1] & 7;
+ st3 |= 0x20;
+ if(fi.dev)
+ st3 |=
+ (fi.dev->wpt_r() ? 0x48 : 0x00) |
+ (fi.dev->trk00_r() ? 0x00 : 0x10);
+ return st3;
+}
+
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)
{
- dor_reset = 0x0c;
+ has_dor = true;
ready_polled = false;
ready_connected = false;
select_connected = true;
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();
@@ -3017,6 +3213,7 @@ tc8566af_device::tc8566af_device(const machine_config &mconfig, const char *tag,
ready_connected = true;
select_connected = true;
select_multiplexed = false;
+ recalibrate_steps = 255;
}
void tc8566af_device::device_start()
@@ -3068,7 +3265,7 @@ void upd72067_device::auxcmd_w(uint8_t data)
for(unsigned i = 0; i < 4; i++)
if(flopi[i].dev)
flopi[i].dev->mon_w(!BIT(data, i + 4));
- // fall through
+ [[fallthrough]];
case 0x03: // enable external mode
case 0x0b: // control internal mode
case 0x0f: // select format
@@ -3082,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);
+}
+