VHDL Code for Synchronous FIFO: Syntax, Example, and Tips
A
synchronous FIFO in VHDL uses a single clock for both read and write operations. It typically includes signals for data input/output, write/read enable, full/empty flags, and internal pointers. The FIFO stores data in a memory array and updates pointers synchronously on clock edges.Syntax
A synchronous FIFO in VHDL usually has these main parts:
- clk: The clock signal for synchronization.
- rst: Reset signal to initialize the FIFO.
- data_in: Input data bus.
- data_out: Output data bus.
- write_en: Write enable signal.
- read_en: Read enable signal.
- full: Flag indicating FIFO is full.
- empty: Flag indicating FIFO is empty.
- memory: Internal array to store data.
- write_ptr and read_ptr: Pointers to track write and read positions.
All read and write operations happen on the rising edge of clk.
vhdl
entity sync_fifo is
generic (
DATA_WIDTH : integer := 8;
FIFO_DEPTH : integer := 16
);
port (
clk : in std_logic;
rst : in std_logic;
data_in : in std_logic_vector(DATA_WIDTH-1 downto 0);
write_en : in std_logic;
read_en : in std_logic;
data_out : out std_logic_vector(DATA_WIDTH-1 downto 0);
full : out std_logic;
empty : out std_logic
);
end sync_fifo;Example
This example shows a complete synchronous FIFO with 8-bit data and 16-depth memory. It handles write and read operations on the clock's rising edge, updates full and empty flags, and outputs data accordingly.
vhdl
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity sync_fifo is
generic (
DATA_WIDTH : integer := 8;
FIFO_DEPTH : integer := 16
);
port (
clk : in std_logic;
rst : in std_logic;
data_in : in std_logic_vector(DATA_WIDTH-1 downto 0);
write_en : in std_logic;
read_en : in std_logic;
data_out : out std_logic_vector(DATA_WIDTH-1 downto 0);
full : out std_logic;
empty : out std_logic
);
end sync_fifo;
architecture Behavioral of sync_fifo is
function log2ceil(n : integer) return integer is
variable i : integer := 0;
variable v : integer := 1;
begin
while v < n loop
v := v * 2;
i := i + 1;
end loop;
return i;
end function;
type memory_array is array (0 to FIFO_DEPTH-1) of std_logic_vector(DATA_WIDTH-1 downto 0);
signal memory : memory_array := (others => (others => '0'));
signal write_ptr : unsigned(log2ceil(FIFO_DEPTH)-1 downto 0) := (others => '0');
signal read_ptr : unsigned(log2ceil(FIFO_DEPTH)-1 downto 0) := (others => '0');
signal count : unsigned(log2ceil(FIFO_DEPTH) downto 0) := (others => '0');
begin
process(clk, rst)
begin
if rst = '1' then
write_ptr <= (others => '0');
read_ptr <= (others => '0');
count <= (others => '0');
data_out <= (others => '0');
elsif rising_edge(clk) then
-- Write operation
if write_en = '1' and full = '0' then
memory(to_integer(write_ptr)) <= data_in;
write_ptr <= write_ptr + 1;
count <= count + 1;
end if;
-- Read operation
if read_en = '1' and empty = '0' then
data_out <= memory(to_integer(read_ptr));
read_ptr <= read_ptr + 1;
count <= count - 1;
elsif empty = '1' then
data_out <= (others => '0');
end if;
end if;
end process;
full <= '1' when count = to_unsigned(FIFO_DEPTH, count'length) else '0';
empty <= '1' when count = 0 else '0';
end Behavioral;Output
No console output; hardware signals update as expected: data_out outputs read data, full and empty flags indicate FIFO status.
Common Pitfalls
Common mistakes when writing synchronous FIFO code include:
- Not resetting pointers and counters properly on
rst. - Allowing write when FIFO is full or read when FIFO is empty, causing data corruption.
- Incorrect pointer increment or overflow handling.
- Not updating
fullandemptyflags correctly.
Always check conditions before read/write and reset all internal signals.
vhdl
wrong: process(clk)
begin
if rising_edge(clk) then
if write_en = '1' then -- No full check
memory(to_integer(write_ptr)) <= data_in;
write_ptr <= write_ptr + 1;
end if;
if read_en = '1' then -- No empty check
data_out <= memory(to_integer(read_ptr));
read_ptr <= read_ptr + 1;
end if;
end if;
end process;
right: process(clk)
begin
if rising_edge(clk) then
if write_en = '1' and full = '0' then
memory(to_integer(write_ptr)) <= data_in;
write_ptr <= write_ptr + 1;
end if;
if read_en = '1' and empty = '0' then
data_out <= memory(to_integer(read_ptr));
read_ptr <= read_ptr + 1;
end if;
end if;
end process;Quick Reference
Tips for writing synchronous FIFO in VHDL:
- Use a single clock for all operations.
- Reset pointers and counters on reset.
- Check
fullbefore writing andemptybefore reading. - Use unsigned arithmetic for pointers and counters.
- Update
fullandemptyflags based on count.
Key Takeaways
A synchronous FIFO uses one clock for both read and write operations to keep data in sync.
Always check full and empty flags before writing or reading to avoid data loss or corruption.
Reset all internal pointers and counters to known states on reset.
Use unsigned counters and pointers for easy arithmetic and boundary checks.
Update full and empty signals based on the count of stored elements.