diff options
Diffstat (limited to 'src/lib/formats/ti99_dsk.cpp')
-rw-r--r-- | src/lib/formats/ti99_dsk.cpp | 208 |
1 files changed, 111 insertions, 97 deletions
diff --git a/src/lib/formats/ti99_dsk.cpp b/src/lib/formats/ti99_dsk.cpp index b248c9dd594..4cca5bdb996 100644 --- a/src/lib/formats/ti99_dsk.cpp +++ b/src/lib/formats/ti99_dsk.cpp @@ -1,4 +1,4 @@ -// license:BSD-3-Clause +// license:LGPL-2.1+ // copyright-holders:Michael Zapf /********************************************************************* @@ -17,7 +17,7 @@ bytes long. The most common formats are 9 sectors per track, single-sided, 40 tracks, which yields 90 KiB of sector data (known as SSSD), and 18 sectors per track, double-sided, and 40 tracks, which is 360 KiB (known as - DSDD). There are rare occurances of 16 sectors/track + DSDD). There are rare occurrences of 16 sectors/track (prototypical TI double-density controller) and 35 track media. Newer controllers and ROMs allow for up to 36 sectors per track and 80 tracks on both sides, which is 1,44 MiB (DSHD80). @@ -40,31 +40,34 @@ ********************************************************************/ -#include <string.h> -#include <time.h> -#include <assert.h> -#include <iomanip> - -#include "emu.h" // osd_printf_* (in osdcore.h) -#include "imageutl.h" #include "ti99_dsk.h" +#include "imageutl.h" + +#include "ioprocs.h" + +#include "osdcore.h" // osd_printf_* (in osdcore.h) + +#include <cstring> +#include <ctime> +#include <iomanip> #define SECTOR_SIZE 256 -#undef LOG_OUTPUT_FUNC #define LOG_OUTPUT_FUNC osd_printf_info -#define LOG_WARN (1U<<1) // Warnings -#define LOG_HEADER (1U<<2) // Header -#define LOG_SHIFT (1U<<3) // Shift register -#define LOG_INTERLEAVE (1U<<4) // Interleave information -#define LOG_INFO (1U<<5) // Disk info -#define LOG_DETAIL (1U<<6) // Details -#define LOG_TRACK (1U<<7) // Track output +#define LOG_WARN (1U << 1) // Warnings +#define LOG_HEADER (1U << 2) // Header +#define LOG_SHIFT (1U << 3) // Shift register +#define LOG_INTERLEAVE (1U << 4) // Interleave information +#define LOG_INFO (1U << 5) // Disk info +#define LOG_DETAIL (1U << 6) // Details +#define LOG_TRACK (1U << 7) // Track output #define VERBOSE ( LOG_WARN ) -#include "logmacro.h" +#define __EMU_H__ // logmacro wasn't really intended to be used outside stuff that uses libemu +#include "../emu/logmacro.h" + // ==================================================== // Common methods for both formats. @@ -78,13 +81,16 @@ int ti99_floppy_format::get_encoding(int cell_size) /* Load the image from disk and convert it into a sequence of flux levels. */ -bool ti99_floppy_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) +bool ti99_floppy_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { + uint64_t file_size; + if (io.length(file_size)) + return false; + int cell_size = 0; int sector_count = 0; int heads = 0; int log_track_count = 0; - int file_size = io_generic_size(io); bool img_high_tpi = false; bool drive_high_tpi = false; @@ -95,7 +101,7 @@ bool ti99_floppy_format::load(io_generic *io, uint32_t form_factor, floppy_image // (the track count as defined by the file system) determine_sizes(io, cell_size, sector_count, heads, log_track_count); - image->get_maximal_geometry(track_count, head_count); + image.get_maximal_geometry(track_count, head_count); drive_high_tpi = (track_count > 44); // Depends on the image format (SDF or TDF) @@ -209,11 +215,8 @@ bool ti99_floppy_format::load(io_generic *io, uint32_t form_factor, floppy_image /* Save all tracks to the image file. */ -bool ti99_floppy_format::save(io_generic *io, floppy_image *image) +bool ti99_floppy_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, const floppy_image &image) const { - int act_track_size = 0; - - uint8_t bitstream[500000/8]; uint8_t sectordata[9216]; // max size (36*256) int cellsizes[] = { 2000, 4000, 1000, 2000 }; @@ -221,7 +224,7 @@ bool ti99_floppy_format::save(io_generic *io, floppy_image *image) // Do we use double-stepping? // If our image was loaded into a 80-track drive, we will always write 80 tracks. int track_count, head_count; - image->get_maximal_geometry(track_count, head_count); + image.get_maximal_geometry(track_count, head_count); if (track_count > 80) track_count = 80; else @@ -244,13 +247,10 @@ bool ti99_floppy_format::save(io_generic *io, floppy_image *image) for (int track = 0; track < track_count; track++) { // Retrieve the cells from the flux sequence. This also delivers the actual track size. - generate_bitstream_from_track(track, head, cell_size, bitstream, act_track_size, image); - - // Maybe the track has become longer due to moving splices - if (act_track_size > 200000000/cell_size) act_track_size = 200000000/cell_size; + auto bitstream = generate_bitstream_from_track(track, head, cell_size, image); LOGMASKED(LOG_DETAIL, "[ti99_dsk] Getting sectors from track %d, head %d\n", track, head); - seccount = get_sectors(bitstream, act_track_size, encoding, track, head, expected_sectors, sectordata, sector); + seccount = get_sectors(bitstream, encoding, track, head, expected_sectors, sectordata, sector); LOGMASKED(LOG_DETAIL, "[ti99_dsk] Seccount = %d\n", seccount); // We may have more sectors in MFM (18). This is OK in track 0; otherwise we need to restart the process. @@ -329,7 +329,7 @@ enum /* Build a new track from sector contents. */ -void ti99_floppy_format::generate_fm_track_from_sectors(floppy_image *image, uint8_t *sectordata, int sector_count, int *sectornmb, int *secoffset, int track, int trackid, int head) +void ti99_floppy_format::generate_fm_track_from_sectors(floppy_image &image, uint8_t *sectordata, int sector_count, int *sectornmb, int *secoffset, int track, int trackid, int head) { std::vector<uint32_t> buffer; @@ -423,7 +423,7 @@ void ti99_floppy_format::generate_fm_track_from_sectors(floppy_image *image, uin generate_track_from_levels(track, head, buffer, 0, image); } -void ti99_floppy_format::generate_mfm_track_from_sectors(floppy_image *image, uint8_t *sectordata, int sector_count, int *sectornmb, int *secoffset, int track, int trackid, int head) +void ti99_floppy_format::generate_mfm_track_from_sectors(floppy_image &image, uint8_t *sectordata, int sector_count, int *sectornmb, int *secoffset, int track, int trackid, int head) { // MFM16: (80,50,22,50,4e,12) // MFM18/36: (10,30,22,21,4e,12) @@ -562,16 +562,15 @@ enum The sectors are assumed to have a length of 256 byte, and their sequence is stored in the secnumber array. */ -int ti99_floppy_format::get_sectors(const uint8_t *bitstream, int cell_count, int encoding, int track, int head, int sectors, uint8_t *sectordata, int *secnumber) +int ti99_floppy_format::get_sectors(const std::vector<bool> &bitstream, int encoding, int track, int head, int sectors, uint8_t *sectordata, int *secnumber) { int bitpos = 0; int lastpos = 0; int spos = 0; int seccount = 0; uint16_t shift_reg = 0; - int bytepos = 0; uint8_t databyte = 0; - uint8_t curbyte = 0; + [[maybe_unused]] uint8_t curbyte = 0; int rep = 0; int cursect = 0; @@ -582,12 +581,10 @@ int ti99_floppy_format::get_sectors(const uint8_t *bitstream, int cell_count, in int first = (encoding==floppy_image::MFM)? A1IDAM1 : FMIDAM; int state = first; - while (bitpos < cell_count) + while (bitpos < bitstream.size()) { LOGMASKED(LOG_SHIFT, "[ti99_dsk] shift = %04x\n", shift_reg); - shift_reg = (shift_reg << 1) & 0xffff; - if ((bitpos & 0x07)==0) curbyte = bitstream[bytepos++]; - if ((curbyte & 0x80) != 0) shift_reg |= 1; + shift_reg = (shift_reg << 1) | bitstream[bitpos]; if (((bitpos - lastpos) & 1)==0) { @@ -908,24 +905,27 @@ uint8_t ti99_floppy_format::get_data_from_encoding(uint16_t raw) bad sector map, we just check whether there are 3 more sectors and ignore them. */ -const char *ti99_sdf_format::name() const +const char *ti99_sdf_format::name() const noexcept { - return "sdf"; + return "ti99"; } -const char *ti99_sdf_format::description() const +const char *ti99_sdf_format::description() const noexcept { return "TI99 sector dump floppy disk image"; } -const char *ti99_sdf_format::extensions() const +const char *ti99_sdf_format::extensions() const noexcept { return "dsk"; } -int ti99_sdf_format::identify(io_generic *io, uint32_t form_factor) +int ti99_sdf_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { - uint64_t file_size = io_generic_size(io); + uint64_t file_size; + if (io.length(file_size)) + return 0; + int vote = 0; // Adding support for another sector image format which adds 768 bytes @@ -943,7 +943,7 @@ int ti99_sdf_format::identify(io_generic *io, uint32_t form_factor) case 368640: // DSDD case 737280: // DSDD80 case 1474560: // DSQD - vote = 50; + vote = FIFID_SIZE; break; default: vote = 0; @@ -954,13 +954,13 @@ int ti99_sdf_format::identify(io_generic *io, uint32_t form_factor) { // Read first sector (Volume Information Block) ti99vib vib; - io_generic_read(io, &vib, 0, sizeof(ti99vib)); + /*auto const [err, actual] =*/ read_at(io, 0, &vib, sizeof(ti99vib)); // FIXME: check for errors and premature EOF // Check from contents if ((vib.id[0]=='D')&&(vib.id[1]=='S')&&(vib.id[2]=='K')) { LOGMASKED(LOG_INFO, "[ti99_dsk] Found formatted SDF disk medium\n"); - vote = 100; + vote |= FIFID_SIGN; } else { @@ -971,10 +971,14 @@ int ti99_sdf_format::identify(io_generic *io, uint32_t form_factor) return vote; } -void ti99_sdf_format::determine_sizes(io_generic *io, int& cell_size, int& sector_count, int& heads, int& tracks) +void ti99_sdf_format::determine_sizes(util::random_read &io, int& cell_size, int& sector_count, int& heads, int& tracks) const { - uint64_t file_size = io_generic_size(io); - ti99vib vib; + uint64_t file_size; + if (io.length(file_size)) + { + cell_size = sector_count = heads = tracks = 0; + return; + } cell_size = 0; sector_count = 0; @@ -987,7 +991,8 @@ void ti99_sdf_format::determine_sizes(io_generic *io, int& cell_size, int& secto file_size -= 768; // Read first sector - io_generic_read(io, &vib, 0, sizeof(ti99vib)); + ti99vib vib; + /*auto const [err, actual] =*/ read_at(io, 0, &vib, sizeof(ti99vib)); // FIXME: check for errors and premature EOF // Check from contents if ((vib.id[0]=='D')&&(vib.id[1]=='S')&&(vib.id[2]=='K')) @@ -1061,18 +1066,18 @@ void ti99_sdf_format::determine_sizes(io_generic *io, int& cell_size, int& secto } } -int ti99_sdf_format::get_track_size(int sector_count) +int ti99_sdf_format::get_track_size(int sector_count) const { return sector_count * SECTOR_SIZE; } -void ti99_sdf_format::load_track(io_generic *io, uint8_t *sectordata, int *sector, int *secoffset, int head, int track, int sectorcount, int trackcount) +void ti99_sdf_format::load_track(util::random_read &io, uint8_t *sectordata, int *sector, int *secoffset, int head, int track, int sectorcount, int trackcount) const { // Calculate the track offset from the beginning of the image file int logicaltrack = (head==0)? track : (2*trackcount - track - 1); int position = logicaltrack * get_track_size(sectorcount); - io_generic_read(io, sectordata, position, sectorcount*SECTOR_SIZE); + /*auto const [err, actual] =*/ read_at(io, position, sectordata, sectorcount*SECTOR_SIZE); // FIXME: check for errors and premature EOF // Interleave and skew int interleave = 7; @@ -1110,7 +1115,7 @@ void ti99_sdf_format::load_track(io_generic *io, uint8_t *sectordata, int *secto /* For debugging. Outputs the byte array in a xxd-like way. */ -void ti99_floppy_format::dumpbytes(uint8_t* trackdata, int length) +void ti99_floppy_format::dumpbytes(const uint8_t* trackdata, int length) { for (int i=0; i < length; i+=16) { @@ -1118,7 +1123,7 @@ void ti99_floppy_format::dumpbytes(uint8_t* trackdata, int length) } } -std::string ti99_floppy_format::dumpline(uint8_t* line, int address) const +std::string ti99_floppy_format::dumpline(const uint8_t* line, int address) { std::ostringstream stream; stream << std::hex << std::setfill('0') << std::setw(6) << unsigned(address); @@ -1140,24 +1145,22 @@ std::string ti99_floppy_format::dumpline(uint8_t* line, int address) const Write the data to the disk. We have a list of sector positions, so we just need to go through that list and save each sector in the sector data. */ -void ti99_sdf_format::write_track(io_generic *io, uint8_t *sectordata, int *sector, int track, int head, int sector_count, int track_count) +void ti99_sdf_format::write_track(util::random_read_write &io, uint8_t *sectordata, int *sector, int track, int head, int sector_count, int track_count) const { - uint8_t* buf; - int logicaltrack = head * track_count; logicaltrack += ((head&1)==0)? track : (track_count - 1 - track); int trackoffset = logicaltrack * sector_count * SECTOR_SIZE; for (int i=0; i < sector_count; i++) { - buf = sectordata + i * SECTOR_SIZE; + uint8_t const *const buf = sectordata + i * SECTOR_SIZE; LOGMASKED(LOG_DETAIL, "[ti99_dsk] Writing sector %d (offset %06x)\n", sector[i], sector[i] * SECTOR_SIZE); - io_generic_write(io, buf, trackoffset + sector[i] * SECTOR_SIZE, SECTOR_SIZE); + /*auto const [err, actual] =*/ write_at(io, trackoffset + sector[i] * SECTOR_SIZE, buf, SECTOR_SIZE); // FIXME: check for errors } } -const floppy_format_type FLOPPY_TI99_SDF_FORMAT = &floppy_image_format_creator<ti99_sdf_format>; +const ti99_sdf_format FLOPPY_TI99_SDF_FORMAT; /* Track Dump Format @@ -1198,17 +1201,17 @@ const floppy_format_type FLOPPY_TI99_SDF_FORMAT = &floppy_image_format_creator<t (Head,Track): (0,0) (0,1) (0,2) ... (0,38) (0,39) (1,0) (1,1) ... (1,39) */ -const char *ti99_tdf_format::name() const +const char *ti99_tdf_format::name() const noexcept { return "tdf"; } -const char *ti99_tdf_format::description() const +const char *ti99_tdf_format::description() const noexcept { return "TI99 track dump floppy disk image"; } -const char *ti99_tdf_format::extensions() const +const char *ti99_tdf_format::extensions() const noexcept { return "dsk,dtk"; } @@ -1216,7 +1219,7 @@ const char *ti99_tdf_format::extensions() const /* Determine whether the image file can be interpreted as a track dump */ -int ti99_tdf_format::identify(io_generic *io, uint32_t form_factor) +int ti99_tdf_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { int vote = 0; uint8_t fulltrack[6872]; @@ -1232,14 +1235,14 @@ int ti99_tdf_format::identify(io_generic *io, uint32_t form_factor) // Do we have a plausible image size? From the size alone we only give a 50 percent vote. if (sector_count != 0) - vote = 50; + vote = FIFID_SIZE; if (vote > 0) { LOGMASKED(LOG_INFO, "[ti99_dsk] Image file length matches TDF\n"); // Fetch track 0 - io_generic_read(io, fulltrack, 0, get_track_size(sector_count)); + /*auto const [err, actual] =*/ read_at(io, 0, fulltrack, get_track_size(sector_count)); // FIXME: check for errors and premature EOF if (sector_count == 9) { @@ -1275,7 +1278,7 @@ int ti99_tdf_format::identify(io_generic *io, uint32_t form_factor) else { LOGMASKED(LOG_INFO, "[ti99_dsk] Image format complies with TDF\n"); - vote = 100; + vote |= FIFID_STRUCT; } } else LOGMASKED(LOG_INFO, "[ti99_dsk] Disk image is not a TDF image\n"); @@ -1283,52 +1286,63 @@ int ti99_tdf_format::identify(io_generic *io, uint32_t form_factor) } /* - Find the proper format for a given image file. + Find the proper format for a given image file. Tracks are counted per side. + Note that only two formats are actually compatible with the PC99 emulator. */ -void ti99_tdf_format::determine_sizes(io_generic *io, int& cell_size, int& sector_count, int& heads, int& tracks) +void ti99_tdf_format::determine_sizes(util::random_read &io, int& cell_size, int& sector_count, int& heads, int& tracks) const { - uint64_t file_size = io_generic_size(io); - heads = 2; // TDF only supports two-sided recordings - tracks = 40; + uint64_t file_size; + if (io.length(file_size)) + { + cell_size = sector_count = heads = tracks = 0; + return; + } + // LOGMASKED(LOG_INFO, "[ti99_dsk] Image size = %ld\n", file_size); // doesn't compile switch (file_size) { - case 260240: // used in PC99 - cell_size = 4000; + case 260240: // used in PC99 sector_count = 9; + tracks = 40; break; - case 491520: // 320K HX5102 - cell_size = 2000; + case 491520: // 320K HX5102 sector_count = 16; + tracks = 40; break; - case 549760: // used in PC99 - cell_size = 2000; + case 549760: // used in PC99 sector_count = 18; + tracks = 40; break; + case 1003520: + sector_count = 36; + tracks = 40; + break; + case 520480: - cell_size = 4000; sector_count = 9; + tracks = 80; break; case 983040: - cell_size = 2000; sector_count = 16; tracks = 80; break; case 1099520: - cell_size = 2000; sector_count = 18; tracks = 80; break; case 2007040: - cell_size = 1000; - sector_count = 18; + sector_count = 36; tracks = 80; break; + default: cell_size = 0; sector_count = 0; - break; + return; } + + heads = 2; // TDF only supports two-sided recordings + cell_size = (sector_count <= 9)? 4000 : ((sector_count <= 18)? 2000 : 1000); } /* @@ -1337,13 +1351,13 @@ void ti99_tdf_format::determine_sizes(io_generic *io, int& cell_size, int& secto track from scratch. TDF is not as flexible as it suggests, it does not allow different gap lengths and so on. */ -void ti99_tdf_format::load_track(io_generic *io, uint8_t *sectordata, int *sector, int *secoffset, int head, int track, int sectorcount, int trackcount) +void ti99_tdf_format::load_track(util::random_read &io, uint8_t *sectordata, int *sector, int *secoffset, int head, int track, int sectorcount, int trackcount) const { - uint8_t fulltrack[6872]; // space for a full TDF track + uint8_t fulltrack[12544]; // space for a full TDF track // Read beginning of track 0. We need this to get the first gap, according // to the format - io_generic_read(io, fulltrack, 0, 100); + read_at(io, 0, fulltrack, 100); // FIXME: check for errors and premature EOF int offset = 0; int tracksize = get_track_size(sectorcount); @@ -1384,7 +1398,7 @@ void ti99_tdf_format::load_track(io_generic *io, uint8_t *sectordata, int *secto int base = (head * trackcount + track) * tracksize; int position = 0; - io_generic_read(io, fulltrack, base, tracksize); + read_at(io, base, fulltrack, tracksize); // FIXME: check for errors and premature EOF for (int i=0; i < sectorcount; i++) { @@ -1432,9 +1446,9 @@ void ti99_tdf_format::load_track(io_generic *io, uint8_t *sectordata, int *secto need the sector contents and the sector sequence, which are passed via sectordata, sector, and sector_count. */ -void ti99_tdf_format::write_track(io_generic *io, uint8_t *sectordata, int *sector, int track, int head, int sector_count, int track_count) +void ti99_tdf_format::write_track(util::random_read_write &io, uint8_t *sectordata, int *sector, int track, int head, int sector_count, int track_count) const { - uint8_t trackdata[14000]; + uint8_t trackdata[12544]; int offset = ((track_count * head) + track) * get_track_size(sector_count); int a1 = 0; @@ -1486,10 +1500,10 @@ void ti99_tdf_format::write_track(io_generic *io, uint8_t *sectordata, int *sect for (int i=0; i < param[WGAP3]; i++) trackdata[pos++] = param[WGAPBYTE]; } for (int i=0; i < param[WGAP4]; i++) trackdata[pos++] = param[WGAPBYTE]; - io_generic_write(io, trackdata, offset, get_track_size(sector_count)); + /*auto const [err, actual] =*/ write_at(io, offset, trackdata, get_track_size(sector_count)); // FIXME: check for errors } -int ti99_tdf_format::get_track_size(int sector_count) +int ti99_tdf_format::get_track_size(int sector_count) const { switch (sector_count) { @@ -1505,4 +1519,4 @@ int ti99_tdf_format::get_track_size(int sector_count) return 0; } -const floppy_format_type FLOPPY_TI99_TDF_FORMAT = &floppy_image_format_creator<ti99_tdf_format>; +const ti99_tdf_format FLOPPY_TI99_TDF_FORMAT; |