code wiki / _hdl_build / nx_fpga_addsub_gate.nx
nx_fpga_addsub_gate.nx source
↩ module page · 150 lines · 7609 B
1import "nx_gate_gn.nx"
2import "nx_gate_base.nx"
3// nx_fpga_addsub_gate.nx -- GATE: the op-selected ADD/SUB ALU arithmetic unit runs on the LUT4 fabric and equals
4// native add/subtract. Proves subtraction (two's-complement borrow) AND op-selection (a control bit picks the op)
5// -- the heart of the CPU ALU, all from the bitstream.
6// T1 W=4 EXHAUSTIVE (16x16x2 sub = 512) -- every operand pair, ADD and SUB.
7// T2 W in {8,16,32}: borrow/underflow KATs + LFSR sweep (sub from the stream) vs native (sub? a-b : a+b)&mask.
8// T3 OP-SELECT REAL -- ADD(a,b) != SUB(a,b) for operands where they must differ -> the control bit truly selects.
9// T4 NEVER-BRICK -- bounded (3W cells), total ({0,1}), deterministic.
10// T5 LIAR-KILL -- corrupting the control-XOR init breaks SUB -> the fabric runs the bitstream; the check bites.
11// GREEN iff all pass. expect_exit: 0 license_tier: ORIGINAL
12import "nx_fpga_addsub.nx"
13import "nx_syscalls.nx"
14
15func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw("
16" as *u8); return ok }
17
18func native_addsub(a: i64, b: i64, sub: i64, mask: i64) -> i64 {
19 if sub == 1 { return (a - b) & mask }
20 return (a + b) & mask
21}
22
23func main() -> i64 {
24 gw("=== nx_fpga_addsub_gate: op-selected ADD/SUB ALU unit on the LUT4 fabric, vs native add/sub ===\n" as *u8)
25 var pass: i64 = 0; var total: i64 = 0
26
27 let inits: *i64 = sys_mmap(8 * 128) as *i64
28 let src: *i64 = sys_mmap(8 * 512) as *i64
29 let po: *i64 = sys_mmap(8 * 40) as *i64
30 let pi: *i64 = sys_mmap(8 * 70) as *i64
31 let co: *i64 = sys_mmap(8 * 130) as *i64
32
33 // ---- T1: W=4 exhaustive ----
34 var npi: i64 = fab_build_addsub(4, inits, src, po)
35 let mask4: i64 = 15
36 var c1: i64 = 0; var b1: i64 = 0
37 var a: i64 = 0
38 while a < 16 {
39 var bb: i64 = 0
40 while bb < 16 {
41 var su: i64 = 0
42 while su < 2 {
43 c1 = c1 + 1
44 let got: i64 = fab_addsub_run(4, npi, inits, src, po, pi, co, a, bb, su)
45 if got != native_addsub(a, bb, su, mask4) { b1 = b1 + 1 }
46 su = su + 1
47 }
48 bb = bb + 1
49 }
50 a = a + 1
51 }
52 total=total+1; if b1==0 { if c1==512 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } } else { gw(" [FAIL] " as *u8) }
53 gw("T1 W=4 ADD/SUB EXHAUSTIVE: " as *u8); gn(c1); gw(" combos, wrong=" as *u8); gn(b1); gw("\n" as *u8)
54
55 // ---- T2: W in {8,16,32} borrow KATs + LFSR ----
56 let widths: *i64 = sys_mmap(8 * 4) as *i64
57 widths[0]=8; widths[1]=16; widths[2]=32
58 var c2: i64 = 0; var b2: i64 = 0
59 var wi: i64 = 0
60 while wi < 3 {
61 let W: i64 = widths[wi]
62 npi = fab_build_addsub(W, inits, src, po)
63 let mask: i64 = (1 << W) - 1
64 // borrow/underflow KATs (sub=1) + add KATs (sub=0)
65 let ka: *i64 = sys_mmap(8*16) as *i64; let kb: *i64 = sys_mmap(8*16) as *i64; let ks: *i64 = sys_mmap(8*16) as *i64
66 ka[0]=0; kb[0]=1; ks[0]=1 // 0-1 = max (full borrow)
67 ka[1]=5; kb[1]=5; ks[1]=1 // a-a = 0
68 ka[2]=mask; kb[2]=mask; ks[2]=1 // max-max = 0
69 ka[3]=1; kb[3]=2; ks[3]=1 // 1-2 underflow
70 ka[4]=mask; kb[4]=1; ks[4]=0 // max+1 = 0 carry-wrap
71 ka[5]=mask; kb[5]=mask; ks[5]=0 // max+max
72 ka[6]=(mask/3); kb[6]=(mask/3)*2; ks[6]=1
73 ka[7]=0; kb[7]=0; ks[7]=1 // 0-0 = 0
74 var ki: i64 = 0
75 while ki < 8 {
76 c2 = c2 + 1
77 let got: i64 = fab_addsub_run(W, npi, inits, src, po, pi, co, ka[ki], kb[ki], ks[ki])
78 if got != native_addsub(ka[ki], kb[ki], ks[ki], mask) { b2 = b2 + 1 }
79 ki = ki + 1
80 }
81 var lcg: i64 = 7777777777
82 var t: i64 = 0
83 while t < 256 {
84 lcg = (lcg * 2862933555777941757 + 3037000493) & 4611686018427387903
85 let av: i64 = (lcg >> 5) & mask
86 lcg = (lcg * 2862933555777941757 + 3037000493) & 4611686018427387903
87 let bv: i64 = (lcg >> 5) & mask
88 let sv: i64 = (lcg >> 3) & 1
89 c2 = c2 + 1
90 let got: i64 = fab_addsub_run(W, npi, inits, src, po, pi, co, av, bv, sv)
91 if got != native_addsub(av, bv, sv, mask) { b2 = b2 + 1 }
92 t = t + 1
93 }
94 wi = wi + 1
95 }
96 total=total+1; if b2==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
97 gw("T2 W in {8,16,32} borrow-KAT+LFSR vs native: " as *u8); gn(c2); gw(" checks, wrong=" as *u8); gn(b2); gw("\n" as *u8)
98
99 // ---- T3: op-select is REAL: ADD != SUB where they must differ ----
100 npi = fab_build_addsub(8, inits, src, po)
101 var diffs: i64 = 0; var samples: i64 = 0
102 var aa: i64 = 1
103 while aa < 6 {
104 var bcur: i64 = 1
105 while bcur < 6 {
106 let radd: i64 = fab_addsub_run(8, npi, inits, src, po, pi, co, aa, bcur, 0)
107 let rsub: i64 = fab_addsub_run(8, npi, inits, src, po, pi, co, aa, bcur, 1)
108 samples = samples + 1
109 if radd != rsub { diffs = diffs + 1 } // a+b != a-b whenever 2b != 0 mod 256 (b in 1..5 -> always)
110 bcur = bcur + 1
111 }
112 aa = aa + 1
113 }
114 total=total+1; if diffs==samples { if samples>0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } } else { gw(" [FAIL] " as *u8) }
115 gw("T3 op-select real: the control bit changes the result in " as *u8); gn(diffs); gw("/" as *u8); gn(samples); gw(" (a+b != a-b)\n" as *u8)
116
117 // ---- T4: never-brick (W=16) ----
118 npi = fab_build_addsub(16, inits, src, po)
119 let r1: i64 = fab_addsub_run(16, npi, inits, src, po, pi, co, 40000, 25000, 1)
120 var t4ok: i64 = 1
121 var cc: i64 = 0
122 while cc < 48 { if co[cc] < 0 { t4ok = 0 } if co[cc] > 1 { t4ok = 0 } cc = cc + 1 }
123 let r2: i64 = fab_addsub_run(16, npi, inits, src, po, pi, co, 40000, 25000, 1)
124 if r1 != r2 { t4ok = 0 }
125 total=total+1; if t4ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
126 gw("T4 never-brick (#26): 3W-cell bounded pass, outputs in {0,1}, deterministic, zero hw-state writes\n" as *u8)
127
128 // ---- T5: liar-kill -- corrupt bit-0's SUM LUT in its carry_in=1 half (which SUB always uses) -> SUB breaks ----
129 npi = fab_build_addsub(8, inits, src, po)
130 inits[8] = inits[8] ^ 240 // adder sum cell of bit 0 (index = width = 8); ^0xF0 flips its c=1 (carry-in=1) entries
131 let mask8: i64 = 255
132 var liar_wrong: i64 = 0
133 var lt: i64 = 0
134 var llcg: i64 = 424242
135 while lt < 64 {
136 llcg = (llcg * 2862933555777941757 + 3037000493) & 4611686018427387903
137 let av: i64 = (llcg >> 5) & mask8
138 llcg = (llcg * 2862933555777941757 + 3037000493) & 4611686018427387903
139 let bv: i64 = (llcg >> 5) & mask8
140 let got: i64 = fab_addsub_run(8, npi, inits, src, po, pi, co, av, bv, 1) // SUB
141 if got != native_addsub(av, bv, 1, mask8) { liar_wrong = liar_wrong + 1 }
142 lt = lt + 1
143 }
144 total=total+1; if liar_wrong > 0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
145 gw("T5 liar-kill: a corrupted bit-0 sum-LUT (carry-in=1 half) breaks SUB in " as *u8); gn(liar_wrong); gw("/64 operands\n" as *u8)
146
147 gw("\n=== nx_fpga_addsub_gate " as *u8); gn(pass); gw("/" as *u8); gn(total)
148 if pass == total { gw(" GREEN (op-selected ADD/SUB ALU unit runs on the simulated fabric == native; subtraction + op-selection proven -- the CPU datapath core)\n" as *u8); sys_exit(0); return 0 }
149 gw(" RED\n" as *u8); sys_exit(1); return 1
150}