diff options
Diffstat (limited to 'src/lib/formats/mfi_dsk.cpp')
-rw-r--r-- | src/lib/formats/mfi_dsk.cpp | 222 |
1 files changed, 135 insertions, 87 deletions
diff --git a/src/lib/formats/mfi_dsk.cpp b/src/lib/formats/mfi_dsk.cpp index b6a8a18460a..eb1e632ec03 100644 --- a/src/lib/formats/mfi_dsk.cpp +++ b/src/lib/formats/mfi_dsk.cpp @@ -1,10 +1,16 @@ // license:BSD-3-Clause // copyright-holders:Olivier Galibert -#include <assert.h> - #include "mfi_dsk.h" + +#include "ioprocs.h" + #include <zlib.h> +#include <cstring> +#include <functional> +#include <tuple> + + /* Mess floppy image structure: @@ -27,37 +33,37 @@ simple "compress" function. Track data consists of a series of 32-bits lsb-first values - representing magnetic cells. Bits 0-27 indicate the sizes, and bits - 28-31 the types. Type can be: - - 0, MG_A -> Magnetic orientation A - - 1, MG_B -> Magnetic orientation B - - 2, MG_N -> Non-magnetized zone (neutral) - - 3, MG_D -> Damaged zone, reads as neutral but cannot be changed by writing - - Remember that the fdcs detect transitions, not absolute levels, so - the actual physical significance of the orientation A and B is - arbitrary. - - Tracks data is aligned so that the index pulse is at the start, - whether the disk is hard-sectored or not. - - The size is the angular size in units of 1/200,000,000th of a turn. - Such a size, not coincidentally at all, is also the flyover time in - nanoseconds for a perfectly stable 300rpm drive. That makes the - standard cell size of a MFM 3.5" DD floppy at 2000 exactly for - instance (2us). Smallest expected cell size is 500 (ED density - drives). - - The sum of all sizes must of course be 200,000,000. - - An unformatted track is equivalent to one big MG_N cell covering a - whole turn, but is encoded as zero-size. + representing magnetic cells. Bits 0-27 indicate the position, + delta-packed (e.g. difference with the previous position, starts at + 0), and bits 28-31 the types. Type can be: + + - 0, MG_F -> Flux orientation change + - 1, MG_N -> Non-magnetized zone (neutral) + - 2, MG_D -> Damaged zone, reads as neutral but cannot be changed by writing + - 3, MG_E -> End of zone + + Tracks data is aligned so that the index pulse is at the start for soft- + sectored disks. For hard-sectored disks, the sector hole for the first + sector is at the start and the index hole is half a sector from the end + of the track. + + The position is the angular position in units of 1/200,000,000th of + a turn. A size in such units, not coincidentally at all, is also + the flyover time in nanoseconds for a perfectly stable 300rpm drive. + That makes the standard cell size of a MFM 3.5" DD floppy at 2000 + exactly for instance (2us). Smallest expected cell size is 500 (ED + density drives). + + An unformatted track is equivalent to a pair (MG_N, 0), (MG_E, + 199999999) but is encoded as zero-size. The "track splice" information indicates where to start writing if you try to rewrite a physical disk with the data. Some preservation formats encode that information, it is guessed for others. The write track function of fdcs should set it. The - representation is the angular position relative to the index. + representation is the angular position relative to the index, for + soft-sectored disks, and the first sector hole for hard-sectored + disks. The media type is divided in two parts. The first half indicate the physical form factor, i.e. all medias with that @@ -68,107 +74,156 @@ TODO: big-endian support */ -const char mfi_format::sign[16] = "MESSFLOPPYIMAGE"; // Includes the final \0 +const char mfi_format::sign_old[16] = "MESSFLOPPYIMAGE"; // Includes the final \0 +const char mfi_format::sign[16] = "MAMEFLOPPYIMAGE"; // Includes the final \0 mfi_format::mfi_format() : floppy_image_format_t() { } -const char *mfi_format::name() const +const char *mfi_format::name() const noexcept { return "mfi"; } -const char *mfi_format::description() const +const char *mfi_format::description() const noexcept { - return "MESS floppy image"; + return "MAME floppy image"; } -const char *mfi_format::extensions() const +const char *mfi_format::extensions() const noexcept { return "mfi"; } -bool mfi_format::supports_save() const +bool mfi_format::supports_save() const noexcept { return true; } -int mfi_format::identify(io_generic *io, uint32_t form_factor) +int mfi_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { header h; + auto const [err, actual] = read_at(io, 0, &h, sizeof(header)); + if (err || (sizeof(header) != actual)) + return 0; - io_generic_read(io, &h, 0, sizeof(header)); - if(memcmp( h.sign, sign, 16 ) == 0 && + if((!memcmp(h.sign, sign, 16) || !memcmp(h.sign, sign_old, 16)) && (h.cyl_count & CYLINDER_MASK) <= 84 && (h.cyl_count >> RESOLUTION_SHIFT) < 3 && h.head_count <= 2 && (!form_factor || !h.form_factor || h.form_factor == form_factor)) - return 100; + return FIFID_SIGN|FIFID_STRUCT; + return 0; } -bool mfi_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) +bool mfi_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { + std::error_condition err; + size_t actual; + header h; - entry entries[84*2*4]; - io_generic_read(io, &h, 0, sizeof(header)); - int resolution = h.cyl_count >> RESOLUTION_SHIFT; + std::tie(err, actual) = read_at(io, 0, &h, sizeof(header)); + if(err || (sizeof(header) != actual)) + return false; + int const resolution = h.cyl_count >> RESOLUTION_SHIFT; h.cyl_count &= CYLINDER_MASK; - io_generic_read(io, &entries, sizeof(header), (h.cyl_count << resolution)*h.head_count*sizeof(entry)); - image->set_variant(h.variant); + image.set_form_variant(h.form_factor, h.variant); + + if(!h.cyl_count) + return true; + + entry entries[84*2*4]; + std::tie(err, actual) = read_at(io, sizeof(header), &entries, (h.cyl_count << resolution)*h.head_count*sizeof(entry)); + if(err || (((h.cyl_count << resolution)*h.head_count*sizeof(entry)) != actual)) + return false; + + std::function<void (const std::vector<uint32_t> &src, std::vector<uint32_t> &track)> converter; + + if(!memcmp(h.sign, sign, 16)) { + converter = [] (const std::vector<uint32_t> &src, std::vector<uint32_t> &track) { + uint32_t ctime = 0; + for(uint32_t mg : src) { + ctime += mg & TIME_MASK; + track.push_back((mg & MG_MASK) | ctime); + } + }; + + } else { + converter = [] (const std::vector<uint32_t> &src, std::vector<uint32_t> &track) { + unsigned int cell_count = src.size(); + uint32_t mg = src[0] & MG_MASK; + uint32_t wmg = src[cell_count - 1] & MG_MASK; + if(mg != wmg && (mg == OLD_MG_A || mg == OLD_MG_B) && (wmg == OLD_MG_A || wmg == OLD_MG_B)) + // Flux change at 0, add it + track.push_back(MG_F | 0); + + uint32_t ctime = 0; + for(unsigned int i=0; i != cell_count; i++) { + uint32_t nmg = src[i] & MG_MASK; + if(nmg == OLD_MG_N || nmg == OLD_MG_D) { + track.push_back((nmg == OLD_MG_N ? MG_N : MG_D) | ctime); + ctime += src[i] & TIME_MASK; + track.push_back(MG_E | (ctime-1)); + nmg = 0xffffffff; + } else { + if(mg != 0xffffffff && mg != nmg) + track.push_back(MG_F | ctime); + ctime += src[i] & TIME_MASK; + } + mg = nmg; + } + }; + } std::vector<uint8_t> compressed; + std::vector<uint32_t> uncompressed; entry *ent = entries; for(unsigned int cyl=0; cyl <= (h.cyl_count - 1) << 2; cyl += 4 >> resolution) for(unsigned int head=0; head != h.head_count; head++) { - image->set_write_splice_position(cyl >> 2, head, ent->write_splice, cyl & 3); + image.set_write_splice_position(cyl >> 2, head, ent->write_splice, cyl & 3); if(ent->uncompressed_size == 0) { // Unformatted track - image->get_buffer(cyl >> 2, head, cyl & 3).clear(); + image.get_buffer(cyl >> 2, head, cyl & 3).clear(); ent++; continue; } + unsigned int cell_count = ent->uncompressed_size/4; compressed.resize(ent->compressed_size); + uncompressed.resize(cell_count); - io_generic_read(io, &compressed[0], ent->offset, ent->compressed_size); - - unsigned int cell_count = ent->uncompressed_size/4; - std::vector<uint32_t> &trackbuf = image->get_buffer(cyl >> 2, head, cyl & 3);; - trackbuf.resize(cell_count); + std::tie(err, actual) = read_at(io, ent->offset, &compressed[0], ent->compressed_size); // FIXME: check for errors and premature EOF uLongf size = ent->uncompressed_size; - if(uncompress((Bytef *)&trackbuf[0], &size, &compressed[0], ent->compressed_size) != Z_OK) + if(uncompress((Bytef *)uncompressed.data(), &size, &compressed[0], ent->compressed_size) != Z_OK) { + fprintf(stderr, "fail1\n"); return false; - - uint32_t cur_time = 0; - for(unsigned int i=0; i != cell_count; i++) { - uint32_t next_cur_time = cur_time + (trackbuf[i] & TIME_MASK); - trackbuf[i] = (trackbuf[i] & MG_MASK) | cur_time; - cur_time = next_cur_time; } - if(cur_time != 200000000) - return false; + std::vector<uint32_t> &trackbuf = image.get_buffer(cyl >> 2, head, cyl & 3); + trackbuf.clear(); + + converter(uncompressed, trackbuf); ent++; } return true; } -bool mfi_format::save(io_generic *io, floppy_image *image) +bool mfi_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, const floppy_image &image) const { int tracks, heads; - image->get_actual_geometry(tracks, heads); - int resolution = image->get_resolution(); + image.get_actual_geometry(tracks, heads); + int resolution = image.get_resolution(); int max_track_size = 0; for(int track=0; track <= (tracks-1) << 2; track += 4 >> resolution) for(int head=0; head<heads; head++) { - int tsize = image->get_buffer(track >> 2, head, track & 3).size(); + int tsize = image.get_buffer(track >> 2, head, track & 3).size(); if(tsize > max_track_size) max_track_size = tsize; } @@ -178,56 +233,49 @@ bool mfi_format::save(io_generic *io, floppy_image *image) memcpy(h.sign, sign, 16); h.cyl_count = tracks | (resolution << RESOLUTION_SHIFT); h.head_count = heads; - h.form_factor = image->get_form_factor(); - h.variant = image->get_variant(); + h.form_factor = image.get_form_factor(); + h.variant = image.get_variant(); - io_generic_write(io, &h, 0, sizeof(header)); + write_at(io, 0, &h, sizeof(header)); // FIXME: check for errors memset(entries, 0, sizeof(entries)); int pos = sizeof(header) + (tracks << resolution)*heads*sizeof(entry); int epos = 0; - auto precomp = global_alloc_array(uint32_t, max_track_size); - auto postcomp = global_alloc_array(uint8_t, max_track_size*4 + 1000); + auto precomp = std::make_unique<uint32_t []>(max_track_size); + auto postcomp = std::make_unique<uint8_t []>(max_track_size*4 + 1000); for(int track=0; track <= (tracks-1) << 2; track += 4 >> resolution) for(int head=0; head<heads; head++) { - std::vector<uint32_t> &buffer = image->get_buffer(track >> 2, head, track & 3); + const std::vector<uint32_t> &buffer = image.get_buffer(track >> 2, head, track & 3); int tsize = buffer.size(); if(!tsize) { epos++; continue; } - memcpy(precomp, &buffer[0], tsize*4); - for(int j=0; j<tsize-1; j++) - precomp[j] = (precomp[j] & floppy_image::MG_MASK) | - ((precomp[j+1] & floppy_image::TIME_MASK) - - (precomp[j] & floppy_image::TIME_MASK)); - precomp[tsize-1] = (precomp[tsize-1] & floppy_image::MG_MASK) | - (200000000 - (precomp[tsize-1] & floppy_image::TIME_MASK)); + uint32_t ctime = 0; + for(int i=0; i != tsize; i++) { + precomp[i] = (buffer[i] & MG_MASK) | ((buffer[i] & TIME_MASK) - ctime); + ctime = buffer[i] & TIME_MASK; + } uLongf csize = max_track_size*4 + 1000; - if(compress(postcomp, &csize, (const Bytef *)precomp, tsize*4) != Z_OK) { - global_free_array(precomp); - global_free_array(postcomp); + if(compress(postcomp.get(), &csize, (const Bytef *)precomp.get(), tsize*4) != Z_OK) return false; - } entries[epos].offset = pos; entries[epos].uncompressed_size = tsize*4; entries[epos].compressed_size = csize; - entries[epos].write_splice = image->get_write_splice_position(track >> 2, head, track & 3); + entries[epos].write_splice = image.get_write_splice_position(track >> 2, head, track & 3); epos++; - io_generic_write(io, postcomp, pos, csize); + write_at(io, pos, postcomp.get(), csize); // FIXME: check for errors pos += csize; } - io_generic_write(io, entries, sizeof(header), (tracks << resolution)*heads*sizeof(entry)); - global_free_array(precomp); - global_free_array(postcomp); + write_at(io, sizeof(header), entries, (tracks << resolution)*heads*sizeof(entry)); // FIXME: check for errors return true; } -const floppy_format_type FLOPPY_MFI_FORMAT = &floppy_image_format_creator<mfi_format>; +const mfi_format FLOPPY_MFI_FORMAT; |