From f2248985239ceb1325d25e8df218ced1556156b2 Mon Sep 17 00:00:00 2001 From: Nigel Barnes Date: Thu, 23 Mar 2017 18:59:43 +0000 Subject: archimedes: Added JFD floppy format as used by JASPP (Archimedes Software Preservation Project) --- scripts/src/formats.lua | 12 ++ scripts/target/mame/mess.lua | 1 + src/lib/formats/jfd_dsk.cpp | 365 +++++++++++++++++++++++++++++++++++++++++++ src/lib/formats/jfd_dsk.h | 31 ++++ src/mame/drivers/aa310.cpp | 4 +- 5 files changed, 412 insertions(+), 1 deletion(-) create mode 100644 src/lib/formats/jfd_dsk.cpp create mode 100644 src/lib/formats/jfd_dsk.h diff --git a/scripts/src/formats.lua b/scripts/src/formats.lua index 81ab80f32be..ba20df392a0 100644 --- a/scripts/src/formats.lua +++ b/scripts/src/formats.lua @@ -941,6 +941,18 @@ if (FORMATS["JVC_DSK"]~=null or _OPTIONS["with-tools"]) then } end +-------------------------------------------------- +-- +--@src/lib/formats/jfd_dsk.h,FORMATS["JFD_DSK"] = true +-------------------------------------------------- + +if (FORMATS["JFD_DSK"]~=null or _OPTIONS["with-tools"]) then + files { + MAME_DIR.. "src/lib/formats/jfd_dsk.cpp", + MAME_DIR.. "src/lib/formats/jfd_dsk.h", + } +end + -------------------------------------------------- -- --@src/lib/formats/kaypro_dsk.h,FORMATS["KAYPRO_DSK"] = true diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 8541d09070f..9abd10c5439 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -802,6 +802,7 @@ FORMATS["HECT_TAP"] = true FORMATS["HP_IPC_DSK"] = true FORMATS["IQ151_DSK"] = true FORMATS["ITT3030_DSK"] = true +FORMATS["JFD_DSK"] = true FORMATS["JVC_DSK"] = true FORMATS["KAYPRO_DSK"] = true FORMATS["KC85_DSK"] = true diff --git a/src/lib/formats/jfd_dsk.cpp b/src/lib/formats/jfd_dsk.cpp new file mode 100644 index 00000000000..d0d55bb0c68 --- /dev/null +++ b/src/lib/formats/jfd_dsk.cpp @@ -0,0 +1,365 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/********************************************************************* + + formats/jfd_dsk.c + + JASPP Floppy Disk image format + + JFD file structure + ------------------ + + A JFD file is a gzip compressed version of the original JFD + file. + + Official files should be named "[optional text name] Fxxxxxnn" + (see below for xxxx / nn explanation) eg "Fire & Ice (1995) + (Warner Interactive Entertainment) F1015401" or shortened to + "F1015401" on an Arc that doesn't support long file names. + + Compressed file always starts: + 1F 8B 08 00 00 00 00 00 00 0B EC BD + ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ + | | | | | | | | | | + | | | | | | | | | +- OS + | | | | | | | | +---- xfl + | | | | +--+--+--+------- time + | | | +------------------- gzip flags + | | +---------------------- gzip compression* + | | + +--+------------------------- gzip header + + * Compression method: 8 is the only supported format + + + Original JFD file structure: + + +0 "JFDI" identifier + +4 Min. version of ADFFS required to handle file * 100 + eg 1.25 would be 125 + +8 Memory allocation required to load file in bytes + ie uncompressed file size + +12 Disc sequence number - SSSSnnnn + Where: + SSSS is the number of discs in this set + nnnn is the number of this disc + +16 Game ID number (xxxxx) - official release ID of this + floppy set. Unofficial releases should be an ID of zero + +20 Image version number: VVVwwwww + Where: + VVV - major release version, 0 being initial release + wwwww - minor version, reset to 0 on a major release + and is incremented on each flush / save as + +24 Offset to Track Table, the end of which is denoted by + the start of the Sector Table + +28 Offset to Sector Table, end of which is denoted by + the start of the Data Table + +32 Offset to Data Table + +36 Offset to optional Delta Track Table. Changes to the + Track table are written here post initial release + 0 denotes not present + +40 Offset to optional Delta Sector Table. Changes to the + Sector table are written here post initial release + 0 denotes not present + +44 Offset to optional Delta Data Table. Changes to the + Data table are written here post initial release + 0 denotes not present + +48 Disc title. eg "Fire & Ice (1995) (Warner Interactive + Entertainment) disc 1 of 2", zero terminated. + +304 ... future expansion space (additions in 2.04+) + + +304 Bit flags: + 0 - Disk write protected + 1 - Disk is RW, write delta changes back to JFD + 2 - Protect CMOS required + 3 - Protect Modules required + 4 - Hide Hourglass + 5 - Requires Shift-Break to load + 6 - Remap video memory to 1FFFFFF downwards + + 8 - ARM3 compatible + 9 - ARM250 compatible + 10 - ARM610/710 compatible + 11 - ARM7500 compatible + 12 - StrongArm compatible + 13 = ARMv5/v5/v7 compatible + + 16 - RiscOS 2 compatible + 17 - RiscOS 3.1 compatible + 18 - RiscOS 3.5 compatible + 19 - RiscOS 3.7 compatible + 20 - RiscOS 3.8 / 4.x compatible + 21 - RiscOS 5.x compatible + 22 - RiscOS 6.x compatible + +308 FPS of the original game * 2 (eg for 12.5 FPS use 25) + +309 - 311 reserved + +312 Length of Obey file in bytes + +316 ... future expansion space (currently 0 bytes) + + [Track Table] + +0 Track 0 offset within Sector Table + +4 Track 1 offset within Sector Table + ... + +n*4 Track n offset within Sector Table + n can be any value, although to allow writes should be at + least 160. For reference, APD's are 166 + A blank track is denoted by FFFFFFFF + + [Sector Table] + +0 ttBdnnCs - Sector Header description (see below) + +4 Offset within Data Table of sector data, if this value is + FFFFFFFF no data is associated with the sector. In the + case of a sector with a CRC flag set in C set, the sector + is a stub to produce a specific error. + + .. repeats for all sectors in track, two doubles (ie 8 bytes) per + sector + + +n FFFFFFFF - end of track marker + + The above repeats for all tracks containing sector data. + + + [Data Table] + ... X bytes of sector data in native byte format. + Not necessarily in disc order, as sectors are located + individually during reads. + + [Obey file] + ... Obey file used to boot the floppy + + + Sector Header description: ttBdnnCs + Where: + + tt - time of sector from start of index marker in milliseconds + max being 200 (optional, required for duplicate sectors) + B - Option bits + bit 0 - sector data contains DiscOp 3 data for the track + bit 1 - reserved + bit 2 - reserved + bit 3 - reserved + d - Density value, where: + 1 - single + 2 - double + 4 - quad + 8 - octal + nn - Sector number + C - CRC bits, where: + bit 0 - ID CRC invalid + bit 1 - Data CRC invalid + bit 2 - reserved + bit 3 - Slow sector (read at normal floppy speed) + s - 1772 sector size, where: + 0 - 128 bytes + 1 - 256 bytes + 2 - 512 bytes + 3 - 1024 bytes + +*********************************************************************/ + +#include +#include "formats/jfd_dsk.h" + +static const uint8_t JFD_HEADER[4] = { 'J', 'F', 'D', 'I' }; +static const uint8_t GZ_HEADER[2] = { 0x1f, 0x8b }; + +jfd_format::jfd_format() +{ +} + +const char *jfd_format::name() const +{ + return "jfd"; +} + +const char *jfd_format::description() const +{ + return "JASPP Floppy Disk image"; +} + +const char *jfd_format::extensions() const +{ + return "jfd"; +} + +int jfd_format::identify(io_generic *io, uint32_t form_factor) +{ + uint64_t size = io_generic_size(io); + std::vector img(size); + io_generic_read(io, &img[0], 0, size); + + int err; + std::vector gz_ptr(4); + z_stream d_stream; + + if (!memcmp(&img[0], GZ_HEADER, sizeof(GZ_HEADER))) { + d_stream.zalloc = nullptr; + d_stream.zfree = nullptr; + d_stream.opaque = nullptr; + d_stream.next_in = &img[0]; + d_stream.avail_in = size; + d_stream.next_out = &gz_ptr[0]; + d_stream.avail_out = 4; + + err = inflateInit2(&d_stream, MAX_WBITS | 16); + if (err != Z_OK) return 0; + + err = inflate(&d_stream, Z_SYNC_FLUSH); + if (err != Z_OK) return 0; + + err = inflateEnd(&d_stream); + if (err != Z_OK) return 0; + + img = gz_ptr; + } + + if (!memcmp(&img[0], JFD_HEADER, sizeof(JFD_HEADER))) { + return 100; + } + + return 0; +} + +bool jfd_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) +{ + uint64_t size = io_generic_size(io); + std::vector img(size); + io_generic_read(io, &img[0], 0, size); + + int err; + std::vector gz_ptr; + z_stream d_stream; + int inflate_size = (img[size - 1] << 24) | (img[size - 2] << 16) | (img[size - 3] << 8) | img[size - 4]; + + if (!memcmp(&img[0], GZ_HEADER, sizeof(GZ_HEADER))) { + gz_ptr.resize(inflate_size); + + d_stream.zalloc = nullptr; + d_stream.zfree = nullptr; + d_stream.opaque = nullptr; + d_stream.next_in = &img[0]; + d_stream.avail_in = size; + d_stream.next_out = &gz_ptr[0]; + d_stream.avail_out = inflate_size; + + err = inflateInit2(&d_stream, MAX_WBITS | 16); + if (err != Z_OK) { + osd_printf_error("inflateInit2 error: %d\n", err); + return false; + } + err = inflate(&d_stream, Z_FINISH); + if (err != Z_STREAM_END && err != Z_OK) { + osd_printf_error("inflate error: %d\n", err); + return false; + } + err = inflateEnd(&d_stream); + if (err != Z_OK) { + osd_printf_error("inflateEnd error: %d\n", err); + return false; + } + size = inflate_size; + img = gz_ptr; + } + + osd_printf_verbose("jfd_dsk: loading %s\n", &img[48]); + + uint32_t offset_track = little_endianize_int32(*(uint32_t *)(&img[24])); /* Track Table */ + uint32_t offset_sector = little_endianize_int32(*(uint32_t *)(&img[28])); /* Sector Table */ + uint32_t offset_data = little_endianize_int32(*(uint32_t *)(&img[32])); /* Data Table */ + + desc_pc_sector sects[256]; + uint8_t den[256]; + uint8_t spt, ssize; + uint32_t header, discop3; + std::vector track_data; + + int track_count = (offset_sector - offset_track) / 4; + + for (int track = 0; track < track_count; track++) { + uint32_t track_offset = little_endianize_int32(*(uint32_t *)(&img[offset_track + (track * 4)])); + spt = 0; + discop3 = 0; + + if (track_offset == 0xffffffff) /* unformatted track */ + { + den[0] = 2; + sects[0].track = track / 2; + sects[0].head = track % 2; + sects[0].sector = 0; + sects[0].size = 0; + } + else + { + for (int i = 0; i < 256; i++) { + header = little_endianize_int32(*(uint32_t *)(&img[offset_sector + track_offset + (i * 8)])); /* Sector Header */ + if (header == 0xffffffff) + break; + + uint32_t data_offset = little_endianize_int32(*(uint32_t *)(&img[offset_sector + track_offset + (i * 8) + 4])); + + den[i] = (header >> 16) & 0x0f; /* sector density */ + if (den[i] != 2) + { + osd_printf_warning("jfd_dsk: track %d sector %d is %s density, not supported\n", track, i, den[0] == 1 ? "single" : "quad"); + } + if (((header >> 20) & 0x0f) == 0x01) /* DiscOp3 data */ + { + discop3 = little_endianize_int32(*(uint32_t *)(&img[offset_data + data_offset])); + for (int i = 0; i < discop3; i++) + { + mfm_w(track_data, 8, img[offset_data + data_offset + 4 + i]); + } + osd_printf_warning("jfd_dsk: track %d contains DiscOp3 data (@%x), not supported\n", track, offset_data + data_offset); + break; + } + else + { + spt = i + 1; + sects[i].track = track / 2; + sects[i].head = track % 2; + sects[i].sector = (header >> 8) & 0xff; + sects[i].bad_crc = (header >> 4) & 0x02; + sects[i].deleted = false; + ssize = header & 0x03; + sects[i].size = ssize; + if (data_offset != 0xffffffff) + { + sects[i].actual_size = 128 << ssize; + sects[i].data = &img[offset_data + data_offset]; + } + else + { + sects[i].actual_size = 0; + } + if (((header >> 24) & 0xff) != 0xff) /* Sector in sector */ + { + osd_printf_warning("jfd_dsk: track %d sector %d specifies time of sector from start of index marker, not supported\n", track, i); + } + } + } + } + + if (discop3) + { + generate_track_from_levels(track / 2, track % 2, track_data, 0, image); + } + else + { + if (den[0] == 1) + build_wd_track_fm(track / 2, track % 2, image, 50000, spt, sects, 10, 40, 10); + else + build_wd_track_mfm(track / 2, track % 2, image, den[0] * 50000, spt, sects, 90, 32, 22); + } + } + image->set_variant(floppy_image::DSDD); + + return true; +} + +bool jfd_format::supports_save() const +{ + return false; +} + +const floppy_format_type FLOPPY_JFD_FORMAT = &floppy_image_format_creator; diff --git a/src/lib/formats/jfd_dsk.h b/src/lib/formats/jfd_dsk.h new file mode 100644 index 00000000000..38374bfb97c --- /dev/null +++ b/src/lib/formats/jfd_dsk.h @@ -0,0 +1,31 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/********************************************************************* + + formats/jfd_dsk.h + + JASPP Floppy Disk image format + +*********************************************************************/ + +#ifndef JFD_DSK_H_ +#define JFD_DSK_H_ + +#include "flopimg.h" + +class jfd_format : public floppy_image_format_t { +public: + jfd_format(); + + virtual const char *name() const override; + virtual const char *description() const override; + virtual const char *extensions() const override; + + virtual int identify(io_generic *io, uint32_t form_factor) override; + virtual bool load(io_generic *io, uint32_t form_factor, floppy_image *image) override; + virtual bool supports_save() const override; +}; + +extern const floppy_format_type FLOPPY_JFD_FORMAT; + +#endif diff --git a/src/mame/drivers/aa310.cpp b/src/mame/drivers/aa310.cpp index 69e29745673..de81fa4514a 100644 --- a/src/mame/drivers/aa310.cpp +++ b/src/mame/drivers/aa310.cpp @@ -89,6 +89,7 @@ #include "cpu/arm/arm.h" #include "formats/acorn_dsk.h" #include "formats/apd_dsk.h" +#include "formats/jfd_dsk.h" #include "machine/i2cmem.h" #include "machine/ram.h" #include "machine/wd_fdc.h" @@ -355,7 +356,8 @@ INPUT_PORTS_END FLOPPY_FORMATS_MEMBER( aa310_state::floppy_formats ) FLOPPY_ACORN_ADFS_NEW_FORMAT, FLOPPY_ACORN_ADFS_OLD_FORMAT, - FLOPPY_APD_FORMAT + FLOPPY_APD_FORMAT, + FLOPPY_JFD_FORMAT FLOPPY_FORMATS_END static SLOT_INTERFACE_START( aa310_floppies ) -- cgit v1.2.3