Xilinx AXI Stream tutorial - Part 2

Hi again,

On the previous chapter of this tutorial we presented the AXI Streaming interface, its main signals and some of its applications.

Now let's go for the funnier stuff, that is, to actually make and test some VHDL code to implement our AXI master. We will proceed gradually, adding features as we go. At the end of this tutorial you will have code that:
  • Implements an AXI master with variable packet length
  • Flow control support (ready and valid)
  • Option for generation of several kinds of data patterns
  • Testbench to check that all features work OK
  • Include an instantiation of Xilinx's AXI Stream protocol checker IP to verify the correctness of our AXI master core.


So let's see the first version of an AXI master. In this version we will have fixed data length of the packet, and the data will be a progression of ascending numbers (the same counter that controls that the packet length is reached, is used to generate the packet data):



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
entity AXIStream_Master_v1 is
  port (      
    start          : in std_logic;                        -- Starts an axi_stream transaction

    -- axi stream ports
    m_axis_clk    : in  std_logic;
    m_axis_tvalid : out std_logic;
    m_axis_tdata : out std_logic_vector(31 downto 0);
    m_axis_tstrb : out std_logic_vector(3 downto 0);
    m_axis_tlast : out std_logic  
  );
end AXIStream_Master_v1;

architecture rtl of AXIStream_Master_v1 is
                              
  constant PACKET_LEN : natural :=  8;
  constant PACKET_W   : natural :=  4;
                                                                                   

  -- Define the states of state machine                                             
  type    state is (IDLE, SEND_STREAM);          

  signal  sm_state : state := IDLE;                                                   

  -- AXI Stream internal signals
  signal tvalid         : std_logic := '0';
  signal tlast         : std_logic := '0';   
  signal data           : unsigned(31 downto 0) := (others => '0');
  signal packet_len_cnt : unsigned(PACKET_W-1 downto 0)  := (others => '0');

begin
  -- I/O Connections assignments
  m_axis_tstrb   <= (others => '1');     -- byte enables always high
  m_axis_tvalid  <= tvalid;
  m_axis_tlast   <= tlast;
  data(PACKET_W-1 downto 0)  <= packet_len_cnt; 
  m_axis_tdata   <= std_logic_vector(data);
   
  -- Control state machine implementation                                               
  sm_pr : process(m_axis_clk)                                                                        
  begin                                                                                       
    if (rising_edge (m_axis_clk)) then                                                       
      case (sm_state) is                                                              
        when IDLE =>
          tvalid            <= '0';
          tlast             <= '0';
          packet_len_cnt    <= (others => '0');      
          
            -- start sending 
            if (start = '1') then
              sm_state <= SEND_STREAM;  
            end if;                                                                                                      
        when SEND_STREAM  =>   
          tvalid            <= '1';               
          packet_len_cnt    <= packet_len_cnt + 1;
          if (packet_len_cnt = PACKET_LEN-1 ) then
            tlast           <= '1';
            sm_state        <= IDLE;
          end if;                                                                                                        
        when others =>                                                                   
          sm_state <= IDLE;                                                                                                                                                       
      end case;                                                                             
    end if;                                                                                 
  end process sm_pr;                                                                                
end rtl;

The lines 32 to 37 assign the AXI Stream master signals to internal signals. At line 36 it can be seen that the data is assigned to the same counter that is used to check the packet length.

The AXI Master is implemented using a very simple state machine. Once a packet is being sent, its length is checked and if it is equal to the desired value, the S.M. returns to the IDLE state.


In the waveform we can see several packets, each one eight clocks length. We can see that once start is asserted, packets are sent non-stop. If start was a signal coming from a FIFO (FIFO not empty), this behavior could be wanted. However, in the next chapter we will also introduce a mechanism that asks for a control signal like start to go from low to high to generate a new packet.

We will also introduce several more features and enhancements.

As usual, the VHDL source and test-bench (including waveform files for Vivado) are available at Github

Comments

Popular posts from this blog

VHDL or Verilog?

FPGA internal tri-state buses

Pseudo random number generator Tutorial