dakies/OSS_Verilog huggingface dataset:
module usb_gamepad_reader #(
    parameter GAMEPAD = "BUFFALO"
) (
    input clk,
    input reset,

    input usb_dif,
    inout usb_dp,
    inout usb_dn,

    output [11:0] usb_btn
);
    localparam C_report_bytes = 8;
    
    wire [C_report_bytes*8-1:0] S_report;
    wire S_report_valid;
    wire [7:0] usb_buttons;

    usbh_host_hid #(
        .C_usb_speed(0),
        .C_report_length(C_report_bytes),
        .C_report_length_strict(0)
    ) us2_hid_host (
        .clk(clk),
        .bus_reset(reset),
        .usb_dif(usb_dif),
        .usb_dp(usb_dp),
        .usb_dn(usb_dn),
        .hid_report(S_report),
        .hid_valid(S_report_valid)
    );

    generate
        if (GAMEPAD == "BUFFALO") begin
            usbh_report_decoder_buffalo usbh_report_decoder(
                .i_clk(clk),
                .i_report(S_report),
                .i_report_valid(S_report_valid),
                .o_btn(usb_btn)
            );
        end

        if (GAMEPAD == "KEYPAD") begin
            usbh_report_decoder_keypad usbh_report_decoder(
                .i_clk(clk),
                .i_report(S_report),
                .i_report_valid(S_report_valid),
                .o_btn(usb_btn)
            );
        end

        if (GAMEPAD == "WINGMAN") begin
            usbh_report_decoder_wingman usbh_report_decoder(
                .i_clk(clk),
                .i_report(S_report),
                .i_report_valid(S_report_valid),
                .o_btn(usb_btn)
            );
        end

        // (...more gamepads)

    endgenerate

endmodule
module re(input wire clk, input wire rst_n, input wire [7:0] in, output match);
assign match = (reg_4 | reg_9);

