Using FIR Function with Streaming Interface - 2023.2 English

Vitis High-Level Synthesis User Guide (UG1399)

Document ID
UG1399
Release Date
2023-12-18
Version
2023.2 English

The run() function with streaming interfaces and without config input is defined in the HLS namespace similar to this:

 void run(
 hls::stream<in_data_t> &in_V,
 hls::stream<out_data_t> &out_V);

With config input, it is defined similar to this:

 void run(
 hls::stream<in_data_t> &in_V,
 hls::stream<out_data_t> &out_V,
 hls::stream<config_t> &config_V);

The FIR function is defined in the HLS namespace and can be called as follows:

// Create an instance of the FIR
static hls::FIR<STATIC_PARAM> fir1;
// Execute the FIR instance fir1
fir1.run(INPUT_DATA_STREAM, OUTPUT_DATA_STREAM);

The STATIC_PARAM is the static parameterization struct that defines most static parameters for the FIR. Both the input and output data are supplied to the function as hls::stream<>. These ports on the FIR IP will be implemented as AXI4-Stream ports.

AMD recommends always using the FIR function in a dataflow region using set_directive_dataflow or #pragma HLS dataflow.

Important: The FIR cannot be used in a region which is pipelined. If high-performance operation is required, pipeline the loops or functions before and after the FIR, and use the DATAFLOW pragma or directive on all loops and functions in the region, as shown in the exampe below.

The multichannel functionality of the FIR is supported through interleaving the data in a single input and single output stream.

  • The size of the input stream should be large enough to accommodate all samples: num_channels * input_length
  • The output stream size should be specified to contain all output samples: num_channels * output_length

The following code example demonstrates how the FIR IP function can be used.

template<typename data_t, int LENGTH>
void process_fe(data_t in[LENGTH], hls::stream<data_t> &out)
{
    for(unsigned i = 0; i < LENGTH; ++i)
        out.write(in[i]);
}

template<typename data_t, int LENGTH>
void process_be(hls::stream<data_t> &in, data_t out[LENGTH])
{
    for(unsigned i = 0; i < LENGTH; ++i)
        out[i] = in.read();
}

// TOP function
void fir_top(
    data_t in[FIR1_LENGTH],
    data_out_t out[FIR2_LENGTH])
{

    #pragma HLS dataflow

    hls::stream<data_t> fir1_in;
    hls::stream<data_intern_t> fir1_out;
    hls::stream<data_out_t> fir2_out;

    // Create FIR instance
    static hls::FIR<config1> fir1;
    static hls::FIR<config2> fir2;

    //==================================================
    // Dataflow process
    process_fe<data_t, FIR1_LENGTH>(in, fir1_in);
    fir1.run(fir1_in, fir1_out);
    fir2.run(fir1_out, fir2_out);
    process_be<data_out_t, FIR2_LENGTH>(fir2_out, out);
    //==================================================
}
Tip: To avoid bubbles in the execution of the FIR you need to ensure the FIFO depth is sufficient for the data throughput in the dataflow region using the config_dataflow -fifo_depth command, and might need to apply loop rewind to the loops in process_fe and process_be as described in the PIPELINE pragma or directive.