Skip to content
@deckyard/d64

D64 cheatsheet

Every export. Names are written bare; after import "@deckyard/d64/" as d64; they read d64.formatDisk(...). Every failure throws an Error with kind "d64". Functions that return an Image leave their img argument unchanged.

Types

Image

A disk image in memory.

FieldNotes
data as bytesthe blocks, then the optional error table
tracks as int35, 40 or 42
errorInfo as booltrue when data carries one error byte per block
format as DiskFormatwhich BAM layout the disk uses

A track/sector pair, the link CBM DOS chains blocks with.

FieldNotes
track as int1 to 42
sector as intwithin the track

Entry

One directory slot.

FieldNotes
name as stringthe filename, pad bytes trimmed, shifted reading
kind as FileTypeDel, Seq, Prg, Usr or Rel
closed as boolfalse marks a splat file the drive never closed
locked as booltrue marks a file SCRATCH refuses, listed <
track as intfirst block
sector as intfirst block
blocks as intlength as the directory records it
recordLength as intREL files only
slot as intposition in the directory chain, 0-based

Program

A PRG split at its load address.

FieldNotes
address as intthe load address the first two bytes carry
data as byteseverything after it

FileInfo

A file's metadata with its chain. A DEL entry reports an empty chain.

FieldNotes
entry as Entrythe directory entry, verbatim
chain as list of Linkevery block, first to last
blocks as intblocks actually in the chain
size as intpayload bytes over the whole chain
lastUsed as intpayload bytes in the last block
loadAddress as intthe PRG load address, -1 when there is none
blocksMatch as boolwhether the entry's block count is right

FormatOptions

What to format. A zero field takes its default.

FieldNotes
tracks as int35, 40 or 42; 0 means the format's own default
format as DiskFormatwhich BAM layout to write
errorInfo as booltrue to append the per-block error table
dosType as stringtwo characters; "" means "2a"
fill as intthe byte every block is set to, 0 to 255
mode as FormatModehow much to rewrite; only reformatWith reads it

DiskFormat

Which BAM layout a disk uses. Zero value Cbm.

VariantNotes
Cbmthe stock layout; tracks 36-42 have no BAM entry
SpeedDosentries for tracks 36-40 at $c0-$d3
DolphinDosentries for tracks 36-40 at $ac-$bf
PrologicDosentries at $90-$a3; the header moves to $a4

FileType

What kind of file a directory entry describes. Zero value Del.

VariantNotes
Dela scratched or decorative slot, not a file
Seqa stream of bytes
Prga program, with a two-byte load address in front
Usras Seq, named for the program's own use
Relrecord-oriented, with a side-sector index

FormatMode

How much of the disk a format rewrites. Zero value Full.

VariantNotes
Fullevery block to the fill byte, then the BAM and directory
Quickthe BAM and first directory block only; other blocks keep their bytes

Charset

Which of the C64's two character sets a PETSCII byte is read in. Zero value Shifted.

VariantNotes
Shifted$41-$5a lower case, $c1-$da upper case
Unshifted$41-$5a upper case, $c1-$da box drawing and shades

Formatting

FunctionReturnsNotes
formatDisk(name, id)Imageblank 35-track CBM disk, 664 blocks free. NEW0:NAME,ID on a 1541. Name 1-16 characters, ID 1-2
formatDiskWith(options, name, id)Imageexplicit geometry and BAM layout; throws on a speeder layout with fewer than 40 tracks
reformat(img, name, id)Imagefull wipe to $00, keeping geometry, layout and error table. N0:NAME,ID
quickFormat(img, name)Imageerase the BAM and directory only; other blocks keep their bytes, the ID is kept. N0:NAME
reformatWith(img, options, name, id)Imageexplicit mode, fill and dosType; geometry and layout always come from the image
defaultFormatOptions()FormatOptions35 tracks, Cbm, no error table, DOS type "2a", fill $00, mode Full
formatName(format)string"cbm" / "speeddos" / "dolphindos" / "prologicdos"
formatFromName(name)DiskFormatinverse, case-insensitive; also "1541", "commodore", "speed", "dolphin", "prologic", hyphenated
formatTracks(format)int35 for Cbm, 40 for the speeder layouts
detectFormat(bam, tracks)DiskFormatguess the layout from sector 18/0; used by fromBytes. Always Cbm for 35 tracks
headerOffsetFor(format)int$90, or $a4 under PrologicDOS
bamEntryOffset(format, track)intoffset of a track's four BAM bytes, -1 when it has none

