(MESS) c64: Floppy WIP. (nw)

This commit is contained in:
Curt Coder 2014-02-12 22:05:12 +00:00
parent f056d758a3
commit 8dd7482652
4 changed files with 116 additions and 450 deletions

View File

@ -27,6 +27,24 @@
//**************************************************************************
// MACROS / CONSTANTS
//**************************************************************************
#define G64_BUFFER_SIZE 32768
#define G64_SYNC_MARK 0x3ff
const int C8050_BITRATE[] =
{
XTAL_12MHz/2/16, /* tracks 1-39 */
XTAL_12MHz/2/15, /* tracks 40-53 */
XTAL_12MHz/2/14, /* tracks 54-65 */
XTAL_12MHz/2/13 /* tracks 65-84 */
};
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************

View File

@ -303,6 +303,8 @@ const floppy_format_type FLOPPY_D64_FORMAT = &floppy_image_format_creator<d64_fo
#define D82_SIZE_154_TRACKS 1066496
#define D82_SIZE_154_TRACKS_WITH_ERRORS 1070662
#define G64_SPEED_BLOCK_SIZE 1982
enum
{
DOS1,

View File

@ -19,21 +19,6 @@ g64_format::g64_format()
{
}
const char *g64_format::name() const
{
return "g64";
}
const char *g64_format::description() const
{
return "Commodore 1541 GCR disk image";
}
const char *g64_format::extensions() const
{
return "g64,g41";
}
const UINT32 g64_format::c1541_cell_size[] =
{
4000, // 16MHz/16/4
@ -42,6 +27,16 @@ const UINT32 g64_format::c1541_cell_size[] =
3250 // 16MHz/13/4
};
const int g64_format::c1541_speed_zone[] =
{
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 1-17
2, 2, 2, 2, 2, 2, 2, // 18-24
1, 1, 1, 1, 1, 1, // 25-30
0, 0, 0, 0, 0, // 31-35
0, 0, 0, 0, 0, // 36-40
0, 0 // 41-42
};
int g64_format::identify(io_generic *io, UINT32 form_factor)
{
char h[8];
@ -65,45 +60,28 @@ bool g64_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
int track_count = img[TRACK_COUNT];
int head = 0;
int splice_pos = 0;
for (int track = 0; track < track_count; track++)
{
offs_t track_offset = pick_integer_le(img, TRACK_OFFSET + (track * 4), 4);
if (track_offset > size) throw emu_fatalerror("g64_format: Track %u offset %06x out of bounds", track, track_offset);
if (!track_offset) continue;
if (!track_offset)
continue;
if (track_offset > size)
throw emu_fatalerror("g64_format: Track %u offset %06x out of bounds", track, track_offset);
offs_t speed_zone = pick_integer_le(img, SPEED_ZONE + (track * 4), 4);
if (speed_zone > 3) throw emu_fatalerror("g64_format: Unsupported variable speed zones on track %d", track);
size_t cell_size = c1541_cell_size[speed_zone];
size_t max_cells = 200000000/cell_size;
size_t track_bytes = pick_integer_le(img, track_offset, 2);
size_t track_cells = track_bytes * 8;
if (speed_zone > 3)
throw emu_fatalerror("g64_format: Unsupported variable speed zones on track %d", track);
size_t track_size = MAX(track_cells, max_cells);
UINT32 *trackbuf = global_alloc_array_clear(UINT32, track_size);
offs_t trackbuf_offs = 0;
track_offset += 2;
while (trackbuf_offs < track_cells) {
for (int bit=7; bit>=0; bit--) {
bit_w(trackbuf, trackbuf_offs++, BIT(img[track_offset], bit), cell_size);
}
track_offset++;
}
// pad the remainder of the track with gap
int gap = 0;
while (trackbuf_offs < max_cells) {
bit_w(trackbuf, trackbuf_offs++, gap, cell_size);
gap = !gap;
}
generate_track_from_levels(track, head, trackbuf, track_size, splice_pos, image);
UINT16 track_bytes = pick_integer_le(img, track_offset, 2);
int track_size = track_bytes * 8;
global_free(trackbuf);
LOG_FORMATS("track %u size %u cell %ld\n", track, track_size, 200000000L/track_size);
generate_track_from_bitstream(track, head, &img[track_offset+2], track_size, image);
}
global_free(img);
@ -113,381 +91,71 @@ bool g64_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
return true;
}
bool g64_format::supports_save() const
bool g64_format::save(io_generic *io, floppy_image *image)
{
return false;
UINT8 header[4] = { 0x00, 0x54, 0xf8, 0x1e };
io_generic_write(io, G64_FORMAT_HEADER, SIGNATURE, sizeof(G64_FORMAT_HEADER));
io_generic_write(io, header, VERSION, 4);
int head = 0;
int tracks_written = 0;
for (int track = 0; track < 84; track++) {
offs_t tpos = TRACK_OFFSET + track * 4;
offs_t spos = SPEED_ZONE + track * 4;
offs_t dpos = TRACK_DATA + tracks_written * TRACK_LENGTH;
io_generic_write_filler(io, 0x00, tpos, 4);
io_generic_write_filler(io, 0x00, spos, 4);
if (image->get_track_size(track, head) <= 1)
continue;
int speed_zone = c1541_speed_zone[track >> 1];
int cell_size = c1541_cell_size[speed_zone];
UINT8 *trackbuf = global_alloc_array(UINT8, TRACK_LENGTH-2);
int track_size;
generate_bitstream_from_track(track, head, cell_size, trackbuf, track_size, image);
LOG_FORMATS("track %u size %u cell %ld\n", track, track_size, 200000000L/track_size);
UINT8 track_offset[4];
UINT8 speed_offset[4];
UINT8 track_length[2];
place_integer_le(track_offset, 0, 4, dpos);
place_integer_le(speed_offset, 0, 4, speed_zone);
place_integer_le(track_length, 0, 2, track_size/8);
io_generic_write(io, track_offset, tpos, 4);
io_generic_write(io, speed_offset, spos, 4);
io_generic_write_filler(io, 0xff, dpos, TRACK_LENGTH);
io_generic_write(io, track_length, dpos, 2);
io_generic_write(io, trackbuf, dpos + 2, track_size);
tracks_written++;
global_free(trackbuf);
}
return true;
}
const char *g64_format::name() const
{
return "g64";
}
const char *g64_format::description() const
{
return "Commodore 1541 GCR disk image";
}
const char *g64_format::extensions() const
{
return "g64,g41";
}
const floppy_format_type FLOPPY_G64_FORMAT = &floppy_image_format_creator<g64_format>;
// ------ LEGACY -----
/*********************************************************************
formats/g64_dsk.c
Floppy format code for Commodore 1541 GCR disk images
http://www.unusedino.de/ec64/technical/formats/g64.html
*********************************************************************/
/*
TODO:
- write to disk
*/
#define XTAL_16MHz 16000000
#define XTAL_12MHz 12000000
#include "g64_dsk.h"
#include "flopimg.h"
#include "imageutl.h"
/***************************************************************************
PARAMETERS
***************************************************************************/
#define HEADER_LENGTH 0x2ac // standard length for 84 half tracks
#define MAX_HEADS 2
#define MAX_TRACKS 84
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
struct g64dsk_tag
{
int version;
int heads; // number of physical heads
int tracks; // number of physical tracks
UINT16 track_size[MAX_HEADS][MAX_TRACKS]; // size of each track
UINT32 track_offset[MAX_HEADS][MAX_TRACKS]; // offset within data for each track
UINT32 speed_zone_offset[MAX_HEADS][MAX_TRACKS]; // offset within data for each track
};
/***************************************************************************
INLINE FUNCTIONS
***************************************************************************/
INLINE struct g64dsk_tag *get_tag(floppy_image_legacy *floppy)
{
return (g64dsk_tag *)floppy_tag(floppy);
}
INLINE float get_dos_track(int track)
{
return ((float)track / 2) + 1;
}
/***************************************************************************
IMPLEMENTATION
***************************************************************************/
/*-------------------------------------------------
g64_get_heads_per_disk - returns the number
of heads in the disk image
-------------------------------------------------*/
static int g64_get_heads_per_disk(floppy_image_legacy *floppy)
{
return get_tag(floppy)->heads;
}
/*-------------------------------------------------
g64_get_tracks_per_disk - returns the number
of DOS tracks in the disk image
-------------------------------------------------*/
static int g64_get_tracks_per_disk(floppy_image_legacy *floppy)
{
return get_tag(floppy)->tracks;
}
/*-------------------------------------------------
get_track_offset - returns the offset within
the disk image for a given track
-------------------------------------------------*/
static floperr_t get_track_offset(floppy_image_legacy *floppy, int head, int track, UINT64 *offset)
{
struct g64dsk_tag *tag = get_tag(floppy);
UINT64 offs = 0;
if ((track < 0) || (track >= MAX_TRACKS))
return FLOPPY_ERROR_SEEKERROR;
offs = tag->track_offset[head][track];
if (offset)
*offset = offs;
return FLOPPY_ERROR_SUCCESS;
}
/*-------------------------------------------------
g64_get_track_size - returns the track size
-------------------------------------------------*/
static UINT32 g64_get_track_size(floppy_image_legacy *floppy, int head, int track)
{
// get track offset
UINT32 track_length = 0;
UINT64 track_offset;
floperr_t err = get_track_offset(floppy, head, track, &track_offset);
if (err)
return 0;
// read track length
if (track_offset > 0)
{
UINT8 size[2];
floppy_image_read(floppy, &size, track_offset, 2);
track_length = pick_integer_le(size, 0, 2);
}
return track_length;
}
/*-------------------------------------------------
g64_read_track - reads a full track from the
disk image
-------------------------------------------------*/
static floperr_t g64_read_track(floppy_image_legacy *floppy, int head, int track, UINT64 offset, void *buffer, size_t buflen)
{
/*
The following is written into the buffer:
n bytes of track data
1982 bytes of speed zone data
get_track_size() returns n (size of track data)
*/
struct g64dsk_tag *tag = get_tag(floppy);
floperr_t err;
UINT64 track_offset;
UINT16 track_length = tag->track_size[head][track];
// get track offset
err = get_track_offset(floppy, head, track, &track_offset);
if (err)
return err;
if ((head <= tag->heads) && track_offset)
{
if (buflen < track_length) { printf("G64 track buffer too small: %u < %u!", (UINT32)buflen, track_length); exit(-1); }
// read track data
floppy_image_read(floppy, ((UINT8*)buffer), track_offset + 2, track_length); // skip the 2 track length bytes in the beginning of track data
if (tag->speed_zone_offset[head][track] > 3)
{
// read speed block
floppy_image_read(floppy, ((UINT8*)buffer) + track_length, tag->speed_zone_offset[head][track], G64_SPEED_BLOCK_SIZE);
}
else
{
// create a speed block with the same speed zone for the whole track
UINT8 speed = tag->speed_zone_offset[head][track] & 0x03;
UINT8 speed_byte = (speed << 6) | (speed << 4) | (speed << 2) | speed;
memset(((UINT8*)buffer) + track_length, speed_byte, G64_SPEED_BLOCK_SIZE);
}
LOG_FORMATS("G64 side %u track %.1f length %u\n", head, get_dos_track(track), track_length);
}
else
{
// no data for given track, or tried to read side 1
memset(((UINT8*)buffer), 0, buflen);
LOG_FORMATS("G64 side %u track %.1f\n", head, get_dos_track(track));
}
return FLOPPY_ERROR_SUCCESS;
}
/*-------------------------------------------------
g64_write_track - writes a full track to the
disk image
-------------------------------------------------*/
static floperr_t g64_write_track(floppy_image_legacy *floppy, int head, int track, UINT64 offset, const void *buffer, size_t buflen)
{
return FLOPPY_ERROR_UNSUPPORTED;
}
/*-------------------------------------------------
FLOPPY_IDENTIFY( g64_dsk_identify )
-------------------------------------------------*/
FLOPPY_IDENTIFY( g64_dsk_identify )
{
UINT8 header[8];
floppy_image_read(floppy, header, 0, 8);
if (!strncmp((const char *)header, "GCR-1541", 8))
{
*vote = 100;
}
else
{
*vote = 0;
}
return FLOPPY_ERROR_SUCCESS;
}
/*-------------------------------------------------
FLOPPY_CONSTRUCT( g64_dsk_construct )
-------------------------------------------------*/
/*
G64 File Header Format
Bytes: $0000-0007: File signature "GCR-1541"
0008: G64 version (presently only $00 defined)
0009: Number of tracks in image (usually $54, decimal 84)
000A-000B: Size of each stored track in bytes (usually 7928, or
$1EF8 in LO/HI format.
Bytes: $000C-000F: Offset to stored track 1.0 ($000002AC, in LO/HI
format, see below for more)
0010-0013: Offset to stored track 1.5 ($00000000)
0014-0017: Offset to stored track 2.0 ($000021A6)
...
0154-0157: Offset to stored track 42.0 ($0004F8B6)
0158-015B: Offset to stored track 42.5 ($00000000)
Bytes: $015C-015F: Speed zone entry for track 1 ($03, in LO/HI format,
see below for more)
0160-0163: Speed zone entry for track 1.5 ($03)
...
02A4-02A7: Speed zone entry for track 42 ($00)
02A8-02AB: Speed zone entry for track 42.5 ($00)
Bytes: $02AC-02AD: Actual size of stored track (7692 or $1E0C, in LO/HI
format)
02AE-02AE+$1E0C: Track data
*/
static void read_g64_header(floppy_image_legacy *floppy, struct g64dsk_tag *tag, int head, UINT64 &pos)
{
UINT8 header[HEADER_LENGTH];
UINT64 start_pos = pos;
// read header
floppy_image_read(floppy, header, pos, HEADER_LENGTH);
// get version
tag->version = header[8];
if (!head) LOG_FORMATS("G64 version: %u\n", tag->version);
// get number of tracks
tag->tracks = header[9];
LOG_FORMATS("G64 side %u tracks: %u\n", head, tag->tracks);
// get track size
UINT16 track_size = (header[0xb] << 8) | header[0xa];
// get data offsets
pos = 0xc;
for (int i = 0; i < tag->tracks; i++)
{
tag->track_offset[head][i] = pick_integer_le(header, pos, 4);
if (tag->track_offset[head][i])
{
tag->track_offset[head][i] += start_pos;
}
pos += 4;
}
// get speed zone information
UINT32 track_offs = 0;
for (int i = 0; i < tag->tracks; i++)
{
tag->speed_zone_offset[head][i] = pick_integer_le(header, pos, 4);
if (tag->speed_zone_offset[head][i] >= 4)
{
tag->speed_zone_offset[head][i] += start_pos;
}
pos += 4;
tag->track_size[head][i] = g64_get_track_size(floppy, head, i);
if (tag->track_offset[head][i] != 0)
{
LOG_FORMATS("G64 side %u track %.1f offset %05x length %04x ", head, get_dos_track(i), tag->track_offset[head][i], tag->track_size[head][i]);
track_offs = tag->track_offset[head][i];
if (tag->speed_zone_offset[head][i] < 4) {
LOG_FORMATS("speed %u\n", tag->speed_zone_offset[head][i]);
} else {
LOG_FORMATS("speed offset %04x\n", tag->speed_zone_offset[head][i]);
}
}
}
pos = track_offs + 2 + track_size;
}
FLOPPY_CONSTRUCT( g64_dsk_construct )
{
struct FloppyCallbacks *callbacks;
struct g64dsk_tag *tag;
UINT64 pos = 0;
if (params)
{
// create not supported
return FLOPPY_ERROR_UNSUPPORTED;
}
tag = (struct g64dsk_tag *) floppy_create_tag(floppy, sizeof(struct g64dsk_tag));
if (!tag) return FLOPPY_ERROR_OUTOFMEMORY;
tag->heads = 0;
int head = 0;
read_g64_header(floppy, tag, head, pos);
if (floppy_image_size(floppy) > pos)
{
tag->heads++;
head++;
read_g64_header(floppy, tag, head, pos);
}
// set callbacks
callbacks = floppy_callbacks(floppy);
callbacks->read_track = g64_read_track;
callbacks->write_track = g64_write_track;
callbacks->get_heads_per_disk = g64_get_heads_per_disk;
callbacks->get_tracks_per_disk = g64_get_tracks_per_disk;
callbacks->get_track_size = g64_get_track_size;
return FLOPPY_ERROR_SUCCESS;
}

View File

@ -18,13 +18,14 @@ class g64_format : public floppy_image_format_t {
public:
g64_format();
virtual int identify(io_generic *io, UINT32 form_factor);
virtual bool load(io_generic *io, UINT32 form_factor, floppy_image *image);
virtual bool save(io_generic *io, floppy_image *image);
virtual const char *name() const;
virtual const char *description() const;
virtual const char *extensions() const;
virtual int identify(io_generic *io, UINT32 form_factor);
virtual bool load(io_generic *io, UINT32 form_factor, floppy_image *image);
virtual bool supports_save() const;
virtual bool supports_save() const { return true; }
protected:
enum
@ -35,38 +36,15 @@ protected:
MAX_TRACK_SIZE = 0xa,
TRACK_OFFSET = 0xc,
SPEED_ZONE = 0x15c,
MASTERING = 0x2ac
MASTERING = 0x2ac,
TRACK_DATA = 0x2ac,
TRACK_LENGTH = 0x1ef8
};
static const UINT32 c1541_cell_size[];
static const int c1541_speed_zone[];
};
extern const floppy_format_type FLOPPY_G64_FORMAT;
// legacy
#define G64_SYNC_MARK 0x3ff /* 10 consecutive 1-bits */
#define G64_BUFFER_SIZE 32768
#define G64_SPEED_BLOCK_SIZE 1982
const int C2040_BITRATE[] =
{
XTAL_16MHz/16, /* tracks 1-17 */
XTAL_16MHz/15, /* tracks 18-24 */
XTAL_16MHz/14, /* tracks 25-30 */
XTAL_16MHz/13 /* tracks 31-42 */
};
const int C8050_BITRATE[] =
{
XTAL_12MHz/2/16, /* tracks 1-39 */
XTAL_12MHz/2/15, /* tracks 40-53 */
XTAL_12MHz/2/14, /* tracks 54-65 */
XTAL_12MHz/2/13 /* tracks 65-84 */
};
FLOPPY_IDENTIFY( g64_dsk_identify );
FLOPPY_CONSTRUCT( g64_dsk_construct );
#endif