转如何设计乘加电路.docx
《转如何设计乘加电路.docx》由会员分享,可在线阅读,更多相关《转如何设计乘加电路.docx(13页珍藏版)》请在冰豆网上搜索。
转如何设计乘加电路
原文出处(真OO无双):
Abstract
z=a*b+c*d;一個很簡單的運算,該如何使用數位電路實現呢?
Introduction
使用環境:
QuartusII8.0
在(原創)如何設計2數相加的電路?
(SOC)(Verilog)中,我們討論過如何實現y=a+b;但在實務上,其實最常用的是y=a*b+c*d,由於Verilog與數位電路本身的限制,不適合真的去實現很複雜的數學,就算真的實現出來,電路也跑不快,又佔resource,所以我們常會重新修改演算法配合數位電路的特性,通常演算法修改到最後,都會只剩下簡單的乘法與加法運算,也就是y=a*b+c*d的型式。
Method1:
一般寫法
ALT_MULTADD.v/Verilog
1 /*
2 (C)OOMusou2008
3
4 Filename :
ALT_MULTADD.v
5 Compiler :
QuartusII8.0
6 Description:
Demohowtowritey=a*b+c*d
7 Release :
10/11/20081.0
8 */
9
10 moduleALT_MULTADD(
11 input iCLK,
12 input iRST_N,
13 input [7:
0] iA0,
14 input [7:
0] iB0,
15 input [7:
0] iA1,
16 input [7:
0] iB1,
17 output[16:
0]oRESULT
18 );
19
20 reg[7:
0]a0;
21 reg[7:
0]a1;
22 reg[7:
0]b0;
23 reg[7:
0]b1;
24 reg[16:
0]result;
25
26 assignoRESULT=result;
27
28 always@(posedgeiCLK,negedgeiRST_N)begin
29 if(!
iRST_N)begin
30 a0 <= 0;
31 a1 <= 0;
32 b0 <= 0;
33 b1 <= 0;
34 result<= 0;
35 end
36 else begin
37 a0 <=iA0;
38 a1 <=iA1;
39 b0 <=iB0;
40 b1 <=iB1;
41
42 result<=a0*b0+a1*b1;
43 end
44 end
45
46 endmodule
模擬結果
輸出結果會delay2個clock,為什麼會這樣呢?
這可由合成結果來解釋。
合成結果
輸出輸入都使用reg寄存,所以一共delay2個clock,中間是組合電路負責乘加運算。
Fmax為195.43MHz
Method2:
使用Pipeline
ALT_MULTADD_pipe.v/Verilog
1 /*
2 (C)OOMusou2008
3
4 Filename :
ALT_MULTADD_pipe.v
5 Compiler :
QuartusII8.0
6 Description:
Demohowtowritey=a*b+c*dwithpipeline
7 Release :
10/11/20081.0
8 */
9
10 moduleALT_MULTADD_pipe(
11 input iCLK,
12 input iRST_N,
13 input [7:
0] iA0,
14 input [7:
0] iB0,
15 input [7:
0] iA1,
16 input [7:
0] iB1,
17 output[16:
0]oRESULT
18 );
19
20 reg[7:
0]a0;
21 reg[7:
0]a1;
22 reg[7:
0]b0;
23 reg[7:
0]b1;
24
25 reg[16:
0]m0;
26 reg[16:
0]m1;
27
28 reg[16:
0]result;
29
30 assignoRESULT=result;
31
32 always@(posedgeiCLK,negedgeiRST_N)begin
33 if(!
iRST_N)begin
34 a0<= 0;
35 a1<= 0;
36 b0<= 0;
37 b1<= 0;
38 m0<= 0;
39 m1<= 0;
40 end
41 else begin
42 a0<=iA0;
43 a1<=iA1;
44 b0<=iB0;
45 b1<=iB1;
46
47 m0<=a0*b0;
48 m1<=a1*b1;
49
50 result<=m0+m1;
51 end
52 end
53
54 endmodule
模擬結果
輸出結果會delay3個clock,為什麼會這樣呢?
這可由合成結果來解釋。
合成結果
由於使用了3級reg,所以delay了3個clock。
其實在code中,也已經描述了這個現象,42行
a0<=iA0;
a1<=iA1;
b0<=iB0;
b1<=iB1;
第1個clock,將input做寄存。
47行
m0<=a0*b0;
m1<=a1*b1;
第2個clock,計算a0*b0與a1*b1,由於這兩個毫不相干,所以可以同時計算。
50行
result<=m0+m1;
第3個clock,將output做寄存。
所以在寫code時,其實腦筋想的正是RTLViewer合成出來的結果,這也是為什麼寫Verilog時,不能像寫C一樣,只要語法對就好,剩下就是Compiler幫你優化,由於目前Ccompiler優化能力都很強,所以就算你亂寫,優化出來的結果也差不多,但寫Verilog卻要時時想著你想描述的硬體,
Fmax為260MHz
加上pipeline後,Fmax大增,為什麼加上pipeline後,Fmax增加這麼多呢?
尤其若你原本是寫C的背景,看到Verilog多了幾個reg後,差異就這麼大,一定很難理解。
解釋pipeline的書很多,在有名的算盤書(ComputerOrganization&DesignTheHardware/SoftwareInterface)Ch.6講得很清楚,在這我用另外一種方法來解釋。
在同步設計中,電路的設計都是循序電路、組合電路交錯的組合,由上面兩個合成結果也能發現這種設計,為了要同步,所以必須很穩定的前一個clock在第1級reg,而下一個clock在第2級reg,因為Fmax是period的倒數,兩級reg中間的組合電路所需時間越長,period一定越大,倒數後的Fmax就越小。
在Method1中
result<=a0*b0+a1*b1;
要乘要加,這樣的組合電路一定要花較長的時間,所以period也越大,Fmax當然也變小。
在Method2中
m0<=a0*b0;
m1<=a1*b1;
result<=m0+m1;
將相乘跟相加分開來做,先將乘法運算的結果做寄存,然後再作加法運算,這樣每個組合電路的時間變少,所以period也變小,Fmax當然也變大了。
但pipeline也是有tradeoff!
!
多花了一級reg,所以delay時間會變長,也就是一開始會慢一個clock出來,但之後每個clock都有產出,換來的就是Fmax變大。
所以有人說,硬體加速基本上就是將演算法切得很細來加速,就是因為pipeline的關係。
看到這裡,你或許會說:
『y=a*b+c*d在C只要一行的東西,在Verilog我要寫這麼多行?
那真的去寫一個演算法還得了?
』
幸好Altera提供了Megafunction,讓我們可以很輕鬆的計算y=a*b+c*d。
Method3:
使用Megafunction:
ALT_MULTADD
ALT_MULTADD_mf.v/Verilog
1 /*
2 (C)OOMusou2008
3
4 Filename :
ALT_MULTADD_mf.v
5 Compiler :
QuartusII8.0
6 Description:
Demohowtowritey=a*b+c*dbyMegafunction
7 Release :
10/11/20081.0
8 */
9
10 moduleALT_MULTADD_mf(
11 input iCLK,
12 input iRST_N,
13 input [7:
0] iA0,
14 input [7:
0] iB0,
15 input [7:
0] iA1,
16 input [7:
0] iB1,
17 output[16:
0]oRESULT
18 );
19
20 MACmac0(
21 .aclr0(!
iRST_N),
22 .clock0(iCLK),
23 .dataa_0(iA0),
24 .datab_0(iB0),
25 .dataa_1(iA1),
26 .datab_1(iB1),
27 .result(oRESULT)
28 );
29
30 endmodule
這樣的code夠精簡了吧!
!
模擬結果
與Method2的結果一樣delay3個clock,可見Megafunction:
ALT_MULTADD預設已經加上了pipeline。
合成結果
很單純的只有一個MACblock。
Fmax一樣為260MHz
所以不用擔心Megafunction:
ALT_MULTADD沒自己寫code效率好。
如何使用Megafunction:
ALT_MULTADD?
Tool->MegaWizardPlug-InManager
之後就是wizard介面,跟著一步一步設定即可。
Megafunction:
ALT_MULTADD預設已經將input與output用reg做寄存,所以我們只需單純的用wire連進去即可。
完整程式下載
ALT_MULTADD.7z(一般寫法)
ALT_MULTADD_pipe.7z(使用pipeline)
ALT_MULTADD_mf.7z(使用Megafunction:
ALT_MULTADD)
Conclusion
本文所要傳達的重點有4:
1.寫Verilog不能像寫C一樣,只要語法對就好,剩下的優化就交給Ccompiler;寫Verilog時要時時想著你要描述的硬體,因為合成器會依照你的code去做合成,寫法的差異影響結果甚鉅。
2.解釋pipeline概念,這是ccoder學Verilog很難理解的地方。
3.Altera提供了不少好用Megafunction,不僅方便,而且執行效率甚至比我們自己寫的還好些,應該盡量使用Megafunction增加開發效率以及執行效率。
4.Megafunction:
ALT_MULTADD在實務上經常使用,在(原創)如何實現RealTime的SobelEdgeDetector?
(SOC)(Verilog)(ImageProcessing)(DE2-70)(TRDB-D5M)(TRDB-LTM),我就曾經使用ALT_MULTADD這個Megafunction實現SobelEdgeDetector演算法。