floppy: First stab at weak zones handling [O. Galibert]

This commit is contained in:
Olivier Galibert 2019-07-01 00:01:03 +02:00
parent 4acf604089
commit def5ea3da1
2 changed files with 169 additions and 28 deletions

View File

@ -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,21 +810,99 @@ 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
{
uint32_t next_position;
int cells = buf.size();
if(index+delta < cells) {
next_position = buf[index+delta] & 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);
return !((buf[buf.size() - 1]^buf[0]) & floppy_image::MG_MASK);
}
return base + attotime::from_nsec((uint64_t(next_position)*2000/floppy_ratio_1+1)/2);
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)
{
int cells = buf.size();
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 {
cache_index = cells - 1;
cache_start_time = position_to_time(base - rev_time, buf[cache_index] & floppy_image::TIME_MASK);
}
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);
}
void floppy_image_device::cache_clear()
{
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) {
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, when);
int index = find_index(position, buf);
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)
@ -789,23 +910,27 @@ attotime floppy_image_device::get_next_transition(const attotime &from_when)
if(!image || mon)
return attotime::never;
std::vector<uint32_t> &buf = image->get_buffer(cyl, ss, subcyl);
uint32_t cells = buf.size();
if(cells <= 1)
return attotime::never;
if(from_when < cache_start_time || (!cache_end_time.is_never() && from_when >= cache_end_time))
cache_fill(from_when);
attotime base;
uint32_t position = find_position(base, from_when);
if(!cache_weak)
return cache_end_time;
int index = find_index(position, buf);
if(index == -1)
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;
// 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++;

View File

@ -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;