; GameBoy Color Boot ROM Disassembly ; Dumped by Costis ; Commenting by Randy Mongenel (Duo) ; WORK-IN-PROGRESS VERSION 09-27-2009 ; =========================================================================== ; Segment type: Pure code SECTION "ROM", CODE ; =============== S U B R O U T I N E ======================================= ; Set Top-Down Stack starting position in cpu-internal HiRAM area. sub_0000: ld sp, $FFFE ld a, 2 ; Set Work RAM Bank 2 jp System_Setup ; Set Work RAM Bank from A ; --------------------------------------------------------------------------- HDMA_1: db $D3, 0,$98,$A0,$12 HDMA_2: db $D3, 0,$80, 0,$40 db $1E db $53 ; S db $D0 ; Ð db 0 db $1F db $42 ; B db $1C db 0 db $14 db $2A ; * db $4D ; M db $19 db $8C ; Œ db $7E ; ~ db 0 db $7C ; | db $31 ; 1 db $6E ; n db $4A ; J db $45 ; E db $52 ; R db $4A ; J db 0 db 0 db $FF db $53 ; S db $1F db $7C ; | db $FF db 3 db $1F db 0 db $FF db $1F db $A7 ; § db 0 db $EF ; ï db $1B db $1F db 0 db $EF ; ï db $1B db 0 db $7C ; | db 0 db 0 db $FF db 3 Nintendo_Logo: db $CE,$ED,$66,$66,$CC, $D, 0, $B, 3,$73, 0,$83, 0 db $C, 0, $D, 0, 8,$11,$1F,$88,$89, 0, $E,$DC,$CC db $6E,$E6,$DD,$DD,$D9,$99,$BB,$BB,$67,$63,$6E, $E,$EC db $CC,$DD,$DC,$99,$9F,$BB,$B9,$33,$3E R_Tile: db $3C,$42,$B9,$A5,$B9,$A5,$42,$3C ; (R) tile, compressed to 8 bytes db $58 ; X db $43 ; C ; --------------------------------------------------------------------------- System_Setup: ; CODE XREF: sub_0000+5j ld [Reg_SVBK], a ; Set Work RAM Bank from A ld a, $FC ; 'ü' ; Set DMG Mode BG Palette to BLACK BLACK BLACK WHITE ld [Reg_BGP], a ; | call Setup_Sound call Clear_8KB_at_8000_Aligned ; Falls through to Clear function below ld h, $D0 ; 'Ð' call Clear_8KB_at_HL_Aligned ; Fill 8KB at HL with zeroes (7-byte TINY version) ; ; Input: ; HL = Pointer to start of area to clear ; ; Note: HL must be aligned to xx000000, due to 8KB Counter check method (bit 5,h = done?) ld hl, $FE00 ; Clear A0 bytes of OAM at FE00 (all of it) ld c, $A0 ; ' ' ; | xor a loc_0093: ; CODE XREF: sub_0000+95j ldi [hl], a ; | dec c ; | jr nz, loc_0093 ; | Load_Logo_into_RAM_VRAM: ; Cartridge ROM Location of Nintendo Logo bytes ld de, $104 ld hl, $8010 ld c, h loc_009E: ; CODE XREF: sub_0000+ABj ld a, [de] ; get header logo byte ld [c], a ; copy it to FF80+ inc c call Scale_Graphic_Byte_2X_Nibble1 ; 2x scales nintendo logo graphic data for display on LCD call Scale_Graphic_Byte_2X_Nibble2 ; must be called after 1 to work right inc de ld a, e cp $34 ; '4' jr nz, loc_009E ; get header logo byte Copy_R_Tile_To_VRAM: ; address of R tile ($0072) ld de, $72 ; 'r' ld b, 8 ; size of R tile (8 bytes 2x vertical compressed tile) _copy_r_tile_loop: ; CODE XREF: sub_0000+B7j ld a, [de] ; get tile byte inc de ; increment pointer ldi [hl], a ; store tile byte at (HL) inc hl ; skip compressed byte by incrementing destination pointer again (after the previous LDI) dec b ; decrement length counter jr nz, _copy_r_tile_loop ; get tile byte call Load_GameBoy_Check_Header ld a, 1 ld [Reg_VBK], a ; VRAM Bank 1 ld a, $91 ; '‘' ld [Reg_LCDC], a ; $91 = LCD ON | Window OFF | Char 8000 | BG 9800 | BG ON | OBJ OFF ld hl, $98B2 ld b, $4E ; 'N' ld c, $44 ; 'D' call sub_0291 ; Input: ; HL = VRAM Map Address ; B = ? ; C = ? xor a ld [Reg_VBK], a ld c, $80 ; '€' ld hl, $42 ; 'B' ld b, $18 loc_00D8: ; CODE XREF: sub_0000+DFj ld a, [c] inc c cp [hl] loc_00DB: ; CODE XREF: sub_0000:loc_00DBj jr nz, @ inc hl dec b jr nz, loc_00D8 ld hl, $134 ; Cartridge ROM Header Game Title ld b, $19 ; Add up Game Title data for checksum check ld a, b ; from 0134 to 014C (title, manufacturer, cart type, version codes) loc_00E7: ; CODE XREF: sub_0000+EAj add a, [hl] inc l dec b jr nz, loc_00E7 add a, [hl] ; Add Complement Checksum at 014D to summed header data. If result = 0, then header is valid FAIL_LOOP: ; CODE XREF: sub_0000:FAIL_LOOPj jr nz, @ ; if Complement Checksum != 0, then check failed. Stop execution by jumping to self. call Load_VRAM_and_Palettes ; If checksum = 0 then success, setup graphics and Palettes and Commit System type and boot cartridge jr Commit_System_and_Boot_Cart ; --------------------------------------------------------------------------- db 0 db 0 ; --------------------------------------------------------------------------- Commit_System_and_Boot_Cart: ; CODE XREF: sub_0000+F2j call Set_System_Mode xor a ; Set work ram bank to 0 (0/1 are both bank 1) ld [Reg_SVBK], a ; | ld a, $11 ld [Reg_BLCK], a ; Disable boot ROM ; End of function sub_0000 nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop loc_0137: ; DATA XREF: Load_GameBoy_Check_Header:loc_04BBr nop nop nop nop nop nop nop nop nop nop nop nop loc_0143: ; DATA XREF: Set_System_Mode+3r nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop ; =============== S U B R O U T I N E ======================================= ; Falls through to Clear function below Clear_8KB_at_8000_Aligned: ; CODE XREF: sub_0000+85p ; Load_GameBoy_Check_Header+4p ld hl, $8000 ; End of function Clear_8KB_at_8000_Aligned ; =============== S U B R O U T I N E ======================================= ; Fill 8KB at HL with zeroes (7-byte TINY version) ; ; Input: ; HL = Pointer to start of area to clear ; ; Note: HL must be aligned to xx000000, due to 8KB Counter check method (bit 5,h = done?) Clear_8KB_at_HL_Aligned: ; CODE XREF: sub_0000+8Ap xor a _clear_8kb_loop: ; CODE XREF: Clear_8KB_at_HL_Aligned+4j ldi [hl], a ; if HL < $2000, loop back bit 5, h jr z, _clear_8kb_loop ; if HL < $2000, loop back ret ; End of function Clear_8KB_at_HL_Aligned ; =============== S U B R O U T I N E ======================================= ; Copy bytes from Pointer in HL to Pointer in DE ; ; Input: ; HL = Source Address ; DE = Destination Address ; C = copy length ; ; Output: ; HL = HL + C ; DE = DE + C ; C = 0 Copy_C_bytes_from_HL_to_DE: ; CODE XREF: Copy_C_bytes_from_HL_to_DE+4j ; Load_HDMA_HL+5p ... ldi a, [hl] ld [de], a inc de dec c jr nz, Copy_C_bytes_from_HL_to_DE ; | ret ; End of function Copy_C_bytes_from_HL_to_DE ; =============== S U B R O U T I N E ======================================= ; Wait until LCD VBlank Interrupt is flagged. ; ; Input: None. ; Output: None. Wait_for_next_VBLANK: ; CODE XREF: sub_0291p sub_0291+2Bp ... push hl ld hl, $FF0F res 0, [hl] _wait_vblank_loop: ; CODE XREF: Wait_for_next_VBLANK+8j bit 0, [hl] ; wait until hardware goes into vblank mode and sets the vblank flag (bit 0 of FF0F) jr z, _wait_vblank_loop ; wait until hardware goes into vblank mode and sets the vblank flag (bit 0 of FF0F) pop hl ret ; End of function Wait_for_next_VBLANK ; =============== S U B R O U T I N E ======================================= ; Input: ; D003 = Last Keypad state ; ; Output: ; Bit Format: D, U, L, R, ST, SEL, B, A ; D003 = New Keypad state ; D004 = Keys changed since last read? Read_Keypad: ; CODE XREF: DMG_Manual_Color_Selectp ld de, $FF00 ; Pad register ld hl, $D003 ; D003 = Copy of keys last/currently pressed ld c, $F ; button mask ld a, $30 ; '0' ; Reset Keypad ld [de], a ; | ld a, $20 ; ' ' ; Enable D-PAD bits ld [de], a ; | ld a, [de] ; Get pad bits cpl ; Invert Pad bits and c ; mask off upper control bits, leaving only lower pad bits swap a ; swap d-pad bits to upper 4 bits ld b, a ; store d-pad bits in B ld a, $10 ; Enable Button (A,B,Select,Start) bits ld [de], a ; | ld a, [de] ; Get button bits cpl ; invert button bits and c ; mask off control bits, leaving only button bits or b ; merge button bits with d-pad bits ld c, a ; store complete button reading in C ld a, [hl] ; get data from D003 xor c ; XOR with last keypad reading. Changed bits since last reading will be 1 in A. and $F0 ; 'ð' ; Isolate D-Pad bits, clear button bits ld b, a ; save dpad bits in B ldi a, [hl] ; get last keypad reading again and increment pointer to D004 xor c ; XOR current keypad reading with last keypad reading. Changed bits are 1 in A and c ; AND changed bits with current keypad data to get bits which have turned ON since last reading or b ; combine with saved Dpad reading. ; At this point, we have the ability to HOLD the d-pad while changing A or B buttons to change the palette ldd [hl], a ld b, a ld a, c ld [hl], a ld a, $30 ; '0' ld [de], a ret ; End of function Read_Keypad ; =============== S U B R O U T I N E ======================================= ; Input: ; HL = Pointer to OBJ Palette Data ; B = Size in bytes of OBJ Palette Data to load ; D = 256-byte offset from end of OBJ palette to start of BG Palette ; E = Size in bytes of BG Palette Data to load Load_BG_OBJ_Palettes: ; CODE XREF: Setup_Color_Palettes_1+Cp ; Set_System_Mode+22p ld a, $80 ; '€' ld [Reg_BCPS], a ; BG Palette Selection ld [Reg_OCPS], a ; setup BG and OBJ color palette registers to accept entries in sequence ld c, $6B ; 'k' ; $6B is register for OBJ Palette Data loc_0252: ; CODE XREF: Load_BG_OBJ_Palettes+Bj ldi a, [hl] ; Load next palette data byte from HL into C, increment HL pointer ld [c], a dec b ; B palette bytes to load into OBJ palette registers jr nz, loc_0252 ; Load next palette data byte from HL into C, increment HL pointer ld c, d add hl, bc ; Next Palette is D+1 bytes from previous ld b, e ld c, $69 ; 'i' loc_025C: ; CODE XREF: Load_BG_OBJ_Palettes+15j ldi a, [hl] ld [c], a dec b ; B palette bytes to load into BG Palette registers jr nz, loc_025C ret ; End of function Load_BG_OBJ_Palettes ; =============== S U B R O U T I N E ======================================= Setup_Color_Palettes_1: ; CODE XREF: sub_0291+3p ; Load_VRAM_and_Palettes+8p ... push bc push de push hl ; save registers ld hl, $D800 ; RAM location of palettes to use ld b, 1 ; Length of OBJ palette to load ld d, $3F ; '?' ; Offset to BG palette start ld e, $40 ; '@' ; Length of BG Palette call Load_BG_OBJ_Palettes ; Input: ; HL = Pointer to OBJ Palette Data ; B = Size in bytes of OBJ Palette Data to load ; D = 256-byte offset from end of OBJ palette to start of BG Palette ; E = Size in bytes of BG Palette Data to load pop hl ; restore saved registers pop de pop bc ret ; End of function Setup_Color_Palettes_1 ; =============== S U B R O U T I N E ======================================= Setup_Sound: ; CODE XREF: sub_0000+82p ld a, $80 ; '€' ld [unk_FF26], a ; Enable sound system, all channels OFF ld [unk_FF11], a ; Sound wave duty 50% ld a, $F3 ; 'ó' ld [unk_FF12], a ; Init Envelope ld [unk_FF25], a ; Set enabled soudn channels ld a, $77 ; 'w' ld [unk_FF24], a ; Set full volume ld hl, $FF30 ; Setup 00 FF repeating waveform in wave RAM xor a ld c, $10 _loop_clear_wave_data: ; CODE XREF: Setup_Sound+19j ldi [hl], a cpl dec c jr nz, _loop_clear_wave_data ret ; End of function Setup_Sound ; =============== S U B R O U T I N E ======================================= ; Input: ; HL = VRAM Map Address ; B = ? ; C = ? sub_0291: ; CODE XREF: sub_0000+CBp sub_0291+83j ... call Wait_for_next_VBLANK ; | call Setup_Color_Palettes_1 ld a, c cp $38 ; '8' jr nz, loc_02B0 push hl xor a ld [Reg_VBK], a ld hl, $99A7 ld a, $38 ; '8' loc_02A5: ; CODE XREF: sub_0291+18j ldi [hl], a inc a cp $3F ; '?' jr nz, loc_02A5 ld a, 1 ld [Reg_VBK], a pop hl loc_02B0: ; CODE XREF: sub_0291+9j push bc push hl ld hl, $143 ; GBC flag bit check bit 7, [hl] call z, DMG_Manual_Color_Select ; if Cartridge Header CGB flag is NOT present, call 0589 pop hl pop bc call Wait_for_next_VBLANK ; | ld a, c sub $30 ; '0' jp nc, loc_0306 ld a, c cp 1 jp z, loc_0306 ld a, l cp $D1 ; 'Ñ' jr z, loc_02F1 push bc ld b, 3 loc_02D3: ; CODE XREF: sub_0291+59j ld c, 1 loc_02D5: ; CODE XREF: sub_0291+52j ld d, 3 loc_02D7: ; CODE XREF: sub_0291+4Cj ld a, [hl] and $F8 ; 'ø' or c ldi [hl], a ; write palette data to screen for color sweep dec d jr nz, loc_02D7 inc c ld a, c cp 6 jr nz, loc_02D5 ld de, $11 add hl, de dec b jr nz, loc_02D3 ld de, $FFA1 add hl, de pop bc loc_02F1: ; CODE XREF: sub_0291+3Dj inc b ld a, b ld e, $83 ; 'ƒ' cp $62 ; 'b' jr z, loc_02FF ld e, $C1 ; 'Á' cp $64 ; 'd' jr nz, loc_0306 loc_02FF: ; CODE XREF: sub_0291+66j ld a, e ld [unk_FF13], a ld a, $87 ; '‡' ld [unk_FF14], a loc_0306: ; CODE XREF: sub_0291+31j sub_0291+37j ... ld a, [byte_C000+$1002] cp 0 jr z, loc_0317 dec a ld [byte_C000+$1002], a ld a, c cp 1 jp z, sub_0291 ; Input: ; HL = VRAM Map Address ; B = ? ; C = ? loc_0317: ; CODE XREF: sub_0291+7Aj dec c jp nz, sub_0291 ; Input: ; HL = VRAM Map Address ; B = ? ; C = ? ret ; End of function sub_0291 ; =============== S U B R O U T I N E ======================================= Load_VRAM_and_Palettes: ; CODE XREF: sub_0000+EFp ld c, $26 ; '&' loc_031E: ; CODE XREF: Load_VRAM_and_Palettes+Cj call Strange_D840_Counter call Wait_for_next_VBLANK ; Wait until LCD VBlank Interrupt is flagged. ; ; Input: None. ; Output: None. call Setup_Color_Palettes_1 dec c jr nz, loc_031E call Wait_for_next_VBLANK ; Wait until LCD VBlank Interrupt is flagged. ; ; Input: None. ; Output: None. ld a, 1 ld [Reg_VBK], a ; VRAM Bank 1 call Load_HDMA_0008 ; Copy 288 Map bytes from D300 to 98A0 (char map) call Load_HDMA_HL ; Copy 64 CHARs from D300 to 8000 xor a ld [Reg_VBK], a ; VRAM Bank 0 call Load_HDMA_0008 ret ; End of function Load_VRAM_and_Palettes ; =============== S U B R O U T I N E ======================================= Load_HDMA_0008: ; CODE XREF: Load_VRAM_and_Palettes+15p ; Load_VRAM_and_Palettes+1Ep ld hl, 8 ; End of function Load_HDMA_0008 ; =============== S U B R O U T I N E ======================================= Load_HDMA_HL: ; CODE XREF: Load_VRAM_and_Palettes+18p ld de, $FF51 ld c, 5 ; Copies 5 bytes of HDMA control data from HL into HDMA registers call Copy_C_bytes_from_HL_to_DE ; Copy bytes from Pointer in HL to Pointer in DE ; ; Input: ; HL = Source Address ; DE = Destination Address ; C = copy length ; ; Output: ; HL = HL + C ; DE = DE + C ; C = 0 ret ; End of function Load_HDMA_HL ; =============== S U B R O U T I N E ======================================= Strange_D840_Counter: ; CODE XREF: Load_VRAM_and_Palettes:loc_031Ep push bc push de ; save BC, DE, HL registers push hl ld hl, $D840 ; RAM structure ?? ld c, $20 ; ' ' loc_0352: ; CODE XREF: Strange_D840_Counter+3Fj ld a, [hl] ; get data from RAM and $1F ; clear upper 3 bits cp $1F ; if lower 5 bits are all 1, then skip jr z, loc_035A ; | inc a ; else inc A loc_035A: ; CODE XREF: Strange_D840_Counter+Dj ld d, a ldi a, [hl] ; get next RAM byte rlca rlca rlca ; rotate left 3 bits and 7 ld b, a ldd a, [hl] rlca rlca rlca and $18 or b cp $1F jr z, loc_036E inc a loc_036E: ; CODE XREF: Strange_D840_Counter+21j rrca rrca rrca ld b, a and $E0 ; 'à' or d ldi [hl], a ld a, b and 3 ld e, a ld a, [hl] rrca rrca and $1F cp $1F jr z, loc_0384 inc a loc_0384: ; CODE XREF: Strange_D840_Counter+37j rlca rlca or e ldi [hl], a dec c ; loop $20 times jr nz, loc_0352 ; get data from RAM pop hl pop de pop bc ret ; End of function Strange_D840_Counter ; =============== S U B R O U T I N E ======================================= Copy_Cart_Logo_Data_Add_Checksum: ; CODE XREF: Load_GameBoy_Check_Header+1Bp ; Load_GameBoy_Check_Header+22p ld c, 0 loc_0391: ; CODE XREF: Copy_Cart_Logo_Data_Add_Checksum+34j ld a, [de] and $F0 ; 'ð' bit 1, c jr z, loc_039A swap a loc_039A: ; CODE XREF: Copy_Cart_Logo_Data_Add_Checksum+7j ld b, a inc hl ld a, [hl] or b ldi [hl], a ld a, [de] and $F bit 1, c jr nz, loc_03A8 swap a loc_03A8: ; CODE XREF: Copy_Cart_Logo_Data_Add_Checksum+15j ld b, a inc hl ld a, [hl] or b ldi [hl], a inc de bit 0, c jr z, loc_03BF push de ld de, $FFF8 bit 1, c jr z, loc_03BD ld de, 8 loc_03BD: ; CODE XREF: Copy_Cart_Logo_Data_Add_Checksum+29j add hl, de pop de loc_03BF: ; CODE XREF: Copy_Cart_Logo_Data_Add_Checksum+21j inc c ld a, c cp $18 jr nz, loc_0391 ret ; End of function Copy_Cart_Logo_Data_Add_Checksum ; =============== S U B R O U T I N E ======================================= Scale_Graphic_Byte_2X_Nibble1: ; CODE XREF: sub_0000+A1p ld b, a ; save logo byte to B ; End of function Scale_Graphic_Byte_2X_Nibble1 ; =============== S U B R O U T I N E ======================================= Scale_Graphic_Byte_2X_Nibble2: ; CODE XREF: sub_0000+A4p push de ; save header logo pointer ld d, 4 ; D = bit counter to scale loc_03CA: ; CODE XREF: Scale_Graphic_Byte_2X_Nibble2+Bj ld e, b ; DE = 40,logo_byte rl b ; scale Nintendo logo horizontally 2x rla ; | rl e ; | rla ; | dec d ; | jr nz, loc_03CA ; | pop de ; restore logo pointer ldi [hl], a ; scale nintendo logo vertically 2x by storing the byte 2x at HL (tile memory) inc hl ; | ldi [hl], a ; | inc hl ; | ret ; End of function Scale_Graphic_Byte_2X_Nibble2 ; =============== S U B R O U T I N E ======================================= ; Draws the basic map for the Nintendo(r) logo in DMG style centered. Copy_Nintendo_Logo_Map: ; CODE XREF: Set_System_Mode+30p ld a, $19 ld [byte_9800+$110], a ; BG MAP ? Bottom of Y graphic gets (R) character from cart logo ld hl, $992F loc_03E2: ; CODE XREF: Copy_Nintendo_Logo_Map+13j ld c, $C loc_03E4: ; CODE XREF: Copy_Nintendo_Logo_Map+Fj dec a jr z, locret_03EF ldd [hl], a dec c jr nz, loc_03E4 ld l, $F jr loc_03E2 ; --------------------------------------------------------------------------- locret_03EF: ; CODE XREF: Copy_Nintendo_Logo_Map+Bj ret ; End of function Copy_Nintendo_Logo_Map ; =============== S U B R O U T I N E ======================================= Load_GameBoy_Check_Header: ; CODE XREF: sub_0000+B9p ld a, 1 ld [Reg_VBK], a ; Set Video Bank 1 call Clear_8KB_at_8000_Aligned ; Falls through to Clear function below ld de, $607 ld hl, $8080 ld c, $C0 ; 'À' loc_03FF: ; CODE XREF: Load_GameBoy_Check_Header+16j ld a, [de] ; decompress vertically squashed GameBoy logo data ldi [hl], a inc hl ldi [hl], a inc hl inc de dec c jr nz, loc_03FF ; decompress vertically squashed GameBoy logo data ld de, $104 ; address of Cartridge Logo data call Copy_Cart_Logo_Data_Add_Checksum ld bc, $FFA8 ; subtract 88 from HL add hl, bc call Copy_Cart_Logo_Data_Add_Checksum ld bc, $FFF8 add hl, bc ; Subtract 8 from HL ld de, $72 ; 'r' ; data at $0072 8-byte vertically compressed (R) tile ld c, 8 _copy_r_tile_loop2: ; CODE XREF: Load_GameBoy_Check_Header+33j inc hl ld a, [de] ; copy (R) tile from 0072 to vram ldi [hl], a inc de dec c jr nz, _copy_r_tile_loop2 @@loc_setup_attributes: ; Map 0 location of top left corner of "GAMEBOY" Graphic ld hl, $98C2 ld b, 8 ld a, 8 loc_042C: ; CODE XREF: Load_GameBoy_Check_Header+47j ld c, $10 ; map data line length loc_042E: ; CODE XREF: Load_GameBoy_Check_Header+40j ldi [hl], a ; fill map attribute bytes with $8 dec c jr nz, loc_042E ; fill map attribute bytes with $8 ld de, $10 ; next map row add hl, de ; | dec b jr nz, loc_042C ; fill 8 lines worth Draw_GAMEBOY_Logo_Map: xor a ld [Reg_VBK], a ; VRAM Bank 0 ld hl, $98C2 ; Map 0 location of top left corner of "GAMEBOY" Graphic ld a, 8 loc_0441: ; CODE XREF: Load_GameBoy_Check_Header+62j ldi [hl], a ; Fill Map rectangle from 2,6 to 11,8 with 08-37 (map data for GAMEBOY logo) inc a ; | cp $18 jr nz, loc_0449 ld l, $E2 ; 'â' loc_0449: ; CODE XREF: Load_GameBoy_Check_Header+55j cp $28 ; '(' jr nz, loc_0450 ld hl, $9902 loc_0450: ; CODE XREF: Load_GameBoy_Check_Header+5Bj cp $38 ; '8' jr nz, loc_0441 ; Done with logo fill Addr_0454: ; Create structures with data at 08D8 ld hl, $8D8 ; FF, FF, xx, xx, 00, 00, XX, XX ; FF, FF, xx, xx, 00, 00, XX, XX ; FF, FF, xx, xx, 00, 00, XX, XX ; FF, FF, xx, xx, 00, 00, XX, XX ; FF, FF, xx, xx, 00, 00, XX, XX ; FF, FF, xx, xx, 00, 00, XX, XX ; FF, FF, xx, xx, 00, 00, XX, XX ; FF, FF, xx, xx, 00, 00, XX, XX ; ld de, $D840 ld b, 8 loc_045C: ; CODE XREF: Load_GameBoy_Check_Header+80j ld a, $FF ld [de], a inc de ld [de], a inc de ld c, 2 call Copy_C_bytes_from_HL_to_DE ; | ld a, 0 ld [de], a inc de ld [de], a inc de inc de inc de dec b jr nz, loc_045C call Setup_Color_Palettes_1 ld hl, $14B ; Cartridge Header Data Magic Number static $33 ld a, [hl] cp $33 ; '3' jr nz, loc_0488 ld l, $44 ; 'D' ld e, $30 ; '0' ldi a, [hl] cp e jr nz, loc_04CE inc e jr loc_048C ; --------------------------------------------------------------------------- loc_0488: ; CODE XREF: Load_GameBoy_Check_Header+8Bj ld l, $4B ; 'K' ld e, 1 loc_048C: ; CODE XREF: Load_GameBoy_Check_Header+96j ldi a, [hl] cp e jr nz, loc_04CE ld l, $34 ; '4' ld bc, $10 loc_0495: ; CODE XREF: Load_GameBoy_Check_Header+A9j ldi a, [hl] add a, b ld b, a dec c jr nz, loc_0495 ld [byte_C000+$1000], a ld hl, $6C7 ld c, 0 loc_04A3: ; CODE XREF: Load_GameBoy_Check_Header+BBj ldi a, [hl] cp b jr z, loc_04AF inc c ld a, c cp $4F ; 'O' jr nz, loc_04A3 jr loc_04CE ; --------------------------------------------------------------------------- loc_04AF: ; CODE XREF: Load_GameBoy_Check_Header+B5j ld a, c sub $41 ; 'A' jr c, loc_04D0 ld hl, $716 ld d, 0 ld e, a add hl, de loc_04BB: ; CODE XREF: Load_GameBoy_Check_Header+DCj ld a, [loc_0137] ld d, a ld a, [hl] cp d jr z, loc_04D0 ld de, $E add hl, de ld a, c add a, e ld c, a sub $5E ; '^' jr c, loc_04BB loc_04CE: ; CODE XREF: Load_GameBoy_Check_Header+93j ; Load_GameBoy_Check_Header+9Ej ... ld c, 0 loc_04D0: ; CODE XREF: Load_GameBoy_Check_Header+C2j ; Load_GameBoy_Check_Header+D1j ld hl, $733 ld b, 0 add hl, bc ld a, [hl] and $1F ld [byte_C000+$1008], a ld a, [hl] and $E0 ; 'à' rlca rlca rlca ld [byte_C000+$100B], a call sub_04E9 ret ; End of function Load_GameBoy_Check_Header ; =============== S U B R O U T I N E ======================================= sub_04E9: ; CODE XREF: Load_GameBoy_Check_Header+F5p ; DMG_Manual_Color_Select+40p ld de, $791 ld hl, $D900 ld a, [byte_C000+$100B] ld b, a ld c, $1E loc_04F5: ; CODE XREF: sub_04E9+33j bit 0, b jr nz, loc_04FB inc de inc de loc_04FB: ; CODE XREF: sub_04E9+Ej ld a, [de] ldi [hl], a jr nz, loc_0501 dec de dec de loc_0501: ; CODE XREF: sub_04E9+14j bit 1, b jr nz, loc_0507 inc de inc de loc_0507: ; CODE XREF: sub_04E9+1Aj ld a, [de] ldi [hl], a inc de inc de jr nz, loc_050F dec de dec de loc_050F: ; CODE XREF: sub_04E9+22j bit 2, b jr z, loc_0518 dec de dec hl ld a, [de] ldi [hl], a inc de loc_0518: ; CODE XREF: sub_04E9+28j ld a, [de] ldi [hl], a inc de dec c jr nz, loc_04F5 ld hl, $D900 ld de, $DA00 call Dictionary_Decompress_HL_to_DE ; This routine uses an index list ($60 long) at HL with a dictionary of 8-byte-long words at $07E8, ; and copies the words in index sequence to DE. ; Index is a byte offset, not a word offset, eg: index $80 is at $07E8+$80, not $80 * 8 byte word size. ret ; End of function sub_04E9 ; =============== S U B R O U T I N E ======================================= sub_0528: ; CODE XREF: DMG_Manual_Color_Select+43p ld hl, $12 ld a, [byte_C000+$1005] rlca rlca ld b, 0 ld c, a add hl, bc ld de, $D840 ld b, 8 loc_0539: ; CODE XREF: sub_0528+1Fj push hl ld c, 2 call Copy_C_bytes_from_HL_to_DE ; Copy bytes from Pointer in HL to Pointer in DE ; ; Input: ; HL = Source Address ; DE = Destination Address ; C = copy length ; ; Output: ; HL = HL + C ; DE = DE + C ; C = 0 inc de inc de inc de inc de inc de inc de pop hl dec b jr nz, loc_0539 ld de, $D842 ld c, 2 call Copy_C_bytes_from_HL_to_DE ; Copy bytes from Pointer in HL to Pointer in DE ; ; Input: ; HL = Source Address ; DE = Destination Address ; C = copy length ; ; Output: ; HL = HL + C ; DE = DE + C ; C = 0 ld de, $D84A ld c, 2 call Copy_C_bytes_from_HL_to_DE ; Copy bytes from Pointer in HL to Pointer in DE ; ; Input: ; HL = Source Address ; DE = Destination Address ; C = copy length ; ; Output: ; HL = HL + C ; DE = DE + C ; C = 0 dec hl dec hl ld de, $D844 ld c, 2 call Copy_C_bytes_from_HL_to_DE ; Copy bytes from Pointer in HL to Pointer in DE ; ; Input: ; HL = Source Address ; DE = Destination Address ; C = copy length ; ; Output: ; HL = HL + C ; DE = DE + C ; C = 0 ret ; End of function sub_0528 ; =============== S U B R O U T I N E ======================================= ; This routine uses an index list ($60 long) at HL with a dictionary of 8-byte-long words at $07E8, ; and copies the words in index sequence to DE. ; Index is a byte offset, not a word offset, eg: index $80 is at $07E8+$80, not $80 * 8 byte word size. Dictionary_Decompress_HL_to_DE: ; CODE XREF: sub_04E9+3Bp ld c, $60 ; '`' loc_0566: ; CODE XREF: Dictionary_Decompress_HL_to_DE+14j ldi a, [hl] push hl push bc ld hl, $7E8 ; Large table ld b, 0 ld c, a add hl, bc ld c, 8 call Copy_C_bytes_from_HL_to_DE ; Copy bytes from Pointer in HL to Pointer in DE ; ; Input: ; HL = Source Address ; DE = Destination Address ; C = copy length ; ; Output: ; HL = HL + C ; DE = DE + C ; C = 0 pop bc pop hl dec c jr nz, loc_0566 ret ; End of function Dictionary_Decompress_HL_to_DE ; =============== S U B R O U T I N E ======================================= HL_plus_D008_times_24: ; CODE XREF: Set_System_Mode+19p ld a, [byte_C000+$1008] ld de, $18 ; HL = HL + 24*[D008] inc a loc_0582: ; CODE XREF: HL_plus_D008_times_24+Bj dec a jr z, locret_0588 add hl, de jr nz, loc_0582 locret_0588: ; CODE XREF: HL_plus_D008_times_24+8j ret ; End of function HL_plus_D008_times_24 ; =============== S U B R O U T I N E ======================================= DMG_Manual_Color_Select: ; CODE XREF: sub_0291+26p call Read_Keypad ; | ld a, b ; Keypad data is left in B and $FF jr z, loc_05A0 ; If no buttons pressed, then skip to return ld hl, $8E4 ; Address of Color_Palette_KeyPad ld b, 0 loc_0596: ; CODE XREF: DMG_Manual_Color_Select+15j ldi a, [hl] cp c jr z, loc_05A2 inc b ld a, b cp $C jr nz, loc_0596 loc_05A0: ; CODE XREF: DMG_Manual_Color_Select+6j jr locret_05CF ; --------------------------------------------------------------------------- loc_05A2: ; CODE XREF: DMG_Manual_Color_Select+Fj ld a, b ld [byte_C000+$1005], a ld a, $1E ld [byte_C000+$1002], a ld de, $B add hl, de ld d, [hl] ld a, d and $1F ld e, a ld hl, $D008 ldd a, [hl] ldi [hl], a ld a, e ld [hl], a ld a, d and $E0 ; 'à' rlca rlca rlca ld e, a ld hl, $D00B ldd a, [hl] ldi [hl], a ld a, e ld [hl], a call sub_04E9 call sub_0528 locret_05CF: ; CODE XREF: DMG_Manual_Color_Select:loc_05A0j ret ; End of function DMG_Manual_Color_Select ; =============== S U B R O U T I N E ======================================= Set_System_Mode: ; CODE XREF: sub_0000:Commit_System_and_Boot_Cartp call Wait_for_next_VBLANK ; Wait until LCD VBlank Interrupt is flagged. ; ; Input: None. ; Output: None. ld a, [loc_0143] ; Cartridge ROM Compatability Flag (CGB = $80) bit 7, a jr z, Set_System_Mode_DMG ; If DMG, skip over FF4C part ld [Reg_LCDMODE], a ; This unknown register is at the tail end of the LCD register space. It may possibly lockdown advanced color hardware features from being accessed by a game in DMG mode. This could be tested. ; The CGB boot ROM sets this to $80 if a CGB game is inserted, or $04 if a DMG game is inserted. jr locret_0606 ; --------------------------------------------------------------------------- Set_System_Mode_DMG: ; CODE XREF: Set_System_Mode+8j ld a, 4 ld [Reg_LCDMODE], a ; This unknown register is at the tail end of the LCD register space. It may possibly lockdown advanced color hardware features from being accessed by a game in DMG mode. This could be tested. ; The CGB boot ROM sets this to $80 if a CGB game is inserted, or $04 if a DMG game is inserted. ld a, 1 ld [Reg_PAL_LOCK], a ; Unknown lockout register? Color palette lockout? ld hl, $DA00 call HL_plus_D008_times_24 ld b, $10 ld d, 0 ld e, 8 call Load_BG_OBJ_Palettes ; Input: ; HL = Pointer to OBJ Palette Data ; B = Size in bytes of OBJ Palette Data to load ; D = 256-byte offset from end of OBJ palette to start of BG Palette ; E = Size in bytes of BG Palette Data to load ld hl, $7A ; 'z' ld a, [byte_C000+$1000] ld b, a ld c, 2 loc_05FE: ; CODE XREF: Set_System_Mode+34j ldi a, [hl] cp b call z, Copy_Nintendo_Logo_Map ; Draws the basic map for the Nintendo(r) logo in DMG style centered. dec c jr nz, loc_05FE locret_0606: ; CODE XREF: Set_System_Mode+Cj ret ; End of function Set_System_Mode ; --------------------------------------------------------------------------- GameBoy_Logo: db 1, $F,$3F,$7E,$FF,$FF,$C0, 0,$C0,$F0,$F1, 3,$7C db $FC,$FE,$FE, 3, 7, 7, $F,$E0,$E0,$F0,$F0,$1E,$3E db $7E,$FE, $F, $F,$1F,$1F,$FF,$FF, 0, 0, 1, 1, 1 db 3,$FF,$FF,$E1,$E0,$C0,$F0,$F9,$FB,$1F,$7F,$F8,$E0 db $F3,$FD,$3E,$1E,$E0,$F0,$F9,$7F,$3E,$7C,$F8,$E0,$F8 db $F0,$F0,$F8, 0, 0,$7F,$7F, 7, $F,$9F,$BF,$9E,$1F db $FF,$FF, $F,$1E,$3E,$3C,$F1,$FB,$7F,$7F,$FE,$DE,$DF db $9F,$1F,$3F,$3E,$3C,$F8,$F8, 0, 0, 3, 3, 7, 7 db $FF,$FF,$C1,$C0,$F3,$E7,$F7,$F3,$C0,$C0,$C0,$C0,$1F db $1F,$1E,$3E,$3F,$1F,$3E,$3E,$80, 0, 0, 0,$7C,$1F db 7, 0, $F,$FF,$FE, 0,$7C,$F8,$F0, 0,$1F, $F, $F db 0,$7C,$F8,$F8, 0,$3F,$3E,$1C, 0, $F, $F, $F, 0 db $7C,$FF,$FF, 0, 0,$F8,$F8, 0, 7, $F, $F, 0,$81 db $FF,$FF, 0,$F3,$E1,$80, 0,$E0,$FF,$7F, 0,$FC,$F0 db $C0, 0,$3E,$7C,$7C, 0, 0, 0, 0, 0 Addr_06C7: db 0,$88,$16,$36,$D1,$DB,$F2,$3C,$8C,$92,$3D,$5C,$58 db $C9,$3E,$70,$1D,$59,$69,$19,$35,$A8,$14,$AA,$75,$95 db $99,$34,$6F,$15,$FF,$97,$4B,$90,$17,$10,$39,$F7,$F6 db $A2,$49,$4E,$43,$68,$E0,$8B,$F0,$CE, $C,$29,$E8,$B7 db $86,$9A,$52, 1,$9D,$71,$9C,$BD,$5D,$6D,$67,$3F,$6B db $B3,$46,$28,$A5,$C6,$D3,$27,$61,$18,$66,$6A,$BF, $D db $F4 Addr_0716: db $42,$45,$46,$41,$41,$52,$42,$45,$4B,$45,$4B,$20,$52 db $2D,$55,$52,$41,$52,$20,$49,$4E,$41,$49,$4C,$49,$43 db $45,$20,$52 Addr_0733: db $7C, 8,$12,$A3,$A2, 7,$87,$4B,$20,$12,$65,$A8,$16 db $A9,$86,$B1,$68,$A0,$87,$66,$12,$A1,$30,$3C,$12,$85 db $12,$64,$1B, 7, 6,$6F,$6E,$6E,$AE,$AF,$6F,$B2,$AF db $B2,$A8,$AB,$6F,$AF,$86,$AE,$A2,$A2,$12,$AF,$13,$12 db $A1,$6E,$AF,$AF,$AD, 6,$4C,$6E,$AF,$AF,$12,$7C,$AC db $A8,$6A,$6E,$13,$A0,$2D,$A8,$2B,$AC,$64,$AC,$6D,$87 db $BC,$60,$B4,$13,$72,$7C,$B5,$AE,$AE,$7C,$7C,$65,$A2 db $6C,$64,$85 Palette_Index: db $80,$B0,$40,$88,$20,$68,$DE, 0,$70,$DE,$20,$78,$20 db $20,$38,$20,$B0,$90,$20,$B0,$A0,$E0,$B0,$C0,$98,$B6 db $48,$80,$E0,$50,$1E,$1E,$58,$20,$B8,$E0,$88,$B0,$10 db $20, 0,$10,$20,$E0,$18,$E0,$18, 0,$18,$E0,$20,$A8 db $E0,$20,$18,$E0, 0,$20,$18,$D8,$C8,$18,$E0, 0,$E0 db $40,$28,$28,$28,$18,$E0,$60,$20,$18,$E0, 0, 0, 8 db $E0,$18,$30,$D0,$D0,$D0,$20,$E0,$E8 Palette_Dictionary:db $FF,$7F,$BF,$32,$D0, 0, 0, 0 db $9F,$63,$79,$42,$B0,$15,$CB, 4 db $FF,$7F,$31,$6E,$4A,$45, 0, 0 db $FF,$7F,$EF,$1B, 0, 2, 0, 0 db $FF,$7F,$1F,$42,$F2,$1C, 0, 0 db $FF,$7F,$94,$52,$4A,$29, 0, 0 db $FF,$7F,$FF, 3,$2F, 1, 0, 0 db $FF,$7F,$EF, 3,$D6, 1, 0, 0 db $FF,$7F,$B5,$42,$C8,$3D, 0, 0 db $74,$7E,$FF, 3,$80, 1, 0, 0 db $FF,$67,$AC,$77,$13,$1A,$6B,$2D db $D6,$7E,$FF,$4B,$75,$21, 0, 0 db $FF,$53,$5F,$4A,$52,$7E, 0, 0 db $FF,$4F,$D2,$7E,$4C,$3A,$E0,$1C db $ED, 3,$FF,$7F,$5F,$25, 0, 0 db $6A, 3,$1F, 2,$FF, 3,$FF,$7F db $FF,$7F,$DF, 1,$12, 1, 0, 0 db $1F,$23,$5F, 3,$F2, 0, 9, 0 db $FF,$7F,$EA, 3,$1F, 1, 0, 0 db $9F,$29,$1A, 0, $C, 0, 0, 0 db $FF,$7F,$7F, 2,$1F, 0, 0, 0 db $FF,$7F,$E0, 3, 6, 2,$20, 1 db $FF,$7F,$EB,$7E,$1F, 0, 0,$7C db $FF,$7F,$FF,$3F, 0,$7E,$1F, 0 db $FF,$7F,$FF, 3,$1F, 0, 0, 0 db $FF, 3,$1F, 0, $C, 0, 0, 0 db $FF,$7F,$3F, 3,$93, 1, 0, 0 db 0, 0, 0,$42,$7F, 3,$FF,$7F db $FF,$7F,$8C,$7E, 0,$7C, 0, 0 db $FF,$7F,$EF,$1B,$80,$61, 0, 0 Addr_08D8: db $FF,$7F db 0,$7C db $E0, 3 db $1F,$7C db $1F, 0 db $FF, 3 Color_Palette_KeyPad:db $40,$41 ; Values used when keypad is pressed to change color palettes db $42,$20 db $21,$22 db $80,$81 db $82,$10 db $11,$12 db $12,$B0 db $79,$B8 db $AD,$16 db $17, 7 db $BA, 5 db $7C,$13 db 0 db 0 db 0 db 0 ; end of 'ROM' ; =========================================================================== ; Segment type: Regular SECTION "VRAM_CHAR", DATA org $8000 ds $1800 ; end of 'VRAM_CHAR' ; =========================================================================== ; Segment type: Regular SECTION "VRAM_MAP", DATA org $9800 byte_9800: ds $800 ; end of 'VRAM_MAP' ; =========================================================================== ; Segment type: Regular SECTION "EXT_RAM", DATA org $A000 ds $2000 ; end of 'EXT_RAM' ; =========================================================================== ; Segment type: Regular SECTION "INT_RAM", DATA org $C000 byte_C000: ds $2000 ; end of 'INT_RAM' ; =========================================================================== ; Segment type: Regular SECTION "IO_REG", DATA org $FF00 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 unk_FF11: ds 1 unk_FF12: ds 1 unk_FF13: ds 1 unk_FF14: ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 unk_FF24: ds 1 unk_FF25: ds 1 unk_FF26: ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 Reg_LCDC: ds 1 ; DATA XREF: sub_0000+C2w ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 Reg_BGP: ds 1 ; DATA XREF: sub_0000+80w ds 1 ds 1 ds 1 ds 1 Reg_LCDMODE: ds 1 ; This unknown register is at the tail end of the LCD register space. It may possibly lockdown advanced color hardware features from being accessed by a game in DMG mode. This could be tested. ; The CGB boot ROM sets this to $80 if a CGB game is inserted, or $04 if a DMG game is inserted. ds 1 ds 1 Reg_VBK: ds 1 ; DATA XREF: sub_0000+BEw sub_0000+CFw ... Reg_BLCK: ds 1 ; DATA XREF: sub_0000+FEw ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 Reg_BCPS: ds 1 ; BG Palette Selection Reg_BCPD: ds 1 ; BG Palette Data Reg_OCPS: ds 1 ; OBJ Palette Selection Reg_OCPD: ds 1 ; OBJ Palette Data Reg_PAL_LOCK: ds 1 ; Unknown lockout register? Color palette lockout? ds 1 ds 1 ds 1 Reg_SVBK: ds 1 ; DATA XREF: sub_0000:System_Setupw ; sub_0000+FAw ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ; end of 'IO_REG' ; =========================================================================== ; Segment type: Regular SECTION "HiRAM", DATA org $FF80 ds $7F ; end of 'HiRAM' ; end of file