Common File Formats for Emulated TRS-80 Floppy Disks

Tim Mann
Last revised 4 Jul 2008

Most current TRS-80 Model I/III/4 emulators use one of three common file formats for emulated floppy disk media. The extension .DSK is usually used for all three formats, and some emulators transparently support two or three of them, while others support only one. The two most common formats both originated with emulators written by Jeff Vavasour, while the third originated with an emulator written by David Keil, so I'll take the liberty of giving the formats names that use their initials.

This document describes the JV1 and JV3 formats in complete detail and indicates (where known) which emulators support which. DMK is quite different from JV1 and JV3 and is not described in this document, but there is a description on David Keil's Web page. You probably don't need any of this information unless you are writing an emulator or working with unusual disks.

The JV1 Format

The JV1 format is simply an array of 256-byte sectors stored in a file. Byte 0 of the file is byte 0 of track 0, sector 0; byte 256 is byte 0 of track 0, sector 1, and so forth. There are 10 sectors per track (i.e., single density), numbered 0 through 9, and only one side. Tracks are numbered starting at 0. All sectors on track 17 are formatted with the nonstandard data address mark 0xFA, indicating a TRSDOS 2.3 directory. All other sectors are formatted with the standard data address mark 0xFB.

Note: In emulations of the WD1791/3 floppy disk controller used in the Model III and 4, it is best to present track 17 as being formatted with the standard deleted data address mark 0xF8. The WD1791/3 cannot write 0xFA, and upon reading, returns it as 0xFB. So Model III/4 operating systems use 0xF8 on the directory track instead.

The JV3 Format

The JV3 format consists of a fixed-size array of sector headers, followed by an area containing the data for each sector. As an extension to allow for more sectors, a second block of sector headers and data can follow. Here is the format in pseudo-C notation. The length of each data area depends on the content of the headers, as described below.
typedef struct {
  SectorHeader headers1[2901];
  unsigned char writeprot;
  unsigned char data1[];
  SectorHeader headers2[2901];
  unsigned char padding;
  unsigned char data2[];
} JV3;

Write Protect and Padding

The field writeprot should normally contain 0xFF. As an extension, a value of 0x00 in his field indicates that the disk is write-protected (i.e., it is not writable).

The field padding is currently unused. It should contain 0xFF.

The Sector Header

Each sector in a JV3 file is described by a three-byte header. The first byte gives the sector's track number, the second gives its sector number on the track, and the third is a set of flags.
typedef struct {
  unsigned char track;
  unsigned char sector;
  unsigned char flags;
} SectorHeader;

#define JV3_DENSITY     0x80  /* 1=dden, 0=sden */
#define JV3_DAM         0x60  /* data address mark code; see below */
#define JV3_SIDE        0x10  /* 0=side 0, 1=side 1 */
#define JV3_ERROR       0x08  /* 0=ok, 1=CRC error */
#define JV3_NONIBM      0x04  /* 0=normal, 1=short */
#define JV3_SIZE        0x03  /* in used sectors: 0=256,1=128,2=1024,3=512
                                 in free sectors: 0=512,1=1024,2=128,3=256 */

#define JV3_FREE        0xFF  /* in track and sector fields of free sectors */
#define JV3_FREEF       0xFC  /* in flags field, or'd with size code */

The track field gives both the physical track number on which the sector lies and the logical track number that is formatted in the sector's ID. Numbering starts from 0. Thus it is not possible to represent a copy-protected disk where sectors were deliberately formatted with incorrect track numbers. The format allows for 255 tracks (numbered 0 through 0xFE), but emulators may impose lower limits. You can expect at least 80 tracks to be supported; xtrs currently allows up to 96.

The sector field gives the logical sector number that is formatted into the sector's ID field. The physical order of sectors on the track is not explicitly represented, but xtrs (and perhaps other emulators) present them in the order they are recorded in the JV3 file; thus when a TRS-80 program formats a track with interleave and reads back the sector ids, they come back in the same interleaved order.

The flags field packs in a lot of information:

If a sector header is not in use (free), its track and sector fields must contain 0xFF. Its flags field must contain 0xFC plus the appropriate free JV3_SIZE field value given above.

The Data Blocks

For each sector header, there is one data block. The blocks are placed in the same order as the headers that describe them, and are tightly packed. Thus to find the data block for the nth header, you need to know the total size of data blocks 0 to n - 1. A sector header marked as free does have a corresponding data block, of the size indicated in its size field. However, the file can (and in fact should; see below) end immediately after the last in-use data block.

The Second Header Block

The second header block is present if and only if the file is long enough to contain it. It starts immediately after the last data block described by the first header block. Thus to find the second header block, you need to know the total size of all data blocks described by the first header block.

It's obvious, by the way, how to extend the format to more than two header blocks, but no known emulators support more than two. Having more than two is not useful to describe any floppy format that was supported by any real TRS-80. One block is sufficient for 5.25-inch DD drives, and two are sufficient for 8-inch drives, 5.25-inch HD drives, or 3.5-inch HD drives.

Allocating and Freeing Sectors

Allocating and freeing sectors is a little tricky (if you support the extension to sizes other than 256 bytes). When a new emulated disk is first created, it should have one header block, filled with free 256-byte sectors. When a new sector is formatted, if a free sector of the correct size exists, it can be reused; otherwise, the next sector after the highest in-use sector can be chosen and changed to the correct size. In the latter case, since there is no data after the sector that is being resized, resizing it does not require anything to move. When a sector is erased (because the track it is on is being reformatted), it should normally be freed without changing its size, so that the data of later sectors need not be moved.

If the highest in-use sector is freed, the emulator should search backward for the new highest in-use sector, and should truncate the file to eliminate any sector data for trailing free sectors, as well as the second header block if it is no longer needed. Why do this? If the user reformats some sectors to be shorter or longer than they used to be, the nominal start of the second header block (as defined above) will shift. If you have garbage at the end of the file, and the block shifts to start somewhere in the garbage, then when you read the file back in again later, you'll have a second header block full of garbage that will confuse you.


Here is a summary of which emulators support which formats and which features. The data is believed current as of this document's revision date. Future versions of some of these emulators may support more (or fewer!) features. If an emulator does not support a feature, it will still work with disks created by emulators that do support the feature, as long as those disks didn't require that feature when they were created. For example, an emulator that supports the second header block will not create a second header block unless you format more that 2901 sectors on one disk; note that an 80 track, double sided, double density 5.25-inch disk contains less than 2901 sectors.
  JV1 JV3 Basic features JV3 Write protect JV3 Second header block JV3 Sizes other than  256 JV3 Non-IBM kludge DMK
Jeff Vavasour Model I v3.02u Yes No No No No No No
Jeff Vavasour Model III/4 v2.3 No Yes No (future) No No No No
Matthew Reed Model I/III v1.10 Yes Yes No (future) No (future) No No No
Matthew Reed Model 4 v1.01 Yes Yes Yes Yes No No No
Matthew Reed TRS32 1.0 Yes Yes Yes Yes Yes Yes No
xtrs Model I/III/4 v3.7 Yes Yes Yes Yes Yes Yes Yes
WinTRS80 Model I/III/4 v1.02 Yes Yes Respected but not generated Yes No No No
Yves Lempereur Model I Yes No No No No No No
David Keil Model III/4 Yes Yes, with some limitations Respected but not generated No Yes No Yes

Additional information or corrections for this table are welcome.

Back to the TRS-80 Page | My home page