summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Michael Zapf <Michael.Zapf@mizapf.de>2018-08-03 22:01:39 +0200
committer Michael Zapf <Michael.Zapf@mizapf.de>2018-08-03 22:01:39 +0200
commit801935badbc9cec92690559942edb23a19711234 (patch)
tree0772ed19953be6aae27f3d2a1397c2f2882d988b
parent9768491e279f766401e06c06c9ae148c7d615a81 (diff)
ti99: Fixed long-standing TDF bug; added support for 16-sector formats
-rw-r--r--src/lib/formats/ti99_dsk.cpp1576
-rw-r--r--src/lib/formats/ti99_dsk.h30
2 files changed, 971 insertions, 635 deletions
diff --git a/src/lib/formats/ti99_dsk.cpp b/src/lib/formats/ti99_dsk.cpp
index 1b198295947..394bb85f1ce 100644
--- a/src/lib/formats/ti99_dsk.cpp
+++ b/src/lib/formats/ti99_dsk.cpp
@@ -1,44 +1,49 @@
// license:BSD-3-Clause
// copyright-holders:Michael Zapf
/*********************************************************************
- *
- * TI-99 family disk images
- *
- * used by TI-99/4, TI-99/4A, TI-99/8, SGCPU ("TI-99/4P"), and Geneve
- *
- * Sector Dump Format, aka "v9t9" format
- * customized wd177x_format
- * no track data
- *
- * Track Dump Format, aka "pc99" format
- * contains all track information, but no clock patterns
- *
- * Both formats allow for a broad range of medium sizes. All sectors are 256
- * 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 8/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).
- *
- * Double stepping
- * --------------
- * When using a 40-track disk in an 80-track drive, it seems as if each
- * track appears twice in sequence (0,0,1,1,2,2,...,39,39).
- * The system will write to each second track and leave the others untouched.
- * When we write back that image, there is no simple way to know that
- * the 80 tracks are in fact doubled 40 tracks. We will actually write
- * all 80 tracks, doubling the size of the image file. This disk image will
- * now become unusable in a 40-track drive - which is exactly what happens in reality.
- *
- * Michael Zapf, July 2015
- *
- ********************************************************************/
+
+ TI-99 family disk images
+
+ used by TI-99/4, TI-99/4A, TI-99/8, SGCPU ("TI-99/4P"), and Geneve
+
+ Sector Dump Format, aka "v9t9" format
+ customized wd177x_format
+ no track data
+
+ Track Dump Format, aka "pc99" format
+ contains all track information, but no clock patterns
+
+ Both formats allow for a broad range of medium sizes. All sectors are 256
+ 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
+ (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).
+
+ Double stepping
+ --------------
+ When using a 40-track disk in an 80-track drive, it seems as if each
+ track appears twice in sequence (0,0,1,1,2,2,...,39,39).
+ The system will write to each second track and leave the others untouched.
+ When we write back that image, there is no simple way to know that
+ the 80 tracks are in fact doubled 40 tracks. We will actually write
+ all 80 tracks, doubling the size of the image file. This disk image will
+ now become unusable in a 40-track drive - which is exactly what happens in reality.
+
+ Michael Zapf, July 2015
+ Updated August 2018
+
+ TODO:
+ - Support for 77 track images for HX5102
+
+********************************************************************/
#include <string.h>
#include <time.h>
#include <assert.h>
+#include <iomanip>
#include "emu.h" // osd_printf_* (in osdcore.h)
#include "imageutl.h"
@@ -46,46 +51,25 @@
#define SECTOR_SIZE 256
-// Debugging
-#define TRACE 0
+#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 VERBOSE ( LOG_WARN )
+
+#include "logmacro.h"
// ====================================================
// Common methods for both formats.
// ====================================================
-/*
- Find out whether there are IDAMs and DAMs (without having clock bits).
- As said above, let's not spend too much effort allowing format deviations.
- If the image does not exactly adhere to the format, give up.
-*/
-bool ti99_floppy_format::check_for_address_marks(uint8_t* trackdata, int encoding)
-{
- int i=0;
-
- if (encoding==floppy_image::FM)
- {
- // Check 5 sectors of track 0
- while (i < 5)
- {
- if (trackdata[16 + 6 + i*334] != 0xfe) break;
- if (trackdata[16 + 30 + i*334] != 0xfb && trackdata[16 + 30 + i*334] != 0xf8) break;
- i++;
- }
- }
- else
- {
- // Try MFM
- i = 0;
- while (i < 5)
- {
- if (trackdata[40 + 13 + i*340] != 0xfe) break;
- if (trackdata[40 + 57 + i*340] != 0xfb && trackdata[40 + 57 + i*340] != 0xf8) break;
- i++;
- }
- }
- return (i==5);
-}
-
int ti99_floppy_format::get_encoding(int cell_size)
{
return (cell_size==4000)? floppy_image::FM : floppy_image::MFM;
@@ -100,18 +84,30 @@ bool ti99_floppy_format::load(io_generic *io, uint32_t form_factor, floppy_image
int sector_count = 0;
int heads = 0;
int log_track_count = 0;
- determine_sizes(io, cell_size, sector_count, heads, log_track_count);
+ int file_size = io_generic_size(io);
- if (cell_size == 0) return false;
+ bool img_high_tpi = false;
+ bool drive_high_tpi = false;
+ bool skip_track = false;
+ int track_count, head_count;
- // Be ready to hold a track of up to 36 sectors (with gaps and marks)
- uint8_t trackdata[13000];
+ // Get information about cell size, sector count, and logical track count
+ // (the track count as defined by the file system)
+ determine_sizes(io, cell_size, sector_count, heads, log_track_count);
- int maxtrack, maxheads;
- image->get_maximal_geometry(maxtrack, maxheads);
+ image->get_maximal_geometry(track_count, head_count);
+ drive_high_tpi = (track_count > 44);
- int file_size = io_generic_size(io);
- int track_size = get_track_size(cell_size, sector_count);
+ // Depends on the image format (SDF or TDF)
+ int track_size = get_track_size(sector_count);
+
+ // Adding support for a variant of the sector image format which adds 768 bytes
+ // as a bad sector map. Only applies for SDF; TDF will not yield that result
+ if (((file_size - 768) % (SECTOR_SIZE*360)) == 0)
+ {
+ LOGMASKED(LOG_INFO, "[ti99_dsk] Stripping map of bad sectors at image end\n");
+ file_size -= 768;
+ }
// Problem: If the disk is improperly formatted, the track count will be
// wrong. For instance, a disk could be reformatted to single-side.
@@ -119,379 +115,426 @@ bool ti99_floppy_format::load(io_generic *io, uint32_t form_factor, floppy_image
if ((heads==1) && (file_size > track_size*40))
heads = 2;
- int phys_track_count = file_size / (track_size*heads);
+ // TI formats are known as having a constant track size, so the physical
+ // track count on the medium can easily be calculated.
+ int img_track_count = file_size / (track_size*heads);
+ img_high_tpi = (img_track_count > 44);
// Some disks are known to have an incomplete header.
// PASCAL disks have a track count of 0.
- if (log_track_count==0) log_track_count = phys_track_count;
+ if (log_track_count == 0) log_track_count = img_track_count;
- if (TRACE) osd_printf_info("ti99_dsk: logical tracks = %d, physical tracks = %d\n", log_track_count, phys_track_count);
+ LOGMASKED(LOG_INFO, "[ti99_dsk] logical tracks = %d, image tracks = %d, drive track_count = %d\n", log_track_count, img_track_count, track_count);
- if (phys_track_count > maxtrack)
+ // If the floppy disk has 80 tracks but the drive has 40 tracks, force
+ // the floppy to 40 tracks (will make it unreadable)
+ if (img_high_tpi && !drive_high_tpi)
{
- osd_printf_error("ti99_dsk: Floppy disk has too many tracks for this drive.\n");
- return false;
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Floppy disk has too many tracks for this drive, will skip every second track.\n");
+ img_high_tpi = false;
+ skip_track = true; // only read the even numbered tracks
}
// Is this the first time that this disk is read in an 80-track drive?
- bool double_step = ((log_track_count * 2) <= maxtrack);
- bool first_time_double = ((phys_track_count * 2) <= maxtrack);
+ bool double_step = (drive_high_tpi && log_track_count <= 44);
+ bool first_time_double = (drive_high_tpi && !img_high_tpi);
- if (first_time_double)
- {
- osd_printf_warning("ti99_dsk: 40-track image in an 80-track drive. On save, image size will double.\n");
- }
+ if (double_step)
+ LOGMASKED(LOG_INFO, "[ti99_dsk] Applying double stepping\n");
- int acttrack;
+ if (first_time_double)
+ LOGMASKED(LOG_WARN, "[ti99_dsk] 40-track image in an 80-track drive. On save, image size will double.\n");
+ int trackid;
// Read the image
+ uint8_t sectordata[36*SECTOR_SIZE];
+ int sectornmb[36];
+ int sectoroff[36];
+
for (int head=0; head < heads; head++)
{
- for (int track=0; track < phys_track_count; track++)
+ for (int track=0; track < img_track_count; track++)
{
- if (double_step && !first_time_double) acttrack = track/2;
- else acttrack = track;
+ LOGMASKED(LOG_TRACK, "[ti99_dsk] Reading track %d, head %d\n", track, head);
+ if (double_step && !first_time_double) trackid = track/2;
+ else trackid = track;
- load_track(io, trackdata, head, track, acttrack, sector_count, phys_track_count, cell_size);
+ load_track(io, sectordata, sectornmb, sectoroff, head, track, sector_count, img_track_count);
- if (first_time_double)
+ if (double_step)
{
- // Create two tracks from each medium track. This reflects the
- // fact that the drive head will find the same data after
- // a single step
- if (get_encoding(cell_size)==floppy_image::FM)
+ if (first_time_double)
{
- generate_track_fm(track*2, head, cell_size, trackdata, image);
- generate_track_fm(track*2+1, head, cell_size, trackdata, image);
+ // Create two tracks from each medium track. This reflects the
+ // fact that the drive head will find the same data after
+ // a single step
+ if (sector_count < 10)
+ {
+ generate_fm_track_from_sectors(image, sectordata, sector_count, sectornmb, sectoroff, track*2, trackid, head);
+ generate_fm_track_from_sectors(image, sectordata, sector_count, sectornmb, sectoroff, track*2+1, trackid, head);
+ }
+ else
+ {
+ generate_mfm_track_from_sectors(image, sectordata, sector_count, sectornmb, sectoroff, track*2, trackid, head);
+ generate_mfm_track_from_sectors(image, sectordata, sector_count, sectornmb, sectoroff, track*2+1, trackid, head);
+ }
}
else
{
- generate_track_mfm(track*2, head, cell_size, trackdata, image);
- generate_track_mfm(track*2+1, head, cell_size, trackdata, image);
+ // Reading 80 track image for double stepping
+ if (sector_count < 10)
+ generate_fm_track_from_sectors(image, sectordata, sector_count, sectornmb, sectoroff, track, trackid, head);
+ else
+ generate_mfm_track_from_sectors(image, sectordata, sector_count, sectornmb, sectoroff, track, trackid, head);
}
}
else
{
+ // No double stepping now, but maybe the image was created under double stepping
+ int drivetrack = (skip_track)? track / 2 : track;
+
// Normal tracks
- if (get_encoding(cell_size)==floppy_image::FM)
- generate_track_fm(track, head, cell_size, trackdata, image);
+ if (sector_count < 10)
+ generate_fm_track_from_sectors(image, sectordata, sector_count, sectornmb, sectoroff, drivetrack, drivetrack, head);
else
- generate_track_mfm(track, head, cell_size, trackdata, image);
+ generate_mfm_track_from_sectors(image, sectordata, sector_count, sectornmb, sectoroff, drivetrack, drivetrack, head);
}
+ if (skip_track) track++;
}
}
return true;
}
+/*
+ Save all tracks to the image file.
+*/
bool ti99_floppy_format::save(io_generic *io, floppy_image *image)
{
int act_track_size = 0;
uint8_t bitstream[500000/8];
- uint8_t trackdata[9216]; // max size
+ uint8_t sectordata[9216]; // max size (36*256)
int cellsizes[] = { 2000, 4000, 1000, 2000 };
// Do we use double-stepping?
// If our image was loaded into a 80-track drive, we will always write 80 tracks.
- int maxtrack, maxheads;
- image->get_maximal_geometry(maxtrack, maxheads);
+ int track_count, head_count;
+ image->get_maximal_geometry(track_count, head_count);
- if (maxtrack > 80) maxtrack = 80;
+ if (track_count > 80) track_count = 80;
else
{
- if (maxtrack > 35 && maxtrack < 80) maxtrack = 40;
- else maxtrack = 35;
+ if (track_count > 35 && track_count < 80) track_count = 40;
+ else track_count = 35;
}
int attempt = 0;
int sector[36];
- int maxsect = 18;
- bool write = true;
+ int seccount = 0;
- // We expect a bitstream of length 50000 for FM and 100000 for MFM
- for(int head=0; head < 2; head++)
+ int head = 0;
+ int cell_size = cellsizes[0];
+ int encoding = get_encoding(cell_size);
+ int expected_sectors = (encoding==floppy_image::MFM)? 16:9;
+
+ while (head < 2)
{
- int track = 0;
- while (track < maxtrack)
+ for (int track = 0; track < track_count; track++)
{
- int cell_size = cellsizes[attempt];
- int encoding = get_encoding(cell_size);
- int track_size = get_track_size(cell_size, 36); // max number of sectors
-
- // Retrieve the cells from the flux sequence
+ // 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;
- int marks = decode_bitstream(bitstream, trackdata, sector, act_track_size, encoding, (encoding==floppy_image::FM)? 0xff:0x4e, track_size);
+ 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);
+ LOGMASKED(LOG_DETAIL, "[ti99_dsk] Seccount = %d\n", seccount);
- if (track==0)
+ // We may have more sectors in MFM (18). This is OK in track 0; otherwise we need to restart the process.
+ if (track==0 && head==0)
{
- if (head==0)
+ if (seccount==18 && expected_sectors==16)
{
- // Find the highest sector in the track
- // This is only needed for the SDF format
- int i=35;
- while (i>=0 && sector[i]==-1) i--;
+ LOGMASKED(LOG_INFO, "[ti99_dsk] Using full 18 sectors/track format for MFM\n");
+ expected_sectors=18;
+ }
+ }
+ else
+ {
+ if (seccount==18 && expected_sectors==16)
+ {
+ // This happens when we assumed 16 sectors/track up to here
+ // and now the track uses 18 tracks. We need to start over,
+ // assuming 18 sectors/track, and adding empty sectors
+ // where necessary
+ head = -1;
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Tracks with variable sector count; assuming 18 sectors/track\n");
+ break;
+ }
+ }
- if (i>18) maxsect = 36;
- else
+ if (seccount < 3 && track == 0)
+ {
+ if (head == 0)
+ {
+ // Bad cell size.
+ LOGMASKED(LOG_DETAIL, "[ti99_dsk] Decoding with cell size %d failed.\n", cell_size);
+ attempt++;
+ if (attempt == 4)
{
- if (i>16) maxsect = 18;
- else
- {
- if (i>9) maxsect = 16;
- else maxsect = 9;
- }
+ LOGMASKED(LOG_INFO, "[ti99_dsk] Unsupported cell size or unformatted medium.\n");
+ return false;
}
- if (TRACE) osd_printf_info("ti99_dsk: Sectors/track: %d\n", maxsect);
-
- // We try different cell sizes until we find a fitting size.
- // If this fails, we fall back to a size of 2000 ns
- // The criterion for a successful decoding is that we find at least
- // 6 ID or data address marks on the track. It is highly unlikely
- // to find so many marks with a wrong cell size.
- if (marks < 6 && attempt < 3)
+ else
{
- if (TRACE) osd_printf_verbose("ti99_dsk: Decoding with cell size %d failed.\n", cell_size);
- attempt++;
- write = false;
+ // Pick a new cell size
+ cell_size = cellsizes[attempt];
+ encoding = get_encoding(cell_size);
+ expected_sectors = (encoding==floppy_image::MFM)? 16:9;
}
- else write = true;
+ head = -1;
+ break;
}
else
{
- if (marks < 6)
+ // head 0 already done, but head 1 failing
+ if (min_heads()==1)
{
- // There are no address marks on track 0, head 1.
- if (min_heads()==1)
- {
- if (TRACE) osd_printf_info("ti99_dsk: We don't have a second side and the format allows for single-sided recording.\n");
- return true;
- }
- else
- {
- osd_printf_warning("ti99_dsk: No second side, but this format requires two-sided recording. Saving empty tracks.\n");
- }
+ LOGMASKED(LOG_INFO, "[ti99_dsk] Saving as single-sided\n");
+ break;
}
- }
- }
-
- if (write)
- {
- if (TRACE)
- {
- if (head == 0 && track == 0)
+ else
{
- if (marks >=6) { if (TRACE) osd_printf_info("ti99_dsk: Decoding with cell size %d successful.\n", cell_size); }
- else osd_printf_info("ti99_dsk: No address marks found on track 0. Assuming FM format.\n");
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Saving empty tracks on second side\n");
}
}
- // Save to the file
- write_track(io, trackdata, sector, track, head, maxsect, maxtrack, track_size);
- track++;
}
+
+ // Save to the file
+ write_track(io, sectordata, sector, track, head, seccount, track_count);
}
+ head++;
}
-
return true;
}
-void ti99_floppy_format::generate_track_fm(int track, int head, int cell_size, uint8_t* trackdata, floppy_image *image)
+enum
+{
+ GAP0 = 0, GAP1, GAP2, GAP3, GAPBYTE, SYNC
+};
+
+/*
+ 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)
{
- int track_size_cells = 200000000/cell_size;
std::vector<uint32_t> buffer;
- // The TDF has a long track lead-out that makes the track length sum up
- // to 3253; this is too long for the number of cells in the real track.
- // This was either an error when that format was defined,
- // or it is due to the fact that when reading a track via
- // the controller, after the track has been read, the controller still
- // delivers some FF values until it times out.
+ const int param[6] = { 10, 26, 11, 28, 0xff, 6 };
- // Accordingly, we limit the track size to cell_number / 16,
- // which means 3125 for FM
- // This also means that Gap 4 (lead-out) is not 231 bytes long but only 103 bytes
+ // cell size in ns
+ const int cell_size = 4000;
+ const int cell_count = 200000000/cell_size;
- int track_size = track_size_cells / 16;
+ int sectorpartlen = 2*param[SYNC] + 10 + param[GAP2] + SECTOR_SIZE + param[GAP3];
+ int tracklen = param[GAP1] + sector_count * sectorpartlen;
+ if (param[GAP0]!=0) tracklen += param[GAP0] + param[SYNC] + 1;
+ // The remaining bytes are filled with the gap byte as gap 4.
+ int gap4 = cell_count/16 - tracklen;
- short crc1, crc2, found_crc;
- int start = 16;
+ short crc = 0;
- if (check_for_address_marks(trackdata, floppy_image::FM)==false)
- {
- if (head==0 && track==0) osd_printf_warning("ti99_dsk: Cannot find FM address marks on track %d, head %d; likely broken or unformatted.\n", track, head);
- return;
- }
+ // Create Gap 0 and Index AM
+ for (int i=0; i < param[GAP0]; i++)
+ fm_w(buffer, 8, param[GAPBYTE], cell_size);
+
+ for (int i=0; i < param[SYNC]; i++)
+ fm_w(buffer, 8, 0x00, cell_size);
+
+ raw_w(buffer, 16, 0xf77a, cell_size); // IXAM
- // Found a track; we now know where the address marks are:
- // (start is positioned at the pre-id gap)
- // IDAM: start + 6 + n*334
- // DAM: start + 30 + n*334
- // and the CRCs are at
- // CRC1: start + 11 + n*334
- // CRC2: start + 287 + n*334
- // If the CRCs are F7F7, we recalculate them.
- for (int i=0; i < track_size; i++)
+ // and Gap 1
+ for (int i=0; i < param[GAP1]; i++)
+ fm_w(buffer, 8, param[GAPBYTE], cell_size);
+
+ // For each sector
+ for (int j=0; j < sector_count; j++)
{
- if (((i-start-6)%334==0) && (i < start + 9*334))
+ // If the sector is not available, create an empty space of zeros
+ if (sectornmb[j]==-1)
{
- // IDAM
- raw_w(buffer, 16, 0xf57e, cell_size);
+ for (int i=0; i < sectorpartlen; i++)
+ raw_w(buffer, 16, 0x0000, cell_size);
}
else
{
- if (((i-start-30)%334==0) && (i < start + 9*334))
+ // Sync
+ for (int i=0; i < param[SYNC]; i++)
+ fm_w(buffer, 8, 0x00, cell_size);
+ raw_w(buffer, 16, 0xf57e, cell_size); // IDAM
+
+ crc = ccitt_crc16_one(0xffff, 0xfe);
+
+ // Header
+ fm_w(buffer, 8, trackid, cell_size);
+ crc = ccitt_crc16_one(crc, trackid);
+ fm_w(buffer, 8, head, cell_size);
+ crc = ccitt_crc16_one(crc, head);
+ fm_w(buffer, 8, sectornmb[j], cell_size);
+ crc = ccitt_crc16_one(crc, sectornmb[j]);
+ fm_w(buffer, 8, 0x01, cell_size);
+ crc = ccitt_crc16_one(crc, 0x01);
+ // CRC
+ fm_w(buffer, 8, (crc>>8)&0xff, cell_size);
+ fm_w(buffer, 8, crc&0xff, cell_size);
+
+ // Gap 2
+ for (int i=0; i < param[GAP2]; i++)
+ fm_w(buffer, 8, param[GAPBYTE], cell_size);
+ // Sync
+ for (int i=0; i < param[SYNC]; i++)
+ fm_w(buffer, 8, 0x00, cell_size);
+ raw_w(buffer, 16, 0xf56f, cell_size); // DAM
+ crc = ccitt_crc16_one(0xffff, 0xfb);
+
+ // Sector contents
+ for (int k=0; k < SECTOR_SIZE; k++)
{
- // DAM
- // FB (1111010101101111) = normal data, F8 (1111010101101010)= deleted data
- raw_w(buffer, 16, (trackdata[i]==0xf8)? 0xf56a : 0xf56f, cell_size);
- }
- else
- {
- if (((i-start-11)%334==0) && (i < start + 9*334))
- {
- // CRC1
- crc1 = ccitt_crc16(0xffff, &trackdata[i-5], 5);
- found_crc = (trackdata[i]<<8 | trackdata[i+1]);
- if ((found_crc & 0xffff) == 0xf7f7)
- {
- // PC99 format: no real CRC; replace it
- // Also, when converting from SDF we let this method create the proper CRC.
- // osd_printf_verbose("Warning: PC99 format using pseudo CRC1; replace by %04x\n", crc1);
- trackdata[i] = (crc1 >> 8) & 0xff;
- trackdata[i+1] = crc1 & 0xff;
- found_crc = crc1;
- }
- if (crc1 != found_crc)
- {
- osd_printf_error("ti99_dsk: Warning: CRC1 does not match (track=%d, head=%d). Found = %04x, calc = %04x\n", track, head, found_crc& 0xffff, crc1& 0xffff);
- }
- }
- else
- {
- if (((i-start-287)%334==0) && (i < start + 9*334))
- {
- // CRC2
- crc2 = ccitt_crc16(0xffff, &trackdata[i-SECTOR_SIZE-1], SECTOR_SIZE+1);
- found_crc = (trackdata[i]<<8 | trackdata[i+1]);
- if ((found_crc & 0xffff) == 0xf7f7)
- {
- // PC99 format: no real CRC; replace it
- // osd_printf_verbose("Warning: PC99 format using pseudo CRC2; replace by %04x\n", crc2);
- trackdata[i] = (crc2 >> 8) & 0xff;
- trackdata[i+1] = crc2 & 0xff;
- found_crc = crc2;
- }
- if (crc2 != found_crc)
- {
- osd_printf_error("ti99_dsk: Warning: CRC2 does not match (track=%d, head=%d). Found = %04x, calc = %04x\n", track, head, found_crc& 0xffff, crc2& 0xffff);
- }
- }
- }
- fm_w(buffer, 8, trackdata[i], cell_size);
+ fm_w(buffer, 8, sectordata[secoffset[j]+k], cell_size);
+ crc = ccitt_crc16_one(crc, sectordata[secoffset[j]+k]);
}
+ // CRC
+ fm_w(buffer, 8, (crc>>8)&0xff, cell_size);
+ fm_w(buffer, 8, crc&0xff, cell_size);
+
+ // Gap 3
+ for (int i=0; i < param[GAP3]; i++)
+ fm_w(buffer, 8, param[GAPBYTE], cell_size);
}
}
+ // and fill the remaining bytes with gap bytes
+ for (int i=0; i < gap4; i++)
+ fm_w(buffer, 8, param[GAPBYTE], cell_size);
+
generate_track_from_levels(track, head, buffer, 0, image);
}
-void ti99_floppy_format::generate_track_mfm(int track, int head, int cell_size, uint8_t* trackdata, floppy_image *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)
{
- int track_size_cells = 200000000/cell_size;
+ // MFM16: (80,50,22,50,4e,12)
+ // MFM18/36: (10,30,22,21,4e,12)
+ // A1: 0x4489 01 00 01 00 10 *00 10 01
+ // C2: 0x5224 01 01 00 10 *00 10 01 00
std::vector<uint32_t> buffer;
- // See above
- // We limit the track size to cell_number / 16, which means 6250 for MFM
- // Here, Gap 4 is actually only 90 bytes long
- // (not 712 as specified in the TDF format)
- int track_size = track_size_cells / 16;
+ const int mfm16param[7] = { 80, 50, 22, 50, 0x4e, 12 };
+ const int mfm18param[7] = { 10, 30, 22, 21, 0x4e, 12 };
+ const int *param = mfm18param;
- short crc1, crc2, found_crc;
- int start = 40;
+ // cell size in ns
+ int cell_size = 2000;
- if (check_for_address_marks(trackdata, floppy_image::MFM)==false)
+ if (sector_count < 30)
{
- if (track==0 && head==0) osd_printf_error("ti99_dsk: Cannot find MFM address marks on track %d, head %d; likely broken or unformatted.\n", track, head);
- return;
+ cell_size = 2000;
+ if (sector_count == 16) param = mfm16param;
}
+ else cell_size = 1000;
+
+ int cell_count = 200000000/cell_size;
+
+ int sectorpartlen = 2*param[SYNC] + 16 + param[GAP2] + SECTOR_SIZE + param[GAP3];
+ int tracklen = param[GAP1] + sector_count * sectorpartlen;
+ if (param[GAP0]!=0) tracklen += param[GAP0] + param[SYNC] + 4;
+ // The remaining bytes are filled with the gap byte as gap 4.
+ int gap4 = cell_count/16 - tracklen;
+
+ short crc = 0;
+
+ // Create Gap 0 and Index AM
+ for (int i=0; i < param[GAP0]; i++)
+ mfm_w(buffer, 8, param[GAPBYTE], cell_size);
- // Found a track; we now know where the address marks are:
- // (start is positioned at the pre-id gap)
- // IDAM: start + 10 + n*340 (starting at first a1)
- // DAM: start + 54 + n*340 (starting at first a1)
- // and the CRCs are at
- // CRC1: start + 18 + n*340
- // CRC2: start + 314 + n*334
+ for (int i=0; i < param[SYNC]; i++)
+ mfm_w(buffer, 8, 0x00, cell_size);
- for (int i=0; i < track_size; i++)
+ for (int i=0; i < 3; i++)
+ raw_w(buffer, 16, 0x5224, cell_size);
+ mfm_w(buffer, 8, 0xfc, cell_size);
+
+ // and Gap 1
+ for (int i=0; i < param[GAP1]; i++)
+ mfm_w(buffer, 8, param[GAPBYTE], cell_size);
+
+ // For each sector
+ for (int j=0; j < sector_count; j++)
{
- if (((i-start-10)%340==0) && (i < start + 18*340))
+ // If the sector is not available, create an empty space of zeros
+ if (sectornmb[j]==-1)
{
- // IDAM
- for (int j=0; j < 3; j++)
- raw_w(buffer, 16, 0x4489, cell_size); // 3 times A1
- i += 2;
+ for (int i=0; i < sectorpartlen; i++)
+ raw_w(buffer, 16, 0x0000, cell_size);
}
else
{
- if (((i-start-54)%340==0) && (i < start + 18*340))
+ // Sync
+ for (int i=0; i < param[SYNC]; i++)
+ mfm_w(buffer, 8, 0x00, cell_size);
+ // IDAM
+ for (int i=0; i < 3; i++)
+ raw_w(buffer, 16, 0x4489, cell_size);
+ mfm_w(buffer, 8, 0xfe, cell_size);
+
+ crc = 0xb230; // pre-init including IDAM
+
+ // Header
+ mfm_w(buffer, 8, trackid, cell_size);
+ crc = ccitt_crc16_one(crc, trackid);
+ mfm_w(buffer, 8, head, cell_size);
+ crc = ccitt_crc16_one(crc, head);
+ mfm_w(buffer, 8, sectornmb[j], cell_size);
+ crc = ccitt_crc16_one(crc, sectornmb[j]);
+ mfm_w(buffer, 8, 0x01, cell_size);
+ crc = ccitt_crc16_one(crc, 0x01);
+ // CRC
+ mfm_w(buffer, 8, (crc>>8)&0xff, cell_size);
+ mfm_w(buffer, 8, crc&0xff, cell_size);
+
+ // Gap 2
+ for (int i=0; i < param[GAP2]; i++)
+ mfm_w(buffer, 8, param[GAPBYTE], cell_size);
+ // Sync
+ for (int i=0; i < param[SYNC]; i++)
+ mfm_w(buffer, 8, 0x00, cell_size);
+
+ // DAM
+ for (int i=0; i < 3; i++)
+ raw_w(buffer, 16, 0x4489, cell_size);
+ mfm_w(buffer, 8, 0xfb, cell_size);
+ crc = 0xe295; // pre-init including DAM
+
+ // Sector contents
+ for (int k=0; k < SECTOR_SIZE; k++)
{
- // DAM
- for (int j=0; j < 3; j++)
- raw_w(buffer, 16, 0x4489, cell_size); // 3 times A1
- i += 2;
- }
- else
- {
- if (((i-start-18)%340==0) && (i < start + 18*340))
- {
- // CRC1
- // The CRC also covers the three A1 bytes!
- crc1 = ccitt_crc16(0xffff, &trackdata[i-8], 8);
- found_crc = (trackdata[i]<<8 | trackdata[i+1]);
- if ((found_crc & 0xffff) == 0xf7f7)
- {
- // PC99 format: pseudo CRC; replace it
- // osd_printf_verbose("Warning: PC99 format using pseudo CRC1; replace by %04x\n", crc1);
- trackdata[i] = (crc1 >> 8) & 0xff;
- trackdata[i+1] = crc1 & 0xff;
- found_crc = crc1;
- }
- if (crc1 != found_crc)
- {
- osd_printf_error("ti99_dsk: Warning: CRC1 does not match (track=%d, head=%d). Found = %04x, calc = %04x\n", track, head, found_crc & 0xffff, crc1& 0xffff);
- }
- }
- else
- {
- if ((i > 340) && ((i-start-314)%340==0) && (i < start + 18*340))
- {
- // CRC2
- crc2 = ccitt_crc16(0xffff, &trackdata[i-SECTOR_SIZE-4], SECTOR_SIZE+4);
- found_crc = (trackdata[i]<<8 | trackdata[i+1]);
- if ((found_crc & 0xffff) == 0xf7f7)
- {
- // PC99 format: pseudo CRC; replace it
- // osd_printf_verbose("Warning: PC99 format using pseudo CRC2; replace by %04x\n", crc2);
- trackdata[i] = (crc2 >> 8) & 0xff;
- trackdata[i+1] = crc2 & 0xff;
- found_crc = crc2;
- }
- if (crc2 != found_crc)
- {
- osd_printf_error("ti99_dsk: Warning: CRC2 does not match (track=%d, head=%d). Found = %04x, calc = %04x\n", track, head, found_crc& 0xffff, crc2& 0xffff);
- }
- }
- }
- mfm_w(buffer, 8, trackdata[i], cell_size);
+ mfm_w(buffer, 8, sectordata[secoffset[j]+k], cell_size);
+ crc = ccitt_crc16_one(crc, sectordata[secoffset[j]+k]);
}
+ // CRC
+ mfm_w(buffer, 8, (crc>>8)&0xff, cell_size);
+ mfm_w(buffer, 8, crc&0xff, cell_size);
+
+ // Gap 3
+ for (int i=0; i < param[GAP3]; i++)
+ mfm_w(buffer, 8, param[GAPBYTE], cell_size);
}
}
+ // and fill the remaining bytes with gap bytes
+ for (int i=0; i < gap4; i++)
+ mfm_w(buffer, 8, param[GAPBYTE], cell_size);
generate_track_from_levels(track, head, buffer, 0, image);
}
@@ -500,44 +543,57 @@ void ti99_floppy_format::generate_track_mfm(int track, int head, int cell_size,
enum
{
FMIDAM,
+ A1IDAM1,
+ A1IDAM2,
+ A1IDAM3,
MFMIDAM,
+ MFMIDENT,
HEADER,
FMDAM,
+ A1DAM1,
+ A1DAM2,
+ A1DAM3,
MFMDAM,
DATA
};
/*
- Decodes the bitstream into a TDF track image.
- Returns the number of detected marks.
+ Retrieve all sectors from the track, given as a bitstream.
+ The sectors are assumed to have a length of 256 byte, and their sequence
+ is stored in the secnumber array.
*/
-int ti99_floppy_format::decode_bitstream(const uint8_t *bitstream, uint8_t *trackdata, int* sector, int cell_count, int encoding, uint8_t gapbytes, int track_size)
+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 databytes = 0;
- int a1count = 0;
+ int bitpos = 0;
int lastpos = 0;
- int headerbytes = 0;
- int curpos = 0;
- uint8_t curbyte = 0;
+ int spos = 0;
+ int seccount = 0;
uint16_t shift_reg = 0;
- int tpos = 0;
- int pos = 0;
- int state;
- int marks = 0;
- int current_sector = 0;
-
- // Init track
- memset(trackdata, 0x00, track_size);
+ int bytepos = 0;
+ uint8_t databyte = 0;
+ uint8_t curbyte = 0;
+ int rep = 0;
+ int cursect = 0;
- for (int i=0; i < 36; i++) sector[i] = -1;
+ // An array of flags (max 32), set for each found sector
+ uint32_t foundsectors = 0;
- state = (encoding==floppy_image::MFM)? MFMIDAM : FMIDAM;
+ int maxsect = (encoding==floppy_image::MFM)? 18 : 9;
+ int first = (encoding==floppy_image::MFM)? A1IDAM1 : FMIDAM;
+ int state = first;
- while (pos < cell_count && tpos < track_size)
+ while (bitpos < cell_count)
{
+ LOGMASKED(LOG_SHIFT, "[ti99_dsk] shift = %04x\n", shift_reg);
shift_reg = (shift_reg << 1) & 0xffff;
- if ((pos & 0x07)==0) curbyte = bitstream[curpos++];
+ if ((bitpos & 0x07)==0) curbyte = bitstream[bytepos++];
if ((curbyte & 0x80) != 0) shift_reg |= 1;
+
+ if (((bitpos - lastpos) & 1)==0)
+ {
+ databyte = (databyte << 1) & 0xff;
+ databyte |= shift_reg & 1;
+ }
curbyte <<= 1;
switch (state)
@@ -545,157 +601,273 @@ int ti99_floppy_format::decode_bitstream(const uint8_t *bitstream, uint8_t *trac
case FMIDAM:
if (shift_reg == 0xf57e)
{
- marks++;
- // Found a header
- headerbytes = 5;
- // Create GAP0 at the beginning or GAP3 later
- if (tpos==0)
- tpos += 16;
- else
- for (int i=0; i < 45; i++) trackdata[tpos++] = gapbytes;
-
- // IDAM sync bytes
- tpos += 6;
- trackdata[tpos++] = 0xfe;
+ // IDAM found
+ LOGMASKED(LOG_DETAIL, "[ti99_dsk] IDAM found at %05x\n", bitpos);
state = HEADER;
- lastpos = pos;
+ lastpos = bitpos;
+ rep = 0;
}
break;
-
- case MFMIDAM:
- // Count three subsequent A1
+ case A1IDAM1:
if (shift_reg == 0x4489)
{
- if (lastpos > 0)
+ state = A1IDAM2;
+ lastpos = bitpos;
+ }
+ break;
+ case A1IDAM2:
+ case A1IDAM3:
+ if (bitpos - lastpos == 16)
+ {
+ if (shift_reg == 0x4489)
{
- if (pos - lastpos == 16) a1count++;
- else a1count = 1;
+ state = (state==A1IDAM2)? A1IDAM3 : MFMIDENT;
}
- else a1count = 1;
-
- lastpos = pos;
+ else
+ {
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Error: Missing A1, not a header at %05x\n", bitpos);
+ state = A1IDAM1;
+ }
+ lastpos = bitpos;
}
- if (a1count == 3)
+ break;
+
+ case MFMIDENT:
+ if (bitpos - lastpos == 16)
{
- marks++;
- // Found a header
- headerbytes = 6;
- // Create GAP0 at the beginning or GAP3 later
- if (tpos==0)
- for (int i=0; i < 40; i++) trackdata[tpos++] = gapbytes;
+ if (databyte != 0xfe)
+ {
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Error: Ident (found) = %02x, expected = fe; skipping header\n", databyte);
+ state = A1IDAM1;
+ }
else
- for (int i=0; i < 24; i++) trackdata[tpos++] = gapbytes;
-
- // IDAM sync bytes
- tpos += 10;
- state = HEADER;
- trackdata[tpos++] = 0xa1;
- trackdata[tpos++] = 0xa1;
- trackdata[tpos++] = 0xa1;
+ {
+ rep = 0;
+ state = HEADER;
+ }
+ lastpos = bitpos;
}
break;
-
case HEADER:
- if (pos - lastpos == 16)
+ // Get the header, store the sector number, and report any
+ // unexpected contents in the other fields. When invalid, skip
+ // that header.
+ if (bitpos - lastpos == 16)
{
- // Transfer header bytes
- trackdata[tpos] = get_data_from_encoding(shift_reg);
+ LOGMASKED(LOG_HEADER, "[ti99_dsk] Header byte: %02x\n", databyte);
- if (headerbytes == 3) current_sector = trackdata[tpos];
- tpos++;
-
- if (headerbytes == 0)
+ switch (rep)
{
- state = (encoding==floppy_image::MFM)? MFMDAM : FMDAM;
- a1count = 0;
+ case 0:
+ if (databyte > 79)
+ {
+ // Illegal cylinder, ignore this header.
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Error: Track (found) = %d, must be less than 80; skipping header.\n", databyte);
+ state = (encoding==floppy_image::MFM)? A1IDAM1 : FMIDAM;
+ break;
+ }
+ // Consider double stepping
+ if (databyte != track && databyte != track/2)
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Warning: Track (found) = %d, assuming %d\n", databyte, track);
+ break;
+ case 1:
+ if (databyte > 2)
+ {
+ // Illegal head, ignore this header.
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Error: Head (found) = %d, must be less than 2; skipping header.\n", databyte);
+ state = (encoding==floppy_image::MFM)? A1IDAM1 : FMIDAM;
+ break;
+ }
+ if (databyte != head)
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Warning: Head (found) = %d, assuming = %d\n", databyte, head);
+ break;
+ case 2:
+ if (databyte >= maxsect)
+ {
+ // Illegal sector, ignore this header.
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Error: Sector number (found) = %d, must be less than %d; skipping header\n", databyte, maxsect);
+ state = (encoding==floppy_image::MFM)? A1IDAM1 : FMIDAM;
+ }
+ else cursect = databyte;
+
+ if ((foundsectors & (1 << cursect)) != 0)
+ {
+ // Sector already appeared; discard it
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Error: Sector number (found) = %d already appeared; skipping header\n", databyte);
+ state = (encoding==floppy_image::MFM)? A1IDAM1 : FMIDAM;
+ }
+ break;
+ case 3:
+ if (databyte != 1)
+ {
+ // Illegal sector, ignore this header.
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Error: Sector size (found) = %d, must be 1; skipping header\n", databyte);
+ state = (encoding==floppy_image::MFM)? A1IDAM1 : FMIDAM;
+ }
+ else
+ {
+ state = (encoding==floppy_image::MFM)? A1DAM1 : FMDAM;
+ }
+ rep = -1;
+ break;
}
- else headerbytes--;
- lastpos = pos;
+ rep++;
+ lastpos = bitpos;
}
break;
-
case FMDAM:
+ if (bitpos - lastpos > 500)
+ {
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Error: DAM too far away, skipping header\n");
+ state = FMIDAM;
+ break;
+ }
+ if (shift_reg == 0xf57e)
+ {
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Error: Expected DAM, found next IDAM; skipping header\n");
+ state = HEADER; // continue with reading the header
+ lastpos = bitpos;
+ break;
+ }
if (shift_reg == 0xf56a || shift_reg == 0xf56f)
{
- if (pos - lastpos > 400)
+ // DAM found
+ LOGMASKED(LOG_DETAIL, "[ti99_dsk] DAM found: %04x\n", bitpos);
+ state = DATA;
+ rep = 0;
+ lastpos = bitpos;
+ secnumber[seccount++] = cursect;
+ // Keep track of the found sectors
+ foundsectors |= (1 << cursect);
+ }
+ break;
+ case A1DAM1:
+ if (bitpos - lastpos > 1000)
+ {
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Error: A1/DAM too far away, skipping header\n");
+ state = A1IDAM1;
+ break;
+ }
+ if (shift_reg == 0x4489)
+ {
+ state = A1DAM2;
+ lastpos = bitpos;
+ }
+ break;
+ case A1DAM2:
+ case A1DAM3:
+ if (bitpos - lastpos == 16)
+ {
+ if (shift_reg == 0x4489)
{
- // Too far apart
- state = FMIDAM;
- // Abort this sector, skip to the next
- tpos += 321;
- a1count = 1;
- break;
+ state = (state==A1DAM2)? A1DAM3 : MFMDAM;
}
- marks++;
- // Add GAP2 and DAM sync
- for (int i=0; i < 11; i++) trackdata[tpos++] = 0xff;
- tpos += 6;
- state = DATA;
- databytes = 257;
- trackdata[tpos++] = (shift_reg==0xf56a)? 0xf8 : 0xfb;
- lastpos = pos;
- sector[current_sector] = tpos;
+ else
+ {
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Error: Missing A1, not a data field at %05x\n", bitpos);
+ state = A1IDAM1;
+ }
+ lastpos = bitpos;
}
break;
case MFMDAM:
- // Count three subsequent A1
- if (shift_reg == 0x4489)
+ if (bitpos - lastpos == 16)
{
- if (pos - lastpos > 560)
+ if (databyte == 0xfe)
{
- // Too far apart
- state = MFMIDAM;
- // Abort this sector, skip to the next
- tpos += 320;
- a1count = 1;
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Error: Expected DAM, found next IDAM; skipping header\n");
+ state = HEADER; // continue with reading the header
+ lastpos = bitpos;
break;
}
- if (lastpos > 0)
+ if (databyte != 0xf8 && databyte != 0xfb)
{
- if (pos - lastpos == 16) a1count++;
- else a1count = 1;
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Error: DAM (found) = %02x, expected = f8 or fb; skipping header\n", databyte);
+ state = HEADER; // continue with reading the header
}
- else a1count = 1;
-
- lastpos = pos;
- }
- if (a1count == 3)
- {
- marks++;
- // Add GAP2 and DAM sync
- for (int i=0; i < 22; i++) trackdata[tpos++] = gapbytes;
- tpos += 12;
- trackdata[tpos++] = 0xa1;
- trackdata[tpos++] = 0xa1;
- trackdata[tpos++] = 0xa1;
- state = DATA;
- databytes = 258;
- sector[current_sector] = tpos+1;
+ else
+ {
+ state = DATA;
+ secnumber[seccount++] = cursect;
+ // Keep track of the found sectors
+ foundsectors |= (1 << cursect);
+ }
+ rep = 0;
+ lastpos = bitpos;
}
break;
case DATA:
- if (pos - lastpos == 16)
+ if (bitpos - lastpos == 16)
{
- // Ident byte
- trackdata[tpos++] = get_data_from_encoding(shift_reg);
- if (databytes > 0) databytes--;
+ if (rep < 256)
+ {
+ sectordata[spos++] = databyte;
+ }
else
{
- state = (encoding==floppy_image::MFM)? MFMIDAM : FMIDAM;
- a1count = 0;
+ state = first;
}
- lastpos = pos;
+ rep++;
+ lastpos = bitpos;
}
break;
}
- pos++;
+ bitpos++;
+ }
+
+ // We start with 9 sectors (FM) and 16 sectors (MFM)
+ // If we have 18 sectors in MFM, and we have track 0/head 0, then accept
+ // it, and switch to expected = 18.
+ // If we have expected=16 and find sectors past sector 15,
+ // and track!=0 or head!=0, then stop
+ // the creation and restart with expected=18.
+
+ // We now add all remaining, unfound sectors to complete the track
+ // If all sectors were found, this loop is skipped
+ int j = 0;
+ int actual_sectors = seccount;
+ LOGMASKED(LOG_DETAIL, "[ti99_dsk] Sector map: %08x\n", foundsectors);
+
+ // Don't try to fill the first track
+ if (track==0 && head==0 && seccount<3)
+ return seccount;
+
+ if (seccount < sectors)
+ {
+ LOGMASKED(LOG_INFO, "[ti99_dsk] %d missing sectors in track %d, head %d, adding as empty\n", sectors-seccount, track, head);
+ }
+
+ for (int i = seccount; i < sectors; i++)
+ {
+ // Search the next missing sector number. All sectors that were
+ // found have a 1 at their bit position in foundsectors.
+ while ((foundsectors & 1)!=0 && j < sectors)
+ {
+ foundsectors >>= 1;
+ j++;
+ }
+ LOGMASKED(LOG_INFO, "[ti99_dsk] add empty sector %d\n", j);
+ // Add the sector
+ secnumber[seccount++] = j;
+ foundsectors >>= 1;
+ j++;
+ // Create an empty sector
+ for (int k=0; k < 256; k++)
+ sectordata[spos++] = 0xe5;
}
- return marks;
+
+ LOGMASKED(LOG_INTERLEAVE, "[ti99_dsk] End of track reached, sectors = %d\n", seccount);
+ LOGMASKED(LOG_INTERLEAVE, "[ti99_dsk] Sector sequence: ");
+ for (int i=0; i < seccount; i++)
+ LOGMASKED(LOG_INTERLEAVE, "%d ", secnumber[i]);
+ LOGMASKED(LOG_INTERLEAVE, "\n");
+ return actual_sectors;
}
+
uint8_t ti99_floppy_format::get_data_from_encoding(uint16_t raw)
{
return (raw & 0x4000 ? 0x80 : 0x00) |
@@ -758,36 +930,26 @@ int ti99_sdf_format::identify(io_generic *io, uint32_t form_factor)
// Adding support for another sector image format which adds 768 bytes
// as a bad sector map
- if ((file_size / SECTOR_SIZE) % 10 == 3)
- {
- if (TRACE) osd_printf_info("ti99_dsk: Stripping map of bad sectors at image end\n");
- file_size -= SECTOR_SIZE*3;
- }
-
- // Formats with 9 or 18 sectors per track (multiples of SSSD)
- // 40-track formats: SSSD/9/40 (1), DSSD/9/40 (2), SSDD/18/40 (2), DSDD/18/40 (4)
- // 80-track formats: SSSD/9/80 (2), DSSD/9/80 (4), SSDD/18/80 (4), DSDD/18/80,(8)
- // High density: DSQD/36/80 (16) (experimental)
+ if (((file_size - 768) % (SECTOR_SIZE*360)) == 0)
+ file_size -= 768;
// All formats apply for 5.25" and 3.5" form factors
-
- // Default formats (when the geometry cannot be determined from the VIB)
- // (1) -> SSSD
- // (2) -> DSSD
- // (4) -> DSDD
- // (8) -> DSDD80
- // (16) -> DSQD
-
- if ((file_size % 92160)==0)
+ switch (file_size)
{
- int multiple = file_size/92160;
- if ((multiple == 1) || (multiple == 2) || (multiple == 4) || (multiple == 8) || (multiple == 16)) vote = 50;
+ case 92160: // SSSD
+ case 163840: // SSDD16
+ case 184320: // DSSD
+ case 327680: // DSDD16
+ case 368640: // DSDD
+ case 737280: // DSDD80
+ case 1474560: // DSQD
+ vote = 50;
+ break;
+ default:
+ vote = 0;
+ break;
}
- // Formats with 16 sectors per track (rare, SSDD/16/40, DSDD/16/40).
- if (file_size == 163840) vote = 50;
- if (file_size == 327680) vote = 50;
-
if (vote > 0)
{
// Read first sector (Volume Information Block)
@@ -797,15 +959,15 @@ int ti99_sdf_format::identify(io_generic *io, uint32_t form_factor)
// Check from contents
if ((vib.id[0]=='D')&&(vib.id[1]=='S')&&(vib.id[2]=='K'))
{
- if (TRACE) osd_printf_info("ti99_dsk: Found formatted SDF disk medium\n");
+ LOGMASKED(LOG_INFO, "[ti99_dsk] Found formatted SDF disk medium\n");
vote = 100;
}
else
{
- if (TRACE) osd_printf_info("ti99_dsk: No valid VIB found; disk may be unformatted\n");
+ LOGMASKED(LOG_INFO, "[ti99_dsk] No valid VIB found; disk may be unformatted\n");
}
}
- else if (TRACE) osd_printf_info("ti99_dsk: Disk image is not a SDF image\n");
+ else LOGMASKED(LOG_INFO, "[ti99_dsk] Disk image is not a SDF image\n");
return vote;
}
@@ -820,8 +982,9 @@ void ti99_sdf_format::determine_sizes(io_generic *io, int& cell_size, int& secto
bool have_vib = false;
- // See above
- if ((file_size / SECTOR_SIZE) % 10 == 3) file_size -= SECTOR_SIZE*3;
+ // Remove the bad sector map
+ if (((file_size - 768) % (SECTOR_SIZE*360)) == 0)
+ file_size -= 768;
// Read first sector
io_generic_read(io, &vib, 0, sizeof(ti99vib));
@@ -841,7 +1004,7 @@ void ti99_sdf_format::determine_sizes(io_generic *io, int& cell_size, int& secto
if (vib.density < 4) cell_size = 2000;
else cell_size = 1000;
}
- if (TRACE) osd_printf_info("ti99_dsk: VIB says that this disk is %s density with %d sectors per track, %d tracks, and %d heads\n", (cell_size==4000)? "single": ((cell_size==2000)? "double" : "high"), sector_count, vib.tracksperside, heads);
+ LOGMASKED(LOG_INFO, "[ti99_dsk] VIB says that this disk is %s density with %d sectors per track, %d tracks, and %d heads\n", (cell_size==4000)? "single": ((cell_size==2000)? "double" : "high"), sector_count, vib.tracksperside, heads);
have_vib = true;
tracks = vib.tracksperside;
}
@@ -881,169 +1044,119 @@ void ti99_sdf_format::determine_sizes(io_generic *io, int& cell_size, int& secto
{
if (sector_count == 16 && sector_count1 == 18)
{
- osd_printf_warning("ti99_dsk: Warning: Invalid 16-sector format. Assuming 18 sectors.\n");
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Warning: Invalid 16-sector format. Assuming 18 sectors.\n");
sector_count = 18;
}
else
{
if (heads == 2 && ((cell_size1 != cell_size) || (sector_count1 != sector_count)))
- osd_printf_warning("ti99_dsk: Warning: Disk image size does not correspond with format information in VIB.\n");
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Warning: Disk image size does not correspond with format information in VIB.\n");
}
}
else
{
- heads = (file_size < 100000)? 1 : 2; // for SSSD
+ heads = (file_size < 180000)? 1 : 2; // for SSSD, SSDD16
cell_size = cell_size1;
sector_count = sector_count1;
}
}
-int ti99_sdf_format::get_track_size(int cell_size, int sector_count)
+int ti99_sdf_format::get_track_size(int sector_count)
{
return sector_count * SECTOR_SIZE;
}
-/*
- Load a SDF image track. Essentially, we want to end up in the same
- kind of track image as with the TDF, so the easiest thing is to produce
- a TDF image track from the sectors and process them as if it came from TDF.
-
- acttrack is the actual track when double stepping is used and changes
- every two physical tracks.
-*/
-void ti99_sdf_format::load_track(io_generic *io, uint8_t *trackdata, int head, int track, int acttrack, int sectorcount, int trackcount, int cellsize)
+void ti99_sdf_format::load_track(io_generic *io, uint8_t *sectordata, int *sector, int *secoffset, int head, int track, int sectorcount, int trackcount)
{
- bool fm = (cellsize==4000);
- int tracksize = sectorcount * SECTOR_SIZE;
-
// Calculate the track offset from the beginning of the image file
- int logicaltrack = head * trackcount;
- logicaltrack += ((head&1)==0)? track : (trackcount - 1 - track);
-
- // Interleave and skew
- int interleave = fm? 4 : 5;
- int skew = fm? 6 : 0;
+ int logicaltrack = (head==0)? track : (2*trackcount - track - 1);
+ int position = logicaltrack * get_track_size(sectorcount);
- int secsize = fm? 334 : 340;
- int position = 0;
- int count = 0;
+ io_generic_read(io, sectordata, position, sectorcount*SECTOR_SIZE);
- memset(trackdata, 0x00, 9216);
+ // Interleave and skew
+ int interleave = 7;
+ if (sectorcount == 18) interleave = 11;
+ else if (sectorcount == 16) interleave = 9;
- int secno = 0;
- secno = (acttrack * skew) % sectorcount;
+ int skew = (sectorcount<10)? 6 : 0;
- // Gap 1
- int gap1 = fm? 16 : 40;
- for (int i=0; i < gap1; i++) trackdata[position+i] = fm? 0x00 : 0x4e;
+ int secno = (track * skew) % sectorcount;
+ // Construct the sector sequence
for (int i=0; i < sectorcount; i++)
{
- position = secno * secsize + gap1;
- // Sync
- count = fm? 6 : 10;
- while (count-- > 0) trackdata[position++] = 0x00;
-
- if (!fm)
+ sector[i] = secno;
+ secoffset[i] = secno*SECTOR_SIZE;
+ secno = (secno + interleave) % sectorcount;
+ }
+ if (track==0 && head==0)
+ {
+ dumpbytes(sectordata, sectorcount*SECTOR_SIZE);
+ LOGMASKED(LOG_TRACK, "[ti99_dsk] Sectors = ");
+ for (int i=0; i < sectorcount; i++)
{
- trackdata[position++] = 0xa1;
- trackdata[position++] = 0xa1;
- trackdata[position++] = 0xa1;
+ LOGMASKED(LOG_TRACK, "%02d ", sector[i]);
}
- trackdata[position++] = 0xfe; // IDAM / ident
-
- // Header
- trackdata[position++] = acttrack;
- trackdata[position++] = head;
- trackdata[position++] = i;
- trackdata[position++] = 1;
-
- trackdata[position++] = 0xf7;
- trackdata[position++] = 0xf7;
-
- // Gap 2
- count = fm? 11 : 22;
- while (count-- > 0) trackdata[position++] = fm? 0xff : 0x4e;
-
- // Sync
- count = fm? 6 : 12;
- while (count-- > 0) trackdata[position++] = 0x00;
-
- if (!fm)
+ LOGMASKED(LOG_TRACK, "\n[ti99_dsk] Offset = ");
+ for (int i=0; i < sectorcount; i++)
{
- trackdata[position++] = 0xa1;
- trackdata[position++] = 0xa1;
- trackdata[position++] = 0xa1;
+ LOGMASKED(LOG_TRACK, "%04x ", secoffset[i]);
}
- trackdata[position++] = 0xfb;
-
- io_generic_read(io, trackdata + position, logicaltrack * tracksize + i*SECTOR_SIZE, SECTOR_SIZE);
-
- position += SECTOR_SIZE;
- trackdata[position++] = 0xf7;
- trackdata[position++] = 0xf7;
-
- // Gap 3
- count = fm? 45 : 24;
- while (count-- > 0) trackdata[position++] = fm? 0xff : 0x4e;
- secno = (secno + interleave) % sectorcount;
+ LOGMASKED(LOG_TRACK, "\n");
}
-
- // Gap 4
- count = fm? 231 : 712;
- position = sectorcount * secsize + gap1;
- while (count-- > 0) trackdata[position++] = fm? 0xff : 0x4e;
-
- // if (head==0 && track==0) showtrack(trackdata, 9216);
}
/*
For debugging. Outputs the byte array in a xxd-like way.
*/
-void ti99_floppy_format::showtrack(uint8_t* trackdata, int length)
+void ti99_floppy_format::dumpbytes(uint8_t* trackdata, int length)
{
for (int i=0; i < length; i+=16)
{
- osd_printf_verbose("%07x: ", i);
- for (int j=0; j < 16; j++)
- {
- osd_printf_verbose("%02x", trackdata[i+j]);
- if ((j&1)==1) osd_printf_verbose(" ");
- }
- osd_printf_verbose(" ");
- for (int j=0; j < 16; j++)
- {
- if (trackdata[i+j] >= 32 && trackdata[i+j]<128) osd_printf_verbose("%c", trackdata[i+j]);
- else osd_printf_verbose(".");
- }
- osd_printf_verbose("\n");
+ LOGMASKED(LOG_TRACK, "[ti99_dsk] %s\n", dumpline(trackdata+i, i).c_str());
}
}
+std::string ti99_floppy_format::dumpline(uint8_t* line, int address) const
+{
+ std::ostringstream stream;
+ stream << std::hex << std::setfill('0') << std::setw(6) << unsigned(address);
+
+ for (int i=0; i < 16; i++)
+ {
+ stream << " " << std::setw(2) << (int)line[i];
+ }
+ stream << " " ;
+ for (int i=0; i < 16; i++)
+ {
+ char ch = (line[i] >= 32 && line[i] < 127)? (char)line[i] : '.';
+ stream << std::setw(1) << ch;
+ }
+ return stream.str();
+}
+
/*
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 track data.
+ 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 *trackdata, int *sector, int track, int head, int maxsect, int maxtrack, int numbytes)
+void ti99_sdf_format::write_track(io_generic *io, uint8_t *sectordata, int *sector, int track, int head, int sector_count, int track_count)
{
uint8_t* buf;
- // For creating an empty space where the sector did not exist
- uint8_t empty[256];
- memset(empty, 0, 256);
- int logicaltrack = head * maxtrack;
- logicaltrack += ((head&1)==0)? track : (maxtrack - 1 - track);
- int trackoffset = logicaltrack * maxsect * SECTOR_SIZE;
+ int logicaltrack = head * track_count;
+ logicaltrack += ((head&1)==0)? track : (track_count - 1 - track);
+ int trackoffset = logicaltrack * sector_count * SECTOR_SIZE;
-// if (head==0 && track==0) showtrack(trackdata, 9216);
-
- for (int i=0; i < maxsect; i++) {
- if (sector[i]==-1) buf = empty;
- else buf = trackdata + sector[i];
- io_generic_write(io, buf, trackoffset + i * SECTOR_SIZE, SECTOR_SIZE);
+ for (int i=0; i < sector_count; i++)
+ {
+ 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);
}
}
+
const floppy_format_type FLOPPY_TI99_SDF_FORMAT = &floppy_image_format_creator<ti99_sdf_format>;
/*
@@ -1078,6 +1191,9 @@ const floppy_format_type FLOPPY_TI99_SDF_FORMAT = &floppy_image_format_creator<t
modified in an 80-track drive. This will automatically cause the creation
of an 80-track image.
+ DSSD80: 520480 bytes
+ DSDD80: 1099520 bytes
+
Tracks are stored from outside to inside of head 0, then outside to inside of head 1:
(Head,Track): (0,0) (0,1) (0,2) ... (0,38) (0,39) (1,0) (1,1) ... (1,39)
@@ -1102,70 +1218,290 @@ const char *ti99_tdf_format::extensions() const
*/
int ti99_tdf_format::identify(io_generic *io, uint32_t form_factor)
{
- uint64_t file_size = io_generic_size(io);
int vote = 0;
- uint8_t trackdata[2000];
+ uint8_t fulltrack[6872];
+
+ int cell_size = 0;
+ int sector_count = 0;
+ int heads = 0;
+ int tracks = 0;
+ int sectorinterval = 0;
+ int headsectoff = 0;
+ int pos = 0;
+ determine_sizes(io, cell_size, sector_count, heads, tracks);
// Do we have a plausible image size? From the size alone we only give a 50 percent vote.
- if ((file_size == 260240) || (file_size == 549760) || (file_size == 1099520))
+ if (sector_count != 0)
vote = 50;
if (vote > 0)
{
- if (TRACE) osd_printf_error("ti99_dsk: Image looks like a TDF image\n");
+ 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));
+
+ if (sector_count == 9)
+ {
+ headsectoff = 24;
+ sectorinterval = 334;
+ }
+ else
+ {
+ headsectoff = 44;
+ sectorinterval = (sector_count==16)? 368 : 340;
+ }
+
+ while (fulltrack[pos] != 0xfe && pos < 70) pos++;
- // Get some bytes from track 0
- io_generic_read(io, trackdata, 0, 2000);
+ bool failed = false;
+ // Find the IDAMs and DAMs on track 0
+ for (int i=0; i < sector_count; i++)
+ {
+ int idam = fulltrack[pos+i*sectorinterval];
+ int dam = fulltrack[pos+headsectoff+i*sectorinterval];
+ if ((idam != 0xfe) || ((dam != 0xfb) && (dam != 0xf8)))
+ {
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Failed at %04x or %04x\n", pos+i*sectorinterval, pos+headsectoff+i*sectorinterval);
+ failed = true;
+ break;
+ }
+ }
- if (check_for_address_marks(trackdata, floppy_image::FM)==true || check_for_address_marks(trackdata, floppy_image::MFM)==true) vote=100;
+ if (failed)
+ {
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Image does not comply with TDF; may be broken or unformatted\n");
+ }
else
{
- if (TRACE) osd_printf_error("ti99_dsk: Image does not comply with TDF; may be broken or unformatted\n");
+ LOGMASKED(LOG_INFO, "[ti99_dsk] Image format complies with TDF\n");
+ vote = 100;
}
}
- else if (TRACE) osd_printf_error("ti99_dsk: Disk image is not a TDF image\n");
+ else LOGMASKED(LOG_INFO, "[ti99_dsk] Disk image is not a TDF image\n");
return vote;
}
/*
- Find the proper format for a given image file. We determine the cell size,
- but we do not care about the sector size (only needed by the SDF converter).
+ Find the proper format for a given image file.
*/
void ti99_tdf_format::determine_sizes(io_generic *io, int& cell_size, int& sector_count, int& heads, int& tracks)
{
uint64_t file_size = io_generic_size(io);
heads = 2; // TDF only supports two-sided recordings
-
- if (file_size % get_track_size(2000, 0)==0) cell_size = 2000;
- else if (file_size % get_track_size(4000, 0)==0) cell_size = 4000;
-
- // We could check for the content, but if we find that the content is
- // FM and the size implies MFM, the calculated track count will be wrong.
+ tracks = 40;
+ LOGMASKED(LOG_INFO, "[ti99_dsk] Image size = %ld\n", file_size);
+ switch (file_size)
+ {
+ case 260240: // used in PC99
+ cell_size = 4000;
+ sector_count = 9;
+ break;
+ case 491520: // 320K HX5102
+ cell_size = 2000;
+ sector_count = 16;
+ break;
+ case 549760: // used in PC99
+ cell_size = 2000;
+ sector_count = 18;
+ break;
+ case 520480:
+ cell_size = 4000;
+ sector_count = 9;
+ 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;
+ tracks = 80;
+ break;
+ default:
+ cell_size = 0;
+ sector_count = 0;
+ break;
+ }
}
/*
- For TDF this just amounts to loading the track from the image file.
- acttrack is not used here, since the file contains the track data.
+ Load a track. Although TDF provides us with a near-precise image of the
+ track, we just copy the sectors, store the sequence, and recreate the
+ 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 *trackdata, int head, int track, int acttrack, int sectorcount, int trackcount, int cellsize)
+void ti99_tdf_format::load_track(io_generic *io, uint8_t *sectordata, int *sector, int *secoffset, int head, int track, int sectorcount, int trackcount)
{
- int offset = ((trackcount * head) + track) * get_track_size(cellsize, 0);
- io_generic_read(io, trackdata, offset, get_track_size(cellsize, 0));
+ uint8_t fulltrack[6872]; // 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);
+
+ int offset = 0;
+ int tracksize = get_track_size(sectorcount);
+ int sectorinterval = 0;
+ int headsectoff = 0;
+ int pos = 0;
+ int img_sect = 0;
+
+ if (sectorcount == 9)
+ {
+ headsectoff = 25;
+ sectorinterval = 334;
+ }
+ else
+ {
+ headsectoff = 45;
+ sectorinterval = (sectorcount==16)? 368 : 340;
+ }
+
+ // Initialize the sequence lists
+ for (int i=0; i < sectorcount; i++)
+ {
+ sector[i] = -1;
+ secoffset[0] = 0;
+ }
+
+ // We already verified that this is TDF, but the disk may be unformatted
+ while (fulltrack[pos] != 0xfe && pos < tracksize) pos++;
+
+ if (pos==tracksize)
+ {
+ // No sectors found
+ LOGMASKED(LOG_WARN, "[ti99_dsk] No sectors on track %d, head %d\n", track, head);
+ return;
+ }
+
+ offset = pos;
+
+ int base = (head * trackcount + track) * tracksize;
+ int position = 0;
+ io_generic_read(io, fulltrack, base, tracksize);
+
+ for (int i=0; i < sectorcount; i++)
+ {
+ position = i*sectorinterval + offset;
+ if (position >= 6872)
+ {
+ LOGMASKED(LOG_WARN, "[ti99_dsk] No more sectors on track %d, head %d\n", track, head);
+ break; // no more sectors
+ }
+ if (fulltrack[position] != 0xfe)
+ {
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Invalid header (no FE) on track %d, head %d\n", track, head);
+ continue; // no valid header
+ }
+ img_sect = fulltrack[position+3];
+ if (img_sect >= 18)
+ {
+ LOGMASKED(LOG_WARN, "[ti99_dsk] Invalid sector number (%d) on track %d, head %d\n", img_sect, track, head);
+ continue; // invalid sector number
+ }
+ sector[i] = img_sect;
+ secoffset[i] = i*SECTOR_SIZE;
+ position += headsectoff;
+ memcpy(sectordata + i*SECTOR_SIZE, fulltrack+position, SECTOR_SIZE);
+ }
+
+ // dumpbytes(sectordata, sectorcount*SECTOR_SIZE);
+ LOGMASKED(LOG_TRACK, "[ti99_dsk] Sectors = ");
+ for (int i=0; i < sectorcount; i++)
+ {
+ LOGMASKED(LOG_TRACK, "%02d ", sector[i]);
+ }
+ LOGMASKED(LOG_TRACK, "\n[ti99_dsk] Offset = ");
+ for (int i=0; i < sectorcount; i++)
+ {
+ LOGMASKED(LOG_TRACK, "%04x ", secoffset[i]);
+ }
+ LOGMASKED(LOG_TRACK, "\n");
}
/*
- Also here, we just need to write the complete track on the image file.
+ Rebuild TDF track image
+ The TDF format is a bit more restrictive than it could be. The gaps need
+ to be of the exact size and contain the expected bytes. So we only
+ 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 *trackdata, int *sector, int track, int head, int maxsect, int maxtrack, int numbytes)
+void ti99_tdf_format::write_track(io_generic *io, uint8_t *sectordata, int *sector, int track, int head, int sector_count, int track_count)
{
- int offset = ((maxtrack * head) + track) * numbytes;
- io_generic_write(io, trackdata, offset, numbytes);
+ uint8_t trackdata[14000];
+ int offset = ((track_count * head) + track) * get_track_size(sector_count);
+ int a1 = 0;
+
+ enum
+ {
+ WGAP1 = 0, WGAP2, WGAP3, WGAP4, WGAP1BYTE, WGAPBYTE, WSYNC1, WSYNC2
+ };
+
+ const int fm9param[8] = { 16, 11, 45, 231, 0x00, 0xff, 6, 6 };
+ const int mfm16param[8] = { 50, 22, 50, 206, 0x4e, 0x4e, 12, 12 };
+ const int mfm18param[8] = { 40, 22, 24, 712, 0x4e, 0x4e, 10, 12 };
+ const int mfm36param[8] = { 40, 22, 24, 264, 0x4e, 0x4e, 10, 12 };
+
+ const int *param = fm9param;
+
+ if (sector_count == 16)
+ param = mfm16param;
+ else if (sector_count == 18)
+ param = mfm18param;
+ else if (sector_count == 36)
+ param = mfm36param;
+
+ LOGMASKED(LOG_TRACK, "[ti99_dsk] Writing track %d, head %d\n", track, head);
+
+ if (sector_count >= 16) a1 = 3;
+
+ // Create track
+ int pos = 0;
+ for (int i=0; i < param[WGAP1]; i++) trackdata[pos++] = param[WGAP1BYTE];
+ for (int j=0; j < sector_count; j++)
+ {
+ for (int i=0; i < param[WSYNC1]; i++) trackdata[pos++] = 0x00;
+ for (int i=0; i < a1; i++) trackdata[pos++] = 0xa1;
+ trackdata[pos++] = 0xfe;
+ trackdata[pos++] = track;
+ trackdata[pos++] = head;
+ trackdata[pos++] = sector[j];
+ trackdata[pos++] = 0x01;
+ trackdata[pos++] = 0xf7; // PC99 does not accept real CRC values
+ trackdata[pos++] = 0xf7;
+ for (int i=0; i < param[WGAP2]; i++) trackdata[pos++] = param[WGAPBYTE];
+ for (int i=0; i < param[WSYNC2]; i++) trackdata[pos++] = 0x00;
+ for (int i=0; i < a1; i++) trackdata[pos++] = 0xa1;
+ trackdata[pos++] = 0xfb;
+ memcpy(trackdata + pos, sectordata + j * SECTOR_SIZE, SECTOR_SIZE);
+ pos +=256;
+ trackdata[pos++] = 0xf7;
+ trackdata[pos++] = 0xf7;
+ 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));
}
-int ti99_tdf_format::get_track_size(int cell_size, int sector_count)
+int ti99_tdf_format::get_track_size(int sector_count)
{
- if (cell_size == 4000) return 3253;
- if (cell_size == 2000) return 6872;
+ switch (sector_count)
+ {
+ case 9:
+ return 3253;
+ case 16:
+ return 6144;
+ case 18:
+ return 6872;
+ case 36:
+ return 12544;
+ }
return 0;
}
diff --git a/src/lib/formats/ti99_dsk.h b/src/lib/formats/ti99_dsk.h
index d596f4bb17c..d67f38acaae 100644
--- a/src/lib/formats/ti99_dsk.h
+++ b/src/lib/formats/ti99_dsk.h
@@ -14,7 +14,7 @@
#define TI99_DSK_H
#include "flopimg.h"
-#include "wd177x_dsk.h"
+#include <sstream>
class ti99_floppy_format : public floppy_image_format_t
{
@@ -26,23 +26,23 @@ public:
protected:
int decode_bitstream(const uint8_t *bitstream, uint8_t *trackdata, int *sector, int cell_count, int encoding, uint8_t gapbytes, int track_size);
uint8_t get_data_from_encoding(uint16_t raw);
+ int get_sectors(const uint8_t *bitstream, int cell_count, int encoding, int track, int head, int sectors, uint8_t *sectordata, int *secnumber);
virtual int min_heads() =0;
virtual void determine_sizes(io_generic *io, int& cell_size, int& sector_count, int& heads, int& tracks) =0;
- virtual int get_track_size(int cell_size, int sector_count) =0;
- virtual void load_track(io_generic *io, uint8_t *trackdata, int head, int track, int acttrack, int sectorcount, int trackcount, int cellsize) =0;
- virtual void write_track(io_generic *io, uint8_t *trackdata, int *sector, int track, int head, int maxsect, int maxtrack, int numbytes) =0;
+ virtual int get_track_size(int sector_count) =0;
+ virtual void load_track(io_generic *io, uint8_t *sectordata, int *sector, int *secoffset, int head, int track, int sectorcount, int trackcount) =0;
+ virtual void write_track(io_generic *io, uint8_t *sectordata, int *sector, int track, int head, int sector_count, int track_count) =0;
int get_encoding(int cell_size);
- void generate_track_fm(int track, int head, int cell_size, uint8_t* trackdata, floppy_image *image);
- void generate_track_mfm(int track, int head, int cell_size, uint8_t* trackdata, floppy_image *image);
-
- bool check_for_address_marks(uint8_t* trackdata, int encoding);
+ void generate_fm_track_from_sectors(floppy_image *image, uint8_t *sectordata, int sector_count, int *sector, int *secoffset, int track, int trackid, int head);
+ void generate_mfm_track_from_sectors(floppy_image *image, uint8_t *sectordata, int sector_count, int *sector, int *secoffset, int track, int trackid, int head);
// Debugging
- void showtrack(uint8_t* trackdata, int length);
+ void dumpbytes(uint8_t* trackdata, int length);
+ std::string dumpline(uint8_t* line, int address) const;
};
/*
@@ -58,9 +58,9 @@ public:
private:
void determine_sizes(io_generic *io, int& cell_size, int& sector_count, int& heads, int& tracks) override;
- int get_track_size(int cell_size, int sector_count) override;
- void write_track(io_generic *io, uint8_t *trackdata, int *sector, int track, int head, int maxsect, int maxtrack, int numbytes) override;
- void load_track(io_generic *io, uint8_t *trackdata, int head, int track, int acttrack, int sectorcount, int trackcount, int cellsize) override;
+ int get_track_size(int sector_count) override;
+ void write_track(io_generic *io, uint8_t *sectordata, int *sector, int track, int head, int sector_count, int track_count) override;
+ void load_track(io_generic *io, uint8_t *sectordata, int *sector, int *secoffset, int head, int track, int sector_count, int track_count) override;
// This format supports single-sided images
int min_heads() override { return 1; }
@@ -97,9 +97,9 @@ public:
private:
void determine_sizes(io_generic *io, int& cell_size, int& sector_count, int& heads, int& tracks) override;
- void load_track(io_generic *io, uint8_t *trackdata, int head, int track, int acttrack, int sectorcount, int trackcount, int cellsize) override;
- void write_track(io_generic *io, uint8_t *trackdata, int *sector, int track, int head, int maxsect, int maxtrack, int numbytes) override;
- int get_track_size(int cell_size, int sector_count) override;
+ void load_track(io_generic *io, uint8_t *sectordata, int *sector, int *secoffset, int head, int track, int sectorcount, int trackcount) override;
+ void write_track(io_generic *io, uint8_t *sectordata, int *sector, int track, int head, int sector_count, int track_count) override;
+ int get_track_size(int sector_count) override;
// This format only supports double-sided images
int min_heads() override { return 2; }