229 lines
12 KiB
JSON
229 lines
12 KiB
JSON
{
|
|
"chunk": "drive_driveBootstrap_0600",
|
|
"unit": "drive/driveBootstrap",
|
|
"unitLabels": {
|
|
"drive/driveBootstrap": {
|
|
"0600": "driveBootstrapEntry",
|
|
"0619": "copySelfToBuffer3Loop",
|
|
"0624": "queueFastLoaderReads",
|
|
"0626": "copyJobQueueLoop",
|
|
"062F": "waitForReadJobsLoop",
|
|
"0641": "jobQueueInitTable",
|
|
"064D": "eaCopyrightMessage",
|
|
"06BA": "eaCopyrightMessageTail"
|
|
}
|
|
},
|
|
"dataTypes": {
|
|
"0641": ["grid", 12, 6],
|
|
"064D": ["text", 179],
|
|
"06BA": ["text", 70]
|
|
},
|
|
"notes": {
|
|
"0600": {
|
|
"unit": "drive/driveBootstrap",
|
|
"routine": [
|
|
"driveBootstrapEntry - the 1541-side bootstrap, i.e. the whole of track 1 sector 17, executed inside the drive by the DOS command 'B-E 2 0 1 17'. It first pulls the serial CLK line low as a 'drive busy' flag (that is what makes the C64 wait until the fast loader is up), then works out which buffer page DOS actually gave it - JSR to an RTS planted at $0300, then TSX / LDA $0100,X picks the return-address high byte off the stack - and copies its own 256-byte page to buffer 3 ($0600), continuing there. The move is necessary because the three sector reads it is about to queue land in buffers 0-2 ($0300-$05FF) and would overwrite the running code.",
|
|
"In: nothing; DOS has read the sector into the buffer of channel 2 (the '#' channel the C64 opened) and jumped to its first byte. The page it runs from is recovered from the stack, so the code is fully position independent.",
|
|
"Out: I flag set; VIA1 port B = $08 (CLK asserted, DATA released, ATN acknowledge off); $0300 = $60 (RTS); $14/$15 = pointer to the page it was loaded into; $0600-$06FF = a copy of this sector. Execution continues at queueFastLoaderReads inside that copy.",
|
|
"Called from: the 1541 DOS block-execute command only. The C64 sends the string 'B-E 2 0 1 17' from bootBlockExecute ($C32C in boot/fastLoaderC000) right after opening buffer channel 2 with the filename '#'."
|
|
],
|
|
"line": "mask the DOS interrupt: neither the disk-controller job loop nor the serial-bus ATN handler may run while this sector relocates itself"
|
|
},
|
|
"0601": {
|
|
"unit": "drive/driveBootstrap",
|
|
"line": "clear decimal mode before touching job codes and pointers (defensive - DOS leaves it clear)"
|
|
},
|
|
"0602": {
|
|
"unit": "drive/driveBootstrap",
|
|
"block": [
|
|
"Take the serial bus away from DOS and hold the host off. VIA1 port B at $1800 is the serial port:",
|
|
"bit 0 = DATA IN, bit 1 = DATA OUT, bit 2 = CLK IN, bit 3 = CLK OUT, bit 4 = ATNA (hardware",
|
|
"acknowledge of ATN), bits 5-6 = device address jumpers, bit 7 = ATN IN. The data direction",
|
|
"register is left as DOS set it ($1A = bits 1,3,4 outputs)."
|
|
],
|
|
"line": "bit 3 alone = CLK OUT on, DATA OUT off, ATN acknowledge off"
|
|
},
|
|
"0604": {
|
|
"unit": "drive/driveBootstrap",
|
|
"line": "pull the serial CLK line low (the drive's outputs are inverted, so writing 1 makes the line true) and release DATA: the C64 sits in bootExchangeByte ($C040: BIT $DD00 / BVC) waiting for CLK IN to go high again, which only happens when the fast loader starts at $0300 and writes $00 here"
|
|
},
|
|
"0607": {
|
|
"unit": "drive/driveBootstrap",
|
|
"block": [
|
|
"Find out which page this code is executing in. DOS block-execute runs the sector from whatever",
|
|
"buffer channel 2 was allocated, so the address is not known at assembly time: JSR to a planted RTS",
|
|
"and read back the return address the JSR left on the stack."
|
|
],
|
|
"line": "$60 = the RTS opcode"
|
|
},
|
|
"0609": {
|
|
"unit": "drive/driveBootstrap",
|
|
"line": "plant that RTS at the first byte of buffer 0; clobbering $0300 is harmless because the track 1 sector 18 read overwrites the whole buffer moments later"
|
|
},
|
|
"060C": {
|
|
"unit": "drive/driveBootstrap",
|
|
"line": "call the planted RTS purely for the side effect: JSR pushes return address $060E, whose high byte is the page this code really lives in"
|
|
},
|
|
"060F": {
|
|
"unit": "drive/driveBootstrap",
|
|
"line": "X = stack pointer, which the RTS has put back to its pre-JSR value"
|
|
},
|
|
"0610": {
|
|
"unit": "drive/driveBootstrap",
|
|
"line": "$0100+X still holds the return-address high byte the RTS read but did not erase = this page number ($03, $04, $05 or $06, whichever buffer DOS handed out)"
|
|
},
|
|
"0613": {
|
|
"unit": "drive/driveBootstrap",
|
|
"line": "high byte of the copy source pointer; drive zero page $14/$15 is the disk id of the non-existent drive 1 in stock DOS, so it is free scratch"
|
|
},
|
|
"0615": {
|
|
"unit": "drive/driveBootstrap",
|
|
"line": "Y = 0: index over the whole 256-byte page, and also the low byte of the source pointer"
|
|
},
|
|
"0617": {
|
|
"unit": "drive/driveBootstrap",
|
|
"line": "source low byte = 0 - every DOS buffer starts on a page boundary"
|
|
},
|
|
"0619": {
|
|
"unit": "drive/driveBootstrap",
|
|
"block": [
|
|
"Copy all 256 bytes of this sector (code, job table and the EA message) from the buffer DOS chose",
|
|
"into buffer 3 at $0600. Y counts 0..255 and wraps to end the loop."
|
|
],
|
|
"line": "read byte Y of the page we are currently executing in"
|
|
},
|
|
"061B": {
|
|
"unit": "drive/driveBootstrap",
|
|
"line": "write it to buffer 3 ($0600); if DOS happened to allocate that very buffer the loop just copies the page onto itself, which is harmless"
|
|
},
|
|
"061E": {
|
|
"unit": "drive/driveBootstrap",
|
|
"line": "advance to the next byte of the page"
|
|
},
|
|
"061F": {
|
|
"unit": "drive/driveBootstrap",
|
|
"line": "loop until Y wraps back to 0, i.e. all 256 bytes have been copied"
|
|
},
|
|
"0621": {
|
|
"unit": "drive/driveBootstrap",
|
|
"line": "jump into the identical copy at $0624 by absolute address - from here on the code runs in buffer 3 and buffers 0-2 are free to be overwritten by the reads"
|
|
},
|
|
"0624": {
|
|
"unit": "drive/driveBootstrap",
|
|
"routine": [
|
|
"queueFastLoaderReads - pulls the fast loader into the drive. It writes jobQueueInitTable over the DOS job queue so that buffers 0, 1 and 2 each get a 'read sector' job for track 1 sectors 18, 19 and 20 ($0300, $0400, $0500), enables interrupts so the disk controller executes them, waits for all three to finish and insists that every one reported OK. Then it re-initialises the disk (BAM and disk id) and jumps into the code it has just loaded.",
|
|
"In: jobQueueInitTable ($0641). Must already be executing from $0600, because the three reads overwrite $0300-$05FF.",
|
|
"Out: $0300-$05FF = the 1541 fast loader (track 1 sectors 18-20, the only game code on the disk stored in plaintext); drive zero page $00-$0B = job queue state ($01 in each of the three job bytes); $12/$13 = disk id; I flag clear. Never returns - it ends with JMP $0300.",
|
|
"Called from: the JMP at $0621 (entry after the self-copy) and from its own retry branch at $0639. A read error re-queues the whole set forever: there is no error exit."
|
|
],
|
|
"block": [
|
|
"Load the three pages of the fast loader. This is also the retry entry point: any failed read comes",
|
|
"back here and re-issues all three jobs from scratch."
|
|
],
|
|
"line": "12 table bytes to copy, highest index first"
|
|
},
|
|
"0626": {
|
|
"unit": "drive/driveBootstrap",
|
|
"block": [
|
|
"Copy the job-queue image into drive zero page $00-$0B, backwards from index 11 to 0."
|
|
],
|
|
"line": "next byte of the image (indices 0-5 are job codes, 6-11 are track/sector pairs)"
|
|
},
|
|
"0629": {
|
|
"unit": "drive/driveBootstrap",
|
|
"line": "store into the DOS job queue: $00-$05 = job code for buffers 0-5, $06-$11 = the track/sector pair belonging to each buffer (only buffers 0-2 are given work here)"
|
|
},
|
|
"062B": {
|
|
"unit": "drive/driveBootstrap",
|
|
"line": "step down one entry"
|
|
},
|
|
"062C": {
|
|
"unit": "drive/driveBootstrap",
|
|
"line": "keep copying until index 0 has been written (BPL, so all 12 bytes $0B..$00)"
|
|
},
|
|
"062E": {
|
|
"unit": "drive/driveBootstrap",
|
|
"line": "let interrupts back in: the DOS disk controller runs from the VIA2 interrupt and only now notices the three $80 jobs, seeks to track 1 and reads the sectors"
|
|
},
|
|
"062F": {
|
|
"unit": "drive/driveBootstrap",
|
|
"block": [
|
|
"Wait for the three reads. While a job is outstanding its queue byte still holds the job code with",
|
|
"bit 7 set; when the controller finishes it replaces the byte with the result code (bit 7 clear,",
|
|
"$01 = OK, $02 = header not found, $05 = data checksum error, ...). ORing the three bytes therefore",
|
|
"gives a negative value while anything is still pending and exactly $01 when all three succeeded."
|
|
],
|
|
"line": "job byte of buffer 0 (track 1 sector 18 -> $0300)"
|
|
},
|
|
"0631": {
|
|
"unit": "drive/driveBootstrap",
|
|
"line": "merge the job byte of buffer 1 (track 1 sector 19 -> $0400)"
|
|
},
|
|
"0633": {
|
|
"unit": "drive/driveBootstrap",
|
|
"line": "merge the job byte of buffer 2 (track 1 sector 20 -> $0500)"
|
|
},
|
|
"0635": {
|
|
"unit": "drive/driveBootstrap",
|
|
"line": "bit 7 still set somewhere, so at least one read is still queued or running: keep spinning"
|
|
},
|
|
"0637": {
|
|
"unit": "drive/driveBootstrap",
|
|
"line": "all three have finished - the OR of three 'OK' result codes ($01) is $01, and no other combination of DOS codes can produce it"
|
|
},
|
|
"0639": {
|
|
"unit": "drive/driveBootstrap",
|
|
"line": "any error code sets extra bits, so re-queue all three reads and try again - forever. There is no error exit and no LED blink: a damaged track 1 hangs the drive here, and the C64 hangs with it because CLK is still held low"
|
|
},
|
|
"063B": {
|
|
"unit": "drive/driveBootstrap",
|
|
"block": [
|
|
"The fast loader is in place; hand the drive over to it."
|
|
],
|
|
"line": "DOS 'initialise drive' ($D042): re-reads the BAM of track 18 and reloads the disk id into $12/$13, which the fast loader needs both to build the expected sector header ($039D) and for its id check at $0525 - zp_12 EOR zp_13 must equal $15, which is 'O' EOR 'Z', the id of the Modem Wars disk"
|
|
},
|
|
"063E": {
|
|
"unit": "drive/driveBootstrap",
|
|
"line": "enter fastloaderMain in the code just read into buffers 0-2; its first two instructions (LDA #$00 / STA $1800) release the CLK line and so unblock the C64, which then starts requesting sectors"
|
|
},
|
|
"0641": {
|
|
"unit": "drive/driveBootstrap",
|
|
"block": [
|
|
"jobQueueInitTable - 12-byte image of drive zero page $00-$0B, copied into the DOS job queue by",
|
|
"queueFastLoaderReads. Element size 1 byte; the index is the zero-page address:",
|
|
" $00-$02 = $80, the DOS 'read sector' job code, for buffers 0, 1, 2 ($0300, $0400, $0500)",
|
|
" $03-$05 = $00, no job, for buffers 3, 4, 5: buffer 3 ($0600) is where this code now runs,",
|
|
" buffer 4 ($0700) is the BAM buffer, and a 1541 has no buffer 5 at all",
|
|
" $06-$0B = the track/sector pair of each job, two bytes per buffer: 1/18 ($01,$12) for buffer 0,",
|
|
" 1/19 ($01,$13) for buffer 1, 1/20 ($01,$14) for buffer 2 - the three pages of the",
|
|
" fast loader, in order.",
|
|
"Because these are ordinary DOS job-code reads, track 1 sectors 18-20 are the only game code on the",
|
|
"disk that cannot be XOR-encrypted; the sector cipher at $0531 is applied by the fast loader itself."
|
|
],
|
|
"line": "row 0 = job codes for buffers 0-5, row 1 = the three track/sector pairs"
|
|
},
|
|
"064D": {
|
|
"unit": "drive/driveBootstrap",
|
|
"block": [
|
|
"eaCopyrightMessage - 179 bytes of plain ASCII filling the rest of the sector, from $064D to the",
|
|
"last byte $06FF. Ordinary ASCII with no bit-7 terminator, unlike the game's own strings, and",
|
|
"nothing ever reads or prints it: like the 'DaN'/'SaRa' signature at the end of the fast loader",
|
|
"($05F4) it is a message for whoever dumps track 1. It reads:",
|
|
" '(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.'",
|
|
"The listing breaks the run into pieces only as an artefact of the build: the C64 side of the game",
|
|
"has its own labels and strings at these same addresses (this page is a drive buffer here and part",
|
|
"of the game's $0400-$07FF scratch page there)."
|
|
],
|
|
"line": "start of the 179-byte message; it runs unbroken to $06FF"
|
|
},
|
|
"06BA": {
|
|
"unit": "drive/driveBootstrap",
|
|
"block": [
|
|
"eaCopyrightMessageTail - the last 70 bytes of eaCopyrightMessage. It only carries its own label",
|
|
"because the C64-side unit has code at this address and splits the text run."
|
|
],
|
|
"line": "'...AMES COMING SOON FROM EA. WRITE TO US & TELL US YOU LIKE MODEM GAMES.'"
|
|
}
|
|
}
|
|
}
|