Module fifo

This document contains technical documentation for the fifo module.

asynchronous_fifo.vhd

View source code on gitlab.com.

component asynchronous_fifo is
  generic (
    width : positive;
    depth : positive;
    -- Changing these levels from default value will increase logic footprint
    almost_full_level : natural range 0 to depth;
    almost_empty_level : natural range 0 to depth;
    -- Set to true in order to use 'read_last' and 'write_last'
    enable_last : boolean;
    -- If enabled, 'read_valid' will not be asserted until a full packet is available in
    -- FIFO. I.e. when 'write_last' has been received.
    enable_packet_mode : boolean;
    -- Set to true in order to use the 'drop_packet' port. Must set 'enable_packet_mode' as
    -- well to use this.
    enable_drop_packet : boolean;
    -- Use an extra output register. This will be integrated in the memory if block RAM is used.
    -- Increases latency but improves timing.
    -- When enabled, the output register is included in the 'depth',
    -- meaning that the RAM depth is 'depth - 1'.
    enable_output_register : boolean;
    -- Select what FPGA primitives will be used to implement the FIFO memory.
    ram_type : ram_style_t
  );
  port (
    -- Read data interface
    clk_read : in std_ulogic;
    read_ready : in  std_ulogic;
    -- '1' if FIFO is not empty
    read_valid : out std_ulogic;
    read_data : out std_ulogic_vector;
    -- Must set 'enable_last' generic in order to use this
    read_last : out std_ulogic;

    -- Status signals on the read side. Updated one clock cycle after read transactions.
    -- Updated "a while" after write transactions .
    --
    -- Note that this port will be CONSTANTLY ZERO if the 'enable_packet_mode' generic is set
    -- to true. This is since a glitch-free value can not be guaranteed in this mode.
    read_level : out natural range 0 to depth;
    -- '1' if there are 'almost_empty_level' or fewer words available to read.
    --
    -- Note that this port will be CONSTANTLY ONE if the 'enable_packet_mode' generic is set
    -- to true, and 'almost_empty_level' has a non-default value.
    -- This is since a glitch-free value of 'read_level' can not be guaranteed in this mode.
    read_almost_empty : out std_ulogic;

    --# {{}}
    -- Write data interface
    clk_write : in std_ulogic;
    -- '1' if FIFO is not full
    write_ready : out std_ulogic;
    write_valid : in  std_ulogic;
    write_data  : in  std_ulogic_vector;
    -- Must set 'enable_last' generic in order to use this
    write_last : in std_ulogic;

    -- Status signals on the write side. Updated one clock cycle after write transactions.
    -- Updated "a while" after read transactions .
    -- In case the enable_output_register is set, this value will never go below 1
    write_level : out natural range 0 to depth;
    -- '1' if there are 'almost_full_level' or more words available in the FIFO
    write_almost_full : out std_ulogic;

    -- Drop the current packet .
    -- Must set 'enable_drop_packet' generic in order to use this.
    drop_packet : in std_ulogic
  );
end component;

Asynchronous (two clocks) First In First Out (FIFO) data buffering stage with AXI-Stream-like handshaking interface. Supports last, packet mode and drop_packet just like the synchronous FIFO. The implementation is quite optimized with very low resource utilization when extra features are not enabled.

Note

This entity has a scoped constraint file that must be used. It further instantiates resync_counter.vhd which also has a constraint file.

Warning

In case enable_output_register is set, the implementation does not keep track of the exact level on the write side. When there is no word in the output register, e.g when the FIFO is empty, the write_level reported will be one higher than the real level.

Resource utilization

This entity has netlist builds set up with automatic size checkers in module_fifo.py. The following table lists the resource utilization for the entity, depending on generic configuration.

Resource utilization for asynchronous_fifo.vhd netlist builds.

Generics

Total LUTs

FFs

RAMB36

RAMB18

Maximum logic level

use_asynchronous_fifo = True

width = 16

depth = 8

enable_output_register = False

(Using wrapper

fifo_netlist_build_wrapper.vhd)

35

50

0

0

4

use_asynchronous_fifo = True

width = 32

depth = 1024

enable_output_register = False

(Using wrapper

fifo_netlist_build_wrapper.vhd)

44

90

1

0

6

use_asynchronous_fifo = True

width = 32

depth = 1025

enable_output_register = True

(Using wrapper

fifo_netlist_build_wrapper.vhd)

45

91

1

0

6

width = 32

depth = 1024

almost_full_level = 800

68

112

