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

176 lines
No EOL
11 KiB
JSON
Generated

{
"_comment": "generated by tools/mergeSurvey.py from survey/*.json - do not edit by hand",
"notes": {
"0300": {
"routine": [
"fastloaderMain - Entry point of the 1541 fast loader; the bootstrap sector (T1 s17) reads T1 s18-20 to $0300-$05FF and JMPs here. Idles the serial lines, sets the default track/sector ($06=18,$07=0), issues disk-controller job $B0 on buffer 0 and waits for it to finish, then falls into commandDispatchLoop.",
"In: none (entered from the bootstrap)",
"Out: zp_06=$12, zp_07=$00, zp_00 job issued; falls through to $0313"
],
"unit": "drive/driveFastLoader"
},
"0313": {
"routine": [
"commandDispatchLoop - Top of the drive command loop. Resets the stack (SP=$45), receives a command byte from the host via receiveCommand, and dispatches: $C0 resets the drive (JMP through reset vector), $60 goes to handleWriteCommand, anything else is a read (receive track and sector, read the sector, send it back, then report status 0). Re-entered after every operation.",
"In: command byte from receiveCommand",
"Out: zp_50=0; branches to read/write/reset handlers"
],
"unit": "drive/driveFastLoader"
},
"0342": {
"routine": [
"setHeadReadMode - Sets VIA2 PCR bits 1-3 (ORA #$0E) to put the read/write head electronics into read mode. Called by prepareHeadAndVerifyId before reading or writing a sector.",
"In: VIA2_PCR",
"Out: VIA2_PCR updated",
"(confidence: medium)"
],
"unit": "drive/driveFastLoader"
},
"034B": {
"routine": [
"exchangeByteWithHost - Core full-duplex serial byte transfer with the C64. Clocks the byte in A out to the host one bit at a time (LSB first) on VIA1 serial bit1 while simultaneously shifting a received byte in on bit0, using a two-phase CLK/ACK handshake on bits 2/3. This is the drive-side counterpart of the C64 routine sendByteToDrive ($089C). Used for all command/parameter bytes, the status byte, and (in the write path) the 256 data bytes from the host.",
"In: A = byte to send (into zp_90)",
"Out: A = byte received from host (zp_8F); uses zp_14 as handshake temp; X clobbered"
],
"unit": "drive/driveFastLoader"
},
"0391": {
"routine": [
"sendStatusAndLoop - Sends the status/error byte in A to the host via exchangeByteWithHost, then JMPs back to commandDispatchLoop. Every error path (header not found=$02, checksum=$05, write protect/id error=$08) jumps here with its code in A; the normal read path jumps here with A=0.",
"In: A = status byte",
"Out: status sent to host; loops to $0313"
],
"unit": "drive/driveFastLoader"
},
"0397": {
"routine": [
"seekSectorAndSyncData - Finds the requested sector header on disk (findSectorHeader) then waits for and reads into the data-block sync (waitForSyncByte). Called at the start of readSectorFromDisk to position the read at the sector's data field.",
"In: zp_3D drive index, zp_12/zp_13, zp_32 header pointer",
"Out: positioned at data field; V clear, Y=0; error $02 via sendStatusAndLoop",
"(confidence: medium)"
],
"unit": "drive/driveFastLoader"
},
"039D": {
"routine": [
"findSectorHeader - Builds the expected 8-byte GCR header image (from the id bytes zp_12/zp_13, the track/sector bytes via (zp_32), and their XOR checksum) with ROM_MAKE_HEADER_GCR into the zp_24 buffer, then reads raw GCR bytes from VIA2 comparing 8 bytes at a time. Returns when the matching header passes under the head; after $5A failed tries reports error $02. Also used by writeSectorToDisk to locate the sector before writing.",
"In: zp_3D drive index, zp_12/zp_13 disk id bytes, zp_32 header ptr",
"Out: header located; zp_16-zp_1A header scratch; error $02 via sendStatusAndLoop",
"(confidence: medium)"
],
"unit": "drive/driveFastLoader"
},
"03E3": {
"routine": [
"waitForSyncByte - Arms VIA1 timer 1 as a timeout, waits for a SYNC mark on VIA2 (bit 7 of the disk-control port), then reads the first byte after sync from VIA2 and returns it. On timeout it branches to the error path ($02 via sendStatusAndLoop). Clears V and Y before returning.",
"In: VIA1_T1, VIA2 disk port",
"Out: A = byte after sync, V clear, Y=0; timeout -> error",
"(confidence: medium)"
],
"unit": "drive/driveFastLoader"
},
"03FB": {
"routine": [
"readSectorFromDisk - Reads the sector named by zp_06/zp_07 from disk into buffer $0600: waits for the buffer-0 job, verifies the head/id (prepareHeadAndVerifyId), seeks to the data field (seekSectorAndSyncData), reads 256 GCR data bytes into $0600 plus the GCR overflow into $0100, converts GCR->binary and verifies the data checksum against zp_3A (error $05 on mismatch), then falls through to cryptSectorBuffer to decrypt. Invoked by the read branch of the command loop.",
"In: zp_06 track, zp_07 sector, zp_31 buffer page",
"Out: decrypted sector in $0600; zp_3A checksum; error $05 via sendStatusAndLoop"
],
"unit": "drive/driveFastLoader"
},
"044B": {
"routine": [
"sendSectorToHost - Sends the 256 decrypted bytes in buffer $0600 back to the C64. Each byte is split into two nibbles, each nibble translated through nibbleSendTable and clocked out 4 bits at a time on the VIA1 serial port with a handshake (bit0 = clock). This bulk path is received by the C64 routine receiveSectorData ($0950). Ends via finishSendByte.",
"In: $0600 buffer (256 decrypted bytes), nibbleSendTable",
"Out: 256 bytes clocked to host; VIA1 serial port"
],
"unit": "drive/driveFastLoader"
},
"0490": {
"routine": [
"handleWriteCommand - Write-command ($60) handler: receives the track and sector bytes from the host into zp_06/zp_07, calls writeSectorToDisk, then returns to commandDispatchLoop.",
"In: track/sector from host via exchangeByteWithHost",
"Out: sector written; loops to $0313"
],
"unit": "drive/driveFastLoader"
},
"04A0": {
"routine": [
"writeSectorToDisk - Receives 256 data bytes from the host into $0600, encrypts them in place (cryptSectorBuffer, symmetric with decrypt), computes the data checksum into zp_3A, checks the write-protect sense (VIA2 bit 4; error $08 if protected), converts binary->GCR, positions on the header (findSectorHeader), switches VIA2 to write mode, writes the GCR overflow ($0100) and data (zp_30) fields, restores read mode, and sends the status byte. Called by handleWriteCommand.",
"In: 256 bytes from host, zp_06/zp_07, zp_30 buffer ptr",
"Out: sector written to disk, zp_3A checksum; error $08 via sendStatusAndLoop"
],
"unit": "drive/driveFastLoader"
},
"0525": {
"routine": [
"prepareHeadAndVerifyId - Selects read mode (setHeadReadMode) and validates the drive id bytes: if zp_12 EOR zp_13 EOR $15 is nonzero it branches to the write-protect/id error path ($08). Called at the start of both readSectorFromDisk and writeSectorToDisk. The exact meaning of the $15 constant is a DOS id/consistency check.",
"In: zp_12, zp_13",
"Out: read mode set; error $08 via sendStatusAndLoop on mismatch",
"(confidence: low)"
],
"unit": "drive/driveFastLoader"
},
"0531": {
"routine": [
"cryptSectorBuffer - The sector cipher: XORs the 256 bytes in $0600 with a self-modifying rolling key (key0 = ROL((track|$C0)<<1 + sector + carry); key[y]=ROL(y EOR key)). Track 18 ($12) is left in plaintext (BAM/directory/map/setup). Symmetric, so the same routine decrypts on read and encrypts on write. This is the cipher documented in overview section 4.",
"In: $0600 buffer, zp_06 track, zp_07 sector",
"Out: $0600 XORed in place (except track 18)"
],
"unit": "drive/driveFastLoader"
},
"0553": {
"routine": [
"uploadBytesToDrive - Code/data injection loop reached from receiveCommand when the host sends a count byte >= $F0: receives (256 - count) bytes and stores them consecutively into drive RAM starting at $0580 (the RTS-filled scratch area) using self-modifying stores, then falls through into receiveCommand again to fetch the real command. Lets the host push a small routine or table into the drive.",
"In: count in patched $057E, bytes from host",
"Out: bytes written to $0580+; re-enters receiveCommand",
"(confidence: medium)"
],
"unit": "drive/driveFastLoader"
},
"0561": {
"routine": [
"receiveCommand - Receives one command/parameter byte from the host: clears a VIA2 status bit, sends $01 and receives a byte via exchangeByteWithHost, patches it into the LDA at $057D. If the byte is >= $F0 it is a byte-count preamble and control drops to uploadBytesToDrive to inject that many bytes into $0580 before looping back for the real command; otherwise the received byte is returned in A.",
"In: host serial input",
"Out: A = command byte",
"(confidence: medium)"
],
"unit": "drive/driveFastLoader"
},
"05DE": {
"routine": [
"finishSendByte - Tail of sendSectorToHost: writes the final value in A to the VIA1 serial port and returns (leaves the serial lines in the idle state after a bulk read).",
"In: A, VIA1 serial port",
"Out: VIA1 serial port set; RTS",
"(confidence: medium)"
],
"unit": "drive/driveFastLoader"
},
"05E2": {
"routine": [
"checksumBufferAndReport - Small 6502 routine that the disassembler classified as data (it sits after an RTS and has no in-file caller). $05E2 does JSR $05E8 / JMP sendStatusAndLoop; $05E8 sums the 256 bytes of $0600 with a ROL+ADC accumulator and returns. Most likely a verify/checksum helper invoked by code injected via uploadBytesToDrive, or dead code. Followed by a hidden signature.",
"In: $0600 buffer",
"Out: A = rolling checksum, reported to host via sendStatusAndLoop",
"(confidence: low)"
],
"unit": "drive/driveFastLoader"
},
"043B": {
"unit": "drive/driveFastLoader",
"block": [
"nibbleSendTable: byteTable, 16 bytes. 16-entry nibble translation table used by sendSectorToHost. Entry n = complement of the nibble n with its two outer bits swapped (0->$0F,1->$07,2->$0D,...). Encodes each nibble into the 4 serial bits sent to the C64 during a bulk read."
]
},
"0582": {
"unit": "drive/driveFastLoader",
"block": [
"driveUploadScratch: byteTable, 92 bytes. $0582-$05DD filled with $60 (RTS). This is the RTS-filled scratch/patch area; uploadBytesToDrive stores injected bytes starting at $0580 into this region. Pre-filling with RTS makes any un-overwritten byte a harmless return."
]
},
"05F4": {
"unit": "drive/driveFastLoader",
"block": [
"hiddenSignature: text, 12 bytes. Hidden signature bytes at the very end of the loader: ASCII fragments 'DaN' and 'SaRa' (Dan Bunten / family names) mixed with a couple of opcode-looking bytes. Not referenced; an easter-egg credit like the EA message in the bootstrap sector."
]
}
}
}