VHDL Code for FIFO: Syntax, Example, and Common Pitfalls
A FIFO in VHDL is a memory buffer that stores data in a first-in-first-out order using
signals and processes. It typically uses pointers for read and write operations and flags for full and empty states. You can implement it with a RAM array and control logic for enqueue and dequeue.Syntax
A FIFO in VHDL uses a RAM array to store data, read_ptr and write_ptr signals to track positions, and control signals like full and empty. The main parts are:
- RAM array: Holds the data elements.
- Write pointer: Points to where new data is stored.
- Read pointer: Points to where data is read from.
- Full and empty flags: Indicate FIFO status.
- Write enable and read enable: Control data input and output.
vhdl
type fifo_array is array (0 to FIFO_DEPTH-1) of std_logic_vector(DATA_WIDTH-1 downto 0); signal fifo_mem : fifo_array; signal write_ptr : integer range 0 to FIFO_DEPTH-1 := 0; signal read_ptr : integer range 0 to FIFO_DEPTH-1 := 0; signal full, empty : std_logic := '0';
Example
This example shows a simple synchronous FIFO with parameterized depth and data width. It supports write and read operations with full and empty flags.
vhdl
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity fifo is
generic (
DATA_WIDTH : integer := 8;
FIFO_DEPTH : integer := 16
);
port (
clk : in std_logic;
rst : in std_logic;
write_en : in std_logic;
read_en : in std_logic;
data_in : in std_logic_vector(DATA_WIDTH-1 downto 0);
data_out : out std_logic_vector(DATA_WIDTH-1 downto 0);
full : out std_logic;
empty : out std_logic
);
end fifo;
architecture rtl of fifo is
type fifo_array is array (0 to FIFO_DEPTH-1) of std_logic_vector(DATA_WIDTH-1 downto 0);
signal fifo_mem : fifo_array := (others => (others => '0'));
signal write_ptr : integer range 0 to FIFO_DEPTH-1 := 0;
signal read_ptr : integer range 0 to FIFO_DEPTH-1 := 0;
signal count : integer range 0 to FIFO_DEPTH := 0;
begin
process(clk, rst)
begin
if rst = '1' then
write_ptr <= 0;
read_ptr <= 0;
count <= 0;
data_out <= (others => '0');
elsif rising_edge(clk) then
-- Write operation
if write_en = '1' and count < FIFO_DEPTH then
fifo_mem(write_ptr) <= data_in;
write_ptr <= (write_ptr + 1) mod FIFO_DEPTH;
count <= count + 1;
end if;
-- Read operation
if read_en = '1' and count > 0 then
data_out <= fifo_mem(read_ptr);
read_ptr <= (read_ptr + 1) mod FIFO_DEPTH;
count <= count - 1;
end if;
end if;
end process;
full <= '1' when count = FIFO_DEPTH else '0';
empty <= '1' when count = 0 else '0';
end rtl;Output
No direct console output; the FIFO stores and outputs data on signals with full and empty flags indicating status.
Common Pitfalls
Common mistakes when coding a FIFO in VHDL include:
- Not handling the full and empty conditions properly, causing data overwrite or invalid reads.
- Incorrect pointer wrap-around logic, leading to out-of-range errors.
- Not synchronizing read and write operations on the clock edge.
- Forgetting to reset pointers and counters on reset.
Always use modulo arithmetic for pointers and check count limits before read/write.
vhdl
---- Wrong: No check for full before write if write_en = '1' then fifo_mem(write_ptr) <= data_in; write_ptr <= write_ptr + 1; -- No modulo, no full check end if; ---- Right: Check full and use modulo if write_en = '1' and count < FIFO_DEPTH then fifo_mem(write_ptr) <= data_in; write_ptr <= (write_ptr + 1) mod FIFO_DEPTH; count <= count + 1; end if;
Quick Reference
| Signal/Concept | Description |
|---|---|
| fifo_mem | Array storing FIFO data elements |
| write_ptr | Index where new data is written |
| read_ptr | Index where data is read from |
| count | Number of elements currently in FIFO |
| full | Flag indicating FIFO is full |
| empty | Flag indicating FIFO is empty |
| write_en | Signal to enable writing data |
| read_en | Signal to enable reading data |
Key Takeaways
Use pointers with modulo arithmetic to manage FIFO read and write positions safely.
Always check full and empty conditions before writing or reading to avoid data loss or invalid reads.
Reset pointers and counters properly to initialize the FIFO state.
Synchronize all operations on the clock edge for reliable behavior.
Use a counter to track the number of stored elements for easy full/empty detection.