Next: , Previous: , Up: The emulator file formats   [Contents][Index]


17.5 The D64 disk image format

(This section was contributed by Peter Schepers and slightly edited by Marco van den Heuvel. Added 42 track info by groepaz)

First and foremost we have D64, which is basically a sector-for-sector copy of a 1540/1541 disk. There are several versions of these which I will cover shortly. The standard D64 is a 174848 byte file comprised of 256 byte sectors arranged in 35 tracks with a varying number of sectors per track for a total of 683 sectors. Track counting starts at 1, not 0, and goes up to 35. Sector counting starts at 0, not 1, for the first sector, therefore a track with 21 sectors will go from 0 to 20.

The original media (a 5.25" disk) has the tracks laid out in circles, with track 1 on the very outside of the disk (closest to the sides) to track 35 being on the inside of the disk (closest to the inner hub ring). Commodore, in their infinite wisdom, varied the number of sectors per track and data densities across the disk to optimize available storage, resulting in the chart below. It shows the sectors/track for a standard D64. Since the outside diameter of a circle is the largest (versus closer to the center), the outside tracks have the largest amount of storage.

TrackSectors/track# Sectors
1-1721357
18-2419133
25-3018108
31-351785
36-40(*)1785
41-42(*)1734
Track#Sect#SectorsInD64 Offset
1210$00000
22121$01500
32142$02A00
42163$03F00
52184$05400
621105$06900
721126$07E00
821147$09300
921168$0A800
1021189$0BD00
1121210$0D200
1221231$0E700
1321252$0FC00
1421273$11100
1521294$12600
1621315$13B00
1721336$15000
1819357$16500
1919376$17800
2019395$18B00
2119414$19E00
2219433$1B100
2319452$1C400
2419471$1D700
2518490$1EA00
2618508$1FC00
2718526$20E00
2818544$22000
2918562$23200
3018580$24400
3117598$25600
3217615$26700
3317632$27800
3417649$28900
3517666$29A00
36(*)17683$2AB00
37(*)17700$2BC00
38(*)17717$2CD00
39(*)17734$2DE00
40(*)17751$2EF00
41(*)17768$30000
42(*)17785$31100

(*) Tracks 36-40 apply to 40- and 42-track images only. (*) Tracks 41-42 apply to 42-track images only.

The directory track should be contained totally on track 18. Sectors 1-18 contain the entries and sector 0 contains the BAM (Block Availability Map) and disk name/ID. Since the directory is only 18 sectors large (19 less one for the BAM), and each sector can contain only 8 entries (32 bytes per entry), the maximum number of directory entries is 18 * 8 = 144. The first directory sector is always 18/1, even though the t/s pointer at 18/0 (first two bytes) might point somewhere else. It then follows the same chain structure as a normal file, using a sector interleave of 3. This makes the chain links go 18/1, 18/4, 18/7 etc.

Note that you can extend the directory off of track 18, but only when reading the disk or image. Attempting to write to a directory sector not on track 18 will cause directory corruption. Each directory sector has the following layout (18/1 partial dump):

 00: 12 04 81 11 00 4E 41 4D 45 53 20 26 20 50 4F 53 <- notice the T/S link
 10: 49 54 A0 A0 A0 00 00 00 00 00 00 00 00 00 15 00 <- to 18/4 ($12/$04)
 20: 00 00 84 11 02 41 44 44 49 54 49 4F 4E 41 4C 20 <- and how its not here
 30: 49 4E 46 4F A0 11 0C FE 00 00 00 00 00 00 61 01 <- ($00/$00)

The first two bytes of the sector ($12/$04) indicate the location of the next track/sector of the directory (18/4). If the track is set to $00, then it is the last sector of the directory. It is possible, however unlikely, that the directory may *not* be competely on track 18 (some disks do exist like this). Just follow the chain anyhow.

When the directory is done, the track value will be $00. The sector link should contain a value of $FF, meaning the whole sector is allocated, but the actual value doesn’t matter. The drive will return all the available entries anyways.

This is a breakdown of a standard directory sector:

BytesDescription
$00-$1FFirst directory entry
$20-$3FSecond dir entry
$40-$5FThird dir entry
$60-$7FFourth dir entry
$80-$9FFifth dir entry
$A0-$BFSixth dir entry
$C0-$DFSeventh dir entry
$E0-$FFEighth dir entry

This is a breakdown of a standard directory entry:

BytesDescription
$00-$01Track/Sector location of next directory sector ($00 $00 if not the first entry in the sector)
$02File type
$03-$04Track/sector location of first sector of file
$05-$1416 character filename (in PETASCII, padded with $A0)
$15-$16Track/Sector location of first side-sector block (REL file only)
$17REL file record length (REL file only, max. value 254)
$18-$1DUnused (except with GEOS disks)
$1E-$1FFile size in sectors, low/high byte order ($1E+$1F*256). The approx. filesize in bytes is <= #sectors * 254

The file type field is used as follows:

BitsDescription
0-3The actual file type
4Unused
5Used only during SAVE-@ replacement
6Locked flag (Set produces ">" locked files)
7Closed flag (Not set produces "*", or "splat" files)

The actual file type can be one of the following:

BinaryDecimalFile type
00000DEL
00011SEQ
00102PRG
00113USR
01004REL

Values 5-15 are illegal, but if used will produce very strange results. The 1541 is inconsistent in how it treats these bits. Some routines use all 4 bits, others ignore bit 3, resulting in values from 0-7.

Files, on a standard 1541, are stored using an interleave of 10. Assuming a starting track/sector of 17/0, the chain would run 17/0, 17/10, 17/20, 17/8, 17/18, etc.

17.5.1 Non-Standard & Long Directories

Most Commdore floppy disk drives use a single dedicated directory track where all filenames are stored. This limits the number of files stored on a disk based on the number of sectors on the directory track. There are some disk images that contain more files than would normally be allowed. This requires extending the directory off the default directory track by changing the last directory sector pointer to a new track, allocating the new sectors in the BAM, and manually placing (or moving existing) file entries there. The directory of an extended disk can be read and the files that reside there can be loaded without problems on a real drive. However, this is still a very dangerous practice as writing to the extended portion of the directory will cause directory corruption in the non-extended part. Many of the floppy drives core ROM routines ignore the track value that the directory is on and assume the default directory track for operations.

To explain: assume that the directory has been extended from track 18 to track 19/6 and that the directory is full except for a few slots on 19/6. When saving a new file, the drive DOS will find an empty file slot at 19/6 offset $40 and correctly write the filename and a few other things into this slot. When the file is done being saved the final file information will be written to 18/6 offset $40 instead of 19/6 causing some directory corruption to the entry at 18/6. Also, the BAM entries for the sectors occupied by the new file will not be saved and the new file will be left as a SPLAT (*) file.

Attempts to validate the disk will result in those files residing off the directory track to not be allocated in the BAM, and could also send the drive into an endless loop. The default directory track is assumed for all sector reads when validating so if the directory goes to 19/6, then the validate code will read 18/6 instead. If 18/6 is part of the normal directory chain then the validate routine will loop endlessly.

17.5.2 BAM layout

The layout of the BAM area (sector 18/0) is a bit more complicated…

     00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
     -----------------------------------------------
 00: 12 01 41 00 12 FF F9 17 15 FF FF 1F 15 FF FF 1F
 10: 15 FF FF 1F 12 FF F9 17 00 00 00 00 00 00 00 00
 20: 00 00 00 00 0E FF 74 03 15 FF FF 1F 15 FF FF 1F
 30: 0E 3F FC 11 07 E1 80 01 15 FF FF 1F 15 FF FF 1F
 40: 15 FF FF 1F 15 FF FF 1F 0D C0 FF 07 13 FF FF 07
 50: 13 FF FF 07 11 FF CF 07 13 FF FF 07 12 7F FF 07
 60: 13 FF FF 07 0A 75 55 01 00 00 00 00 00 00 00 00
 70: 00 00 00 00 00 00 00 00 01 08 00 00 03 02 48 00
 80: 11 FF FF 01 11 FF FF 01 11 FF FF 01 11 FF FF 01
 90: 53 48 41 52 45 57 41 52 45 20 31 20 20 A0 A0 A0
 A0: A0 A0 56 54 A0 32 41 A0 A0 A0 A0 00 00 00 00 00
 B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
BytesDescription
$00-$01Track/Sector location of the first directory sector (should be set to 18/1 but it doesn’t matter, and don’t trust what is there, always go to 18/1 for first directory entry)
$02Disk DOS version type (see note below) $41 ("A")
$03Unused
$04-$8FBAM entries for each track, in groups of four bytes per track, starting on track 1 (see below for more details)
$90-$9FDisk Name (padded with $A0)
$A0-$A1Filled with $A0
$A2-$A3Disk ID
$A4Usually $A0
$A5-$A6DOS type, usually "2A"
$A7-$AAFilled with $A0
$ABUnused ($00)
$AC-$BFFor DOLPHIN DOS track 36-40 BAM entries, otherwise unused ($00)
$C0-$D3For SPEED DOS track 36-40 BAM entries, otherwise unused ($00)
$D4-$FF Unused ($00)

Note: The BAM entries for SPEED, DOLPHIN and ProLogic DOS use the same layout as standard BAM entries. One of the interesting things from the BAM sector is the byte at offset $02, the DOS version byte. If it is set to anything other than $41 or $00, then we have what is called "soft write protection". Any attempt to write to the disk will return the "DOS Version" error code 73 ,"CBM DOS V 2.6 1541". The 1541 is simply telling you that it thinks the disk format version is incorrect. This message will normally come up when you first turn on the 1541 and read the error channel. If you write a $00 or a $41 into 1541 memory location $00FF (for device 0), then you can circumvent this type of write-protection, and change the DOS version back to what it should be.

The BAM entries require a bit (no pun intended) more of a breakdown. Take the first entry at bytes $04-$07 ($12 $FF $F9 $17). The first byte ($12) is the number of free sectors on that track. Since we are looking at the track 1 entry, this means it has 18 (decimal) free sectors. The next three bytes represent the bitmap of which sectors are used/free. Since it is 3 bytes (8 bits/byte) we have 24 bits of storage. Remember that at most, each track only has 21 sectors, so there are a few unused bits.

BytesDataDescription
$04-$07$12 $FF $F9 $17Track 1 BAM
$08-$0B$15 $FF $FF $FFTrack 2 BAM
$0C-$0F$15 $FF $FF $1FTrack 3 BAM
$8C-$8F$11 $FF $FF $01Track 35 BAM

These entries must be viewed in binary to make any sense. We will use the first entry (track 1) at bytes 04-07:

 FF=11111111, F9=11111001, 17=00010111

In order to make any sense from the binary notation, flip the bits around.

            111111 11112222
 01234567 89012345 67890123
 --------------------------
 11111111 10011111 11101000
 ^                     ^
 sector 0           sector 20

Since we are on the first track, we have 21 sectors, and only use up to the bit 20 position. If a bit is on (1), the sector is free. Therefore, track 1 has sectors 9, 10 and 19 used, all the rest are free. Any leftover bits that refer to sectors that don’t exist, like bits 21-23 in the above example, are set to allocated.

Each filetype has its own unique properties, but most follow one simple structure. The first file sector is pointed to by the directory and follows a t/s chain, until the track value reaches $00. When this happens, the value in the sector link location indicates how much of the sector is used. For example, the following chain indicates a file 6 sectors long, and ends when we encounter the $00/$34 chain. At this point the last sector occupies from bytes $02-$34.

123456
—-—-—-—-—-—-
17/017/1017/2017/117/110/52
(11/00)(11/0A)(11/14)(11/01)(11/0B)(0/34)

17.5.3 Variations on the D64 layout

These are some variations of the D64 layout:

1. Standard 35 track layout but with 683 error bytes added on to the end of the file. Each byte of the error info corresponds to a single sector stored in the D64, indicating if the sector on the original disk contained an error. The first byte is for track 1/0, and the last byte is for track 35/16.

2. A 40 track layout, following the same layout as a 35 track disk, but with 5 extra tracks. These contain 17 sectors each, like tracks 31-35. Some of the PC utilities do allow you to create and work with these files. This can also have error bytes attached like variant #1.

3. A 42 track layout, with two extra tracks of 17 sectors each. This is extremely uncommon, since real drives often have problems with accessing these tracks, software that uses them is very rare.

4. The Commodore 128 allowed for "auto-boot" disks. With this, t/s 1/0 holds a specific byte sequence which the computer recognizes as boot code.

Below is a small chart detailing the standard file sizes of D64 images, 35, 40 or 42 tracks, with or without error bytes.

Disk typeSize
35 track, no errors174848
35 track, 683 error bytes175531
40 track, no errors196608
40 track, 768 error bytes197376
42 track, no errors205312
42 track, 802 error bytes206114

The following table (provided by Wolfgang Moser) outlines the differences between the standard 1541 DOS and the various "speeder" DOS’s that exist. The ’header 7/8’ category is the ’fill bytes’ as the end of the sector header of a real 1541 disk.

Disk formattracksheader 7/8Dos typeDiskdos vs. type
Original CBM DOS v2.635$0f $0f"2A"$41/’A’
*SpeedDOS+40$0f $0f"2A"$41/’A’
Professional DOS Initial35$0f $0f"2A"$41/’A’
Professional DOS Version 1/Prototype40$0f $0f"2A"$41/’A’
ProfDOS Release40$0f $0f"4A"$41/’A’
Dolphin-DOS 2.0/3.035$0f $0f"2A"$41/’A’
Dolphin-DOS 2.0/3.040$0d $0f"2A"$41/’A’
PrologicDOS 154135$0f $0f"2A"$41/’A’
PrologicDOS 154140$0f $0f"2P"$50/’P’
ProSpeed 1571 2.035$0f $0f"2A"$41/’A’
ProSpeed 1571 2.040$0f $0f"2P"$50/’P’

*Note: There are also clones of SpeedDOS that exist, such as RoloDOS and DigiDOS. Both are just a change of the DOS startup string.

The location of the extra BAM information in sector 18/0, for 40 track images, will be different depending on what standard the disks have been formatted with. SPEED DOS stores them from $C0 to $D3, DOLPHIN DOS stores them from $AC to $BF and PrologicDOS stored them right after the existing BAM entries from $90-A3. PrologicDOS also moves the disk label and ID forward from the standard location of $90 to $A4. 64COPY and Star Commander let you select from several different types of extended disk formats you want to create/work with.

All three of the speeder DOS’s mentioned above don’t alter the standard sector interleave of 10 for files and 3 for directories. The reason is that they use a memory cache installed in the drive which reads the entire track in one pass. This alleviates the need for custom interleave values. They do seem to alter the algorithm that finds the next available free sector so that the interleave value can deviate from 10 under certain circumstances, but I don’t know why they would bother.

Below is a HEX dump of a Speed DOS BAM sector. Note the location of the extra BAM info from $C0-D3.

       00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
       -----------------------------------------------
 0070: 12 FF FF 03 12 FF FF 03 12 FF FF 03 11 FF FF 01
 0080: 11 FF FF 01 11 FF FF 01 11 FF FF 01 11 FF FF 01
 0090: A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0
 00A0: A0 A0 30 30 A0 32 41 A0 A0 A0 A0 00 00 00 00 00
 00B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00C0: 11 FF FF 01 11 FF FF 01 11 FF FF 01 11 FF FF 01
 00D0: 11 FF FF 01 00 00 00 00 00 00 00 00 00 00 00 00

Below is a HEX dump of a Dolphin DOS BAM sector. Note the location of the extra BAM info from $AC-BF.

       00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
       -----------------------------------------------
 0070: 12 FF FF 03 12 FF FF 03 12 FF FF 03 11 FF FF 01
 0080: 11 FF FF 01 11 FF FF 01 11 FF FF 01 11 FF FF 01
 0090: A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0
 00A0: A0 A0 30 30 A0 32 41 A0 A0 A0 A0 00 11 FF FF 01
 00B0: 11 FF FF 01 11 FF FF 01 11 FF FF 01 11 FF FF 01
 00C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Below is a HEX dump of a PrologicDOS BAM sector. Note that the disk name and ID are now located at $A4 instead of starting at $90.

       00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
       -----------------------------------------------
 0070: 12 FF FF 03 12 FF FF 03 12 FF FF 03 11 FF FF 01
 0080: 11 FF FF 01 11 FF FF 01 11 FF FF 01 11 FF FF 01
 0090: 11 FF FF 01 11 FF FF 01 11 FF FF 01 11 FF FF 01
 00A0: 11 FF FF 01 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0
 00B0: A0 A0 A0 A0 A0 A0 30 30 A0 32 50 A0 A0 A0 A0 00
 00C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

17.5.4 Error codes

Here is the meaning of the error bytes added onto the end of any extended D64. The CODE is the same as that generated by the 1541 drive controller… it reports these numbers, not the error code we usually see when an error occurs.

Some of what comes below is taken from Immers/Neufeld book "Inside Commodore DOS". Note the descriptions are not completely accurate as to what the drive DOS is actually doing to seek/read/decode/write sectors, but serve as simple examples only. The "type" field is where the error usually occurs, whether it’s searching for any SYNC mark, any header ID, any valid header, or reading a sector.

CodeErrorTypeD64Description
$0100N/A*No error.
$0220Seek*Header block not found / Header descriptor byte not found
$0321Seek*No SYNC sequence found
$0422Read*Data descriptor byte not found
$0523Read*Checksum error in data block
$0624WriteWrite verify on format (never occurs on 1541)
$0725WriteWrite verify error
$0826WriteWrite protect on
$0927Seek*Checksum error in header block
$0A28WriteWrite error (never occurs on 1541)
$0B29Seek*Disk sector ID mismatch
$0F74ReadDrive Not Ready (no disk in drive or no device 1)

Codes $0 and $C to $E are unused and never occur.

These first errors are "seek" errors, where the disk controller is simply reading headers and looking at descriptor bytes, checksums, format ID’s and reporting what errors it sees. These errors do *not* necessarily apply to the exact sector being looked for. This fact makes duplication of these errors very unreliable.

Code : $03 Error : 21 Type : Seek Message : No SYNC sequence found.

Each sector data block and header block are preceeded by SYNC marks. If *no* sync sequence is found within 20 milliseconds (only ~1/10 of a disk rotation!) then this error is generated. This error used to mean the entire track is bad, but it does not have to be the case. Only a small area of the track needs to be without a SYNC mark and this error will be generated.

Converting this error to a D64 is very problematic because it depends on where the physical head is on the disk when a read attempt is made. If it is on valid header/sectors then it won’t occur. If it happens over an area without SYNC marks, it will happen.

Code : $02 Error : 20 Type : Seek Message : Header descriptor byte not found (HEX $08, GCR $52)

Each sector is preceeded by an 8-byte GCR header block, which starts with the value $52 (GCR). If this value is not found after 90 attempts, this error is generated.

Basically, what a track has is SYNC marks, and possibly valid data blocks, but no valid header descriptors.

Code : $09 Error : 27 Type : Seek Message : Checksum error in header block

The header block contains a checksum value, calculated by XOR’ing the TRACK, SECTOR, ID1 and ID2 values. If this checksum is wrong, this error is generated.

Code : $0B Error : 29 Type : Seek Message : Disk sector ID mismatch

The ID’s from the header block of the currently read sector are compared against the ones from the low-level header of 18/0. If there is a mismatch, this error is generated.

Code : $02 Error : 20 Type : Seek Message : Header block not found

This error can be reported again when searching for the correct header block. An image of the header is built and searched for, but not found after 90 read attempts. Note the difference from the first occurance. The first one only searches for a valid ID, not the whole header.

Note that error 20 occurs twice during this phase. The first time is when a header ID is being searched for, the second is when the proper header pattern for the sector being searched for is not found.

From this point on, all the errors apply to the specific sector you are looking for. If a read passed all the previous checks, then we are at the sector being searched for.

Note that the entire sector is read before these errors are detected. Therefore the data, checksum and off bytes are available.

Code : $04 Error : 22 Type : Read Message : Data descriptor byte not found (HEX $07, GCR $55)

Each sector data block is preceeded by the value $07, the "data block" descriptor. If this value is not there, this error is generated. Each encoded sector has actually 260 bytes. First is the descriptor byte, then follows the 256 bytes of data, a checksum, and two "off" bytes.

Code : $05 Error : 23 Type : Read Message : Checksum error in data block

The checksum of the data read of the disk is calculated, and compared against the one stored at the end of the sector. If there’s a discrepancy, this error is generated.

Code : $0F Error : 74 Type : Read Message : Drive Not Ready (no disk in drive or no device 1)

These errors only apply when writing to a disk. I don’t see the usefulness of having these as they cannot be present when only *reading* a disk.

Code : $06 Error : 24 Type : Write Message : Write verify (on format)

Code : $07 Error : 25 Type : Write Message : Write verify error

Once the GCR-encoded sector is written out, the drive waits for the sector to come around again and verifies the whole 325-byte GCR block. Any errors encountered will generate this error.

Code : $08 Error : 26 Type : Write Message : Write protect on

Self explanatory. Remove the write-protect tab, and try again.

Code : $0A Error : 28 Type : Write Message : Write error

In actual fact, this error never occurs, but it is included for completeness.

This is not an error at all, but it gets reported when the read of a sector is ok.

Code : $01 Error : 00 Type : N/A Message : No error.

Self explanatory. No errors were detected in the reading and decoding of the sector.

The advantage with using the 35 track D64 format, regardless of error bytes, is that it can be converted directly back to a 1541 disk by either using the proper cable and software on the PC, or send it down to the C64 and writing it back to a 1541. It is the best documented format since it is also native to the C64, with many books explaining the disk layout and the internals of the 1541.


Next: The X64 disk image format, Previous: The G64 GCR-encoded disk image format, Up: The emulator file formats   [Contents][Index]