As discussed in AI Engine Graphs, a graph is a connection of different compute kernel functions. Unlike when importing kernels, where a kernel function is imported as a block into Model Composer, in this case, graph code is imported as a block. To import the graph as block into Model Composer, you need to select the AI Engine graph block from the AI Engine library (shown in the following figure).
Model Composer allows to connect the AI Engine graph block with the AI Engine kernel block so that the whole design can be simulated in the Simulink environment.
To import the graph code, double-click the AIE Graph block. This opens the block parameters GUI from where you can specify the graph source file, search paths, and preprocessor options as shown in the following figure.
The following table provides further details including names and descriptions of each parameter.
Parameter Name | Parameter Type | Criticality | Description |
---|---|---|---|
Graph application file | String | Mandatory | Specify the file(.cpp), where the adf dataflow
graph is instantiated and connected to the simulation platform. This
file should contain the main() function from where the
dataflow graph initializes and runs. |
Graph search paths | Vector of strings | Mandatory | Specify search paths where header files, kernels, and other included files can be located and included for simulation. The search path $XILINX_VITIS/adf/include (where adf.h is defined) is be included by default and does not need to be specified. |
Preprocessor options | Optional | Optional preprocessor arguments for downstream compilation with
specific preprocessor options. The following preprocessor option formats
are accepted and multiple can be selected: -Dname and
-Dname=definition . That is, the optional argument
must begin with the -D string and if the option
definition value is not provided, it is assumed to be
1 . |
The following example shows the sample graph header file (graph.h) with class definitions and interconnections of different kernels.
graph.h
#ifndef _GRAPH_H
#define _GRAPH_H
#include <adf.h>
#include "kernels.h"
class mygraph : public adf::graph {
private:
adf::kernel k0;
adf::kernel k1;
adf::bypass b1;
adf::kernel k2;
public:
adf::port<input> datain[2];
adf::port<output> dataout[2];
adf::port<input> control;
mygraph() {
// Nodes
// Create kernel0
k0 = adf::kernel::create(kernel0);
adf::source(k0) = "kernel0.cc";
adf::runtime<ratio>(k0) = 0.9;
adf::location<adf::kernel>(k0) = adf::tile(0,0);
// Create kernel1
k1 = adf::kernel::create(kernel1);
adf::source(k1) = "kernel1.cc";
adf::runtime<ratio>(k1) = 0.9;
adf::location<adf::kernel>(k1) = adf::tile(1,0);
b1 = adf::bypass::create(k1);
// Create kernel2
k2 = adf::kernel::create(kernel2);
adf::source(k2) = "kernel2.cc";
adf::runtime<ratio>(k2) = 0.9;
adf::location<adf::kernel>(k2) = adf::tile(3,0); // Far away, so as to force ME-to-ME tile DMA.
// Edges
adf::connect< adf::parameter > (control, b1.bp);
adf::connect< adf::stream, adf::window<64,32> > (datain[0], k0.in[0]);
adf::connect< adf::stream, adf::window<256,128> > (datain[1], k0.in[1]);
adf::connect< adf::window<64> > (k0.out[0], b1.in[0]);
adf::connect< adf::window<256> > (k0.out[1], b1.in[1]);
adf::connect< adf::window<64> > (b1.out[0], k2.in[0]);
adf::connect< adf::window<256> > (b1.out[1], k2.in[1]);
adf::connect< adf::window<64>, adf::stream > (k2.out[0], dataout[0]);
adf::connect< adf::window<256>, adf::stream > (k2.out[1], dataout[1]);
};
};
#endif
The kernels and the function definitions are provided to the graph by the kernels.h file. A preview of that file is as follows.
kernels.h
#ifndef KERNEL_H
void kernel0(input_window_int32 * in0, input_window_int32 * in1, output_window_int32 * out0, output_window_int32 * out1);
void kernel1(input_window_int32 * in0, input_window_int32 * in1, output_window_int32 * out0, output_window_int32 * out1);
void kernel2(input_window_int32 * in0, input_window_int32 * in1, output_window_int32 * out0, output_window_int32 * out1);
#endif
The graph.cpp file is where the graph is connected to the simulation platform as follows. This file should be pointed to the Graph application file field in the Block parameters GUI.
#include "graph.h"
adf::simulation::platform<2,2> platform("data/input0.txt", "data/input1.txt", "data/output0.txt", "data/output1.txt");
mygraph g;
adf::connect<> i0(platform.src[0], g.datain[0]);
adf::connect<> i1(platform.src[1], g.datain[1]);
adf::connect<> o0(g.dataout[0], platform.sink[0]);
adf::connect<> o1(g.dataout[1], platform.sink[1]);
int main(int argc, char ** argv) {
int value;
g.init();
g.run();
value = 1;
g.update(g.control, value);
value = 0;
g.update(g.control, value);
value = 0;
g.update(g.control, value);
value = 1;
g.update(g.control, value);
g.end();
}
When the GUI parameters are updated, click the Import button. After a successful import, the tool generates the graph database and updates the AI Engine graph block with inputs and outputs. The GUI interface is as shown in the following figure.
After import, the Function tab GUI displays as shown in the following figure. This includes parameters such as Data Type and Size which are automatically captured from the graph code.
The user-editable function configuration parameters (Graph Port Name and Signal size) are described in the following table.
Use-Editable Parameter | Criticality | Description |
---|---|---|
Graph Port Name | Mandatory | Enter the port names for all interfaces as specified in the graph
header file (graph.h). Snippet of graph.h
|
Signal size | Mandatory | This parameter represents the size of the output signal and should be set to a value equal to or greater than the number of samples that are produced at every invocation of the kernel. |
In the General tab, the Import button changes to Update, enabling further update of block parameters.
- To connect an AI Engine graph
inout
port to an AI Engine graphinput
RTP port, the synchronocities of both ports must be compatible, otherwise, an appropriate error is reported by Model Composer. - If the RTP port's behavior is different from its default behavior, the
connection should appropriately specify it as an
async
orsync
port in graph code.