mirror of
https://github.com/holub/mame
synced 2025-04-27 18:53:05 +03:00
floppy: Handle half and quarter tracks [O. Galibert]
This commit is contained in:
parent
54aeef2210
commit
c6da8ca408
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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];
|
||||
|
Loading…
Reference in New Issue
Block a user