code wiki / _hdl_build / nx_fpga_addsub.nx

nx_fpga_addsub.nx source

↩ module page · 67 lines · 3146 B

1// nx_fpga_addsub.nx -- LIB: the FPGA ALU ARITHMETIC UNIT (ADD/SUB, op-selected) as a LUT4 fabric. Extends the 2// rung-6 ripple adder with OP-SELECTION -- the essence of an ALU. Two's-complement trick: a - b = a + (~b) + 1, 3// so a single control bit `sub` drives BOTH a per-bit XOR (invert b when sub=1) AND the carry-in (cin=sub): 4// sub=0 -> b XOR 0 = b, cin=0 -> a + b 5// sub=1 -> b XOR 1 = ~b, cin=1 -> a + ~b + 1 = a - b (mod 2^W) 6// All on the fabric, run from its bitstream via fab_eval. The bridge from "the adder runs on the fabric" to 7// "an op-SELECTED ALU runs on the fabric" -> the rv64 ALU on the simulated FPGA (rung 9). 8// 9// FABRIC LAYOUT width W (npi = 2W+1): PI 0..W-1 = a, PI W..2W-1 = b, PI 2W = sub(control). 10// cells 0..W-1 : bxor_i = b_i XOR sub (XOR LUT) 11// cells W..3W-1 : ripple adder over a_i + bxor_i with carry_0 = sub (parity3 sum + maj3 carry per bit) 12// POs: po_src[i] = npi + (W + 2i) = sum bit i (i=0..W-1) -- the W-bit result a +/- b 13// ncells = 3W, npo = W. NEVER-BRICK (#26): pure integer, bounded, total, deterministic, zero hardware writes. 14// license_tier: ORIGINAL 15import "nx_fpga_adder.nx" 16import "nx_fpga_fabric.nx" 17import "nx_fpga_lut.nx" 18import "nx_syscalls.nx" 19 20// EMIT the op-selected ADD/SUB fabric for `width`. Returns npi (= 2W+1). ncells = 3W, npo = W. 21// Caller allocates inits[3W], src[3W*4], po_src[W]. 22func fab_build_addsub(width: i64, inits: *i64, src: *i64, po_src: *i64) -> i64 { 23 let npi: i64 = 2*width + 1 24 let sub_pi: i64 = 2*width 25 let par: i64 = fab_parity3_init() 26 let maj: i64 = fab_maj3_init() 27 let xr: i64 = fl_gate_to_lut4(FL_XOR) 28 // XOR layer: bxor_i = b_i XOR sub 29 var i: i64 = 0 30 while i < width { 31 inits[i] = xr 32 src[i*4 + 0] = width + i // b_i 33 src[i*4 + 1] = sub_pi // sub (control) 34 src[i*4 + 2] = width + i 35 src[i*4 + 3] = width + i 36 i = i + 1 37 } 38 // ripple adder over a_i + bxor_i, carry_0 = sub 39 i = 0 40 while i < width { 41 let sumc: i64 = width + 2*i 42 let cryc: i64 = width + 2*i + 1 43 let a_pi: i64 = i 44 let bx_src: i64 = npi + i // XOR cell i output 45 var carry_src: i64 = sub_pi // cin = sub 46 if i > 0 { carry_src = npi + (width + 2*(i-1) + 1) } 47 inits[sumc] = par 48 src[sumc*4 + 0]=a_pi; src[sumc*4 + 1]=bx_src; src[sumc*4 + 2]=carry_src; src[sumc*4 + 3]=a_pi 49 inits[cryc] = maj 50 src[cryc*4 + 0]=a_pi; src[cryc*4 + 1]=bx_src; src[cryc*4 + 2]=carry_src; src[cryc*4 + 3]=a_pi 51 po_src[i] = npi + sumc 52 i = i + 1 53 } 54 return npi 55} 56 57// load a,b,sub into PI; run; assemble the W-bit result 58func fab_addsub_run(width: i64, npi: i64, inits: *i64, src: *i64, po_src: *i64, pi: *i64, co: *i64, a: i64, b: i64, sub: i64) -> i64 { 59 var i: i64 = 0 60 while i < width { pi[i] = (a >> i) & 1; pi[width+i] = (b >> i) & 1; i = i + 1 } 61 pi[2*width] = sub & 1 62 fab_eval(3*width, npi, inits, src, pi, co) 63 var s: i64 = 0 64 i = 0 65 while i < width { s = s | (fab_po(po_src[i], npi, pi, co) << i); i = i + 1 } 66 return s 67}