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


17.9 The D80 disk image format

(This section was contributed by Peter Schepers and slightly edited by Marco van den Heuvel.)

This is a sector-for-sector copy of an 8050 floppy disk. The file size for an 8050 image is 533248 bytes. It is comprised of 256-byte sectors arranged across 77 tracks, with a varying number of sectors per track for a total of 2083 sectors. Track counting starts at 1 (not 0) and sector counting starts at 0 (not 1), therefore a track with 29 sectors will go from 0 to 28.

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 77 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 D80. Since the outside diameter of a circle is the largest (versus closer to the center), the outside tracks have the largest amount of storage.

Track RangeSectors/track# Sectors
1-39291131
40-5327378
54-6425275
65-7723299
Track#Sect#SectorsInD8x Offset
1290$00000
22929$01D00
32958$03A00
42987$05700
529116$07400
629145$09100
729174$0AE00
829203$0CB00
929232$0E800
1029261$10500
1129290$12200
1229319$13F00
1329348$15C00
1429377$17900
1529406$19600
1629435$1B300
1729464$1D000
1829493$1ED00
1929522$20A00
2029551$22700
2129580$24400
2229609$26100
2329638$27E00
2429667$29B00
2529696$2B800
2629725$2D500
2729754$2F200
2829783$30F00
2929812$32C00
3029841$34900
3129870$36600
3229899$38300
3329928$3A000
3429957$3BD00
3529986$3DA00
36291015$3F700
37291044$41400
38291073$43100
39291102$44E00
40271131$46B00
41271158$48600
42271185$4A100
43271212$4BC00
44271239$4D700
45271266$4F200
46271293$50D00
47271320$52800
48271347$54300
49271374$55E00
50271401$57900
51271428$59400
52271455$5AF00
53271482$5CA00
54251509$5E500
55251534$5FE00
56251559$61700
57251584$63000
58251609$64900
59251634$66200
60251659$67B00
61251684$69400
62251709$6AD00
63251734$6C600
64251759$6DF00
65231784$6F800
66231807$70F00
67231830$72600
68231853$73D00
69231876$75400
70231899$76B00
71231922$78200
72231945$79900
73231968$7B000
74231991$7C700
75232014$7DE00
76232037$7F500
77232060$80C00

The BAM (Block Availability Map) is on track 38. The D80 is only 77 tracks and so the BAM is contained on 38/0 and 38/3. The BAM interleave is 3.

The directory is on track 39, with 39/0 contains the header (DOS type, disk name, disk ID’s) and sectors 1-28 contain the directory entries. Both files and the directory use an interleave of 1. Since the directory is only 28 sectors large (29 less one for the header), and each sector can contain only 8 entries (32 bytes per entry), the maximum number of directory entries is 28 * 8 = 224. The first directory sector is always 39/1. It then follows a chain structure using a sector interleave of 1 making the links go 39/1, 39/2, 39/3 etc.

When reading a disk, you start with 39/0 (disk label/ID) which points to 38/0 (BAM0), 38/3 (BAM1), and finally to 39/1 (first dir entry sector). When writing a file to a blank disk, it will start at 38/1 because 38/0 is already allocated.

Below is a dump of the header sector 39/0:

    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
    -----------------------------------------------
00: 26 00 43 00 00 00 73 61 6D 70 6C 65 20 64 38 30
10: A0 A0 A0 A0 A0 A0 A0 A0 65 72 A0 32 43 A0 A0 A0
20: A0 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-$01T/S pointer to first BAM sector (38/0)
$02$43 ’C’ is for DOS format version
$03Reserved
$04-$05Unused
$06-$16Disk name, padded with 0xA0 ("sample d80")
$170xA0
$18-$19Disk ID bytes "er"
$1A0xA0
$1B-$1CDOS version bytes "2C"
$1D-$200xA0
$21-$FFUnused

Below is a dump of the first directory sector, 39/1

    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
    -----------------------------------------------
00: 27 02 82 26 01 54 45 53 54 A0 A0 A0 A0 A0 A0 A0
10: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 01 00
20: 00 00 82 26 02 54 45 53 54 32 A0 A0 A0 A0 A0 A0
30: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 01 00
40: 00 00 82 26 04 54 45 53 54 33 A0 A0 A0 A0 A0 A0
50: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 05 00
60: 00 00 82 26 0B 54 45 53 54 34 A0 A0 A0 A0 A0 A0
70: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 09 00
80: 00 00 82 26 14 54 45 53 54 35 A0 A0 A0 A0 A0 A0
90: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 0C 00
A0: 00 00 82 28 00 54 45 53 54 36 A0 A0 A0 A0 A0 A0
B0: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 01 00
C0: 00 00 82 28 01 54 45 53 54 37 A0 A0 A0 A0 A0 A0
D0: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 01 00
E0: 00 00 82 28 02 54 45 53 54 38 A0 A0 A0 A0 A0 A0
F0: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 01 00

