1. 程式人生 > >forahead adder 超前進位加法器

forahead adder 超前進位加法器

數電書上說道超前進位加法器,沒有仔細講。上網搜了這篇資料,摘抄下來

序列進位加法器需要一級一級的進位,進位延遲很大。先行進位加法器(也叫超前進位加法器)可以有效的減少進位延遲。

    設二進位制加法器的第i位輸入為Xi, Yi, 輸出為Si, 進位輸入為Ci,進位輸出為Ci+1

則有

         Si = Xi⊕Yi⊕Ci

      Ci+1  = Xi·Yi + Xi·Ci + Yi·Ci = Xi·Yi + (Xi + Yi)·Ci

令Gi = Xi·Yi,     Pi = Xi+Yi

則Ci+1  = Gi + Pi·Ci

當Xi和Yi都為1時,Gi = 1,產生進位Ci+1 

= 1

當Xi和Yi有一個為1時,Pi = 1,傳遞進位Ci+1 = Ci

    因此Gi 定義為進位產生訊號,Pi定義為進位傳遞訊號。Gi的優先順序比Pi高,也就是說:當Gi = 1時(當然此時也有 Pi = 1 ),無條件產生進位,而不管Ci是多少;

當Gi=0而Pi=1時,進位輸出為Ci, 跟Ci之前的邏輯有關。

    下面推導4位超前進位加法器。設4位加數和被加數為A 和 B,進位輸入為Cin, 進位輸出為Cout, 對於第i位的進位產生Gi = Ai·Bi , 進位傳遞 Pi=Ai+Bi , i=0,1,2,3

於是這各級進位輸出,遞迴的展開Ci ,有:

C0 = Cin

C1=G0 + P0·C0

C2=G1 + P1·C1 = G1 + P1·(G0 + P0·C0)=G1 + P1·G0 + P1·P0 ▪C0

C3=G2 + P2·C2 = G2 + P2·G1 + P2·P1·G0 + P2·P1·P0·C0

C4=G3 + P3·C3 = G3 + P3·G2 + P3·P2·G1 + P3·P2·P1·G0 + P3·P2·P1·P0·C0

Cout=C4

    由此可以看出,各級的進位彼此獨立產生,只與輸入資料和Cin有關,將各級間的進位級聯傳播給去掉了,因此減小了進位產生的延遲。

    每個等式與只有三級延遲的電路對應,第一級延遲對應進位產生訊號和進位傳遞訊號,後兩級延遲對應上面的積之和,這可由Synplify綜合後的RTL電路看到。

同時由真值表可以簡單的得出第i位的和為:

            Si = Xi⊕Yi⊕Ci = (Xi·Yi)⊕(Xi+Yi)⊕Ci = Gi⊕Pi⊕Ci

    根據上面的式子便可以設計出超前進位加法器。按照《數字系統設計與Verilog HDL》中的方法,用Verilog編寫了4位超前進位加法器,程式碼如下:

複製程式碼
 1 module add_ahead(a,b,sum,cin,cout
 2     );
 3 input [3:0] a,b;
 4 input cin;
 5 output [3:0] sum;
 6 output cout;
 7 wire c1,c2,c3;//各級進位輸出
 8 wire [3:0] g,p;
 9 
10 //產生第 0 位的本位值和進位輸出
11 assign g[0]= a[0]& b[0];
12 assign p[0]= a[0]| b[0];
13 assign sum[0]= g[0]^p[0]^cin;
14 assign c1=g[0]|(p[0]&cin);
15 
16 //產生第 1 位的本位值和進位輸出
17 assign g[1]= a[1]& b[1];
18 assign p[1]= a[1]| b[1];
19 assign sum[1]= g[1]^p[1]^c1;
20 assign c2=g[1]|(p[1]&c1);
21 
22 //產生第 2 位的本位值和進位輸出
23 assign g[2]= a[2]& b[2];
24 assign p[2]= a[2]| b[2];
25 assign sum[2]= g[2]^p[2]^c2;
26 assign c3=g[2]|(p[2]&c2);
27 
28 //產生第 3 位(最高位)的本位值和進位輸出
29 assign g[3]= a[3]& b[3];
30 assign p[3]= a[3]| b[3];
31 assign sum[3]= g[3]^p[3]^c3;
32 assign cout=g[3]|(p[3]&c3);
33 
34 endmodule
複製程式碼

這段程式碼在實現c2,c3,cout的時候,仍然用了前一級的進位,我開始以為綜合器會自動展開,但是用Synplify綜合後發現,每一位的進位仍然與前一位的進位輸出有關。於是將上面計算c2,c3,cout的程式碼用上面展開後的公式實現,如下:

1 assign c2=g[1]|(p[1]&g[0])|(p[1]&p[0]&cin);
2 assign c3=g[2]|(p[2]&g[1])|(p[2]&p[1]&g[0])|(p[2]&p[1]&p[0]&cin);
3 assign cout=g[3]|(p[3]&g[2])|(p[3]&p[2]&g[1])|(p[3]&p[2]&p[1]&g[0])|(p[3]&p[2]&p[1]&p[0]&cin);

再用Synplify綜合,發現c1,c2,c3,cout都只與初始進位和輸出資料有關,各級進位間不存在進位延遲了。

 修改後的程度用Modelsim模擬結果正確。

其實比較好理解,就是如果按照正常的加法進行進位,如果使用邏輯電路,那麼第一次的進位會加到第二次的進位上,第二次的進位會加到第三次上,這樣實際上第一次的進位會一直傳遞到最後一次的進位上,這樣必然會導致較大的延遲,delay。而如果採用時序電路的話,那麼就會需要幾次進位,就延遲幾個週期之後才能輸出資料,這樣的latency較大。

採用了超前進位的方法就把剛才的情況避免了,因為超前進位歸納了進位的特點,每一次的進位都和之前的進位無關,只和之前的p和g的結果有關,而這些p和g的結果是可以通過一個時鐘週期就計算出來的,即1)一個時鐘週期內,計算出所有的p,g  2)第二個時鐘週期內,計算出所有的c 3)第三個時鐘週期,計算出所有的s。並且如果對很長的數進行加法,可以拆成小的位數進行相加。即64bit的加法操作可以拆成32bit的加法操作。