The tools complains that it cannot deal with the binary operators in imgOut= (0.2126*Imgin[coord] + 0.7152*Imgin[coord+1] + 0.0722*Imgin[coord+2])
. Binary operators are operators with two operands, here *
and +
. As mentioned in the error message, datau32
is of type ap_axiu<32, 2, 5, 6>
. Imgin
and imgOut
have datau32
as basetype. Hence, the message appears to be referring to the multiplications of Imgin[...]
with the floating-point constants (0.2126
, etc.)
Anyway, ap_axiu
is used to declare AXI buses. It is a structure with the following format (See page 110 of UG902 for Vivado HLS 2017.1.):
template<int D,int U,int TI,int TD>
struct ap_axiu{
ap_uint<D> data;
ap_uint<D/8> keep;
ap_uint<D/8> strb;
ap_uint<U> user;
ap_uint<1> last;
ap_uint<TI> id;
ap_uint<TD> dest;
};
So what you are trying to do is multiply a floating-point constant with a structure. That is not allowed in C++.
If you did intent to use an AXI bus, you will have to use the data
field of the structure to convey the data. The result of multiplying the integer data
field with a double
is another double
. double
is 64-bit wide, so you will have to handle that discrepancy too. You could use constants of type float
, which is likely enough precision. Or you could make your AXI bus wider. Or you could reduce the precision after the computation by casting to float
. Or you could use 2 bus cycles to transfer a single element. Note that if you want to convert a double
or float
to an integer, you will have to use reinterpret_cast
to avoid losing precision. Note that you will also have to assign values to all other fields of the ap_axiu
structure. Note that you will also have to assign values to all other fields of the ap_axiu
structure (keep
, strb
, etc.).
An easier way to use the AXI bus is by declaring inStream
and outStream
as arrays, e.g. ap_uint<32> inStream[320*240]
. The handshaking (TREADY
and TVALID
) is automatically taken care of. If you need the so-called side-channel (the remaining signals like TLAST
or TUSER
), you cannot use this method. That may be the case, for example, if you want to transmit packets of data instead of a continuous stream (can be done with TLAST
), or if your data size is not a multiple of the bus size such that you need a byte enable signal (TKEEP
).
I can also imagine that you never intended to use an AXI bus. There are types such as ap_uint
and ap_fixed
that can be used to submit data on a plain bus.
Finally, I want to emphasize that you should always debug your code in software first. There are many bugs that are hard to solve based on the output of the synthesis alone. Some messages tend to point people in the wrong direction. I recommend that you debug your code using the C simulation functionality first. Alternatively, you can compile the code outside Vivado HLS with a regular C compiler such as gcc
. I also recommend using a memory checker such as valgrind
to ensure that your code does not write outside array bounds, etc. The tool does not always find these issues, but it does result in unusable hardware.
I think this is the solution that you are looking for:
void resize_half(ap_uint<32> inAXI[640 * 480 * 3], ap_uint<32> outAXI[320 * 240])
{
#pragma HLS INTERFACE axis port=inAXI
#pragma HLS INTERFACE axis port=outAXI
#pragma HLS INTERFACE s_axilite port=return bundle=CRTL_BUS
#pragma HLS dataflow
hls::stream<ap_uint<32> > Stream[3];
for (int i = 0; i < 480; i++)
for (int j = 0; j < 640; j++)
for (int k = 0; k < 3; k++)
{
#pragma HLS PIPELINE II=1
ap_uint<32> value = inAXI[3 * (640 * i + j) + k];
if (i % 2 == 0 && j % 2 == 0)
Stream[k].write(value);
}
for (int a = 0; a < 240; a++)
{
for (int b = 0; b < 320; b++)
{
#pragma HLS PIPELINE II=1
ap_uint<32> x = Stream[0].read();
ap_uint<32> y = Stream[1].read();
ap_uint<32> z = Stream[2].read();
outAXI[320 * a + b] = 0.2126 * x + 0.7152 * y + 0.0722 * z;
}
}
}