1

0

6

width = 32

depth = 1024

almost_full_level = 800

enable_last = True

68

112

1

0

6

width = 32

depth = 1024

almost_full_level = 800

enable_last = True

enable_packet_mode = True

60

123

1

0

6

width = 32

depth = 1025

almost_full_level = 800

enable_last = True

enable_packet_mode = True

enable_output_register = True

76

135

1

0

8

width = 32

depth = 1024

almost_full_level = 800

enable_last = True

enable_packet_mode = True

enable_output_register = False

enable_drop_packet = True

66

134

1

0

6

fifo.vhd

View source code on gitlab.com.

component fifo is
  generic (
    width : positive;
    depth : positive;
    -- Changing these levels from default value will increase logic footprint
    almost_full_level : natural range 0 to depth;
    almost_empty_level : natural range 0 to depth;
    -- Set to true in order to use 'read_last' and 'write_last'
    enable_last : boolean;
    -- If enabled, 'read_valid' will not be asserted until a full packet is available in
    -- FIFO. I.e. when 'write_last' has been received. Must set 'enable_last' as well to use this.
    enable_packet_mode : boolean;
    -- Set to true in order to use the 'drop_packet' port. Must set 'enable_packet_mode' as
    -- well to use this.
    enable_drop_packet : boolean;
    -- Set to true in order to read words without popping from FIFO using the 'read_peek_mode' port.
    -- Must set 'enable_packet_mode' as well to use this.
    -- Can not be used in conjunction with 'enable_output_register'.
    enable_peek_mode : boolean;
    -- Use an extra output register. This will be integrated in the memory if block RAM is used.
    -- Increases latency but improves timing on the data path.
    -- When enabled, the output register is included in the 'depth',
    -- meaning that the RAM depth is 'depth - 1'.
    -- The "peek read" mode can not be used when this is enabled.
    enable_output_register : boolean;
    -- Select what FPGA primitives will be used to implement the FIFO memory.
    ram_type : ram_style_t
  );
  port (
    clk : in std_ulogic;
    --# {{}}
    -- When 'packet_mode' is enabled, this value will still reflect the number of words that are in
    -- the FIFO RAM. This is not necessarily the same as the number of words that can be read, in
    -- this mode.
    level : out natural range 0 to depth;

    --# {{}}
    read_ready : in std_ulogic;
    -- '1' if FIFO is not empty
    read_valid : out std_ulogic;
    read_data : out std_ulogic_vector;
    -- Must set 'enable_last' generic in order to use this
    read_last : out std_ulogic;
    -- When this is asserted, packets can be read multiple times from the FIFO.
    -- Must set 'enable_peek_mode' generic in order to use this.
    read_peek_mode : in std_ulogic;
    -- '1' if there are 'almost_empty_level' or fewer words available to read
    almost_empty : out std_ulogic;

    --# {{}}
    -- '1' if FIFO is not full
    write_ready : out std_ulogic;
    write_valid : in std_ulogic;
    write_data : in std_ulogic_vector;
    -- Must set 'enable_last' generic in order to use this
    write_last : in std_ulogic;
    -- '1' if there are 'almost_full_level' or more words available in the FIFO
    almost_full : out std_ulogic;
    -- Drop the current packet .
    -- Must set 'enable_drop_packet' generic in order to use this.
    drop_packet : in std_ulogic
  );
end component;

Synchronous (one clock) First In First Out (FIFO) data buffering stage with AXI-Stream-like handshaking interface. This implementation is very versatile in terms of features that can be enabled. Despite this it is very optimized when used in its barebone configuration, and will result in a very small logic footprint.

Features that can be enabled:

  • If enable_last is set to true, the write_last signal will be concatenated with write_data and stored in RAM, and then passed on to read_last. Without this, read_last will have an undefined value and write_last will not be used.

  • FIFO packet mode is enabled by setting the generic enable_packet_mode to true. When this mode is enabled, read_valid will not be asserted until the whole “packet” has been written to FIFO, as indicated by write_valid and write_last.

  • The FIFO supports dropping packets that are in the progress of being written. If the enable_drop_packet generic is set to true, the drop_packet port can be used to drop the current packet, i.e. all words written since the last write_valid and write_last happened.

    The port can be asserted at any time, regardless of e.g. write_ready or write_valid.

  • Additionally there is a “peek read” mode available that is enabled by setting the enable_peek_mode generic to true. It makes it possible to read a packet multiple times. If the read_peek_mode signal is asserted when read_ready is asserted, the current packet will not be popped from the FIFO, but can instead be read again. Once the readout encounters read_last, the readout will return again to the first word of the packet. Note that the read_peek_mode value may not be changed during the readout of a packet. It must be static for all words in a packet, but may be updated after read_last.

  • There is an option to enable an output register using the enable_output_register generic. This can be used to improve timing since the routing delay on the data output of a block RAM is usually quite high. Most block RAM primitives have a “hard” output register that can be used. It has been verified (with Netlist builds in CI) that the implementation in this file will map to the hard output register in Xilinx 7-series devices, and hence not consume extra flip-flops.

    Note

    The “peek read” mode can not be used when output register is enabled.

