{ "_comment": "Seed annotations written while reverse engineering the loader. Format: labels {hexAddr: name}, notes {hexAddr: {routine:[header lines], block:[comment lines before the address], line: 'end of line comment'}}, dataTypes {hexAddr: [type, length]} with type text|addr|word|byte, zp {hexAddr: [name, comment]}, driveZp likewise for the 1541 listings. Drive/raw-unit notes carry a 'unit' field.", "entries": [ "09A6" ], "labels": { "0800": "gameEntry", "0803": "loaderStatus", "0804": "loadSectors", "0808": "loadSectorsLoop", "0820": "loadSectorOk", "0830": "loadSectorNext", "0840": "writeSectorsFail", "0843": "writeSectors", "0847": "writeSectorsLoop", "085C": "setLoadDest", "0863": "writeOneSector", "088F": "sendSectorData", "089C": "sendByteToDrive", "08E8": "sendByteShift", "08E9": "recvByteShift", "08EB": "readOneSector", "08FE": "readSectorBody", "0943": "finishTransfer", "0950": "receiveSectorData", "0957": "receiveByteLoop", "09A2": "loadDestLo", "09A3": "loadDestHi", "09A5": "savedSpriteEnable", "09A6": "manualLookupCheck", "0A1E": "wipeMemoryLoop", "0A48": "msgIdentifyMap", "0A6C": "mainStart", "0B4F": "loadCommTailBuild1", "0EFE": "loadRuntimeOverlays", "0F31": "loadCommBuild2", "0F41": "loadCommFinish", "0F55": "loadSectorsRetry", "0F81": "msgNotADataDisk", "0F91": "msgInsertGameDisk", "0FA2": "msgDiskError", "0FAD": "diskIdTable", "0FB1": "checkDiskId", "1018": "diskErrorExit", "1047": "loadOverlayA", "1060": "loadStringsAndCommTail", "1081": "loadOverlayBIfNeeded", "1086": "loadOverlayB", "10A4": "loadMapAndSetup", "10DF": "waitForGameDisk", "02B8": "eaLoadGame", "02EC": "eaFileName" }, "notes": { "0800": { "routine": [ "gameEntry - jumped to by the boot code at $02B8 after the fast loader has filled memory." ], "line": "-> mainStart" }, "0803": { "line": "bit 7 = a read error occurred (cleared once reported)" }, "0804": { "routine": [ "loadSectors - read A consecutive sectors from track Y starting at sector X into the address set by setLoadDest.", "In: A = sector count, Y = track, X = first sector. Out: C = 0. Destination advances one page per sector.", "Private copy of the boot loader's $C004; on an error it shows msgDiskError and retries forever." ] }, "0843": { "routine": [ "writeSectors - write A consecutive sectors to track Y from sector X, source address set by setLoadDest.", "In: A = count, Y = track, X = first sector. Out: C = 1 on failure, 0 on success." ] }, "085C": { "routine": [ "setLoadDest - X = low byte, Y = high byte of the next transfer address (patches loadDestLo/Hi)." ] }, "0863": { "routine": [ "writeOneSector - send command $60, track, sector and 256 data bytes to the drive, then read the status byte." ] }, "089C": { "routine": [ "sendByteToDrive - clock one byte to the drive 1 bit at a time through CIA2 port A bits 4/5 with a handshake on bits 6/7." ] }, "08EB": { "routine": [ "readOneSector - request track Y sector X from the drive (command $80) and receive 256 bytes. Out: C = 1 on error." ] }, "0950": { "routine": [ "receiveSectorData - the timing critical 2-bit receive loop. Sprites are disabled and bad lines avoided", "by waiting for a raster line that is not a multiple of 8 (the operand at $095F is patched with $D011 & 7 + $2F)." ] }, "09A6": { "routine": [ "manualLookupCheck - copy protection: ask the player to identify a map from the manual.", "Picks one of 32 three-byte answers from the table at $0401 (index patched into $09C4), prints msgIdentifyMap,", "reads the player's answer into $5A-$5C and allows three tries; after that it erases all of memory and hangs." ] }, "0A48": { "line": "copy-protection prompt (bit 7 set on the last character terminates the string)" }, "0A9B": { "line": "was JSR manualLookupCheck ($20 A6 09); the opcode is $2C = BIT, so the manual check is disabled in this build" }, "0EFE": { "routine": [ "loadRuntimeOverlays - called once at start-up: $C000 <- track 30, then loadOverlayA, then the communications", "module at $E000 (build 1 from track 35 when $0BA5 bit 7 is set, otherwise track 18 s7 + track 34)." ] }, "0F55": { "routine": [ "loadSectorsRetry - like loadSectors but first calls $C37F with A=8 (drive/UI housekeeping in the $C000 overlay)." ] }, "0FB1": { "routine": [ "checkDiskId - read the BAM (track 18 sector 0) into $0200 and compare the disk id with diskIdTable[X] (X=0 'OZ' game", "disk, X=2 'EA' data disk). Copies the 10-byte serial at BAM offset $AB to $FFDE-$FFE7 for the game disk.", "Out: C = 0 ok, C = 1 wrong disk / error (message already shown)." ] }, "1047": { "routine": [ "loadOverlayA - $6F00 <- track 31 s0-16, $8000 <- track 32 s0-7; falls through into loadStringsAndCommTail." ] }, "1060": { "routine": [ "loadStringsAndCommTail - $8800 <- track 29 s9-10 (messages), $EC00 <- track 34 s12-15." ] }, "1086": { "routine": [ "loadOverlayB - $6F00 <- track 33 s0-16, $8000 <- track 32 s8-15 (the variant the boot loader installs)." ] }, "10A4": { "routine": [ "loadMapAndSetup - $F000 <- track 18 s8-14 (battlefield map), $0200 <- track 18 s15-16 (saved setup block)." ] }, "C004": { "routine": [ "bootLoadSectors - read A sectors from track Y starting at sector X to the address set by bootSetDest.", "The game keeps its own identical copy at $0804 because this page is overwritten by the $C000 overlay." ], "unit": "boot/fastLoaderC000" }, "C03B": { "routine": [ "bootSendByte - full-duplex 1-bit exchange: shifts the command byte out LSB first on CIA2 port A and shifts the drive's", "reply in (LSB first, into $C088); returns the reply in A (Z set when it is 0)." ], "unit": "boot/fastLoaderC000" }, "C0EF": { "routine": [ "bootReceiveSectorData - 2-bit parallel receive loop; identical to $0950 in the game." ], "unit": "boot/fastLoaderC000" }, "C145": { "routine": [ "bootMain - entry from $02B8. Shows the title picture, initialises modem and drive, installs the drive code", "(B-E of track 1 sector 17), banks out the ROMs and loads the game (see docs/overview.md section 2)." ], "unit": "boot/fastLoaderC000" }, "C1B1": { "line": "patched to PHA by bootShowTitlePicture (DEC $C1B1): pushes the RTS opcode ($60 read from bootDone) onto the stack at $01FD", "unit": "boot/fastLoaderC000" }, "C168": { "line": "patched from STA abs,Y ($99) to TXS ($9A) by bootShowTitlePicture: S=$FD, so the return stack is $01FE/$01FF", "unit": "boot/fastLoaderC000" }, "C219": { "line": "leftover strings from the shared EA loader ('GAMECHAR', 'HMEM'); unused here", "unit": "boot/fastLoaderC000" }, "C229": { "routine": [ "rtiVector - NMI and IRQ vector target while the loader runs with the ROMs banked out." ], "unit": "boot/fastLoaderC000" }, "C23F": { "routine": [ "bootShowTitlePicture - clear VIC registers, copy colour RAM from $9800 and screen RAM $9C00 -> $8C00,", "select VIC bank 2 and multicolour bitmap mode (bitmap at $A000)." ], "unit": "boot/fastLoaderC000" }, "C2AB": { "routine": [ "bootDriveInitialize - OPEN 15,8,15,\"I0\" then CLOSE (initialise the drive)." ], "unit": "boot/fastLoaderC000" }, "C2DA": { "routine": [ "bootModemInit - MEMTOP = $9700, OPEN 2,2,0 with RS-232 parameters $06/$00 (300 baud, 8N1) and send the", "Hayes command ATE0S0=0 (echo off, no auto-answer) so a connected modem is quiet while the game loads." ], "unit": "boot/fastLoaderC000" }, "C32C": { "routine": [ "bootBlockExecute - open a buffer channel (\"#\" on channel 2) and send \"B-E 2 0 1 17\" on the command channel:", "the drive loads track 1 sector 17 and executes it, which installs the fast loader in the drive." ], "unit": "boot/fastLoaderC000" }, "C372": { "block": [ "$C372-$C3FF: leftover code from the shared EA loader (references $BCC8/$BE6D/$CBED/$CBF2 that do not exist", "in this build). Not reachable from the boot path." ], "unit": "boot/fastLoaderC000" }, "02B8": { "routine": [ "eaLoadGame - reached through the hijacked BASIC vectors: SETLFS 8,1 / SETNAM \"LOAD\" / LOAD, then JSR $C000, JMP $0800." ], "unit": "boot/ea" }, "02AA": { "block": [ "$02A8-$02B7: a never-executed tokenised BASIC line (10 LOAD\"EA\",8,1) left in the file as filler." ], "unit": "boot/ea" }, "C218": { "routine": [ "bootDone - RTS, but the stack was rebuilt ($01FD=$60 via PHA, $01FE=$04 from $C26F): the return address on the stack is $0460,", "so execution continues at $0461 in the $0400 block (a memory checksum routine that ends with JMP $0800) and never", "returns to eaLoadGame's JMP $0800." ], "unit": "boot/fastLoaderC000" }, "0B25": { "line": "filename field of the boot sector ($A0 = shifted space, then terminator); the C128 KERNAL skips it and enters at $0B27", "unit": "boot/c128boot_T1S0" } }, "dataTypes": { "0A48": [ "text", 36 ], "0F81": [ "text", 16 ], "0F91": [ "text", 17 ], "0FA2": [ "text", 11 ], "0FAD": [ "text", 4 ], "C219": [ "text", 9 ], "C222": [ "text", 5 ], "C2D8": [ "text", 2 ], "C320": [ "byte", 2 ], "C322": [ "text", 10 ], "C35F": [ "text", 13 ], "C36C": [ "text", 2 ], "C3C0": [ "text", 4 ], "02EC": [ "text", 4 ], "0B25": [ "byte", 2 ] }, "zp": { "E0": [ "ldTrack", "loader: current track" ], "E1": [ "ldSector", "loader: current sector" ], "E2": [ "ldDestPtr", "loader: destination pointer (lo)" ], "E3": [ "ldDestPtrHi", "loader: destination pointer (hi)" ], "E4": [ "ldCia2Bits", "loader: CIA2 port A bits 0-1 (VIC bank) kept during the transfer" ], "E5": [ "wrSrcPtr", "loader: write source pointer (lo)" ], "E6": [ "wrSrcPtrHi", "loader: write source pointer (hi)" ], "E7": [ "ldCount", "loader: sectors left to transfer" ] }, "unitLabels": { "boot/fastLoaderC000": { "C000": "bootEntry", "C003": "bootLoaderStatus", "C004": "bootLoadSectors", "C034": "bootSetDest", "C03B": "bootSendByte", "C08A": "bootReadOneSector", "C09D": "bootReadSectorBody", "C0EF": "bootReceiveSectorData", "C141": "bootDestLo", "C142": "bootDestHi", "C144": "bootSavedSprites", "C145": "bootMain", "C218": "bootDone", "C219": "strGameChar", "C222": "strHmem", "C229": "rtiVector", "C22A": "bootDisableIrqs", "C23F": "bootShowTitlePicture", "C2AB": "bootDriveInitialize", "C2CA": "bootWaitFrames", "C2D8": "strInitDrive", "C2DA": "bootModemInit", "C320": "rs232Params", "C322": "strHayesInit", "C32C": "bootBlockExecute", "C341": "bootSendDosCommand", "C35F": "strBlockExecute", "C36C": "strBufferChannel", "C371": "bootSavedCpuPort", "C3C0": "bootDiskIdTable" } } }