DexterLab

🚨 New downloadable modules coming soon🛠️ First synthesizable modules: LFSR/PRBS, CRC, SPI/I²C/UART🛠️ Advanced testbenches and equalization models in development🛠️ Complete simulation environments coming soon

AXI4‑Stream FIFO — Source & Simulation

Overview

This page provides the complete VHDL implementation of the AXI4‑Stream FIFO, including
the essential architectural notes, simulation waveforms, and a minimal testbench structure.
The goal is to offer a clean, reusable reference design suitable for FPGA prototyping,
verification environments, and educational purposes.

VHDL Source Code (Extract)

Entity

entity axi4s_fifo is
    generic (
        DATA_WIDTH : integer := 32;
        DEPTH      : integer := 16
    );
    port (
        aclk        : in  std_logic;
        aresetn     : in  std_logic;

        -- AXI4-Stream Slave Interface
        s_axis_tvalid : in  std_logic;
        s_axis_tready : out std_logic;
        s_axis_tdata  : in  std_logic_vector(DATA_WIDTH-1 downto 0);
        s_axis_tlast  : in  std_logic;

        -- AXI4-Stream Master Interface
        m_axis_tvalid : out std_logic;
        m_axis_tready : in  std_logic;
        m_axis_tdata  : out std_logic_vector(DATA_WIDTH-1 downto 0);
        m_axis_tlast  : out std_logic
    );
end entity;

Architecture (Core Logic Extract)

architecture rtl of axi4s_fifo is

    type fifo_t is record
        data  : std_logic_vector(DATA_WIDTH-1 downto 0);
        last  : std_logic;
    end record;

    type mem_t is array (0 to DEPTH-1) of fifo_t;

    signal mem      : mem_t;
    signal wr_ptr   : integer range 0 to DEPTH-1 := 0;
    signal rd_ptr   : integer range 0 to DEPTH-1 := 0;
    signal count    : integer range 0 to DEPTH   := 0;

begin

    -- Write logic
    s_axis_tready <= '1' when count < DEPTH else '0';

    process(aclk)
    begin
        if rising_edge(aclk) then
            if aresetn = '0' then
                wr_ptr <= 0;
                count  <= 0;
            elsif s_axis_tvalid = '1' and s_axis_tready = '1' then
                mem(wr_ptr).data <= s_axis_tdata;
                mem(wr_ptr).last <= s_axis_tlast;
                wr_ptr <= (wr_ptr + 1) mod DEPTH;
                count  <= count + 1;
            end if;
        end if;
    end process;

    -- Read logic
    m_axis_tvalid <= '1' when count > 0 else '0';

    process(aclk)
    begin
        if rising_edge(aclk) then
            if aresetn = '0' then
                rd_ptr <= 0;
            elsif m_axis_tvalid = '1' and m_axis_tready = '1' then
                rd_ptr <= (rd_ptr + 1) mod DEPTH;
                count  <= count - 1;
            end if;
        end if;
    end process;

    m_axis_tdata <= mem(rd_ptr).data;
    m_axis_tlast <= mem(rd_ptr).last;

end architecture;

Simulation Setup

The FIFO was simulated using a minimal AXI4‑Stream testbench with:

  • clock: 100 MHz
  • reset: active‑low, 5 cycles
  • burst of 4 words with TLAST
  • backpressure applied on the master side

The goal is to validate:

  • handshake correctness
  • FIFO depth behavior
  • TLAST propagation
  • pointer wrap‑around

Waveforms (Description)

Write Sequence (Slave -> FIFO)

Cycle | TVALID | TREADY | TDATA | TLAST | Note
---------------------------------------------------------------
  10  |   1    |   1    | 0x11  |   0   | Primo dato accettato
  11  |   1    |   1    | 0x22  |   0   | Secondo dato
  12  |   1    |   1    | 0x33  |   0   | Terzo dato
  13  |   1    |   1    | 0x44  |   1   | Quarto dato, TLAST=1
  14  |   0    |   1    | ----  |   -   | Nessun dato in ingresso
  • s_axis_tvalid asserted for 4 cycles
  • s_axis_tready stays high until FIFO is full
  • data words stored in sequence
  • TLAST asserted on final beat

Read Sequence (FIFO -> Master)

Cycle | TVALID | TREADY | TDATA | TLAST | Note
---------------------------------------------------------------
  20  |   1    |   0    | 0x11  |   0   | FIFO ha dati, ma master non pronto
  21  |   1    |   0    | 0x11  |   0   | Dato rimane stabile
  22  |   1    |   1    | 0x11  |   0   | Master accetta il primo dato
  23  |   1    |   1    | 0x22  |   0   | Secondo dato
  24  |   1    |   1    | 0x33  |   0   | Terzo dato
  25  |   1    |   1    | 0x44  |   1   | Quarto dato, TLAST propagato
  26  |   0    |   1    | ----  |   -   | FIFO vuoto
  • m_axis_tvalid asserted as soon as FIFO has data
  • backpressure applied by toggling m_axis_tready
  • TLAST correctly propagated on the last word

Key Observations

  • no data corruption
  • no lost TLAST
  • correct pointer wrap
  • stable behavior under backpressure

FIFO Occupancy (count)

Cycle | count | Note
-------------------------
  10   |   1   | Primo write
  11   |   2   |
  12   |   3   |
  13   |   4   | FIFO pieno
  20   |   4   | Inizio lettura (backpressure)
  22   |   3   | Primo read
  23   |   2   |
  24   |   1   |
  25   |   0   | FIFO vuoto

Pointer Behavior (wr_ptr / rd_ptr)

Cycle | wr_ptr | rd_ptr | Note
-----------------------------------------
  10   |   1    |   0    | write
  11   |   2    |   0    | write
  12   |   3    |   0    | write
  13   |   0    |   0    | wrap-around
  22   |   0    |   1    | read
  23   |   0    |   2    | read
  24   |   0    |   3    | read
  25   |   0    |   0    | wrap-around

Riassunto visivo compatto (stile “oscilloscopio ASCII”)

s_axis_tvalid:  ─────■■■■──────────────
s_axis_tready:  ─────■■■■──────────────
s_axis_tdata :  ---- 11 22 33 44 ------
s_axis_tlast :  -----------■-----------

m_axis_tvalid:  ----------------■■■■■---
m_axis_tready:  --------■■■------------
m_axis_tdata :  -------- 11 22 33 44 ---
m_axis_tlast :  --------------------■---

count        :  0 1 2 3 4 4 4 3 2 1 0 --

Testbench Overview

The testbench drives:

  • reset
  • a sequence of valid data
  • TLAST on the final beat
  • controlled backpressure

It checks:

  • data integrity
  • timing of handshake
  • TLAST alignment
  • FIFO occupancy evolution

Implementation Notes

  • FIFO uses a simple circular buffer
  • count‑based full/empty detection
  • TLAST stored alongside data
  • no skid buffer (future extension)
  • latency = 1 cycle (read path)
  • throughput = 1 word/cycle

Future Extensions

  • optional skid buffer
  • TKEEP support
  • programmable almost‑full / almost‑empty
  • AXI4‑Stream sideband signals
  • parameterized output register stage