code wiki / _hdl_build / nx_timer_irq_emit.nx
nx_timer_irq_emit.nx source
↩ module page · 122 lines · 7366 B
1// nx_timer_irq_emit.nx -- TIMER-INTERRUPT (preemption mechanism) emitter, the foundation slice
2// of the preemptive scheduler (kernel-up ladder, toward census GEN-K-preemptive-smp-scheduler).
3//
4// AUTHOR=ORGAN: table-computes a bare-metal rv64 qemu-virt flat image (zero hand-written machine
5// code) that installs an mtvec trap vector, prints a BOOT marker, arms the CLINT timer
6// (MTIMECMP=0x02004000) + enables mie.MTIE/mstatus.MIE, then SPINS. When MTIME reaches MTIMECMP
7// the CLINT asserts MTIP and the CPU takes the machine-timer trap -> the handler prints a TIMER
8// marker and clean-halts via the SiFive finisher. PROVES timer-interrupt DELIVERY + handling =
9// the mechanism preemption is built on. The GOLDEN transcript ("BT") is TABLE-COMPUTED, byte-
10// reproducibly. Reuses the proven rv64 mini-encoder (same forms as nx_trap_syscall_emit).
11// nx_timer_irq_emit -> writes runtime/_hdl_build/_timer_irq_virt.bin + .gold
12// Next slices: re-arm + multi-tick, then 2-task context-switch = the full scheduler.
13// Sovereign: syscalls only, no gcc/.sh. license_tier: ORIGINAL
14import "nx_syscalls.nx"
15const TI_MAGIC_4096: i64 = 4096
16
17const TI_OUT: *u8 = "runtime/_hdl_build/_timer_irq_virt.bin"
18const TI_GOLD: *u8 = "runtime/_hdl_build/_timer_irq_virt.bin.gold"
19const TI_LOG: *u8 = "knowledge/status/timer_irq.log"
20
21// qemu-virt platform map (data, not magic)
22const TI_UART: i64 = 0x10000000 // NS16550A THR
23const TI_FIN: i64 = 0x100000 // SiFive finisher
24const TI_PASS: i64 = 0x5555 // FINISHER_PASS -> clean halt
25const TI_MTIMECMP: i64 = 0x02004000 // CLINT MTIMECMP[0]
26const TI_TICK: i64 = 0x40 // MTIMECMP value (fires after MTIME reaches it)
27// CSRs
28const TI_MSTATUS: i64 = 0x300
29const TI_MIE: i64 = 0x304
30const TI_MTVEC: i64 = 0x305
31const TI_MIE_MTIE: i64 = 0x80 // mie.MTIE (bit 7)
32const TI_MSTATUS_MIE: i64 = 0x08 // mstatus.MIE (bit 3)
33// markers
34const TI_BOOT_CH: i64 = 66 // 'B'
35const TI_TIMER_CH: i64 = 84 // 'T'
36// rv64 registers
37const RV_X0: i64 = 0
38const RV_T0: i64 = 5
39const RV_T1: i64 = 6
40const RV_T2: i64 = 7
41const RV_T3: i64 = 28
42
43// ---- rv64 mini-encoder (identical forms to nx_trap_syscall_emit, proven) ----
44func ti_lui(rd: i64, imm20: i64) -> i64 { return ((imm20 & 0xFFFFF) << 12) | (rd << 7) | 0x37 }
45func ti_auipc(rd: i64, imm20: i64) -> i64 { return ((imm20 & 0xFFFFF) << 12) | (rd << 7) | 0x17 }
46func ti_addi(rd: i64, rs1: i64, imm: i64) -> i64 { return ((imm & 0xFFF) << 20) | (rs1 << 15) | (rd << 7) | 0x13 }
47func ti_store(rs2: i64, rs1: i64, f3: i64, imm: i64) -> i64 {
48 let hi: i64 = ((imm >> 5) & 0x7f) << 25
49 let lo: i64 = (imm & 0x1f) << 7
50 return hi | (rs2 << 20) | (rs1 << 15) | (f3 << 12) | lo | 0x23
51}
52func ti_jal(rd: i64, imm: i64) -> i64 {
53 let b20: i64 = ((imm >> 20) & 0x1) << 31
54 let b19_12: i64 = ((imm >> 12) & 0xff) << 12
55 let b11: i64 = ((imm >> 11) & 0x1) << 20
56 let b10_1: i64 = ((imm >> 1) & 0x3ff) << 21
57 return b20 | b10_1 | b11 | b19_12 | (rd << 7) | 0x6f
58}
59func ti_csrrw(rd: i64, csr: i64, rs1: i64) -> i64 { return ((csr & 0xFFF) << 20) | (rs1 << 15) | (1 << 12) | (rd << 7) | 0x73 }
60func ti_csrrs(rd: i64, csr: i64, rs1: i64) -> i64 { return ((csr & 0xFFF) << 20) | (rs1 << 15) | (2 << 12) | (rd << 7) | 0x73 }
61
62func ti_w32(buf: *u8, off: i64, w: i64) -> i64 {
63 buf[off] = (w & 0xff) as u8
64 buf[off+1] = ((w >> 8) & 0xff) as u8
65 buf[off+2] = ((w >> 16) & 0xff) as u8
66 buf[off+3] = ((w >> 24) & 0xff) as u8
67 return off + 4
68}
69
70func ti_p(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
71func ti_fp(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 }
72func ti_fn(fd: i64, v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(fd,"-" as *u8,1)}; let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48;k=1}; while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(fd,bb,k); return 0 }
73
74func main() -> i64 {
75 let buf: *u8 = sys_mmap(TI_MAGIC_4096)
76 // BOOT = 14 words (bytes 0..52); HANDLER starts at byte 56.
77 let HANDLER: i64 = 56
78 var o: i64 = 0
79 // install trap vector: t3 = pc(=base) + HANDLER ; mtvec = t3
80 o = ti_w32(buf, o, ti_auipc(RV_T3, 0)) // 0: auipc t3,0 -> t3=base
81 o = ti_w32(buf, o, ti_addi(RV_T3, RV_T3, HANDLER)) // 4: addi t3,t3,56
82 o = ti_w32(buf, o, ti_csrrw(RV_X0, TI_MTVEC, RV_T3)) // 8: csrrw x0,mtvec,t3
83 o = ti_w32(buf, o, ti_lui(RV_T0, TI_UART >> 12)) // 12: lui t0,0x10000 (UART)
84 o = ti_w32(buf, o, ti_addi(RV_T1, RV_X0, TI_BOOT_CH)) // 16: addi t1,'B'
85 o = ti_w32(buf, o, ti_store(RV_T1, RV_T0, 0, 0)) // 20: sb t1,0(t0) -> 'B'
86 o = ti_w32(buf, o, ti_lui(RV_T2, TI_MTIMECMP >> 12)) // 24: lui t2,0x02004 (mtimecmp)
87 o = ti_w32(buf, o, ti_addi(RV_T1, RV_X0, TI_TICK)) // 28: addi t1,0x40
88 o = ti_w32(buf, o, ti_store(RV_T1, RV_T2, 3, 0)) // 32: sd t1,0(t2) -> mtimecmp=64
89 o = ti_w32(buf, o, ti_addi(RV_T1, RV_X0, TI_MIE_MTIE)) // 36: addi t1,0x80
90 o = ti_w32(buf, o, ti_csrrs(RV_X0, TI_MIE, RV_T1)) // 40: csrrs x0,mie,t1 -> MTIE
91 o = ti_w32(buf, o, ti_addi(RV_T1, RV_X0, TI_MSTATUS_MIE)) // 44: addi t1,0x08
92 o = ti_w32(buf, o, ti_csrrs(RV_X0, TI_MSTATUS, RV_T1)) // 48: csrrs x0,mstatus,t1 -> MIE
93 o = ti_w32(buf, o, ti_jal(RV_X0, 0)) // 52: jal x0,0 (SPIN until timer)
94 // HANDLER (byte 56): print 'T', then SiFive finisher -> clean halt
95 o = ti_w32(buf, o, ti_addi(RV_T1, RV_X0, TI_TIMER_CH)) // 56: addi t1,'T'
96 o = ti_w32(buf, o, ti_store(RV_T1, RV_T0, 0, 0)) // 60: sb t1,0(t0) -> 'T'
97 o = ti_w32(buf, o, ti_lui(RV_T1, TI_PASS >> 12)) // 64: lui t1,0x5 -> 0x5000
98 o = ti_w32(buf, o, ti_addi(RV_T1, RV_T1, TI_PASS & 0xFFF)) // 68: addi t1,t1,0x555 -> 0x5555
99 o = ti_w32(buf, o, ti_lui(RV_T2, TI_FIN >> 12)) // 72: lui t2,0x100 -> 0x100000
100 o = ti_w32(buf, o, ti_store(RV_T1, RV_T2, 2, 0)) // 76: sw t1,0(t2) -> finisher PASS (halt)
101 o = ti_w32(buf, o, ti_jal(RV_X0, 0)) // 80: jal x0,0 (guard, never reached)
102
103 let fd: i64 = sys_openat_wr(TI_OUT, 420)
104 if fd < 0 { ti_p("TIMERIRQEMIT verdict=RED reason=out-unwritable\n" as *u8); return 1 }
105 sys_write(fd, buf, o)
106 sys_close(fd)
107
108 // TABLE-COMPUTED golden transcript: boot marker then timer marker.
109 let gold: *u8 = sys_mmap(16)
110 gold[0] = TI_BOOT_CH as u8
111 gold[1] = TI_TIMER_CH as u8
112 let gfd: i64 = sys_openat_wr(TI_GOLD, 420)
113 if gfd < 0 { ti_p("TIMERIRQEMIT verdict=RED reason=gold-unwritable\n" as *u8); return 1 }
114 sys_write(gfd, gold, 2)
115 sys_close(gfd)
116
117 ti_p("TIMERIRQEMIT name=" as *u8); ti_p(TI_OUT); ti_p(" machine=virt bytes=" as *u8); ti_fn(1, o)
118 ti_p(" golden=BT\n" as *u8)
119 let lf: i64 = sys_openat_append(TI_LOG, 420)
120 if lf >= 0 { ti_fp(lf, "TIMERIRQEMIT name=" as *u8); ti_fp(lf, TI_OUT); ti_fp(lf, " machine=virt bytes=" as *u8); ti_fn(lf, o); ti_fp(lf, " golden=BT epoch=" as *u8); ti_fn(lf, sys_now_realtime_sec()); ti_fp(lf, "\n" as *u8); sys_close(lf) }
121 return 0
122}