dakies/OSS_Verilog huggingface dataset:
module hazard (
    `ifdef USE_POWER_PINS
    inout vccd1,	// User area 1 1.8V supply
    inout vssd1,	// User area 1 digital ground
    `endif
    input reset,

    // from decode
    input valid_decode,
    input [4:0] rs1_address_decode,
    input [4:0] rs2_address_decode,
    input uses_rs1,
    input uses_rs2,
    input uses_csr,

    // from execute
    input valid_execute,
    input [4:0] rd_address_execute,
    input csr_write_execute,
        
    // from memory
    input valid_memory,
    input [4:0] rd_address_memory,
    input csr_write_memory,
    input branch_taken,
    input mret_memory,
    input load_store,
    input bypass_memory,

    // from writeback
    input valid_writeback,
    input csr_write_writeback,
    input mret_writeback,
    input wfi,
    input traped,

    // from busio
    input fetch_ready,
    input mem_ready,

    // to fetch
    output stall_fetch,
    output invalidate_fetch,

    // to decode
    output stall_decode,
    output invalidate_decode,

    // to execute
    output stall_execute,
    output invalidate_execute,

    // to memory
    output stall_memory,
    output invalidate_memory
);

assign stall_fetch = stall_decode || data_hazard;
assign stall_decode = stall_execute;
assign stall_execute = stall_memory
    || (!mem_ready && load_store)
    || (valid_memory && mret_memory);
assign stall_memory = wfi;

wire trap_invalidate = mret_writeback || traped;
wire branch_invalidate = branch_taken || trap_invalidate;

wire data_hazard = valid_decode && (
    (valid_execute && rd_address_execute != 0 && (
        uses_rs1 && rs1_address_decode == rd_address_execute
        || uses_rs2 && rs2_address_decode == rd_address_execute
    ))
    || (valid_memory && rd_address_memory != 0 && !bypass_memory && (
        uses_rs1 && rs1_address_decode == rd_address_memory
        || uses_rs2 && rs2_address_decode == rd_address_memory
    ))
    || uses_csr && (
        csr_write_execute && valid_execute
        || csr_write_memory && valid_memory
        || csr_write_writeback && valid_writeback
    ));

assign invalidate_fetch = reset || branch_invalidate || (!fetch_ready && !data_hazard);
assign invalidate_decode = reset || branch_invalidate || data_hazard;
assign invalidate_execute = reset || branch_invalidate;
assign invalidate_memory = reset || trap_invalidate || (!mem_ready && load_store);

