floppy: Handle half and quarter tracks [O. Galibert]

This commit is contained in:
Olivier Galibert 2014-08-09 12:36:09 +00:00
parent 54aeef2210
commit c6da8ca408
8 changed files with 136 additions and 83 deletions

View File

@ -273,6 +273,7 @@ void floppy_image_device::device_start()
mon = 1;
cyl = 0;
subcyl = 0;
ss = 0;
stp = 1;
wpt = 0;
@ -535,9 +536,51 @@ void floppy_image_device::stp_w(int state)
if (dskchg==0) dskchg = 1;
}
}
subcyl = 0;
}
}
void floppy_image_device::seek_phase_w(int phases)
{
int cur_pos = (cyl << 2) | subcyl;
int req_pos;
switch(phases) {
case 0x1: req_pos = 0; break;
case 0x3: req_pos = 1; break;
case 0x2: req_pos = 2; break;
case 0x6: req_pos = 3; break;
case 0x4: req_pos = 4; break;
case 0xc: req_pos = 5; break;
case 0x8: req_pos = 6; break;
case 0x9: req_pos = 7; break;
default: return;
}
// Opposite phase, don't move
if(((cur_pos ^ req_pos) & 7) == 4)
return;
int next_pos = (cur_pos & ~7) | req_pos;
if(next_pos < cur_pos-4)
next_pos += 8;
else if(next_pos > cur_pos+4)
next_pos -= 8;
if(next_pos < 0)
next_pos = 0;
else if(next_pos > (tracks-1)*4)
next_pos = (tracks-1)*4;
cyl = next_pos >> 2;
subcyl = next_pos & 3;
if(TRACE_STEP && (next_pos != cur_pos))
logerror("%s: track %d.%d\n", tag(), cyl, subcyl);
/* Update disk detection if applicable */
if (exists())
if (dskchg==0)
dskchg = 1;
}
int floppy_image_device::find_index(UINT32 position, const UINT32 *buf, int buf_size)
{
int spos = (buf_size >> 1)-1;

View File

@ -105,6 +105,7 @@ public:
bool ss_r() { return ss; }
bool twosid_r();
void seek_phase_w(int phases);
void stp_w(int state);
void dir_w(int state) { dir = state; }
void ss_w(int state) { ss = state; }
@ -164,7 +165,7 @@ protected:
attotime revolution_start_time, rev_time;
UINT32 revolution_count;
int cyl;
int cyl, subcyl;
bool image_dirty;
int ready_counter;

View File

@ -72,7 +72,6 @@ void wozfdc_device::device_start()
void wozfdc_device::device_reset()
{
current_cyl = 0;
floppy = NULL;
active = MODE_IDLE;
phases = 0x00;
@ -199,22 +198,8 @@ void wozfdc_device::phase(int ph, bool on)
else
phases &= ~(1 << ph);
if(floppy && active) {
int cph = current_cyl & 3;
int pcyl = current_cyl;
if(!(phases & (1 << cph))) {
if(current_cyl < 70 && (phases & (1 << ((cph+1) & 3))))
current_cyl++;
if(current_cyl && (phases & (1 << ((cph+3) & 3))))
current_cyl--;
if(current_cyl != pcyl && !(current_cyl & 1)) {
floppy->dir_w(current_cyl < pcyl);
floppy->stp_w(true);
floppy->stp_w(false);
floppy->stp_w(true);
}
}
}
if(floppy && active)
floppy->seek_phase_w(phases);
}
void wozfdc_device::control(int offset)
@ -238,10 +223,8 @@ void wozfdc_device::control(int offset)
case 0x9:
switch(active) {
case MODE_IDLE:
if(floppy) {
if(floppy)
floppy->mon_w(false);
current_cyl = floppy->get_cyl() << 1;
}
active = MODE_ACTIVE;
if(floppy)
lss_start();

View File

@ -60,7 +60,7 @@ private:
};
const UINT8 *m_rom_p6;
UINT8 current_cyl, last_6502_write;
UINT8 last_6502_write;
bool mode_write, mode_load;
int active;
UINT8 phases;

View File

@ -947,19 +947,13 @@ floppy_image::floppy_image(int _tracks, int _heads, UINT32 _form_factor)
form_factor = _form_factor;
variant = 0;
memset(cell_data, 0, sizeof(cell_data));
memset(track_size, 0, sizeof(track_size));
memset(track_alloc_size, 0, sizeof(track_alloc_size));
memset(write_splice, 0, sizeof(write_splice));
track_array.resize(tracks*4+1);
for(int i=0; i<tracks*4+1; i++)
track_array[i].resize(heads);
}
floppy_image::~floppy_image()
{
for (int i=0;i<MAX_FLOPPY_TRACKS;i++) {
for (int j=0;j<MAX_FLOPPY_HEADS;j++) {
global_free_array(cell_data[i][j]);
}
}
}
void floppy_image::get_maximal_geometry(int &_tracks, int &_heads)
@ -970,7 +964,7 @@ void floppy_image::get_maximal_geometry(int &_tracks, int &_heads)
void floppy_image::get_actual_geometry(int &_tracks, int &_heads)
{
int maxt = tracks-1, maxh = heads-1;
int maxt = tracks*4, maxh = heads-1;
while(maxt >= 0) {
for(int i=0; i<=maxh; i++)
@ -987,22 +981,29 @@ void floppy_image::get_actual_geometry(int &_tracks, int &_heads)
maxh--;
}
head_done:
_tracks = maxt+1;
_tracks = (maxt+4)/4;
_heads = maxh+1;
}
int floppy_image::get_resolution() const
{
int mask = 0;
for(int i=0; i<tracks*4+1; i++)
for(int j=0; j<heads; j++)
if(track_array[i][j].track_size)
mask |= 1 << (i & 3);
if(mask & 0xa)
return 2;
if(mask & 0x4)
return 1;
return 0;
}
void floppy_image::ensure_alloc(int track, int head)
{
if(track_size[track][head] > track_alloc_size[track][head]) {
UINT32 new_size = track_size[track][head]*11/10;
UINT32 *new_array = global_alloc_array(UINT32, new_size);
if(track_alloc_size[track][head]) {
memcpy(new_array, cell_data[track][head], track_alloc_size[track][head]*4);
global_free_array(cell_data[track][head]);
}
cell_data[track][head] = new_array;
track_alloc_size[track][head] = new_size;
}
track_info &tr = track_array[track][head];
if(tr.track_size > tr.cell_data.count())
tr.cell_data.resize_keep_and_clear_new(tr.track_size);
}
const char *floppy_image::get_variant_name(UINT32 form_factor, UINT32 variant)

