0

我正在使用 Vitis HLS 编写一些代码。代码如下:

#include "algo.h"

void find_peaks(ap_uint<14> input[NDATA], bool *peak, ap_uint<14> *start_time, ap_uint<14> *end_time, ap_uint<14> *peak_time, ap_uint<14> *peak_value, ap_uint<14> *sum_value){
    ap_uint<14> local_start_time = 0;
    ap_uint<14> local_end_time = 0;
    ap_uint<14> local_peak_time = 0;
    ap_uint<14> local_peak_value = 0;
    ap_uint<14> local_sum_value = 0;
    ap_uint<14> width = 0;
    bool prev_peak = false;

    for (ap_uint<14> i = 0; i<NDATA; i++){
        prev_peak = *peak;
        *peak = input[i]>20;
        local_start_time = (*peak && !prev_peak)? i:local_start_time;
        local_end_time = *peak? i:local_end_time;
        local_peak_time = (*peak && (input[i]>local_peak_value))? i:local_peak_time;
        local_peak_value = (*peak && (input[i]>local_peak_value))? input[i]:local_peak_value;
        local_sum_value += *peak ? input[i]:ap_uint<14>(0);

        width = local_end_time - local_start_time;

        *start_time = (!*peak && prev_peak && (width>3))? local_start_time: *start_time ;
        *end_time = (!*peak && prev_peak && (width>3))? local_end_time: *end_time ;
        *peak_time = (!*peak && prev_peak && (width>3))? local_peak_time: *peak_time ;
        *peak_value = (!*peak && prev_peak && (width>3))? local_peak_value: *peak_value ;
        *sum_value = (!*peak && prev_peak && (width>3))? local_sum_value: *sum_value ;
    }
}

NDATA输入文件中定义为 64 的位置。这可以正常工作并且可以正常合成。当我尝试使用#pragmas 来优化它时,问题就开始了。主要要求之一是将代码流水线化。我尝试使用以下两个:

#pragma HLS pipeline II=1 style=flp

可以理解的是,这不能单独工作,考虑到它无法足够快地读取输入,我使用了推荐的修复方法,即使用将输入拆分为单独的寄存器

#pragma HLS ARRAY_PARTITION variable=input complete

这就是问题所在:Vitis 无法合成它,而是给出以下错误:

ERROR: [HLS 214-247] in function 'find_peaks(ap_uint<14>*, bool*, ap_uint<14>*, ap_uint<14>*, ap_uint<14>*, ap_uint<14>*, ap_uint<14>*) (.12)': Cannot apply array transformation pragma/directive because of pointer selection. (src/algo.cpp:21:22)

我还没有在任何地方找到任何文档。有谁知道是什么原因造成的,或者我该如何解决?

4

1 回答 1

1

首先:你在哪里应用管道?在功能级别还是在循环级别?

  • 在第一种情况下,HLS 将展开循环,您基本上一次更新输出信号/参数(这可能不是您想要的)。
  • 否则,输出信号/参数将在每个循环中更新,并且可能需要volatile在它们前面加上 a(否则编译器可能会假设您只关心它们在循环结束时的最后一个值)

我不完全确定为什么在插入 pragma 时会出现问题,但是您也在处理指针,并且指针(以及指针算术)与 HLS 配合得不是很好。

我的第一个建议是用传递引用参数替换指针参数,如下所示:

void find_peaks(ap_uint<14> input[NDATA], volatile bool &peak,
    volatile ap_uint<14> &start_time, volatile ap_uint<14> &end_time,
    volatile ap_uint<14> &peak_time, volatile ap_uint<14> &peak_value,
    volatile ap_uint<14> &sum_value) {
  ap_uint<14> local_start_time = 0;
  ap_uint<14> local_end_time = 0;
  ap_uint<14> local_peak_time = 0;
  ap_uint<14> local_peak_value = 0;
  ap_uint<14> local_sum_value = 0;
  ap_uint<14> width = 0;
  bool prev_peak = false;

  for (int i = 0; i < NDATA; i++){
    assert(i < NDATA);
    prev_peak = peak;
    peak = input[i] > 20;
    local_start_time = (peak && !prev_peak)? i:local_start_time;
    local_end_time = peak? i : local_end_time;
    local_peak_time = (peak && (input[i] > local_peak_value))? i : local_peak_time;
    local_peak_value = (peak && (input[i]>local_peak_value))? input[i] : local_peak_value;
    local_sum_value += peak ? input[i] : ap_uint<14>(0);

    width = local_end_time - local_start_time;

    const bool cond = !peak && prev_peak && (width > 3);
    start_time = cond ? local_start_time: start_time;
    end_time = cond ? local_end_time: end_time;
    peak_time = cond ? local_peak_time: peak_time;
    peak_value = cond ? local_peak_value: peak_value;
    sum_value = cond ? local_sum_value: sum_value;
  }
}

对于 HLS 来说,这应该是等效的并且“不那么令人困惑”。

您可能需要考虑使用 FIFO 或缓冲区(或更好的 RTL 语言)将信号状态通知给“外部世界”。使用volatile可能不是最好的,毕竟 HLS 更适合其他东西,而不是真正的时间/性能跟踪。(当然你仍然可以尝试,这里是在 HLS 中做的参考)。

ps 我目前手头没有 HLS,但我可能会尝试稍后合成代码,看看是否也可以插入 pragma。

于 2021-10-07T11:56:34.313 回答