From 97432b1c2ba4f4c360fd21035b63e45fa5397b64 Mon Sep 17 00:00:00 2001 From: shoofle Date: Mon, 13 Jan 2025 15:44:01 -0500 Subject: [PATCH] async subsystem :) --- 00TheFool.inc | 1 + Async.inc | 260 ++++++++++++++++++++++++ CardLibrary.inc | 18 +- CopyRangeSafe.inc | 12 +- CopyTilesSafe.inc | 60 +++++- ScreenCardRead.inc | 120 +---------- ScreenMainMenu.inc | 7 +- ScreenSpreadSelect.inc | 447 +++++++++++++++++++++++++++++++++++++++++ main.asm | 34 +++- 9 files changed, 824 insertions(+), 135 deletions(-) create mode 100644 Async.inc diff --git a/00TheFool.inc b/00TheFool.inc index 862d833..d9c9a57 100644 --- a/00TheFool.inc +++ b/00TheFool.inc @@ -14,6 +14,7 @@ TheFool: dw FoolMap dw FoolTilesEnd - FoolTiles dw 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,$01,$00,$01,$00,$02 diff --git a/Async.inc b/Async.inc new file mode 100644 index 0000000..8c0f898 --- /dev/null +++ b/Async.inc @@ -0,0 +1,260 @@ +def vAsyncAF equ $ff80 +def vAsyncHL EQU $ff82 +def vAsyncDE EQU $ff84 +def vAsyncBC equ $ff86 +def vAsyncPC equ $ff88 +def vAsyncNext equ $ff8a +def vAsyncAfter equ $ff8c + +def SAFE_ASYNC_START EQU 144 +def SAFE_ASYNC_END EQU 151 + +DoInAsyncVBlank: + di + push af + + ld a, l + ldh [vAsyncHL], a + ld a, h + ldh [vAsyncHL+1], a + ld a, e + ldh [vAsyncDE], a + ld a, d + ldh [vAsyncDE+1], a + ld a, c + ldh [vAsyncBC], a + ld a, b + ldh [vAsyncBC+1], a + + pop hl + ld a, l + ldh [vAsyncAF], a + ld a, h + ldh [vAsyncAF+1], a + + ; set pu the next call! + ldh a, [vAsyncNext] + ldh [vAsyncPC], a + ldh a, [vAsyncNext+1] + ldh [vAsyncPC+1], a ; put next into pc + ldh a, [vAsyncAfter] + ldh [vAsyncNext], a + ldh a, [vAsyncAfter+1] + ldh [vAsyncNext+1], a ; puut after into next + ld a, 0 + ldh [vAsyncAfter], a ; unless this gets overwritten later, end execution after that + ldh [vAsyncAfter+1], a + + ld a, LOW(DoInAsyncVBlank_EnterThread) + ld [INTERRUPT_LCD], a + ld a, HIGH(DoInAsyncVBlank_EnterThread) + ld [INTERRUPT_LCD + 1], a; set interrupt handler to "ENTER THREAD" + ld a, SAFE_ASYNC_START ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING + ld [rLYC], a ; set LYC + ld hl, rIE + set 1, [hl] ; enable vblank + ld hl, rSTAT + set 6, [hl] ; set the stat interrupt to LYC mode + ld hl, rIF + res 1, [hl] ; clear the interrupt so we don't immediately fire it + ei + + ret + +DoInAsyncVBlank_EnterThread: + ;stack looks like: + ;c113 (SMC int @ LYC 90 pc), 004b (hw int @ LYC 90 pc), outer context pc + + push hl + push bc + push de + push af + + ;af, de, bc, hl, c113 (SMC interrupt pc), 004b (hardwired interrput pc), outer context pc + + ; check if there's anything queued up for next execution + ldh a, [vAsyncPC] + ld l, a + ldh a, [vAsyncPC+1] + ld h, a + or a, l + jp z, DoInAsyncVBlank_EndThread ; if nothing is queued up, jump to cleanup + + ld a, LOW(DoInAsyncVBlank_ExitThread) + ld [INTERRUPT_LCD], a + ld a, HIGH(DoInAsyncVBlank_ExitThread) + ld [INTERRUPT_LCD+1], a + ld a, SAFE_ASYNC_END ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING + ld [rLYC], a ; set lcd interrupt handler to EXIT SAFE MODE on line 153 + + ; what if our async thread calls return? + ; we need to have a PC to return to. if that happens, we will want to + ; reti. + ld hl, DoInAsyncVBlank_EarlyReturn + push hl ; address for if the thread retrns + + ldh a, [vAsyncPC] + ld l, a + ldh a, [vAsyncPC+1] + ld h, a + push hl ; put vAsyncPC on the stack! for jumping to it! + ; stack looks like: vasyncpc, early return, af, de, bc, hll, SMC interrput pc, hardwired interrupt pc, outer context pc + + ldh a, [vAsyncAF] + ld l, a + ldh a, [vAsyncAF+1] + ld h, a + push hl + + ldh a, [vAsyncHL] + ld l, a + ldh a, [vAsyncHL+1] + ld h, a + ldh a, [vAsyncDE] + ld e, a + ldh a, [vAsyncDE+1] + ld d, a + ldh a, [vAsyncBC] + ld c, a + ldh a, [vAsyncBC+1] + ld b, a + + pop af; putting vAsyncAF into af requires this hoop-jumping + + ei + ret ; "return" to the vAsyncPC wee put on the stack previously. + ; this is more or less a jump, not a return. + ; is that the source of our problems? + ; after this instruction executes, stack looks like: + ; early return, af, de, bc, hl, PC (smc int), PC (hardwired int), PC (outer context) + ; and we'll be in the async thread, executing + +DoInAsyncVBlank_EarlyReturn: + ; stack: + ; af, de, bc, hl, PC (smc int @ LYC90), PC (hw int @ LYC 90), PC (outer context) + PRINTln "early return handle is ", DoInAsyncVBlank_EarlyReturn + ; save state of registers + di + push af + + ld a, l + ldh [vAsyncHL], a + ld a, h + ldh [vAsyncHL+1], a + ld a, e + ldh [vAsyncDE], a + ld a, d + ldh [vAsyncDE+1], a + ld a, c + ldh [vAsyncBC], a + ld a, b + ldh [vAsyncBC+1], a + + pop hl + ld a, l + ldh [vAsyncAF], a + ld a, h + ldh [vAsyncAF+1], a + + + + ; set pu the next call! + ldh a, [vAsyncNext] + ldh [vAsyncPC], a + ldh a, [vAsyncNext+1] + ldh [vAsyncPC+1], a ; put next into pc + ldh a, [vAsyncAfter] + ldh [vAsyncNext], a + ldh a, [vAsyncAfter+1] + ldh [vAsyncNext+1], a ; puut after into next + ld a, 0 + ldh [vAsyncAfter], a ; unless this gets overwritten later, end execution after that + ldh [vAsyncAfter+1], a + + ld a, LOW(DoInAsyncVBlank_EnterThread) ; set up next call + ld [INTERRUPT_LCD], a + ld a, HIGH(DoInAsyncVBlank_EnterThread) + ld [INTERRUPT_LCD+1], a + ld a, SAFE_ASYNC_START + ld [rLYC], a + + ; restore the pre-interrupt registers, return and enable interrupts + pop af + pop de + pop bc + pop hl + reti + +DoInAsyncVBlank_EndThread: + ; end execution of the thread by disabling the interrupt + ; and restore the state for the outer thread + ld hl, rIE + res 1, [hl] ; disable STAT/vblank interrupt + pop af + pop de + pop bc + pop hl + reti + +DoInAsyncVBlank_ExitThread: + ; at this point, it's an interrpt being called from inside the interrupt + ; our stack probably looks like this: + ; PC (smc int), PC (hardwired int), PC (inside thread), early return, af, de, bc, hl, PC (smc int), PC (hardwired int), PC (outer context) + ; first, save the interrpt thread registers. + push af + + ld a, l + ldh [vAsyncHL], a + ld a, h + ldh [vAsyncHL+1], a + ld a, e + ldh [vAsyncDE], a + ld a, d + ldh [vAsyncDE+1], a + ld a, c + ldh [vAsyncBC], a + ld a, b + ldh [vAsyncBC+1], a + + pop hl + ld a, l + ldh [vAsyncAF], a + ld a, h + ldh [vAsyncAF+1], a + + ;god i'm such a genius + ; this was called as an interrupt inside the interrupt + ;so our stack looks like this: + ; PC (smc int), PC (hardwired int), PC (inside thread), early return, af, de, bc, hl, PC (smc int), PC (hardwired int), PC (outer context) + ; we've got the two PCs from the inner interrupt call stack. + ; get rid of them! we're running without handrails! i know what i'm doing! I hope! + pop hl + pop hl + ; now, save the interrupt thread's pc., which is on the stack from this + ; interrupt being called. + pop hl + ld a, l + ldh [vAsyncPC], a + ld a, h + ldh [vAsyncPC+1], a + ; now we are done with this entire execution of thread. now we need to set up + ; the next execution of this thread. + ld a, LOW(DoInAsyncVBlank_EnterThread) + ld [INTERRUPT_LCD], a + ld a, HIGH(DoInAsyncVBlank_EnterThread) + ld [INTERRUPT_LCD+1], a + ld a, SAFE_ASYNC_START ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING + ld [rLYC], a ; set lcd interrupt handler to EXIT SAFE MODE on line 153 + + ;at present the stack looks like: + ; early return, af, de, bc, hl, pc (smc int @ LYC 90), pc (hardwired int at LYC 90), PC (outer context) + ; pop the early return and discard it. + pop hl + ; and finally, we can restore the state of the registers to what they were + ; before this whole handler got called. + pop af + pop de + pop bc + pop hl + reti ; this is a proper return + \ No newline at end of file diff --git a/CardLibrary.inc b/CardLibrary.inc index 2d3db8b..3ae559f 100644 --- a/CardLibrary.inc +++ b/CardLibrary.inc @@ -1,17 +1,31 @@ SECTION "Card Data", ROM0 Spreads: + db 5 ; length .nospread db 0 + db 20, " Nothing " + db 20, " This is no spread. " +.onecard + db 1, $21 + db 20, " One Card Spread " + db 20, " Draw a single card." .tencard db 10, $00, $10, $20, $30, $40, $02, $12, $22, $32, $42 + db 20, " Ten Card Spread " + db 20, "Throw more cards on." .fivecard db 5, $11, $20, $22, $31, $41 + db 20, " Horizontal Cross " + db 20, " A little spicy. " .threecard - db 3, $11, $21, $31 + db 3, $01, $21, $41 + db 20, " Three Card Spread " + db 20, " Old reliable. " +.end Cards: - db 5 + db 5 ; length dw TheFool dw TheMagician dw TheHighPriestess diff --git a/CopyRangeSafe.inc b/CopyRangeSafe.inc index 434f403..b2a9019 100644 --- a/CopyRangeSafe.inc +++ b/CopyRangeSafe.inc @@ -9,6 +9,8 @@ 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 +DEF SAFE_TRANSFER_START EQU 145 +DEF SAFE_TRANSFER_END EQU 153 CopyRangeSafe: ; hl is source @@ -56,7 +58,7 @@ CopyRangeSafe: ld [INTERRUPT_LCD], a ld a, h ld [INTERRUPT_LCD + 1], a; set interrupt handler to "ENTER SAFE MODE" - ld a, 143 ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING + ld a, SAFE_TRANSFER_START ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING ld [$ff45], a ld hl, $ffff set 1, [hl] @@ -88,7 +90,7 @@ CopyRangeSafe_EnterSafeMode: ld [INTERRUPT_LCD], a ld a, h ld [INTERRUPT_LCD+1], a - ld a, 153 ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING + ld a, SAFE_TRANSFER_END ; 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 @@ -145,7 +147,7 @@ CopyRangeSafe_CleanUp: ld [INTERRUPT_LCD], a ld a, h ld [INTERRUPT_LCD+1], a - ld a, 143 ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING + ld a, SAFE_TRANSFER_START ; 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 @@ -174,7 +176,7 @@ CopyRangeSafe_Done: ; called when the complete transfer is finished, ld [INTERRUPT_LCD], a ld a, h ld [INTERRUPT_LCD+1], a - ld a, 143 ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING + ld a, SAFE_TRANSFER_START ; 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 @@ -205,7 +207,7 @@ CopyRangeSafe_Done: ; called when the complete transfer is finished, CopyRangeSafe_Return: reti -CopyRangeUnsafe: +CopyRangeUnsafe: ; this is threadsafe but not vblank safe ; hl is source ; de is destination ; bc is length to copy diff --git a/CopyTilesSafe.inc b/CopyTilesSafe.inc index 64d4338..4fd37fa 100644 --- a/CopyTilesSafe.inc +++ b/CopyTilesSafe.inc @@ -40,7 +40,7 @@ CopyTilesSafe: 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 a, SAFE_TRANSFER_START ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING ld [$ff45], a ld hl, $ffff set 1, [hl] @@ -65,7 +65,7 @@ CopyTilesSafe_EnterSafeMode: ld [INTERRUPT_LCD], a ld a, h ld [INTERRUPT_LCD+1], a - ld a, 153 ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING + ld a, SAFE_TRANSFER_END ; 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 @@ -120,7 +120,6 @@ CopyTilesSafe_DoneWithLine: dec b ld a, b - cp a, 0 ldh [vSafeCopyOriginalCount+1], a ; store the decremented line count jp nz, CopyTilesSafe_TransferLoop @@ -151,7 +150,7 @@ CopyTilesSafe_CleanUp: ld [INTERRUPT_LCD], a ld a, h ld [INTERRUPT_LCD+1], a - ld a, 148 ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING + ld a, SAFE_TRANSFER_START ; 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 @@ -180,7 +179,7 @@ CopyTilesSafe_Done: ; called when the complete transfer is finished, ld [INTERRUPT_LCD], a ld a, h ld [INTERRUPT_LCD+1], a - ld a, 148 ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING + ld a, SAFE_TRANSFER_START ; 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 @@ -213,11 +212,11 @@ CopyTilesSafe_Return: CopyTilesToMapUnsafe: - ; copy tiles from where they are linearly packed at an origin (de) - ; to a rectangle in the tilemap in vram (hl) + ; copy tiles from where they are linearly packed at an origin (hl) + ; to a rectangle in the tilemap in vram (de) ; assuming it has height in b and width in c. push bc -CopyTile: +.copyTile 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 @@ -226,8 +225,8 @@ CopyTile: ; 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, CopyTile -DoneWithLine: + jp nz, .copyTile +.doneWithLine pop bc ld a, e @@ -247,4 +246,45 @@ DoneWithLine: ld a, b cp a, 0 jp nz, CopyTilesToMapUnsafe + ret + +CopyTilesToMapThreadsafe: + ; copy tiles from where they are linearly packed at an origin (hl) + ; to a rectangle in the tilemap in vram (de) + ; assuming it has height in b and width in c. + di + ei + nop + di + push bc +.copyTile + 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, .copyTile +.doneWithLine + pop bc + + 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 + jp nz, CopyTilesToMapThreadsafe ret \ No newline at end of file diff --git a/ScreenCardRead.inc b/ScreenCardRead.inc index 574793e..13d5a88 100644 --- a/ScreenCardRead.inc +++ b/ScreenCardRead.inc @@ -8,8 +8,7 @@ ScreenCardRead: dw CardReadUpdate dw CardReadDraw dw CardReadTeardown - -;; CARD READ PAGE STARTS HERE + CardReadSetup: ; Turn the LCD off ld hl, rLCDC @@ -37,18 +36,8 @@ CardReadSetup: ld c, 10 ; width call CopyTilesToMapUnsafe - ld a, 0 - ld hl, $c000 - ld bc, 18*10 -.buildZeros - ld a, 0 - ld [hl+], a - ld a, b - or a, c - dec bc - jp nz, .buildZeros - ld hl, $c000 + ld hl, ZEROES ld de, $9800 + 10 ld b, 18 ld c, 10 @@ -75,37 +64,25 @@ CardReadSetup: CardReadUpdate: ld hl, rMYBTNP - bit 5, [hl] + bit 4, [hl] jp z, .doneWithB ld hl, ScreenMainMenu call ChangeScene ret .doneWithB + ldh a, [vSelectedCardIndex] + bit 3, [hl] ; select the down key jp z, :+ ; skip the following code if down is not pressed - ldh a, [vSelectedCardIndex] inc a ; increment when they press down because the deck has card 0 at the top - ldh [vSelectedCardIndex], a : bit 2, [hl] ; select up key %0000_0100 jp z, :+ ; skip the following code if up is not pressed - ldh a, [vSelectedCardIndex] dec a ; decrement when they press up because the deck has card 0 at the top - ldh [vSelectedCardIndex], a -: - ldh a, [vSelectedCardIndex] ; load current selected tile index - ld hl, Cards ; deck length - cp a, [hl] ; ddoes the index equal the deck length? - jp nz, :+ - ld a, 0 ; if the index equals the deck length replace it with zero - ldh [vSelectedCardIndex], a -: - cp a, $FF ; if the tile index is $FF (underflowed from dec) - jp nz, :+ - ld a, [hl] - dec a ;replace with deck length - 1 - ldh [vSelectedCardIndex], a : + ld hl, Cards + call ArrayClampLooping + ldh [vSelectedCardIndex], a ; load current selected tile index ld hl, rMYBTNP bit 1, [hl] @@ -140,90 +117,13 @@ CardReadUpdate: CardReadDraw: ; first, we draw the spread minimap -.drawSpread ldh a, [vCurrentSpread] ld c, a ldh a, [vCurrentSpread+1] ld b, a - ld a, [bc] - ld e, a - ld d, 0 - -.foundSpread - push de ; length of the spread in e! -.drawCard - ld a, e - cp a, 0 - jp z, .doneWithSpread - inc bc ; first card of spread is after the length of the spread - ld hl, $9800 + (32*12)+11 - - ld a, [bc] - swap a - and a, %0000_1111 - ld d, 0 - ld e, a ; add a to hl - add hl, de -.doneWithWalkRight - ld a, [bc] - and a, %0000_1111 - ld d, 0 - ld e, 32 - jp z, .doneWithWalkDown -.walkDown - dec a - add hl, de - cp a, 0 - jp nz, .walkDown -.doneWithWalkDown -.drawMiniCard - ld [hl], $83 - add hl, de - ld [hl], $84 -.doneDrawingCard - pop de - dec de - ld a, e - cp a, 0 - jp nz, .foundSpread - -.doneWithSpread - ; highlight the selected card - ldh a, [vCurrentSpread] - ld l, a - ldh a, [vCurrentSpread+1] - ld h, a - ldh a, [vSelectedCardInSpread] - ld d, 0 - ld e, a ; index of selected card in spread - inc e ; skip length - - add hl, de - ld b, h - ld c, l ; move location of selected card to bc - - ld hl, $9800 + (32*12)+11 - ld a, [bc] ; a has card location - swap a - and a, %0000_1111 - ld e, a - add hl, de ; step right - ld e, 32 - ld a, [bc] - and a, %0000_1111 - jp z, CardReadDraw_DrawSelectedCard -: - dec a - add hl, de ; step down - cp a, 0 - jp nz, :- -CardReadDraw_DrawSelectedCard: - ld [hl], $85 - add hl, de - ld [hl], $86 - + call DrawSpreadMinimap ; okay now we draw the deck minimap ld a, [Cards] @@ -384,8 +284,6 @@ INCLUDE "CopyRangeSafe.inc" INCLUDE "CopyTilesSafe.inc" -INCLUDE "CardLibrary.inc" - SECTION "Tile data", ROM0 UITiles: diff --git a/ScreenMainMenu.inc b/ScreenMainMenu.inc index 6e6cb95..2eb8b89 100644 --- a/ScreenMainMenu.inc +++ b/ScreenMainMenu.inc @@ -182,7 +182,11 @@ MainMenuUpdate: jp z, .option3 jp .doneWithMenuSelect .option1 - jp .doneWithMenuSelect + ld a, 0 + ld [vSelectedSpreadIndex], a + ld hl, ScreenSpreadSelect + call ChangeScene + ret .option2 jp .doneWithMenuSelect .option3 @@ -193,7 +197,6 @@ MainMenuUpdate: ld hl, ScreenCardRead call ChangeScene ret - jp .doneWithMenuSelect .doneWithMenuSelect diff --git a/ScreenSpreadSelect.inc b/ScreenSpreadSelect.inc index e69de29..9b3a884 100644 --- a/ScreenSpreadSelect.inc +++ b/ScreenSpreadSelect.inc @@ -0,0 +1,447 @@ +DEF vSelectedSpreadIndex EQU VARIABLES_START +DEF vPreviousSpreadIndex EQU vSelectedSpreadIndex + 1 +def vSelectedSpreadCard equ vPreviousSpreadIndex + 1 + +ScreenSpreadSelect: + dw SpreadSelectSetup + dw SpreadSelectUpdate + dw SpreadSelectDraw + dw SpreadSelectTeardown + +SpreadSelectSetup: + ld a, 0 + ldh [vSelectedCardInSpread], a + ldh [vPreviousSpreadIndex], a + ldh [vSelectedSpreadIndex], a + + ld hl, ZEROES + ld de, $9800 + ld b, 18 + ld c, 20 + + ld a, LOW(CopyTilesToMapThreadsafe) + ld [vAsyncNext], a + ld a, HIGH(CopyTilesToMapThreadsafe) + ld [vAsyncNext+1], a + ld a, LOW(.loadUITiles) + ld [vAsyncAfter], a + ld a, HIGH(.loadUITiles) + ld [vAsyncAfter+1], a + call DoInAsyncVBlank + + ld a, HIGH(ZEROES) + ld de, $ffc0 + call RunDMA + ret + +.loadUITiles + ld hl, UITiles ; source + ld de, $8000 + $80*16; destination of copy + ld bc, UITilesEnd - UITiles ; length to copy + + ld a, LOW(CopyRangeUnsafe) + ld [vAsyncNext], a + ld a, HIGH(CopyRangeUnsafe) + ld [vAsyncNext+1], a + ld a, LOW(DrawSpreadAsync) + ld [vAsyncAfter], a + ld a, HIGH(DrawSpreadAsync) + ld [vAsyncAfter+1], a + ret + +SpreadSelectUpdate: + ld hl, rMYBTNP + bit 4, [hl] + jp z, .doneB + ld hl, ScreenMainMenu + call ChangeScene + ret +.doneB + ld a, [vSelectedSpreadIndex] + + bit 3, [hl] ; select the down key + jp z, .doneDown ; skip the following code if down is not pressed + dec a ; increment when they press down because the deck has card 0 at the top +.doneDown + bit 2, [hl] ; select up key + jp z, .doneUp ; skip the following code if up is not pressed + inc a ; decrement when they press up because the deck has card 0 at the top +.doneUp + ld hl, Spreads + call ArrayClampLooping + ldh [vSelectedSpreadIndex], a ; load current selected tile index + + ld hl, vPreviousSpreadIndex + cp a, [hl] + ret z ; we're done if previous index is same as new index + + ; execute an async call to DrawSpreadAsync. + ld a, LOW(DrawSpreadAsync) + ld [vAsyncNext], a + ld a, HIGH(DrawSpreadAsync) + ld [vAsyncNext+1], a + + call DoInAsyncVBlank + ret ; return from main thread. go back to looping. + +DrawSpreadAsync: + ldh a, [vSelectedSpreadIndex] + ldh [vPreviousSpreadIndex], a + + ; find the correct spread address + ld hl, Spreads + inc hl ; skip length of spreads + ld a, [vSelectedSpreadIndex] + inc a ; we're decing at the start so we inc first to prepare... + ld d, 0 +.findSpread + dec a + jp z, .spreadFound + + ld e, [hl] ; skip cards in spread + inc hl + add hl, de + + ld e, [hl] ; skip title of spread + inc hl + add hl, de + + ld e, [hl] ; skip description + inc hl + add hl, de + + jp .findSpread +.spreadFound + ld a, l + ld [vCurrentSpread], a + ld a, h + ld [vCurrentSpread+1], a ; save the current spread (hl) into vcurrentspread. + + ld de, $9800 + 32*4 + 3 + ld hl, ZEROES + ld b, 8 + ld c, 10 + + ld a, LOW(CopyTilesToMapThreadsafe) + ld [vAsyncNext], a + ld a, HIGH(CopyTilesToMapThreadsafe) + ld [vAsyncNext+1], a + ld a, LOW(.afterClear) + ld [vAsyncAfter], a + ld a, HIGH(.afterClear) + ld [vAsyncAfter+1], a + ret ; return from async execution now that we've registered desire + ; to call copytilestomapthreadsafe + ; and then drawspread + +.afterClear + ld a, [vCurrentSpread] + ld l, a + ld a, [vCurrentSpread+1] + ld h, a + ld d, 0 + ld e, [hl] + inc e + add hl, de + ld de, $9800 + 32 + ld a, LOW(PrintString) + ld [vAsyncNext], a + ld a, HIGH(PrintString) + ld [vAsyncNext+1], a + ld a, LOW(.afterTitle) + ld [vAsyncAfter], a + ld a, HIGH(.afterTitle) + ld [vAsyncAfter+1], a + ret + +.afterTitle + ld de, $9800 + (32*2) + ld a, LOW(PrintString) + ld [vAsyncNext], a + ld a, HIGH(PrintString) + ld [vAsyncNext+1], a + ld a, LOW(.afterDescription) + ld [vAsyncAfter], a + ld a, HIGH(.afterDescription) + ld [vAsyncAfter+1], a + ret + +.afterDescription + + ld hl, $9800 + 32*4 + 3 + ldh a, [vSelectedSpreadCard] + ld e, a ; e contains the selected index + + ld a, LOW(DrawSpreadBigAndThreadsafe) + ld [vAsyncNext], a + ld a, HIGH(DrawSpreadBigAndThreadsafe) + ld [vAsyncNext+1], a + ld a, LOW(.finishAsyncUpdate) + ld [vAsyncAfter], a + ld a, HIGH(.finishAsyncUpdate) + ld [vAsyncAfter+1], a + ret + +.finishAsyncUpdate + ; signal that we're done with execution of the async thread + ld a, 0 + ld [vAsyncNext], a + ld [vAsyncNext+1], a + ld [vAsyncAfter], a + ld [vAsyncAfter+1], a + ret + +SpreadSelectDraw: + ret +SpreadSelectTeardown: + ret + +DrawSpreadBigAndThreadsafe: +; hl for location on screen +; bc for current spread address ; actually holding that in vCurrentSpread +; e for index of selected card + di + ld a, [vCurrentSpread] + ld c, a + ld a, [vCurrentSpread+1] + ld b, a + ld a, [bc] + cp a, 0 ; length of spread + ret z ; return early if the spread is empty + ld d, a ; length of spread in d + inc d +.drawCards + ei + nop + di + dec d + jp z, .doneWithSpread ; if we're drawing zero remaining cards, stop drawing + inc bc ; step forward + push hl ; need this bc drawsmallcard changes hl + ld a, [bc] + call DrawBigCard + pop hl + jp .drawCards +.doneWithSpread +; stack has spread address +; d is zero +; e should have currently selected index + ld b, h + ld c, l ; stash hl in bc for a mo; this should be a location in vram + + ld a, [vCurrentSpread] + ld l, a + ld a, [vCurrentSpread+1] + ld h, a + ;spread address in hl + + inc e ; skip the tiles length + + add hl, de + ld a, [hl] ; load card descriptor into a + + ld h, b + ld l, c; retrieve vram address + ei + nop + di + call DrawBigCardSelected + + ei + ret + + + +DrawSpreadBig: +; hl for location on screen +; bc for current spread address +; e for index of selected card + ld a, [bc] + cp a, 0 ; length of spread + ret z ; return early if the spread is empty + push bc + ld d, a ; length of spread in d + inc d +.drawCards + dec d + jp z, .doneWithSpread ; if we're drawing zero remaining cards, stop drawing + inc bc ; step forward + push hl ; need this bc drawsmallcard changes hl + ld a, [bc] + call DrawBigCard + pop hl + jp .drawCards +.doneWithSpread +; stack has spread address +; d is zero +; e should have currently selected index + ld b, h + ld c, l ; stash hl in bc for a mo; this should be a location in vram + pop hl ; put bc from stack into hl, this is the spread address + + inc e ; skip the tiles length + + add hl, de + ld a, [hl] + + ld h, b + ld l, c; retrieve + ;call DrawBigCardSelected + + ret + +DrawBigCard: ; starting from screen location hl, draw a card at +;the location described in a +; saves de and is therefore not threadsafe + push de + ld d, a + swap a + and a, %0000_1111 + sla a + ld e, a + + ld a, d + and a, %0000_1111 + + ld d, 0 + add hl, de ; step right + + ld e, 64 + jp z, .drawCard +.stepDown + add hl, de ; step down + dec a + jp nz, .stepDown +.drawCard + ld de, 32 + ld [hl], $12 + inc hl + ld [hl], $1e + add hl, de + ld [hl], $1f + dec hl + ld [hl], $13 + add hl, de + ld [hl], $13 + inc hl + ld [hl], $1f + add hl, de + ld [hl], $23 + dec hl + ld [hl], $17 + + pop de + ret + +DrawBigCardSelected: ; starting from screen location hl, draw a card at +;the location described in a + push de + push af + swap a + ld d, 0 + and a, %0000_1111 + sla a + ld e, a + add hl, de ; step right + + ld e, 64 + pop af + and a, %0000_1111 + jp z, .drawCard +.stepDown + add hl, de ; step down + dec a + jp nz, .stepDown +.drawCard + ld de, 32 + ld [hl], $12 + inc hl + ld [hl], $1e + add hl, de + ld [hl], $1f + dec hl + ld [hl], $13 + add hl, de + ld [hl], $13 + inc hl + ld [hl], $1f + add hl, de + ld [hl], $23 + dec hl + ld [hl], $17 + + pop de + ret + +DrawSpreadMinimap: +; hl for location on screen +; bc for current spread address +; a for index of selected card + push af + push bc + + ld a, [bc] + ld d, 0 + ld e, a ; length of spread in de +.drawCards + ld a, e + cp a, 0 + jp z, .doneWithSpread ; if we're drawing zero remaining cards, stop drawing + dec e + inc bc ; step forward + + push hl ; need this bc drawsmallcard changes hl + push bc + ld a, [bc] + ld bc, $8384 + call DrawSmallCard + pop bc + pop hl + + jp .drawCards +.doneWithSpread ; stack has hl, bc, af at the time of jumping here + pop bc ; stack: af + pop af + ld d, 0 + ld e, a ; index of selected card in spread + inc e ; skip the length + + push hl ; stack: hl + ld h, b + ld l, c ; put bc in hl temporarily so we can add to hl + + add hl, de + + ld a, [hl] + pop hl ; stack: empty + ld bc, $8586 + call DrawSmallCard + + ret + +DrawSmallCard: ; starting from screen location hl, draw a card at +;the location described in a, top and bottom sprite in b and c + push de + push af + swap a + ld d, 0 + and a, %0000_1111 + ld e, a + add hl, de ; step right + + ld e, 32 + pop af + and a, %0000_1111 + jp z, .drawCard +: + dec a + add hl, de ; step down + cp a, 0 + jp nz, :- +.drawCard + ld [hl], b + add hl, de + ld [hl], c + + pop de + ret \ No newline at end of file diff --git a/main.asm b/main.asm index 4faf855..6bc9e9d 100644 --- a/main.asm +++ b/main.asm @@ -10,6 +10,8 @@ DEF SCENE_TEARDOWN EQU SCENE_DRAW + 4 DEF INTERRUPT_LCD EQU $c111 +def ZEROES equ $D000 + DEF rMYBTN EQU $FFA8 DEF rMYBTNP EQU rMYBTN + 1 DEF rDELTAT EQU rMYBTNP + 1 @@ -30,8 +32,20 @@ SECTION "Header", ROM0[$100] EntryPoint: ; Shut down audio circuitry ld a, 0 - ld [rNR52], a ; shut down audio + ldh [rNR52], a ; shut down audio ldh [rDIV], a ; reset timer just in case?? + + ld a, 0 + ld hl, ZEROES + ld bc, $200 +.buildZeros + ld a, 0 + ld [hl+], a + ld a, b + or a, c + dec bc + jp nz, .buildZeros + ; set up the scene and interrupt vectors ld hl, Instructions @@ -101,7 +115,6 @@ EntryPoint: call ChangeScene Loop: - di ; okay this is kinda sketchy. we want a delta time variable. ; we've got two eight-bit counters, one at 4096hz and one at 16384hz ; we can definitely reset the faster counter. @@ -156,7 +169,13 @@ Loop: call SCENE_DRAW - 1 ; hope this takes fewer than 9 scanlines! ; either way it's going to eat into the update timing + ; at this point we want to make sure that scanline 153 has passed + ; we should check if we're past there and skip this await if necessary + ld b, 5 + call AwaitLine + jp Loop + ChangeScene: ; hl should be a pointer to, in sequence, setup update draw teardown call SCENE_TEARDOWN - 1 @@ -199,8 +218,11 @@ ArrayClampLooping: ; loops a to be in the array, assuming hl points to the lengt : ret ; a is return value -PrintString: ; write ascii string which has been prefixed by its length. +PrintString: ; write ascii string which has been prefixed by its length. at hl ld b, [hl] + ld a, b + cp a, 0 + ret z inc hl PrintBChars: ;write ascii characters. will not respect newlines or anything like that ; hl should be the source of ascii text @@ -240,7 +262,9 @@ run_dma_tail: ; This part must be in HRAM. Instructions: call SCENE_UPDATE + 2 ret - +INCLUDE "Async.inc" INCLUDE "ScreenMainMenu.inc" +INCLUDE "ScreenSpreadSelect.inc" INCLUDE "ScreenCardRead.inc" -INCLUDE "ScreenSpreadSelect.inc" \ No newline at end of file + +INCLUDE "CardLibrary.inc"