In the alternative programming model, simulation::platform is no longer required and global PLIO/GMIO objects construction are not needed.
An example of graph.h in the current programming model is as follows.
class simpleGraph : public graph
{
private
/* declares kernels */
kernel k1;
kernel k2;
public
/* declares input/output ports */
input_port in0;
input_port in1;
output_port out0;
output_port out1;
/* declare graph constructor */
simpleGraph()
{
k1 = kernel::create(kerne11);
k2 = kernel::create(kerne12);
connect< stream > (in0, k1.in[0]);
connect< stream > (k1.out[0], out0);
connect< stream > (in1, k2.in[0]);
connect< stream > (k2.out[0], out1);
}
};
An example of graph.cpp in the current programming model is as follows.
/* Instantiate GMIO/PLIO objects and links to logical names for design. */
GMIO *in0 = new GMIO("GMIO_In0", 64, 1);
GMIO *out0 = new GMIO)"GMIO_Out0", 64, 1);
PLIO *in1 = new PLIO("PLIO_In0", plio_32_bits, "data/input.txt", 250.0);
PLIO *out1 = new PLIO("PLIO_Out0", plio_32_bits, "data/output.txt", 250.0);
/* Instantiate mygraph object */
simpleGraph mygraph;
/* Link inputs/outputs to simulation::palatform */
simulation::platform<2, 2> platform(in0, in1, out0, out1);
connect<> net0(platform.src[0], mygraph.in0);
connect<> net1(platform.src[1], mygraph.in1);
connect<> net2(platform.sink[0], mygraph.out0);
connect<> net3(platform.sink[1], mygraph.out1);
The new alternative AI Engine programming model has the following advantages.
- It eliminates global PLIO/GMIO instances construction. In global scope, using
for-loop expression to create an array of PLIO/GMIO objects is not supported. This
makes implementing a design with large number of PLIO/GMIO objects error prone. For
example:
class mygraph : public graph { public: // Declare N kernels. kernel k[N]; // Declare N input_gmio(s) and output_gmio(s) input_gmio gmioIn[N]; output_gmio gmioOut[N]; mygraph() { // Create multiple input_gmio(s)/output_gmio(s) and connections for (int i=0; i<N; i++) { gmioIn[i] = input_gmio::create("gmioIn" + std::io_string(i), 64, 1); gmioOut[i] = output_gmio::create("gmioOut" + std::io_string(i), 64, 1); connect<window<128>>(gmio[i].out[0], k[i].in[0]); connect<window<128>>(k[i].out[0], gmioOut[i].in[0]); } } };
Note: It is not required to provide logical names when creating the GMIO/ PLIO objects. If the user chooses not to provide the logical name, AI Engine compiler will automatically come up with a unique logical name. - It provides ease of use for connections within the design. With PLIO/GMIO objects in local scope, connect<> calls are not required to provide a unique connection name. For example, in the previous graph.cpp example, net0, net1, net2, and net3 are no longer needed.
- It supports the direction property of PLIO/GMIO objects is determined within object construction. With simulation::platform in design, the direction property was determined by the position of the objects in simulation::platform<num_input, num_output) constructor parameters that is outside of the PLIO/GMIO constructor. For example, in the previous graph.cpp example, simulation::platform<m, n> indicates there are m inputs and n outputs.
An example of alternative programming model that addresses these previously listed enhancements is as follows.
/* A graph with both PLIO and GMIO*/
class mygraph : graph
{
public:
/* New classes support input_gmio/output_gmio and input_plio/output_plio */
input_gmio gm_in;
output_gmio gm_out;
input_plio pl_in;
output_plio pl_out;
kernel k1, k2;
mygraph()
{
k1 = kernel::create(...);
k2 = kernel::create(...);
/* create() API for PLIO and GMIO objects support same arguments specified as in global scope */
gm_in = input_gmio::create("GMIO_In0", /*const std::string& logical_name*/
64, /*size_t burst_length*/
1 /*size_t bandwidth*/);
gm_out = output_gmio::create("GMIO_Out0", 64, 1);
pl_in = input_plio::create("PLIO_In0", /* std::string logical_name */
plio_32_bits, /* enum plio_type plio_width */
"data/input.txt", /* std::string data_file */
250.0 /* double frequency */ );
pl_out = output_plio::create("PLIO_Out0", plio_32_bits, "data/output.txt", 250.0);
/* Each input_gmio/output_gmio and input_plio/output_plio supports 1 port per direction */
connect<>(gm_in.out[0], k1.in[0]);
connect<>(k1.out[0], gm_out.in[0]);
connect<>(pl_in.out[0], k2.in[0]);
connect<>(k2.out[0], pl_out.in[0]);
location<GMIO>(gm_in) = shim(col);
location<GMIO>(gm_out) = shim(col, ch_num); /* not supported */
location<PLIO>(pl_in) = shim(col);
location<PLIO>(pl_out) = shim(col, ch_num);
}
};
The previous code snippet demonstrates:
- PLIO/GMIO objects are no longer in global scope. They are public objects within the graph.
-
input_plio
,output_plio
classes are inherited fromPLIO
class. -
input_gmio
,output_gmio
classes are inherited fromGMIO
class. -
simulation::platform
is not required. - PLIO/GMIO object construction contains direction property. It is not
determined by the position of
simulation::platform
construction. -
connect
call does not require unique name. - Location constraints can be applied to PLIO/GMIO objects directly with the
exception of GMIO channel constraint which is not supported in this release.Note:
- GMIO shim tile location constraint with DMA channel is not supported.
- Host application calling profiling APIs need to update from referencing
global PLIO/GMIO variables,
in0
,out0
,in1
,out1
to referencing object’s public members,mygraph.gm_in
,mygraph.gm_out
,mygraph.pl_in
,mygraph.pl_out
. See Performance Analysis of AI Engine Graph Application during Simulation for additional details about profiling APIs.
An example of a profile call from the original programming model is as follows.
event::handle handle0 = event::start_profiling(*in0, event::io_stream_start_to_bytes_transferred_cycles, sizeIn*sizeof(cint16));
An example of a profile call from the alternative programming model is as follows.
event::handle handle0 = event::start_profiling(mygraph.gm_in, event::io_stream_start_to_bytes_transferred_cycles, sizeIn*sizeof(cint16));
Important: The PLIO/GMIO object creation
requires to have uniqueness throughout the AI Engine
design. The following error message indicates the violation of the PLIO/GMIO name
uniqueness.
ERROR: [aiecompiler 77-4551] The logical name DataIn1 of node i6 conflicts with the logical/qualified name of node i0.