pragma HLS interface - 2021.2 English

Vitis High-Level Synthesis User Guide (UG1399)

Document ID
UG1399
Release Date
2021-12-15
Version
2021.2 English

Description

In C/C++ code, all input and output operations are performed, in zero time, through formal function arguments. In a RTL design, these same input and output operations must be performed through a port in the design interface and typically operate using a specific input/output (I/O) protocol. For more information, see Defining Interfaces.

The INTERFACE pragma specifies how RTL ports are created from the function definition during interface synthesis. The ports in the RTL implementation are derived from the following:

  • Block-level I/O protocols: Provide signals to control when the function starts operation, and indicate when function operation ends, is idle, and is ready for new inputs. The implementation of a block-level protocol is:
    • Specified by the <mode> values ap_ctrl_none, ap_ctrl_hs, or ap_ctrl_chain. The ap_ctrl_chain block protocol is the default.
    • Associated with the function name.
  • Function arguments: Each function argument can be specified to have its own port-level (I/O) interface protocol, such as valid handshake (ap_vld), or acknowledge handshake (ap_ack). Port-level interface protocols are created for each argument in the top-level function and the function return, if the function returns a value. The default I/O protocol created depends on the type of C argument. After the block-level protocol has been used to start the operation of the block, the port-level I/O protocols are used to sequence data into and out of the block.
  • Global variables accessed by the top-level function, and defined outside its scope:
    • If a global variable is accessed, but all read and write operations are local to the function, the resource is created in the RTL design. There is no need for an I/O port in the RTL. If the global variable is expected to be an external source or destination, specify its interface in a similar manner as standard function arguments. See the following Examples.
Tip: The Vitis HLS tool automatically determines the I/O protocol used by any sub-functions. You cannot specify the INTERFACE pragma or directive for sub-functions.

Specifying Burst Mode

When specifying burst-mode for interfaces, using the max_read_burst_length or max_write_burst_length options (as described in the Syntax section) there are limitations and related considerations that are derived from the AXI standard:

  1. The burst length should be less than, or equal to 256 words per transaction, because ARLEN & AWLEN are 8 bits; the actual burst length is AxLEN+1.
  2. In total, less than 4 KB is transferred per burst transaction.
  3. Do not cross the 4 KB address boundary.
  4. The bus width is specified as a power of 2, between 32 bits and 512 bits (that is, 32, 64, 128, 256, 512 bits) or in bytes: 4, 8, 16, 32, 64.

With the 4 KB limit, the max burst length for a bus width of:

  • 4 bytes (32 bits) is 256 words transferred in a single burst transaction. In this case, the total bytes transferred per transaction would be 1024.
  • 8 bytes (64 bits) is 256 words transferred in a single burst transaction. The total bytes transferred per transaction would be 2048.
  • 16 bytes (128 bits) is 256 words transferred in a single burst transaction. The total bytes transferred per transaction would be 4096.
  • 32 bytes (256 bits) is 128 words transferred in a single burst transaction. The total bytes transferred per transaction would be 4096.
  • 64 bytes (512 bits) is 64 words transferred in a single burst transaction. The total bytes transferred per transaction would be 4096.
Tip: The IP generated by the HLS tool might not actually perform the maximum burst length as this is design dependent. Refer to AXI Burst Transfers for more information.

For example, pipelined accesses from a for-loop of 100 iterations will not fill the max burst length when max_read_burst_length or max_write_burst_length is set to 128.

However, if the design is doing longer accesses than the specified maximum burst length, the access will be split into multiple bursts. For example, a pipelined for-loop with 100 accesses, and max_read_burst_length or max_write_burst_length of 64, will be split into 2 transactions: one sized to the max burst length (64), and one with the remaining data (burst of length 36 words).

Syntax

Place the pragma within the boundaries of the function.

#pragma HLS interface mode=<mode> port=<name> bundle=<string> \
register register_mode=<mode> depth=<int> offset=<string> latency=<value>\
clock=<string> name=<string> storage_type=<value>\
num_read_outstanding=<int> num_write_outstanding=<int> \
max_read_burst_length=<int> max_write_burst_length=<int>

Where:

