verilog – axi stream data generator

An Axi Stream Data Generator which can take data from both file or just an counter. This ip needed for me as a testbench component for interfaces which work on one hand as an AXIS slave and on the other hand Ethernet, pcie and etc.

A struct module

`timescale 1ns / 1ps

module axis_data_generator #
(
  parameter integer                       AXIS_DATA_WIDTH = 32,
  parameter ((AXIS_DATA_WIDTH / 8) - 1:0) AXIS_TKEEP      = 4'hf,
  parameter                               INIT_FILE       = "",
  parameter integer                       BURST_SIZE      = 1024
)
(
  input  wire                                clk_i,
  input  wire                                s_rst_n_i,
  input  wire                                enable_i,                    

  output wire  (AXIS_DATA_WIDTH - 1 : 0)     m_axis_tdata_o,
  output wire  ((AXIS_DATA_WIDTH / 8) - 1:0) m_axis_tkeep_o,
  output wire                                m_axis_tvalid_o,
  output wire                                m_axis_tlast_o,
  input  wire                                m_axis_tready_i
);

  wire                           counter_terminate;
  wire                           counter_enable;
  wire (AXIS_DATA_WIDTH - 1 : 0) data;
  wire (AXIS_DATA_WIDTH - 1 : 0) counter_value;

  COUNTER_TC_MACRO #
  (
    .COUNT_BY      (48'h1              ),
    .DEVICE        ("7SERIES"         ), 
    .DIRECTION     ("UP"              ),
    .RESET_UPON_TC ("TRUE"            ),
    .TC_VALUE      (BURST_SIZE        ),
    .WIDTH_DATA    (AXIS_DATA_WIDTH   )
  ) 
  tc_counter_inst_0 
  (
    .Q             (counter_value    ),
    .TC            (counter_terminate),
    .CLK           (clk_i            ),
    .CE            (counter_enable   ),
    .RST           (!s_rst_n_i       )
  );
  
  generate
    if ("" != INIT_FILE)
      begin : init_from_file
        BRAM_SINGLE_MACRO #
        (
          .BRAM_SIZE   ("18Kb"                 ), 
          .DEVICE      ("7SERIES"              ), 
          .DO_REG      (0                      ), 
          .INIT        ({AXIS_DATA_WIDTH{1'h0}}),
          .INIT_FILE   ("NONE"                 ),
          .WRITE_WIDTH (AXIS_DATA_WIDTH        ),
          .READ_WIDTH  (AXIS_DATA_WIDTH        ),
          .SRVAL       ({AXIS_DATA_WIDTH{1'h0}}),
          .WRITE_MODE  ("NO_CHANGE"            )
        ) 
        single_bram_inst_0
        (
          .DO    (data                   ),
          .ADDR  (counter_value          ),
          .CLK   (clk_i                  ),
          .DI    ({AXIS_DATA_WIDTH{1'h0}}),
          .EN    (enable_i               ),
          .REGCE (1'h0                   ),
          .RST   (!s_rst_n_i             ),
          .WE    (1'h0                   )
        );
      end
    else
      begin : data_from_counter_buf
        IBUF #
        (
          .IBUF_LOW_PWR ("TRUE"   ),  
          .IOSTANDARD   ("DEFAULT")  
        ) 
        ibuf_inst_0
        (
         .O (data         ),    
         .I (counter_value)     
        );
      end
  endgenerate

  axis_data_generator_cntr #
  (
    .AXIS_DATA_WIDTH (AXIS_DATA_WIDTH),
    .AXIS_TKEEP      (AXIS_TKEEP     )
  )
  (
    .clk_i              (clk_i            ),
    .s_rst_n_i          (s_rst_n_i        ),
    .enable_i           (enable_i         ),                    
                       
    .m_axis_tdata_o     (m_axis_tdata_o   ),
    .m_axis_tkeep_o     (m_axis_tkeep_o   ),
    .m_axis_tvalid_o    (m_axis_tvalid_o  ),
    .m_axis_tlast_o     (m_axis_tlast_o   ),
    .m_axis_tready_i    (m_axis_tready_i  ),
                       
    .data_i             (data             ),
    .counter_terminal_i (counter_terminate),
    .counter_enable_o   (counter_enable   )
  );
  
endmodule

axi stream controller module

`timescale 1ns / 1ps

