7800 NTSC BIOS

From 8BitDev.org - Atari 7800 Development Wiki
Revision as of 20:27, 20 July 2025 by MSaarna (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

7800 NTSC BIOS

This reverse engineered 7800 NTSC BIOS code contains helpful context-comments and builds a 1:1 with the official BIOS ROM. In DASM syntax.


; Disassembly of the Atari 7800 NTSC BIOS (bios7800.bin)
; Originally disassembled by DiStella v2.0 on Sun Mar 08 20:30:38 1998
;
; This version has been heavily commented and refactored for maximum clarity,
; with generic labels (e.g., LF400) renamed to descriptive ones.
; The goal is to explain the inner workings of the BIOS for educational
; and development purposes.
;
; Original comments by:
;   - Keith Henrickson <flipper@phin.com>
;   - Daniel Boris <dboris@home.com>
;   - Mike Saarna (dasm fixups, additional comments)
;   - Gemini 2.5 Pro (semantic meaningful label names, comments galore)
;
; The code must be assembled with DASM.
;

 processor 6502

;=============================================================================
;
; I. HARDWARE AND MEMORY EQUATES
;
;=============================================================================

; --- Misc System Equates ---
LFD80 = $FD80
CartKey           = $FF80   ; Start address of the 8-byte cartridge security key
CartRegion        = $FFF8   ; Cartridge region/signature byte
CartKeyStartPage  = $FFF9   ; Cartridge ROM start page and signature byte
CartResetVectorHi = $FFFD   ; High byte of the cartridge's RESET vector address
LF112             = $F112
LF118             = $F118
LF460             = $F460
LF700             = $F700
LF800             = $F800

; --- 7800 System Control ---
INPTCTRL = $01              ; Input Control Register. Controls memory mapping (BIOS, RAM, Cart) and TIA access.

; --- TIA (Television Interface Adapter) Registers (for 2600 Mode) ---
VSYNC   =  $00              ; Vertical Sync
VBLANK  =  $01              ; Vertical Blank
WSYNC   =  $02              ; Wait for Horizontal Sync
RSYNC   =  $03              ; Reset Horizontal Sync Counter
COLUP0  =  $06              ; Color-Luminance for Player 0
COLUPF  =  $08              ; Color-Luminance for Playfield
COLUBK  =  $09              ; Color-Luminance for Background
PF2     =  $0F              ; Playfield Register 2
RESP1   =  $11              ; Reset Player 1
GRP0    =  $1B              ; Player 0 Graphics
GRP1    =  $1C              ; Player 1 Graphics

; --- Maria (Custom Graphics Chip) Registers ---
BACKGRND =  $20             ; Background Color
POC1     =  $21             ; Palette 0, Color 1
P0C2     =  $22             ; Palette 0, Color 2
POC3     =  $23             ; Palette 0, Color 3
MWSYNC   =  $24             ; Maria Wait for Sync
P1C1     =  $25             ; Palette 1, Color 1
P1C2     =  $26             ; Palette 1, Color 2
P1C3     =  $27             ; Palette 1, Color 3
MSTAT    =  $28             ; Maria Status Register (VBLANK, etc.)
DPPH     =  $2C             ; Display List Pointer High Byte
DPPL     =  $30             ; Display List Pointer Low Byte
CTRL     =  $3C             ; Maria Control Register (DMA, graphics mode)

; --- Zero Page RAM Vectors/Variables ---
DLIAddr       =  $F4        ; RAM vector for Display List Interrupts (NMI)
ConsoleRegion =  $FE        ; Console region byte (used in cart verification)

;=============================================================================
;
; II. CARTRIDGE AUTHENTICATION & MODE SWITCHING LOGIC
;
; This entire block of code from $F000 to $F880 is not executed from ROM.
; Instead, it is copied to RAM ($2300-$2700) by the main BIOS init routine
; at Bios_InitSystem. The jump to $2306 then begins execution from RAM.
;
;=============================================================================

       ORG $F000

; --- NMI Vector (ROM) ---
; This is the hardware NMI vector. It immediately jumps to a RAM vector at $F4,
; which allows the running program (including the BIOS itself) to define its
; own NMI handler.
NmiVector_Rom:
       pha                ; This is the NMI routine.
       jmp (DLIAddr)      ; Jump to RAM NMI vector.


       ORG $F400

; --- RAM Routine: Cartridge Detection and Authentication ---
; This code is designed to be executed from RAM starting at address $2300.
; Its primary job is to determine if a valid, signed 7800 cartridge is
; present. If it is, the system boots in 7800 mode. If not, it attempts
; to boot in 2600 mode.

RamExec_Start:
SwitchTo2600Mode1:
       jmp    Enter2600Mode           ; Branch to the 2600 mode initialization routine.
SwitchTo2600Mode2:
       jmp    Enter2600Mode           ; Branch to the 2600 mode initialization routine.

CartTest:
       lda    #$16                    ; Value to enable Maria and map in the cartridge ROM.
       sta    INPTCTRL                ; Switch in cart + enable Maria.

       ldy    #$FF                    ; Initialize Y to $FF.
       ldx    #$7F                    ; Initialize X to $7F.
; --- Cartridge Presence Test ---
; This loop compares two different ROM regions ($FD80-$FDFF and $FE00-$FE7F).
; If a cartridge is not present, the data bus "floats", and reading any address
; might return the last value seen on the bus (or garbage). By comparing two
; regions that should contain different data, the BIOS can detect this state.
; If the data is the same, it's likely a floating bus, so no cart is present.
CartPresenceCheck_Loop:
       lda    LFE00,X                 ; Read from the $FExx range.
       cmp    LFD80,Y                 ; Compare with the $FDxx range.
       bne    SwitchTo2600Mode1       ; If they differ, the test passes (so far). Branch if they are the same (fail).
       dey                            ;
       dex                            ;
       bpl    CartPresenceCheck_Loop  ; Loop for 128 bytes.

; --- Cartridge Reset Vector Test ---
; A valid 7800 or 2600 cart must have a valid reset vector. A vector of $FFFF
; or $0000 typically indicates an empty socket or a problem.
       lda    CartResetVectorLo       ;
       and    CartResetVectorHi       ;
       cmp    #$FF                    ;
       beq    SwitchTo2600Mode1       ; If RESET vector is $FFFF, then go 2600.
       lda    CartResetVectorLo       ;
       ora    CartResetVectorHi       ;
       beq    SwitchTo2600Mode1       ; If RESET vector is $0000, then go 2600.

; --- Cartridge Signature/Region Verification ---
; This is a series of simple, quick checks on bytes in the $FFF8-$FFF9 region
; of the cartridge ROM to see if it looks like an official 7800 cart.
       lda    CartRegion              ; Read signature byte at $FFF8.
       ora    #ConsoleRegion          ; OR with the console's region byte ($FE).
       cmp    #$FF                    ;
       bne    SwitchTo2600Mode2       ; If low-bit of CartRegion=0, then go 2600.
       lda    CartRegion              ;
       eor    #$F0                    ; Invert high nibble.
       and    #$F0                    ; Isolate the high nibble.
       bne    SwitchTo2600Mode2       ; If high nibble was not originally $F, then go 2600.
       lda    CartKeyStartPage        ; Read signature byte at $FFF9.
       and    #$0B                    ;
       cmp    #$03                    ;
       bne    SwitchTo2600Mode2       ; If low nibble of $FFF9 was not 3 or 7, go 2600.

; --- Cartridge Header Processing ---
; If the quick checks pass, the BIOS proceeds with the full authentication.
       lda    CartKeyStartPage        ;
       and    #$F0                    ; Extract ROM start page from high nibble of $FFF9.
       sta    $EE                     ; Store it in zero page.
       sta    $2406                   ; Store it in RAM for the authentication routine.
       cmp    #$40                    ;
       bcc    SwitchTo2600Mode2       ; If ROM start page < $40 (i.e., address < $4000), fail.
       sbc    #$01                    ;
       cmp    CartResetVectorHi       ; Compare ROM start page with high byte of reset vector.
       bcs    SwitchTo2600Mode2       ; If start page is >= reset vector high byte, fail.
       jsr    $2536                   ; If all checks pass, start the full authentication process.

; --- Obfuscated Authentication Code ---
; The following code is part of the digital signature verification. It involves
; complex mixing, rotating, and lookup operations on the cartridge's security
; key and internal BIOS data tables. Its purpose is to be difficult to analyze
; and replicate. The high-level goal is to compute a hash from the cart key
; and compare it against an expected result.

       lda    #$00
       sta    $F0
       jsr    $241B
       lda    #$16
       sta    INPTCTRL
       ldx    #$00
       txa
Auth_RamFillLoop1:
       sta    $1800,X
       dex
       bne    Auth_RamFillLoop1
       pha
       ldy    #$7F
Auth_CopyRomToRamLoop:
       lda    LFF00,Y
       sta    $1800,Y
       dey
       cpy    #$F8
       bne    Auth_CopyRomToRamLoop
       lda    #$2E
       sta    $2409
       lda    #$24
       sta    $240A

Auth_MainLoop1:
       jsr    $241B
       pla
       jsr    $23FF
       pha
       inc    $2406
       lda    $2406
       cmp    #$FF
       bne    Auth_MainLoop1

       jsr    $241B
       jsr    $2412
       jsr    $2412
       lda    #$36
       sta    $2409
       lda    #$24
       sta    $240A
       dec    $2406
Auth_MainLoop2:
       jsr    $241B
       pla
       jsr    $23FF
       pha
       dec    $2406
       lda    $2406
       cmp    $EE
       bcs    Auth_MainLoop2
       lda    #$60
       sta    CTRL
       ldx    #$77
Auth_XorAndStoreLoop:
       lda    $1800,X
       eor    $1850,X
       eor    $1888,X
       sta    $1A00,X
       dex
       bpl    Auth_XorAndStoreLoop
       lda    $1A00
       and    #$07
       sta    $1A00
       lda    #$00
       ldx    #$04
       sta    $1A00,X
       sta    $2000,X

; --- Final Authentication Check ---
; After all the cryptographic hashing, this is the final comparison.
; It compares two blocks of memory in RAM. If they match, the cart is authentic.
       ldx    #$77
Auth_FinalCompareLoop:
       lda    $2000,X                 ; Read from one workspace area.
       cmp    $1A00,X                 ; Compare with the computed hash.
       bne    Auth_FailAndSwitchTo2600; If they don't match, authentication fails.
       dex
       bpl    Auth_FinalCompareLoop   ; Loop until all bytes are compared.
       jmp    Enter7800Mode           ; AUTHENTICATION PASSED: Jump to 7800 mode init.
Auth_FailAndSwitchTo2600:
       jmp    Enter2600Mode           ; AUTHENTICATION FAILED: Jump to 2600 mode init.


; --- Authentication Subroutines ---
; More opaque subroutines used by the main authentication algorithm.
Auth_Sub_MixAndLookup_Equate =  $F500
       ldx    #$00
Auth_Sub_MixAndLookup_Loop:
       adc    $1800,X
       adc    LFF00,X
       tay
       lda    $2DD5,Y
       sta    $1800,X
       inx
       bne    Auth_Sub_MixAndLookup_Loop
       rts

       ldx    #$00
Auth_Sub_RotateRam_Loop:
       rol    $1800,X
       inx
       bne    Auth_Sub_RotateRam_Loop
       rts

; Subroutine at $241B - This routine briefly disables the cartridge to access BIOS ROM/RAM.
       php
       dec    $F0
       bpl    Auth_Sub_AccessBios_Done
       lda    #$02
       sta    INPTCTRL
Auth_Sub_AccessBios_WaitLoop:
       lda    $F0
       bmi    Auth_Sub_AccessBios_WaitLoop
       lda    #$16
       sta    INPTCTRL
Auth_Sub_AccessBios_Done:
       plp
       rts

; --- Authentication Signature Data Tables ---
; These large blocks of byte data are part of the digital signature scheme.
; They are used as lookup tables and keys during the verification process.
AuthData_Table1: .byte $C7,$65,$AB,$CA,$EE,$F7,$83,$09
AuthData_Table2: .byte $E1,$D0,$92,$67,$62,$B6,$72,$55,$8E,$91,$DC,$C5,$81,$BE,$78,$20
       .byte $59,$B7,$E6,$3D,$06,$45,$AF,$C8,$08,$31,$38,$D1,$FB,$73,$84,$A9
       .byte $17,$FC,$34,$87,$A3,$94,$FA,$90,$B8,$ED,$CE,$3B,$5B,$0A,$43,$D9
       .byte $F3,$53,$82,$B3,$0D,$6D,$5A,$60,$9D,$51,$A7,$B9
AuthData_Table3: .byte $11,$10,$BC,$E4,$7F,$80,$41,$E7,$E3
AuthData_Table4: .byte $F6,$56,$26,$35,$EC,$D6,$DF,$0C,$7F,$F4,$9E,$AC,$52,$46,$EF,$CF
       .byte $BF,$A2,$3F,$A4,$13,$15,$97,$4A,$1C,$B0,$42,$8C,$B1,$05,$58,$80
       .byte $18,$77,$2B,$02,$3E,$A8,$49,$1A,$6A
AuthData_Table5: .byte $CB,$6E,$0B,$8A,$EB,$F1,$4F,$14,$79,$8B,$D8,$9F,$9B,$57,$19,$F8
       .byte $2A,$2D,$76,$0E,$E8,$2E,$4B,$F9,$07,$03,$DE,$93,$16,$7E,$D4,$E5
       .byte $B2,$F0,$7D,$7A,$DA,$D2,$A1,$CC,$1D,$E0,$5E,$23,$A0,$95,$22,$1E
       .byte $36,$85,$FE,$1F,$39
AuthData_Table6: .byte $AA,$89,$96,$AD,$0F,$2F,$C0,$47
AuthData_Table7: .byte $27,$5D,$24,$EA,$C3,$A5,$F5,$21,$5F,$1B,$40,$8F,$AE,$74,$25,$DD
       .byte $C1,$7C,$CD,$A6,$70,$D7,$33,$7B,$2C,$75,$BB,$86,$99,$BD,$54
AuthData_Table8: .byte $9A,$6C,$63,$32,$48,$4C,$8D,$BA
AuthData_Table9: .byte $5C,$61,$C4,$4E,$29,$37,$12,$C6,$98,$9C,$D5,$69,$6B,$E2,$04,$4D
       .byte $E9,$C2,$88,$3A,$DB,$64,$01,$44,$6F,$B5,$F2,$30,$28,$FD,$50,$71
       .byte $3C,$B4,$66,$68,$C9,$D3,$CA,$83,$C7,$AB,$F7,$65,$09,$EE

; --- Main Authentication Routine ($2536) ---
; This routine is the entry point for the signature verification process.
; It copies the 128-byte security key from the cartridge ROM into RAM.
       ldx    #$77      ; ($2536) Start of routine, X=119
       stx    $E4
       stx    $E5
Auth_CopyCartKey_Loop:
       lda    CartKey,X   ; Read a byte from the cart security key area ($FF80-FFFF).
       sta    $1901,X           ; Store it in RAM work area 1.
       sta    $2000,X           ; Store it in RAM work area 2.
       dex                      ; next byte of key
       bpl    Auth_CopyCartKey_Loop ; Loop until all 128 bytes are copied.

       lda    #$02      ;
       sta    INPTCTRL  ; Disable cart ROM to access BIOS routines.
       jsr    Display_InitLogo ; Initialize Maria for the Fuji logo display.
       jsr    $257B
       dec    $F2
       ldx    #$77
       stx    $E4
Auth_CopyInternalKey_Loop:
       lda    LFED5,X
       sta    $1901,X
       dex
       bpl    Auth_CopyInternalKey_Loop
       lda    $E1
       sta    $E3
       jsr    $25E1
       dec    $F2
Auth_CopyWorkspace_Start:
       lda    $E0
       sta    $2572
       ldx    #$77
Auth_CopyWorkspace_Loop:
       lda    $1800,X
Auth_CopyWorkspace_Store:
       sta    $2000,X
       dex
       bpl    Auth_CopyWorkspace_Loop
       rts

; --- More Authentication Subroutines ---
       jsr    $2639   ; ($257B)
       ldy    $E5
       iny
Auth_Sub_KeyProcess_OuterLoop:
       STY    $E1
       TYA
       clc
       adc    $E2
       pha
Auth_Sub_KeyProcess_ClearRam:
       tax
       lda    #$00
       sta    $2671
Auth_Sub_KeyProcess_ClearRam_Loop:
       sta    $1800,X
       dex
Auth_Sub_KeyProcess_ClearRam_Check:
       bne    Auth_Sub_KeyProcess_ClearRam_Loop
       sta    $1800
Auth_Sub_KeyProcess_SetupCounters:
       iny
       STY    $266E
       STY    $2674
       STY    $267C
       STY    $2681
       ldx    #$00
Auth_Sub_KeyProcess_InnerLoop:
       dec    $266E
       dec    $2674
       dec    $267C
       dec    $2681
       dec    $E1
       bmi    Auth_Sub_KeyProcess_Done
Auth_Sub_KeyProcess_BitCheck:
       ldy    $E1
       lda    $2000,Y
       and    $25D9,X
       beq    Auth_Sub_KeyProcess_NextBit
       lda    $2662,X
       sta    $2672
       jsr    $266A
Auth_Sub_KeyProcess_NextBit:
       inx
       cpx    #$08
       bmi    Auth_Sub_KeyProcess_BitCheck
       jmp    $25A4
Auth_Sub_KeyProcess_Done:
       pla
       sta    $E1
       lda    #$01
       sta    $E0
       rts

AuthData_Bitmasks: .byte $01,$02,$04,$08,$10,$20,$40,$80

       jsr    $2639
       lda    $E3
       sec
       sbc    $E4
       sta    $E0
       sta    $E1
       ldx    #$00
       stx    $1800
       stx    $268F
       stx    $26AC
       dex
       stx    $26A9
       stx    $268C
       stx    $2692
       stx    $269A
       stx    $269F
       ldx    #$07
       inc    $26A9
       inc    $268C
       inc    $2692
       inc    $269A
       inc    $269F
       dec    $E1
       bmi    Auth_Sub_Op_Done
Auth_Sub_Op_Loop:
       lda    $2662,X
       sta    $2690
       sta    $26AD
       jsr    $26A6
       bcc    Auth_Sub_Op_Next
       jsr    $2688
Auth_Sub_Op_Next:
       dex
       bpl    Auth_Sub_Op_Loop
       jmp    $2608
Auth_Sub_Op_Done:
       lda    $E3
       sta    $E1
       rts

       ldx    $E4   ; ($2639)
       inx
       stx    $E2
       ldy    #$00
       STY    $1900
Auth_Sub_Rotate_OuterLoop:
       lda    $2662,Y
       sta    $2655
       iny
       lda    $2662,Y
       sta    $2659
       ldx    $E2
       clc
Auth_Sub_Rotate_InnerLoop:
       lda    $1900,X
       rol
       sta    $1900,X
       dex
       bpl    Auth_Sub_Rotate_InnerLoop
       cpy    #$07
       bmi    Auth_Sub_Rotate_OuterLoop
       rts

AuthData_Indices: .byte $19,$1A,$1B,$1C,$1D,$1E,$1F,$21

       ldy    $E2
       clc
Auth_Sub_Add_Loop:
       lda    $1800,Y
       adc    $1900,Y
       sta    $1800,Y
       dey
       bpl    Auth_Sub_Add_Loop
       bcc    Auth_Sub_Add_NoCarry
       lda    $1700,Y
       adc    #$00
       sta    $1700,Y
       dey
       jmp    $2679
Auth_Sub_Add_NoCarry:
       rts

       ldy    $E2
       sec
Auth_Sub_Subtract_Loop:
       lda    $1800,Y
       sbc    $1900,Y
       sta    $1800,Y
       dey
       bpl    Auth_Sub_Subtract_Loop
       bcs    Auth_Sub_Subtract_NoBorrow
       lda    $1700,Y
       sbc    #$00
       sta    $1700,Y
       dey
       jmp    $2697
Auth_Sub_Subtract_NoBorrow:
       rts

       ldy    #$00
       lda    $1800,Y
       cmp    $1900,Y
       beq    Auth_Sub_Compare_Equal
Auth_Sub_Compare_NotEqual:
       rts

Auth_Sub_Compare_Equal:
       cpy    $E2
       beq    Auth_Sub_Compare_NotEqual
       iny
       jmp    $26A8

; --- 7800 Mode Initialization ---
       ORG $F7B9
; This label is an equate, not a location. It calculates the correct RAM address
; for the routine, which is needed by the code executing from RAM.
; ROM address $F7B9 -> RAM address $26B9. Offset is $D100.
Enter7800Mode = . - $D100
Routine_Enter7800Mode:
       ldx    #$16        ; Enable Maria and Cartridge ROM.
       stx    INPTCTRL    ; Lock out BIOS, enable cartridge.
       txs                ; Set up stack pointer.
       SED                ; Set Decimal Mode (a 7800 convention, often cleared by games).
       jmp (CartResetVectorLo) ; Jump to the game's starting address on the cartridge.

; --- 2600 Mode Initialization ---
       ORG $F7C2
; This label is also an equate to calculate the correct RAM address.
; ROM address $F7C2 -> RAM address $26C2. Offset is $D100.
Enter2600Mode = . - $D100
Routine_Enter2600Mode:
       lda    #$02        ; Enable 7800 RAM and BIOS ROM.
       sta    INPTCTRL    ;
       ldx    #$7F
; Copy the 2600 TIA setup code from BIOS ROM into RIOT RAM ($0480).
CopyTiaInitToRam_Loop:
       lda    TiaInitCode,X
       sta    $0480,X
       dex
       bpl    CopyTiaInitToRam_Loop
       jmp    $0480       ; Jump to the newly copied code in RIOT RAM to execute it.

; --- 2600 TIA Setup Code (Executed from RIOT RAM at $0480) ---
TiaInitCode:
       lda    #$00        ;
       tax                ;
       sta    INPTCTRL    ; Disable 7800 RAM/BIOS, giving full control to cart.
; Clear all TIA registers to put it in a known state.
TiaInit_ClearLoop:
       sta    RSYNC,X
       inx                ;
       cpx    #$2A        ;
       bne    TiaInit_ClearLoop
       sta    WSYNC       ; Wait for horizontal sync.
       lda    #$04        ;
       nop                ;
       bmi    TiaInit_SetColors1
       ldx    #$04
TiaInit_DelayLoop:
       dex
       bpl    TiaInit_DelayLoop
       txs
       sta    $0110
       jsr    $04CB
       jsr    $04CB
       sta    RESP1
       sta    GRP0
       sta    GRP1
       sta    PF2
       nop
       sta    WSYNC
       lda    #$00
       nop
       bmi    TiaInit_SetColors1
       bit    RSYNC
       bmi    TiaInit_SetColors2
TiaInit_SetColors1:
       lda    #$02
       sta    COLUBK
       sta    LF112
       bne    TiaInit_Finalize
TiaInit_SetColors2:
       bit    WSYNC
       bmi    TiaInit_SetColors3
       lda    #$02
       sta    COLUP0
       sta    LF118
       sta    LF460
       bne    TiaInit_Finalize
TiaInit_SetColors3:
       sta    DPPH
       lda    #$08
       sta    GRP0
       jsr    $04CB
       nop
       bit    WSYNC
       bmi    TiaInit_SetColors1
TiaInit_Finalize:
       lda    #$FD
       sta    COLUPF
       jmp (CartResetVectorLo) ; Jump to the 2600 game's starting address on the cartridge.
       nop

;=============================================================================
;
; III. BIOS ENTRY, POWER-ON SELF TEST (POST), AND SYSTEM INIT
;
;=============================================================================

       ORG $F880

; --- Self-Test Failure Handler ---
; This code is jumped to whenever a POST routine fails. It writes an error
; code to INPTCTRL, which can be read by external diagnostic hardware.
Post_FailHandler:
       lda    #$1D
       sta    INPTCTRL    ; Enable TIA/Cart/lock out INPTCTRL.

; --- BIOS Entry Point / Cold Start ---
START:                    ; $F884
       SEI                ; Disable interrupts on power-on.
       CLD                ; Clear decimal flag.
       lda    #$02        ;
Bios_SetRamAndBios:
       sta    INPTCTRL    ; Enable 7800 RAM and map BIOS into memory.
       lda    #$FB        ; Set high byte of NMI vector to $FB.
       sta    $F5         ;
       lda    #$12        ; Set low byte of NMI vector to $12.
       sta    $F4         ; NMI vector is now $FB12 (points to IRQ cleanup).
       lda    #$7F        ;
       sta    CTRL        ; Turn off Maria DMA.
       lda    #$00        ;
       sta    BACKGRND    ; Set background color to black.

; --- POST: RAM Test 1 (Basic) ---
; This is a quick test of the two 2KB RAM chips ($2000-$27FF).
; It writes several patterns to each byte and reads them back.
       ldx    #$05        ; Loop counter for the 6 test patterns.
Post_RamTest1_PatternLoop:
       lda    Post_RamTest_Data,X ; Load a test pattern ($00, $FF, $55, $AA, $69, $0F).
       ldy    #$00        ; Inner loop counter for 256 bytes.
Post_RamTest1_PageLoop:
       sta    $2000,Y     ; Write pattern to first RAM chip.
       cmp    $2000,Y     ; Read it back and compare.
       bne    Post_RamTest_Fail1 ; If it fails, branch to error handler.
       sta    $2100,Y     ; Write pattern to second RAM chip.
       cmp    $2100,Y     ; Read it back and compare.
       bne    Post_RamTest_Fail1 ; If it fails, branch to error handler.
       dey                ;
       bne    Post_RamTest1_PageLoop ; Loop through all 256 bytes of a page.
       dex                ;
       bpl    Post_RamTest1_PatternLoop ; Loop to the next test pattern.

; --- POST: RAM Mirror Test ---
; Checks that the RAM is correctly mirrored every 256 bytes.
       lda    #$43        ; Check RAM 0 mirror.
       sta    $2080       ; Write to $2080.
       cmp    $80         ; Compare with $0080 (a mirror).
       bne    Post_RamMirror_Fail ; make sure they match. If not, fail selftest.
       sta    $2180       ; Check RAM 1 mirror
       cmp    $0180       ;
       bne    Post_RamMirror_Fail ; make sure they match. If not, fail selftest.
       jmp    Post_CpuTest_Start ; continue selftest
Post_RamMirror_Fail:
       ldy    #$04        ;
       jmp    Post_FailHandler ; selftest fail.

; --- POST: RAM Failure Handlers ---
; These routines are jumped to from the RAM tests to indicate failure.
Post_RamTest_Fail1:
       sta    $1800       ; test store and compare
       cmp    $1800
       bne    Post_RamTest_Fail3 ; some kind of error code is being determined
Post_RamTest_Fail2:
       ldy    #$01
       jmp    Post_FailHandler

Post_RamTest_Fail_Indirect:
       ldy    #$02
       jmp    $F880

Post_RamTest_Fail3:
       ldy    #$03
       jmp    Post_FailHandler

; --- POST: RAM Test 2 (Comprehensive) ---
; This is a more thorough RAM test called later in the boot process. It uses
; indirect addressing to test all 8 pages of the 4KB RAM.
Post_RamTest2_Start:
       lda    #$00
       sta    $F0         ; Base address low byte pointer.
       sta    $F2         ;
       ldy    #$07        ; Loop counter for 8 pages.
       STY    $F4
Post_RamTest2_OuterLoop:
       lda    Post_RamTest_AddrHi1,Y ; Load high byte of address for RAM chip 1.
       sta    $F1
       lda    Post_RamTest_AddrHi2,Y ; Load high byte of address for RAM chip 2.
       sta    $F3
       ldx    #$05        ; Loop counter for 6 test patterns.
Post_RamTest2_PatternLoop:
       lda    Post_RamTest_Data,X ; Load a test pattern.
Post_RamTest2_InnerLoop:
       ldy    #$00        ; Inner loop counter for 256 bytes.
Post_RamTest2_ByteLoop:
       sta    ($F0),Y     ; Write to RAM 1 via indirect pointer ($F0/$F1).
       cmp    ($F0),Y     ; Read back and compare.
       bne    Post_RamTest_Fail2 ; Fail.
       sta    ($F2),Y     ; Write to RAM 2 via indirect pointer ($F2/$F3).
       cmp    ($F2),Y     ; Read back and compare.
       bne    Post_RamTest_Fail_Indirect ; Fail.
       dey
       bne    Post_RamTest2_ByteLoop ; Loop through page.
       dex
       bpl    Post_RamTest2_PatternLoop ; Loop through patterns.
       dec    $F4
       ldy    $F4
       bpl    Post_RamTest2_OuterLoop ; Loop through pages.
       jmp    Bios_InitSystem ; ram test passed, so jump in here.

; --- RAM Test Data ---
Post_RamTest_Data: .byte $00,$FF,$55,$AA,$69,$0F
Post_RamTest_AddrHi1: .byte $22,$23,$24,$25,$26,$27,$22,$23
Post_RamTest_AddrHi2: .byte $18,$19,$1A,$1B,$1C,$1D,$1E,$1F

Post_CpuTest_Fail:
       ldy    #$00       ; local place for selftest fail branch target
       jmp    Post_FailHandler

; --- POST: 6502 CPU Test ---
; This section exhaustively tests the 6502's instruction set, flags,
; and addressing modes to ensure the CPU is functioning correctly.
Post_CpuTest_Start:
       lda    #$AA       ; test some flags and branches
       beq    Post_CpuTest_Fail ; test failed
       bpl    Post_CpuTest_Fail ; test failed
       bmi    CpuTest_CheckBne ; test passed
       jmp    Post_CpuTest_Fail ; test failed
CpuTest_CheckBne:
       bne    CpuTest_CheckStore ; test passed
       jmp    Post_CpuTest_Fail ; test failed
CpuTest_CheckStore:
       sta    $AA        ; store AA to 00AA
       cmp    $AA        ; compare it back
       bne    Post_CpuTest_Fail ; if it doesn't match, selftest fail
       lda    #$00       ; do some more flag tests
       bne    Post_CpuTest_Fail ;
       bmi    Post_CpuTest_Fail ;
       bpl    CpuTest_CheckBeq ; test passed
       jmp    Post_CpuTest_Fail ;
CpuTest_CheckBeq:
       beq    CpuTest_CheckCmp ; test passed
       jmp    Post_CpuTest_Fail ;
CpuTest_CheckCmp:
       cmp    #$00       ; test the compare instruction
       bne    Post_CpuTest_Fail ;
       bcc    Post_CpuTest_Fail ;
       bcs    CpuTest_CheckCmpBcs ; test passed, since they're equal
       jmp    Post_CpuTest_Fail ;
CpuTest_CheckCmpBcs:
       cmp    #$01       ; compare it to 01
       bcs    Post_CpuTest_Fail ;
       bcc    CpuTest_CheckCpx ; A < 01, so carry is clear
       jmp    Post_CpuTest_Fail ;
CpuTest_CheckCpx:
       ldx    #$55       ; test comparisons with the X register
       cpx    #$56       ;
       beq    Post_CpuTest_Fail ;
       stx    $01AA      ;
       cpx    $01AA      ;
       bne    Post_CpuTest_Fail ;
       ldy    $AA        ; and with the Y register.
       cpy    #$AB       ;
CpuTest_CheckCpy:
       beq    Post_CpuTest_Fail ;
       STY    $0155      ; put some stuff in the stack area to test stack
       cpy    $0155      ; and then access this data in many different ways
       bne    Post_CpuTest_Fail ;
       dex               ;
       txs               ;
       inx               ;
       pla               ;
       cmp    #$AA       ;
       bne    Post_CpuTest_Fail_Central ;
       txa               ;
       pha               ;
       cpx    $0155      ;
       bne    Post_CpuTest_Fail_Central ;
       TYA               ;
       cmp    #$AA       ;
       bne    Post_CpuTest_Fail_Central ;
       tax               ;
       lda    $0100,X    ;
       tay               ;
       cpy    #$55       ;
       bne    Post_CpuTest_Fail_Central ;
       lda    VSYNC,X    ;
       cmp    $AA        ;
       bne    Post_CpuTest_Fail_Central ;
       cmp    #$AA       ;
       bne    Post_CpuTest_Fail_Central ;
       eor    #$FF       ;
       sta    $0000,Y    ;
       cmp    $55        ;
       bne    Post_CpuTest_Fail_Central ;
       cmp    $0100,Y    ;
       bne    Post_CpuTest_Fail_Central ;
       cmp    $20AB,X    ;
       bne    Post_CpuTest_Fail_Central ;
       lda    #$20       ;
       sta    $F1        ;
       lda    #$CC       ;
       sta    $F0        ;
       sta    ($46,X)    ;
       cmp    $CC        ;
       bne    Post_CpuTest_Fail_Central ;
       sta    ($F0),Y    ;
       cmp    $2121      ;
       bne    Post_CpuTest_Fail_Central ;
       lda    #$EE       ; test the indirect jump by setting up a jump
       sta    $F0        ; to Post_CpuMath_Start
       lda    #$F9       ;
       sta    $F1        ;
       jmp ($00F0)        ; and do it.

CpuTest_ShouldNotBeReached:
       jmp    Post_CpuTest_Fail_Central

Post_CpuTest_Fail_Central:
       jmp    Post_CpuTest_Fail


; --- POST: CPU Math and Logic Tests ---
Post_CpuMath_Start:
       lda    #$55       ; now test out the math functions.
       clc
       adc    #$55
       nop
       bcs    Post_CpuTest_Fail_Central ; test addition.
       bpl    Post_CpuTest_Fail_Central
       beq    Post_CpuTest_Fail_Central
       cmp    #$AA       ; make sure it worked
       bne    Post_CpuTest_Fail_Central
       adc    #$55       ; test addition again.
CpuMath_TestAdcCarry:
       nop
       bcc    Post_CpuTest_Fail_Central
       bmi    Post_CpuTest_Fail_Central
       bne    Post_CpuTest_Fail_Central
       sbc    #$55       ; test subtraction
       bcs    Post_CpuTest_Fail_Central
       bpl    Post_CpuTest_Fail_Central
       beq    Post_CpuTest_Fail_Central
       cmp    #$AB       ; make sure it worked
       bne    Post_CpuTest_Fail_Central
       clc
       sbc    #$AA       ; test subtraction again
       bcc    Post_CpuTest_Fail_Central
       bmi    Post_CpuTest_Fail_Central
       bne    Post_CpuTest_Fail_Central
       lda    #$FF       ; set up a stack
       tax               ; and do all kinds of stuff in it for tests
       inx
       bne    CpuMath_Fail
       dex
       beq    CpuMath_Fail
       bpl    CpuMath_Fail
       cpx    #$FF
       bne    CpuMath_Fail
       tay
       iny
       bne    CpuMath_Fail
       dey
       beq    CpuMath_Fail
       iny
       bne    CpuMath_Fail
       sta    $F0
       inc    $F0
       bne    CpuMath_Fail
       cpy    $F0
       bne    CpuMath_Fail
       dec    $F0
       beq    CpuMath_Fail
       cmp    $F0
       bne    CpuMath_Fail
       lda    #$AA
       clc
       rol               ; now we get onto the more complex math instrs
       rol
       rol
       cmp    #$52
       bne    CpuMath_Fail ; make sure rotate left works.
       ror
       ror
       ror
       cmp    #$AA
       beq    CpuMath_TestAsl ; test rotate right
CpuMath_Fail:
       jmp    Post_CpuTest_Fail ; fail!

CpuMath_TestAsl:
       asl               ; test arithmetic shift left
       bcc    CpuMath_Fail
       asl
       bcs    CpuMath_Fail
       asl
       cmp    #$50
       bne    CpuMath_Fail
       eor    #$05
       lsr               ; and logical shift right
       bcc    CpuMath_Fail
       lsr
       bcs    CpuMath_Fail
       lsr
       cmp    #$0A
       bne    CpuMath_Fail
       lda    #$55       ; now test the ands and ors.
       ora    #$1B
       cmp    #$5F
       bne    CpuMath_Fail
       and    #$55
       and    #$1B
       cmp    #$11
       bne    CpuMath_Fail
       ora    #$55
       eor    #$1B       ; and the eors
       cmp    #$4E
       bne    CpuMath_Fail
       jsr    Cpu_TestJsr ; test jump subroutine instruction
       jmp    CpuMath_Fail ; if we return, fail

Cpu_TestJsr:
       tsx
       cpx    #$52       ; check stack pointer
       bne    CpuMath_Fail ; fail if not right
       pla
       cmp    #$8D
       bne    CpuMath_Fail
       pla
       cmp    #$FA
       bne    CpuMath_Fail ; get the old return address off the stack
       lda    #$F8
       pha
       lda    #$E6
       pha               ; and make our own
       rts               ; and 'return' to Post_RamTest2_Start

       jmp    CpuMath_Fail ; another jump to catch a failure

;=============================================================================
;
; IV. NMI HANDLER (FUJI LOGO DISPLAY)
;
;=============================================================================

; This NMI routine is responsible for drawing the "Fuji" mountain logo and
; the "ATARI" text on the screen during the boot-up/authentication process.
; It is called on every VBLANK. Its main job is to manipulate Maria's palette
; registers to create the signature color-cycling effect on the Fuji logo.

Nmi_DrawFujiAndAtari:
       txa          ;Save A
       pha          ;
       lda    #$43  ;Setup control register
       sta    CTRL  ;
       ldx    #$0F  ; Handle the color scrolling in the FUJI
       lda    $EF
       sta    P0C2
       bit    $F3
       bvc    Nmi_Sync3
       bpl    Nmi_Sync2
Nmi_Sync1:
       sta    MWSYNC ;Wait for 3 scanlines
Nmi_Sync2:
       sta    MWSYNC ;
Nmi_Sync3:
       sta    MWSYNC ;
       sec
       sbc    #$10
       cmp    #$10
       bcs    Nmi_StoreColor
       sbc    #$0F
Nmi_StoreColor:
       sta    P0C2
       dex
       bpl    Nmi_Sync1 ;Branch to do next section of fuji
       ldx    #$40    ;set 160x2/160x4 mode
       stx    CTRL    ;
       and    #$F0    ;
       ora    #$0E    ;set Palette 1 color 3
       sta    P1C3    ;
       lda    $EF     ;
       and    #$F0    ;
       ora    #$06    ;set Palette 1 color 1
       sta    P1C1    ;
       and    #$F0
       clc
       adc    #$40
       bcc    Nmi_SetPalette1Color2
       adc    #$0F
Nmi_SetPalette1Color2:
       ora    #$03   ;set Palette 1 color 2
       sta    P1C2
       dec    $F1
       bpl    Nmi_RestoreRegs
       lda    $F3
       adc    #$60
       bcc    Nmi_UpdateFrameCounter
       lda    $EF
       clc
       adc    #$10
       bcc    Nmi_StoreNewBaseColor
       adc    #$0F
Nmi_StoreNewBaseColor:
       sta    $EF
       lda    $F2
       sta    $F1
       lda    #$00
Nmi_UpdateFrameCounter:
       sta    $F3
Nmi_RestoreRegs:
       lda    #$02
       sta    $F0
       pla
       tax
       pla
       rti

Trap_InfiniteLoop:
       jmp    Trap_InfiniteLoop

;=============================================================================
;
; V. SYSTEM INITIALIZATION (POST-TEST)
;
;=============================================================================

; This routine is executed after all Power-On Self Tests have passed.
Bios_InitSystem:
       ldx    #$FF       ; selftest has passed, start system init
       txs               ; set up a stack
       lda    #$00       ; Clear TIA/Maria registers
       tax               ;
Bios_ClearRegsLoop:
       sta    $01,X ;
       inx               ;
       cpx    #$2C       ;
       bne    Bios_ClearRegsLoop
       lda    #$02       ;
       sta    INPTCTRL   ; Enable 7800 RAM
       ldx    #$00       ;
       stx    BACKGRND   ; Set background color

; --- Copy BIOS Routines and Data to RAM ---
; This is a critical step. It copies the cartridge authentication code,
; graphics display routines, and associated data from the BIOS ROM
; into the main system RAM. This allows the BIOS to run its complex
; authentication logic from RAM, freeing up the cartridge bus.
Bios_CopyCodeToRam_Loop:
       lda    RamExec_Start,X ; copy the authentication and title screen to
       sta    $2300,X    ; ram
       lda    Auth_Sub_MixAndLookup_Equate,X ;
       sta    $2400,X    ;
       lda    AuthData_Table8,X ;
       sta    $2500,X    ;
       lda    LF700,X    ;
       sta    $2600,X    ;
       lda    LF800,X    ;
       sta    $2700,X    ;
       lda    DisplayList_Defs,X ;
       sta    $2200,X    ;
       cpx    #$00       ;
       bmi    Bios_CopyCodeToRam_Done ;
       lda    DisplayList_Master,X ;
       sta    $1F84,X     ;
       lda    GraphicsData_FujiAtari_1,X ;
       sta    $1984,X     ;
       lda    LFD3D,X     ;
       sta    $1A84,X     ;
       lda    LFDB4,X     ;
       sta    $1B84,X     ;
       lda    LFE18,X     ;
       sta    $1C84,X     ;
       lda    LFE57,X     ;
       sta    $1D84,X     ;
       lda    LFE96,X     ;
       sta    $1E84,X     ;
Bios_CopyCodeToRam_Done:
       dex                ;
       bne    Bios_CopyCodeToRam_Loop ;
       jmp    $2306       ; and execute it (CartTest)

;Start display of Atari logo
Display_InitLogo:
       lda    CartKeyStartPage      ; Read ROM start byte from cart
       and    #$04       ; Is rom start greater then $4000?
       beq    Display_InitLogo_Done ; Branch if not
       lda    #$03
       sta    $F1
       sta    $F2
       lda    #$49
       sta    $EF
       lda    #$66       ;Palette 1 Color 1
       sta    P1C1       ;
       lda    #$56       ;Palette 1 Color 2
       sta    P1C2       ;
       lda    #$2E       ;Palette 1 Color 3
       sta    P1C3       ;
       lda    #$AA       ;Set NMI vector to Nmi_DrawFujiAndAtari
       sta    $F4        ;
       lda    #$FA       ;
       sta    $F5        ;
Display_WaitForVblankEnd:
       bit    MSTAT      ;Check VBLANK status
       bmi    Display_WaitForVblankEnd ;Wait till end of VBLANK
Display_WaitForVblankStart:
       bit    MSTAT      ;Check BLANK status
       bpl    Display_WaitForVblankStart ;Wait for start of next VBLANK
       lda    #$84       ;Set Display list pointer to $1f84
       sta    DPPL       ;
       lda    #$1F       ;
       sta    DPPH       ;
       lda    #$43       ;Maria mode = DMA on/320A or 320C
       sta    CTRL       ;
Display_InitLogo_Done:
       rts               ;

;=============================================================================
;
; VI. GRAPHICS DATA AND DISPLAY LISTS
;
;=============================================================================

; --- Display List Definitions for Fuji/Atari Logo ---
; Each entry defines a block of scanlines, pointing to the graphics data
; to be displayed. Copied to $2200 in RAM.
DisplayList_Defs:                       ;$2200

       .byte $84,$1F,$19,$BB            ;$2200   Blank space
       .byte $00,$00

       .byte $84,$40,$19,$1F,$BB        ;$2206   First DL on screen
       .byte $00,$00

       .byte $85,$1C,$19,$4A            ;$220D   Blank space before Fuji
       .byte $00,$00

       .byte $89,$1C,$19,$4A            ;$2213   Fuji line 1
       .byte $00,$00

       .byte $8D,$1C,$19,$48            ;$2219   Fuji line 2
       .byte $00,$00

       .byte $91,$1B,$19,$46            ;$221F   Fuji line 3
       .byte $00,$00

       .byte $96,$19,$19,$42            ;$2225   Fuji line 4
       .byte $00,$00

       .byte $9D,$17,$19,$3E            ;$222B   Fuji line 5
       .byte $00,$00

       .byte $A6,$17,$19,$3E            ;$2231   Fuji line 6
       .byte $00,$00

       .byte $AF,$2C,$1C,$00            ;$2237   Start of Atari
       .byte $AF,$2C,$1C,$50            ;        and between lines
       .byte $00,$00

       .byte $AF,$2C,$1D,$00            ;$2241   End of Atari
       .byte $AF,$2C,$1D,$50
       .byte $00,$00

       .byte $AF,$2D,$19,$28            ;$224B    Atari line 1
       .byte $00,$00

       .byte $C2,$2D,$19,$28            ;$2251    Atari line 2
       .byte $00,$00

       .byte $D5,$2D,$19,$28            ;$2257     Atari line 3
       .byte $00,$00

       .byte $E8,$2D,$19,$28            ;$225D     Atari line 4
       .byte $00,$00

       .byte $AF,$2D,$1A,$28            ;$2263     Atari line 5
       .byte $00,$00

       .byte $C2,$2D,$1A,$28            ;$2269     Atari line 6
       .byte $00,$00

       .byte $D5,$2D,$1A,$28            ;$226F     Atari line 7
       .byte $00,$00

       .byte $E8,$2D,$1A,$28            ;$2275     Atari line 8
       .byte $00,$00

       .byte $AF,$2D,$1B,$28            ;$227B     Atari line 9
       .byte $00,$00

       .byte $C2,$2D,$1B,$28            ;$2281     Atari line 10
       .byte $00,$00

       .byte $D5,$2D,$1B,$28            ;$2287     Atari line 11
       .byte $00,$00

; --- Master Display List for Boot Screen ---
; This is the main display list that Maria reads. It is a list of pointers
; to the display list definitions above. Copied to $1F84 in RAM.
DisplayList_Master:
       .byte $0F,$22,$06      ;Blank space
       .byte $0F,$22,$00      ;
       .byte $0F,$22,$00      ;
       .byte $0F,$22,$00      ;
       .byte $03,$22,$00      ;
       .byte $85,$22,$0D      ;DLI - Triggers NMI for color cycling
       .byte $05,$22,$13      ;Draw Fuji
       .byte $05,$22,$19      ;
       .byte $05,$22,$1F      ;
       .byte $05,$22,$25      ;
       .byte $05,$22,$2B      ;
       .byte $05,$22,$31      ;
       .byte $0F,$22,$00      ;Blank area
       .byte $01,$22,$37      ;Draw "ATARI"
       .byte $00,$22,$4B      ;Line 1
       .byte $02,$22,$37
       .byte $00,$22,$51      ;Line 2
       .byte $02,$22,$37
       .byte $00,$22,$57      ;Line 3
       .byte $02,$22,$37
       .byte $00,$22,$5D      ;Line 4
       .byte $02,$22,$37
       .byte $00,$22,$63      ;Line 5
       .byte $02,$22,$37
       .byte $00,$22,$69      ;Line 6
       .byte $02,$22,$37
       .byte $00,$22,$6F      ;Line 7
       .byte $02,$22,$37
       .byte $00,$22,$75      ;Line 8
       .byte $02,$22,$37
       .byte $00,$22,$7B      ;Line 9
       .byte $02,$22,$37
       .byte $00,$22,$81      ;Line 10
       .byte $02,$22,$37
       .byte $00,$22,$87      ;Line 11
       .byte $01,$22,$41
       .byte $0F,$22,$00      ;Blank Space
       .byte $0F,$22,$00      ;
       .byte $0F,$22,$00      ;
       .byte $0F,$22,$00      ;
       .byte $0F,$22,$00      ;

; --- Fuji/Atari Logo Graphics Data ---
; These are the raw bitmap graphics for the logo, copied to RAM.
GraphicsData_FujiAtari_1:
    .byte $00,$7c,$7f,$8f,$80,$fc,$7f,$8f,$c0,$1f,$87,$f8,$7e,$0f,$e0,$7f
GraphicsData_FujiAtari_2:
    .byte $81,$fc,$07,$ff,$80,$7f,$80,$7f,$f8,$1f,$ff,$f0,$00,$7f,$80,$03
GraphicsData_FujiAtari_3:
    .byte $ff,$fe,$1f,$00,$00,$00,$7f,$80,$00,$00,$3e,$00,$00,$0c,$00,$3f
GraphicsData_FujiAtari_4:
    .byte $ff,$ff,$ff,$f0,$00,$c0,$00,$00,$3f,$ff,$ff,$00,$03,$fc,$00,$00
GraphicsData_FujiAtari_5:
    .byte $3f,$00,$3f,$ff,$ff,$ff,$f0,$03,$f0,$00,$00,$3f,$ff,$ff,$fc,$03
GraphicsData_FujiAtari_6:
    .byte $fc,$00,$00,$ff,$c0,$00,$03,$ff,$00,$00,$0f,$fc,$00,$00,$3f,$f0
GraphicsData_FujiAtari_7:
    .byte $03,$ff,$c3,$fc,$00,$03,$ff,$f0,$00,$03,$ff,$00,$00,$3f,$ff,$00
LFD36:
    .byte $00,$3f,$f0,$00,$3f,$c3,$fc,$00,$7c,$7f,$8f,$80,$7c,$7f,$8f,$80
LFD46:
    .byte $1f,$87,$f8,$7e,$0f,$f0,$7f,$83,$fc,$01,$ff,$80,$7f,$80,$7f,$e0
LFD56:
    .byte $1f,$ff,$f8,$00,$7f,$80,$07,$ff,$fe,$1f,$f0,$00,$00,$7f,$80,$00
LFD66:
    .byte $03,$fe,$00,$0f,$f3,$fc,$00,$03,$ff,$00,$00,$ff,$3f,$c0,$00,$3f
LFD76:
    .byte $f0,$00,$ff,$c3,$fc,$00,$3f,$c0,$ff,$00,$03,$ff,$00,$03,$fc,$0f
LFD86:
    .byte $f0,$00,$3f,$f0,$3f,$fc,$03,$fc,$00,$ff,$00,$3f,$c0,$03,$ff,$00
LFD96:
    .byte $0f,$f0,$03,$fc,$00,$3f,$f0,$ff,$c0,$03,$fc,$03,$ff,$ff,$ff,$f0
LFDA6:
    .byte $03,$ff,$00,$3f,$ff,$ff,$ff,$00,$3f,$f0,$3f,$f0,$03,$fc,$00,$7c
LFDB6:
    .byte $7f,$8f,$80,$7c,$7f,$8f,$80,$1f,$87,$f8,$7e,$07,$f0,$7f,$83,$f8
LFDC6:
    .byte $00,$ff,$c0,$7f,$80,$ff,$c0,$1f,$ff,$fc,$00,$7f,$80,$0f,$ff,$fe
LFDD6:
    .byte $1f,$fc,$00,$00,$7f,$80,$00,$0f,$fe,$0f,$ff,$ff,$ff,$fc,$03,$ff
LFDE6:
    .byte $00,$ff,$ff,$ff,$ff,$c0,$3f,$f0,$0f,$fc,$03,$fc,$3f,$f0,$00,$03
LFDF6:
    .byte $ff,$03,$ff,$03,$ff,$00,$00,$3f,$f0,$3f
LFE00:
    .byte $f0,$03,$ff,$03,$fc,$ff
LFE06:
    .byte $c0,$00,$00,$ff,$c3,$ff,$0f,$fc,$00,$00,$0f,$fc,$3f,$f0,$00,$ff
LFE16:
    .byte $c3,$fc,$00,$7c,$7f,$8f,$80,$7c,$7f,$8f,$80,$0f,$87,$f8,$7c,$07
LFE26:
    .byte $f0,$7f,$83,$f8,$00,$7f,$c0,$7f,$80,$ff,$80,$1f,$ff,$fe,$00,$7f
LFE36:
    .byte $80,$1f,$ff,$fe,$1f,$ff,$00,$00,$7f,$80,$00,$3f,$fe,$55,$55,$55
LFE46:
    .byte $55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55
LFE56:
    .byte $55,$00,$7c,$7f,$8f,$80,$7c,$7f,$8f,$80,$0f,$c7,$f8,$fc,$03,$f0
LFE66:
    .byte $7f,$83,$f0,$00,$3f,$e0,$7f,$81,$ff,$00,$01,$ff,$fe,$00,$7f,$80
LFE76:
    .byte $1f,$ff,$e0,$1f,$ff,$c0,$00,$7f,$80,$00,$ff,$fe,$aa,$aa,$aa,$aa
LFE86:
    .byte $aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa,$aa
LFE96:
    .byte $00,$7c,$7f,$8f,$80,$7c,$7f,$8f,$80,$0f,$c7,$f8,$fc,$03,$f8,$7f
LFEA6:
    .byte $87,$f0,$00,$1f,$e0,$7f,$81,$fe,$00,$00,$1f,$ff,$00,$7f,$80,$3f
LFEB6:
    .byte $fe,$00,$1f,$ff,$e0,$00,$7f,$80,$01,$ff,$fe,$55,$55,$55,$55,$55
LFEC6:
    .byte $55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$09
LFED6:
    .byte $ca,$c9,$c6,$b4,$12,$08,$1b,$60,$58,$81,$4b,$86,$01,$d8,$bf,$d9
LFEE6:
    .byte $25,$a0,$7b,$dc,$32,$79,$84,$3b,$7c,$bc,$2f,$e2,$e2,$fa,$8d,$0a
LFEF6:
    .byte $00,$3b,$c5,$ec,$af,$2d,$8a,$cd,$06,$93
LFF00:
    .byte $6a,$a5,$14,$46,$77,$c4
LFF06:
    .byte $6a,$b2,$53,$36,$ef,$8c,$ce,$0c,$a2,$68,$71,$d3,$73,$e8,$f7,$6d
LFF16:
    .byte $06,$b5,$20,$ef,$23,$47,$0c,$51,$55,$c8,$fe,$f4,$58,$c4,$3f,$20
LFF26:
    .byte $a7,$67,$38,$b0,$76,$e2,$c4,$d8,$05,$63,$f8,$3c,$58,$3b,$2d,$22
LFF36:
    .byte $cc,$88,$b3,$71,$8f,$1d,$80,$0a,$87,$bd,$a1,$59,$23,$e9,$70,$e2
LFF46:
    .byte $d3,$ec,$46,$68,$80,$42,$39,$ea,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
LFF56:
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
LFF66:
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
LFF76:
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
LFF86:
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
LFF96:
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
LFFA6:
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
LFFB6:
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
LFFC6:
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
LFFD6:
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
LFFE6:
    .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff



LFD3D = $FD3D
LFDB4 = $FDB4
LFDD5 = $FDD5
LFE18 = $FE18
LFE57 = $FE57
LFE84 = $FE84
LFE96 = $FE96
LFED5 = $FED5
LFF00 = $FF00

GccCopyright:
       .byte $47,$43,$43,$28,$43,$29 ; 'GCC(C)'
       .byte $31,$39,$38,$34,$2D,$F7 ; '1984-'

;=============================================================================
;
; VII. 6502 HARDWARE VECTORS
;
;=============================================================================

; These are the processor's hard-wired vectors at the top of memory.
; The BIOS uses these to direct the CPU on NMI, Reset, and IRQ events.
; When a cartridge is mapped in, its own vectors at these locations are used.

CartNMIVectorLo:
       .byte $00,$F0 ; System NMI vector points to NmiVector_Rom.
CartResetVectorLo:
       .word START   ; System RESET vector points to $F884.
CartIRQVectorLo:
       .byte $33,$F9 ; System IRQ vector.