注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

dp: 生活的脚步,进步的点滴...

Cam、DSP、FPGA、PM、Life、More ...

 
 
 

日志

 
 

Verilog如何实现乘加运算?  

2013-03-28 09:12:48|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

Abstract
z = a*b + c*d;一个很简单的运算,该如何使用verilog实现?

Introduction
使用環境:Quartus II 8.0

由于Verilog與數位電路本身的限制,不適合真的去實現很複雜的數學,就算真的實現出來,電路也跑不快,又佔resource,所以我們常會重新修改演算法配合數位電路的特性,通常演算法修改到最後,都會只剩下簡單的乘法與加法運算,也就是y = a*b + c*d的型式。

Method 1:
一般寫法

ALT_MULTADD.v / Verilog

复制代码
1 /* 
2 (C) OOMusou 2008 http://oomusou.cnblogs.com
3 
4 Filename    : ALT_MULTADD.v
5 Compiler    : Quartus II 8.0
6 Description : Demo how to write y = a*b + c*d
7 Release     : 10/11/2008 1.0
8 */
9 
10 module ALT_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 assign oRESULT = result;
27 
28 always@(posedge iCLK, negedge iRST_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
复制代码


模擬結果

multadd00

輸出結果會delay 2個clock,為什麼會這樣呢?這可由合成結果來解釋。

合成結果

multadd02

輸出輸入都使用reg寄存,所以一共delay 2個clock,中間是組合電路負責乘加運算。

Fmax為195.43MHz

multadd01 

Method 2:
使用Pipeline

ALT_MULTADD_pipe.v / Verilog

复制代码
1 /* 
2 (C) OOMusou 2008 http://oomusou.cnblogs.com
3 
4 Filename    : ALT_MULTADD_pipe.v
5 Compiler    : Quartus II 8.0
6 Description : Demo how to write y = a*b + c*d with pipeline
7 Release     : 10/11/2008 1.0
8 */
9 
10 module ALT_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 assign oRESULT = result;
31 
32 always@(posedge iCLK, negedge iRST_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
复制代码


模擬結果

multadd03 

輸出結果會delay 3個clock,為什麼會這樣呢?這可由合成結果來解釋。

合成結果

multadd04

由於使用了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時,其實腦筋想的正是RTL Viewer合成出來的結果, 這也是為什麼寫Verilog時,不能像寫C一樣,只要語法對就好,剩下就是Compiler幫你優化,由於目前C compiler優化能力都很強,所以就算你亂寫,優化出來的結果也差不多,但寫Verilog卻要時時想著你想描述的硬體,

Fmax為260MHz

multadd05

加上pipeline後,Fmax大增,為什麼加上pipeline後,Fmax增加這麼多呢?尤其若你原本是寫C的背景,看到Verilog多了幾個reg後,差異就這麼大,一定很難理解。

解釋pipeline的書很多,在有名的算盤書(Computer Organization & Design The Hardware / Software Interface) Ch.6講得很清楚,在這我用另外一種方法來解釋。

在同步設計中,電路的設計都是循序電路、組合電路交錯的組合,由上面兩個合成結果也能發現這種設計,為了要同步,所以必須很穩定的前一個clock在第1級reg,而下一個clock在第2級reg,因為Fmax是period的倒數,兩級reg中間的組合電路所需時間越長,period一定越大,倒數後的Fmax就越小。

在Method 1中

result <= a0 * b0 + a1 * b1;


要乘要加,這樣的組合電路一定要花較長的時間,所以period也越大,Fmax當然也變小。

在Method 2中

m0 <= a0 * b0;
m1
<= a1 * b1;
   
result
<= m0 + m1;


將相乘跟相加分開來做,先將乘法運算的結果做寄存,然後再作加法運算,這樣每個組合電路的時間變少,所以period也變小,Fmax當然也變大了。

但pipeline也是有trade off!!

多花了一級reg,所以delay時間會變長,也就是一開始會慢一個clock出來,但之後每個clock都有產出,換來的就是Fmax變大。

所以有人說,硬體加速基本上就是將演算法切得很細來加速,就是因為pipeline的關係。

看到這裡,你或許會說:
『y = a*b + c*d在C只要一行的東西,在Verilog我要寫這麼多行?那真的去寫一個演算法還得了?』

幸好Altera提供了Megafunction,讓我們可以很輕鬆的計算y = a*b + c*d。

Method 3:
使用Megafunction:ALT_MULTADD

ALT_MULTADD_mf.v / Verilog

复制代码
1 /* 
2 (C) OOMusou 2008 http://oomusou.cnblogs.com
3 
4 Filename    : ALT_MULTADD_mf.v
5 Compiler    : Quartus II 8.0
6 Description : Demo how to write y = a*b + c*d by Megafunction
7 Release     : 10/11/2008 1.0
8 */
9 
10 module ALT_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 MAC mac0 (
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夠精簡了吧!!

模擬結果

multadd06 

與Method 2的結果一樣delay 3個clock,可見Megafunction:ALT_MULTADD預設已經加上了pipeline。

合成結果

 multadd07

很單純的只有一個MAC block。

Fmax一樣為260MHz

multadd08

所以不用擔心Megafunction:ALT_MULTADD沒自己寫code效率好。

如何使用Megafunction:ALT_MULTADD?

Tool -> MegaWizard Plug-In Manager

multadd09

之後就是wizard介面,跟著一步一步設定即可。Megafunction:ALT_MULTADD預設已經將input與output用reg做寄存,所以我們只需單純的用wire連進去即可。

完整程式下載
ALT_MULTADD.7z (一般寫法)
ALT_MULTADD_pipe.7z (使用pipeline)
ALT_MULTADD_mf.7z (使用Megafunction:ALT_MULTADD)

Conclusion
本文所要傳達的重點有3:
1.寫Verilog不能像寫C一樣,只要語法對就好,剩下的優化就交給C compiler;寫Verilog時要時時想著你要描述的硬體,因為合成器會依照你的code去做合成,寫法的差異影響結果甚鉅。

2.解釋pipeline概念,這是c coder學Verilog很難理解的地方。

3.Altera提供了不少好用Megafunction,不僅方便,而且執行效率甚至比我們自己寫的還好些,應該盡量使用Megafunction增加開發效率以及執行效率。

  评论这张
 
阅读(377)| 评论(0)
推荐

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2016