`include "lr_acc.svh"


module comb_adder_18b (
    
    //Port Structure
    input clk, 
    input reset,
    input logic adder_start, 
    input logic [`ADDER_IN_SIZE_18b-1:0]   op0,
    input logic [`ADDER_IN_SIZE_18b-1:0]   op1,
    input logic [`ADDER_IN_SIZE_18b-1:0]   op2,
    input logic [`ADDER_IN_SIZE_18b-1:0]   op3, 
    input logic [`ADDER_IN_SIZE_18b-1:0]   op4,
    input logic [`ADDER_IN_SIZE_18b-1:0]   op5, 
    input logic [`ADDER_IN_SIZE_18b-1:0]   op6,
    input logic [`ADDER_IN_SIZE_18b-1:0]   op7, 
    input logic [`ADDER_IN_SIZE_18b-1:0]   op8,
    input logic [`ADDER_IN_SIZE_18b-1:0]   op9, 
    input logic [`ADDER_IN_SIZE_18b-1:0]   opA,
    input logic [`ADDER_IN_SIZE_18b-1:0]   opB, 
    input logic [`ADDER_IN_SIZE_18b-1:0]   opC,
    input logic [`ADDER_IN_SIZE_18b-1:0]   opD, 
    input logic [`ADDER_IN_SIZE_18b-1:0]   opE,
    input logic [`ADDER_IN_SIZE_18b-1:0]   opF,

    output logic [`ADDER_OUT_SIZE_18b-1:0] result
);

    logic [`ADDER_IN_SIZE_18b-1:0]   op01;
    logic [`ADDER_IN_SIZE_18b-1:0]   op23; 
    logic [`ADDER_IN_SIZE_18b-1:0]   op45;
    logic [`ADDER_IN_SIZE_18b-1:0]   op67; 
    logic [`ADDER_IN_SIZE_18b-1:0]   op89;
    logic [`ADDER_IN_SIZE_18b-1:0]   opAB; 
    logic [`ADDER_IN_SIZE_18b-1:0]   opCD;
    logic [`ADDER_IN_SIZE_18b-1:0]   opEF; 


    unsigned_adder #(.WIDTH(18)) adder_inst0 (
        .dataa(op0),
        .datab(op1),
        .cin('0),
        .result(op01)
    );


    unsigned_adder #(.WIDTH(18)) adder_inst1 (
        .dataa(op2),
        .datab(op3),
        .cin('0),
        .result(op23)
    );


    unsigned_adder #(.WIDTH(18)) adder_inst2 (
        .dataa(op4),
        .datab(op5),
        .cin('0),
        .result(op45)
    );


    unsigned_adder #(.WIDTH(18)) adder_inst3 (
        .dataa(op6),
        .datab(op7),
        .cin('0),
        .result(op67)
    );

    unsigned_adder #(.WIDTH(18)) adder_inst4 (
        .dataa(op8),
        .datab(op9),
        .cin('0),
        .result(op89)
    );


    unsigned_adder #(.WIDTH(18)) adder_inst5 (
        .dataa(opA),
        .datab(opB),
        .cin('0),
        .result(opAB)
    );


    unsigned_adder #(.WIDTH(18)) adder_inst6 (
        .dataa(opC),
        .datab(opD),
        .cin('0),
        .result(opCD)
    );


    unsigned_adder #(.WIDTH(18)) adder_inst7 (
        .dataa(opE),
        .datab(opF),
        .cin('0),
        .result(opEF)
    );

    logic [`ADDER_IN_SIZE_18b:0]   local_op01;
    logic [`ADDER_IN_SIZE_18b-1:0]   local_op23; 
    logic [`ADDER_IN_SIZE_18b-1:0]   local_op45;
    logic [`ADDER_IN_SIZE_18b-1:0]   local_op67; 
    logic [`ADDER_IN_SIZE_18b-1:0]   local_op89;
    logic [`ADDER_IN_SIZE_18b-1:0]   local_opAB; 
    logic [`ADDER_IN_SIZE_18b-1:0]   local_opCD;
    logic [`ADDER_IN_SIZE_18b-1:0]   local_opEF;

     always_ff @(posedge clk or posedge reset) begin
        if (reset) begin
            local_op01 <= '0;
            local_op23 <= '0;
            local_op45 <= '0;
            local_op67 <= '0;
            local_op89 <= '0;
            local_opAB <= '0;
            local_opCD <= '0;
            local_opEF <= '0;
        end else begin
            local_op01 <= op01;
            local_op23 <= op23;
            local_op45 <= op45;
            local_op67 <= op67;
            local_op89 <= op89;
            local_opAB <= opAB;
            local_opCD <= opCD;
            local_opEF <= opEF;
        end
    end

    logic [`ADDER_IN_SIZE_18b-1:0]   op0123;
    logic [`ADDER_IN_SIZE_18b-1:0]   op4567; 
    logic [`ADDER_IN_SIZE_18b-1:0]   op89AB;
    logic [`ADDER_IN_SIZE_18b-1:0]   opCDEF; 

    unsigned_adder #(.WIDTH(18)) adder_inst00 (
        .dataa(local_op01),
        .datab(local_op23),
        .cin('0),
        .result(op0123)
    );


    unsigned_adder #(.WIDTH(18)) adder_inst01 (
        .dataa(local_op45),
        .datab(local_op67),
        .cin('0),
        .result(op4567)
    );


    unsigned_adder #(.WIDTH(18)) adder_inst02 (
        .dataa(local_op89),
        .datab(local_opAB),
        .cin('0),
        .result(op89AB)
    );


    unsigned_adder #(.WIDTH(18)) adder_inst03 (
        .dataa(local_opCD),
        .datab(local_opEF),
        .cin('0),
        .result(opCDEF)
    );

    logic [`ADDER_IN_SIZE_18b-1:0]   local_op0123;
    logic [`ADDER_IN_SIZE_18b-1:0]   local_op4567; 
    logic [`ADDER_IN_SIZE_18b-1:0]   local_op89AB;
    logic [`ADDER_IN_SIZE_18b-1:0]   local_opCDEF; 

    always_ff @(posedge clk or posedge reset) begin
        if (reset) begin
            local_op0123  <= '0;
            local_op4567  <= '0;
            local_op89AB  <= '0;
            local_opCDEF  <= '0;
        end else begin
            local_op0123  <= op0123;
            local_op4567  <= op4567;
            local_op89AB  <= op89AB;
            local_opCDEF  <= opCDEF;
        end
    end

    logic [`ADDER_IN_SIZE_18b-1:0]   op01234567;
    logic [`ADDER_IN_SIZE_18b-1:0]   op89ABCDEF;

    unsigned_adder #(.WIDTH(18)) adder_inst000 (
        .dataa(local_op0123),
        .datab(local_op4567),
        .cin('0),
        .result(op01234567)
    );


    unsigned_adder #(.WIDTH(18)) adder_inst001 (
        .dataa(local_op89AB),
        .datab(local_opCDEF),
        .cin('0),
        .result(op89ABCDEF)
    );

    logic [`ADDER_IN_SIZE_18b-1:0] local_op01234567;
    logic [`ADDER_IN_SIZE_18b-1:0] local_op89ABCDEF;

    always_ff @(posedge clk or posedge reset) begin
        if (reset) begin
            local_op01234567 <= '0;
            local_op89ABCDEF <= '0;
        end else begin
            local_op01234567 <= op01234567;
            local_op89ABCDEF <= op89ABCDEF;
        end
    end

    logic [`ADDER_IN_SIZE_18b-1:0]   final_sum;


    // Final addition
    unsigned_adder #(.WIDTH(18)) adder_final0000 (
        .dataa(local_op01234567),
        .datab(local_op89ABCDEF),
        .cin('0),
        .result(final_sum)
    );

    // Registered final result
    logic [`ADDER_IN_SIZE_18b-1:0] final_sum_reg;

    always_ff @(posedge clk or posedge reset) begin
        if (reset)
            final_sum_reg <= '0;
        else
            final_sum_reg <= final_sum;
    end

    assign result = final_sum_reg;

endmodule