summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/formats/fdos_dsk.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/formats/fdos_dsk.cpp')
-rw-r--r--src/lib/formats/fdos_dsk.cpp189
1 files changed, 189 insertions, 0 deletions
diff --git a/src/lib/formats/fdos_dsk.cpp b/src/lib/formats/fdos_dsk.cpp
new file mode 100644
index 00000000000..138ad986011
--- /dev/null
+++ b/src/lib/formats/fdos_dsk.cpp
@@ -0,0 +1,189 @@
+// license:BSD-3-Clause copyright-holders:Michael R. Furman
+/*
+ * fdos_dsk.cpp - FDOS compatible disk images
+ *
+ * Created on: 24/08/2022
+ *
+ * This FDOS floppy disk image support leverages the wd177x_format support with
+ * verification of the disk formatting and the the ability to support format
+ * variations.
+ *
+ * The FDOS Disk format is as follows:
+ *
+ * Geometry:: 10 Sectors * 35 Tracks * 256 Bytes * 1 Side
+ * Sectors Numbered from 0-9
+ * Gap Bytes: Verified from FDOS source code
+ *
+ * Disk Format::
+ *
+ * Operating System:: Tracks 0-1
+ * Directory:: Track 2
+ * Data:: Tracks 3-34
+ *
+ *
+ * Note: Due to hardware differences between the original DC-1 (WD1771)
+ * controller for which FDOS was designed and DC-4 (WD1797) or DC-5 (WD2797)
+ * Controllers (DC-5 is Emulated in MAME), the machine can only be booted with
+ * a specific disk image from deramp.com (Mike Douglas) at the following
+ * location. The other disks available in the same directory can then be read
+ * once FDOS is loaded. This disk image also works on real hardware with a DC-4
+ * or PT FD-2A controllers.
+ *
+ * https://deramp.com/downloads/swtpc/software/FDOS/Disk%20Images/FDOSMPS.DSK
+ *
+ * This disk contains the all of these required patches:
+ *
+ * https://deramp.com/downloads/swtpc/software/FDOS/Disk%20Images/Patches/
+ */
+
+#include "fdos_dsk.h"
+
+#include "imageutl.h"
+
+#include "ioprocs.h"
+#include "multibyte.h"
+
+#include <tuple>
+
+
+namespace
+{
+ class fdos_formats : public wd177x_format
+ {
+ public:
+ struct dirent_entry_fdos
+ {
+ char filename[8] = {};
+ char password[8] = {};
+ uint8_t start_track = 0;
+ uint8_t start_sector = 0;
+ uint8_t num_sectors[2] = {};
+ uint8_t file_type = 0;
+ uint8_t start_addr[2] = {};
+ uint8_t end_addr[2] = {};
+ uint8_t exec_addr[2] = {};
+ uint8_t basic_high_line[2] = {};
+ uint8_t spares[3] = {};
+ };
+
+ static const format formats[];
+ };
+}
+
+fdos_format::fdos_format() : wd177x_format(fdos_formats::formats)
+{
+}
+
+const char *fdos_format::name() const noexcept
+{
+ return "fdos";
+}
+
+const char *fdos_format::description() const noexcept
+{
+ return "FDOS compatible disk image";
+}
+
+const char *fdos_format::extensions() const noexcept
+{
+ return "dsk";
+}
+
+int fdos_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const
+{
+ int type = find_size(io, form_factor, variants);
+
+ if (type != -1)
+ return FIFID_SIZE;
+ return 0;
+}
+
+
+int fdos_format::find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const
+{
+ uint64_t size;
+ if (io.length(size))
+ return -1;
+
+ uint8_t boot0[256];
+ fdos_formats::dirent_entry_fdos info;
+ size_t actual;
+ std::error_condition ec;
+
+ for (int i=0; fdos_formats::formats[i].form_factor; i++) {
+ const format &f = fdos_formats::formats[i];
+
+ // Format Check
+ // Check byte 0 and byte 3 of Track 0 Sector 0
+ // 00320 2400 BD 240C START JSR BOOT
+ // 00330 2403 DE OB RESTRT LDX PROGX
+ // Should be $BD and $DE respectively
+ // There could be additional variations
+ std::tie(ec, actual) = read_at(io, 0, &boot0, f.sector_base_size);
+ if (ec || actual != f.sector_base_size)
+ return -1;
+ if (boot0[0] != 0xbd && boot0[3] != 0xde)
+ continue;
+
+ LOG_FORMATS("FDOS floppy dsk: size %u bytes, %u total sectors, %u remaining bytes, expected form factor %x\n",
+ size,
+ size / f.sector_base_size,
+ size % f.sector_base_size,
+ form_factor);
+
+ // Directory entries start at Track 2 Sector 0
+ std::tie(ec, actual) = read_at(io, 2 * f.sector_count * f.sector_base_size, &info, sizeof(struct fdos_formats::dirent_entry_fdos));
+ if (ec || actual != sizeof(struct fdos_formats::dirent_entry_fdos))
+ continue;
+
+ // First directory entry should be "$DOS"
+ if (memcmp(info.filename, "$DOS ", 8) != 0)
+ continue;
+ if (memcmp(info.password, " ", 8) != 0)
+ continue;
+ if (info.start_track != 0)
+ continue;
+ if (info.start_sector != 0)
+ continue;
+ if (get_u16be(info.num_sectors) != 0x0014)
+ continue;
+ // $DOS File type is supposed to be $11 but some disks (FDOSMPS) have $00
+ if (info.file_type != 0 && info.file_type != 0x11)
+ continue;
+ if (get_u16be(info.start_addr) != 0x2400)
+ continue;
+ if (get_u16be(info.end_addr) != 0x2fff)
+ continue;
+ // FDOS entry is supposed to be $2600 but some disks have $2400
+ uint16_t exec = get_u16be(info.exec_addr);
+ if (exec != 0x2600 && exec != 0x2400)
+ continue;
+
+
+ unsigned int format_size = 0;
+ for (int track=0; track < f.track_count; track++) {
+ for (int head=0; head < f.head_count; head++) {
+ const format &tf = get_track_format(f, head, track);
+ format_size += compute_track_size(tf);
+ }
+ }
+
+ if (format_size != size)
+ continue;
+
+
+ LOG_FORMATS("FDOS matching format index %d\n", i);
+ return i;
+ }
+ return -1;
+}
+
+const fdos_formats::format fdos_formats::formats[] = {
+ { // 0 89.6K 5 1/4 inch single density fdos format
+ floppy_image::FF_525, floppy_image::SSSD, floppy_image::FM,
+ 4000, 10, 35, 1, 256, {}, 0, {}, 11, 11, 11
+ },
+ {}
+};
+
+const fdos_format FLOPPY_FDOS_FORMAT;