The AI Engine architecture uses streaming data extensively for communicating between two AI Engines, and for communicating between the AI Engine and the programmable logic (PL). This raises the potential for a resource deadlock when the data flow graph has reconvergent stream paths. If the pipeline depth of one path is longer than the other, the producer kernel can stall and might not be able to push data into the shorter path because of back pressure. At the same time, the consumer kernel is waiting to receive data on the longer path due to the lack of data. If the order of data production and consumption between two stream paths is different, a deadlock can happen even between two kernels that are directly connected with two stream paths.
Model Composer supports adding a FIFO_DEPTH between two AI Engine kernels or between an AI Engine and the programmable logic (PL) using the AIE Signal Spec
block and automatically generates the graph code with fifo_depth
constraint on a connection.
The AIE Signal Spec block specifies properties of a signal connecting AI Engines and PL kernels. When you double click the AIE Signal Spec block, notice that the block parameters consists of two tabs: Connection and PlatformI/O.
- Connection
- Use this tab to specify FIFO depth
- PlatformI/O
- Use this tab to specify platform I/O properties (for more details on this topic, refer to PLIO Attributes).
Consider the following example where the AIE Signal Spec blocks are connected in two stream paths between AI Engine kernel blocks.
The FIFO depth value is are specified as 0
by default and the corresponding information is reflected on the
block symbol. For example, if values 2
and 4
are specified as parameters of the two AIE Signal
Spec blocks, the GUI will update as shown in the following figures.
The stream FIFO values specified using the AIE Signal Spec block are
automatically updated in the generated graph code (graph.h) with fifo_depth
constraints as shown in the following code.
Snippet of graph.h
// create nets to specify connections
adf::connect< adf::stream > net0 (In1, AIE_Kernel.in[0]);
adf::connect< adf::stream > net1 (AIE_Kernel.out[0], AIE_Kernel1.in[0]);
adf::fifo_depth(net1) = 2;
adf::connect< adf::stream > net2 (AIE_Kernel.out[1], AIE_Kernel1.in[1]);
adf::fifo_depth(net2) = 4;
adf::connect< adf::stream > net3 (AIE_Kernel1.out[0], Out1);
Notice the two fifo_depth
constraints corresponding to the
two stream paths in the design. Using this fifo_depth
constraint on a connection is useful as it creates more
buffering in paths with back pressure, and hence avoids any deadlock.