code wiki / _hdl_build / nx_recip64.nx
nx_recip64.nx source
↩ module page · 89 lines · 3616 B
1// nx_recip64.nx -- the TRUE 64-bit Goldschmidt/Newton reciprocal divider as a
2// GATE-NETWORK. Mirrors the bit-exact scalar (nx_recip64_scalar_test) op-for-op,
3// using ONLY gate-sim cells + the proven 64x64->128 wide multiplier for mulh. No
4// 128-bit datapath: the normalized reciprocal keeps every value in 64 bits and
5// uses the high word of each product (mulhu = nx_mul_wide hi). Requires the sim's
6// LOGICAL SHR (the quotient can have bit 63 set). license_tier: ORIGINAL
7
8import "nx_mul_wide.nx"
9
10const R64_ITERS: i64 = 7
11const R64_KCORR: i64 = 6
12
13// returns the HI net (mulhu) of a*b.
14func r64_mulhu(g: *NxGsim, a: i64, b: i64) -> i64 {
15 let hio: *i64 = sys_mmap(8) as *i64
16 hio[0] = 0
17 nx_mul_wide_synth(g, a, b, hio)
18 return hio[0]
19}
20
21// 64-bit priority encoder: net p with 2^p <= D < 2^(p+1), D in [1, 2^64).
22func r64_msb(g: *NxGsim, nd: i64) -> i64 {
23 let c1: i64 = div_const(g, 1)
24 var p: i64 = div_const(g, 0)
25 var k: i64 = 1
26 while k < 64 {
27 let pow: i64 = div_const(g, 1 << k)
28 let lt: i64 = div_op2(g, NX_GATE_KIND_LTU, nd, pow)
29 let ge: i64 = div_op2(g, NX_GATE_KIND_XOR, lt, c1)
30 p = div_op2(g, NX_GATE_KIND_ADD, p, ge)
31 k = k + 1
32 }
33 return p
34}
35
36func nx_recip64_synth(g: *NxGsim, na: i64, nb: i64, rem_out: *i64) -> i64 {
37 let c0: i64 = div_const(g, 0)
38 let c1: i64 = div_const(g, 1)
39 let c63: i64 = div_const(g, 63)
40 let half: i64 = div_const(g, 1 << 63) // 2^63 (x = 1.0 in Q63)
41 let allones: i64 = div_const(g, 0 - 1)
42
43 let p: i64 = r64_msb(g, nb)
44 let s: i64 = div_op2(g, NX_GATE_KIND_SUB, c63, p)
45 let Dn: i64 = div_op2(g, NX_GATE_KIND_SHL, nb, s)
46 var X: i64 = half
47
48 var it: i64 = 0
49 while it < R64_ITERS {
50 let dx: i64 = r64_mulhu(g, Dn, X)
51 let t: i64 = div_op2(g, NX_GATE_KIND_SUB, c0, dx) // 2^64 - dx
52 let Xm: i64 = r64_mulhu(g, X, t)
53 let lt: i64 = div_op2(g, NX_GATE_KIND_LTU, Xm, half) // Xm < 2^63 ?
54 let xshl: i64 = div_op2(g, NX_GATE_KIND_SHL, Xm, c1)
55 X = div_mux(g, lt, xshl, allones) // cap at ALLONES
56 it = it + 1
57 }
58
59 let nxhi: i64 = r64_mulhu(g, na, X)
60 var q: i64 = div_op2(g, NX_GATE_KIND_SHR, nxhi, p) // LOGICAL >> msb(D)
61
62 var kc: i64 = 0
63 while kc < R64_KCORR {
64 let phi: i64 = r64_mulhu(g, q, nb)
65 let qD: i64 = div_op2(g, NX_GATE_KIND_MUL, q, nb)
66 let phigt: i64 = div_op2(g, NX_GATE_KIND_NEQ, phi, c0) // q*D >= 2^64
67 let nlt: i64 = div_op2(g, NX_GATE_KIND_LTU, na, qD) // N < q*D (low)
68 let toobig: i64 = div_op2(g, NX_GATE_KIND_OR, phigt, nlt)
69 let qdec: i64 = div_op2(g, NX_GATE_KIND_SUB, q, c1)
70 // up branch: (q+1) doesn't wrap, (q+1)*D fits, and <= N
71 let qp1: i64 = div_op2(g, NX_GATE_KIND_ADD, q, c1)
72 let qp1nz: i64 = div_op2(g, NX_GATE_KIND_NEQ, qp1, c0)
73 let phu: i64 = r64_mulhu(g, qp1, nb)
74 let phuz: i64 = div_op2(g, NX_GATE_KIND_EQ, phu, c0)
75 let qp1D: i64 = div_op2(g, NX_GATE_KIND_MUL, qp1, nb)
76 let nle: i64 = div_op2(g, NX_GATE_KIND_LTU, na, qp1D) // N < qp1*D
77 let nge: i64 = div_op2(g, NX_GATE_KIND_XOR, nle, c1) // qp1*D <= N
78 let f1: i64 = div_op2(g, NX_GATE_KIND_AND, qp1nz, phuz)
79 let fits: i64 = div_op2(g, NX_GATE_KIND_AND, f1, nge)
80 let qinc: i64 = div_mux(g, fits, qp1, q)
81 q = div_mux(g, toobig, qdec, qinc)
82 kc = kc + 1
83 }
84
85 let qDf: i64 = div_op2(g, NX_GATE_KIND_MUL, q, nb)
86 let r: i64 = div_op2(g, NX_GATE_KIND_SUB, na, qDf)
87 rem_out[0] = r
88 return q
89}