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}