From 9a06c424e0a900a1327ef1c52768bb6602f300fc Mon Sep 17 00:00:00 2001 From: Mark Garlanger Date: Sun, 12 Jan 2025 10:27:13 -0600 Subject: formats/h17disk.cpp: Add format for Heath hard-sectored formats (#13222) * formats/h17disk.cpp: Add format for Heath hard-sectored formats * fix compile error * minor formatting changes --- scripts/src/formats.lua | 12 ++ src/devices/bus/heathzenith/h89/h17_fdc.cpp | 9 +- src/lib/formats/all.cpp | 9 + src/lib/formats/h17disk.cpp | 246 ++++++++++++++++++++++++++++ src/lib/formats/h17disk.h | 38 +++++ 5 files changed, 313 insertions(+), 1 deletion(-) create mode 100644 src/lib/formats/h17disk.cpp create mode 100644 src/lib/formats/h17disk.h diff --git a/scripts/src/formats.lua b/scripts/src/formats.lua index fa0d3d5f8dc..bf1086cb13a 100644 --- a/scripts/src/formats.lua +++ b/scripts/src/formats.lua @@ -1050,6 +1050,18 @@ if opt_tool(FORMATS, "GUAB_DSK") then } end +-------------------------------------------------- +-- +--@src/lib/formats/h17disk.h,FORMATS["H17D_DSK"] = true +-------------------------------------------------- + +if opt_tool(FORMATS, "H17D_DSK") then + files { + MAME_DIR.. "src/lib/formats/h17disk.cpp", + MAME_DIR.. "src/lib/formats/h17disk.h", + } +end + -------------------------------------------------- -- --@src/lib/formats/h8_cas.h,FORMATS["H8_CAS"] = true 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 + +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 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 &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 &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 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 &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 &variants) const override; + bool load(util::random_read &io, uint32_t form_factor, const std::vector &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 &buffer, uint8_t val) const; +}; + +extern const heath_h17d_format FLOPPY_H17D_FORMAT; + +#endif // MAME_FORMATS_H17DISK_H -- cgit v1.2.3