213 lines
3.4 KiB
NASM
213 lines
3.4 KiB
NASM
; SameBoy SGB bootstrap ROM
|
|
; Todo: use friendly names for HW registers instead of magic numbers
|
|
SECTION "BootCode", ROM0[$0]
|
|
Start:
|
|
; Init stack pointer
|
|
ld sp, $fffe
|
|
|
|
; Clear memory VRAM
|
|
ld hl, $8000
|
|
|
|
.clearVRAMLoop
|
|
ldi [hl], a
|
|
bit 5, h
|
|
jr z, .clearVRAMLoop
|
|
|
|
; Init Audio
|
|
ld a, $80
|
|
ldh [$26], a
|
|
ldh [$11], a
|
|
ld a, $f3
|
|
ldh [$12], a
|
|
ldh [$25], a
|
|
ld a, $77
|
|
ldh [$24], a
|
|
|
|
; Init BG palette to white
|
|
ld a, $0
|
|
ldh [$47], a
|
|
|
|
; Load logo from ROM.
|
|
; A nibble represents a 4-pixels line, 2 bytes represent a 4x4 tile, scaled to 8x8.
|
|
; Tiles are ordered left to right, top to bottom.
|
|
ld de, $104 ; Logo start
|
|
ld hl, $8010 ; This is where we load the tiles in VRAM
|
|
|
|
.loadLogoLoop
|
|
ld a, [de] ; Read 2 rows
|
|
ld b, a
|
|
call DoubleBitsAndWriteRow
|
|
call DoubleBitsAndWriteRow
|
|
inc de
|
|
ld a, e
|
|
xor $34 ; End of logo
|
|
jr nz, .loadLogoLoop
|
|
|
|
; Load trademark symbol
|
|
ld de, TrademarkSymbol
|
|
ld c,$08
|
|
.loadTrademarkSymbolLoop:
|
|
ld a,[de]
|
|
inc de
|
|
ldi [hl],a
|
|
inc hl
|
|
dec c
|
|
jr nz, .loadTrademarkSymbolLoop
|
|
|
|
; Set up tilemap
|
|
ld a,$19 ; Trademark symbol
|
|
ld [$9910], a ; ... put in the superscript position
|
|
ld hl,$992f ; Bottom right corner of the logo
|
|
ld c,$c ; Tiles in a logo row
|
|
.tilemapLoop
|
|
dec a
|
|
jr z, .tilemapDone
|
|
ldd [hl], a
|
|
dec c
|
|
jr nz, .tilemapLoop
|
|
ld l,$0f ; Jump to top row
|
|
jr .tilemapLoop
|
|
.tilemapDone
|
|
|
|
; Turn on LCD
|
|
ld a, $91
|
|
ldh [$40], a
|
|
|
|
ld a, $f1 ; Packet magic, increases by 2 for every packet
|
|
ldh [$80], a
|
|
ld hl, $104 ; Header start
|
|
|
|
xor a
|
|
ld c, a ; JOYP
|
|
|
|
.sendCommand
|
|
xor a
|
|
ld [c], a
|
|
ld a, $30
|
|
ld [c], a
|
|
|
|
ldh a, [$80]
|
|
call SendByte
|
|
push hl
|
|
ld b, $e
|
|
ld d, 0
|
|
|
|
.checksumLoop
|
|
call ReadHeaderByte
|
|
add d
|
|
ld d, a
|
|
dec b
|
|
jr nz, .checksumLoop
|
|
|
|
; Send checksum
|
|
call SendByte
|
|
pop hl
|
|
|
|
ld b, $e
|
|
.sendLoop
|
|
call ReadHeaderByte
|
|
call SendByte
|
|
dec b
|
|
jr nz, .sendLoop
|
|
|
|
; Done bit
|
|
ld a, $20
|
|
ld [c], a
|
|
ld a, $30
|
|
ld [c], a
|
|
|
|
; Update command
|
|
ldh a, [$80]
|
|
add 2
|
|
ldh [$80], a
|
|
|
|
ld a, $58
|
|
cp l
|
|
jr nz, .sendCommand
|
|
|
|
; Write to sound registers for DMG compatibility
|
|
ld c, $13
|
|
ld a, $c1
|
|
ld [c], a
|
|
inc c
|
|
ld a, 7
|
|
ld [c], a
|
|
|
|
; Init BG palette
|
|
ld a, $fc
|
|
ldh [$47], a
|
|
|
|
; Set registers to match the original SGB boot
|
|
IF DEF(SGB2)
|
|
ld a, $FF
|
|
ELSE
|
|
ld a, 1
|
|
ENDC
|
|
ld hl, $c060
|
|
|
|
; Boot the game
|
|
jp BootGame
|
|
|
|
ReadHeaderByte:
|
|
ld a, $4F
|
|
cp l
|
|
jr c, .zero
|
|
ld a, [hli]
|
|
ret
|
|
.zero:
|
|
inc hl
|
|
xor a
|
|
ret
|
|
|
|
SendByte:
|
|
ld e, a
|
|
ld d, 8
|
|
.loop
|
|
ld a, $10
|
|
rr e
|
|
jr c, .zeroBit
|
|
add a ; 10 -> 20
|
|
.zeroBit
|
|
ld [c], a
|
|
ld a, $30
|
|
ld [c], a
|
|
dec d
|
|
ret z
|
|
jr .loop
|
|
|
|
DoubleBitsAndWriteRow:
|
|
; Double the most significant 4 bits, b is shifted by 4
|
|
ld a, 4
|
|
ld c, 0
|
|
.doubleCurrentBit
|
|
sla b
|
|
push af
|
|
rl c
|
|
pop af
|
|
rl c
|
|
dec a
|
|
jr nz, .doubleCurrentBit
|
|
ld a, c
|
|
; Write as two rows
|
|
ldi [hl], a
|
|
inc hl
|
|
ldi [hl], a
|
|
inc hl
|
|
ret
|
|
|
|
WaitFrame:
|
|
push hl
|
|
ld hl, $FF0F
|
|
res 0, [hl]
|
|
.wait
|
|
bit 0, [hl]
|
|
jr z, .wait
|
|
pop hl
|
|
ret
|
|
|
|
TrademarkSymbol:
|
|
db $3c,$42,$b9,$a5,$b9,$a5,$42,$3c
|
|
|
|
SECTION "BootGame", ROM0[$fe]
|
|
BootGame:
|
|
ldh [$50], a |