summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/lib/formats/ap2_dsk.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/lib/formats/ap2_dsk.c')
-rw-r--r--trunk/src/lib/formats/ap2_dsk.c511
1 files changed, 511 insertions, 0 deletions
diff --git a/trunk/src/lib/formats/ap2_dsk.c b/trunk/src/lib/formats/ap2_dsk.c
new file mode 100644
index 00000000000..7be7150ad28
--- /dev/null
+++ b/trunk/src/lib/formats/ap2_dsk.c
@@ -0,0 +1,511 @@
+/*********************************************************************
+
+ ap2_dsk.c
+
+ Apple II disk images
+
+*********************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "ap2_dsk.h"
+#include "basicdsk.h"
+
+
+#define APPLE2_IMAGE_DO 0
+#define APPLE2_IMAGE_PO 1
+#define APPLE2_IMAGE_NIB 2
+
+
+/* used in for all Apple II images */
+static UINT32 apple2_get_track_size(floppy_image_legacy *floppy, int head, int track);
+static int disk_decode_nib(UINT8 *data, const UINT8 *nibble, int *volume, int *track, int *sector);
+static void disk_encode_nib(UINT8 *nibble, const UINT8 *data, int volume, int track, int sector);
+
+/* used in DOS/ProDOS order images */
+static int apple2_do_translate_sector(floppy_image_legacy *floppy, int sector);
+static int apple2_po_translate_sector(floppy_image_legacy *floppy, int sector);
+static floperr_t apple2_dsk_read_track(floppy_image_legacy *floppy, int head, int track, UINT64 offset, void *buffer, size_t buflen);
+static floperr_t apple2_dsk_write_track(floppy_image_legacy *floppy, int head, int track, UINT64 offset, const void *buffer, size_t buflen);
+
+/* used in nibble order images */
+static floperr_t apple2_nib_read_track(floppy_image_legacy *floppy, int head, int track, UINT64 offset, void *buffer, size_t buflen);
+static floperr_t apple2_nib_write_track(floppy_image_legacy *floppy, int head, int track, UINT64 offset, const void *buffer, size_t buflen);
+static floperr_t apple2_nib_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen);
+static floperr_t apple2_nib_write_sector(floppy_image_legacy *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam);
+static floperr_t apple2_nib_get_sector_length(floppy_image_legacy *floppy, int head, int track, int sector, UINT32 *sector_length);
+
+
+static const UINT8 translate6[0x40] =
+{
+ 0x96, 0x97, 0x9a, 0x9b, 0x9d, 0x9e, 0x9f, 0xa6,
+ 0xa7, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb2, 0xb3,
+ 0xb4, 0xb5, 0xb6, 0xb7, 0xb9, 0xba, 0xbb, 0xbc,
+ 0xbd, 0xbe, 0xbf, 0xcb, 0xcd, 0xce, 0xcf, 0xd3,
+ 0xd6, 0xd7, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde,
+ 0xdf, 0xe5, 0xe6, 0xe7, 0xe9, 0xea, 0xeb, 0xec,
+ 0xed, 0xee, 0xef, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
+ 0xf7, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+
+
+/* -----------------------------------------------------------------------
+ * Utility code
+ * ----------------------------------------------------------------------- */
+
+static const UINT8 *get_untranslate6_map(void)
+{
+ static UINT8 map[256];
+ static int map_inited = 0;
+ UINT8 i;
+
+ if (!map_inited)
+ {
+ memset(map, 0xff, sizeof(map));
+ for (i = 0; i < ARRAY_LENGTH(translate6); i++)
+ map[translate6[i]] = i;
+ map_inited = 1;
+ }
+ return map;
+}
+
+
+
+/* -----------------------------------------------------------------------
+ * Core constructor
+ * ----------------------------------------------------------------------- */
+
+
+static floperr_t apple2_general_construct(floppy_image_legacy *floppy, int floppy_type)
+{
+ floperr_t err;
+ struct basicdsk_geometry geometry;
+ struct FloppyCallbacks *format;
+
+ format = floppy_callbacks(floppy);
+
+ switch(floppy_type) {
+ case APPLE2_IMAGE_DO:
+ case APPLE2_IMAGE_PO:
+ memset(&geometry, 0, sizeof(geometry));
+ geometry.heads = 1;
+ geometry.tracks = APPLE2_TRACK_COUNT;
+ geometry.sectors = APPLE2_SECTOR_COUNT;
+ geometry.sector_length = APPLE2_SECTOR_SIZE;
+ geometry.translate_sector = (floppy_type == APPLE2_IMAGE_DO) ? apple2_do_translate_sector : apple2_po_translate_sector;
+
+ err = basicdsk_construct(floppy, &geometry);
+ if (err)
+ return err;
+
+ format->read_track = apple2_dsk_read_track;
+ format->write_track = apple2_dsk_write_track;
+ break;
+
+ case APPLE2_IMAGE_NIB:
+ format->read_track = apple2_nib_read_track;
+ format->write_track = apple2_nib_write_track;
+ format->read_sector = apple2_nib_read_sector;
+ format->write_sector = apple2_nib_write_sector;
+ format->get_sector_length = apple2_nib_get_sector_length;
+ break;
+
+ default:
+ assert(0);
+ return FLOPPY_ERROR_INTERNAL;
+ }
+
+ format->get_track_size = apple2_get_track_size;
+
+ return FLOPPY_ERROR_SUCCESS;
+}
+
+
+
+/* -----------------------------------------------------------------------
+ * DOS order and ProDOS order code
+ * ----------------------------------------------------------------------- */
+
+static FLOPPY_IDENTIFY(apple2_dsk_identify)
+{
+ UINT64 size;
+ UINT64 expected_size;
+
+ size = floppy_image_size(floppy);
+ expected_size = APPLE2_TRACK_COUNT * APPLE2_SECTOR_COUNT * APPLE2_SECTOR_SIZE;
+
+ if (size == expected_size)
+ *vote = 100;
+ else if (size - expected_size < 8 && size - expected_size > -8)
+ *vote = 90; /* tolerate images with up to eight fewer/extra bytes (bug #638) */
+ else
+ *vote = 0;
+ return FLOPPY_ERROR_SUCCESS;
+}
+
+
+
+static int apple2_do_translate_sector(floppy_image_legacy *floppy, int sector)
+{
+ static const UINT8 skewing[] =
+ {
+ /* DOS order (*.do) */
+ 0x00, 0x07, 0x0E, 0x06, 0x0D, 0x05, 0x0C, 0x04,
+ 0x0B, 0x03, 0x0A, 0x02, 0x09, 0x01, 0x08, 0x0F
+ };
+ return skewing[sector];
+}
+
+
+
+static int apple2_po_translate_sector(floppy_image_legacy *floppy, int sector)
+{
+ static const UINT8 skewing[] =
+ {
+ /* ProDOS order (*.po) */
+ 0x00, 0x08, 0x01, 0x09, 0x02, 0x0A, 0x03, 0x0B,
+ 0x04, 0x0C, 0x05, 0x0D, 0x06, 0x0E, 0x07, 0x0F
+ };
+ return skewing[sector];
+}
+
+
+
+static FLOPPY_CONSTRUCT(apple2_do_construct)
+{
+ return apple2_general_construct(floppy, APPLE2_IMAGE_DO);
+}
+
+
+
+static FLOPPY_CONSTRUCT(apple2_po_construct)
+{
+ return apple2_general_construct(floppy, APPLE2_IMAGE_PO);
+}
+
+
+
+static floperr_t apple2_dsk_read_track(floppy_image_legacy *floppy, int head, int track, UINT64 offset, void *buffer, size_t buflen)
+{
+ UINT8 sector_buffer[APPLE2_SECTOR_SIZE];
+ int sector;
+ UINT8 *nibble;
+
+ if (buflen < APPLE2_NIBBLE_SIZE*APPLE2_SECTOR_COUNT)
+ return FLOPPY_ERROR_INTERNAL;
+ if (offset != 0)
+ return FLOPPY_ERROR_UNSUPPORTED;
+
+ memset(buffer, 0, buflen);
+
+ for (sector = 0; sector < APPLE2_SECTOR_COUNT; sector++)
+ {
+ nibble = (UINT8 *)buffer;
+ nibble += sector * APPLE2_SMALL_NIBBLE_SIZE;
+
+ floppy_read_sector(floppy, head, track, sector, 0, sector_buffer, sizeof(sector_buffer));
+ disk_encode_nib(nibble, sector_buffer, 254, track, sector);
+ }
+ return FLOPPY_ERROR_SUCCESS;
+}
+
+
+
+static floperr_t apple2_dsk_write_track(floppy_image_legacy *floppy, int head, int track, UINT64 offset, const void *buffer, size_t buflen)
+{
+ int sector;
+ UINT8 sector_buffer[APPLE2_SECTOR_SIZE];
+ const UINT8 *nibble;
+
+ if (offset != 0)
+ return FLOPPY_ERROR_UNSUPPORTED;
+
+ for (sector = 0; sector < APPLE2_SECTOR_COUNT; sector++)
+ {
+ nibble = (UINT8 *)buffer;
+ nibble += sector * APPLE2_SMALL_NIBBLE_SIZE;
+
+ disk_decode_nib(sector_buffer, nibble, NULL, NULL, NULL);
+ floppy_write_sector(floppy, head, track, sector, 0, sector_buffer, sizeof(sector_buffer), 0);
+ }
+
+ return FLOPPY_ERROR_SUCCESS;
+}
+
+
+
+/* -----------------------------------------------------------------------
+ * Nibble order code
+ * ----------------------------------------------------------------------- */
+
+static FLOPPY_IDENTIFY(apple2_nib_identify)
+{
+ UINT64 size;
+ size = floppy_image_size(floppy);
+ *vote = (size == APPLE2_TRACK_COUNT * APPLE2_SECTOR_COUNT * APPLE2_NIBBLE_SIZE) ? 100 : 0;
+ return FLOPPY_ERROR_SUCCESS;
+}
+
+
+
+static FLOPPY_CONSTRUCT(apple2_nib_construct)
+{
+ return apple2_general_construct(floppy, APPLE2_IMAGE_NIB);
+}
+
+
+
+static floperr_t apple2_nib_read_track(floppy_image_legacy *floppy, int head, int track, UINT64 offset, void *buffer, size_t buflen)
+{
+ if ((head != 0) || (track < 0) || (track >= APPLE2_TRACK_COUNT))
+ return FLOPPY_ERROR_SEEKERROR;
+ if (offset != 0)
+ return FLOPPY_ERROR_UNSUPPORTED;
+ floppy_image_read(floppy, buffer, track * APPLE2_NIBBLE_SIZE * APPLE2_SECTOR_COUNT, buflen);
+ return FLOPPY_ERROR_SUCCESS;
+}
+
+
+
+static floperr_t apple2_nib_write_track(floppy_image_legacy *floppy, int head, int track, UINT64 offset, const void *buffer, size_t buflen)
+{
+ if ((head != 0) || (track < 0) || (track >= APPLE2_TRACK_COUNT))
+ return FLOPPY_ERROR_SEEKERROR;
+ if (offset != 0)
+ return FLOPPY_ERROR_UNSUPPORTED;
+ floppy_image_write(floppy, buffer, track * APPLE2_NIBBLE_SIZE * APPLE2_SECTOR_COUNT, buflen);
+ return FLOPPY_ERROR_SUCCESS;
+}
+
+
+
+/* -----------------------------------------------------------------------
+ * Track conversion
+ * ----------------------------------------------------------------------- */
+
+static int decode_nibbyte(UINT8 *nibint, const UINT8 *nibdata)
+{
+ if ((nibdata[0] & 0xAA) != 0xAA)
+ return 1;
+ if ((nibdata[1] & 0xAA) != 0xAA)
+ return 1;
+
+ *nibint = (nibdata[0] & ~0xAA) << 1;
+ *nibint |= (nibdata[1] & ~0xAA) << 0;
+ return 0;
+}
+
+
+
+static int disk_decode_nib(UINT8 *data, const UINT8 *nibble, int *volume, int *track, int *sector)
+{
+ UINT8 read_volume;
+ UINT8 read_track;
+ UINT8 read_sector;
+ UINT8 read_checksum;
+ int i;
+ UINT8 b, xorvalue, newvalue;
+
+ const UINT8 *untranslate6 = get_untranslate6_map();
+
+ /* pick apart the volume/track/sector info and checksum */
+ if (decode_nibbyte(&read_volume, &nibble[10]))
+ return 1;
+ if (decode_nibbyte(&read_track, &nibble[12]))
+ return 1;
+ if (decode_nibbyte(&read_sector, &nibble[14]))
+ return 1;
+ if (decode_nibbyte(&read_checksum, &nibble[16]))
+ return 1;
+ if (read_checksum != (read_volume ^ read_track ^ read_sector))
+ return 1;
+
+ /* decode the nibble core */
+ xorvalue = 0;
+ for (i = 0; i < 342; i++)
+ {
+ b = untranslate6[nibble[i+28]];
+ if (b == 0xff)
+ return 1;
+ newvalue = b ^ xorvalue;
+
+ if (i >= 0x56)
+ {
+ /* 6 bit */
+ data[i - 0x56] |= (newvalue << 2);
+ }
+ else
+ {
+ /* 3 * 2 bit */
+ data[i + 0x00] = ((newvalue >> 1) & 0x01) | ((newvalue << 1) & 0x02);
+ data[i + 0x56] = ((newvalue >> 3) & 0x01) | ((newvalue >> 1) & 0x02);
+ if (i + 0xAC < APPLE2_SECTOR_SIZE)
+ data[i + 0xAC] = ((newvalue >> 5) & 0x01) | ((newvalue >> 3) & 0x02);
+ }
+ xorvalue = newvalue;
+ }
+
+ /* success; write out values if pointers not null */
+ if (volume)
+ *volume = read_volume;
+ if (track)
+ *track = read_track;
+ if (sector)
+ *sector = read_sector;
+ return 0;
+}
+
+
+
+static floperr_t apple2_nib_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen)
+{
+ floperr_t err;
+ const UINT8 *nibble;
+ UINT8 *track_data;
+ void *track_data_v;
+
+ if ((sector < 0) || (sector >= APPLE2_SECTOR_COUNT))
+ return FLOPPY_ERROR_SEEKERROR;
+ if (buflen != APPLE2_SECTOR_SIZE)
+ return FLOPPY_ERROR_INTERNAL;
+
+ err = floppy_load_track(floppy, head, track, FALSE, &track_data_v, NULL);
+ if (err)
+ return err;
+ track_data = (UINT8 *) track_data_v;
+
+ nibble = track_data + (sector * APPLE2_NIBBLE_SIZE);
+
+ if (disk_decode_nib((UINT8 *)buffer, nibble, NULL, NULL, NULL))
+ return FLOPPY_ERROR_INVALIDIMAGE;
+
+ return FLOPPY_ERROR_SUCCESS;
+}
+
+
+
+static void disk_encode_nib(UINT8 *nibble, const UINT8 *data, int volume, int track, int sector)
+{
+ int checksum, oldvalue, xorvalue, i;
+
+ /* setup header values */
+ checksum = volume ^ track ^ sector;
+
+ memset(nibble, 0xFF, APPLE2_NIBBLE_SIZE);
+ nibble[ 7] = 0xD5;
+ nibble[ 8] = 0xAA;
+ nibble[ 9] = 0x96;
+ nibble[10] = (volume >> 1) | 0xAA;
+ nibble[11] = volume | 0xAA;
+ nibble[12] = (track >> 1) | 0xAA;
+ nibble[13] = track | 0xAA;
+ nibble[14] = (sector >> 1) | 0xAA;
+ nibble[15] = sector | 0xAA;
+ nibble[16] = (checksum >> 1) | 0xAA;
+ nibble[17] = (checksum) | 0xAA;
+ nibble[18] = 0xDE;
+ nibble[19] = 0xAA;
+ nibble[20] = 0xEB;
+ nibble[25] = 0xD5;
+ nibble[26] = 0xAA;
+ nibble[27] = 0xAD;
+ nibble[27+344] = 0xDE;
+ nibble[27+345] = 0xAA;
+ nibble[27+346] = 0xEB;
+ xorvalue = 0;
+
+ for (i = 0; i < 342; i++)
+ {
+ if (i >= 0x56)
+ {
+ /* 6 bit */
+ oldvalue = data[i - 0x56];
+ oldvalue = oldvalue >> 2;
+ }
+ else
+ {
+ /* 3 * 2 bit */
+ oldvalue = 0;
+ oldvalue |= (data[i + 0x00] & 0x01) << 1;
+ oldvalue |= (data[i + 0x00] & 0x02) >> 1;
+ oldvalue |= (data[i + 0x56] & 0x01) << 3;
+ oldvalue |= (data[i + 0x56] & 0x02) << 1;
+ if (i + 0xAC < APPLE2_SECTOR_SIZE)
+ {
+ oldvalue |= (data[i + 0xAC] & 0x01) << 5;
+ oldvalue |= (data[i + 0xAC] & 0x02) << 3;
+ }
+
+ }
+ xorvalue ^= oldvalue;
+ nibble[28+i] = translate6[xorvalue & 0x3F];
+ xorvalue = oldvalue;
+ }
+
+ nibble[27+343] = translate6[xorvalue & 0x3F];
+}
+
+
+
+static floperr_t apple2_nib_write_sector(floppy_image_legacy *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam)
+{
+ floperr_t err;
+ UINT8 *track_data;
+ void *track_data_v;
+
+ if ((sector < 0) || (sector >= APPLE2_SECTOR_COUNT))
+ return FLOPPY_ERROR_SEEKERROR;
+ if (buflen != APPLE2_SECTOR_SIZE)
+ return FLOPPY_ERROR_INTERNAL;
+
+ err = floppy_load_track(floppy, head, track, TRUE, &track_data_v, NULL);
+ if (err)
+ return err;
+ track_data = (UINT8 *) track_data_v;
+
+ disk_encode_nib(track_data + sector * APPLE2_NIBBLE_SIZE, (const UINT8 *)buffer, 254, track, sector);
+ return FLOPPY_ERROR_SUCCESS;
+}
+
+
+
+static floperr_t apple2_nib_get_sector_length(floppy_image_legacy *floppy, int head, int track, int sector, UINT32 *sector_length)
+{
+ *sector_length = APPLE2_SECTOR_SIZE;
+ return FLOPPY_ERROR_SUCCESS;
+}
+
+
+
+static UINT32 apple2_get_track_size(floppy_image_legacy *floppy, int head, int track)
+{
+ return APPLE2_NIBBLE_SIZE * APPLE2_SECTOR_COUNT;
+}
+
+
+
+/* ----------------------------------------------------------------------- */
+
+LEGACY_FLOPPY_OPTIONS_START( apple2 )
+ LEGACY_FLOPPY_OPTION( apple2_do, "do,dsk,bin", "Apple ][ DOS order disk image", apple2_dsk_identify, apple2_do_construct, NULL,
+ HEADS([1])
+ TRACKS([35])
+ SECTORS([16])
+ SECTOR_LENGTH([256])
+ FIRST_SECTOR_ID([0]))
+ LEGACY_FLOPPY_OPTION( apple2_po, "po,dsk,bin", "Apple ][ ProDOS order disk image", apple2_dsk_identify, apple2_po_construct, NULL,
+ HEADS([1])
+ TRACKS([35])
+ SECTORS([16])
+ SECTOR_LENGTH([256])
+ FIRST_SECTOR_ID([0]))
+ LEGACY_FLOPPY_OPTION( apple2_nib, "dsk,nib", "Apple ][ Nibble order disk image", apple2_nib_identify, apple2_nib_construct, NULL,
+ HEADS([1])
+ TRACKS([35])
+ SECTORS([16])
+ SECTOR_LENGTH([256])
+ FIRST_SECTOR_ID([0]))
+LEGACY_FLOPPY_OPTIONS_END