AXI4 Master Interface

You can use an AXI4 master interface on array or pointer/reference arguments, which HLS implements in one of the following modes:

  • Individual data transfers
  • Burst mode data transfers

With individual data transfers, HLS reads or writes a single element of data for each address. The following example shows a single read and single write operation. In this example, HLS generates an address on the AXI interface to read a single data value and an address to write a single data value. The interface transfers one data value per address.

void bus (int *d) {
 static int acc = 0;

 acc += *d;
 *d  = acc;
}

With burst mode transfers, HLS reads or writes data using a single base address followed by multiple sequential data samples, which makes this mode capable of higher data throughput. Burst mode of operation is possible when you use the C memcpy function or a pipelined for loop.

Note: The C memcpy function is only supported for synthesis when used to transfer data to or from a top-level function argument specified with an AXI4 master interface.

The following example shows a copy of burst mode using the memcpy function. The top-level function argument a is specified as an AXI4 master interface.

void example(volatile int *a){

#pragma HLS INTERFACE m_axi depth=50 port=a
#pragma HLS INTERFACE s_axilite port=return

//Port a is assigned to an AXI4 master interface

 int i;
 int buff[50];

//memcpy creates a burst access to memory
 memcpy(buff,(const int*)a,50*sizeof(int));

 for(i=0; i < 50; i++){
 buff[i] = buff[i] + 100;
 }

 memcpy((int *)a,buff,50*sizeof(int));
}

When this example is synthesized, it results in the interface shown in the following figure.

Note: In this figure, the AXI4 interfaces are collapsed.

Figure: AXI4 Interface



The following example shows the same code as the preceding example but uses a for loop to copy the data out:

void example(volatile int *a){

#pragma HLS INTERFACE m_axi depth=50 port=a
#pragma HLS INTERFACE s_axilite port=return

//Port a is assigned to an AXI4 master interface

 int i;
 int buff[50];

//memcpy creates a burst access to memory
 memcpy(buff,(const int*)a,50*sizeof(int));

 for(i=0; i < 50; i++){
 buff[i] = buff[i] + 100;
 }

 for(i=0; i < 50; i++){
#pragma HLS PIPELINE
 a[i] = buff[i];
 }
}

When using a for loop to implement burst reads or writes, follow these requirements:

  • Pipeline the loop
  • Access addresses in increasing order
  • Do not place accesses inside a conditional statement
  • For nested loops, do not flatten loops, because this inhibits the burst operation
Note: Only one read and one write is allowed in a for loop unless the ports are bundled in different AXI ports. The following example shows how to perform two reads in burst mode using different AXI interfaces.

In the following example, HLS implements the port reads as burst transfers. Port a is specified without using the bundle option and is implemented in the default AXI interface. Port b is specified using a named bundle and is implemented in a separate AXI interface called d2_port.

void example(volatile int *a, int *b){

#pragma HLS INTERFACE s_axilite port=return 
#pragma HLS INTERFACE m_axi depth=50 port=a
#pragma HLS INTERFACE m_axi depth=50 port=b bundle=d2_port


 int i;
 int buff[50];

//copy data in
 for(i=0; i < 50; i++){
#pragma HLS PIPELINE
 buff[i] = a[i] + b[i];
 }
...
 }
IMPORTANT: Structs are only supported for the AXI4 master interface if the struct is packed, which is the default in HLS.