; ============================================================================
; EA - 1-block BASIC-vector hijack loader (directory file "ea", loads at $02A8)
; ============================================================================
; Loaded with LOAD"EA",8,1 (or LOAD"*",8,1). The file overwrites the BASIC vectors at $0300-$030B so that
; control reaches $02B8 as soon as BASIC returns to its main loop after the LOAD completes.
; $02B8 then KERNAL-LOADs the file "load" ($9800-$C3FF) and calls the fast loader at $C000.

        .setcpu "6502"
        .include "c64.inc"
        .include "kernal.inc"
        .include "zeropage.inc"

; ---- references to code/data outside this file ----
gameEntry                := $0800
bootEntry                := $C000

; Contents
; --------
;    $02B8  eaLoadGame                   Stage 1 of the boot chain.

        .org $02A8


; strayBasicStub - 16 bytes of tokenised BASIC program text that are never executed.  This is the line
; the player is told to type; it survives in the file only as filler, so that the last 12 bytes of the
; LOAD land exactly on BASIC's vector table at $0300.  Layout: link word, line number, token $93
; (LOAD), the argument text, the end-of-line $00 and a null link word. It is formatted as if it lived
; at $0801 (BASIC's start of program), and the link word is two bytes short of this line's real end,
; so the ',1' was probably typed into the master by hand after the link had been computed for
; LOAD"EA",8.  Nothing in the boot chain reads these bytes; once the game runs the same page holds the
; map generator's contour rule table (track 18 s15-16) or the BAM sector buffer of the disk-id check,
; which is what the XREF hits on $02AB refer to.
strayBasicStub:
        .byte   $0D,$08                 ; 02A8  ..  BASIC link word $080D: where the next line would begin if this program sat at $0801 - two bytes short of the end of the line as it stands here
        .byte   $0A                     ; 02AA  line number low byte: this is line 10
D_02AB:
        .byte   $00                     ; 02AB  line number high byte ($000A = 10).  At run time this address is BAM offset $AB, the 10-byte disk serial that the copy loop at $0FF3 moves into ownPlayerName - that is the only real reader of D_02AB
        .byte   $93                     ; 02AC  BASIC token $93 = LOAD
        .byte   $22,$45,$41,$22,$2C,$38,$2C,$31; 02AD  "EA",8,1  the rest of the statement as plain PETSCII: "EA",8,1 - file name EA, device 8, secondary address 1 (load at the file's own address)
        .byte   $00                     ; 02B5  $00 terminates the BASIC line
        .byte   $00,$00                 ; 02B6  ..  null link word = end of the BASIC program

; ----------------------------------------------------------------------
; eaLoadGame - Stage 1 of the boot chain.  Reached through the BASIC vectors this file has just
; overwritten (normally IMAIN $0302, taken by BASIC's ready loop the moment LOAD"EA",8,1 finishes), or
; on the C128 path by a direct JMP from the CBM80 cartridge stub at $8065.  It opens logical file 8 on
; device 8 with secondary address 1 so the file supplies its own load address, points SETNAM at the
; name 'LOAD' a few bytes further down this same file, silences the KERNAL's messages and KERNAL-LOADs
; the 45-block file 'LOAD' to $9800-$C3FF (title picture plus the boot loader). It then calls the boot
; loader at $C000, which never comes back: that code shows the title picture, initialises the modem
; and the drive, block-executes the drive bootstrap and reads the rest of the game in, and its closing
; RTS is rigged to continue at $0461 (the checksum routine in the $0400 block), which ends with JMP
; $0800.  The JMP gameEntry at $02D5 is therefore only reached when the KERNAL LOAD failed; the error
; handler that used to live there was overwritten when the JSR/JMP pair was patched in (see
; orphanedStoreOperand at $02D8).  Everything here runs with the ROMs still banked in and interrupts
; still enabled.
; In:  no register inputs (entered by JMP through the BASIC vector table, KERNAL/BASIC ROMs in,
;     BASIC's stack in place); reads the file name at eaFileName $02EC
; Out: file 'LOAD' at $9800-$C3FF; kernalMsgFlag ($9D, KERNAL MSGFLG) = 0; control passes to bootEntry
;     $C000 and never returns to this file.  Only on a KERNAL LOAD error does it fall through to JMP
;     gameEntry $0800 with nothing loaded.
; Called from: the BASIC vector table $0300-$030B written by this very file (basicVectorHijack) on the
;     C64 path, and boot/c64CartridgeStub8000 cartLoadEaFile ($8065) on the C128 path.  The '(also
;     textEngineC000:...)' alias the listing prints on the JSR at $02D2 is an artefact: the runtime
;     text-engine overlay later replaces the whole $C000 page and XREF cannot tell the two apart.
; ----------------------------------------------------------------------
eaLoadGame:
        lda     #$08                    ; 02B8  logical file number 8 for the KERNAL LOAD (any nonzero value would do)
        tax                             ; 02BA  X = device number 8 = the disk drive; the same $08 serves as both file and device number
        ldy     #$01                    ; 02BB  secondary address 1: load to the address in the file's own two-byte header ($9800), not to BASIC's start of program
        jsr     KERNAL_SETLFS           ; 02BD  SETLFS ($FFBA): set file 8, device 8, secondary address 1
        lda     #$04                    ; 02C0  A = file name length: 4 characters
        ldx     #$EC                    ; 02C2  X = low byte of the name pointer -> eaFileName
        ldy     #$02                    ; 02C4  Y = high byte: the name 'LOAD' sits at $02EC, inside this very file
        jsr     KERNAL_SETNAM           ; 02C6  SETNAM ($FFBD): the file to fetch is 'LOAD'
        lda     #$00                    ; 02C9  0 = LOAD rather than VERIFY for the call below, and the value stored into MSGFLG next
        sta     kernalMsgFlag           ; 02CB  MSGFLG = 0: bit 7 (control messages SEARCHING FOR / LOADING) and bit 6 (I/O ERROR messages) both off, so the KERNAL LOAD prints nothing
        jsr     KERNAL_LOAD             ; 02CD  LOAD ($FFD5): pull the 45-block file 'LOAD' to its header address $9800-$C3FF - title colour RAM $9800, title screen $9C00, title bitmap $A000 and the boot loader $C000-$C3FF
        bcs     jumpToGameEntry         ; 02D0  branch if the KERNAL reported an error (C=1, A = error code): skip the boot loader.  In the unpatched EA template this branch reached the 'ERROR' handler whose remains start at $02DA
        jsr     bootEntry               ; 02D2  enter the boot loader that was just loaded ($C000 = JMP bootMain $C145): title picture, modem/drive init, B-E of the drive bootstrap, then tracks 22-27 into $0800+.  It never returns here - bootMain's faked RTS lands at $0461, which JMPs to $0800  (also textEngineC000:bitPairHighTable)

; ----------------------------------------------------------------------
; Only reached when the KERNAL LOAD above failed - on the normal path the boot loader never returns
; here.
; ----------------------------------------------------------------------
jumpToGameEntry:
        jmp     gameEntry               ; 02D5  jump into the game at $0800 with nothing loaded.  $0800 then still holds $00 = BRK and the ROMs are still in, so this probably falls through the KERNAL BRK handler to BASIC's warm start, which JMPs ($0302) straight back to eaLoadGame: a failed load quietly retries (inferred, not verified)


; orphanedStoreOperand - the two operand bytes of an instruction that no longer exists.  In the
; untouched EA loader template the load-error path started at $02D5 with LDA #$05 / STA $0400 (screen
; code 'E' in the top left corner) and the success path was a plain JMP at $02D2.  This build patched
; JSR bootEntry ($02D2) and JMP gameEntry ($02D5) over $02D2-$02D7, which ate the LDA and the opcode
; of the STA and left its address operand $0400 stranded here (probable reconstruction: the byte
; counts and the missing 'E' both fit).  The rest of that handler still assembles - see
; deadLoadErrorRetry below.
orphanedStoreOperand:
        .byte   $00,$04                 ; 02D8  ..  little-endian $0400 = the screen-RAM operand of the overwritten 'STA $0400'

; deadLoadErrorRetry - Unreachable remnant of the load-error handler of the shared EA loader template.
; It still decodes cleanly: it writes screen codes 'R','R','O','R' into $0401-$0404, i.e. the top left
; corner of the default text screen (the leading 'E' at $0400 came from the LDA/STA that the JSR/JMP
; patch destroyed), and then branches unconditionally back to eaLoadGame to retry the whole
; SETLFS/SETNAM/LOAD sequence.  Nothing reaches it in this build: the BCS at $02D0 that used to land
; here now lands on the JMP gameEntry at $02D5.  The writes only make sense this early in the boot,
; while the VIC still shows the text screen at $0400 and the ROMs are banked in.
; In:  nothing (would have been entered with C=1 from the BCS at $02D0 in the original build)
; Out: would put 'ERROR' at the start of the top screen line and re-enter eaLoadGame; dead code as
;     built
; Called from: nothing in this build
deadLoadErrorRetry:
        .byte   $A9                     ; 02DA  screen code $12 = 'R' (screen codes, not PETSCII: 'A' = 1)
        .byte   $12                     ; 02DB  .
        .byte   $8D                     ; 02DC  second character of ERROR, column 1 of the top row of the default text screen at $0400
        .byte   $01,$04                 ; 02DD  ..
        .byte   $8D                     ; 02DF  third character, column 2 - the two 'R's share one LDA
        .byte   $02,$04                 ; 02E0  ..
        .byte   $8D                     ; 02E2  fifth character, column 4; written out of order so that all three 'R's use the same loaded value
        .byte   $04,$04                 ; 02E3  ..
        .byte   $A9                     ; 02E5  screen code $0F = 'O'
        .byte   $0F                     ; 02E6  .
        .byte   $8D                     ; 02E7  fourth character, column 3, completing E-R-R-O-R
        .byte   $03,$04                 ; 02E8  ..
        .byte   $D0                     ; 02EA  always taken (A = $0F, never zero): go back and try the whole load again
        .byte   $CC                     ; 02EB  .

; eaFileName - the PETSCII name of the second-stage file, 4 characters with no terminator; the length
; is handed to SETNAM in A at $02C0 and the pointer in X/Y at $02C2/$02C4.  'LOAD' is the 45-block
; directory file that carries the title picture ($9800 colour RAM, $9C00 screen, $A000 bitmap) and the
; boot loader at $C000-$C3FF.
eaFileName:
        .byte   "LOAD"                  ; 02EC  'LOAD' - exactly the 4 bytes SETNAM is told about

; fileNamePadding - '00' followed by 14 zero bytes, never read.  SETNAM is told the name is 4
; characters long, so the '00' is not part of it; it looks like the tail of a longer name (LOAD00)
; left over from the EA mastering template.  The zeros pad the file out so that the next byte is
; $0300.
fileNamePadding:
        .byte   $30,$30,$00,$00,$00,$00,$00,$00; 02F0  00......  unused tail of the file name plus padding up to the BASIC vector table
        .byte   $00,$00,$00,$00,$00,$00,$00,$00; 02F8  ........

; basicVectorHijack - the actual payload of this file.  Six little-endian pointers, every one of them
; $02B8 (eaLoadGame), which the tail of the KERNAL LOAD drops straight onto BASIC's indirect vectors:
; IERROR $0300, IMAIN $0302, ICRNCH $0304, IQPLOP $0306, IGONE $0308 and IEVAL $030A. Because
; LOAD"EA",8,1 was typed in direct mode, BASIC returns to its ready loop, which dispatches through JMP
; ($0302) - so the game starts by itself with no RUN.  Aiming all six at the same address also makes
; the boot self-healing: an error, a tokenise, a LIST, the start of a statement or the evaluation of
; an expression all end up in eaLoadGame.  The table ends at $030B, the last byte of the file.
; Everything the XREF lists for $0300-$030B belongs to later owners of this page (initGameSystems
; loaded from track 18 s15-16, the map generator's scratch variables, the film directory), not to this
; table.
basicVectorHijack:
        .byte   $B8                     ; 0300  IERROR low byte: BASIC's error-handler vector, aimed at eaLoadGame
D_0301:
        .byte   $02                     ; 0301  IERROR high byte - $02B8 (this label exists only because the map generator uses the same address for a variable)
D_0302:
        .byte   $B8                     ; 0302  IMAIN low byte: the vector BASIC JMPs through after printing READY. - this is the one that really launches the game
        .byte   $02                     ; 0303  IMAIN high byte - $02B8
D_0304:
        .byte   $B8                     ; 0304  ICRNCH low byte: the tokenise-a-line vector, aimed at eaLoadGame as well
        .byte   $02                     ; 0305  ICRNCH high byte - $02B8
        .byte   $B8                     ; 0306  IQPLOP low byte: the list-a-token vector
D_0307:
        .byte   $02                     ; 0307  IQPLOP high byte - $02B8
        .byte   $B8                     ; 0308  IGONE low byte: the execute-next-statement vector
        .byte   $02                     ; 0309  IGONE high byte - $02B8
        .byte   $B8                     ; 030A  IEVAL low byte: the evaluate-an-expression-element vector
        .byte   $02                     ; 030B  IEVAL high byte - $02B8; the file ends here, exactly on the last byte of the BASIC vector table
