module CicCombFilter # (
    parameter M = 4, // Differential delay
    parameter InOutDataWidth = 18 // Input and output data width
)
(
    input logic                                 Clk_i,
    input logic                                 Rst_i,
    input logic     signed [InOutDataWidth-1:0] Data_i,
    input logic                                 DataVal_i,

    output logic    signed [InOutDataWidth-1:0] Data_o,
    output logic                                DataVal_o
);

//================================================================================
//								REG/WIRE
//================================================================================
logic signed [InOutDataWidth-1:0] combDataReg;
logic combDataValReg;

logic signed [InOutDataWidth-1:0] delayedDataReg [0:M-1];

logic dataValReg;

//================================================================================
//								ASSIGNMENTS
//================================================================================
assign Data_o = combDataReg;
assign DataVal_o = combDataValReg;

//================================================================================
//								CODING
//================================================================================
genvar i;
generate
    for (i = 0; i < M; i++) begin : comb_stage
        always_ff @(posedge Clk_i) begin 
            if (Rst_i) begin
                delayedDataReg[i] <= 0;
            end 
            else begin
                if (DataVal_i) begin
                    if (i == 0) begin
                        delayedDataReg[i] <= Data_i;
                    end 
                    else begin
                        delayedDataReg[i] <= delayedDataReg[i-1];
                    end
                end
            end
        end
    end
endgenerate

always_ff @(posedge Clk_i) begin 
    if (Rst_i) begin 
        dataValReg <= 0;
    end
    else begin 
        if (DataVal_i) begin
            dataValReg <= 1;
        end  
        else begin
            dataValReg <= 0;
        end
    end
end

always_ff @(posedge Clk_i) begin 
    if (Rst_i) begin
        combDataReg <= 0;
        combDataValReg <= 0;
    end 
    else begin
        if (DataVal_i) begin
            combDataReg <= Data_i - delayedDataReg[M-1]; // y[n] = x[n-M] - x[n]
            combDataValReg <= 1;
        end 
        else begin
            combDataValReg <= 0;
        end
    end
end

endmodule