Vivado HLS 综合错误
Vivado HLS Synthesize error
我目前正在尝试在 Vivado HLS 上做一些项目。但是,我在合成过程中出现了如标题所示的错误。但是,出现此错误:
error:** invalid operands to binary expression ('double' and 'datau32' (aka 'ap_axiu<32, 2, 5, 6>')) imgOut= (0.2126*Imgin[coord] + 0.7152*Imgin[coord+1] + 0.0722*Imgin[coord+2])
这是我的 HLS 代码:
#include "core.h"
void imgreading(hls::stream<datau32> &inStream, datau32 Imgin[imagesize])
{
for(int i=0;i<imagesize;i++)
{
Imgin[i]=(datau32)inStream.read();
}
}
void resize_half(hls::stream<datau32> &inStream, hls::stream<datau32> &outStream)
{
#pragma HLS INTERFACE axis port=inStream
#pragma HLS INTERFACE axis port=outStream
#pragma HLS INTERFACE s_axilite port=return bundle=CRTL_BUS
datau32 Imgin[imagesize];
imgreading (inStream,Imgin);
datau32 imgOut;
int coord=0;
#pragma HLS DATAFLOW
for (int a=0; a<240; a++) {
for(int b=0; b<320; b++){
#pragma HLS PIPELINE II=1
coord=6*(a*640+b);
imgOut= (0.2126*Imgin[coord] + 0.7152*Imgin[coord+1] + 0.0722*Imgin[coord+2]) ;
datau32 dataOutSideChannel;
dataOutSideChannel.data = imgOut;
outStream.write (dataOutSideChannel);
}
}
}
工具抱怨无法处理 imgOut= (0.2126*Imgin[coord] + 0.7152*Imgin[coord+1] + 0.0722*Imgin[coord+2])
中的二元运算符。二元运算符是具有两个操作数的运算符,此处为 *
和 +
。如错误消息中所述,datau32
的类型为 ap_axiu<32, 2, 5, 6>
。 Imgin
和 imgOut
具有 datau32
作为基类型。因此,该消息似乎指的是 Imgin[...]
与浮点常数(0.2126
等)
的乘法
总之,ap_axiu
是用来声明AXI总线的。它是具有以下格式的结构(参见 UG902 第 110 页,适用于 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;
};
因此,您要做的是将浮点常量与结构相乘。这在 C++ 中是不允许的。
如果您确实打算使用 AXI 总线,则必须使用结构的 data
字段来传送数据。将整数 data
字段与 double
相乘的结果是另一个 double
。 double
是 64 位宽,因此您也必须处理这种差异。您可以使用 float
类型的常量,这可能足够精确。或者你可以让你的 AXI 总线更宽。或者您可以通过强制转换为 float
来降低计算后的精度。或者您可以使用 2 个总线周期来传输单个元素。请注意,如果要将 double
或 float
转换为整数,则必须使用 reinterpret_cast
以避免丢失精度。请注意,您还必须为 ap_axiu
结构的所有其他字段赋值。请注意,您还必须为 ap_axiu
结构(keep
、strb
等)的所有其他字段赋值。
使用 AXI 总线的一种更简单的方法是将 inStream
和 outStream
声明为数组,例如ap_uint<32> inStream[320*240]
。握手(TREADY
和 TVALID
)会自动处理。如果你需要所谓的side-channel(剩下的信号如TLAST
或TUSER
),你不能使用这种方法。例如,如果您想要传输数据包而不是连续流(可以使用 TLAST
来完成),或者如果您的数据大小不是总线大小的倍数,那么您可能就是这种情况需要一个字节使能信号(TKEEP
)。
我还可以想象您从未打算使用 AXI 总线。有ap_uint
和ap_fixed
等类型可以用来在普通总线上提交数据
最后,我想强调的是你应该总是先在软件中调试你的代码。有很多bug,单靠综合的输出是很难解决的。有些消息往往会将人们引向错误的方向。我建议您首先使用 C 语言模拟功能调试您的代码。或者,您可以使用 gcc
等常规 C 编译器在 Vivado HLS 外部编译代码。我还建议使用内存检查器,例如 valgrind
以确保您的代码不会写入数组边界等。该工具并不总能发现这些问题,但它确实会导致硬件无法使用。
我认为这是您正在寻找的解决方案:
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;
}
}
}
我目前正在尝试在 Vivado HLS 上做一些项目。但是,我在合成过程中出现了如标题所示的错误。但是,出现此错误:
error:** invalid operands to binary expression ('double' and 'datau32' (aka 'ap_axiu<32, 2, 5, 6>')) imgOut= (0.2126*Imgin[coord] + 0.7152*Imgin[coord+1] + 0.0722*Imgin[coord+2])
这是我的 HLS 代码:
#include "core.h"
void imgreading(hls::stream<datau32> &inStream, datau32 Imgin[imagesize])
{
for(int i=0;i<imagesize;i++)
{
Imgin[i]=(datau32)inStream.read();
}
}
void resize_half(hls::stream<datau32> &inStream, hls::stream<datau32> &outStream)
{
#pragma HLS INTERFACE axis port=inStream
#pragma HLS INTERFACE axis port=outStream
#pragma HLS INTERFACE s_axilite port=return bundle=CRTL_BUS
datau32 Imgin[imagesize];
imgreading (inStream,Imgin);
datau32 imgOut;
int coord=0;
#pragma HLS DATAFLOW
for (int a=0; a<240; a++) {
for(int b=0; b<320; b++){
#pragma HLS PIPELINE II=1
coord=6*(a*640+b);
imgOut= (0.2126*Imgin[coord] + 0.7152*Imgin[coord+1] + 0.0722*Imgin[coord+2]) ;
datau32 dataOutSideChannel;
dataOutSideChannel.data = imgOut;
outStream.write (dataOutSideChannel);
}
}
}
工具抱怨无法处理 imgOut= (0.2126*Imgin[coord] + 0.7152*Imgin[coord+1] + 0.0722*Imgin[coord+2])
中的二元运算符。二元运算符是具有两个操作数的运算符,此处为 *
和 +
。如错误消息中所述,datau32
的类型为 ap_axiu<32, 2, 5, 6>
。 Imgin
和 imgOut
具有 datau32
作为基类型。因此,该消息似乎指的是 Imgin[...]
与浮点常数(0.2126
等)
总之,ap_axiu
是用来声明AXI总线的。它是具有以下格式的结构(参见 UG902 第 110 页,适用于 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;
};
因此,您要做的是将浮点常量与结构相乘。这在 C++ 中是不允许的。
如果您确实打算使用 AXI 总线,则必须使用结构的 data
字段来传送数据。将整数 data
字段与 double
相乘的结果是另一个 double
。 double
是 64 位宽,因此您也必须处理这种差异。您可以使用 float
类型的常量,这可能足够精确。或者你可以让你的 AXI 总线更宽。或者您可以通过强制转换为 float
来降低计算后的精度。或者您可以使用 2 个总线周期来传输单个元素。请注意,如果要将 double
或 float
转换为整数,则必须使用 reinterpret_cast
以避免丢失精度。请注意,您还必须为 ap_axiu
结构的所有其他字段赋值。请注意,您还必须为 ap_axiu
结构(keep
、strb
等)的所有其他字段赋值。
使用 AXI 总线的一种更简单的方法是将 inStream
和 outStream
声明为数组,例如ap_uint<32> inStream[320*240]
。握手(TREADY
和 TVALID
)会自动处理。如果你需要所谓的side-channel(剩下的信号如TLAST
或TUSER
),你不能使用这种方法。例如,如果您想要传输数据包而不是连续流(可以使用 TLAST
来完成),或者如果您的数据大小不是总线大小的倍数,那么您可能就是这种情况需要一个字节使能信号(TKEEP
)。
我还可以想象您从未打算使用 AXI 总线。有ap_uint
和ap_fixed
等类型可以用来在普通总线上提交数据
最后,我想强调的是你应该总是先在软件中调试你的代码。有很多bug,单靠综合的输出是很难解决的。有些消息往往会将人们引向错误的方向。我建议您首先使用 C 语言模拟功能调试您的代码。或者,您可以使用 gcc
等常规 C 编译器在 Vivado HLS 外部编译代码。我还建议使用内存检查器,例如 valgrind
以确保您的代码不会写入数组边界等。该工具并不总能发现这些问题,但它确实会导致硬件无法使用。
我认为这是您正在寻找的解决方案:
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;
}
}
}