Difference between revisions of "7800 PAL BIOS"

From 8BitDev.org - Atari 7800 Development Wiki
Jump to: navigation, search
(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)

Latest 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