code wiki / _hdl_build / nx_alu_divider_floor_test.nx
nx_alu_divider_floor_test.nx source
↩ module page · 87 lines · 3857 B
1// nx_alu_divider_floor_test.nx -- COMPLETE THE FLOOR (honest step 0 toward the
2// real divider exceed). The original floor was incomplete: it used a SIGNED
3// compare for an unsigned remainder, so it broke for large operands (the rem<<1
4// overflow into the sign bit). Now the divider uses LTU (true unsigned compare),
5// so it is correct over the FULL non-negative i64 range, INCLUDING the large-b
6// overflow cases the signed compare got wrong.
7//
8// Verified here at width 63 over the whole non-negative range: 200000 randomized
9// (a,b) in [0, 2^63) via an LCG -- which naturally exercises b in (2^62, 2^63)
10// where rem<<1 overflows the sign bit and LTU is REQUIRED -- plus a few edges,
11// each checked 1:1 vs behavioral a/b + a%b (signed `/` is a valid oracle since
12// both operands are < 2^63). HONEST: this is heavy RANDOMIZED testing over the
13// full range (exhaustive is impossible at 63-bit) -- a completed FLOOR, NOT yet
14// the machine-checked-proof EXCEED (that needs a sovereign BMC/equivalence
15// engine; full 64-bit unsigned with b>=2^63 needs >64-bit intermediates; signed
16// division also still owed).
17//
18// Known answer (FAIL LOUD): "200003 200003 " (ok, total). exit 0 iff ok==total.
19
20import "nx_alu_divider.nx"
21
22const MASK63: i64 = 9223372036854775807 // 2^63 - 1
23const LCG_A: i64 = 6364136223846793005
24const LCG_C: i64 = 1442695040888963407
25
26func _emit_num(v: i64) -> i64 {
27 let b: *u8 = sys_mmap(28); var n: i64 = v; if n < 0 { n = 0 - n }
28 let t2: *u8 = sys_mmap(28); var t: i64 = 0
29 if n == 0 { t2[0] = 48; t = 1 }
30 while n > 0 { t2[t] = 48 + (n % 10); n = n / 10; t = t + 1 }
31 var i: i64 = 0; while i < t { b[i] = t2[t - 1 - i]; i = i + 1 }
32 b[t] = 32; sys_write(1, b, t + 1); return 0
33}
34func _nl() -> i64 { let z: *u8 = sys_mmap(2); z[0] = 10; sys_write(1, z, 1); return 0 }
35
36func main() -> i64 {
37 let vals: *i64 = sys_mmap(1024 * 8) as *i64
38 let cells: *NxGsimCell = sys_mmap(1024 * 48) as *NxGsimCell
39 let g: *NxGsim = sys_mmap(64) as *NxGsim
40 g.vals = vals; g.n_nets = 2; g.cells = cells; g.n_cells = 0
41 let ro: *i64 = sys_mmap(8) as *i64; ro[0] = 0
42 let quo: i64 = nx_div_synth(g, 0, 1, 63, ro) // width-63 divider
43 let rem: i64 = ro[0]
44
45 var total: i64 = 0
46 var ok: i64 = 0
47
48 // explicit edges (incl. the large-b overflow region where LTU is required)
49 let ea: *i64 = sys_mmap(8 * 3) as *i64
50 let eb: *i64 = sys_mmap(8 * 3) as *i64
51 ea[0] = MASK63; eb[0] = 4611686018427387905 // a=2^63-1, b=2^62+1 (rem<<1 overflows sign bit)
52 ea[1] = MASK63; eb[1] = 1 // b=1
53 ea[2] = 12345; eb[2] = 9223372036854775806 // a < b, b near 2^63
54 var e: i64 = 0
55 while e < 3 {
56 g.vals[0] = ea[e]; g.vals[1] = eb[e]
57 if nx_gsim_run(g) != NX_GSIM_OK { sys_exit(20); return 20 }
58 let q: i64 = g.vals[quo]; let r: i64 = g.vals[rem]
59 let bq: i64 = ea[e] / eb[e]
60 total = total + 1
61 if q == bq { if r == ea[e] - bq * eb[e] { ok = ok + 1 } }
62 e = e + 1
63 }
64
65 // 200000 randomized (a,b) in [0, 2^63)
66 var seed: i64 = 88172645463325252
67 var nrand: i64 = 0
68 while nrand < 200000 {
69 seed = seed * LCG_A + LCG_C
70 let a: i64 = seed & MASK63
71 seed = seed * LCG_A + LCG_C
72 var b: i64 = seed & MASK63
73 if b == 0 { b = 1 }
74 g.vals[0] = a; g.vals[1] = b
75 if nx_gsim_run(g) != NX_GSIM_OK { sys_exit(21); return 21 }
76 let q: i64 = g.vals[quo]; let r: i64 = g.vals[rem]
77 let bq: i64 = a / b
78 total = total + 1
79 if q == bq { if r == a - bq * b { ok = ok + 1 } }
80 nrand = nrand + 1
81 }
82
83 _emit_num(ok); _emit_num(total); _nl()
84 if ok != total { sys_exit(1); return 1 } // every case correct (full non-neg range)
85 if total != 200003 { sys_exit(2); return 2 }
86 sys_exit(0); return 0
87}