summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--src/lib/formats/mfi_dsk.c222
-rw-r--r--src/lib/formats/mfi_dsk.h47
-rw-r--r--src/lib/lib.mak1
3 files changed, 270 insertions, 0 deletions
diff --git a/src/lib/formats/mfi_dsk.c b/src/lib/formats/mfi_dsk.c
index e69de29bb2d..66ae217f41c 100644
--- a/src/lib/formats/mfi_dsk.c
+++ b/src/lib/formats/mfi_dsk.c
@@ -0,0 +1,222 @@
+#include "emu.h"
+#include "mfi_dsk.h"
+#include <zlib.h>
+
+/*
+ Mess floppy image structure:
+
+ - header with signature, number of cylinders, number of heads. Min
+ track and min head are considered to always be 0.
+
+ - vector of track descriptions, looping on cylinders and sub-lopping
+ on heads, each description composed of:
+ - offset of the track data in bytes from the start of the file
+ - size of the compressed track data in bytes (0 for unformatted)
+ - size of the uncompressed track data in bytes (0 for unformatted)
+
+ - track data
+
+ All values are 32-bits lsb first.
+
+ Track data is zlib-compressed independently for each track using the
+ 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 -> 0-level bit
+ - 1 -> 1-level bit
+ - 2 -> weak bit, randomly appears at 0 or 1
+
+ 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.
+
+ TODO: big-endian support, cleanup pll, move it where it belongs.
+*/
+
+const char mfi_format::sign[16] = "MESSFLOPPYIMAGE"; // Includes the final \0
+
+mfi_format::mfi_format() : floppy_image_format_t()
+{
+}
+
+const char *mfi_format::name() const
+{
+ return "mfi";
+}
+
+const char *mfi_format::description() const
+{
+ return "MESS floppy image";
+}
+
+const char *mfi_format::extensions() const
+{
+ return "mfi";
+}
+
+bool mfi_format::supports_save() const
+{
+ return false;
+}
+
+int mfi_format::identify(floppy_image *image)
+{
+ header h;
+
+ image->image_read(&h, 0, sizeof(header));
+ if(memcmp( h.sign, sign, 16 ) == 0 &&
+ h.cyl_count > 0 && h.cyl_count <= 84 &&
+ h.head_count > 0 && h.head_count <= 2)
+ return 100;
+ return 0;
+}
+
+void mfi_format::advance(const UINT32 *trackbuf, UINT32 &cur_cell, UINT32 cell_count, UINT32 time)
+{
+ if(time >= 200000000) {
+ cur_cell = cell_count;
+ return;
+ }
+
+ while(cur_cell != cell_count-1 && (trackbuf[cur_cell+1] & TIME_MASK) < time)
+ cur_cell++;
+}
+
+UINT32 mfi_format::get_next_edge(const UINT32 *trackbuf, UINT32 cur_cell, UINT32 cell_count)
+{
+ if(cur_cell == cell_count)
+ return 200000000;
+ UINT32 cur_bit = trackbuf[cur_cell] & BIT_MASK;
+ if(cur_bit == BIT_WEAK)
+ cur_bit = BIT_0;
+ cur_cell++;
+ while(cur_cell != cell_count) {
+ UINT32 next_bit = trackbuf[cur_cell] & BIT_MASK;
+ if(next_bit == BIT_WEAK)
+ next_bit = BIT_0;
+ if(next_bit != cur_bit)
+ break;
+ }
+ return cur_cell == cell_count ? 200000000 : trackbuf[cur_cell] & TIME_MASK;
+}
+
+bool mfi_format::load(floppy_image *image)
+{
+ header h;
+ entry entries[84*2];
+ image->image_read(&h, 0, sizeof(header));
+ image->image_read(&entries, sizeof(header), h.cyl_count*h.head_count*sizeof(entry));
+ image->set_meta_data(h.cyl_count, h.head_count, 300, (UINT16)253360);
+
+ UINT32 *trackbuf = 0;
+ int trackbuf_size = 0;
+ UINT8 *compressed = 0;
+ int compressed_size = 0;
+
+ entry *ent = entries;
+ for(unsigned int cyl=0; cyl != h.cyl_count; cyl++)
+ for(unsigned int head=0; head != h.head_count; head++) {
+ if(ent->uncompressed_size == 0) {
+ // Unformatted track
+ image->set_track_size(cyl, head, 0);
+ continue;
+ }
+
+ if(ent->compressed_size > compressed_size) {
+ if(compressed)
+ global_free(compressed);
+ compressed_size = ent->compressed_size;
+ compressed = global_alloc_array(UINT8, compressed_size);
+ }
+
+ if(ent->uncompressed_size > trackbuf_size) {
+ if(trackbuf)
+ global_free(trackbuf);
+ trackbuf_size = ent->uncompressed_size;
+ trackbuf = global_alloc_array(UINT32, trackbuf_size/4);
+ }
+
+ image->image_read(compressed, ent->offset, ent->compressed_size);
+
+ uLongf size = ent->uncompressed_size;
+ if(uncompress((Bytef *)trackbuf, &size, compressed, ent->compressed_size) != Z_OK)
+ return true;
+
+ UINT8 *mfm = image->get_buffer(cyl, head);
+ image->set_track_size(cyl, head, 16384);
+ memset(mfm, 0, 16384);
+ int bit = 0;
+
+ // Extract the bits using a quick-n-dirty software pll
+ // expecting mfm 2us data. Eventually the plls will end
+ // up in the fdc simulations themselves. Weak bits are
+ // always 0 for now.
+
+ // Start by turning the cell times into absolute
+ // positions, it's easier to use that way.
+
+ unsigned int cell_count = ent->uncompressed_size/4;
+ UINT32 cur_time = 0;
+ for(unsigned int i=0; i != cell_count; i++) {
+ UINT32 next_cur_time = cur_time + (trackbuf[i] & TIME_MASK);
+ trackbuf[i] = (trackbuf[i] & BIT_MASK) | cur_time;
+ cur_time = next_cur_time;
+ }
+ if(cur_time != 200000000)
+ return true;
+
+ // Then pll the hell out of the bits
+
+ UINT32 cur_cell = 0;
+ UINT32 pll_period = 2000;
+ UINT32 pll_phase = 1000;
+ for(;;) {
+ advance(trackbuf, cur_cell, cell_count, pll_phase);
+ if(cur_cell == cell_count)
+ break;
+
+ if((trackbuf[cur_cell] & BIT_MASK) == BIT_1)
+ mfm[bit >> 3] |= 0x80 >> (bit & 7);
+ bit++;
+
+#if 0
+ printf("%09d: (%d, %09d) - (%d, %09d) - (%d, %09d)\n",
+ pll_phase,
+ trackbuf[cur_cell] >> BIT_SHIFT, trackbuf[cur_cell] & TIME_MASK,
+ trackbuf[cur_cell+1] >> BIT_SHIFT, trackbuf[cur_cell+1] & TIME_MASK,
+ trackbuf[cur_cell]+2 >> BIT_SHIFT, trackbuf[cur_cell+2] & TIME_MASK);
+#endif
+
+ UINT32 next_edge = get_next_edge(trackbuf, cur_cell, cell_count);
+ if(next_edge > pll_phase + pll_period) {
+ // free run
+ // printf("%09d: %4d - Free run\n", pll_phase, pll_period);
+ pll_phase += pll_period;
+ } else {
+ // Adjust
+ INT32 delta = next_edge - (pll_phase + pll_period/2);
+ // printf("%09d: %4d - Delta = %d\n", pll_phase, pll_period, delta);
+ // The deltas should be lowpassed, the amplification factor tuned...
+ pll_period += delta/2;
+ pll_phase += pll_period;
+ }
+ }
+ image->set_track_size(cyl, head, (bit+7)/8);
+
+ ent++;
+ }
+
+ return false;
+}
+
+const floppy_format_type FLOPPY_MFI_FORMAT = &floppy_image_format_creator<mfi_format>;
diff --git a/src/lib/formats/mfi_dsk.h b/src/lib/formats/mfi_dsk.h
index e69de29bb2d..420cf9ba3ed 100644
--- a/src/lib/formats/mfi_dsk.h
+++ b/src/lib/formats/mfi_dsk.h
@@ -0,0 +1,47 @@
+#ifndef MFI_DSK_H
+#define MFI_DSK_H
+
+#include "flopimg.h"
+
+class mfi_format : public floppy_image_format_t
+{
+public:
+ mfi_format();
+
+ virtual int identify(floppy_image *image);
+ virtual bool load(floppy_image *image);
+
+ virtual const char *name() const;
+ virtual const char *description() const;
+ virtual const char *extensions() const;
+ virtual bool supports_save() const;
+
+private:
+ enum {
+ TIME_MASK = 0x0fffffff,
+ BIT_MASK = 0xf0000000,
+ BIT_SHIFT = 28,
+
+ BIT_0 = (0 << BIT_SHIFT),
+ BIT_1 = (1 << BIT_SHIFT),
+ BIT_WEAK = (2 << BIT_SHIFT)
+ };
+
+ static const char sign[16];
+
+ struct header {
+ char sign[16];
+ unsigned int cyl_count, head_count;
+ };
+
+ struct entry {
+ unsigned int offset, compressed_size, uncompressed_size;
+ };
+
+ void advance(const UINT32 *trackbuf, UINT32 &cur_cell, UINT32 cell_count, UINT32 time);
+ UINT32 get_next_edge(const UINT32 *trackbuf, UINT32 cur_cell, UINT32 cell_count);
+};
+
+extern const floppy_format_type FLOPPY_MFI_FORMAT;
+
+#endif /* MFI_DSK_H */
diff --git a/src/lib/lib.mak b/src/lib/lib.mak
index 1c1ca90bf69..121c7627763 100644
--- a/src/lib/lib.mak
+++ b/src/lib/lib.mak
@@ -121,6 +121,7 @@ FORMATSOBJS = \
$(LIBOBJ)/formats/kim1_cas.o \
$(LIBOBJ)/formats/lviv_lvt.o \
$(LIBOBJ)/formats/msx_dsk.o \
+ $(LIBOBJ)/formats/mfi_dsk.o \
$(LIBOBJ)/formats/mz_cas.o \
$(LIBOBJ)/formats/nes_dsk.o \
$(LIBOBJ)/formats/orao_cas.o \