summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/formats/vgi_dsk.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/formats/vgi_dsk.cpp')
-rw-r--r--src/lib/formats/vgi_dsk.cpp146
1 files changed, 146 insertions, 0 deletions
diff --git a/src/lib/formats/vgi_dsk.cpp b/src/lib/formats/vgi_dsk.cpp
new file mode 100644
index 00000000000..c15bba33d86
--- /dev/null
+++ b/src/lib/formats/vgi_dsk.cpp
@@ -0,0 +1,146 @@
+// license:BSD-3-Clause
+// copyright-holders:Eric Anderson
+/*********************************************************************
+
+Micropolis VGI disk image format
+
+The format is essentially an HCS-ordered sector image, but with raw
+275 byte sectors. The sector format is: SYNC (0xFF), track, sector,
+10 byte "user data", 256 byte data, checksum, 4 byte ECC, ECC present
+flag.
+
+http://www.bitsavers.org/pdf/micropolis/metafloppy/1084-01_1040_1050_Users_Manual_Apr79.pdf
+
+*********************************************************************/
+
+#include "vgi_dsk.h"
+#include "ioprocs.h"
+
+#include <cstring>
+
+static const int track_size = 100'000;
+static const int half_bitcell_size = 2000;
+
+micropolis_vgi_format::micropolis_vgi_format() : floppy_image_format_t()
+{
+}
+
+struct format {
+ int head_count;
+ int track_count;
+ uint32_t variant;
+};
+
+static const format formats[] = {
+ {1, 35, floppy_image::SSDD}, // MOD-I
+ {2, 35, floppy_image::DSDD},
+ {1, 77, floppy_image::SSQD}, // MOD-II
+ {2, 77, floppy_image::DSQD},
+ {}
+};
+
+static format find_format(int file_size)
+{
+ for (int i = 0; formats[i].head_count; i++)
+ if (file_size == formats[i].head_count * formats[i].track_count * 16 * 275)
+ return formats[i];
+ return {};
+}
+
+int micropolis_vgi_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const
+{
+ uint64_t file_size;
+ if (io.length(file_size))
+ return 0;
+ format fmt = find_format(file_size);
+ if (!fmt.head_count)
+ return 0;
+ if (!has_variant(variants, fmt.variant))
+ return 0;
+ return FIFID_SIZE;
+}
+
+bool micropolis_vgi_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) const
+{
+ uint64_t file_size;
+ if (io.length(file_size))
+ return false;
+ const format fmt = find_format(file_size);
+ if (!fmt.head_count)
+ return false;
+ image->set_variant(fmt.variant);
+
+ std::vector<uint32_t> buf;
+ uint8_t sector_bytes[275];
+ for (int head = 0; head < fmt.head_count; head++) {
+ for (int track = 0; track < fmt.track_count; track++) {
+ for (int sector = 0; sector < 16; sector++) {
+ for (int i = 0; i < 40; i++)
+ mfm_w(buf, 8, 0, half_bitcell_size);
+ std::size_t actual;
+ if (io.read(sector_bytes, std::size(sector_bytes), actual))
+ return false;
+ for (int i = 0; i < std::size(sector_bytes); i++)
+ mfm_w(buf, 8, sector_bytes[i], half_bitcell_size);
+ while (buf.size() < track_size/16 * (sector+1))
+ mfm_w(buf, 8, 0, half_bitcell_size);
+ }
+ generate_track_from_levels(track, head, buf, 0, image);
+ buf.clear();
+ }
+ }
+ return true;
+}
+
+bool micropolis_vgi_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) const
+{
+ uint32_t variant = image->get_variant();
+ format fmt = {};
+ for (int i = 0; formats[i].head_count; i++)
+ if (variant == formats[i].variant)
+ fmt = formats[i];
+ if (!fmt.head_count) {
+ int heads, tracks;
+ image->get_actual_geometry(tracks, heads);
+ if (heads == 0 && tracks == 0)
+ return false; // Brand-new image; we don't know the size yet
+ for (int i = 0; formats[i].head_count; i++)
+ if (heads <= formats[i].head_count && tracks <= formats[i].track_count)
+ fmt = formats[i];
+ }
+ if (!fmt.head_count)
+ return false;
+
+ if (io.seek(0, SEEK_SET))
+ return false;
+ uint8_t sector_bytes[275];
+ for (int head = 0; head < fmt.head_count; head++) {
+ for (int track = 0; track < fmt.track_count; track++) {
+ std::vector<bool> bitstream = generate_bitstream_from_track(track, head, half_bitcell_size, image);
+ for (int sector = 0; sector < 16; sector++) {
+ int sector_start = track_size/16 * sector;
+ uint32_t pos = sector_start + 512 - 16;
+ uint16_t shift_reg = 0;
+ while (pos < sector_start + 60*16 && pos < bitstream.size()) {
+ shift_reg = (shift_reg << 1) | bitstream[pos++];
+ if (shift_reg == 0x5554)
+ break;
+ }
+ if (shift_reg == 0x5554) {
+ pos--;
+ for (int i = 0; i < std::size(sector_bytes); i++)
+ sector_bytes[i] = sbyte_mfm_r(bitstream, pos);
+ } else {
+ memset(sector_bytes, 0, std::size(sector_bytes));
+ }
+
+ std::size_t actual;
+ if (io.write(sector_bytes, std::size(sector_bytes), actual))
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+const micropolis_vgi_format FLOPPY_VGI_FORMAT;