code wiki / _hdl_build / nx_fpga_alu.nx
nx_fpga_alu.nx source
↩ module page · 88 lines · 4699 B
1// nx_fpga_alu.nx -- LIB: RUNG 8 -- the LOGIC+ARITHMETIC ALU DATAPATH on the LUT4 fabric, op-selected by a
2// per-bit result-MUX. Computes a/b -> {AND, OR, XOR, ADD, SUB} and selects one via control bits, ALL on the
3// fabric (run from its bitstream by fab_eval). Verified (in the gate) against the team's behavioral
4// nx_rv64im_alu_compute at the full 64-bit RV64 word width. This is the datapath; the op->control DECODE is
5// the control unit (rung 9). Shifts/compares/mul/div are follow-on rungs (barrel-shifter / borrow-logic /
6// multiplier-tree LUT networks). Builds on nx_fpga_addsub / nx_fpga_adder / nx_fpga_fabric / nx_fpga_lut.
7//
8// CONTROL INPUTS (decoded per op by the caller): sub (add/sub), msel0/msel1 (2-bit result select):
9// msel1=0,msel0=0 -> AND msel1=0,msel0=1 -> OR msel1=1,msel0=0 -> XOR msel1=1,msel0=1 -> ARITH(=add/sub)
10// ARITH op: sub=0 -> a+b, sub=1 -> a-b (two's complement, the rung-7 unit).
11//
12// FABRIC LAYOUT width W (npi = 2W+3): PI 0..W-1=a, W..2W-1=b, 2W=sub, 2W+1=msel0, 2W+2=msel1. ncells = 9W:
13// [0,W) AND_i [W,2W) OR_i [2W,3W) XOR_i [3W,4W) bxor_i=XOR(b_i,sub)
14// [4W,6W) ripple adder over a_i+bxor_i (cin=sub): sum cell 4W+2i = arith_i, carry cell 4W+2i+1
15// [6W,9W) per-bit result MUX (3 cells/bit): m_lo=MUX(msel0,AND,OR), m_hi=MUX(msel0,XOR,arith), res=MUX(msel1,m_lo,m_hi)
16// POs: po_src[i] = res cell of bit i (= the selected op's bit i)
17// NEVER-BRICK (#26): pure integer, bounded (9W cells), total, deterministic, zero hardware-state writes.
18// license_tier: ORIGINAL
19import "nx_fpga_addsub.nx"
20import "nx_fpga_adder.nx"
21import "nx_fpga_fabric.nx"
22import "nx_fpga_lut.nx"
23import "nx_syscalls.nx"
24
25// EMIT the ALU datapath fabric for `width`. Returns npi (=2W+3). ncells=9W, npo=W.
26// Caller allocates inits[9W], src[9W*4], po_src[W].
27func fab_build_alu(width: i64, inits: *i64, src: *i64, po_src: *i64) -> i64 {
28 let npi: i64 = 2*width + 3
29 let sub_pi: i64 = 2*width
30 let m0_pi: i64 = 2*width + 1
31 let m1_pi: i64 = 2*width + 2
32 let kAND: i64 = fl_gate_to_lut4(FL_AND)
33 let kOR: i64 = fl_gate_to_lut4(FL_OR)
34 let kXOR: i64 = fl_gate_to_lut4(FL_XOR)
35 let kMUX: i64 = fl_gate_to_lut4(FL_MUX)
36 let par: i64 = fab_parity3_init()
37 let maj: i64 = fab_maj3_init()
38 var i: i64 = 0
39 // AND / OR / XOR layers
40 while i < width {
41 let ca: i64 = i; inits[ca]=kAND; src[ca*4+0]=i; src[ca*4+1]=width+i; src[ca*4+2]=i; src[ca*4+3]=i
42 let co: i64 = width+i; inits[co]=kOR; src[co*4+0]=i; src[co*4+1]=width+i; src[co*4+2]=i; src[co*4+3]=i
43 let cx: i64 = 2*width+i; inits[cx]=kXOR; src[cx*4+0]=i; src[cx*4+1]=width+i; src[cx*4+2]=i; src[cx*4+3]=i
44 let cb: i64 = 3*width+i; inits[cb]=kXOR; src[cb*4+0]=width+i; src[cb*4+1]=sub_pi; src[cb*4+2]=width+i; src[cb*4+3]=width+i
45 i = i + 1
46 }
47 // ripple adder over a_i + bxor_i, cin = sub
48 i = 0
49 while i < width {
50 let sumc: i64 = 4*width + 2*i
51 let cryc: i64 = 4*width + 2*i + 1
52 let bx: i64 = npi + 3*width + i
53 var carry: i64 = sub_pi
54 if i > 0 { carry = npi + (4*width + 2*(i-1) + 1) }
55 inits[sumc]=par; src[sumc*4+0]=i; src[sumc*4+1]=bx; src[sumc*4+2]=carry; src[sumc*4+3]=i
56 inits[cryc]=maj; src[cryc*4+0]=i; src[cryc*4+1]=bx; src[cryc*4+2]=carry; src[cryc*4+3]=i
57 i = i + 1
58 }
59 // per-bit result MUX
60 i = 0
61 while i < width {
62 let mlo: i64 = 6*width + 3*i
63 let mhi: i64 = 6*width + 3*i + 1
64 let res: i64 = 6*width + 3*i + 2
65 let and_o: i64 = npi + i
66 let or_o: i64 = npi + width + i
67 let xor_o: i64 = npi + 2*width + i
68 let arith: i64 = npi + 4*width + 2*i
69 inits[mlo]=kMUX; src[mlo*4+0]=m0_pi; src[mlo*4+1]=and_o; src[mlo*4+2]=or_o; src[mlo*4+3]=and_o
70 inits[mhi]=kMUX; src[mhi*4+0]=m0_pi; src[mhi*4+1]=xor_o; src[mhi*4+2]=arith; src[mhi*4+3]=xor_o
71 inits[res]=kMUX; src[res*4+0]=m1_pi; src[res*4+1]=npi+mlo; src[res*4+2]=npi+mhi; src[res*4+3]=npi+mlo
72 po_src[i] = npi + res
73 i = i + 1
74 }
75 return npi
76}
77
78// load a,b + control; run; assemble the W-bit result (i64; for W=64 bit 63 sets the sign bit -- exact i64 value)
79func fab_alu_run(width: i64, npi: i64, inits: *i64, src: *i64, po_src: *i64, pi: *i64, co: *i64, a: i64, b: i64, sub: i64, m0: i64, m1: i64) -> i64 {
80 var i: i64 = 0
81 while i < width { pi[i] = (a >> i) & 1; pi[width+i] = (b >> i) & 1; i = i + 1 }
82 pi[2*width] = sub & 1; pi[2*width+1] = m0 & 1; pi[2*width+2] = m1 & 1
83 fab_eval(9*width, npi, inits, src, pi, co)
84 var s: i64 = 0
85 i = 0
86 while i < width { s = s | (fab_po(po_src[i], npi, pi, co) << i); i = i + 1 }
87 return s
88}