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}