code wiki / _hdl_build / nx_rv64_csr_trap_oracle.nx
nx_rv64_csr_trap_oracle.nx source
↩ module page · 104 lines · 7970 B
1// nx_rv64_csr_trap_oracle.nx -- ROADMAP R2 (Zicsr + privilege conformance): validate the golden sim's CSR + TRAP
2// machinery against real QEMU. The golden sim (rv64im_min_sim) has a full privileged CPU (ecall/mret, mtvec/mepc/
3// mcause, S-mode delegation, Sv39 MMU) but it has NEVER been diff-tested vs the world reference (the fuzz fleet is
4// RV64IM-base only). This emits a deterministic CSR+M-mode-trap program: CSR round-trip (csrrw/csrrs on mscratch) +
5// an ecall that traps to a handler (reads mcause=11=ecall-from-M, bumps mepc past the ecall, mret's back). Runs it on
6// the golden sim (UART capture) + writes the binary so the SAME bytes run in qemu-system-riscv64. expect UART = ab ff
7// 0b 2a. expect_exit: 0 NEVER-BRICK: simulation, writes 0 hardware state.
8import "nx_syscalls.nx"
9import "nishi_hdl_primitives.nx"
10import "rv64im_min_decoder.nx"
11import "rv64im_min_alu.nx"
12import "rv64im_min_regfile.nx"
13import "rv64im_min_csr.nx"
14import "rv64im_min_clint.nx"
15import "rv64im_min_uart.nx"
16import "rv64im_min_virtio.nx"
17import "rv64im_min_sim.nx"
18import "nx_rv64_asm.nx"
19const DMEM_MAGIC_4096: i64 = 4096
20const DMEM_MAGIC_10000000: i64 = 10000000
21
22func g_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
23func g_pn(v: i64) -> i64 { let b: *u8=sys_mmap(28); var x: i64=v; if x==0{b[0]=48;sys_write(1,b,1);return 0} var d: i64=0; var y: i64=x; while y>0{d=d+1;y=y/10} var i: i64=d-1; y=x; while i>=0{b[i]=(48+(y%10)) as u8;y=y/10;i=i-1} sys_write(1,b,d); return 0 }
24func g_hx(v: i64) -> i64 { let b: *u8=sys_mmap(4); let n0: i64=(v>>4)&15; let n1: i64=v&15; if n0<10 { b[0]=(48+n0) as u8 } else { b[0]=(87+n0) as u8 } if n1<10 { b[1]=(48+n1) as u8 } else { b[1]=(87+n1) as u8 } b[2]=32 as u8; sys_write(1,b,3); return 0 }
25func ck(name: *u8, c: i64) -> i64 { if c==1 { g_puts(" PASS " as *u8) } else { g_puts(" FAIL " as *u8) } g_puts(name); g_puts("\n" as *u8); return c }
26
27const DMEM_BASE: i64 = 0x80000000
28const DMEM_SIZE: i64 = 65536
29const CSR_MSCRATCH: i64 = 0x340
30const CSR_MTVEC: i64 = 0x305
31const CSR_MEPC: i64 = 0x341
32const CSR_MCAUSE: i64 = 0x342
33
34func main() -> i64 {
35 g_puts("nx_rv64_csr_trap_oracle (R2: CSR + M-mode trap round-trip on the golden sim, binary for the QEMU diff)\n" as *u8)
36 var pass: i64=0; var total: i64=0
37 let code: *u8=sys_mmap(DMEM_MAGIC_4096); let po: *i64=sys_mmap(8) as *i64; po[0]=0
38 // setup: x1=UART 0x10000000, x2=finisher 0x100000, x3=0x5555
39 po[0]=ra_put(code, po[0], ra_u(0x37, 1, 0x10000)); po[0]=ra_put(code, po[0], ra_u(0x37, 2, 0x100))
40 po[0]=ra_put(code, po[0], ra_u(0x37, 3, 0x5)); po[0]=ra_put(code, po[0], ra_i(0x13, 0, 3, 3, 0x555))
41 // CSR round-trip: mscratch = 0xAB, read back into x6
42 po[0]=ra_put(code, po[0], ra_i(0x13, 0, 5, 0, 0xAB)) // addi x5,x0,0xAB
43 po[0]=ra_put(code, po[0], ra_i(0x73, 1, 0, 5, CSR_MSCRATCH)) // csrrw x0, mscratch, x5
44 po[0]=ra_put(code, po[0], ra_i(0x73, 2, 6, 0, CSR_MSCRATCH)) // csrrs x6, mscratch, x0 -> x6=0xAB
45 // csrrs set-bits: mscratch=0x0F, then set 0xF0 -> read new 0xFF into x10
46 po[0]=ra_put(code, po[0], ra_i(0x13, 0, 7, 0, 0x0F)) // addi x7,x0,0x0F
47 po[0]=ra_put(code, po[0], ra_i(0x73, 1, 0, 7, CSR_MSCRATCH)) // csrrw x0, mscratch, x7
48 po[0]=ra_put(code, po[0], ra_i(0x13, 0, 8, 0, 0xF0)) // addi x8,x0,0xF0
49 po[0]=ra_put(code, po[0], ra_i(0x73, 2, 9, 8, CSR_MSCRATCH)) // csrrs x9, mscratch, x8 (set 0xF0)
50 po[0]=ra_put(code, po[0], ra_i(0x73, 2, 10, 0, CSR_MSCRATCH)) // csrrs x10, mscratch, x0 -> x10=0xFF
51 // trap setup: x12 = handler addr via auipc (position-independent), then csrw mtvec
52 let auipc_off: i64 = po[0]
53 po[0]=ra_put(code, po[0], ra_u(0x17, 12, 0)) // auipc x12, 0 -> x12 = this pc = 0x80000000+auipc_off
54 let addi_pos: i64 = po[0]
55 po[0]=ra_put(code, po[0], ra_i(0x13, 0, 12, 12, 0)) // addi x12, x12, <patched: handler_off - auipc_off>
56 po[0]=ra_put(code, po[0], ra_i(0x73, 1, 0, 12, CSR_MTVEC)) // csrrw x0, mtvec, x12
57 po[0]=ra_put(code, po[0], ra_i(0x73, 0, 0, 0, 0)) // ecall (M-mode -> mcause=11)
58 // --- mret returns HERE (ecall+4) --- emit x6, x10, x11(mcause), sentinel; halt
59 po[0]=ra_put(code, po[0], ra_s(0x23, 0, 1, 6, 0)) // sb x6, 0(x1) -> 0xAB
60 po[0]=ra_put(code, po[0], ra_s(0x23, 0, 1, 10, 0)) // sb x10,0(x1) -> 0xFF
61 po[0]=ra_put(code, po[0], ra_s(0x23, 0, 1, 11, 0)) // sb x11,0(x1) -> 0x0B (mcause)
62 po[0]=ra_put(code, po[0], ra_i(0x13, 0, 13, 0, 0x2A)) // addi x13,x0,0x2A
63 po[0]=ra_put(code, po[0], ra_s(0x23, 0, 1, 13, 0)) // sb x13,0(x1) -> 0x2A sentinel
64 po[0]=ra_put(code, po[0], ra_s(0x23, 2, 2, 3, 0)) // sw x3,0(x2) finisher halt
65 // handler (offset H): read mcause -> x11, bump mepc past ecall, mret
66 let handler_off: i64 = po[0]
67 po[0]=ra_put(code, po[0], ra_i(0x73, 2, 11, 0, CSR_MCAUSE)) // csrrs x11, mcause, x0
68 po[0]=ra_put(code, po[0], ra_i(0x73, 2, 14, 0, CSR_MEPC)) // csrrs x14, mepc, x0
69 po[0]=ra_put(code, po[0], ra_i(0x13, 0, 14, 14, 4)) // addi x14,x14,4 (skip the ecall)
70 po[0]=ra_put(code, po[0], ra_i(0x73, 1, 0, 14, CSR_MEPC)) // csrrw x0, mepc, x14
71 po[0]=ra_put(code, po[0], ra_i(0x73, 0, 0, 0, 0x302)) // mret
72 let nb: i64 = po[0]
73 // patch the addi immediate = handler_off - auipc_off (auipc gave 0x80000000+auipc_off; +delta = 0x80000000+H)
74 ra_put(code, addi_pos, ra_i(0x13, 0, 12, 12, handler_off - auipc_off))
75
76 g_puts(" emitted "); g_pn(nb/4); g_puts(" instructions; handler at byte "); g_pn(handler_off); g_puts("\n" as *u8)
77
78 // run on the golden sim (full privileged CPU)
79 let rf_storage: *i64=sys_mmap(8*NX_RV64IM_RF_N_REGS) as *i64; let csr_storage: *i64=sys_mmap(8*NX_CSR_SLOT_N) as *i64
80 let clint_storage: *i64=sys_mmap(8*NX_CLINT_SLOT_N) as *i64; let uart_storage: *i64=sys_mmap(8*NX_UART_SLOT_N) as *i64
81 let mem: *u8=sys_mmap(DMEM_SIZE); let tx_buf: *u8=sys_mmap(256)
82 let rf: *NxRv64imRegfile=sys_mmap(64) as *NxRv64imRegfile; let csr: *NxRv64imCsrFile=sys_mmap(64) as *NxRv64imCsrFile
83 let clint: *NxClint=sys_mmap(64) as *NxClint; let uart: *NxUart=sys_mmap(64) as *NxUart; let sim: *NxRv64imSim=sys_mmap(128) as *NxRv64imSim
84 nx_rv64im_rf_init(rf, rf_storage); nx_rv64im_csr_init(csr, csr_storage, 0); nx_clint_init(clint, clint_storage); nx_uart_init(uart, uart_storage, tx_buf, 256)
85 nx_rv64im_sim_init(sim, rf, csr, clint, uart, DMEM_BASE, mem, DMEM_SIZE, 0)
86 var i: i64=0; while i<nb { mem[i]=code[i]; i=i+1 }
87 nx_rv64im_sim_run(sim, DMEM_MAGIC_10000000)
88 let n: i64=nx_uart_tx_count(uart)
89 g_puts(" golden sim UART ("); g_pn(n); g_puts(" bytes): "); i=0; while i<n { g_hx(tx_buf[i] as i64); i=i+1 } g_puts("\n" as *u8)
90 g_puts(" expected : ab ff 0b 2a (mscratch RW=0xAB, csrrs-set=0xFF, mcause=0x0B ecall-from-M, sentinel)\n" as *u8)
91
92 var t1: i64=0
93 if n==4 { if tx_buf[0]==(0xab as u8) { if tx_buf[1]==(0xff as u8) { if tx_buf[2]==(0x0b as u8) { if tx_buf[3]==(0x2a as u8) { t1=1 } } } } }
94 pass=pass+ck("T1: golden sim executes CSR round-trip + M-mode ecall/mret trap -> UART = ab ff 0b 2a" as *u8, t1); total=total+1
95
96 let fd: i64=sys_openat_wr("knowledge/hw/csrtrap.bin" as *u8, 420)
97 var t2: i64=0; if fd>=0 { let wn: i64=sys_write(fd, code, nb); sys_close(fd); if wn==nb { t2=1 } }
98 pass=pass+ck("T2: flat binary written to knowledge/hw/csrtrap.bin for the QEMU cross-check" as *u8, t2); total=total+1
99
100 var okall: i64=0; if pass==total { okall=1 }
101 g_puts("---- nx_rv64_csr_trap_oracle: passed "); g_pn(pass); g_puts(" / "); g_pn(total); g_puts(" ----\n" as *u8)
102 if okall==1 { g_puts("verdict=GREEN (golden-sim CSR+trap bytes emitted + binary written; run in qemu-system-riscv64 and diff)\n" as *u8); sys_exit(0); return 0 }
103 g_puts("verdict=RED\n" as *u8); sys_exit(1); return 1
104}