diff options
Diffstat (limited to 'src/lib/formats/ap_dsk35.cpp')
-rw-r--r-- | src/lib/formats/ap_dsk35.cpp | 1532 |
1 files changed, 281 insertions, 1251 deletions
diff --git a/src/lib/formats/ap_dsk35.cpp b/src/lib/formats/ap_dsk35.cpp index c18ea8c65d4..4096215c35f 100644 --- a/src/lib/formats/ap_dsk35.cpp +++ b/src/lib/formats/ap_dsk35.cpp @@ -1,8 +1,8 @@ // license:BSD-3-Clause -// copyright-holders:Nathan Woods, R. Belmont +// copyright-holders:O. Galibert, R. Belmont /********************************************************************* - ap_dsk35.c + ap_dsk35.cpp Apple 3.5" disk images @@ -98,1405 +98,435 @@ *********************************************************************/ -#include <stdio.h> -#include <assert.h> - -#include "emu.h" // logerror #include "ap_dsk35.h" -struct apple35_tag -{ - uint32_t data_offset; - uint32_t data_size; - uint8_t format_byte; - uint8_t sides; - unsigned int is_1440k : 1; - - /* stuff used in DiskCopy images */ - uint32_t tag_offset; - uint32_t tag_size; -}; +#include "ioprocs.h" +#include "multibyte.h" +#include "opresolv.h" +#include "eminline.h" +#include "osdcore.h" // osd_printf_error +#include <cassert> +#include <cstdio> +#include <cstring> -/* normal number of sector for each track */ -static const uint8_t apple35_tracklen_800kb[80] = -{ - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 -}; - -/* blocks of data used to nibblize tracks */ -static const uint8_t diskbytes[] = -{ - 0x96, 0x97, 0x9A, 0x9B, 0x9D, 0x9E, 0x9F, 0xA6, /* 0x00 */ - 0xA7, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB2, 0xB3, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB9, 0xBA, 0xBB, 0xBC, /* 0x10 */ - 0xBD, 0xBE, 0xBF, 0xCB, 0xCD, 0xCE, 0xCF, 0xD3, - 0xD6, 0xD7, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, /* 0x20 */ - 0xDF, 0xE5, 0xE6, 0xE7, 0xE9, 0xEA, 0xEB, 0xEC, - 0xED, 0xEE, 0xEF, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, /* 0x30 */ - 0xF7, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF -}; - -/* reverse lookup of diskbytes */ -static const int16_t rev_diskbytes[] = -{ - -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* 0x30 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* 0x60 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* 0x70 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 0x00, 0x01, /* 0x90 */ - -1, -1, 0x02, 0x03, -1, 0x04, 0x05, 0x06, - -1, -1, -1, -1, -1, -1, 0x07, 0x08, /* 0xA0 */ - -1, -1, -1, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, - -1, -1, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, /* 0xB0 */ - -1, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, - -1, -1, -1, -1, -1, -1, -1, -1, /* 0xC0 */ - -1, -1, -1, 0x1B, -1, 0x1C, 0x1D, 0x1E, - -1, -1, -1, 0x1F, -1, -1, 0x20, 0x21, /* 0xD0 */ - -1, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, - -1, -1, -1, -1, -1, 0x29, 0x2A, 0x2B, /* 0xE0 */ - -1, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, - -1, -1, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, /* 0xF0 */ - -1, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F -}; - -static const uint8_t blk1[] = -{ - /*0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xD5, 0xAA, 0x96*/ - 0xFF, - 0xFF, 0x3F, 0xCF, 0xF3, 0xFC, 0xFF, - 0xFF, 0x3F, 0xCF, 0xF3, 0xFC, 0xFF, - 0xFF, 0x3F, 0xCF, 0xF3, 0xFC, 0xFF, - 0xFF, 0x3F, 0xCF, 0xF3, 0xFC, 0xFF, - 0xFF, 0x3F, 0xCF, 0xF3, 0xFC, 0xFF, - 0xFF, 0x3F, 0xCF, 0xF3, 0xFC, 0xFF, - 0xFF, 0x3F, 0xCF, 0xF3, 0xFC, 0xFF, - 0xD5, 0xAA, 0x96 -}; -static const uint8_t blk2[] = -{ - 0xDE, 0xAA, 0xFF, 0xFF, 0x3F, 0xCF, 0xF3, 0xFC, 0xFF, 0xD5, 0xAA, 0xAD -}; -static const uint8_t blk3[] = +dc42_format::dc42_format() : floppy_image_format_t() { - 0xDE, 0xAA, 0xFF -}; - - +} -static struct apple35_tag *get_apple35_tag(floppy_image_legacy *floppy) +const char *dc42_format::name() const noexcept { - struct apple35_tag *tag; - tag = (struct apple35_tag *) floppy_tag(floppy); - return tag; + return "dc42"; } - - -int apple35_sectors_per_track(floppy_image_legacy *image, int track) +const char *dc42_format::description() const noexcept { - int sectors; - - assert(track >= 0); - assert(track < ARRAY_LENGTH(apple35_tracklen_800kb)); - - if (get_apple35_tag(image)->is_1440k) - sectors = 18; - else - sectors = apple35_tracklen_800kb[track]; - return sectors; + return "DiskCopy 4.2 image"; } - - -/* - converts data to its nibblized representation, and generate checksum - - now handles 524-byte-long sectors - - tag data IS important, since it allows data recovery when the catalog is trashed -*/ -static void sony_nibblize35(const uint8_t *in, uint8_t *nib_ptr, uint8_t *csum) +const char *dc42_format::extensions() const noexcept { - int i, j; - uint32_t c1, c2, c3, c4; - uint8_t val; - uint8_t w1, w2, w3, w4; - uint8_t b1[175], b2[175], b3[175]; - - /* Copy from the user's buffer to our buffer, while computing - * the three-byte data checksum - */ - - i = 0; - j = 0; - c1 = 0; - c2 = 0; - c3 = 0; - while (1) - { - c1 = (c1 & 0xFF) << 1; - if (c1 & 0x0100) - c1++; - - val = in[i++]; - c3 += val; - if (c1 & 0x0100) - { - c3++; - c1 &= 0xFF; - } - b1[j] = (val ^ c1) & 0xFF; - - val = in[i++]; - c2 += val; - if (c3 > 0xFF) - { - c2++; - c3 &= 0xFF; - } - b2[j] = (val ^ c3) & 0xFF; - - if (i == 524) break; - - val = in[i++]; - c1 += val; - if (c2 > 0xFF) - { - c1++; - c2 &= 0xFF; - } - b3[j] = (val ^ c2) & 0xFF; - j++; - } - c4 = ((c1 & 0xC0) >> 6) | ((c2 & 0xC0) >> 4) | ((c3 & 0xC0) >> 2); - b3[174] = 0; - - j = 0; - for (i = 0; i <= 174; i++) - { - w1 = b1[i] & 0x3F; - w2 = b2[i] & 0x3F; - w3 = b3[i] & 0x3F; - w4 = ((b1[i] & 0xC0) >> 2); - w4 |= ((b2[i] & 0xC0) >> 4); - w4 |= ((b3[i] & 0xC0) >> 6); - - nib_ptr[j++] = w4; - nib_ptr[j++] = w1; - nib_ptr[j++] = w2; - - if (i != 174) nib_ptr[j++] = w3; - } - - csum[0] = c1 & 0x3F; - csum[1] = c2 & 0x3F; - csum[2] = c3 & 0x3F; - csum[3] = c4 & 0x3F; + return "dc42"; } - - -/* - does the reverse process of sony_nibblize35 -*/ -static void sony_denibblize35(uint8_t *out, const uint8_t *nib_ptr, uint8_t *checksum) +bool dc42_format::supports_save() const noexcept { - int i, j; - uint32_t c1,c2,c3,c4; - uint8_t val; - uint8_t w1,w2,w3=0,w4; - uint8_t b1[175],b2[175],b3[175]; - - j = 0; - for (i=0; i<=174; i++) - { - w4 = nib_ptr[j++]; - w1 = nib_ptr[j++]; - w2 = nib_ptr[j++]; - - if (i != 174) w3 = nib_ptr[j++]; - - b1[i] = (w1 & 0x3F) | ((w4 << 2) & 0xC0); - b2[i] = (w2 & 0x3F) | ((w4 << 4) & 0xC0); - b3[i] = (w3 & 0x3F) | ((w4 << 6) & 0xC0); - } + return true; +} - /* Copy from the user's buffer to our buffer, while computing - * the three-byte data checksum - */ +int dc42_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const +{ + uint64_t size; + if(io.length(size) || (size < 0x54)) + return 0; - i = 0; - j = 0; - c1 = 0; - c2 = 0; - c3 = 0; - while (1) - { - c1 = (c1 & 0xFF) << 1; - if (c1 & 0x0100) - c1++; - - val = (b1[j] ^ c1) & 0xFF; - c3 += val; - if (c1 & 0x0100) - { - c3++; - c1 &= 0xFF; - } - out[i++] = val; - - val = (b2[j] ^ c3) & 0xFF; - c2 += val; - if (c3 > 0xFF) - { - c2++; - c3 &= 0xFF; - } - out[i++] = val; + uint8_t h[0x54]; + auto const [err, actual] = read_at(io, 0, h, 0x54); + if (err || (0x54 != actual)) + return 0; - if (i == 524) break; + uint32_t const dsize = get_u32be(&h[0x40]); + uint32_t const tsize = get_u32be(&h[0x44]); - val = (b3[j] ^ c2) & 0xFF; - c1 += val; - if (c2 > 0xFF) - { - c1++; - c2 &= 0xFF; - } - out[i++] = val; - j++; - } - c4 = ((c1 & 0xC0) >> 6) | ((c2 & 0xC0) >> 4) | ((c3 & 0xC0) >> 2); - b3[174] = 0; + uint8_t const encoding = h[0x50]; + uint8_t const format = h[0x51]; + // if it's a 1.44MB DC42 image, reject it so the generic PC MFM handler picks it up + if ((encoding == 0x03) && (format == 0x02)) + return 0; - checksum[0] = c1 & 0x3F; - checksum[1] = c2 & 0x3F; - checksum[2] = c3 & 0x3F; - checksum[3] = c4 & 0x3F; + return (size == 0x54+tsize+dsize && h[0] < 64 && h[0x52] == 1 && h[0x53] == 0) ? FIFID_STRUCT : 0; } - - -void sony_filltrack(uint8_t *buffer, size_t buffer_len, size_t *pos, uint8_t data) +bool dc42_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { - buffer[*pos / 8] &= 0xFF << (8 - (*pos % 8)); - buffer[*pos / 8] |= data >> (*pos % 8); + uint8_t h[0x54]; + read_at(io, 0, h, 0x54); // FIXME: check for errors and premature EOF + int dsize = get_u32be(&h[0x40]); + int tsize = get_u32be(&h[0x44]); - *pos += 8; - *pos %= buffer_len * 8; + uint8_t encoding = h[0x50]; + uint8_t format = h[0x51]; - buffer[*pos / 8] &= 0xFF >> (*pos % 8); - buffer[*pos / 8] |= data << (8 - (*pos % 8)); -} + if((encoding != 0x00 || format != 0x02) && ((encoding != 0x01 && encoding != 0x03) || (format != 0x22 && format != 0x24))) { + osd_printf_error("dc42: Unsupported encoding/format combination %02x/%02x\n", encoding, format); + return false; + } + switch(dsize) { + case 409600: // Mac 400K + image.set_form_variant(floppy_image::FF_35, floppy_image::SSDD); + break; + case 737280: // PC 720K + case 819200: // Mac/A2 800K + image.set_form_variant(floppy_image::FF_35, floppy_image::DSDD); + break; -uint8_t sony_fetchtrack(const uint8_t *buffer, size_t buffer_len, size_t *pos) -{ - uint8_t data; + case 1474560: // PC or Mac 1.44M + image.set_form_variant(floppy_image::FF_35, floppy_image::DSHD); + break; - data = buffer[*pos / 8] << (*pos % 8); - *pos += 8; - *pos %= (buffer_len * 8); - data |= buffer[*pos / 8] >> (8 - (*pos % 8)); + case 871424: // Apple Twiggy 851KiB + image.set_form_variant(floppy_image::FF_525, floppy_image::DSHD); + break; - while ((data & 0x80) == 0) - { - /* this code looks weird because it isn't simply rotating the new bit - * in, but for some reason it won't work if I rotate the bit in; I - * have to match the algorithm used by the old code */ - data <<= 1; - data |= (buffer[*pos / 8] >> (8 - ((*pos % 8) + 1))); - (*pos)++; - *pos %= (buffer_len * 8); + default: + osd_printf_error("dc42: dsize is %d, unknown form factor\n"); + break; } -// printf("sony_fetchtrack: pos %ld = %02x\n", *pos/8, data); + uint8_t sector_data[(512+12)*12]; + memset(sector_data, 0, sizeof(sector_data)); - return data; -} + desc_gcr_sector sectors[12]; + int pos_data = 0x54; + int pos_tag = 0x54+dsize; + int head_count = encoding == 1 ? 2 : 1; -static uint32_t apple35_get_offset(floppy_image_legacy *floppy, int head, int track, int sector, uint32_t *tag_offset) -{ - int i; - uint32_t sector_index = 0; - struct apple35_tag *tag; - - tag = get_apple35_tag(floppy); - - if (track >= ARRAY_LENGTH(apple35_tracklen_800kb)) - return ~0; - if (head >= tag->sides) - return ~0; - if (sector >= apple35_sectors_per_track(floppy, track)) - return ~0; - - for (i = 0; i < track; i++) - sector_index += apple35_sectors_per_track(floppy, i); - sector_index *= tag->sides; - if (head) - sector_index += apple35_sectors_per_track(floppy, i); - sector_index += sector; - - if (tag_offset) - { - *tag_offset = sector_index * 12; - if (*tag_offset >= tag->tag_size) - { - *tag_offset = ~0; - } - else - { - *tag_offset += tag->tag_offset; + for(int track=0; track < 80; track++) { + for(int head=0; head < head_count; head++) { + int ns = 12 - (track/16); + int si = 0; + for(int i=0; i<ns; i++) { + uint8_t *data = sector_data + (512+12)*i; + sectors[si].track = track; + sectors[si].head = head; + sectors[si].sector = i; + sectors[si].info = format; + if(tsize) { + read_at(io, pos_tag, data, 12); // FIXME: check for errors and premature EOF + sectors[si].tag = data; + pos_tag += 12; + } else { + sectors[si].tag = nullptr; + } + sectors[si].data = data+12; + read_at(io, pos_data, data+12, 512); // FIXME: check for errors and premature EOF + pos_data += 512; + si = (si + 2) % ns; + if(si == 0) + si++; + } + build_mac_track_gcr(track, head, image, sectors); } } - return sector_index * 0x200 + tag->data_offset; + return true; } - - -static floperr_t apple35_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen) +void dc42_format::update_chk(const uint8_t *data, int size, uint32_t &chk) { - uint32_t data_offset; - data_offset = apple35_get_offset(floppy, head, track, sector, nullptr); - if (data_offset == ~0) - { - return FLOPPY_ERROR_SEEKERROR; + for(int i=0; i<size; i+=2) { + chk += get_u16be(&data[i]); + chk = rotr_32(chk, 1); } - floppy_image_read(floppy, buffer, data_offset, buflen); - return FLOPPY_ERROR_SUCCESS; } - - -static floperr_t apple35_write_sector(floppy_image_legacy *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam) +bool dc42_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, const floppy_image &image) const { - uint32_t data_offset; - - data_offset = apple35_get_offset(floppy, head, track, sector, nullptr); - if (data_offset == ~0) - return FLOPPY_ERROR_SEEKERROR; - floppy_image_write(floppy, buffer, data_offset, buflen); - return FLOPPY_ERROR_SUCCESS; -} - + int g_tracks, g_heads; + image.get_actual_geometry(g_tracks, g_heads); + if(g_heads == 0) + g_heads = 1; -static floperr_t apple35_read_sector_td(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen) -{ - floperr_t err; - uint32_t tag_offset = 0; + uint8_t h[0x54]; + memset(h, 0, 0x54); + strcpy((char *)h+1, "Unnamed"); + h[0] = 7; + int nsect = 16*(12+11+10+9+8)*g_heads; + uint32_t dsize = nsect*512; + uint32_t tsize = nsect*12; + put_u32be(&h[0x40], dsize); + put_u32be(&h[0x44], tsize); + h[0x50] = g_heads == 2 ? 0x01 : 0x00; + h[0x51] = g_heads == 2 ? 0x22 : 0x02; + h[0x52] = 0x01; + h[0x53] = 0x00; - assert(buflen == 524); + uint32_t dchk = 0; + uint32_t tchk = 0; - /* first read the sector */ - err = apple35_read_sector(floppy, head, track, sector, ((uint8_t *) buffer) + 12, 512); - if (err) - { - return err; - } + int pos_data = 0x54; + int pos_tag = 0x54+dsize; - /* read the tag data, if possible */ - memset(buffer, '\0', 12); - apple35_get_offset(floppy, head, track, sector, &tag_offset); - if (tag_offset != ~0) - { - floppy_image_read(floppy, buffer, tag_offset, 12); + for(int track=0; track < 80; track++) { + for(int head=0; head < g_heads; head++) { + auto sectors = extract_sectors_from_track_mac_gcr6(head, track, image); + for(unsigned int i=0; i < sectors.size(); i++) { + auto &sdata = sectors[i]; + sdata.resize(512+12); + write_at(io, pos_tag, &sdata[0], 12); // FIXME: check for errors + write_at(io, pos_data, &sdata[12], 512); // FIXME: check for errors + pos_tag += 12; + pos_data += 512; + if(track || head || i) + update_chk(&sdata[0], 12, tchk); + update_chk(&sdata[12], 512, dchk); + } + } } - return FLOPPY_ERROR_SUCCESS; -} - - - -static floperr_t apple35_write_sector_td(floppy_image_legacy *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam) -{ - floperr_t err; - uint32_t tag_offset = 0; + put_u32be(&h[0x48], dchk); + put_u32be(&h[0x4c], tchk); - assert(buflen == 524); - - /* first write the sector */ - err = apple35_write_sector(floppy, head, track, sector, ((const uint8_t *) buffer) + 12, 512, 0); - if (err) - return err; - - /* write the tag data, if possible */ - apple35_get_offset(floppy, head, track, sector, &tag_offset); - if (tag_offset != ~0) - floppy_image_write(floppy, buffer, tag_offset, 12); - - return FLOPPY_ERROR_SUCCESS; + write_at(io, 0, h, 0x54); // FIXME: check for errors + return true; } +const dc42_format FLOPPY_DC42_FORMAT; -static floperr_t apple35_get_sector_length(floppy_image_legacy *floppy, int head, int track, int sector, uint32_t *sector_length) +apple_gcr_format::apple_gcr_format() : floppy_image_format_t() { - *sector_length = 512; - return FLOPPY_ERROR_SUCCESS; } - - -static int apple35_get_heads_per_disk(floppy_image_legacy *floppy) +const char *apple_gcr_format::name() const noexcept { - return get_apple35_tag(floppy)->sides; + return "apple_gcr"; } - - -static int apple35_get_tracks_per_disk(floppy_image_legacy *floppy) +const char *apple_gcr_format::description() const noexcept { - return 80; + return "Apple GCR 400/800K raw sector image"; } - - -static uint32_t apple35_get_track_size(floppy_image_legacy *floppy, int head, int track) +const char *apple_gcr_format::extensions() const noexcept { - if ((track < 0) || (track >= 80)) - return 0; - return apple35_sectors_per_track(floppy, track) * 800; + return "img"; } - - -static uint8_t calculate_side(int head, int track) +bool apple_gcr_format::supports_save() const noexcept { - uint8_t side; - side = head ? 0x20 : 0x00; - if (track & 0x40) - side |= 0x01; - return side; + return true; } - - -static floperr_t apple35_read_track(floppy_image_legacy *floppy, int head, int track, uint64_t offset, void *buffer, size_t buflen) +int apple_gcr_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { - floperr_t err; - size_t pos = 0; - int sector_count, sector, i; - uint8_t sum, side; - struct apple35_tag *tag; - uint8_t sector_data[524]; - uint8_t nibble_data[699]; - uint8_t checksum[4]; - - tag = get_apple35_tag(floppy); - - if (track >= ARRAY_LENGTH(apple35_tracklen_800kb)) - return FLOPPY_ERROR_SEEKERROR; - if (offset != 0) - return FLOPPY_ERROR_UNSUPPORTED; - - memset(buffer, 0xFF, buflen); - sector_count = apple35_sectors_per_track(floppy, track); - side = calculate_side(head, track); - - for (sector = 0; sector < sector_count; sector++) - { - /* read the sector */ - err = apple35_read_sector_td(floppy, head, track, sector, sector_data, ARRAY_LENGTH(sector_data)); - if (err) - { - return err; - } - - sony_nibblize35(sector_data, nibble_data, checksum); - - for (i = 0; i < ARRAY_LENGTH(blk1); i++) - sony_filltrack((uint8_t*)buffer, buflen, &pos, blk1[i]); - - sum = (track ^ sector ^ side ^ tag->format_byte) & 0x3F; - - sony_filltrack((uint8_t*)buffer, buflen, &pos, diskbytes[track & 0x3f]); - sony_filltrack((uint8_t*)buffer, buflen, &pos, diskbytes[sector]); - sony_filltrack((uint8_t*)buffer, buflen, &pos, diskbytes[side]); - sony_filltrack((uint8_t*)buffer, buflen, &pos, diskbytes[tag->format_byte]); - sony_filltrack((uint8_t*)buffer, buflen, &pos, diskbytes[sum]); - - for (i = 0; i < ARRAY_LENGTH(blk2); i++) - sony_filltrack((uint8_t*)buffer, buflen, &pos, blk2[i]); - - sony_filltrack((uint8_t*)buffer, buflen, &pos, diskbytes[sector]); - - for (i = 0; i < ARRAY_LENGTH(nibble_data); i++) - sony_filltrack((uint8_t*)buffer, buflen, &pos, diskbytes[nibble_data[i]]); + uint64_t size; + if(io.length(size)) + return 0; - for (i = 3; i >= 0; i--) - sony_filltrack((uint8_t*)buffer, buflen, &pos, diskbytes[checksum[i]]); + if(size == 409600 || (size == 819200 && (variants.empty() || has_variant(variants, floppy_image::DSDD)))) + return FIFID_SIZE; - for (i = 0; i < ARRAY_LENGTH(blk3); i++) - sony_filltrack((uint8_t*)buffer, buflen, &pos, blk3[i]); - } - - return FLOPPY_ERROR_SUCCESS; + return 0; } - - -static floperr_t apple35_write_track(floppy_image_legacy *floppy, int head, int track, uint64_t offset, const void *buffer, size_t buflen) +bool apple_gcr_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { - floperr_t err; - size_t pos = 0; - int sector_count, sector, i, j; - struct apple35_tag *tag; - uint8_t sum, format_byte, val, side; - uint32_t found_sectors = 0; - uint8_t sector_data[524]; - uint8_t nibble_data[699]; - uint8_t checksum[4]; - - tag = get_apple35_tag(floppy); - - if (track >= ARRAY_LENGTH(apple35_tracklen_800kb)) - return FLOPPY_ERROR_SEEKERROR; - if (offset != 0) - return FLOPPY_ERROR_UNSUPPORTED; - - sector_count = apple35_sectors_per_track(floppy, track); - side = calculate_side(head, track); - - /* do 2 rotations, in case the bit slip stuff prevent us to read the first sector */ - for (j = 0; j < (buflen * 2); j++) - { - if (sony_fetchtrack((uint8_t*)buffer, buflen, &pos) != 0xD5) - continue; - j++; - - if (sony_fetchtrack((uint8_t*)buffer, buflen, &pos) != 0xAA) - continue; - j++; - - if (sony_fetchtrack((uint8_t*)buffer, buflen, &pos) != 0x96) - continue; - j++; - - if (rev_diskbytes[sony_fetchtrack((uint8_t*)buffer, buflen, &pos)] != (track & 0x3F)) - continue; - j++; - - sector = rev_diskbytes[sony_fetchtrack((uint8_t*)buffer, buflen, &pos)]; - if ((sector < 0) || (sector >= sector_count)) - continue; - j++; - - if (rev_diskbytes[sony_fetchtrack((uint8_t*)buffer, buflen, &pos)] != side) - continue; - j++; - - format_byte = rev_diskbytes[sony_fetchtrack((uint8_t*)buffer, buflen, &pos)]; - if (format_byte != tag->format_byte) - { - /* this is an error, but not THAT critical, I guess */ - } - j++; - - sum = track ^ sector ^ side ^ format_byte; - if (rev_diskbytes[sony_fetchtrack((uint8_t*)buffer, buflen, &pos)] != sum) - continue; - j++; - - if (sony_fetchtrack((uint8_t*)buffer, buflen, &pos) != 0xDE) - continue; - j++; - - if (sony_fetchtrack((uint8_t*)buffer, buflen, &pos) != 0xAA) - continue; - j++; - - while((val = sony_fetchtrack((uint8_t*)buffer, buflen, &pos)) == 0xFF) - j++; - if (val != 0xD5) - continue; /* lost bit slip mark! */ - j++; - - if (sony_fetchtrack((uint8_t*)buffer, buflen, &pos) != 0xAA) - continue; - j++; - - if (sony_fetchtrack((uint8_t*)buffer, buflen, &pos) != 0xAD) - continue; - j++; - - /* should this be regarded as a critical error ??? */ - if (rev_diskbytes[sony_fetchtrack((uint8_t*)buffer, buflen, &pos)] != sector) - continue; - j++; - - for (i = 0; i < ARRAY_LENGTH(nibble_data); i++) - { - nibble_data[i] = rev_diskbytes[sony_fetchtrack((uint8_t*)buffer, buflen, &pos)]; - j++; - } + desc_gcr_sector sectors[12]; + uint8_t sdata[512*12]; - for (i = 3; i >= 0; i--) - { - /* should be checking checksum */ - sony_fetchtrack((uint8_t*)buffer, buflen, &pos); - } + int pos_data = 0; + + uint8_t header[64]; + read_at(io, 0, header, 64); // FIXME: check for errors and premature EOF - sony_fetchtrack((uint8_t*)buffer, buflen, &pos); /* should get 0xDE */ - sony_fetchtrack((uint8_t*)buffer, buflen, &pos); /* should get 0xAA */ - sony_fetchtrack((uint8_t*)buffer, buflen, &pos); /* should get 0xFF */ + uint64_t size; + if(io.length(size)) + return false; + int head_count = size == 409600 ? 1 : size == 819200 ? 2 : 0; - /* did we already write this sector? */ - if ((found_sectors & (1 << sector)) == 0) - { - sony_denibblize35(sector_data, nibble_data, checksum); + image.set_form_variant(floppy_image::FF_35, head_count == 2 ? floppy_image::DSDD : floppy_image::SSDD); - /* write the sector */ - err = apple35_write_sector_td(floppy, head, track, sector, sector_data, ARRAY_LENGTH(sector_data), 0); - if (err) - return err; + if(!head_count) + return false; + for(int track=0; track < 80; track++) { + for(int head=0; head < head_count; head++) { + int ns = 12 - (track/16); + read_at(io, pos_data, sdata, 512*ns); // FIXME: check for errors and premature EOF + pos_data += 512*ns; - found_sectors |= 1 << sector; + int si = 0; + for(int i=0; i<ns; i++) { + sectors[si].track = track; + sectors[si].head = head; + sectors[si].sector = i; + sectors[si].info = head_count == 2 ? 0x22 : 0x02; + sectors[si].tag = nullptr; + sectors[si].data = sdata + 512*i; + si = (si + 2) % ns; + if(si == 0) + si++; + } + build_mac_track_gcr(track, head, image, sectors); } } - return FLOPPY_ERROR_SUCCESS; + return true; } +bool apple_gcr_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, const floppy_image &image) const +{ + int g_tracks, g_heads; + image.get_actual_geometry(g_tracks, g_heads); + if(g_heads == 0) + g_heads = 1; -static floperr_t apple35_construct(floppy_image_legacy *floppy, uint32_t data_offset, uint32_t data_size, - uint32_t tag_offset, uint32_t tag_size, int16_t format_byte, uint8_t sides, bool is_1440k) -{ - struct apple35_tag *tag; - struct FloppyCallbacks *format; + int pos_data = 0; - /* figure out format byte if not specified */ - if (format_byte < 0) - { - switch(sides) - { - case 1: - format_byte = 0x02; - break; - case 2: - format_byte = 0x22; - break; - default: - return FLOPPY_ERROR_INVALIDIMAGE; + for(int track=0; track < 80; track++) { + for(int head=0; head < g_heads; head++) { + auto sectors = extract_sectors_from_track_mac_gcr6(head, track, image); + for(unsigned int i=0; i < sectors.size(); i++) { + auto &sdata = sectors[i]; + sdata.resize(512+12); + /*auto const [err, actual] =*/ write_at(io, pos_data, &sdata[12], 512); // FIXME: check for errors + pos_data += 512; + } } } - /* create tag */ - tag = (struct apple35_tag *) floppy_create_tag(floppy, sizeof(struct apple35_tag)); - if (!tag) - return FLOPPY_ERROR_OUTOFMEMORY; - tag->data_offset = data_offset; - tag->data_size = data_size; - tag->tag_offset = tag_offset; - tag->tag_size = tag_size; - tag->format_byte = (uint8_t) format_byte; - tag->sides = sides; - tag->is_1440k = is_1440k ? 1 : 0; - - /* set up format callbacks */ - format = floppy_callbacks(floppy); - format->read_sector = apple35_read_sector; - format->write_sector = apple35_write_sector; - format->read_track = apple35_read_track; - format->write_track = apple35_write_track; - format->get_sector_length = apple35_get_sector_length; - format->get_heads_per_disk = apple35_get_heads_per_disk; - format->get_tracks_per_disk = apple35_get_tracks_per_disk; - format->get_track_size = apple35_get_track_size; - return FLOPPY_ERROR_SUCCESS; + return true; } +const apple_gcr_format FLOPPY_APPLE_GCR_FORMAT; - -/* ----------------------------------------------------------------------- */ - -static FLOPPY_IDENTIFY(apple35_raw_identify) +// .2MG format +apple_2mg_format::apple_2mg_format() : floppy_image_format_t() { - uint64_t size; - size = floppy_image_size(floppy); - *vote = ((size == 80*1*10*512) || (size == 80*2*10*512) || (size == (80*2*18*512)+84) - || (size == 80*2*18*512)) ? 100 : 0; - return FLOPPY_ERROR_SUCCESS; } - - - -static FLOPPY_CONSTRUCT(apple35_raw_construct) +const char *apple_2mg_format::name() const noexcept { - uint64_t size; - uint8_t sides; - bool is_1440k; - - if (params) - { - /* create */ - sides = params->lookup_int(PARAM_HEADS); - size = 80*sides*10*512; - is_1440k = false; - } - else - { - /* load */ - size = floppy_image_size(floppy); - if (size == 80*1*10*512) - { - sides = 1; - is_1440k = false; - } - else if ((size == 80*2*10*512) || (size == 80*2*18*512) || (size == (80*2*18*512)+84)) - { - sides = 2; - is_1440k = (size == 80*2*18*512) || (size == (80*2*18*512)+84); - } - else - return FLOPPY_ERROR_INVALIDIMAGE; - } - - return apple35_construct(floppy, 0, (uint32_t) size, 0, 0, -1, sides, is_1440k); + return "apple_2mg"; } - - -/* ----------------------------------------------------------------------- */ - -struct header_diskcopy -{ - uint8_t disk_name[64]; /* name of the disk */ - uint32_t data_size; /* total size of data for all sectors (512*number_of_sectors) */ - uint32_t tag_size; /* total size of tag data for all sectors (12*number_of_sectors for GCR 3.5" floppies, 20*number_of_sectors for HD20, 0 otherwise) */ - uint32_t data_checksum; /* CRC32 checksum of all sector data */ - uint32_t tag_checksum; /* CRC32 checksum of all tag data */ - uint8_t disk_format; /* 0 = 400K, 1 = 800K, 2 = 720K, 3 = 1440K (other values reserved) */ - uint8_t format_byte; /* should be $00 Apple II, $01 Lisa, $02 Mac MFS ??? */ - /* $12 = 400K, $22 = >400K Macintosh (DiskCopy uses this value for - all Apple II disks not 800K in size, and even for some of those), - $24 = 800K Apple II disk */ - uint16_t magic; /* always $0100 (otherwise, the file may be in a different format. */ -}; - - - -static floperr_t apple35_diskcopy_headerdecode(floppy_image_legacy *floppy, uint32_t *data_offset, - uint32_t *data_size, uint32_t *tag_offset, uint32_t *tag_size, uint8_t *format_byte, uint8_t *sides) +const char *apple_2mg_format::description() const noexcept { - uint64_t size; - struct header_diskcopy header; - - if (data_offset) - *data_offset = 0; - if (data_size) - *data_size = 0; - if (tag_offset) - *tag_offset = 0; - if (tag_size) - *tag_size = 0; - if (format_byte) - *format_byte = 0; - if (sides) - *sides = 0; - - size = floppy_image_size(floppy); - if (size < sizeof(struct header_diskcopy)) - return FLOPPY_ERROR_INVALIDIMAGE; - - floppy_image_read(floppy, &header, 0, sizeof(header)); - - header.data_size = big_endianize_int32(header.data_size); - header.tag_size = big_endianize_int32(header.tag_size); - header.data_checksum = big_endianize_int32(header.data_checksum); - header.tag_checksum = big_endianize_int32(header.tag_checksum); - header.magic = big_endianize_int16(header.magic); - - if (header.disk_name[0] >= sizeof(header.disk_name)) - return FLOPPY_ERROR_INVALIDIMAGE; - if (header.magic != 0x0100) - return FLOPPY_ERROR_INVALIDIMAGE; - if (size != (header.data_size + header.tag_size + sizeof(header))) - return FLOPPY_ERROR_INVALIDIMAGE; - - if (header.data_size == 80*1*10*512) - { - if (sides) - *sides = 1; - } - else if (header.data_size == 80*2*10*512) - { - if (sides) - *sides = 2; - } - else - return FLOPPY_ERROR_INVALIDIMAGE; - - if (data_offset) - *data_offset = sizeof(header); - if (data_size) - *data_size = header.data_size; - if (tag_offset) - *tag_offset = sizeof(header) + header.data_size; - if (tag_size) - *tag_size = header.tag_size; - if (format_byte) - *format_byte = header.format_byte; - return FLOPPY_ERROR_SUCCESS; + return "Apple II .2MG image"; } - - -static FLOPPY_IDENTIFY(apple35_diskcopy_identify) +const char *apple_2mg_format::extensions() const noexcept { - *vote = apple35_diskcopy_headerdecode(floppy, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr) ? 0 : 100; - return FLOPPY_ERROR_SUCCESS; + return "2mg"; } - - - -static FLOPPY_CONSTRUCT(apple35_diskcopy_construct) +bool apple_2mg_format::supports_save() const noexcept { - floperr_t err; - uint8_t format_byte, sides; - uint32_t data_offset, data_size; - uint32_t tag_offset, tag_size; - int16_t format_byte_param = -1; - struct header_diskcopy header; - - if (params) - { - /* create */ - sides = params->lookup_int(PARAM_HEADS); - - data_size = 80*sides*10*512; - tag_size = 80*sides*10*12; - - memset(&header, 0, sizeof(header)); - header.data_size = big_endianize_int32(data_size); - header.tag_size = big_endianize_int32(tag_size); - header.disk_format = (sides > 1) ? 1 : 0; - header.magic = big_endianize_int16(0x100); - - floppy_image_write(floppy, &header, 0, sizeof(header)); - floppy_image_write_filler(floppy, 0, sizeof(header), data_size + tag_size); - } - - /* load */ - err = apple35_diskcopy_headerdecode(floppy, &data_offset, &data_size, - &tag_offset, &tag_size, &format_byte, &sides); - if (err) - return err; - - format_byte_param = format_byte; - - return apple35_construct(floppy, data_offset, data_size, - tag_offset, tag_size, format_byte_param, sides, false); + return true; } - - -/* ----------------------------------------------------------------------- */ - -struct header_2img +int apple_2mg_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { - char magic[4]; /* '2IMG' */ - char creator[4]; /* signature; 'MESS' for MESS */ - uint16_t header_length; - uint16_t version; - uint32_t image_format; - uint32_t flags; - uint32_t block_count; - uint32_t data_offset; - uint32_t data_length; - uint32_t comment_offset; - uint32_t comment_length; - uint32_t creator_offset; - uint32_t creator_length; - uint32_t padding[4]; -}; - -#define IMAGE_FORMAT_DO 0 -#define IMAGE_FORMAT_PO 1 -#define IMAGE_FORMAT_NIB 2 -#define IMAGE_FLAGS_LOCKED 0x80000000 - - - -static floperr_t apple35_2img_decode(floppy_image_legacy *floppy, uint32_t *image_format, - uint32_t *data_offset, uint32_t *data_length) -{ - struct header_2img header; - uint64_t size; - - if (image_format) - *image_format = 0; - if (data_offset) - *data_offset = 0; - if (data_length) - *data_length = 0; - - size = floppy_image_size(floppy); - if (size < sizeof(header)) + uint8_t signature[4]; + auto const [err, actual] = read_at(io, 0, signature, 4); + if (err || (4 != actual)) { - return FLOPPY_ERROR_INVALIDIMAGE; + return 0; } - floppy_image_read(floppy, &header, 0, sizeof(header)); - - if (memcmp(header.magic, "2IMG", 4)) + if (!memcmp(signature, "2IMG", 4)) { - return FLOPPY_ERROR_INVALIDIMAGE; + return FIFID_SIGN; } - header.header_length = little_endianize_int16(header.header_length); - header.version = little_endianize_int16(header.version); - header.image_format = little_endianize_int32(header.image_format); - header.flags = little_endianize_int32(header.flags); - header.block_count = little_endianize_int32(header.block_count); - header.data_offset = little_endianize_int32(header.data_offset); - header.data_length = little_endianize_int32(header.data_length); - header.comment_offset = little_endianize_int32(header.comment_offset); - header.comment_length = little_endianize_int32(header.comment_length); - header.creator_offset = little_endianize_int32(header.creator_offset); - header.creator_length = little_endianize_int32(header.creator_length); - - // at least some images "in the wild" (e.g. TOSEC Minor Set 1) have big-endian data sizes - // even though that's against the .2mg spec - if (header.data_length == 0x800c00) + // Bernie ][ The Rescue wrote 2MGs with the signature byte-flipped, other fields are valid + if (!memcmp(signature, "GMI2", 4)) { - LOG_FORMATS("ap_dsk35: corrected bad-endian data length\n"); - header.data_length = 0x0c8000; + return FIFID_SIGN; } - if ((((uint64_t) header.data_offset) + header.data_length) > size) - return FLOPPY_ERROR_INVALIDIMAGE; - if ((((uint64_t) header.comment_offset) + header.comment_length) > size) - return FLOPPY_ERROR_INVALIDIMAGE; - if ((((uint64_t) header.creator_offset) + header.creator_length) > size) - return FLOPPY_ERROR_INVALIDIMAGE; - if ((header.image_format != IMAGE_FORMAT_DO) && - (header.image_format != IMAGE_FORMAT_PO) && - (header.image_format != IMAGE_FORMAT_NIB)) - return FLOPPY_ERROR_INVALIDIMAGE; - - if (image_format) - *image_format = header.image_format; - if (data_offset) - *data_offset = header.data_offset; - if (data_length) - *data_length = header.data_length; - return FLOPPY_ERROR_SUCCESS; -} - - - -static FLOPPY_IDENTIFY(apple35_2img_identify) -{ - *vote = apple35_2img_decode(floppy, nullptr, nullptr, nullptr) ? 0 : 100; - return FLOPPY_ERROR_SUCCESS; + return 0; } - - -static FLOPPY_CONSTRUCT(apple35_2img_construct) +bool apple_2mg_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { - floperr_t err; - uint32_t image_format; - uint32_t data_offset; - uint32_t data_size; - uint8_t sides = 2; - struct header_2img header; - - if (params) - { - /* create */ - sides = params->lookup_int(PARAM_HEADS); - - data_offset = sizeof(header); - data_size = 80*sides*10*512; - - memset(&header, 0, sizeof(header)); - header.header_length = little_endianize_int16(sizeof(header)); - header.block_count = little_endianize_int32(80*sides*10); - header.data_offset = little_endianize_int32(data_offset); - header.data_length = little_endianize_int32(data_size); - - floppy_image_write(floppy, &header, 0, sizeof(header)); - floppy_image_write_filler(floppy, 0, sizeof(header), data_size); - } - else - { - /* load */ - err = apple35_2img_decode(floppy, &image_format, &data_offset, &data_size); - if (err) - return err; - - if (data_size == 80*1*10*512) - sides = 1; /* single sided */ - else if (data_size == 80*2*10*512) - sides = 2; /* double sided */ - else - sides = 2; /* unknown... what to do... */ - } - - return apple35_construct(floppy, data_offset, data_size, - 0, 0, -1, sides, false); -} - - - -LEGACY_FLOPPY_OPTIONS_START( apple35_mac ) - LEGACY_FLOPPY_OPTION( apple35_raw, "dsk,img,image", "Apple raw 3.5\" disk image", apple35_raw_identify, apple35_raw_construct, nullptr, - HEADS([1]-2) - TRACKS([80]) - SECTOR_LENGTH([512]) - FIRST_SECTOR_ID([0])) - LEGACY_FLOPPY_OPTION( apple35_dc, "dc,dc42,dsk,img,image", "Apple DiskCopy disk image", apple35_diskcopy_identify, apple35_diskcopy_construct, nullptr, - HEADS([1]-2) - TRACKS([80]) - SECTOR_LENGTH([512]) - FIRST_SECTOR_ID([0])) -LEGACY_FLOPPY_OPTIONS_END - -LEGACY_FLOPPY_OPTIONS_START( apple35_iigs ) - LEGACY_FLOPPY_OPTION( apple35_raw, "dsk,img,image,po", "Apple raw 3.5\" disk image", apple35_raw_identify, apple35_raw_construct, nullptr, - HEADS([1]-2) - TRACKS([80]) - SECTOR_LENGTH([512]) - FIRST_SECTOR_ID([0])) - LEGACY_FLOPPY_OPTION( apple35_dc, "dc,dsk,img,image", "Apple DiskCopy disk image", apple35_diskcopy_identify, apple35_diskcopy_construct, nullptr, - HEADS([1]-2) - TRACKS([80]) - SECTOR_LENGTH([512]) - FIRST_SECTOR_ID([0])) - LEGACY_FLOPPY_OPTION( apple35_2img, "2img,2mg", "Apple ][gs 2IMG disk image", apple35_2img_identify, apple35_2img_construct, nullptr, - HEADS([1]-2) - TRACKS([80]) - SECTOR_LENGTH([512]) - FIRST_SECTOR_ID([0])) -LEGACY_FLOPPY_OPTIONS_END + desc_gcr_sector sectors[12]; + uint8_t sdata[512*12], header[64]; + read_at(io, 0, header, 64); // FIXME: check for errors and premature EOF + uint32_t blocks = get_u32le(&header[0x14]); + uint32_t pos_data = get_u32le(&header[0x18]); - -// license:BSD-3-Clause -// copyright-holders:Olivier Galibert -dc42_format::dc42_format() : floppy_image_format_t() -{ -} - -const char *dc42_format::name() const -{ - return "dc42"; -} - -const char *dc42_format::description() const -{ - return "DiskCopy 4.2 image"; -} - -const char *dc42_format::extensions() const -{ - return "dc42"; -} - -bool dc42_format::supports_save() const -{ - return true; -} - -int dc42_format::identify(io_generic *io, uint32_t form_factor) -{ - uint8_t h[0x54]; - uint64_t size = io_generic_size(io); - if(size < 0x54) - return 0; - - io_generic_read(io, h, 0, 0x54); - uint32_t dsize = (h[0x40] << 24) | (h[0x41] << 16) | (h[0x42] << 8) | h[0x43]; - uint32_t tsize = (h[0x44] << 24) | (h[0x45] << 16) | (h[0x46] << 8) | h[0x47]; - - return size == 0x54+tsize+dsize && h[0] < 64 && h[0x52] == 1 && h[0x53] == 0 ? 100 : 0; -} - -const floppy_image_format_t::desc_e dc42_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 dc42_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) -{ - uint8_t h[0x54]; - io_generic_read(io, h, 0, 0x54); - int dsize = (h[0x40] << 24) | (h[0x41] << 16) | (h[0x42] << 8) | h[0x43]; - int tsize = (h[0x44] << 24) | (h[0x45] << 16) | (h[0x46] << 8) | h[0x47]; - - uint8_t encoding = h[0x50]; - uint8_t format = h[0x51]; - - if((encoding != 0x00 || format != 0x02) && (encoding != 0x01 || format != 0x22)) { - osd_printf_error("dc42: Unsupported encoding/format combination %02x/%02x\n", encoding, format); + if(blocks != 1600 && blocks != 16390) return false; - } - - uint8_t sector_data[(512+12)*12]; - memset(sector_data, 0, sizeof(sector_data)); - - desc_s sectors[12]; - int pos_data = 0x54; - int pos_tag = 0x54+dsize; - - int head_count = encoding == 1 ? 2 : 1; + image.set_form_variant(floppy_image::FF_35, (blocks > 800) ? floppy_image::DSDD : floppy_image::SSDD); for(int track=0; track < 80; track++) { - for(int head=0; head < head_count; head++) { + for(int head=0; head < 2; head++) { int ns = 12 - (track/16); + read_at(io, pos_data, sdata, 512*ns); // FIXME: check for errors and premature EOF + pos_data += 512*ns; + int si = 0; for(int i=0; i<ns; i++) { - uint8_t *data = sector_data + (512+12)*i; - sectors[si].data = data; - sectors[si].size = 512+12; - sectors[si].sector_id = i; - sectors[si].sector_info = format; - if(tsize) { - io_generic_read(io, data, pos_tag, 12); - pos_tag += 12; - } - io_generic_read(io, data+12, pos_data, 512); - pos_data += 512; + sectors[si].track = track; + sectors[si].head = head; + sectors[si].sector = i; + sectors[si].info = 0x22; + sectors[si].tag = nullptr; + sectors[si].data = sdata + 512*i; si = (si + 2) % ns; if(si == 0) si++; } - generate_track(mac_gcr, track, head, sectors, ns, 6208*ns, image); + build_mac_track_gcr(track, head, image, sectors); } } return true; } -uint8_t dc42_format::gb(const uint8_t *buf, int ts, 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); - pos++; - if(pos == ts) { - pos = 0; - wrap++; - } - } - return v; -} - -void dc42_format::update_chk(const uint8_t *data, int size, uint32_t &chk) -{ - for(int i=0; i<size; i+=2) { - chk += (data[i] << 8) | data[i+1]; - chk = (chk >> 1) | (chk << 31); - } -} - -bool dc42_format::save(io_generic *io, floppy_image *image) -{ - int g_tracks, g_heads; - image->get_actual_geometry(g_tracks, g_heads); - - if(g_heads == 0) - g_heads = 1; - - uint8_t h[0x54]; - memset(h, 0, 0x54); - strcpy((char *)h+1, "Unnamed"); - h[0] = 7; - int nsect = 16*(12+11+10+9+8)*g_heads; - uint32_t dsize = nsect*512; - uint32_t tsize = nsect*12; - h[0x40] = dsize >> 24; - h[0x41] = dsize >> 16; - h[0x42] = dsize >> 8; - h[0x43] = dsize; - h[0x44] = tsize >> 24; - h[0x45] = tsize >> 16; - h[0x46] = tsize >> 8; - h[0x47] = tsize; - h[0x50] = g_heads == 2 ? 0x01 : 0x00; - h[0x51] = g_heads == 2 ? 0x22 : 0x02; - h[0x52] = 0x01; - h[0x53] = 0x00; - - uint32_t dchk = 0; - uint32_t tchk = 0; - - int pos_data = 0x54; - int pos_tag = 0x54+dsize; +bool apple_2mg_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, const floppy_image &image) const +{ + uint8_t header[0x40]; + int pos_data = 0x40; + + memset(header, 0, sizeof(header)); + // file ID + header[0] = '2'; header[1] = 'I'; header[2] = 'M'; header[3] = 'G'; + // creator program + header[4] = 'M'; header[5] = 'A'; header[6] = 'M'; header[7] = 'E'; + // header size + header[8] = 0x40; + // version + header[0xa] = 1; + // flags + header[0xc] = 1; // ProDOS sector order + // number of ProDOS blocks + header[0x14] = 0x40; header[0x15] = 0x06; // 0x640 (1600) + // offset to sector data + header[0x18] = 0x40; + // bytes of disk data + header[0x1c] = 0x00; header[0x1d] = 0x80; header[0x1e] = 0x0c; // 0xC8000 (819200) + write_at(io, 0, header, 0x40); // FIXME: check for errors for(int track=0; track < 80; track++) { - for(int head=0; head < g_heads; head++) { - uint8_t sectdata[(512+12)*12]; - memset(sectdata, 0, sizeof(sectdata)); - int nsect = 12-(track/16); - uint8_t buf[13000]; - int ts; - generate_bitstream_from_track(track, head, 200000000/(6208*nsect), buf, ts, image); - int pos = 0; - int wrap = 0; - int hb = 0; - for(;;) { - uint8_t 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 == 0x96) - hb = 4; - else - hb = 0; - - if(hb == 4) { - uint8_t h[7]; - for(auto & elem : h) - elem = gb(buf, ts, pos, wrap); - uint8_t v2 = gcr6bw_tb[h[2]]; - uint8_t v3 = gcr6bw_tb[h[3]]; - uint8_t tr = gcr6bw_tb[h[0]] | (v2 & 1 ? 0x40 : 0x00); - uint8_t se = gcr6bw_tb[h[1]]; - uint8_t si = v2 & 0x20 ? 1 : 0; - // uint8_t ds = v3 & 0x20 ? 1 : 0; - // uint8_t fmt = v3 & 0x1f; - uint8_t c1 = (tr^se^v2^v3) & 0x3f; - uint8_t chk = gcr6bw_tb[h[4]]; - if(chk == c1 && tr == track && si == head && se < nsect) { - 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) { - uint8_t *dest = sectdata+(512+12)*se; - gb(buf, ts, pos, wrap); // Ignore the sector byte - uint8_t ca = 0, cb = 0, cc = 0; - for(int i=0; i<522/3+1; i++) { - uint8_t e0 = gb(buf, ts, pos, wrap); - uint8_t e1 = gb(buf, ts, pos, wrap); - uint8_t e2 = gb(buf, ts, pos, wrap); - uint8_t e3 = i == 522/3 ? 0x96 : gb(buf, ts, pos, wrap); - uint8_t va, vb, vc; - gcr6_decode(e0, e1, e2, e3, va, vb, vc); - cc = (cc << 1) | (cc >> 7); - va = va ^ cc; - int suma = ca + va + (cc & 1); - ca = suma; - vb = vb ^ ca; - int sumb = cb + vb + (suma >> 8); - cb = sumb; - vc = vc ^ cb; - cc = cc + vc + (sumb >> 8); - *dest++ = va; - *dest++ = vb; - if(i != 522/3) - *dest++ = vc; - } - } else { - pos = opos; - wrap = owrap; - } - } - hb = 0; - } - if(wrap) - break; - } - for(int i=0; i<nsect; i++) { - uint8_t *data = sectdata + (512+12)*i; - io_generic_write(io, data, pos_tag, 12); - io_generic_write(io, data+12, pos_data, 512); - pos_tag += 12; + for(int head=0; head < 2; head++) { + auto sectors = extract_sectors_from_track_mac_gcr6(head, track, image); + for(unsigned int i=0; i < sectors.size(); i++) { + auto &sdata = sectors[i]; + sdata.resize(512+12); + write_at(io, pos_data, &sdata[12], 512); // FIXME: check for errors pos_data += 512; - if(track || head || i) - update_chk(data, 12, tchk); - update_chk(data+12, 512, dchk); } } } - h[0x48] = dchk >> 24; - h[0x49] = dchk >> 16; - h[0x4a] = dchk >> 8; - h[0x4b] = dchk; - h[0x4c] = tchk >> 24; - h[0x4d] = tchk >> 16; - h[0x4e] = tchk >> 8; - h[0x4f] = tchk; - - io_generic_write(io, h, 0, 0x54); return true; } -const floppy_format_type FLOPPY_DC42_FORMAT = &floppy_image_format_creator<dc42_format>; +const apple_2mg_format FLOPPY_APPLE_2MG_FORMAT; |