2025-01-08 14:03:54 -05:00
|
|
|
; variables for safe transfer async function
|
2025-01-11 12:45:13 -05:00
|
|
|
DEF vSafeCopySource EQU $ff80
|
2025-01-08 14:03:54 -05:00
|
|
|
DEF vSafeCopyDest EQU vSafeCopySource + 2
|
|
|
|
DEF vSafeCopyCount EQU vSafeCopyDest + 2 ; check this for safe transfer being complete
|
|
|
|
DEF vSafeCopyOriginalCount EQU vSafeCopyCount + 2
|
|
|
|
; stash previous interrupt state before using the interrupts
|
|
|
|
DEF vSafeCopyLYC EQU vSafeCopyOriginalCount + 2 ; stashes $FF45, the LYC register
|
|
|
|
DEF vSafeCopySTAT EQU vSafeCopyLYC + 1 ; stashes $FF41, the STAT register
|
|
|
|
DEF vSafeCopyInterrupt EQU vSafeCopySTAT + 1 ; stashes the previous LCD interrupt
|
|
|
|
DEF vSafeCopyInterruptEnable EQU vSafeCopyInterrupt + 2 ; stashes $FFFF, which interrupts are enabled
|
|
|
|
|
|
|
|
|
2025-01-07 13:23:32 -05:00
|
|
|
CopyRangeSafe:
|
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 a destination in memory.
|
|
|
|
; this is completely different from CopyRangeUnsafe.
|
|
|
|
; this initiates an asynchronous, interrupt-driven copy of BC bytes of memory
|
|
|
|
; from HL to DE.
|
|
|
|
; it may return a memory address to look at for progress of the transfer,
|
|
|
|
; or else it's just going to do it with a hard-coded address.
|
|
|
|
; check the transfer status address for zero; when it's zero, the transfer is done!
|
|
|
|
; this works by using the STAT interrupt in LYC mode to interrupt its own execution at
|
|
|
|
; two scanlines inside the vblank interval to know when to start and stop.
|
|
|
|
; 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
|
|
|
|
ld a, b
|
|
|
|
ldh [vSafeCopyCount+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]
|
2025-01-08 14:03:54 -05:00
|
|
|
ld [vSafeCopyInterrupt], a
|
|
|
|
ld a, [INTERRUPT_LCD+1]
|
|
|
|
ld [vSafeCopyInterrupt+1], a ; stashes the current STAT interrupt handler
|
2025-01-07 11:34:53 -05:00
|
|
|
ld a, [$ffff]
|
|
|
|
and a, %0000_0010
|
|
|
|
ld [vSafeCopyInterruptEnable], a ; stashes whether LCD interrupt are enabled
|
|
|
|
|
|
|
|
ld hl, CopyRangeSafe_EnterSafeMode
|
|
|
|
ld a, l
|
|
|
|
ld [INTERRUPT_LCD], a
|
|
|
|
ld a, h
|
|
|
|
ld [INTERRUPT_LCD + 1], a; set interrupt handler to "ENTER SAFE MODE"
|
2025-01-09 15:39:07 -05:00
|
|
|
ld a, 143 ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING
|
2025-01-07 11:34:53 -05:00
|
|
|
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
|
|
|
|
nop
|
|
|
|
nop
|
|
|
|
nop
|
|
|
|
|
|
|
|
|
|
|
|
ei
|
|
|
|
nop
|
|
|
|
nop
|
|
|
|
nop
|
|
|
|
ret ; return address of bytes remaining to copy
|
|
|
|
|
|
|
|
CopyRangeSafe_EnterSafeMode:
|
|
|
|
push hl
|
|
|
|
push bc
|
|
|
|
push de
|
|
|
|
push af
|
|
|
|
ld hl, CopyRangeSafe_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
|
|
|
|
CopyRangeSafe_TransferLoop:
|
|
|
|
ei
|
|
|
|
nop ; ei only sets the flag one instruction later apparently. safety nop!
|
|
|
|
di ; process interrupts
|
|
|
|
jp z, CopyRangeSafe_CleanUp ; zero flag will only be set if the exitsafemode handler fired
|
|
|
|
ld a, [hl+]
|
|
|
|
ld [de], a ;
|
|
|
|
inc de
|
|
|
|
dec bc
|
|
|
|
ld a, b
|
|
|
|
or a, c
|
|
|
|
jp nz, CopyRangeSafe_TransferLoop
|
|
|
|
jp CopyRangeSafe_Done
|
|
|
|
|
|
|
|
CopyRangeSafe_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
|
|
|
|
|
|
|
|
CopyRangeSafe_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, CopyRangeSafe_EnterSafeMode
|
|
|
|
ld a, l
|
|
|
|
ld [INTERRUPT_LCD], a
|
|
|
|
ld a, h
|
|
|
|
ld [INTERRUPT_LCD+1], a
|
2025-01-09 15:39:07 -05:00
|
|
|
ld a, 143 ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING
|
2025-01-07 11:34:53 -05:00
|
|
|
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.
|
|
|
|
|
|
|
|
CopyRangeSafe_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, c
|
|
|
|
ldh [vSafeCopyCount], a
|
|
|
|
ld a, b
|
|
|
|
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
|
2025-01-09 15:39:07 -05:00
|
|
|
ld a, 143 ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING
|
2025-01-07 11:34:53 -05:00
|
|
|
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
|
2025-01-08 14:03:54 -05:00
|
|
|
ldh a, [vSafeCopyInterrupt]
|
2025-01-07 11:34:53 -05:00
|
|
|
ld [INTERRUPT_LCD], a
|
2025-01-08 14:03:54 -05:00
|
|
|
ldh a, [vSafeCopyInterrupt+1]
|
2025-01-11 12:45:13 -05:00
|
|
|
ld [INTERRUPT_LCD+1], a
|
2025-01-07 11:34:53 -05:00
|
|
|
|
|
|
|
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 ; if the stashed enable was 0 return. if the stashed enable was 1 then turn it on
|
|
|
|
jp z, CopyRangeSafe_Return
|
|
|
|
set 1, [hl] ; turn on the lcd interrupt
|
|
|
|
|
|
|
|
CopyRangeSafe_Return:
|
|
|
|
reti
|
2025-01-08 14:03:54 -05:00
|
|
|
|
|
|
|
CopyRangeUnsafe:
|
|
|
|
; hl is source
|
|
|
|
; de is destination
|
|
|
|
; bc is length to copy
|
2025-01-09 15:39:07 -05:00
|
|
|
ld a, [hl+]
|
2025-01-08 14:03:54 -05:00
|
|
|
ld [de], a
|
|
|
|
inc de
|
|
|
|
dec bc
|
|
|
|
ld a, b
|
|
|
|
or a, c ; check if bc is zero
|
|
|
|
jp nz, CopyRangeUnsafe
|
2025-01-11 12:45:13 -05:00
|
|
|
ret
|
|
|
|
|
|
|
|
CopyRangeUnsafeBy8s:
|
|
|
|
; hl is source
|
|
|
|
; de is destination
|
|
|
|
; bc is length to copy
|
|
|
|
|
|
|
|
ld a, [hl+]
|
|
|
|
ld [de], a
|
|
|
|
inc de
|
|
|
|
ld a, [hl+]
|
|
|
|
ld [de], a
|
|
|
|
inc de
|
|
|
|
ld a, [hl+]
|
|
|
|
ld [de], a
|
|
|
|
inc de
|
|
|
|
ld a, [hl+]
|
|
|
|
ld [de], a
|
|
|
|
inc de
|
|
|
|
ld a, [hl+]
|
|
|
|
ld [de], a
|
|
|
|
inc de
|
|
|
|
ld a, [hl+]
|
|
|
|
ld [de], a
|
|
|
|
inc de
|
|
|
|
ld a, [hl+]
|
|
|
|
ld [de], a
|
|
|
|
inc de
|
|
|
|
ld a, [hl+]
|
|
|
|
ld [de], a
|
|
|
|
inc de
|
|
|
|
dec bc
|
|
|
|
ld a, b
|
|
|
|
or a, c ; check if bc is zero
|
|
|
|
jp nz, CopyRangeUnsafeBy8s
|
2025-01-08 14:03:54 -05:00
|
|
|
ret
|