iwm: Better state management, better write flush, better underrun handling

This commit is contained in:
Olivier Galibert 2021-02-15 08:10:53 +01:00
parent c823e1668f
commit 2835f1c165
2 changed files with 58 additions and 55 deletions

View File

@ -56,6 +56,7 @@ void iwm_device::device_start()
save_item(NAME(m_rsh));
save_item(NAME(m_wsh));
save_item(NAME(m_rw_bit_count));
save_item(NAME(m_devsel));
}
void iwm_device::device_reset()
@ -77,6 +78,7 @@ void iwm_device::device_reset()
m_flux_write_start = 0;
m_flux_write_count = 0;
m_rw_bit_count = 0;
m_devsel = 0;
m_devsel_cb(0);
}
@ -85,9 +87,12 @@ void iwm_device::device_timer(emu_timer &, device_timer_id, int, void *)
if(m_active == MODE_DELAY) {
flush_write();
m_active = MODE_IDLE;
m_rw = MODE_IDLE;
m_rw_state = S_IDLE;
if(m_floppy)
m_floppy->mon_w(true);
m_devsel_cb(0);
m_devsel = 0;
m_status &= ~0x20;
m_whd &= ~0x40;
}
@ -99,6 +104,7 @@ void iwm_device::set_floppy(floppy_image_device *floppy)
return;
sync();
flush_write();
logerror("floppy %s\n", floppy ? floppy->tag() : "-");
@ -128,7 +134,8 @@ void iwm_device::write(offs_t offset, u8 data)
void iwm_device::flush_write()
{
if(m_floppy && m_flux_write_start && m_last_sync > m_flux_write_start) {
if(m_flux_write_count && m_flux_write[m_flux_write_count-1] == m_last_sync)
bool last_on_edge = m_flux_write_count && m_flux_write[m_flux_write_count-1] == m_last_sync;
if(last_on_edge)
m_flux_write_count--;
attotime start = cycles_to_time(m_flux_write_start);
attotime end = cycles_to_time(m_last_sync);
@ -137,16 +144,18 @@ void iwm_device::flush_write()
fluxes[i] = cycles_to_time(m_flux_write[i]);
m_floppy->write_flux(start, end, m_flux_write_count, m_flux_write_count ? &fluxes[0] : nullptr);
m_flux_write_start = m_last_sync;
}
m_flux_write_count = 0;
m_flux_write_count = 0;
if(last_on_edge)
m_flux_write[m_flux_write_count++] = m_last_sync;
} else
m_flux_write_count = 0;
}
u8 iwm_device::control(int offset, u8 data)
{
sync();
// logerror("control trigger %x, %02x\n", offset, data);
u8 changed = m_control | (m_phases & 0xf);
if(offset < 8) {
if(offset & 1)
m_phases |= 1 << (offset >> 1);
@ -160,22 +169,48 @@ u8 iwm_device::control(int offset, u8 data)
m_control &= ~(1 << (offset >> 1));
}
changed ^= m_control | (m_phases & 0xf);
if(changed & 0x30)
m_devsel_cb(m_control & 0x10 ? m_control & 0x20 ? 2 : 1 : 0);
if(changed & 0x10) {
if(m_control & 0x10) {
if(m_control & 0x10) {
if(m_active != MODE_ACTIVE) {
m_active = MODE_ACTIVE;
m_status |= 0x20;
if(m_floppy)
m_floppy->mon_w(false);
}
if((m_control & 0x80) == 0x00) {
if(m_rw != MODE_READ) {
if(m_rw == MODE_WRITE) {
flush_write();
m_flux_write_start = 0;
}
m_rw = MODE_READ;
m_rw_state = S_IDLE;
m_next_state_change = 0;
m_sync_update = 0;
m_async_update = 0;
m_data = 0x00;
}
} else {
if(m_rw != MODE_WRITE) {
m_rw = MODE_WRITE;
m_rw_state = S_IDLE;
m_whd |= 0x40;
m_next_state_change = 0;
m_flux_write_start = m_last_sync;
m_flux_write_count = 0;
if(m_floppy)
m_floppy->set_write_splice(cycles_to_time(m_flux_write_start));
}
}
} else {
if(m_active == MODE_ACTIVE) {
flush_write();
if(m_mode & 0x04) {
flush_write();
m_flux_write_start = 0;
m_active = MODE_IDLE;
m_rw = MODE_IDLE;
m_rw_state = S_IDLE;
m_status &= ~0x20;
m_whd &= ~0x40;
if(m_floppy)
@ -188,37 +223,10 @@ u8 iwm_device::control(int offset, u8 data)
}
}
if(changed & 0xd0) {
if((m_control & 0xc0) == 0x00 && m_active) {
if(m_rw == MODE_WRITE) {
flush_write();
m_flux_write_start = 0;
}
m_rw = MODE_READ;
m_rw_state = S_IDLE;
m_next_state_change = 0;
m_sync_update = 0;
m_async_update = 0;
m_data = 0x00;
} else if((m_control & 0xc0) == 0xc0 && m_active && m_rw != MODE_WRITE) {
m_rw = MODE_WRITE;
m_rw_state = S_IDLE;
m_whd |= 0x40;
m_next_state_change = 0;
m_flux_write_start = m_last_sync;
m_flux_write_count = 0;
if(m_floppy)
m_floppy->set_write_splice(cycles_to_time(m_flux_write_start));
} else if(m_rw == MODE_WRITE) {
if(!(m_control & 0x80)) {
flush_write();
m_flux_write_start = 0;
m_rw = MODE_IDLE;
}
} else
m_rw = MODE_IDLE;
u8 devsel = m_active != MODE_IDLE ? m_control & 0x20 ? 2 : 1 : 0;
if(devsel != m_devsel) {
m_devsel = devsel;
m_devsel_cb(devsel);
}
if(0) {
@ -253,7 +261,7 @@ u8 iwm_device::control(int offset, u8 data)
m_whd, m_data);
}
if(m_active && !(m_control & 0xc0) && !is_sync() && (m_data & 0x80))
if(m_active && !(m_control & 0x80) && !is_sync() && (m_data & 0x80))
m_async_update = m_last_sync + 14;
switch(m_control & 0xc0) {
@ -337,8 +345,6 @@ u64 iwm_device::write_sync_half_window_size() const
return m_mode & 0x08 ? 2 : 4;
}
static u64 ssx1 = 0, ssx2 = 0;
void iwm_device::sync()
{
if(!m_active)
@ -358,12 +364,6 @@ void iwm_device::sync()
next_flux_change = flux.is_never() ? u64(-1) : time_to_cycles(flux);
if(next_flux_change <= m_last_sync)
next_flux_change = m_last_sync+1;
if(!ssx1)
ssx1 = ssx2 = next_flux_change;
if(ssx2 != next_flux_change) {
ssx1 = ssx2;
ssx2 = next_flux_change;
}
}
if(next_sync < m_next_state_change) {
m_last_sync = next_sync;
@ -429,7 +429,7 @@ void iwm_device::sync()
case MODE_WRITE: {
while(next_sync > m_last_sync) {
if(next_sync < m_next_state_change) {
if(next_sync < m_next_state_change || !(m_whd & 0x40)) {
m_last_sync = next_sync;
break;
}
@ -454,8 +454,10 @@ void iwm_device::sync()
case SW_WINDOW_LOAD:
if(m_whd & 0x80) {
logerror("underrun\n");
flush_write();
m_flux_write_start = 0;
m_whd &= ~0x40;
m_rw_state = S_IDLE;
m_last_sync = next_sync;
} else {
m_wsh = m_data;

View File

@ -67,6 +67,7 @@ private:
int m_active, m_rw, m_rw_state;
u8 m_data, m_whd, m_mode, m_status, m_control, m_rw_bit_count;
u8 m_rsh, m_wsh;
u8 m_devsel;
u8 control(int offset, u8 data);
u64 time_to_cycles(const attotime &tm) const;