dakies/OSS_Verilog huggingface dataset:
module addertree_stage2_mod2(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 x17;
input [1:0] x16;
input [3: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 [8:0] x6;
input [7:0] x5;
input [7:0] x4;
input [5:0] x3;

input [13:1] pre_output;

wire p19;
output o19;
output [1:0] o18;
output [2:0] 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 2 - 2
HA A180(x18,           pre_output[13],             o18[0], p19);

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

// x16 3 - 3
FA A160(x16[0], x16[1],  pre_output[11],                o16[0], o17[1]);

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

// x14 5 - 5
adder_5to3 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 10 - 0
adder_10to4 A60({x6,   pre_output[1]},                                                                                          o9[3], o8[2], o7[1], o6[0]);

// x5 8 - 8
adder_8to4 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 - 6
adder_6to3 A30(x3,                                                                                                                                          o5[2], o4[1], o3);





endmodule
module maxpooling(in, en, en_mp, out, out_en, clk, reset);

input signed [7:0] in;
input en, en_mp, clk, reset;
output signed [7:0] out;
output out_en;

wire en_count, en2;
assign en_count = en & en_mp;
assign en2 = en & (~en_mp);

//comparator
reg comparator_out;
wire signed [7:0] mux_out;
always @(*) begin
    if (mux_out > in) comparator_out = 1'b0;
    else comparator_out = 1'b1;
end

reg [1:0] count;
reg count_out;
// counter
always @(posedge clk) begin
    if (!reset) begin
        count <= 0;
        count_out <= 0;
    end
    else if (en_count == 1) begin
        if (count == 2'b11) begin
            count <= count + 1'b1;
            count_out <= 1;
        end
        else begin
            count <= count + 1'b1;
            count_out <= 0;
        end
    end
    else count_out <= 0;
end


//out_en
wire en2_d;
D_FF1 D_en2(en2, en2_d, clk, reset);
assign out_en = count_out | en2_d;


//mux_in
wire com_en_and;
assign com_en_and = comparator_out & en;

wire mux_in_s;
assign mux_in_s = com_en_and | en2;

wire signed [7:0] mux_in;
assign mux_in = mux_in_s ? in : mux_out;

D_FF8 D_in(mux_in, out, clk, reset);

/*wire en_mp_d_i;
D_FF1 D_en_mp(~(en_mp), en_mp_d_i, clk, reset);*/

//mux_out
assign mux_out = (out_en) ? 8'b1000_0000 : out;



endmodule
module relu(in, en_relu, out);

input [7:0] in;
input en_relu;
output [7:0] out;

wire sel;

assign sel = ~(en_relu & in[7]);

assign out[7] = in[7] & sel;
assign out[6] = in[6] & sel;
assign out[5] = in[5] & sel;
assign out[4] = in[4] & sel;
assign out[3] = in[3] & sel;
assign out[2] = in[2] & sel;
assign out[1] = in[1] & sel;
assign out[0] = in[0] & sel;

/* using mux
assign out[7] = sel ? in[7] : 1'b0;
assign out[6] = sel ? in[7] : 1'b0;
assign out[5] = sel ? in[7] : 1'b0;
assign out[4] = sel ? in[7] : 1'b0;
assign out[3] = sel ? in[7] : 1'b0;
assign out[2] = sel ? in[7] : 1'b0;
assign out[1] = sel ? in[7] : 1'b0;
assign out[0] = sel ? in[7] : 1'b0;
*/

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

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

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

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

FA F0(x0, x1, x2, sum[0], cout[0]);
FA F1(x3, x4, x5, sum[1], cout[1]);
FA F2(x6, x7, x8, sum[2], cout[2]);
FA F3(x9, x10, x11, sum[3], cout[3]);
FA F4(x12, x13, x14, sum[4], cout[4]);

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

//choose from original, mod and mod2
adder_5to3 A530({sum[0], sum[1], sum[2], sum[3], sum[4]}, B[2], B[1], B[0]);
adder_5to3 A531({cout[0], cout[1], cout[2], cout[3], cout[4]}, 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 adder_15to4_mod(in, O3, O2, O1, O0);

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

assign {x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14} = 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;
FA FA0(A[0], B[0], x14, O0, C1);
FA FA5(A[1], B[1], C1, O1, C2);
FA FA6(A[2], B[2], C2, O2, O3);

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

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

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


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

//choose from original, mod and mod2
adder_5to3 A530({x0, x1, x2, x3, x4}, A[2], A[1], A[0]);
adder_5to3 A531({x5, x6, x7, x8, x9}, B[2], B[1], B[0]);
adder_5to3 A532({x10, x11, x12, x13}, x14, C[2], C[1], C[0]);

wire C1, C2, C2_0, C2_1, O1_0, O1_1, O2_0, O2_1, O3_0, O3_1;
FA FA0(A[0], B[0], C[0],  O0, C1);


/*
FA FA10(A[1], B[1], C[] O1_0, C2_0);
FA FA11(A[1], B[1], O1_1, C2_1);

assign C2 = C1 ? C2_1 : C2_0;
assign O1 = C1 ? O1_1 : O1_0;

FA FA20(1'b0, A[2], B[2], O2_0, O3_0);
FA FA21(1'b1, A[2], B[2], O2_1, O3_1);

assign O2 = C2 ? O2_1 : O2_0;
assign O3 = C2 ? O3_1 : O3_0;
*/
endmodule
module tb_mp;

	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;

	maxpooling mp0(in, en, en_mp, out, out_en, clk, reset);

	
	initial
	begin
		clk = 1;
		reset = 0;
		en = 0;
		#12
		reset = 1;
		#8
		en = 1;
        en_mp = 1;
		#100
		en = 0;
        en_mp = 1;
		#100
		en = 1;
        en_mp = 1;
		#100
		en = 1;
        en_mp = 0;
		#100
		en = 0;
        en_mp = 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 control_part_simple

#(

parameter width = 80,
parameter height = 8,

parameter width_b = 7,
parameter height_b = 3

)

(en_read, en_bias,// from ram


fmaps, biases, // from mem

fmap, biasp, // to pe

clk
);

parameter step0 = width - 9;
parameter step1 = width - 18;
parameter step2 = width - 27;
parameter step3 = width - 36;
parameter step4 = width - 45;
parameter step5 = width - 54;

parameter bias = 2;


input [8:0] en_read;
input en_bias;
input clk;

input [8*9-1:0] fmaps;
output [8*9-1:0] fmap;
input [16*8-1:0] biases;
output [16*8-1:0] biasp;

reg [8:0] en_read_d;
reg en_bias_d;

always @(posedge clk) begin
       en_read_d <= en_read;
       en_bias_d <= en_bias;
end


//for zero padding and else
assign fmap[8*9-1-8*0-:8] = en_read_d[8] ? fmaps[8*9-1-8*0-:8] : 8'b0000_0000;
assign fmap[8*9-1-8*1-:8] = en_read_d[7] ? fmaps[8*9-1-8*1-:8] : 8'b0000_0000;
assign fmap[8*9-1-8*2-:8] = en_read_d[6] ? fmaps[8*9-1-8*2-:8] : 8'b0000_0000;
assign fmap[8*9-1-8*3-:8] = en_read_d[5] ? fmaps[8*9-1-8*3-:8] : 8'b0000_0000;
assign fmap[8*9-1-8*4-:8] = en_read_d[4] ? fmaps[8*9-1-8*4-:8] : 8'b0000_0000;
assign fmap[8*9-1-8*5-:8] = en_read_d[3] ? fmaps[8*9-1-8*5-:8] : 8'b0000_0000;
assign fmap[8*9-1-8*6-:8] = en_read_d[2] ? fmaps[8*9-1-8*6-:8] : 8'b0000_0000;
assign fmap[8*9-1-8*7-:8] = en_read_d[1] ? fmaps[8*9-1-8*7-:8] : 8'b0000_0000;
assign fmap[8*9-1-8*8-:8] = en_read_d[0] ? fmaps[8*9-1-8*8-:8] : 8'b0000_0000;

assign biasp = en_bias_d ? biases : 0;



   

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

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

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

wire y0, y1, y2, y3;

assign y0 = x4 | x3;
assign y1 = x4 & x3;
assign y2 = x2 | x1;
assign y3 = x2 & x1;

wire sand0, sand1, sxor0;

assign sand0 = y2 & (~y3);
assign sand1 = y0 & (~y1);
assign sxor0 = sand0 ^ sand1;
assign sum = sxor0 ^ x0;

wire mux0;

assign mux0 = sxor0 ? x0 : y3;

wire cor0, cand0;

assign cor0 = y1 | y2;
assign cand0 = y0 & cor0;

assign carry = mux0 ^ cand0;
assign cout = mux0 & cand0;


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

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

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

wire y0, y1, y2, y3;

assign y0 = x4 | x3;
assign y1 = x4 & x3;
assign y2 = x2 | x1;
assign y3 = x2 & x1;

wire sxor0, sxor1, sxor2;

assign sxor1 = y2 ^ y3;
assign sxor2 = y0 ^ y1;

assign sxor0 = sxor1 ^ sxor2;
assign sum = sxor0 ^ x0;

wire mux0;

assign mux0 = sxor0 ? x0 : y3;

wire cor0, cand0;

assign cor0 = y1 | y2;
assign cand0 = y0 & cor0;

assign carry = mux0 ^ cand0;
assign cout = mux0 & cand0;


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

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

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

wire and12, xor12, and34, xor34;

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

wire  and3, xor3, and4, xor4;

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

wire xor5, and6, xor6;

assign xor5 = xor3 ^ and4;
assign and6 = x5 & xor4;
assign xor6 = x5 ^ xor4;

wire and7, xor7, xor8;

assign and7 = xor5 & and6;
assign xor7 = xor5 ^ and6;
assign xor8 = and7 ^ and3;

assign sum = xor6;
assign carry = xor7;
assign cout = xor8;

endmodule
module FA(A, B, Cin, S, Cout);

input A, B, Cin;
output S, Cout;

wire w1, w2, w3;

assign w1 = A ^ B;
assign w2 = w1 & Cin;
assign w3 = A & B;

assign S = w1 ^ Cin;
assign Cout = w2 | w3;

endmodule
module axis_adjustable_delay # (
    parameter DATA_WIDTH = 256,
    parameter MAX_LATENCY = 50  // buffer size in terms of cycle
)(
    input wire clk,
    input wire rst,
    input wire [15:0] delay_count,

    input wire [DATA_WIDTH-1:0] s_axis_tdata,
    input wire s_axis_tvalid,
    input wire s_axis_tlast,

    output wire [DATA_WIDTH-1:0] m_axis_tdata,
    output wire m_axis_tvalid,
    output wire m_axis_tlast
);
    integer i;

    reg [DATA_WIDTH-1:0] tdata[MAX_LATENCY-1:0]; 
    reg tvalid[MAX_LATENCY-1:0];
    reg tlast[MAX_LATENCY-1:0];

    reg [15:0] local_delay_count;
    
    assign m_axis_tdata = tdata[local_delay_count-1];
    assign m_axis_tvalid = tvalid[local_delay_count-1];
    assign m_axis_tlast = tlast[local_delay_count-1];

    always @ (posedge clk)
        if (rst) begin
            local_delay_count <= 16'd0;
            for (i = 0; i < MAX_LATENCY; i=i+1) begin
                tdata[i] <= {DATA_WIDTH{1'b0}};
                tvalid[i] <= 1'b0;
                tlast[i] <= 1'b0;
            end
        end else begin
            local_delay_count <= delay_count;
            if (s_axis_tvalid) begin
                tdata[0] <= s_axis_tdata;
                tvalid[0] <= 1'b1;
                tlast[0] <= s_axis_tlast;
            end else begin
                tvalid[0] <= 1'b0;
                tlast[0] <= 1'b0;
            end

            // delay tdata and tvalid
            for (i = 1; i < MAX_LATENCY; i=i+1) begin
                tdata[i] <= tdata[i-1];
                tvalid[i] <= tvalid[i-1];
                tlast[i] <= tlast[i-1];
            end
        end

endmodule
module axis_adjustable_intra_cycle_delay # (
    parameter DATA_WIDTH = 256,
    parameter SAMPLE_PER_CYCLE = 16
)(
    input wire clk,
    input wire rst,
    input wire [15:0] intra_cycle_delay_count,

    input wire [DATA_WIDTH-1:0] s_axis_tdata,
    input wire s_axis_tvalid,
    input wire s_axis_tlast,

    output wire [DATA_WIDTH-1:0] m_axis_tdata,
    output wire m_axis_tvalid,
    output wire m_axis_tlast
);

    reg [DATA_WIDTH-1:0] tdata[1:0];
    reg tvalid [1:0];
    reg tlast [1:0];

    reg [DATA_WIDTH-1:0] shifted_tdata;
    reg shifted_tvalid;
    reg shifted_tlast;

    reg [DATA_WIDTH-1:0] mask_left;
    reg [DATA_WIDTH-1:0] mask_right;

    assign m_axis_tdata = shifted_tdata;
    assign m_axis_tvalid = shifted_tvalid;
    assign m_axis_tlast = shifted_tlast;

    wire [15:0] left_shift_intra_bit_delay_count = (SAMPLE_PER_CYCLE - intra_cycle_delay_count) * 16;
    wire [15:0] right_shift_intra_bit_delay_count = intra_cycle_delay_count*16;
    wire [15:0] left_shift_intra_sample_delay_count = (SAMPLE_PER_CYCLE - intra_cycle_delay_count);

    integer i;

    always @ (posedge clk)
        if (rst) begin
            mask_left <= 0;
            mask_right <= 0;
        end else begin
            for (i=0; i<DATA_WIDTH; i=i+1) begin
                mask_left[i] <= i < intra_cycle_delay_count*16;
                mask_right[i] <= i > intra_cycle_delay_count*16-1;
            end
        end

    always @ (posedge clk)
        if (rst) begin
            tdata[0] <= {DATA_WIDTH{1'b0}};
            tvalid[0] <= 1'b0;
            tlast[0] <= 1'b0;
            tdata[1] <= {DATA_WIDTH{1'b0}};
            tvalid[1] <= 1'b0;
            tlast[1] <= 1'b0;
        end else begin
            if (s_axis_tvalid) begin
                tdata[0] <= s_axis_tdata;
                tvalid[0] <= 1'b1;
                tlast[0] <= s_axis_tlast;
            end else begin
                tdata[0] <= {DATA_WIDTH{1'b0}};
                tvalid[0] <= 1'b0;
                tlast[0] <= 1'b0;
            end

            tdata[1] <= tdata[0];
            tvalid[1] <= tvalid[0];
            tlast[1] <= tlast[0];

            shifted_tdata <= ((tdata[0] & mask_left) << left_shift_intra_bit_delay_count) + ((tdata[1] & mask_right) >> right_shift_intra_bit_delay_count);
            shifted_tvalid <= tvalid[0] || tvalid[1];
            shifted_tlast <= tlast[1];
        end


endmodule
module axis_delay # (
    parameter DATA_WIDTH = 8,
    parameter LATENCY = 10
)(
    input wire clk,
    input wire rst,

    input wire [DATA_WIDTH-1:0] s_axis_tdata,
    input wire s_axis_tvalid,
    input wire s_axis_tlast,

    output wire [DATA_WIDTH-1:0] m_axis_tdata,
    output wire m_axis_tvalid,
    output wire m_axis_tlast
);
    integer i;

    reg [DATA_WIDTH-1:0] tdata[LATENCY-1:0];
    reg tvalid[LATENCY-1:0];
    reg tlast[LATENCY-1:0];
    
    assign m_axis_tdata = tdata[LATENCY-1];
    assign m_axis_tvalid = tvalid[LATENCY-1];
    assign m_axis_tlast = tlast[LATENCY-1];

    always @ (posedge clk)
        if (rst) begin
            for (i = 0; i < LATENCY; i=i+1) begin
                tdata[i] <= {DATA_WIDTH{1'b0}};
                tvalid[i] <= 1'b0;
                tlast[i] <= 1'b0;
            end
        end else begin
            if (s_axis_tvalid) begin
                tdata[0] <= s_axis_tdata;
                tvalid[0] <= 1'b1;
                tlast[0] <= s_axis_tlast;
            end else begin
                tvalid[0] <= 1'b0;
                tlast[0] <= 1'b0;
            end

            // delay tdata and tvalid
            for (i = 1; i < LATENCY; i=i+1) begin
                tdata[i] <= tdata[i-1];
                tvalid[i] <= tvalid[i-1];
                tlast[i] <= tlast[i-1];
            end
        end

endmodule
module axis_intra_cycle_delay # (
    parameter DATA_WIDTH = 256,
    parameter SAMPLE_PER_CYCLE = 16,
    parameter LATENCY_SAMPLE = 10
)(
    input wire clk,
    input wire rst,

    input wire [DATA_WIDTH-1:0] s_axis_tdata,
    input wire s_axis_tvalid,
    input wire s_axis_tlast,

    output wire [DATA_WIDTH-1:0] m_axis_tdata,
    output wire m_axis_tvalid,
    output wire m_axis_tlast
);

    reg [DATA_WIDTH-1:0] tdata[1:0];
    reg tvalid [1:0];
    reg tlast [1:0];

    reg [DATA_WIDTH-1:0] shifted_tdata;
    reg shifted_tvalid;
    reg shifted_tlast;

    assign m_axis_tdata = shifted_tdata;
    assign m_axis_tvalid = shifted_tvalid;
    assign m_axis_tlast = shifted_tlast;

    always @ (posedge clk)
        if (rst) begin
            tdata[0] <= {DATA_WIDTH{1'b0}};
            tvalid[0] <= 1'b0;
            tlast[0] <= 1'b0;
            tdata[1] <= {DATA_WIDTH{1'b0}};
            tvalid[1] <= 1'b0;
            tlast[1] <= 1'b0;
        end else begin
            if (s_axis_tvalid) begin
                tdata[0] <= s_axis_tdata;
                tvalid[0] <= 1'b1;
                tlast[0] <= s_axis_tlast;
            end else begin
                tdata[0] <= {DATA_WIDTH{1'b0}};
                tvalid[0] <= 1'b0;
                tlast[0] <= 1'b0;
            end

            tdata[1] <= tdata[0];
            tvalid[1] <= tvalid[0];
            tlast[1] <= tlast[0];

            shifted_tdata <= {tdata[0][16*LATENCY_SAMPLE-1:0], tdata[1][DATA_WIDTH-1: 16*LATENCY_SAMPLE]};
            shifted_tvalid <= tvalid[0] || tvalid[1];
            shifted_tlast <= tlast[1];
        end


endmodule
module exp # (
    parameter DATA_WIDTH = 16,
    parameter MEM_LEN = 12
)(
    input wire clk,
    input wire rst,

    input wire [DATA_WIDTH-1:0] input_tdata,
    input wire input_tvalid,
    // output wire input_tready,
    input wire input_tlast,

    output reg [DATA_WIDTH-1:0] output_tdata,
    output reg output_tvalid,
    // input wire output_tready,
    output reg output_tlast
);

    // exp for inputs between 0 and 11
    // overflows for inputs greater than 11
    wire [DATA_WIDTH-1:0] exp_value =
			  ($signed(input_tdata) < $signed(16'd0)) ? 16'd0
			  : (input_tdata == 16'd0) ? 16'd1
			  : (input_tdata == 16'd1) ? 16'd3
			  : (input_tdata == 16'd2) ? 16'd7
			  : (input_tdata == 16'd3) ? 16'd20
			  : (input_tdata == 16'd4) ? 16'd55
			  : (input_tdata == 16'd5) ? 16'd148
			  : (input_tdata == 16'd6) ? 16'd403
			  : (input_tdata == 16'd7) ? 16'd1096
			  : (input_tdata == 16'd8) ? 16'd2980
			  : (input_tdata == 16'd9) ? 16'd8103
			  : (input_tdata == 16'd10) ? 16'd2206
			  : (input_tdata == 16'd11) ? 16'd59874
			  : 16'hffff;

    always @ (posedge clk) begin
        output_tdata <= (rst) ? 'b0 : exp_value;
        output_tvalid <= (rst) ? 'b0 : input_tvalid;
        output_tlast <= (rst) ? 1'b0 : input_tlast;
        // if (input_tvalid) begin
        //     $display("exp input %d -> %d", $signed(input_tdata), exp_value);
        // end
    end

endmodule
module adder_tree # (
    parameter IN_DATA_WIDTH = 256,
    parameter OUT_DATA_WIDTH = 16
)(
    input wire clk,
    input wire rst,

    input wire [IN_DATA_WIDTH-1:0] s_tdata,  // we assume the number here is signed
    input wire s_tvalid,

    output wire [OUT_DATA_WIDTH-1:0] m_tdata,
    output wire m_tvalid
);
    reg [15:0] r1_adder_1;
    reg [15:0] r1_adder_2;
    reg [15:0] r1_adder_3;
    reg [15:0] r1_adder_4;
    reg [15:0] r1_adder_5;
    reg [15:0] r1_adder_6;
    reg [15:0] r1_adder_7;
    reg [15:0] r1_adder_8;

    reg [15:0] r2_adder_1;
    reg [15:0] r2_adder_2;
    reg [15:0] r2_adder_3;
    reg [15:0] r2_adder_4;

    reg [15:0] r3_adder_1;
    reg [15:0] r3_adder_2;

    reg [15:0] r4_adder_1;

    reg r1_valid;
    reg r2_valid;
    reg r3_valid;
    reg r4_valid;

    assign m_tdata = r4_adder_1;
    assign m_tvalid = r4_valid;

    always @ (posedge clk) begin
        if (rst) begin
            r1_adder_1 <= 16'd0;
            r1_adder_2 <= 16'd0;
            r1_adder_3 <= 16'd0;
            r1_adder_4 <= 16'd0;
            r1_adder_5 <= 16'd0;
            r1_adder_6 <= 16'd0;
            r1_adder_7 <= 16'd0;
            r1_adder_8 <= 16'd0;
            r1_valid <= 1'b0;

            r2_adder_1 <= 16'd0;
            r2_adder_2 <= 16'd0;
            r2_adder_3 <= 16'd0;
            r2_adder_4 <= 16'd0;
            r2_valid <= 1'b0;

            r3_adder_1 <= 16'd0;
            r3_adder_2 <= 16'd0;
            r3_valid <= 1'b0;

            r4_adder_1 <= 16'd0;
            r4_valid <= 1'b0;

        end else begin
            r1_adder_1 <= s_tdata[15:0] + s_tdata[31:16];
            r1_adder_2 <= s_tdata[47:32] + s_tdata[63:48];
            r1_adder_3 <= s_tdata[79:64] + s_tdata[95:80];
            r1_adder_4 <= s_tdata[111:96] + s_tdata[127:112];
            r1_adder_5 <= s_tdata[143:128] + s_tdata[159:144];
            r1_adder_6 <= s_tdata[175:160] + s_tdata[191:176];
            r1_adder_7 <= s_tdata[207:192] + s_tdata[223:208];
            r1_adder_8 <= s_tdata[239:224] + s_tdata[255:240];
            r1_valid <= s_tvalid;

            r2_adder_1 <= r1_adder_1 + r1_adder_2;
            r2_adder_2 <= r1_adder_3 + r1_adder_4;
            r2_adder_3 <= r1_adder_5 + r1_adder_6;
            r2_adder_4 <= r1_adder_7 + r1_adder_8;
            r2_valid <= r1_valid;

            r3_adder_1 <= r2_adder_1 + r2_adder_2;
            r3_adder_2 <= r2_adder_3 + r2_adder_4;
            r3_valid <= r2_valid;

            r4_adder_1 <= r3_adder_1 + r3_adder_2;
            r4_valid <= r3_valid;
        end
    end
        
endmodule
module averager_tree # (
    parameter IN_DATA_WIDTH = 256,
    parameter OUT_DATA_WIDTH = 16
)(
    input wire clk,
    input wire rst,
    input wire start_signal,
    input wire [15:0] persist_cycle_length,

    input wire [IN_DATA_WIDTH-1:0] s_tdata,  // we assume the number here is signed
    input wire s_tvalid,

    output wire [OUT_DATA_WIDTH-1:0] m_tdata,
    output wire m_tvalid
);
    reg [15:0] r1_adder_1;
    reg [15:0] r1_adder_2;
    reg [15:0] r1_adder_3;
    reg [15:0] r1_adder_4;
    reg [15:0] r1_adder_5;
    reg [15:0] r1_adder_6;
    reg [15:0] r1_adder_7;
    reg [15:0] r1_adder_8;

    reg [15:0] r2_adder_1;
    reg [15:0] r2_adder_2;
    reg [15:0] r2_adder_3;
    reg [15:0] r2_adder_4;

    reg [15:0] r3_adder_1;
    reg [15:0] r3_adder_2;

    reg [15:0] r4_adder_1;

    reg r1_valid;
    reg r2_valid;
    reg r3_valid;
    reg r4_valid;

    assign m_tdata = r4_adder_1;
    assign m_tvalid = r4_valid;

    reg [15:0] cycle_count;

    always @ (posedge clk) begin
        if (rst) begin
            r1_adder_1 <= 16'd0;
            r1_adder_2 <= 16'd0;
            r1_adder_3 <= 16'd0;
            r1_adder_4 <= 16'd0;
            r1_adder_5 <= 16'd0;
            r1_adder_6 <= 16'd0;
            r1_adder_7 <= 16'd0;
            r1_adder_8 <= 16'd0;
            r1_valid <= 1'b0;

            r2_adder_1 <= 16'd0;
            r2_adder_2 <= 16'd0;
            r2_adder_3 <= 16'd0;
            r2_adder_4 <= 16'd0;
            r2_valid <= 1'b0;

            r3_adder_1 <= 16'd0;
            r3_adder_2 <= 16'd0;
            r3_valid <= 1'b0;

            r4_adder_1 <= 16'd0;
            r4_valid <= 1'b0;

            cycle_count <= 0;
        end else if (start_signal) begin
            cycle_count <= 0;
        end else if (s_tvalid && cycle_count < persist_cycle_length + 4) begin  // 4 more cycles adder tree delay
            r1_adder_1 <= (s_tdata[15:0] + s_tdata[31:16])/2;
            r1_adder_2 <= (s_tdata[47:32] + s_tdata[63:48])/2;
            r1_adder_3 <= (s_tdata[79:64] + s_tdata[95:80])/2;
            r1_adder_4 <= (s_tdata[111:96] + s_tdata[127:112])/2;
            r1_adder_5 <= (s_tdata[143:128] + s_tdata[159:144])/2;
            r1_adder_6 <= (s_tdata[175:160] + s_tdata[191:176])/2;
            r1_adder_7 <= (s_tdata[207:192] + s_tdata[223:208])/2;
            r1_adder_8 <= (s_tdata[239:224] + s_tdata[255:240])/2;
            r1_valid <= s_tvalid;

            r2_adder_1 <= (r1_adder_1 + r1_adder_2)/2;
            r2_adder_2 <= (r1_adder_3 + r1_adder_4)/2;
            r2_adder_3 <= (r1_adder_5 + r1_adder_6)/2;
            r2_adder_4 <= (r1_adder_7 + r1_adder_8)/2;
            r2_valid <= r1_valid;

            r3_adder_1 <= (r2_adder_1 + r2_adder_2)/2;
            r3_adder_2 <= (r2_adder_3 + r2_adder_4)/2;
            r3_valid <= r2_valid;

            r4_adder_1 <= (r3_adder_1 + r3_adder_2)/2;
            r4_valid <= r3_valid;

            cycle_count <= cycle_count + 1;
        end else begin
            r4_adder_1 <= 0;
            r4_valid <= 0;
        end
    end
        
endmodule
module relu # (
    parameter DATA_WIDTH = 16
)(
    input wire clk,
    input wire rst,

    input wire [DATA_WIDTH-1:0] pre_relu_tdata,
    input wire pre_relu_tvalid,

    output wire [DATA_WIDTH-1:0] post_relu_tdata,
    output wire post_relu_tvalid
);
    reg [DATA_WIDTH-1:0] relu_tdata;
    reg relu_tvalid;

    assign post_relu_tdata = relu_tdata;
    assign post_relu_tvalid = relu_tvalid;

    always @ (posedge clk)
        if (rst) begin
            relu_tdata <= {DATA_WIDTH{1'b0}};
            relu_tvalid <= 1'b0;
        end else if (pre_relu_tvalid) begin
            relu_tdata <= (pre_relu_tdata[15] == 0)? pre_relu_tdata : 16'd0; // a ReLU function, based on sign bit
            relu_tvalid <= 1'b1;
        end else begin
            relu_tdata <= {DATA_WIDTH{1'b0}};
            relu_tvalid <= 1'b0;
        end

endmodule
module layer_activation_switch # (
    parameter DATA_WIDTH = 256  // the bus bandwidth for the glue logic is 256 for the DAC 
)(
    input wire clk,
    input wire rst,
    
    input wire [2:0] layer,

    input wire [DATA_WIDTH-1:0] initial_layer_tdata,
    input wire initial_layer_tvalid,
    input wire initial_layer_tlast,

    input wire [DATA_WIDTH-1:0] intermediate_layer_tdata,
    input wire intermediate_layer_tvalid,
    input wire intermediate_layer_tlast,

    output reg [DATA_WIDTH-1:0] m_layer_tdata,
    output reg m_layer_tvalid,
    output reg m_layer_tlast
);  
    wire [DATA_WIDTH-1:0] delayed_intermediate_layer_tdata;
    wire delayed_intermediate_layer_tvalid;
    wire delayed_intermediate_layer_tlast;

    always @ (posedge clk) begin
        if (rst) begin
            m_layer_tdata <= {DATA_WIDTH{1'b0}};
            m_layer_tvalid <= 1'b0;
            m_layer_tlast <= 1'b0;
        end else begin
            case (layer)
                3'b001 : begin
                    m_layer_tdata <= initial_layer_tdata;
                    m_layer_tvalid <= initial_layer_tvalid;
                    m_layer_tlast <= initial_layer_tlast;
                end 
                3'b010: begin
                    m_layer_tdata <= delayed_intermediate_layer_tdata << 7;
                    m_layer_tvalid <= delayed_intermediate_layer_tvalid;
                    m_layer_tlast <= delayed_intermediate_layer_tlast;
                end 
                3'b100: begin
                    m_layer_tdata <= delayed_intermediate_layer_tdata << 7;
                    m_layer_tvalid <= delayed_intermediate_layer_tvalid;
                    m_layer_tlast <= delayed_intermediate_layer_tlast;
                end
                default: begin
                    m_layer_tdata <= {DATA_WIDTH{1'b0}};
                    m_layer_tvalid <= 1'b0;
                    m_layer_tlast <= 1'b0;
                end
            endcase
        end
    end

    // also need to shift bu 7 bits to match the 8b accuracy on 16/14b DAC
    generate
        axis_delay # (
            .DATA_WIDTH(DATA_WIDTH),
            .LATENCY(2)
        ) following_layer_buffer_delay_inst (
            .clk(clk),
            .rst(rst),
            .s_axis_tdata(intermediate_layer_tdata),
            .s_axis_tvalid(intermediate_layer_tvalid),
            .s_axis_tlast(intermediate_layer_tlast),
            .m_axis_tdata(delayed_intermediate_layer_tdata),
            .m_axis_tvalid(delayed_intermediate_layer_tvalid),
            .m_axis_tlast(delayed_intermediate_layer_tlast)
        );
    endgenerate
endmodule
module normalization # (
    parameter DATA_BITWIDTH = 16
) (
    input wire clk,
    input wire rst,
    input wire [1:0] state,

    input wire [DATA_BITWIDTH-1:0] input_tdata,
    input wire input_tvalid,

    output reg [DATA_BITWIDTH-1:0] output_shift,
    output reg output_shift_left
);

    reg [DATA_BITWIDTH - 1:0]   max_value, new_shift;
    reg                         new_shift_left;
    integer i;

    always @(posedge clk) begin
        if (rst) begin
            max_value <= 0;
            new_shift <= 0;
            new_shift_left <= 0;

        end else if (state == `ST_PREAM_RECEPTIVE) begin
            max_value <= 0;
            output_shift <= new_shift;
            output_shift_left <= new_shift_left;

        end else if (input_tvalid && input_tdata > max_value) begin
                for (i = 0; i < DATA_BITWIDTH; i = i + 1)
                    if (input_tdata[i]) begin
                        new_shift_left <= i < 8;
                        /* verilator lint_off WIDTH */
                        new_shift <= (i < 8) ? 7 - i : i - 7;
                    end

                max_value <= input_tdata;
        end
    end


endmodule
module loss_compensator # (
    parameter DATA_WIDTH = 256,
    parameter WORD_WIDTH = 16
)(
    input wire clk,
    input wire rst,

    input wire [DATA_WIDTH-1:0] pre_mul_tdata,
    input wire pre_mul_tvalid,
    output reg pre_mul_tready,

    input wire [WORD_WIDTH-1:0] multiply,

    output reg [DATA_WIDTH-1:0] post_mul_tdata,
    output reg post_mul_tvalid,
    input wire post_mul_tready // ignored, to match RFSOC ADC behavior
);

    integer i;

    // note that this causes a combinational path from post_mul_tready to pre_mul_1_tready and pre_mul_2_tready
    reg [DATA_WIDTH-1:0] tdata;
    reg tvalid;

    wire [DATA_WIDTH-1:0] shifted_tdata;
    wire shifted_tvalid;
   
   always @ (posedge clk)
        if (rst) begin
            post_mul_tdata <= 0;
            post_mul_tvalid <= 1'b0;
            pre_mul_tready <= 1'b1; // always ready
        end else begin
            post_mul_tdata <= tdata;
            post_mul_tvalid <= tvalid;
            pre_mul_tready <= 1'b1; // always ready
        end
    
    always @ (posedge clk)
        if (rst) begin
            tdata <= 0;
            tvalid <= 0;
        end else begin
            if (pre_mul_tvalid) begin
                for (i=0; i<DATA_WIDTH/WORD_WIDTH; i=i+1) begin
                    tdata[i*WORD_WIDTH +: WORD_WIDTH] <= pre_mul_tdata[i*WORD_WIDTH+7 +: 8] * multiply;
                end
                tvalid <= 1'b1;
            end else begin
                tdata <= {DATA_WIDTH{1'b0}};
                tvalid <= 1'b0;
            end

        end

endmodule
module wb_data_resize
  #(parameter aw  = 32, //Address width
    parameter mdw = 32, //Master Data Width
    parameter sdw = 8, //Slave Data Width
    parameter [47:0] endian = "big") // Endian for byte reads/writes
   (//Wishbone Master interface
    input wire [aw-1:0]	  wbm_adr_i,
    input wire [mdw-1:0]  wbm_dat_i,
    input wire [3:0]	  wbm_sel_i,
    input wire		  wbm_we_i,
    input wire		  wbm_cyc_i,
    input wire		  wbm_stb_i,
    input wire [2:0]	  wbm_cti_i,
    input wire [1:0]	  wbm_bte_i,
    output wire [mdw-1:0] wbm_dat_o,
    output wire		  wbm_ack_o,
    output wire		  wbm_err_o,
    output wire		  wbm_rty_o,
    // Wishbone Slave interface
    output wire [aw-1:0]  wbs_adr_o,
    output wire [sdw-1:0] wbs_dat_o,
    output wire		  wbs_we_o,
    output wire		  wbs_cyc_o,
    output wire		  wbs_stb_o,
    output wire [2:0]	  wbs_cti_o,
    output wire [1:0]	  wbs_bte_o,
    input wire [sdw-1:0]  wbs_dat_i,
    input wire		  wbs_ack_i,
    input wire		  wbs_err_i,
    input wire		  wbs_rty_i);

   assign wbs_adr_o[aw-1:2] = wbm_adr_i[aw-1:2];

   generate if (endian == "little") begin : le_resize_gen
      assign wbs_adr_o[1:0] = wbm_sel_i[3] ? 2'd3 :
                              wbm_sel_i[2] ? 2'd2 :
                              wbm_sel_i[1] ? 2'd1 : 2'd0;
   end else begin : be_resize_gen
      assign wbs_adr_o[1:0] = wbm_sel_i[3] ? 2'd0 :
                              wbm_sel_i[2] ? 2'd1 :
                              wbm_sel_i[1] ? 2'd2 : 2'd3;
   end endgenerate

   assign wbs_dat_o = wbm_sel_i[3] ? wbm_dat_i[31:24] :
                      wbm_sel_i[2] ? wbm_dat_i[23:16] :
                      wbm_sel_i[1] ? wbm_dat_i[15:8]  :
                      wbm_sel_i[0] ? wbm_dat_i[7:0]   : 8'b0;

   assign wbs_we_o  = wbm_we_i;

   assign wbs_cyc_o = wbm_cyc_i;
   assign wbs_stb_o = wbm_stb_i;

   assign wbs_cti_o = wbm_cti_i;
   assign wbs_bte_o = wbm_bte_i;

   assign wbm_dat_o = (wbm_sel_i[3]) ? {wbs_dat_i, 24'd0} :
                      (wbm_sel_i[2]) ? {8'd0 , wbs_dat_i, 16'd0} :
                      (wbm_sel_i[1]) ? {16'd0, wbs_dat_i, 8'd0} :
                                       {24'd0, wbs_dat_i};
   assign wbm_ack_o = wbs_ack_i;
   assign wbm_err_o = wbs_err_i;
   assign wbm_rty_o = wbs_rty_i;

endmodule
module wb_cdc
  #(parameter AW = 32)
  (input wire		wbm_clk,
   input wire		wbm_rst,
   input wire [AW-1:0]	wbm_adr_i,
   input wire [31:0]	wbm_dat_i,
   input wire [3:0]	wbm_sel_i,
   input wire		wbm_we_i,
   input wire		wbm_cyc_i,
   input wire		wbm_stb_i,
   output wire [31:0]	wbm_dat_o,
   output wire		wbm_ack_o,
   input wire		wbs_clk,
   input wire		wbs_rst,
   output wire [AW-1:0]	wbs_adr_o,
   output wire [31:0]	wbs_dat_o,
   output wire [3:0]	wbs_sel_o,
   output wire		wbs_we_o,
   output wire		wbs_cyc_o,
   output wire		wbs_stb_o,
   input wire [31:0]	wbs_dat_i,
   input wire		wbs_ack_i);

   wire 	   wbm_m2s_en;
   reg 		   wbm_busy = 1'b0;
   wire 	   wbm_cs;
   wire 	   wbm_done;

   wire 	   wbs_m2s_en;
   reg 		   wbs_cs = 1'b0;

   cc561
     #(.DW (AW+32+4+1))
   cdc_m2s
     (.aclk  (wbm_clk),
      .arst  (wbm_rst),
      .adata ({wbm_adr_i, wbm_dat_i, wbm_sel_i, wbm_we_i}),
      .aen   (wbm_m2s_en),
      .bclk  (wbs_clk),
      .bdata ({wbs_adr_o, wbs_dat_o, wbs_sel_o, wbs_we_o}),
      .ben   (wbs_m2s_en));

   assign wbm_cs = wbm_cyc_i & wbm_stb_i;
   assign wbm_m2s_en = wbm_cs & ~wbm_busy;

   always @(posedge wbm_clk) begin
      if (wbm_ack_o | wbm_rst)
	wbm_busy <= 1'b0;
      else if (wbm_cs)
	wbm_busy <= 1'b1;
   end

   always @(posedge wbs_clk) begin
      if (wbs_ack_i)
	wbs_cs <= 1'b0;
      else if (wbs_m2s_en)
	wbs_cs <= 1'b1;
   end

   assign wbs_cyc_o = wbs_m2s_en | wbs_cs;
   assign wbs_stb_o = wbs_m2s_en | wbs_cs;

   cc561
     #(.DW (32))
   cdc_s2m
     (.aclk  (wbs_clk),
      .arst  (wbs_rst),
      .adata (wbs_dat_i),
      .aen   (wbs_ack_i),
      .bclk  (wbm_clk),
      .bdata (wbm_dat_o),
      .ben   (wbm_ack_o));

endmodule
module sync
  (
   input        rstn_i,

   input        iclk_i,
   input [7:0]  idata_i,
   input        ivalid_i,
   output       iready_o,

   input        oclk_i,
   output [7:0] odata_o,
   output       ovalid_o,
   input        oready_i
   );

   reg [1:0]    iready_sq;
   reg          iready_mask_q;
   reg [7:0]    idata_q;

   assign iready_o = iready_sq[0] & ~iready_mask_q;

   always @(posedge iclk_i or negedge rstn_i) begin
      if (~rstn_i) begin
         iready_sq <= 2'b00;
         iready_mask_q <= 1'b0;
         idata_q <= 8'd0;
      end else begin
         iready_sq <= {~ovalid_mask_q, iready_sq[1]};
         if (~iready_sq[0])
           iready_mask_q <= 1'b0;
         else if (ivalid_i & ~iready_mask_q) begin
            idata_q <= idata_i;
            iready_mask_q <= 1'b1;
         end
      end
   end

   reg [1:0] ovalid_sq;
   reg       ovalid_mask_q;

   assign ovalid_o = ovalid_sq[0] & ~ovalid_mask_q;
   assign odata_o = idata_q;

   always @(posedge oclk_i or negedge rstn_i) begin
      if (~rstn_i) begin
         ovalid_sq <= 2'b00;
         ovalid_mask_q <= 1'b0;
      end else begin
         ovalid_sq <= {iready_mask_q, ovalid_sq[1]};
         if (~ovalid_sq[0])
           ovalid_mask_q <= 1'b0;
         else if (oready_i & ~ovalid_mask_q)
           ovalid_mask_q <= 1'b1;
      end
   end
endmodule
module prescaler
  (
   input  clk_i,
   input  rstn_i,
   output clk_div16_o,
   output clk_div8_o,
   output clk_div4_o,
   output clk_div2_o
   );

   reg [3:0] prescaler_cnt;

   always @(posedge clk_i or negedge rstn_i) begin
      if (~rstn_i) begin
         prescaler_cnt <= 'd0;
      end else begin
         prescaler_cnt <= prescaler_cnt + 1;
      end
   end

   assign clk_div16_o = prescaler_cnt[3];
   assign clk_div8_o = prescaler_cnt[2];
   assign clk_div4_o = prescaler_cnt[1];
   assign clk_div2_o = prescaler_cnt[0];
   
endmodule
module fifo_if
  (
   input        clk_i,
   input        rstn_i,

   // ---- to/from uC -----------------------------------------------
   input        sel_i,
   input        read_i,
   input        write_i,
   input [1:0]  addr_i,
   input [7:0]  data_i,
   output [7:0] data_o,
   output       in_irq_o,
   output       out_irq_o,

   // ---- to/from USB_CDC ------------------------------------------
   output [7:0] in_data_o,
   output       in_valid_o,
   // While in_valid_o is high, in_data_o shall be valid and both
   //   in_valid_o and in_data_o shall not change until consumed.
   input        in_ready_i,
   // When both in_ready_i and in_valid_o are high, in_data_o shall
   //   be consumed.
   input [7:0]  out_data_i,
   input        out_valid_i,
   // While out_valid_i is high, the out_data_i shall be valid.
   output       out_ready_o
   // When both out_valid_i and out_ready_o are high, the out_data_i shall
   //   be consumed.
   );

   reg [7:0]    in_buffer_q;
   reg          in_valid_q;
   reg          in_irq_q;

   assign in_data_o = in_buffer_q;
   assign in_valid_o = in_valid_q;
   assign in_irq_o = in_irq_q;

   always @(posedge clk_i or negedge rstn_i) begin
      if (~rstn_i) begin
         in_buffer_q <= 8'd0;
         in_valid_q <= 1'b0;
         in_irq_q <= 1'b0;
      end else begin
         in_irq_q <= 1'b0;
         if (in_valid_q == 1'b1) begin
            if (in_ready_i == 1'b1) begin
               in_valid_q <= 1'b0;
               in_irq_q <= 1'b1;
            end
         end else
           if (write_i == 1'b1 && sel_i == 1'b1 && addr_i == 2'b01) begin
              in_buffer_q <= data_i;
              in_valid_q <= 1'b1;
           end
      end
   end

   reg [1:0]     addr_q;
   reg [7:0]     out_buffer_q;
   reg           out_ready_q;
   reg           out_irq_q;
   reg           started_q;

   assign out_ready_o = out_ready_q;
   assign out_irq_o = out_irq_q;

   always @(posedge clk_i or negedge rstn_i) begin
      if (~rstn_i) begin
         started_q <= 1'b0;
         addr_q <= 2'd0;
         out_buffer_q <= 8'd0;
         out_ready_q <= 1'b0;
         out_irq_q <= 1'b0;
      end else begin
         started_q <= 1'b1;
         if (read_i == 1'b1 && sel_i == 1'b1)
           addr_q <= addr_i;
         out_irq_q <= 1'b0;
         if ((read_i == 1'b1 && sel_i == 1'b1 && addr_i == 2'b11) || ~started_q)
           out_ready_q <= 1'b1;
         if (out_valid_i == 1'b1 && out_ready_q == 1'b1) begin
            out_buffer_q <= out_data_i;
            out_ready_q <= 1'b0;
            out_irq_q <= 1'b1;
         end
      end
   end

   reg [7:0] rdata;
   assign data_o = rdata;

   always @(/*AS*/addr_q or in_valid_q or out_buffer_q or out_ready_q) begin
      case (addr_q) 
        2'b01: begin
           rdata = {7'b0, ~in_valid_q};
        end
        2'b10: begin
           rdata = {7'b0, ~out_ready_q};
        end
        2'b11: begin
           rdata = out_buffer_q;
        end
        default: begin
           rdata = 8'b0;
        end
      endcase
   end
endmodule
module SB_PLL40_CORE (
	                    input       REFERENCECLK,
	                    output      PLLOUTCORE,
	                    output      PLLOUTGLOBAL,
	                    input       EXTFEEDBACK,
	                    input [7:0] DYNAMICDELAY,
	                    output      LOCK,
	                    input       BYPASS,
	                    input       RESETB,
	                    input       LATCHINPUTVALUE,
	                    output      SDO,
	                    input       SDI,
	                    input       SCLK
                      );
	 parameter                      FEEDBACK_PATH = "SIMPLE";
	 parameter                      DELAY_ADJUSTMENT_MODE_FEEDBACK = "FIXED";
	 parameter                      DELAY_ADJUSTMENT_MODE_RELATIVE = "FIXED";
	 parameter                      SHIFTREG_DIV_MODE = 1'b0;
	 parameter                      FDA_FEEDBACK = 4'b0000;
	 parameter                      FDA_RELATIVE = 4'b0000;
	 parameter                      PLLOUT_SELECT = "GENCLK";
	 parameter                      DIVR = 4'b0000;
	 parameter                      DIVF = 7'b0000000;
	 parameter                      DIVQ = 3'b000;
	 parameter                      FILTER_RANGE = 3'b000;
	 parameter                      ENABLE_ICEGATE = 1'b0;
	 parameter                      TEST_MODE = 1'b0;
	 parameter                      EXTERNAL_DIVIDE_FACTOR = 1;

   localparam                     CLK_RATIO = (DIVF+1)/(2**DIVQ*(DIVR+1));

   time                           ref_per;
   time                           clk_per;
   time                           last_ref_rising;

   integer                        timeout;

   reg                            clk;
   reg                            lock_reg;

   assign #(clk_per/4) PLLOUTGLOBAL = clk; // glitch filter
   assign #(clk_per+ref_per) LOCK = lock_reg; // glitch filter

   initial begin
      ref_per = 0;
      clk_per = 10;
      last_ref_rising = $time;
      clk = 0;
      lock_reg = 1;
      timeout = 4*CLK_RATIO;
      #1 lock_reg = 0; // negedge to trigger reset
      #100;
      ref_per = 0;
      clk_per = 100000000;
   end

   always @(posedge REFERENCECLK) begin
      if (`abs($time - last_ref_rising - ref_per)*100/ref_per < 1)
        lock_reg = 1;
      else
        lock_reg = 0;
      ref_per = $time - last_ref_rising;
      last_ref_rising = $time;
      if (clk_per != 2**DIVQ * (DIVR + 1) * ref_per / (DIVF + 1)) begin
         clk_per = 2**DIVQ * (DIVR + 1) * ref_per / (DIVF + 1);
         clk <= ~clk;
      end
      timeout = 4*CLK_RATIO;
   end

   always @(clk)
     if (timeout > 0) begin
        clk <= #(clk_per/2) ~clk;
        if (clk)
          timeout = timeout - 1;
     end else
       lock_reg = 0;
endmodule
module SB_RAM256x16
  #(parameter INIT_0 = 256'h0000000000000000000000000000000000000000000000000000000000000000,
    parameter INIT_1 = 256'h0000000000000000000000000000000000000000000000000000000000000000,
    parameter INIT_2 = 256'h0000000000000000000000000000000000000000000000000000000000000000,
    parameter INIT_3 = 256'h0000000000000000000000000000000000000000000000000000000000000000,
    parameter INIT_4 = 256'h0000000000000000000000000000000000000000000000000000000000000000,
    parameter INIT_5 = 256'h0000000000000000000000000000000000000000000000000000000000000000,
    parameter INIT_6 = 256'h0000000000000000000000000000000000000000000000000000000000000000,
    parameter INIT_7 = 256'h0000000000000000000000000000000000000000000000000000000000000000,
    parameter INIT_8 = 256'h0000000000000000000000000000000000000000000000000000000000000000,
    parameter INIT_9 = 256'h0000000000000000000000000000000000000000000000000000000000000000,
    parameter INIT_A = 256'h0000000000000000000000000000000000000000000000000000000000000000,
    parameter INIT_B = 256'h0000000000000000000000000000000000000000000000000000000000000000,
    parameter INIT_C = 256'h0000000000000000000000000000000000000000000000000000000000000000,
    parameter INIT_D = 256'h0000000000000000000000000000000000000000000000000000000000000000,
    parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000,
    parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000)
   (
    output [15:0] RDATA,
    input         RCLK,
    input         RCLKE,
    input         RE,
    input [7:0]   RADDR,
    input         WCLK,
    input         WCLKE,
    input         WE,
    input [7:0]   WADDR,
    input [15:0]  MASK,
    input [15:0]  WDATA
    );

   SB_RAM40_4K #(.INIT_0(INIT_0),
                 .INIT_1(INIT_1),
                 .INIT_2(INIT_2),
                 .INIT_3(INIT_3),
                 .INIT_4(INIT_4),
                 .INIT_5(INIT_5),
                 .INIT_6(INIT_6),
                 .INIT_7(INIT_7),
                 .INIT_8(INIT_8),
                 .INIT_9(INIT_9),
                 .INIT_A(INIT_A),
                 .INIT_B(INIT_B),
                 .INIT_C(INIT_C),
                 .INIT_D(INIT_D),
                 .INIT_E(INIT_E),
                 .INIT_F(INIT_F))
   u_ram40_4k (.RDATA(RDATA),
               .RADDR({3'b0, RADDR}),
               .RCLK(RCLK),
               .RCLKE(RCLKE),
               .RE(RE),
               .WADDR({3'b0, WADDR}),
               .WCLK(WCLK),
               .WCLKE(WCLKE),
               .WDATA(WDATA),
               .WE(WE),
               .MASK(MASK));
endmodule
module tcm_mem_pmem_fifo2

//-----------------------------------------------------------------
// Params
//-----------------------------------------------------------------
#(
    parameter WIDTH   = 8,
    parameter DEPTH   = 4,
    parameter ADDR_W  = 2
)
//-----------------------------------------------------------------
// Ports
//-----------------------------------------------------------------
(
    // Inputs
     input               clk_i
    ,input               rst_i
    ,input  [WIDTH-1:0]  data_in_i
    ,input               push_i
    ,input               pop_i

    // Outputs
    ,output [WIDTH-1:0]  data_out_o
    ,output              accept_o
    ,output              valid_o
);

//-----------------------------------------------------------------
// Local Params
//-----------------------------------------------------------------
localparam COUNT_W = ADDR_W + 1;

//-----------------------------------------------------------------
// Registers
//-----------------------------------------------------------------
reg [WIDTH-1:0]         ram [DEPTH-1:0];
reg [ADDR_W-1:0]        rd_ptr;
reg [ADDR_W-1:0]        wr_ptr;
reg [COUNT_W-1:0]       count;

//-----------------------------------------------------------------
// Sequential
//-----------------------------------------------------------------
always @ (posedge clk_i or posedge rst_i)
if (rst_i)
begin
    count   <= {(COUNT_W) {1'b0}};
    rd_ptr  <= {(ADDR_W) {1'b0}};
    wr_ptr  <= {(ADDR_W) {1'b0}};
end
else
begin
    // Push
    if (push_i & accept_o)
    begin
        ram[wr_ptr] <= data_in_i;
        wr_ptr      <= wr_ptr + 1;
    end

    // Pop
    if (pop_i & valid_o)
        rd_ptr      <= rd_ptr + 1;

    // Count up
    if ((push_i & accept_o) & ~(pop_i & valid_o))
        count <= count + 1;
    // Count down
    else if (~(push_i & accept_o) & (pop_i & valid_o))
        count <= count - 1;
end

//-------------------------------------------------------------------
// Combinatorial
//-------------------------------------------------------------------
/* verilator lint_off WIDTH */
assign accept_o   = (count != DEPTH);
assign valid_o    = (count != 0);
/* verilator lint_on WIDTH */

assign data_out_o = ram[rd_ptr];



endmodule