XMC SUPPORTS_STREAMING - 2024.1 English

Vitis Model Composer User Guide (UG1483)

Document ID
UG1483
Release Date
2024-05-30
Version
2024.1 English

The Vitis Model Composer SUPPORTS_STREAMING pragma indicates that the array parameters of a function support streaming data. This means that each element of the array is accessed once in a strict sequential order and indicates to Model Composer to optimize the design for streaming data. There can be no random access to the non-scalar arguments of a function to which the SUPPORTS_STREAMING pragma is applied.

The following example illustrates the difference between random access and sequential access. The transform_matrix output array of the create_transform_matrix function is addressed in a random order. It accesses the last row of the transform_matrix first, followed by the first and second row. This prevents the block from supporting streaming data.

void create_transform_matrix(const float angle, const float center_x, 
                             const float center_y, float transform_matrix[3][3]) { 
    float a = hls::cosf(angle);
    float b = hls::sinf(angle);

    transform_matrix[2][0] = 0;
    transform_matrix[2][1] = 0;
    transform_matrix[2][2] = 0;
    
    transform_matrix[0][0] = a;
    transform_matrix[0][1] = b;
    transform_matrix[0][2] = (1-a)*center_x-b*center_y;
    
    transform_matrix[1][0] = -b;
    transform_matrix[1][1] = a;
    transform_matrix[1][2] = b*center_x +(1-a)*center_y;
}

To change this function to support streaming data, it can be modified as depicted below to address the transform_matrix output array in a sequential manner:

#pragma XMC SUPPORTS_STREAMING
void create_transform_matrix(const float angle, const float center_x, 
                             const float center_y, float transform_matrix[3][3]) { 
    float a = hls::cosf(angle);
    float b = hls::sinf(angle);
    
    transform_matrix[0][0] = a;
    transform_matrix[0][1] = b;
    transform_matrix[0][2] = (1-a)*center_x-b*center_y;
    
    transform_matrix[1][0] = -b;
    transform_matrix[1][1] = a;
    transform_matrix[1][2] = b*center_x +(1-a)*center_y;

    transform_matrix[2][0] = 0;
    transform_matrix[2][1] = 0;
    transform_matrix[2][2] = 0;
}
As shown in the preceding example, to specify that an imported function supports streaming, simply add the SUPPORTS_STREAMING pragma in the C or C++ header file before the function declaration:
#pragma XMC SUPPORTS_STREAMING

If the function has array arguments that are accessed sequentially, but SUPPORTS_STREAMING is not specified, then a subsystem using that block will not be implemented in a streaming architecture. This means the performance of the function will not be optimized.

Important: If your function accesses the array arguments in random order, you must not specify the SUPPORTS_STREAMING pragma or an error will be returned when generating output or verifying your design.
The following is an example of a function that accesses the array arguments in a strictly sequential order, supporting the streaming of data. This function flips the rows of an input image horizontally. The function accesses the input image in a sequential order and buffers two rows of the input image in a circular buffer. Once two full rows are buffered, the function writes the buffer content to the function argument in a sequential order. As such, this function supports streaming, and uses the SUPPORTS_STREAMING pragma to specify it.
#ifndef _MY_FUNCS
#define _MY_FUNCS
 
#include <stdint.h>
 
#pragma XMC INPORT in1
#pragma XMC OUTPORT out1
#pragma XMC SUPPORTS_STREAMING
#pragma XMC BUFFER_DEPTH 4+2*WIDTH
// This function reverses each of the rows of the input image.
template<int WIDTH, int HEIGHT>
void
flip(uint8_t in1[HEIGHT][WIDTH],
     uint8_t out1[HEIGHT][WIDTH])
{
#pragma HLS dataflow
 
   uint8_t buf[2][WIDTH];
 
   int readBuf = 0;
   int writeBuf = 0;
   for (int row = 0; row < HEIGHT + 2; ++row) {
      for (int col = 0; col < WIDTH; ++col) {
#pragma HLS DEPENDENCE array inter false
#pragma HLS PIPELINE II=1
         if (row < HEIGHT) {
            buf[writeBuf][col] = in1[row][col];
            if (col == WIDTH-1) {
               ++writeBuf;
               writeBuf = (3 == writeBuf) ? 0 : writeBuf;
            }
         }
         if (row > 1) {
            out1[row - 2][col] = buf[readBuf][WIDTH- 1 - col];
            if (col == WIDTH-1) {
               ++readBuf;
               readBuf = (3 == readBuf) ? 0 : readBuf;
            }
         }
      }
   }
}
#endif