summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/formats/ap2_dsk.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/formats/ap2_dsk.cpp')
-rw-r--r--src/lib/formats/ap2_dsk.cpp1598
1 files changed, 609 insertions, 989 deletions
diff --git a/src/lib/formats/ap2_dsk.cpp b/src/lib/formats/ap2_dsk.cpp
index b9685d8e40f..1880ad7bd23 100644
--- a/src/lib/formats/ap2_dsk.cpp
+++ b/src/lib/formats/ap2_dsk.cpp
@@ -2,689 +2,323 @@
// copyright-holders:Olivier Galibert, R. Belmont
/*********************************************************************
- ap2_dsk.c
+ ap2_dsk.cpp
Apple II disk images
*********************************************************************/
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
#include "ap2_dsk.h"
#include "basicdsk.h"
+#include "ioprocs.h"
+#include "multibyte.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_t apple2_get_track_size(floppy_image_legacy *floppy, int head, int track);
-static int disk_decode_nib(uint8_t *data, const uint8_t *nibble, int *volume, int *track, int *sector);
-static void disk_encode_nib(uint8_t *nibble, const uint8_t *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_t offset, void *buffer, size_t buflen);
-static floperr_t apple2_dsk_write_track(floppy_image_legacy *floppy, int head, int track, uint64_t offset, const void *buffer, size_t buflen);
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
-/* used in nibble order images */
-static floperr_t apple2_nib_read_track(floppy_image_legacy *floppy, int head, int track, uint64_t offset, void *buffer, size_t buflen);
-static floperr_t apple2_nib_write_track(floppy_image_legacy *floppy, int head, int track, uint64_t 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_t *sector_length);
-
-
-static const uint8_t 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
+static const uint8_t translate5[] = {
+ 0xab, 0xad, 0xae, 0xaf, 0xb5, 0xb6, 0xb7, 0xba,
+ 0xbb, 0xbd, 0xbe, 0xbf, 0xd6, 0xd7, 0xda, 0xdb,
+ 0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xed, 0xee, 0xef,
+ 0xf5, 0xf6, 0xf7, 0xfa, 0xfb, 0xfd, 0xfe, 0xff,
};
-
-
-/* -----------------------------------------------------------------------
- * Utility code
- * ----------------------------------------------------------------------- */
-
-static const uint8_t *get_untranslate6_map(void)
+a2_13sect_format::a2_13sect_format() : floppy_image_format_t()
{
- static uint8_t map[256];
- static int map_inited = 0;
- uint8_t 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)
+int a2_13sect_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const
{
- 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;
- }
+ uint64_t size;
+ if (io.length(size))
+ return 0;
- format->get_track_size = apple2_get_track_size;
+ if (size != APPLE2_STD_TRACK_COUNT * 13 * APPLE2_SECTOR_SIZE)
+ return 0;
- return FLOPPY_ERROR_SUCCESS;
+ return FIFID_SIZE;
}
-
-
-/* -----------------------------------------------------------------------
- * DOS order and ProDOS order code
- * ----------------------------------------------------------------------- */
-
-static FLOPPY_IDENTIFY(apple2_dsk_identify)
+bool a2_13sect_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const
{
uint64_t size;
- uint64_t expected_size;
-
- size = floppy_image_size(floppy);
- expected_size = APPLE2_TRACK_COUNT * APPLE2_SECTOR_COUNT * APPLE2_SECTOR_SIZE;
-
- if ((size == expected_size) || (size == 35 * APPLE2_SECTOR_COUNT * APPLE2_SECTOR_SIZE))
- *vote = 100;
- else if ((size > expected_size) && ((size - expected_size) < 8))
- *vote = 90; /* tolerate images with up to eight fewer/extra bytes (bug #638) */
- else if ((size < expected_size) && ((expected_size - size) < 8))
- *vote = 90; /* tolerate images with up to eight fewer/extra bytes (bug #638) */
- else
- *vote = 0;
- return FLOPPY_ERROR_SUCCESS;
-}
+ if (io.length(size))
+ return false;
+ image.set_form_variant(floppy_image::FF_525, floppy_image::SSSD);
+ int tracks = size / 13 / APPLE2_SECTOR_SIZE;
-static int apple2_do_translate_sector(floppy_image_legacy *floppy, int sector)
-{
- static const uint8_t skewing[] =
- {
- /* DOS order (*.do) */
- 0x00, 0x07, 0x0E, 0x06, 0x0D, 0x05, 0x0C, 0x04,
- 0x0B, 0x03, 0x0A, 0x02, 0x09, 0x01, 0x08, 0x0F
- };
- return skewing[sector];
-}
+ for(int track = 0; track < tracks; track++) {
+ std::vector<uint32_t> track_data;
+ uint8_t sector_data[APPLE2_SECTOR_SIZE * 13];
+ auto const [err, actual] = read_at(
+ io, track * sizeof sector_data, sector_data, sizeof sector_data);
+ if (err || actual != sizeof sector_data)
+ return false;
+ for(int i=0; i<13; i++) {
+ int sector = (i * 10) % 13;
-static int apple2_po_translate_sector(floppy_image_legacy *floppy, int sector)
-{
- static const uint8_t skewing[] =
- {
- /* ProDOS order (*.po) */
- 0x00, 0x08, 0x01, 0x09, 0x02, 0x0A, 0x03, 0x0B,
- 0x04, 0x0C, 0x05, 0x0D, 0x06, 0x0E, 0x07, 0x0F
- };
- return skewing[sector];
-}
+ // write inter-sector padding
+ for(int j=0; j<40; j++)
+ raw_w(track_data, 9, 0x1fe);
+ raw_w(track_data, 8, 0xff);
+ // write sector address
+ raw_w(track_data, 24, 0xd5aab5);
+ raw_w(track_data, 16, gcr4_encode(0xfe));
+ raw_w(track_data, 16, gcr4_encode(track));
+ raw_w(track_data, 16, gcr4_encode(sector));
+ raw_w(track_data, 16, gcr4_encode(0xfe ^ track ^ sector));
+ raw_w(track_data, 24, 0xdeaaeb);
+ // write intra-sector padding
+ for(int j=0; j<11; j++)
+ raw_w(track_data, 9, 0x1fe);
-static FLOPPY_CONSTRUCT(apple2_do_construct)
-{
- return apple2_general_construct(floppy, APPLE2_IMAGE_DO);
-}
+ // write sector data
+ raw_w(track_data, 24, 0xd5aaad);
+ uint8_t pval = 0x00;
+ auto write_data_byte = [&track_data, &pval](uint8_t nval) {
+ raw_w(track_data, 8, translate5[nval ^ pval]);
+ pval = nval;
+ };
+
+ const uint8_t *sdata = sector_data + APPLE2_SECTOR_SIZE * sector;
+
+ // write 154 bytes encoding bits 2-0
+ write_data_byte(sdata[255] & 7);
+ for (int k=2; k>-1; k--)
+ for (int j=0; j<51; j++)
+ write_data_byte(
+ (sdata[j*5+k] & 7) << 2
+ | ((sdata[j*5+3] >> (2-k)) & 1) << 1
+ | ((sdata[j*5+4] >> (2-k)) & 1));
+
+ // write 256 bytes encoding bits 7-3
+ for (int k=0; k<5; k++)
+ for (int j=50; j>-1; j--)
+ write_data_byte(sdata[j*5+k] >> 3);
+ write_data_byte(sdata[255] >> 3);
+
+ raw_w(track_data, 8, translate5[pval]);
+ raw_w(track_data, 24, 0xdeaaeb);
+ raw_w(track_data, 8, 0xff);
+ }
+ generate_track_from_levels(track, 0, track_data, 0, image);
+ }
-static FLOPPY_CONSTRUCT(apple2_po_construct)
-{
- return apple2_general_construct(floppy, APPLE2_IMAGE_PO);
+ return true;
}
-
-static floperr_t apple2_dsk_read_track(floppy_image_legacy *floppy, int head, int track, uint64_t offset, void *buffer, size_t buflen)
+const char *a2_13sect_format::name() const noexcept
{
- uint8_t sector_buffer[APPLE2_SECTOR_SIZE];
- int sector;
- uint8_t *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_t *)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;
+ return "a2_13sect";
}
-
-
-static floperr_t apple2_dsk_write_track(floppy_image_legacy *floppy, int head, int track, uint64_t offset, const void *buffer, size_t buflen)
+const char *a2_13sect_format::description() const noexcept
{
- int sector;
- uint8_t sector_buffer[APPLE2_SECTOR_SIZE];
- const uint8_t *nibble;
-
- if (offset != 0)
- return FLOPPY_ERROR_UNSUPPORTED;
-
- for (sector = 0; sector < APPLE2_SECTOR_COUNT; sector++)
- {
- nibble = (uint8_t *)buffer;
- nibble += sector * APPLE2_SMALL_NIBBLE_SIZE;
-
- disk_decode_nib(sector_buffer, nibble, nullptr, nullptr, nullptr);
- floppy_write_sector(floppy, head, track, sector, 0, sector_buffer, sizeof(sector_buffer), 0);
- }
-
- return FLOPPY_ERROR_SUCCESS;
+ return "Apple II 13-sector d13 image";
}
-
-
-/* -----------------------------------------------------------------------
- * Nibble order code
- * ----------------------------------------------------------------------- */
-
-static FLOPPY_IDENTIFY(apple2_nib_identify)
+const char *a2_13sect_format::extensions() const noexcept
{
- uint64_t size;
- size = floppy_image_size(floppy);
- *vote = ((size == APPLE2_TRACK_COUNT * APPLE2_SECTOR_COUNT * APPLE2_NIBBLE_SIZE) || (size == (APPLE2_TRACK_COUNT + 1) * APPLE2_SECTOR_COUNT * APPLE2_NIBBLE_SIZE)) ? 100 : 0;
- return FLOPPY_ERROR_SUCCESS;
+ return "d13";
}
-
-
-static FLOPPY_CONSTRUCT(apple2_nib_construct)
+bool a2_13sect_format::supports_save() const noexcept
{
- return apple2_general_construct(floppy, APPLE2_IMAGE_NIB);
+ return false;
}
+const a2_13sect_format FLOPPY_A213S_FORMAT;
-
-static floperr_t apple2_nib_read_track(floppy_image_legacy *floppy, int head, int track, uint64_t offset, void *buffer, size_t buflen)
+static const uint8_t translate6[0x40] =
{
- 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;
-}
-
-
+ 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
+};
-static floperr_t apple2_nib_write_track(floppy_image_legacy *floppy, int head, int track, uint64_t offset, const void *buffer, size_t buflen)
+static const uint8_t dos_skewing[] =
{
- 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
- * ----------------------------------------------------------------------- */
+ 0x00, 0x07, 0x0E, 0x06, 0x0D, 0x05, 0x0C, 0x04,
+ 0x0B, 0x03, 0x0A, 0x02, 0x09, 0x01, 0x08, 0x0F
+};
-static int decode_nibbyte(uint8_t *nibint, const uint8_t *nibdata)
+static const uint8_t prodos_skewing[] =
{
- 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;
-}
-
+ 0x00, 0x08, 0x01, 0x09, 0x02, 0x0A, 0x03, 0x0B,
+ 0x04, 0x0C, 0x05, 0x0D, 0x06, 0x0E, 0x07, 0x0F
+};
-static int disk_decode_nib(uint8_t *data, const uint8_t *nibble, int *volume, int *track, int *sector)
+a2_16sect_format::a2_16sect_format(bool prodos_order) : floppy_image_format_t(), m_prodos_order(prodos_order)
{
- uint8_t read_volume;
- uint8_t read_track;
- uint8_t read_sector;
- uint8_t read_checksum;
- int i;
- uint8_t b, xorvalue, newvalue;
-
- const uint8_t *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)
+a2_16sect_dos_format::a2_16sect_dos_format() : a2_16sect_format(false)
{
- floperr_t err;
- const uint8_t *nibble;
- uint8_t *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, nullptr);
- if (err)
- return err;
- track_data = (uint8_t *) track_data_v;
-
- nibble = track_data + (sector * APPLE2_NIBBLE_SIZE);
-
- if (disk_decode_nib((uint8_t *)buffer, nibble, nullptr, nullptr, nullptr))
- return FLOPPY_ERROR_INVALIDIMAGE;
-
- return FLOPPY_ERROR_SUCCESS;
}
-
-
-static void disk_encode_nib(uint8_t *nibble, const uint8_t *data, int volume, int track, int sector)
+const char *a2_16sect_dos_format::name() const noexcept
{
- 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];
+ return "a2_16sect_dos";
}
-
-
-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)
+const char *a2_16sect_dos_format::description() const noexcept
{
- floperr_t err;
- uint8_t *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, nullptr);
- if (err)
- return err;
- track_data = (uint8_t *) track_data_v;
-
- disk_encode_nib(track_data + sector * APPLE2_NIBBLE_SIZE, (const uint8_t *)buffer, 254, track, sector);
- return FLOPPY_ERROR_SUCCESS;
+ return "Apple II 16-sector dsk image (DOS sector order)";
}
-
-
-static floperr_t apple2_nib_get_sector_length(floppy_image_legacy *floppy, int head, int track, int sector, uint32_t *sector_length)
+const char *a2_16sect_dos_format::extensions() const noexcept
{
- *sector_length = APPLE2_SECTOR_SIZE;
- return FLOPPY_ERROR_SUCCESS;
+ return "dsk,do";
}
-
-
-static uint32_t apple2_get_track_size(floppy_image_legacy *floppy, int head, int track)
+a2_16sect_prodos_format::a2_16sect_prodos_format() : a2_16sect_format(true)
{
- 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, nullptr,
- HEADS([1])
- TRACKS([APPLE2_TRACK_COUNT])
- 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, nullptr,
- HEADS([1])
- TRACKS([APPLE2_TRACK_COUNT])
- 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, nullptr,
- HEADS([1])
- TRACKS([APPLE2_TRACK_COUNT])
- SECTORS([16])
- SECTOR_LENGTH([256])
- FIRST_SECTOR_ID([0]))
-LEGACY_FLOPPY_OPTIONS_END
-
-// license:BSD-3-Clause
-// copyright-holders:Olivier Galibert
-/***************************************************************************
-
- New implementation
-
-****************************************************************************/
-
-static const uint8_t dos_skewing[] =
-{
- 0x00, 0x07, 0x0E, 0x06, 0x0D, 0x05, 0x0C, 0x04,
- 0x0B, 0x03, 0x0A, 0x02, 0x09, 0x01, 0x08, 0x0F
-};
-
-static const uint8_t prodos_skewing[] =
-{
- 0x00, 0x08, 0x01, 0x09, 0x02, 0x0A, 0x03, 0x0B,
- 0x04, 0x0C, 0x05, 0x0D, 0x06, 0x0E, 0x07, 0x0F
-};
-
-
-a2_16sect_format::a2_16sect_format() : floppy_image_format_t(), m_prodos_order(false)
+const char *a2_16sect_prodos_format::name() const noexcept
{
+ return "a2_16sect_prodos";
}
-const char *a2_16sect_format::name() const
+const char *a2_16sect_prodos_format::description() const noexcept
{
- return "a2_16sect";
+ return "Apple II 16-sector dsk image (ProDos sector order)";
}
-const char *a2_16sect_format::description() const
+const char *a2_16sect_prodos_format::extensions() const noexcept
{
- return "Apple II 16-sector dsk image";
+ return "dsk,po";
}
-const char *a2_16sect_format::extensions() const
+bool a2_16sect_format::supports_save() const noexcept
{
- return "dsk,do,po";
+ return true;
}
-bool a2_16sect_format::supports_save() const
+int a2_16sect_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const
{
- return true;
-}
+ uint64_t size;
+ if (io.length(size))
+ return 0;
-int a2_16sect_format::identify(io_generic *io, uint32_t form_factor)
-{
- uint64_t size = io_generic_size(io);
- //uint32_t expected_size = 35 * 16 * 256;
- uint32_t expected_size = APPLE2_TRACK_COUNT * 16 * 256;
+ // check standard size plus some oddball sizes in our softlist
+ if (
+ size != APPLE2_TRACK_COUNT * 16 * APPLE2_SECTOR_SIZE
+ && size != APPLE2_STD_TRACK_COUNT * 16 * APPLE2_SECTOR_SIZE
+ && size != 143403 && size != 143363 && size != 143358 && size != 143195
+ )
+ {
+ return 0;
+ }
+
+ uint8_t sector_data[APPLE2_SECTOR_SIZE*2];
+ static const unsigned char pascal_block1[4] = { 0x08, 0xa5, 0x0f, 0x29 };
+ static const unsigned char pascal2_block1[4] = { 0xff, 0xa2, 0x00, 0x8e };
+ static const unsigned char dos33_block1[4] = { 0xa2, 0x02, 0x8e, 0x52 };
+ static const unsigned char sos_block1[4] = { 0xc9, 0x20, 0xf0, 0x3e };
+ static const unsigned char a3a2emul_block1[6] = { 0x8d, 0xd0, 0x03, 0x4c, 0xc7, 0xa4 };
+ static const unsigned char cpm22_block1[8] = { 0xa2, 0x55, 0xa9, 0x00, 0x9d, 0x00, 0x0d, 0xca };
+ static const unsigned char subnod_block1[8] = { 0x63, 0xaa, 0xf0, 0x76, 0x8d, 0x63, 0xaa, 0x8e };
+
+ auto const [err, actual] = read_at(io, 0, sector_data, sizeof sector_data);
+ if (err || actual != sizeof sector_data)
+ return 0;
- // check standard size plus some oddball sizes in our softlist
- if ((size == expected_size) || (size == 35 * 16 * 256) || (size == 143403) || (size == 143363) || (size == 143358))
+ bool prodos_order = false;
+ // check ProDOS boot block
+ if (!memcmp("PRODOS", &sector_data[0x103], 6))
+ {
+ prodos_order = true;
+ } // check for alternate version ProDOS boot block
+ if (!memcmp("PRODOS", &sector_data[0x121], 6))
+ {
+ prodos_order = true;
+ } // check for ProDOS order SOS disk
+ else if (!memcmp(sos_block1, &sector_data[0x100], 4))
+ {
+ prodos_order = true;
+ } // check for Apple III A2 emulator disk in ProDOS order
+ else if (!memcmp(a3a2emul_block1, &sector_data[0x100], 6))
+ {
+ prodos_order = true;
+ } // check for PCPI Applicard software in ProDOS order
+ else if (!memcmp("COPYRIGHT (C) 1979, DIGITAL RESEARCH", &sector_data[0x118], 36))
+ {
+ prodos_order = true;
+ } // check Apple II Pascal
+ else if (!memcmp("SYSTEM.APPLE", &sector_data[0xd7], 12))
+ {
+ // Pascal discs can still be DOS order.
+ // Check for the second half of the boot code at 0x100
+ // (which means ProDOS order)
+ if (!memcmp(pascal_block1, &sector_data[0x100], 4))
{
- return 50;
+ prodos_order = true;
}
+ } // check for DOS 3.3 disks in ProDOS order
+ else if (!memcmp(dos33_block1, &sector_data[0x100], 4))
+ {
+ prodos_order = true;
+ } // check for a later version of the Pascal boot block
+ else if (!memcmp(pascal2_block1, &sector_data[0x100], 4))
+ {
+ prodos_order = true;
+ } // check for CP/M disks in ProDOS order
+ else if (!memcmp(cpm22_block1, &sector_data[0x100], 8))
+ {
+ prodos_order = true;
+ } // check for subnodule disk
+ else if (!memcmp(subnod_block1, &sector_data[0x100], 8))
+ {
+ prodos_order = true;
+ } // check for ProDOS 2.5's new boot block
+ else if (!memcmp("PRODOS", &sector_data[0x3a], 6))
+ {
+ prodos_order = true;
+ }
- return 0;
+ return FIFID_SIZE | (m_prodos_order == prodos_order ? FIFID_HINT : 0);
}
-// following is placeholder, is completely wrong.
-const floppy_image_format_t::desc_e a2_16sect_format::mac_gcr[] = {
- { SECTOR_LOOP_START, 0, -1 },
- { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 },
- { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 },
- { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 },
- { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 },
- { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 },
- { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 },
- { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 },
- { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 },
- { RAWBITS, 0xd5aa96, 24 },
- { CRC_MACHEAD_START, 0 },
- { TRACK_ID_GCR6 },
- { SECTOR_ID_GCR6 },
- { TRACK_HEAD_ID_GCR6 },
- { SECTOR_INFO_GCR6 },
- { CRC_END, 0 },
- { CRC, 0 },
- { RAWBITS, 0xdeaaff, 24 },
- { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 },
- { RAWBITS, 0xd5aaad, 24 },
- { SECTOR_ID_GCR6 },
- { SECTOR_DATA_MAC, -1 },
- { RAWBITS, 0xdeaaff, 24 },
- { RAWBITS, 0xff, 8 },
- { SECTOR_LOOP_END },
- { END },
-};
-
-bool a2_16sect_format::load(io_generic *io, uint32_t form_factor, floppy_image *image)
+bool a2_16sect_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const
{
- uint64_t size = io_generic_size(io);
+ uint64_t size;
+ if (io.length(size))
+ return false;
- m_prodos_order = false;
- m_tracks = (size == (40 * 16 * 256)) ? 40 : 35;
+ image.set_form_variant(floppy_image::FF_525, floppy_image::SSSD);
+
+ int tracks = (size == (APPLE2_TRACK_COUNT * 16 * APPLE2_SECTOR_SIZE)) ? APPLE2_TRACK_COUNT : APPLE2_STD_TRACK_COUNT;
int fpos = 0;
- for(int track=0; track < m_tracks; track++) {
+ for(int track=0; track < tracks; track++) {
std::vector<uint32_t> track_data;
- uint8_t sector_data[256*16];
- static const unsigned char pascal_block1[4] = { 0x08, 0xa5, 0x0f, 0x29 };
- static const unsigned char pascal2_block1[4] = { 0xff, 0xa2, 0x00, 0x8e };
- static const unsigned char dos33_block1[4] = { 0xa2, 0x02, 0x8e, 0x52 };
- static const unsigned char sos_block1[4] = { 0xc9, 0x20, 0xf0, 0x3e };
- static const unsigned char a3a2emul_block1[6] = { 0x8d, 0xd0, 0x03, 0x4c, 0xc7, 0xa4 };
- static const unsigned char cpm22_block1[8] = { 0xa2, 0x55, 0xa9, 0x00, 0x9d, 0x00, 0x0d, 0xca };
- static const unsigned char subnod_block1[8] = { 0x63, 0xaa, 0xf0, 0x76, 0x8d, 0x63, 0xaa, 0x8e };
-
- io_generic_read(io, sector_data, fpos, 256*16);
-
- if (track == 0 && fpos == 0)
- {
- // check ProDOS boot block
- if (!memcmp("PRODOS", &sector_data[0x103], 6))
- {
- m_prodos_order = true;
- } // check for alternate version ProDOS boot block
- if (!memcmp("PRODOS", &sector_data[0x121], 6))
- {
- m_prodos_order = true;
- } // check for ProDOS order SOS disk
- else if (!memcmp(sos_block1, &sector_data[0x100], 4))
- {
- m_prodos_order = true;
- } // check for Apple III A2 emulator disk in ProDOS order
- else if (!memcmp(a3a2emul_block1, &sector_data[0x100], 6))
- {
- m_prodos_order = true;
- } // check for PCPI Applicard software in ProDOS order
- else if (!memcmp("COPYRIGHT (C) 1979, DIGITAL RESEARCH", &sector_data[0x118], 36))
- {
- m_prodos_order = true;
- } // check Apple II Pascal
- else if (!memcmp("SYSTEM.APPLE", &sector_data[0xd7], 12))
- {
- // Pascal discs can still be DOS order.
- // Check for the second half of the boot code at 0x100
- // (which means ProDOS order)
- if (!memcmp(pascal_block1, &sector_data[0x100], 4))
- {
- m_prodos_order = true;
- }
- } // check for DOS 3.3 disks in ProDOS order
- else if (!memcmp(dos33_block1, &sector_data[0x100], 4))
- {
- m_prodos_order = true;
- } // check for a later version of the Pascal boot block
- else if (!memcmp(pascal2_block1, &sector_data[0x100], 4))
- {
- m_prodos_order = true;
- } // check for CP/M disks in ProDOS order
- else if (!memcmp(cpm22_block1, &sector_data[0x100], 8))
- {
- m_prodos_order = true;
- } // check for subnodule disk
- else if (!memcmp(subnod_block1, &sector_data[0x100], 8))
- {
- m_prodos_order = true;
- } // check for ProDOS 2.5's new boot block
- else if (!memcmp("PRODOS", &sector_data[0x3a], 6))
- {
- m_prodos_order = true;
- }
- else if (!memcmp("PRODOS", &sector_data[0x40], 6))
- {
- m_prodos_order = true;
- }
- }
+ uint8_t sector_data[APPLE2_SECTOR_SIZE*16];
- fpos += 256*16;
+ auto const [err, actual] = read_at(io, fpos, sector_data, sizeof sector_data);
+ // Some supported images have oddball sizes, where the last track is incomplete.
+ // Skip the `actual` check to avoid rejecting them.
+ if (err /* || actual != sizeof sector_data */)
+ return false;
+
+ fpos += APPLE2_SECTOR_SIZE*16;
for(int i=0; i<49; i++)
raw_w(track_data, 10, 0x3fc);
for(int i=0; i<16; i++) {
@@ -699,7 +333,7 @@ bool a2_16sect_format::load(io_generic *io, uint32_t form_factor, floppy_image *
sector = dos_skewing[i];
}
- const uint8_t *sdata = sector_data + 256 * sector;
+ const uint8_t *sdata = sector_data + APPLE2_SECTOR_SIZE * sector;
for(int j=0; j<20; j++)
raw_w(track_data, 10, 0x3fc);
raw_w(track_data, 8, 0xff);
@@ -747,14 +381,14 @@ bool a2_16sect_format::load(io_generic *io, uint32_t form_factor, floppy_image *
return true;
}
-uint8_t a2_16sect_format::gb(const uint8_t *buf, int ts, int &pos, int &wrap)
+uint8_t a2_16sect_format::gb(const std::vector<bool> &buf, int &pos, int &wrap)
{
uint8_t v = 0;
int w1 = wrap;
while(wrap != w1+2 && !(v & 0x80)) {
- v = v << 1 | ((buf[pos >> 3] >> (7-(pos & 7))) & 1);
+ v = (v << 1) | buf[pos];
pos++;
- if(pos == ts) {
+ if(pos == buf.size()) {
pos = 0;
wrap++;
}
@@ -762,239 +396,238 @@ uint8_t a2_16sect_format::gb(const uint8_t *buf, int ts, int &pos, int &wrap)
return v;
}
-void a2_16sect_format::update_chk(const uint8_t *data, int size, uint32_t &chk)
-{
-}
-
-//#define VERBOSE_SAVE
-
-bool a2_16sect_format::save(io_generic *io, floppy_image *image)
+bool a2_16sect_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, const floppy_image &image) const
{
- int g_tracks, g_heads;
- int visualgrid[16][APPLE2_TRACK_COUNT]; // visualizer grid, cleared/initialized below
-
-// lenient addr check: if unset, only accept an addr mark if the checksum was good
-// if set, accept an addr mark if the track and sector values are both sane
-#undef LENIENT_ADDR_CHECK
-// if set, use the old, not as robust logic for choosing which copy of a decoded sector to write
-// to the resulting image if the sector has a bad checksum and/or postamble
-#undef USE_OLD_BEST_SECTOR_PRIORITY
-// nothing found
-#define NOTFOUND 0
-// address mark was found
-#define ADDRFOUND 1
-// address checksum is good
-#define ADDRGOOD 2
-// data mark was found (requires addrfound and sane values)
-#define DATAFOUND 4
-// data checksum is good
-#define DATAGOOD 8
-// data postamble is good
-#define DATAPOST 16
- for (auto & elem : visualgrid) {
- for (int j = 0; j < m_tracks; j++) {
- elem[j] = 0;
- }
+ int g_tracks, g_heads;
+ int visualgrid[16][APPLE2_TRACK_COUNT]; // visualizer grid, cleared/initialized below
+
+ constexpr bool VERBOSE_SAVE = false;
+
+ // if false, only accept an addr mark if the checksum was good
+ // if true, accept an addr mark if the track and sector values are both sane
+ constexpr bool LENIENT_ADDR_CHECK = false;
+
+ // if true, use the old, not as robust logic for choosing which copy of a decoded sector to write
+ // to the resulting image if the sector has a bad checksum and/or postamble
+ constexpr bool USE_OLD_BEST_SECTOR_PRIORITY = false;
+
+ // nothing found
+ constexpr int NOTFOUND = 0;
+ // address mark was found
+ constexpr int ADDRFOUND = 1;
+ // address checksum is good
+ constexpr int ADDRGOOD = 2;
+ // data mark was found (requires addrfound and sane values)
+ constexpr int DATAFOUND = 4;
+ // data checksum is good
+ constexpr int DATAGOOD = 8;
+ // data postamble is good
+ constexpr int DATAPOST = 16;
+
+ for (auto & elem : visualgrid) {
+ for (int j = 0; j < APPLE2_TRACK_COUNT; j++) {
+ elem[j] = NOTFOUND;
}
- image->get_actual_geometry(g_tracks, g_heads);
+ }
+ image.get_actual_geometry(g_tracks, g_heads);
- int head = 0;
+ int head = 0;
- int pos_data = 0;
+ int pos_data = 0;
- for(int track=0; track < m_tracks; track++) {
- uint8_t sectdata[(256)*16];
- memset(sectdata, 0, sizeof(sectdata));
- int nsect = 16;
- uint8_t buf[10000]; // normal is 51090 cells, e.g. 6387 bytes, add 50% and round up for denser than normal disks
- int ts;
- #ifdef VERBOSE_SAVE
- fprintf(stderr,"DEBUG: a2_16sect_format::save() about to generate bitstream from track %d...", track);
- #endif
- generate_bitstream_from_track(track, head, 3915, buf, ts, image);
- #ifdef VERBOSE_SAVE
- fprintf(stderr,"done.\n");
- #endif
- int pos = 0;
- int wrap = 0;
- int hb = 0;
- int dosver = 0; // apple dos version; 0 = >=3.3, 1 = <3.3
- for(;;) {
- uint8_t v = gb(buf, ts, pos, wrap);
- if(v == 0xff) {
+ for(int track=0; track < g_tracks; track++) {
+ uint8_t sectdata[APPLE2_SECTOR_SIZE*16];
+ memset(sectdata, 0, sizeof(sectdata));
+ int nsect = 16;
+ if(VERBOSE_SAVE) {
+ fprintf(stderr,"DEBUG: a2_16sect_format::save() about to generate bitstream from track %d...", track);
+ }
+ auto buf = generate_bitstream_from_track(track, head, 3915, image);
+ if(VERBOSE_SAVE) {
+ fprintf(stderr,"done.\n");
+ }
+ int pos = 0;
+ int wrap = 0;
+ int hb = 0;
+ int dosver = 0; // apple dos version; 0 = >=3.3, 1 = <3.3
+ for(;;) {
+ uint8_t v = gb(buf, pos, wrap);
+ if(v == 0xff) {
+ hb = 1;
+ }
+ else if(hb == 1 && v == 0xd5){
+ hb = 2;
+ }
+ else if(hb == 2 && v == 0xaa) {
+ hb = 3;
+ }
+ else if(hb == 3 && ((v == 0x96) || (v == 0xab))) { // 0x96 = dos 3.3/16sec, 0xab = dos 3.21 and below/13sec
+ hb = 4;
+ if (v == 0xab) dosver = 1;
+ }
+ else
+ hb = 0;
+
+ if(hb == 4) {
+ uint8_t h[11];
+ for(auto & elem : h)
+ elem = gb(buf, pos, wrap);
+ //uint8_t v2 = gcr6bw_tb[h[2]];
+ uint8_t vl = gcr4_decode(h[0],h[1]);
+ uint8_t tr = gcr4_decode(h[2],h[3]);
+ uint8_t se = gcr4_decode(h[4],h[5]);
+ uint8_t chk = gcr4_decode(h[6],h[7]);
+ if(VERBOSE_SAVE) {
+ uint32_t post = get_u24be(&h[8]);
+ printf("Address Mark:\tVolume %d, Track %d, Sector %2d, Checksum %02X: %s, Postamble %03X: %s\n",
+ vl, tr, se, chk, (chk ^ vl ^ tr ^ se)==0?"OK":"BAD", post, (post&0xFFFF00)==0xDEAA00?"OK":"BAD");
+ }
+ // sanity check
+ if (tr == track && se < nsect) {
+ visualgrid[se][track] |= ADDRFOUND;
+ visualgrid[se][track] |= ((chk ^ vl ^ tr ^ se)==0)?ADDRGOOD:0;
+
+ if (visualgrid[se][track] & (LENIENT_ADDR_CHECK ? ADDRFOUND : ADDRGOOD)) {
+ int opos = pos;
+ int owrap = wrap;
+ hb = 0;
+ for(int i=0; i<20 && hb != 4; i++) {
+ v = gb(buf, pos, wrap);
+ if(v == 0xff)
hb = 1;
- }
- else if(hb == 1 && v == 0xd5){
+ else if(hb == 1 && v == 0xd5)
hb = 2;
- }
- else if(hb == 2 && v == 0xaa) {
+ else if(hb == 2 && v == 0xaa)
hb = 3;
- }
- else if(hb == 3 && ((v == 0x96) || (v == 0xab))) { // 0x96 = dos 3.3/16sec, 0xab = dos 3.21 and below/13sec
+ else if(hb == 3 && v == 0xad)
hb = 4;
- if (v == 0xab) dosver = 1;
- }
else
hb = 0;
+ }
+ if((hb == 4)&&(dosver == 0)) {
+ visualgrid[se][track] |= DATAFOUND;
+ uint8_t *dest;
+ uint8_t data[0x157];
+ uint32_t dpost = 0;
+ uint8_t c = 0;
+
+ if (m_prodos_order)
+ {
+ dest = sectdata+APPLE2_SECTOR_SIZE*prodos_skewing[se];
+ }
+ else
+ {
+ dest = sectdata+APPLE2_SECTOR_SIZE*dos_skewing[se];
+ }
- if(hb == 4) {
- uint8_t h[11];
- for(auto & elem : h)
- elem = gb(buf, ts, pos, wrap);
- //uint8_t v2 = gcr6bw_tb[h[2]];
- uint8_t vl = gcr4_decode(h[0],h[1]);
- uint8_t tr = gcr4_decode(h[2],h[3]);
- uint8_t se = gcr4_decode(h[4],h[5]);
- uint8_t chk = gcr4_decode(h[6],h[7]);
- #ifdef VERBOSE_SAVE
- uint32_t post = (h[8]<<16)|(h[9]<<8)|h[10];
- printf("Address Mark:\tVolume %d, Track %d, Sector %2d, Checksum %02X: %s, Postamble %03X: %s\n", vl, tr, se, chk, (chk ^ vl ^ tr ^ se)==0?"OK":"BAD", post, (post&0xFFFF00)==0xDEAA00?"OK":"BAD");
- #endif
- // sanity check
- if (tr == track && se < nsect) {
- visualgrid[se][track] |= ADDRFOUND;
- visualgrid[se][track] |= ((chk ^ vl ^ tr ^ se)==0)?ADDRGOOD:0;
-#ifdef LENIENT_ADDR_CHECK
- if ((visualgrid[se][track] & ADDRFOUND) == ADDRFOUND) {
-#else
- if ((visualgrid[se][track] & ADDRGOOD) == ADDRGOOD) {
-#endif
- int opos = pos;
- int owrap = wrap;
- hb = 0;
- for(int i=0; i<20 && hb != 4; i++) {
- v = gb(buf, ts, pos, wrap);
- if(v == 0xff)
- hb = 1;
- else if(hb == 1 && v == 0xd5)
- hb = 2;
- else if(hb == 2 && v == 0xaa)
- hb = 3;
- else if(hb == 3 && v == 0xad)
- hb = 4;
- else
- hb = 0;
- }
- if((hb == 4)&&(dosver == 0)) {
- visualgrid[se][track] |= DATAFOUND;
- uint8_t *dest;
- uint8_t data[0x157];
- uint32_t dpost = 0;
- uint8_t c = 0;
-
- if (m_prodos_order)
- {
- dest = sectdata+(256)*prodos_skewing[se];
- }
- else
- {
- dest = sectdata+(256)*dos_skewing[se];
- }
-
- // first read in sector and decode to 6bit form
- for(int i=0; i<0x156; i++) {
- data[i] = gcr6bw_tb[gb(buf, ts, pos, wrap)] ^ c;
- c = data[i];
- // printf("%02x ", c);
- // if (((i&0xf)+1)==0x10) printf("\n");
- }
- // read the checksum byte
- data[0x156] = gcr6bw_tb[gb(buf,ts,pos,wrap)];
- // now read the postamble bytes
- for(int i=0; i<3; i++) {
- dpost <<= 8;
- dpost |= gb(buf, ts, pos, wrap);
- }
- // next combine in the upper 2 bits of each byte
- uint8_t bit_swap[4] = { 0, 2, 1, 3 };
- for(int i=0; i<0x56; i++)
- data[i+0x056] = data[i+0x056]<<2 | bit_swap[data[i]&3];
- for(int i=0; i<0x56; i++)
- data[i+0x0ac] = data[i+0x0ac]<<2 | bit_swap[(data[i]>>2)&3];
- for(int i=0; i<0x54; i++)
- data[i+0x102] = data[i+0x102]<<2 | bit_swap[(data[i]>>4)&3];
- // now decode it into 256 bytes
- // but only write it if the bitfield of the track shows datagood is NOT set.
- // if it is set we don't want to overwrite a guaranteed good read with a bad one
- // if past read had a bad checksum or bad postamble...
-#ifndef USE_OLD_BEST_SECTOR_PRIORITY
- if (((visualgrid[se][track]&DATAGOOD)==0)||((visualgrid[se][track]&DATAPOST)==0)) {
- // if the current read is good, and postamble is good, write it in, no matter what.
- // if the current read is good and the current postamble is bad, write it in unless the postamble was good before
- // if the current read is bad and the current postamble is good and the previous read had neither good, write it in
- // if the current read isn't good and neither is the postamble but nothing better
- // has been written before, write it anyway.
- if ( ((data[0x156] == c) && (dpost&0xFFFF00)==0xDEAA00) ||
- (((data[0x156] == c) && (dpost&0xFFFF00)!=0xDEAA00) && ((visualgrid[se][track]&DATAPOST)==0)) ||
- (((data[0x156] != c) && (dpost&0xFFFF00)==0xDEAA00) && (((visualgrid[se][track]&DATAGOOD)==0)&&(visualgrid[se][track]&DATAPOST)==0)) ||
- (((data[0x156] != c) && (dpost&0xFFFF00)!=0xDEAA00) && (((visualgrid[se][track]&DATAGOOD)==0)&&(visualgrid[se][track]&DATAPOST)==0))
- ) {
- for(int i=0x56; i<0x156; i++) {
- uint8_t dv = data[i];
- *dest++ = dv;
- }
- }
- }
-#else
- if ((visualgrid[se][track]&DATAGOOD)==0) {
- for(int i=0x56; i<0x156; i++) {
- uint8_t dv = data[i];
- *dest++ = dv;
- }
- }
-#endif
- // do some checking
- #ifdef VERBOSE_SAVE
- if ((data[0x156] != c) || (dpost&0xFFFF00)!=0xDEAA00)
- fprintf(stderr,"Data Mark:\tChecksum xpctd %d found %d: %s, Postamble %03X: %s\n", data[0x156], c, (data[0x156]==c)?"OK":"BAD", dpost, (dpost&0xFFFF00)==0xDEAA00?"OK":"BAD");
- #endif
- if (data[0x156] == c) visualgrid[se][track] |= DATAGOOD;
- if ((dpost&0xFFFF00)==0xDEAA00) visualgrid[se][track] |= DATAPOST;
- } else if ((hb == 4)&&(dosver == 1)) {
- fprintf(stderr,"ERROR: We don't handle dos sectors below 3.3 yet!\n");
- } else {
- pos = opos;
- wrap = owrap;
+ // first read in sector and decode to 6bit form
+ for(int i=0; i<0x156; i++) {
+ data[i] = gcr6bw_tb[gb(buf, pos, wrap)] ^ c;
+ c = data[i];
+ // printf("%02x ", c);
+ // if (((i&0xf)+1)==0x10) printf("\n");
+ }
+ // read the checksum byte
+ data[0x156] = gcr6bw_tb[gb(buf,pos,wrap)];
+ // now read the postamble bytes
+ for(int i=0; i<3; i++) {
+ dpost <<= 8;
+ dpost |= gb(buf, pos, wrap);
+ }
+ // next combine in the upper 2 bits of each byte
+ uint8_t bit_swap[4] = { 0, 2, 1, 3 };
+ for(int i=0; i<0x56; i++)
+ data[i+0x056] = data[i+0x056]<<2 | bit_swap[data[i]&3];
+ for(int i=0; i<0x56; i++)
+ data[i+0x0ac] = data[i+0x0ac]<<2 | bit_swap[(data[i]>>2)&3];
+ for(int i=0; i<0x54; i++)
+ data[i+0x102] = data[i+0x102]<<2 | bit_swap[(data[i]>>4)&3];
+ // now decode it into 256 bytes
+ // but only write it if the bitfield of the track shows datagood is NOT set.
+ // if it is set we don't want to overwrite a guaranteed good read with a bad one
+ // if past read had a bad checksum or bad postamble...
+ if(USE_OLD_BEST_SECTOR_PRIORITY) {
+ if ((visualgrid[se][track]&DATAGOOD)==0) {
+ for(int i=0x56; i<0x156; i++) {
+ uint8_t dv = data[i];
+ *dest++ = dv;
+ }
+ }
+ } else {
+ if (((visualgrid[se][track]&DATAGOOD)==0)||((visualgrid[se][track]&DATAPOST)==0)) {
+ // if the current read is good, and postamble is good, write it in, no matter what.
+ // if the current read is good and the current postamble is bad, write it in unless the postamble was good before
+ // if the current read is bad and the current postamble is good and the previous read had neither good, write it in
+ // if the current read isn't good and neither is the postamble but nothing better
+ // has been written before, write it anyway.
+ if ( ((data[0x156] == c) && (dpost&0xFFFF00)==0xDEAA00) ||
+ (((data[0x156] == c) && (dpost&0xFFFF00)!=0xDEAA00) && ((visualgrid[se][track]&DATAPOST)==0)) ||
+ (((data[0x156] != c) && (dpost&0xFFFF00)==0xDEAA00) && (((visualgrid[se][track]&DATAGOOD)==0)&&(visualgrid[se][track]&DATAPOST)==0)) ||
+ (((data[0x156] != c) && (dpost&0xFFFF00)!=0xDEAA00) && (((visualgrid[se][track]&DATAGOOD)==0)&&(visualgrid[se][track]&DATAPOST)==0))
+ ) {
+ for(int i=0x56; i<0x156; i++) {
+ uint8_t dv = data[i];
+ *dest++ = dv;
}
}
}
- hb = 0;
+ }
+ // do some checking
+ if(VERBOSE_SAVE) {
+ if ((data[0x156] != c) || (dpost&0xFFFF00)!=0xDEAA00)
+ fprintf(stderr,"Data Mark:\tChecksum xpctd %d found %d: %s, Postamble %03X: %s\n",
+ data[0x156], c, (data[0x156]==c)?"OK":"BAD", dpost, (dpost&0xFFFF00)==0xDEAA00?"OK":"BAD");
+ }
+ if (data[0x156] == c) visualgrid[se][track] |= DATAGOOD;
+ if ((dpost&0xFFFF00)==0xDEAA00) visualgrid[se][track] |= DATAPOST;
+ } else if ((hb == 4)&&(dosver == 1)) {
+ fprintf(stderr,"ERROR: We don't handle dos sectors below 3.3 yet!\n");
+ } else {
+ pos = opos;
+ wrap = owrap;
}
- if(wrap)
- break;
- }
- for(int i=0; i<nsect; i++) {
- //if(nsect>0) printf("t%d,", track);
- uint8_t *data = sectdata + (256)*i;
- io_generic_write(io, data, pos_data, 256);
- pos_data += 256;
+ }
}
- //printf("\n");
+ hb = 0;
+ }
+ if(wrap)
+ break;
}
- // display a little table of which sectors decoded ok
- #ifdef VERBOSE_SAVE
+ for(int i=0; i<nsect; i++) {
+ //if(nsect>0) printf("t%d,", track);
+ uint8_t const *const data = sectdata + APPLE2_SECTOR_SIZE*i;
+ auto const [err, actual] = write_at(io, pos_data, data, APPLE2_SECTOR_SIZE);
+ if (err || actual != APPLE2_SECTOR_SIZE)
+ return false;
+ pos_data += APPLE2_SECTOR_SIZE;
+ }
+ //printf("\n");
+ }
+ // display a little table of which sectors decoded ok
+ if(VERBOSE_SAVE) {
int total_good = 0;
for (int j = 0; j < APPLE2_TRACK_COUNT; j++) {
printf("T%2d: ",j);
for (int i = 0; i < 16; i++) {
if (visualgrid[i][j] == NOTFOUND) printf("-NF- ");
else {
- if (visualgrid[i][j] & ADDRFOUND) printf("a"); else printf(" ");
- if (visualgrid[i][j] & ADDRGOOD) printf("A"); else printf(" ");
- if (visualgrid[i][j] & DATAFOUND) printf("d"); else printf(" ");
- if (visualgrid[i][j] & DATAGOOD) { printf("D"); total_good++; } else printf(" ");
- if (visualgrid[i][j] & DATAPOST) printf("."); else printf(" ");
+ if (visualgrid[i][j] & ADDRFOUND) printf("a"); else printf(" ");
+ if (visualgrid[i][j] & ADDRGOOD) printf("A"); else printf(" ");
+ if (visualgrid[i][j] & DATAFOUND) printf("d"); else printf(" ");
+ if (visualgrid[i][j] & DATAGOOD) { printf("D"); total_good++; } else printf(" ");
+ if (visualgrid[i][j] & DATAPOST) printf("."); else printf(" ");
}
}
printf("\n");
}
printf("Total Good Sectors: %d\n", total_good);
- #endif
+ }
- return true;
+ return true;
}
-const floppy_format_type FLOPPY_A216S_FORMAT = &floppy_image_format_creator<a2_16sect_format>;
+const a2_16sect_dos_format FLOPPY_A216S_DOS_FORMAT;
+const a2_16sect_prodos_format FLOPPY_A216S_PRODOS_FORMAT;
/* RWTS18 format
* Developed by Roland Gustafsson (http://www.acts.org/roland/index.html)
for Br0derbund Software around 1986
@@ -1026,65 +659,36 @@ a2_rwts18_format::a2_rwts18_format() : floppy_image_format_t()
{
}
-const char *a2_rwts18_format::name() const
+const char *a2_rwts18_format::name() const noexcept
{
return "a2_rwts18";
}
-const char *a2_rwts18_format::description() const
+const char *a2_rwts18_format::description() const noexcept
{
return "Apple II RWTS18-type Image";
}
-const char *a2_rwts18_format::extensions() const
+const char *a2_rwts18_format::extensions() const noexcept
{
return "rti";
}
-bool a2_rwts18_format::supports_save() const
+bool a2_rwts18_format::supports_save() const noexcept
{
return true;
}
-int a2_rwts18_format::identify(io_generic *io, uint32_t form_factor)
+int a2_rwts18_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const
{
- uint64_t size = io_generic_size(io);
- uint32_t expected_size = APPLE2_TRACK_COUNT * 16 * 256;
- return size == expected_size;
+ uint64_t size;
+ if(io.length(size))
+ return 0;
+ uint32_t const expected_size = APPLE2_TRACK_COUNT * 16 * 256;
+ return size == expected_size ? FIFID_SIZE : 0;
}
-// following is placeholder, is completely wrong.
-const floppy_image_format_t::desc_e a2_rwts18_format::mac_gcr[] = {
- { SECTOR_LOOP_START, 0, -1 },
- { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 },
- { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 },
- { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 },
- { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 },
- { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 },
- { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 },
- { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 },
- { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 },
- { RAWBITS, 0xd5aa96, 24 },
- { CRC_MACHEAD_START, 0 },
- { TRACK_ID_GCR6 },
- { SECTOR_ID_GCR6 },
- { TRACK_HEAD_ID_GCR6 },
- { SECTOR_INFO_GCR6 },
- { CRC_END, 0 },
- { CRC, 0 },
- { RAWBITS, 0xdeaaff, 24 },
- { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 },
- { RAWBITS, 0xd5aaad, 24 },
- { SECTOR_ID_GCR6 },
- { SECTOR_DATA_MAC, -1 },
- { RAWBITS, 0xdeaaff, 24 },
- { RAWBITS, 0xff, 8 },
- { SECTOR_LOOP_END },
- { END },
-};
-
-
-bool a2_rwts18_format::load(io_generic *io, uint32_t form_factor, floppy_image *image)
+bool a2_rwts18_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const
{
/* TODO: rewrite me properly
uint8_t sector_data[(256)*16];
@@ -1104,7 +708,8 @@ bool a2_rwts18_format::load(io_generic *io, uint32_t form_factor, floppy_image *
sectors[si].size = 256;
sectors[si].sector_id = si;
sectors[si].sector_info = format;
- io_generic_read(io, data, pos_data, 256);
+ size_t actual;
+ io.read_at(pos_data, data, 256, actual);
pos_data += 256;
}
generate_track(mac_gcr, track, head, sectors, 16, 3104*16, image);
@@ -1114,14 +719,14 @@ bool a2_rwts18_format::load(io_generic *io, uint32_t form_factor, floppy_image *
return false; // I hope that throws an error...
}
-uint8_t a2_rwts18_format::gb(const uint8_t *buf, int ts, int &pos, int &wrap)
+uint8_t a2_rwts18_format::gb(const std::vector<bool> &buf, int &pos, int &wrap)
{
uint8_t v = 0;
int w1 = wrap;
while(wrap != w1+2 && !(v & 0x80)) {
- v = v << 1 | ((buf[pos >> 3] >> (7-(pos & 7))) & 1);
+ v = (v << 1) | buf[pos];
pos++;
- if(pos == ts) {
+ if(pos == buf.size()) {
pos = 0;
wrap++;
}
@@ -1129,11 +734,7 @@ uint8_t a2_rwts18_format::gb(const uint8_t *buf, int ts, int &pos, int &wrap)
return v;
}
-void a2_rwts18_format::update_chk(const uint8_t *data, int size, uint32_t &chk)
-{
-}
-
-bool a2_rwts18_format::save(io_generic *io, floppy_image *image)
+bool a2_rwts18_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, const floppy_image &image) const
{
int g_tracks, g_heads;
int visualgrid[18][APPLE2_TRACK_COUNT]; // visualizer grid, cleared/initialized below
@@ -1162,7 +763,7 @@ bool a2_rwts18_format::save(io_generic *io, floppy_image *image)
elem[j] = 0;
}
}
- image->get_actual_geometry(g_tracks, g_heads);
+ image.get_actual_geometry(g_tracks, g_heads);
int head = 0;
@@ -1172,18 +773,16 @@ bool a2_rwts18_format::save(io_generic *io, floppy_image *image)
uint8_t sectdata[(768)*6];
memset(sectdata, 0, sizeof(sectdata));
int nsect = 18;
- uint8_t buf[130000]; // originally 13000, multiread dfi disks need larger
- int ts;
//fprintf(stderr,"DEBUG: a2_rwts18_format::save() about to generate bitstream from physical track %d (logical %d)...", track, track/2);
//~332 samples per cell, times 3+8+3 (14) for address mark, 24 for sync, 3+343+3 (349) for data mark, 24 for sync is around 743, near 776 expected
- generate_bitstream_from_track(0, head, 200000000/((3004*nsect*6)/2), buf, ts, image); // 3104 needs tweaking
+ auto buf = generate_bitstream_from_track(0, head, 200000000/((3004*nsect*6)/2), image); // 3104 needs tweaking
//fprintf(stderr,"done.\n");
int pos = 0;
int wrap = 0;
int hb = 0;
int dosver = 0; // apple dos version; 0 = >=3.3, 1 = <3.3
for(;;) {
- uint8_t v = gb(buf, ts, pos, wrap);
+ uint8_t v = gb(buf, pos, wrap);
if(v == 0xff)
hb = 1;
else if(hb == 1 && v == 0xd5)
@@ -1200,13 +799,13 @@ bool a2_rwts18_format::save(io_generic *io, floppy_image *image)
if(hb == 4) {
uint8_t h[11];
for(auto & elem : h)
- elem = gb(buf, ts, pos, wrap);
+ elem = gb(buf, pos, wrap);
//uint8_t v2 = gcr6bw_tb[h[2]];
uint8_t vl = gcr4_decode(h[0],h[1]);
uint8_t tr = gcr4_decode(h[2],h[3]);
uint8_t se = gcr4_decode(h[4],h[5]);
uint8_t chk = gcr4_decode(h[6],h[7]);
- uint32_t post = (h[8]<<16)|(h[9]<<8)|h[10];
+ uint32_t post = get_u24be(&h[8]);
printf("Address Mark:\tVolume %d, Track %d, Sector %2d, Checksum %02X: %s, Postamble %03X: %s\n", vl, tr, se, chk, (chk ^ vl ^ tr ^ se)==0?"OK":"BAD", post, (post&0xFFFF00)==0xDEAA00?"OK":"BAD");
// sanity check
if (tr == 0 && se < nsect) {
@@ -1221,7 +820,7 @@ bool a2_rwts18_format::save(io_generic *io, floppy_image *image)
int owrap = wrap;
hb = 0;
for(int i=0; i<20 && hb != 4; i++) {
- v = gb(buf, ts, pos, wrap);
+ v = gb(buf, pos, wrap);
if(v == 0xff)
hb = 1;
else if(hb == 1 && v == 0xd5)
@@ -1256,17 +855,17 @@ bool a2_rwts18_format::save(io_generic *io, floppy_image *image)
uint8_t c = 0;
// first read in sector and decode to 6bit form
for(int i=0; i<0x156; i++) {
- data[i] = gcr6bw_tb[gb(buf, ts, pos, wrap)] ^ c;
+ data[i] = gcr6bw_tb[gb(buf, pos, wrap)] ^ c;
c = data[i];
// printf("%02x ", c);
// if (((i&0xf)+1)==0x10) printf("\n");
}
// read the checksum byte
- data[0x156] = gcr6bw_tb[gb(buf,ts,pos,wrap)];
+ data[0x156] = gcr6bw_tb[gb(buf,pos,wrap)];
// now read the postamble bytes
for(int i=0; i<3; i++) {
dpost <<= 8;
- dpost |= gb(buf, ts, pos, wrap);
+ dpost |= gb(buf, pos, wrap);
}
// next combine in the upper 2 bits of each byte
uint8_t bit_swap[4] = { 0, 2, 1, 3 };
@@ -1326,8 +925,8 @@ bool a2_rwts18_format::save(io_generic *io, floppy_image *image)
}
for(int i=0; i<nsect; i++) {
//if(nsect>0) printf("t%d,", track);
- uint8_t *data = sectdata + (256)*i;
- io_generic_write(io, data, pos_data, 256);
+ uint8_t const *const data = sectdata + (256)*i;
+ /*auto const [err, actual] =*/ write_at(io, pos_data, data, 256); // FIXME: check for errors
pos_data += 256;
}
@@ -1336,18 +935,16 @@ bool a2_rwts18_format::save(io_generic *io, floppy_image *image)
uint8_t sectdata[(768)*6];
memset(sectdata, 0, sizeof(sectdata));
int nsect = 18;
- uint8_t buf[130000]; // originally 13000, multiread dfi disks need larger
- int ts;
//fprintf(stderr,"DEBUG: a2_rwts18_format::save() about to generate bitstream from physical track %d (logical %d)...", track, track/2);
//~332 samples per cell, times 3+8+3 (14) for address mark, 24 for sync, 3+343+3 (349) for data mark, 24 for sync is around 743, near 776 expected
- generate_bitstream_from_track(track, head, 200000000/((3004*nsect*6)/2), buf, ts, image); // 3104 needs tweaking
+ auto buf = generate_bitstream_from_track(track, head, 200000000/((3004*nsect*6)/2), image); // 3104 needs tweaking
//fprintf(stderr,"done.\n");
int oldpos = 0; // DEBUG
int pos = 0;
int wrap = 0;
int hb = 0;
for(;;) {
- uint8_t v = gb(buf, ts, pos, wrap);
+ uint8_t v = gb(buf, pos, wrap);
if((v == 0xff) || (v == 0x9a)) // note 0x9a varies per title! this is an LFSR? generated value intended to throw off copiers, and only appears after the track splice (before sector 5)
hb = 1;
else if(hb == 1 && v == 0xd5)
@@ -1363,11 +960,11 @@ bool a2_rwts18_format::save(io_generic *io, floppy_image *image)
uint8_t h[7];
// grab exactly 7 bytes: should be Track, Sector, Checksum, AA, FF and FF and the Br0derbund Title ID
for(auto & elem : h)
- elem = gb(buf, ts, pos, wrap);
+ elem = gb(buf, pos, wrap);
uint8_t tr = gcr6bw_tb[h[0]];
uint8_t se = gcr6bw_tb[h[1]];
uint8_t chk = gcr6bw_tb[h[2]];
- uint32_t post = (h[3]<<16)|(h[4]<<8)|h[5];
+ uint32_t post = get_u24be(&h[3]);
uint8_t bbundid = h[6];
printf("RWTS18 AM:\t Track %d, Sector %2d, Checksum %02X: %s, Postamble %03X: %s, BBUNDID %02x\n", tr, se, chk, (chk ^ tr ^ se)==0?"OK":"BAD", post, post==0xAAFFFF?"OK":"BAD", bbundid);
// sanity check
@@ -1390,7 +987,7 @@ bool a2_rwts18_format::save(io_generic *io, floppy_image *image)
//dest = sectdata+(768)*se;
// now read in the sector and decode to 6bit form
for(int i=0; i<0x400; i++) {
- data[i] = gcr6bw_tb[gb(buf, ts, pos, wrap)] ;//^ c;
+ data[i] = gcr6bw_tb[gb(buf, pos, wrap)] ;//^ c;
c ^= data[i];
/*if (((i&0x3)+1)==0x04) {
printf("%c", ((((data[i-3]&0x30)<<2)|((data[i-2]&0x3F)>>0))&0x3F)+0x40);
@@ -1404,18 +1001,18 @@ bool a2_rwts18_format::save(io_generic *io, floppy_image *image)
// if (((i&0xf)+1)==0x10) printf("\n");
}
// read the checksum byte (checksum is calced by xoring all data together)
- data[0x400] = gcr6bw_tb[gb(buf,ts,pos,wrap)];
+ data[0x400] = gcr6bw_tb[gb(buf,pos,wrap)];
// now read the postamble bytes
for(int i=0; i<4; i++) {
dpost <<= 8;
- dpost |= gb(buf, ts, pos, wrap);
+ dpost |= gb(buf, pos, wrap);
}
/*if (se == 0) // dump some debug data to help find the lfsr before sector 5
{
printf("Data Postamble was 0x%08x\n", dpost);
for(int i=0; i<0x400; i++) {
- data[i] = gcr6bw_tb[gb(buf, ts, pos, wrap)] ;//^ c;
+ data[i] = gcr6bw_tb[gb(buf, pos, wrap)] ;//^ c;
c ^= data[i];
printf("%02x ", data[i]);
if (((i&0xf)+1)==0x10) printf("\n");
@@ -1509,8 +1106,8 @@ bool a2_rwts18_format::save(io_generic *io, floppy_image *image)
}
for(int i=0; i<nsect; i++) {
//if(nsect>0) printf("t%d,", track);
- uint8_t *data = sectdata + (256)*i;
- io_generic_write(io, data, pos_data, 256);
+ uint8_t const *const data = sectdata + (256)*i;
+ /*auto const [err, actual] =*/ write_at(io, pos_data, data, 256); // FIXME: check for errors
pos_data += 256;
}
//printf("\n");
@@ -1536,59 +1133,57 @@ bool a2_rwts18_format::save(io_generic *io, floppy_image *image)
return true;
}
-const floppy_format_type FLOPPY_RWTS18_FORMAT = &floppy_image_format_creator<a2_rwts18_format>;
+const a2_rwts18_format FLOPPY_RWTS18_FORMAT;
a2_edd_format::a2_edd_format() : floppy_image_format_t()
{
}
-const char *a2_edd_format::name() const
+const char *a2_edd_format::name() const noexcept
{
return "a2_edd";
}
-const char *a2_edd_format::description() const
+const char *a2_edd_format::description() const noexcept
{
return "Apple II EDD Image";
}
-const char *a2_edd_format::extensions() const
+const char *a2_edd_format::extensions() const noexcept
{
return "edd";
}
-bool a2_edd_format::supports_save() const
+bool a2_edd_format::supports_save() const noexcept
{
return false;
}
-int a2_edd_format::identify(io_generic *io, uint32_t form_factor)
+int a2_edd_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const
{
- return ((io_generic_size(io) == 2244608) || (io_generic_size(io) == 2310144)) ? 50 : 0;
+ uint64_t size;
+ if (io.length(size))
+ return 0;
+ return ((size == 2244608) || (size == 2310144)) ? FIFID_SIZE : 0;
}
uint8_t a2_edd_format::pick(const uint8_t *data, int pos)
{
- return ((data[pos>>3] << 8) | data[(pos>>3)+1]) >> (8-(pos & 7));
+ return get_u16be(&data[pos>>3]) >> (8-(pos & 7));
}
-bool a2_edd_format::load(io_generic *io, uint32_t form_factor, floppy_image *image)
+bool a2_edd_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const
{
- uint8_t *img;
uint8_t nibble[16384], stream[16384];
int npos[16384];
+ static const size_t img_size = 2'244'608;
- img = (uint8_t *) malloc(2244608);
-
- if (!img)
- {
+ auto [err, img, actual] = read_at(io, 0, img_size);
+ if(err || actual != img_size)
return false;
- }
-
- io_generic_read(io, img, 0, 2244608);
for(int i=0; i<137; i++) {
- const uint8_t *trk = img + 16384*i;
+ uint8_t const *const trk = &img[16384*i];
int pos = 0;
int wpos = 0;
while(pos < 16383*8) {
@@ -1650,166 +1245,191 @@ bool a2_edd_format::load(io_generic *io, uint32_t form_factor, floppy_image *ima
stream[splice >> 3] ^= 0x80 >> (splice & 7);
generate_track_from_bitstream(i >> 2, 0, stream, len, image, i & 3);
- image->set_write_splice_position(i >> 2, 0, uint32_t(uint64_t(200'000'000)*splice/len), i & 3);
+ image.set_write_splice_position(i >> 2, 0, uint32_t(uint64_t(200'000'000)*splice/len), i & 3);
}
- free(img);
+ img.reset();
+
+ image.set_form_variant(floppy_image::FF_525, floppy_image::SSSD);
+
return true;
}
-const floppy_format_type FLOPPY_EDD_FORMAT = &floppy_image_format_creator<a2_edd_format>;
+const a2_edd_format FLOPPY_EDD_FORMAT;
-a2_woz_format::a2_woz_format() : floppy_image_format_t()
+a2_nib_format::a2_nib_format() : floppy_image_format_t()
{
}
-const char *a2_woz_format::name() const
+const char *a2_nib_format::name() const noexcept
{
- return "a2_woz";
+ return "a2_nib";
}
-const char *a2_woz_format::description() const
+const char *a2_nib_format::description() const noexcept
{
- return "Apple II WOZ Image";
+ return "Apple II NIB Image";
}
-const char *a2_woz_format::extensions() const
+const char *a2_nib_format::extensions() const noexcept
{
- return "woz";
+ return "nib";
}
-bool a2_woz_format::supports_save() const
+bool a2_nib_format::supports_save() const noexcept
{
return false;
}
-const uint8_t a2_woz_format::signature[8] = { 0x57, 0x4f, 0x5a, 0x31, 0xff, 0x0a, 0x0d, 0x0a };
-const uint8_t a2_woz_format::signature2[8] = { 0x57, 0x4f, 0x5a, 0x32, 0xff, 0x0a, 0x0d, 0x0a };
-
-int a2_woz_format::identify(io_generic *io, uint32_t form_factor)
+int a2_nib_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const
{
- uint8_t header[8];
- io_generic_read(io, header, 0, 8);
- if (!memcmp(header, signature, 8)) return 100;
- if (!memcmp(header, signature2, 8)) return 100;
- return 0;
-}
+ uint64_t size;
+ if (io.length(size))
+ return 0;
-bool a2_woz_format::load(io_generic *io, uint32_t form_factor, floppy_image *image)
-{
- std::vector<uint8_t> img(io_generic_size(io));
- io_generic_read(io, &img[0], 0, img.size());
+ if (size == expected_size_35t || size == expected_size_40t)
+ return FIFID_SIZE;
- // Check signature
- if ((memcmp(&img[0], signature, 8)) && (memcmp(&img[0], signature2, 8)))
- return false;
+ return 0;
+}
- uint32_t woz_vers = 1;
- if (!memcmp(&img[0], signature2, 8)) woz_vers = 2;
- // Check integrity
- uint32_t crc = crc32r(&img[12], img.size() - 12);
- if(crc != r32(img, 8))
- return false;
+template<class It>
+static
+size_t count_leading_FFs(const It first, const It last)
+{
+ auto curr = first;
+ for (; curr != last; ++curr) {
+ if (*curr != 0xFF) {
+ break;
+ }
+ }
+ return curr - first;
+}
- uint32_t off_info = find_tag(img, 0x4f464e49);
- uint32_t off_tmap = find_tag(img, 0x50414d54);
- uint32_t off_trks = find_tag(img, 0x534b5254);
-// uint32_t off_writ = find_tag(img, 0x54495257);
+static
+size_t count_trailing_padding(const std::vector<uint8_t>& nibbles) {
+ const auto b = nibbles.rbegin();
+ const auto e = nibbles.rend();
+ auto i = b;
- if(!off_info || !off_tmap || !off_trks)
- return false;
+ // skip until the first valid nibble...
+ for (; i != e; ++i) {
+ if ((*i & 0x80) != 0) { // valid nibble
+ break;
+ }
+ }
+ return i - b;
+}
- uint32_t info_vers = r8(img, off_info + 0);
+std::vector<uint32_t> a2_nib_format::generate_levels_from_nibbles(const std::vector<uint8_t>& nibbles)
+{
+ std::vector<uint32_t> levels;
+ const auto append_FFs = [&] (size_t count) {
+ while (count-- > 0) {
+ raw_w(levels, 8, 0xFF);
+ }
+ };
+ const auto append_syncs = [&] (size_t count) {
+ while (count-- > 0) {
+ raw_w(levels, 10, 0x00FF << 2);
+ }
+ };
+ const auto append_byte = [&] (uint8_t byte) {
+ raw_w(levels, 8, byte);
+ };
- if ((info_vers != 1) && (info_vers != 2))
- return false;
- bool is_35 = r8(img, off_info + 1) == 2;
- if((form_factor == floppy_image::FF_35 && !is_35) || (form_factor == floppy_image::FF_525 && is_35))
- return false;
+ const auto leading_FF_count =
+ count_leading_FFs(nibbles.begin(), nibbles.end());
- unsigned int limit = is_35 ? 160 : 141;
+ if (leading_FF_count >= nibbles.size()) { // all are 0xFF !?!?
+ assert(leading_FF_count >= min_sync_bytes);
+ append_syncs(leading_FF_count);
+ return levels;
+ }
- if (woz_vers == 1) {
- for (unsigned int trkid = 0; trkid != limit; trkid++) {
- int head = is_35 && trkid >= 80 ? 1 : 0;
- int track = is_35 ? trkid % 80 : trkid / 4;
- int subtrack = is_35 ? 0 : trkid & 3;
+ const auto trailing_padding_size = count_trailing_padding(nibbles);
+ const auto trailing_FF_count =
+ count_leading_FFs(nibbles.rbegin() + trailing_padding_size,
+ nibbles.rend());
+ const auto wrapped_FF_count = leading_FF_count + trailing_FF_count;
+ const bool wrapped_FF_are_syncs = wrapped_FF_count >= min_sync_bytes;
+
+ if (wrapped_FF_are_syncs) {
+ append_syncs(leading_FF_count);
+ } else {
+ append_FFs(leading_FF_count);
+ }
- uint8_t idx = r8(img, off_tmap + trkid);
- if(idx != 0xff) {
- uint32_t boff = off_trks + 6656*idx;
- if (r16(img, boff + 6648) == 0)
- return false;
- generate_track_from_bitstream(track, head, &img[boff], r16(img, boff + 6648), image, subtrack, r16(img, boff + 6650));
+ {
+ size_t FF_count = 0;
+ const auto flush_FFs = [&] {
+ if (FF_count == 0) {
+ return;
}
- }
- } else if (woz_vers == 2) {
- for (unsigned int trkid = 0; trkid != limit; trkid++) {
- int head = is_35 && trkid & 1 ? 1 : 0;
- int track = is_35 ? trkid >> 1 : trkid / 4;
- int subtrack = is_35 ? 0 : trkid & 3;
- uint8_t idx = r8(img, off_tmap + trkid);
- if(idx != 0xff) {
- uint32_t trks_off = off_trks + (idx * 8);
-
- uint32_t boff = (uint32_t)r16(img, trks_off + 0) * 512;
-
- if (r16(img, trks_off + 4) == 0)
- return false;
+ if (FF_count >= a2_nib_format::min_sync_bytes) {
+ append_syncs(FF_count);
+ } else {
+ append_FFs(FF_count);
+ }
+ FF_count = 0;
+ };
+
+ const auto end = nibbles.end() - trailing_padding_size - trailing_FF_count;
+ for (auto i = nibbles.begin() + leading_FF_count; i != end; ++i) {
+ const auto nibble = *i;
+ if ((nibble & 0x80) == 0) {
+ continue;
+ }
- // TODO: when write capability is added, use the WRIT chunk data if it's present
- generate_track_from_bitstream(track, head, &img[boff], r16(img, trks_off + 4), image, subtrack, 0xffff);
+ if (nibble == 0xFF) {
+ ++FF_count;
+ continue;
}
+
+ flush_FFs();
+ append_byte(nibble);
}
+ flush_FFs();
}
- else return false;
- return true;
-}
+ if (wrapped_FF_are_syncs) {
+ append_syncs(trailing_FF_count);
+ } else {
+ append_FFs(trailing_FF_count);
+ }
-uint32_t a2_woz_format::find_tag(const std::vector<uint8_t> &data, uint32_t tag)
-{
- uint32_t offset = 12;
- do {
- if(r32(data, offset) == tag)
- return offset + 8;
- offset += r32(data, offset+4) + 8;
- } while(offset < data.size() - 8);
- return 0;
+ return levels;
}
-uint32_t a2_woz_format::r32(const std::vector<uint8_t> &data, uint32_t offset)
+bool a2_nib_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const
{
- return data[offset] | (data[offset+1] << 8) | (data[offset+2] << 16) | (data[offset+3] << 24);
-}
+ uint64_t size;
+ if (io.length(size))
+ return false;
+ if (size != expected_size_35t && size != expected_size_40t)
+ return false;
-uint16_t a2_woz_format::r16(const std::vector<uint8_t> &data, uint32_t offset)
-{
- return data[offset] | (data[offset+1] << 8);
-}
+ const auto nr_tracks = size / nibbles_per_track;
-uint8_t a2_woz_format::r8(const std::vector<uint8_t> &data, uint32_t offset)
-{
- return data[offset];
-}
+ std::vector<uint8_t> nibbles(nibbles_per_track);
+ for (unsigned track = 0; track < nr_tracks; ++track) {
+ auto const [err, actual] = read_at(io, track * nibbles_per_track, &nibbles[0], nibbles_per_track);
+ if (err || actual != nibbles_per_track)
+ return false;
-uint32_t a2_woz_format::crc32r(const uint8_t *data, uint32_t size)
-{
- // Reversed crc32
- uint32_t crc = 0xffffffff;
- for(uint32_t i=0; i != size; i++) {
- crc = crc ^ data[i];
- for(int j=0; j<8; j++)
- if(crc & 1)
- crc = (crc >> 1) ^ 0xedb88320;
- else
- crc = crc >> 1;
+ auto levels = generate_levels_from_nibbles(nibbles);
+ if (!levels.empty()) {
+ generate_track_from_levels(track, 0, levels, 0, image);
+ }
}
- return ~crc;
+
+ image.set_form_variant(floppy_image::FF_525, floppy_image::SSSD);
+
+ return true;
}
-const floppy_format_type FLOPPY_WOZ_FORMAT = &floppy_image_format_creator<a2_woz_format>;
+const a2_nib_format FLOPPY_NIB_FORMAT;