Structs in the interface are kept aggregated by Vitis HLS by default; combining all of the elements of a struct into a single wide
vector. This allows all members of the struct to be read and written-to simultaneously. You
can disaggregate structs in the interface by using the DISAGGREGATE pragma or directive. When a struct contains
one or more hls::stream
objects Vitis HLS will automatically disaggregate the struct as described below in Structs in the Interface with hls::stream
Elements.
v++
command. To support the Vitis Kernel flow you must manually break the struct into its constituent
elements, and define any hls::stream
objects as using an
AXIS interface. As part of aggregation, the elements of the struct are also aligned on a 4
byte alignment for the Vitis kernel flow, and on 1 byte
alignment for the Vivado IP flow. This alignment might
require the addition of bit padding to keep or make things aligned, as discussed in Struct Padding and Alignment. By default the aggregated struct is padded
rather than packed, but in the Vivado IP flow you can
pack it using the compact=bit
option of the AGGREGATE pragma or directive. However, any
port that gets defined as an AXI4 interface (m_axi
, s_axilite
, or axis
) cannot use compact=bit
.
The member elements of the struct are placed into the vector in the order 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. This allows more data to be accessed in a single clock cycle. Any arrays in the struct are partitioned into individual array elements and placed in the vector from lowest to highest, in order.
In the following example, struct data_t
is
defined in the header file shown. The struct has two data members:
- An unsigned vector
varA
of typeshort
(16-bit). - An array
varB
of fourunsigned char
types (8-bit).typedef struct { unsigned short varA; unsigned char varB[4]; } data_t; data_t struct_port(data_t i_val, data_t *i_pt, data_t *o_pt);
Aggregating the struct on the interface results in a single 48-bit port
containing 16 bits of varA
, and 4x8 bits of varB
.
axis
streaming interfaces.There are no limitations in the size or complexity of structs that can be synthesized by Vitis HLS. There can be as many array dimensions and as many members in a struct as required. The only limitation with the implementation of structs occurs when arrays are to be implemented as streaming (such as a FIFO interface). In this case, follow the same general rules that apply to arrays on the interface (FIFO Interfaces).
Structs on the Interface with hls::stream Elements
User-defined structs on the interface containing hls::stream
elements are automatically disaggregated by Vitis HLS. This disaggregated struct is supported in the
Vivado IP flow, and the exported IP will work as
expected. However, this disaggregated struct is not supported for the Vitis Kernel flow, and the exported kernel (.xo) will cause an error when used with the v++ --link
command. To support the Vitis Kernel flow you must manually break the struct into its constituent
elements, and define the hls::stream
object as using an
AXIS interface.
If you have a struct that is disaggregated automatically, Vitis HLS applies any INTERFACE pragmas to the individual elements of the disaggregated struct. If there is only one INTERFACE pragma specified for the struct, it is applied to each element of the struct. If you provide an INTERFACE pragma for each element of the disaggregated struct, it is applied as expected.