; ============================================================================
; Pseudo-cartridge image copied to $8000 by the C128 boot sector (bytes $89-$FF of track 1 sector 0)
; ============================================================================
; $8000/$8002 = cold/warm start vectors ($8009), $8004 = "CBM80".  The C64 KERNAL reset code jumps to
; $8009, which initialises I/O, clears low RAM, sets MEMTOP and LOADs the normal boot file.

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

; ---- references to code/data outside this file ----
D_0200                   := $0200
D_0282                   := $0282
D_0288                   := $0288
L_02B8                   := $02B8
D_0300                   := $0300
sub_0B45                 := $0B45
sub_0B55                 := $0B55

; Contents
; --------
;    $8009  cartColdStart                Cold/warm start of the CBM80 pseudo-cartridge that the C128 boot sector plants
;                                        at $8000 before GO64.
;    $800F  clearLowRamLoop              Not a callable routine, just the body of the clear loop inside cartColdStart.
;    $8065  cartLoadEaFile               Tail of cartColdStart, reached by the JMP at $805E that steps over the inline
;                                        filename.

        .org $8000


; cartHeader ($8000-$8008) - the 9-byte autostart cartridge header the C64 KERNAL looks for.
; $8000/$8001 = cold-start vector, $8002/$8003 = warm-start (NMI) vector, $8004-$8008 = the
; signature 'CBM80'.  Both vectors point at $8009, so RESET and RESTORE do exactly the same thing.
; This is RAM, not ROM: the C128 boot sector at $0B27 copies 256 bytes from $0B89 to $8000-$80FF and
; then calls GO64 ($FF4D).  The C64 reset code ($FCE4: SEI / TXS / CLD) calls the signature check at
; $FD02, finds CBM80 here, and takes the JMP ($8000) at $FCEC - which skips IOINIT, RAMTAS, RESTOR and
; CINT entirely.  cartColdStart has to redo all four by hand. On the plain C64 path (LOAD"EA",8,1)
; none of this exists and $8000 is just free RAM.
cartHeader:
        .addr   cartColdStart           ; 8000  cold-start vector -> cartColdStart ($8009); taken by the KERNAL reset at $FCEC
        .addr   cartColdStart           ; 8002  warm-start vector, also $8009: the KERNAL NMI handler ($FE47) jumps here when RESTORE is pressed, so RESTORE restarts the whole boot

; cbm80Signature ($8004-$8008) - the five magic bytes $C3 $C2 $CD $38 $30 = 'C'|$80, 'B'|$80, 'M'|$80,
; '8', '0'.  The KERNAL's cartridge test at $FD02 compares these against its own copy at
; $FD10; a match is what makes both the reset and the NMI vector through $8000/$8002.  Not a
; string in the game's own format (no bit-7 terminator) - the high bits are part of the magic.
cbm80Signature:
        .byte   $C3,$C2,$CD,$38,$30     ; 8004  ...80  'CBM80' with bit 7 set on the first three characters - the autostart magic tested by $FD02

