7800 NTSC BIOS
From 8BitDev.org - Atari 7800 Development Wiki
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.