The AXI4 Master interface has a
read/write address channel that can be used to read/write specific addresses. By default the
m_axi interface starts all read and write operations
from the address 0x00000000. For example, given the
following code, the design reads data from addresses 0x00000000 to 0x000000C7 (50 32-bit words,
gives 200 bytes), which represents 50 address values. The design then writes data back to
the same addresses.
#include <stdio.h>
#include <string.h>
void example(volatile int *a){
#pragma HLS INTERFACE m_axi port=a depth=50
int i;
int buff[50];
//memcpy creates a burst access to memory
//multiple calls of memcpy cannot be pipelined and will be scheduled sequentially
//memcpy requires a local buffer to store the results of the memory transaction
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));
}
The tool provides the capability to let the base address be configured statically in the Vivado IP for instance, or dynamically by the application or another IP during run time.
The m_axi interface can be both a master
initiating transactions, and also a slave interface that receives the data and sends
acknowledgment. Depending on the mode specified with the offset option of the INTERFACE pragma, an HLS IP can use multiple approaches to
set the base address.
config_interface -m_axi_offset command provides a global setting
for the offset, that can be overridden for specific m_axi
interfaces using the INTERFACE pragma offset
option.-
Master Mode: When acting as a
master interface with different
offsetoptions, them_axiinterface start address can be either hard-coded or set at run time.-
offset=off: Vitis HLS sets a base address for them_axiinterface when the IP is used in the Vivado IP integrator tool. One disadvantage with this approach is that you cannot change the base address during run time. See Customizing AXI4 Master Interfaces in IP Integrator for setting the base address.The following example is synthesized withoffset=off, the default for the Vivado IP flow.void example(volatile int *a){ #pragma HLS INTERFACE m_axi depth=50 port=a offset=off int i; int buff[50]; //memcpy creates a burst access to memory //multiple calls of memcpy cannot be pipelined and will be scheduled sequentially //memcpy requires a local buffer to store the results of the memory transaction 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)); } -
offset=direct: Vitis HLS generates a port on the IP for setting the address. Note the addition of theaport as shown in the figure below. This lets you update the address at run time, so you can have onem_axiinterface reading and writing different locations. For example, an HLS module that reads data from an ADC into RAM, and an HLS module that processes that data. Since you can change the address on the module, while one HLS module is processing the initial dataset the other module can be reading more data into different address.void example(volatile int *a){ #pragma HLS INTERFACE m_axi depth=50 port=a offset=direct ... }
Figure 1. offset=direct -
-
Slave Mode: The slave mode for an
interface is set with
offset=slave. In this mode the IP will be controlled by the host application, or the micro-controller through thes_axiliteinterface. This is the default for the Vitis kernel flow, and can also be used in the Vivado IP flow. Here is the flow of operation:- initially, the Host/CPU will start the IP or kernel using the
block-level control protocol which is mapped to the
s_axiliteadapter. - The host will send the scalars and address offsets for the
m_axiinterfaces through thes_axiliteadapter. - The
m_axiadapter will read the start address from thes_axiliteadapter and store it in a queue. - The HLS design starts to read the data from the global memory.
- initially, the Host/CPU will start the IP or kernel using the
block-level control protocol which is mapped to the
As shown in the figure below, the HLS design will have both the s_axilite adapter for the base address, and the m_axi to perform read and write transfer to the global
memory.
The following are rules associated with the offset option:
- Fully Specified Offset: When the user explicitly sets the offset value
the tool uses the specified settings. The user can also set different offset values for
different
m_axiinterfaces in the design, and the tool will use the specified offsets.#pragma HLS INTERFACE s_axilite port=return #pragma HLS INTERFACE m_axi bundle=BUS_A port=out_r offset=direct #pragma HLS INTERFACE m_axi bundle=BUS_B port=in1 offset=slave #pragma HLS INTERFACE m_axi bundle=BUS_C port=in2 offset=off - No Offset Specified: If there are no offsets specified in the INTERFACE
pragma, the tool will defer to the setting specified by
config_interface -m_axi_offset.Note: If the globalm_axi_offsetsetting is specified, and the design has an s_axilite interface, the global setting is ignored andoffset=slaveis assumed.void top(int *a) { #pragma HLS interface m_axi port=a #pragma HLS interface s_axilite port=a }