nx_smoke_sim.nx source
↩ module page · 97 lines · 3573 B
1// nx_smoke_sim.nx -- end-to-end smoke test of the off-C run-loop.
2//
3// Hand-builds a minimal RV64 Linux ELF that exits with code 42,
4// loads it via nx_loader, runs it via nx_rv64_sim, asserts the
5// exit code matches. Proves the OFF-C verification path works
6// without docker / qemu.
7//
8// This is the smallest possible end-to-end demonstration of the
9// sovereign run-loop:
10//
11// 1. Bytes shaped like an ELF -> nx_loader places PT_LOAD
12// segment at vaddr 0x10000.
13// 2. Entry pc = 0x10000 + 120; PC walks 3 instructions:
14// addi a0, zero, 42 -- a0 = 42
15// addi a7, zero, 93 -- a7 = sys_exit
16// ecall -- syscall(93, 42, ...)
17// 3. nx_rv64_sim's syscall handler sees nr=93, halts cpu,
18// records exit_code = 42.
19// 4. We assert cpu.halted=1 + cpu.exit_code=42.
20//
21// Run: produces a 0 exit code on success, non-zero on any failure.
22//
23// Pairs with bootstrap_native.sh as the proof-of-concept that the
24// in-NishiLang sim is a viable qemu replacement.
25
26// nx_safety_envelope:
27// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
28// sil_target: SIL1
29// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
30// verdict: NOT_YET_EVALUATED
31
32import "syscalls.nx"
33import "nx_loader.nx"
34import "nx_rv64_sim.nx"
35
36// Build the same ELF that nx_loader's self-test does, then run it.
37func main() -> i64 {
38 // Construct a minimal ELF in memory:
39 // header (64) + 1 program header (56) + 12 bytes of code
40 // total = 132 bytes; vaddr = 0x10000; entry = 0x10000 + 120
41 let elf: *u8 = sys_mmap(256)
42 var i: i64 = 0
43 while i < 256 { elf[i] = 0; i = i + 1 }
44
45 elf[0] = 0x7F; elf[1] = 0x45; elf[2] = 0x4C; elf[3] = 0x46
46 elf[4] = 2; elf[5] = 1; elf[6] = 1
47 elf[16] = 2 // ET_EXEC
48 elf[18] = 0xF3 // EM_RISCV
49 elf[24] = 0x78; elf[25] = 0x00; elf[26] = 0x01; elf[27] = 0x00 // entry = 0x10078
50 elf[32] = 64 // phoff
51 elf[52] = 64 // ehsize
52 elf[54] = 56 // phentsize
53 elf[56] = 1 // phnum
54
55 // Program header at offset 64.
56 elf[64] = 1 // PT_LOAD
57 elf[68] = 5 // R|X
58 elf[72] = 120 // p_offset
59 elf[80] = 0x00; elf[81] = 0x00; elf[82] = 0x01; elf[83] = 0x00 // p_vaddr = 0x10000
60 elf[96] = 12 // p_filesz
61 elf[104] = 12 // p_memsz
62
63 // Code: addi a0, zero, 42 ; addi a7, zero, 93 ; ecall
64 elf[120] = 0x13; elf[121] = 0x05; elf[122] = 0xA0; elf[123] = 0x02
65 elf[124] = 0x93; elf[125] = 0x08; elf[126] = 0xD0; elf[127] = 0x05
66 elf[128] = 0x73; elf[129] = 0x00; elf[130] = 0x00; elf[131] = 0x00
67
68 // Allocate a 1 MB sim memory and load the segment.
69 let mem: *u8 = sys_mmap(0x20000)
70 let entry: i64 = nx_loader_load(elf, 132, mem, 0x20000)
71 if entry != 0x10078 {
72 sys_write(2, "smoke: load failed\n" as *u8, 19)
73 return 1
74 }
75
76 // Spin up CPU + run.
77 let cpu: *NxRv64Cpu = nx_rv64_cpu_new(mem, 0x20000, entry)
78 nx_rv64_cpu_set_sp(cpu, 0x20000 - 64)
79 let r: i64 = nx_rv64_run(cpu, 1000)
80 if r != 0 {
81 sys_write(2, "smoke: run failed\n" as *u8, 18)
82 return 2
83 }
84 if cpu.halted != 1 {
85 sys_write(2, "smoke: not halted\n" as *u8, 18)
86 return 3
87 }
88 if cpu.exit_code != 42 {
89 sys_write(2, "smoke: wrong exit code\n" as *u8, 23)
90 return 4
91 }
92
93 // Success: verifies that on this host, the in-NishiLang
94 // simulator can run a complete RV64 ELF end-to-end.
95 sys_write(2, "smoke: off-C run-loop OK -- exit=42 as expected\n" as *u8, 48)
96 return 0
97}