Forum Discussion
Altera_Forum
Honored Contributor
9 years agoDual Clock FIFO Implementation VHDL
Hi,
I'm pretty newto VHDL and I'm trying to implement a Dual Clock Synchronous FIFO but I'm getting loads of error mainly things like:- Error (10822): HDL error at FIFO.vhd(57): couldn't implement registers for assignments on this clock edge
- Error (10820): Netlist error at FIFO.vhd(85): can't infer register for fifo_proc:Head
- Error (10821): HDL error at FIFO.vhd(86): can't infer register for "fifo_proc:Head
library IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
entity FIFO is
Generic (
constant DATA_WIDTH : positive := 8;
constant FIFO_DEPTH : positive := 256
);
Port (
-- CLK : in STD_LOGIC;
WriteCLK : in STD_LOGIC;
ReadCLK : in STD_LOGIC;
RST : in STD_LOGIC;
WriteEn : in STD_LOGIC;
DataIn : in STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
ReadEn : in STD_LOGIC;
DataOut : out STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
Empty : out STD_LOGIC;
Full : out STD_LOGIC
);
end FIFO;
architecture Behavioral of FIFO is
begin
-- Memory Pointer Process
fifo_proc : process (WriteCLK, ReadCLK, RST, ReadEn, WriteEn)
type FIFO_Memory is array (0 to FIFO_DEPTH - 1) of STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
variable Memory : FIFO_Memory;
variable Head : natural range 0 to FIFO_DEPTH - 1;
variable Tail : natural range 0 to FIFO_DEPTH - 1;
variable Looped : boolean;
--Read_proc : process(ReadCLK)
begin
--Reset device on ReadCLK only
if rising_edge(ReadCLK) then
if RST = '1' then
Head := 0;
Tail := 0;
Looped := false;
Full <= '0';
Empty <= '1';
elsif ReadEn = '1' then
--Read Functionality
--if (ReadEn = '1') then
if ((Looped = true) or (Head /= Tail)) then
-- Update data output
DataOut <= Memory(Tail);
-- Update Tail pointer as needed
if (Tail = FIFO_DEPTH - 1) then
Tail := 0;
Looped := false;
else
Tail := Tail + 1;
end if;
end if;
end if;
end if;
if rising_edge(WriteCLK) then
if (WriteEn = '1') then
if ((Looped = false) or (Head /= Tail)) then
-- Write Data to Memory
Memory(Head) := DataIn;
-- Increment Head pointer as needed
if (Head = FIFO_DEPTH - 1) then
Head := 0;
Looped := true;
else
Head := Head + 1;
end if;
end if;
end if;
end if;
-- Update Empty and Full flags
if (Head = Tail) then
if Looped then
Full <= '1';
else
Empty <= '1';
end if;
else
Empty <= '0';
Full <= '0';
end if;
end process;
end Behavioral;
4 Replies
- Altera_Forum
Honored Contributor
This looks very much like a software approach to digital electronics - it will not work. You cannot have a register that is clocked from two clocks in FPGAs. And reading registers in one clock domain that is registered in another clock domain is very poor practice unless you're doing safe clock domain crossing.
Altera already provides a dual clock FIFO for free - check out the IP catalog. - Altera_Forum
Honored Contributor
Hi,
there are a lot of peculiarities about your code; nothing out of the common when you say you're new with VHDL, though. The following changes are recommended, some even necessary:- use signals instead of variables
- make sure each signal is only accessed by a single clock
- only use one clock/reset-sensitive IF per process
This is the pattern that you will find almost anywhere, and everybody familiar with VHDL will understand it. Multiple clocks per process just lead to confusion. Also, the sensitivity list of your process is wrong. It should contain the reset and the clock, and only those. Your code won't simulate correctly. Finally, since you're going to implement a dual-clock FIFO, you need to learn about synchronization between crossing clock domains. I can't see any. Such FIFOs are typically built with gray counters, to avoid problems, and proper synchronization is a must. Just google about "VHDL clock domain crossing". Or just google for dual clock FIFOs and see how they do it. Without that understanding, your FIFO will work perfectly in simulation, and most of the time perfectly in reality, but sometimes just mess up your data. Best regards, GooGooClusterprocess(rst, clk) is begin if(rst = '1') then -- reset code elsif(rising_edge(clk)) then -- synchronous code end if; end process; - Altera_Forum
Honored Contributor
--- Quote Start --- I'm not 100% sure, but I think variables don't map to physical wires or registers, but I could be wrong (I never use variables for the purpose you use it for). Use a variable as a "helper" only, not for things that must be remembered between clocks. All of your variables should map to signals. --- Quote End --- Variables can map to anything that signals can map to. But it can be less obvious what that may be. Hence why it is highly recommended that you use signals for everything. There is nothing you cant do with a signal (for logic implementation). - Altera_Forum
Honored Contributor
Thanks for the information guys, sorry for the late reply.
All of this is very useful, I'll see what I can do with it.