Given the behavior of the GCC compiler described previously, this section
will detail how Vitis HLS uses aligned
and packed
attributes to create
efficient hardware. First, you need to understand the Aggregate and Disaggregate features in Vitis HLS. Structures or class objects in the code, for instance internal
and global variables, are disaggregated by default. Disaggregation implies that the
structure/class is decomposed into separate objects, one for each struct/class member.
The number and type of elements created are determined by the contents of the struct
itself. Arrays of structs are implemented as multiple arrays, with a separate array for
each member of the struct.
However, structs used as arguments to the top-level function are kept aggregated by default. Aggregation implies that all the elements of a struct are collected into a single wide vector. This allows all members of the struct to be read and written simultaneously. The member elements of the struct are placed into the vector in the order in which they appear in the C/C++ code: the first element of the struct is aligned on the LSB of the vector and the final element of the struct is aligned with the MSB of the vector. Any arrays in the struct are partitioned into individual array elements and placed in the vector from lowest to the highest order.
Behavior without AGGREGATE
pragma
|
Behavior with AGGREGATE pragma
(compact=auto or not specified)
|
|||
---|---|---|---|---|
Interface Argument | Internal Variable | Interface Argument | Internal variable | |
AXI protocol interface ( |
aggregate compact=none | N/A | compact=none | N/A |
Struct/Class containing hls::stream object |
Automatically disaggregate the struct/class | Automatically disaggregate the struct/class | N/A | N/A |
other interface protocols | aggregate compact=bit | Automatically disaggregated | compact=bit | compact=bit |
The goal of the default aggregation behavior in Vitis HLS is to use an x86_64-gnu-linux memory layout at the top level
hardware interface while optimizing the internal hardware for better quality of results
(QoR). The above table shows the default behavior of Vitis HLS. Two modes are shown in the table: the default mode where the
AGGREGATE
pragma is not specified by the user, and
the case where the AGGREGATE
pragma is specified by the
user.
In the case of AXI4 interfaces
(m_axi
/s_axilite
/axis
), a structure is padded by
default according to the order of elements of the struct as explained in Data Structure Padding. This aggregates the structure to a size
that is the closest power of 2, and so some padding may be applied in this case. This in
effect infers the compact=none
option on the AGGREGATE
pragma.
In the case of other interface protocols, the struct is packed at the
bit-level, so the aggregated vector is only the size of the various elements of the
struct, This in effect infers the compact=bit
option on
the AGGREGATE pragma.
The only exception to the above rules is when using hls::stream
in the interface indirectly (i.e. the hls::stream
object is specified inside a struct/class that
is then used as the type of an interface port). The struct containing the hls::stream
object is always disaggregated into its
individual member elements.