; ----------------------------------------------------------------------
; cartColdStart - Cold/warm start of the CBM80 pseudo-cartridge that the C128 boot sector plants at
; $8000 before GO64.  Because the KERNAL reset jumps through the $8000 vector before it runs
; IOINIT/RAMTAS/RESTOR/CINT, this routine performs all of them itself (I/O init, clear $0002-$0101 and
; $0200-$03FF, MEMTOP=$A000, MEMSTR=$0800, HIBASE=$0400, RESTOR, CINT), blanks the screen in blue,
; initialises the drive with a DOS 'I' command, then SETNAMs "0:EA" and falls through cartLoadEaFile
; into the normal boot chain.  It never returns.
; In:  Nothing in registers (entered from the KERNAL reset at $FCEC via JMP ($8000), or from the NMI
;     handler at $FE4D via JMP ($8002) if RESTORE is pressed).  Requires the C128 boot sector's helper
;     routines at $0B45 (open command channel) and $0B55 (send DOS command) to still be in RAM - they
;     are, because the reset skipped RAMTAS and the clear loop below stops at $03FF.
; Out: $0002-$0101 and $0200-$03FF zeroed; MEMSIZ $0283/$0284 = $A000; MEMSTR high $0282 = $08; HIBASE
;     $0288 = $04; KERNAL indirect vectors restored; screen editor initialised; VIC_BORDER = VIC_BG0 =
;     6 (blue); VIC_CTRL1 bit 4 (DEN) cleared so the display is blank; drive initialised and logical
;     file 15 closed; stack pointer = $F0; A = 0 for the LOAD.  Does not return - control ends up at
;     $02B8 (eaLoadGame).
; Called from: nobody in this disassembly - only the C64 KERNAL reset/NMI, through the vectors at
;     $8000/$8002.  (The XREF entries for L_8059/L_805C/L_8065/L_806A come from game/mapGenerator6F00
;     and game/comcenScreens6F00, which are different code loaded over these addresses at run time.)
; Note: unlike the real RAMTAS this does not set the tape buffer pointer $B2/$B3 = $033C (harmless -
; the game never touches tape), and it never executes CLI, so the I flag set by the reset's SEI at
; $FCE4 is only cleared later, inside the KERNAL's own serial routines.
; ----------------------------------------------------------------------
cartColdStart:
        jsr     KERNAL_IOINIT           ; 8009  IOINIT ($FF84): set up CIA1/CIA2 (keyboard, serial bus, jiffy timer) and the SID/VIC defaults the reset skipped
        lda     #$00                    ; 800C  $00 = the fill value for the low-RAM clear below
        tay                             ; 800E  Y = 0: first of the 256 offsets to clear

; ----------------------------------------------------------------------
; clearLowRamLoop - Not a callable routine, just the body of the clear loop inside cartColdStart.  One
; pass of Y = 0..255 writes $00 through three absolute,Y stores, clearing $0002-$0101, $0200-$02FF and
; $0300-$03FF.  It is a byte-for-byte copy of the clear loop at the head of the KERNAL's RAMTAS
; ($FD54), which the reset did not run.
; In:  A = 0 (fill value), Y = 0 (index)
; Out: $0002-$0101, $0200-$03FF all zero; Y = 0 again on exit; A still 0
; Called from: fall-through from $800E, and its own BNE at $8019.
; The clear deliberately stops at $03FF: $0400 upwards holds the C128 boot sector's code and its
; still-needed helpers at $0B45/$0B55, and $0000/$0001 (the 6510 CPU port) are skipped because the
; first store is at $0002.
; ----------------------------------------------------------------------
clearLowRamLoop:
        sta     a:$0002,y               ; 800F  clear $0002+Y - absolute,Y, so the last two passes spill into $0100/$0101; $00/$01 (CPU port) are never touched
        sta     D_0200,y                ; 8012  clear $0200+Y - BASIC input buffer and the KERNAL workspace ($0282 MEMSTR, $0288 HIBASE included; both are rewritten below)
        sta     D_0300,y                ; 8015  clear $0300+Y - the vector page; RESTOR at $802D refills $0314-$0333 afterwards
        iny                             ; 8018  advance to the next of the 256 offsets
        bne     clearLowRamLoop         ; 8019  loop until Y wraps back to 0, i.e. all 256 offsets of all three pages are cleared

