mirror of
https://github.com/holub/mame
synced 2025-06-18 18:28:57 +03:00
floppy: First stab at weak zones handling [O. Galibert]
This commit is contained in:
parent
4acf604089
commit
def5ea3da1
@ -346,8 +346,31 @@ void floppy_image_device::device_start()
|
|||||||
|
|
||||||
if (m_make_sound) m_sound_out = subdevice<floppy_sound_device>(FLOPSND_TAG);
|
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(cyl));
|
||||||
save_item(NAME(subcyl));
|
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()
|
void floppy_image_device::device_reset()
|
||||||
@ -364,6 +387,7 @@ void floppy_image_device::device_reset()
|
|||||||
set_ready(true);
|
set_ready(true);
|
||||||
if(motor_always_on && image)
|
if(motor_always_on && image)
|
||||||
mon_w(0);
|
mon_w(0);
|
||||||
|
cache_clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void floppy_image_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
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)
|
void floppy_image_device::init_floppy_load(bool write_supported)
|
||||||
{
|
{
|
||||||
|
cache_clear();
|
||||||
revolution_start_time = mon ? attotime::never : machine().time();
|
revolution_start_time = mon ? attotime::never : machine().time();
|
||||||
revolution_count = 0;
|
revolution_count = 0;
|
||||||
|
|
||||||
@ -471,6 +496,7 @@ image_init_result floppy_image_device::call_load()
|
|||||||
|
|
||||||
void floppy_image_device::call_unload()
|
void floppy_image_device::call_unload()
|
||||||
{
|
{
|
||||||
|
cache_clear();
|
||||||
dskchg = 0;
|
dskchg = 0;
|
||||||
|
|
||||||
if (image) {
|
if (image) {
|
||||||
@ -542,6 +568,7 @@ void floppy_image_device::mon_w(int state)
|
|||||||
if (!mon && image)
|
if (!mon && image)
|
||||||
{
|
{
|
||||||
revolution_start_time = machine().time();
|
revolution_start_time = machine().time();
|
||||||
|
cache_clear();
|
||||||
if (motor_always_on) {
|
if (motor_always_on) {
|
||||||
// Drives with motor that is always spinning are immediately ready when a disk is loaded
|
// Drives with motor that is always spinning are immediately ready when a disk is loaded
|
||||||
// because there is no spin-up time
|
// because there is no spin-up time
|
||||||
@ -556,6 +583,7 @@ void floppy_image_device::mon_w(int state)
|
|||||||
else {
|
else {
|
||||||
if(image_dirty)
|
if(image_dirty)
|
||||||
commit_image();
|
commit_image();
|
||||||
|
cache_clear();
|
||||||
revolution_start_time = attotime::never;
|
revolution_start_time = attotime::never;
|
||||||
index_timer->adjust(attotime::zero);
|
index_timer->adjust(attotime::zero);
|
||||||
set_ready(true);
|
set_ready(true);
|
||||||
@ -658,6 +686,7 @@ void floppy_image_device::stp_w(int state)
|
|||||||
// if (ready_counter > 0) return;
|
// if (ready_counter > 0) return;
|
||||||
|
|
||||||
if ( stp != state ) {
|
if ( stp != state ) {
|
||||||
|
cache_clear();
|
||||||
stp = state;
|
stp = state;
|
||||||
if ( stp == 0 ) {
|
if ( stp == 0 ) {
|
||||||
int ocyl = cyl;
|
int ocyl = cyl;
|
||||||
@ -715,6 +744,8 @@ void floppy_image_device::seek_phase_w(int phases)
|
|||||||
cyl = next_pos >> 2;
|
cyl = next_pos >> 2;
|
||||||
subcyl = next_pos & 3;
|
subcyl = next_pos & 3;
|
||||||
|
|
||||||
|
cache_clear();
|
||||||
|
|
||||||
if(TRACE_STEP && (next_pos != cur_pos))
|
if(TRACE_STEP && (next_pos != cur_pos))
|
||||||
logerror("track %d.%d\n", cyl, subcyl);
|
logerror("track %d.%d\n", cyl, subcyl);
|
||||||
|
|
||||||
@ -724,7 +755,19 @@ void floppy_image_device::seek_phase_w(int phases)
|
|||||||
dskchg = 1;
|
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 spos = (buf.size() >> 1)-1;
|
||||||
int step;
|
int step;
|
||||||
@ -767,21 +810,99 @@ uint32_t floppy_image_device::find_position(attotime &base, const attotime &when
|
|||||||
return res;
|
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;
|
return !((buf[buf.size() - 1]^buf[0]) & floppy_image::MG_MASK);
|
||||||
int cells = buf.size();
|
}
|
||||||
if(index+delta < cells) {
|
|
||||||
next_position = buf[index+delta] & floppy_image::TIME_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)
|
||||||
|
{
|
||||||
|
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 {
|
} else {
|
||||||
if((buf[cells-1]^buf[0]) & floppy_image::MG_MASK)
|
cache_index = cells - 1;
|
||||||
delta--;
|
cache_start_time = position_to_time(base - rev_time, buf[cache_index] & floppy_image::TIME_MASK);
|
||||||
index = index + delta - cells + 1;
|
|
||||||
next_position = 200000000 + (buf[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
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)
|
if(!image || mon)
|
||||||
return attotime::never;
|
return attotime::never;
|
||||||
|
|
||||||
std::vector<uint32_t> &buf = image->get_buffer(cyl, ss, subcyl);
|
if(from_when < cache_start_time || (!cache_end_time.is_never() && from_when >= cache_end_time))
|
||||||
uint32_t cells = buf.size();
|
cache_fill(from_when);
|
||||||
if(cells <= 1)
|
|
||||||
return attotime::never;
|
|
||||||
|
|
||||||
attotime base;
|
if(!cache_weak)
|
||||||
uint32_t position = find_position(base, from_when);
|
return cache_end_time;
|
||||||
|
|
||||||
int index = find_index(position, buf);
|
// 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(index == -1)
|
if(interval_index < 0)
|
||||||
return attotime::never;
|
interval_index = 0;
|
||||||
|
attotime weak_time = cache_weak_start + attotime::from_ticks(interval_index*2+1, 500000);
|
||||||
for(unsigned int i=1;; i++) {
|
for(;;) {
|
||||||
attotime result = get_next_index_time(buf, index, i, base);
|
if(weak_time >= cache_end_time)
|
||||||
if(result > from_when)
|
return cache_end_time;
|
||||||
return result;
|
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)
|
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(spos < epos) {
|
||||||
while(index != cells-1 && (buf[index+1] & floppy_image::TIME_MASK) <= spos)
|
while(index != cells-1 && (buf[index+1] & floppy_image::TIME_MASK) <= spos)
|
||||||
index++;
|
index++;
|
||||||
|
@ -191,6 +191,12 @@ protected:
|
|||||||
uint32_t revolution_count;
|
uint32_t revolution_count;
|
||||||
int cyl, subcyl;
|
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;
|
bool image_dirty;
|
||||||
int ready_counter;
|
int ready_counter;
|
||||||
|
|
||||||
@ -203,10 +209,19 @@ protected:
|
|||||||
|
|
||||||
void check_led();
|
void check_led();
|
||||||
uint32_t find_position(attotime &base, const attotime &when);
|
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 write_zone(uint32_t *buf, int &cells, int &index, uint32_t spos, uint32_t epos, uint32_t mg);
|
||||||
void commit_image();
|
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
|
// Sound
|
||||||
bool m_make_sound;
|
bool m_make_sound;
|
||||||
|
Loading…
Reference in New Issue
Block a user