// Post-Training Quantization Engine
module ptq_quant #(parameter DW=16, QW=8, NC=64, SF=16)(
    input clk, rst_n, qen, per_ch, input [1:0] scheme,
    input signed [DW-1:0] din, input [$clog2(NC)-1:0] ch,
    input din_valid,
    input [SF+8-1:0] scale[0:NC-1], input signed [QW-1:0] zp[0:NC-1],
    output reg signed [QW-1:0] dout, output reg dout_valid,
    output reg signed [DW-1:0] minv[0:NC-1], maxv[0:NC-1], output reg stats_valid
);
    wire [SF+8-1:0] sc=per_ch?scale[ch]:scale[0]; wire signed [QW-1:0] czp=per_ch?zp[ch]:zp[0];
    wire signed [DW+SF+7:0] scaled=din*sc;
    wire signed [DW+SF+7:0] rounded=scaled+(1<<<(SF-1));
    wire signed [DW+7:0] iv=rounded[DW+SF+7:SF];
    wire signed [QW-1:0] clamped=(iv>(1<<<(QW-1))-1)?((1<<<(QW-1))-1):(iv<(-(1<<<(QW-1))))?(-(1<<<(QW-1))):iv[QW-1:0];
    wire signed [QW:0] wzp=clamped+czp;
    wire signed [QW-1:0] fv=(wzp>(1<<<QW)-1)?((1<<<QW)-1):(wzp<0)?'0:wzp[QW-1:0];
    integer ci;
    always_ff @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin for(ci=0;ci<NC;ci++) begin minv[ci]<='1; maxv[ci]<='0; end dout<='0; dout_valid<=0; stats_valid<=0; end
        else begin dout_valid<=din_valid&&qen; stats_valid<=din_valid;
            if(din_valid) begin if(din<minv[ch]) minv[ch]<=din; if(din>maxv[ch]) maxv[ch]<=din; if(qen) dout<=fv; end
        end
    end
endmodule