Resource utilization

This entity has netlist builds set up with automatic size checkers in module_fifo.py. The following table lists the resource utilization for the entity, depending on generic configuration.

Resource utilization for fifo.vhd netlist builds.

Generics

Total LUTs

FFs

RAMB36

RAMB18

Maximum logic level

use_asynchronous_fifo = False

width = 32

depth = 1024

enable_output_register = False

(Using wrapper

fifo_netlist_build_wrapper.vhd)

14

24

1

0

6

use_asynchronous_fifo = False

width = 32

depth = 1025

enable_output_register = True

(Using wrapper

fifo_netlist_build_wrapper.vhd)

15

25

1

0

6

width = 32

depth = 1024

almost_full_level = 800

27

35

1

0

6

width = 32

depth = 1024

almost_full_level = 800

enable_last = True

27

35

1

0

6

width = 32

depth = 1024

almost_full_level = 800

enable_last = True

enable_packet_mode = True

40

47

1

0

6

width = 32

depth = 1025

almost_full_level = 800

enable_last = True

enable_packet_mode = True

enable_output_register = True

45

50

1

0

9

width = 32

depth = 1024

almost_full_level = 800

enable_last = True

enable_packet_mode = True

enable_output_register = False

enable_drop_packet = True

45

58

1

0

6

width = 32

depth = 1024

almost_full_level = 800

enable_last = True

enable_packet_mode = True

enable_output_register = False

enable_drop_packet = False

enable_peek_mode = True

58

58

1

0

6

use_asynchronous_fifo = False

width = 8

depth = 32

enable_last = True

enable_output_register = False

(Using wrapper

fifo_netlist_build_wrapper.vhd)

32

22

0

0

3

fifo_wrapper.vhd

View source code on gitlab.com.

component fifo_wrapper is
  generic (
    use_asynchronous_fifo : boolean;
    -- Generics for the FIFOs.
    -- Note that the default values are carefully chosen. Must be exactly the same as in fifo.vhd
    -- and asynchronous_fifo.vhd.
    width : positive;
    -- Set depth to 0 to not include any fifo at all
    depth : natural;
    almost_full_level : natural range 0 to depth;
    almost_empty_level : natural range 0 to depth;
    enable_last : boolean;
    enable_packet_mode : boolean;
    enable_drop_packet : boolean;
    enable_peek_mode : boolean;
    enable_output_register : boolean;
    ram_type : ram_style_t
  );
  port (
    -- This clock is used for a synchronous FIFO
    clk : in std_ulogic;
    -- These clocks are used for an asynchronous FIFO
    clk_read : in std_ulogic;
    clk_write : in std_ulogic;

    --# {{}}
    read_ready : in  std_ulogic;
    read_valid : out std_ulogic;
    read_data : out std_ulogic_vector;
    read_last : out std_ulogic;
    read_peek_mode : in std_ulogic;

    -- Note that this is the same as write_level for a synchronous FIFO.
    -- Note that this value is not assigned for an asynchronous FIFO in packet mode.
    read_level : out natural range 0 to depth;
    -- Note that for an asynchronous FIFO, this signal is in the "read" clock domain.
    almost_empty : out std_ulogic;

    --# {{}}
    write_ready : out std_ulogic;
    write_valid : in  std_ulogic;
    write_data : in  std_ulogic_vector;
    write_last : in std_ulogic;

    -- Note that this is the same as read_level for a synchronous FIFO.
    write_level : out natural range 0 to depth;
    -- Note that for an asynchronous FIFO, this signal is in the "write" clock domain.
    almost_full : out std_ulogic;

    -- Note that for an asynchronous FIFO, this signal is in the "write" clock domain
    drop_packet : in std_ulogic
  );
end component;

Wrapper that selects synchronous/asynchronous FIFO or passthrough depending on on generic values.