void cnn( int *pixel, // Input pixel
int *weights, // Input Weight Matrix
int *out, // Output pixel
... // Other input or Output ports
In the example above, the kernel function has three pointer parameters:
pixel, weights, and
out. By default the Vitis compiler will map these three parameters to the same AXI4 interface (m_axi).
The default interface mapping inferred by the compiler is equivalent to the following INTERFACE pragmas:
#pragma HLS INTERFACE m_axi port=pixel offset=slave bundle=gmem
#pragma HLS INTERFACE m_axi port=weights offset=slave bundle=gmem
#pragma HLS INTERFACE m_axi port=out offset=slave bundle=gmem
The bundle keyword on the INTERFACE pragma
defines the name of the port. The Vitis compiler will
create a port for each unique bundle name, resulting in a compiled kernel object (XO) file
that has a single AXI interface, m_axi_gmem. When the same
bundle name is used for different interfaces, this results
in these interfaces being mapped to same port.
gmem name is short for global memory; however, it is not a keyword and is just
used for consistency. You can assign your own names for the bundles.Sharing ports helps save FPGA resources by eliminating AXI interfaces, but it
can limit the performance of the kernel because all the memory transfers have to go through a
single port. The m_axi port has independent READ and WRITE
channels, so with a single m_axi port, you can do reads and
writes simultaneously. However, the bandwidth and throughput of the kernel can be increased by
creating multiple ports, using different bundle names, to connect to multiple memory banks.
There are many options for configuring the INTERFACE, as described in
pragma HLS
interface
. Some reasons to manually
define an INTERFACE pragma in your code could include:
- Specifying the bundle for the INTERFACE pragma to separate AXI signals into separate bundles.
- Specifying the interface width to deviate from default int = 64 bytes (512-bits).
- Specifying AXI properties for burst transactions.
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 the example above, two bundle names
create two distinct ports: gmem and gmem1. The kernel will access pixel and out data through the gmem port,
while weights data will be accessed through the gmem1 port. As a result, the kernel will be able to make parallel
accesses to pixel and weights, potentially improving the throughput of the kernel.
bundle= names using all lowercase characters, so you can
assign it to a specific memory bank using the connectivity.sp option. The INTERFACE pragma is used during v++
compilation, resulting in a compiled kernel object (XO) file with two separate AXI interfaces,
m_axi_gmem and m_axi_gmem1, that can be connected to global memory as needed. During linking, the
separate interfaces can be mapped to different global memory banks using the connectivity.sp option in a configuration file, as described in
Mapping Kernel Ports to Memory.