aboutsummaryrefslogtreecommitdiffstats
path: root/src/hram.asm
blob: facccd000295ae9879c5ecb873711c4d690b98ce (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
; =============================================================================
; 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)
hSCY::         DS 1       ; VBlank-latched SCY: term_view_update writes this,
                          ; the VBlank ISR applies it - a mid-frame SCY write
                          ; would shear the picture (SCY is sampled per
                          ; scanline), so ring-scrolls land at frame boundaries

; -----------------------------------------------------------------------------
; 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::
    di                          ; no tick ISR while SP and the banks under it
                                ; are out of sync (pushes would hit the wrong
                                ; bank); ei below once the incoming stack is up
    ; 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 ---
    ei                          ; SP + banks consistent again (takes effect
                                ; after the next instruction)
    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