From eb2a8346252aa4ee15e602bb8dc578a6f95077a9 Mon Sep 17 00:00:00 2001 From: AJR Date: Sun, 3 Nov 2024 17:43:13 -0500 Subject: Add support for reading SAP (Systeme d'Archivage Pukall) disk images to Thomson systems --- hash/to_flop.xml | 5 +- scripts/src/formats.lua | 12 +++ src/devices/bus/thomson/cd90_015.cpp | 2 + src/devices/bus/thomson/cd90_351.cpp | 2 + src/devices/bus/thomson/cd90_640.cpp | 2 + src/lib/formats/all.cpp | 7 ++ src/lib/formats/sap_dsk.cpp | 168 +++++++++++++++++++++++++++++++++++ src/lib/formats/sap_dsk.h | 30 +++++++ src/mame/thomson/thomson.cpp | 2 + 9 files changed, 227 insertions(+), 3 deletions(-) create mode 100644 src/lib/formats/sap_dsk.cpp create mode 100644 src/lib/formats/sap_dsk.h diff --git a/hash/to_flop.xml b/hash/to_flop.xml index 924698a67ca..9bafb2fa81c 100644 --- a/hash/to_flop.xml +++ b/hash/to_flop.xml @@ -5,9 +5,8 @@ license:CC0-1.0 Thanks to DCMOTO (http://dcmoto.free.fr) for info! -FIXME: Many of these images should be 5.25" rather than 3.5". (The old custom Thomson floppy emulation didn't care about form factor.) -TODO: SAP format is not currently supported. -TBD: Which images are compatible with which systems? +FIXME: Some images should be 5.25" rather than 3.5", though TO8/TO9/TO9+ software can assumed to be the latter. + (The old custom Thomson floppy emulation didn't care about form factor, and many images are probably conversions.) --> diff --git a/scripts/src/formats.lua b/scripts/src/formats.lua index 320f2123674..fa0d3d5f8dc 100644 --- a/scripts/src/formats.lua +++ b/scripts/src/formats.lua @@ -1771,6 +1771,18 @@ if opt_tool(FORMATS, "RX50_DSK") then } end +-------------------------------------------------- +-- +--@src/lib/formats/sap_dsk.h,FORMATS["SAP_DSK"] = true +-------------------------------------------------- + +if opt_tool(FORMATS, "SAP_DSK") then + files { + MAME_DIR.. "src/lib/formats/sap_dsk.cpp", + MAME_DIR.. "src/lib/formats/sap_dsk.h", + } +end + -------------------------------------------------- -- --@src/lib/formats/sc3000_bit.h,FORMATS["SC3000_BIT"] = true diff --git a/src/devices/bus/thomson/cd90_015.cpp b/src/devices/bus/thomson/cd90_015.cpp index 86e132301d4..f51b47f4dd2 100644 --- a/src/devices/bus/thomson/cd90_015.cpp +++ b/src/devices/bus/thomson/cd90_015.cpp @@ -8,6 +8,7 @@ #include "emu.h" #include "cd90_015.h" +#include "formats/sap_dsk.h" #include "formats/thom_dsk.h" DEFINE_DEVICE_TYPE(CD90_015, cd90_015_device, "cd90_015", "Thomson CD 90-015 floppy drive controller") @@ -78,6 +79,7 @@ void cd90_015_device::floppy_drives(device_slot_interface &device) void cd90_015_device::floppy_formats(format_registration &fr) { fr.add(FLOPPY_THOMSON_525_FORMAT); + fr.add(FLOPPY_SAP_FORMAT); } void cd90_015_device::device_add_mconfig(machine_config &config) diff --git a/src/devices/bus/thomson/cd90_351.cpp b/src/devices/bus/thomson/cd90_351.cpp index 870c0843733..1247a2c3185 100644 --- a/src/devices/bus/thomson/cd90_351.cpp +++ b/src/devices/bus/thomson/cd90_351.cpp @@ -10,6 +10,7 @@ #include "emu.h" #include "cd90_351.h" +#include "formats/sap_dsk.h" #include "formats/thom_dsk.h" #include "machine/thmfc1.h" @@ -60,6 +61,7 @@ void cd90_351_device::floppy_formats(format_registration &fr) { fr.add_pc_formats(); fr.add(FLOPPY_THOMSON_35_FORMAT); + fr.add(FLOPPY_SAP_FORMAT); } void cd90_351_device::device_add_mconfig(machine_config &config) diff --git a/src/devices/bus/thomson/cd90_640.cpp b/src/devices/bus/thomson/cd90_640.cpp index a49d579704e..ba8a9a95969 100644 --- a/src/devices/bus/thomson/cd90_640.cpp +++ b/src/devices/bus/thomson/cd90_640.cpp @@ -7,6 +7,7 @@ #include "emu.h" #include "cd90_640.h" +#include "formats/sap_dsk.h" #include "formats/thom_dsk.h" DEFINE_DEVICE_TYPE(CD90_640, cd90_640_device, "cd90_640", "Thomson CD 90-640 floppy drive controller") @@ -49,6 +50,7 @@ void cd90_640_device::floppy_drives(device_slot_interface &device) void cd90_640_device::floppy_formats(format_registration &fr) { fr.add(FLOPPY_THOMSON_525_FORMAT); + fr.add(FLOPPY_SAP_FORMAT); } void cd90_640_device::device_add_mconfig(machine_config &config) diff --git a/src/lib/formats/all.cpp b/src/lib/formats/all.cpp index 02f5b636cf5..c068969db2e 100644 --- a/src/lib/formats/all.cpp +++ b/src/lib/formats/all.cpp @@ -576,6 +576,10 @@ #include "rx50_dsk.h" #endif +#ifdef HAS_FORMATS_SAP_DSK +#include "sap_dsk.h" +#endif + #ifdef HAS_FORMATS_SC3000_BIT #include "sc3000_bit.h" #endif @@ -1339,6 +1343,9 @@ void mame_formats_full_list(mame_formats_enumerator &en) en.add(FLOPPY_THOMSON_525_FORMAT); // thom_dsk.h en.add(FLOPPY_THOMSON_35_FORMAT); // thom_dsk.h #endif +#ifdef HAS_FORMATS_SAP_DSK + en.add(FLOPPY_SAP_FORMAT); +#endif en.category("Texas Instruments"); #ifdef HAS_FORMATS_TI99_DSK diff --git a/src/lib/formats/sap_dsk.cpp b/src/lib/formats/sap_dsk.cpp new file mode 100644 index 00000000000..6809b8bab29 --- /dev/null +++ b/src/lib/formats/sap_dsk.cpp @@ -0,0 +1,168 @@ +// license:BSD-3-Clause +// copyright-holders:AJR + +#include "sap_dsk.h" + +#include "ioprocs.h" +#include "multibyte.h" + +static constexpr unsigned HEADER_LENGTH = 66; +static constexpr uint8_t MAGIC_XOR = 0xb3; + +const sap_dsk_format FLOPPY_SAP_FORMAT; + +inline uint16_t sap_dsk_format::accumulate_crc(uint16_t crc, uint8_t data) noexcept +{ + // Almost CRC16-CCITT, but not quite... + for (int shift : {0, 4}) + crc = ((crc >> 4) & 0xfff) ^ 0x1081 * ((crc ^ (data >> shift)) & 0xf); + return crc; +} + +const char *sap_dsk_format::name() const noexcept +{ + return "sap_dsk"; +} + +const char *sap_dsk_format::description() const noexcept +{ + return "Thomson SAP disk image (Systeme d'Archivage Pukall)"; +} + +const char *sap_dsk_format::extensions() const noexcept +{ + return "sap"; +} + +bool sap_dsk_format::supports_save() const noexcept +{ + return false; +} + +int sap_dsk_format::identify(util::random_read &io, uint32_t form_factor, const std::vector &variants) const +{ + uint8_t buffer[HEADER_LENGTH]; + auto [err, actual] = read_at(io, 0, buffer, HEADER_LENGTH); + if (err || actual != HEADER_LENGTH) + return 0; + + // Check ID string + if (memcmp(&buffer[1], "SYSTEME D'ARCHIVAGE PUKALL S.A.P. (c) Alexandre PUKALL Avril 1998", HEADER_LENGTH - 1) != 0) + return 0; + + // Check disk format + if (form_factor == floppy_image::FF_35) + { + // 3.5" disks must have 80 double-density tracks + if ((buffer[0] & 0x7f) != 0x01) + return 0; + } + else if (form_factor == floppy_image::FF_525) + { + // 5.25" disks must have 40 tracks + if ((buffer[0] & 0x7e) != 0x02) + return 0; + } + else if (form_factor != floppy_image::FF_UNKNOWN) + return 0; + + uint32_t expected_size = HEADER_LENGTH + uint32_t((buffer[0] & 0x01) ? 256 + 6 : 128 + 6) * ((buffer[0] & 0x02) ? 40 : 80) * 16 * ((buffer[0] & 0x80) ? 2 : 1); + uint64_t actual_size; + if (!io.length(actual_size) && expected_size == actual_size) + return FIFID_SIGN | FIFID_SIZE; + else + return FIFID_SIGN; +} + +bool sap_dsk_format::load(util::random_read &io, uint32_t form_factor, const std::vector &variants, floppy_image &image) const +{ + uint8_t disk_type; + if (auto [err, actual] = read_at(io, 0, &disk_type, 1); err || actual != 1) + return false; + + int track_count = (disk_type & 0x02) ? 40 : 80; + int head_count = (disk_type & 0x80) ? 2 : 1; + int max_tracks, max_heads; + image.get_maximal_geometry(max_tracks, max_heads); + if (max_heads < head_count || max_tracks < track_count) + return false; + + switch (disk_type & 0x03) + { + case 0x01: + image.set_form_variant(floppy_image::FF_35, (disk_type & 0x80) ? floppy_image::DSDD : floppy_image::SSDD); + break; + + case 0x02: + image.set_form_variant(floppy_image::FF_525, (disk_type & 0x80) ? floppy_image::DSSD : floppy_image::SSSD); + break; + + case 0x03: + image.set_form_variant(floppy_image::FF_525, (disk_type & 0x80) ? floppy_image::DSDD : floppy_image::SSDD); + break; + + default: + return false; + } + + uint8_t sector_buf[16 * 1024]; + uint8_t sector_header[4]; + uint8_t sector_crc[2]; + desc_pc_sector sectors[16]; + + size_t read_offset = HEADER_LENGTH; + for (int head = 0; head < head_count; head++) + { + for (int track = 0; track < track_count; track++) + { + uint8_t *bufptr = §or_buf[0]; + uint8_t track_size = 16; + int sector_count = 0; + bool is_mfm = disk_type & 0x01; + while (track_size != 0) + { + if (auto [err, actual] = read_at(io, read_offset, §or_header[0], 4); err || actual != 4) + return false; + if (sector_count == 0 && sector_header[0] == 1) + is_mfm = false; + uint8_t sector_size = (sector_header[0] & 2) ? 4 >> (sector_header[0] & 1) : 1; + if (track_size < sector_size) + return false; + uint16_t sector_octets = sector_size * (is_mfm ? 256 : 128); + if (auto [err, actual] = read_at(io, read_offset + 4, bufptr, sector_octets); err || actual != sector_octets) + return false; + if (auto [err, actual] = read_at(io, read_offset + 4 + sector_octets, §or_crc[0], 2); err || actual != 2) + return false; + + uint16_t crc = 0xffff; + for (uint8_t data : sector_header) + crc = accumulate_crc(crc, data); + for (uint16_t i = 0; i < sector_octets; i++) + { + bufptr[i] ^= MAGIC_XOR; + crc = accumulate_crc(crc, bufptr[i]); + } + + sectors[sector_count].track = sector_header[2]; + sectors[sector_count].head = head; + sectors[sector_count].sector = sector_header[3]; + sectors[sector_count].size = sector_size; + sectors[sector_count].actual_size = sector_octets; + sectors[sector_count].data = bufptr; + sectors[sector_count].deleted = false; + sectors[sector_count].bad_crc = crc != get_u16be(sector_crc); + + read_offset += sector_octets + 6; + bufptr += sector_octets; + track_size -= sector_size; + sector_count++; + } + if (is_mfm) + build_pc_track_mfm(track, head, image, 100000, sector_count, sectors, calc_default_pc_gap3_size(form_factor, sectors[0].actual_size)); + else + build_pc_track_fm(track, head, image, 100000 / 2, sector_count, sectors, calc_default_pc_gap3_size(form_factor, sectors[0].actual_size)); + } + } + + return true; +} diff --git a/src/lib/formats/sap_dsk.h b/src/lib/formats/sap_dsk.h new file mode 100644 index 00000000000..5bc86a2d6ef --- /dev/null +++ b/src/lib/formats/sap_dsk.h @@ -0,0 +1,30 @@ +// license:BSD-3-Clause +// copyright-holders:AJR + +#ifndef MAME_FORMATS_SAP_DSK_H +#define MAME_FORMATS_SAP_DSK_H + +#pragma once + +#include "flopimg.h" + +class sap_dsk_format : public floppy_image_format_t +{ +public: + sap_dsk_format() = default; + + virtual const char *name() const noexcept override; + virtual const char *description() const noexcept override; + virtual const char *extensions() const noexcept override; + virtual bool supports_save() const noexcept override; + + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector &variants) const override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector &variants, floppy_image &image) const override; + +private: + static inline uint16_t accumulate_crc(uint16_t crc, uint8_t data) noexcept; +}; + +extern const sap_dsk_format FLOPPY_SAP_FORMAT; + +#endif // MAME_FORMATS_SAP_DSK_H diff --git a/src/mame/thomson/thomson.cpp b/src/mame/thomson/thomson.cpp index 856987ef807..8c1ae828082 100644 --- a/src/mame/thomson/thomson.cpp +++ b/src/mame/thomson/thomson.cpp @@ -97,6 +97,7 @@ #include "softlist_dev.h" #include "speaker.h" +#include "formats/sap_dsk.h" #include "formats/thom_cas.h" #include "formats/thom_dsk.h" @@ -494,6 +495,7 @@ static void to35_floppy_formats(format_registration &fr) { fr.add_pc_formats(); fr.add(FLOPPY_THOMSON_35_FORMAT); + fr.add(FLOPPY_SAP_FORMAT); } /* ------------ driver ------------ */ -- cgit v1.2.3