endmodule
module regfile (
    `ifdef USE_POWER_PINS
    inout vccd1,	// User area 1 1.8V supply
    inout vssd1,	// User area 1 digital ground
    `endif
    input clk,
    input [4:0] rs1_address,
    input [4:0] rs2_address,
    input [4:0] rd_address,
    input [31:0] rd_data,
    output reg [31:0] rs1_data,
    output reg [31:0] rs2_data
);

    // 32 registers, each 32 bits wide
    reg [31:0] registers [31:0];

    // Read data from the registers continuously
    always @(*) begin
        rs1_data = registers[rs1_address];
        rs2_data = registers[rs2_address];
    end

    // Write data to the registers on the rising edge of the clock
    // Note: Register 0 is hardwired to zero in RISC-V architecture, hence no data can be written into it
    always @(posedge clk) begin
        if(rd_address != 5'b00000) begin
            registers[rd_address] <= rd_data;
        end
    end
endmodule
module alu (
    `ifdef USE_POWER_PINS
    inout vccd1,	// User area 1 1.8V supply
    inout vssd1,	// User area 1 digital ground
    `endif
    input clk,

    input [31:0] input_a,
    input [31:0] input_b,

    input [2:0] function_select,
    input function_modifier,

    // 1st cycle output
    output [31:0] add_result,
    // 2nd cycle output
    output reg [31:0] result
);

    // Define function codes
    localparam 
        ALU_ADD_SUB = 3'b000,
        ALU_SLL     = 3'b001,
        ALU_SLT     = 3'b010,
        ALU_SLTU    = 3'b011,
        ALU_XOR     = 3'b100,
        ALU_SRL_SRA = 3'b101,
        ALU_OR      = 3'b110,
        ALU_AND_CLR = 3'b111;

    // Define result registers
    reg [31:0] result_add_sub, result_sll, result_slt, result_sltu,
                result_xor, result_srl_sra, result_or, result_and_clr;
    /* verilator lint_off UNUSED */ // The first bit [32] will intentionally be ignored
    wire [32:0] tmp_shifted = $signed({function_modifier ? input_a[31] : 1'b0, input_a}) >>> input_b[4:0];
    /* verilator lint_on UNUSED */
    // Store the old function
    reg [2:0] old_function;
    assign add_result = result_add_sub;
    // Calculate results based on the selected function
    always @(posedge clk) begin
        // Compute add/subtract result
        if (function_select == ALU_ADD_SUB)
            result_add_sub <= function_modifier ? (input_a - input_b) : (input_a + input_b);

        // Compute shift left logical result
        if (function_select == ALU_SLL)
            result_sll <= input_a << input_b[4:0];

        // Compute set less than result
        if (function_select == ALU_SLT)
            result_slt <= ($signed(input_a) < $signed(input_b)) ? 1 : 0;

        // Compute set less than unsigned result
        if (function_select == ALU_SLTU)
            result_sltu <= (input_a < input_b) ? 1 : 0;

        // Compute XOR result
        if (function_select == ALU_XOR)
            result_xor <= input_a ^ input_b;

        // Compute shift right logical/arithmetic result
        if (function_select == ALU_SRL_SRA)
            result_srl_sra <= tmp_shifted[31:0];

        // Compute OR result
        if (function_select == ALU_OR)
            result_or <= input_a | input_b;

        // Compute AND/CLR result
        if (function_select == ALU_AND_CLR)
            result_and_clr <= (function_modifier ? ~input_a : input_a) & input_b;
        
        // Update old function
        old_function <= function_select;
    end
    // Output result based on the old function
    always @(*) begin
        case (old_function)
            ALU_ADD_SUB: result = result_add_sub;
            ALU_SLL:     result = result_sll;
            ALU_SLT:     result = result_slt;
            ALU_SLTU:    result = result_sltu;
            ALU_XOR:     result = result_xor;
            ALU_SRL_SRA: result = result_srl_sra;
            ALU_OR:      result = result_or;
            ALU_AND_CLR: result = result_and_clr;
        endcase
    end

    // Output add/subtract result immediately

endmodule
module fetch #(
    parameter RESET_VECTOR = 32'h8000_0000
) (
    `ifdef USE_POWER_PINS
    inout vccd1,	// User area 1 1.8V supply
    inout vssd1,	// User area 1 digital ground
    `endif
    input clk,
    input reset,

    // from execute
    input branch,
    input [31:0] branch_vector,

    // from writeback
    input trap,
    input mret,

    // from csr
    input [31:0] trap_vector,
    input [31:0] mret_vector,

    // from hazard
    input stall,
    input invalidate,

    // to busio
    output [31:0] fetch_address,
    // from busio
    input [31:0] fetch_data,

    // to decode
    output reg [31:0] pc_out,
    output reg [31:0] next_pc_out,
    output reg [31:0] instruction_out,
    output reg valid_out
);

    reg [31:0] pc = RESET_VECTOR;
    wire [31:0] next_pc = pc + 4;

// Select the next PC
// Select the next PC
always @(posedge clk) begin
    if (reset) begin
        pc <= RESET_VECTOR;
    end
    else if (trap) begin
        pc <= trap_vector;
    end
    else if (mret) begin
        pc <= mret_vector;
    end
    else if (branch) begin
        pc <= branch_vector;
    end
    else if (stall || invalidate) begin
        pc <= pc;
    end
    else begin
        pc <= next_pc;
    end
end


    // Output fetch address to busio
    assign fetch_address = pc;

    // Handle instruction fetch and output to decode
    always @(posedge clk) begin
        if(stall || invalidate)
            valid_out <= 0;
        else
            valid_out <= 1;

        if(!stall) begin
            pc_out <= pc;
            next_pc_out <= next_pc;
            instruction_out <= fetch_data;
        end
    end

endmodule
module writeback (
    `ifdef USE_POWER_PINS
    inout vccd1,	// User area 1 1.8V supply
    inout vssd1,	// User area 1 digital ground
    `endif
    /* input clk, */

    // from memory
    input [31:0] pc_in,
    input [31:0] next_pc_in,
    // from memory (control WB)
    input [31:0] alu_data_in,
    input [31:0] csr_data_in,
    input [31:0] load_data_in,
    input [1:0] write_select_in,
    input [4:0] rd_address_in,
    input [11:0] csr_address_in,
    input csr_write_in,
    input mret_in,
    input wfi_in,
    // from memory
    input valid_in,
    input [3:0] ecause_in,
    input exception_in,

    // from csr
    input sip,
    input tip,
    input eip,

    // to regfile
    output [4:0] rd_address,
    output reg [31:0] rd_data,

    // to csr
    output csr_write,
    output [11:0] csr_address,
    output [31:0] csr_data,

    // to fetch and csr and hazard
    output traped,
    output mret,

    // to hazard
    output wfi,

    // to csr
    output retired,
    output [31:0] ecp,
    output reg [3:0] ecause,
    output reg interupt
);

localparam WRITE_SEL_ALU     = 2'b00;
localparam WRITE_SEL_CSR     = 2'b01;
localparam WRITE_SEL_LOAD    = 2'b10;
localparam WRITE_SEL_NEXT_PC = 2'b11;

wire exception = exception_in && valid_in;

assign traped = (sip || tip || eip || exception);
assign ecp = wfi_in ? next_pc_in : pc_in;
assign wfi = valid_in && wfi_in;

assign retired = valid_in && !traped && !wfi;

assign mret = valid_in && mret_in;

always @(*) begin
    if (eip) begin
        ecause = 11;
        interupt = 1;
    end else if (tip) begin
        ecause = 7;
        interupt = 1;
    end else if (sip) begin
        ecause = 3;
        interupt = 1;
    end else if (exception_in) begin
        ecause = ecause_in;
        interupt = 0;
    end else begin
        ecause = 0;
        interupt = 0;
    end
end

assign rd_address = (!valid_in || traped) ? 5'h0 : rd_address_in;

always @(*) begin
    case (write_select_in)
        WRITE_SEL_ALU: rd_data = alu_data_in;
        WRITE_SEL_CSR: rd_data = csr_data_in;
        WRITE_SEL_LOAD: rd_data = load_data_in;
        WRITE_SEL_NEXT_PC: rd_data = next_pc_in;
    endcase
end

assign csr_write = valid_in && !traped && csr_write_in;
assign csr_address = csr_address_in;
assign csr_data = alu_data_in;

endmodule
module multiplier(multiplicand, multiplier,
                        O14, O13, O12, O11, O10, O9, O8, O7, O6, O5, O4, O3, O2, O1, O0);

input [8*9-1:0] multiplicand, multiplier;
wire signed [8-1:0] md[0:8], mr[0:8];

wire [10:0] pp0[0:8];
wire [8:0] pp1[0:8], pp2[0:8], pp3[0:8];
wire neg0[0:8], neg1[0:8], neg2[0:8], neg3[0:8];

genvar i;
generate
for(i=0; i<9; i=i+1) begin : app
    assign md[i] = multiplicand[8*9-1 - 8*i -: 8];
    assign mr[i] = multiplier[8*9-1 - 8*i -: 8];
    PPG P0(md[i], mr[i], pp0[i],  pp1[i],  pp2[i],  pp3[i], neg0[i], neg1[i], neg2[i], neg3[i]);
end
endgenerate



wire [8:0] pp0_trans[0:11];
wire [8:0] pp1_trans[0:9], pp2_trans[0:9], pp3_trans[0:9];

genvar j;
generate
for(j=0; j<11; j=j+1) begin : transpose_pp0
    assign pp0_trans[j] = {pp0[0][j], pp0[1][j], pp0[2][j], pp0[3][j], pp0[4][j], pp0[5][j], pp0[6][j], pp0[7][j], 
                pp0[8][j]};
end

for(j=0; j<9; j=j+1) begin : transpose_pp123
    assign pp1_trans[j] = {pp1[0][j], pp1[1][j], pp1[2][j], pp1[3][j], pp1[4][j], pp1[5][j], pp1[6][j], pp1[7][j], 
                pp1[8][j]};
    assign pp2_trans[j] = {pp2[0][j], pp2[1][j], pp2[2][j], pp2[3][j], pp2[4][j], pp2[5][j], pp2[6][j], pp2[7][j], 
                pp2[8][j]};
    assign pp3_trans[j] = {pp3[0][j], pp3[1][j], pp3[2][j], pp3[3][j], pp3[4][j], pp3[5][j], pp3[6][j], pp3[7][j], 
                pp3[8][j]};
end

endgenerate

output [8:0] O14, O13;
output [17:0] O12, O11;
output [35:0] O10, O9, O8, O7;
output [44:0] O6;
output [26:0] O5;
output [35:0] O4;
output [17:0] O3;
output [26:0] O2;
output [8:0] O1;
output [17:0] O0;

assign O14 = pp3_trans[8];
assign O13 = pp3_trans[7];
assign O12 = {pp3_trans[6], pp2_trans[8]};
assign O11 = {pp3_trans[5], pp2_trans[7]};
assign O10 = {pp3_trans[4], pp2_trans[6], pp1_trans[8], pp0_trans[10]};
assign O9 = {pp3_trans[3], pp2_trans[5], pp1_trans[7], pp0_trans[9]};
assign O8 = {pp3_trans[2], pp2_trans[4], pp1_trans[6], pp0_trans[8]};
assign O7 = {pp3_trans[1], pp2_trans[3], pp1_trans[5], pp0_trans[7]};
assign O6 = {pp3_trans[0], pp2_trans[2], pp1_trans[4], pp0_trans[6], 
                neg3[0], neg3[1], neg3[2], neg3[3], neg3[4], neg3[5], neg3[6], neg3[7], neg3[8]};
assign O5 = {               pp2_trans[1], pp1_trans[3], pp0_trans[5]};
assign O4 = {               pp2_trans[0], pp1_trans[2], pp0_trans[4],
                neg2[0], neg2[1], neg2[2], neg2[3], neg2[4], neg2[5], neg2[6], neg2[7], neg2[8]};
assign O3 = {                             pp1_trans[1], pp0_trans[3]};
assign O2 = {                             pp1_trans[0], pp0_trans[2],
                neg1[0], neg1[1], neg1[2], neg1[3], neg1[4], neg1[5], neg1[6], neg1[7], neg1[8]};
assign O1 = pp0_trans[1];
assign O0 = {pp0_trans[0], 
                         neg0[0], neg0[1], neg0[2], neg0[3], neg0[4], neg0[5], neg0[6], neg0[7], neg0[8]};


endmodule
module adder_7to3(in, cout, carry, sum);

input [6:0] in;
wire x1, x2, x3, x4, x5, x6, x7;
output cout, carry, sum;

assign {x1, x2, x3, x4, x5, x6, x7} = in;

wire and12, xor12, and34, xor34, and56, xor56;

assign and12 = x1 & x2;
assign xor12 = x1 ^ x2;
assign and34 = x3 & x4;
assign xor34 = x3 ^ x4;
assign and56 = x5 & x6;
assign xor56 = x5 ^ x6;

wire  and4, xor4, and5, xor5, and6, xor6;

assign and4 = and12 & and34;
assign xor4 = and12 ^ and34;
assign and5 = xor12 & xor34;
assign xor5 = xor12 ^ xor34;
assign and6 = x7 & xor56;
assign xor6 = x7 ^ xor56;

wire xor10, xor7;

assign xor10 = xor4 ^ and5;
assign xor7 = and56 ^ and6;

wire and8, xor8, and9, xor9;

assign and8 = xor5 & xor6;
assign xor8 = xor5 ^ xor6;
assign and9 = xor10 & xor7;
assign xor9 = xor10 ^ xor7;


wire xor12_, and11, xor11, xor13;

assign xor12_ = and9 ^ and11;
assign and11 = xor9 & and8;
assign xor11 = xor9 ^ and8;
assign xor13 = xor12_ ^ and4;

assign sum = xor8;
assign carry = xor11;
assign cout = xor13;

endmodule
module addertree_stage3_mod2(x19, x18, x17, x16, x15, x14, x13, x12, x11, x10, x9, x8, x7, x6, x5, x4, x3,
                        o19, o18, o17, o16, o15, o14, o13, o12, o11, o10, o9, o8, o7, o6, o5
                        );


input x19;
input [1:0] x18;
input [2:0] x17;
input [3:0] x16, x15, x14, x13, x12, x11, x10, x9, x8, x7;
input [2:0] x6, x5;
input [1:0] x4;
input x3;

wire [1:0] a19, a18, a17;
wire [2:0] a16, a15, a14, a13, a12, a11, a10, a9, a8, a7;
wire [1:0] a6, a5;
wire a4;

// x19
assign a19[0] = x19;

// x18 3
HA A180(x18[0], x18[1], a18[0], a19[1]);

// x17 3
FA A170(x17[0], x17[1], x17[2], a17[0], a18[1]);

// x16 3
FA A160(x16[0], x16[1], x16[2], a16[0], a17[1]);

// x15 3
FA A150(x15[0], x15[1], x15[2], a15[0], a16[1]);

// x14 3
FA A140(x14[0], x14[1], x14[2], a14[0], a15[1]);

// x13 3
FA A130(x13[0], x13[1], x13[2], a13[0], a14[1]);

// x12 3
FA A120(x12[0], x12[1], x12[2], a12[0], a13[1]);

// x11 3
FA A110(x11[0], x11[1], x11[2], a11[0], a12[1]);

// x10 3
FA A100(x10[0], x10[1], x10[2], a10[0], a11[1]);

// x9 3
FA A90(x9[0], x9[1], x9[2], a9[0], a10[1]);

// x8 3
FA A80(x8[0], x8[1], x8[2], a8[0], a9[1]);

// x7 3
FA A70(x7[0], x7[1], x7[2], a7[0], a8[1]);

// x6 3
FA A60(x6[0], x6[1], x6[2], a6[0], a7[1]);

// x5 3
FA A50(x5[0], x5[1], x5[2], a5[0], a6[1]);

// x4 2
HA A40(x4[0], x4[1], a4, a5[1]);

assign a16[2] = x16[3];
assign a15[2] = x15[3];
assign a14[2] = x14[3];
assign a13[2] = x13[3];
assign a12[2] = x12[3];
assign a11[2] = x11[3];
assign a10[2] = x10[3];
assign a9[2] = x9[3];
assign a8[2] = x8[3];
assign a7[2] = x7[3];



//stage4

output [1:0] o19, o18, o17, o16, o15, o14, o13, o12, o11, o10, o9, o8, o7, o6;
output o5; 

// a19 2
assign o19[0] = a19[0] ^ a19[1];

// a18 2
HA A181(a18[0], a18[1], o18[0], o19[1]);

// a17 2
HA A171(a17[0], a17[1], o17[0], o18[1]);

// a16 3
FA A161(a16[0], a16[1], a16[2], o16[0], o17[1]);

// a15 3
FA A151(a15[0], a15[1], a15[2], o15[0], o16[1]);

// a14 3
FA A141(a14[0], a14[1], a14[2], o14[0], o15[1]);

// a13 3
FA A131(a13[0], a13[1], a13[2], o13[0], o14[1]);

// a12 3
FA A121(a12[0], a12[1], a12[2], o12[0], o13[1]);

// a11 3
FA A111(a11[0], a11[1], a11[2], o11[0], o12[1]);

// a10 3
FA A101(a10[0], a10[1], a10[2], o10[0], o11[1]);

// a9 3
FA A91(a9[0], a9[1], a9[2], o9[0], o10[1]);

// a8 3
FA A81(a8[0], a8[1], a8[2], o8[0], o9[1]);

// a7 3
FA A71(a7[0], a7[1], a7[2], o7[0], o8[1]);

// a6 2
HA A61(a6[0], a6[1], o6[0], o7[1]);

// a5 2
HA A51(a5[0], a5[1], o5, o6[1]);



endmodule
module PPG(multiplicand, multiplier, pp0,  pp1,  pp2,  pp3, neg0, neg1, neg2, neg3);

input signed [7:0] multiplicand, multiplier;
wire [2:0] S[0:3];

/// line 0
wire [2:0] S0;
MBE_enc Me0(multiplier[1], multiplier[0], 1'b0, S[0]);
MBE_enc Me1(multiplier[3], multiplier[2], multiplier[1], S[1]);
MBE_enc Me2(multiplier[5], multiplier[4], multiplier[3], S[2]);
MBE_enc Me3(multiplier[7], multiplier[6], multiplier[5], S[3]);

wire [7:0] sign[0:3];

genvar i;
generate
for(i=0; i<4; i=i+1) begin : signa
    assign sign[i] = multiplicand ^ {S[i][2], S[i][2], S[i][2], S[i][2], S[i][2], S[i][2], S[i][2], S[i][2]};
end
endgenerate

wire [8:0] m[0:3];

genvar j;
generate
for(j=0; j<4; j=j+1) begin : multia
    assign m[j] = S[j][0] ? 9'b0_0000_0000 :
                            S[j][1] ? {sign[j][7],sign[j]} : {sign[j], S[j][2]};

end
endgenerate

output [10:0] pp0;
output [8:0] pp1, pp2, pp3;

assign pp0 = {~m[0][8], m[0][8], m[0]};
assign pp1 = {~m[1][8], m[1][7-:8]};
assign pp2 = {~m[2][8], m[2][7-:8]};
assign pp3 = {~m[3][8], m[3][7-:8]};


output neg0, neg1, neg2, neg3;

assign neg0 = (S[0][2]) & (~S[0][0]);
assign neg1 = (S[1][2]) & (~S[1][0]);
assign neg2 = (S[2][2]) & (~S[2][0]);
assign neg3 = (S[3][2]) & (~S[3][0]);

endmodule
module tb_adder;

	reg clk, reset;

    wire x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14;
    wire O3, O2, O1, O0, O3m, O2m, O1m, O0m;
	
	
    adder_15to4 A0({x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14}, O3, O2, O1, O0);
    adder_15to4_mod A15({x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14}, O3m, O2m, O1m, O0m);

    wire OO2, OO1, OO0, OOO2, OOO1, OOO0, OOOO2, OOOO1, OOOO0, O2_, O1_, O0_, O26, O16, O06;
    adder_5to3 A1({x10, x11, x12, x13, x14}, OO2, OO1, OO0);
    adder_5to3_mod A2({x10, x11, x12, x13, x14}, OOO2, OOO1, OOO0);
    adder_5to3_mod2 A3({x10, x11, x12, x13, x14}, OOOO2, OOOO1, OOOO0);

    adder_7to3 A4({x8, x9, x10, x11, x12, x13, x14}, O2_, O1_, O0_);

    adder_6to3 A5({x9, x10, x11, x12, x13, x14}, O26, O16, O06);

    reg [14:0] in;
    wire [3:0] out, outm, p_out;
    wire [2:0] p_out_7, p_out_6;

    assign {x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14} = in;
    assign out = {O3, O2, O1, O0};
    assign outm = {O3m, O2m, O1m, O0m};
    assign p_out = x0+x1+x2+x3+x4+x5+x6+x7+x8+x9+x10+x11+x12+x13+x14;
    assign p_out_7 = x8+x9+x10+x11+x12+x13+x14;
    assign p_out_6 = x9+x10+x11+x12+x13+x14;

	initial
	begin
    in = 15'b000_0000_0000_0000;		
	end

    integer err = 0, err1 = 0, err7 = 0, err6 = 0;

    always #10 in = in + 1;
    always begin #9; if (out != p_out | outm != p_out) err = err + 1; #1; end
    always begin #9; if ({OO2, OO1, OO0} != {OOO2, OOO1, OOO0} | {OO2, OO1, OO0} != {OOOO2, OOOO1, OOOO0}) err1 = err1 + 1; #1; end
    always begin #9; if ({O2_, O1_, O0_} != p_out_7) err7 = err7 + 1; #1; end
    always begin #9; if ({O26, O16, O06} != p_out_6) err6 = err6 + 1; #1; end
	




endmodule
module FF_test;

	reg clk, reset;

    reg [8-1:0] A1;
    wire [8-1:0] A2, A3, A4, A5, A6;
    reg [8-1:0] B2, B3, B4, B5, B6;
    reg [8-1:0] C2, C3, C4, C5, C6;

    D_FF8 FF0 (A1, A2, clk, reset);
    D_FF8 FF1 (A2, A3, clk, reset);
    D_FF8 FF2 (A3, A4, clk, reset);
    D_FF8 FF3 (A4, A5, clk, reset);
    D_FF8 FF4 (A5, A6, clk, reset);

	
	initial
	begin
		clk = 1;
		reset = 0;
		
		#12
		reset = 1;
        #8
        A1 = 8'd4;

	end
	
	always #5 clk = ~clk;

    always @ (posedge clk) begin
        B2 <= A1;
        B3 <= B2;
        B4 <= B3;
        B5 <= B4;
        B6 <= B5;
    end

    always @ (posedge clk) begin
        C2 <= A1;
    end

    always @ (posedge clk) begin
        C3 <= C2;
    end

    always @ (posedge clk) begin
        C4 <= C3;
    end

    always @ (posedge clk) begin
        C5 <= C4;
    end

    always @ (posedge clk) begin
        C6 <= C5;
    end


endmodule
module addertree_stage3(x19, x18, x17, x16, x15, x14, x13, x12, x11, x10, x9, x8, x7, x6, x5, x4, x3,
                        o19, o18, o17, o16, o15, o14, o13, o12, o11, o10, o9, o8, o7, o6, o5
                        );


input x19;
input [2:0] x18, x17;
input [3:0] x16, x15, x14, x13, x12, x11, x10, x9, x8, x7;
input [2:0] x6, x5;
input [1:0] x4;
input x3;

wire [1:0] a19, a18, a17;
wire [2:0] a16, a15, a14, a13, a12, a11, a10, a9, a8, a7;
wire [1:0] a6, a5;
wire a4;

// x19
assign a19[0] = x19;

// x18 3
FA A180(x18[0], x18[1], x18[2], a18[0], a19[1]);

// x17 3
FA A170(x17[0], x17[1], x17[2], a17[0], a18[1]);

// x16 3
FA A160(x16[0], x16[1], x16[2], a16[0], a17[1]);

// x15 3
FA A150(x15[0], x15[1], x15[2], a15[0], a16[1]);

// x14 3
FA A140(x14[0], x14[1], x14[2], a14[0], a15[1]);

// x13 3
FA A130(x13[0], x13[1], x13[2], a13[0], a14[1]);

// x12 3
FA A120(x12[0], x12[1], x12[2], a12[0], a13[1]);

// x11 3
FA A110(x11[0], x11[1], x11[2], a11[0], a12[1]);

// x10 3
FA A100(x10[0], x10[1], x10[2], a10[0], a11[1]);

// x9 3
FA A90(x9[0], x9[1], x9[2], a9[0], a10[1]);

// x8 3
FA A80(x8[0], x8[1], x8[2], a8[0], a9[1]);

// x7 3
FA A70(x7[0], x7[1], x7[2], a7[0], a8[1]);

// x6 3
FA A60(x6[0], x6[1], x6[2], a6[0], a7[1]);

// x5 3
FA A50(x5[0], x5[1], x5[2], a5[0], a6[1]);

// x4 2
HA A40(x4[0], x4[1], a4, a5[1]);

assign a16[2] = x16[3];
assign a15[2] = x15[3];
assign a14[2] = x14[3];
assign a13[2] = x13[3];
assign a12[2] = x12[3];
assign a11[2] = x11[3];
assign a10[2] = x10[3];
assign a9[2] = x9[3];
assign a8[2] = x8[3];
assign a7[2] = x7[3];



//stage4

output [1:0] o19, o18, o17, o16, o15, o14, o13, o12, o11, o10, o9, o8, o7, o6;
output o5; 

// a19 2
assign o19[0] = a19[0] ^ a19[1];

// a18 2
HA A181(a18[0], a18[1], o18[0], o19[1]);

// a17 2
HA A171(a17[0], a17[1], o17[0], o18[1]);

// a16 3
FA A161(a16[0], a16[1], a16[2], o16[0], o17[1]);

// a15 3
FA A151(a15[0], a15[1], a15[2], o15[0], o16[1]);

// a14 3
FA A141(a14[0], a14[1], a14[2], o14[0], o15[1]);

// a13 3
FA A131(a13[0], a13[1], a13[2], o13[0], o14[1]);

// a12 3
FA A121(a12[0], a12[1], a12[2], o12[0], o13[1]);

// a11 3
FA A111(a11[0], a11[1], a11[2], o11[0], o12[1]);

// a10 3
FA A101(a10[0], a10[1], a10[2], o10[0], o11[1]);

// a9 3
FA A91(a9[0], a9[1], a9[2], o9[0], o10[1]);

// a8 3
FA A81(a8[0], a8[1], a8[2], o8[0], o9[1]);

// a7 3
FA A71(a7[0], a7[1], a7[2], o7[0], o8[1]);

// a6 2
HA A61(a6[0], a6[1], o6[0], o7[1]);

// a5 2
HA A51(a5[0], a5[1], o5, o6[1]);



endmodule
module adder_14to4(in, O3, O2, O1, O0);

input [13:0] in;
wire x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13;
output O3, O2, O1, O0;

assign {x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13} = in;

wire A[2:0], B[2:0];

adder_7to3 A730({x0, x1, x2, x3, x4, x5, x6}, B[2], B[1], B[0]);
adder_7to3 A731({x7, x8, x9, x10, x11, x12, x13}, A[2], A[1], A[0]);

wire C1, C2;

HA HA0(A[0], B[0], O0, C1);
FA FA0(A[1], B[1], C1, O1, C2);
FA FA1(A[2], B[2], C2, O2, O3);

endmodule
module adder_14to4_mod(in, O3, O2, O1, O0);

input [13:0] in;
wire x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13;
output O3, O2, O1, O0;

assign {x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13} = in;

wire cout[0:6], sum[0:6];

HA H0(x0, x1, sum[0], cout[0]);
HA H1(x2, x3, sum[1], cout[1]);
HA H2(x4, x5, sum[2], cout[2]);
HA H3(x6, x7, sum[3], cout[3]);
HA H4(x8, x9, sum[4], cout[4]);
HA H5(x10, x11, sum[5], cout[5]);
HA H6(x12, x13, sum[6], cout[6]);

wire A[3:1], B[2:0];

//choose from original, mod and mod2
adder_7to3 A730({sum[0], sum[1], sum[2], sum[3], sum[4], sum[5], sum[6]}, B[2], B[1], B[0]);
adder_7to3 A731({cout[0], cout[1], cout[2], cout[3], cout[4], cout[5], cout[6]}, A[3], A[2], A[1]);


assign O0 = B[0];

wire C1, C2;
HA HA0(A[1], B[1], O1, C1);
FA FA5(A[2], B[2], C1, O2, C2);

assign O3 = A[3] ^ C2;

endmodule
module tb_ad_mul;

	reg clk, reset;

    reg [8*9-1:0] mat_in [0:63];
	reg [8-1:0] ina[0:8];
	reg [8-1:0] weight[0:8];
    reg [8-1:0] mat_out [0:63];
	//reg [32-1:0] mata_in [0:27];
	//reg [16-1:0] mata_out [0:27];
	//reg [8-1:0] A, B;
	//reg [16-1:0] Aa, Ab;

    //wire [17-1:0] outa;
	//wire [16-1:0] out;
    reg [8-1:0] p_out;
	
	
	//M_8 M0 (A, B, out);
	//A_16 A0 (Aa, Ab, outa);
	reg [8*9-1:0] in;
	wire [8*9-1:0] weightin;
	reg [16-1:0] bias;
	wire [8-1:0] out;
	reg en;
	wire out_en;
	
	assign {ina[0], ina[1], ina[2], ina[3], ina[4], ina[5], ina[6], ina[7], ina[8]} = in;

	assign weightin = {weight[0], weight[1], weight[2], weight[3], weight[4], weight[5], weight[6], weight[7], weight[8]}; 

	//module PE(in, weight, bias, bound_level, step, en, out, out_en, clk, reset);
	PE P0(in, weightin, 16'b0000_0000_0000_0000, 3'b000, 3'b000, en, out, out_en, clk, reset);
	
	initial
	begin
		clk = 1;
		reset = 0;
		en = 0;
		#12
		reset = 1;
	end
	
	always #5 clk = ~clk;
	
    integer i=0, j=0;

	initial
	begin		
		$readmemh("input_pe.txt", mat_in);
		$readmemh("input_pe_wi.txt", weight);
		begin
			#(21);
			for (i=0; i<64; i=i+1)
			begin
				in = mat_in[i];
				en = 1;
				#(10);
			end
		end
	end

	
	integer err = 0;
	initial
	begin		
		$readmemh("output_pe.txt", mat_out);
		begin
			#(40); //change if needed
			for (j=0; j<64; j=j+1)
			begin
                p_out = mat_out[j];
                #(9);
				if (out != p_out) err = err + 1;
				#(1);
			end
		end
	end





endmodule
module addertree_stage2(x18, x17, x16, x15, x14, x13, x12, x11, x10, x9, x8, x7, x6, x5, x4, x3,
                        pre_output,
                        o19, o18, o17, o16, o15, o14, o13, o12, o11, o10, o9, o8, o7, o6, o5, o4, o3
                        );

input x18;
input [1:0] x17;
input [2:0] x16;
input [4:0] x15, x14;
input [6:0] x13;
input [8:0] x12;
input [9:0] x11;
input [10:0] x10;
input [11:0] x9;
input [10:0] x8;
input [9:0] x7;
input [9:0] x6;
input [8:0] x5;
input [7:0] x4;
input [5:0] x3;

input [13:1] pre_output;

wire p19;
output o19;
output [2:0] o18, o17;
output [3:0] o16, o15, o14, o13, o12, o11, o10, o9, o8, o7;
output [2:0] o6, o5;
output [1:0] o4;
output o3;

// x19
assign o19 = ~(p19 ^ pre_output[13]);

// x18 3 - 3
HA A180(x18,           pre_output[13],             o18[0], p19);

// x17 3 - 3
FA A170(x17[0], x17[1],pre_output[12],                  o17[0], o18[1]);

// x16 4 - 4
adder_4to3 A160({x16,   pre_output[11]},                o18[2], o17[1], o16[0]);

// x15 6 - 6
adder_6to3 A150({x15,  pre_output[10]},                         o17[2], o16[1], o15[0]);

// x14 6 - 6
adder_6to3 A140({x14,  pre_output[9]},                                  o16[2], o15[1], o14[0]);

// x13 8 - 8
adder_8to4 A130({x13,  pre_output[8]},                                  o16[3], o15[2], o14[1], o13[0]);

// x12 10 - 10
adder_10to4 A120({x12, pre_output[7]},                                          o15[3], o14[2], o13[1], o12[0]);

// x11 11 - 11
adder_11to4 A110({x11, pre_output[6]},                                                  o14[3], o13[2], o12[1], o11[0]);

// x10 12 - 12
adder_12to4 A100({x10, pre_output[5]},                                                          o13[3], o12[2], o11[1], o10[0]);

// x9 13 - 13
adder_13to4 A90({x9,   pre_output[4]},                                                                  o12[3], o11[2], o10[1], o9[0]);

// x8 12 - 12
adder_12to4 A80({x8,   pre_output[3]},                                                                          o11[3], o10[2], o9[1], o8[0]);

// x7 11 -11
adder_11to4 A70({x7,   pre_output[2]},                                                                                  o10[3], o9[2], o8[1], o7[0]);

// x6 11 - 11
adder_11to4 A60({x6,   pre_output[1]},                                                                                          o9[3], o8[2], o7[1], o6[0]);

// x5 9 - 9
adder_9to4 A50(x5,                                                                                                                     o8[3], o7[2], o6[1], o5[0]);

// x4 8 - 8
adder_8to4 A40(x4,                                                                                                                            o7[3], o6[2], o5[1], o4[0]);

// x3 6 - 9
adder_6to3 A30(x3,                                                                                                                                          o5[2], o4[1], o3);





endmodule
module arithmetic_core_mod (in, weight, bias, bound_level, step, en,
                            en_relu, en_mp, 
                            out, out_en,
                            clk, reset);
    parameter cell_bit = 8;
    parameter N_cell = 9;
    parameter biasport = 16;
    parameter outport = 8;

    input [cell_bit*N_cell-1:0] in;
    input [cell_bit*N_cell-1:0] weight;
    input signed [biasport-1:0] bias;
    input [2:0] bound_level;
    input [2:0] step;
    input en, en_relu, en_mp;
    input clk, reset;

    output signed [outport-1:0] out;
    output out_en;

    
//////////////// pe
    wire signed [outport-1:0] out_pe;
    wire out_en_pe;

    PE_m P0(in, weight, bias, bound_level, step, en, out_pe, out_en_pe, clk, reset);
///////////////


/////////////////// clk+2


//////////////// FF for other input
    wire en_relu_d, en_relu_d2;

    D_FF1 D_en_relu0(en_relu, en_relu_d, clk, reset);
    D_FF1 D_en_relu1(en_relu_d, en_relu_d2, clk, reset);

    wire en_mp_d, en_mp_d2;

    D_FF1 D_en_mp0(en_mp, en_mp_d, clk, reset);
    D_FF1 D_en_mp1(en_mp_d, en_mp_d2, clk, reset);
////////////////


////// relu
    wire signed [outport-1:0] out_relu;
    relu r0(out_pe, en_relu_d2, out_relu);
//////



////////// maxpooling
    maxpooling m0(out_relu, out_en_pe, en_mp_d2, out, out_en, clk, reset);


    ///// out < clk+3

endmodule
module tb_relu;

	reg clk, reset;

    reg [8-1:0] mat_in [0:59];
    reg [8-1:0] mat_out [0:63];

    reg [8-1:0] p_out;
	

	reg [8-1:0] in;
	wire [8-1:0] out;
	reg en, en_mp;
	wire out_en;

	relu r0(in, en, out);

	
	initial
	begin
		clk = 1;
		reset = 0;
		en = 0;
		#12
		reset = 1;
		#8
		en = 1;

		#100
		en = 0;

		#100
		en = 1;

		#100
		en = 0;

	end
	
	always #5 clk = ~clk;
	
    integer i=0, j=0;

	initial
	begin		
		$readmemh("input_mp.txt", mat_in);
		begin
			#(20);
			for (i=0; i<60; i=i+1)
			begin
				in = mat_in[i];

				#(10);
			end
		end
	end

	/*
	integer err = 0;
	initial
	begin		
		$readmemh("output_pe.txt", mat_out);
		begin
			#(40); //change if needed
			for (j=0; j<64; j=j+1)
			begin
                p_out = mat_out[j];
                #(9);
				if (out != p_out) err = err + 1;
				#(1);
			end
		end
	end

*/



endmodule
module adder_6to3(in, cout, carry, sum);

input [5:0] in;
wire x1, x2, x3, x4, x5, x6;
output cout, carry, sum;

assign {x1, x2, x3, x4, x5, x6} = in;

wire and12, xor12, and34, xor34, and56, xor56;

assign and12 = x1 & x2;
assign xor12 = x1 ^ x2;
assign and34 = x3 & x4;
assign xor34 = x3 ^ x4;
assign and56 = x5 & x6;
assign xor56 = x5 ^ x6;

wire  and4, xor4, and5, xor5, xor6;

assign and4 = and12 & and34;
assign xor4 = and12 ^ and34;
assign and5 = xor12 & xor34;
assign xor5 = xor12 ^ xor34;
assign xor6 = xor56;

wire xor10, xor7;

assign xor10 = xor4 ^ and5;
assign xor7 = and56;

wire and8, xor8, and9, xor9;

assign and8 = xor5 & xor6;
assign xor8 = xor5 ^ xor6;
assign and9 = xor10 & xor7;
assign xor9 = xor10 ^ xor7;


wire xor12_, and11, xor11, xor13;

assign xor12_ = and9 ^ and11;
assign and11 = xor9 & and8;
assign xor11 = xor9 ^ and8;
assign xor13 = xor12_ ^ and4;

assign sum = xor8;
assign carry = xor11;
assign cout = xor13;

endmodule
module tb_ppg;

	reg clk, reset;
    reg signed [7:0] multiplicand, multiplier;
    reg [15:0] mat_in[0:140];
    wire [10:0] pp0;
    wire [8:0] pp1, pp2, pp3;
    wire neg0, neg1, neg2, neg3;

    PPG P0(multiplicand, multiplier, pp0,  pp1,  pp2,  pp3, neg0, neg1, neg2, neg3);

	initial
	begin
		clk = 1;
        multiplier = 8'b0000_0000;
        multiplicand = 8'b0000_0000;
	end
	
	always #5 clk = ~clk;

    wire [18:0] Ob;
    wire [16:0] O, Om;
    wire [18:0] O10;
    wire signed [18:0] O10m;

    assign Om = multiplier * multiplicand;
    assign Ob = pp0 + (pp1<<2) + (pp2<<4) + (pp3<<6) + (neg0) + (neg1<<2) + (neg2<<4) + (neg3<<6) + 
                    19'b111_1010_1000_0000_0000;
    assign O = Ob[16:0];
    assign O10 = pp0 + (pp1<<2) + (pp2<<4) + (pp3<<6) + (neg0) + (neg1<<2) + (neg2<<4) + (neg3<<6) + 
                pp0 + (pp1<<2) + (pp2<<4) + (pp3<<6) + (neg0) + (neg1<<2) + (neg2<<4) + (neg3<<6) + 
                pp0 + (pp1<<2) + (pp2<<4) + (pp3<<6) + (neg0) + (neg1<<2) + (neg2<<4) + (neg3<<6) + 
                pp0 + (pp1<<2) + (pp2<<4) + (pp3<<6) + (neg0) + (neg1<<2) + (neg2<<4) + (neg3<<6) + 
                pp0 + (pp1<<2) + (pp2<<4) + (pp3<<6) + (neg0) + (neg1<<2) + (neg2<<4) + (neg3<<6) + 

                pp0 + (pp1<<2) + (pp2<<4) + (pp3<<6) + (neg0) + (neg1<<2) + (neg2<<4) + (neg3<<6) + 
                pp0 + (pp1<<2) + (pp2<<4) + (pp3<<6) + (neg0) + (neg1<<2) + (neg2<<4) + (neg3<<6) + 
                pp0 + (pp1<<2) + (pp2<<4) + (pp3<<6) + (neg0) + (neg1<<2) + (neg2<<4) + (neg3<<6) + 
                pp0 + (pp1<<2) + (pp2<<4) + (pp3<<6) + (neg0) + (neg1<<2) + (neg2<<4) + (neg3<<6) + 
                19'b100_1110_1000_0000_0000;
    assign O10m = multiplier * multiplicand * 9;


    integer err = 0, i = 0, j = 0, err10 = 0;
    initial
	begin		
		$readmemh("input_ppg.txt", mat_in);
        #10
		begin
			for (i=0; i<20; i=i+1)
			begin
				{multiplier, multiplicand} = mat_in[i];
                #(1);
                if (O != Om) err = err + 1;
				#(9);
			end
		end
        i = 0;
        multiplicand = 8'b1111_1111;
        multiplier = 8'b1111_1111;

        begin
			for (i=0; i<256; i=i+1)
			begin
                multiplier = multiplier + 1;
                for (j=0; j<256; j=j+1)
                begin
                    multiplicand = multiplicand + 1;
                    #(1);
                    if (O != Om) err = err + 1;
                    if (O10 != O10m) err10 = err10 + 1;
                    #(9);
                end
			end
		end

	end





endmodule
module arithmetic_core (in, weight, bias, bound_level, step, en,
                            en_relu, en_mp, 
                            out, out_en,
                            clk, reset);
    parameter cell_bit = 8;
    parameter N_cell = 9;
    parameter biasport = 16;
    parameter outport = 8;

    input [cell_bit*N_cell-1:0] in;
    input [cell_bit*N_cell-1:0] weight;
    input signed [biasport-1:0] bias;
    input [2:0] bound_level;
    input [2:0] step;
    input en, en_relu, en_mp;
    input clk, reset;

    output signed [outport-1:0] out;
    output out_en;

    
//////////////// pe
    wire signed [outport-1:0] out_pe;
    wire out_en_pe;

    PE P0(in, weight, bias, bound_level, step, en, out_pe, out_en_pe, clk, reset);
///////////////


/////////////////// clk+2


//////////////// FF for other input
    wire en_relu_d, en_relu_d2;

    D_FF1 D_en_relu0(en_relu, en_relu_d, clk, reset);
    D_FF1 D_en_relu1(en_relu_d, en_relu_d2, clk, reset);

    wire en_mp_d, en_mp_d2;

    D_FF1 D_en_mp0(en_mp, en_mp_d, clk, reset);
    D_FF1 D_en_mp1(en_mp_d, en_mp_d2, clk, reset);
////////////////


////// relu
    wire signed [outport-1:0] out_relu;
    relu r0(out_pe, en_relu_d2, out_relu);
//////



////////// maxpooling
    maxpooling m0(out_relu, out_en_pe, en_mp_d2, out, out_en, clk, reset);


    ///// out < clk+3

endmodule
module HA(A, B, S, C);

input A, B;
output S, C;

assign S = A ^ B;
assign C = A & B;

endmodule
module adder_10to4(in, O3, O2, O1, O0);

input [9:0] in;
wire x0, x1, x2, x3, x4, x5, x6, x7, x8, x9;
output O3, O2, O1, O0;

assign {x0, x1, x2, x3, x4, x5, x6, x7, x8, x9} = in;

wire A[2:0], B[2:0];

adder_5to3 A530({x0, x1, x2, x3, x4}, B[2], B[1], B[0]);
adder_5to3 A531({x5, x6, x7, x8, x9}, A[2], A[1], A[0]);

wire C1, C2;

HA HA0(A[0], B[0], O0, C1);
FA FA0(A[1], B[1], C1, O1, C2);
FA FA1(A[2], B[2], C2, O2, O3);

endmodule
module AP(in, weight, bias, bound_level, step, en, en_relu, en_mp, out, out_en, clk, reset);

parameter cell_bit = 8;
parameter N_cell = 9;
parameter biasport = 16;
parameter N_core = 8;
parameter outport = 8;

input [cell_bit*N_cell-1:0] in;
input [cell_bit*N_cell*N_core-1:0] weight;
input [biasport*N_core-1:0] bias;
input [2:0] bound_level;
input [2:0] step;
input en, en_relu, en_mp;
input clk, reset;

output [outport*N_core-1:0] out;
output [N_core-1:0] out_en;

genvar i;
generate
for(i=0; i<N_core; i=i+1) begin : generate_ac
    arithmetic_core_mod ac (in, weight[cell_bit*N_cell*N_core-i*cell_bit*N_cell-1-:cell_bit*N_cell], bias[biasport*N_core-i*biasport-1-:biasport],
                                bound_level, step, en, en_relu, en_mp,
                            out[outport*N_core-i*outport-1-:outport], out_en[N_core-i-1], clk, reset);
end
endgenerate

endmodule
module adder_12to4(in, O3, O2, O1, O0);

input [11:0] in;
wire x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11;
output O3, O2, O1, O0;

assign {x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11} = in;

wire A[2:0], B[2:0];

adder_6to3 A630({x0, x1, x2, x3, x4, x5}, B[2], B[1], B[0]);
adder_6to3 A631({x6, x7, x8, x9, x10, x11}, A[2], A[1], A[0]);

wire C1, C2;

HA HA0(A[0], B[0], O0, C1);
FA FA0(A[1], B[1], C1, O1, C2);
FA FA1(A[2], B[2], C2, O2, O3);

endmodule
module adder_12to4_mod(in, O3, O2, O1, O0);

input [11:0] in;
wire x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11;
output O3, O2, O1, O0;

assign {x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11} = in;

wire cout[0:5], sum[0:5];

HA H0(x0, x1, sum[0], cout[0]);
HA H1(x2, x3, sum[1], cout[1]);
HA H2(x4, x5, sum[2], cout[2]);
HA H3(x6, x7, sum[3], cout[3]);
HA H4(x8, x9, sum[4], cout[4]);
HA H5(x10, x11, sum[5], cout[5]);

wire A[3:1], B[2:0];

//choose from original, mod and mod2
adder_6to3 A630({sum[0], sum[1], sum[2], sum[3], sum[4], sum[5]}, B[2], B[1], B[0]);
adder_6to3 A631({cout[0], cout[1], cout[2], cout[3], cout[4], cout[5]}, A[3], A[2], A[1]);


assign O0 = B[0];

wire C1, C2;
HA HA0(A[1], B[1], O1, C1);
FA FA5(A[2], B[2], C1, O2, C2);

assign O3 = A[3] ^ C2;

endmodule
module tb_adderfinal;

	reg clk, reset;

    wire [1:0] x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13;
    wire [13:0] out, p_out;
	
	
    adder_final A0(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13,
                    out);

    reg [13:0] in0, in1;
    assign {x0[0], x1[0], x2[0], x3[0], x4[0], x5[0], x6[0], x7[0], x8[0], x9[0], x10[0], x11[0], x12[0], x13[0]} = in0;
    assign {x0[1], x1[1], x2[1], x3[1], x4[1], x5[1], x6[1], x7[1], x8[1], x9[1], x10[1], x11[1], x12[1], x13[1]} = in1;

    wire [14:0] outb;
    assign outb = in0 + in1;
    assign p_out = outb[13:0];

    integer err = 0, i = 0, j = 0;

	initial
	begin
    in0 = 14'b00_0000_0000_0000;
    in1 = 14'b00_0000_0000_0000;		
    #10
			for (i=0; i<32768; i=i+1)
			begin
                in0 = in0 + 1;
                for (j=0; j<32768; j=j+1)
                begin
                    in1 = in1 + 1;
                    #(1);
                    if (out != p_out) err = err + 1;
                    #(9);
                end
			end
		end
	




endmodule
module adder_4to3(in, cout, carry, sum);

input [3:0] in;
wire x0, x1, x2, x3;
output cout, carry, sum;

assign {x0, x1, x2, x3} = in;

wire s0, c0, c1;

FA FA0(x0, x1, x2, s0, c0);
HA HA0(x3, s0, sum, c1);
HA HA1(c0, c1, carry, cout);

endmodule
module adder_4to3_mod(in, cout, carry, sum);

input [3:0] in;
wire x0, x1, x2, x3;
output cout, carry, sum;

assign {x0, x1, x2, x3} = in;

wire and12, xor12, and34, xor34;

assign and12 = x0 & x1;
assign xor12 = x0 ^ x1;
assign and34 = x2 & x3;
assign xor34 = x2 ^ x3;

wire  and3, xor3, and4, xor4;

assign and3 = and12 & and34;
assign xor3 = and12 ^ and34;
assign and4 = xor12 & xor34;
assign xor4 = xor12 ^ xor34;

wire xor5;

assign xor5 = xor3 ^ and4;

assign sum = xor4;
assign carry = xor5;
assign cout = and3;

endmodule
module adder_final(i19, i18, i17, i16, i15, i14, i13, i12, i11, i10, i9, i8, i7, i6,
                    out);


input [1:0] i19, i18, i17, i16, i15, i14, i13, i12, i11, i10, i9, i8, i7, i6;
wire c0, c1, c2, c3, c4;
output [13:0] out;

CLG4_3 C3(i16[0], i16[1], i17[0], i17[1], i18[0], i18[1], i19[0], i19[1], c4, out[10], out[11], out[12], out[13]);
CLG4 C2(i12[0], i12[1], i13[0], i13[1], i14[0], i14[1], i15[0], i15[1], c3, out[6], out[7], out[8], out[9], c4);
CLG2 C1(i10[0], i10[1], i11[0], i11[1], c2, out[4], out[5], c3);
CLG2 C0(i8[0], i8[1], i9[0], i9[1], c1, out[2], out[3], c2);
FA FA0(i7[0], i7[1], c0, out[1], c1);
HA HA0(i6[0], i6[1], out[0], c0);



endmodule
module adder_final_simple(i19, i18, i17, i16, i15, i14, i13, i12, i11, i10, i9, i8, i7, i6, i5,
                    out);


input [1:0] i19, i18, i17, i16, i15, i14, i13, i12, i11, i10, i9, i8, i7, i6;
input i5;

wire [19:0] outb;

assign outb = (i19[0]<<19) + (i18[0]<<18) +(i17[0]<<17) +(i16[0]<<16) +(i15[0]<<15) +
                    (i14[0]<<14) +(i13[0]<<13) +(i12[0]<<12) +(i11[0]<<11) +
                    (i10[0]<<10) +(i9[0]<<9) +(i8[0]<<8) +(i7[0]<<7) +
                    (i6[0]<<6) +(i5<<5) + 
            (i19[1]<<19) + (i18[1]<<18) +(i17[1]<<17) +(i16[1]<<16) +(i15[1]<<15) +
                    (i14[1]<<14) +(i13[1]<<13) +(i12[1]<<12) +(i11[1]<<11) +
                    (i10[1]<<10) +(i9[1]<<9) +(i8[1]<<8) +(i7[1]<<7) +
                    (i6[1]<<6);


output [13:0] out;

assign out = outb[19-:14];

endmodule
module adder_9to4(in, O3, O2, O1, O0);

input [8:0] in;
wire x0, x1, x2, x3, x4, x5, x6, x7, x8;
output O3, O2, O1, O0;

assign {x0, x1, x2, x3, x4, x5, x6, x7, x8} = in;

wire s00, s01, s10, s11, s2, c0, c1; 

HA HA0(x7, x8, s00, s10);
adder_7to3 A730( {x0, x1, x2, x3, x4, x5, x6}, s2, s11, s01);

HA HA1(s00, s01, O0, c0);
FA FA0(s10, s11, c0, O1, c1);
HA HA2(s2, c1, O2, O3);



endmodule
module adder_13to4(in, O3, O2, O1, O0);

input [12:0] in;
wire x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12;
output O3, O2, O1, O0;

assign {x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12} = in;

wire A[2:0], B[2:0];

adder_7to3 A730({x0, x1, x2, x3, x4, x5, x6}, B[2], B[1], B[0]);
adder_6to3 A630({x7, x8, x9, x10, x11, x12}, A[2], A[1], A[0]);

wire C1, C2;

HA HA0(A[0], B[0], O0, C1);
FA FA0(A[1], B[1], C1, O1, C2);
FA FA1(A[2], B[2], C2, O2, O3);

endmodule
module D_FF144 # (parameter port = 144) (d, q, clk, reset);


input [port-1:0] d;
input clk, reset;
output reg [port-1:0] q;


always @ (posedge clk)

begin

if(!reset)
	q <= 'd0;
else
	q <= d;

end

endmodule
module D_FF114 # (parameter port = 114) (d, q, clk, reset);


input [port-1:0] d;
input clk, reset;
output reg [port-1:0] q;


always @ (posedge clk)

begin

if(!reset)
	q <= 'd0;
else
	q <= d;

end

endmodule
module D_FF8 # (parameter port = 8) (d, q, clk, reset);


input [port-1:0] d;
input clk, reset;
output reg [port-1:0] q;


always @ (posedge clk)

begin

if(!reset)
	q <= 'd0;
else
	q <= d;

end

endmodule
module D_FF1 # (parameter port = 1) (d, q, clk, reset);


input [port-1:0] d;
input clk, reset;
output reg [port-1:0] q;


always @ (posedge clk)

begin

if(!reset)
	q <= 'd0;
else
	q <= d;

end

endmodule
module D_FF3 # (parameter port = 3) (d, q, clk, reset);


input [port-1:0] d;
input clk, reset;
output reg [port-1:0] q;


always @ (posedge clk)

begin

if(!reset)
	q <= 'd0;
else
	q <= d;

end

endmodule
module D_FF2 # (parameter port = 2) (d, q, clk, reset);


input [port-1:0] d;
input clk, reset;
output reg [port-1:0] q;


always @ (posedge clk)

begin

if(!reset)
	q <= 'd0;
else
	q <= d;

end

endmodule
module D_FF16 # (parameter port = 16) (d, q, clk, reset);


input [port-1:0] d;
input clk, reset;
output reg [port-1:0] q;


always @ (posedge clk)

begin

if(!reset)
	q <= 'd0;
else
	q <= d;

end

endmodule
module D_FF119 # (parameter port = 119) (d, q, clk, reset);


input [port-1:0] d;
input clk, reset;
output reg [port-1:0] q;


always @ (posedge clk)

begin

if(!reset)
	q <= 'd0;
else
	q <= d;

end

endmodule
module D_FF10 # (parameter port = 10) (d, q, clk, reset);


input [port-1:0] d;
input clk, reset;
output reg [port-1:0] q;


always @ (posedge clk)

begin

if(!reset)
	q <= 'd0;
else
	q <= d;

end

endmodule
module D_FF13 # (parameter port = 13) (d, q, clk, reset);


input [port-1:0] d;
input clk, reset;
output reg [port-1:0] q;


always @ (posedge clk)

begin

if(!reset)
	q <= 'd0;
else
	q <= d;

end

endmodule
module MBE_enc(A, B, C, S);

input A, B, C;
output [2:0] S; 
//S[2] = sign, 0 = +, 1 = -
//S[1] = mult, 0 = 2 or 0, 1 = 1
//S[0] = zero, 0 = not 0, 1 = 0

assign S[2] = A;

assign S[1] = B ^ C;

assign S[0] = (A & B & C) | ((~A) & (~B) & (~C));

endmodule
module adder_8to4(in, O3, O2, O1, O0);

input [7:0] in;
wire x0, x1, x2, x3, x4, x5, x6, x7;
output O3, O2, O1, O0;

assign {x0, x1, x2, x3, x4, x5, x6, x7} = in;

wire s00, s01, s10, s11, s2, c0, c1; 

FA FA0(x5, x6, x7, s00, s10);
adder_5to3 A530( {x0, x1, x2, x3, x4}, s2, s11, s01);

HA HA0(s00, s01, O0, c0);
FA FA1(s10, s11, c0, O1, c1);
HA HA1(s2, c1, O2, O3);

endmodule
module CLG2(x1, y1, x2, y2, c1,
            s1, s2, c3);

input x1, y1, x2, y2, c1;
wire p1, c2, p2, g1, g2;
output s1, s2, c3;

assign p1 = x1 ^ y1;
assign p2 = x2 ^ y2;
assign g1 = x1 & y1;
assign g2 = x2 & y2;

assign c2 = g1 | (p1 & c1);
assign c3 = g2 | (p2 & g1) | (p2 & p1 & c1);

assign s1 = c1 ^ p1;
assign s2 = c2 ^ p2;

endmodule
module CLG4(x1, y1, x2, y2, x3, y3, x4, y4, c1,
            s1, s2, s3, s4, c5);

input x1, y1, x2, y2, x3, y3, x4, y4, c1;
wire p1, p2, p3, p4, g1, g2, g3, g4, c2, c3, c4;
output s1, s2, s3, s4, c5;

assign p1 = x1 ^ y1;
assign p2 = x2 ^ y2;
assign p3 = x3 ^ y3;
assign p4 = x4 ^ y4;
assign g1 = x1 & y1;
assign g2 = x2 & y2;
assign g3 = x3 & y3;
assign g4 = x4 & y4;

assign c2 = g1 | (p1 & c1);
assign c3 = g2 | (p2 & g1) | (p2 & p1 & c1);
assign c4 = g3 | (p3 & g2) | (p3 & p2 & g1) | (p3 & p2 & p1 & c1);
assign c5 = g4 | (p4 & g3) | (p4 & p3 & g2) | (p4 & p3 & p2 & g1) | (p4 & p3 & p2 & p1 & c1);

assign s1 = c1 ^ p1;
assign s2 = c2 ^ p2;
assign s3 = c3 ^ p3;
assign s4 = c4 ^ p4;

endmodule
module CLG4_3(x1, y1, x2, y2, x3, y3, x4, y4, c1,
            s1, s2, s3, s4);

input x1, y1, x2, y2, x3, y3, x4, y4, c1;
wire p1, p2, p3, p4, g1, g2, g3, g4, c2, c3, c4;
output s1, s2, s3, s4;

assign p1 = x1 ^ y1;
assign p2 = x2 ^ y2;
assign p3 = x3 ^ y3;
assign p4 = x4 ^ y4;
assign g1 = x1 & y1;
assign g2 = x2 & y2;
assign g3 = x3 & y3;

assign c2 = g1 | (p1 & c1);
assign c3 = g2 | (p2 & g1) | (p2 & p1 & c1);
assign c4 = g3 | (p3 & g2) | (p3 & p2 & g1) | (p3 & p2 & p1 & c1);

assign s1 = c1 ^ p1;
assign s2 = c2 ^ p2;
assign s3 = c3 ^ p3;
assign s4 = c4 ^ p4;

endmodule
module adder_11to4(in, O3, O2, O1, O0);

input [10:0] in;
wire x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10;
output O3, O2, O1, O0;

assign {x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10} = in;

wire A[2:0], B[2:0];

adder_6to3 A630({x0, x1, x2, x3, x4, x5}, B[2], B[1], B[0]);
adder_5to3 A531({x6, x7, x8, x9, x10}, A[2], A[1], A[0]);

wire C1, C2;

HA HA0(A[0], B[0], O0, C1);
FA FA0(A[1], B[1], C1, O1, C2);
FA FA1(A[2], B[2], C2, O2, O3);

endmodule