2

我目前正在尝试在 Vivado HLS 上做一些项目。但是,在合成过程中出现如标题所示的错误。但是,会出现此错误:

错误:** 二进制表达式的无效操作数('double' 和 'datau32' (aka 'ap_axiu<32, 2, 5, 6>')) imgOut= (0.2126*Imgin[coord] + 0.7152*Imgin[coord+1 ] + 0.0722*Imgin[坐标+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);
        }
    }
}
4

1 回答 1

1

这些工具抱怨它无法处理imgOut= (0.2126*Imgin[coord] + 0.7152*Imgin[coord+1] + 0.0722*Imgin[coord+2]). 二元运算符是具有两个操作数的运算符,此处为*+。如错误消息中所述datau32,类型为ap_axiu<32, 2, 5, 6>. Imgin并作为基本类型imgOutdatau32因此,该消息似乎是指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将整数字段与 a相乘的结果double是另一个double. double是 64 位宽的,所以你也必须处理这种差异。您可以使用 type 的常量float,这可能足够精确。或者您可以使您的 AXI 总线更宽。或者,您可以通过转换为 来降低计算后的精度float。或者您可以使用 2 个总线周期来传输单个元素。请注意,如果要将 a doubleor转换float为整数,则必须使用reinterpret_cast以避免丢失精度。请注意,您还必须为ap_axiu结构体。请注意,您还必须为ap_axiu结构的所有其他字段分配值(keepstrb等)。

使用 AXI 总线的一种更简单的方法是将inStream和声明outStream为数组,例如ap_uint<32> inStream[320*240]. 握手 (TREADYTVALID) 会自动处理。如果您需要所谓的旁道(其余信号如TLASTor TUSER),则不能使用此方法。例如,如果您想传输数据包而不是连续流(可以使用 完成TLAST),或者如果您的数据大小不是总线大小的倍数,那么您需要一个字节启用信号( TKEEP)。

我还可以想象您从未打算使用 AXI 总线。有诸如ap_uint和之类的类型ap_fixed可用于在普通总线上提交数据。

最后,我想强调的是,您应该始终首先在软件中调试您的代码。仅基于综合的输出,有很多 bug 很难解决。有些信息往往会把人们引向错误的方向。我建议您首先使用 C 模拟功能调试您的代码。或者,您可以使用常规 C 编译器(例如gcc. 我还建议使用内存检查器,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;
    }
  }
}
于 2018-05-11T12:00:04.227 回答