code wiki / _hdl_build / nx_fpga_shift_gate.nx
nx_fpga_shift_gate.nx source
↩ module page · 136 lines · 6973 B
1import "nx_gate_gn.nx"
2import "nx_gate_base.nx"
3// nx_fpga_shift_gate.nx -- GATE for RUNG 8c: the barrel-shifter fabric SLL/SRL/SRA == behavioral
4// nx_rv64im_alu_compute @ 64-bit, over ALL 64 shift amounts (every barrel stage combination) + sign-fill + the
5// shamt = b & 0x3f masking + LFSR.
6// T1 SLL == behavioral T2 SRL == behavioral T3 SRA == behavioral (incl negative a sign-fill)
7// T4 OP-DISTINCT -- SLL/SRL/SRA give different results (the control bits genuinely pick the shift kind).
8// T5 NEVER-BRICK T6 LIAR-KILL (scramble a stage MUX -> a shift breaks).
9// GREEN iff all pass. expect_exit: 0 license_tier: ORIGINAL
10import "nx_fpga_shift.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_shift_gate: RUNG 8c -- barrel-shifter SLL/SRL/SRA == behavioral @64-bit, all 64 shamts ===\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 * 800) as *i64
23 let src: *i64 = sys_mmap(8 * 3200) as *i64
24 let po: *i64 = sys_mmap(8 * 72) as *i64
25 let pi: *i64 = sys_mmap(8 * 80) as *i64
26 let co: *i64 = sys_mmap(8 * 800) as *i64
27 let npi: i64 = fab_build_shifter(W, inits, src, po)
28
29 // operand KATs (incl sign-set + all-ones for SRA fill)
30 let ka: *i64 = sys_mmap(8 * 12) as *i64
31 ka[0]=1; ka[1]=0-1; ka[2]=6148914691236517205; ka[3]=(1<<63); ka[4]=81985529216486895; ka[5]=9223372036854775807
32 let nka: i64 = 6
33 // shift KATs (incl 32/63 boundary + 64/65/100 to test shamt = b&0x3f masking)
34 let kb: *i64 = sys_mmap(8 * 16) as *i64
35 kb[0]=0; kb[1]=1; kb[2]=7; kb[3]=31; kb[4]=32; kb[5]=63; kb[6]=64; kb[7]=65; kb[8]=100; kb[9]=0-1
36 let nkb: i64 = 10
37
38 // op table: opcode, right, arith
39 let opc: *i64 = sys_mmap(8 * 4) as *i64; let orp: *i64 = sys_mmap(8 * 4) as *i64; let oar: *i64 = sys_mmap(8 * 4) as *i64
40 opc[0]=NX_RV64IM_ALU_SLL; orp[0]=0; oar[0]=0
41 opc[1]=NX_RV64IM_ALU_SRL; orp[1]=1; oar[1]=0
42 opc[2]=NX_RV64IM_ALU_SRA; orp[2]=1; oar[2]=1
43
44 let names: *i64 = sys_mmap(8 * 4) as *i64
45 names[0]="SLL" as *u8 as i64; names[1]="SRL" as *u8 as i64; names[2]="SRA" as *u8 as i64
46
47 var oi: i64 = 0
48 while oi < 3 {
49 var checks: i64 = 0; var mism: i64 = 0
50 // KAT operands x shift KATs
51 var ai: i64 = 0
52 while ai < nka {
53 var bi: i64 = 0
54 while bi < nkb {
55 let a: i64 = ka[ai]; let b: i64 = kb[bi]; let shamt: i64 = b & 63
56 let got: i64 = fab_shift_run(W, npi, inits, src, po, pi, co, a, shamt, orp[oi], oar[oi])
57 let want: i64 = nx_rv64im_alu_compute(opc[oi], a, b)
58 checks = checks + 1
59 if got != want { mism = mism + 1 }
60 bi = bi + 1
61 }
62 ai = ai + 1
63 }
64 // also EXHAUSTIVE over all 64 shamts for one witness operand (every stage combo)
65 var sh: i64 = 0
66 while sh < 64 {
67 let a: i64 = 0-81985529216486896 // a sign-set witness
68 let got: i64 = fab_shift_run(W, npi, inits, src, po, pi, co, a, sh, orp[oi], oar[oi])
69 let want: i64 = nx_rv64im_alu_compute(opc[oi], a, sh)
70 checks = checks + 1
71 if got != want { mism = mism + 1 }
72 sh = sh + 1
73 }
74 // LFSR
75 var lcg: i64 = 1234567891011
76 var t: i64 = 0
77 while t < 200 {
78 lcg = (lcg * 2862933555777941757 + 3037000493) & 4611686018427387903
79 let d1: i64 = (lcg >> 5) & 4294967295
80 lcg = (lcg * 2862933555777941757 + 3037000493) & 4611686018427387903
81 let d2: i64 = (lcg >> 5) & 4294967295
82 let a: i64 = (d1 << 32) | d2
83 lcg = (lcg * 2862933555777941757 + 3037000493) & 4611686018427387903
84 let b: i64 = (lcg >> 5)
85 let got: i64 = fab_shift_run(W, npi, inits, src, po, pi, co, a, b & 63, orp[oi], oar[oi])
86 let want: i64 = nx_rv64im_alu_compute(opc[oi], a, b)
87 checks = checks + 1
88 if got != want { mism = mism + 1 }
89 t = t + 1
90 }
91 total=total+1; if mism==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
92 gw("T"); gn(oi+1); gw(" "); gw(names[oi] as *u8); gw(" == behavioral: "); gn(checks); gw(" checks, wrong="); gn(mism); gw("\n" as *u8)
93 oi = oi + 1
94 }
95
96 // ---- T4: op-distinct -- SLL/SRL/SRA differ for a sign-set operand shifted by 4 ----
97 let wa: i64 = (1<<63) | 255
98 let rl: i64 = fab_shift_run(W, npi, inits, src, po, pi, co, wa, 4, 0, 0)
99 let rr: i64 = fab_shift_run(W, npi, inits, src, po, pi, co, wa, 4, 1, 0)
100 let rar: i64 = fab_shift_run(W, npi, inits, src, po, pi, co, wa, 4, 1, 1)
101 total=total+1
102 var ok4: i64 = 1
103 if rl==rr { ok4=0 } if rr==rar { ok4=0 } if rl==rar { ok4=0 }
104 if ok4==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
105 gw("T4 op-distinct: SLL/SRL/SRA give 3 different results for a sign-set operand (control bits select the shift)\n" as *u8)
106
107 // ---- T5: never-brick ----
108 var t5ok: i64 = 1
109 let s1: i64 = fab_shift_run(W, npi, inits, src, po, pi, co, 123456789, 13, 1, 1)
110 var cc: i64 = 0
111 while cc < 2+12*W { if co[cc] < 0 { t5ok = 0 } if co[cc] > 1 { t5ok = 0 } cc = cc + 1 }
112 let s2: i64 = fab_shift_run(W, npi, inits, src, po, pi, co, 123456789, 13, 1, 1)
113 if s1 != s2 { t5ok = 0 }
114 total=total+1; if t5ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
115 gw("T5 never-brick (#26): bounded 2+12W-cell pass, outputs in {0,1}, deterministic, zero hw-state writes\n" as *u8)
116
117 // ---- T6: liar-kill -- scramble a stage-0 out MUX -> SLL breaks ----
118 inits[3] = inits[3] ^ 0xffff // out MUX of stage0 bit0 (cell 3)
119 var liar_wrong: i64 = 0
120 var lt: i64 = 0
121 var llcg: i64 = 271828182
122 while lt < 64 {
123 llcg = (llcg * 2862933555777941757 + 3037000493) & 4611686018427387903
124 let a: i64 = (llcg >> 5)
125 llcg = (llcg * 2862933555777941757 + 3037000493) & 4611686018427387903
126 let b: i64 = (llcg >> 5)
127 if fab_shift_run(W, npi, inits, src, po, pi, co, a, b & 63, 0, 0) != nx_rv64im_alu_compute(NX_RV64IM_ALU_SLL, a, b) { liar_wrong = liar_wrong + 1 }
128 lt = lt + 1
129 }
130 total=total+1; if liar_wrong > 0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
131 gw("T6 liar-kill: scrambling a stage-0 MUX breaks SLL in "); gn(liar_wrong); gw("/64 operands\n" as *u8)
132
133 gw("\n=== nx_fpga_shift_gate " as *u8); gn(pass); gw("/" as *u8); gn(total)
134 if pass == total { gw(" GREEN (barrel-shifter SLL/SRL/SRA == behavioral rv64 ALU @64-bit, all shamts; log-depth shift network on the simulated FPGA)\n" as *u8); sys_exit(0); return 0 }
135 gw(" RED\n" as *u8); sys_exit(1); return 1
136}