diff options
Diffstat (limited to 'src/hram.asm')
| -rw-r--r-- | src/hram.asm | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/src/hram.asm b/src/hram.asm new file mode 100644 index 0000000..7c1910c --- /dev/null +++ b/src/hram.asm @@ -0,0 +1,142 @@ +; ============================================================================= +; hram.asm - the trampoline. +; +; The context switch writes SVBK ($D000-$DFFF) and the MBC5 RAM bank +; ($A000-$BFFF). Because a task's stack lives in the RAM window, the code +; performing the swap MUST NOT execute from any bank it is about to change and +; MUST NOT touch the stack across the swap. HRAM is never banked, so the +; switch lives here. We assemble it with HRAM addresses (LOAD) but store the +; bytes in ROM0 and copy them up at boot. +; +; Convention: to compute &(PCB + OFF) we do +; ld a,e : add OFF : ld l,a : ld a,d : adc 0 : ld h,a ; HL = DE + OFF +; ============================================================================= +INCLUDE "include/gbos.inc" + +SECTION "hram_vars", HRAM +hCurBankRAM: DS 1 ; shadow of active cart-RAM bank +hCurBankWRAM: DS 1 ; shadow of active SVBK bank +hSwitchTgt: DS 2 ; &incoming PCB (set before the pushes clobber DE) + +; ----------------------------------------------------------------------------- +; Source image (lives in ROM0); CopyHramCode blits it to HRAM at boot. +; ----------------------------------------------------------------------------- +SECTION "hram_src", ROM0 + +HramSrc: +LOAD "hram_code", HRAM +; --------------------------------------------------------------------------- +; hSwitchTo: switch from the current task (wCurProc) to the PCB in DE. +; in: DE = &incoming PCB +; Runs from HRAM. Saves/restores full context. Clobbers everything. +; --------------------------------------------------------------------------- +hSwitchTo:: + ; stash target while DE is still valid + ld a, e + ld [hSwitchTgt], a + ld a, d + ld [hSwitchTgt+1], a + + ; --- save outgoing context on its (currently-mapped) stack --- + push af + push bc + push de + push hl + + ; SP -> outgoing PCB.PROC_SP (outgoing = wCurProc, in WRAM0, always mapped) + ld hl, sp+0 ; HL = SP + ld b, h + ld c, l ; BC = SP value + ld a, [wCurProc] + add PROC_SP + ld l, a + ld a, [wCurProc+1] + adc 0 + ld h, a ; HL = &outgoing.PROC_SP + ld a, c + ld [hl+], a + ld a, b + ld [hl], a + + ; --- incoming becomes current --- + ld a, [hSwitchTgt] + ld e, a + ld [wCurProc], a + ld a, [hSwitchTgt+1] + ld d, a ; DE = &incoming PCB + ld [wCurProc+1], a + + ; --- program banks for incoming task (order: RAM, WRAM, ROM) --- + ; cart-RAM bank + ld a, e + add PROC_RAMB + ld l, a + ld a, d + adc 0 + ld h, a + ld a, [hl] + ld [hCurBankRAM], a + ld [MBC5_RAMB], a + ; u-area WRAM bank via SVBK + ld a, e + add PROC_WRAMB + ld l, a + ld a, d + adc 0 + ld h, a + ld a, [hl] + ld [hCurBankWRAM], a + ld [rSVBK], a + ; text ROM bank (16-bit) + ld a, e + add PROC_ROMB + ld l, a + ld a, d + adc 0 + ld h, a + ld a, [hl+] + ld [MBC5_ROMB_LO], a + ld a, [hl] + ld [MBC5_ROMB_HI], a + + ; --- restore incoming SP (its banks are now mapped) --- + ld a, e + add PROC_SP + ld l, a + ld a, d + adc 0 + ld h, a + ld a, [hl+] + ld c, a + ld a, [hl] + ld h, a + ld l, c + ld sp, hl + + ; --- pop incoming context and resume it --- + pop hl + pop de + pop bc + pop af + ret +ENDL +HramSrcEnd: + +; ----------------------------------------------------------------------------- +; CopyHramCode - blit the LOAD'd image up to HRAM. Runs once at boot. +; ----------------------------------------------------------------------------- +SECTION "hram_copy", ROM0 + +CopyHramCode:: + ld hl, HramSrc + ld de, hSwitchTo + ld bc, HramSrcEnd - HramSrc +.loop + ld a, [hl+] + ld [de], a + inc de + dec bc + ld a, b + or c + jr nz, .loop + ret |
