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.
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.
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
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];
}
...
}