pokecrystal-board/engine/gfx/dma_transfer.asm
2024-02-11 00:16:00 +01:00

529 lines
8.2 KiB
NASM

HDMATransferTilemapToWRAMBank3::
ld hl, .Function
jp CallInSafeGFXMode
.Function:
decoord 0, 0
ld hl, wScratchTilemap
call PadTilemapForHDMATransfer
ld a, $0
ldh [rVBK], a
ld hl, wScratchTilemap
call HDMATransferToWRAMBank3
ret
HDMATransferAttrmapToWRAMBank3:
ld hl, .Function
jp CallInSafeGFXMode
.Function:
decoord 0, 0, wAttrmap
ld hl, wScratchAttrmap
call PadAttrmapForHDMATransfer
ld a, $1
ldh [rVBK], a
ld hl, wScratchAttrmap
call HDMATransferToWRAMBank3
ret
HDMATransferTilemapAndAttrmap_Overworld::
ld hl, .Function
jp CallInSafeGFXMode
.Function:
; Pad BG attrs with $00
; Pad BG tiles with " "
decoord 0, 0, wAttrmap
ld hl, wScratchAttrmap
call PadAttrmapForHDMATransfer
decoord 0, 0
ld hl, wScratchTilemap
call PadTilemapForHDMATransfer
call DelayFrame
ldh a, [hWindowHUDLY]
and a
jr z, .go
; wait until LCD interrupt has ocurred this frame ([rLY] - [hWindowHUDLY] >= 0)
.wait_lcd
; ldh a, [hWindowHUDLY]
ld b, a
ldh a, [rLY]
sub b
jr c, .wait_lcd
.go
; Transfer Attrmap and Tilemap to BG map
di
ldh a, [rVBK]
push af
ld a, $1
ldh [rVBK], a
ld hl, wScratchAttrmap
call HDMATransfer_WaitForScanline128_toBGMap
ld a, $0
ldh [rVBK], a
ld hl, wScratchTilemap
call HDMATransfer_WaitForScanline128_toBGMap
pop af
ldh [rVBK], a
ei
ret
_HDMATransferTilemapAndAttrmap_Menu::
ld hl, .Function
jp CallInSafeGFXMode
.Function:
; Pad BG attrs with $00
; Pad BG tiles with " "
decoord 0, 0, wAttrmap
ld hl, wScratchAttrmap
call PadAttrmapForHDMATransfer
decoord 0, 0
ld hl, wScratchTilemap
call PadTilemapForHDMATransfer
call DelayFrame
ldh a, [hWindowHUDLY]
and a
jr z, .go
; wait until LCD interrupt has ocurred this frame ([rLY] - [hWindowHUDLY] >= 0)
.wait_lcd
; ldh a, [hWindowHUDLY]
ld b, a
ldh a, [rLY]
sub b
jr c, .wait_lcd
.go
; Transfer Attrmap and Tilemap to BG map
di
ldh a, [rVBK]
push af
ld a, $1
ldh [rVBK], a
ld hl, wScratchAttrmap
call HDMATransfer_WaitForScanline124_toBGMap
ld a, $0
ldh [rVBK], a
ld hl, wScratchTilemap
call HDMATransfer_WaitForScanline124_toBGMap
pop af
ldh [rVBK], a
ei
ret
CallInSafeGFXMode:
ldh a, [hBGMapMode]
push af
ldh a, [hMapAnims]
push af
xor a
ldh [hBGMapMode], a
ldh [hMapAnims], a
ldh a, [rSVBK]
push af
ld a, BANK(wScratchTilemap)
ldh [rSVBK], a
ldh a, [rVBK]
push af
call ._hl_
pop af
ldh [rVBK], a
pop af
ldh [rSVBK], a
pop af
ldh [hMapAnims], a
pop af
ldh [hBGMapMode], a
ret
._hl_
jp hl
HDMATransferToWRAMBank3:
call _LoadHDMAParameters
ld a, $23
ldh [hDMATransfer], a
WaitDMATransfer:
.loop
call DelayFrame
ldh a, [hDMATransfer]
and a
jr nz, .loop
ret
HDMATransfer_WaitForScanline128_toBGMap:
; HDMA transfer from hl to [hBGMapAddress]
; hBGMapAddress -> de
; 2 * SCREEN_HEIGHT -> c
ldh a, [hBGMapAddress + 1]
ld d, a
ldh a, [hBGMapAddress]
ld e, a
ld c, 2 * SCREEN_HEIGHT
jr HDMATransfer_WaitForScanline128
HDMATransfer_WaitForScanline124_toBGMap:
; HDMA transfer from hl to [hBGMapAddress]
; hBGMapAddress -> de
; 2 * SCREEN_HEIGHT -> c
; $7b --> b
ldh a, [hBGMapAddress + 1]
ld d, a
ldh a, [hBGMapAddress]
ld e, a
ld c, 2 * SCREEN_HEIGHT
jr HDMATransfer_WaitForScanline124
HDMATransfer_NoDI:
; HDMA transfer from hl to [hBGMapAddress]
; [hBGMapAddress] --> de
; 2 * SCREEN_HEIGHT --> c
ldh a, [hBGMapAddress + 1]
ld d, a
ldh a, [hBGMapAddress]
ld e, a
ld c, 2 * SCREEN_HEIGHT
; [rHDMA1, rHDMA2] = hl & $fff0
ld a, h
ldh [rHDMA1], a
ld a, l
and $f0
ldh [rHDMA2], a
; [rHDMA3, rHDMA4] = de & $1ff0
ld a, d
and $1f
ldh [rHDMA3], a
ld a, e
and $f0
ldh [rHDMA4], a
; b = c | %10000000
ld a, c
dec c
or $80
ld b, a
; d = $7f - c + 1
ld a, $7f
sub c
ld d, a
; while [rLY] >= d: pass
.loop1
ldh a, [rLY]
cp d
jr nc, .loop1
; while not [rSTAT] & 3: pass
.loop2
ldh a, [rSTAT]
and rSTAT_STATUS_FLAGS
jr z, .loop2
; load the 5th byte of HDMA
ld a, b
ldh [rHDMA5], a
; wait until rLY advances (c + 1) times
ldh a, [rLY]
inc c
ld hl, rLY
.loop3
cp [hl]
jr z, .loop3
ld a, [hl]
dec c
jr nz, .loop3
ld hl, rHDMA5
res 7, [hl]
ret
HDMATransfer_WaitForScanline124:
ld b, 124 - 1
jr _continue_HDMATransfer
HDMATransfer_WaitForScanline128:
ld b, 128 - 1
_continue_HDMATransfer:
; a lot of waiting around for hardware registers
; [rHDMA1, rHDMA2] = hl & $fff0
ld a, h
ldh [rHDMA1], a
ld a, l
and $f0 ; high nybble
ldh [rHDMA2], a
; [rHDMA3, rHDMA4] = de & $1ff0
ld a, d
and $1f ; lower 5 bits
ldh [rHDMA3], a
ld a, e
and $f0 ; high nybble
ldh [rHDMA4], a
; e = c | %10000000
ld a, c
dec c
or $80
ld e, a
; d = b - c + 1
ld a, b
sub c
ld d, a
; while [rLY] >= d: pass
.ly_loop
ldh a, [rLY]
cp d
jr nc, .ly_loop
ldh a, [hWindowHUDLY]
and a
jr z, .go
; wait until LCD interrupt has ocurred this frame ([rLY] - [hWindowHUDLY] >= 0)
.wait_lcd
; ldh a, [hWindowHUDLY]
ld b, a
ldh a, [rLY]
sub b
jr c, .wait_lcd
.go
di
; while [rSTAT] & 3: pass
.rstat_loop_1
ldh a, [rSTAT]
and rSTAT_STATUS_FLAGS
jr nz, .rstat_loop_1
; while not [rSTAT] & 3: pass
.rstat_loop_2
ldh a, [rSTAT]
and rSTAT_STATUS_FLAGS
jr z, .rstat_loop_2
; load the 5th byte of HDMA
ld a, e
ldh [rHDMA5], a
; wait until rLY advances (c + 1) times
ldh a, [rLY]
inc c
ld hl, rLY
.final_ly_loop
cp [hl]
jr z, .final_ly_loop
ld a, [hl]
dec c
jr nz, .final_ly_loop
ld hl, rHDMA5
res 7, [hl]
ei
ret
_LoadHDMAParameters:
ld a, h
ldh [rHDMA1], a
ld a, l
ldh [rHDMA2], a
ldh a, [hBGMapAddress + 1]
and $1f
ldh [rHDMA3], a
ldh a, [hBGMapAddress]
ldh [rHDMA4], a
ret
PadTilemapForHDMATransfer:
ld c, " "
jr PadMapForHDMATransfer
PadAttrmapForHDMATransfer:
ld c, $0
PadMapForHDMATransfer:
; pad a 20x18 map to 32x18 for HDMA transfer
; back up the padding value in c to hMapObjectIndex
ldh a, [hMapObjectIndex]
push af
ld a, c
ldh [hMapObjectIndex], a
; for each row on the screen
ld c, SCREEN_HEIGHT
.loop1
; for each tile in the row
ld b, SCREEN_WIDTH
.loop2
; copy from de to hl
ld a, [de]
inc de
ld [hli], a
dec b
jr nz, .loop2
; load the original padding value of c into hl for 32 - 20 = 12 rows
ldh a, [hMapObjectIndex]
ld b, BG_MAP_WIDTH - SCREEN_WIDTH
.loop3
ld [hli], a
dec b
jr nz, .loop3
dec c
jr nz, .loop1
; restore the original value of hMapObjectIndex
pop af
ldh [hMapObjectIndex], a
ret
HDMATransfer2bpp::
; 2bpp when [rLCDC] & $80
; switch to WRAM bank 6
ldh a, [rSVBK]
push af
ld a, BANK(wScratchTilemap)
ldh [rSVBK], a
push bc
push hl
; Copy c tiles of the 2bpp from b:de to wScratchTilemap
ld a, b ; bank
ld l, c ; number of tiles
ld h, $0
; multiply by 16 (16 bytes of a 2bpp = 8 x 8 tile)
add hl, hl
add hl, hl
add hl, hl
add hl, hl
ld b, h
ld c, l
ld h, d ; address
ld l, e
ld de, wScratchTilemap
call FarCopyBytes
pop hl
pop bc
push bc
call DelayFrame
pop bc
ld d, h
ld e, l
ld hl, wScratchTilemap
call HDMATransfer_WaitForScanline128
; restore the previous bank
pop af
ldh [rSVBK], a
ret
HDMATransfer1bpp::
; 1bpp when [rLCDC] & $80
.loop
ld a, c
cp $10
jp c, .bankswitch
jp z, .bankswitch
push bc
push hl
push de
ld c, $10
call .bankswitch
pop de
ld hl, $80
add hl, de
ld d, h
ld e, l
pop hl
lb bc, 1, 0
add hl, bc
pop bc
ld a, c
sub $10
ld c, a
jr .loop
.bankswitch
ldh a, [rSVBK]
push af
ld a, BANK(wScratchTilemap)
ldh [rSVBK], a
push bc
push hl
ld a, b
ld l, c
ld h, $0
add hl, hl ; multiply by 8
add hl, hl ; multiply by 8
add hl, hl ; multiply by 8
ld c, l
ld b, h
ld h, d
ld l, e
ld de, wScratchTilemap
call FarCopyBytesDouble_DoubleBankSwitch
pop hl
pop bc
push bc
call DelayFrame
pop bc
ld d, h
ld e, l
ld hl, wScratchTilemap
call HDMATransfer_WaitForScanline128
pop af
ldh [rSVBK], a
ret
HDMATransfer_OnlyTopFourRows:
ld hl, .Function
jp CallInSafeGFXMode
.Function:
ld hl, wScratchTilemap
decoord 0, 0
call .Copy
ld hl, wScratchTilemap + $80
decoord 0, 0, wAttrmap
call .Copy
ld a, $1
ldh [rVBK], a
ld c, $8
ld hl, wScratchTilemap + $80
debgcoord 0, 0, vBGMap1
call HDMATransfer_WaitForScanline128
ld a, $0
ldh [rVBK], a
ld c, $8
ld hl, wScratchTilemap
debgcoord 0, 0, vBGMap1
call HDMATransfer_WaitForScanline128
ret
.Copy:
ld b, 4
.outer_loop
ld c, SCREEN_WIDTH
.inner_loop
ld a, [de]
ld [hli], a
inc de
dec c
jr nz, .inner_loop
ld a, l
add BG_MAP_WIDTH - SCREEN_WIDTH
ld l, a
ld a, h
adc 0
ld h, a
dec b
jr nz, .outer_loop
ret