mode=<mode>
Specifies the interface protocol mode for function arguments, global variables used by the function, or the block-level control protocols. The mode can be specified as one of the following:
ap_none
No protocol. The interface is a data port.
ap_stable
No protocol. The interface is a data port. The HLS tool assumes the data port is always stable after reset, which allows internal optimizations to remove unnecessary registers.
ap_vld
Implements the data port with an associated valid port to indicate when the data is valid for reading or writing.
ap_ack
Implements the data port with an associated acknowledge port to acknowledge that the data was read or written.
ap_hs
Implements the data port with associated valid and acknowledge ports to provide a two-way handshake to indicate when the data is valid for reading and writing and to acknowledge that the data was read or written.
ap_ovld
Implements the output data port with an associated valid port to indicate when the data is valid for reading or writing.
Important: The HLS tool implements the input argument or the input half of any read/write arguments with mode ap_none.
ap_fifo
Implements the port with a standard FIFO interface using data input and output ports with associated active-Low FIFO empty and full ports.
Note: You can only use this interface on read arguments or write arguments. The ap_fifo mode does not support bidirectional read/write arguments.
ap_memory
Implements array arguments as a standard RAM interface. If you use the RTL design in the Vivado IP integrator, the memory interface appears as discrete ports.
bram
Implements array arguments as a standard RAM interface. If you use the RTL design in the IP integrator, the memory interface appears as a single port.
axis
Implements all ports as an AXI4-Stream interface.
s_axilite
Implements all ports as an AXI4-Lite interface. The HLS tool produces an associated set of C driver files during the Export RTL process.
m_axi
Implements all ports as an AXI4 interface. You can use the config_interface command to specify either 32-bit (default) or 64-bit address ports and to control any address offset.
ap_ctrl_chain
Implements a set of block-level control ports to start the design operation, continue operation, and indicate when the design is idle, done, and ready for new input data.
Note: The ap_ctrl_chain interface mode is similar to ap_ctrl_hs but provides an additional input signal ap_continue to apply back pressure. Xilinx recommends using the ap_ctrl_chain block-level I/O protocol when chaining the HLS tool blocks together.
Note: The ap_ctrl_chain is the default block-level I/O protocol.
ap_ctrl_hs
Implements a set of block-level control ports to start the design operation and to indicate when the design is idle, done, and ready for new input data.
ap_ctrl_none
No block-level I/O protocol.
Note: Using the ap_ctrl_none mode might prevent the design from being verified using the C//RTL co-simulation feature.
port=<name>
Specifies the name of the function argument, function return, or global variable which the INTERFACE pragma applies to.
Tip: Block-level I/O protocols (ap_ctrl_none, ap_ctrl_hs, or ap_ctrl_chain) can be assigned to a port for the function return value.
bundle=<string>
By default, the HLS tool groups or bundles function arguments with compatible options into interface ports in the RTL code. All AXI4-Lite (s_axilite) interfaces are bundled into a single AXI4-Lite port whenever possible. Similarly, all function arguments specified as an AXI4 (m_axi) interface are bundled into a single AXI4 port by default.
All interface ports with compatible options, such as mode, offset, and bundle, are grouped into a single interface port. The port name is derived automatically from a combination of the mode and bundle, or is named as specified by -name.
Important: When specifying the bundle name you should use all lower-case characters.
register
An optional keyword to register the signal and any relevant protocol signals, and causes the signals to persist until at least the last cycle of the function execution. This option applies to the following interface modes:
  • s_axilite
  • ap_fifo
  • ap_none
  • ap_hs
  • ap_ack
  • ap_vld
  • ap_ovld
  • ap_stable
Tip: The -register_io option of the config_interface command globally controls registering all inputs/outputs on the top function.
register_mode=<forward|reverse|both|off>
This option applies to AXI4-Stream interfaces, and specifies if registers are placed on the forward path (TDATA and TVALID), the reverse path (TREADY), on both paths (TDATA, TVALID, and TREADY), or if none of the ports signals are to be registered (off). The default is both. AXI4-Stream side-channel signals are considered to be data signals and are registered whenever the TDATA is registered.
depth=<int>
Specifies the maximum number of samples for the test bench to process. This setting indicates the maximum size of the FIFO needed in the verification adapter that the HLS tool creates for RTL co-simulation.
Tip: While depth is usually an option, it is required for m_axi interfaces.
offset=<string>
Controls the address offset in AXI4-Lite (s_axilite) and AXI4 memory mapped (m_axi) interfaces for the specified port.
  • In an s_axilite interface, <string> specifies the address in the register map.
  • In an m_axi interface this option overrides the global option specified by the config_interface -m_axi_offset option, and <string> is specified as:
    • off: Do not generate an offset port.
    • direct: Generate a scalar input offset port.
    • slave: Generate an offset port and automatically map it to an AXI4-Lite slave interface. This is the default offset.
