aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/blk.asm5
-rw-r--r--src/boot.asm14
-rw-r--r--src/hram.asm5
-rw-r--r--src/kdata.asm1
-rw-r--r--src/programs.asm7
-rw-r--r--src/sched.asm25
-rw-r--r--src/syscall.asm19
7 files changed, 70 insertions, 6 deletions
diff --git a/src/blk.asm b/src/blk.asm
index 2be961e..76561da 100644
--- a/src/blk.asm
+++ b/src/blk.asm
@@ -34,6 +34,8 @@ ENDM
; -----------------------------------------------------------------------------
read_block::
ld c, a
+ di ; the tick ISR pushes on SP, which points into
+ ; the $A000 window we are about to remap
srl a
srl a
srl a
@@ -54,6 +56,7 @@ read_block::
dec b
jr nz, .cp
restore_bank ; inline - no stack while the disk bank is mapped
+ ei
ret
; -----------------------------------------------------------------------------
@@ -61,6 +64,7 @@ read_block::
; -----------------------------------------------------------------------------
write_block::
ld c, a
+ di ; see read_block
srl a
srl a
srl a
@@ -81,6 +85,7 @@ write_block::
dec b
jr nz, .cp
restore_bank
+ ei
ret
; =============================================================================
diff --git a/src/boot.asm b/src/boot.asm
index c2d461a..4049f9d 100644
--- a/src/boot.asm
+++ b/src/boot.asm
@@ -81,11 +81,19 @@ KernelInit:
call SchedInit ; pick first task, set wCurProc
- ; interrupts: enable timer for preemption
+ ; system tick: hardware timer at 16384 Hz input, TMA=0 -> TIMA overflow
+ ; IRQ at 64 Hz. TimerISR just counts (wTicks); scheduling stays
+ ; cooperative. Only the timer bit is enabled in IE.
+ xor a
+ ld [rTIMA], a
+ ld [rTMA], a
+ ld a, %00000111 ; enable | 16384 Hz
+ ld [rTAC], a
xor a
ld [rIF], a
- ; ld a, IEF_TIMER ; (timer bit) - leave masked for cooperative demo
- ; ld [rIE], a
+ ld a, IEF_TIMER
+ ld [rIE], a
+ ei
; hand control to the first task via a context switch-in
jp SchedRunFirst
diff --git a/src/hram.asm b/src/hram.asm
index 7c1910c..9e65982 100644
--- a/src/hram.asm
+++ b/src/hram.asm
@@ -31,6 +31,9 @@ LOAD "hram_code", HRAM
; Runs from HRAM. Saves/restores full context. Clobbers everything.
; ---------------------------------------------------------------------------
hSwitchTo::
+ di ; no tick ISR while SP and the banks under it
+ ; are out of sync (pushes would hit the wrong
+ ; bank); ei below once the incoming stack is up
; stash target while DE is still valid
ld a, e
ld [hSwitchTgt], a
@@ -114,6 +117,8 @@ hSwitchTo::
ld sp, hl
; --- pop incoming context and resume it ---
+ ei ; SP + banks consistent again (takes effect
+ ; after the next instruction)
pop hl
pop de
pop bc
diff --git a/src/kdata.asm b/src/kdata.asm
index 65a059a..b0cd71b 100644
--- a/src/kdata.asm
+++ b/src/kdata.asm
@@ -65,3 +65,4 @@ wPnStart:: DS 2 ; scratch for sys_progname
wBootA:: DS 1 ; A at entry: console model from the boot ROM
wBootB:: DS 1 ; B at entry: bit0 set = AGB (GBA in CGB mode)
wBootFsFresh::DS 1 ; fs_init formatted a blank disk this boot
+wTicks:: DS 4 ; monotonic 64 Hz system tick (TimerISR), LE
diff --git a/src/programs.asm b/src/programs.asm
index 6dbc584..7c17fb5 100644
--- a/src/programs.asm
+++ b/src/programs.asm
@@ -133,6 +133,9 @@ ProgDhcp:
SECTION "prog_irc", ROMX[$4000], BANK[32]
ProgIrc:
INCBIN "build/usr/irc.bin"
+SECTION "prog_uptime", ROMX[$4000], BANK[33]
+ProgUptime:
+ INCBIN "build/usr/uptime.bin"
; -----------------------------------------------------------------------------
; PROG_SH (bank 3) - the shell, now written in C (usr/sh.c): parses >/</| and
@@ -237,6 +240,8 @@ ProgramTable::
dw ProgDhcp
db LOW(BANK(ProgIrc)), HIGH(BANK(ProgIrc))
dw ProgIrc
+ db LOW(BANK(ProgUptime)), HIGH(BANK(ProgUptime))
+ dw ProgUptime
ProgramTableEnd::
; -----------------------------------------------------------------------------
@@ -306,4 +311,6 @@ NameTable::
db PROG_DHCP
db "irc", 0
db PROG_IRC
+ db "uptime", 0
+ db PROG_UPTIME
db 0
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
diff --git a/src/syscall.asm b/src/syscall.asm
index bd58cc2..e3f0b1b 100644
--- a/src/syscall.asm
+++ b/src/syscall.asm
@@ -70,6 +70,7 @@ SyscallTable:
dw sys_net ; 33 NET
dw sys_sleep ; 34 SLEEP
dw sys_pollcon ; 35 POLLCON
+ dw sys_uptime ; 36 UPTIME
; -----------------------------------------------------------------------------
sys_nosys:
@@ -257,6 +258,24 @@ sys_yield:
ret
; -----------------------------------------------------------------------------
+; sys_uptime(buf=DE) - copy the monotonic 64 Hz tick counter (4 bytes, LE)
+; into the caller's buffer. di/ei so the ISR can't split the 32-bit read.
+; -----------------------------------------------------------------------------
+sys_uptime:
+ di
+ ld hl, wTicks
+REPT 3
+ ld a, [hl+]
+ ld [de], a
+ inc de
+ENDR
+ ld a, [hl]
+ ld [de], a
+ ei
+ xor a
+ 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.