From def5ea3da15d2cf21474bdaeb97f9979a332fe71 Mon Sep 17 00:00:00 2001 From: Olivier Galibert Date: Mon, 1 Jul 2019 00:01:03 +0200 Subject: floppy: First stab at weak zones handling [O. Galibert] --- src/devices/imagedev/floppy.cpp | 168 +++++++++++++++++++++++++++++++++++----- src/devices/imagedev/floppy.h | 19 ++++- 2 files changed, 164 insertions(+), 23 deletions(-) diff --git a/src/devices/imagedev/floppy.cpp b/src/devices/imagedev/floppy.cpp index 5a7c362f42a..3eb0c279be3 100644 --- a/src/devices/imagedev/floppy.cpp +++ b/src/devices/imagedev/floppy.cpp @@ -346,8 +346,31 @@ void floppy_image_device::device_start() if (m_make_sound) m_sound_out = subdevice(FLOPSND_TAG); + save_item(NAME(dir)); + save_item(NAME(stp)); + save_item(NAME(wtg)); + save_item(NAME(mon)); + save_item(NAME(ss)); + save_item(NAME(ds)); + save_item(NAME(idx)); + save_item(NAME(wpt)); + save_item(NAME(rdy)); + save_item(NAME(dskchg)); + save_item(NAME(ready)); + save_item(NAME(rpm)); + save_item(NAME(floppy_ratio_1)); + save_item(NAME(revolution_start_time)); + save_item(NAME(rev_time)); + save_item(NAME(revolution_count)); save_item(NAME(cyl)); save_item(NAME(subcyl)); + save_item(NAME(cache_start_time)); + save_item(NAME(cache_end_time)); + save_item(NAME(cache_index)); + save_item(NAME(cache_entry)); + save_item(NAME(cache_weak)); + save_item(NAME(image_dirty)); + save_item(NAME(ready_counter)); } void floppy_image_device::device_reset() @@ -364,6 +387,7 @@ void floppy_image_device::device_reset() set_ready(true); if(motor_always_on && image) mon_w(0); + cache_clear(); } void floppy_image_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) @@ -402,6 +426,7 @@ floppy_image_format_t *floppy_image_device::identify(std::string filename) void floppy_image_device::init_floppy_load(bool write_supported) { + cache_clear(); revolution_start_time = mon ? attotime::never : machine().time(); revolution_count = 0; @@ -471,6 +496,7 @@ image_init_result floppy_image_device::call_load() void floppy_image_device::call_unload() { + cache_clear(); dskchg = 0; if (image) { @@ -542,6 +568,7 @@ void floppy_image_device::mon_w(int state) if (!mon && image) { revolution_start_time = machine().time(); + cache_clear(); if (motor_always_on) { // Drives with motor that is always spinning are immediately ready when a disk is loaded // because there is no spin-up time @@ -556,6 +583,7 @@ void floppy_image_device::mon_w(int state) else { if(image_dirty) commit_image(); + cache_clear(); revolution_start_time = attotime::never; index_timer->adjust(attotime::zero); set_ready(true); @@ -658,6 +686,7 @@ void floppy_image_device::stp_w(int state) // if (ready_counter > 0) return; if ( stp != state ) { + cache_clear(); stp = state; if ( stp == 0 ) { int ocyl = cyl; @@ -715,6 +744,8 @@ void floppy_image_device::seek_phase_w(int phases) cyl = next_pos >> 2; subcyl = next_pos & 3; + cache_clear(); + if(TRACE_STEP && (next_pos != cur_pos)) logerror("track %d.%d\n", cyl, subcyl); @@ -724,7 +755,19 @@ void floppy_image_device::seek_phase_w(int phases) dskchg = 1; } -int floppy_image_device::find_index(uint32_t position, const std::vector &buf) +// From http://burtleburtle.net/bob/hash/integer.html +uint32_t floppy_image_device::hash32(uint32_t a) const +{ + a = (a+0x7ed55d16) + (a<<12); + a = (a^0xc761c23c) ^ (a>>19); + a = (a+0x165667b1) + (a<<5); + a = (a+0xd3a2646c) ^ (a<<9); + a = (a+0xfd7046c5) + (a<<3); + a = (a^0xb55a4f09) ^ (a>>16); + return a; +} + +int floppy_image_device::find_index(uint32_t position, const std::vector &buf)const { int spos = (buf.size() >> 1)-1; int step; @@ -767,45 +810,127 @@ uint32_t floppy_image_device::find_position(attotime &base, const attotime &when return res; } -attotime floppy_image_device::get_next_index_time(std::vector &buf, int index, int delta, attotime base) +bool floppy_image_device::test_track_last_entry_warps(const std::vector &buf) const +{ + return !((buf[buf.size() - 1]^buf[0]) & floppy_image::MG_MASK); +} + +attotime floppy_image_device::position_to_time(const attotime &base, int position) const +{ + return base + attotime::from_nsec((int64_t(position)*2000/floppy_ratio_1+1)/2); +} + +void floppy_image_device::cache_fill_index(const std::vector &buf, int &index, attotime &base) { - uint32_t next_position; int cells = buf.size(); - if(index+delta < cells) { - next_position = buf[index+delta] & floppy_image::TIME_MASK; + if(index != 0 || !test_track_last_entry_warps(buf)) { + cache_index = index; + cache_start_time = position_to_time(base, buf[index] & floppy_image::TIME_MASK); } else { - if((buf[cells-1]^buf[0]) & floppy_image::MG_MASK) - delta--; - index = index + delta - cells + 1; - next_position = 200000000 + (buf[index] & floppy_image::TIME_MASK); + cache_index = cells - 1; + cache_start_time = position_to_time(base - rev_time, buf[cache_index] & floppy_image::TIME_MASK); } - return base + attotime::from_nsec((uint64_t(next_position)*2000/floppy_ratio_1+1)/2); + cache_entry = buf[cache_index]; + + index ++; + if(index >= cells) { + index = test_track_last_entry_warps(buf) ? 1 : 0; + base += rev_time; + } + + cache_end_time = position_to_time(base, buf[index] & floppy_image::TIME_MASK); } -attotime floppy_image_device::get_next_transition(const attotime &from_when) +void floppy_image_device::cache_clear() { - if(!image || mon) - return attotime::never; + cache_start_time = cache_end_time = cache_weak_start = attotime::zero; + cache_index = 0; + cache_entry = 0; + cache_weak = false; +} +void floppy_image_device::cache_fill(const attotime &when) +{ std::vector &buf = image->get_buffer(cyl, ss, subcyl); uint32_t cells = buf.size(); - if(cells <= 1) - return attotime::never; + if(cells <= 1) { + cache_start_time = attotime::zero; + cache_end_time = attotime::never; + cache_index = 0; + cache_entry = cells == 1 ? buf[0] : floppy_image::MG_N; + cache_weakness_setup(); + return; + } attotime base; - uint32_t position = find_position(base, from_when); + uint32_t position = find_position(base, when); int index = find_index(position, buf); - if(index == -1) + if(index == -1) { + // I suspect this should be an abort(), to check... + cache_start_time = attotime::zero; + cache_end_time = attotime::never; + cache_index = 0; + cache_entry = buf[0]; + cache_weakness_setup(); + return; + } + + for(;;) { + cache_fill_index(buf, index, base); + if(cache_end_time > when) { + cache_weakness_setup(); + return; + } + } +} + +void floppy_image_device::cache_weakness_setup() +{ + u32 type = cache_entry & floppy_image::MG_MASK; + if(type == floppy_image::MG_N || type == floppy_image::MG_D) { + cache_weak = true; + cache_weak_start = cache_start_time; + return; + } + + cache_weak = cache_end_time.is_never() || (cache_end_time - cache_start_time >= attotime::from_usec(16)); + if(!cache_weak) { + cache_weak_start = attotime::never; + return; + } + cache_weak_start = cache_start_time + attotime::from_usec(16); +} + +attotime floppy_image_device::get_next_transition(const attotime &from_when) +{ + if(!image || mon) return attotime::never; - for(unsigned int i=1;; i++) { - attotime result = get_next_index_time(buf, index, i, base); - if(result > from_when) - return result; + if(from_when < cache_start_time || (!cache_end_time.is_never() && from_when >= cache_end_time)) + cache_fill(from_when); + + if(!cache_weak) + return cache_end_time; + + // Put a flux transition in the middle of a 4us interval with a 50% probability + int interval_index = (from_when - cache_weak_start).as_ticks(250000); + if(interval_index < 0) + interval_index = 0; + attotime weak_time = cache_weak_start + attotime::from_ticks(interval_index*2+1, 500000); + for(;;) { + if(weak_time >= cache_end_time) + return cache_end_time; + if(weak_time > from_when) { + u32 test = hash32(hash32(hash32(hash32(revolution_count) ^ 0x4242) + cache_index) + interval_index); + if(test & 1) + return weak_time; + } + weak_time += attotime::from_usec(4); + interval_index ++; } } @@ -867,6 +992,7 @@ void floppy_image_device::write_flux(const attotime &start, const attotime &end, void floppy_image_device::write_zone(uint32_t *buf, int &cells, int &index, uint32_t spos, uint32_t epos, uint32_t mg) { + cache_clear(); while(spos < epos) { while(index != cells-1 && (buf[index+1] & floppy_image::TIME_MASK) <= spos) index++; diff --git a/src/devices/imagedev/floppy.h b/src/devices/imagedev/floppy.h index 6223933c74e..c2380d6d02b 100644 --- a/src/devices/imagedev/floppy.h +++ b/src/devices/imagedev/floppy.h @@ -191,6 +191,12 @@ protected: uint32_t revolution_count; int cyl, subcyl; + /* Current floppy zone cache */ + attotime cache_start_time, cache_end_time, cache_weak_start; + int cache_index; + u32 cache_entry; + bool cache_weak; + bool image_dirty; int ready_counter; @@ -203,10 +209,19 @@ protected: void check_led(); uint32_t find_position(attotime &base, const attotime &when); - int find_index(uint32_t position, const std::vector &buf); + int find_index(uint32_t position, const std::vector &buf) const; + bool test_track_last_entry_warps(const std::vector &buf) const; + attotime position_to_time(const attotime &base, int position) const; + void write_zone(uint32_t *buf, int &cells, int &index, uint32_t spos, uint32_t epos, uint32_t mg); void commit_image(); - attotime get_next_index_time(std::vector &buf, int index, int delta, attotime base); + + u32 hash32(u32 val) const; + + void cache_clear(); + void cache_fill_index(const std::vector &buf, int &index, attotime &base); + void cache_fill(const attotime &when); + void cache_weakness_setup(); // Sound bool m_make_sound; -- cgit v1.2.3