From 0cc9b0a8bdf774ee376937d5a6767ccdced51245 Mon Sep 17 00:00:00 2001 From: user Date: Sat, 18 Jul 2026 10:10:04 +0200 Subject: kernel: a real timer source (64 Hz tick IRQ) + uptime(1) The kernel had no clock: TimerISR was a reti stub, IEF_TIMER masked, and IME was never enabled - the vectors were decorative. sys_sleep just polls DIV deltas per-process; nothing counted globally. Now: TAC runs the hardware timer at 16384 Hz with TMA=0, so TIMA overflows at exactly 64 Hz; TimerISR increments a monotonic 32-bit wTicks (wraps after ~2.1 years). Scheduling stays cooperative - the ISR is transparent. Enabling IME in a kernel written for zero interrupts needs care wherever SP points into memory whose bank is being switched (an IRQ pushes onto SP): - read_block/write_block map the disk bank over the $A000 window that holds the caller's stack -> di/ei around the transfer (~2ms, well under the 15.6ms tick period, so no tick is ever lost) - hSwitchTo switches SVBK + cart-RAM banks under the outgoing stack -> di on entry, ei once the incoming stack is mapped - fork already runs on KSTACK_TOP2 (fixed WRAM) - safe as-is - term_putc's SVBK switch only remaps $Dxxx, stacks live in $Axxx/$Cxxx SYS_UPTIME (36) copies the counter (4B LE, di/ei so the read can't tear) to a user buffer; libc gticks(); usr/uptime.c formats 'up [Nd] H:MM:SS'. uptime avoids SDCC long div/shift entirely: sm83.lib modules link into their own areas that land in the $A000 RAM window (latent build.sh trap, documented there) - bytewise >>6 plus bounded subtraction loops instead. --- src/sched.asm | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'src/sched.asm') diff --git a/src/sched.asm b/src/sched.asm index a540c49..0369ff4 100644 --- a/src/sched.asm +++ b/src/sched.asm @@ -67,9 +67,28 @@ FindNextReady:: 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 - the system tick. TAC runs the timer at 16384 Hz with TMA=0, so +; TIMA overflows (and this fires) at 64 Hz: wTicks is a monotonic 32-bit +; 1/64-second counter (SYS_UPTIME reads it; wraps after ~2.1 years). +; 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, 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 -- cgit v1.3.1-sl0p