CBM DOS
Disk format for the C64 1541 disk drive
Table of Contents
The 1541 disk drive used 5.25" disks.
The standard CBM DOS format is 170 KB with 35 tracks and 256-byte sectors providing 165K for storage.
Although standard disks are only 35 tracks, it was mechanically possible to get 40 tracks by using either custom
formatting or third party DOS's.
The format described in this section also applies to .D64
disk images that can be used with both
Emulators like VICE
and the PI1541 attached to a real C64.
1 - Physical layout
Physical Disk Layout for the 1540/1541
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, varied the number of sectors per track and data densities across the disk to optimize available storage.
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 counting starts at 1, not 0, and goes up to 35.
Track's 36…40 are only valid for 40 track disks, although with low-level programming
the 1541 drive could access tracks 36…40.
Some copy-protection schemes did this.
Sector counting starts at 0, not 1, for the first sector, therefore a track with 21 sectors will go from 0 to 20.
Track |
Sectors/Track |
# Sectors |
Storage in bytes |
01 |
17 |
21 |
357 |
7820 |
18 |
24 |
19 |
133 |
7170 |
25 |
30 |
18 |
108 |
6300 |
31 |
35 |
17 |
85 |
6020 |
36* |
40* |
17 |
85 |
6020 |
* Standard CBM DOS disks had only 35 tracks.
2 - Directory Track
Directory track 18
The directory track is contained totally on track 18.
Sectors 1…18 contain the directory entries whilst 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.
Byte |
Content |
|
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
00 |
15 |
Location of next directory sector, 0x0000=end |
8 |
First Directory entry |
01 |
7 |
0 |
02 |
Closed |
Locked |
Save |
|
30File Type |
03 |
15 |
Location of first sector of file |
8 |
04 |
7 |
0 |
05 |
|
Filename in PETASCII padded with 0xA0 |
06 |
07 |
08 |
09 |
0A |
0B |
0C |
0D |
0E |
0F |
10 |
11 |
12 |
13 |
14 |
15 |
15 |
Location of first side-sector block |
8 |
16 |
7 |
0 |
17 |
REL file record length, max value 254 |
18 |
Unused in CBM DOS, GEOS only |
19 |
1A |
1B |
1C |
1D |
1E |
7 |
File size in sectors |
0 |
1F |
15 |
8 |
20 |
Must be set to 0x0000 |
Second Directory entry |
21 |
22 |
Closed |
Locked |
Save |
|
30File Type |
23 |
15 |
Location of first sector of file |
8 |
24 |
7 |
0 |
25 |
|
Filename in PETASCII padded with 0xA0 |
26 |
27 |
28 |
29 |
2A |
2B |
2C |
2D |
2E |
2F |
30 |
31 |
32 |
33 |
34 |
35 |
15 |
Location of first side-sector block |
8 |
36 |
7 |
0 |
37 |
REL file record length, max value 254 |
38 |
Unused in CBM DOS, GEOS only |
39 |
3A |
3B |
3C |
3D |
3E |
7 |
File size in sectors |
0 |
3F |
15 |
8 |
|
|
|
Sector pointers
The sector pointers at offset 0x00, 0x03 & 0x15 are Track/Sector values.
The track number is in the first byte, sector number in the second.
Next directory sector pointer
The next directory sector pointer at offset 0 points to the next directory sector in the chain.
If it's the last entry in the chain then it is set to 0x0000.
It is only valid for the first directory entry.
On file entries other than the first one in the sector this pointer is unused & is set to 0x0000.
File Type
7 |
3 |
2 |
1 |
0 |
Name |
File Type |
0 | 0 | 0 | 0 | 0 | | Scratched, deleted file entry |
1 | 0 | 0 | 0 | 0 | DEL | Deleted |
1 | 0 | 0 | 0 | 1 | SEQ | Sequential |
1 | 0 | 0 | 1 | 0 | PRG | Program |
1 | 0 | 0 | 1 | 1 | USR | User |
1 | 0 | 1 | 0 | 0 | REL | Rel |
All other values are illegal and will produce strange results.
Some routines use all 4 lower bits, some ignore bit 3.
All file types require the Closed
flag (bit 7) to be set.
Only DEL
is valid with Closed
cleared when it indicates a deleted file entry.
File length
The file length is a little endian value with the lsb first, msb last.
It is a sector count, not the file count.
REL files
Bytes with offset 0x15…0x17 are only used for REL files.
3 - Block Availability Map
Directory track 18 sector 0, the BAM and disk details
Track 18 sector 0 contains the Block Availability Map (BAM) and details about the disk including it's title.
Track 18 Sector 0
Byte |
Content |
|
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
00 |
15 |
Location of first directory sector |
8 |
Header |
01 |
7 |
0 |
02 |
DOS version type, normally 0x41 "A" |
03 |
|
04 |
Free sector count Track 1 |
Block Availability Map |
05 |
S7 |
S6 |
S5 |
S4 |
S3 |
S2 |
S1 |
S0 |
06 |
S15 |
S14 |
S13 |
S12 |
S11 |
S10 |
S9 |
S8 |
07 |
|
S20 |
S19 |
S18 |
S17 |
S16 |
08 |
Free sector count Track 2 |
09 |
S7 |
S6 |
S5 |
S4 |
S3 |
S2 |
S1 |
S0 |
0A |
S15 |
S14 |
S13 |
S12 |
S11 |
S10 |
S9 |
S8 |
0B |
|
S20 |
S19 |
S18 |
S17 |
S16 |
|
|
|
44 |
Free sector count Track 17 |
45 |
S7 |
S6 |
S5 |
S4 |
S3 |
S2 |
S1 |
S0 |
46 |
S15 |
S14 |
S13 |
S12 |
S11 |
S10 |
S9 |
S8 |
47 |
|
S20 |
S19 |
S18 |
S17 |
S16 |
48 |
Directory Track 18 = 0 Free |
49 |
All allocated so should be set to 0 |
4A |
as entire track is reserved for the directory |
4B |
|
|
4C |
Free sector count Track 19 |
4D |
S7 |
S6 |
S5 |
S4 |
S3 |
S2 |
S1 |
S0 |
4E |
S15 |
S14 |
S13 |
S12 |
S11 |
S10 |
S9 |
S8 |
4F |
|
S18 |
S17 |
S16 |
|
|
|
60 |
Free sector count Track 24 |
61 |
S7 |
S6 |
S5 |
S4 |
S3 |
S2 |
S1 |
S0 |
62 |
S15 |
S14 |
S13 |
S12 |
S11 |
S10 |
S9 |
S8 |
63 |
|
S18 |
S17 |
S16 |
64 |
Free sector count Track 25 |
65 |
S7 |
S6 |
S5 |
S4 |
S3 |
S2 |
S1 |
S0 |
66 |
S15 |
S14 |
S13 |
S12 |
S11 |
S10 |
S9 |
S8 |
67 |
|
S17 |
S16 |
|
|
|
78 |
Free sector count Track 30 |
79 |
S7 |
S6 |
S5 |
S4 |
S3 |
S2 |
S1 |
S0 |
7A |
S15 |
S14 |
S13 |
S12 |
S11 |
S10 |
S9 |
S8 |
7B |
|
S17 |
S16 |
7C |
Free sector count Track 31 |
7D |
S7 |
S6 |
S5 |
S4 |
S3 |
S2 |
S1 |
S0 |
7E |
S15 |
S14 |
S13 |
S12 |
S11 |
S10 |
S9 |
S8 |
7F |
|
S16 |
|
|
|
8C |
Free sector count Track 35 |
8D |
S7 |
S6 |
S5 |
S4 |
S3 |
S2 |
S1 |
S0 |
8E |
S15 |
S14 |
S13 |
S12 |
S11 |
S10 |
S9 |
S8 |
8F |
|
S16 |
90 |
Disk Name padded with 0xA0 |
Disk title & type |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
9A |
9B |
9C |
9D |
9E |
9F |
A0 |
Unused set to 0xA0A0 |
A1 |
A2 |
7 |
Disk ID |
0 |
A3 |
15 |
8 |
A4 |
Unused set to 0xA0 |
A5 |
DOS type, usually ASCII "2A" |
A6 |
A7 |
Unused set to 0xA0 |
A8 |
A9 |
AA |
AB |
Unused, set to 0x00 |
Reserved |
|
FF |
Offset for each Track BAM entry
Track |
Offset |
01 | 04 |
02 | 08 |
03 | 0C |
04 | 10 |
05 | 14 |
06 | 18 |
07 | 1C |
08 | 20 |
09 | 24 |
10 | 28 |
11 | 2C |
12 | 30 |
13 | 34 |
14 | 38 |
15 | 3C |
16 | 40 |
17 | 44 |
18 | 48 |
19 | 4C |
20 | 50 |
21 | 54 |
22 | 58 |
23 | 5C |
24 | 60 |
25 | 64 |
26 | 68 |
27 | 6C |
28 | 70 |
29 | 74 |
30 | 78 |
31 | 7C |
32 | 80 |
33 | 84 |
34 | 88 |
35 | 8C |
How BAM entries work
Each track has a BAM entry, which consists of 4 bytes.
The first byte is the number of free sectors on that track.
The next three bytes form a bit map of the available sectors in little endian format.
A 1 represents a free sector, whilst a 0 represents an allocated sector.
As there are 24 bits available but tracks range from 16 to 21 sectors then the unavailable
sectors are marked as allocated, i.e. 0.
4 - File format
How files are stored on the disk
In the directory a file's location on the disk is stored with
the first Track/Sector it occupies and the file length is in sectors not bytes.
This is done because on the disk a file is a linked list of sectors with each sector consisting of
two bytes containing the Track/Sector of the next sector then 254 bytes of data.
The last sector of the file is marked when the Track ID is set to 0.
When this happens the Sector portion indicates how many bytes remain for the file,
a value from 1 to 254 bytes.
Byte |
First sectors |
Last sector |
|
00 |
15 |
Next sector location |
8 |
EOF marker |
Header |
01 |
7 |
0 |
Number of bytes |
02 |
254 bytes data |
remaining bytes data |
Data |
nn |
|
Undefined |
FF |
Example
Let's imaging we have a file that's 1322 bytes long spread over 6 sectors.
The first sector of the file is stored at Track 17 Sector 21.
In the directory we have the start sector set to 17/21.
1 |
2 |
3 |
4 |
5 |
6 |
T |
S |
T |
S |
T |
S |
T |
S |
T |
S |
T |
S |
17 |
0 |
17 |
10 |
17 |
20 |
17 |
1 |
17 |
11 |
0 |
52 |
The first 2 bytes of that sector consists of 17 and 0 indicating the next sector is track 17 sector 0.
The rest of that sector is 254 bytes of data.
The second sector at Track 17 Sector 0 consists of 17 and 10 which points to the third sector.
It also has 254 bytes.
The sixth and final sector has Track set to 0. This is not a valid track as they start from 1, so it marks this sector
as the final one in the file.
Here, the sectorId is taken as the number of bytes in this sector which contains data, 52 bytes in this instance.
All other bytes in the sector after the data is ignored.
5 - D64 Image Format
CBM DOS as a single image for Emulators
The .D64
disk image format follows the format as defined for
CBM DOS.
Images of this format can be used in Emulators like
VICE
and the PI1541 attached to a real C64.
As stated in Physical Layout, Track numbers start from 1 but Sectors in a track start from
0.
35 track images are exactly 174848 bytes long whilst a 40 track image is exactly 196608 bytes.
The table below shows the position of the start of each 256 byte sector within the .D64
file.
Track |
Sector |
Sectors In |
D64 Offset |
Track |
Sector |
Sectors In |
D64 Offset |
1 |
21 |
0 |
0x00000 |
21 |
19 |
414 |
0x19E00 |
2 |
21 |
21 |
0x01500 |
22 |
19 |
433 |
0x1B100 |
3 |
21 |
42 |
0x02A00 |
23 |
19 |
452 |
0x1C400 |
4 |
21 |
63 |
0x03F00 |
24 |
19 |
471 |
0x1D700 |
5 |
21 |
84 |
0x05400 |
25 |
18 |
490 |
0x1EA00 |
6 |
21 |
105 |
0x06900 |
26 |
18 |
508 |
0x1FC00 |
7 |
21 |
126 |
0x07E00 |
27 |
18 |
526 |
0x20E00 |
8 |
21 |
147 |
0x09300 |
28 |
18 |
544 |
0x22000 |
9 |
21 |
168 |
0x0A800 |
29 |
18 |
562 |
0x23200 |
10 |
21 |
189 |
0x0BD00 |
30 |
18 |
580 |
0x24400 |
11 |
21 |
210 |
0x0D200 |
31 |
17 |
598 |
0x25600 |
12 |
21 |
231 |
0x0E700 |
32 |
17 |
615 |
0x26700 |
13 |
21 |
252 |
0x0FC00 |
33 |
17 |
632 |
0x27800 |
14 |
21 |
273 |
0x11100 |
34 |
17 |
649 |
0x28900 |
15 |
21 |
294 |
0x12600 |
35 |
17 |
666 |
0x29A00 |
16 |
21 |
315 |
0x13B00 |
36* |
17 |
683 |
0x2AB00 |
17 |
21 |
336 |
0x15000 |
37* |
17 |
700 |
0x2BC00 |
18† |
19 |
357 |
0x16500 |
38* |
17 |
717 |
0x2CD00 |
19 |
19 |
376 |
0x17800 |
39* |
17 |
734 |
0x2DE00 |
20 |
19 |
395 |
0x18B00 |
40* |
17 |
751 |
0x2EF00 |
† Track 18 is reserved for the Directory and
Block Allocation Map.
* Track's 36…40 are only available on 40 track images.
6 - Auto boot
Making a disk bootable on the C128
On the Commodore C128 it was possible to auto-boot a floppy disk that's in the drive when the system is powered up.
This does NOT work on the C64.
This only works if Track 1 Sector 0 is allocated and contains a specific signature.
I don't have a C128 so I cannot confirm this, only know of this functionality as it's mentioned in some documentation
about the disk format and even then they are not 100% certain if even this is accurate.
Boot sector format
Byte |
Content |
Description |
00 |
Signature |
Auto-boot Signature "CBM" |
01 |
02 |
03 |
Additional sectors |
Track/Sector address or 0x0000 for none |
04 |
05 |
Bank |
Bank for additional sectors, default 0x00 |
06 |
Load count |
Number of sectors to load, default 0x00 |
07 |
Boot message |
0x00 terminated string, can be just 0x00 for "BOOTING..." |
08+b |
Program name |
0x00 terminated string, can be just 0x00 for none |
09+b+p |
Boot Loader |
Boot Loader code, padded with 0x00 |
|
FF |
Example 1
This is from lemon64.com
which has an example of a boot sector in DASM.
In this instance it autoboot's CPM:
Boot loader:
processor 6502
org0x0b00
byte"CBM"
word0x0000
byte0x00
byte0x00
byte"", 0x00
byte"", 0x00
startldx#<cmd-1
ldy#>cmd
jmp0xafa5
cmdbyte"OPEN1,8,15,", $22
byte"CD:CPM.D64", $22
byte":CLOSE1:BOOT"
org0xbff, 0x00
byte0x00
Example 2
This is from C128BOOT.txt
which seems to be different to the above.
|
00 |
01 |
02 |
03 |
04 |
05 |
06 |
07 |
08 |
09 |
0A |
0B |
0C |
0D |
0E |
0F |
00 |
43 | 42 | 4D |
00 | 0C |
00 | 02 | 00 | 00 |
A5 | D7 |
C9 | 80 |
F0 | 03 |
20 |
Code |
10 |
5F | FF |
A9 | 05 | 8D | 06 | D5 | A9 | 4E | 8D | 00 | FF | 4C | 00 | 0C |
|
20 |
All 0x00 |
|
Blank |
|
F0 |
The code for the above loader is:
Boot loader:
ORG0x0c00
bootloaderLDA0xD7
CMP#0x80
BEQinit
JSR0xFF5F
initLDA#0x05
STA0xD506
LDA#0x4E
STA0xFF00
JMPbootloader
7 - GEOS Extensions
GEOS VLIR (Variable Length Index Record)
Later on in the life of the C64, the GEOS OS came out. It was a system
much like many other windowing OS's (MAC OS, Windows) in that it used
icons, windows, a mouse pointer and resource drivers. In order to contain
all the information needed for the windowing system (icon, window position,
creation time/date), a new filetype called VLIR was needed and directory
changes were made. While GEOS files might not be of interest to many of the
emulator users, it is likely that these files will be encountered, and
knowledge of them would be helpful.
There are actually two types of GEOS files, VLIR and SEQuential. Don't
confuse the GEOS SEQuential type with that of the standard D64 SEQ file.
They are related, but not the same. VLIR are described in more detail
following this paragraph. GEOS SEQuential files are all non-VLIR files,
including normal PRG, USR and SEQ types.
GEOS files usually have an entity attached called an INFO block. It
contains ICON info, author, file description, load address etc. However,
just because an INFO block does not exist for a given file, does not mean
that the file is not a GEOS file.
Each GEOS VLIR file or application is comprised of many separate chains
(called RECORDS) for different sections of the app/file. Each RECORD can be
loaded in separately and overtop of other ones. Below is a dump of the
first directory sector of the GEOS 2.0 disk. Note the first entry seems
normal enough, but the rest have additional information in the normally
unused section of the entry.
Directory entry
Byte |
Content |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
00 |
15 |
As per CBM DOS, Location of next directory sector
or 0x0000 for last sector or not first file
|
8 |
01 |
7 |
0 |
02 |
Closed |
Locked |
Save |
|
30CBM File Type |
03 |
15 |
Location of first sector of file |
8 |
04 |
7 |
0 |
05 |
|
Filename in PETASCII padded with 0xA0 |
06 |
07 |
08 |
09 |
0A |
0B |
0C |
0D |
0E |
0F |
10 |
11 |
12 |
13 |
14 |
15 |
15 |
Location of info block |
8 |
16 |
7 |
0 |
17 |
GEOS file structure, 00=Sequential 01=VLIR file |
18 |
GEOS file type |
19 |
Year (1900+value) |
1A |
|
Month (1-12) |
1B |
|
Day (1-31) |
1C |
|
Hour (0-23) |
1D |
|
Minute (1-59) |
1E |
7 |
File size in sectors |
0 |
1F |
15 |
8 |
Info block
Byte |
Content |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
00 |
15 |
Always 0x00, 0xFF as this is 1 sector long
|
8 |
01 |
7 |
0 |
02 |
Information sector ID
Always 0x03 0x15, 0xBF
|
03 |
04 |
05 |
Icon bitmap in sprite format, 63 bytes
|
|
43 |
44 |
|
30CBM File Type |
45 |
GEOS file type |
46 |
GEOS file structure |
47 |
7 |
Program load address |
0 |
48 |
15 |
8 |
49 |
7 |
Program end address Accessories only |
0 |
4A |
15 |
8 |
4B |
7 |
Program start address |
0 |
4C |
15 |
8 |
4D |
Class text, terminated with 0x00
|
|
60 |
61 |
Author, terminated with 0x00
|
|
74 |
75 |
If document name of application that created it
|
|
88 |
89 |
Free for applications, unreserved
|
|
9F |
A0 |
Description, terminated with 0x00
|
|
FF |
The CBM File Type, GEOS file type and GEOS file structure fields are duplicated in
both structures
CBM DOS file type
REL files are not permitted with GEOS.
If byte 0x18 in the directory entry is 0x00 then it's a standard
CBM DOS file, otherwise it's a GEOS file.
GEOS File type
Value |
Type |
Value |
Type |
00 | Normal C64 file |
08 | Font File |
01 | BASIC |
09 | Printer Driver |
02 | Assembler |
0A | Input Driver |
03 | Data file |
0B | Disk Driver |
04 | System file |
0C | System Boot file |
05 | Desk Accessory |
0D | Temporary |
06 | Application |
0E | Auto-Execute file |
07 | Application Data |
0F | Undefined |
File types 0x0F…0xFF are undefined.
Sources