ZED-Board從入門到精通系列(八)——Vivado HLS實現FIR濾波器


http://www.tuicool.com/articles/eQ7nEn


最終到了HLS部分。HLS是High Level Synthesis的縮寫,是一種能夠將高級程序設計語言C,C++。SystemC綜合為RTL代碼的工具。

生產力的發展推動了設計模式。在電子技術0基礎階段,人們關注的是RLC電路。通過建立微分方程求解電路響應。

門級電路是對RLC的初步封裝,人們進而採用布爾代數、卡諾圖進行電路設計與分析。之后隨着集成電路進一步發展。門電路能夠集成為寄存器、觸發器、ROM等宏單元。設計工具也變得更為高度模塊化。算法級別的電路設計,則一直沒有特別好的工具,直到出現了HLS。

HLS能夠將算法直接映射為RTL電路,實現了高層次綜合。從這個層面上講,System Generator也是一種高層次綜合工具。由於它將matlab算法描寫敘述綜合為RTL代碼。假設今后機器學習、人工智能獲得重大突破,也許會出現將人類自然語言綜合為RTL代碼的工具,不知我們能否見證它的面世。

HLS的學習資源能夠參考 http://xilinx.eetrend.com/article/5096 。本節給出較為通用的矩陣與向量相乘樣例,從全串行到全並行進行了一步步優化實現。

矩陣實驗室Matlab是比較經常使用的數學仿真軟件。

本博主用的是R2013a版本號。為了驗證矩陣向量相乘正確性。我們先用matlab生成測試矩陣和向量。並利用matlab計算結果。代碼例如以下:

clear;
clc;
close all;

N = 5;

A = randi([1,100],N,N);
b = randi(100,N,1);

c = A*b;

KKK_SaveToCHeaderFile(A,'A.h');

KKK_SaveToCHeaderFile(b,'b.h');
KKK_SaveToCHeaderFile(c,'c.h');

這里給出的是A*b = c的簡單樣例,A為5X5矩陣。b為5X1向量,結果c為5X1向量。當中KKK_SaveToCHeaderFile()是將矩陣、向量保存為C語言數組的子函數。定義例如以下:

