{ "_comment": "generated by tools/mergeSurvey.py from survey/*.json - do not edit by hand", "notes": { "C000": { "routine": [ "bootEntry - Public entry of the boot loader: JMP bootMain ($C145). Called once by eaLoadGame ($02D2) after the KERNAL has loaded the file 'load' to $9800-$C3FF. Emitted as .byte in the listing but it is a 3-byte JMP.", "In: none", "Out: never returns to the caller (see bootMain)" ], "unit": "boot/fastLoaderC000" }, "C004": { "routine": [ "bootLoadSectors - Read A consecutive sectors from track Y starting at sector X into the address set by bootSetDest, one page per sector. On a drive error it stores the status byte in bootLoaderStatus, turns the border red and retries the same sector forever; a good sector turns the border black. Public API used five times by bootMain; the game keeps an identical private copy at $0804.", "In: A = sector count, X = first sector, Y = track, bootDestLo/Hi = destination", "Out: C = 0, X = next sector, Y = track, ldCount = 0, bootDestHi advanced by A pages, I flag restored (PHP/PLP), border colour changed" ], "unit": "boot/fastLoaderC000" }, "C031": { "routine": [ "bootLoadSectorsFail - Dead 3-byte error exit PLP / SEC / RTS (emitted as .byte). It is the counterpart of writeSectorsFail ($0840) in the game's copy; nothing in the boot loader branches to it because read errors retry forever.", "In: none", "Out: C = 1 (unreachable)" ], "unit": "boot/fastLoaderC000" }, "C034": { "routine": [ "bootSetDest - Set the next transfer address for bootLoadSectors by patching the two operand bytes bootDestLo/bootDestHi.", "In: X = destination low byte, Y = destination high byte", "Out: bootDestLo, bootDestHi" ], "unit": "boot/fastLoaderC000" }, "C03B": { "routine": [ "bootExchangeByte - Full-duplex 1-bit-at-a-time byte exchange with the drive over CIA2 port A: shifts the byte in A out LSB first on DATA OUT (bit 5) with CLK OUT (bit 4) as strobe while shifting the drive's reply in from DATA IN (bit 7) using CLK IN (bit 6) as handshake (the drive side does the same in $034B). Used to send the command byte, track and sector and afterwards, with a dummy byte, to fetch the status. Seed name bootSendByte; the seed's 'MSB first' is wrong (LSR D_C087 sends bit 0 first).", "In: A = byte to send", "Out: A = byte received (LSB first), Z reflects it, C = 0, X = 0, bootSendShiftReg = 0, bootRecvShiftReg = received byte" ], "unit": "boot/fastLoaderC000" }, "C08A": { "routine": [ "bootReadOneSector - Read one sector: stores track/sector, stops CIA1 timer A (no jiffy IRQ during the timed transfer), calls bootReadSectorBody and restarts timer A. Called only by bootLoadSectors.", "In: Y = track, X = sector, bootDestLo/Hi", "Out: C = 1 on error (A = status byte), C = 0 on success; ldTrack, ldSector set; I flag set; CIA1_CRA = 1" ], "unit": "boot/fastLoaderC000" }, "C09D": { "routine": [ "bootReadSectorBody - Protocol body of a sector read: sends $80, track, sector; saves VIC_SPR_ENA and the VIC bank bits of CIA2_PRA (ldCia2Bits), raises DATA OUT and clears CLK OUT / ATN / TXD, patches the raster threshold of the receive loop to (VIC_CTRL1 and 7) + $2F, waits for CLK IN to drop, disables sprites, copies bootDestLo/Hi to ldDestPtr, receives 256 bytes, restores sprites and exchanges a dummy byte to get the status (0 = ok).", "In: ldTrack, ldSector, bootDestLo/Hi, VIC_CTRL1 (y-scroll)", "Out: C = 0 and Z = 1 on success, C = 1 on error (A = status); 256 bytes stored at the destination; bootSavedSprites, ldCia2Bits, ldDestPtr, bootRasterThreshold updated" ], "unit": "boot/fastLoaderC000" }, "C0EF": { "routine": [ "bootReceiveSectorData - Timing-critical 2-bit parallel receive loop, identical to $0950 in the game. Waits for CLK IN high, then for each of 256 bytes: waits until the raster line is not the line before a bad line (relative to the patched threshold), drops CLK OUT to request a byte, reads four 2-bit pairs from bits 6/7 at fixed cycle offsets (LSB pair first, EOR-combined after LSR LSR shifts), raises DATA OUT to acknowledge and stores the byte via (ldDestPtr),Y. 'bit zp_80' and the NOPs are pure delays.", "In: ldCia2Bits (VIC bank bits to keep in CIA2_PRA), ldDestPtr, bootRasterThreshold (operand at $C0FE)", "Out: 256 bytes at (ldDestPtr); Y = 0; CIA2_PRA left with DATA OUT set" ], "unit": "boot/fastLoaderC000" }, "C145": { "routine": [ "bootMain - The boot sequence: blank screen, noise on SID voice 3 (random source), show the title picture, set S=$FD via the patched TXS, init modem and drive, B-E the drive bootstrap, disable IRQs, $01=$35 with NMI/IRQ vectors to rtiVector, then load tracks 22-27 (18 sectors each) to $0800, copy $6F00-$72FF to $0400, load track 33 s0-16 + track 32 s8-15 to $6F00 (overlay B), track 28 s0-12 to $9300, track 29 s11-15 to $FA00 and move that block up by $1B8 to end at $FFD1; finally stores a SID noise sample in randomSeed. Its RTS is an obfuscated jump: the stack holds $60 (pushed by the patched PHA at $C1B1, the value is the RTS opcode read from bootDone) under $04 (stored at $01FE by bootShowTitlePicture), so execution continues at $0461 (memory checksum in the $0400 copy) which ends with JMP $0800. It never returns to eaLoadGame.", "In: disk in drive 8, title data at $9800-$BF3F", "Out: memory image of the game ($0400-$87FF, $9300-$9FFF, $FBB8-$FFD1), randomSeed ($09C3), $01=$35, vectors $FFFA/$FFFE = $C229, S = $FE at $0461" ], "unit": "boot/fastLoaderC000" }, "C229": { "routine": [ "rtiVector - Single RTI used as the NMI and IRQ target ($FFFA/$FFFE) while the loader runs with the ROMs banked out.", "In: none", "Out: none" ], "unit": "boot/fastLoaderC000" }, "C22A": { "routine": [ "bootDisableIrqs - SEI, mask and acknowledge all CIA1/CIA2 interrupts ($7F to both ICRs, then read them) and clear VIC_IRQ_MASK. Leaves the I flag set; callers CLI later.", "In: none", "Out: CIA1_ICR, CIA2_ICR, VIC_IRQ_MASK; I = 1" ], "unit": "boot/fastLoaderC000" }, "C23F": { "routine": [ "bootShowTitlePicture - Disables IRQs, patches $C168 to TXS and $C1B1 to PHA (the obfuscated exit), zeroes the sprite registers, VIC IRQ/collision registers, selects VIC bank 2 (CIA2_PRA = $05, DDR bits 0-1 out), writes $04 to $01FE (high byte of the fake return address), copies 4 pages of colour RAM $9800->$D800 and screen RAM $9C00->$8C00 with self-modifying loops, then sets multicolour bitmap mode (VIC_CTRL2 = $D8, VIC_MEM_PTR = $38 -> screen $8C00 / bitmap $A000, VIC_CTRL1 = $3B) and CLI.", "In: title data at $9800 (colour), $9C00 (screen), $A000 (bitmap)", "Out: VIC registers, COLOR_RAM, $8C00-$8FFF, $01FE = $04, code bytes $C168 and $C1B1 patched, loop operands $C273/$C276/$C28A/$C28D advanced; I = 0" ], "unit": "boot/fastLoaderC000" }, "C2AB": { "routine": [ "bootDriveInitialize - OPEN 15,8,15,\"I0\" (initialise drive 0), wait 4 frames, CLOSE 15. Uses the KERNAL (ROMs still banked in).", "In: strInitDrive", "Out: drive initialised; A/X/Y clobbered" ], "unit": "boot/fastLoaderC000" }, "C2CA": { "routine": [ "bootWaitFrames - Wait Y video frames by watching bit 7 of VIC_RASTER go high and then low again once per iteration.", "In: Y = number of frames", "Out: Y = 0" ], "unit": "boot/fastLoaderC000" }, "C2DA": { "routine": [ "bootModemInit - MEMTOP = $9700 (so the RS-232 buffers allocated by OPEN stay below the loaded file), OPEN 2,2,0 with rs232Params ($06 = 300 baud 8N1, $00 = 3-line handshake), CHKOUT 2, send CR, wait 20 frames, send the 0-terminated Hayes string 'ATE0S0=0' CR, wait 60 frames, CLRCHN, CLOSE 2. Silences a connected modem (echo off, no auto-answer); harmless without one.", "In: rs232Params, strHayesInit", "Out: RS-232 channel opened and closed; KERNAL MEMTOP lowered" ], "unit": "boot/fastLoaderC000" }, "C32C": { "routine": [ "bootBlockExecute - SEI, saves CPU_PORT and banks the ROMs in (ORA #$03), opens buffer channel 2 on the drive with filename '#' (SECOND $F2) and then opens channel 15 with the command 'B-E 2 0 1 17' (SECOND $FF): the drive loads track 1 sector 17 into buffer 2 and executes it, installing the fast loader in the drive. Falls through into bootSendDosCommand for the second command.", "In: strBlockExecute, strBufferChannel, kernalCurrentDevice ($BA = 8)", "Out: drive now runs the fast-loader code; CPU_PORT restored; I = 1" ], "unit": "boot/fastLoaderC000" }, "C341": { "routine": [ "bootSendDosCommand - LISTEN the current device ($BA), SECOND with the secondary address in A ($F0 | channel = OPEN), CIOUT the 0-terminated string at strBlockExecute+Y, UNLSN, then restore CPU_PORT from bootSavedCpuPort. Called once by JSR and once by fall-through from bootBlockExecute.", "In: A = secondary address byte, Y = offset into strBlockExecute, kernalCurrentDevice, bootSavedCpuPort", "Out: command sent; CPU_PORT restored" ], "unit": "boot/fastLoaderC000" }, "C373": { "routine": [ "leftoverLookupC373 - Unreachable leftover from the shared EA loader (listed as .byte): SEC; SBC #$AC; if A < $10 then X = A, $BE6D = $BE68 = $BCC8,X; RTS. Targets do not exist in this build.", "In: A", "Out: $BE6D, $BE68 (dead)", "(confidence: low)" ], "unit": "boot/fastLoaderC000" }, "C387": { "routine": [ "leftoverSetC387 - Unreachable leftover: TAY; $BE6D = $FF; $4D = A; RTS.", "In: A", "Out: $BE6D, $4D (dead)", "(confidence: low)" ], "unit": "boot/fastLoaderC000" }, "C390": { "routine": [ "leftoverSetC390 - Unreachable leftover: $4D = $FF; $BE6C = $FF; falls into leftoverSetC397.", "In: none", "Out: $4D, $BE6C, $BE6D (dead)", "(confidence: low)" ], "unit": "boot/fastLoaderC000" }, "C397": { "routine": [ "leftoverSetC397 - Unreachable leftover: $BE6D = $FF; RTS.", "In: none", "Out: $BE6D (dead)", "(confidence: low)" ], "unit": "boot/fastLoaderC000" }, "C39D": { "routine": [ "leftoverCheckC39D - Unreachable leftover: returns A = 1 if $51 != 0 or ($48 | $57) == 0; otherwise if $48 == 0 sets $51 = $0A, $BE65 = 0, $57 = 0, else $57 = $48; RTS.", "In: $48, $51, $57", "Out: A, $51, $57, $BE65 (dead)", "(confidence: low)" ], "unit": "boot/fastLoaderC000" }, "C3BC": { "routine": [ "leftoverStoreBE65 - Unreachable leftover: STA $BE65; RTS.", "In: A", "Out: $BE65 (dead)", "(confidence: low)" ], "unit": "boot/fastLoaderC000" }, "C3C4": { "routine": [ "leftoverCheckDiskId - Unreachable, truncated original of the game's checkDiskId ($0FB1): saves zp $04/$05, calls $CBED (setDest $BA00) and $CBF2 (read 1 sector, track 18 sector 0 = BAM) from a build where the loader lived at $CBxx, then compares the disk id at $BAA2/$BAA3 with bootDiskIdTable entries 'EA' (zp $18 = 2) and 'OZ' (0), branching to $C411 which lies beyond the end of the file.", "In: bootDiskIdTable, BAM at $BA00 (in that build)", "Out: zp $18 = matched index / 2, branches outside the file (dead)", "(confidence: medium)" ], "unit": "boot/fastLoaderC000" }, "C132": { "unit": "boot/fastLoaderC000", "block": [ "strBlockExecuteCopy: text, 13 bytes. Second, unused copy of the 0-terminated DOS command 'B-E 2 0 1 17' (the labels sub_C133/sub_C137 come from runtime-overlay callers, not from this text)" ] }, "C13F": { "unit": "boot/fastLoaderC000", "block": [ "strBufferChannelCopy: text, 2 bytes. Unused copy of the 0-terminated buffer-channel filename '#'" ] }, "C143": { "unit": "boot/fastLoaderC000", "block": [ "bootUnusedC143: unknown, 1 bytes. Zero byte between bootDestHi and bootSavedSprites, unused" ] }, "C219": { "unit": "boot/fastLoaderC000", "block": [ "strGameChar: text, 9 bytes. 0-terminated 'GAMECHAR' - leftover from the shared EA loader, not referenced" ] }, "C222": { "unit": "boot/fastLoaderC000", "block": [ "strHmem: text, 7 bytes. $00, 'HMEM', $00, $00 - leftover from the shared EA loader, not referenced" ] }, "C2D8": { "unit": "boot/fastLoaderC000", "block": [ "strInitDrive: text, 2 bytes. 'I0' drive initialise command (length passed explicitly to SETNAM)" ] }, "C320": { "unit": "boot/fastLoaderC000", "block": [ "rs232Params: byteTable, 2 bytes. RS-232 control/command bytes for OPEN 2,2,0: $06 = 300 baud, 8 data bits, 1 stop bit; $00 = 3-line handshake, full duplex, no parity" ] }, "C322": { "unit": "boot/fastLoaderC000", "block": [ "strHayesInit: text, 10 bytes. 0-terminated 'ATE0S0=0' + CR sent to a modem (echo off, auto-answer off)" ] }, "C35F": { "unit": "boot/fastLoaderC000", "block": [ "strBlockExecute: text, 13 bytes. 0-terminated DOS command 'B-E 2 0 1 17' (block-execute channel 2, drive 0, track 1, sector 17) sent to channel 15" ] }, "C36C": { "unit": "boot/fastLoaderC000", "block": [ "strBufferChannel: text, 2 bytes. 0-terminated '#' used as the filename when opening buffer channel 2 (reached as strBlockExecute+$0D)" ] }, "C36E": { "unit": "boot/fastLoaderC000", "block": [ "bootPaddingC36E: unknown, 3 bytes. Three zero bytes, padding" ] }, "C372": { "unit": "boot/fastLoaderC000", "block": [ "bootStrayC372: unknown, 1 bytes. Single byte $13, probably the tail of an instruction of the leftover code that preceded it in the original loader" ] }, "C3C0": { "unit": "boot/fastLoaderC000", "block": [ "bootDiskIdTable: text, 4 bytes. Two 2-character disk ids 'OZ' (game disk) and 'EA' (data disk) used only by the unreachable leftoverCheckDiskId; the live copy is diskIdTable at $0FAD" ] } } }