modemwars/annotations/00_seed.json
2026-08-23 02:09:40 -05:00

388 lines
No EOL
11 KiB
JSON

{
"_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"
}
}
}