aboutsummaryrefslogtreecommitdiffstats
path: root/src/hram.asm
diff options
context:
space:
mode:
Diffstat (limited to 'src/hram.asm')
-rw-r--r--src/hram.asm142
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