FPGA 脈動陣列的設計

一:定義

脈動陣列:數據流同步流過相鄰的二維陣列單元的處理器結構,一般不同方向流過不同數據。如下圖:

二維不同數據在同一時鐘下依次輸入每個處理單元,而後完成乘法並存在其寄存器中。

二:舉例

三:設計

結構:

單個PE的代碼

module pe(clk, reset, coeff, in_x, in_y, out_x, out_y);

parameter size = 8;

input?????????????? clk, reset;

input???? [size-1:0]????????? in_x, coeff;

input???? [size+size-1:0]? in_y;

output?? [size-1:0]????????? out_x;

output?? [size+size-1:0]? out_y;

reg??????? [size+size-1:0]? out_y;

reg??????? [size-1:0]?????????? out_x;

always@(posedge clk)

?begin

?? if(reset) begin

???? out_x <= 0;

???? out_y <= 0;

???? end

?? else begin

???? out_y <= in_y + (in_x * coeff);

???? out_x <= in_x;

???? end

?end

endmodule

?

四個PE,其餘類推

//***** main ****************************

module systolic(clk, reset, input_x, output_y);

parameter?? size = 8;

input?? clk, reset;

input?? [size-1:0]????????? input_x;

output [size+size-1:0]? output_y;

wire??? [size-1:0]?????????? pe0_x, pe1_x, pe2_x, pe3_x;???????

wire??? [size+size-1:0]? pe1_y, pe2_y, pe3_y;

wire?? [size-1:0]?????? h0 = 8'h01;

wire?? [size-1:0]?????? h1 = 8'h01;

wire?? [size-1:0]?????? h2 = 8'h01;

wire?? [size-1:0]?????? h3 = 8'h01;

wire?? [size+size-1:0]? pe4_y = 16'h0000;??

pe pe_0(clk, reset, h0, input_x, pe1_y, pe0_x, output_y);

pe pe_1(clk, reset, h1, pe0_x, pe2_y, pe1_x, pe1_y);

pe pe_2(clk, reset, h2, pe1_x, pe3_y, pe2_x, pe2_y);

pe pe_3(clk, reset, h3, pe2_x, pe4_y, pe3_x, pe3_y);

endmodule

 

 

=========================================================================================================

 

脈動陣列(Systolic Array)計算矩陣乘法(Array Multiplication)

下一個目標是實現流水線輸出,提升硬件資源的利用率。

脈動陣列(Systolic Array):數據流同步流過相鄰的二維陣列單元的處理器結構,一般不同方向流過不同數據。

結構:

矩陣計算:

C語言描述每個輸出矩陣中的值:

For I = 1 to N

???? For J = 1 to N

????????? For K = 1 to N

?????????????? C[I,J] = C[I,J] + A[J,K] * B[K,J];

運用N x N processing units,輸入數據呈批次輸入:

二維不同數據在同一時鐘下依次輸入每個處理單元,而後完成乘法並存在其寄存器中。

?

?

其中每個PE(處理單元)結構如下:

是一個乘加單元? c=c+(a*b)

?

例子:計算兩個3×3矩陣的乘積

結構:

?

?

在CLK驅動下的每一個步驟如下:

Clk1:

?

Clk2:

Clk3:

Clk4:

???????? 

Clk5:

?

?

Clk6:

Clk7:

Clk8:輸出

功能仿真圖:

在start 上升沿到來後的第一個CLK上升沿開始計數

Count_start高電平期間

Cout=1時,準備a11和b11;

Cout=2時,將數據打入寄存器,並計數出a11*b11;

Cout=3時,計數a11*b11+a12*b21

Cout=4時,計數a11*b11+a12*b21+a13*b31

Cout=5時,用寄存器打一拍輸出Y11。

其他類似。

時序仿真圖:

連續運算,中間忘了將乘加單元寄存器清零的情況,功能仿真:

每次計算出結果後清零寄存器,修改後的功能仿真圖:

數據在送入運算單元之前,採用寄存器打一拍,功能仿真圖:

?

?

?

狀態機便於實現控制。

狀態機控制:功能仿真

時序仿真圖:

?

 

 

=======================================================================================================

二維流水線結構矩陣乘法(Array Multiplication)

