From b52f37602968768901d2dd83ccf966d953a532f0 Mon Sep 17 00:00:00 2001 From: user Date: Fri, 17 Jul 2026 13:43:10 +0200 Subject: 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. --- src/kdata.asm | 3 +++ src/syscall.asm | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) (limited to 'src') diff --git a/src/kdata.asm b/src/kdata.asm index 6333f38..eece708 100644 --- a/src/kdata.asm +++ b/src/kdata.asm @@ -57,6 +57,9 @@ wFsSlashPtr::DS 2 ; last '/' seen while splitting a path wListDir:: DS 1 ; directory sys_list enumerates wKChar:: DS 1 ; scratch for KPutc wConInSkip:: DS 1 ; console input: mid-SLIP-frame? (skip net packets) +wSleepTarget::DS 1 ; sys_sleep: target in 1/64-second units +wSleepAcc:: DS 2 ; sys_sleep: accumulated DIV ticks +wSleepLastDiv::DS 1 ; sys_sleep: previous DIV reading wKillParent::DS 1 ; scratch for sys_kill wPsBuf:: DS 2 ; scratch for sys_ps wPnStart:: DS 2 ; scratch for sys_progname 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: @@ -278,6 +279,46 @@ sys_yield: call SchedYield 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 -- cgit v1.3.1-sl0p