module axis_data_generator_cntr #
(
  parameter integer                        AXIS_DATA_WIDTH = 32,
  parameter ((AXIS_DATA_WIDTH / 8) - 1:0)  AXIS_TKEEP      = 'hf
)
(
  input  wire                                clk_i,
  input  wire                                s_rst_n_i,
  input  wire                                enable_i,                    

  output wire  (AXIS_DATA_WIDTH - 1 : 0)     m_axis_tdata_o,
  output wire  ((AXIS_DATA_WIDTH / 8) - 1:0) m_axis_tkeep_o,
  output wire                                m_axis_tvalid_o,
  output wire                                m_axis_tlast_o,
  input  wire                                m_axis_tready_i,
  
  input  wire  (AXIS_DATA_WIDTH - 1 : 0)     data_i,
  input  wire                                counter_terminal_i,
  output wire                                counter_enable_o
);

  localparam integer               STATE_NUM   = 3;
  localparam integer               STATE_WIDTH = $clog2(STATE_NUM);
  
  localparam (STATE_WIDTH - 1 : 0) IDLE_STATE    = 0;
  localparam (STATE_WIDTH - 1 : 0) SENDING_STATE = 1;
  localparam (STATE_WIDTH - 1 : 0) STOP_STATE    = 2;  
  
  reg (STATE_WIDTH - 1 : 0) fsm_state;
  reg (STATE_WIDTH - 1 : 0) next_fsm_state;
  
  assign m_axis_tvalid_o  = enable_i;
  assign m_axis_tkeep_o   = AXIS_TKEEP;
  assign m_axis_tlast_o   = counter_terminal_i;
  
  assign counter_enable_o = ((SENDING_STATE == fsm_state) && (1'h1 == m_axis_tready_i));
  assign m_axis_tdata_o   = data_i;
  
  always @( posedge clk_i )
    begin
      if(1'h0 == s_rst_n_i)
        begin
          fsm_state      <= IDLE_STATE;
          next_fsm_state <= IDLE_STATE;
        end
      else
        begin
          fsm_state <= next_fsm_state;
        end
    end

  always @ (*)
    begin
      next_fsm_state = fsm_state;
      
      if (1'h1 == enable_i)
       begin
        case (fsm_state)
        IDLE_STATE:
          begin
            if (1'h1 == m_axis_tready_i) 
              begin
                next_fsm_state = SENDING_STATE;
              end
            end
          SENDING_STATE:
            begin
              if (1'h1 == counter_terminal_i)
                begin
                  next_fsm_state = STOP_STATE;
                end
            end
          STOP_STATE:
            begin
              next_fsm_state = IDLE_STATE;
            end
          endcase
        end
    end

endmodule

testbench

`timescale 1ns / 1ps

module axis_data_generator_cntr_tb;

  localparam integer                  DATA_WIDTH       = 32;
  localparam integer                  CLOCK_PERIOD     = 100;
  localparam integer                  PACK_SIZE        = 1024;
  localparam integer                  PACK_NUMBER      = 1024;
  localparam integer                  ITERATION_NUMBER = PACK_SIZE * PACK_NUMBER;
  localparam (DATA_WIDTH / 8 - 1 : 0) KEEP             = 'hf;
  
  wire                          counter_enable;
  wire                          terminate;
  wire                          axis_tvalid;
  wire                          axis_tlast;
  
  wire (DATA_WIDTH - 1 : 0)     axis_tdata;
  wire (DATA_WIDTH / 8 - 1 : 0) axis_tkeep;
 
  wire (DATA_WIDTH - 1 : 0)     data;
  
  reg                      axis_tready;
  
  reg                      clk;
  reg                      rst_n;
  reg                      enable;
  
  COUNTER_TC_MACRO #
  (
    .COUNT_BY      (48'h1     ),
    .DEVICE        ("7SERIES" ), 
    .DIRECTION     ("UP"      ),
    .RESET_UPON_TC ("TRUE"    ),
    .TC_VALUE      (PACK_SIZE ),
    .WIDTH_DATA    (DATA_WIDTH)
  ) 
  COUNTER_TC_MACRO_inst_0 
  (
    .Q             (data          ),
    .TC            (terminate     ),
    .CLK           (clk           ),
    .CE            (counter_enable),
    .RST           (!rst_n        )
  );

  axis_data_generator_cntr #
  (
    .AXIS_DATA_WIDTH (DATA_WIDTH),
    .AXIS_TKEEP      (KEEP      )
  )
  axis_data_generator_cntr_dut_0
  (
    .clk_i              (clk           ),
    .s_rst_n_i          (rst_n         ),
    .enable_i           (enable        ),                    
                     
    .m_axis_tdata_o     (axis_tdata    ),
    .m_axis_tkeep_o     (axis_tkeep    ),
    .m_axis_tvalid_o    (axis_tvalid   ),
    .m_axis_tlast_o     (axis_tlast    ),
    .m_axis_tready_i    (axis_tready   ),
                     
    .data_i             (data          ),
    .counter_terminal_i (terminate     ),
    .counter_enable_o   (counter_enable)
  );
  
  task check_data;
    begin
      enable <= 1'h1;
      rst_n  <= 1'h1;
      @(posedge clk);
    
      wait (axis_tvalid);
    
      repeat(100) 
        begin 
          if ({DATA_WIDTH{1'h0}} != axis_tdata)
            begin
              $display("The ready signal error.");
              $stop();
            end
          
           @(posedge clk); 
         end
    
      repeat(ITERATION_NUMBER) 
        begin 
          axis_tready <= $urandom % 2; 
          @(posedge clk); 
        end

      enable <= 1'h0;
    end
  endtask
  
  initial
    begin
      clk = 1'h0;

      forever
        begin
          #(CLOCK_PERIOD / 2) clk = !clk;
        end 
    end    

  initial
    begin
      rst_n  = 1'h0;
      enable = 1'h0;
      
      @(posedge clk);
      check_data;

      $display("The test has finished.");  

      $stop();            
    end


endmodule