summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/formats/ti99_dsk.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/formats/ti99_dsk.c')
-rw-r--r--src/lib/formats/ti99_dsk.c2000
1 files changed, 1 insertions, 1999 deletions
diff --git a/src/lib/formats/ti99_dsk.c b/src/lib/formats/ti99_dsk.c
index f0688634d9f..599cbe4eda3 100644
--- a/src/lib/formats/ti99_dsk.c
+++ b/src/lib/formats/ti99_dsk.c
@@ -2,8 +2,6 @@
// copyright-holders:Michael Zapf
/*********************************************************************
*
- * formats/ti99_dsk.c
- *
* TI-99 family disk images
*
* used by TI-99/4, TI-99/4A, TI-99/8, SGCPU ("TI-99/4P"), and Geneve
@@ -34,10 +32,7 @@
* 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.
*
- * -------------------------------------------------------------------
- * The second half of this file contains the legacy implementation.
- *
- * Michael Zapf, Sep 2014
+ * Michael Zapf, July 2015
*
********************************************************************/
@@ -1139,1996 +1134,3 @@ int ti99_tdf_format::get_track_size(int cell_size, int sector_count)
}
const floppy_format_type FLOPPY_TI99_TDF_FORMAT = &floppy_image_format_creator<ti99_tdf_format>;
-
-
-//==========================================================================
-
-/**************************************************************
- *
- * Legacy implementation
- *
- * Different to earlier implementations, these format implementations provide
- * full track read/write capabilities. For the SDF format, the missing track
- * information is recreated, and a common interleave is assumed.
- *
- * Note that in principle, writing tracks may change track sizes.
- * As neither one of the formats contains meta-information about track lengths,
- * and as the image consists of a contiguous sequence of the tracks, we
- * cannot allow different track sizes currently. Accordingly, the track size
- * cannot be changed after the image has been created by imgtool.
- * Hence, also sector count per tracks and recording type (FM or MFM) cannot be
- * changed without breaking the image.
- * For example, MFM disks with 18 sectors per track can only be reformatted to
- * MFM/18. Moreover, while this could be handled in a future revision,
- * the number of tracks should also remain unchanged.
- *
- * You can use blank image files (filled with zeros or arbitrary data) and use
- * the Disk Manager cartridge to properly format them. Also, this can be done
- * by imgtool. The image file must match the format length (representing the
- * space on the physical medium).
- *
- * 80 track drive handling
- *
- * For the TI system there may be a situation where 40 track disks are used
- * in 80 track drives. In these cases, the disk driver applies double-stepping,
- * that is, it advances the head twice in order to seek the next track. We
- * emulate this by dividing the track number by 2, which means that two tracks
- * are mapped to one (0,1 -> 0; 2,3 -> 1; 4,5 -> 2; ...; 78,79 -> 39)
- *
- * Technical detail: The size of the track must be given before actually
- * starting write_track as the controller implementation uses buffered
- * transfer.
- *
- * Michael Zapf, Feb 2010
- *
- * TODO: Link to imgtool. imgtool still uses its own format creation
- *
- * FIXME: If image is broken with good first track and defect higher tracks,
- * tdf_guess_geometry fails to define a geometry. The guessing should
- * always be done.
-**************************************************************/
-
-#define TI99_IDAM_LENGTH 7
-
-/*
- Determines whether we are using 80 track drives. This variable is
- necessary unless we get information about the dip
- switch settings. It is set by the disk controller implementations
- (bwg, hfdc, ti_fdc).
-*/
-static int use_80_track_drives = FALSE;
-
-struct ti99dsk_geometry
-{
- UINT8 sides;
- UINT8 tracksperside;
- UINT8 secspertrack;
- UINT8 density;
-};
-
-struct ti99dsk_tag
-{
- int heads;
- int tracks;
- int sectors;
- int track_size; // Complete track; to be calculated
- int format;
- int first_idam;
- int dam_offset;
-};
-
-/*
- Parametrizes the format to use 80 track drives. For TI systems we
- need to be able to emulate 40 track drives and 80 track drives.
- This is set in the configuration, but the format has no direct access.
- So as a preliminary solution we use this global function which sets the
- flag. This function is called by the disk controller implementations
- (bwg, hfdc, ti_fdc).
-*/
-void ti99_set_80_track_drives(int use80)
-{
- use_80_track_drives = use80;
-}
-
-#define TI99_DSK_TAG "ti99dsktag"
-#define TI99DSK_BLOCKNOTFOUND -1
-
-/*
- Searches a block containing number * byte, starting at the given
- position. Returns the position of the first byte of the block.
-*/
-static int find_block(const UINT8 *buffer, int start, int stop, UINT8 byte, size_t number)
-{
- int i = start;
- size_t current = number;
- while (i < stop && current > 0)
- {
- if (buffer[i++] != byte)
- {
- current = number;
- }
- else
- {
- current--;
- }
- }
- if (current==0)
- {
- return i - number;
- }
- else
- return TI99DSK_BLOCKNOTFOUND;
-}
-
-/*
- Queried by flopdrv. Instead of the image tracks, we return the tracks
- of the floppy drive. We assume we always have two heads.
-*/
-static int ti99_get_heads_per_disk(floppy_image_legacy *floppy)
-{
-// struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
-// return tag->heads;
- return 2;
-}
-
-/*
- Queried by flopdrv. Instead of the image tracks, we return the tracks
- of the floppy drive.
-*/
-static int ti99_get_tracks_per_disk(floppy_image_legacy *floppy)
-{
- int drivetracks = 42;
-
- // This may fail on startup; therefore we use a special function in
- // in the floppy controller implementations to explicitly set the geometry.
- if (use_80_track_drives)
- {
- drivetracks = 83;
- }
- return drivetracks;
-}
-
-static floperr_t ti99_get_sector_length(floppy_image_legacy *floppy, int head, int track, int sector, UINT32 *sector_length)
-{
- *sector_length=SECTOR_SIZE;
- return FLOPPY_ERROR_SUCCESS;
-}
-
-/*
- Return the track size. We do not allow different track
- sizes, so we store the track size in the tag.
-*/
-static UINT32 ti99_get_track_size(floppy_image_legacy *floppy, int head, int track)
-{
- struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
- return tag->track_size;
-}
-
-/*
-static void create_vib(UINT8 *sector0, option_resolution *params)
-{
- const char *name = "UNNAMED ";
- int sides, tracksperside,secspertrack,totalsectors,ausize,allocbytes,i;
-
- enum { NAME=0, TOTALSECS=10, SECSPERTRACK=11, SIG=12, PROT=16, TRACKS=17, SIDES=18, DENSITY=19, EXT=20, ALLOC=56 };
-
- sides = option_resolution_lookup_int(params, PARAM_HEADS);
- tracksperside = option_resolution_lookup_int(params, PARAM_TRACKS);
- secspertrack = option_resolution_lookup_int(params, PARAM_SECTORS);
-
- totalsectors = sides * tracksperside * secspertrack;
-
- memcpy(&sector0[NAME], name, 10);
-
- sector0[TOTALSECS] = (totalsectors>>8)&0xff;
- sector0[TOTALSECS+1] = (totalsectors&0xff);
-
- sector0[SECSPERTRACK] = secspertrack;
- sector0[SIG] = 'D';
- sector0[SIG+1] = 'S';
- sector0[SIG+2] = 'K';
-
- sector0[PROT] = ' ';
- sector0[TRACKS] = tracksperside;
- sector0[SIDES] = sides;
- sector0[DENSITY] = (secspertrack<10)? 0x01 : 0x02;
-
- for (i=EXT; i < ALLOC; i++)
- sector0[i] = 0;
-
- ausize = (totalsectors / 1441) + 1;
-
- allocbytes = totalsectors / ausize / 8;
-
- for (i=ALLOC; i < ALLOC+allocbytes; i++)
- sector0[i] = 0;
-
- while (i++ < SECTOR_SIZE)
- sector0[i] = 0xff;
-}
-*/
-/* =========================================================================
- Sector dump format
- =========================================================================*/
-
-static floperr_t ti99_sdf_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen);
-static floperr_t ti99_sdf_write_sector(floppy_image_legacy *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam);
-
-/* -----------------------------------------------------------------------
- * Guess the geometry of the sector dump disk.
- *
- * Sector size is always 256 bytes.
- *
- * Common formats:
- * 90 KiB = 40 tracks / 1 side / 9 sectors = SSSD
- * 180 KiB = 40 tracks / 2 side / 9 sectors = DSSD (most common)
- * = 40 tracks / 1 side / 18 sectors = SSDD (rare)
- * = 80 tracks / 1 side / 9 sectors = SSSD80 (rare)
- * 360 KiB = 40 tracks / 2 side / 18 sectors = DSDD (most common)
- * = 80 tracks / 2 side / 9 sectors = DSSD80 (rare)
- * = 80 tracks / 1 side / 18 sectors = SSDD80 (rare)
- * = 40 tracks / 1 side / 36 sectors = SSHD (rare)
- * 720 KiB = 80 tracks / 2 side / 18 sectors = DSDD80 (most common)
- * 1440 KiB= 80 tracks / 2 side / 36 sectors = DSHD80 (most common)
- *
- * Moreover, there may be formats with 35 tracks (ancient) and 8 sectors/track.
- * We only check for the 8 sector formats.
- * 160 KiB = 40 tracks / 1 side / 16 sectors = SSDD8
- * 320 KiB = 40 tracks / 2 side / 16 sectors = DSDD8
- *
- * The Volume Information Block may contain suitable information, but not
- * before the disk is formatted and initialized.
- *
- * returns 100 if recognized, 0 if not recognized
- * ----------------------------------------------------------------------- */
-
-static int ti99_sdf_guess_geometry(floppy_image_legacy *floppy, UINT64 size,
- struct ti99dsk_geometry *geometry)
-{
- int totsecs;
- typedef struct ti99_vib
- {
- char name[10]; // volume name (10 characters, pad with spaces)
- UINT8 totsecsMSB; // disk length in sectors (big-endian) (usually 360, 720 or 1440)
- UINT8 totsecsLSB;
- UINT8 secspertrack; // sectors per track (usually 9 (FM) or 18 (MFM))
- UINT8 id[3]; // String "DSK"
- UINT8 protection; // 'P' if disk is protected, ' ' otherwise.
- UINT8 tracksperside; // tracks per side (usually 40)
- UINT8 sides; // sides (1 or 2)
- UINT8 density; // 0,1 (FM) or 2,3,4 (MFM)
- UINT8 res[36]; // Empty for traditional disks, or up to 3 directory pointers
- UINT8 abm[200]; // allocation bitmap: a 1 for each sector in use (sector 0 is LSBit of byte 0,
- // sector 7 is MSBit of byte 0, sector 8 is LSBit of byte 1, etc.)
- } ti99_vib;
-
- ti99_vib vib;
- UINT32 file_size;
- struct ti99dsk_geometry dummy_geometry;
-
- if (geometry)
- memset(geometry, 0, sizeof(*geometry));
- else
- geometry = &dummy_geometry;
-
- if (size > 0xFFFFFFFF)
- return 0;
-
- file_size = (UINT32) size;
-
- // Read the Volume Information Block
- floppy_image_read(floppy, &vib, 0, sizeof(vib));
-
- // If we have read the sector successfully, let us parse it
- totsecs = (vib.totsecsMSB << 8) | vib.totsecsLSB;
- geometry->secspertrack = vib.secspertrack;
- if (geometry->secspertrack == 0)
- // Some images might be like this, because the original SSSD
- // TI controller always assumes 9.
- geometry->secspertrack = 9;
- geometry->tracksperside = vib.tracksperside;
- if (geometry->tracksperside == 0)
- // Some images are like this, because the original SSSD TI controller
- // always assumes 40.
- geometry->tracksperside = 40;
- geometry->sides = vib.sides;
- if (geometry->sides == 0)
- // Some images are like this, because the original SSSD TI controller
- // always assumes that tracks beyond 40 are on side 2. */
- geometry->sides = totsecs / (geometry->secspertrack * geometry->tracksperside);
- geometry->density = vib.density;
- // check that the format makes sense
- if (((geometry->secspertrack * geometry->tracksperside * geometry->sides) == totsecs)
- && (geometry->density <= 4) && (totsecs >= 2) && (! memcmp(vib.id, "DSK", 3))
- && (file_size == totsecs*256))
- {
- LOG_FORMATS("SDF/VIB consistent; tracks = %d, heads = %d, sectors = %d\n", geometry->tracksperside, geometry->sides, geometry->secspertrack);
- return 100;
- }
- LOG_FORMATS("SDF/VIB not consistent; guessing format\n");
-
- // So that was not consistent. We guess the size from the file size
- // and assume that the VIB did not contain reliable data. For the
- // ambiguous case we choose the most common format.
-
- // Adding support for another sector image format which adds 768 bytes
- // as a bad sector map
- if ((file_size / 256) % 10 == 3)
- {
- LOG_FORMATS("Stripping map of bad sectors at image end\n");
- file_size -= 768;
- }
-
- switch (file_size)
- {
- case 1*40*9*256:
- // 90kbytes: SSSD
- case 0:
- /*default:*/
- geometry->sides = 1;
- geometry->tracksperside = 40;
- geometry->secspertrack = 9;
- geometry->density = 1;
- break;
-
- case 2*40*9*256:
- // 180kbytes: either DSSD or 18-sector-per-track SSDD.
- // We assume DSSD since DSSD is more common and is supported by
- // the original TI SD disk controller.
- geometry->sides = 2;
- geometry->tracksperside = 40;
- geometry->secspertrack = 9;
- geometry->density = 1;
- break;
-
- case 1*40*16*256:
- // 160kbytes: 16-sector-per-track SSDD (standard format for TI
- // DD disk controller prototype, and the TI hexbus disk
- // controller?) */
- geometry->sides = 1;
- geometry->tracksperside = 40;
- geometry->secspertrack = 16;
- geometry->density = 2;
- break;
-
- case 2*40*16*256:
- // 320kbytes: 16-sector-per-track DSDD (standard format for TI
- // DD disk controller prototype, and TI hexbus disk
- // controller?)
- geometry->sides = 2;
- geometry->tracksperside = 40;
- geometry->secspertrack = 16;
- geometry->density = 2;
- break;
-
- case 2*40*18*256:
- // 360kbytes: 18-sector-per-track DSDD (standard format for most
- // third-party DD disk controllers, but reportedly not supported by
- // the original TI DD disk controller prototype)
- geometry->sides = 2;
- geometry->tracksperside = 40;
- geometry->secspertrack = 18;
- geometry->density = 2;
- break;
-
- case 2*80*18*256:
- // 720kbytes: 18-sector-per-track 80-track DSDD (Myarc only)
- geometry->sides = 2;
- geometry->tracksperside = 80;
- geometry->secspertrack = 18;
- geometry->density = 2;
- break;
-
- case 2*80*36*256:
- // 1.44Mbytes: DSHD (Myarc only)
- geometry->sides = 2;
- geometry->tracksperside = 80;
- geometry->secspertrack = 36;
- geometry->density = 3;
- break;
-
- default:
- LOG_FORMATS("Unrecognized disk image geometry\n");
- return 0;
- }
-
- LOG_FORMATS("SDF geometry guess: tracks = %d, heads = %d, sectors = %d\n", geometry->tracksperside, geometry->sides, geometry->secspertrack);
- return 100;
-}
-
-/*
- Figure out the interleave for the sector arrangement in the track. For
- SDF format this is required for the read_track function.
-
- Interleave:
- 0 7 5 3 1 8 6 4 2;
- start with 0, 3, 6, 0, 3, 6, ...
- 0 11 4 15 8 1 12 5 16 9 2 13 6 17 10 3 14 7
- start with 0 for every track
-
- Rare formats: 8 sectors
- 0 3 6 1 4 7 2 5 (i*3)%8
-
- 16 sectors
- 0 9 2 11 4 13 6 15 8 1 10 3 12 5 14 7 (i*9)%16
-
- 36 sectors
- 0 11 22 ... 3 14 25 (i*11)%36
-*/
-static void guess_interleave(int sectors, int *step, int *initial)
-{
- switch (sectors)
- {
- case 8:
- *step = 3;
- /* initial is the offset from track to track+1 of the starting sector number */
- *initial = 0;
- break;
- case 9:
- *step = 7;
- *initial = 3;
- break;
- case 16:
- *step = 9;
- *initial = 0;
- break;
- case 18:
- *step = 11;
- *initial = 0;
- break;
- case 36:
- *step = 11;
- *initial = 0;
- break;
- default:
- *step = 11;
- *initial = 0;
- break;
- }
-}
-
-/*
- Delivers a whole track. As the image consists only of
- sector data, we must reconstruct the track data and
- then insert the sector data.
-
- The track layout is exactly the Track Dump Format, except that the
- CRC values must be correctly calculated.
-
- Total length (FM) = 247 + sectors*334; (sectors=8 or 9)
- Total length (MFM) = 752 + sectors*340; (sectors=16 or 18)
-*/
-static floperr_t ti99_sdf_read_track(floppy_image_legacy *floppy, int head, int track, UINT64 offset, void *buffer, size_t buflen)
-{
- int sector;
- int startstep;
- int step;
- int position=0;
- unsigned short crc;
- int i;
- floperr_t err;
- int imgtrack = track;
-
- UINT8 *trackdata = (UINT8*)buffer;
-
- /* Determine from the image geometry whether we have FM or MFM */
- struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
-
- // Do we have a 40 track disk in an 80 track drive? In that case we
- // double the "width" of the tracks. */
- if (use_80_track_drives && tag->tracks<=40)
- {
- imgtrack = track / 2;
- }
-
- guess_interleave(tag->sectors, &step, &startstep);
-
- if (tag->sectors < 10) /* must be FM */
- {
- /* Write lead-in. */
- memset(trackdata, 0x00, 16);
- position += 16;
- for (i=0; i < tag->sectors; i++)
- {
- /* Create interleaving */
- sector = (i*step + imgtrack*startstep) % tag->sectors;
-
- memset(&trackdata[position], 0x00, 6);
- position += 6;
- /* Set IDAM */
- trackdata[position++] = 0xfe;
- trackdata[position++] = imgtrack;
- trackdata[position++] = head;
- trackdata[position++] = sector;
- trackdata[position++] = 0x01;
- /* Calculate CRC16. Preset to 0xffff (what is 0xcdb4?) */
- crc = ccitt_crc16(0xffff, &trackdata[position-(TI99_IDAM_LENGTH-2)], TI99_IDAM_LENGTH - 2);
- trackdata[position++] = (crc>>8)&0xff;
- trackdata[position++] = crc & 0xff;
-
- /* Write Gap2 */
- memset(&trackdata[position], 0xff, 11);
- position += 11;
- memset(&trackdata[position], 0x00, 6);
- position += 6;
- /* Write DAM */
- trackdata[position++] = 0xfb;
-
- /* Locate the sector content in the image and load it. */
- err = ti99_sdf_read_sector(floppy, head, imgtrack, sector, &trackdata[position], SECTOR_SIZE);
- if (err)
- return err;
-
- position += SECTOR_SIZE;
-
- /* Set CRC16 */
- crc = ccitt_crc16(0xffff, &trackdata[position-(SECTOR_SIZE+1)], SECTOR_SIZE+1);
- trackdata[position++] = (crc>>8)&0xff;
- trackdata[position++] = crc & 0xff;
-
- /* Write Gap3 */
- memset(&trackdata[position], 0xff, 45);
- position += 45;
- }
- /* Write lead-out */
- memset(&trackdata[position], 0xff, 231);
- position += 231;
- }
- else /* we have MFM */
- {
- /* Write lead-in. */
- memset(trackdata, 0x4e, 40);
- position += 40;
- for (i=0; i < tag->sectors; i++)
- {
- sector = (i*step + imgtrack*startstep) % tag->sectors;
-
- memset(&trackdata[position], 0x00, 10);
- position += 10;
- /* Write sync */
- memset(&trackdata[position], 0xa1, 3);
- position += 3;
- /* Set IDAM */
- trackdata[position++] = 0xfe;
- trackdata[position++] = imgtrack;
- trackdata[position++] = head;
- trackdata[position++] = sector;
- trackdata[position++] = 0x01;
- /* Set CRC16 */
- crc = ccitt_crc16(0xffff, &trackdata[position-TI99_IDAM_LENGTH+2], TI99_IDAM_LENGTH - 2);
- trackdata[position++] = (crc>>8)&0xff;
- trackdata[position++] = crc & 0xff;
-
- /* Write Gap2 */
- memset(&trackdata[position], 0x4e, 22);
- position += 22;
- memset(&trackdata[position], 0x00, 12);
- position += 12;
- /* Write sync */
- memset(&trackdata[position], 0xa1, 3);
- position += 3;
- /* Write DAM */
- trackdata[position++] = 0xfb;
-
- /* Locate the sector content in the image and load it. */
- err = ti99_sdf_read_sector(floppy, head, track, sector, &trackdata[position], SECTOR_SIZE);
- if (err)
- return err;
-
- position += SECTOR_SIZE;
-
- /* Set CRC16 */
- crc = ccitt_crc16(0xffff, &trackdata[position-SECTOR_SIZE-1], SECTOR_SIZE+1);
- trackdata[position++] = (crc>>8)&0xff;
- trackdata[position++] = crc & 0xff;
-
- /* Write Gap3 */
- memset(&trackdata[position], 0x4e, 24);
- position += 24;
- }
- /* Write lead-out */
- memset(&trackdata[position], 0x4e, 712);
- position += 712;
- }
- return FLOPPY_ERROR_SUCCESS;
-}
-
-/*
- Writes a whole track. As the sector dump format does not include track
- data, we have to extract the sector contents and to write them
- in sequence into the image. All the rest (gaps, crc, sync bytes) are
- dropped here.
- Bytes written to locations beyond the image end will be droppped
- silently (as if the medium is unwritable from that point).
-*/
-static floperr_t ti99_sdf_write_track(floppy_image_legacy *floppy, int head, int track, UINT64 offset, const void *buffer, size_t buflen)
-{
- int current_pos = 0;
- UINT8 *track_image;
- int leadin, gap1, gap2;
- int is_fm, found;
- struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
- int imgtrack = track;
-
- // Find out if we are going to write an FM or MFM track. Note that the
- // original TI controller is known to have a bug in the formatting
- // routine (using a MOVB instead of a MOV instruction when setting the
- // pointer to the track data), outputting false bytes at the
- // beginning of the track. So we do not rely on absolute positions
- // (and neither does the controller).
- track_image = (UINT8*)buffer;
-
- if (use_80_track_drives && tag->tracks<=40)
- {
- imgtrack = track / 2;
- }
-
- /* Only search in the first 100 bytes for the start. */
- leadin = 40;
- gap1 = 10;
- gap2 = 12;
- is_fm = FALSE;
-
- current_pos = find_block(track_image, 0, 100, 0x4e, leadin);
-
- // In case of defect formats, we continue as far as possible. This
- // may lead to sectors not being written. */
- if (current_pos==TI99DSK_BLOCKNOTFOUND)
- {
- /* Not MFM, possibly FM image */
- /* Again, find Lead-in */
- leadin = 16;
- current_pos = find_block(track_image, 0, 100, 0x00, leadin);
- if (current_pos==TI99DSK_BLOCKNOTFOUND)
- {
- /* If neither, forget about this process completely. */
- LOG_FORMATS("Cannot find lead-in for track %d, head %d.\n", track, head);
- return FLOPPY_ERROR_INVALIDIMAGE;
- }
- gap1 = 6;
- gap2 = 6;
- is_fm = TRUE;
- }
-
- found = FALSE;
- /* Get behind lead-in */
- current_pos += leadin;
- while (current_pos < buflen)
- {
- /* We must find the address block to determine the sector. */
- int new_pos = find_block(track_image, current_pos, buflen, 0x00, gap1);
- if (new_pos==TI99DSK_BLOCKNOTFOUND)
- {
- /* Forget about the rest. */
- if (found) break; /* we were already successful, so all ok */
- LOG_FORMATS("Cannot find gap1 for track %d, head %d.\n", track, head);
- return FLOPPY_ERROR_INVALIDIMAGE;
- }
- found = TRUE;
-
- if (!is_fm)
- new_pos += 3; /* skip sync bytes in MFM */
-
- if (track_image[new_pos + gap1]==0xfe)
- {
- current_pos = new_pos + gap1 + 1;
- /* IDAM found. */
- int wtrack = track_image[current_pos];
- int whead = track_image[current_pos+1];
- int sector = track_image[current_pos+2];
- if (wtrack == imgtrack && whead == head)
- {
- /* We skip the first part of gap2. */
- new_pos = find_block(track_image, current_pos, buflen, 0x00, gap2);
- if (current_pos==TI99DSK_BLOCKNOTFOUND)
- {
- LOG_FORMATS("Cannot find gap2 for track %d, head %d.\n", imgtrack, head);
- return FLOPPY_ERROR_INVALIDIMAGE;
- }
- else
- {
- new_pos += gap2;
- if (!is_fm)
- new_pos += 3; /* skip sync */
- current_pos = new_pos;
- if (track_image[current_pos]==0xfb)
- {
- /* DAM found. We now write the sector content to the image. */
- ti99_sdf_write_sector(floppy, head, track, sector, &track_image[current_pos+1], SECTOR_SIZE, 0);
- current_pos += SECTOR_SIZE;
- }
- else
- LOG_FORMATS("DAM not found. Not writing write sector %d\n", sector);
- /* else not found, ignore this sector. */
- }
- }
- else
- {
- // else the sector head data do not match the
- // current track and head. Ignore the sector.
- LOG_FORMATS("Wrong track: wtrack=%d, imgtrack=%d, whead=%d, imghead=%d\n",wtrack,imgtrack, whead,head);
- }
- }
- else
- {
- /* One step forward. Retry. */
- current_pos++;
- }
- }
- return FLOPPY_ERROR_SUCCESS;
-}
-
-/*
- This method creates a properly formatted image.
-
- For a proper image, we need to format all tracks, and to create a
- minimal filesystem:
-
- name = "UNNAMED "
- number of sectors
- sectors/track
- "DSK"
- protection = 0x00
- tracks/side
- sides
- density (0,1 = FM, 2 = MFM)
- 0x14 - 0x37 : 0x00
- Allocation bitmap: 0xFF except for the first #sectors/AU size
-
- AU size = 1 (360 - 1440 sectors)
- = 2 (1441 - 2880 sectors)
- = 4 (2881 - 5760 sectors)
- = 8 (5760 - 11520 sectors)
-
- sector 0 =
- sector 1 = 256* 0x00
-*/
-/* static floperr_t ti99_sdf_format_track(floppy_image_legacy *floppy, int head, int track, option_resolution *params)
-{
- dynamic_buffer sector0(SECTOR_SIZE);
- create_vib(sector0, params);
- if (true)
- {
- printf("not implemented\n");
- return FLOPPY_ERROR_SEEKERROR;
- }
- return FLOPPY_ERROR_SUCCESS;
-}
-*/
-
-/*
- Get the offset from the start of the image file. In this format, logical
- tracks on two-sided disks are arranged as follows (example for 40
- tracks; accordingly for 35 or 80)
-
- head-track
- 0-0
- 0-1
- 0-2
- 0-3
- ...
- 0-39
- 1-39
- 1-38
- 1-37
- ...
- 1-0
- Note that we take the imgtrack, which may be half of the drive track.
-*/
-static floperr_t ti99_sdf_get_offset(floppy_image_legacy *floppy, int head, int imgtrack, int sector, UINT64 *offset)
-{
- struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
-
- if ((head < 0) || (head >= tag->heads)
- || (imgtrack < 0) || (imgtrack >= tag->tracks)
- || (sector < 0) || (sector > tag->sectors))
- return FLOPPY_ERROR_SEEKERROR;
-
- if (head == 0) /* track numbers increasing towards inner track */
- {
- *offset = (imgtrack * tag->sectors + sector) * SECTOR_SIZE;
- }
- else /* track numbers increasing towards outer track */
- {
- *offset = (((2*tag->tracks)-1-imgtrack) * tag->sectors + sector) * SECTOR_SIZE;
- }
- return FLOPPY_ERROR_SUCCESS;
-}
-
-/*
- Read one sector at the specified position.
-*/
-static floperr_t ti99_sdf_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen)
-{
- floperr_t err;
- UINT64 offset;
- int imgtrack = track;
- struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
-
- if (use_80_track_drives && tag->tracks<=40)
- {
- imgtrack = track / 2;
- }
-
- err = ti99_sdf_get_offset(floppy, head, imgtrack, sector, &offset);
- if (err)
- {
- return err;
- }
- floppy_image_read(floppy, buffer, offset, SECTOR_SIZE);
-
- return FLOPPY_ERROR_SUCCESS;
-}
-
-/*
- For the SDF format, sectors are always numbered in ascending order,
- starting with the lowest numbered sector in each track. In other words,
- we have nothing to calculate here.
-*/
-static floperr_t ti99_sdf_read_indexed_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen)
-{
- return ti99_sdf_read_sector(floppy, head, track, sector, buffer, buflen);
-}
-
-/*
- Write one sector at the specified position.
-*/
-static floperr_t ti99_sdf_write_sector(floppy_image_legacy *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam)
-{
- UINT64 offset;
- floperr_t err;
- int imgtrack = track;
-
- struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
-
- if (use_80_track_drives && tag->tracks<=40)
- {
- imgtrack = track / 2;
- }
-
- err = ti99_sdf_get_offset(floppy, head, imgtrack, sector, &offset);
- if (err)
- {
- return err;
- }
- floppy_image_write(floppy, buffer, offset, SECTOR_SIZE);
-
- return FLOPPY_ERROR_SUCCESS;
-}
-
-/*
- See above; indexing and numbering coincide.
-*/
-static floperr_t ti99_sdf_write_indexed_sector(floppy_image_legacy *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam)
-{
- return ti99_sdf_write_sector(floppy, head, track, sector, buffer, buflen, ddam);
-}
-
-/*
- Required for ReadAddress command
-*/
-static floperr_t ti99_sdf_get_indexed_sector_info(floppy_image_legacy *floppy, int head, int track, int sector_index, int *cylinder, int *side, int *sector, UINT32 *sector_length, unsigned long *flags)
-{
- struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
-
- if (use_80_track_drives && tag->tracks<=40)
- {
- track = track / 2;
- }
-
- if (sector_length)
- *sector_length=SECTOR_SIZE;
- if (cylinder)
- *cylinder = track;
- if (side)
- *side = head;
- if (sector)
- *sector = sector_index;
- if (flags)
- *flags = 0;
- if (sector_index >= tag->sectors)
- {
- return FLOPPY_ERROR_SEEKERROR;
- }
-
- return FLOPPY_ERROR_SUCCESS;
-}
-
-/*
- Try to identify the image as an SDF format image.
-*/
-static FLOPPY_IDENTIFY(ti99_sdf_identify)
-{
- UINT64 size;
- size = floppy_image_size(floppy);
- *vote = ti99_sdf_guess_geometry(floppy, size, NULL);
- LOG_FORMATS("SDF voting %d\n", *vote);
- return FLOPPY_ERROR_SUCCESS;
-}
-
-/*
- Create the SDF data structures and set the callbacks.
-*/
-static FLOPPY_CONSTRUCT(ti99_sdf_construct)
-{
- struct ti99dsk_geometry geometry;
- struct FloppyCallbacks *callbacks;
- struct ti99dsk_tag *tag;
- LOG_FORMATS("Reading image as SDF\n");
-
- if (params)
- {
- /* create */
- memset(&geometry, 0, sizeof(geometry));
- geometry.sides = option_resolution_lookup_int(params, PARAM_HEADS);
- geometry.tracksperside = option_resolution_lookup_int(params, PARAM_TRACKS);
- geometry.secspertrack = option_resolution_lookup_int(params, PARAM_SECTORS);
-
- /* We don't have headers for geometry */
- /* check for usage in imgtool - we want to be able to create useful disks */
- }
- else
- {
- /* load */
- if (ti99_sdf_guess_geometry(floppy, floppy_image_size(floppy), &geometry)<50)
- return FLOPPY_ERROR_INVALIDIMAGE;
- }
-
- assert(geometry.sides);
- assert(geometry.tracksperside);
- assert(geometry.secspertrack);
-
- tag = (struct ti99dsk_tag *) floppy_create_tag(floppy, sizeof(struct ti99dsk_tag));
-
- if (!tag)
- return FLOPPY_ERROR_OUTOFMEMORY;
-
- tag->heads = geometry.sides;
- tag->tracks = geometry.tracksperside;
- tag->sectors = geometry.secspertrack;
- if (tag->sectors < 10)
- /* FM mode */
- tag->track_size = 16 + tag->sectors*334 + 231;
- else
- tag->track_size = 40 + tag->sectors*340 + 712;
-
- /* set up format callbacks */
- callbacks = floppy_callbacks(floppy);
- callbacks->read_sector = ti99_sdf_read_sector;
- callbacks->write_sector = ti99_sdf_write_sector;
- callbacks->read_indexed_sector = ti99_sdf_read_indexed_sector;
- callbacks->write_indexed_sector = ti99_sdf_write_indexed_sector;
- callbacks->read_track = ti99_sdf_read_track;
- callbacks->write_track = ti99_sdf_write_track;
-/* callbacks->format_track = ti99_sdf_format_track; */
- callbacks->get_track_size = ti99_get_track_size;
- /* post format unset */
- callbacks->get_heads_per_disk = ti99_get_heads_per_disk;
- callbacks->get_tracks_per_disk = ti99_get_tracks_per_disk;
- callbacks->get_sector_length = ti99_get_sector_length;
- callbacks->get_indexed_sector_info = ti99_sdf_get_indexed_sector_info;
-
- return FLOPPY_ERROR_SUCCESS;
-}
-
-/* -----------------------------------------------------------------------
- * Track Dump Format, aka PC99 format
- * This format includes all track data, including address marks and gaps.
- * However, CRC is not stored; instead, a f7f7 is stored at that location.
- * Two track images exist, one for FM and one for MFM format.
- *
- * In this implementation, however, we do calculate the CRC.
- *
- * All tracks have exactly the same size, so offsets are calculated easily.
- *
- * This format is a precise map of the data contents of the track;
- * however, it does not store clock patterns.
- *
- * The TDF format does not have a special index part, so any sector on it
- * must be searched (as done by the disk controller)
- *
- * Interesting detail: The original TI disk controller has a bug which has
- * just recently been discovered (using MESS!): The lead-in has another 9
- * bytes as a prefix; this is due to a wrongly set pointer in the format
- * routine. Strictly speaking, it produces invalid track images.
- * The original hardware does not care, however, so neither should we.
- * To keep the emulation realistic (and to allow for a
- * possible future extension with clock bits), we search for the
- * beginning of the track. From there on, however, we accept no further
- * deviations. This may make the resulting format unusable with the PC99
- * emulator, but it only appears when formatting with the TI disk
- * controller anyway. If the image is created with another disk controller or
- * using imgtool, the format is correctly created.
- *
- * FM track image
- *
- * Lead-in: 16* 00
- * Pre-ID gap: 6* 00 ---+
- * IDAM: fe |
- * Track: tt |
- * Head: hh |
- * Sector: ss |
- * Size: 01 |
- * CRC: 2* f7 +--- repeat 9 times (8 in rare cases)
- * Gap2: 11* ff |
- * 6* 00 |
- * DAM: fb |
- * Content: 256* xx |
- * CRC: 2* f7 |
- * Gap3: 45* ff ---+
- * Lead-out: 231* ff
- *
- * --------------
- *
- * MFM track image
- *
- * Lead-in: 40* 4e
- * Pre-ID gap: 10* 00 ---+
- * Sync: 3* a1 |
- * IDAM: fe |
- * Track: tt |
- * Head: hh |
- * Sector: ss |
- * Size: 01 |
- * CRC: 2* f7 +--- repeat 18 times (16 in rare cases)
- * Gap2: 22* 4e |
- * 12* 00 |
- * Sync: 3* a1 |
- * DAM: fb |
- * Content: 256* xx |
- * CRC: 2* f7 |
- * Gap3: 24* 4e ---+
- * Lead-out: 712* 4e
- *
- * ------------------
- * The tracks are located on the image as follows (different to SDF!):
- *
- * head-track
- * 0-0
- * 0-1
- * 0-2
- * 0-3
- * ...
- * 0-39
- * 1-0
- * 1-1
- * 1-2
- * ...
- * 1-39
- * ----------------------------------------------------------------------- */
-
-#define TI99_FM 1
-#define TI99_MFM 2
-
-/* For the emulation of the clock pattern, we add a 9th bit. */
-#define TI99_DAM 0x1fb
-#define TI99_IDAM 0x1fe
-
-#define TI99_FM_DAM_OFFSET 24
-#define TI99_MFM_DAM_OFFSET 44
-
-#define TI99_FM_TRACK_ADD 247
-#define TI99_MFM_TRACK_ADD 752
-
-#define TI99_FM_TOTAL_SECTOR 334
-#define TI99_MFM_TOTAL_SECTOR 340
-
-/*
- Determine offset of the first IDAM. This is the base of the simulation
- of the clock bytes. We use a heuristic to guess where the track begins
- and simply check whether we can locate the first IDAM and DAM. Return
- value is the offset to the first IDAM.
-*/
-static floperr_t determine_offset(int format, UINT8 *track, int *offset)
-{
- floperr_t retval;
- int current_pos;
-
- if (format==TI99_FM)
- {
-// printf("Trying FM\n");
- // We are seeking the lead-in and pre-id gap from
- // position 0 to position 50. This is just to make sure that
- // if there are bad bytes at the beginning (original TI controller)
- // we will skip them.
- current_pos = find_block(track, 0, 50, 0x00, 22);
- if (current_pos==TI99DSK_BLOCKNOTFOUND)
- {
- LOG_FORMATS("Lead-in not found\n");
- retval = FLOPPY_ERROR_SEEKERROR;
- }
- else
- {
- current_pos += 22;
- if (track[current_pos]==0xfe /* IDAM */ &&
- track[current_pos+4]==0x01 /* sector length, always 256 for TI */ &&
- track[current_pos+24]==0xfb) /* DAM */
- {
- /* We're pretty sure this is the beginning. */
- *offset = current_pos;
- retval = FLOPPY_ERROR_SUCCESS;
- }
- else
- {
- LOG_FORMATS("IDAM or DAM not found\n");
- retval = FLOPPY_ERROR_SEEKERROR;
- }
- }
- }
- else
- {
- /* MFM */
-// printf("Trying MFM\n");
- int track_start = find_block(track, 0, 100, 0x4e, 40);
- if (track_start==TI99DSK_BLOCKNOTFOUND)
- {
- LOG_FORMATS("Lead-in not found\n");
- retval = FLOPPY_ERROR_SEEKERROR;
- }
- else
- {
- track_start += 40;
- current_pos = find_block(track, track_start, track_start+10, 0x00, 10);
- if (current_pos==TI99DSK_BLOCKNOTFOUND)
- {
- LOG_FORMATS("Pre-gap not found\n");
- retval = FLOPPY_ERROR_SEEKERROR;
- }
- else
- {
- current_pos += 10;
- if (track[current_pos] == 0xa1 /* First sync */ &&
- track[current_pos+3] == 0xfe /* IDAM */ &&
- track[current_pos+44] == 0xa1 /* First sync */ &&
- track[current_pos+47] == 0xfb) /* DAM */
- {
- /* We're pretty sure this is the beginning. */
- *offset = current_pos + 3;
- retval = FLOPPY_ERROR_SUCCESS;
- }
- else
- {
- LOG_FORMATS("Sync/IDAM/DAM not found\n");
- retval = FLOPPY_ERROR_SEEKERROR;
- }
- }
- }
- }
-/* printf("TDF offset = 0x%x\n", *offset); */
- return retval;
-}
-
-/*
- Gets a byte from the track. In this format we do not have a clock
- signal, so we will simulate it. Thus, this function returns a 9-bit
- value, with the first bit set as a marker for an address mark.
-
- This may be a little more complicated than necessary, but it correctly
- emulates the behavior of the controller (and it allows for an
- alternative format which actually supports clock and data).
-*/
-static int read_byte(int format, int first_idam, UINT8 *track, int position)
-{
- int totalseclen;
- int dam_offset;
- int byte;
-
- /* Check whether we are at any IDAM or DAM in this track. */
- if (format==TI99_FM)
- {
- totalseclen = TI99_FM_TOTAL_SECTOR;
- dam_offset = TI99_FM_DAM_OFFSET;
- }
- else
- {
- totalseclen = TI99_MFM_TOTAL_SECTOR;
- dam_offset = TI99_MFM_DAM_OFFSET;
- }
-
- int curpos = (position - first_idam) % totalseclen;
- if (curpos==0 && track[position]==0xfe)
- byte = TI99_IDAM;
- else
- {
- if (curpos==dam_offset && track[position]==0xfb)
- byte = TI99_DAM;
- else
- byte = track[position] & 0xff;
- }
- return byte;
-}
-
-/*
- Determine the position of this track in the image.
-*/
-static floperr_t ti99_tdf_get_offset(floppy_image_legacy *floppy, int head, int imgtrack, UINT64 *offset)
-{
- struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
-
- if ((head < 0) || (head >= tag->heads) || (imgtrack < 0) || (imgtrack >= tag->tracks))
- return FLOPPY_ERROR_SEEKERROR;
-
- // For head 0, tracks increase from 0 to tracks-1; then for head 1,
- // tracks also increase from 0 to tracks-1. */
- *offset = head * (tag->tracks * tag->track_size) + imgtrack * tag->track_size;
-
- return FLOPPY_ERROR_SUCCESS;
-}
-
-/*
- Reads a track. We just copy the contents from the format and recreate
- the CRC if it is the "blank" CRC as F7F7.
- This method assumes that the track division be done already.
-*/
-static floperr_t ti99_tdf_read_track_internal(floppy_image_legacy *floppy, int head, int imgtrack, UINT64 offset, void *buffer, size_t buflen)
-{
- floperr_t err;
- UINT64 track_offset;
- int first_idam = 0;
- struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
- int i, byte, crc;
-
- UINT8 *track_data = (UINT8*)buffer;
-
- err = ti99_tdf_get_offset(floppy, head, imgtrack, &track_offset);
- if (err)
- return err;
-
- floppy_image_read(floppy, buffer, track_offset, buflen);
-
- // Rebuild the CRCs. PC99 did not store the CRC but put
- // F7F7 in its place.
- // The first CRC is at position IDAM + 5
- // The second CRC is at position IDAM + 0x119 (FM) or +0x12d (MFM)
- // All this is repeated for each sector in the track
-
- if (determine_offset(tag->format, track_data, &first_idam)==FLOPPY_ERROR_SEEKERROR)
- return FLOPPY_ERROR_SEEKERROR;
-
- i = 0;
- while (i < buflen)
- {
- byte = read_byte(tag->format, first_idam, track_data, i);
- if (byte == TI99_IDAM)
- {
- // Do we have a valid CRCs already? Then this image
- // already contains proper CRCs handling. Do not recreate them.
- if (track_data[i+5] != 0xf7 || track_data[i+6] != 0xf7)
- return FLOPPY_ERROR_SUCCESS;
-
- crc = ccitt_crc16(0xffff, &track_data[i], 5);
- track_data[i+5] = (crc>>8) & 0xff;
- track_data[i+6] = (crc & 0xff);
- }
- else
- {
- if (byte == TI99_DAM)
- {
- crc = ccitt_crc16(0xffff, &track_data[i], SECTOR_SIZE+1);
- track_data[i+SECTOR_SIZE+1] = (crc>>8) & 0xff;
- track_data[i+SECTOR_SIZE+2] = (crc & 0xff);
- }
- }
- i++;
- }
-// dump_contents(track_data, buflen);
- return FLOPPY_ERROR_SUCCESS;
-}
-
-/*
- Reads a track. We just copy the contents from the format, without
- changes.
-*/
-static floperr_t ti99_tdf_read_track(floppy_image_legacy *floppy, int head, int track, UINT64 offset, void *buffer, size_t buflen)
-{
- int imgtrack = track;
-
- struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
- if (use_80_track_drives && tag->tracks<=40)
- {
- imgtrack = track / 2;
- }
- return ti99_tdf_read_track_internal(floppy, head, imgtrack, offset, buffer, buflen);
-}
-
-/*
- Writes a track.
-*/
-static floperr_t ti99_tdf_write_track(floppy_image_legacy *floppy, int head, int track, UINT64 offset, const void *buffer, size_t buflen)
-{
- floperr_t err;
- UINT64 track_offset;
- int imgtrack = track;
-
- struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
- if (use_80_track_drives && tag->tracks<=40)
- {
- imgtrack = track / 2;
- }
-
- err = ti99_tdf_get_offset(floppy, head, imgtrack, &track_offset);
- if (err)
- return err;
-
- // According to the TDF format, we don't need the CRC but replace it
- // with F7F7. For now we keep it and see whether PC99 can cope with
- // that. (Otherwise we would have to copy the const buffer). */
- floppy_image_write(floppy, buffer, offset + track_offset, buflen);
- return FLOPPY_ERROR_SUCCESS;
-}
-
-/*
-static floperr_t ti99_tdf_format_track(floppy_image_legacy *floppy, int head, int track, option_resolution *params)
-{
- int sectors;
- int sector_length;
- int interleave;
- int first_sector_id;
- sectors = option_resolution_lookup_int(params, PARAM_SECTORS);
- sector_length = option_resolution_lookup_int(params, PARAM_SECTOR_LENGTH);
- interleave = option_resolution_lookup_int(params, PARAM_INTERLEAVE);
- first_sector_id = option_resolution_lookup_int(params, PARAM_FIRST_SECTOR_ID);
- return FLOPPY_ERROR_SUCCESS;
-}
-*/
-
-/*
- Get a sector from a track. This function takes a complete track,
- searches for the sector, and passes a pointer to the sector contents
- back.
- As the original TI controller creates bad bytes at the start of a track
- we do *not* assume a simple layout. The strategy is to search the
- lead-in of the track, and from this offset, step through the track
- in search for the sector. Since we do not have index marks (we cannot
- distinguish them from ordinary data, as we do not store the clock), we
- do not attempt to detect IDAM or DAM.
-*/
-static floperr_t ti99_tdf_seek_sector_in_track(floppy_image_legacy *floppy, int head, int track, int sector, UINT8 *track_data, UINT8 **sector_data)
-{
- struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
-
- int byte;
- int state;
- enum { SEARCHIDAM, SEARCHDAM };
-
- state = SEARCHIDAM;
- if (tag->first_idam==0) /* should we check for every track? */
- {
- if (determine_offset(tag->format, track_data, &tag->first_idam)==FLOPPY_ERROR_SEEKERROR)
- {
- LOG_FORMATS("could not determine offset\n");
- return FLOPPY_ERROR_SEEKERROR;
- }
- }
-
- for (int i=0; i < tag->track_size; i++)
- {
- byte = read_byte(tag->format, tag->first_idam, track_data, i);
-
- switch (state)
- {
- case SEARCHIDAM:
- /* search for the IDAM */
- if (byte==TI99_IDAM)
- {
- if ((track_data[i+1]==track) && (track_data[i+2]==head) && (track_data[i+3]==sector))
- state = SEARCHDAM;
- else
- state = SEARCHIDAM;
- }
- break;
- case SEARCHDAM:
- if (byte==TI99_DAM)
- {
- *sector_data = &track_data[i+1];
- return FLOPPY_ERROR_SUCCESS;
- }
- break;
- }
- }
- LOG_FORMATS("Sector not found.\n");
- return FLOPPY_ERROR_SEEKERROR;
-}
-
-static floperr_t ti99_tdf_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen)
-{
- floperr_t err;
- UINT8 *sector_data;
- int imgtrack = track;
- struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
- dynamic_buffer track_data(tag->track_size);
-
- if (use_80_track_drives && tag->tracks<=40)
- {
- imgtrack = track / 2;
- }
-
- err = ti99_tdf_read_track_internal(floppy, head, imgtrack, 0, &track_data[0], tag->track_size);
- if (err)
- return err;
-
- err = ti99_tdf_seek_sector_in_track(floppy, head, imgtrack, sector, &track_data[0], &sector_data);
- if (err)
- return err;
- /* verify CRC? */
-
- memcpy(buffer, sector_data, SECTOR_SIZE);
- return FLOPPY_ERROR_SUCCESS;
-}
-
-/*
- Writes a sector into the track. Note that the indexed_write method
- may be used instead of this method, according to the implementation
- of flopimg/flopdrv.
-*/
-static floperr_t ti99_tdf_write_sector(floppy_image_legacy *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam)
-{
- floperr_t err;
- UINT8 *sector_data;
- UINT8 *track_data;
- UINT64 track_offset;
- int imgtrack = track;
- UINT64 offset;
- UINT8 crc_field[2];
- int crc;
-
- struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
-
- track_data = (UINT8*)malloc(tag->track_size);
- if (use_80_track_drives && tag->tracks<=40)
- {
- imgtrack = track / 2;
- }
-
- err = ti99_tdf_read_track_internal(floppy, head, imgtrack, 0, track_data, tag->track_size);
- if (err)
- return err;
- err = ti99_tdf_seek_sector_in_track(floppy, head, imgtrack, sector, track_data, &sector_data);
- if (err)
- return err;
-
- err = ti99_tdf_get_offset(floppy, head, imgtrack, &track_offset);
- if (err)
- return err;
-
- offset = track_offset + (sector_data - track_data);
-
- floppy_image_write(floppy, buffer, offset, SECTOR_SIZE);
-
- // Recalculate CRC. We init the CRC with bf84 (DAM fb is
- // already included; would be ffff without)
- crc = ccitt_crc16(0xbf84, (UINT8*)buffer, SECTOR_SIZE);
- crc_field[0] = (crc>>8) & 0xff;
- crc_field[1] = (crc & 0xff);
- floppy_image_write(floppy, crc_field, offset+SECTOR_SIZE, 2);
-
- return FLOPPY_ERROR_SUCCESS;
-}
-
-static floperr_t ti99_tdf_write_indexed_sector(floppy_image_legacy *floppy, int head, int track, int sector_index, const void *buffer, size_t buflen, int ddam)
-{
- /* Read track, head */
- int byte;
- struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
- dynamic_buffer track_data(tag->track_size);
- UINT8 *sector_data;
- UINT64 track_offset;
- UINT64 offset;
- UINT8 crc_field[2];
-
- int crc;
- int imgtrack = track;
-
- int i;
- floperr_t err;
-
- if (use_80_track_drives && tag->tracks<=40)
- {
- imgtrack = track / 2;
- }
-
- err = ti99_tdf_read_track_internal(floppy, head, imgtrack, 0, &track_data[0], tag->track_size);
- if (err)
- {
- return err;
- }
-
- /* Search for the sector_index-th sector. */
- if (tag->first_idam==0) /* should we check for every track? */
- {
- if (determine_offset(tag->format, &track_data[0], &tag->first_idam)==FLOPPY_ERROR_SEEKERROR)
- {
- return FLOPPY_ERROR_SEEKERROR;
- }
- }
-
- /* Search for the IDAM of the n-th sector */
- i=0;
- while (i < tag->track_size && sector_index>=0)
- {
- byte = read_byte(tag->format, tag->first_idam, &track_data[0], i);
- if (byte == TI99_IDAM)
- {
- sector_index--;
- }
- i++;
- }
- i--;
-
- /* Not that many sectors in this track? */
- if (sector_index>0)
- {
- return FLOPPY_ERROR_SEEKERROR;
- }
-
- /* Find the DAM. */
- while (i < tag->track_size)
- {
- byte = read_byte(tag->format, tag->first_idam, &track_data[0], i);
- if (byte == TI99_DAM)
- break;
- else
- i++;
- }
-
- /* There was no DAM. Image seems to be broken. */
- if (i == tag->track_size)
- {
- return FLOPPY_ERROR_SEEKERROR;
- }
-
- /* Sector data is right after the DAM. */
- sector_data = &track_data[i+1];
-
- /* Get the position of the track in the image. */
- err = ti99_tdf_get_offset(floppy, head, imgtrack, &track_offset);
- if (err)
- return err;
-
- offset = track_offset + (sector_data - &track_data[0]);
-
- /* Write the sector data at that position. */
- floppy_image_write(floppy, buffer, offset, SECTOR_SIZE);
-
- // Recalculate CRC. We init the CRC with bf84 (DAM fb is
- // already included; would be ffff without)
- crc = ccitt_crc16(0xbf84, (UINT8*)buffer, SECTOR_SIZE);
- crc_field[0] = (crc>>8) & 0xff;
- crc_field[1] = (crc & 0xff);
- floppy_image_write(floppy, crc_field, offset+SECTOR_SIZE, 2);
-
- return FLOPPY_ERROR_SUCCESS;
-}
-
-
-static floperr_t ti99_tdf_find_indexed_sector(floppy_image_legacy *floppy, int head, int track, int sector_index, int *cylinder, int *side, int *sector, UINT32 *sector_length, void *buffer, unsigned long *flags)
-{
- /* Read track, head */
- int byte = 0;
- struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
- dynamic_buffer track_data(tag->track_size);
- int imgtrack = track;
- int i;
- floperr_t err;
- floperr_t retval;
-
- if (use_80_track_drives && tag->tracks<=40)
- {
- imgtrack = track / 2;
- }
-
- err = ti99_tdf_read_track_internal(floppy, head, imgtrack, 0, &track_data[0], tag->track_size);
- if (err)
- {
- return err;
- }
-
- /* Search for the sector_index-th sector. */
-
- if (tag->first_idam==0) /* should we check for every track? */
- {
- if (determine_offset(tag->format, &track_data[0], &tag->first_idam)==FLOPPY_ERROR_SEEKERROR)
- {
- return FLOPPY_ERROR_SEEKERROR;
- }
- }
-
- i=0;
- sector_index = sector_index+1;
- while (i++ < tag->track_size && sector_index>0)
- {
- byte = read_byte(tag->format, tag->first_idam, &track_data[0], i);
- if (byte == TI99_IDAM)
- {
- sector_index--;
- }
- }
-
- retval = FLOPPY_ERROR_SEEKERROR;
- if (sector_index==0)
- {
- /* If desired, return the ID field */
- if (cylinder)
- {
- *cylinder = track_data[i];
- // printf("cylinder=%d", *cylinder);
-
- }
- if (side)
- {
- *side = track_data[i+1];
- // printf(", side=%d", *side);
- }
- if (sector)
- {
- *sector = track_data[i+2];
- // printf(", sector=%d", *sector);
- }
- if (sector_length)
- {
- *sector_length = 128 << track_data[i+3];
- // printf(", sector_length=%d\n", *sector_length);
- }
- if (flags)
- {
- *flags = 0;
- }
- retval = FLOPPY_ERROR_SUCCESS;
-
- /* If desired, return the sector contents. */
- if (buffer)
- {
- while (i++ < tag->track_size)
- {
- byte = read_byte(tag->format, tag->first_idam, &track_data[0], i);
- if (byte == TI99_DAM)
- break;
- }
- if (byte == TI99_DAM)
- {
- memcpy(buffer, &track_data[i+1], SECTOR_SIZE);
- }
- else
- {
- retval = FLOPPY_ERROR_SEEKERROR;
- }
- }
- }
- return retval;
-}
-
-/*
- Required for ReadAddress command. This function gets the 1st, 2nd, 3rd,
- sector (and so on) from the track, not sector 1, 2, 3. That is, the
- returned sector info depends on the interleave and the start sector.
-*/
-static floperr_t ti99_tdf_get_indexed_sector_info(floppy_image_legacy *floppy, int head, int track, int sector_index, int *cylinder, int *side, int *sector, UINT32 *sector_length, unsigned long *flags)
-{
- return ti99_tdf_find_indexed_sector(floppy, head, track, sector_index, cylinder, side, sector, sector_length, NULL, flags);
-}
-
-static floperr_t ti99_tdf_read_indexed_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen)
-{
- return ti99_tdf_find_indexed_sector(floppy, head, track, sector, (int*)NULL, (int*)NULL, (int*)NULL, (UINT32*)NULL, buffer, (unsigned long*)NULL);
-}
-
-
-/*
- Guess the geometry of the disk.
- 1. Check whether the disk is formatted, and if so, whether it is
- a FM or a MFM disk
- 2. If this fails, guess from the file size which format it should have
-
- SDF formats have sizes which are multiples of 10KiB.
- TDF: full sector size FM (MFM) = 334 (340) bytes
- additional track data FM (MFM) = 247 (752) bytes
-
- => check whether size is dividable by 40 (or 35) and by 2
- => get track size
- => subtract track data
- => divide by 334 or 340
- => number of sectors should be 8, 9, 16, 18, 32, or 36
-
- SSDD is 274880, but DSSD is 260240, so they differ (unlike in the SDF format)
- Still, we cannot tell apart single-sided 80 track formats from double-sided
- 40 tracks. We assume the latter. Moreover, we only attempt to detect
- 9/18/36 sectors (no 8/16) and 40 tracks (no 35).
-
- SSSD40 = 130120
- DSSD = 260240
- SSDD = 274880
- DSDD = 549760
- DSHD = 1039360
- DSDD80 = 1099520
- DSHD80 = 2078720
-*/
-static int ti99_tdf_guess_geometry(floppy_image_legacy *floppy, UINT64 size,
- struct ti99dsk_geometry *geometry)
-{
- int idamcnt, state, track, head, i, totalseclen = 0, format = 0, byte, tracklength, trackadd = 0;
- int first_idam = 0;
- /* Allocate enough bytes to hold the longest supported track. */
- dynamic_buffer track_data(13000);
- /*int offset;*/
-
- struct ti99dsk_geometry dummy_geometry;
-
- if (geometry)
- memset(geometry, 0, sizeof(*geometry));
- else
- geometry = &dummy_geometry;
-
- floppy_image_read(floppy, &track_data[0], 0, 13000);
-
- if (determine_offset(TI99_MFM, &track_data[0], &first_idam)==FLOPPY_ERROR_SEEKERROR)
- {
- /* MFM failed. */
- if (determine_offset(TI99_FM, &track_data[0], &first_idam)==FLOPPY_ERROR_SEEKERROR)
- {
- LOG_FORMATS("IDAM not found. Unformatted disk.\n");
-
- // FM failed as well. Disk is not formatted. We assume
- // a format that fits into the space provided by the file.
- // We only give a moderate vote in this case, so SDF
- // make take it.
-
- if (size < 130120 || size > 2078720)
- {
- LOG_FORMATS("Unknown format size: %d\n", (int)size);
- return 0;
- }
- if (size >= 130120 && size < 260240)
- {
- /* SSSD */
- geometry->sides = 1;
- geometry->tracksperside = 40;
- geometry->secspertrack = 9;
- geometry->density = 1;
- return 50;
- }
- if (size >= 260240 && size < 274880)
- {
- /* DSSD */
- geometry->sides = 2;
- geometry->tracksperside = 40;
- geometry->secspertrack = 9;
- geometry->density = 1;
- return 50;
- }
- if (size >= 274880 && size < 549760)
- {
- /* SSDD */
- geometry->sides = 1;
- geometry->tracksperside = 40;
- geometry->secspertrack = 18;
- geometry->density = 2;
- return 50;
- }
- if (size >= 549760 && size < 1039360)
- {
- /* DSDD */
- geometry->sides = 2;
- geometry->tracksperside = 40;
- geometry->secspertrack = 18;
- geometry->density = 2;
- return 50;
- }
- if (size >= 1039360 && size < 1099520)
- {
- /* DSHD */
- geometry->sides = 2;
- geometry->tracksperside = 40;
- geometry->secspertrack = 36;
- geometry->density = 2;
- return 50;
- }
- if (size >= 1099520 && size < 2078720)
- {
- /* DSDD80 */
- geometry->sides = 2;
- geometry->tracksperside = 80;
- geometry->secspertrack = 18;
- geometry->density = 2;
- return 50;
- }
- if (size == 2078720)
- {
- /* DSHD80 */
- geometry->sides = 2;
- geometry->tracksperside = 80;
- geometry->secspertrack = 36;
- geometry->density = 2;
- return 50;
- }
- }
- else
- {
- /* FM format */
- totalseclen = TI99_FM_TOTAL_SECTOR;
- trackadd = TI99_FM_TRACK_ADD; /* additional track data (gaps etc.) */
- geometry->density = 1;
- format = TI99_FM;
- }
- }
- else
- {
- /* MFM format */
- totalseclen = TI99_MFM_TOTAL_SECTOR;
- trackadd = TI99_MFM_TRACK_ADD;
- geometry->density = 2;
- format = TI99_MFM;
- }
-
- /* Count the number of IDAMs on track 0, head 0 */
- idamcnt = 0;
- state = 0;
- track = 0;
- head = 0;
- i=0;
-
- while (i++ < 13000 && head == 0 && track == 0)
- {
- byte = read_byte(format, first_idam, &track_data[0], i);
- switch (state)
- {
- case 0:
- if (byte==TI99_IDAM)
- state = 1;
- break;
- case 1:
- track = byte;
- state = 2;
- break;
- case 2:
- head = byte;
- state = 3;
- break;
- case 3:
- idamcnt++;
- state = 0;
- }
- }
- LOG_FORMATS("Determined %d sectors\n", idamcnt);
-
- // Now calculate the geometry
- // The track size, in theory, may change due to reformatting,
- // and it may also vary between tracks, but the TDF does not support
- // varying track lengths. So every track has the same length as track 0.
- // Also, we don't yet know whether the drive and the disk have the
- // same track count. For 80 track drives and 40 track disks, we need
- // double-stepping; this will be known as soon as the controller is
- // initialized; we need to check that in the access methods.
-
- tracklength = idamcnt * totalseclen + trackadd;
- /*offset = 0;*/
-
- // Read the last track. We assume that all tracks are properly
- // formatted; otherwise, the above calculations would already fail.
- // That is, the last track in the image tells us whether it is for
- // head 0 or for head 1.
-
- geometry->sides = 1;
- floppy_image_read(floppy, &track_data[0], size-tracklength, tracklength);
- if (determine_offset(format, &track_data[0], &first_idam)==FLOPPY_ERROR_SEEKERROR)
- {
- /* error ... what now? */
- LOG_FORMATS("Error when reading last track. Image broken.\n");
- return 50;
- }
- else
- {
- if (track_data[first_idam+2]==0)
- {
- geometry->sides = 1;
- }
- else
- {
- if (track_data[first_idam+2]==1)
- {
- geometry->sides = 2;
- }
- else
- {
- LOG_FORMATS("Error: Last track has invalid first IDAM: head = %d.\n", track_data[first_idam+2]);
- }
-
- }
- }
-
-
- geometry->tracksperside = (size / tracklength) / geometry->sides;
- geometry->secspertrack = idamcnt;
-
- if (geometry->tracksperside < 35 || geometry->tracksperside > 80)
- {
- LOG_FORMATS("Unsupported track count: %d\n", geometry->tracksperside);
- return 0;
- }
-
- return 100;
-}
-
-static FLOPPY_IDENTIFY(ti99_tdf_identify)
-{
- UINT64 size;
- size = floppy_image_size(floppy);
- *vote = ti99_tdf_guess_geometry(floppy, size, NULL);
- LOG_FORMATS("TDF voting %d\n", *vote);
- return FLOPPY_ERROR_SUCCESS;
-}
-
-static FLOPPY_CONSTRUCT(ti99_tdf_construct)
-{
- struct ti99dsk_geometry geometry;
- struct FloppyCallbacks *callbacks;
- struct ti99dsk_tag *tag;
- LOG_FORMATS("Reading image as TDF\n");
- if (params)
- {
- /* create */
- memset(&geometry, 0, sizeof(geometry));
-/*
- geometry.sides = option_resolution_lookup_int(params, PARAM_HEADS);
- geometry.tracksperside = option_resolution_lookup_int(params, PARAM_TRACKS);
- geometry.secspertrack = option_resolution_lookup_int(params, PARAM_SECTORS);
-*/
- }
- else
- {
- /* load */
- if (ti99_tdf_guess_geometry(floppy, floppy_image_size(floppy), &geometry)<50)
- return FLOPPY_ERROR_INVALIDIMAGE;
- }
-
- assert(geometry.sides);
- assert(geometry.tracksperside);
- assert(geometry.secspertrack);
-
- tag = (struct ti99dsk_tag *) floppy_create_tag(floppy, sizeof(struct ti99dsk_tag));
-
- tag->heads = geometry.sides;
- tag->tracks = geometry.tracksperside;
-
- if (geometry.density==TI99_FM)
- tag->track_size = geometry.secspertrack * TI99_FM_TOTAL_SECTOR + TI99_FM_TRACK_ADD;
- else
- tag->track_size = geometry.secspertrack * TI99_MFM_TOTAL_SECTOR + TI99_MFM_TRACK_ADD;
-
- tag->format = geometry.density;
- tag->first_idam = 0; /* let's find out later */
- tag->dam_offset = 0;
-
- /* set up format callbacks */
- callbacks = floppy_callbacks(floppy);
- callbacks->read_sector = ti99_tdf_read_sector;
- callbacks->write_sector = ti99_tdf_write_sector;
- callbacks->read_indexed_sector = ti99_tdf_read_indexed_sector;
- callbacks->write_indexed_sector = ti99_tdf_write_indexed_sector;
- callbacks->read_track = ti99_tdf_read_track;
- callbacks->write_track = ti99_tdf_write_track;
-/* callbacks->format_track = ti99_tdf_format_track; */
- callbacks->get_track_size = ti99_get_track_size;
- /* post format unset */
- callbacks->get_heads_per_disk = ti99_get_heads_per_disk;
- callbacks->get_tracks_per_disk = ti99_get_tracks_per_disk;
- callbacks->get_sector_length = ti99_get_sector_length;
- callbacks->get_indexed_sector_info = ti99_tdf_get_indexed_sector_info;
-
- return FLOPPY_ERROR_SUCCESS;
-}
-
-/* ----------------------------------------------------------------------- */
-
-LEGACY_FLOPPY_OPTIONS_START( ti99 )
- LEGACY_FLOPPY_OPTION( ti99_sdf, "dsk", "TI99 sector dump (v9t9)", ti99_sdf_identify, ti99_sdf_construct, NULL,
- HEADS([1]-2)
- TRACKS(35-[40]-80)
- SECTORS(8/9/16/[18]/36)
- SECTOR_LENGTH([256])
- FIRST_SECTOR_ID(0))
- LEGACY_FLOPPY_OPTION( ti99_tdf, "dsk,dtk", "TI99 track dump (pc99)", ti99_tdf_identify, ti99_tdf_construct, NULL,
- TRACKS(35-[40]-80)
- SECTORS(8/9/16/[18]/36)
- SECTOR_LENGTH([256])
- FIRST_SECTOR_ID(0))
-LEGACY_FLOPPY_OPTIONS_END