// poly_arith_sync.v - Polynomial modular add/sub for ML-KEM
//
// Performs element-wise modular addition or subtraction on two streaming
// 256-coefficient polynomials over Z_q (q=3329).
//
// mode=0: coeff_out = (coeff_a_in + coeff_b_in) mod Q
// mode=1: coeff_out = (coeff_a_in - coeff_b_in) mod Q
//
// Each cycle processes one coefficient pair. Pure streaming — no internal
// storage; the caller sequences all 256 coefficients in order.

`include "sync_rtl/common/defines.vh"

module poly_arith_sync (
    input         clk,
    input         rst_n,
    input  [11:0] coeff_a_in,
    input  [11:0] coeff_b_in,
    input         mode,       // 0=add, 1=sub
    input         valid_i,
    output        ready_o,
    output [11:0] coeff_out,
    output        valid_o,
    input         ready_i
);

    //--------------------------------------------------------------
    // Combinational modular arithmetic
    //--------------------------------------------------------------
    wire [12:0] add_raw;        // a + b (13-bit to catch overflow)
    wire [11:0] add_sub_q;      // (a + b) - Q
    wire [11:0] add_result;     // (a + b) mod Q

    assign add_raw   = {1'b0, coeff_a_in} + {1'b0, coeff_b_in};
    assign add_sub_q = add_raw[11:0] - `Q;
    assign add_result = (add_raw < `Q) ? add_raw[11:0] : add_sub_q;

    wire [11:0] sub_result;     // (a - b) mod Q
    // When a >= b: diff = a - b (already in [0, Q-2])
    // When a <  b: diff = a + Q - b (borrow correction)
    assign sub_result = (coeff_a_in < coeff_b_in)
        ? (coeff_a_in + `Q - coeff_b_in)
        : (coeff_a_in - coeff_b_in);

    wire [11:0] mod_result = mode ? sub_result : add_result;

    //--------------------------------------------------------------
    // Pipeline the result through pipeline_reg for valid/ready
    //--------------------------------------------------------------
    pipeline_reg #(.DW(12)) u_pipe (
        .clk    (clk),
        .rst_n  (rst_n),
        .data_i (mod_result),
        .valid_i(valid_i),
        .ready_o(ready_o),
        .data_o (coeff_out),
        .valid_o(valid_o),
        .ready_i(ready_i)
    );

endmodule
