Description
The BIND_STORAGE pragma assigns a variable (array, or function argument)
in the code to a specific memory type (type) in the RTL.
If the pragma is not specified, the Vitis HLS tool
determines the memory type to assign. The HLS tool implements the memory using specified
implementations (impl) in the hardware.
For example, you can use the pragma to specify which memory type to use to
implement an array. This lets you control whether the array is implemented as a single or a
dual-port RAM for example.
Important: This feature is important for
arrays on the top-level function interface, because the memory type associated with the
array determines the number and type of ports needed in the RTL, as discussed in
Arrays on the Interface. However, for variables assigned to top-level
function arguments you must assign the memory type and implementation using the
-storage_type and
-storage_impl options of the INTERFACE pragma or directive.
You can also specify the latency of the implementation. For block RAMs on
the interface, the latency option lets you model off-chip,
non-standard SRAMs at the interface, for example supporting an SRAM with a latency of 2 or
3. For internal operations, the latency option allows the
memory to be implemented using more pipelined stages. These additional pipeline stages can
help resolve timing issues during RTL synthesis.
Important: To use the
latency option, the operation must have an available
multi-stage implementation. The HLS tool provides a multi-stage implementation for all block
RAMs.
Syntax
Place the pragma in the C/C++ source within the body of the function where
the variable is defined.
#pragma HLS bind_storage variable=<variable> type=<type>\
[ impl=<value> latency=<int> ]
Where:
-
variable=<variable>
- Defines the variable to assign the BIND_STORAGE pragma to. This is
required when specifying the pragma.
-
Tip: If the variable is an argument
of a top-level function, then use the -storage_type
and -storage_impl options of the INTERFACE pragma or
directive.
-
type=<type>
- Defines the type of memory to bind to the specified variable.
- Supported types include:
fifo,
ram_1p, ram_1wnr,
ram_2p, ram_s2p,
ram_t2p, rom_1p,
rom_2p, rom_np.
Table 1. Storage Types
| Type |
Description |
| FIFO |
A FIFO. Vitis HLS
determines how to implement this in the RTL, unless the -impl option is specified. |
| RAM_1P |
A single-port RAM. Vitis HLS determines how to implement this in the RTL, unless the
-impl option is specified. |
| RAM_1WNR |
A RAM with 1 write port and N read ports, using N banks
internally. |
| RAM_2P |
A dual-port RAM that allows read operations on one port
and both read and write operations on the other port. |
| RAM_S2P |
A dual-port RAM that allows read operations on one port
and write operations on the other port. |
| RAM_T2P |
A true dual-port RAM with support for both read and
write on both ports. |
| ROM_1P |
A single-port ROM. Vitis HLS determines how to implement this in the RTL, unless the
-impl option is specified. |
| ROM_2P |
A dual-port ROM. |
| ROM_NP |
A multi-port ROM. |
Tip: If you specify a single port RAM for a
PIPO, then the binder will typically allocate a merged-PIPO, with only one bank, and
reader and writer accessing different halves of the bank. The info message reported by
the HLS compiler says "Implementing PIPO using a single memory for all blocks." This
is often cheaper for small PIPOs, where all banks can share a single RAM block.
However, if you specify a dual-port RAM for a PIPO to get higher bandwidth and the
scheduler uses both ports either in the producer or in the consumer, then the binder
will typically allocate a split-PIPO, where the producer will use 1 port and the
consumer 2 ports of different banks. The info message reported by the HLS compiler in
this case says "Implementing PIPO using a separate memory for each block."
-
impl=<value>
- Defines the implementation for the specified memory type. Supported
implementations include:
bram, bram_ecc, lutram, uram, uram_ecc, srl, memory, and auto as described below.
-
Table 2. Supported Implementation
| Name |
Description |
| MEMORY |
Generic memory lets the Vivado tool choose the implementation. |
| URAM |
UltraRAM resource |
| URAM_ECC |
UltraRAM with ECC |
| SRL |
Shift Register Logic resource |
| LUTRAM |
Distributed RAM resource |
| BRAM |
Block RAM resource |
| BRAM_ECC |
Block RAM with ECC |
| AUTO |
Vitis HLS
automatically determine the implementation of the variable. |
-
Table 3. Supported Implementations by FIFO/RAM/ROM
| Type |
Command/Pragma |
Scope |
Supported Implementations |
| FIFO |
bind_storage
1
|
local |
AUTO, BRAM, LUTRAM, URAM,
MEMORY, SRL |
| FIFO |
config_storage
|
global |
AUTO, BRAM, LUTRAM, URAM,
MEMORY, SRL |
| RAM* | ROM* |
bind_storage
|
local |
AUTO BRAM, BRAM_ECC, LUTRAM,
URAM, URAM_ECC |
| RAM* | ROM* |
config_storage
2
|
global |
N/A |
| RAM_1P |
set_directive_interface
s_axilite -storage_impl
|
local |
AUTO, BRAM, URAM
|
| |
config_interface
-m_axi_buffer_impl
|
global |
AUTO, BRAM, LUTRAM, URAM
|
- When no implementation is specified
the directive uses AUTOSRL behavior as a default. However, this value
cannot be specified.
-
config_storage only supports FIFO types.
|
-
latency=<int>
- Defines the default latency for the binding of the type. As shown in
the following table, the valid latency varies according to the specified
type and impl. The default
is -1, that lets Vitis HLS choose the latency.
Table 4. Supported Combinations of Memory Type, Implementation, and
Latency
| Type |
Implementation |
Min Latency |
Max Latency |
| FIFO |
BRAM |
1 |
4 |
| FIFO |
LUTRAM |
1 |
4 |
| FIFO |
MEMORY |
1 |
4 |
| FIFO |
SRL |
1 |
4 |
| FIFO |
URAM |
1 |
4 |
| RAM_1P |
AUTO |
1 |
3 |
| RAM_1P |
BRAM |
1 |
3 |
| RAM_1P |
LUTRAM |
1 |
3 |
| RAM_1P |
URAM |
1 |
3 |
| RAM_1WNR |
AUTO |
1 |
3 |
| RAM_1WNR |
BRAM |
1 |
3 |
| RAM_1WNR |
LUTRAM |
1 |
3 |
| RAM_1WNR |
URAM |
1 |
3 |
| RAM_2P |
AUTO |
1 |
3 |
| RAM_2P |
BRAM |
1 |
3 |
| RAM_2P |
LUTRAM |
1 |
3 |
| RAM_2P |
URAM |
1 |
3 |
| RAM_S2P |
BRAM |
1 |
3 |
| RAM_S2P |
BRAM_ECC |
1 |
3 |
| RAM_S2P |
LUTRAM |
1 |
3 |
| RAM_S2P |
URAM |
1 |
3 |
| RAM_S2P |
URAM_ECC |
1 |
3 |
| RAM_T2P |
BRAM |
1 |
3 |
| RAM_T2P |
URAM |
1 |
3 |
| ROM_1P |
AUTO |
1 |
3 |
| ROM_1P |
BRAM |
1 |
3 |
| ROM_1P |
LUTRAM |
1 |
3 |
| ROM_2P |
AUTO |
1 |
3 |
| ROM_2P |
BRAM |
1 |
3 |
| ROM_2P |
LUTRAM |
1 |
3 |
| ROM_NP |
BRAM |
1 |
3 |
| ROM_NP |
LUTRAM |
1 |
3 |
Important: Any combinations
of memory type and implementation that are not listed in the prior table are not supported
by set_directive_bind_storage.
Example
The pragma specifies that the variable coeffs uses a single port RAM implemented on a BRAM core from the library.
#pragma HLS bind_storage variable=coeffs type=RAM_1P impl=bram
Tip: The ports created in
the RTL to access the values of coeffs are defined in the
RAM_1P.