A FIFO (First In First Out) is like a line where the first person to get in is the first to get out. A synchronous FIFO uses one clock to control both adding and removing data, making it simple and reliable.
Synchronous FIFO design in 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; 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 sync_fifo; architecture Behavioral of sync_fifo is type memory_array is array (0 to FIFO_DEPTH-1) of std_logic_vector(DATA_WIDTH-1 downto 0); signal mem : memory_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 if write_en = '1' and full = '0' then mem(write_ptr) <= data_in; write_ptr <= (write_ptr + 1) mod FIFO_DEPTH; count <= count + 1; end if; if read_en = '1' and empty = '0' then data_out <= 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 Behavioral;
The FIFO uses a circular buffer with read and write pointers.
Count keeps track of how many items are inside to detect full and empty states.
-- Case: FIFO is empty -- count = 0, empty = '1', full = '0' -- read_ptr = write_ptr = 0 -- No data to read
-- Case: FIFO has one element -- count = 1, empty = '0', full = '0' -- read_ptr and write_ptr differ by 1 -- You can read or write data
-- Case: FIFO is full -- count = FIFO_DEPTH, full = '1', empty = '0' -- write_ptr catches up to read_ptr -- No more writes allowed
This testbench creates a 4-bit wide, 4-depth synchronous FIFO. It writes 3 values, reads 2, writes 2 more, then reads all remaining values. The monitor prints FIFO status and output data on each clock.
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity testbench is end testbench; architecture Behavioral of testbench is constant DATA_WIDTH : integer := 4; constant FIFO_DEPTH : integer := 4; signal clk : std_logic := '0'; signal rst : std_logic := '1'; signal write_en : std_logic := '0'; signal read_en : std_logic := '0'; signal data_in : std_logic_vector(DATA_WIDTH-1 downto 0) := (others => '0'); signal data_out : std_logic_vector(DATA_WIDTH-1 downto 0); signal full : std_logic; signal empty : std_logic; component sync_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 component; begin uut: sync_fifo generic map(DATA_WIDTH => DATA_WIDTH, FIFO_DEPTH => FIFO_DEPTH) port map(clk => clk, rst => rst, write_en => write_en, read_en => read_en, data_in => data_in, data_out => data_out, full => full, empty => empty); clk_process : process begin while true loop clk <= '0'; wait for 5 ns; clk <= '1'; wait for 5 ns; end loop; end process; stim_proc: process begin rst <= '1'; wait for 20 ns; rst <= '0'; -- Write 3 values for i in 0 to 2 loop wait until rising_edge(clk); data_in <= std_logic_vector(to_unsigned(i+1, DATA_WIDTH)); write_en <= '1'; read_en <= '0'; wait until rising_edge(clk); write_en <= '0'; end loop; -- Read 2 values for i in 0 to 1 loop wait until rising_edge(clk); write_en <= '0'; read_en <= '1'; wait until rising_edge(clk); read_en <= '0'; end loop; -- Write 2 more values for i in 3 to 4 loop wait until rising_edge(clk); data_in <= std_logic_vector(to_unsigned(i+1, DATA_WIDTH)); write_en <= '1'; read_en <= '0'; wait until rising_edge(clk); write_en <= '0'; end loop; -- Read all remaining values while empty = '0' loop wait until rising_edge(clk); write_en <= '0'; read_en <= '1'; wait until rising_edge(clk); read_en <= '0'; end loop; wait; end process; monitor_proc: process(clk) begin if rising_edge(clk) then report "Full=" & std_logic'image(full) & " Empty=" & std_logic'image(empty) & " Data_out=" & integer'image(to_integer(unsigned(data_out))); end if; end process; end Behavioral;
Time complexity: O(1) for both write and read operations because pointers just move.
Space complexity: O(N) where N is FIFO_DEPTH, as memory stores all data.
Common mistake: Forgetting to check full before writing or empty before reading causes data loss or invalid reads.
Use synchronous FIFO when both sides share the same clock. For different clocks, use asynchronous FIFO.
A synchronous FIFO stores data in order using one clock.
It uses read and write pointers and a count to track fullness and emptiness.
Always check full before writing and empty before reading to avoid errors.
Practice
Solution
Step 1: Understand FIFO functionality
A FIFO (First-In-First-Out) stores data in the order it arrives.Step 2: Identify synchronous aspect
A synchronous FIFO uses one clock to control both read and write operations.Final Answer:
To store data in order using a single clock signal -> Option BQuick Check:
Synchronous FIFO = single clock storage [OK]
- Confusing synchronous with asynchronous FIFO
- Thinking FIFO generates clocks
- Mixing FIFO with analog-to-digital conversion
Solution
Step 1: Identify pointer representation
Write pointers are usually binary counters represented as vectors.Step 2: Choose appropriate type
std_logic_vector is used to represent binary numbers in VHDL.Final Answer:
std_logic_vector -> Option AQuick Check:
Write pointer = std_logic_vector [OK]
- Using integer which is less hardware-friendly
- Using boolean which can't count multiple bits
- Using real which is for floating-point numbers
Solution
Step 1: Check FIFO status
Count is 2, depth is 4, so FIFO is not full.Step 2: Write operation effect
Data writes at write pointer position 2, pointer increments to 3, count increments to 3.Final Answer:
Data is written at position 2, write pointer increments to 3, count becomes 3 -> Option DQuick Check:
Write enabled + not full = write and increment [OK]
- Writing at read pointer instead of write pointer
- Not incrementing count after write
- Assuming FIFO is full incorrectly
process(clk)
begin
if rising_edge(clk) then
if (write_enable = '1') and (not full) then
fifo_mem(write_ptr) <= data_in;
write_ptr <= write_ptr + 1;
count <= count + 1;
end if;
end if;
end process;
Solution
Step 1: Analyze pointer increment logic
write_ptr increments without wrapping back to zero at FIFO depth limit.Step 2: Understand FIFO pointer behavior
Write pointer must wrap around to zero after reaching max depth to avoid overflow.Final Answer:
write_ptr and count signals are not wrapped around FIFO depth -> Option AQuick Check:
Pointer wrap-around needed to avoid overflow [OK]
- Ignoring pointer wrap-around causing overflow
- Assuming reset is mandatory in this snippet
- Confusing sensitivity list with process behavior
Solution
Step 1: Determine pointer size
Depth 8 requires 3-bit pointers (since 2^3=8).Step 2: Understand full/empty detection without count
Full when write pointer is one less than read pointer (circular), empty when equal.Step 3: Evaluate options
Use 3-bit write and read pointers without count; check full when write_ptr + 1 = read_ptr and empty when write_ptr = read_ptr correctly uses 3-bit pointers without count and proper full/empty logic.Final Answer:
Use 3-bit write and read pointers without count; check full when write_ptr + 1 = read_ptr and empty when write_ptr = read_ptr -> Option CQuick Check:
Pointer wrap + compare = full/empty detection [OK]
- Using wrong pointer size for FIFO depth
- Confusing full and empty conditions
- Using count with incorrect max value
Ready to prove it?
Pass the test and this pattern moves unknown
