Mapping Kernel Ports to Memory - 2024.2 English - UG1700

Data Center Acceleration Using Vitis User Guide (UG1700)

Document ID
UG1700
Release Date
2025-01-15
Version
2024.2 English

The link phase is when the memory ports of the kernels are connected to memory resources such as DDR, HBM, and PLRAM.

By default, all kernel memory interfaces are connected to the same global memory bank (or gmem). As a result, only one kernel interface can transfer data to or from the memory bank at one time, limiting the performance of the application due to memory access.

Because of this, it is important to explicitly specify which global memory bank each kernel argument (or interface) is connected to. Proper configuration of kernel to memory connectivity is important to maximize bandwidth, optimize data transfers, and improve overall performance. Even if there is only one compute unit in the device, mapping its input and output arguments to different global memory banks can improve performance by enabling simultaneous accesses to input and output data.

The following block diagram illustrates the Using Multiple DDR Banks example in Vitis Examples on GitHub. This example connects the input pointer interface of the kernel to DDR bank 0, and the output pointer interface to DDR bank 1.

Figure 1. Global Memory Two Banks Example
Important: Up to 15 separate kernel interfaces can be connected to a given global memory bank. Therefore, if there are more than 15 memory interfaces in the design you must explicitly perform the memory mapping as described here, using the --conectivity.sp option to distribute connections across different memory banks.

Start by assigning the kernel arguments to separate bundles to increase the available interface ports, then assign the arguments to separate memory banks. The following example uses the interfaces described in HW Interfaces in the Data Center Acceleration using Vitis (UG1700).

  1. In the C/C++ kernel code assign arguments to separate bundles using the INTERFACE pragma prior to compiling them:
    void cnn( int *pixel, // Input pixel
      int *weights, // Input Weight Matrix
      int *out, // Output pixel
      ... // Other input or Output ports
    		   
    #pragma HLS INTERFACE m_axi port=pixel offset=slave bundle=gmem
    #pragma HLS INTERFACE m_axi port=weights offset=slave bundle=gmem1
    #pragma HLS INTERFACE m_axi port=out offset=slave bundle=gmem
    
    In this example, the cnn kernel has 3 arguments: pixel, weights and out. Using the bundle attribute of the INTERFACE pragma, each argument is mapped to a specific interface. The pixel and out arguments are both mapped to the same interface called gmem. The weights argument is mapped to a different interface called gmem1. The resulting kernel has therefore 2 distinct interfaces (gmem and gmem1) which can be connected to different memory banks.
    Important: You must specify bundle= names using all lowercase characters to be able to assign it to a specific memory bank using the --connectivity.sp option.
  2. Use the --connectivity.sp option, or include it in a config file, as described in --connectivity Options .
    For example, for the cnn kernel shown above, the connectivity.sp option in the config file would be as follows:
    [connectivity]
    #sp=<compute_unit_name>.<argument>:<bank name> 
    sp=cnn_1.pixel:DDR[0]          
    sp=cnn_1.weights:DDR[1]
    sp=cnn_1.out:DDR[0]
    #sp=<aie_instance>.<gmio_port>:<memory_sp_tag_name>[bank_number]
    sp=ai_engine_0.my_gmio:LPDDR[0]
    

    Where:

    • <compute_unit_name> is an instance name of the CU as determined by the connectivity.nk option, described in Creating Multiple Instances of a Kernel, or is simply <kernel_name>_1 if multiple CUs are not specified.
    • <argument> is the name of the kernel argument. Alternatively, you can specify the name of the kernel interface as defined by the HLS INTERFACE pragma for C/C++ kernels, including m_axi_ and the bundle name. In the cnn kernel above, the ports would be m_axi_gmem and m_axi_gmem1.
      Tip: For RTL kernels, the interface is specified by the interface name defined in the kernel.xml file.
    • <bank_name> is denoted as DDR[0], DDR[1], DDR[2], and DDR[3] for a platform with four DDR banks. You can also specify the memory as a contiguous range of banks, such as DDR[0:2], in which case XRT will assign the memory bank at runtime.

      Some platforms also provide support for LPDDR, PLRAM, HBM, HP or MIG memory, in which case you would use LPDDR[0], PLRAM[0], HBM[0], HP[0] or MIG[0]. You can use the platforminfo utility to get information on the global memory banks available in a specified platform. Refer to platforminfo Utility in the Vitis Reference Guide (UG1702) for more information.

      In platforms that include both DDR and HBM memory banks, kernels must use separate AXI interfaces to access the different memories. DDR and PLRAM access can be shared from a single port.

      Note: The SP tag name is declared in Vivado block design as part of the platform properties. The SP tag names can be customized by user to help distinguish specific memory controllers.
      Tip: Assigning kernel interfaces to specific memory banks may also require you to specify the SLR to place the kernel into. For more information, refer to Assigning Compute Units to SLRs on Alveo Accelerator Cards in the Data Center Acceleration using Vitis (UG1700).

You can use the Device Hardware Transaction view in Vitis Analyzer to observe the actual DDR Bank communication, and to analyze DDR usage.

Figure 2. Device Hardware Transaction View Transactions on DDR Bank