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
|
; =============================================================================
; 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 - preemption hook (TODO). A real preemptive switch must save the
; interrupted context and call hSwitchTo from here. For now the demo is
; cooperative (tasks call SYS_YIELD), so we just acknowledge and return.
; -----------------------------------------------------------------------------
TimerISR::
reti
|