summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/lib/formats/g64_dsk.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/lib/formats/g64_dsk.c')
-rw-r--r--trunk/src/lib/formats/g64_dsk.c296
1 files changed, 296 insertions, 0 deletions
diff --git a/trunk/src/lib/formats/g64_dsk.c b/trunk/src/lib/formats/g64_dsk.c
new file mode 100644
index 00000000000..395dac5cc5a
--- /dev/null
+++ b/trunk/src/lib/formats/g64_dsk.c
@@ -0,0 +1,296 @@
+/*********************************************************************
+
+ formats/g64_dsk.c
+
+ Floppy format code for Commodore 1541 GCR disk images
+
+*********************************************************************/
+
+/*
+
+ TODO:
+
+ - speed zones
+ - writing
+
+*/
+
+#define XTAL_16MHz 16000000
+#define XTAL_12MHz 12000000
+#include "g64_dsk.h"
+#include "flopimg.h"
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+#define LOG 0
+
+#define HEADER_LENGTH 0x2ac /* standard length for 84 half tracks */
+#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; /* size of each track */
+ UINT32 track_offset[MAX_TRACKS]; /* offset within data for each track */
+ UINT32 speed_zone_offset[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 >= tag->tracks))
+ return FLOPPY_ERROR_SEEKERROR;
+
+ offs = tag->track_offset[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 */
+ UINT64 track_offset;
+ floperr_t err = get_track_offset(floppy, head, track, &track_offset);
+
+ if (err)
+ return 0;
+
+ /* read track length */
+ UINT8 size[2];
+ floppy_image_read(floppy, &size, track_offset, 2);
+ UINT32 track_length = (size[1] << 8) | size[0];
+
+ 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)
+{
+ struct g64dsk_tag *tag = get_tag(floppy);
+ floperr_t err;
+ UINT64 track_offset;
+ UINT16 track_length = 0;
+
+ /* get track offset */
+ err = get_track_offset(floppy, head, track, &track_offset);
+
+ if (err)
+ return err;
+
+ if (!head && track_offset)
+ {
+ if (buflen < tag->track_size) { printf("G64 track buffer too small: %u!", (UINT32)buflen); exit(-1); }
+
+ /* read track */
+ floppy_image_read(floppy, buffer, track_offset + 2, tag->track_size);
+ }
+ else
+ {
+ /* set track length to 0 */
+ memset(buffer, 0, buflen);
+ }
+
+ if (LOG) LOG_FORMATS("G64 track %.1f length %u\n", get_dos_track(track), track_length);
+
+ 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
+
+*/
+
+FLOPPY_CONSTRUCT( g64_dsk_construct )
+{
+ struct FloppyCallbacks *callbacks;
+ struct g64dsk_tag *tag;
+ UINT8 header[HEADER_LENGTH];
+ UINT64 pos = 0;
+ int i;
+
+ 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;
+
+ /* version */
+ floppy_image_read(floppy, header, pos, 0x0c); pos += 0xc;
+ tag->version = header[8];
+ if (LOG) LOG_FORMATS("G64 version: %u\n", tag->version);
+
+ /* number of half tracks */
+ tag->heads = 1;
+ tag->tracks = header[9];
+ if (LOG) LOG_FORMATS("G64 tracks: %u\n", tag->tracks);
+
+ /* size of each stored half track */
+ tag->track_size = (header[11] << 8) | header[10];
+ if (LOG) LOG_FORMATS("G64 track size: %04x\n", tag->track_size);
+
+ /* data offsets */
+ for (i = 0; i < tag->tracks; i++)
+ {
+ floppy_image_read(floppy, header, pos, 4); pos += 4;
+ tag->track_offset[i] = (header[3] << 24) | (header[2] << 16) | (header[1] << 8) | header[0];
+
+ if (LOG) LOG_FORMATS("G64 track %.1f data offset: %04x\n", get_dos_track(i), tag->track_offset[i]);
+ }
+
+ /* speed zone offsets */
+ for (i = 0; i < tag->tracks; i++)
+ {
+ floppy_image_read(floppy, header, pos, 4); pos += 4;
+ tag->speed_zone_offset[i] = (header[3] << 24) | (header[2] << 16) | (header[1] << 8) | header[0];
+
+ if (LOG)
+ {
+ if (tag->speed_zone_offset[i] < 4) {
+ LOG_FORMATS("G64 track %.1f speed zone: %u\n", get_dos_track(i), tag->speed_zone_offset[i]);
+ } else {
+ LOG_FORMATS("G64 track %.1f speed zone offset: %04x\n", get_dos_track(i), tag->speed_zone_offset[i]);
+ }
+ }
+ }
+
+ /* 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;
+}