Graphs with Libraries Components - 2023.2 English

AI Engine Kernel and Graph Programming Guide (UG1079)

Document ID
UG1079
Release Date
2023-12-04
Version
2023.2 English

The Vitis libraries targeting AI Engine are currently split into two levels:

Level 1
Basic kernels
Level 2
Graphs that use multiple Level 1 kernels with parameters specified through templates. The following examples contain PL data movers and host code that uses Level 2 functions in hardware.

This example is created with the DSP Library (DSPLib) containing two filters, with the first filter being built with five sections to fulfill the throughput of the overall system. The system settings are shown below:

#include <adf.h>
#include "fir_sr_sym_graph.hpp"
#include "fir_interpolate_hb_graph.hpp"

// Filter parameters
#define DATA_TYPE cint16
#define COEFF_TYPE int16

#define FIR_LEN_CHAN 151
#define SHIFT_CHAN 15
#define ROUND_MODE_CHAN 0
#define AIES_CHAN 5 

#define FIR_LEN_HB 43
#define SHIFT_HB 15
#define ROUND_MODE_HB 0

#define WINDOW_SIZE 1024

// Simulation parameters
#define NUM_ITER 8

The graph instantiating the filter sub-graph is shown below:

using namespace adf;
namespace dsplib = xf::dsp::aie;

class FirGraph: public graph
{
private:
  // Channel Filter coefficients
  std::vector<int16> chan_taps = std::vector<int16>{
  -17, -65, -35, 34, -13, -6, 18, -22,
  18, -8, -5, 18, -26, 26, -16, -1,
  21, -36, 40, -31, 8, 21, -46, 59,
  -53, 26, 13, -54, 81, -83, 56, -6,
  -54, 102, -122, 101, -43, -38, 116, -164,
  161, -102, 1, 114, -204, 235, -190, 74,
  83, -231, 319, -310, 193, 5, -229, 406,
  -468, 380, -147, -174, 487, -684, 680, -437,
  -10, 553, -1030, 1262, -1103, 474, 596, -1977,
  3451, -4759, 5660, 26983};

  // HalfBand Filter coefficients
  std::vector<int16> hb_taps = std::vector<int16>{
  23, -63, 143, -281, 503, -845, 1364, -2173,
  3557, -6568, 20729, 32767};
  
using channel = xf::dsp::aie::fir::sr_sym::
fir_sr_sym_graph<DATA_TYPE, COEFF_TYPE, FIR_LEN_CHAN, SHIFT_CHAN, ROUND_MODE_CHAN, WINDOW_SIZE, AIES_CHAN>;

using halfband = xf::dsp::aie::fir::interpolate_hb::
fir_interpolate_hb_graph<DATA_TYPE, COEFF_TYPE, FIR_LEN_HB, SHIFT_HB, ROUND_MODE_HB, WINDOW_SIZE>;

public:
  port<input> in;
  port<output> out;

  // Constructor - with FIR graph classes initialization
  FirGraph(){

    channel chan_FIR(chan_taps);
    halfband hb_FIR(hb_taps);

    // Margin gets automatically added within the FIR graph class.
    // Margin equals to FIR length rounded up to nearest multiple of 32 Bytes.
    connect(in, chan_FIR.in[0]);
    connect(chan_FIR.out[0], hb_FIR.in[0]);
    connect(hb_FIR.out[0], out);
  };
};

As usual the connections to the external world are specified in another graph to allow for more flexibility in this graph use:

class TopGraph : public graph
{
public:
  input_plio in;
  output_plio out;

  FirGraph F;

  TopGraph()
  {
    in = input_plio::create("128 bits read in",
    adf::plio_128_bits,"data/input_128b.txt", 250);
    out = output_plio::create("128 bits read out",
    adf::plio_128_bits,"data/output_128b.txt", 250);

    connect (in.out[0],F.in);
    connect (F.out, out.in[0]);
  };
};

And, finally the test bench used to launch the simulation is shown below:

TopGraph LibBasedGraph;

int main(void) {
  LibBasedGraph.init() ;
  LibBasedGraph.run(NUM_ITER) ;
  LibBasedGraph.end() ;
  return 0 ;
}

The graph view in the Vitis IDE is shown below:

Figure 1. DPSLib Graph View

As you can see chan_FIR is built on five kernels (AIES_CHAN = 5) which are grouped in a single graph, and hb_FIR is based on a single kernel in its own sub-graph.

Important: Kernels and sub-graphs must be part of the graph class. There is no support for conditional declaration or pointer-based declaration. In the same way input/output ports should be also member of the graph class.