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