Enhanced Programming Model - 2021.2 English

Versal ACAP AI Engine Programming Environment User Guide (UG1076)

Document ID
Release Date
2021.2 English

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
    /* declares kernels */
    kernel k1;
    kernel k2;
    /* declares input/output ports */
    input_port in0;
    input_port in1;
    output_port out0;
    output_port out1;

    /* declare graph constructor */
        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
        // Declare N kernels.
        kernel k[N];
        // Declare N input_gmio(s) and output_gmio(s)
        input_gmio gmioIn[N];
        output_gmio gmioOut[N];
            // 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

    /* 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;
        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 from PLIO class.
  • input_gmio, output_gmio classes are inherited from GMIO 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.
    1. GMIO shim tile location constraint with DMA channel is not supported.
    2. 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.