summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/formats/mfi_dsk.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/formats/mfi_dsk.cpp')
-rw-r--r--src/lib/formats/mfi_dsk.cpp191
1 files changed, 118 insertions, 73 deletions
diff --git a/src/lib/formats/mfi_dsk.cpp b/src/lib/formats/mfi_dsk.cpp
index 049660272a3..e8ab99ee852 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 <cassert>
-
#include "mfi_dsk.h"
+
+#include "ioprocs.h"
+
#include <zlib.h>
+#include <cstring>
+#include <functional>
+#include <tuple>
+
+
/*
Mess floppy image structure:
@@ -27,31 +33,27 @@
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
+ 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:
- Remember that the fdcs detect transitions, not absolute levels, so
- the actual physical significance of the orientation A and B is
- arbitrary.
+ - 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,
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.
+ 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 one big MG_N cell covering a
- whole turn, but is encoded as zero-size.
+ 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
@@ -68,111 +70,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, const std::vector<uint32_t> &variants)
+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, const std::vector<uint32_t> &variants, 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_form_variant(h.form_factor, 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, const std::vector<uint32_t> &variants, 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;
}
@@ -182,10 +229,10 @@ bool mfi_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo
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));
@@ -196,20 +243,18 @@ bool mfi_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo
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[0], &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.get(), &csize, (const Bytef *)precomp.get(), tsize*4) != Z_OK)
@@ -218,15 +263,15 @@ bool mfi_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo
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.get(), 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));
+ 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;