module nt_recv_capture_fifo_merge
(
  // clock and resets
  input wire          clk,
  input wire          rstn,
  input wire          rst_sw,

  // meta data input fifo
  input wire [74:0]   fifo_meta_dout_i,
  input wire          fifo_meta_empty_i,
  output wire         fifo_meta_rd_en_o,

  // data input fifo
  input wire [63:0]   fifo_data_dout_i,
  input wire          fifo_data_empty_i,
  output wire         fifo_data_rd_en_o,

  // output fifo
  output wire [63:0]  fifo_din_o,
  output wire         fifo_wr_en_o,
  input wire          fifo_full_i
);

  // extract packet capture length from meta data
  wire [10:0] meta_len_capture;
  assign meta_len_capture = fifo_meta_dout_i[74:64];

  // number of 64 bit words we need to read from data fifo
  reg [7:0] data_word_cnt_sig;

  // process calculates the number of data words that need to be read from the
  // data input fifo for the current packet
  always @(*) begin
    if ((meta_len_capture & 11'h7) == 0) begin
      // meta_len_capture is a multiple of 8
      data_word_cnt_sig = meta_len_capture >> 3;
    end else begin
      // meta_len_capture is not a multiple of 8 bytes -> round up
      data_word_cnt_sig = (meta_len_capture >> 3) + 11'b1;
    end
  end

  // FSM states
  parameter META = 1'b0,
            DATA = 1'b1;

  reg           state, nxt_state;
  reg [7:0]     data_word_cnt, nxt_data_word_cnt;
  reg [7:0]     data_word_cntr, nxt_data_word_cntr;

  // FSM
  always @(posedge clk) begin
    if (~rstn | rst_sw) begin
      state <= META;
    end else begin
      state <= nxt_state;
    end

    data_word_cnt <= nxt_data_word_cnt;
    data_word_cntr <= nxt_data_word_cntr;
  end

  // FSM
  always @(*) begin
    nxt_state = state;
    nxt_data_word_cnt = data_word_cnt;
    nxt_data_word_cntr = data_word_cntr;

    case (state)
      META: begin
        if (~fifo_full_i & ~fifo_meta_empty_i) begin
          // there is data to be read from the meta input FIFO and the output
          // FIFO is not full. Initialize the number of data words that need to
          // be read from the data FIFO
          nxt_data_word_cnt = data_word_cnt_sig;
          nxt_data_word_cntr = 8'b0;

          if (data_word_cnt_sig > 0) begin
            // we are going to read at least one data word from the data fifo
            nxt_state = DATA;
          end
        end
      end

      DATA: begin
        if (~fifo_full_i & ~fifo_data_empty_i) begin
          // the output FIFO is not full and there is data to be read from the
          // data input FIFO

          // increment counter
          nxt_data_word_cntr = data_word_cntr + 1;

          if ((data_word_cntr + 1) == data_word_cnt) begin
            // all data words have been read
            nxt_state = META;
          end
        end
      end

    endcase
  end

  // assign output FIFO input signals (capture length in bits [74:64] of the
  // meta data word is not transferred to software)
  assign fifo_din_o = (state == META) ? fifo_meta_dout_i[63:0] :
                        fifo_data_dout_i;
  assign fifo_wr_en_o = ~fifo_full_i &
                          (((state == META) & ~fifo_meta_empty_i) ||
                           ((state == DATA) & ~fifo_data_empty_i));

  // assign input FIFOs output signals
  assign fifo_meta_rd_en_o
    = ~fifo_full_i & (state == META) & ~fifo_meta_empty_i;
  assign fifo_data_rd_en_o
    = ~fifo_full_i & (state == DATA) & ~fifo_data_empty_i;

endmodule