- Muchas notas - Fran Acién

20220912 - AXI Stream port

On Vivado you can generate a module with axi stream port with Tools > Create and package an IP, or creating a VHDL file and add the axi interphase by putting the correct labels to the input and the outputs. It is necessary to have the inputs / outputs as signalname_tvalid, signalname_tdata, signalname_tready for the Vivado to interpret it as a Master/Slave AXI-Stream input or output.


Generic properties of a AXI module:

-- Parameters of Axi Slave Bus Interface S00_AXIS
C_S_AXIS_TDATA_WIDTH	: integer	:= 32;

-- Parameters of Axi Master Bus Interface M00_AXIS
C_M_AXIS_TDATA_WIDTH	: integer	:= 32;

Output Master Axis port:

aclk	: in std_logic;
m_axis_tvalid	: out std_logic;
m_axis_tdata	: out std_logic_vector(C_S_AXIS_TDATA_WIDTH-1 downto 0);
m_axis_tready	: in std_logic;

-- OPTIONAL
m_axis_aresetn	: in std_logic; -- Negative input
m_axis_tlast : out std_logic;

Slave Axis port:

aclk	: in std_logic;
s_axis_tready	: out std_logic;
s_axis_tdata	: in std_logic_vector(C_M_AXIS_TDATA_WIDTH-1 downto 0);
s_axis_tvalid	: in std_logic;

-- OPTIONAL
s_axis_aresetn	: in std_logic; -- Negative input
s_axis_tlast : in std_logic;

AXIS_CONFIG

This example send a signal to a axis interface

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity axis_config is
  generic (
    -- Parameters of Axi Master Bus Interface M00_AXIS
    C_M_AXIS_TDATA_WIDTH	: integer	:= 32;
    
    C_TDATA_VALUE : std_logic_vector(32-1 downto 0) := X"00000004" --! the Control Word to send
  );
  Port ( 
    m_axis_aclk	: in std_logic;
    m_axis_aresetn	: in std_logic;
    m_axis_tvalid	: out std_logic;
    m_axis_tdata	: out std_logic_vector(C_M_AXIS_TDATA_WIDTH-1 downto 0);
    m_axis_tready	: in std_logic
  );
end axis_config;

architecture Behavioral of axis_config is
  signal done : std_logic := '0'; --! 1 if config is configured, 0 otherwise
  signal m_axis_tvalid_reg : std_logic := '0';

begin
	m_axis_tdata <= C_TDATA_VALUE(C_M_AXIS_TDATA_WIDTH-1 downto 0);
  m_axis_tvalid <= m_axis_tvalid_reg;
  
  process(m_axis_aclk) begin
    if rising_edge(m_axis_aclk) then
      if m_axis_aresetn /= '1' then
        done <= '0';
        m_axis_tvalid_reg <= '0';
      elsif (done = '1') or ((m_axis_tready = '1') and (m_axis_tvalid_reg = '1')) then
        -- already done or just done right now
        done <= '1';
        m_axis_tvalid_reg <= '0';
      else
        m_axis_tvalid_reg <= '1';
        done <= '0';
      end if;
    end if;
  end process;
end Behavioral;

and the testbench:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity axis_config_tb is
end axis_config_tb;

architecture Behavioral of axis_config_tb is
	component axis_config port(
		m_axis_aclk	: in std_logic;
    m_axis_aresetn	: in std_logic;
    m_axis_tvalid	: out std_logic;
    m_axis_tdata	: out std_logic_vector;
    m_axis_tready	: in std_logic
	);
	end component;
	
	constant C_M_AXIS_TDATA_WIDTH	: integer	:= 32;
	
	-- input signals
	signal m_axis_aclk, m_axis_aresetn : std_logic := '1';
	signal m_axis_tready : std_logic := '0';
	
	-- output signals
	signal m_axis_tvalid : std_logic := '0';
	signal m_axis_tdata : std_logic_vector (C_M_AXIS_TDATA_WIDTH-1 downto 0);
	
	--Time interval between two test vectors
  constant clk_period : time := 10 ns;			-- Freq of 100 MHz
begin

	DUT: axis_config port map(
		m_axis_aclk => m_axis_aclk,
		m_axis_aresetn => m_axis_aresetn,
		m_axis_tvalid => m_axis_tvalid,
		m_axis_tdata => m_axis_tdata,
		m_axis_tready => m_axis_tready
	);
	
	m_axis_aclk <= NOT m_axis_aclk AFTER clk_period/2;
	
	process
	begin
		wait for clk_period;
		
		m_axis_aresetn <= '1';
		m_axis_tready <= '1';
		
		wait for clk_period;
		wait for clk_period;
		wait for clk_period;
		wait for clk_period;
	end process;	
	
end Behavioral;