ref: 1bf1d6e3ea7b75445803ed8d01c49014adf2e114
parent: 6259d4c605dae9e7c990aee11c6865c3e47b5f9f
parent: ec66551519195ee81176b7a07d5fb6871d96112d
author: Bryan Bishop <[email protected]>
date: Sat Feb 2 08:56:18 EST 2013
Merge pull request #97 from yenatch/master More things in bank 0.
--- a/main.asm
+++ b/main.asm
@@ -35,7 +35,7 @@
rst $38
SECTION "vblank",HOME[$40] ; vblank interrupt
- jp $0283
+ jp VBlank
SECTION "lcd",HOME[$48] ; lcd interrupt
jp $0552
@@ -56,8 +56,542 @@
SECTION "start",HOME[$150]
-INCBIN "baserom.gbc",$150,$45a - $150
+INCBIN "baserom.gbc",$150,$283 - $150
+VBlank: ; 283
+ push af
+ push bc
+ push de
+ push hl
+
+; get vblank type
+ ld a, [$ff9e]
+ and $7
+
+; get fn pointer
+ ld e, a
+ ld d, $0
+ ld hl, .VBlanks
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+
+; down to business
+ call JpHl
+
+; since this is called once per frame
+ call GameTimer
+
+ pop hl
+ pop de
+ pop bc
+ pop af
+ reti
+; 2a1
+
+.VBlanks ; 2a1
+ dw VBlank0 ; 0
+ dw VBlank1 ; 1
+ dw VBlank2 ; 2
+ dw VBlank3 ; 3
+ dw VBlank4 ; 4
+ dw VBlank5 ; 5
+ dw VBlank6 ; 6
+ dw VBlank0 ; 7
+; 2b1
+
+
+VBlank0: ; 2b1
+; normal operation
+
+; rng
+; scx, scy, wy, wx
+; bg map buffer
+; palettes
+; dma transfer
+; bg map
+; tiles
+; oam
+; joypad
+; sound
+
+; inc frame counter
+ ld hl, $ff9b
+ inc [hl]
+
+; advance rng
+ ld a, [$ff04] ; divider
+ ld b, a
+ ld a, [$ffe1]
+ adc b
+ ld [$ffe1], a
+
+ ld a, [$ff04] ; divider
+ ld b, a
+ ld a, [$ffe2]
+ sbc b
+ ld [$ffe2], a
+
+; save bank
+ ld a, [$ff9d] ; current bank
+ ld [$ff8a], a
+
+; scroll x
+ ld a, [$ffcf]
+ ld [$ff43], a ; scx
+; scroll y
+ ld a, [$ffd0]
+ ld [$ff42], a ; scy
+; window y
+ ld a, [$ffd2]
+ ld [$ff4a], a ; wy
+; window x + 7
+ ld a, [$ffd1]
+ ld [$ff4b], a ; wx
+
+; some time management is in order
+; only have time for one of these during vblank
+
+; bg map buffer has priority
+ call UpdateBGMapBuffer
+ jr c, .doneframeaction
+
+; then pals
+ call UpdatePalsIfCGB
+ jr c, .doneframeaction
+
+; dma transfer
+ call DMATransfer
+ jr c, .doneframeaction
+
+; bg map
+ call UpdateBGMap
+
+; these have their own timing checks
+ call SafeLoadTiles
+ call SafeLoadTiles2
+ call SafeTileAnimation
+
+.doneframeaction
+; oam update off?
+ ld a, [$ffd8]
+ and a
+ jr nz, .vblankoccurred
+
+; update oam by dma transfer
+ call $ff80
+; 403f:
+; ld a, $c4
+; ld [$ff46], a ; oam dma
+; ld a, $28
+; .loop
+; dec a
+; jr nz, .loop
+; ret
+
+
+; vblank-sensitive operations are done
+
+.vblankoccurred
+; tell other fns vblank happened
+ xor a
+ ld [VBlankOccurred], a
+
+; dec $cfb1 until 0
+ ld a, [$cfb1]
+ and a
+ jr z, .textdelay
+ dec a
+ ld [$cfb1], a
+
+.textdelay
+; dec text delay counter until 0
+ ld a, [TextDelayFrames]
+ and a
+ jr z, .joypad
+ dec a
+ ld [TextDelayFrames], a
+
+.joypad
+ call Joypad
+
+; update sound
+ ld a, BANK(UpdateSound)
+ rst Bankswitch ; bankswitch
+ call UpdateSound
+ ld a, [$ff8a]
+ rst Bankswitch ; restore bank
+
+;
+ ld a, [$ff98]
+ ld [$ffe3], a
+
+ ret
+; 325
+
+
+VBlank2: ; 325
+; sound only
+
+; save bank
+ ld a, [$ff9d]
+ ld [$ff8a], a
+
+; update sound
+ ld a, BANK(UpdateSound)
+ rst Bankswitch ; bankswitch
+ call UpdateSound
+
+; restore bank
+ ld a, [$ff8a]
+ rst Bankswitch
+
+; tell other fns vblank happened
+ xor a
+ ld [VBlankOccurred], a
+ ret
+; 337
+
+
+VBlank1: ; 337
+; scx, scy
+; palettes
+; bg map
+; tiles
+; oam
+; sound / lcd stat
+
+; save bank
+ ld a, [$ff9d]
+ ld [$ff8a], a
+
+; scroll x
+ ld a, [$ffcf]
+ ld [$ff43], a ; scx
+
+; scroll y
+ ld a, [$ffd0]
+ ld [$ff42], a ; scy
+
+; time-sensitive fns
+ call UpdatePals
+ jr c, .vblankoccurred
+
+; these have their own timing checks
+ call UpdateBGMap
+ call LoadTiles
+; update oam by dma transfer
+ call $ff80
+; 403f:
+; ld a, $c4
+; ld [$ff46], a ; oam dma
+; ld a, $28
+; .loop
+; dec a
+; jr nz, .loop
+; ret
+
+.vblankoccurred
+; tell other fns vblank happened
+ xor a
+ ld [VBlankOccurred], a
+
+; get requested ints
+ ld a, [$ff0f] ; IF
+ ld b, a
+; discard requested ints
+ xor a
+ ld [$ff0f], a ; IF
+; enable lcd stat
+ ld a, %10 ; lcd stat
+ ld [$ffff], a ; IE
+; rerequest serial int if applicable (still disabled)
+; request lcd stat
+ ld a, b
+ and %1000 ; serial
+ or %10 ; lcd stat
+ ld [$ff0f], a ; IF
+
+ ei
+; update sound
+ ld a, BANK(UpdateSound)
+ rst Bankswitch ; bankswitch
+ call UpdateSound
+; restore bank
+ ld a, [$ff8a]
+ rst Bankswitch
+ di
+
+; get requested ints
+ ld a, [$ff0f] ; IF
+ ld b, a
+; discard requested ints
+ xor a
+ ld [$ff0f], a ; IF
+; enable ints besides joypad
+ ld a, %1111 ; serial timer lcdstat vblank
+ ld [$ffff], a ; IE
+; rerequest ints
+ ld a, b
+ ld [$ff0f], a ; IF
+ ret
+; 37f
+
+
+UpdatePals: ; 37f
+; update pals for either dmg or cgb
+
+; check cgb
+ ld a, [$ffe6]
+ and a
+ jp nz, UpdateCGBPals
+
+; update gb pals
+ ld a, [$cfc7]
+ ld [$ff47], a ; BGP
+
+ ld a, [$cfc8]
+ ld [$ff48], a ; OBP0
+
+ ld a, [$cfc9]
+ ld [$ff49], a ; 0BP1
+
+ and a
+ ret
+; 396
+
+
+VBlank3: ; 396
+; scx, scy
+; palettes
+; bg map
+; tiles
+; oam
+; sound / lcd stat
+
+; save bank
+ ld a, [$ff9d]
+ ld [$ff8a], a
+
+; scroll x
+ ld a, [$ffcf]
+ ld [$ff43], a ; scx
+; scroll y
+ ld a, [$ffd0]
+ ld [$ff42], a ; scy
+
+; any pals to update?
+ ld a, [$ffe5]
+ and a
+ call nz, ForceUpdateCGBPals
+ jr c, .vblankoccurred
+; else
+ call UpdateBGMap
+ call LoadTiles
+
+; update oam by dma transfer
+ call $ff80
+; 403f:
+; ld a, $c4 ; Sprites / $100
+; ld [$ff46], a ; oam dma
+; ld a, $28
+; .loop
+; dec a
+; jr nz, .loop
+; ret
+
+.vblankoccurred
+; tell other fns vblank happened
+ xor a
+ ld [VBlankOccurred], a
+
+; save int flag
+ ld a, [$ff0f] ; IF
+ push af
+; reset ints
+ xor a
+ ld [$ff0f], a ; IF
+; force lcdstat int during sound update
+ ld a, %10 ; lcd stat
+ ld [$ffff], a ; IE
+ ld [$ff0f], a ; IF
+
+ ei
+; update sound
+ ld a, BANK(UpdateSound)
+ rst Bankswitch ; bankswitch
+ call UpdateSound
+; restore bank
+ ld a, [$ff8a]
+ rst Bankswitch
+ di
+
+; request lcdstat
+ ld a, [$ff0f] ; IF
+ ld b, a
+; and any other ints
+ pop af
+ or b
+ ld b, a
+; reset ints
+ xor a
+ ld [$ff0f], a ; IF
+; enable ints besides joypad
+ ld a, %1111 ; serial timer lcdstat vblank
+ ld [$ffff], a ; IE
+; request ints
+ ld a, b
+ ld [$ff0f], a ; IF
+ ret
+; 3df
+
+
+VBlank4: ; 3df
+; bg map
+; tiles
+; oam
+; joypad
+; serial
+; sound
+
+; save bank
+ ld a, [$ff9d]
+ ld [$ff8a], a
+
+ call UpdateBGMap
+ call SafeLoadTiles
+
+; update oam by dma transfer
+ call $ff80
+; 403f:
+; ld a, $c4
+; ld [$ff46], a ; oam dma
+; ld a, $28
+; .loop
+; dec a
+; jr nz, .loop
+; ret
+
+; update joypad
+ call Joypad
+
+; tell other fns vblank happened
+ xor a
+ ld [VBlankOccurred], a
+
+; handshake
+ call AskSerial
+
+; update sound
+ ld a, BANK(UpdateSound)
+ rst Bankswitch ; bankswitch
+ call UpdateSound
+; restore bank
+ ld a, [$ff8a]
+ rst Bankswitch
+ ret
+; 400
+
+
+VBlank5: ; 400
+; scx
+; palettes
+; bg map
+; tiles
+; joypad
+;
+
+; save bank
+ ld a, [$ff9d]
+ ld [$ff8a], a
+
+; scroll x
+ ld a, [$ffcf]
+ ld [$ff43], a ; scx
+
+; if we can update pals, skip this part
+ call UpdatePalsIfCGB
+ jr c, .vblankoccurred
+
+ call UpdateBGMap
+ call SafeLoadTiles
+
+.vblankoccurred
+; tell other fns vblank happened
+ xor a
+ ld [VBlankOccurred], a
+
+; joypad
+ call Joypad
+
+; discard requested ints
+ xor a
+ ld [$ff0f], a ; IF
+; enable lcd stat
+ ld a, %10 ; lcd stat
+ ld [$ffff], a ; IE
+; request lcd stat
+ ld [$ff0f], a ; IF
+
+ ei
+; update sound
+ ld a, BANK(UpdateSound)
+ rst Bankswitch ; bankswitch
+ call UpdateSound
+; restore bank
+ ld a, [$ff8a]
+ rst Bankswitch
+ di
+
+; discard requested ints
+ xor a
+ ld [$ff0f], a ; IF
+; enable ints besides joypad
+ ld a, %1111 ; serial timer lcdstat vblank
+ ld [$ffff], a ; IE
+ ret
+; 436
+
+
+VBlank6: ; 436
+; palettes
+; tiles
+; dma transfer
+; sound
+
+; save bank
+ ld a, [$ff9d]
+ ld [$ff8a], a
+
+; inc frame counter
+ ld hl, $ff9b
+ inc [hl]
+
+ call UpdateCGBPals
+ jr c, .vblankoccurred
+
+ call SafeLoadTiles
+ call SafeLoadTiles2
+ call DMATransfer
+
+.vblankoccurred
+; tell other fns vblank happened
+ xor a
+ ld [VBlankOccurred], a
+
+; update sound
+ ld a, BANK(UpdateSound)
+ rst Bankswitch ; bankswitch
+ call UpdateSound
+; restore bank
+ ld a, [$ff8a]
+ rst Bankswitch
+ ret
+; 45a
+
+
DelayFrame: ; 0x45a
; delay for one frame
ld a, $1
@@ -369,10 +903,8 @@
ret
; 658
-
INCBIN "baserom.gbc",$658,$691 - $658
-
SetClock: ; 691
; set clock data from hram
@@ -421,8 +953,88 @@
ret
; 6c4
-INCBIN "baserom.gbc",$6c4,$984 - $6c4
+INCBIN "baserom.gbc",$6c4,$935 - $6c4
+Joypad: ; 935
+; update joypad state
+; $ffa2: released
+; $ffa3: pressed
+; $ffa4: input
+; $ffa5: total pressed
+
+;
+ ld a, [$cfbe]
+ and $d0
+ ret nz
+
+; pause game update?
+ ld a, [$c2cd]
+ and a
+ ret nz
+
+; d-pad
+ ld a, $20
+ ld [$ff00], a
+ ld a, [$ff00]
+ ld a, [$ff00]
+; hi nybble
+ cpl
+ and $f
+ swap a
+ ld b, a
+
+; buttons
+ ld a, $10
+ ld [$ff00], a
+; wait to stabilize
+ ld a, [$ff00]
+ ld a, [$ff00]
+ ld a, [$ff00]
+ ld a, [$ff00]
+ ld a, [$ff00]
+ ld a, [$ff00]
+; lo nybble
+ cpl
+ and $f
+ or b
+ ld b, a
+
+; reset joypad
+ ld a, $30
+ ld [$ff00], a
+
+; get change in input
+ ld a, [$ffa4] ; last frame's input
+ ld e, a
+ xor b ; current frame input
+ ld d, a
+; released
+ and e
+ ld [$ffa2], a
+; pressed
+ ld a, d
+ and b
+ ld [$ffa3], a
+
+; total pressed
+ ld c, a
+ ld a, [$ffa5]
+ or c
+ ld [$ffa5], a
+
+; original input
+ ld a, b
+ ld [$ffa4], a
+
+; A+B+SELECT+START
+ and $f
+ cp $f
+ jp z, $0150 ; reset
+
+ ret
+; 984
+
+
GetJoypadPublic: ; 984
; update mirror joypad input from $ffa4 (real input)
@@ -588,8 +1200,507 @@
ret
; a1b
-INCBIN "baserom.gbc",$a1b,$c9f - $a1b
+INCBIN "baserom.gbc",$a1b,$b40 - $a1b
+FarDecompress: ; b40
+; Decompress graphics data at a:hl to de
+
+; put a away for a sec
+ ld [$c2c4], a
+; save bank
+ ld a, [$ff9d]
+ push af
+; bankswitch
+ ld a, [$c2c4]
+ rst Bankswitch
+
+; what we came here for
+ call Decompress
+
+; restore bank
+ pop af
+ rst Bankswitch
+ ret
+; b50
+
+
+Decompress: ; b50
+; Pokemon Crystal uses an lz variant for compression.
+
+; This is mainly used for graphics, but the intro's
+; tilemaps also use this compression.
+
+; This function decompresses lz-compressed data at hl to de.
+
+
+; Basic rundown:
+
+; A typical control command consists of:
+; -the command (bits 5-7)
+; -the count (bits 0-4)
+; -and any additional params
+
+; $ff is used as a terminator.
+
+
+; Commands:
+
+; 0: literal
+; literal data for some number of bytes
+; 1: iterate
+; one byte repeated for some number of bytes
+; 2: alternate
+; two bytes alternated for some number of bytes
+; 3: zero (whitespace)
+; 0x00 repeated for some number of bytes
+
+; Repeater control commands have a signed parameter used to determine the start point.
+; Wraparound is simulated:
+; Positive values are added to the start address of the decompressed data
+; and negative values are subtracted from the current position.
+
+; 4: repeat
+; repeat some number of bytes from decompressed data
+; 5: flipped
+; repeat some number of flipped bytes from decompressed data
+; ex: $ad = %10101101 -> %10110101 = $b5
+; 6: reverse
+; repeat some number of bytes in reverse from decompressed data
+
+; If the value in the count needs to be larger than 5 bits,
+; control code 7 can be used to expand the count to 10 bits.
+
+; A new control command is read in bits 2-4.
+; The new 10-bit count is split:
+; bits 0-1 contain the top 2 bits
+; another byte is added containing the latter 8
+
+; So, the structure of the control command becomes:
+; 111xxxyy yyyyyyyy
+; | | | |
+; | | our new count
+; | the control command for this count
+; 7 (this command)
+
+; For more information, refer to the code below and in extras/gfx.py .
+
+; save starting output address
+ ld a, e
+ ld [$c2c2], a
+ ld a, d
+ ld [$c2c3], a
+
+.loop
+; get next byte
+ ld a, [hl]
+; done?
+ cp $ff ; end
+ ret z
+
+; get control code
+ and %11100000
+
+; 10-bit param?
+ cp $e0 ; LZ_HI
+ jr nz, .normal
+
+
+; 10-bit param:
+
+; get next 3 bits (%00011100)
+ ld a, [hl]
+ add a
+ add a ; << 3
+ add a
+
+; this is our new control code
+ and %11100000
+ push af
+
+; get param hi
+ ld a, [hli]
+ and %00000011
+ ld b, a
+
+; get param lo
+ ld a, [hli]
+ ld c, a
+
+; read at least 1 byte
+ inc bc
+ jr .readers
+
+
+.normal
+; push control code
+ push af
+; get param
+ ld a, [hli]
+ and %00011111
+ ld c, a
+ ld b, $0
+; read at least 1 byte
+ inc c
+
+.readers
+; let's get started
+
+; inc loop counts since we bail as soon as they hit 0
+ inc b
+ inc c
+
+; get control code
+ pop af
+; command type
+ bit 7, a ; 80, a0, c0
+ jr nz, .repeatertype
+
+; literals
+ cp $20 ; LZ_ITER
+ jr z, .iter
+ cp $40 ; LZ_ALT
+ jr z, .alt
+ cp $60 ; LZ_ZERO
+ jr z, .zero
+ ; else $00
+
+; 00 ; LZ_LIT
+; literal data for bc bytes
+.loop1
+; done?
+ dec c
+ jr nz, .next1
+ dec b
+ jp z, .loop
+
+.next1
+ ld a, [hli]
+ ld [de], a
+ inc de
+ jr .loop1
+
+
+; 20 ; LZ_ITER
+; write byte for bc bytes
+.iter
+ ld a, [hli]
+
+.iterloop
+ dec c
+ jr nz, .iternext
+ dec b
+ jp z, .loop
+
+.iternext
+ ld [de], a
+ inc de
+ jr .iterloop
+
+
+; 40 ; LZ_ALT
+; alternate two bytes for bc bytes
+
+; next pair
+.alt
+; done?
+ dec c
+ jr nz, .alt0
+ dec b
+ jp z, .altclose0
+
+; alternate for bc
+.alt0
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .alt1
+; done?
+ dec b
+ jp z, .altclose1
+.alt1
+ ld a, [hld]
+ ld [de], a
+ inc de
+ jr .alt
+
+; skip past the bytes we were alternating
+.altclose0
+ inc hl
+.altclose1
+ inc hl
+ jr .loop
+
+
+; 60 ; LZ_ZERO
+; write 00 for bc bytes
+.zero
+ xor a
+
+.zeroloop
+ dec c
+ jr nz, .zeronext
+ dec b
+ jp z, .loop
+
+.zeronext
+ ld [de], a
+ inc de
+ jr .zeroloop
+
+
+; repeats
+; 80, a0, c0
+; repeat decompressed data from output
+.repeatertype
+ push hl
+ push af
+; get next byte
+ ld a, [hli]
+; absolute?
+ bit 7, a
+ jr z, .absolute
+
+; relative
+; a = -a
+ and %01111111 ; forget the bit we just looked at
+ cpl
+; add de (current output address)
+ add e
+ ld l, a
+ ld a, $ff ; -1
+ adc d
+ ld h, a
+ jr .repeaters
+
+.absolute
+; get next byte (lo)
+ ld l, [hl]
+; last byte (hi)
+ ld h, a
+; add starting output address
+ ld a, [$c2c2]
+ add l
+ ld l, a
+ ld a, [$c2c3]
+ adc h
+ ld h, a
+
+.repeaters
+ pop af
+ cp $80 ; LZ_REPEAT
+ jr z, .repeat
+ cp $a0 ; LZ_FLIP
+ jr z, .flip
+ cp $c0 ; LZ_REVERSE
+ jr z, .reverse
+
+; e0 -> 80
+
+; 80 ; LZ_REPEAT
+; repeat some decompressed data
+.repeat
+; done?
+ dec c
+ jr nz, .repeatnext
+ dec b
+ jr z, .cleanup
+
+.repeatnext
+ ld a, [hli]
+ ld [de], a
+ inc de
+ jr .repeat
+
+
+; a0 ; LZ_FLIP
+; repeat some decompressed data w/ flipped bit order
+.flip
+ dec c
+ jr nz, .flipnext
+ dec b
+ jp z, .cleanup
+
+.flipnext
+ ld a, [hli]
+ push bc
+ ld bc, $0008
+
+.fliploop
+ rra
+ rl b
+ dec c
+ jr nz, .fliploop
+ ld a, b
+ pop bc
+ ld [de], a
+ inc de
+ jr .flip
+
+
+; c0 ; LZ_REVERSE
+; repeat some decompressed data in reverse
+.reverse
+ dec c
+ jr nz, .reversenext
+
+ dec b
+ jp z, .cleanup
+
+.reversenext
+ ld a, [hld]
+ ld [de], a
+ inc de
+ jr .reverse
+
+
+.cleanup
+; get type of repeat we just used
+ pop hl
+; was it relative or absolute?
+ bit 7, [hl]
+ jr nz, .next
+
+; skip two bytes for absolute
+ inc hl
+; skip one byte for relative
+.next
+ inc hl
+ jp .loop
+; c2f
+
+
+
+
+UpdatePalsIfCGB: ; c2f
+; update bgp data from BGPals
+; update obp data from OBPals
+; return carry if successful
+
+; check cgb
+ ld a, [$ffe6]
+ and a
+ ret z
+
+UpdateCGBPals: ; c33
+; return carry if successful
+; any pals to update?
+ ld a, [$ffe5]
+ and a
+ ret z
+
+ForceUpdateCGBPals: ; c37
+; save wram bank
+ ld a, [$ff70] ; wram bank
+ push af
+; bankswitch
+ ld a, 5 ; BANK(BGPals)
+ ld [$ff70], a ; wram bank
+; get bg pal buffer
+ ld hl, BGPals ; 5:d080
+
+; update bg pals
+ ld a, %10000000 ; auto increment, index 0
+ ld [$ff68], a ; BGPI
+ ld c, $69 ; $ff69
+ ld b, 4 ; NUM_PALS / 2
+
+.bgp
+; copy 16 bytes (8 colors / 2 pals) to bgpd
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+; done?
+ dec b
+ jr nz, .bgp
+
+; hl is now 5:d0c0 OBPals
+
+; update obj pals
+ ld a, %10000000 ; auto increment, index 0
+ ld [$ff6a], a
+ ld c, $6b ; $ff6b - $ff00
+ ld b, 4 ; NUM_PALS / 2
+
+.obp
+; copy 16 bytes (8 colors / 2 pals) to obpd
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+ ld a, [hli]
+ ld [$ff00+c], a
+; done?
+ dec b
+ jr nz, .obp
+
+; restore wram bank
+ pop af
+ ld [$ff70], a ; wram bank
+; clear pal update queue
+ xor a
+ ld [$ffe5], a
+; successfully updated palettes
+ scf
+ ret
+; c9f
+
+
DmgToCgbBGPals: ; c9f
; exists to forego reinserting cgb-converted image data
@@ -1074,8 +2185,618 @@
pop hl
ret
-INCBIN "baserom.gbc",$135a,$185d - $135a
+INCBIN "baserom.gbc",$135a,$15d8 - $135a
+DMATransfer: ; 15d8
+; DMA transfer
+; return carry if successful
+
+; anything to transfer?
+ ld a, [$ffe8]
+ and a
+ ret z
+; start transfer
+ ld [$ff55], a ; hdma5
+; indicate that transfer has occurred
+ xor a
+ ld [$ffe8], a
+; successful transfer
+ scf
+ ret
+; 15e3
+
+
+UpdateBGMapBuffer: ; 15e3
+; write [$ffdc] 16x8 tiles from BGMapBuffer to bg map addresses in BGMapBufferPtrs
+; [$ffdc] must be even since this is done in 16x16 blocks
+
+; return carry if successful
+
+; any tiles to update?
+ ld a, [$ffdb]
+ and a
+ ret z
+; save wram bank
+ ld a, [$ff4f] ; vram bank
+ push af
+; save sp
+ ld [$ffd9], sp
+
+; temp stack
+ ld hl, BGMapBufferPtrs
+ ld sp, hl
+; we can now pop the addresses of affected spots in bg map
+
+; get pal and tile buffers
+ ld hl, BGMapPalBuffer
+ ld de, BGMapBuffer
+
+.loop
+; draw one 16x16 block
+
+; top half:
+
+; get bg map address
+ pop bc
+; update palettes
+ ld a, $1
+ ld [$ff4f], a ; vram bank
+; tile 1
+ ld a, [hli]
+ ld [bc], a
+ inc c
+; tile 2
+ ld a, [hli]
+ ld [bc], a
+ dec c
+; update tiles
+ ld a, $0
+ ld [$ff4f], a ; vram bank
+; tile 1
+ ld a, [de]
+ inc de
+ ld [bc], a
+ inc c
+; tile 2
+ ld a, [de]
+ inc de
+ ld [bc], a
+
+; bottom half:
+
+; get bg map address
+ pop bc
+; update palettes
+ ld a, $1
+ ld [$ff4f], a ; vram bank
+; tile 1
+ ld a, [hli]
+ ld [bc], a
+ inc c
+; tile 2
+ ld a, [hli]
+ ld [bc], a
+ dec c
+; update tiles
+ ld a, $0
+ ld [$ff4f], a ; vram bank
+; tile 1
+ ld a, [de]
+ inc de
+ ld [bc], a
+ inc c
+; tile 2
+ ld a, [de]
+ inc de
+ ld [bc], a
+
+; we've done 2 16x8 blocks
+ ld a, [$ffdc]
+ dec a
+ dec a
+ ld [$ffdc], a
+
+; if there are more left, get the next 16x16 block
+ jr nz, .loop
+
+
+; restore sp
+ ld a, [$ffd9]
+ ld l, a
+ ld a, [$ffda]
+ ld h, a
+ ld sp, hl
+
+; restore vram bank
+ pop af
+ ld [$ff4f], a ; vram bank
+
+; we don't need to update bg map until new tiles are loaded
+ xor a
+ ld [$ffdb], a
+
+; successfully updated bg map
+ scf
+ ret
+; 163a
+
+
+WaitTop: ; 163a
+ ld a, [$ffd4]
+ and a
+ ret z
+
+; wait until top third of bg map can be updated
+ ld a, [$ffd5]
+ and a
+ jr z, .quit
+
+ call DelayFrame
+ jr WaitTop
+
+.quit
+ xor a
+ ld [$ffd4], a
+ ret
+; 164c
+
+
+UpdateBGMap: ; 164c
+; get mode
+ ld a, [$ffd4]
+ and a
+ ret z
+
+; don't save bg map address
+ dec a ; 1
+ jr z, .tiles
+ dec a ; 2
+ jr z, .attr
+ dec a ; ?
+
+; save bg map address
+ ld a, [$ffd6]
+ ld l, a
+ ld a, [$ffd7]
+ ld h, a
+ push hl
+
+; bg map 1 ($9c00)
+ xor a
+ ld [$ffd6], a
+ ld a, $9c
+ ld [$ffd7], a
+
+; get mode again
+ ld a, [$ffd4]
+ push af
+ cp 3
+ call z, .tiles
+ pop af
+ cp 4
+ call z, .attr
+
+; restore bg map address
+ pop hl
+ ld a, l
+ ld [$ffd6], a
+ ld a, h
+ ld [$ffd7], a
+ ret
+
+.attr
+; switch vram banks
+ ld a, 1
+ ld [$ff4f], a ; vram bank
+; bg map 1
+ ld hl, AttrMap
+ call .getthird
+; restore vram bank
+ ld a, 0
+ ld [$ff4f], a ; vram bank
+ ret
+
+.tiles
+; bg map 0
+ ld hl, TileMap
+
+.getthird
+; save sp
+ ld [$ffd9], sp
+
+; # tiles to move down * 6 (which third?)
+ ld a, [$ffd5]
+ and a ; 0
+ jr z, .top
+ dec a ; 1
+ jr z, .middle
+
+; .bottom ; 2
+; move 12 tiles down
+ ld de, $00f0 ; TileMap(0,12) - TileMap
+ add hl, de
+; stack now points to source
+ ld sp, hl
+; get bg map address
+ ld a, [$ffd7]
+ ld h, a
+ ld a, [$ffd6]
+ ld l, a
+; move 12 tiles down
+ ld de, $0180 ; bgm(0,12)
+ add hl, de
+; start at top next time
+ xor a
+ jr .start
+
+.middle
+; move 6 tiles down
+ ld de, $0078 ; TileMap(0,6) - TileMap
+ add hl, de
+; stack now points to source
+ ld sp, hl
+; get bg map address
+ ld a, [$ffd7]
+ ld h, a
+ ld a, [$ffd6]
+ ld l, a
+; move 6 tiles down
+ ld de, $00c0 ; bgm(0,6)
+ add hl, de
+; start at bottom next time
+ ld a, 2
+ jr .start
+
+.top
+; stack now points to source
+ ld sp, hl
+; get bg map address
+ ld a, [$ffd7]
+ ld h, a
+ ld a, [$ffd6]
+ ld l, a
+; start at middle next time
+ ld a, 1
+
+.start
+; which third to draw next update
+ ld [$ffd5], a
+; # rows per third
+ ld a, 6 ; SCREEN_HEIGHT / 3
+; # tiles from the edge of the screen to the next row
+ ld bc, $000d ; BG_WIDTH + 1 - SCREEN_WIDTH
+
+.row
+; write a row of 20 tiles
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+; next row
+ add hl, bc
+; done?
+ dec a
+ jr nz, .row
+
+; restore sp
+ ld a, [$ffd9]
+ ld l, a
+ ld a, [$ffda]
+ ld h, a
+ ld sp, hl
+ ret
+; 170a
+
+
+SafeLoadTiles2: ; 170a
+; only execute during first fifth of vblank
+; any tiles to draw?
+ ld a, [$cf6c]
+ and a
+ ret z
+; abort if too far into vblank
+ ld a, [$ff44] ; LY
+; ly = 144-145?
+ cp 144
+ ret c
+ cp 146
+ ret nc
+
+GetTiles2: ; 1717
+; load [$cf6c] tiles from [$cf6d-e] to [$cf6f-70]
+; save sp
+ ld [$ffd9], sp
+
+; sp = [$cf6d-e] tile source
+ ld hl, $cf6d
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld sp, hl
+
+; hl = [$cf6f-70] tile dest
+ ld hl, $cf6f
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+
+; # tiles to draw
+ ld a, [$cf6c]
+ ld b, a
+
+; clear tile queue
+ xor a
+ ld [$cf6c], a
+
+.loop
+; put 1 tile (16 bytes) into hl from sp
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ ld [hl], d
+ inc l
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ ld [hl], d
+ inc l
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ ld [hl], d
+ inc l
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ ld [hl], d
+; next tile
+ inc hl
+; done?
+ dec b
+ jr nz, .loop
+
+; update $cf6f-70
+ ld a, l
+ ld [$cf6f], a
+ ld a, h
+ ld [$cf70], a
+
+; update $cf6d-e
+ ld [$cf6d], sp
+
+; restore sp
+ ld a, [$ffd9]
+ ld l, a
+ ld a, [$ffda]
+ ld h, a
+ ld sp, hl
+ ret
+; 1769
+
+
+SafeLoadTiles: ; 1769
+; only execute during first fifth of vblank
+; any tiles to draw?
+ ld a, [$cf67]
+ and a
+ ret z
+; abort if too far into vblank
+ ld a, [$ff44] ; LY
+; ly = 144-145?
+ cp 144
+ ret c
+ cp 146
+ ret nc
+ jr GetTiles
+
+LoadTiles: ; 1778
+; use only if time is allotted
+; any tiles to draw?
+ ld a, [$cf67]
+ and a
+ ret z
+; get tiles
+
+GetTiles: ; 177d
+; load [$cf67] tiles from [$cf68-9] to [$cf6a-b]
+
+; save sp
+ ld [$ffd9], sp
+
+; sp = [$cf68-9] tile source
+ ld hl, $cf68
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld sp, hl
+
+; hl = [$cf6a-b] tile dest
+ ld hl, $cf6a
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+
+; # tiles to draw
+ ld a, [$cf67]
+ ld b, a
+; clear tile queue
+ xor a
+ ld [$cf67], a
+
+.loop
+; put 1 tile (16 bytes) into hl from sp
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+; next tile
+ inc hl
+; done?
+ dec b
+ jr nz, .loop
+
+; update $cf6a-b
+ ld a, l
+ ld [$cf6a], a
+ ld a, h
+ ld [$cf6b], a
+
+; update $cf68-9
+ ld [$cf68], sp
+
+; restore sp
+ ld a, [$ffd9]
+ ld l, a
+ ld a, [$ffda]
+ ld h, a
+ ld sp, hl
+ ret
+; 17d3
+
+
+SafeTileAnimation: ; 17d3
+; call from vblank
+
+ ld a, [$ffde]
+ and a
+ ret z
+
+; abort if too far into vblank
+ ld a, [$ff44] ; LY
+; ret unless ly = 144-150
+ cp 144
+ ret c
+ cp 151
+ ret nc
+
+; save affected banks
+; switch to new banks
+ ld a, [$ff9d]
+ push af ; save bank
+ ld a, BANK(DoTileAnimation)
+ rst Bankswitch ; bankswitch
+
+ ld a, [$ff70] ; wram bank
+ push af ; save wram bank
+ ld a, $1 ; wram bank 1
+ ld [$ff70], a ; wram bank
+
+ ld a, [$ff4f] ; vram bank
+ push af ; save vram bank
+ ld a, $0 ; vram bank 0
+ ld [$ff4f], a ; vram bank
+
+; take care of tile animation queue
+ call DoTileAnimation
+
+; restore affected banks
+ pop af
+ ld [$ff4f], a ; vram bank
+ pop af
+ ld [$ff70], a ; wram bank
+ pop af
+ rst Bankswitch ; bankswitch
+ ret
+; 17ff
+
+INCBIN "baserom.gbc",$17ff,$185d - $17ff
+
GetTileType: ; 185d
; checks the properties of a tile
; input: a = tile id
@@ -1099,8 +2820,178 @@
ret
; 1875
-INCBIN "baserom.gbc",$1875,$261f - $1875
+INCBIN "baserom.gbc",$1875,$2063 - $1875
+AskSerial: ; 2063
+; send out a handshake while serial int is off
+ ld a, [$c2d4]
+ bit 0, a
+ ret z
+
+ ld a, [$c2d5]
+ and a
+ ret nz
+
+; once every 6 frames
+ ld hl, $ca8a
+ inc [hl]
+ ld a, [hl]
+ cp 6
+ ret c
+
+ xor a
+ ld [hl], a
+
+ ld a, $c
+ ld [$c2d5], a
+
+; handshake
+ ld a, $88
+ ld [$ff01], a
+
+; switch to internal clock
+ ld a, %00000001
+ ld [$ff02], a
+
+; start transfer
+ ld a, %10000001
+ ld [$ff02], a
+
+ ret
+; 208a
+
+INCBIN "baserom.gbc",$208a,$209e - $208a
+
+GameTimer: ; 209e
+; precautionary
+ nop
+
+; save wram bank
+ ld a, [$ff70] ; wram bank
+ push af
+
+ ld a, $1
+ ld [$ff70], a ; wram bank
+
+ call UpdateGameTimer
+
+; restore wram bank
+ pop af
+ ld [$ff70], a ; wram bank
+ ret
+; 20ad
+
+
+UpdateGameTimer: ; 20ad
+; increment the game timer by one frame
+; capped at 999:59:59.00 after exactly 1000 hours
+
+; pause game update?
+ ld a, [$c2cd]
+ and a
+ ret nz
+
+; game timer paused?
+ ld hl, GameTimerPause
+ bit 0, [hl]
+ ret z
+
+; reached cap? (999:00:00.00)
+ ld hl, GameTimeCap
+ bit 0, [hl]
+ ret nz
+
+; increment frame counter
+ ld hl, GameTimeFrames ; frame counter
+ ld a, [hl]
+ inc a
+
+; reached 1 second?
+ cp 60 ; frames/second
+ jr nc, .second ; 20c5 $2
+
+; update frame counter
+ ld [hl], a
+ ret
+
+.second
+; reset frame counter
+ xor a
+ ld [hl], a
+
+; increment second counter
+ ld hl, GameTimeSeconds
+ ld a, [hl]
+ inc a
+
+; reached 1 minute?
+ cp 60 ; seconds/minute
+ jr nc, .minute
+
+; update second counter
+ ld [hl], a
+ ret
+
+.minute
+; reset second counter
+ xor a
+ ld [hl], a
+
+; increment minute counter
+ ld hl, GameTimeMinutes
+ ld a, [hl]
+ inc a
+
+; reached 1 hour?
+ cp 60 ; minutes/hour
+ jr nc, .hour
+
+; update minute counter
+ ld [hl], a
+ ret
+
+.hour
+; reset minute counter
+ xor a
+ ld [hl], a
+
+; increment hour counter
+ ld a, [GameTimeHours]
+ ld h, a
+ ld a, [GameTimeHours+1]
+ ld l, a
+ inc hl
+
+; reached 1000 hours?
+ ld a, h
+ cp $3 ; 1000 / $100
+ jr c, .updatehr
+
+ ld a, l
+ cp $e8 ; 1000 & $ff
+ jr c, .updatehr
+
+; cap at 999:59:59.00
+ ld hl, GameTimeCap
+ set 0, [hl] ; stop timer
+
+ ld a, 59
+ ld [GameTimeMinutes], a
+ ld [GameTimeSeconds], a
+
+; this will never be run again
+ ret
+
+.updatehr
+ ld a, h
+ ld [GameTimeHours], a
+ ld a, l
+ ld [GameTimeHours+1], a
+ ret
+; 210f
+
+INCBIN "baserom.gbc",$210f,$261f - $210f
+
PushScriptPointer: ; 261f
; used to call a script from asm
; input:
@@ -1496,8 +3387,12 @@
ret
; 2fec
-INCBIN "baserom.gbc",$2fec,$300b-$2fec
+JpHl: ; 2fec
+ jp [hl]
+; 2fed
+INCBIN "baserom.gbc",$2fed,$300b-$2fed
+
ClearSprites: ; 300b
ld hl, Sprites
ld b, TileMap - Sprites
@@ -2399,7 +4294,7 @@
ret
; 3e32
-INCBIN "baserom.gbc",$3e32,$4000 - $3e32
+INCBIN "baserom.gbc",$3e32,$3fb5 - $3e32
SECTION "bank1",DATA,BANK[$1]
@@ -89885,6 +91780,8 @@
INCBIN "baserom.gbc",$FBCCF,$fc000-$fbccf
SECTION "bank3F",DATA,BANK[$3F]
+
+DoTileAnimation:
INCBIN "baserom.gbc",$FC000,$fcdc2-$fc000