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}