code wiki / _hdl_build / nx_fpga_shift.nx
nx_fpga_shift.nx source
↩ module page · 77 lines · 3920 B
1// nx_fpga_shift.nx -- LIB: RUNG 8c -- the ALU SHIFTS (SLL/SRL/SRA) as a BARREL SHIFTER on the LUT4 fabric.
2// The classic log-depth structure: log2(W)=6 stages (for W=64), stage k conditionally shifts by 2^k iff
3// shamt bit k is set. Two control bits unify all three shifts: `right` (0=left SLL, 1=right) and `arith`
4// (right-shift fill = original sign bit for SRA, else 0 for SRL/SLL). Per bit per stage = 2 MUX LUT4s
5// (pick the shifted source by direction, then pick shifted-vs-passthrough by shamt bit). Builds on nx_fpga_lut.
6//
7// FABRIC (npi = W+8): PI 0..W-1 = a, W..W+5 = shamt[0..5] (= b&0x3f), W+6 = right, W+7 = arith. ncells = 2+12W:
8// cell 0 = const0 (init 0) cell 1 = fill = MUX(arith, 0, a_sign) [right-shift in-bit]
9// stage k (k=0..5) cells [2+k*2W, 2+(k+1)*2W): per bit i: shifted_src = MUX(right, left_src, right_src),
10// out = MUX(shamt_k, in_i, shifted_src); where left_src_i = (i>=2^k)? in(i-2^k):0,
11// right_src_i = (i+2^k<W)? in(i+2^k):fill. Stage k's `in` vector = stage k-1's outputs (a for k=0).
12// POs = stage-5 outputs. NEVER-BRICK (#26): pure integer, bounded (2+12W cells), total, deterministic, no hw write.
13// license_tier: ORIGINAL
14import "nx_fpga_lut.nx"
15import "nx_fpga_fabric.nx"
16import "nx_syscalls.nx"
17
18func fab_build_shifter(width: i64, inits: *i64, src: *i64, po_src: *i64) -> i64 {
19 let npi: i64 = width + 8
20 let right_pi: i64 = width + 6
21 let arith_pi: i64 = width + 7
22 let a_sign_pi: i64 = width - 1
23 let kMUX: i64 = fl_gate_to_lut4(FL_MUX)
24 // const0 (cell 0), fill (cell 1) = MUX(arith, const0, a_sign)
25 inits[0] = 0; src[0]=0; src[1]=0; src[2]=0; src[3]=0
26 inits[1] = kMUX; src[4]=arith_pi; src[5]=npi+0; src[6]=a_sign_pi; src[7]=npi+0
27 let const0_src: i64 = npi + 0
28 let fill_src: i64 = npi + 1
29 // current input-vector wire sources (stage 0 input = a PIs)
30 let inwire: *i64 = sys_mmap(8 * (width + 4)) as *i64
31 let outwire: *i64 = sys_mmap(8 * (width + 4)) as *i64
32 var i: i64 = 0
33 while i < width { inwire[i] = i; i = i + 1 }
34 var base: i64 = 2
35 var k: i64 = 0
36 while k < 6 {
37 let d: i64 = 1 << k
38 let sel: i64 = width + k // shamt bit k PI
39 i = 0
40 while i < width {
41 let ss_cell: i64 = base + 2*i
42 let out_cell: i64 = base + 2*i + 1
43 var left_src: i64 = const0_src
44 if i >= d { left_src = inwire[i - d] }
45 var right_src: i64 = fill_src
46 if i + d < width { right_src = inwire[i + d] }
47 // shifted_src = MUX(right, left_src, right_src) = right ? right_src : left_src
48 inits[ss_cell]=kMUX; src[ss_cell*4+0]=right_pi; src[ss_cell*4+1]=left_src; src[ss_cell*4+2]=right_src; src[ss_cell*4+3]=left_src
49 // out = MUX(shamt_k, in_i, shifted_src) = shamt_k ? shifted_src : in_i
50 inits[out_cell]=kMUX; src[out_cell*4+0]=sel; src[out_cell*4+1]=inwire[i]; src[out_cell*4+2]=npi+ss_cell; src[out_cell*4+3]=inwire[i]
51 outwire[i] = npi + out_cell
52 i = i + 1
53 }
54 i = 0
55 while i < width { inwire[i] = outwire[i]; i = i + 1 }
56 base = base + 2*width
57 k = k + 1
58 }
59 i = 0
60 while i < width { po_src[i] = inwire[i]; i = i + 1 }
61 return npi
62}
63
64// run; assemble the W-bit shifted result. right=0->SLL, right=1&arith=0->SRL, right=1&arith=1->SRA. shamt = b & 0x3f.
65func fab_shift_run(width: i64, npi: i64, inits: *i64, src: *i64, po_src: *i64, pi: *i64, co: *i64, a: i64, shamt: i64, right: i64, arith: i64) -> i64 {
66 var i: i64 = 0
67 while i < width { pi[i] = (a >> i) & 1; i = i + 1 }
68 i = 0
69 while i < 6 { pi[width+i] = (shamt >> i) & 1; i = i + 1 }
70 pi[width+6] = right & 1
71 pi[width+7] = arith & 1
72 fab_eval(2 + 12*width, npi, inits, src, pi, co)
73 var s: i64 = 0
74 i = 0
75 while i < width { s = s | (fab_po(po_src[i], npi, pi, co) << i); i = i + 1 }
76 return s
77}