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