// basecase_mul_pipe.v - pipelined NTT-domain degree-1 multiplication // // Fixed-latency replacement for the combinational basecase_mul hot path. // The shared ntt/barrett_mul remains combinational for NTT users; this module // keeps the extra registers local to poly_mul_sync. (* use_dsp = "no" *) module basecase_mul_pipe ( input clk, input rst_n, input valid_i, input [11:0] a0, a1, input [11:0] b0, b1, input [11:0] zeta, output [11:0] c0, output [11:0] c1, output valid_o ); localparam [11:0] Q12 = 12'd3329; localparam [12:0] K13 = 13'd5039; localparam [24:0] Q25 = 25'd3329; function [12:0] barrett_q; input [23:0] p; reg [36:0] prod; begin prod = {13'd0, p} * K13; barrett_q = prod[36:24]; end endfunction function [11:0] barrett_reduce; input [23:0] p; input [12:0] qe; reg [24:0] q_approx; reg [24:0] r0; reg [24:0] r1; reg [24:0] r2; begin q_approx = qe * Q12; r0 = {1'b0, p} - q_approx; r1 = (r0 >= Q25) ? (r0 - Q25) : r0; r2 = (r1 >= Q25) ? (r1 - Q25) : r1; barrett_reduce = r2[11:0]; end endfunction function [11:0] mod_add; input [11:0] x; input [11:0] y; reg [12:0] sum; begin sum = {1'b0, x} + {1'b0, y}; mod_add = (sum >= {1'b0, Q12}) ? (sum[11:0] - Q12) : sum[11:0]; end endfunction // Stage 1: first-level scalar products. reg [23:0] p10, p11, p12, p13; reg [11:0] zeta_s1; // Stage 2: Barrett quotient estimates for first-level products. reg [23:0] p20, p21, p22, p23; reg [12:0] q20, q21, q22, q23; reg [11:0] zeta_s2; // Stage 3: first-level reduced products. reg [11:0] t1_s3, t2_s3, t3_s3, t4_s3; reg [11:0] zeta_s3; // Stage 4: zeta product for c0's second Barrett multiply. reg [11:0] t1_s4, t3_s4, t4_s4; reg [23:0] pz_s4; // Stage 5: Barrett quotient estimate for zeta product. reg [11:0] t1_s5, t3_s5, t4_s5; reg [23:0] pz_s5; reg [12:0] qz_s5; // Stage 6: reduced zeta product. reg [11:0] t1_s6, t3_s6, t4_s6, tz_s6; // Stage 7: final modular additions. reg [11:0] c0_r, c1_r; reg [6:0] valid_sr; assign c0 = c0_r; assign c1 = c1_r; assign valid_o = valid_sr[6]; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin p10 <= 24'd0; p11 <= 24'd0; p12 <= 24'd0; p13 <= 24'd0; zeta_s1 <= 12'd0; p20 <= 24'd0; p21 <= 24'd0; p22 <= 24'd0; p23 <= 24'd0; q20 <= 13'd0; q21 <= 13'd0; q22 <= 13'd0; q23 <= 13'd0; zeta_s2 <= 12'd0; t1_s3 <= 12'd0; t2_s3 <= 12'd0; t3_s3 <= 12'd0; t4_s3 <= 12'd0; zeta_s3 <= 12'd0; t1_s4 <= 12'd0; t3_s4 <= 12'd0; t4_s4 <= 12'd0; pz_s4 <= 24'd0; t1_s5 <= 12'd0; t3_s5 <= 12'd0; t4_s5 <= 12'd0; pz_s5 <= 24'd0; qz_s5 <= 13'd0; t1_s6 <= 12'd0; t3_s6 <= 12'd0; t4_s6 <= 12'd0; tz_s6 <= 12'd0; c0_r <= 12'd0; c1_r <= 12'd0; valid_sr <= 7'd0; end else begin valid_sr <= {valid_sr[5:0], valid_i}; p10 <= {12'd0, a0} * b0; p11 <= {12'd0, a1} * b1; p12 <= {12'd0, a1} * b0; p13 <= {12'd0, a0} * b1; zeta_s1 <= zeta; p20 <= p10; p21 <= p11; p22 <= p12; p23 <= p13; q20 <= barrett_q(p10); q21 <= barrett_q(p11); q22 <= barrett_q(p12); q23 <= barrett_q(p13); zeta_s2 <= zeta_s1; t1_s3 <= barrett_reduce(p20, q20); t2_s3 <= barrett_reduce(p21, q21); t3_s3 <= barrett_reduce(p22, q22); t4_s3 <= barrett_reduce(p23, q23); zeta_s3 <= zeta_s2; t1_s4 <= t1_s3; t3_s4 <= t3_s3; t4_s4 <= t4_s3; pz_s4 <= {12'd0, t2_s3} * zeta_s3; t1_s5 <= t1_s4; t3_s5 <= t3_s4; t4_s5 <= t4_s4; pz_s5 <= pz_s4; qz_s5 <= barrett_q(pz_s4); t1_s6 <= t1_s5; t3_s6 <= t3_s5; t4_s6 <= t4_s5; tz_s6 <= barrett_reduce(pz_s5, qz_s5); c0_r <= mod_add(t1_s6, tz_s6); c1_r <= mod_add(t3_s6, t4_s6); end end endmodule