In the following code example, a union is created with a double
and a struct
. Unlike C/C++
compilation, synthesis does not guarantee using the same memory (in the case of
synthesis, registers) for all fields in the union
.
Vitis HLS perform the optimization that provides
the most optimal hardware.
#include "types_union.h"
dout_t types_union(din_t N, dinfp_t F)
{
union {
struct {int a; int b; } intval;
double fpval;
} intfp;
unsigned long long one, exp;
// Set a floating-point value in union intfp
intfp.fpval = F;
// Slice out lower bits and add to shifted input
one = intfp.intval.a;
exp = (N & 0x7FF);
return ((exp << 52) + one) & (0x7fffffffffffffffLL);
}
Vitis HLS does not support the following:
- Unions on the top-level function interface.
- Pointer reinterpretation for synthesis. Therefore, a union cannot hold pointers to different types or to arrays of different types.
- Access to a union through another variable. Using the same union as the
previous example, the following is not
supported:
for (int i = 0; i < 6; ++i) if (i<3) A[i] = intfp.intval.a + B[i]; else A[i] = intfp.intval.b + B[i]; }
- However, it can be explicitly re-coded
as:
A[0] = intfp.intval.a + B[0]; A[1] = intfp.intval.a + B[1]; A[2] = intfp.intval.a + B[2]; A[3] = intfp.intval.b + B[3]; A[4] = intfp.intval.b + B[4]; A[5] = intfp.intval.b + B[5];
The synthesis of unions does not support casting between native C/C++ types and user-defined types.
Often with Vitis HLS designs, unions are used to convert the raw bits from one data type to another data type. Generally, this raw bit conversion is needed when using floating point values at the top-level port interface. For one example, see below:
typedef float T;
unsigned int value; // the "input"€ of the conversion
T myhalfvalue; // the "output" of the conversion
union
{
unsigned int as_uint32;
T as_floatingpoint;
} my_converter;
my_converter.as_uint32 = value;
myhalfvalue = my_converter. as_floatingpoint;
This type of code is fine for float C/C++ data types and with modification, it
is also fine for double data types. Changing the typedef
and the int
to short
will not work for half data types, however, because
half is a class and cannot be used in a union. Instead, the following code can be
used:
typedef half T;
short value;
T myhalfvalue = static_cast<T>(value);
Similarly, the conversion the other way around uses value=static_cast<ap_uint<16> >(myhalfvalue)
or static_cast< unsigned short >(myhalfvalue)
.
ap_fixed<16,4> afix = 1.5;
ap_fixed<20,6> bfix = 1.25;
half ahlf = afix.to_half();
half bhlf = bfix.to_half();
Another method is to use the helper class fp_struct<half>
to make conversions using the methods data()
or to_int()
. Use the
header file hls/utils/x_hls_utils.h.