Module ring_buffer

This document contains technical documentation for the ring_buffer module. To browse the source code, visit the repository on GitHub.

ring_buffer_write_simple.vhd

View source code on GitHub.

component ring_buffer_write_simple is
  generic (
    address_width : positive;
    segment_length_bytes : positive;
    segments_per_packet : positive
  );
  port (
    clk : in std_ulogic;
    --# {{}}
    enable : in std_ulogic;
    --# {{}}
    buffer_start_address : in u_unsigned;
    buffer_end_address : in u_unsigned;
    buffer_written_address : out u_unsigned;
    buffer_read_address : in u_unsigned;
    --# {{}}
    segment_ready : in std_ulogic;
    segment_valid : out std_ulogic;
    segment_address : out u_unsigned;
    --# {{}}
    write_done : in std_ulogic;
    --# {{}}
    status : out ring_buffer_write_simple_status_t
  );
end component;

Simple implementation of the logic for a ring buffer or circular buffer. It is simple in the sense that address segments are always of the same length, which is defined at compile-time.

The entity is designed to be used with applications where the FPGA writes data to a memory buffer and a CPU progressively reads/consumes it. Even though the entity might have other use cases, the terminology and naming of things is based on this presumed use case.

Operation

The buffer_start_address, buffer_end_address and buffer_read_address must be set by the user before enabling the entity with the enable signal. Initially, the buffer_read_address should be set to the buffer_start_address. All these addresses need to be byte-aligned with the segment length, i.e. they must be integer multiples of segment_length_bytes.

Warning

Once the entity has been enabled, it does not support disabling, doing so would result in undefined behavior.

Once enabled, the entity will start providing segment addresses to the user on the segment interface. This is an AXI-Stream-like handshaking interface. Once a segment has been written, the segment_written signal must be pulsed by the user. The entity will then update the buffer_written_address accordingly. Once the CPU has updated buffer_read_address accordingly, the address of this segment can once again be provided on the segment interface.

Note

In order to distinguish between the full and empty states, this entity will never utilize 100% of the provided buffer space. There will always be one segment that is not used. In other words, there will never be more than (buffer_end_address - buffer_start_address) / segment_length_bytes - 1 segments outstanding.

Warning

This entity will fail if buffer_last_address is the very last address in the address space. (e.g. 0xFFFFFFFF). There is no check for this unlikely case.

Segment length vs packet length

The addresses served on the segment interface are always incremented by segment_length_bytes. And per default, the buffer_written_address is also incremented with segment_length_bytes every time the write_done signal is asserted. This is the default behavior that is suitable for most applications.

There is a use case, however, where buffer_written_address shall only be updated once a number of segments have been written. The typical use case is an application that writes a packet in multiple split bursts. It will probably pop a segment for each burst, but it wants to indicate towards the software that the packet is complete only after all bursts have been written.

In this case, the segments_per_packet generic shall be set to a value greater than one, and the write_done signal asserted only when the last segment of the packet has been written. buffer_written_address will then increment by segments_per_packet * segment_length_bytes.

Note

When this feature is enabled, all address provided to the core must be aligned with the packet length instead of the segment length.

Resource utilization

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

Resource utilization for ring_buffer_write_simple netlist builds.

Generics

Total LUTs

FFs

Maximum logic level

address_width = 29

segment_length_bytes = 64

94

52

12

ring_buffer_write_simple_pkg.vhd

View source code on GitHub.

Package with types and constants for ring_buffer_write_simple.vhd.