; ----------------------------------------------------------------------
; Rebuild the power-on memory layout that RAMTAS would normally have measured and stored.  The values
; are simply hardcoded rather than RAM-tested: top of memory $A000, bottom of user memory
; $0800, screen page $0400.  RESTOR and CINT then repair the vectors and the editor that the clear
; loop above just wiped.
; ----------------------------------------------------------------------
        ldx     #$00                    ; 801B  top-of-memory low byte = $00
        ldy     #$A0                    ; 801D  top-of-memory high byte = $A0, i.e. MEMTOP = $A000 (the standard C64 value; $A000-$BFFF later holds the title bitmap)
        clc                             ; 801F  C = 0 selects the 'set' direction of MEMTOP (C = 1 would read it back)
        jsr     KERNAL_MEMTOP           ; 8020  MEMTOP ($FF99): store $A000 into MEMSIZ $0283/$0284
        lda     #$08                    ; 8023  page $08 = the standard start of user RAM
        sta     D_0282                  ; 8025  MEMSTR high byte $0282 = $08 -> bottom of memory $0800 (its low byte $0281 is already 0 from the clear loop)
        lda     #$04                    ; 8028  page $04 = the default text screen
        sta     D_0288                  ; 802A  HIBASE $0288 = $04 so CINT below points the screen editor at $0400
        jsr     KERNAL_RESTOR           ; 802D  RESTOR ($FF8A): reload the KERNAL indirect vectors $0314-$0333, which the clear loop had zeroed
        jsr     KERNAL_CINT             ; 8030  CINT ($FF81): program the VIC from the KERNAL's default table, clear screen RAM at $0400 and reset the editor

; ----------------------------------------------------------------------
; Hide the load.  CINT has just switched on a normal blue-on-blue text screen, so paint border and
; background the same colour and then turn the display off completely; the player sees a plain blue
; screen until the boot loader at $C145 sets VIC_CTRL1 = $3B and shows the title bitmap.
; ----------------------------------------------------------------------
        lda     #$06                    ; 8033  colour 6 = blue
        sta     VIC_BORDER              ; 8035  VIC_BORDER ($D020) = blue
        sta     VIC_BG0                 ; 8038  VIC_BG0 ($D021) = blue as well, so no text can show through
        lda     VIC_CTRL1               ; 803B  read VIC_CTRL1 ($D011) - the raster/mode register CINT just initialised to $1B
        and     #$EF                    ; 803E  clear bit 4 (DEN, display enable); the other bits (RSEL, YSCROLL, raster MSB) are left alone
        sta     VIC_CTRL1               ; 8040  write it back: screen blanked ($D011 = $0B) for the whole loading sequence

; ----------------------------------------------------------------------
; Reset the drive.  Both calls go to routines that belong to the C128 boot sector and are still
; sitting in RAM at $0B45/$0B55 - the KERNAL reset skipped RAMTAS and this stub only cleared up to
; $03FF, so they survived GO64.  The SETLFS inside $0B45 (lfn 15, device 8, secondary 15) also sets
; up the logical-file variables that the LOAD at $8065 later inherits. Note that these are NOT the
; game's own $0B45/$0B55 - the main program's code at $0B00 only exists after the fast loader has run,
; long after this stub is dead.
; ----------------------------------------------------------------------
        jsr     sub_0B45                ; 8043  c128OpenCommandChannel ($0B45): SETNAM length 0 / SETLFS 15,8,15 / OPEN -> drive command channel open
        lda     #$02                    ; 8046  drive-command index 2 = the string "I" at $0B87 (DOS INITIALIZE); index 0/1 are the 1571 commands the C128-mode code already sent
        jsr     sub_0B55                ; 8048  c128SendDriveCommand ($0B55): CHKOUT 15, send "I" byte by byte, CLRCHN - the drive re-reads the BAM and clears any pending error
        lda     #$0F                    ; 804B  logical file 15 = the command channel just used
        jsr     KERNAL_CLOSE            ; 804D  CLOSE ($FFC3): shut the command channel; the KERNAL leaves the current-file variables $B8/$B9/$BA at 15 / 15 / 8, which is exactly what the LOAD below needs