reg reg_0;
always @(posedge clk or negedge rst_n) begin
    if (rst_n == 0) begin
        reg_0 <= 'd0;
    end else begin
        if (('d72 == in))
            reg_0 <= 'd1;
        else if (~(('d72 == in)))
            reg_0 <= 'd0;
    end
end

reg reg_1;
always @(posedge clk or negedge rst_n) begin
    if (rst_n == 0) begin
        reg_1 <= 'd0;
    end else begin
        if ((reg_0 & ('d101 == in)))
            reg_1 <= 'd1;
        else if (~((reg_0 & ('d101 == in))))
            reg_1 <= 'd0;
    end
end

reg reg_2;
always @(posedge clk or negedge rst_n) begin
    if (rst_n == 0) begin
        reg_2 <= 'd0;
    end else begin
        if ((reg_1 & ('d108 == in)))
            reg_2 <= 'd1;
        else if (~((reg_1 & ('d108 == in))))
            reg_2 <= 'd0;
    end
end

reg reg_3;
always @(posedge clk or negedge rst_n) begin
    if (rst_n == 0) begin
        reg_3 <= 'd0;
    end else begin
        if ((reg_2 & ('d108 == in)))
            reg_3 <= 'd1;
        else if (~((reg_2 & ('d108 == in))))
            reg_3 <= 'd0;
    end
end

reg reg_4;
always @(posedge clk or negedge rst_n) begin
    if (rst_n == 0) begin
        reg_4 <= 'd0;
    end else begin
        if (((reg_2 | reg_3) & ('d111 == in)))
            reg_4 <= 'd1;
        else if (~(((reg_2 | reg_3) & ('d111 == in))))
            reg_4 <= 'd0;
    end
end

reg reg_5;
always @(posedge clk or negedge rst_n) begin
    if (rst_n == 0) begin
        reg_5 <= 'd0;
    end else begin
        if (((in == 'd87) | (in == 'd119)))
            reg_5 <= 'd1;
        else if (~(((in == 'd87) | (in == 'd119))))
            reg_5 <= 'd0;
    end
end

reg reg_6;
always @(posedge clk or negedge rst_n) begin
    if (rst_n == 0) begin
        reg_6 <= 'd0;
    end else begin
        if ((reg_5 & ('d111 == in)))
            reg_6 <= 'd1;
        else if (~((reg_5 & ('d111 == in))))
            reg_6 <= 'd0;
    end
end

reg reg_7;
always @(posedge clk or negedge rst_n) begin
    if (rst_n == 0) begin
        reg_7 <= 'd0;
    end else begin
        if ((reg_6 & ('d114 == in)))
            reg_7 <= 'd1;
        else if (~((reg_6 & ('d114 == in))))
            reg_7 <= 'd0;
    end
end

reg reg_8;
always @(posedge clk or negedge rst_n) begin
    if (rst_n == 0) begin
        reg_8 <= 'd0;
    end else begin
        if ((reg_7 & ('d108 == in)))
            reg_8 <= 'd1;
        else if (~((reg_7 & ('d108 == in))))
            reg_8 <= 'd0;
    end
end

reg reg_9;
always @(posedge clk or negedge rst_n) begin
    if (rst_n == 0) begin
        reg_9 <= 'd0;
    end else begin
        if ((reg_8 & ('d100 == in)))
            reg_9 <= 'd1;
        else if (~((reg_8 & ('d100 == in))))
            reg_9 <= 'd0;
    end
end
endmodule
module fixed_sme_wrapper (
  input  wire            clk,
  input  wire            rst,

  // AXI Stream input
  input  wire [8*8-1:0]  s_axis_tdata,
  input  wire [8-1:0]    s_axis_tkeep,
  input  wire            s_axis_tvalid,

  // Match output
  input  wire            next_index,
  output reg  [9:0]      match_index,
  output reg             match_valid,
  output reg             match_error,

  // merged state
  output reg  [3:0]      match_valid_stat,
  output reg  [3:0]      match_error_stat
);

  ///////////////////////////////////////////////
  ////////// Check for fixed patterns ///////////
  ///////////////////////////////////////////////
  wire [561-1:0] sme_output;

  fixed_loc_sme FSME (
    .clk(clk),
    .rst(rst | reload),

    .s_axis_tdata(s_axis_tdata),
    .s_axis_tkeep(s_axis_tkeep),
    .s_axis_tvalid(s_axis_tvalid),
    .match(sme_output)
  );

  // Encoding the output matches
  wire [4*10-1:0] shrinker_output;
  wire [3:0]      match_valids;
  wire [3:0]      match_errors;

  spaced_2lvl_penc # (
    .INPUT_WIDTH(561),
    .PENC1_SIZE (16),
    .PENC2_SIZE (16),
    .BIN_COUNT  (4)
  ) match_shrinker (
    .clk(clk),
    .rst(rst),

    .one_hot(sme_output),
    .index(shrinker_output),
    .valid(match_valids),
    .error(match_errors)
  );

  reg [3:0] selected_match;
  reg [3:0] selected_match_r;
  reg [9:0] selected_match_index;
  reg       selected_match_error;
  reg [3:0] match_mask;

  integer k;
  always @ (*) begin
    selected_match = 4'd1;
    selected_match_index = shrinker_output[0*10+:10];
    selected_match_error = match_errors[0];

    for (k=3;k>=0;k=k-1)
      if (match_valids[k] & match_mask[k]) begin
        selected_match       = 4'd1 << k;
        selected_match_index = shrinker_output[k*10+:10];
        selected_match_error = match_errors[k];
      end
  end

  always @ (posedge clk) begin
    selected_match_r <= selected_match;
    match_index      <= selected_match_index;
    match_error      <= selected_match_error;

    match_valid      <= |(match_valids & match_mask);
    match_valid_stat <= match_valids & match_mask;
    match_error_stat <= match_errors & match_mask;

    if (rst) begin
      match_valid      <= 1'b0;
      match_valid_stat <= 4'd0;
      match_error_stat <= 4'd0;
    end
  end

  always @ (posedge clk) begin
    if (rst || reload)
      match_mask <= 4'hF;
    else if (next_index)
      match_mask <= match_mask & ~selected_match_r;
  end

endmodule
module hash_acc #(
    parameter HASH_WIDTH = 36
)
(
    input  wire                         clk,
    input  wire                         rst,

    input  wire [31:0]                  hash_data,
    input  wire [1:0]                   hash_data_len,
    input  wire                         hash_data_valid,
    input  wire                         hash_clear,

    input  wire [(HASH_WIDTH+4)*8-1:0]  hash_key,

    output wire [31:0]                  hash_out
);

parameter OFFSET_WIDTH = $clog2(HASH_WIDTH);

reg [HASH_WIDTH*8-1:0] hash_data_reg = 0;
reg [OFFSET_WIDTH-1:0] offset_reg = 0;
// reg [31:0] hash_reg;

function [31:0] hash_toep(input [HASH_WIDTH*8-1:0] data, input [5:0] len, input [(HASH_WIDTH+4)*8-1:0] key);
    integer i, j;
    begin
        hash_toep = 0;
        for (i = 0; i < len; i = i + 1) begin
            for (j = 0; j < 8; j = j + 1) begin
                if (data[i*8 + (7-j)]) begin
                    hash_toep = hash_toep ^ key[(HASH_WIDTH+4)*8 - 32 - i*8 - j +: 32];
                end
            end
        end
    end
endfunction

wire [31:0] hash = hash_toep(hash_data_reg, HASH_WIDTH, hash_key);

assign hash_out = hash; // _reg;

always @(posedge clk) begin
    if (hash_data_valid) begin
        if (hash_data_len == 1) begin
            hash_data_reg[offset_reg*8 +: 8] <= hash_data[7:0];
            offset_reg <= offset_reg + 1;
        end else if (hash_data_len == 2) begin
            hash_data_reg[offset_reg*8 +: 16] <= hash_data[15:0];
            offset_reg <= offset_reg + 2;
        end else begin
            hash_data_reg[offset_reg*8 +: 32] <= hash_data;
            offset_reg <= offset_reg + 4;
        end
    end

    // hash_reg <= hash;

    if (rst || hash_clear) begin
        hash_data_reg <= 0;
        offset_reg <= 0;
    end
end

endmodule
module test_mul_hash (
  input  clk,
  input  [63:0] a,
  output [63:0] p
);

parameter MSK_BYTES = 0;
localparam ANDMSK   = {{(8-MSK_BYTES)*8{1'b1}},{MSK_BYTES*8{1'b0}}};

wire [23:0] a0b0;
wire [23:0] a0b1;
wire [23:0] a0b2;
wire [23:0] a0b3;
wire [23:0] a1b0;
wire [23:0] a1b1;
wire [23:0] a1b2;
wire [23:0] a1b3;
wire [23:0] a2b0;
wire [23:0] a2b1;
wire [23:0] a2b2;
wire [23:0] a2b3;
wire [23:0] a3b0;
wire [23:0] a3b1;
wire [23:0] a3b2;
wire [23:0] a3b3;
wire [23:0] a4b0;
wire [23:0] a4b1;
wire [23:0] a4b2;
wire [23:0] a4b3;
wire [23:0] a5b0;
wire [23:0] a5b1;
wire [23:0] a5b2;
wire [23:0] a5b3;
wire [23:0] a6b0;
wire [23:0] a6b1;
wire [23:0] a6b2;
wire [23:0] a6b3;
wire [23:0] a7b0;
wire [23:0] a7b1;
wire [23:0] a7b2;
wire [23:0] a7b3;

mul_hash dut_mul_0 (
  .clk(clk),
  .a(a[0*8+:8]), 
  .ab0(a0b0),                 
  .ab1(a0b1), 
  .ab2(a0b2),                 
  .ab3(a0b3)
);

mul_hash dut_mul_1 (
  .clk(clk),
  .a(a[1*8+:8]), 
  .ab0(a1b0),                 
  .ab1(a1b1), 
  .ab2(a1b2),                 
  .ab3(a1b3)
);

mul_hash dut_mul_2 (
  .clk(clk),
  .a(a[2*8+:8]), 
  .ab0(a2b0),                 
  .ab1(a2b1), 
  .ab2(a2b2),                 
  .ab3(a2b3)
);

mul_hash dut_mul_3 (
  .clk(clk),
  .a(a[3*8+:8]), 
  .ab0(a3b0),                 
  .ab1(a3b1), 
  .ab2(a3b2),                 
  .ab3(a3b3)
);

mul_hash dut_mul_4 (
  .clk(clk),
  .a(a[4*8+:8]), 
  .ab0(a4b0),                 
  .ab1(a4b1), 
  .ab2(a4b2),                 
  .ab3(a4b3)
);

mul_hash dut_mul_5 (
  .clk(clk),
  .a(a[5*8+:8]), 
  .ab0(a5b0),                 
  .ab1(a5b1), 
  .ab2(a5b2),                 
  .ab3(a5b3)
);

mul_hash dut_mul_6 (
  .clk(clk),
  .a(a[6*8+:8]), 
  .ab0(a6b0),                 
  .ab1(a6b1), 
  .ab2(a6b2),                 
  .ab3(a6b3)
);

mul_hash dut_mul_7 (
  .clk(clk),
  .a(a[7*8+:8]), 
  .ab0(a7b0),                 
  .ab1(a7b1), 
  .ab2(a7b2),                 
  .ab3(a7b3)
);

acc_hash # (
	.ANDMSK(ANDMSK),
	.NBITS(64)
) dut_acc_hash (
  .clk(clk), .p(p),

  .a0b0(a0b0), .a0b1(a0b1), .a0b2(a0b2), .a0b3(a0b3),
  .a1b0(a1b0), .a1b1(a1b1), .a1b2(a1b2), .a1b3(a1b3),
  .a2b0(a2b0), .a2b1(a2b1), .a2b2(a2b2),
  .a3b0(a3b0), .a3b1(a3b1), .a3b2(a3b2),
  .a4b0(a4b0), .a4b1(a4b1),
  .a5b0(a5b0), .a5b1(a5b1),
  .a6b0(a6b0),
  .a7b0(a7b0)
);
  
initial begin
  $dumpfile ("sim_build/mul_hash_waveform.fst");
  $dumpvars (0,test_mul_hash);
  #1;
end

endmodule
module test_firewall (
  input  wire             clk,
  input  wire             rst,

  input  [31:0]           ip,
  input                   ip_valid,

  output                  match,
  output                  match_valid
);

  firewall DUT (
    .clk(clk), 
    .rst(rst), 
    .addr(ip), 
    .valid(ip_valid), 
    .match(match), 
    .done(match_valid)
  );
  
  // Generating Waveform
  initial begin
    $dumpfile ("sim_build/test_firewall.fst");
    $dumpvars (0,test_firewall);
    #1;
  end

endmodule
module pcie_s10_msi #
(
    parameter MSI_COUNT = 32
)
(
    input  wire                  clk,
    input  wire                  rst,

    /*
     * Interrupt request inputs
     */
    input  wire [MSI_COUNT-1:0]  msi_irq,

    /*
     * Interface to H-Tile/L-Tile PCIe IP core
     */
    output wire                  app_msi_req,
    input  wire                  app_msi_ack,
    output wire [2:0]            app_msi_tc,
    output wire [4:0]            app_msi_num,
    output wire [1:0]            app_msi_func_num,

    /*
     * Configuration
     */
    input  wire                  cfg_msi_enable,
    input  wire [2:0]            cfg_multiple_msi_enable,
    input  wire [31:0]           cfg_msi_mask
);

reg active_reg = 1'b0, active_next;

reg [MSI_COUNT-1:0] msi_irq_reg = {MSI_COUNT{1'b0}};
reg [MSI_COUNT-1:0] msi_irq_last_reg = {MSI_COUNT{1'b0}};
reg [MSI_COUNT-1:0] msi_irq_active_reg = {MSI_COUNT{1'b0}}, msi_irq_active_next;

reg [MSI_COUNT-1:0] msi_irq_mask_reg = {MSI_COUNT{1'b0}}, msi_irq_mask_next;

reg [4:0] msi_int_reg = 0, msi_int_next;

assign app_msi_req = active_reg;
assign app_msi_tc = 0; // TC 0
assign app_msi_num = msi_int_reg;
assign app_msi_func_num = 0; // PF 0

wire [MSI_COUNT-1:0] message_enable_mask = cfg_multiple_msi_enable > 3'd4 ? {32{1'b1}} : {32{1'b1}} >> (32 - (1 << cfg_multiple_msi_enable));

reg [MSI_COUNT-1:0] acknowledge;
wire [MSI_COUNT-1:0] grant;
wire [4:0] grant_encoded;
wire grant_valid;

// arbiter instance
arbiter #(
    .PORTS(MSI_COUNT),
    .ARB_TYPE_ROUND_ROBIN(1),
    .ARB_BLOCK(1),
    .ARB_BLOCK_ACK(1),
    .ARB_LSB_HIGH_PRIORITY(1)
)
arb_inst (
    .clk(clk),
    .rst(rst),
    .request(msi_irq_active_reg & msi_irq_mask_reg & ~grant),
    .acknowledge(acknowledge),
    .grant(grant),
    .grant_valid(grant_valid),
    .grant_encoded(grant_encoded)
);

always @* begin
    active_next = active_reg;

    msi_irq_active_next = (msi_irq_active_reg | (msi_irq_reg & ~msi_irq_last_reg));

    msi_irq_mask_next = ~cfg_msi_mask & message_enable_mask & {32{cfg_msi_enable}};

    msi_int_next = msi_int_reg;

    acknowledge = {MSI_COUNT{1'b0}};

    if (!active_reg) begin
        if (cfg_msi_enable && grant_valid) begin
            msi_int_next = grant_encoded;
            active_next = 1'b1;
        end
    end else begin
        if (app_msi_ack) begin
            msi_irq_active_next = msi_irq_active_next & ~grant;
            acknowledge = grant;
            active_next = 1'b0;
        end
    end
end

always @(posedge clk) begin
    active_reg <= active_next;
    msi_irq_reg <= msi_irq;
    msi_irq_last_reg <= msi_irq_reg;
    msi_irq_active_reg <= msi_irq_active_next;
    msi_irq_mask_reg <= msi_irq_mask_next;
    msi_int_reg <= msi_int_next;

    if (rst) begin
        active_reg <= 1'b0;
        msi_irq_reg <= {MSI_COUNT{1'b0}};
        msi_irq_last_reg <= {MSI_COUNT{1'b0}};
        msi_irq_active_reg <= {MSI_COUNT{1'b0}};
        msi_irq_mask_reg <= {MSI_COUNT{1'b0}};
        msi_int_reg <= {MSI_COUNT{1'b0}};
    end
end

endmodule
module pcie_ptile_fc_counter #
(
    parameter WIDTH = 16,
    parameter INDEX = 0
)
(
    input  wire              clk,
    input  wire              rst,

    input  wire [WIDTH-1:0]  tx_cdts_limit,
    input  wire [2:0]        tx_cdts_limit_tdm_idx,
    input  wire [WIDTH-1:0]  fc_dec,
    output wire [WIDTH-1:0]  fc_av
);

reg [WIDTH-1:0] fc_cap_reg = 0;
reg [WIDTH-1:0] fc_limit_reg = 0;
reg [WIDTH-1:0] fc_inc_reg = 0;
reg [WIDTH-1:0] fc_av_reg = 0;

assign fc_av = fc_av_reg;

always @(posedge clk) begin
    if (tx_cdts_limit_tdm_idx == INDEX) begin
        if (!fc_cap_reg) begin
            fc_cap_reg <= tx_cdts_limit;
        end
        fc_inc_reg <= tx_cdts_limit - fc_limit_reg;
        fc_limit_reg <= tx_cdts_limit;
    end

    if ($signed({1'b0, fc_av_reg}) - $signed({1'b0, fc_dec}) + $signed({1'b0, fc_inc_reg}) < 0) begin
        fc_av_reg <= 0;
    end else if ($signed({1'b0, fc_av_reg}) - $signed({1'b0, fc_dec}) + $signed({1'b0, fc_inc_reg}) > fc_cap_reg) begin
        fc_av_reg <= fc_cap_reg;
    end else begin
        fc_av_reg <= $signed({1'b0, fc_av_reg}) - $signed({1'b0, fc_dec}) + $signed({1'b0, fc_inc_reg});
    end

    if (rst) begin
        fc_cap_reg <= 0;
        fc_limit_reg <= 0;
        fc_inc_reg <= 0;
        fc_av_reg <= 0;
    end
end

endmodule
module simple_sync_sig # (
  parameter RST_VAL = 1'b0,
  parameter WIDTH   = 1
) (
  input  wire dst_clk,
  input  wire dst_rst,
  input  wire [WIDTH-1:0] in,
  output wire [WIDTH-1:0] out
);

(* KEEP = "TRUE" *) reg [WIDTH-1:0] sync_reg_1;
(* KEEP = "TRUE" *) reg [WIDTH-1:0] sync_reg_2;

always @ (posedge dst_clk)
  if (dst_rst) begin
    sync_reg_1 <= {WIDTH{RST_VAL}};
    sync_reg_2 <= {WIDTH{RST_VAL}};
  end else begin
    sync_reg_1 <= in;
    sync_reg_2 <= sync_reg_1;
  end

assign out = sync_reg_2;

endmodule
module pipe_reg #(
    parameter WIDTH=1, // width of the input and output signals
    parameter N=2 // depth of synchronizer
)(
    input  wire             clk,

    input  wire [WIDTH-1:0] in,
    output wire [WIDTH-1:0] out
);

 (* srl_style="register", keep="true", shreg_extract="no" *)
 reg [WIDTH-1:0] sync_reg [N-1:0];

  integer i;

  always @(posedge clk) begin
    sync_reg[0] <= in;

    for (i = 1; i < N; i = i + 1)
      sync_reg[i] <= sync_reg[i-1];
  end

  assign out = sync_reg[N-1];

endmodule
module pipe_register #(
  parameter WIDTH = 8,
  // 0 to bypass, 1 for simple buffer, 2 for skid buffer
  parameter TYPE  = 2
) (
  input  wire             clk,
  input  wire             rst,

  input  wire             din_valid,
  input  wire [WIDTH-1:0] din,
  output wire             din_ready,

  output wire             dout_valid,
  output wire [WIDTH-1:0] dout,
  input  wire             dout_ready
);

  if (TYPE > 1) begin // Skid buffer, practically a 2 element FIFO

    // Since dout_valid=!empty and din_ready=!full, their negate version
    // are used to make those signals registered without the not
    reg n_empty, n_full;

    // Two registers to buffer the data
    reg [WIDTH-1:0] dout_reg;
    reg [WIDTH-1:0] tmp_reg;

    always @ (posedge clk) begin
      if (rst) begin
        // Using the error state of both full and empty to detect cycle after reset
        // We don't want the din_ready to stay 1 during rst
        n_full  <= 1'b0; // full  <= 1'b1;
        n_empty <= 1'b0; // empty <= 1'b1;
      end else begin
        if (!n_full) begin // if (full)
          // ** both full and empty can only happen the cycle after reset
          if (dout_ready || !n_empty)
            n_full <= 1'b1; // full <= 1'b0;
        end else if (!n_empty) begin // if (empty)
          if (din_valid)
            n_empty <= 1'b1; // empty <= 1'b0;
        end else begin
          if (din_valid && !dout_ready)
            n_full  <= 1'b0; // full <= 1'b1;
          else if (!din_valid && dout_ready)
            n_empty <= 1'b0; // empty <= 1'b1;
        end
      end
    end

    always @ (posedge clk) begin
      if (!n_full) begin // if (full)
        if (dout_ready)
          dout_reg <= tmp_reg;
      end else begin
        // Can check for din_valid, but without it dout_valid won't be asserted
        if (dout_ready || !n_empty) // (dout_ready || empty)
          dout_reg <= din;
      end

      // Always load tmp_reg from input if there was a transaction,
      // to simplify the overall logic, even if not used
      if (din_valid && din_ready)
        tmp_reg <= din;
    end

    assign dout       = dout_reg;
    assign dout_valid = n_empty;
    assign din_ready  = n_full;

  end else if (TYPE == 1) begin // Simple buffer, inserts bubble cycle

    reg empty, full;
    reg [WIDTH-1:0] dout_reg;

    always @(posedge clk) begin
        if (rst) begin
          empty  <= 1'b0;
          full   <= 1'b0;
        end else if (full && dout_ready) begin
          full   <= 1'b0;
          empty  <= 1'b1;
        end else if (empty) begin
          full   <=  din_valid;
          empty  <= !din_valid; // To become 1 the cycle after rst
        end

        // Can check for din_valid, but without it dout_valid won't be asserted
        if (empty)
            dout_reg <= din;
    end

    assign dout_valid = full;
    assign din_ready  = empty;
    assign dout       = dout_reg;

  end else begin // Bypass

    assign dout       = din;
    assign dout_valid = din_valid;
    assign din_ready  = dout_ready;

  end

endmodule
module pipe_reg_rst #(
    parameter WIDTH=1, // width of the input and output signals
    parameter N=2, // depth of synchronizer
    parameter INIT=1'b0
)(
    input  wire             clk,
    input  wire             rst,

    input  wire [WIDTH-1:0] in,
    output wire [WIDTH-1:0] out
);

 (* srl_style="register", keep="true", shreg_extract="no" *)
 reg [WIDTH-1:0] sync_reg [N-1:0];

  integer i;

  always @(posedge clk) begin
    if (rst)
      sync_reg[0] <= {WIDTH{INIT}};
    else
      sync_reg[0] <= in;

    for (i = 1; i < N; i = i + 1)
      if (rst)
        sync_reg[i] <= sync_reg[i-1];
      else
        sync_reg[i] <= {WIDTH{INIT}};
  end

  assign out = sync_reg[N-1];

endmodule
module accel_wrap #(
  parameter IO_DATA_WIDTH   = 32,
  parameter IO_STRB_WIDTH   = (IO_DATA_WIDTH/8),
  parameter IO_ADDR_WIDTH   = 22,
  parameter DATA_WIDTH      = 128,
  parameter STRB_WIDTH      = (DATA_WIDTH/8),
  parameter PMEM_ADDR_WIDTH = 1,
  parameter AROM_ADDR_WIDTH = 1,
  parameter AROM_DATA_WIDTH = DATA_WIDTH,
  parameter SLOW_M_B_LINES  = 4096,
  parameter ACC_ADDR_WIDTH  = $clog2(SLOW_M_B_LINES),
  parameter PMEM_SEL_BITS   = PMEM_ADDR_WIDTH-$clog2(STRB_WIDTH)
                              -1-$clog2(SLOW_M_B_LINES),
  parameter ACC_MEM_BLOCKS  = 2**PMEM_SEL_BITS,
  parameter SLOT_COUNT      = 16
) (
  input  wire                                     clk,
  input  wire                                     rst,

  input  wire                                     io_en,
  input  wire                                     io_wen,
  input  wire [IO_STRB_WIDTH-1:0]                 io_strb,
  input  wire [IO_ADDR_WIDTH-1:0]                 io_addr,
  input  wire [IO_DATA_WIDTH-1:0]                 io_wr_data,
  output wire [IO_DATA_WIDTH-1:0]                 io_rd_data,
  output wire                                     io_rd_valid,

  input  wire [AROM_ADDR_WIDTH-1:0]               acc_rom_wr_addr,
  input  wire [AROM_DATA_WIDTH-1:0]               acc_rom_wr_data,
  input  wire                                     acc_rom_wr_en,

  output wire [ACC_MEM_BLOCKS-1:0]                acc_en_b1,
  output wire [ACC_MEM_BLOCKS*STRB_WIDTH-1:0]     acc_wen_b1,
  output wire [ACC_MEM_BLOCKS*ACC_ADDR_WIDTH-1:0] acc_addr_b1,
  output wire [ACC_MEM_BLOCKS*DATA_WIDTH-1:0]     acc_wr_data_b1,
  input  wire [ACC_MEM_BLOCKS*DATA_WIDTH-1:0]     acc_rd_data_b1,

  output wire [ACC_MEM_BLOCKS-1:0]                acc_en_b2,
  output wire [ACC_MEM_BLOCKS*STRB_WIDTH-1:0]     acc_wen_b2,
  output wire [ACC_MEM_BLOCKS*ACC_ADDR_WIDTH-1:0] acc_addr_b2,
  output wire [ACC_MEM_BLOCKS*DATA_WIDTH-1:0]     acc_wr_data_b2,
  input  wire [ACC_MEM_BLOCKS*DATA_WIDTH-1:0]     acc_rd_data_b2,

  output wire                                     error,
  input  wire                                     error_ack
);

assign acc_en_b1 = 0;
assign acc_wen_b1 = 0;
assign acc_addr_b1 = 0;
assign acc_wr_data_b1 = 0;

assign acc_en_b2 = 0;
assign acc_wen_b2 = 0;
assign acc_addr_b2 = 0;
assign acc_wr_data_b2 = 0;

assign io_rd_data  = 0;
assign io_rd_valid = 0;

assign error = 1'b0;

endmodule
module slot_keeper # (
  parameter SLOT_COUNT = 8,
  parameter SLOT_WIDTH = $clog2(SLOT_COUNT+1)
)(
  input  wire                  clk,
  input  wire                  rst,

  input  wire [SLOT_WIDTH-1:0] init_slots,
  input  wire                  init_valid,

  input  wire [SLOT_WIDTH-1:0] slot_in,
  input  wire                  slot_in_valid,

  output wire [SLOT_WIDTH-1:0] slot_out,
  output wire                  slot_out_valid,
  input  wire                  slot_out_pop,

  output wire [SLOT_WIDTH-1:0] slot_count,
  // enq_err is asserted 2 cycles later after the wrong slot enq
  output wire                  enq_err
);

  wire enque = slot_in_valid && (slot_in!=0);
  wire deque = slot_out_valid && slot_out_pop;

  reg [SLOT_COUNT:1]   occupied;
  reg [SLOT_WIDTH-1:0] selected_slot;

  integer i;
  always@(*) begin
    selected_slot = {{(SLOT_WIDTH-1){1'b0}},1'b1};
    for (i=SLOT_COUNT;i>=1;i=i-1)
      if (occupied[i])
        selected_slot = i;
  end

  reg [SLOT_COUNT:1] slot_err;
  //counts enq error to know when output is not valid
  reg [SLOT_WIDTH:0] last_valid_count;

  always @ (posedge clk) begin
    if (enque) begin
      if (occupied[slot_in]) begin
        slot_err[slot_in] <= 1'b1;
        last_valid_count  <= last_valid_count + {{(SLOT_WIDTH-1){1'b0}},1'b1};
      end
      occupied[slot_in] <= 1'b1;
    end

    if (deque)
       occupied[selected_slot] <= 1'b0;

    if (init_valid) begin
       occupied         <= ({SLOT_COUNT{1'b1}} >> (SLOT_COUNT-init_slots));
       slot_err         <= {SLOT_COUNT{1'b0}};
       last_valid_count <= {{(SLOT_WIDTH-1){1'b0}},1'b1};
    end

    if (rst) begin
       occupied         <= {SLOT_COUNT{1'b0}};
       slot_err         <= {SLOT_COUNT{1'b0}};
       last_valid_count <= {{(SLOT_WIDTH-1){1'b0}},1'b1};
    end
  end

  reg [SLOT_WIDTH:0] slot_count_r;
  reg                valid_r;
  always @ (posedge clk)
    if (rst) begin
      slot_count_r <= {SLOT_WIDTH{1'b0}};
      valid_r      <= 1'b0;
    end else begin
      if (init_valid) begin
        slot_count_r <= init_slots;
        valid_r      <= (init_slots!=0);
      end if (enque && !deque) begin
        slot_count_r <= slot_count_r + {{(SLOT_WIDTH-1){1'b0}},1'b1};
        valid_r      <= 1'b1;
      end else if (!enque && deque) begin
        slot_count_r <= slot_count_r - {{(SLOT_WIDTH-1){1'b0}},1'b1};
        if (slot_count_r == last_valid_count)
          valid_r <= 1'b0;
      end
    end

  reg enq_err_r;
  always @ (posedge clk)
    if (rst)
      enq_err_r <= 1'b0;
    else
      enq_err_r <= |slot_err;

  assign slot_out_valid = valid_r;
  assign slot_out       = selected_slot;
  assign enq_err        = enq_err_r;
  assign slot_count     = slot_count_r;

endmodule
module max_finder_tree # (
  parameter PORT_COUNT = 16,
  parameter DATA_WIDTH = 8,
  parameter ADDR_WIDTH = $clog2(PORT_COUNT)
) (
  input  wire [PORT_COUNT*DATA_WIDTH-1:0] values,
  input  wire [PORT_COUNT-1:0]            valids,

  output wire [DATA_WIDTH-1:0]            max_val,
  output wire [ADDR_WIDTH-1:0]            max_ptr,
  output wire                             max_valid
);

localparam CEIL_PORT_CNT = (2**$clog2(PORT_COUNT));
localparam PADDING       = CEIL_PORT_CNT - PORT_COUNT;

reg [PORT_COUNT*DATA_WIDTH-1:0] masked_values;
integer i;

always @ (*)
  for (i=0; i< PORT_COUNT; i=i+1)
    if (!valids[i])
      masked_values [i*DATA_WIDTH +: DATA_WIDTH] = {DATA_WIDTH{1'b0}};
    else
      masked_values [i*DATA_WIDTH +: DATA_WIDTH] = values [i*DATA_WIDTH +: DATA_WIDTH];

max_finder_tree_pow_of_2 # (
  .PORT_COUNT(CEIL_PORT_CNT),
  .DATA_WIDTH(DATA_WIDTH),
  .ADDR_WIDTH(ADDR_WIDTH)
) max_finder (
  .values({{PADDING*DATA_WIDTH{1'b0}}, masked_values}),
  .max_val(max_val),
  .max_ptr(max_ptr)
);

assign max_valid = (masked_values != {PORT_COUNT*DATA_WIDTH{1'b0}});

endmodule
module max_finder_tree_pow_of_2 # (
  parameter PORT_COUNT = 16,
  parameter DATA_WIDTH = 8,
  parameter ADDR_WIDTH = $clog2(PORT_COUNT)
) (
  input  wire [PORT_COUNT*DATA_WIDTH-1:0] values,
  output wire [DATA_WIDTH-1:0]            max_val,
  output wire [ADDR_WIDTH-1:0]            max_ptr
);

// intermediate signals
wire [DATA_WIDTH-1:0] int_max [0:PORT_COUNT-2];
wire [ADDR_WIDTH-1:0] int_ptr [0:PORT_COUNT-2];
wire                  cmp_res [0:PORT_COUNT-2];

function [ADDR_WIDTH:0] l_offset (input [ADDR_WIDTH-1:0] stage);
  integer i;
  begin
    l_offset = 0;
    for (i=1;i<=stage;i=i+1)
      l_offset = l_offset + PORT_COUNT/(2**i);
  end
endfunction

function [ADDR_WIDTH:0] r_offset (input [ADDR_WIDTH-1:0] stage);
  integer i;
  begin
    r_offset = 0;
    for (i=1;i<stage;i=i+1)
      r_offset = r_offset + PORT_COUNT/(2**i);
  end
endfunction

genvar stage,j,k;

generate
  for (k=0; k<PORT_COUNT; k=k+2) begin
    greater_than # (.DATA_WIDTH(DATA_WIDTH)) inp_stage (
      .inp_A(values[(k+1)*DATA_WIDTH +: DATA_WIDTH]),
      .inp_B(values [k*DATA_WIDTH +: DATA_WIDTH]),
      .result(cmp_res[k/2]));

    assign int_max [k/2] = cmp_res[k/2] ?
              values[(k+1)*DATA_WIDTH +: DATA_WIDTH] : values[k*DATA_WIDTH +: DATA_WIDTH];

    assign int_ptr [k/2] = cmp_res[k/2] ?
                       {{(ADDR_WIDTH-1){1'b0}},1'b1} : {{(ADDR_WIDTH-1){1'b0}},1'b0};
  end


  for (stage=1; stage < ADDR_WIDTH; stage = stage+1) begin
    for (j=0; j<(PORT_COUNT/(2**stage)); j=j+2) begin
      // initial
      //   $display("%d %d %d %d", stage, j, r_offset(stage), l_offset(stage));
      greater_than # (.DATA_WIDTH(DATA_WIDTH)) intermediate_stage (
        .inp_A(int_max[r_offset(stage)+j+1]),
        .inp_B(int_max[r_offset(stage)+j]),
        .result(cmp_res[l_offset(stage)+(j/2)]));

      assign int_max [l_offset(stage)+(j/2)] = cmp_res[l_offset(stage)+(j/2)] ?
                             int_max[r_offset(stage)+j+1] : int_max[r_offset(stage)+j] ;

      assign int_ptr [l_offset(stage)+(j/2)] = cmp_res[l_offset(stage)+(j/2)] ?
             {{(ADDR_WIDTH-stage-1){1'b0}},1'b1,int_ptr[r_offset(stage)+j+1][stage-1:0]} :
             {{(ADDR_WIDTH-stage-1){1'b0}},1'b0,int_ptr[r_offset(stage)+j][stage-1:0]} ;
    end
  end

endgenerate


assign max_val = int_max [PORT_COUNT-2];
assign max_ptr = int_ptr [PORT_COUNT-2];

endmodule
module greater_than #(
  parameter DATA_WIDTH=8
)(
  input  wire [DATA_WIDTH-1:0] inp_A,
  input  wire [DATA_WIDTH-1:0] inp_B,
  output wire                  result
);
    assign result = (inp_A>inp_B);

endmodule
module mem_1r1w # (
  parameter BYTES_PER_LINE = 4,
  parameter ADDR_WIDTH     = 11,
  parameter LINE_SIZE      = 8*BYTES_PER_LINE
)(
  input  wire                      clka,
  input  wire                      ena,
  input  wire [BYTES_PER_LINE-1:0] wea,
  input  wire [ADDR_WIDTH-1:0]     addra,
  input  wire [LINE_SIZE-1 :0]     dina,

  input  wire                      clkb,
  input  wire                      enb,
  input  wire [ADDR_WIDTH-1:0]     addrb,
  output wire [LINE_SIZE-1 :0]     doutb
);

(* ram_style = "block" *)
reg [LINE_SIZE-1:0] mem [0:(2**ADDR_WIDTH)-1];
reg [LINE_SIZE-1:0] mem_out;
integer i;

always @ (posedge clka)
  if (ena)
    for (i = 0; i < BYTES_PER_LINE; i = i + 1)
      if (wea[i] == 1'b1)
        mem[addra][i*8 +: 8]  <= dina[i*8 +: 8];

always @ (posedge clkb)
  if (enb)
    mem_out <= mem[addrb];

assign doutb = mem_out;

endmodule
module mem_2rw_bram # (
  parameter BYTES_PER_LINE = 4,
  parameter ADDR_WIDTH     = 13,
  parameter LINE_SIZE      = 8*BYTES_PER_LINE
)(
  input  wire                      clka,
  input  wire                      ena,
  input  wire                      rena,
  input  wire [BYTES_PER_LINE-1:0] wena,
  input  wire [ADDR_WIDTH-1    :0] addra,
  input  wire [LINE_SIZE-1     :0] dina,
  output wire [LINE_SIZE-1     :0] douta,

  input  wire                      clkb,
  input  wire                      enb,
  input  wire                      renb,
  input  wire [BYTES_PER_LINE-1:0] wenb,
  input  wire [ADDR_WIDTH-1    :0] addrb,
  input  wire [LINE_SIZE-1     :0] dinb,
  output wire [LINE_SIZE-1     :0] doutb
);

(* ram_style = "block" *)
reg [LINE_SIZE-1:0] mem [0:(2**ADDR_WIDTH)-1];
reg [LINE_SIZE-1:0] mem_out_a;
reg [LINE_SIZE-1:0] mem_out_b;
integer i;

always @ (posedge clka)
  if (ena) begin
    for (i = 0; i < BYTES_PER_LINE; i = i + 1)
      if (wena[i])
        mem[addra][i*8 +: 8]  <= dina[i*8 +: 8];
    if (rena)
      mem_out_a <= mem[addra];
  end

always @ (posedge clkb)
  if (enb) begin
    for (i = 0; i < BYTES_PER_LINE; i = i + 1)
      if (wenb[i])
        mem[addrb][i*8 +: 8]  <= dinb[i*8 +: 8];
    if (renb)
      mem_out_b <= mem[addrb];
  end

assign douta = mem_out_a;
assign doutb = mem_out_b;

// Mostly for test benches
// synthesis translate_off
integer j;
initial begin
    // two nested loops for smaller number of iterations per loop
    // workaround for synthesizer complaints about large loop counts
    for (i = 0; i < 2**(ADDR_WIDTH); i = i + 2**((ADDR_WIDTH-1)/2)) begin
        for (j = i; j < i + 2**((ADDR_WIDTH-1)/2); j = j + 1) begin
            mem[j] = {LINE_SIZE{1'b0}};
        end
    end
end
// synthesis translate_on

endmodule
module mem_1r1w_uram_pipelined # (
  parameter BYTES_PER_LINE = 4,
  parameter ADDR_WIDTH     = 11,
  parameter LINE_SIZE      = 8*BYTES_PER_LINE,
  parameter RAM_PIPELINE   = 2
)(
  input  wire                      clk,
  input  wire                      rst,

  input  wire                      ena,
  input  wire [ADDR_WIDTH-1:0]     addra,
  input  wire [LINE_SIZE-1 :0]     dina,

  input  wire                      enb,
  input  wire [ADDR_WIDTH-1:0]     addrb,
  output wire [LINE_SIZE-1 :0]     doutb
);

(* ram_style = "ultra" *)
reg [LINE_SIZE-1:0] mem [(1<<ADDR_WIDTH)-1:0];
reg [LINE_SIZE-1:0] mem_out;

reg [LINE_SIZE-1: 0]   dout_regs [RAM_PIPELINE-1:0];
reg [RAM_PIPELINE-1:0] enb_regs;

integer i;

always @ (posedge clk)
  if (ena)
    mem[addra] <= dina;

always @ (posedge clk)
  if (enb)
    dout_regs[0] <= mem[addrb];

// Pipeline registers
always @(posedge clk) begin
  enb_regs[0] <= enb;
  for (i = 1 ; i < RAM_PIPELINE; i = i + 1) begin
    enb_regs[i] <= enb_regs[i-1];
    if (enb_regs[i-1])
      dout_regs[i] <= dout_regs[i-1];
  end
  if (rst)
    enb_regs <= 0;
end

assign doutb = dout_regs[RAM_PIPELINE-1];

endmodule
module mem_2rw_uram # (
  parameter BYTES_PER_LINE = 4,
  parameter ADDR_WIDTH     = 13,
  parameter LINE_SIZE      = 8*BYTES_PER_LINE
)(
  input  wire                      clk,

  input  wire                      ena,
  input  wire [BYTES_PER_LINE-1:0] wena,
  input  wire [ADDR_WIDTH-1    :0] addra,
  input  wire [LINE_SIZE-1     :0] dina,
  output wire [LINE_SIZE-1     :0] douta,

  input  wire                      enb,
  input  wire [BYTES_PER_LINE-1:0] wenb,
  input  wire [ADDR_WIDTH-1    :0] addrb,
  input  wire [LINE_SIZE-1     :0] dinb,
  output wire [LINE_SIZE-1     :0] doutb
);

(* ram_style = "ultra" *)
reg [LINE_SIZE-1:0] mem [(1<<ADDR_WIDTH)-1:0];
reg [LINE_SIZE-1:0] mem_out_a;
reg [LINE_SIZE-1:0] mem_out_b;
integer i;

always @ (posedge clk)
  if (ena)
    for (i = 0; i < BYTES_PER_LINE; i = i + 1)
      if (wena[i])
        mem[addra][i*8 +: 8]  <= dina[i*8 +: 8];

always @ (posedge clk)
  if (ena)
    if (~|wena)
      mem_out_a <= mem[addra];

always @ (posedge clk)
  if (enb)
    for (i = 0; i < BYTES_PER_LINE; i = i + 1)
      if (wenb[i])
        mem[addrb][i*8 +: 8]  <= dinb[i*8 +: 8];

always @ (posedge clk)
  if (enb)
    if (~|wenb)
      mem_out_b <= mem[addrb];

assign douta = mem_out_a;
assign doutb = mem_out_b;

// Only for simulation, URAM cannot be loaded during programming
// synthesis translate_off
integer j;
initial begin
    // two nested loops for smaller number of iterations per loop
    // workaround for synthesizer complaints about large loop counts
    for (i = 0; i < 2**(ADDR_WIDTH); i = i + 2**((ADDR_WIDTH-1)/2)) begin
        for (j = i; j < i + 2**((ADDR_WIDTH-1)/2); j = j + 1) begin
            mem[j] = {LINE_SIZE{1'b0}};
        end
    end
end
// synthesis translate_on

endmodule
module axis_stopper # (
  parameter PORT_COUNT = 4,
  parameter REG_FOR_EN = 0
) (
  input  wire                  clk,
  input  wire                  rst,

  input  wire [PORT_COUNT-1:0] enable,

  input  wire [PORT_COUNT-1:0] s_axis_tvalid,
  input  wire [PORT_COUNT-1:0] s_axis_tlast,
  output wire [PORT_COUNT-1:0] s_axis_tready,

  output wire [PORT_COUNT-1:0] m_axis_tvalid,
  output wire [PORT_COUNT-1:0] m_axis_tlast,
  input  wire [PORT_COUNT-1:0] m_axis_tready
);

  // Register enable input if necessary
  reg [PORT_COUNT-1:0] enable_r;
  generate
    if (REG_FOR_EN) begin

      always @ (posedge clk)
        if (rst)
          enable_r <= {PORT_COUNT{1'b1}};
        else
          enable_r <= enable;

    end else begin

      always @ (*)
          enable_r = enable;

    end
  endgenerate

  // Detect Start of Packet
  reg [PORT_COUNT-1:0] SoP;
  integer i;

  always @ (posedge clk)
    if (rst)
      SoP <= {PORT_COUNT{1'b1}};
    else
      for (i=0;i<PORT_COUNT;i=i+1)
        if (s_axis_tvalid[i] && s_axis_tready[i]) // If there was a transaction
          SoP[i] <= s_axis_tlast[i]; // SoP becomes 1 only after tlast

  // Combinational logic for the outputs.
  // Blocking happens only from start of a packet until enable is re-asserted
  wire [PORT_COUNT-1:0] block = SoP & ~enable_r;

  assign m_axis_tlast  = s_axis_tlast;
  assign m_axis_tvalid = s_axis_tvalid & ~block;
  assign s_axis_tready = m_axis_tready & ~block;

endmodule
module axis_stat # (
  parameter KEEP_WIDTH        = 8,
  // If KEEP_ENABLE is not 1, byte_count represents word count
  parameter KEEP_ENABLE       = KEEP_WIDTH>1,
  parameter BYTE_COUNT_WIDTH  = 32,
  parameter FRAME_COUNT_WIDTH = 32
) (
  input  wire                         clk,
  input  wire                         rst,
  input  wire                         clear,

  input  wire [KEEP_WIDTH-1:0]        monitor_axis_tkeep,
  input  wire                         monitor_axis_tvalid,
  input  wire                         monitor_axis_tready,
  input  wire                         monitor_axis_tlast,
  input  wire                         monitor_drop_pulse,

  output reg  [BYTE_COUNT_WIDTH-1:0]  byte_count,
  output reg  [FRAME_COUNT_WIDTH-1:0] frame_count,
  output reg  [FRAME_COUNT_WIDTH-1:0] drop_count,
  output reg  [FRAME_COUNT_WIDTH-1:0] stall_count
);

integer i, bit_cnt;

always @ (posedge clk) begin

  // valid transfer cycle
  if (monitor_axis_tready && monitor_axis_tvalid) begin
    if (KEEP_ENABLE) begin
      bit_cnt = 0;
      for (i = 0; i <= KEEP_WIDTH; i = i + 1) begin
        //bit_cnt = bit_cnt + monitor_axis_tkeep[i];
        if (monitor_axis_tkeep == ({KEEP_WIDTH{1'b1}}) >> (KEEP_WIDTH-i)) bit_cnt = i;
      end
      byte_count <= byte_count + bit_cnt;
    end else begin
      byte_count <= byte_count + 1;
    end

    if (monitor_axis_tlast)
      frame_count <= frame_count + 1;
  end

  if (!monitor_axis_tready && monitor_axis_tvalid)
    stall_count <= stall_count + 1;

  if (monitor_drop_pulse)
    drop_count <= drop_count + 1;


  if (rst || clear) begin
    byte_count  <= {BYTE_COUNT_WIDTH{1'b0}};
    frame_count <= {FRAME_COUNT_WIDTH{1'b0}};
    drop_count  <= {FRAME_COUNT_WIDTH{1'b0}};
    stall_count  <= {FRAME_COUNT_WIDTH{1'b0}};
  end

end

endmodule
module simple_axis_srl_fifo #(
  parameter WIDTH = 8,
  parameter DEPTH = 16
) (
  input  wire                       clk,
  input  wire                       rst,

  input  wire                       din_valid,
  input  wire [WIDTH-1:0]           din,

  output wire                       dout_valid,
  output wire [WIDTH-1:0]           dout,
  input  wire                       dout_ready,

  output wire [$clog2(DEPTH+1)-1:0] count
);

  reg [WIDTH-1:0] data_reg[DEPTH-1:0];
  reg [$clog2(DEPTH+1)-1:0] ptr_reg = 0;
  reg empty_reg = 1'b1, empty_next;

  wire ptr_empty  = ptr_reg == 0;
  wire ptr_empty1 = ptr_reg == 1;
  wire ptr_full   = ptr_reg == DEPTH;
  wire ptr_full1  = ptr_reg == DEPTH-1;

  reg shift;
  reg inc;
  reg dec;

  integer i;

  initial begin
    for (i = 0; i < DEPTH; i = i + 1)
      data_reg[i] <= 0;
  end

  always @* begin
    shift = 1'b0;
    inc = 1'b0;
    dec = 1'b0;
    empty_next = empty_reg;

    if (dout_ready && din_valid) begin
      shift = 1'b1;
      inc = ptr_empty;
      empty_next = 1'b0;
    end else if (dout_ready && dout_valid) begin
      dec = 1'b1;
      empty_next = ptr_empty1;
    end else if (din_valid) begin
      shift = 1'b1;
      inc = 1'b1;
      empty_next = 1'b0;
    end
  end

  always @(posedge clk) begin
    if (inc)
      ptr_reg <= ptr_reg + 1;
    else if (dec)
      ptr_reg <= ptr_reg - 1;
    else
      ptr_reg <= ptr_reg;

    empty_reg <= empty_next;

    if (shift) begin
      data_reg[0] <= din;
      for (i = 0; i < DEPTH-1; i = i + 1)
        data_reg[i+1] <= data_reg[i];
    end

    if (rst) begin
      ptr_reg <= 0;
      empty_reg <= 1'b1;
    end
  end

  assign dout = data_reg[ptr_reg-1];
  assign dout_valid = !empty_reg;
  assign count = ptr_reg;

endmodule
module axis_slr_register_source #(
  parameter WIDTH = 8
) (
  input  wire             clk,
  input  wire             rst,

  input  wire             din_valid,
  input  wire [WIDTH-1:0] din,
  output wire             din_ready,

  output wire             dout_valid,
  output wire [WIDTH-1:0] dout,
  input  wire             dout_ready
);

  (* USER_SLL_REG="true" *)                     reg  sll_valid   = 1'b0;
  (* USER_SLL_REG="true", shreg_extract="no" *) reg  [WIDTH-1:0] sll_data;
  (* USER_SLL_REG="true", keep="true" *)        reg  sll_ready   = 1'b0;
  (* keep="true" *)                             reg  sll_ready_r = 1'b0;

  // Register input, including ready signal
  always @(posedge clk) begin
    sll_data    <= din;
    sll_valid   <= din_valid & sll_ready_r;
    sll_ready   <= dout_ready;
    sll_ready_r <= sll_ready;

    if (rst)
      sll_ready_r <= 1'b0;
  end

  assign dout_valid = sll_valid;
  assign dout       = sll_data;
  assign din_ready  = sll_ready_r;

endmodule
module axis_slr_register_dest #(
  parameter WIDTH = 8,
  parameter DEPTH = 16
) (
  // System Signals
  input  wire             clk,
  input  wire             rst,

  // Slave side
  input  wire             din_valid,
  input  wire [WIDTH-1:0] din,
  output wire             din_ready,

  // Master side
  output wire             dout_valid,
  output wire [WIDTH-1:0] dout,
  input  wire             dout_ready
);

  // Make sure SLL Registers are used for crossing SLR boundary
  (* USER_SLL_REG="true" *)                     reg  sll_valid = 1'b0;
  (* USER_SLL_REG="true", shreg_extract="no" *) reg  [WIDTH-1:0] sll_data;
  (* USER_SLL_REG="true", keep="true" *)        reg  sll_ready = 1'b0;

  // If FIFO is empty or downstream can accept we ready the input to avoid overflow
  always @(posedge clk) begin
    sll_ready <= dout_ready | ~dout_valid;
    sll_data  <= din;
    sll_valid <= din_valid;
  end

  wire dout_ready_n;

  simple_axis_srl_fifo #(
    .WIDTH (WIDTH),
    .DEPTH (DEPTH)
  ) srl_fifo (
    .clk        (clk),
    .rst        (rst),

    .din        (sll_data),
    .din_valid  (sll_valid),

    .dout       (dout),
    .dout_valid (dout_valid),
    .dout_ready (dout_ready_n),

    .count      ()
  );

  assign din_ready    = sll_ready;
  assign dout_ready_n = dout_ready & dout_valid;


endmodule
module basic_fifo # (
  parameter DEPTH      = 5,
  parameter DATA_WIDTH = 32,
  parameter INIT_ZERO  = 0,
  parameter ADDR_WIDTH = $clog2(DEPTH)
)(
  input  wire                  clk,
  input  wire                  rst,
  input  wire                  clear,

  input  wire                  din_valid,
  input  wire [DATA_WIDTH-1:0] din,
  output wire                  din_ready,

  output wire                  dout_valid,
  output wire [DATA_WIDTH-1:0] dout,
  input  wire                  dout_ready,

  output wire [ADDR_WIDTH:0]   item_count,
  output wire                  full,
  output wire                  empty
);

reg [DATA_WIDTH-1:0] mem [0:(2**ADDR_WIDTH)-1];
reg [ADDR_WIDTH-1:0] rptr, wptr;
reg [ADDR_WIDTH:0]   item_count_r;

wire enque = din_valid  & din_ready;
wire deque = dout_valid & dout_ready;

always @ (posedge clk)
  if (rst || clear) begin
    wptr <= {ADDR_WIDTH{1'b0}};
    rptr <= {ADDR_WIDTH{1'b0}};
  end else begin
    if (enque) begin
      mem[wptr] <= din;
      wptr      <= wptr + {{(ADDR_WIDTH-1){1'b0}},1'b1};
    end
    if (deque) begin
      rptr      <= rptr + {{(ADDR_WIDTH-1){1'b0}},1'b1};
    end
  end

assign dout = mem[rptr];

// Latching last transaction to know FIFO is full or empty
// Using not version of them to make din_ready and dout_valid registered
reg n_full, n_empty;

always @ (posedge clk)
  if (rst || clear) begin
    // Eventhough din_ready is asserted during rst due to n_full, enque is 0
    n_full  <= 1'b0;
    n_empty <= 1'b0;
  end else if (!n_full && !n_empty) begin // Detecting cycle after rst or clear
    n_full  <= 1'b1;
  end else if (enque ^ deque) begin
    n_full  <= !(((wptr + {{(ADDR_WIDTH-1){1'b0}},1'b1}) == rptr) && enque);
    n_empty <= !(((rptr + {{(ADDR_WIDTH-1){1'b0}},1'b1}) == wptr) && deque);
  end

always @ (posedge clk)
  if (rst || clear)
    item_count_r <= {(ADDR_WIDTH+1){1'b0}};
  else
    if (enque && !deque)
      item_count_r <= item_count_r + {{(ADDR_WIDTH){1'b0}},1'b1};
    else if (!enque && deque)
      item_count_r <= item_count_r - {{(ADDR_WIDTH){1'b0}},1'b1};

assign din_ready  = n_full;
assign dout_valid = n_empty;

// Status outputs, so a not is fine
assign empty = !n_empty;
assign full  = !n_full;

assign item_count = item_count_r;

integer i;
initial begin
  if (INIT_ZERO)
    for (i=0; i<2**ADDR_WIDTH; i=i+1)
      mem[i] <= {DATA_WIDTH{1'b0}};
end

endmodule
module accel_width_conv # (
  parameter DATA_IN_WIDTH  = 128,
  parameter DATA_OUT_WIDTH = 8,
  parameter STRB_OUT_WIDTH = DATA_OUT_WIDTH/8,
  // TUSER is offset of last valid byte
  parameter USER_WIDTH     = $clog2(DATA_IN_WIDTH/8)
) (
  input  wire                      clk,
  input  wire                      rst,

  // Read data input
  input  wire [DATA_IN_WIDTH-1:0]  s_axis_tdata,
  input  wire [USER_WIDTH-1:0]     s_axis_tuser,
  input  wire                      s_axis_tlast,
  input  wire                      s_axis_tvalid,
  output wire                      s_axis_tready,

  // Read data output
  output reg  [DATA_OUT_WIDTH-1:0] m_axis_tdata,
  output reg  [STRB_OUT_WIDTH-1:0] m_axis_tkeep,
  output reg                       m_axis_tlast,
  output reg                       m_axis_tvalid,
  input  wire                      m_axis_tready
);

    localparam SKIP_BITS = $clog2(DATA_OUT_WIDTH/8);
    localparam PTR_WIDTH = USER_WIDTH-SKIP_BITS;

    reg  [PTR_WIDTH-1:0]      rd_ptr;
    wire [STRB_OUT_WIDTH-1:0] strobe;

    // Detecting last chunk and setting strobe
    wire last_chunk = (rd_ptr==s_axis_tuser[USER_WIDTH-1:SKIP_BITS]);
    if (SKIP_BITS==0)
      assign strobe = 1'b1;
    else
      assign strobe = ~({{STRB_OUT_WIDTH-1{1'b1}},1'b0} << s_axis_tuser[SKIP_BITS-1:0]);

    // out_ready works with accel always asserting tready or
    // accepting tvalid in same cycle
    wire out_ready  = !m_axis_tvalid || m_axis_tready;
    assign s_axis_tready = out_ready && last_chunk;

    always @ (posedge clk) begin
      // Since data is coming from a FIFO, tvalid drop without
      // tready assertion means there was a stop signal and
      // rd_ptr needs to be reset. In normal mode and no
      // tvalid it keeps the rd_ptr to be zero.
      if (!s_axis_tvalid)
        rd_ptr <= {PTR_WIDTH{1'b0}};
      else if (out_ready) begin
        if (last_chunk)
          rd_ptr <= {PTR_WIDTH{1'b0}};
        else
          rd_ptr <= rd_ptr + 1;
      end

      if (rst)
        rd_ptr <= {PTR_WIDTH{1'b0}};
    end

    // Register the outputs
    always @ (posedge clk) begin
      m_axis_tdata   <= s_axis_tdata[rd_ptr*DATA_OUT_WIDTH+:DATA_OUT_WIDTH];
      m_axis_tkeep   <= (s_axis_tlast && last_chunk) ?
                         strobe : {STRB_OUT_WIDTH{1'b1}};
      m_axis_tlast   <= s_axis_tlast && last_chunk;
      m_axis_tvalid  <= s_axis_tvalid;
    end

endmodule