gb-tarot/CopyTilesSafe.inc

213 lines
5.1 KiB
PHP
Raw Normal View History

CopyTilesSafe:
2025-01-07 11:34:53 -05:00
; hl is source
; de is destination
; bc is length to copy
; copy an array of bytes to the bgmap in vram.
; this is the safe-copy analogue of CopyTilesToMap
; stash arguments in memory
di
ld a, l
ldh [vSafeCopySource], a
ld a, h
ldh [vSafeCopySource+1], a
ld a, e
ldh [vSafeCopyDest], a
ld a, d
ldh [vSafeCopyDest+1], a
ld a, c
ldh [vSafeCopyCount], a
ldh [vSafeCopyOriginalCount], a
ld a, b
ldh [vSafeCopyCount+1], a
ldh [vSafeCopyOriginalCount+1], a
; stash interrupt state in memory
ldh a, [$ff41]
ldh [vSafeCopySTAT], a ; stashes $FF41, the STAT register
ldh a, [$ff45]
ldh [vSafeCopyLYC], a ; stashes $FF45, the LYC register
ld a, [INTERRUPT_LCD]
ld [vSafeCopyInterruptFirst], a
ld a, [INTERRUPT_LCD + 1]
ld [vSafeCopyInterruptSecond], a ; stashes the current STAT interrupt handler
ld a, [$ffff]
and a, %0000_0010
ld [vSafeCopyInterruptEnable], a ; stashes whether LCD interrupt are enabled
ld hl, CopyTilesSafe_EnterSafeMode
ld a, l
ld [INTERRUPT_LCD], a
ld a, h
ld [INTERRUPT_LCD + 1], a; set interrupt handler to "ENTER SAFE MODE"
ld a, 148 ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING
ld [$ff45], a
ld hl, $ffff
set 1, [hl]
ld a, %0100_0000
ld [$ff41], a
ld hl, vSafeCopyCount
ld a, 0
ld [$ff0f], a
ei
ret ; return address of bytes remaining to copy
CopyTilesSafe_EnterSafeMode:
push hl ; stash registers! we just took over as an interrupt!
push bc
push de
push af
ld hl, CopyTilesSafe_ExitSafeMode
ld a, l
ld [INTERRUPT_LCD], a
ld a, h
ld [INTERRUPT_LCD+1], a
ld a, 153 ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING
ld [$ff45], a ; set lcd interrupt handler to EXIT SAFE MODE on line 153
ldh a, [vSafeCopySource]
ld l, a
ldh a, [vSafeCopySource+1]
ld h, a ; fetch the source
ldh a, [vSafeCopyDest]
ld e, a
ldh a, [vSafeCopyDest+1]
ld d, a ; fetch the dest
ldh a, [vSafeCopyCount]
ld c, a
ldh a, [vSafeCopyCount+1]
ld b, a ; fetch the count
; before starting transfer, make sure the zero flag is false.
ld a, 1
cp a, 0
CopyTilesSafe_TransferLoop:
ei
nop ; ei only sets the flag one instruction later apparently. safety nop!
nop ; we're processing interrupts here
di
jp z, CopyTilesSafe_CleanUp ; zero flag will only be set if the exit handler fired
ld a, [hl] ; load from the tile map into a
ld [de], a ; load from a into the destination
inc hl ; this is slower than using hli but i'm trying to work with this here
inc de
dec c
; check if we've completed a line?
ld a, 0
or a, c ; check if c is zero, if it's not zero go back and copy more bytes
jp nz, CopyTilesSafe_TransferLoop
CopyTilesSafe_DoneWithLine:
ldh a, [vSafeCopyOriginalCount]
ld c, a
ldh a, [vSafeCopyOriginalCount+1]
ld b, a
ld a, e
add a, 32
ld e, a
ld a, d
adc a, 0
ld d, a
ld a, e
sub a, c
ld e, a
ld a, d
sbc a, 0
ld d, a
dec b
ld a, b
cp a, 0
ldh [vSafeCopyOriginalCount+1], a ; store the decremented line count
jp nz, CopyTilesSafe_TransferLoop
jp CopyTilesSafe_Done
CopyTilesSafe_ExitSafeMode:
ld a, 0
cp a, 0 ; set the zero flag, which we're using as a signal to stop transferring
reti ; set a to zero and set the zero flag true. now the transfer loop will end
CopyTilesSafe_CleanUp:
ld a, l
ldh [vSafeCopySource], a
ld a, h
ldh [vSafeCopySource+1], a ; store new source
ld a, e
ldh [vSafeCopyDest], a
ld a, d
ldh [vSafeCopyDest+1], a ; store new dest
ld a, c
ldh [vSafeCopyCount], a
ld a, b
ldh [vSafeCopyCount+1], a ; store new count
ld hl, CopyTilesSafe_EnterSafeMode
ld a, l
ld [INTERRUPT_LCD], a
ld a, h
ld [INTERRUPT_LCD+1], a
ld a, 148 ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING
ld [$ff45], a ; set lcd interrupt handler to ENTER SAFE MODE on line 148
pop af
pop de
pop bc
pop hl
reti ; we're done with this memcpy cycle so we return from interrupt.
CopyTilesSafe_Done: ; called when the complete transfer is finished,
; this restores interrupts to how they were.
; stash interrupt state in memory
ld a, l
ldh [vSafeCopySource], a
ld a, h
ldh [vSafeCopySource+1], a ; store new source
ld a, e
ldh [vSafeCopyDest], a
ld a, d
ldh [vSafeCopyDest+1], a ; store new dest
ld a, 0
ldh [vSafeCopyCount], a
ld a, 0
ldh [vSafeCopyCount+1], a ; store new count
ld hl, CopyRangeSafe_EnterSafeMode
ld a, l
ld [INTERRUPT_LCD], a
ld a, h
ld [INTERRUPT_LCD+1], a
ld a, 148 ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING
ld [$ff45], a ; set lcd interrupt handler to ENTER SAFE MODE on line 148
pop af
pop de
pop bc
pop hl
ldh a, [vSafeCopySTAT]
ldh [$ff41], a
ldh a, [vSafeCopyLYC]
ldh [$ff45], a
ldh a, [vSafeCopyInterruptFirst]
ld [INTERRUPT_LCD], a
ldh a, [vSafeCopyInterruptSecond]
ldh [INTERRUPT_LCD+1], a
ld hl, $ffff
ld a, [hl]
cpl
set 1, a
cpl ; turn off the lcd interrupt enable
ld [hl], a
ld a, [vSafeCopyInterruptEnable]
cp a, 0 ; check if the stat interrupt was active before we took over
jp z, CopyRangeSafe_Return
set 1, [hl] ; turn on the lcd interrupt
CopyTilesSafe_Return:
reti