static
qualifier. This not
only ensures that Vitis HLS
implements the array with a memory in the RTL; it also allows
the default initialization behavior of the static types to be
used. In the following code, an array is initialized with a set
of values. Each time the function is executed, array coeff
is assigned these
values. After synthesis, each time the design executes the RAM
that implements coeff
is loaded
with these values. For a single-port RAM this would take eight
clock cycles. For an array of 1024, it would of course take 1024
clock cycles, during which time no operations depending on
coeff
could
occur.
int coeff[8] = {-2, 8, -4, 10, 14, 10, -4, 8, -2};
The following code uses the static
qualifier to define array coeff
. The array is
initialized with the specified values at start of execution.
Each time the function is executed, array coeff
remembers its values
from the previous execution. A static array behaves in C/C++
code as a memory does in RTL.
static int coeff[8] = {-2, 8, -4, 10, 14, 10, -4, 8, -2};
In addition, if the variable has the static
qualifier, Vitis HLS initializes the
variable in the RTL design and in the FPGA bitstream. This
removes the need for multiple clock cycles to initialize the
memory and ensures that initializing large memories is not an
operational overhead. Refer to the initialization_and_reset example available
on GitHub for examples.
The RTL configuration command syn.rtl.reset
can specify if static
variables return to their initial state after a reset is
applied. This is not the default. When syn.rtl.reset=state
or all
are used, it forces all
arrays implemented as block RAM to be returned to their
initialized state after reset. This can result in two very
undesirable conditions in the RTL design:
- Unlike a power-up initialization (or power-on reset), an explicit reset requires the RTL design to iterate through each address in the block RAM to set the value: this can take many clock cycles if N is large, and requires more area resources to implement the reset.
- A reset is added to every array in the design.
To prevent adding reset logic onto every such block RAM,
and incurring the cycle overhead to reset all elements in the
RAM, specify the default syn.rtl.reset=control
reset mode and use
the RESET pragma or directive to identify individual static or
global variables to be reset.
Alternatively, you can use the syn.rtl.reset=state
reset mode, and use
the RESET directive off
option
to select which individual static or global variables to not
reset.
Finally, depending on the hardware device or platform of your choice (UltraScale+ or Versal, etc), there can be differences in how block RAMs and URAMs are initialized and/or reset. In general, Vitis HLS supports two types of reset: one is when the device is powered on (and also termed as power-up initialization or power-on reset), and the second is when a hardware RESET signal is asserted during device execution. The following shows the differences in behavior for the different memory resources:
- Initialization Behavior: Applies to all block RAMs on all platforms and only to Versal URAMs. This is the behavior during power-on initialization (or power-on reset).
- Maintaining an “initial value array” and “runtime array” if the array is read/written. This applies to both block RAMs and URAMs and this corresponds to the hardware “RESET” signal during device execution.
write thru
, read first
, no change
. URAM only
supports no change
. Vitis HLS will issue the
following warning message when it cannot schedule memory
operations in the same cycle on a URAM port:
Usage of URAM can potentially cause worse II as Vitis HLS does not exploit
read-first mode for URAMs. Consider using block RAMs instead.