code wiki / _hdl_build / nx_fpga_cmp_gate.nx
nx_fpga_cmp_gate.nx source
↩ module page · 111 lines · 6302 B
1import "nx_gate_gn.nx"
2import "nx_gate_base.nx"
3// nx_fpga_cmp_gate.nx -- GATE for RUNG 8b: the fabric SLT/SLTU == behavioral nx_rv64im_alu_compute @ 64-bit.
4// T1 SLT == behavioral over signed-edge KATs (incl INT_MIN/INT_MAX overflow) + 64-bit LFSR.
5// T2 SLTU == behavioral.
6// T3 SIGNED != UNSIGNED -- the control bit genuinely picks a different comparison (they diverge where they must).
7// T4 NEVER-BRICK.
8// T5 LIAR-KILL -- scrambling the SLT-select MUX LUT breaks SLT.
9// GREEN iff all pass. expect_exit: 0 license_tier: ORIGINAL
10import "nx_fpga_cmp.nx"
11import "rv64im_min_alu.nx"
12import "nx_syscalls.nx"
13
14func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw("
15" as *u8); return ok }
16
17func main() -> i64 {
18 gw("=== nx_fpga_cmp_gate: RUNG 8b -- fabric SLT/SLTU == behavioral nx_rv64im_alu_compute @ 64-bit ===\n" as *u8)
19 var pass: i64 = 0; var total: i64 = 0
20 let W: i64 = 64
21
22 let inits: *i64 = sys_mmap(8 * 256) as *i64
23 let src: *i64 = sys_mmap(8 * 1024) as *i64
24 let po: *i64 = sys_mmap(8 * 72) as *i64
25 let pi: *i64 = sys_mmap(8 * 140) as *i64
26 let co: *i64 = sys_mmap(8 * 256) as *i64
27 let npi: i64 = fab_build_cmp(W, inits, src, po)
28
29 // signed/unsigned edge KATs
30 let ka: *i64 = sys_mmap(8 * 16) as *i64
31 let kb: *i64 = sys_mmap(8 * 16) as *i64
32 ka[0]=0; kb[0]=0
33 ka[1]=1; kb[1]=2
34 ka[2]=2; kb[2]=1
35 ka[3]=0-1; kb[3]=0 // -1 vs 0: SLT 1, SLTU 0
36 ka[4]=0; kb[4]=0-1 // 0 vs -1: SLT 0, SLTU 1
37 ka[5]=(1 << 63); kb[5]=9223372036854775807 // INT_MIN vs INT_MAX
38 ka[6]=9223372036854775807; kb[6]=(1 << 63) // INT_MAX vs INT_MIN
39 ka[7]=0-1; kb[7]=0-2 // -1 vs -2
40 ka[8]=0-2; kb[8]=0-1 // -2 vs -1
41 let nkat: i64 = 9
42
43 // ---- T1: SLT, T2: SLTU vs behavioral ----
44 var c1: i64=0; var b1: i64=0; var c2: i64=0; var b2: i64=0
45 var ki: i64 = 0
46 while ki < nkat {
47 c1=c1+1; if fab_cmp_run(W,npi,inits,src,po,pi,co,ka[ki],kb[ki],0) != nx_rv64im_alu_compute(NX_RV64IM_ALU_SLT, ka[ki],kb[ki]) { b1=b1+1 }
48 c2=c2+1; if fab_cmp_run(W,npi,inits,src,po,pi,co,ka[ki],kb[ki],1) != nx_rv64im_alu_compute(NX_RV64IM_ALU_SLTU, ka[ki],kb[ki]) { b2=b2+1 }
49 ki=ki+1
50 }
51 var lcg: i64 = 2718281828459045
52 var t: i64 = 0
53 while t < 300 {
54 lcg = (lcg * 2862933555777941757 + 3037000493) & 4611686018427387903
55 let d1: i64 = (lcg >> 5) & 4294967295
56 lcg = (lcg * 2862933555777941757 + 3037000493) & 4611686018427387903
57 let d2: i64 = (lcg >> 5) & 4294967295
58 let a: i64 = (d1 << 32) | d2
59 lcg = (lcg * 2862933555777941757 + 3037000493) & 4611686018427387903
60 let d3: i64 = (lcg >> 5) & 4294967295
61 lcg = (lcg * 2862933555777941757 + 3037000493) & 4611686018427387903
62 let d4: i64 = (lcg >> 5) & 4294967295
63 let b: i64 = (d3 << 32) | d4
64 c1=c1+1; if fab_cmp_run(W,npi,inits,src,po,pi,co,a,b,0) != nx_rv64im_alu_compute(NX_RV64IM_ALU_SLT, a,b) { b1=b1+1 }
65 c2=c2+1; if fab_cmp_run(W,npi,inits,src,po,pi,co,a,b,1) != nx_rv64im_alu_compute(NX_RV64IM_ALU_SLTU, a,b) { b2=b2+1 }
66 t=t+1
67 }
68 total=total+1; if b1==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
69 gw("T1 SLT (signed) == behavioral: " as *u8); gn(c1); gw(" checks, wrong=" as *u8); gn(b1); gw("\n" as *u8)
70 total=total+1; if b2==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
71 gw("T2 SLTU (unsigned) == behavioral: " as *u8); gn(c2); gw(" checks, wrong=" as *u8); gn(b2); gw("\n" as *u8)
72
73 // ---- T3: signed != unsigned where it must (the control bit genuinely selects) ----
74 var diverge: i64 = 0
75 if fab_cmp_run(W,npi,inits,src,po,pi,co,0-1,0,0) != fab_cmp_run(W,npi,inits,src,po,pi,co,0-1,0,1) { diverge = diverge + 1 } // -1 vs 0
76 if fab_cmp_run(W,npi,inits,src,po,pi,co,0,0-1,0) != fab_cmp_run(W,npi,inits,src,po,pi,co,0,0-1,1) { diverge = diverge + 1 } // 0 vs -1
77 if fab_cmp_run(W,npi,inits,src,po,pi,co,(1<<63),9223372036854775807,0) != fab_cmp_run(W,npi,inits,src,po,pi,co,(1<<63),9223372036854775807,1) { diverge = diverge + 1 }
78 total=total+1; if diverge==3 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
79 gw("T3 signed != unsigned: the control bit picks a different comparison in " as *u8); gn(diverge); gw("/3 witnesses\n" as *u8)
80
81 // ---- T4: never-brick ----
82 var t4ok: i64 = 1
83 let r1: i64 = fab_cmp_run(W,npi,inits,src,po,pi,co,12345,67890,0)
84 var cc: i64 = 0
85 while cc < 3*W+6 { if co[cc] < 0 { t4ok = 0 } if co[cc] > 1 { t4ok = 0 } cc = cc + 1 }
86 let r2: i64 = fab_cmp_run(W,npi,inits,src,po,pi,co,12345,67890,0)
87 if r1 != r2 { t4ok = 0 }
88 total=total+1; if t4ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
89 gw("T4 never-brick (#26): bounded pass, outputs in {0,1}, deterministic, zero hw-state writes\n" as *u8)
90
91 // ---- T5: liar-kill -- scramble the SLT-select MUX -> SLT breaks ----
92 let slt_c: i64 = 3*W + 4
93 inits[slt_c] = inits[slt_c] ^ 0xffff
94 var liar_wrong: i64 = 0
95 var lt: i64 = 0
96 var llcg: i64 = 161803398
97 while lt < 64 {
98 llcg = (llcg * 2862933555777941757 + 3037000493) & 4611686018427387903
99 let a: i64 = (llcg >> 5)
100 llcg = (llcg * 2862933555777941757 + 3037000493) & 4611686018427387903
101 let b: i64 = (llcg >> 5)
102 if fab_cmp_run(W,npi,inits,src,po,pi,co,a,b,0) != nx_rv64im_alu_compute(NX_RV64IM_ALU_SLT, a, b) { liar_wrong = liar_wrong + 1 }
103 lt = lt + 1
104 }
105 total=total+1; if liar_wrong > 0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
106 gw("T5 liar-kill: scrambling the SLT-select MUX breaks SLT in " as *u8); gn(liar_wrong); gw("/64 operands\n" as *u8)
107
108 gw("\n=== nx_fpga_cmp_gate " as *u8); gn(pass); gw("/" as *u8); gn(total)
109 if pass == total { gw(" GREEN (fabric SLT/SLTU == behavioral rv64 ALU @64-bit; compares derived from the subtractor's carry+sign run on the simulated FPGA)\n" as *u8); sys_exit(0); return 0 }
110 gw(" RED\n" as *u8); sys_exit(1); return 1
111}