function [] = KKK_SaveToCHeaderFile(var,fn)
fid = fopen(fn,'w');
var = reshape(var.',1,[]);
fprintf(fid,'%d,\r\n',var);
fclose(fid);


給出測試例程中,A例如以下:

82	10	16	15	66
91	28	98	43	4
13	55	96	92	85
92	96	49	80	94
64	97	81	96	68
76
75
40
66
18

9800 
15846 
16555 
23124 
22939 

執行matlab腳本之后,生成三個文件:A.h。b.h。c.h,這些是作為HLS程序的輸入數據和參考結果。以下我們用HLS工具實現上述矩陣X向量的功能。第一步,執行Vivado HLS。

選擇第一項,Create New Project,建立新projectMatrixMultiply

輸入路徑和project名之后,點Next。

加入頂層模塊文件。這里我們Top Functions輸入MatrixMultiply,然后New File...,新建一個.c文件。命名為MatrixMultiply.c(后綴不要省略!

),然后點Next

加入頂層文件測試腳本。這里New一個文件TestMatrixMultiply.c(后綴不要省略!

),然后Add前面用Matlab生成的A.h。b.h,c.h,例如以下圖所看到的:

點Next,選擇解決方式配置,例如以下圖所看到的

其余保持默認,僅僅改動Part Selection部分,改為ZedBoard。

改完后。Finish就可以進入主界面,例如以下圖所看到的

能夠看出。Vivado HLS界面非常像非常像Xilinx SDK,不同的是前者負責PL部分開發。后者負責PS軟件編寫。定位不同決定了二者今后的路必定走向分歧。

將MatrixMultiply.c內容改為:

typedef int data_type;
#define N 5

void MatrixMultiply(data_type AA[N*N],data_type bb[N],data_type cc[N])
{
  int i,j;
  for(i = 0;i<N;i++)
  {
    data_type sum = 0;
    for(j = 0;j<N;j++)
    {
      sum += AA[i*N+j]*bb[j];
    }
    cc[i] = sum;
  }
}

將TestMatrixMultiply.c內容改為:

#include <stdio.h> typedef int data_type; #define N 5

const data_type MatrixA[] = { #include "A.h" }; const data_type Vector_b[] = { #include "b.h" }; const data_type MatlabResult_c[] = { #include "c.h" };

data_type HLS_Result_c[N] = {0}; void CheckResult(data_type * matlab_result,data_type * your_result); int main(void) {  printf("Checking Results:\r\n");  MatrixMultiply(MatrixA,Vector_b,HLS_Result_c);  CheckResult(MatlabResult_c,HLS_Result_c);  return 0; } void CheckResult(data_type * matlab_result,data_type * your_result) {  int i;  for(i = 0;i<N;i++)  {   printf("Idx %d: Error = %d \r\n",i,matlab_result[i]-your_result[i]);  } }


首先進行C語言仿真驗證,點這個button:

結果例如以下:

從C仿真輸出看到,仿真結果與matlab計算結果一致,說明我們編寫的C程序MatrixMultiply是正確的。

接下來進行綜合。按C仿真后面那個三角形button,得到結果例如以下:

注意到,計算延遲為186個時鍾周期。

這是未經過優化的版本號,記為版本號1。

為了提高FPGA並行計算性能,我們接下來對它進行優化。

打開MatrixMultiply.c,點Directives頁面,能夠看到我們能夠優化的對象。

注意到矩陣和向量相乘是雙層for循環結構。我們先展開最內層for循環,過程例如以下:

右鍵點擊最內側循環,右鍵,然后Insert Directive...

彈出對話框例如以下,Directives選擇UNROLL,OK就可以。后面全部都保持默認。

再次綜合后,結果例如以下

可見效果很明顯,延遲縮短到51個時鍾周期。

用相同方法,展開外層循環。綜合后結果例如以下:

計算延遲又減少了1/3。!

但是代價呢?細心的你可能發現占用資源情況發生了較大變化,DSP48E1由最初的4個變為8個后來又成為76個。!

FPGA設計中,延遲的減少,即速度提高,必定會導致面積的增大!

循環展開是優化的一個角度,還有一個角度是從資源出發進行優化。

我們打開Analysis視圖。例如以下所看到的:

從分析視圖能夠看出各個模塊的執行順序,從而為優化提供更為明白的指引。我們發現AA_load導致了延遲,假設全部AA的值都能一次性並行取出,勢必會加快計算效率!

回到Synthetic視圖,為AA添加Directives:

選擇Resources,再點Cores后面的方框,進入Vivado HLS core選擇對話框

按上圖進行選擇。使用ROM是由於在計算矩陣和向量相乘時,AA為常數。確認。

仍然選擇AA。添加Directives,例如以下圖:

選擇數組分解,mode選擇全然complete,綜合后結果例如以下圖:

延遲進一步減少,已經降到11個時鍾周期了!。!是否已經達到極限了呢???

答案是否定的。我們進入Analysis視圖。看一下還有哪些地方能夠優化的。經過對照發現bb也須要分解,於是依照上面的方法對bb進行資源優化,也用ROM-2P類型,也做全分解,再次綜合,結果例如以下:

發現延遲進一步減少到8個時鍾周期了。。!

老師。能不能再給力點?

能夠的!!

我們進入分析視圖,發現cc這個回寫的步驟堵塞了總體流程,於是我們將cc也進行上述資源優化。僅僅只是資源類型要變為RAM_2P,由於它是須要寫入的。

綜合結果:

總體延遲已經減少到6個clk周期了!!!

再看Analysis視圖:

延遲已經被壓縮到極限了。

。。

老師。還能再給力點嘛?

答案是能夠的。!

我們前面的全部運算都是基於整形數int,假設將數值精度減少,將大大節省資源。

注意如今DSP48E1須要100個!

看我們怎樣將資源再降下來。

這就須要借助“隨意精度”數據類型了。

HLS中除了C中定義的char。shrot,int。long。long long 之外。還有隨意bit長度的int類型。

我們將代碼開頭的data_type定義改為:

#include <ap_cint.h>
typedef uint15 data_type;

因為matlab生成的隨機數在1~100以內。乘積范圍不會超過10000。於是取15bit就能滿足要求。

首先驗證下結果的正確性,用C Simulation試一下。結果例如以下:

看來結果是正確的(當然也不排除數位不夠,溢出后的結果相減也是0,須要你自己決定數值位寬)

綜合一下。結果例如以下:

延遲縮短了一半,DSP48E1降低到原來的1/4!!

!!!。!!!!

。!!!

。!

!。!。!!!。。!!!

!!

。。!!。!!

!!

。!

我和我的小伙伴們都震驚了!

!!

。!!!

。!!

。。。!

!!。!

。!!

!!

!!!!。。!

!。!。!

!!!!!

。!!。。

再看Analysis視圖

能夠發現我們的資源利用率已經達到極致,時序已經壓縮到無以復加,實現了全並行計算。系統時鍾全然能夠達到100MHz。延遲僅3CLK。約30ns,相比matlab。得到約數百倍加速(matlab進行矩陣——向量相乘時採用浮點計算)。

通過本文實驗,能夠發現利用Vivado HLS實現從最初的C串行實現到全並行實現的步步優化。總結一下優化步驟:

(1)粗優化(循環展開、子函數內聯)

(2)訪存優化(塊存儲分散化、多port存取)

(3)精優化(數值位寬優化、流水線優化)

(4)總線化(利用AXI4、AXI-Stream總線接口,減少總體訪存需求)

利用HLS能夠將原來的C算法高速部署到FPGA上,降低直接進行硬件編程的工作量。在非常多情況下,優化手段能夠和CUDA進行類比,相互借鑒。CUDA事實上更接近軟件接口,而HLS更接近硬件編程接口,也許今后兩者會在新的層次上融合為統一架構語言。



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM