Buffer Location Constraints - 2023.2 English

AI Engine Kernel and Graph Programming Guide (UG1079)

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

The AI Engine compiler tries to automatically allocate buffers for buffers, lookup tables, and run-time parameters in the most efficient manner possible. However, you might want to explicitly control their placement in memory. Similar to the kernels shown previously in this section, buffers inferred on a kernel port can also be constrained to be mapped to specific tiles, banks, or even address offsets using location constraints, as shown in the following example.

#include <adf.h>
#include "kernels.h"
#define NUMCORES (COLS*ROWS) 
using namespace adf;

template <int COLS, int ROWS, int STARTCOL, int STARTROW>
class indep_nodes_graph2 : public graph {
 public:
   kernel kr[NUMCORES];
   port<input> datain[NUMCORES] ;
   port<output> dataout[NUMCORES] ;
  
 indep_nodes_graph() {
  for (int i = 0; i < COLS; i++) {
    for (int j = 0; j < ROWS; j++) {
      int k = i*ROWS + j;
      kr[k] = kernel::create(mykernel);
      source(kr[k])  = "kernels/kernel.cc";
      runtime<ratio>(kr[k]) = 0.9;
      location<kernel>(kr[k]) = tile(STARTCOL+i, STARTROW+j); // kernel location
      location<buffer>(kr[k].in[0]) = 
        { address(STARTCOL+i, STARTROW+j, 0x0), 
          address(STARTCOL+i, STARTROW+j, 0x2000) };          // double buffer location
      location<stack>(kr[k]) = bank(STARTCOL+i, STARTROW+j, 2); // stack location
      location<buffer>(kr[k].out[0]) = location<kernel>(kr[k]); // relative buffer location
    }
  }

  for (int i = 0; i < NUMCORES; i++) {
    connect(datain[i], kr[i].in[0]);
    connect(kr[i].out[0], dataout[i]);
  }
 };
};

In the previous code, the location of double buffers at port kr[k].in[0] is constrained to the specific memory tile address offsets that are created using the address(col,row,offset) constructor. Furthermore, the location of the system memory (including the sync buffer, stack and static heap) for the processor that executes kernel instance kr[k] is constrained to a particular bank using the bank(col,row,bankid) constructor. Finally, the tile location of the buffers connected to the port kr[k].out[0] is constrained to be the same tile as that of the kernel instance kr[k]. Buffer location constraints are applied on kernel buffer ports.

The second example shows how a buffer constraint (for PING and PONG buffers) can be added to a constraints file, and the constraints file can be used by --constraints option for aiecompiler.
{
  "PortConstraints": {
    "gr.k[0].in[0]": {
      "buffers": [{
          "column": 16,
          "row": 1,
          "bankId": 0,
          "offset": 16320
        }, {
          "column": 16,
          "row": 1,
          "bankId": 3,
          "offset": 0
        }]
    }
  }
}
If there is an RTP port for a graph, there is an additional selector word that can be optionally constrained as follows (for PING, PONG and selector word):
{
  "PortConstraints": {
    "gr.fir24.in[1]": {
      "buffers": [{
          "column": 17,
          "row": 1,
          "bankId": 0,
          "offset": 16320
        }, {
          "column": 17,
          "row": 1,
          "bankId": 3,
          "offset": 0
        }, {
          "column": 18,
          "row": 1,
          "bankId": 0,
          "offset": 16224
        }]
    }
  }
}
Important: Using location constraint constructors and equality relations between them, you can make fine-grain mapping decisions that the compiler must honor. However, you must be careful because it is easy to create constraints that are impossible for the compiler to satisfy. For example, the compiler cannot allow two buffers to be mapped to the same address offset.