progress on the safe copy routine

This commit is contained in:
Shoofle 2025-01-05 18:33:30 -05:00
parent de58b8f8af
commit 4b100cf2a2

261
tarot.asm
View File

@ -9,11 +9,32 @@ DEF SCENE_SETUP EQU $FF81
DEF SCENE_UPDATE EQU SCENE_SETUP + 4 ; call then ret is 3+1 bytes DEF SCENE_UPDATE EQU SCENE_SETUP + 4 ; call then ret is 3+1 bytes
DEF SCENE_DRAW EQU SCENE_UPDATE + 4 DEF SCENE_DRAW EQU SCENE_UPDATE + 4
DEF SCENE_TEARDOWN EQU SCENE_DRAW + 4 DEF SCENE_TEARDOWN EQU SCENE_DRAW + 4
DEF rMYBTN EQU $FF90 DEF rMYBTN EQU $FFA0
DEF rMYBTNP EQU rMYBTN + 1 DEF rMYBTNP EQU rMYBTN + 1
DEF vSelectedTileIndex EQU $FF90+2
DEF vPreviousCardIndex EQU $FF90+3 DEF INTERRUPT_LCD EQU $FF91
; tile index variables
DEF vSelectedTileIndex EQU $FFA0+2
DEF vPreviousCardIndex EQU $FFA0+3
; variables for safe transfer async function
DEF vSafeCopySource EQU $FFA0+4
DEF vSafeCopyDest EQU vSafeCopySource + 2
DEF vSafeCopyCount EQU vSafeCopyDest + 2 ; check this for safe transfer being complete
; stash previous interrupt state before using the interrupts
DEF vSafeCopyLYC EQU vSafeCopyCount + 2 ; stashes $FF45, the LYC register
DEF vSafeCopySTAT EQU vSafeCopyLYC + 1 ; stashes $FF41, the STAT register
DEF vSafeCopyInterruptFirst EQU vSafeCopySTAT + 1 ; stashes $0048 the STAT interrupt
DEF vSafeCopyInterruptSecond EQU vSafeCopyInterruptFirst + 1
DEF vSafeCopyInterruptEnable EQU vSafeCopyInterruptSecond + 1 ; stashes $FFFF, which interrupts are enabled
INCLUDE "hardware.inc" INCLUDE "hardware.inc"
SECTION "Interrupts", ROM0[$0]
ds $48 - @, 0
call INTERRUPT_LCD - 1
ret
SECTION "Header", ROM0[$100] SECTION "Header", ROM0[$100]
@ -35,6 +56,8 @@ EntryPoint:
ld [hl], a ld [hl], a
ld hl, SCENE_TEARDOWN - 1 ld hl, SCENE_TEARDOWN - 1
ld [hl], a ld [hl], a
ld hl, INTERRUPT_LCD - 1
ld [hl], a
ld a, [Instructions + 3] ; get the value of a ret instruction ld a, [Instructions + 3] ; get the value of a ret instruction
ld hl, SCENE_SETUP + 2 ld hl, SCENE_SETUP + 2
@ -45,6 +68,8 @@ EntryPoint:
ld [hl], a ld [hl], a
ld hl, SCENE_TEARDOWN + 2 ld hl, SCENE_TEARDOWN + 2
ld [hl], a ld [hl], a
ld hl, INTERRUPT_LCD + 2
ld [hl], a
; set up our scene vectors ; set up our scene vectors
ld hl, SCENE_SETUP ld hl, SCENE_SETUP
@ -71,6 +96,14 @@ EntryPoint:
ld [hl+], a ld [hl+], a
ld a, d ld a, d
ld [hl+], a ld [hl+], a
; set up the interrupt vector to just be ret.
ld hl, INTERRUPT_LCD
ld de, INTERRUPT_LCD + 2
ld a, e
ld [hl+], a
ld a, d
ld [hl+], a
; Do not turn the LCD off outside of VBlank ; Do not turn the LCD off outside of VBlank
WaitVBlank: WaitVBlank:
@ -81,6 +114,7 @@ WaitVBlank:
call SCENE_SETUP - 1 call SCENE_SETUP - 1
Loop: Loop:
di
ld hl, rP1 ld hl, rP1
ld [hl], P1F_GET_DPAD ld [hl], P1F_GET_DPAD
ld a, [hl] ld a, [hl]
@ -107,13 +141,15 @@ Loop:
ld a, b ld a, b
ld [rMYBTN], a ld [rMYBTN], a
di
call SCENE_UPDATE - 1 call SCENE_UPDATE - 1
ei
ld b, 144 ld b, 144
call AwaitLine call AwaitLine
di
call SCENE_DRAW - 1 call SCENE_DRAW - 1
ei
jp Loop jp Loop
@ -126,17 +162,17 @@ CardReadSetup:
ld hl, UITiles ; source ld hl, UITiles ; source
ld de, $8800 ; destination of copy ld de, $8800 ; destination of copy
ld bc, UITilesEnd - UITiles ; length to copy ld bc, UITilesEnd - UITiles ; length to copy
call CopyRange call CopyRangeUnsafe
ld hl, LetterTiles ; map the small font into vram at ascii locations ld hl, LetterTiles ; map the small font into vram at ascii locations
ld de, $8000 + (127 + $21)*16 ld de, $8000 + (127 + $21)*16
ld bc, LetterTilesEnd - LetterTiles ld bc, LetterTilesEnd - LetterTiles
call CopyRange call CopyRangeUnsafe
ld hl, BigLetterTiles ld hl, BigLetterTiles
ld de, $8000 + (128 + 16 + 32)*16 ld de, $8000 + (128 + 16 + 32)*16
ld bc, BigLetterTilesEnd - BigLetterTiles ld bc, BigLetterTilesEnd - BigLetterTiles
; call CopyRange ; call CopyRangeUnsafe
ld de, UITilemap ; origin ld de, UITilemap ; origin
ld hl, $9800 ; destination ld hl, $9800 ; destination
@ -150,11 +186,6 @@ CardReadSetup:
ld c, 8 ld c, 8
call CopyTilesToMap call CopyTilesToMap
ld a, $FF
ld [vPreviousCardIndex], a
ld a, 0
call LoadCardData
; Turn the LCD on ; Turn the LCD on
ld a, LCDCF_BLK01 | LCDCF_ON | LCDCF_BGON ld a, LCDCF_BLK01 | LCDCF_ON | LCDCF_BGON
ld [rLCDC], a ld [rLCDC], a
@ -163,43 +194,44 @@ CardReadSetup:
ld a, %11100100 ld a, %11100100
ld [rBGP], a ld [rBGP], a
ld a, $FF
ldh [vPreviousCardIndex], a
ld a, 0 ld a, 0
ldh [vSelectedTileIndex], a ldh [vSelectedTileIndex], a
call LoadCardData
ei
ret ; return from cardreadsetup ret ; return from cardreadsetup
CardReadUpdate: CardReadUpdate:
ldh a, [rMYBTNP] ldh a, [rMYBTNP]
and a, %0000_1000 ; check if down is held and a, %0000_1000 ; select the down key
jp z, CardReadUpdateDoneDown jp z, CardReadUpdateDoneDown
ldh a, [vSelectedTileIndex] ldh a, [vSelectedTileIndex]
inc a ; increment when they press down because the stack has card 0 at the top inc a ; increment when they press down because the stack has card 0 at the top
ldh [vSelectedTileIndex], a ldh [vSelectedTileIndex], a
CardReadUpdateDoneDown: CardReadUpdateDoneDown:
ldh a, [rMYBTNP] ldh a, [rMYBTNP]
and a, %0000_0100 and a, %0000_0100 ; select the up key
jp z, CardReadUpdateDoneUp jp z, CardReadUpdateDoneUp
ldh a, [vSelectedTileIndex] ldh a, [vSelectedTileIndex]
dec a ; decrement when they press up because the stack has card 0 at the top dec a ; decrement when they press up because the stack has card 0 at the top
ldh [vSelectedTileIndex], a ldh [vSelectedTileIndex], a
CardReadUpdateDoneUp: CardReadUpdateDoneUp:
ldh a, [vSelectedTileIndex] ldh a, [vSelectedTileIndex]
cp a, 22 cp a, 2
jp nz, CardReadUpdateDoneZero jp nz, CardReadUpdateDoneZero
ld a, 0 ld a, 0
ldh [vSelectedTileIndex], a ldh [vSelectedTileIndex], a
CardReadUpdateDoneZero: CardReadUpdateDoneZero:
cp a, $FF cp a, $FF
jp nz, CardReadUpdateReturn jp nz, CardReadUpdateReturn
ld a, 21 ld a, 1
ldh [vSelectedTileIndex], a ldh [vSelectedTileIndex], a
CardReadUpdateReturn: CardReadUpdateReturn:
ret ret
CardReadDraw: CardReadDraw:
ldh a, [vSelectedTileIndex] ld b, 1 ; 11 rows, and we stop before drawing row zero
call LoadCardData
ld b, 11 ; 11 rows, and we stop before drawing row zero
ld hl, $9800+32*4+19 ; start point ld hl, $9800+32*4+19 ; start point
ld de, 32 ; stride ld de, 32 ; stride
CardReadDrawCopyTile: CardReadDrawCopyTile:
@ -240,33 +272,23 @@ CardReadDraw_PickTileWithTop:
ld a, $82 ld a, $82
ld [hl], a ld [hl], a
CardReadDrawReturn: CardReadDrawReturn:
ld a, [vSelectedTileIndex] ldh a, [vSelectedTileIndex]
call LoadCardData ld hl, vPreviousCardIndex
cp a, [hl]
call nz, LoadCardData ; only load new card data if the selected card has changed
ret ret
CardReadTeardown: CardReadTeardown:
ret ret
LoadCardData: LoadCardData:
ld hl, vPreviousCardIndex ld a, [vSelectedTileIndex]
cp a, [hl]
ret z
ld [vPreviousCardIndex], a ld [vPreviousCardIndex], a
ld [vSelectedTileIndex], a
ld a, [rLCDC]
cp 0
jp z, LoadCardData_DoneTurningOff
ld b, 144 ld b, 144
call AwaitLine ; put the line you want to reach in b call AwaitLine ; wait for vblank before starting to work
ld a, 0
ld [rLCDC], a ; turn off the lcd so we don't cause memory corruption
LoadCardData_DoneTurningOff: LoadCardData_DoneTurningOff:
ld a, [vSelectedTileIndex] ld a, [vSelectedTileIndex]
ld b, 0 ld b, 0
ld c, a ; load bc from a. coming into this we have the number of the card in the card array in a ld c, a ; load bc from a. coming into this we have the number of the card in the card array in a
ld hl, Cards + 1 ; skip the length prefix ld hl, Cards + 1 ; skip the length prefix
@ -316,7 +338,7 @@ LoadCardData_DoneTurningOff:
ld de, $8000 ; always load tile data into the same spot in vram ld de, $8000 ; always load tile data into the same spot in vram
call CopyRange call CopyRangeSafe
pop hl pop hl
ld a, [hl+] ld a, [hl+]
@ -337,8 +359,7 @@ LoadCardData_DoneTurningOff:
ld c, 8 ; width ld c, 8 ; width
call CopyTilesToMap call CopyTilesToMap
ld a, LCDCF_BLK01 | LCDCF_ON | LCDCF_BGON ret
ld [rLCDC], a
Instructions: Instructions:
@ -368,7 +389,7 @@ AwaitLine: ; put the line you want to reach in b
jp nz, AwaitLine jp nz, AwaitLine
ret ret
CopyRange: CopyRangeUnsafe:
; hl is source ; hl is source
; de is destination ; de is destination
; bc is length to copy ; bc is length to copy
@ -378,7 +399,161 @@ CopyRange:
dec bc dec bc
ld a, b ld a, b
or a, c ; check if bc is zero or a, c ; check if bc is zero
jp nz, CopyRange jp nz, CopyRangeUnsafe
ret
CopyRangeSafe:
; 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]
ld [vSafeCopyInterruptFirst], a
ld a, [INTERRUPT_LCD + 1]
ld [vSafeCopyInterruptSecond], a ; stashes $0048 the STAT interrupt handler
ld a, [$ffff]
and a, %0000_0010
ld [vSafeCopyInterruptEnable], a ; stashes whether LCD interrupt are enabled
ld a, 148 ; adjust this to change timing of copy
ld [$ff45], a
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"
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
ei
ret ; return address of bytes remaining to copy
CopyRangeSafe_EnterSafeMode:
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!
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
ld a, 148 ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING
ld [$ff45], a ; set lcd interrupt handler to ENTER SAFE MODE on line 148
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
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 ; 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:
ret ret
CopyTilesToMap: CopyTilesToMap:
@ -438,7 +613,7 @@ TheFool:
dw FoolTilesEnd - FoolTiles dw FoolTilesEnd - FoolTiles
dw FoolTiles dw FoolTiles
dw FoolMapEnd - FoolMap dw FoolMapEnd - FoolMap
dw FoolMap, FoolMapEnd dw FoolMap
FoolTiles: FoolTiles:
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$01,$00,$01,$00,$02 db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$01,$00,$01,$00,$02