aboutsummaryrefslogtreecommitdiffstats
path: root/src/sched.asm
blob: b4b5a3058b41ab38676e68341e7b633ff8e3df70 (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
; =============================================================================
; sched.asm - round-robin scheduler + yield + timer stub
; =============================================================================
INCLUDE "include/gbos.inc"

SECTION "sched", ROM0

; -----------------------------------------------------------------------------
; SchedInit - prime the round-robin cursor so the first pick lands on slot 0.
; -----------------------------------------------------------------------------
SchedInit::
    ld a, MAX_PROCS - 1
    ld [wSchedNext], a
    ret

; -----------------------------------------------------------------------------
; SchedRunFirst - hand control to the first runnable task. Never returns; the
; kernel-init context is saved into wKernelPCB and simply abandoned.
; -----------------------------------------------------------------------------
SchedRunFirst::
    ld hl, wKernelPCB
    ld a, l
    ld [wCurProc], a
    ld a, h
    ld [wCurProc+1], a
    call FindNextReady          ; DE = &first ready PCB
    jp hSwitchTo

; -----------------------------------------------------------------------------
; SchedYield - cooperative switch to the next runnable task.  Returns to the
; caller when this task is eventually rescheduled.
; -----------------------------------------------------------------------------
SchedYield::
    call FindNextReady          ; DE = &next PCB, CF if none runnable
    ret c                       ; nobody else ready: keep running current
    call hSwitchTo
    ret

; -----------------------------------------------------------------------------
; FindNextReady - round-robin from wSchedNext.
;   out: DE = &PCB and CF clear on success; CF set if nothing is PS_READY.
; -----------------------------------------------------------------------------
FindNextReady::
    ld a, [wSchedNext]
    ld b, MAX_PROCS
.scan
    inc a
    cp MAX_PROCS
    jr c, .nowrap
    xor a
.nowrap
    push af                     ; save candidate slot
    call PcbPtr                 ; DE = &PCB[slot]  (preserves BC)
    ld a, [de]                  ; state
    cp PS_READY
    jr z, .found
    pop af                      ; restore candidate slot
    dec b
    jr nz, .scan
    scf                         ; nothing runnable
    ret
.found
    pop af                      ; A = chosen slot
    ld [wSchedNext], a
    call PcbPtr                 ; DE = &PCB
    and a                       ; clear carry
    ret

; -----------------------------------------------------------------------------
; TimerISR - the system tick. TAC runs the timer at 16384 Hz with TMA=0 -
; but the CPU is in DOUBLE-SPEED mode, so the input clock is really 32768 Hz
; and this fires at 128 Hz. A toggle halves that back down: wTicks stays a
; monotonic 32-bit 1/64-second counter (SYS_UPTIME reads it; wraps ~2.1 yr).
; Scheduling stays cooperative - this ISR is deliberately transparent (all
; registers preserved, fixed-WRAM only), so it can interrupt anything,
; including kernel code mid-syscall. Preemption would hook in here later.
; -----------------------------------------------------------------------------
TimerISR::
    push af
    push hl
    ld hl, wTickTog
    ld a, [hl]
    xor 1
    ld [hl], a
    jr nz, .done                ; first IRQ of the 128 Hz pair: count nothing
    ld hl, wTicks
    inc [hl]
    jr nz, .done                ; no carry out of byte 0
    inc hl
    inc [hl]
    jr nz, .done
    inc hl
    inc [hl]
    jr nz, .done
    inc hl
    inc [hl]
.done
    pop hl
    pop af
    reti