Difference between revisions of "7800 PAL BIOS"
From 8BitDev.org - Atari 7800 Development Wiki
(Created page with "==7800 PAL BIOS== This reverse engineered 7800 PAL BIOS code contains helpful context-comments and builds a 1:1 with the official BIOS ROM. In DASM syntax. <pre> ; Disasse...") |
(No difference)
|
Revision as of 22:00, 20 July 2025
7800 PAL BIOS
This reverse engineered 7800 PAL BIOS code contains helpful context-comments and builds a 1:1 with the official BIOS ROM. In DASM syntax.
; Disassembly of the Atari 7800 PAL BIOS
;
; - Daniel Boris <dboris@home.com>
; - Mike Saarna
; - Gemini 2.5 Pro
;
; Key differences from the NTSC BIOS:
; 1. Built-in Game: Includes a full version of Asteroids that runs if no
; valid cartridge is detected.
; 2. No Encryption: Due to 1980s-era export laws, the complex signature
; verification from the NTSC BIOS is absent. Cartridge checks are simpler.
;
; The code must be assembled with DASM.
processor 6502
;=============================================================================
;
; I. HARDWARE AND MEMORY EQUATES
;
;=============================================================================
STACKPTR EQU $FF
REGION EQU $FE
; --- TIA (Television Interface Adapter) Registers ---
INPTCTRL EQU $01 ; Input Control Register. Controls memory mapping (BIOS, RAM, Cart) and TIA access.
TIAWSYNC EQU $02 ; TIA's WSYNC, not Maria's
CXP0FB EQU $02 ; TIA Collision Register
CXP1FB EQU $03 ; TIA Collision Register
COLUP0 EQU $06 ; TIA P0 Color
COLUBK EQU $09 ; TIA Background Color
INPT4 EQU $0C ; Input Port 4 (Joystick Triggers)
INPT5 EQU $0D ; Input Port 5 (Joystick Triggers)
AUDC0 EQU $15 ; Audio Control 0
AUDC1 EQU $16 ; Audio Control 1
AUDF0 EQU $17 ; Audio Frequency 0
AUDF1 EQU $18 ; Audio Frequency 1
AUDV0 EQU $19 ; Audio Volume 0
AUDV1 EQU $1A ; Audio Volume 1
; --- Maria (Custom Graphics Chip) Registers ---
BACKGRND EQU $20 ; Background Color
P0C1 EQU $21 ; Palette 0, Color 1
P0C2 EQU $22 ; Palette 0, Color 2
P0C3 EQU $23 ; Palette 0, Color 3
WSYNC EQU $24 ; Maria Wait for Sync (halts CPU until horizontal blank)
P1C1 EQU $25 ; Palette 1, Color 1
P1C2 EQU $26 ; Palette 1, Color 2
P1C3 EQU $27 ; Palette 1, Color 3
MSTAT EQU $28 ; Maria Status Register (VBLANK, etc.)
P2C1 EQU $29 ; Palette 2, Color 1
P2C2 EQU $2A ; Palette 2, Color 2
P2C3 EQU $2B ; Palette 2, Color 3
DPPH EQU $2C ; Display List Pointer High Byte
P3C1 EQU $2D ; Palette 3, Color 1
P3C2 EQU $2E ; Palette 3, Color 2
P3C3 EQU $2F ; Palette 3, Color 3
DPPL EQU $30 ; Display List Pointer Low Byte
P4C1 EQU $31 ; Palette 4, Color 1
P4C2 EQU $32 ; Palette 4, Color 2
P4C3 EQU $33 ; Palette 4, Color 3
CHARBASE EQU $34 ; Character Mode High Pointer
P5C1 EQU $35 ; Palette 5, Color 1
P5C2 EQU $36 ; Palette 5, Color 2
P5C3 EQU $37 ; Palette 5, Color 3
OFFSET EQU $38 ; Not used by BIOS
P6C1 EQU $39 ; Palette 6, Color 1
P6C2 EQU $3A ; Palette 6, Color 2
P6C3 EQU $3B ; Palette 6, Color 3
CTRL EQU $3C ; Maria Control Register (DMA, graphics mode)
P7C1 EQU $3D ; Palette 7, Color 1
P7C2 EQU $3E ; Palette 7, Color 2
P7C3 EQU $3F ; Palette 7, Color 3
; --- RAM Address Equates ---
RAM_BASE_1 EQU $2000
RAM_BASE_2 EQU $2100
RAM_CODE_BASE EQU $2300
RAM_DLL_BASE EQU $2700
RAM_DLL_START EQU $2707
;=============================================================================
;
; II. BUILT-IN ASTEROIDS GAME DATA
;
;=============================================================================
ORG $C000
; This directive includes the 15,933 byte ROM image for the built-in
; Asteroids game. To generate this file from a PAL BIOS ROM on Mac OS
; or Linux, do the following...
;
; dd if=7800pal.rom of=ASTEROID.BIN bs=1 count=15933
INCBIN "ASTEROID.BIN"
;=============================================================================
;
; III. MAIN BIOS LOGIC (EXECUTED FROM ROM)
;
;=============================================================================
ORG $FE3D
; --- Data for Initial Display List ---
; This data is copied to RAM at RAM_DLL_BASE ($2700) during initialization.
DisplayList_InitialData:
.byte $00 ; DL entry - this is copied to $2700
.byte $40
.byte $F0
.byte $1F
.byte $BB
.byte $00
.byte $00
.byte $8F ; DLL entry - this is copied repeatedly at $2707
.byte >RAM_DLL_BASE
DisplayList_InitialData_End:
.byte <RAM_DLL_BASE
; --- BIOS Entry Point on Power-On/Reset ---
Bios_EntryPoint_Reset:
SEI ; Disable interrupts.
CLD ; Clear decimal mode.
LDA #$02 ; Enable Maria and map BIOS into memory.
STA INPTCTRL
LDX #STACKPTR
TXS ; Set stack pointer.
LDA #$7F
STA CTRL ; Turn off Maria DMA.
LDA #$00
STA BACKGRND ; Set background color to black.
LDX #$7F ; Copy 2600 mode initialization code to RIOT RAM.
Bios_Copy2600InitToRam_Loop:
LDA TiaInitCode_2600Mode,X ; Move from ROM...
STA $480,X ; ...to RIOT RAM at $0480.
DEX
BPL Bios_Copy2600InitToRam_Loop
; Copy the main cartridge checking logic from ROM to system RAM.
; This is done so the system can disable the BIOS ROM to read the
; cartridge, while still executing the necessary checker code from RAM.
LDX #[TiaInitCode_2600Mode - RamCode_Start]
Bios_CopyCartCheckToRam_Loop:
LDA RamCode_Start-1,X
STA RAM_CODE_BASE-1,X
DEX
BNE Bios_CopyCartCheckToRam_Loop
LDA #0 ; Zero out all TIA registers.
TAX
Bios_ClearTiaRegs_Loop:
STA 1,X
INX
CPX #$2C
BNE Bios_ClearTiaRegs_Loop
LDA #$02 ; Switch back into Maria mode.
STA INPTCTRL
; Initialize the first 64 bytes of both RAM chips to $FF.
LDA #$FF
LDX #$3F
Bios_InitRam_Loop:
STA RAM_BASE_1,X
STA RAM_BASE_2,X
DEX
BPL Bios_InitRam_Loop
; Copy the initial Display List data to its location in RAM.
LDX #(DisplayList_InitialData_End - DisplayList_InitialData)
Bios_CopyDisplayList_Loop:
LDA DisplayList_InitialData,X
STA RAM_DLL_BASE,X
DEX
BPL Bios_CopyDisplayList_Loop
; Replicate the last 3 bytes of the DL data to fill out the list.
INX
LDY #80
Bios_FillDisplayList_Loop:
LDA RAM_DLL_START,X
STA RAM_DLL_START+3,X
INX
DEY
BNE Bios_FillDisplayList_Loop
; Jump to the cartridge test routine, now located in RAM.
JMP [CartCheck_Start - RamCode_Start + RAM_CODE_BASE]
;=============================================================================
;
; IV. RAM-EXECUTED CODE (COPIED FROM ROM)
;
; This block of code is not executed from its ROM address. It is copied to
; system RAM starting at RAM_CODE_BASE ($2300) and executed from there.
;
;=============================================================================
RamCode_Start: ; (Base address for relative calculations, starts at $FEBD in ROM)
CartCheck_RunInternalGame:
LDA #$13 ; Enable BIOS ROM and Maria.
STA INPTCTRL
JMP StartInternalAsteroidsGame ; Jump to the built-in game.
CartCheck_Start:
LDA #$16 ; Enable external cartridge ROM and Maria.
STA INPTCTRL
LDY #$FF
LDX #$7F
; --- Cartridge Presence Test (Floating Bus Check) ---
; This loop compares the same ROM regions using different base addresses.
; If no cart is present, the bus will "float" with the last byte of the opcode
; which differs in our test. Therefore, if the compared bytes differ, then
; If a cart IS NOT present.
CartCheck_FloatingBus_Loop:
LDA $FE00,X
CMP $FD80,Y
BNE CartCheck_RunInternalGame
DEY
DEX
BPL CartCheck_FloatingBus_Loop
; --- Cartridge Reset Vector Test ---
; A valid cart must have a valid reset vector. $FFFF or $0000 indicates an
; empty socket or a problem.
LDA $FFFC
AND $FFFD
CMP #$FF
BEQ CartCheck_RunInternalGame ; All lines high -> No cart.
LDA $FFFC
ORA $FFFD
BEQ CartCheck_RunInternalGame ; All lines low -> No cart.
; --- Simple 7800 Signature Checks ---
LDA $FFF8 ; Check region verification byte.
ORA #REGION
CMP #$FF
BNE CartCheck_7800Fail_Try2600
LDA $FFF8
EOR #$F0
AND #$F0
BNE CartCheck_7800Fail_Try2600
LDA $FFF9 ; Check Maria signature byte.
AND #$0B ; $07 or $03 are valid values.
CMP #$03
BNE CartCheck_7800Fail_Try2600
LDA $FFF9 ; Get bottom of cart address range.
AND #$F0
CMP #$40 ; Make sure it is not below $4000.
BCC CartCheck_7800Fail_Try2600
SBC #$01 ; Check that start vector is within cart range.
CMP $FFFD
BCS CartCheck_7800Fail_Try2600
; --- Final Header Check ---
; This appears to be a final, simple checksum or signature validation.
LDA $1BEA
EOR #$FF
STA $1BEA
TAY
LDX #$05
CartCheck_HeaderValidation_Loop:
LDA $FFFA,X
CMP $DFFA,X
BNE CartCheck_HeaderValidation_Fail
DEX
BPL CartCheck_HeaderValidation_Loop
CPY $1BEA
BNE CartCheck_7800Fail_Try2600
CartCheck_HeaderValidation_Fail:
LDA #$02
STA INPTCTRL
JSR [Util_WaitForVblank - RamCode_Start + RAM_CODE_BASE]
LDA #>(RAM_DLL_START)
STA DPPH
LDA #<(RAM_DLL_START)
STA DPPL ; Set Display List pointer.
LDA #$43
STA $78
STA CTRL ; Turn graphics on.
LDX #$01
Util_WaitTwoFrames:
JSR [Util_WaitForVblank - RamCode_Start + RAM_CODE_BASE]
DEX
BPL Util_WaitTwoFrames
LDA #$60 ; Turn off graphics DMA.
STA CTRL
; --- Boot into 7800 Mode ---
Boot_Enter7800Mode:
LDX #$16 ; Enable cartridge ROM and Maria.
STX INPTCTRL
TXS ; Set stack pointer.
SED ; Set decimal mode.
JMP ($FFFC) ; Jump to the cartridge's reset vector.
; --- Boot into 2600 Mode ---
CartCheck_7800Fail_Try2600:
Boot_Enter2600Mode_FromRam:
LDA #$02 ; Enable BIOS ROM.
STA INPTCTRL ; Lock cart in 2600 mode.
JMP $480 ; Execute 2600 init code from RIOT RAM.
; --- Utility: Wait for Vertical Blank ---
Util_WaitForVblank:
BIT MSTAT ; Is VBLANK ended yet?
BMI Util_WaitForVblank
Util_WaitForVblank_Start:
BIT MSTAT ; Is VBLANK started yet?
BPL Util_WaitForVblank_Start
RTS
; --- 2600 TIA Setup Code (Copied to and executed from RIOT RAM at $0480) ---
TiaInitCode_2600Mode:
LDA #0
TAX
STA INPTCTRL
TiaInit_ClearLoop:
STA $03,X
INX
CPX #$2A
BNE TiaInit_ClearLoop
STA TIAWSYNC
LDA #4
NOP
BMI TiaInit_SetColors1
LDX #4
TiaInit_DelayLoop:
DEX
BPL TiaInit_DelayLoop
TXS
STA $110
JSR [TiaInit_DummyLabel+1 - TiaInitCode_2600Mode + $480]
JSR [TiaInit_DummyLabel+1 - TiaInitCode_2600Mode + $480]
STA $11
STA $1B
STA $1C
STA $F
NOP
STA TIAWSYNC
LDA #$00
NOP
BMI TiaInit_SetColors1
BIT CXP1FB
BMI TiaInit_SetColors2
TiaInit_SetColors1:
LDA #2
STA COLUBK
STA $F112
BNE TiaInit_Finalize
TiaInit_SetColors2:
BIT CXP0FB
BMI TiaInit_SetColors3
LDA #2
STA COLUP0
STA $F118
TiaInit_DummyLabel:
STA $F460
BNE TiaInit_Finalize
TiaInit_SetColors3:
STA $2C
LDA #$08
STA $1B
JSR [TiaInit_DummyLabel+1 - TiaInitCode_2600Mode + $480]
NOP
BIT CXP0FB
BMI TiaInit_SetColors1
TiaInit_Finalize:
LDA #$FD
STA 8
JMP ($FFFC)
; --- Internal Asteroids Game Startup Logic ---
; This routine is only called from inside the Asteroids game code.
Asteroids_InternalSubroutine_Equate = $F444
Asteroids_InternalSubroutine:
JSR Asteroids_InternalSubroutine_Equate
LDA $82
BPL Asteroids_Sub_SkipZero
LDA #$00
Asteroids_Sub_SkipZero:
ASL
ASL
CLC
ADC $83
STA $55
LDA #$01
RTS
StartInternalAsteroidsGame:
JSR Util_WaitForVblank
StartInternalGame_WaitFrame1:
BIT MSTAT
BMI StartInternalGame_WaitFrame1
LDA #$9E
LDY #$00
LDX #$00
StartInternalGame_WaitFrame2:
BIT MSTAT
BMI StartInternalGame_SyncWaitDone
STA WSYNC
STA WSYNC
DEX
BNE StartInternalGame_WaitFrame2
StartInternalGame_SyncWaitDone:
CPX #$78
BCS StartInternalGame_SetDPPL
LDA #$98
LDY #$2B
StartInternalGame_SetDPPL:
STA DPPL
STY $2001
JMP $D000 ; Jump into the Asteroids game code.
.byte 0,0,0,0,0,0,0,0
.byte 0,0
; --- Equates for Asteroids Game Vectors ---
ASTEROIDS_NMI_VECTOR EQU $D2E9
ASTEROIDS_IRQ_VECTOR EQU $D329
;=============================================================================
;
; V. 6502 HARDWARE VECTORS
;
;=============================================================================
.word ASTEROIDS_NMI_VECTOR ; NMI (DLI handler for Asteroids)
.word Bios_EntryPoint_Reset ; RESET
.word ASTEROIDS_IRQ_VECTOR ; IRQ