; ----------------------------------------------------------------------
; Name the stage-1 file and hand over.  The filename is stored inline four bytes further on, so the
; pointer passed to SETNAM points back into this routine.  No SETLFS is issued: the device (8) and the
; non-zero secondary address (15) left over from the command channel are what make LOAD honour the
; load address in the file's own header.
; ----------------------------------------------------------------------
        lda     #$04                    ; 8050  filename length = 4 characters
        ldx     #$61                    ; 8052  filename pointer low byte $61
        ldy     #$80                    ; 8054  filename pointer high byte $80 -> eaFileNameCart at $8061, embedded in this very routine
        jsr     KERNAL_SETNAM           ; 8056  SETNAM ($FFBD): filename = "0:EA"
        ldx     #$F0                    ; 8059  stack pointer value $F0 (the reset had set $FF)
        txs                             ; 805B  SP = $F0, i.e. stack top $01F0; safe because nothing on the stack is ever needed again - this code never returns.  Probably just copied from EA's generic cartridge template
        lda     #$00                    ; 805C  A = 0 tells LOAD to load (A = 1 would mean verify)
        jmp     cartLoadEaFile          ; 805E  jump over the four inline filename bytes at $8061 into cartLoadEaFile


; eaFileNameCart ($8061-$8064) - 4 bytes of plain PETSCII, "0:EA": drive 0, file "EA" (the 1-block
; directory file that loads to $02A8-$030B).  Length-counted by SETNAM, so there is no terminator and
; no bit-7 flag.  It sits in the middle of the code and is stepped over by the JMP at $805E.
eaFileNameCart:
        .byte   "0:EA"                  ; 8061  "0:EA" - drive number, colon, filename; passed to SETNAM as X=$61 / Y=$80 / A=4

; ----------------------------------------------------------------------
; cartLoadEaFile - Tail of cartColdStart, reached by the JMP at $805E that steps over the inline
; filename.  KERNAL-LOADs "0:EA" and jumps straight into it.  Because the secondary address inherited
; from the command channel is 15 (non-zero), LOAD uses the two-byte load address in the file itself,
; so "ea" lands at $02A8-$030B; the JMP then enters eaLoadGame at $02B8 by hand.  On the ordinary C64
; path that entry happens indirectly, through the BASIC vectors that "ea" overwrites at $0300-$030B -
; here BASIC never runs at all, which is why the jump is explicit.  The carry/error result of LOAD is
; discarded: a load failure runs whatever happens to be at $02B8.
; In:  A = 0 (load, not verify); filename set by the SETNAM at $8056; device 8 / secondary 15 left in
;     $B8/$B9/$BA by $0B45 and the CLOSE at $804D
; Out: $02A8-$030B filled from disk; control passes to $02B8 (eaLoadGame), which SETLFS 8,8,1, loads
;     the 45-block file "LOAD" to $9800-$C3FF, JSRs the boot loader at $C000 and finally JMPs to the
;     game at $0800.  Never returns.
; Called from: only the JMP at $805E.
; ----------------------------------------------------------------------
cartLoadEaFile:
        jsr     KERNAL_LOAD             ; 8065  LOAD ($FFD5): pull "0:EA" from device 8; secondary 15 means 'use the file's own load address' -> $02A8-$030B
        jmp     L_02B8                  ; 8068  enter eaLoadGame at $02B8 directly, skipping the BASIC-vector hijack that the C64 path relies on; C (LOAD error) is ignored


; cartTailFiller ($806B-$8076) - 12 dead bytes, never referenced by anything.  A $00 followed by 8E 72
; 17 / 8E 73 17 / 8E 70 17 / 8E 71, which disassembles as STX $1772 / STX $1773 / STX $1770 / STX
; $1771 with the last operand byte cut off.  These are simply the last bytes ($F4-$FF) of track 1
; sector 0 that the C128 boot sector's 256-byte copy loop dragged along with the real cartridge image;
; they look like leftovers in the mastering system's buffer, the same way track 1 sector 16 still
; holds fragments of assembler source text.  Execution can never reach them (the routine above ends in
; a JMP), and at run time the whole $8000-$87FF block is overwritten by the $6F00 overlay's upper half
; anyway.
cartTailFiller:
        .byte   $00,$8E,$72,$17,$8E,$73,$17,$8E; 806B  ..r..s..  leftover mastering-buffer bytes: $00, then STX $1772 / STX $1773 / STX $1770 ...
        .byte   $70,$17,$8E,$71         ; 8073  p..q  ... and the truncated STX $1771 that ends the sector; dead filler, never referenced
