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}