// rc_alpha_q15.vh // Plain Verilog-2001 constant function: R(ohm), C(pF), Fs(Hz) -> alpha_q15 (Q1.15) // Uses fixed-point approximation: 1 - exp(-x) ≈ x - x^2/2 + x^3/6, where x = 1/(Fs*R*C) // All integer math; suitable for elaboration-time constant folding (e.g., XST). `ifndef RC_ALPHA_Q15_VH `define RC_ALPHA_Q15_VH function integer alpha_q15_from_rc; input integer R_OHM; // ohms input integer C_PF; // picofarads input integer FS_HZ; // Hz // Choose QN for x. N=24 is a good balance for accuracy/width. integer N; // We'll keep everything as unsigned vectors; inputs copied into vectors first. reg [63:0] R_u, C_u, FS_u; // x = 1 / (Fs * R * C) with C in pF -> x = 1e12 / (Fs*R*C_pf) // x_qN = round( x * 2^N ) = round( (1e12 << N) / denom ) reg [127:0] NUM_1E12_SLLN; // big enough for 1e12 << N reg [127:0] DENOM; // Fs*R*C reg [127:0] X_qN; // x in QN // Powers reg [255:0] X2; // x^2 in Q(2N) reg [383:0] X3; // x^3 in Q(3N) integer term1_q15; integer term2_q15; integer term3_q15; integer acc; begin N = 24; // Copy integer inputs into 64-bit vectors (no bit-slicing of integers) R_u = R_OHM[31:0]; C_u = C_PF[31:0]; FS_u = FS_HZ[31:0]; // Denominator = Fs * R * C_pf (fits in < 2^64 for typical values) DENOM = 128'd0; DENOM = FS_u; DENOM = DENOM * R_u; DENOM = DENOM * C_u; // // Guard: avoid divide by zero // if (DENOM == 0) begin // alpha_q15_from_rc = 0; // disable alpha_q15_from_rc; // end // Numerator = (1e12 << N). 1e12 * 2^24 ≈ 1.6777e19 (fits in 2^64..2^65), // so use 128 bits to be safe. NUM_1E12_SLLN = 128'd1000000000000 << N; // x_qN = rounded division X_qN = (NUM_1E12_SLLN + (DENOM >> 1)) / DENOM; // Powers X2 = X_qN * X_qN; X3 = X2 * X_qN; // Convert terms to Q1.15: // term1 = x -> shift from QN to Q15 term1_q15 = (X_qN >> (N - 15)) & 16'hFFFF; // term2 = x^2 / 2 -> Q(2N) to Q15 and /2 term2_q15 = (X2 >> (2*N - 15 + 1)) & 16'hFFFF; // term3 = x^3 / 6 -> Q(3N) to Q15, then /6 with rounding begin : gen_t3 reg [383:0] tmp_q15_wide; reg [383:0] tmp_div6; tmp_q15_wide = (X3 >> (3*N - 15)); tmp_div6 = (tmp_q15_wide + 6'd3) / 6; term3_q15 = tmp_div6[15:0]; end // Combine and clamp acc = term1_q15 - term2_q15 + term3_q15; if (acc < 0) acc = 0; else if (acc > 16'h7FFF) acc = 16'h7FFF; alpha_q15_from_rc = acc; end endfunction `endif