summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/lib/formats/mfi_dsk.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/lib/formats/mfi_dsk.c')
-rw-r--r--trunk/src/lib/formats/mfi_dsk.c258
1 files changed, 258 insertions, 0 deletions
diff --git a/trunk/src/lib/formats/mfi_dsk.c b/trunk/src/lib/formats/mfi_dsk.c
new file mode 100644
index 00000000000..942d9ef0c8f
--- /dev/null
+++ b/trunk/src/lib/formats/mfi_dsk.c
@@ -0,0 +1,258 @@
+/***************************************************************************
+
+ Copyright Olivier Galibert
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+****************************************************************************/
+
+#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, 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.
+
+ 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.
+
+ The media type is divided in two parts. The first half
+ indicate the physical form factor, i.e. all medias with that
+ form factor can be physically inserted in a reader that handles
+ it. The second half indicates the variants which are usually
+ detectable by the reader, such as density and number of sides.
+
+ TODO: big-endian support
+*/
+
+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 true;
+}
+
+int mfi_format::identify(io_generic *io, UINT32 form_factor)
+{
+ header h;
+
+ io_generic_read(io, &h, 0, sizeof(header));
+ if(memcmp( h.sign, sign, 16 ) == 0 &&
+ h.cyl_count <= 160 &&
+ h.head_count <= 2 &&
+ (!form_factor || h.form_factor == form_factor))
+ return 100;
+ return 0;
+}
+
+bool mfi_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
+{
+ header h;
+ entry entries[84*2];
+ io_generic_read(io, &h, 0, sizeof(header));
+ io_generic_read(io, &entries, sizeof(header), h.cyl_count*h.head_count*sizeof(entry));
+
+ image->set_variant(h.variant);
+
+ 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);
+ ent++;
+ continue;
+ }
+
+ if(ent->compressed_size > compressed_size) {
+ if(compressed)
+ global_free(compressed);
+ compressed_size = ent->compressed_size;
+ compressed = global_alloc_array(UINT8, compressed_size);
+ }
+
+ io_generic_read(io, compressed, ent->offset, ent->compressed_size);
+
+ unsigned int cell_count = ent->uncompressed_size/4;
+ image->set_track_size(cyl, head, cell_count);
+ UINT32 *trackbuf = image->get_buffer(cyl, head);
+
+ uLongf size = ent->uncompressed_size;
+ if(uncompress((Bytef *)trackbuf, &size, compressed, ent->compressed_size) != Z_OK)
+ return false;
+
+ 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] & MG_MASK) | cur_time;
+ cur_time = next_cur_time;
+ }
+ if(cur_time != 200000000)
+ return false;
+
+ ent++;
+ }
+
+ if(compressed)
+ global_free(compressed);
+
+ return true;
+}
+
+bool mfi_format::save(io_generic *io, floppy_image *image)
+{
+ int tracks, heads;
+ image->get_actual_geometry(tracks, heads);
+ int max_track_size = 0;
+ for(int track=0; track<tracks; track++)
+ for(int head=0; head<heads; head++) {
+ int tsize = image->get_track_size(track, head);
+ if(tsize > max_track_size)
+ max_track_size = tsize;
+ }
+
+ header h;
+ entry entries[84*2];
+ memcpy(h.sign, sign, 16);
+ h.cyl_count = tracks;
+ h.head_count = heads;
+ h.form_factor = image->get_form_factor();
+ h.variant = image->get_variant();
+
+ io_generic_write(io, &h, 0, sizeof(header));
+
+ memset(entries, 0, sizeof(entries));
+
+ int pos = sizeof(header) + tracks*heads*sizeof(entry);
+ int epos = 0;
+ UINT32 *precomp = global_alloc_array(UINT32, max_track_size);
+ UINT8 *postcomp = global_alloc_array(UINT8, max_track_size*4 + 1000);
+
+ for(int track=0; track<tracks; track++)
+ for(int head=0; head<heads; head++) {
+ int tsize = image->get_track_size(track, head);
+ if(!tsize) {
+ epos++;
+ continue;
+ }
+
+ memcpy(precomp, image->get_buffer(track, head), 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));
+
+ uLongf csize = max_track_size*4 + 1000;
+ if(compress(postcomp, &csize, (const Bytef *)precomp, 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, head);
+ epos++;
+
+ io_generic_write(io, postcomp, pos, csize);
+ pos += csize;
+ }
+
+ io_generic_write(io, entries, sizeof(header), tracks*heads*sizeof(entry));
+ return true;
+}
+
+const floppy_format_type FLOPPY_MFI_FORMAT = &floppy_image_format_creator<mfi_format>;