clock=<name>
Optionally specified only for interface mode s_axilite. This defines the clock signal to use for the interface. By default, the AXI4-Lite interface clock is the same clock as the system clock. This option is used to specify a separate clock for the AXI4-Lite (s_axilite) interface.
Tip: If the bundle option is used to group multiple top-level function arguments into a single AXI4-Lite interface, the clock option need only be specified on one of the bundle members.
name=<string>
Specifies a name for the port which will be used in the generated RTL.
latency=<value>
When mode is m_axi, this specifies the expected latency of the AXI4 interface, allowing the design to initiate a bus request a number of cycles (latency) before the read or write is expected. If this figure is too low, the design will be ready too soon and might stall waiting for the bus. If this figure is too high, bus access can be granted but the bus might stall waiting on the design to start the access.
storage_impl=<impl>
For use with s_axilite only. This options defines a storage implementation to assign to the interface.
Supported implementation values include auto, bram, and uram. The default is auto.
Tip: uram is a synchronous memory with only a single clock for two ports. Therefore uram cannot be specified for an s_axilite adapter with a second clock.
storage_type=<value>
For use with ap_memory and bram interfaces only. This options specifies a storage type (that is, RAM_T2P) to assign to the variable.
Supported types include: ram_1p, ram_1wnr, ram_2p, ram_s2p, ram_t2p, rom_1p, rom_2p, and rom_np.
Tip: This can also be specified using the BIND_STORAGE pragma or directive for an object not on the interface.
num_read_outstanding=<int>
For AXI4 (m_axi) interfaces, this option specifies how many read requests can be made to the AXI4 bus, without a response, before the design stalls. This implies internal storage in the design, a FIFO of size: num_read_outstanding*max_read_burst_length*word_size.
num_write_outstanding=<int>
For AXI4 (m_axi) interfaces, this option specifies how many write requests can be made to the AXI4 bus, without a response, before the design stalls. This implies internal storage in the design, a FIFO of size: num_write_outstanding*max_write_burst_length*word_size.
max_read_burst_length=<int>
  • For AXI4 (m_axi) interfaces, this option specifies the maximum number of data values read during a burst transfer.
max_write_burst_length=<int>
  • For AXI4 (m_axi) interfaces, this option specifies the maximum number of data values written during a burst transfer.
    Tip: If the port is a read-only port, then set the num_write_outstanding=1 and max_write_burst_length=2 to conserve memory resources. For write-only ports, set the num_read_outstanding=1 and max_read_burst_length=2.
-max_widen_bitwidth <int>
Specifies the maximum bit width available for the interface when automatically widening the interface. This overrides the global value specified by the config_interface -m_axi_max_bitwidth command.

Example 1

In this example, both function arguments are implemented using an AXI4-Stream interface:

void example(int A[50], int B[50]) {
  //Set the HLS native interface types
  #pragma HLS INTERFACE mode=axis port=A
  #pragma HLS INTERFACE mode=axis port=B
  int i;
  for(i = 0; i < 50; i++){
    B[i] = A[i] + 5;
  }
}

Example 2

The following turns off block-level I/O protocols, and is assigned to the function return value:

#pragma HLS interface mode=ap_ctrl_none port=return

The function argument InData is specified to use the ap_vld interface and also indicates the input should be registered:

#pragma HLS interface mode=ap_vld register port=InData

This exposes the global variable lookup_table as a port on the RTL design, with an ap_memory interface:

pragma HLS interface mode=ap_memory port=lookup_table

Example 3

This example defines the INTERFACE standards for the ports of the top-level transpose function. Notice the use of the bundle= option to group signals.

// TOP LEVEL - TRANSPOSE
void transpose(int* input, int* output) {
	#pragma HLS INTERFACE mode=m_axi port=input offset=slave bundle=gmem0
	#pragma HLS INTERFACE mode=m_axi port=output offset=slave bundle=gmem1

	#pragma HLS INTERFACE mode=s_axilite port=input bundle=control
	#pragma HLS INTERFACE mode=s_axilite port=output bundle=control
	#pragma HLS INTERFACE mode=s_axilite port=return bundle=control

	#pragma HLS dataflow