273 lines
5.5 KiB
PHP
273 lines
5.5 KiB
PHP
; async variables somewhere in RAM
|
|
PUSHS "Async Variables", WRAM0[ASYNC_VARS_START]
|
|
vAsyncAF: dw
|
|
vAsyncHL: dw
|
|
vAsyncDE: dw
|
|
vAsyncBC: dw
|
|
vAsyncPC: dw
|
|
vAsyncMainSP: dw
|
|
vAsyncThreadSP: dw
|
|
POPS
|
|
; canonical ordering to push should be: AF, BC, DE, HL,
|
|
|
|
def ASYNC_STACK_TOP equ $ffc0
|
|
; stack top is ffc0
|
|
; first value on the stack is the early return pointer, at ffbe = ffc0-2
|
|
; second value is the destination of the async call, at ffbc = ffbe-2 = ffc0-2-2
|
|
def ASYNC_THREAD_CALL equ ASYNC_STACK_TOP - 2 - 2
|
|
|
|
; timing for async execution, in scanlines
|
|
def SAFE_ASYNC_START EQU 145
|
|
def SAFE_ASYNC_END EQU 0
|
|
|
|
Async_Spawn_HL:
|
|
di
|
|
ld a, l
|
|
ld [ASYNC_THREAD_CALL], a
|
|
ld a, h
|
|
ld [ASYNC_THREAD_CALL+1], a
|
|
Async_Spawn:
|
|
di
|
|
nop
|
|
|
|
; save all the registers
|
|
push af
|
|
ld a, l
|
|
ld [vAsyncHL], a
|
|
ld a, h
|
|
ld [vAsyncHL+1], a
|
|
ld a, e
|
|
ld [vAsyncDE], a
|
|
ld a, d
|
|
ld [vAsyncDE+1], a
|
|
ld a, c
|
|
ld [vAsyncBC], a
|
|
ld a, b
|
|
ld [vAsyncBC+1], a
|
|
pop hl
|
|
ld a, l
|
|
ld [vAsyncAF], a
|
|
ld a, h
|
|
ld [vAsyncAF+1], a
|
|
|
|
; save main sp
|
|
ld hl, sp+0
|
|
ld a, l
|
|
ld [vAsyncMainSP], a
|
|
ld a, h
|
|
ld [vAsyncMainSP+1], a
|
|
|
|
; switch to thread sp
|
|
ld a, LOW(ASYNC_STACK_TOP)
|
|
ld l, a
|
|
ld a, HIGH(ASYNC_STACK_TOP)
|
|
ld h, a
|
|
ld sp, hl
|
|
|
|
|
|
; push early return onto thread stack
|
|
ld l, LOW(Async_EarlyReturn)
|
|
ld h, HIGH(Async_EarlyReturn)
|
|
push hl
|
|
|
|
; requestedd pc is expected to be set at ASYNC_THREAD_CALL by the calling func
|
|
ld hl, sp-2
|
|
ld sp, hl
|
|
|
|
; push registers
|
|
; canonical ordering to push should be: AF, BC, DE, HL,
|
|
ld a, [vAsyncAF]
|
|
ld l, a
|
|
ld a, [vAsyncAF+1]
|
|
ld h, a
|
|
push hl
|
|
|
|
ld a, [vAsyncBC]
|
|
ld l, a
|
|
ld a, [vAsyncBC+1]
|
|
ld h, a
|
|
push hl
|
|
|
|
ld a, [vAsyncDE]
|
|
ld l, a
|
|
ld a, [vAsyncDE+1]
|
|
ld h, a
|
|
push hl
|
|
|
|
ld a, [vAsyncHL]
|
|
ld l, a
|
|
ld a, [vAsyncHL+1]
|
|
ld h, a
|
|
push hl
|
|
|
|
; save current sp to vAsyncThreadSP
|
|
ld hl, sp+0
|
|
ld a, l
|
|
ld [vAsyncThreadSP], a
|
|
ld a, h
|
|
ld [vAsyncThreadSP+1], a
|
|
|
|
; now the stack looks like: early return, ASYNC_THREAD_CALL, AF, BC, DE, HL
|
|
; switch back to main thread.
|
|
|
|
; register enterthread
|
|
ld a, LOW(Async_EnterThread)
|
|
ld [INTERRUPT_LCD], a
|
|
ld a, HIGH(Async_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
|
|
|
|
|
|
|
|
; restore main sp
|
|
ld a, [vAsyncMainSP]
|
|
ld l, a
|
|
ld a, [vAsyncMainSP+1]
|
|
ld h, a
|
|
ld sp, hl
|
|
|
|
; restore registers from memory
|
|
ld a, [vAsyncAF]
|
|
ld l, a
|
|
ld a, [vAsyncAF+1]
|
|
ld h, a
|
|
push hl ; this is so we can pop af when we're done
|
|
|
|
ld a, [vAsyncHL]
|
|
ld l, a
|
|
ld a, [vAsyncHL+1]
|
|
ld h, a
|
|
|
|
ld a, [vAsyncDE]
|
|
ld e, a
|
|
ld a, [vAsyncDE+1]
|
|
ld d, a
|
|
|
|
ld a, [vAsyncBC]
|
|
ld c, a
|
|
ld a, [vAsyncBC+1]
|
|
ld b, a
|
|
|
|
pop af
|
|
|
|
reti
|
|
|
|
Async_EnterThread:
|
|
;stack looks like:
|
|
;c113 (SMC int @ LYC 90 pc), 004b (hw int @ LYC 90 pc), outer context pc
|
|
|
|
; 16 cycles
|
|
push af
|
|
push bc
|
|
push de
|
|
push hl
|
|
|
|
;af, de, bc, hl, c113 (SMC interrupt pc), 004b (hardwired interrput pc), outer context pc
|
|
|
|
; 18 cycles
|
|
ld a, LOW(Async_ExitThread)
|
|
ld [INTERRUPT_LCD], a
|
|
ld a, HIGH(Async_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
|
|
|
|
; 5 cycles
|
|
; save main thread stack pointer
|
|
ld [vAsyncMainSP], sp
|
|
|
|
; 12 cycless
|
|
; load side thread stack pointer
|
|
ld a, [vAsyncThreadSP] ; 4
|
|
ld l, a ; 1
|
|
ld a, [vAsyncThreadSP+1] ; 4
|
|
ld h, a ; 1
|
|
ld sp, hl ; 2
|
|
|
|
; 12 cycles
|
|
; pop registers
|
|
; canonical ordering to push should be: AF, BC, DE, HL,
|
|
; pop is HL, DE, BC, AF
|
|
pop hl
|
|
pop de
|
|
pop bc
|
|
pop af
|
|
|
|
; 4 cycles
|
|
reti ; "return" to the vAsyncPC wee put on the stack previously. ; 4
|
|
; 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
|
|
|
|
Async_ExitThread:
|
|
; save interrupt registers (AF, BC, DE, HL)
|
|
push af
|
|
push bc
|
|
push de
|
|
push hl
|
|
|
|
ld a, LOW(Async_EnterThread)
|
|
ld [INTERRUPT_LCD], a
|
|
ld a, HIGH(Async_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
|
|
|
|
; save side thread stack pointer
|
|
ld [vAsyncThreadSP], sp
|
|
|
|
; load main thread stack pointer
|
|
ld a, [vAsyncMainSP]
|
|
ld l, a
|
|
ld a, [vAsyncMainSP+1]
|
|
ld h, a
|
|
ld sp, hl
|
|
|
|
; pop registers
|
|
; canonical ordering to push should be: AF, BC, DE, HL,
|
|
; pop is HL, DE, BC, AF
|
|
pop hl
|
|
pop de
|
|
pop bc
|
|
pop af
|
|
|
|
reti
|
|
|
|
|
|
Async_EarlyReturn:
|
|
di
|
|
; don't care about current registers bc we're done executing.
|
|
|
|
; store side thread SP, so everyone knows that the side thread stack is empty
|
|
ld [vAsyncThreadSP], sp ; 5 cycles instead of 13
|
|
|
|
; unset next call
|
|
ld hl, rIE
|
|
res 1, [hl] ; disable stat interrupt
|
|
ld hl, rIF
|
|
res 1, [hl] ; clear the interrupt
|
|
|
|
; load main thread stack pointer
|
|
ld a, [vAsyncMainSP]
|
|
ld l, a
|
|
ld a, [vAsyncMainSP+1]
|
|
ld h, a
|
|
ld sp, hl
|
|
|
|
; restore the pre-interrupt registers, return and enable interrupts
|
|
pop af
|
|
pop de
|
|
pop bc
|
|
pop hl
|
|
|
|
reti
|