aboutsummaryrefslogtreecommitdiffstats
path: root/src/sched.asm
blob: a540c49de32b4c27c2d44a0a566f5500cd8a05f1 (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
; =============================================================================
; 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