code wiki / (root) / nx_smoke_sim.nx

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}