summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/devices/bus/heathzenith/h89/h17_fdc.cpp9
-rw-r--r--src/lib/formats/all.cpp9
-rw-r--r--src/lib/formats/h17disk.cpp246
-rw-r--r--src/lib/formats/h17disk.h38
4 files changed, 301 insertions, 1 deletions
diff --git a/src/devices/bus/heathzenith/h89/h17_fdc.cpp b/src/devices/bus/heathzenith/h89/h17_fdc.cpp
index 26edaaa8929..8f57a8ed72d 100644
--- a/src/devices/bus/heathzenith/h89/h17_fdc.cpp
+++ b/src/devices/bus/heathzenith/h89/h17_fdc.cpp
@@ -15,6 +15,7 @@
#include "emu.h"
#include "h17_fdc.h"
+#include "formats/h17disk.h"
#include "imagedev/floppy.h"
#include "machine/s2350.h"
@@ -63,6 +64,7 @@ protected:
void ctrl_w(u8 val);
u8 floppy_status_r();
+ static void floppy_formats(format_registration &fr);
void set_floppy(floppy_image_device *floppy);
void step_w(int state);
void dir_w(int state);
@@ -340,6 +342,11 @@ TIMER_DEVICE_CALLBACK_MEMBER(heath_h17_fdc_device::tx_timer_cb)
m_s2350->tcp_w();
}
+void heath_h17_fdc_device::floppy_formats(format_registration &fr)
+{
+ fr.add(FLOPPY_H17D_FORMAT);
+}
+
void heath_h17_fdc_device::device_add_mconfig(machine_config &config)
{
S2350(config, m_s2350, 0);
@@ -348,7 +355,7 @@ void heath_h17_fdc_device::device_add_mconfig(machine_config &config)
for (int i = 0; i < MAX_FLOPPY_DRIVES; i++)
{
// TODO -> add (and define) heath hard-sectored floppy formats.
- FLOPPY_CONNECTOR(config, m_floppies[i], h17_floppies, "ssdd", floppy_image_device::default_fm_floppy_formats);
+ FLOPPY_CONNECTOR(config, m_floppies[i], h17_floppies, "ssdd", heath_h17_fdc_device::floppy_formats);
m_floppies[i]->enable_sound(true);
}
diff --git a/src/lib/formats/all.cpp b/src/lib/formats/all.cpp
index 80d5930e37b..bab86919cb7 100644
--- a/src/lib/formats/all.cpp
+++ b/src/lib/formats/all.cpp
@@ -320,6 +320,10 @@
#include "guab_dsk.h"
#endif
+#ifdef HAS_FORMATS_H17D_DSK
+#include "h17disk.h"
+#endif
+
#ifdef HAS_FORMATS_H8_CAS
#include "h8_cas.h"
#endif
@@ -1530,4 +1534,9 @@ void mame_formats_full_list(mame_formats_enumerator &en)
#ifdef HAS_FORMATS_X07_CAS
en.add(x07_cassette_formats); // x07_cas.h
#endif
+
+ en.category("Heath");
+#ifdef HAS_FORMATS_H17D_DSK
+ en.add(FLOPPY_H17D_FORMAT); // h17disk.h
+#endif
}
diff --git a/src/lib/formats/h17disk.cpp b/src/lib/formats/h17disk.cpp
new file mode 100644
index 00000000000..47d164fda1d
--- /dev/null
+++ b/src/lib/formats/h17disk.cpp
@@ -0,0 +1,246 @@
+// license:BSD-3-Clause
+// copyright-holders:Mark Garlanger
+/*********************************************************************
+
+Heath H17D disk image format (version 2.0.0)
+
+ Format for Heath hard-sectored 5.25" disk images.
+
+ See https://heathkit.garlanger.com/diskformats/ for more information
+
+ TODO - implement writing to H17D image
+
+*********************************************************************/
+
+#include "h17disk.h"
+#include "ioprocs.h"
+#include "imageutl.h"
+
+#include <cstring>
+
+static constexpr int TRACK_SIZE = 50'000;
+static constexpr int BITCELL_SIZE = 4000;
+
+static constexpr int SECTOR_METADATA_SIZE = 16;
+
+static constexpr int SECTOR_DATA_SIZE = 256;
+static constexpr int SECTORS_PER_TRACK = 10;
+
+
+heath_h17d_format::heath_h17d_format() : floppy_image_format_t()
+{
+}
+
+struct format {
+ int head_count;
+ int track_count;
+ uint32_t variant;
+};
+
+static const format formats[] = {
+ { 1, 40, floppy_image::SSSD10 }, // H-17-1
+ { 2, 40, floppy_image::DSSD10 },
+ { 1, 80, floppy_image::SSQD10 },
+ { 2, 80, floppy_image::DSQD10 }, // H-17-4
+ {}
+};
+
+struct block_header {
+ uint32_t block_name;
+ uint32_t length;
+};
+
+enum {
+ DskF = 0x466b7344, //!< "DskF", Disk Format
+ Parm = 0x6b726150, //!< "Parm", Parameters
+ Date = 0x65746144, //!< "Date", Date
+ Imgr = 0x72676d49, //!< "Imgr", Imager
+
+ Prog = 0x676f7250, //!< "Prog", Program (creation)
+ Padd = 0x64646150, //!< "Padd", Padding
+ H8DB = 0x42443848, //!< "H8DB", H8D data block
+ SecM = 0x4d636553, //!< "SecM", Sector Metadata
+ Labl = 0x6c62614c, //!< "Labl", Label
+ Comm = 0x6d6d6f43, //!< "Comm", Comment
+};
+
+static std::pair<std::uint64_t, std::size_t> find_block(util::random_read &io, uint32_t block_id)
+{
+ LOG_FORMATS("find_block: 0x%x\n", block_id);
+
+ // start of file
+ int pos = 0;
+ block_header header = { 0, 0 };
+
+ do
+ {
+ pos += header.length + 8;
+ auto const [err, actual] = read_at(io, pos, (void *) &header, 8);
+ if (err || actual !=8)
+ {
+ return std::make_pair(0, 0);
+ }
+ header.length = swapendian_int32(header.length);
+ }
+ while (header.block_name != block_id);
+
+ // update position to point to data portion of the block
+ return std::make_pair(pos + 8, header.length);
+}
+
+static format find_format(util::random_read &io)
+{
+ auto const [pos, length] = find_block(io, DskF);
+ if ((pos == 0) || (length < 2) || (length > 3))
+ {
+ LOG_FORMATS("Can't find valid DskF block %d/%d\n", pos, length);
+
+ return {};
+ }
+
+ uint8_t buf[3];
+
+ auto const [err, actual] = read_at(io, pos, buf, length);
+ if (err || (actual != length))
+ {
+ LOG_FORMATS("read error\n");
+
+ return {};
+ }
+
+ int head_count = buf[0];
+ int track_count = buf[1];
+
+ for (int i = 0; formats[i].head_count; i++)
+ {
+ if ((formats[i].head_count == head_count) && (formats[i].track_count == track_count))
+ {
+ LOG_FORMATS("find_format format found: %d - variant: 0x%x\n", i, formats[i].variant);
+
+ return formats[i];
+ }
+ }
+
+ LOG_FORMATS("Invalid disk format - heads: %d, tracks: %d\n", head_count, track_count);
+ return {};
+}
+
+int heath_h17d_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const
+{
+ uint8_t h[4];
+ auto const [err, actual] = read_at(io, 0, h, 4);
+
+ if (err || (actual != 4))
+ {
+ return 0;
+ }
+
+ // Verify "H17D" Signature.
+ if ((h[0] == 0x48) && (h[1] == 0x31) && (h[2] == 0x37) && (h[3] == 0x44))
+ {
+ return FIFID_SIGN;
+ }
+
+ return 0;
+}
+
+bool heath_h17d_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const
+{
+ const format fmt = find_format(io);
+
+ if (!fmt.head_count)
+ {
+ LOG_FORMATS("invalid format\n");
+
+ return false;
+ }
+
+ image.set_variant(fmt.variant);
+
+ std::vector<uint32_t> buf;
+
+ auto const [secm_pos, secm_length] = find_block(io, SecM);
+
+ uint8_t sector_meta_data[SECTOR_METADATA_SIZE];
+ uint8_t sector_data[SECTOR_DATA_SIZE];
+
+ for (int head = 0; head < fmt.head_count; head++)
+ {
+ for (int track = 0; track < fmt.track_count; track++)
+ {
+ for (int sector = 0; sector < SECTORS_PER_TRACK; sector++)
+ {
+ int sect_meta_pos = (sector + (track * fmt.head_count + head) * SECTORS_PER_TRACK) * SECTOR_METADATA_SIZE + secm_pos;
+
+ auto const [err, actual] = read_at(io, sect_meta_pos, sector_meta_data, SECTOR_METADATA_SIZE);
+
+ if (err || (actual != SECTOR_METADATA_SIZE))
+ {
+ LOG_FORMATS("unable to read sect meta data %d/%d/%d\n", head, track, sector);
+
+ return false;
+ }
+ int data_offset = sector_meta_data[0] << 24 | sector_meta_data[1] << 16 | sector_meta_data[2] << 8 | sector_meta_data[3];
+
+ auto const [err2, actual2] = read_at(io, data_offset, sector_data, SECTOR_DATA_SIZE);
+
+ if (err2 || (actual2 != SECTOR_DATA_SIZE))
+ {
+ LOG_FORMATS("unable to read sect data %d/%d/%d\n", head, track, sector);
+
+ return false;
+ }
+
+ // Inital 15 zero bytes
+ for (int i = 0; i < 15; i++)
+ {
+ fm_reverse_byte_w(buf, 0);
+ }
+
+ // header (sync byte, volume, track, sector, checksum)
+ for (int i = 0; i < 5; i++)
+ {
+ fm_reverse_byte_w(buf, sector_meta_data[5 + i]);
+ }
+
+ // 12 zero bytes
+ for (int i = 0; i < 12; i++)
+ {
+ fm_reverse_byte_w(buf, 0);
+ }
+
+ // data sync byte
+ fm_reverse_byte_w(buf, sector_meta_data[10]);
+
+ // sector data
+ for (int i = 0; i < 256; i++)
+ {
+ fm_reverse_byte_w(buf, sector_data[i]);
+ }
+
+ // sector data checksum
+ fm_reverse_byte_w(buf, sector_meta_data[11]);
+
+ // trailing zero's until the next sector hole usually ~ 30 characters.
+ while (buf.size() < TRACK_SIZE / SECTORS_PER_TRACK * (sector + 1))
+ {
+ fm_reverse_byte_w(buf, 0);
+ }
+ }
+
+ generate_track_from_levels(track, head, buf, 0, image);
+ buf.clear();
+ }
+ }
+
+ return true;
+}
+
+void heath_h17d_format::fm_reverse_byte_w(std::vector<uint32_t> &buffer, uint8_t val) const
+{
+ static unsigned char lookup[16] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf };
+
+ fm_w(buffer, 8, lookup[val & 0x0f] << 4 | lookup[val >> 4], BITCELL_SIZE);
+}
+
+const heath_h17d_format FLOPPY_H17D_FORMAT;
diff --git a/src/lib/formats/h17disk.h b/src/lib/formats/h17disk.h
new file mode 100644
index 00000000000..19ac0bac052
--- /dev/null
+++ b/src/lib/formats/h17disk.h
@@ -0,0 +1,38 @@
+// license:BSD-3-Clause
+// copyright-holders:Mark Garlanger
+/*********************************************************************
+
+Heath h17disk disk image format
+
+The Heath hard-sectored disk format for the H8 and H89 systems with the
+H17 controller on the H8 and the H-88-1 controller on the H89.
+
+*********************************************************************/
+#ifndef MAME_FORMATS_H17DISK_H
+#define MAME_FORMATS_H17DISK_H
+
+#pragma once
+
+#include "flopimg.h"
+
+class heath_h17d_format : public floppy_image_format_t
+{
+public:
+ heath_h17d_format();
+
+ int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const override;
+ bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const override;
+
+ const char *name() const noexcept override { return "h17disk"; }
+ const char *description() const noexcept override { return "Heath H17D disk image"; }
+ const char *extensions() const noexcept override { return "h17,h17d,h17disk"; }
+ bool supports_save() const noexcept override { return false; }
+
+protected:
+
+ void fm_reverse_byte_w(std::vector<uint32_t> &buffer, uint8_t val) const;
+};
+
+extern const heath_h17d_format FLOPPY_H17D_FORMAT;
+
+#endif // MAME_FORMATS_H17DISK_H