In the Standard FIFO post I talked about how a traditional FIFO works and supplied code for one. In this post I will be describing a First Word Fall Through (FWFT) FIFO. The main difference between standard FIFOs and FWFT FIFOs are that, as the name describes, the first byte written into the FIFO immediately appears on the output (See image below). This allows the first byte to be read on the next clock cycle without having to strobe the read enable. Additionally you can read the byte and strobe the write enable high at the same time so the next byte will be available to read on the next clock cycle.
As with the standard FIFO the FWFT FIFO module below have two settings that can be configured to adjust the width and depth of the FIFO. The DATA_WIDTH variable adjusts the size of the DataIn and DataOut buses so that you can write different sizes of bytes if needed. The FIFO_DEPTH variable adjusts how big the internal memory of the FIFO is.
In order to write data into the FIFO first push the data onto the DataIn bus and then strobe the WriteEn input high for one clock cycle. This will write whatever is on DataIn into the FIFOs internal memory. If writing in bulk the WriteEn signal can be left high while changing the data on the DataIn bus each clock cycle. When the Full flag goes high, this means that the FIFO’s memory is full and will not accept any more writes until data is read using the ReadEn input. If data is written while the Full flag is high it will be ignored.
For a FWFT FIFO once the first byte is written into the FIFO it will immediately appear on the DataOut bus. Allowing you to read the first byte without pulsing the ReadEn signal first, this feature is the defining characteristic of a FWFT FIFO. Once a byte has been written into the FIFO the Empty flag will go low. To read the next byte from the FWFT FIFO strobe the ReadEn signal high for one clock cycle. If there is no more data to read from the FIFO the DataOut bus will become invalid data and the Empty flag will go high.
VHDL Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
library IEEE; use IEEE.STD_LOGIC_1164.ALL; USE IEEE.NUMERIC_STD.ALL; entity FWFT_FIFO is Generic ( constant DATA_WIDTH : positive := 8; constant FIFO_DEPTH : positive := 256 ); Port ( CLK : 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 FWFT_FIFO; architecture Behavioral of FWFT_FIFO is begin -- Memory Pointer Process fifo_proc : process (CLK) 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; begin if rising_edge(CLK) then if RST = '1' then Head := 0; Tail := 0; Looped := false; Full <= '0'; Empty <= '1'; else if (ReadEn = '1') then if ((Looped = true) or (Head /= Tail)) then -- 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; 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; -- Update data output DataOut <= Memory(Tail); -- 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 if; end if; end process; end Behavioral; |
Test bench
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.NUMERIC_STD.ALL; ENTITY TB_FWFT_FIFO IS END TB_FWFT_FIFO; ARCHITECTURE behavior OF TB_FWFT_FIFO IS -- Component Declaration for the Unit Under Test (UUT) component FWFT_FIFO Generic ( constant DATA_WIDTH : positive := 8; constant FIFO_DEPTH : positive := 16 ); port ( CLK : in std_logic; RST : in std_logic; DataIn : in std_logic_vector(7 downto 0); WriteEn : in std_logic; ReadEn : in std_logic; DataOut : out std_logic_vector(7 downto 0); Full : out std_logic; Empty : out std_logic ); end component; --Inputs signal CLK : std_logic := '0'; signal RST : std_logic := '0'; signal DataIn : std_logic_vector(7 downto 0) := (others => '0'); signal ReadEn : std_logic := '0'; signal WriteEn : std_logic := '0'; --Outputs signal DataOut : std_logic_vector(7 downto 0); signal Empty : std_logic; signal Full : std_logic; -- Clock period definitions constant CLK_period : time := 10 ns; BEGIN -- Instantiate the Unit Under Test (UUT) uut: FWFT_FIFO PORT MAP ( CLK => CLK, RST => RST, DataIn => DataIn, WriteEn => WriteEn, ReadEn => ReadEn, DataOut => DataOut, Full => Full, Empty => Empty ); -- Clock process definitions CLK_process :process begin CLK <= '0'; wait for CLK_period/2; CLK <= '1'; wait for CLK_period/2; end process; -- Reset process rst_proc : process begin wait for CLK_period * 5; RST <= '1'; wait for CLK_period * 5; RST <= '0'; wait; end process; -- Write process wr_proc : process variable counter : unsigned (7 downto 0) := (others => '0'); begin wait for CLK_period * 20; for i in 1 to 32 loop counter := counter + 1; DataIn <= std_logic_vector(counter); wait for CLK_period * 1; WriteEn <= '1'; wait for CLK_period * 1; WriteEn <= '0'; end loop; wait for clk_period * 20; for i in 1 to 32 loop counter := counter + 1; DataIn <= std_logic_vector(counter); wait for CLK_period * 1; WriteEn <= '1'; wait for CLK_period * 1; WriteEn <= '0'; end loop; wait; end process; -- Read process rd_proc : process begin wait for CLK_period * 20; wait for CLK_period * 40; ReadEn <= '1'; wait for CLK_period * 60; ReadEn <= '0'; wait for CLK_period * 256 * 2; ReadEn <= '1'; wait; end process; END; |
Very nice, short and sweet. I’ve coded my own before but I like yours better, mind if I put it in my design? It’s for my own personal use anyway!
Thanks
Feel free to use any code here as you wish, there is no copyright or restrictions.
Thank you! Very useful post!
Could you explain to me one thing:
when you code
“– Update data output
DataOut <= Memory(Tail);"
you put this in Rising_Edge(clk) section of the process. I see in simulate:
when I set readen signal to '1', the counter Tail has incremented on the rising clk, but why DataOut changes without rising clk on the next cycle of clk?
Also, in RTL we see FDE trigger after the memory – how does it works? I think, we need two clocks to change Tail counter and then to change DataOut memory.
Thanks a lot.
The head and tail are variables, which act more like software variables in that they are updated instantly so you don’t have to wait for the next clock edge. So when the data output is updated tail has already been updated by the read and write operations above.
In my design I need to have 2 different clocks, rd_clk and wr_clk to a FWFT FIFO with 8-bit bus_in bus_out . The wr_clk (18Mhz) is faster than rd_clk (16Mhz). I generated the Xilinx FIFO core but the read DataOut is missing bytes occasionally but persistently. Please give me any idea why the data is missing occasionally at the dout.
Read1stFIFOInst: entity work.ReadFIFOv4
port map (
rst => RAMRST,
wr_clk => Clk18MHz,
rd_clk => Clk16MHz,
wr_en => Write_En,
din => Write_Data,
rd_en => Read_Enable,
dout => Read_Data,
empty => Flag_Empty,
almost_full => open,
Prog_full => open,
full => Flag_Full );
Write_Enable < = Connection and not Flag_Full; — Connection always ='1'
Read_enable <= Connection and not Flag_Empty; — Connection always ='1'
Thanks very much
Reading does not have time to select data and part is lost, which follows from rd_clk less wr_clk.
Use the x16 data bus for reading.
Or use two FIFO x8, in the first FIFO write every odd clock wr_clk, in the second FIFO every even clock.
how will the valid be handled in FWFT FIFO.?
Hy there, Look what we arrange an eye to you! an enchantingprovide
Are you in?
https://drive.google.com/file/d/178b95HuevXj8TVpIGX8zACEtlw9FkMBL/preview
This is hilarious.
dus i spyk gud tu?
I just wanted to let you know that I reported your document to google for distribution of malware via google drive.
where I get the verilog code for this.
thank you!