Kernel Coding Guidelines - 2021.1 English

Vitis Unified Software Platform Documentation: Application Acceleration Development (UG1393)

Document ID
UG1393
Release Date
2022-03-29
Version
2021.1 English

Never-ending kernels have the following coding requirements for top-level function arguments:

  • The kernel implements the ap_ctrl_chain block control protocol to enable the auto_restart bit.
  • The kernel supports AXI4-Stream interfaces (axis) and has no AXI4 memory mapped (m_axi) interface, and interacts with other kernels only through streams.

Modeling designs that use the streaming paradigm can be difficult in C. The approach of using pointers to perform multiple read and/or write accesses can introduce issues because there are implications for the type qualifier. Vitis HLS provides a C++ template class hls::stream<ap_axis<N>> for modeling streaming data structures. On the hardware, the hls::stream is implemented as an axis interface.

Vitis HLS implements the AXI4-Stream interface as a struct type with the following signature, as defined in ap_axi_sdata.h:
template <typename T, size_t WUser, size_t WId, size_t WDest> struct axis { .. };

Where:

  • T is the stream data type
  • WUser is the width of the TUSER signal
  • WId is the width of the TID signal
  • WDest is the width of the TDest signal

When the stream data type (T) are simple integer types, there are two predefined types of AXI4-Stream implementations available:

  1. A signed implementation of the AXI4-Stream class:
    hls::axis<ap_int<WData>, WUser, WId, WDest>
  2. An unsigned implementation:
    hls::axis<ap_uint<WData>, WUser, WId, WDest>

TVALID, TREADY, and TLAST are required control signals for the AXI4-Stream protocol. Side-channel signals TKEEP, TSTRB, TUSER, TID, and TDEST are special signals that can be used to pass around additional bookkeeping data. The values specified for the template parameters WUser, WId, and WDest define the use of side-channel signals in the interface as explained in AXI4-Stream Interfaces in the Vitis High-Level Synthesis User Guide (UG1399).

The following example shows a programming model for a data-driven, never-ending kernel using AXI4-Stream:

#include "ap_axi_sdata.h"
#include "hls_stream.h"
 
typedef ap_axis<32, 0, 0, 0> pkt;
 
extern "C" {
10 void krnl_stream_vdatamover(hls::stream<pkt> &in,
11 	hls::stream<pkt> &out  // Internal Stream
12 ) {
13 #pragma HLS interface ap_ctrl_chain port=return
14 bool eos = false;
15 vdatamover:
16   do {
17     // Reading a and b streaming into packets
18     pkt t1 = in.read();
19 
20     // Packet for output
21     pkt t_out;
22 
23     // Reading data from input packet
24     ap_uint<DWIDTH> in1 = t1.data;
25 
26     // Vadd operation
27     ap_uint<DWIDTH> tmpOut = in1;
28 
29     // Setting data and configuration to output packet
30     t_out.data = tmpOut;
31     t_out.last = t1.last;
32     t_out.keep = -1; // Enabling all bytes
33 
34     // Writing packet to output stream
35     out.write(t_out);
36 
37     if (t1.last) {
38 	 eos = true;
39     }
40   } while (eos == false);
Important: Never-ending kernels exhibit the behavior of having a while(1) loop around the kernel. Therefore, you should not explicitly specify a while(1) loop in your source code to prevent non-deterministic behavior.