code wiki / _hdl_build / nx_fpga_cmp.nx
nx_fpga_cmp.nx source
↩ module page · 80 lines · 4555 B
1// nx_fpga_cmp.nx -- LIB: RUNG 8b -- the ALU COMPARE ops (SLT signed, SLTU unsigned) on the LUT4 fabric. New
2// mechanic: derive a result from a subtractor's INTERNAL signals (carry-out + sign bit), and use CONSTANT LUTs
3// (init 0xffff = always 1, the carry-in; init 0 = always 0, the fill). Computes a-b = a + ~b + 1, then:
4// SLTU = NOT(carry-out) -- unsigned a<b iff the subtraction borrows.
5// SLT = (a_sign XOR b_sign) ? a_sign : (a-b)_sign -- signed a<b, overflow-correct (differ-signs -> a is neg;
6// same-signs -> the (non-overflowing) diff's sign).
7// A control bit `unsigned` selects which (result in bit 0; bits 1..W-1 are 0). Verified vs nx_rv64im_alu_compute.
8//
9// FABRIC (npi = 2W+1: PI 0..W-1=a, W..2W-1=b, 2W=unsigned). ncells = 3W+6:
10// cell 0 = const1 (init 0xffff) cell 1 = const0 (init 0)
11// cells 2..W+1 = notb_i = NOT(b_i)
12// cells W+2..3W+1 = ripple adder a_i + notb_i, carry_0 = const1 (sum cell W+2+2i, carry cell W+2+2i+1)
13// cell 3W+2 = sltu = NOT(carry-out) 3W+3 = diffsign = XOR(a_sign,b_sign)
14// cell 3W+4 = slt = MUX(diffsign, subsign, a_sign) 3W+5 = res = MUX(unsigned, slt, sltu)
15// NEVER-BRICK (#26): pure integer, bounded, total, deterministic, zero hardware writes.
16// license_tier: ORIGINAL
17import "nx_fpga_adder.nx"
18import "nx_fpga_fabric.nx"
19import "nx_fpga_lut.nx"
20import "nx_syscalls.nx"
21const K_MAGIC_65535: i64 = 65535
22
23func fab_build_cmp(width: i64, inits: *i64, src: *i64, po_src: *i64) -> i64 {
24 let npi: i64 = 2*width + 1
25 let uns_pi: i64 = 2*width
26 let kNOT: i64 = fl_gate_to_lut4(FL_NOT)
27 let kXOR: i64 = fl_gate_to_lut4(FL_XOR)
28 let kMUX: i64 = fl_gate_to_lut4(FL_MUX)
29 let par: i64 = fab_parity3_init()
30 let maj: i64 = fab_maj3_init()
31 // constant LUTs (inputs = PI0, value independent of inputs)
32 inits[0] = K_MAGIC_65535; src[0]=0; src[1]=0; src[2]=0; src[3]=0 // const1 (always 1)
33 inits[1] = 0; src[4]=0; src[5]=0; src[6]=0; src[7]=0 // const0 (always 0)
34 // NOT-b layer
35 var i: i64 = 0
36 while i < width {
37 let c: i64 = 2 + i
38 inits[c]=kNOT; src[c*4+0]=width+i; src[c*4+1]=width+i; src[c*4+2]=width+i; src[c*4+3]=width+i
39 i = i + 1
40 }
41 // ripple adder a_i + notb_i, carry-in = const1
42 i = 0
43 while i < width {
44 let sumc: i64 = width + 2 + 2*i
45 let cryc: i64 = width + 2 + 2*i + 1
46 let notb: i64 = npi + 2 + i
47 var carry: i64 = npi + 0 // const1 cell -> cin = 1
48 if i > 0 { carry = npi + (width + 2 + 2*(i-1) + 1) }
49 inits[sumc]=par; src[sumc*4+0]=i; src[sumc*4+1]=notb; src[sumc*4+2]=carry; src[sumc*4+3]=i
50 inits[cryc]=maj; src[cryc*4+0]=i; src[cryc*4+1]=notb; src[cryc*4+2]=carry; src[cryc*4+3]=i
51 i = i + 1
52 }
53 let subsign_src: i64 = npi + (width + 2 + 2*(width-1)) // sub sum cell of bit W-1
54 let carryout_src: i64 = npi + (width + 2 + 2*(width-1) + 1) // carry cell of bit W-1
55 let a_sign_pi: i64 = width - 1
56 let b_sign_pi: i64 = 2*width - 1
57 let sltu_c: i64 = 3*width + 2
58 let diff_c: i64 = 3*width + 3
59 let slt_c: i64 = 3*width + 4
60 let res_c: i64 = 3*width + 5
61 inits[sltu_c]=kNOT; src[sltu_c*4+0]=carryout_src; src[sltu_c*4+1]=carryout_src; src[sltu_c*4+2]=carryout_src; src[sltu_c*4+3]=carryout_src
62 inits[diff_c]=kXOR; src[diff_c*4+0]=a_sign_pi; src[diff_c*4+1]=b_sign_pi; src[diff_c*4+2]=a_sign_pi; src[diff_c*4+3]=a_sign_pi
63 // slt = MUX(sel=diffsign, in0=subsign, in1=a_sign) = diffsign ? a_sign : subsign
64 inits[slt_c]=kMUX; src[slt_c*4+0]=npi+diff_c; src[slt_c*4+1]=subsign_src; src[slt_c*4+2]=a_sign_pi; src[slt_c*4+3]=subsign_src
65 // res = MUX(sel=unsigned, in0=slt, in1=sltu) = unsigned ? sltu : slt
66 inits[res_c]=kMUX; src[res_c*4+0]=uns_pi; src[res_c*4+1]=npi+slt_c; src[res_c*4+2]=npi+sltu_c; src[res_c*4+3]=npi+slt_c
67 po_src[0] = npi + res_c
68 i = 1
69 while i < width { po_src[i] = npi + 1; i = i + 1 } // const0 for the upper bits
70 return npi
71}
72
73// run; return the comparison bit (0/1) -- bit 0 of the result. unsigned=0 -> SLT, unsigned=1 -> SLTU.
74func fab_cmp_run(width: i64, npi: i64, inits: *i64, src: *i64, po_src: *i64, pi: *i64, co: *i64, a: i64, b: i64, unsigned: i64) -> i64 {
75 var i: i64 = 0
76 while i < width { pi[i] = (a >> i) & 1; pi[width+i] = (b >> i) & 1; i = i + 1 }
77 pi[2*width] = unsigned & 1
78 fab_eval(3*width + 6, npi, inits, src, pi, co)
79 return fab_po(po_src[0], npi, pi, co)
80}