Introduction

The Xilinx® SDx tools, including the SDAccel™ environment, the SDSoC™ environment, and Vivado® HLS, provide an out-of-the-box experience for system programmers looking to partition elements of a software application to run in an FPGA-based hardware kernel, and having that hardware work seamlessly with the rest of the application running in a processor or embedded processor. The out-of-the-box experience will provide adequate results for many applications. However, you may also be the need to optimize the hardware logic to extract the best quality of results from the hardware partition; to improve the performance of the kernel, the data throughput, reduce the latency, or reduce the resources utilized by the kernel. In this case, certain attributes, directives, or pragmas, can be used to direct the compilation and synthesis of the hardware kernel, or to optimize the function of the data mover operating between the processor and the hardware logic.

This guide describes the different forms and types of pragmas available for use in the OpenCL™ C language, or in standard C/C++ language definitions of a system-level application in the SDx Development Environment.
  • OpenCL attributes are defined in the OpenCL language standard, and apply optimizations to the hardware kernel.
  • Xilinx provides additional OpenCL attributes that are named starting with "xcl_"
  • SDS pragmas are defined for use with C or C++ language, and apply to the interface, data mover, and hardware kernel in SDSoC design projects.
  • HLS pragmas are defined for use with C or C++ language and can be used in the SDx flow to apply optimizations to the hardware kernel in Vivado HLS.
  • Directives are Vivado HLS Tcl commands that can be applied to the hardware partition, like HLS pragmas, but are not discussed in any detail here. Refer to the Vivado Design Suite User Guide: High-Level Synthesis (UG902) for more information.

The goal of kernel optimization is to create processing logic that can consume all the data as soon as it arrives at the kernel interfaces. This is generally achieved by expanding the processing code to match the data path with techniques such as function pipelining, loop unrolling, array partitioning, dataflowing, etc. The attributes and pragmas described here are provided to assist your optimization effort.

You can apply optimization pragmas and attributes to the following objects and scopes:
  • Interfaces: When you apply pragmas to an interface, SDx applies the directive to the top-level function, because the top-level function is the scope that contains the interface.
  • Functions: When you apply pragmas to functions, SDx applies the directive to all objects within the scope of the function. The effect of any directive stops at the next level of function hierarchy. The only exception is a directive that supports or uses a recursive option, such as the PIPELINE pragmas that recursively unrolls all loops in the hierarchy.
  • Loops: When you apply pragmas to loops, SDx applies the directive to all objects within the scope of the loop. For example, if you apply a LOOP_MERGE directive to a loop, SDx applies the pragmas to any sub-loops within the loop but not to the loop itself.
  • Arrays: When you apply pragmas to arrays, SDx applies the directive to the scope that contains the array.
  • Regions: When you apply pragmas to regions, SDx applies the directive to the entire scope of the region. A region is any area enclosed within two braces. For example:
    {
    the scope between these braces is a region
    }
    TIP: You can apply optimizations to a region in the same way you apply them to functions and loops.
  • You can label loops and regions to make it easier to identify them in your code, and to assign pragmas to the code. The following shows examples of labeled and unlabeled loops and regions:
    // Example of a loop with a label
    My_For_Loop:for(i=0; i<3;i++ {
    printf(“This loop has the label My_For_Loop \n”);
    }
    
    // Example of an region with no label
    {
    printf(“The scope between these braces has NO label”);
    }
    
    // Example of a NAMED region
    My_Region:{
    printf(“The scope between these braces HAS the label My_Region”);
    }
  • When specifying values for arguments of attributes or pragmas, you can use literal values (e.g. 1, 55, 3.14), or pass a macro using #define. The following example shows an attribute and pragma with literal values:

    __attribute__((xcl_array_partition(cyclic,5,1)));
    
    #pragma HLS ARRAY_PARTITION variable = k_matrix_val  cyclic   factor=5
    

    This example uses defined macros:

    #define E 5
    #pragma HLS ARRAY_PARTITION variable = k_matrix_val  cyclic   factor=E
    
    __attribute__((xcl_array_partition(cyclic,E,1)));
    
    IMPORTANT!: For both attributes and pragmas, do not use declared constants to specify values as they are not supported.