上一篇文中建立了矩陣乘法運算的數據路徑,從仿真結構中可以看出整個計算方案的可行性,但是存在一個問題,就是硬件運算單元的資源利用率不高。這是什麼意思呢?就是說,在每次計算兩個3*3矩陣的乘法之前,需要將整個運算單元中的每個寄存器都清零,但是9個輸出結果不是在同一個時刻輸出,有先有後。當最先出結果的P11計算出第一個結果之後,它就不再輸出新值了。其實這時硬件電路是存在的,而且是在不斷計算出新值,只是這些值不是我們需要的有效值。那麼如果將這些硬件資源完全被利用起來,讓它們在最短的時間間隔裏都有有效正確數據輸出呢。

其實要說的就是流水線設計思想,我們只需要當P11單元計算出新的值,下個CLK將其計算結果輸出(只要有另一個機制接收這些值),然後將其清零(如果不清零,那個會累加了上次的計算結果),再然後就可以將下個要計算的兩個3*3矩陣對應位置上面的新值輸入給P11單元,讓其計算兩個數的乘積。

其他單元類似,思想就是在輸出結果後立即做清零和賦新值,不必等整個計算單元都出結果之後纔開始進行下個矩陣乘法的計算。

那麼從大局來看,就出現個這樣的情況:在上個矩陣計算還沒有完全計算出9個值的時候(右下角部分還在計算),左上角的單元就已經開始下個矩陣乘法的計算。關於輸出就是,每個CLK都有有效的數據輸出,產生了流水輸出。而這些輸出是從這整個二維矩陣計算單元的某些地方同時輸出的,就像水流即向下流也向右流,只是在這裏水流對應了數據輸出。

回顧一下這樣做的目的是什麼:爲了增加整個運算單元的利用率。做了改進,我們可以看出,每個CLK到來時,每個計算單元中的乘法和加法器的運算都是有效的計算。我們一定要記住FPGA做運算和CPU做計算的不同點。FPGA做運算,那些設計好的運算單元,不管你對這些運算單元操作或者不操作,它們都已經以硬件電路的形式存在了,也就是說,每個CLK到來時,它們都進行了一次計算。那麼如何有效的利用這些運算單元,就是不要讓它們做無效的計算,讓它們每一次的計算都對我們來說是有效的,是一個對整個單元輸出有影響的計算。而想實現這樣的功能流水線設計方法是必須要採用的。只是有時候單向流水(一維)更容易被我們所理解。其實這二維運算單元也是如此,也可以產生流水。

相對於不採用流水線操作,數據路徑不必做太多修改,主要是控制單元更爲複雜,要考慮何時對某個單元清零,何時再對其賦值,何時把數據讀走等。這些需要比較精準的調度。有人會想,那麼這樣是不是需要更多狀態機狀態?答案是肯定的。那麼是不是需要更多的硬件資源的開銷呢?答案也是肯定的。那麼這種流水線的優勢在哪呢?其實是速度上面的優勢,有時候在不能提高整個系統的工作頻率的情況下,再消耗一點資源來提高其它部分(運算單元)的利用率也是一個很好的提高運算速度的辦法。(注:這並不等同於面積與速度的法則)其實這也是一個比較好的,硬件算法優化方案。我們可以將其歸納爲以優化算法路徑的算法優化方法。

下面是仿真結果:

?

說明: C:\Users\Administrator\AppData\Local\youdao\ynote\images\38553C81823041DF9129DC26B329C82F\clipboard.png

矩陣還是之前的矩陣。可以看出每個CLK都有2-3個有效輸出。

增加了Valid信號,當其爲高電平時,說明對應運算單元輸出是有效值。其實在算法成熟之後,這些Valid信號是可以撤銷的,因爲我們完全知道了,輸出的規律,只需要在特定的時間讀走數據即可。而且我們可以將這些數據合併到幾根連續有效的總線上面。讓每個總線上面每個CLK都是有效值。(筆者將按照此方法,繼續優化輸出總線)

下面是對輸入最大值時的輸出仿真,主要是看數據會不會益處:

測試8bits輸入最大值255對應的輸出值:

時序仿真:

255*255+255*255+255*255=195075

255*254+255*254+255*254=194310

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章