summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/formats/ti99_dsk.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/formats/ti99_dsk.cpp')
-rw-r--r--src/lib/formats/ti99_dsk.cpp208
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;