summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Olivier Galibert <galibert@pobox.com>2019-07-01 00:01:03 +0200
committer Olivier Galibert <galibert@pobox.com>2019-07-01 00:01:31 +0200
commitdef5ea3da15d2cf21474bdaeb97f9979a332fe71 (patch)
tree564d940b704633afc7858ddd13e646bd48418eb1
parent4acf604089513be82f07e2afc88be27ab807ff00 (diff)
floppy: First stab at weak zones handling [O. Galibert]
-rw-r--r--src/devices/imagedev/floppy.cpp168
-rw-r--r--src/devices/imagedev/floppy.h19
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<floppy_sound_device>(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<uint32_t> &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<uint32_t> &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<uint32_t> &buf, int index, int delta, attotime base)
+bool floppy_image_device::test_track_last_entry_warps(const std::vector<uint32_t> &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<uint32_t> &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<uint32_t> &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<uint32_t> &buf);
+ int find_index(uint32_t position, const std::vector<uint32_t> &buf) const;
+ bool test_track_last_entry_warps(const std::vector<uint32_t> &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<uint32_t> &buf, int index, int delta, attotime base);
+
+ u32 hash32(u32 val) const;
+
+ void cache_clear();
+ void cache_fill_index(const std::vector<uint32_t> &buf, int &index, attotime &base);
+ void cache_fill(const attotime &when);
+ void cache_weakness_setup();
// Sound
bool m_make_sound;