code wiki / _hdl_build / nx_alu_divider_alu_test.nx
nx_alu_divider_alu_test.nx source
↩ module page · 199 lines · 8580 B
1// nx_alu_divider_alu_test.nx -- HARDWARE INVENTIONS verified IN the ALU. Builds
2// the ALU op-select netlist with the proven restoring divider (nx_div_synth)
3// wired into DIV/DIVU/REM/REMU AND the proven wide multiplier (nx_mul_wide) wired
4// into MULH/MULHSU/MULHU (high-product + sign corrections), then censuses every
5// op vs the behavioral oracle nx_rv64im_alu_compute. Compared to the stub census
6// (gate_nx_alu_netlist_full = match 17 / diverge 11), seven ops FLIP to MATCH:
7// the Verifier PROVES the divider + the mulh high-product replaced the stubs,
8// gate-level, inside the full ALU.
9//
10// a=20 b=4. Known answer (FAIL LOUD): "covered=28 match=28 diverge=0" rc=0 --
11// the FULL RV64IM ALU verified gate-level, ZERO holes. All 28 ops match behavioral:
12// the divider (DIV/DIVU/REM/REMU), the wide-mul high-product (MULH/MULHSU/MULHU),
13// and the 32-bit W-variants (DIVUW/REMUW/DIVW/REMW, mask->32-bit divide->sext32,
14// signed via abs+sign-correct). Hardened: divider 5 vectors, mulh 5 (neg/max),
15// W-unsigned 5 (large/sext/div0), W-signed 6 (all sign combos + INT_MIN/-1 + div0).
16
17import "nx_alu_netlist_build_div.nx"
18import "rv64im_min_alu.nx"
19
20func _emit_cstr(s: *u8) -> i64 {
21 var n: i64 = 0
22 while s[n] != (0 as u8) { n = n + 1 }
23 sys_write(1, s, n)
24 return 0
25}
26
27func _emit_dec(v: i64) -> i64 {
28 let b: *u8 = sys_mmap(28)
29 let t2: *u8 = sys_mmap(28)
30 var n: i64 = v
31 if n < 0 { n = 0 - n }
32 var t: i64 = 0
33 if n == 0 { t2[0] = 48; t = 1 }
34 while n > 0 { t2[t] = 48 + (n % 10); n = n / 10; t = t + 1 }
35 var i: i64 = 0
36 while i < t { b[i] = t2[t - 1 - i]; i = i + 1 }
37 sys_write(1, b, t)
38 return 0
39}
40
41// Re-evaluate the netlist for (a,b) at op, return 1 iff gate == behavioral.
42func _div_check(g: *NxGsim, info: *NxAluNetlist, a: i64, b: i64, op: i64) -> i64 {
43 g.vals[NX_ALUNL_A] = a
44 g.vals[NX_ALUNL_B] = b
45 g.vals[NX_ALUNL_OPIN] = op
46 if nx_gsim_run(g) != NX_GSIM_OK { return 0 - 1 }
47 let got: i64 = g.vals[info.result]
48 let beh: i64 = nx_rv64im_alu_compute(op, a, b)
49 if got == beh { return 1 }
50 return 0
51}
52
53func main() -> i64 {
54 let cells: *NxGsimCell = sys_mmap(48 * 8000) as *NxGsimCell
55 let vals: *i64 = sys_mmap(8 * 8000) as *i64
56 let info: *NxAluNetlist = sys_mmap(64) as *NxAluNetlist
57 let g: *NxGsim = sys_mmap(64) as *NxGsim
58
59 g.vals = vals
60 g.cells = cells
61 nx_alu_netlist_build_div(g, info)
62 g.n_nets = info.n_nets
63 g.n_cells = info.n_cells
64
65 let a: i64 = 20
66 let b: i64 = 4
67
68 var n_match: i64 = 0
69 var n_div: i64 = 0
70 var div_ok: i64 = 0
71 var divu_ok: i64 = 0
72 var rem_ok: i64 = 0
73 var remu_ok: i64 = 0
74 var mhu_ok: i64 = 0
75 var mh_ok: i64 = 0
76 var mhsu_ok: i64 = 0
77 var divuw_ok: i64 = 0
78 var remuw_ok: i64 = 0
79 var divw_ok: i64 = 0
80 var remw_ok: i64 = 0
81
82 var op: i64 = 1
83 while op < NX_RV64IM_ALU_N {
84 vals[NX_ALUNL_A] = a
85 vals[NX_ALUNL_B] = b
86 vals[NX_ALUNL_OPIN] = op
87 if nx_gsim_run(g) != NX_GSIM_OK { sys_exit(40); return 40 }
88 let got: i64 = vals[info.result]
89 let beh: i64 = nx_rv64im_alu_compute(op, a, b)
90 if got == beh { n_match = n_match + 1 }
91 if got != beh { n_div = n_div + 1 }
92 if op == NX_RV64IM_ALU_DIV { if got == beh { div_ok = 1 } }
93 if op == NX_RV64IM_ALU_DIVU { if got == beh { divu_ok = 1 } }
94 if op == NX_RV64IM_ALU_REM { if got == beh { rem_ok = 1 } }
95 if op == NX_RV64IM_ALU_REMU { if got == beh { remu_ok = 1 } }
96 if op == NX_RV64IM_ALU_MULHU { if got == beh { mhu_ok = 1 } }
97 if op == NX_RV64IM_ALU_MULH { if got == beh { mh_ok = 1 } }
98 if op == NX_RV64IM_ALU_MULHSU { if got == beh { mhsu_ok = 1 } }
99 if op == NX_RV64IM_ALU_DIVUW { if got == beh { divuw_ok = 1 } }
100 if op == NX_RV64IM_ALU_REMUW { if got == beh { remuw_ok = 1 } }
101 if op == NX_RV64IM_ALU_DIVW { if got == beh { divw_ok = 1 } }
102 if op == NX_RV64IM_ALU_REMW { if got == beh { remw_ok = 1 } }
103 op = op + 1
104 }
105
106 _emit_cstr("covered=" as *u8)
107 _emit_dec(NX_RV64IM_ALU_N - 1)
108 _emit_cstr(" match=" as *u8)
109 _emit_dec(n_match)
110 _emit_cstr(" diverge=" as *u8)
111 _emit_dec(n_div)
112 _emit_cstr("\n" as *u8)
113
114 // Harden: the divider must match behavioral over MORE than the census vector
115 // -- q>1, r>0, a==b (q=1,r=0), a<b (q=0,r=a) -- across all 4 div/rem ops.
116 // Refutes "matches 24->5 by coincidence at (20,4)".
117 let av: *i64 = sys_mmap(8 * 5) as *i64
118 let bv: *i64 = sys_mmap(8 * 5) as *i64
119 av[0] = 100; bv[0] = 7
120 av[1] = 255; bv[1] = 16
121 av[2] = 1000; bv[2] = 3
122 av[3] = 42; bv[3] = 42
123 av[4] = 7; bv[4] = 9
124 var vi: i64 = 0
125 while vi < 5 {
126 if _div_check(g, info, av[vi], bv[vi], NX_RV64IM_ALU_DIV) != 1 { sys_exit(10); return 10 }
127 if _div_check(g, info, av[vi], bv[vi], NX_RV64IM_ALU_DIVU) != 1 { sys_exit(11); return 11 }
128 if _div_check(g, info, av[vi], bv[vi], NX_RV64IM_ALU_REM) != 1 { sys_exit(12); return 12 }
129 if _div_check(g, info, av[vi], bv[vi], NX_RV64IM_ALU_REMU) != 1 { sys_exit(13); return 13 }
130 vi = vi + 1
131 }
132
133 // Harden mulh: exercise the sign corrections (negative operands) + a nonzero
134 // high product, across MULH / MULHU / MULHSU vs behavioral.
135 let ma: *i64 = sys_mmap(8 * 5) as *i64
136 let mb: *i64 = sys_mmap(8 * 5) as *i64
137 ma[0] = 0 - 5; mb[0] = 3 // a<0 correction
138 ma[1] = 7; mb[1] = 0 - 3 // b<0 correction
139 ma[2] = 0 - 5; mb[2] = 0 - 3 // both
140 ma[3] = 1099511627776; mb[3] = 1099511627776 // 2^40 * 2^40 = 2^80 -> hi = 2^16 (nonzero)
141 ma[4] = 0 - 1; mb[4] = 0 - 1 // max-magnitude
142 var mi: i64 = 0
143 while mi < 5 {
144 if _div_check(g, info, ma[mi], mb[mi], NX_RV64IM_ALU_MULH) != 1 { sys_exit(20); return 20 }
145 if _div_check(g, info, ma[mi], mb[mi], NX_RV64IM_ALU_MULHU) != 1 { sys_exit(21); return 21 }
146 if _div_check(g, info, ma[mi], mb[mi], NX_RV64IM_ALU_MULHSU) != 1 { sys_exit(22); return 22 }
147 mi = mi + 1
148 }
149
150 if div_ok != 1 { sys_exit(1); return 1 } // DIV now matches behavioral (divider, not stub)
151 if divu_ok != 1 { sys_exit(2); return 2 }
152 if rem_ok != 1 { sys_exit(3); return 3 }
153 if remu_ok != 1 { sys_exit(4); return 4 }
154 if mhu_ok != 1 { sys_exit(5); return 5 } // mulhu now high-product via wide multiplier
155 if mh_ok != 1 { sys_exit(6); return 6 }
156 if mhsu_ok != 1 { sys_exit(7); return 7 }
157
158 // Harden the W-suffix unsigned div/rem: large 32-bit operands, a bit-31-set
159 // quotient (exercises sext32), and the div-by-zero edge.
160 let wa: *i64 = sys_mmap(8 * 5) as *i64
161 let wb: *i64 = sys_mmap(8 * 5) as *i64
162 wa[0] = 4000000000; wb[0] = 7 // large unsigned 32-bit
163 wa[1] = 4294967294; wb[1] = 1 // q=0xFFFFFFFE -> sext32 negative
164 wa[2] = 100; wb[2] = 0 // div-by-zero edge
165 wa[3] = 4294967295; wb[3] = 65535
166 wa[4] = 1000000; wb[4] = 999 // r>0
167 var wi: i64 = 0
168 while wi < 5 {
169 if _div_check(g, info, wa[wi], wb[wi], NX_RV64IM_ALU_DIVUW) != 1 { sys_exit(23); return 23 }
170 if _div_check(g, info, wa[wi], wb[wi], NX_RV64IM_ALU_REMUW) != 1 { sys_exit(24); return 24 }
171 wi = wi + 1
172 }
173
174 // Harden the W-suffix SIGNED div/rem: all four sign combinations, the
175 // INT_MIN/-1 overflow case, div-by-zero, and a remainder-sign case.
176 let sa: *i64 = sys_mmap(8 * 6) as *i64
177 let sb: *i64 = sys_mmap(8 * 6) as *i64
178 sa[0] = 0 - 7; sb[0] = 2 // -/+
179 sa[1] = 7; sb[1] = 0 - 2 // +/-
180 sa[2] = 0 - 7; sb[2] = 0 - 2 // -/-
181 sa[3] = 0 - 2147483648; sb[3] = 0 - 1 // INT_MIN / -1 overflow
182 sa[4] = 100; sb[4] = 0 // div-by-zero
183 sa[5] = 0 - 100; sb[5] = 7 // remainder sign
184 var si: i64 = 0
185 while si < 6 {
186 if _div_check(g, info, sa[si], sb[si], NX_RV64IM_ALU_DIVW) != 1 { sys_exit(25); return 25 }
187 if _div_check(g, info, sa[si], sb[si], NX_RV64IM_ALU_REMW) != 1 { sys_exit(26); return 26 }
188 si = si + 1
189 }
190
191 if divuw_ok != 1 { sys_exit(8); return 8 }
192 if remuw_ok != 1 { sys_exit(9); return 9 }
193 if divw_ok != 1 { sys_exit(10); return 10 }
194 if remw_ok != 1 { sys_exit(11); return 11 }
195 if n_match != 28 { sys_exit(12); return 12 }
196 if n_div != 0 { sys_exit(13); return 13 }
197 sys_exit(0)
198 return 0
199}