diff options
| author | user <user@clank> | 2026-07-17 13:43:10 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-07-17 13:43:10 +0200 |
| commit | b52f37602968768901d2dd83ccf966d953a532f0 (patch) | |
| tree | d497c52bf672291d1cd9cf0579b6191155cb56d4 /src/syscall.asm | |
| parent | net: keep network packets out of the console (fixes shell garbage on netboot) (diff) | |
| download | gbos-b52f37602968768901d2dd83ccf966d953a532f0.tar.gz gbos-b52f37602968768901d2dd83ccf966d953a532f0.tar.xz gbos-b52f37602968768901d2dd83ccf966d953a532f0.zip | |
kernel: sys_sleep - a cooperative delay off the DIV timer (+ ping pacing)
There was no time source at all (IRQ vectors just reti; scheduler is purely
cooperative). The DIV register (FF04) free-runs at 16384 Hz regardless of
interrupts, so sys_sleep accumulates DIV deltas across SchedYields (other procs
keep running) until the requested number of 1/64-second units elapse.
- SYS_SLEEP(34): B = 1/64s units; libc gsleep(units) / msleep(ms) wrappers.
- ping now msleep(800) between echoes, so it paces like real ping instead of
blasting all four at once.
Verified real-time (capped emulator): replies land ~0.85s apart. In --uncapped
runs the delay is GB-time (fast wall-clock), as expected.
Diffstat (limited to 'src/syscall.asm')
| -rw-r--r-- | src/syscall.asm | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/src/syscall.asm b/src/syscall.asm index 04e9661..1051a4d 100644 --- a/src/syscall.asm +++ b/src/syscall.asm @@ -68,6 +68,7 @@ SyscallTable: dw sys_srecv_nb ; 31 SRECVNB dw sys_pollin ; 32 POLLIN dw sys_net ; 33 NET + dw sys_sleep ; 34 SLEEP ; ----------------------------------------------------------------------------- sys_nosys: @@ -279,6 +280,46 @@ sys_yield: ret ; ----------------------------------------------------------------------------- +; sys_sleep(B = 1/64-second units) - cooperative delay driven by the DIV timer. +; DIV (FF04) free-runs at 16384 Hz, so 256 ticks = 1/64 s. We accumulate DIV +; deltas across SchedYields (other procs run) until enough units have elapsed. +; ----------------------------------------------------------------------------- +sys_sleep: + ld a, b + or a + ret z ; sleep 0 = no-op + ld [wSleepTarget], a + xor a + ld [wSleepAcc], a + ld [wSleepAcc+1], a + ld a, [rDIV] + ld [wSleepLastDiv], a +.loop + call SchedYield + ld a, [rDIV] + ld c, a ; current DIV + ld a, [wSleepLastDiv] + ld b, a ; previous DIV + ld a, c + ld [wSleepLastDiv], a + sub b ; A = DIV delta (mod 256) + ld e, a + ld a, [wSleepAcc] ; acc += delta + add e + ld [wSleepAcc], a + ld a, [wSleepAcc+1] + adc 0 + ld [wSleepAcc+1], a ; acc high byte = elapsed 1/64-second units + ld b, a + ld a, [wSleepTarget] + cp b + jr z, .done ; elapsed == target + jr c, .done ; elapsed > target + jr .loop +.done + ret + +; ----------------------------------------------------------------------------- ; sys_exit(code=B) -- become a zombie awaiting reap; never returns. ; - store exit code, set PS_ZOMBIE ; - reparent any children to init (so they can still be waited on) |
