3.5.1.17.1 Streaming Library

The streaming library includes the FIFO (first-in first-out) data structure along with its associated API functions. The library can be compiled in software to run on the host machine (e.g., x86). Each FIFO instance in software is implemented as a First Word Fall Through (FWFT) FIFO in hardware.

The FIFO library is provided as a C++ template class. The FIFO data type can be flexibly defined and specified as a template argument of the FIFO object. For example, the FIFO data type could be defined as a struct containing multiple integers:

struct AxisWord { ap_uint<64> data; ap_uint<8> keep; ap_uint<1> last; };

hls::FIFO<AxisWord> my_axi_stream_interface_fifo;
Important: A valid data type could be any of the 1) C/C++ primitive integer types, 2) SmartHLS's 3.5.1.17.2 C++ Arbitrary Precision Data Types Library (ap_int, ap_uint, ap_fixpt, ap_ufixpt), or 3) a struct containing primitive integer types or SmartHLS's C++ arbitrary Precision Data Types. In the case of a struct type, it is prohibited to use 'ready' or 'valid' as the name of a struct field. This is because in the generated Verilog, a FIFO object will introduce an AXI-stream interface associated with valid/ready handshaking signals and the names will overlap.

You can use the C++ streaming library by including the header file:

#include "hls/streaming.hpp"
Important: Users should always use the APIs below to create and access FIFOs. Any other uses of FIFOs are not supported in SmartHLS.
Class MethodDescription
FIFO<T> ()Create a new FIFO.
FIFO<T> (unsigned depth)Create a new FIFO with the specified depth.
void write(T data)Write data to the FIFO.
T read()Read an element from the FIFO.
bool empty()Returns 1 if the FIFO is empty.
bool full()Returns 1 if the FIFO is full.
void setDepth(unsigned depth)Set the FIFO’s depth.
An example code for using the streaming library is shown below.
#include <hls/streaming.hpp>

void write(hls::FIFO<unsigned> *my_fifo, unsigned data) {
    // write to the fifo
    my_fifo->write(data);
}

void read_write(hls::FIFO<unsigned> *my_fifo, hls::FIFO<unsigned> *out_fifo) {
#pragma HLS function top
    // read from the fifo
    unsigned data = my_fifo->read();
    out_fifo->write(data);
}

int main() {
    // declare a 32-bit wide fifo
    hls::FIFO<unsigned> my_fifo;
    // set the fifo's depth to 10
    my_fifo.setDepth(10);

    // declare a 32-bit wide fifo with a depth of 10
    hls::FIFO<unsigned> my_fifo_depth_10(10);

    write(&my_fifo, 10);
    read_write(&my_fifo, &my_fifo_depth_10);

    // check if my_fifo is empty - should be empty since we read from it in
    // read_write (is_empty = 1)
    bool is_empty = my_fifo.empty();

    // check if my_fifo_depth_10 is empty - should not be empty since we write
    // to it in read_write (is_empty = 0)
    bool is_second_empty = my_fifo_depth_10.empty();

    // We will use the fail variable to check for any failures. fail will become
    // 1 if is_empty != 1 and is_second_empty != 0
    int fail = (is_empty == 1) ? ((is_second_empty == 0) ? 0 : 1) : 1;
    // If fail is 1, test will fail.

    return fail;
}

As shown above, there are two ways of creating a FIFO (hls::FIFO<unsigned> my_fifo and hls::FIFO<unsigned> my_fifo_depth_10(10)). The width of the FIFO is determined based on the templated data type of the FIFO. For example, FIFO<unsigned> my_fifo creates a FIFO that is 32 bits wide. The FIFO's data type can be any primitive type or arbitrary bitwidth types (ap_int/ap_uint/ap_fixpt/ap_ufixpt), or a struct of primitive/arbitrary bitwidth types (or nested structs of those types) but cannot be a pointer or an array (or a struct with a pointer/array). An array or a struct of FIFOs is supported.

The depth of the FIFO can be provided by the user as a constructor argument when the FIFO is declared, or it can also be set afterwards with the setDepth(unsigned depth) function. If the depth is not provided by the user, SmartHLS uses a default FIFO depth of 2. The depth of a FIFO can also be set to 0, in which case SmartHLS will create direct ready/valid/data wire connections (without a FIFO) between the source and the sink.