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)
|
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