I'm working on a design right now but I'm struggling with the axistream bus. I just want to be sure that I'm understanding well how it works. To do so I'm using the uvvm library to do a generator that send some data through a axis bus to my IP and then my IP sends it back to a uvvm axistream slave. The IP is very simple: I just read what's in the databus coming from the master then I transmit it to the slave.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity AXI4_Stream_IP is
port (
-- Clock and Reset Signals
axi_clk : in std_logic;
axi_rstn : in std_logic;
-- AXI4-Stream Input Signals
tvalid_in : in std_logic; -- Input Data Valid
tready_in : out std_logic; -- Ready for Input Data
tdata_in : in std_logic_vector(7 downto 0); -- Input Data
tlast_in : in std_logic;
tkeep_in : in std_logic_vector(0 downto 0); -- Assuming tkeep is not used in the component
tuser_in : in std_logic_vector(0 downto 0); -- Assuming tuser is not used in the component
tid_in : in std_logic_vector(0 downto 0); -- Assuming tid is not used in the component
tstrb_in : in std_logic_vector(0 downto 0); -- Assuming tstrb is not used in the component
t_dest_in : in std_logic_vector(0 downto 0);
-- AXI4-Stream Output Signals
tvalid_out : out std_logic; -- Output Data Valid
tready_out : in std_logic; -- Ready for Output Data
tdata_out : out std_logic_vector(7 downto 0); -- Output Data
tlast_out : out std_logic; -- Output Last Data Indicator
tkeep_out : out std_logic_vector(0 downto 0); -- Assuming tkeep is not used in the component
tuser_out : out std_logic_vector(0 downto 0); -- Assuming tuser is not used in the component
tid_out : out std_logic_vector(0 downto 0); -- Assuming tid is not used in the component
tstrb_out : out std_logic_vector(0 downto 0); -- Assuming tstrb is not used in the component
t_dest_out : out std_logic_vector(0 downto 0) -- Assuming t_dest is not used in the component
);
end entity AXI4_Stream_IP;
architecture rtl of AXI4_Stream_IP is
-- Internal Signals for Input Data Storage and Read Control
signal reg_data_in : std_logic_vector(7 downto 0) := (others => '0');
signal state : std_logic_vector(1 downto 0) := "00";
begin
-- Process for IP Logic
process(axi_clk, axi_rstn)
begin
if axi_rstn = '0' then
-- Reset conditions
tvalid_out <= '0';
tdata_out <= (others => '0');
tlast_out <= '0';
reg_data_in <= (others => '0'); -- Reset internal register
-- state <= "00";
tready_in <= '0';
elsif rising_edge(axi_clk) then
if tvalid_in = '1' then
tready_in <= '1';
else
tready_in <= '0';
end if;
case state is
when "00" =>
if tvalid_in = '1' and tready_in = '1' then
reg_data_in <= tdata_in;
tvalid_out <= '1';
state <= "01";
end if;
when "01" =>
if tready_out = '1' and tvalid_out = '1' then
tdata_out <= reg_data_in;
tvalid_out <= '0';
state <= "00";
end if;
when others =>
state <= "00";
end case;
end if;
end process;
end architecture rtl;
This is the code of the IP, and I use the following testbench:
library ieee;
use ieee.std_logic_1164.all;
library std;
use std.env.all;
library uvvm_util;
context uvvm_util.uvvm_util_context;
library bitvis_vip_axistream;
use bitvis_vip_axistream.axistream_bfm_pkg.all;
use std.textio.all;
use std.env.finish;
entity alorsla is
end alorsla;
architecture behavioral of alorsla is
-- Clock signal
signal clk : std_logic;
signal rst_n:std_logic;
-- Record definition for the AXI4-Stream bus
subtype t_axistream is t_axistream_if (
tdata (7 downto 0),
tkeep (0 downto 0),
tuser (0 downto 0),
tstrb (0 downto 0),
tid (0 downto 0),
tdest (0 downto 0)
);
signal m_axistream : t_axistream;
signal s_axistream : t_axistream;
-- AXI4-Stream data
signal tdata_array : t_slv_array(0 to 15) (7 downto 0) := ( x"00", x"11", x"22", x"33",
x"44", x"55", x"66", x"77",
x"88", x"59", x"AA", x"BB",
x"CC", x"DD", x"EE", x"FF");
signal tdata_expected_array : t_slv_array(0 to 15) (7 downto 0) := ( x"00", x"11", x"22", x"33",
x"44", x"55", x"66", x"77",
x"88", x"59", x"AA", x"BB",
x"CC", x"DD", x"EE", x"FF");
signal msg_id_panel : t_msg_id_panel := shared_msg_id_panel;
-- Configure the AXI4-Stream BFM
constant C_AXISTREAM_BFM_CONFIG_DEFAULT : t_axistream_bfm_config := (
max_wait_cycles => 100,
max_wait_cycles_severity => ERROR,
clock_period => -1 ns,
clock_period_margin => 0 ns,
clock_margin_severity => TB_ERROR,
setup_time => -1 ns,
hold_time => -1 ns,
bfm_sync => SYNC_ON_CLOCK_ONLY,
match_strictness => MATCH_EXACT,
byte_endianness => LOWER_BYTE_LEFT,
valid_low_at_word_num => 0,
valid_low_multiple_random_prob => 0.5,
valid_low_duration => 0,
valid_low_max_random_duration => 5,
check_packet_length => false,
protocol_error_severity => ERROR,
ready_low_at_word_num => 0,
ready_low_multiple_random_prob => 0.5,
ready_low_duration => 0,
ready_low_max_random_duration => 5,
ready_default_value => '0',
id_for_bfm => ID_BFM
);
constant C_AXISTREAM_SLAVE_BFM_CONFIG_DEFAULT : t_axistream_bfm_config := (
max_wait_cycles => 100,
max_wait_cycles_severity => ERROR,
clock_period => -1 ns,
clock_period_margin => 0 ns,
clock_margin_severity => TB_ERROR,
setup_time => -1 ns,
hold_time => -1 ns,
bfm_sync => SYNC_ON_CLOCK_ONLY,
match_strictness => MATCH_EXACT,
byte_endianness => LOWER_BYTE_LEFT,
valid_low_at_word_num => 0,
valid_low_multiple_random_prob => 0.5,
valid_low_duration => 0,
valid_low_max_random_duration => 5,
check_packet_length => false,
protocol_error_severity => ERROR,
ready_low_at_word_num => 0,
ready_low_multiple_random_prob => 0.5,
ready_low_duration => 0,
ready_low_max_random_duration => 5,
ready_default_value => '0',
id_for_bfm => ID_BFM
);
component AXI4_Stream_IP is
port (
-- Clock and Reset Signals
axi_clk : in std_logic;
axi_rstn : in std_logic;
-- AXI4-Stream Input Signals
tvalid_in : in std_logic; -- Input Data Valid
tready_in : out std_logic; -- Ready for Input Data
tdata_in : in std_logic_vector(7 downto 0); -- Input Data
tlast_in : in std_logic;
tkeep_in : in std_logic_vector(0 downto 0); -- Assuming tkeep is not used in the component
tuser_in : in std_logic_vector(0 downto 0); -- Assuming tuser is not used in the component
tid_in : in std_logic_vector(0 downto 0); -- Assuming tid is not used in the component
tstrb_in : in std_logic_vector(0 downto 0); -- Assuming tstrb is not used in the component
t_dest_in : in std_logic_vector(0 downto 0);
-- AXI4-Stream Output Signals
tvalid_out : out std_logic; -- Output Data Valid
tready_out : in std_logic; -- Ready for Output Data
tdata_out : out std_logic_vector(7 downto 0); -- Output Data
tlast_out : out std_logic; -- Output Last Data Indicator
tkeep_out : out std_logic_vector(0 downto 0); -- Assuming tkeep is not used in the component
tuser_out : out std_logic_vector(0 downto 0); -- Assuming tuser is not used in the component
tid_out : out std_logic_vector(0 downto 0); -- Assuming tid is not used in the component
tstrb_out : out std_logic_vector(0 downto 0); -- Assuming tstrb is not used in the component
t_dest_out : out std_logic_vector(0 downto 0) -- Assuming t_dest is not used in the component
);
end component AXI4_Stream_IP;
begin
-- Generate the clock
clock_generator(clk, 10 ns);
uut: AXI4_Stream_IP
port map (
axi_clk =>clk,
axi_rstn =>rst_n,
tdata_in => m_axistream.tdata,
tkeep_in => m_axistream.tkeep,
tuser_in => m_axistream.tuser,
tvalid_in => m_axistream.tvalid,
tlast_in => m_axistream.tlast,
tready_out => s_axistream.tready,
tstrb_in => m_axistream.tstrb,
tid_in => m_axistream.tid,
t_dest_in => m_axistream.tdest,
tdata_out => s_axistream.tdata,
tkeep_out => s_axistream.tkeep,
tuser_out => s_axistream.tuser,
tvalid_out => s_axistream.tvalid,
tlast_out => s_axistream.tlast,
tready_in => m_axistream.tready,
tstrb_out => s_axistream.tstrb,
tid_out => s_axistream.tid,
t_dest_out => s_axistream.tdest
);
-- uut: AXI4_Stream_IP
-- port map (
-- axi_clk => clk,
-- axi_rstn => rst_n,
-- tvalid_in => m_axistream.tvalid,
-- tready_out => s_axistream.tready,
-- tdata_in => m_axistream.tdata,
-- tlast_in => m_axistream.tlast,
--tkeep_in => (others => '0'), -- Assuming tkeep is not used in the component
--tuser_in => (others => '0'), -- Assuming tuser is not used in the component
--tid_in => (others => '0'), -- Assuming tid is not used in the component
--tstrb_in => (others => '0'), -- Assuming tstrb is not used in the component
--t_dest_in => (others => '0'), -- Assuming t_dest is not used in the component
-- tvalid_out => s_axistream.tvalid,
-- tready_in => m_axistream.tready,
-- tdata_out => s_axistream.tdata,
-- tlast_out => s_axistream.tlast
--tkeep_out => s_axistream.tkeep-- Assuming tkeep is not used in the component
--);
-- Drive tready
--m_axistream.tready <= '1';
stimuli : process
constant C_SCOPE : string := "STIMULI Process";
begin
-- reset
rst_n <='0';
wait for 10 ns;
rst_n <= '1';
-- Log setup
enable_log_msg(ALL_MESSAGES, "Logging all Messages", NON_QUIET, C_SCOPE);
log(ID_LOG_HDR, "SIMULATION START", C_SCOPE);
-- Send data over AXI4-Stream
axistream_transmit(tdata_array, "Send AXI4-Stream data", clk, m_axistream, C_SCOPE, msg_id_panel, C_AXISTREAM_BFM_CONFIG_DEFAULT);
wait for 50 ns;
-- End of simulation
report_alert_counters(FINAL);
log(ID_LOG_HDR, "SIMULATION END", C_SCOPE);
std.env.stop;
wait;
end process stimuli;
check_data : process
constant C_SCOPE : string := "CHECK PROCESS";
begin
-- Check data over AXI4-Stream
axistream_expect( tdata_expected_array, "Check AXI4-Stream data", clk, s_axistream,
WARNING, C_SCOPE, msg_id_panel, C_AXISTREAM_SLAVE_BFM_CONFIG_DEFAULT);
log(ID_LOG_HDR, "AXI4-Stream Data checked", C_SCOPE);
wait;
end process check_data;
end architecture behavioral;
When I do the simulation I end up with this signal:
You can see I am missing some data in the reception part and I don't know why. I read that is it recommended to use a buffer sometimes, but it seems a little bit complex and I want to be sure that it's not something else before doing that.
Can someone help me? I have been working on this for a very long time now and I did not find anything else on the internet than "use the vivavado axistream so you have nothing to do".