View File

@ -12,6 +12,7 @@
#include "osdcore.h"
#include "ioprocs.h"
#include "opresolv.h"
#include "coretmpl.h"
#ifndef LOG_FORMATS
#define LOG_FORMATS if (0) printf
@ -637,7 +638,13 @@ floppy_image_format_t *floppy_image_format_creator()
//! form factor can be physically inserted in a reader that handles
//! it. The second half indicates the variants which are usually
//! detectable by the reader, such as density and number of sides.
//!
//! Resolution is quarter-track. The optional subtrack parameter is
//! 0-3:
//! - 0 = Track itself
//! - 1 = 1st quarter track
//! - 2 = Half track
//! - 3 = 2nd quarter track
class floppy_image
{
@ -682,7 +689,7 @@ public:
M2FM = 0x4D32464D, //!< "M2FM", modified modified frequency modulation
};
// construction/destruction
// construction/destruction
//! floppy_image constructor
@ -703,21 +710,25 @@ public:
/*!
@param track
@param subtrack
@param head
@param size size of this track
*/
void set_track_size(int track, int head, UINT32 size) { track_size[track][head] = size; ensure_alloc(track, head); }
void set_track_size(int track, int head, UINT32 size, int subtrack = 0) { track_array[track*4+subtrack][head].track_size = size; ensure_alloc(track*4+subtrack, head); }
/*!
@param track track number
@param track
@param subtrack
@param head head number
@return a pointer to the data buffer for this track and head
*/
UINT32 *get_buffer(int track, int head) { return cell_data[track][head]; }
UINT32 *get_buffer(int track, int head, int subtrack = 0) { return track_array[track*4+subtrack][head].cell_data; }
//! @return the track size
//! @param track
//! @param subtrack
//! @param head
UINT32 get_track_size(int track, int head) { return track_size[track][head]; }
UINT32 get_track_size(int track, int head, int subtrack = 0) { return track_array[track*4+subtrack][head].track_size; }
//! Sets the write splice position.
//! The "track splice" information indicates where to start writing
@ -727,18 +738,22 @@ public:
//! representation is the angular position relative to the index.
/*! @param track
@param subtrack
@param head
@param pos the position
*/
void set_write_splice_position(int track, int head, UINT32 pos) { write_splice[track][head] = pos; }
void set_write_splice_position(int track, int head, UINT32 pos, int subtrack = 0) { track_array[track*4+subtrack][head].write_splice = pos; }
//! @return the current write splice position.
UINT32 get_write_splice_position(int track, int head) const { return write_splice[track][head]; }
UINT32 get_write_splice_position(int track, int head, int subtrack = 0) const { return track_array[track*4+subtrack][head].write_splice; }
//! @return the maximal geometry supported by this format.
void get_maximal_geometry(int &tracks, int &heads);
//! @return the current geometry of the loaded image.
void get_actual_geometry(int &tracks, int &heads);
//! @return the track resolution (0=full track, 1 = half-track, 2 = quarter track)
int get_resolution() const;
//! Returns the variant name for the particular disk form factor/variant
//! @param form_factor
//! @param variant
@ -746,20 +761,21 @@ public:
static const char *get_variant_name(UINT32 form_factor, UINT32 variant);
private:
enum {
MAX_FLOPPY_HEADS = 2,
MAX_FLOPPY_TRACKS = 84
};
int tracks, heads;
UINT32 form_factor, variant;
UINT32 *cell_data[MAX_FLOPPY_TRACKS][MAX_FLOPPY_HEADS];
UINT32 track_size[MAX_FLOPPY_TRACKS][MAX_FLOPPY_HEADS];
UINT32 track_alloc_size[MAX_FLOPPY_TRACKS][MAX_FLOPPY_HEADS];
UINT32 write_splice[MAX_FLOPPY_TRACKS][MAX_FLOPPY_HEADS];
struct track_info {
dynamic_array<UINT32> cell_data;
UINT32 track_size;
UINT32 write_splice;
track_info() { track_size = write_splice = 0; }
};
// track number multiplied by 4 then head
// last array size may be bigger than actual track size
dynamic_array<dynamic_array<track_info> > track_array;
void ensure_alloc(int track, int head);
};