Image

FunctionReturnsNotes
fromBytes(raw)Imagegeometry from the length, layout from detectFormat; throws when the length is not a D64 size
toBytes(img)bytesthe image, ready to write
open(path)Imageread one from a file; throws when the file is missing
save(img, path)write one to a file, replacing it
withFormat(img, format)Imageoverrule detectFormat. No bytes change
blockCount(img)int683, 768 or 802
readSector(img, track, sector)bytesexactly 256 bytes. The BAM is not consulted
writeSector(img, track, sector, block)Imagetakes exactly 256. The BAM is not consulted or updated
readBlocks(img, first, count)bytesa run of consecutive blocks, crossing track boundaries; count * 256 bytes
writeBlocks(img, first, data)Imagethe same in reverse; data is a whole multiple of 256 bytes
blockNumber(track, sector)intthe flat block index, 0 at 1/0
blockLink(number)Linkthe inverse; number 0-801
patchSector(img, track, sector, offset, data)Imageoverwrite part of one block, leaving the rest of it alone
readAt(img, offset, length)bytesthe flat byte view, block boundaries ignored; the error table is outside it
writeAt(img, offset, data)Imagethe same in reverse
findBytes(img, pattern)list of intevery offset the pattern occurs at, ascending. blockLink($at // SECTOR_SIZE) gives the address
sectorError(img, track, sector)intrecorded read result; ERROR_OK when there is no error table
setSectorError(img, track, sector, code)Imagethrows without an error table
clearErrorTable(img)Imagemark every block good; no-op without a table

Geometry

FunctionReturnsNotes
sectorsPerTrack(track)int21, 19, 18 or 17
totalSectors(tracks)int683/768/802 at 35/40/42; 0 answers 0
sectorOffset(track, sector)intthe byte offset of a block
imageSize(tracks, errorInfo)intone of the six D64 sizes
tracksForSize(size)int35/40/42, or 0 when not a D64 size
sizeHasErrorInfo(size)boolwhether the size includes the error table

BAM

FunctionReturnsNotes
blocksFree(img)intallocatable free blocks, track 18 excluded; 664 on a fresh 35-track disk
trackBlocksFree(img, track)int0 when the track has no BAM entry
hasBamEntry(img, track)boolwhether the track is covered
isFree(img, track, sector)boolwhether the block is available
isAllocated(img, track, sector)boolthe inverse
allocateSector(img, track, sector)Imagethrows if already taken or the track has no BAM entry
freeSector(img, track, sector)Imagethrows if already free or the track has no BAM entry
nextFreeSector(img, near, interleave)Linkstay on near's track at the interleave, then spiral out from track 18. Throws on a full disk
trackSearchOrder(img, preferred)list of intthat spiral, preferred first when usable

Disk header

FunctionReturnsNotes
diskName(img)stringthe shifted reading
diskNameIn(img, charset)stringthe name in a chosen character set
setDiskName(img, name)Image1 to 16 characters
diskId(img)stringpad byte trimmed
setDiskId(img, id)Imageone or two characters; one is padded with $a0
dosType(img)string"2a" on anything a 1541 wrote
dosVersion(img)intthe byte at $02 of the BAM; $41 normally. A 1541 will not write to a disk with another value

Directory

FunctionReturnsNotes
listFiles(img)list of Entrylive files, in directory order
findFiles(img, pattern)list of Entrymatching a CBM pattern
findFile(img, name)Entryexact name, case-insensitive; throws on a miss
hasFile(img, name)boolexact name, case-insensitive
directoryText(img)stringthe LOAD"$",8 listing
directoryTextIn(img, charset)stringthe same listing in a chosen character set; Charset.Unshifted shows border art as borders
nameBytes(img, entry)bytesthe 16 raw name bytes of an entry's slot, the lossless route to the other reading
renameFile(img, oldName, newName)Imagethrows on a missing file or a name already taken
lockFile(img, name)ImageSCRATCH then refuses it
unlockFile(img, name)Image
directorySectors(img)list of Linkthe directory chain; throws if it loops or leaves track 18
fileTypeName(kind)string"del" / "seq" / "prg" / "usr" / "rel"
fileTypeFromName(name)FileTypeinverse, case-insensitive
fileTypeFromByte(raw)FileTypethe low nibble of a type byte
fileTypeByte(kind, closed, locked)int$82 is a closed PRG

Files

FunctionReturnsNotes
readFile(img, name)bytesraw; nothing transcoded. Refuses a DEL entry, which is a directory slot rather than a file
readText(img, name)stringPETSCII to text
readProgram(img, name)Programsplit at the load address
readChain(img, track, sector)bytesthe payload of any chain, entry or not
chainOf(img, track, sector)list of Linkthe blocks a file uses
fileInfo(img, name)FileInfothe entry, the chain, the real size and the PRG load address. A DEL entry reports an empty chain
listFileInfo(img)list of FileInfothe same for every file
writeFile(img, name, kind, data)Imagethrows on a taken name, a REL or DEL kind, or a full disk or directory
writeText(img, name, kind, text)Imagetranscodes to PETSCII
writeProgram(img, name, address, data)Imageload address first, low byte first
updateFile(img, name, kind, data)Imagereplace, or write if absent; throws on a locked file
patchFile(img, name, offset, data)Imageoverwrite bytes in place; chain, entry and BAM untouched. Cannot change the length
deleteFile(img, name)Imagescratch; throws on a locked file. A DEL entry loses its slot and frees no blocks

PETSCII

FunctionReturnsNotes
toPetscii(text)bytescase-swapped, the petcat convention. Charset.Shifted
fromPetscii(data)stringinverse; $80-$9f and $e0-$fe become ?
toPetsciiIn(text, charset)bytesthe same in a chosen character set
fromPetsciiIn(data, charset)stringthe same in a chosen character set
encodeName(name)bytes16 PETSCII bytes, pad-filled. Raises on an empty name, one over 16 characters, or one holding the pad byte
decodeName(raw)stringtrailing padding dropped, an inner pad byte read as a space
encodeNameIn(name, charset)bytesthe same in a chosen character set
decodeNameIn(raw, charset)stringthe same in a chosen character set
matchName(pattern, name)boolthe drive's * and ?, case-insensitive

Constants

NameValueWhat it is
SECTOR_SIZE256bytes in one block
DATA_BYTES_PER_SECTOR254payload bytes per block
DIRECTORY_TRACK18the track CBM DOS keeps for itself
BAM_SECTOR0the BAM, on that track
FIRST_DIRECTORY_SECTOR1where the directory chain starts
TRACKS_STANDARD35a stock 1541 disk
TRACKS_EXTENDED40what the speeder DOSes formatted
TRACKS_MAX42the largest D64 in circulation
FILE_INTERLEAVE10sectors skipped between file blocks
DIRECTORY_INTERLEAVE3sectors skipped between directory blocks
ENTRIES_PER_SECTOR8directory slots in one block
ENTRY_SIZE32bytes in one slot
MAX_DIRECTORY_ENTRIES14418 blocks of 8
MAX_FILENAME16characters CBM DOS stores
PAD_BYTE$a0the shifted space a short name is padded with
SUBSTITUTE_BYTE$3fwhat an unmappable character becomes
DOS_VERSION_BYTE$41the byte at $02 of the BAM
DOS_TYPE"2a"the DOS type a 1541 stamps in
HEADER_OFFSET$90where the disk header sits
HEADER_OFFSET_PROLOGIC$a4where PrologicDOS moved it
ERROR_OK$01the error code of a good block
ERROR_KIND"d64"the kind every Error here carries
VERSIONgeneratedthe deck version, injected from the git tag