{
 "chunk": "drive_bootstrap_T1S17_0600",
 "unit": "drive/bootstrap_T1S17",
 "routines": [
  {
   "addr": "0600",
   "name": "driveBootstrapEntry",
   "summary": "Entry point of the 1541 bootstrap sector, executed by DOS 'B-E 2 0 1 17' at the first byte of whatever buffer channel 2 was given (so it runs at an unknown page, not necessarily $0600). It disables IRQs, writes $08 to VIA1 port B (CLK OUT asserted, DATA OUT released, ATNA off), plants an RTS ($60) at $0300 (buffer 0, free to clobber) and JSRs to it; TSX / LDA $0100,X then reads the return-address high byte left on the stack, which is the page the code is currently running in. That page is copied verbatim to $0600 (buffer 3) and execution continues with an absolute JMP to $0624 inside the copy.",
   "inputs": "None beyond DOS having loaded the sector into a channel buffer and jumped to its first byte. Uses the stack to discover its own page.",
   "outputs": "$0300 = $60 (RTS, later overwritten by the fast loader read); $14/$15 = pointer to the original page (lo always 0); $0600-$06FF = copy of the sector; VIA1_PRB_SERIAL = $08; I flag set. Falls into queueFastLoaderReads at $0624 via JMP.",
   "confidence": "high"
  },
  {
   "addr": "0624",
   "name": "queueFastLoaderReads",
   "summary": "Copies the 12-byte jobQueueInitTable to drive zero page $00-$0B: job code $80 (read sector) for buffers 0,1,2 ($0300,$0400,$0500), $00 (no job) for buffers 3,4,5, and track/sector pairs 1/18, 1/19, 1/20 for buffers 0-2. Enables IRQs so the DOS job controller runs, then spins while any of the three job bytes still has bit 7 set. When all three have finished it ORs the result codes and requires exactly $01 (all OK); any DOS error code makes the OR differ and the whole queue is re-issued (infinite retry, no error exit). On success it calls ROM_INIT_DRIVE ($D042, re-reads the BAM / disk id) and jumps to the freshly loaded fast loader at $0300.",
   "inputs": "jobQueueInitTable at $0641. Requires that the code is already running from $0600 (the DOS reads target buffers 0-2, which would otherwise overwrite it).",
   "outputs": "$0300-$05FF = fast loader (track 1 sectors 18-20, unencrypted); $00-$0B = job queue state; I flag cleared; disk re-initialised. Does not return - ends with JMP $0300.",
   "confidence": "high"
  }
 ],
 "variables": [
  {"addr": "00", "scope": "zp", "name": "jobCodeBuf0", "meaning": "1541 DOS job code for buffer 0 ($0300); set to $80 (read) by queueFastLoaderReads, polled until bit 7 clears, result $01 = OK.", "confidence": "high"},
  {"addr": "01", "scope": "zp", "name": "jobCodeBuf1", "meaning": "DOS job code for buffer 1 ($0400); $80 = read track 1 sector 19.", "confidence": "high"},
  {"addr": "02", "scope": "zp", "name": "jobCodeBuf2", "meaning": "DOS job code for buffer 2 ($0500); $80 = read track 1 sector 20.", "confidence": "high"},
  {"addr": "03", "scope": "zp", "name": "jobCodeBuf3", "meaning": "DOS job code for buffer 3 ($0600), where the bootstrap now runs; cleared to $00 so the job controller never touches that buffer.", "confidence": "high"},
  {"addr": "04", "scope": "zp", "name": "jobCodeBuf4", "meaning": "DOS job code for buffer 4 ($0700, BAM buffer); cleared to $00.", "confidence": "high"},
  {"addr": "05", "scope": "zp", "name": "jobCodeBuf5", "meaning": "Unused sixth job slot (the 1541 has no buffer 5); cleared to $00 together with the others.", "confidence": "high"},
  {"addr": "06", "scope": "zp", "name": "jobTrackBuf0", "meaning": "Track for buffer 0 job = 1.", "confidence": "high"},
  {"addr": "07", "scope": "zp", "name": "jobSectorBuf0", "meaning": "Sector for buffer 0 job = 18 ($12): first page of the fast loader -> $0300.", "confidence": "high"},
  {"addr": "08", "scope": "zp", "name": "jobTrackBuf1", "meaning": "Track for buffer 1 job = 1.", "confidence": "high"},
  {"addr": "09", "scope": "zp", "name": "jobSectorBuf1", "meaning": "Sector for buffer 1 job = 19 ($13) -> $0400.", "confidence": "high"},
  {"addr": "0A", "scope": "zp", "name": "jobTrackBuf2", "meaning": "Track for buffer 2 job = 1.", "confidence": "high"},
  {"addr": "0B", "scope": "zp", "name": "jobSectorBuf2", "meaning": "Sector for buffer 2 job = 20 ($14) -> $0500.", "confidence": "high"},
  {"addr": "14", "scope": "zp", "name": "bootstrapSrcPtrLo", "meaning": "Low byte of the pointer to the page the bootstrap was originally executing in; always $00. In stock DOS $14/$15 hold the disk id of the nonexistent drive 1, so they are safe scratch.", "confidence": "high"},
  {"addr": "15", "scope": "zp", "name": "bootstrapSrcPtrHi", "meaning": "High byte of the source page, recovered from the stack after the JSR $0300 / RTS trick (page of the buffer DOS assigned to channel 2).", "confidence": "high"},
  {"addr": "0100", "scope": "abs", "name": "cpuStackPage", "meaning": "6502 stack; $0100,X with X = SP after the RTS holds the high byte of the return address pushed by JSR $0300, i.e. the page the bootstrap is running in.", "confidence": "high"},
  {"addr": "0300", "scope": "abs", "name": "fastLoaderEntry", "meaning": "Buffer 0 / first byte of the fast loader. Temporarily patched with $60 (RTS) for the self-locating trick, then overwritten by the sector-18 read and finally jumped to.", "confidence": "high"}
 ],
 "dataBlocks": [
  {"addr": "0641", "length": 12, "type": "byteTable", "name": "jobQueueInitTable", "description": "Image of drive zero page $00-$0B copied by queueFastLoaderReads: $80,$80,$80 (read jobs for buffers 0-2), $00,$00,$00 (no job for buffers 3-5), then track/sector pairs $01,$12 / $01,$13 / $01,$14 (track 1 sectors 18,19,20)."},
  {"addr": "064D", "length": 179, "type": "text", "name": "eaCopyrightMessage", "description": "Plain ASCII, no terminator, fills the sector to $06FF and is never displayed: '(C)1988 ELECTRONIC ARTS, 1820 GATEWAY DR, SAN MATEO,CA 94404. THE AGE OF MODEM WARFARE HAS BEGUN.  MORE TELEGAMES COMING SOON FROM EA.  WRITE TO US & TELL US YOU LIKE MODEM GAMES.'"}
 ],
 "misclassified": [],
 "insights": [
  "The bootstrap is position independent: DOS executes B-E from whichever buffer channel 2 was allocated, so the code locates its own page with JSR to a planted RTS at $0300 followed by TSX / LDA $0100,X (the high byte of the return address is still on the stack after RTS). It then copies itself to buffer 3 ($0600) because the three reads it is about to queue land in buffers 0-2 ($0300-$05FF) and would overwrite it if it stayed there.",
  "The listing label D_0600 is really the code entry point (suggest driveBootstrapEntry). Loop labels inside the chunk: L_0619 = page copy loop, L_0624 = (re)queue the three read jobs, L_0626 = job-table copy loop, L_062F = wait-for-jobs loop.",
  "The job completion check is 'OR of the three result bytes == $01': while any job is pending its byte still has bit 7 set (BMI loop); any DOS error code ($02..$0B) makes the OR differ from $01 and all three reads are re-queued. There is no error exit or LED indication - a bad track 1 hangs the drive in a retry loop, and the C64 side (bootLoadSectors) waits on the CLK line indefinitely as well.",
  "Track 1 sectors 18-20 (the fast loader at $0300-$05FF) are fetched with plain DOS job-code reads, so they cannot be encrypted; the XOR sector cipher only applies to data read later by the fast loader itself. The fast loader's first instruction (LDA #$00 / STA $1800) releases the CLK line that the bootstrap asserted with $08.",
  "$0300 is patched with $60 before the JSR; this is harmless because the same byte is overwritten moments later by the sector-18 read. ROM_INIT_DRIVE ($D042) is called after the loads so the BAM buffer ($0700) and disk id ($12/$13) are valid when the fast loader starts.",
  "The byte table at $0641 is shown in the listing as one .byte run that continues into the ASCII message; the table proper is only 12 bytes ($0641-$064C) and the text starts at $064D (179 bytes to the end of the sector). The text is ordinary ASCII with no bit-7 terminator, unlike the game's strings.",
  "Drive zero page $14/$15 is used as the copy pointer; in stock 1541 DOS these hold the drive-1 disk id, which is never used on a single-drive unit, so nothing is disturbed."
 ]
}