View File

@ -8,10 +8,12 @@
Mess floppy image structure:
- header with signature, number of cylinders, number of heads. Min
track and min head are considered to always be 0.
track and min head are considered to always be 0. The two top bits
of the cylinder count is the resolution: 0=tracks, 1=half tracks,
2=quarter tracks.
- vector of track descriptions, looping on cylinders and sub-lopping
on heads, each description composed of:
- vector of track descriptions, looping on cylinders with the given
resolution and sub-lopping on heads, each description composed of:
- offset of the track data in bytes from the start of the file
- size of the compressed track data in bytes (0 for unformatted)
- size of the uncompressed track data in bytes (0 for unformatted)
@ -97,7 +99,8 @@ int mfi_format::identify(io_generic *io, UINT32 form_factor)
io_generic_read(io, &h, 0, sizeof(header));
if(memcmp( h.sign, sign, 16 ) == 0 &&
h.cyl_count <= 160 &&
(h.cyl_count & CYLINDER_MASK) <= 84 &&
(h.cyl_count >> RESOLUTION_SHIFT) < 3 &&
h.head_count <= 2 &&
(!form_factor || !h.form_factor || h.form_factor == form_factor))
return 100;
@ -107,22 +110,24 @@ int mfi_format::identify(io_generic *io, UINT32 form_factor)
bool mfi_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
{
header h;
entry entries[84*2];
entry entries[84*2*4];
io_generic_read(io, &h, 0, sizeof(header));
io_generic_read(io, &entries, sizeof(header), h.cyl_count*h.head_count*sizeof(entry));
int resolution = h.cyl_count >> RESOLUTION_SHIFT;
h.cyl_count &= CYLINDER_MASK;
io_generic_read(io, &entries, sizeof(header), (h.cyl_count << resolution)*h.head_count*sizeof(entry));
image->set_variant(h.variant);
dynamic_buffer compressed;
entry *ent = entries;
for(unsigned int cyl=0; cyl != h.cyl_count; cyl++)
for(unsigned int cyl=0; cyl <= (h.cyl_count - 1) << 2; cyl += 4 >> resolution)
for(unsigned int head=0; head != h.head_count; head++) {
image->set_write_splice_position(cyl, head, ent->write_splice);
image->set_write_splice_position(cyl >> 2, head, ent->write_splice, cyl & 3);
if(ent->uncompressed_size == 0) {
// Unformatted track
image->set_track_size(cyl, head, 0);
image->set_track_size(cyl >> 2, head, 0, cyl & 3);
ent++;
continue;
}
@ -132,8 +137,8 @@ bool mfi_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
io_generic_read(io, compressed, ent->offset, ent->compressed_size);
unsigned int cell_count = ent->uncompressed_size/4;
image->set_track_size(cyl, head, cell_count);
UINT32 *trackbuf = image->get_buffer(cyl, head);
image->set_track_size(cyl >> 2, head, cell_count, cyl & 3);
UINT32 *trackbuf = image->get_buffer(cyl >> 2, head, cyl & 3);
uLongf size = ent->uncompressed_size;
if(uncompress((Bytef *)trackbuf, &size, compressed, ent->compressed_size) != Z_OK)
@ -158,18 +163,19 @@ bool mfi_format::save(io_generic *io, floppy_image *image)
{
int tracks, heads;
image->get_actual_geometry(tracks, heads);
int resolution = image->get_resolution();
int max_track_size = 0;
for(int track=0; track<tracks; track++)
for(int track=0; track <= (tracks-1) << 2; track += 4 >> resolution)
for(int head=0; head<heads; head++) {
int tsize = image->get_track_size(track, head);
int tsize = image->get_track_size(track >> 2, head, track & 3);
if(tsize > max_track_size)
max_track_size = tsize;
}
header h;
entry entries[84*2];
entry entries[84*2*4];
memcpy(h.sign, sign, 16);
h.cyl_count = tracks;
h.cyl_count = tracks | (resolution << RESOLUTION_SHIFT);
h.head_count = heads;
h.form_factor = image->get_form_factor();
h.variant = image->get_variant();
@ -178,20 +184,20 @@ bool mfi_format::save(io_generic *io, floppy_image *image)
memset(entries, 0, sizeof(entries));
int pos = sizeof(header) + tracks*heads*sizeof(entry);
int pos = sizeof(header) + (tracks << resolution)*heads*sizeof(entry);
int epos = 0;
UINT32 *precomp = global_alloc_array(UINT32, max_track_size);
UINT8 *postcomp = global_alloc_array(UINT8, max_track_size*4 + 1000);
for(int track=0; track<tracks; track++)
for(int track=0; track <= (tracks-1) << 2; track += 4 >> resolution)
for(int head=0; head<heads; head++) {
int tsize = image->get_track_size(track, head);
int tsize = image->get_track_size(track >> 2, head, track & 3);
if(!tsize) {
epos++;
continue;
}
memcpy(precomp, image->get_buffer(track, head), tsize*4);
memcpy(precomp, image->get_buffer(track >> 2, head, track & 3), tsize*4);
for(int j=0; j<tsize-1; j++)
precomp[j] = (precomp[j] & floppy_image::MG_MASK) |
((precomp[j+1] & floppy_image::TIME_MASK) -
@ -206,14 +212,14 @@ bool mfi_format::save(io_generic *io, floppy_image *image)
entries[epos].offset = pos;
entries[epos].uncompressed_size = tsize*4;
entries[epos].compressed_size = csize;
entries[epos].write_splice = image->get_write_splice_position(track, head);
entries[epos].write_splice = image->get_write_splice_position(track >> 2, head, track & 3);
epos++;
io_generic_write(io, postcomp, pos, csize);
pos += csize;
}
io_generic_write(io, entries, sizeof(header), tracks*heads*sizeof(entry));
io_generic_write(io, entries, sizeof(header), (tracks << resolution)*heads*sizeof(entry));
return true;
}

View File

@ -26,7 +26,10 @@ private:
MG_A = (0 << MG_SHIFT),
MG_B = (1 << MG_SHIFT),
MG_N = (2 << MG_SHIFT),
MG_D = (3 << MG_SHIFT)
MG_D = (3 << MG_SHIFT),
RESOLUTION_SHIFT = 30,
CYLINDER_MASK = 0x3fffffff
};
static const char sign[16];