Skilopsaros
Skilopsaros

Reputation: 67

HLS: Cannot apply array transformation pragma/directive because of pointer selection

I am writing some code using Vitis HLS. The code reads as follows:

#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 ;
    }
}

Where NDATA is defined in the input file as 64. This works and can get synthesised alright. The problem starts when I try to use #pragmas to optimise it. One of the main requirements is for the code to be pipelined. I tried using the following two:

#pragma HLS pipeline II=1 style=flp

This understandably does not work alone, considering it can't read the input fast enough, and I used the recommended fix which is splitting the input into separate registers using

#pragma HLS ARRAY_PARTITION variable=input complete

This is where the problem exists: Vitis stops being able to synthesise it and instead gives the following error:

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)

for which I have yet to find any documentation anywhere. Does anybody have any idea what is causing it or how I can fix it?

Upvotes: 0

Views: 977

Answers (1)

Stefano Ribes
Stefano Ribes

Reputation: 359

First off: where do you apply the pipeline? At function level or at loop level?

  • In the first case, HLS will unroll the loop and you basically update the output signals/arguments all at once (which maybe is no what you intended).
  • Otherwise, the output signals/arguments would be updated at each cycle, and maybe require a volatile in front of them (otherwise the compiler might assume that you care only about the last value they will have at the end of the loop)

I'm not entirely sure why the problem arises when you insert pragmas, but you are also dealing with pointers, and pointers (and also pointers arithmetic) don't go along very well with HLS.

My first suggestion would be to replace the pointer arguments with pass-by-reference arguments, like so:

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;
  }
}

Which should be equivalent and "less confusing" for the HLS to understand.

You might want to consider using FIFOs or buffers (or better, RTL languages) for notifying the status of your signals to the "external world". Using volatile might not be the best, afterall HLS is more suited for other stuff, not really for time/performance tracking. (But you can still try it of course, here is a reference for doing it in HLS).

p.s. I don't have HLS at hand at the moment, but I might try synthesizing the code later to see if I can insert the pragmas as well.

Upvotes: 1

Related Questions