天天看點

Vivado_HLS 學習筆記3-循環的pipeline與展開

優化手段

1 優化之:循環展開

  • 對某個标記的循環進行Directive-> Unroll.
  • 對循環展開的越徹底(Directive-> Unroll -> complete),消耗的資源數和端口數越多,帶來的吞吐量越大.需要trade-off.
  • 那麼該展開到什麼程度呢? 可以全部展開(complete),可以部分展開(factor:8,展開為8份);
可以學習ug871的Ch4 lab3 and lab4.

2 優化之:移位寄存器

  • 如果使用C數組實作移位寄存器,那麼綜合出來的會是memory.
  • 對某個array(shift_reg)進行Directive-> Array_Partition -> type: complete

3 優化之: 循環PipeLine

  • 對于循環, 可以選擇Pipeline優化-> II (Initiation Interval)保持不填,即為Interval=1 -> 選擇enable loop rewinding(告訴HLS當實作為RTL時,該循環不間斷運作)
  • Pipeline将把循環内的操作進行流水設計.

4 工程檔案組織

  • top.cpp: 頂層子產品, 例化一個object,并調用一系列的methods.
  • top.h: 使用宏定義,對top.cpp中的object進行配置;
  • class.h(.cpp): 類的定義與實作,建議使用模闆;
  • test.c: testbench要包括 輸入激勵,對照結果,測試結果,對比打分.

5 循環合并

  • 相同疊代次數(常數)的循環,如果可以并行(無資料依賴), 可以使用loop merging;
  • 相同疊代次數(變量)的循環,如果可以并行(無資料依賴), 可以使用loop merging;

ROM的綜合

1 要綜合出來MEMORY,需要使用static關鍵詞來定義數組,并一定要使用{}進行初始化.

  • static關鍵詞的作用是保證初始化數組在函數執行時隻被初始化一次,避免了每次調用函數時都需要初始化數組都要占用時間的問題。

    2 const關鍵字,當數組隻可以被讀取時(會被綜合為ROM). 例如`const coef_t coef[N] = {1,2,4,5,7,8};

  • 當ROM内容較大時,可以使用#include的方式,注意隻能這樣使用(#include "coef.h"語句必須單獨成一行)!
const coef_t coef[N] = {
                        #include "coef.h"
                        };
           

此時,"coef.h"内容為

1,
2,
3,
4  //注意最後一行的逗号用空格替代
           

3 複雜的情況請參考以下代碼

// This template function selects the coefficient equation specific to the
// window function type chosen at class object instantiation.
template<int SZ, win_fn_t FT>
double coef_calc(int i)
{
   double coef_val;

   switch(FT) {
   case RECT:
      coef_val = 1.0;
      break;
   case HANN:
      coef_val = 0.5 * (1.0 - cos(2.0 * M_PI * i / double(SZ)));
      break;
   case HAMMING:
      coef_val = 0.54 - 0.46 * cos(2.0 * M_PI * i / double(SZ));
      break;
   case GAUSSIAN:
      const double gaussian_sigma = 0.5;
      double x = (i - SZ / 2) / (gaussian_sigma * (SZ / 2));
      coef_val = exp(-0.5 * x * x);
      break;
   }
   return coef_val;
}

// This template function is used to initialize the contents of the 
// coefficient table.  Currently, in order for the table to be mapped to
// a ROM it must be defined at file (global) scope, i.e. it cannot be
// a class method (member function).
template<class TC, int SZ, win_fn_t FT>
void init_coef_tab(TC *coeff)
{
   for (int i = 0; i < SZ; i++) {
      coeff[i] = coef_calc<SZ,FT>(i);
   }
};

template<class TI, class TO, class TC, int SZ, win_fn_t FT>
void window_fn<TI,TO,TC,SZ,FT>::apply(TO *outdata, TI *indata)
{
   TC coeff_tab[SZ];
   // To ensure coeff_tab is implemented as a ROM on the FPGA, it must
   // be initialized by a separate function. No hardware is synthesized
   // for ROM initialization.
   init_coef_tab<TC,SZ,FT>(coeff_tab);
winfn_loop:
   for (unsigned i = 0; i < SZ; i++) {
//#pragma AP PIPELINE // implemented as TCL directive in this example
      outdata[i] = coeff_tab[i] * indata[i];
   }
}