Vivado HLS class with member of type hls::stream<int>& leads to error: "Constant '' has an unsynthesizable type ..."

Vivado HLS class with member of type hls::stream<int>& leads to error: "Constant '' has an unsynthesizable type ..."

我正在尝试查看是否可以在具有 hls::stream<> 引用成员的 vivado_hls 中实例化一个 class,以便我可以直接 read/write流,而不必将流作为参数传递到调用链中。

注意:这是在 vivado_hls 2018.2 中,该项目的顶级模块是 "ModuleX" 考虑下面的简化场景:

#include <hls_stream.h>
#include <ap_int.h>

using hls_int = ap_uint<32>;

class X
{
  private:
    hls::stream<hls_int> &s1;
    hls::stream<hls_int> &s2;

  public:
    X(hls::stream<hls_int> &_s1, hls::stream<hls_int> &_s2) :
        s1(_s1), s2(_s2)
    {}

    void Run()
    {
        hls_int s = s2.read();
        hls_int out = s * 2;
        s1.write(out);
    }
};

void ModuleX(hls::stream<hls_int> &s1, hls::stream<hls_int> &s2)
{
    #pragma HLS INTERFACE ap_ctrl_none PORT=return
    #pragma HLS STREAM VARIABLE=s1 DEPTH=1
    #pragma HLS STREAM VARIABLE=s2 DEPTH=1

    static X x {s1, s2};

    x.Run();
}

使用这种方法,我得到以下错误:ERROR: [SYNCHK 200-11] ClassWithStreamRefs.cpp:18: Constant 'x.s2.V.V' has an unsynthesizable type 'i32P*' (possible cause(s): pointer to pointer or global pointer).

我知道在后台,编译器可能将引用存储为流的指针,但据我所知,这应该是这种情况下工具的错误,因为它正在阻塞,我认为是有效的 HLS。

希望有另一种方法来实现我正在寻找的东西(引用,而不是值存储在 class 中)。

下面是我尝试过的其他方法。然而,这是非常不受欢迎的,因为该方法增加了 2 个时钟周期的延迟(入口和出口各 1 个 - 没有充分的理由)。

#include <hls_stream.h>
#include <ap_int.h>

using hls_int = ap_uint<32>;

class X
{
  public:
    hls::stream<hls_int> s1;
    hls::stream<hls_int> s2;
    X()
    {
        #pragma HLS STREAM VARIABLE=s1 DEPTH=1
        #pragma HLS STREAM VARIABLE=s2 DEPTH=1
    }

    void Run()
    {
        hls_int s = s2.read();
        hls_int out = s * 2;
        s1.write(out);
    }
};

void ModuleX(hls::stream<hls_int> &s1, hls::stream<hls_int> &s2)
{
    #pragma HLS INTERFACE ap_ctrl_none PORT=return
    #pragma HLS INLINE
    static X x;

    x.s2.write(s2.read());
    x.Run();
    s1.write(x.s1.read());
}

这是一个示例 tcl 脚本(虽然它基本上只是由 vivado_hls 自动生成)

open_project ClassWithStreamRef
set_top ModuleX
add_files ClassWithStreamRefs.cpp -cflags "-std=c++11"
open_solution "solution1"
set_part {xczu19eg-ffvc1760-2-i} -tool vivado
create_clock -period 10 -name default
csynth_design

我不确定底层机制,但删除 static 限定符允许 Vivado HLS 2018.2 综合示例。然而,这会在每个顶级函数调用时创建一个 X 的新实例,因此它的字段不会持久存在。下面的示例通过在顶部函数中添加另一个静态变量以实现持久化并通过引用将其传递给 X 的构造函数来解决该问题。

#include <hls_stream.h>
#include <ap_int.h>

using hls_int = ap_uint<32>;

struct State
{
    hls_int counter;
};

class X
{
  private:
    hls::stream<hls_int> &s1;
    hls::stream<hls_int> &s2;
    State& state;

  public:
    X(hls::stream<hls_int> &_s1, hls::stream<hls_int> &_s2, State& _state) :
        s1(_s1), s2(_s2), state(_state)
    {}

    void Run()
    {
        hls_int s = s2.read();
        s1.write(s + state.counter++);
    }
};

void ModuleX(hls::stream<hls_int> &s1, hls::stream<hls_int> &s2)
{
    #pragma HLS INTERFACE ap_ctrl_none PORT=return
    #pragma HLS STREAM VARIABLE=s1 DEPTH=1
    #pragma HLS STREAM VARIABLE=s2 DEPTH=1

    static State state {0};
    X x {s1, s2, state};

    x.Run();
}