VHDL: Standard FIFO

FIFOs (First In, First Out) are essentially memory buffers used to temporarily store data until another process is ready to read it. As their name suggests the first byte written into a FIFO will be the first one to appear on the output. Typically FIFOs are used when you have two processes that operate and a different rate. A common example is a high speed communications channel that writes a burst of data into a FIFO and then a slower communications channel that read the data as need to send it at a slower rate.

The FIFO module below has 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 and 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 standard FIFO when you write the first byte into the FIFO nothing happens on the DataOut bus until the ReadEn signal is pulsed high for at-least one clock cycle to. Once a byte has been written into the FIFO the Empty flag will go low. To read the next byte from the FIFO strobe the ReadEn signal high for one clock cycle and the next byte of data will be available to read on the next clock cycle. When the last byte of data is pushed onto the DataOut bus the Empty flag will go high.


Test bench


63 thoughts on “VHDL: Standard FIFO

  1. Pingback: VHDL: First Word Fall Through FIFO | Death by Logic

  2. Thanks for putting this up. It looks like pretty good style.

    I ran your testbench and th results look right. I then tried compiling the design and comparing the logic utilization against the Xilinx Vivado IP Core Generator FIFO implementation.

    I want to use distributed memory so I added these lines to your code.

    attribute ram_style : string;
    attribute ram_style of Memory : variable is “distributed”;

    Here is the resulting utilization.
    | Site Type | Used | Fixed | Available | Util% |
    | Slice Registers | 65 | 0 | 65200 | 0.09 |
    | LUT as Logic | 88 | 0 | 32600 | 0.26 |
    | LUT as Memory | 128 | 0 | 9600 | 1.33 |

    For the same FIFO configuration from the Vivado Core generator.

    | Site Type | Used | Fixed | Available | Util% |
    | Slice Registers | 80 | 0 | 65200 | 0.12 |
    | LUT as Logic | 51 | 0 | 32600 | 0.15 |
    | LUT as Memory | 128 | 0 | 9600 | 1.33 |

    As you can see your design is very competitive. The extra registers can probably be address but heck this is great!

  3. I think there is an easier way to make the user flags (empty, full etc) for single clock domain FIFOs. Concatenate the write and read user ports and inc/dec a single counter so that 00=> null, 01 => +1, 10=> -1, 11=> null. You can add under/overrun qualifications on that case statement too. The advantage of this is that you have a single counter that holds the absolute count of FIFO entries so empty, full, half full, programmable pointers become really simple rather than comparing two pointers

  4. As the read and write counters are not going to change unless a read or write is performed (ignoring reset) does this not make the empty and full latches redundant and also create a delay of one clock cycle as the empty and full flags will not be latched until the next clock after the counters have been updated.

  5. So I just realized the variables will be evaluated at the start of the process not the end like the signals, still this would seem to lead to convoluted RTL logic 😉

  6. I tried your test bench in XILINX ISIM and it shows errors when checking behavioral syntax.
    The following errors are :
    ERROR:HDLCompiler:69 – “H:/project/buffer/TB_STD_FIFO.vhd” Line 116: is not declared.
    ERROR:HDLCompiler:622 – “H:/project/buffer/TB_STD_FIFO.vhd” Line 116: Near std_logic_vector ; type conversion expression type cannot be determined uniquely
    ERROR:HDLCompiler:854 – “H:/project/buffer/TB_STD_FIFO.vhd” Line 38: Unit ignored due to previous errors
    Please help me solve the errors

    • Heller,

      Sorry for the delayed response, I grabbed a copy of the code from the website and simulated it without any errors. I would first check that you copied everything correctly or go to my git-hub repo at https://github.com/DeathByLogic/HDL and download it straight from there. I say that because one of the errors refers to line 116 on TB_STD_FIFO, which is a blank line on the website version.

  7. DataIn : in STD_LOGIC_VECTOR (511 downto 0);
    DataOut : out STD_LOGIC_VECTOR (31 downto 0);

    I want to input to the fifo to be 512 bits wide and output to be 32 bits wide, can I just change the width of DataIn and DataOut accordingly? Will it still work?

    Will I need to change the value of Head or Tail?

    Thanks in Advance!

  8. hello thanks a lot daniel for your code.
    if i want to have a FIFO=32×1024 (32bit width and 1024bit depth) what to do?please help me.

  9. Thankyou for this code. It really helped me alot but i am a beginner and i am confused. Why are we using ‘looped’? Also if i want a FIFO of 24 bits what should be my counter value? I am sorry for asking such a basic question. Please dont get annoyed. 🙂

    • Asra, the looped variable keeps track if the tail is before the head. A good way to understand this to look at the Wikipedia article on FIFO at en.m.wikipedia.org/wiki/FIFO_(computing_and_electronics). If you want the input and output to be 24 bits then change the DATA_WIDTH variable to 24.
      P.S. No questing is a stupid questions, that is how you learn.

  10. Hi,
    My input data is data_in (7 downto 0) and my fifo depth is 8192.
    I need the data_out is continuously incrementing upto the depth value.
    This is both for write and read operation. What do i need to change?

  11. can u give me some example showing control delays and power consuned for asynchronus fifo imlementation in xilinx?

  12. can u give me some example showing control delays and power consuned for asynchronus fifo imlementation in xilinx?

    • Good question, I’ll have to look into it and get back to you. At a first glance you would have to separate the read and write into two different processes with the two different clocks. What I’m not sure how to handle is the updating of the full and empty flags.

  13. Pingback: PapilioでのRS232C通信4 – Crow's Laboratory

  14. I have little confusion about reading operation. I mean when we turn high the readen signal we will get data at same clock or next clock? For example I have to copy data from fifo so when i turn high the data at same time I mean next line of code should Icopy or wait for next clock and then copy

    • When you set the ReadEn high, the next rising edge of the clock will change the data on the output. You will not be able to do anything with that data until the next rising edge of the clock.

  15. Dave,

    Your code is poorly designed and is buggy.

    Poorly designed because it uses variables while it should use signals. Variables must not be used this way. Variables are useful for temporary computation/state inside a process. Using variables instead of signals may generate incredibly complex hidden logic.

    There is also a bug : When the FIFO is full and Tail = FIFO_DEPTH – 1, asserting WriteEn and ReadEn simultaneously shall output a data from the FIFO (read) but reject the write (FIFO is full). With your code, the write will be accepted while it should not.

  16. Hi how can I use this code to load data from a serial transmission and then read from FIFO elements one by one. And I have one more question how can i get only the first value stored in the FIFO. Please give me some advice am I struggling to do that but I didn’t managed to do it.
    Thanks! 🙂

  17. Hi, I’m having trouble designing a ffo. Please help me. Continue reading the description in reply. Thank you

  18. Hi, in your opinion can FIFO be very large? for instance, it should contain 39204 9-bit data. Is it too expensive for what concerns power consumption and velocity?

    • You can have a fifo that big, but it kind of defeats the purpose of a fifo. You will likely use up a lot or all of the resources on the fpga too implement such a big fifo. If you’re going to store that much information I would think about going to an external RAM.

    • When you write or read new data into the the FIFO, rather than shifting all of the date currently in the FIFO to shift it over one I used pointers to save the current position of the start and end of the FIFO. So if you think of the FIFO memory as a circle, as you write and read, where the FIFO data is stored in memory moves around the circle with the head and tail pointing to where the beginning and end is.

  19. hi,please I want to declare this two lines as signals how should I do?

    type FIFO_Memory is array (0 to FIFO_DEPTH – 1) of STD_LOGIC_VECTOR (DATA_WIDTH – 1 downto 0);
    variable Memory : FIFO_Memory;

  20. I tried using data_width in signal declarations of din and dout like below
    signal DataIn : std_logic_vector(data_width-1 downto 0) := (others => ‘0’);
    signal DataOut : std_logic_vector(data_width-1 downto 0);
    instead of
    signal DataIn : std_logic_vector(7 downto 0) := (others => ‘0’);
    signal DataOut : std_logic_vector(7 downto 0);

    In this case, I am getting an error stating that ” is not declared”.

    I don’t want to use direct values in my din and dout for data_width since width might change with the requirements and I want to change the value only in generics declaration not anywhere else. In this case what I should do?

    • If you’re using a constant, make sure it’s declared before you declare your signals. The best option would be to declare it as a generic, then it should be available anywhere in that module.

Leave a Reply to Daniel Cancel reply

Your email address will not be published. Required fields are marked *