The first two bytes of the directory sector ($27/$02) indicate the location of the next track/sector of the directory (39/2). If the track is set to $00, then it is the last sector of the directory.

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
$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.

17.9.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.

17.9.2 BAM layout

The BAM only occupies up to four sectors on track 38, so the rest of the track is empty and is available for file storage. Below is a dump of the first BAM block, 38/0. A D80 will only contain two BAM sectors, 38/0 and 38/3. Each entry takes 5 bytes, 1 for the free count on that track, and 4 for the BAM bits.

    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
    -----------------------------------------------
00: 26 03 43 00 01 33 1D FF FF FF 1F 1D FF FF FF 1F
10: 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D
20: FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF
30: FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF
40: FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF
50: 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F
60: 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D
70: FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF
80: FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF
90: FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF
A0: 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F
B0: 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1B
C0: F6 FF FF 1F 1B FC FF FF 1F 1B FF FF FF 07 1B FF
D0: FF FF 07 1B FF FF FF 07 1B FF FF FF 07 1B FF FF
E0: FF 07 1B FF FF FF 07 1B FF FF FF 07 1B FF FF FF
F0: 07 1B FF FF FF 07 1B FF FF FF 07 1B FF FF FF 07
BytesDescription
$00-$01T/S pointer to second BAM sector (38/3)
$02DOS version byte (0x43=’C’)
$03Reserved
$04Lowest track covered by this BAM (0x01=1)
$05Highest+1 track covered by this BAM (0x33=51)
$06-$0ABAM for track 1. The first byte shows the "blocks free" for this track, the remaining 4 show the BAM for the track.
$0B-$0FBAM for track 2
$FB-$FFBAM for track 50

Being bit-based, the BAM entries need some explanation. The first track entry in the above BAM sector is at offset 06, "1D FF FF FF 1F". The first number is how many blocks are free on this track ($1D=29) and the remainder is the bit representation of the usage map for the track. These entries must be viewed in binary to make any sense. First convert the values to binary:

 FF=11111111, FF=11111111, FF=11111111, 1F=00011111

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

            111111 11112222 222222
 01234567 89012345 67890123 456789…
 -------------------------- ---------
 11111111 11111111 11111111 11111000
 ^                              ^
 sector 0                   sector 28

Since we are on the first track, we have 29 sectors, and only use up to the bit 28 position. If a bit is on (1), the sector is free. Therefore, track 1 is clean, all sectors are free. Any leftover bits that refer to sectors that don’t exist, like bits 29-31 in the above example, are set to allocated.

Second BAM block 38/3.

    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
    -----------------------------------------------
00: 27 01 43 00 33 4E 1B FF FF FF 07 1B FF FF FF 07
10: 1B FF FF FF 07 19 FF FF FF 01 19 FF FF FF 01 19
20: FF FF FF 01 19 FF FF FF 01 19 FF FF FF 01 19 FF
30: FF FF 01 19 FF FF FF 01 19 FF FF FF 01 19 FF FF
40: FF 01 19 FF FF FF 01 19 FF FF FF 01 17 FF FF 7F
50: 00 17 FF FF 7F 00 17 FF FF 7F 00 17 FF FF 7F 00
60: 17 FF FF 7F 00 17 FF FF 7F 00 17 FF FF 7F 00 17
70: FF FF 7F 00 17 FF FF 7F 00 17 FF FF 7F 00 17 FF
80: FF 7F 00 17 FF FF 7F 00 17 FF FF 7F 00 00 00 00
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
A0: 00 00 00 00 00 00 00 00 00 00 00 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-$01T/S pointer to second BAM sector (39/1)
$02DOS version byte (0x43=’C’)
$03Reserved
$04Lowest track covered by this BAM (0x33=51)
$05Highest+1 track covered by this BAM (0x43=78)
$06-$0ABAM for track 51. The first byte shows the "blocks free" for this track, the remaining 4 show the BAM for the track.
$0B-$0FBAM for track 52
$88-$8CBAM for track 77
$8D-$FFNot used

Next: The D82 disk image format, Previous: The D81 disk image format, Up: The emulator file formats   [Contents][Index]