code wiki / _hdl_build / nx_alu_netlist_full_test.nx

nx_alu_netlist_full_test.nx source

↩ module page · 99 lines · 3656 B

1// nx_alu_netlist_full_test.nx -- SIL-3 VERIFIER over the FULL 29-op ALU. 2// 3// Builds the ALU op-select netlist via nx_alu_netlist_build (the ONE source the 4// text emitter also derives from), then for EVERY op K in 1..28 runs the 5// gate-level functional sim and diffs vs the behavioral oracle 6// nx_rv64im_alu_compute(K, a, b). This is the closure of "consume the ACTUAL 7// emitter topology + diff vs behavioral over all 29 ops": where the seed 8// emitter is faithful the sim MATCHES; where it stubs (DIV/REM->ADD, mulh->MUL) 9// the sim DIVERGES -- the verifier CATCHES every silent gate-emit hole, not just 10// DIV. That divergence set is the 5W1H feedback the Generator consumes. 11// 12// a=20 b=4. Known answer (FAIL LOUD): "covered=28 match=17 diverge=11" rc=0. 13// 17 faithful: ADD SUB AND OR XOR SLL SRL SRA SLT SLTU MUL ADDW SUBW SLLW 14// SRLW SRAW MULW (all single-cell ops the seed lowers exactly) 15// 11 holes: MULH MULHSU MULHU (low-product MUL, want high) + 16// DIV DIVU REM REMU DIVW DIVUW REMW REMUW (ADD stub, want divider) 17// When a real divider sub-network replaces the DIV stub in nx_alu_op_to_gate_kind, 18// this same gate flips DIV from DIVERGE to MATCH -- the first HW invention. 19 20import "nx_alu_netlist_build.nx" 21import "rv64im_min_alu.nx" 22 23func _emit_cstr(s: *u8) -> i64 { 24 var n: i64 = 0 25 while s[n] != (0 as u8) { n = n + 1 } 26 sys_write(1, s, n) 27 return 0 28} 29 30func _emit_dec(v: i64) -> i64 { 31 let b: *u8 = sys_mmap(28) 32 let t2: *u8 = sys_mmap(28) 33 var n: i64 = v 34 if n < 0 { n = 0 - n } 35 var t: i64 = 0 36 if n == 0 { t2[0] = 48; t = 1 } 37 while n > 0 { t2[t] = 48 + (n % 10); n = n / 10; t = t + 1 } 38 var i: i64 = 0 39 while i < t { b[i] = t2[t - 1 - i]; i = i + 1 } 40 sys_write(1, b, t) 41 return 0 42} 43 44func main() -> i64 { 45 let cells: *NxGsimCell = sys_mmap(48 * 160) as *NxGsimCell 46 let vals: *i64 = sys_mmap(8 * 160) as *i64 47 let info: *NxAluNetlist = sys_mmap(64) as *NxAluNetlist 48 let g: *NxGsim = sys_mmap(64) as *NxGsim 49 50 nx_alu_netlist_build(cells, info) 51 52 g.vals = vals 53 g.n_nets = info.n_nets 54 g.cells = cells 55 g.n_cells = info.n_cells 56 57 let a: i64 = 20 58 let b: i64 = 4 59 60 var n_match: i64 = 0 61 var n_div: i64 = 0 62 var add_ok: i64 = 0 63 var div_caught: i64 = 0 64 var mulh_caught: i64 = 0 65 66 var op: i64 = 1 67 while op < NX_RV64IM_ALU_N { 68 vals[NX_ALUNL_A] = a 69 vals[NX_ALUNL_B] = b 70 vals[NX_ALUNL_OPIN] = op 71 if nx_gsim_run(g) != NX_GSIM_OK { sys_exit(40); return 40 } 72 let got: i64 = vals[info.result] 73 let beh: i64 = nx_rv64im_alu_compute(op, a, b) 74 if got == beh { n_match = n_match + 1 } 75 if got != beh { n_div = n_div + 1 } 76 if op == NX_RV64IM_ALU_ADD { if got == beh { add_ok = 1 } } 77 if op == NX_RV64IM_ALU_DIV { if got != beh { div_caught = 1 } } 78 if op == NX_RV64IM_ALU_MULH { if got != beh { mulh_caught = 1 } } 79 op = op + 1 80 } 81 82 _emit_cstr("covered=" as *u8) 83 _emit_dec(NX_RV64IM_ALU_N - 1) 84 _emit_cstr(" match=" as *u8) 85 _emit_dec(n_match) 86 _emit_cstr(" diverge=" as *u8) 87 _emit_dec(n_div) 88 _emit_cstr("\n" as *u8) 89 90 // Anchors: the verifier must (1) accept a faithful op, (2) catch the DIV 91 // stub, (3) catch a mulh stub -- then the exact census counts. 92 if add_ok != 1 { sys_exit(1); return 1 } 93 if div_caught != 1 { sys_exit(2); return 2 } 94 if mulh_caught != 1 { sys_exit(3); return 3 } 95 if n_match != 17 { sys_exit(4); return 4 } 96 if n_div != 11 { sys_exit(5); return 5 } 97 sys_exit(0) 98 return 0 99}