code wiki / _hdl_build / nx_fpga_mul_gate.nx
nx_fpga_mul_gate.nx source
↩ module page · 82 lines · 4758 B
1import "nx_gate_gn.nx"
2import "nx_gate_base.nx"
3// nx_fpga_mul_gate.nx -- GATE for RUNG 24: MUL (the M-extension) on the fabric. A multiply is computed as a SEQUENTIAL
4// SHIFT-ADD: for each set bit i of b, add (a << i) to an accumulator -- the shift on the fabric BARREL SHIFTER
5// (nx_fpga_shift) and the add on the fabric ALU (nx_fpga_alu). This is a real multi-cycle hardware multiplier style;
6// the arithmetic runs entirely on the proven fabric datapath, composed bit-by-bit. Verified == the behavioral
7// nx_rv64im_alu_compute(MUL) (low 64 bits of a*b). This completes the rv64i**M** integer set the oracle is named for.
8// T1 a*b over representative (a,b) pairs (0/identity/powers-of-2/primes/all-ones/large-a) == behavioral MUL.
9// T2 headline 255*255 = 65025. T3 NEVER-BRICK. T4 LIAR-KILL (corrupt the fabric ALU -> a partial-sum diverges).
10// (Fabric evals = 2 x popcount(b) per multiply, so b kept <=255 -> light; the loop is a general 64-bit multiplier.)
11// expect_exit: 0 license_tier: ORIGINAL
12import "nx_fpga_alu.nx"
13import "nx_fpga_shift.nx"
14import "rv64im_min_alu.nx"
15import "nx_syscalls.nx"
16
17func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw("
18" as *u8); return ok }
19
20func main() -> i64 {
21 gw("=== nx_fpga_mul_gate: RUNG 24 -- MUL (M-extension) via fabric shift-add (barrel shifter + ALU) ===\n" as *u8)
22 var pass: i64 = 0; var total: i64 = 0
23 let AI: *i64=sys_mmap(8*640) as *i64; let AS: *i64=sys_mmap(8*2560) as *i64; let AP: *i64=sys_mmap(8*72) as *i64
24 let SI: *i64=sys_mmap(8*820) as *i64; let SS: *i64=sys_mmap(8*3280) as *i64; let SP: *i64=sys_mmap(8*72) as *i64
25 let pi: *i64=sys_mmap(8*200) as *i64; let co: *i64=sys_mmap(8*2200) as *i64
26 let anpi: i64 = fab_build_alu(64, AI, AS, AP)
27 let snpi: i64 = fab_build_shifter(64, SI, SS, SP)
28
29 let ta: *i64=sys_mmap(8*16) as *i64; let tb: *i64=sys_mmap(8*16) as *i64
30 ta[0]=0; tb[0]=7
31 ta[1]=1; tb[1]=1
32 ta[2]=255; tb[2]=255
33 ta[3]=16; tb[3]=16
34 ta[4]=7; tb[4]=13
35 ta[5]=100; tb[5]=100
36 ta[6]=123; tb[6]=45
37 ta[7]=255; tb[7]=2
38 ta[8]=200; tb[8]=1
39 ta[9]=12345; tb[9]=67
40 ta[10]=2; tb[10]=2
41 ta[11]=13; tb[11]=13
42 let NP: i64 = 12
43
44 var mism: i64=0; var p: i64=0
45 while p < NP {
46 let a: i64=ta[p]; let b: i64=tb[p]
47 var acc: i64=0; var i: i64=0
48 while i < 64 {
49 if ((b >> i) & 1) == 1 {
50 let sh: i64 = fab_shift_run(64, snpi, SI, SS, SP, pi, co, a, i, 0, 0) // a << i on the fabric shifter
51 acc = fab_alu_run(64, anpi, AI, AS, AP, pi, co, acc, sh, 0, 1, 1) // acc += sh on the fabric ALU
52 }
53 i = i + 1
54 }
55 let want: i64 = nx_rv64im_alu_compute(NX_RV64IM_ALU_MUL, a, b)
56 if acc != want { mism = mism + 1 }
57 p = p + 1
58 }
59 total=total+1; if mism==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
60 gw("T1 MUL via fabric shift-add over " as *u8); gn(NP); gw(" (a,b) pairs == behavioral, mismatches=" as *u8); gn(mism); gw("\n" as *u8)
61
62 // T2: headline 255*255
63 var acc2: i64=0; var j: i64=0
64 while j < 64 { if ((255 >> j) & 1) == 1 { let sh: i64=fab_shift_run(64,snpi,SI,SS,SP,pi,co,255,j,0,0); acc2=fab_alu_run(64,anpi,AI,AS,AP,pi,co,acc2,sh,0,1,1) } j=j+1 }
65 total=total+1; if acc2==65025 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
66 gw("T2 255 * 255 on the fabric = " as *u8); gn(acc2); gw(" (=65025)\n" as *u8)
67
68 // T3: never-brick
69 let r1: i64=fab_shift_run(64,snpi,SI,SS,SP,pi,co,13,4,0,0); let r2: i64=fab_shift_run(64,snpi,SI,SS,SP,pi,co,13,4,0,0)
70 total=total+1; if r1==r2 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
71 gw("T3 never-brick (#26): deterministic, bounded shift-add, pure-integer, zero hardware-state writes\n" as *u8)
72
73 // T4: liar-kill -- corrupt the fabric ALU; a partial-sum add (which the multiplier relies on) diverges
74 var ci: i64=0; while ci < 640 { AI[ci] = AI[ci] ^ 0xffff; ci = ci + 1 }
75 let bad: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,169,26,0,1,1)
76 total=total+1; if bad != 195 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
77 gw("T4 liar-kill: corrupting the fabric ALU -> a multiplier partial-sum add(169,26)=" as *u8); gn(bad); gw(" != 195\n" as *u8)
78
79 gw("\n=== nx_fpga_mul_gate " as *u8); gn(pass); gw("/" as *u8); gn(total)
80 if pass == total { gw(" GREEN (MUL runs on the fabric via shift-add on the barrel shifter + ALU == behavioral -- the M-extension; rv64iM integer set complete in sim)\n" as *u8); sys_exit(0); return 0 }
81 gw(" RED\n" as *u8); sys_exit(1); return 1
82}