Skip to content
@deckyard/d64

The D64 format on disk

Every byte offset the deck implements, in hexadecimal, relative to the start of the block.

The image

The blocks of the disk back to back, in track order, then sector order. One error byte per block may follow.

TracksBlocksPlainWith error table
35683174,848175,531
40768196,608197,376
42802205,312206,114

There is no header; the six sizes are distinct, so the length gives the geometry.

Zones

TracksSectors each
1-1721
18-2419
25-3018
31-4217

Tracks 36-42 are beyond a stock drive's range; every extended format uses the innermost zone's 17 sectors.

offset(track, sector) = (totalSectors(track - 1) + sector) * 256

Sector 18/0 - the BAM

OffsetContent
$00-$01track/sector of the first directory block - 18 / 1
$02DOS version byte, $41 ('A')
$03unused, $00
$04-$8fBAM entries for tracks 1-35, four bytes each
$90-$9fdisk name, 16 bytes, PETSCII padded with $a0
$a0-$a1$a0 $a0
$a2-$a3disk ID, two bytes
$a4$a0
$a5-$a6DOS type, "2A" ($32 $41)
$a7-$aa$a0 $a0 $a0 $a0
$ab-$ffunused on a stock disk - see below

A BAM entry

Four bytes per track: a free-sector count, then a 24-bit map where a set bit means free. Sector n is bit n % 8 of byte 1 + n / 8. Bits past the end of the track stay clear.

track 1, all free:       15 ff ff 1f  21 free, bits 0-20 set
track 18, fresh disk:    11 fc ff 07  17 free, bits 0 and 1 clear

The 40-track extensions

Each speeder DOS put the five entries for tracks 36-40 in a different place:

FormatTracks 36-40Disk header
CBM-$90
SpeedDOS$c0-$d3$90
DolphinDOS$ac-$bf$90
PrologicDOS$90-$a3$a4

PrologicDOS put the entries over the disk name and moved the whole header - name, filler, ID, filler, DOS type, filler - up 20 bytes, so its DOS type sits at $b9-$ba. detectFormat tests for that first.

No format ever defined entries for tracks 41 and 42.

Track 18 - the directory

A chain from 18/1, each block linked by its first two bytes, at interleave 3 (18/1, 18/4, 18/7, and so on). 18 blocks fit, 8 slots each: 144 files maximum.

On the last block of the chain the link is $00 $ff.

A directory slot

OffsetContent
$00-$01track/sector of the next directory block - first slot only, $00 $00 in the rest
$02file type byte
$03-$04track/sector of the file's first block
$05-$14filename, 16 bytes, PETSCII padded with $a0
$15-$16track/sector of the first side-sector block, REL only
$17record length, REL only, at most 254
$18-$1dunused (GEOS uses them)
$1e-$1ffile length in blocks, low byte first

Slots start at $00, $20, $40, $60, $80, $a0, $c0, $e0.

The file type byte

Bits 0-3 are the type. Values 5-15 are invalid and a real drive's behaviour on them is undefined; the deck reads them as DEL.

ValueType
0DEL
1SEQ
2PRG
3USR
4REL
BitMeaning
6locked - lists as <, SCRATCH refuses it
7closed - clear means a "splat" file, listed with a leading *

So $82 is a closed PRG, $c2 a closed locked PRG, $02 an unclosed PRG, and $00 a scratched slot.

A scratch zeroes the type byte and nothing else in the slot. The name and first-block pointer remain, and the file's blocks are freed in the BAM.

A file

A linked list of blocks at an interleave of 10.

OffsetContent
$00track of the next block, or $00 in the last one
$01sector of the next block - or, when $00 is zero, the length
$02-$ffpayload, 254 bytes

In the last block a length byte of n means bytes $02-$n are file data: n - 1 payload bytes. $02 is one byte, $ff the full 254, $01 none (an empty file). $00 is not a length; the deck throws on it.

A PRG's first two payload bytes are its load address, low byte first: $01 $08 is $0801, the start of BASIC on a C64.

Sources

  • C64-Wiki: D64 - container, sizes, zones.
  • Peter Schepers, D64 (Electronic form of a physical 1541 disk), rev 1.11 - BAM, directory, chain, and the three speeder BAM offsets.
  • VICE - reference implementation these offsets were checked against.