文章目录
一、半加法器(Half Adder)
输入:
A
A
A、
B
B
B(代表相加的两个位)
输出:
S
S
S(代表
A
A
A与
B
B
B的和)、
C
out
C_{\text{out}}
Cout(进位)
计算公式:
- S = A ⊕ B S=A\oplus B S=A⊕B( A A A和 B B B的异或)
- C out = A B C_{\text{out}}=AB Cout=AB( A A A和 B B B进行与操作,仅当 A A A、 B B B同时为 1 1 1时才进位)
图示:
二、全加器(Full Adder)
输入:
A
A
A、
B
B
B(相加的两个位)、
C
in
C_{\text{in}}
Cin(上一位的进位)
输出:
S
S
S、
C
out
C_{\text{out}}
Cout
功能:计算 A + B + C in A+B+C_{\text{in}} A+B+Cin,输出 S S S和进位 C out C_{\text{out}} Cout
计算公式:
- S = A ⊕ B ⊕ C in S=A\oplus B\oplus C_{\text{in}} S=A⊕B⊕Cin(注意 A ⊕ B A\oplus B A⊕B本质上等于 ( A + B ) mod 2 (A+B)\ \text{mod}\ 2 (A+B) mod 2)
- C out = A B + A C in + B C in C_{\text{out}}=AB+AC_{\text{in}}+BC_{\text{in}} Cout=AB+ACin+BCin(在 A , B , C in A,B,C_{\text{in}} A,B,Cin中至少有两个为 1 1 1则需进位)
图示:
三、进位传播加法器(Carry Propagate Adder, CPA)
输入:两个
N
N
N位输入
A
,
B
A,B
A,B;一位进位
C
in
C_{\text{in}}
Cin
输出:一个
N
N
N位输入
S
S
S;进位
C
out
C_{\text{out}}
Cout
实现方法:行波进位加法器、先行进位加法器、前缀加法器
图示:
1. 行波进位加法器(Ripple-Carry Adder)
构造方法:把
N
N
N个全加器串联起来,一级的
C
out
C_{\text{out}}
Cout作为下一级的
C
in
C_{\text{in}}
Cin
缺点:当
N
N
N较大时运算速度会慢下来
延迟:
t
ripple
=
N
t
FA
t_{\text{ripple}}=Nt_{\text{FA}}
tripple=NtFA,其中
t
FA
t_{\text{FA}}
tFA为全加器的延迟
图示:
2. 先行进位加法器(Carry-Lookahead Adder, CLA)
特点:把加法器分成若干块,在每块一得到输入进位时就快速算出此块的输出进位。例如,
32
32
32为加法器
=
=
=
8
×
4
8\times4
8×4位的块
原理:
- 进位分两种:(考虑第
i
i
i位,也叫第
i
i
i列)
- A i A_i Ai和 B i B_i Bi(均为 1 1 1时)本身就能产生进位——产生进位,令 G i = A i B i G_i=A_iB_i Gi=AiBi
- A i A_i Ai或 B i B_i Bi为 1 1 1,且在有上一位的进位 C i − 1 C_{i-1} Ci−1时才能进位——传播进位,令 P i = A i + B i P_i=A_i+B_i Pi=Ai+Bi
- 因此第 i i i位的进位 C i = A i B i + ( A i + B i ) C i − 1 = G i + P i C i − 1 C_i=A_iB_i+(A_i+B_i)C_{i-1}=G_i+P_iC_{i-1} Ci=AiBi+(Ai+Bi)Ci−1=Gi+PiCi−1
- 推广到多位构成的块:
- 一个块在不考虑进位输入的情况下也能发生进位——产生进位
- 一个块在有进位输入时才能进位——传播进位
- 定义
G
i
:
j
G_{i:j}
Gi:j和
P
i
:
j
P_{i:j}
Pi:j为从第
i
i
i到第
j
j
j为的产生和传播信号
- 一个块产生进位( G i : j = 1 G_{i:j}=1 Gi:j=1)的条件:最高位产生进位,或最高位传播进位且前一位产生进位。设块的位数是 i : 0 i:0 i:0,则有递推公式 G i : 0 = G i + P i G i − 1 : 0 G_{i:0}=G_i+P_iG_{i-1:0} Gi:0=Gi+PiGi−1:0。当 i = 3 i=3 i=3时有 G 3 : 0 = G 3 + P 3 ( G 2 + P 2 ( G 1 + P 1 G 0 ) ) G_{3:0}=G_3+P_3(G_2+P_2(G_1+P_1G_0)) G3:0=G3+P3(G2+P2(G1+P1G0))
- 一个块传播进位( P i : j = 1 P_{i:j}=1 Pi:j=1)的条件:输入到块中的进位 C j − 1 C_{j-1} Cj−1能经过块传到 C i C_i Ci,这就要求进行环环相扣的进位(连锁反应),即块中的每一列都能传播进位。则 P i : 0 = P i P i − 1 ⋯ P i P 0 P_{i:0}=P_iP_{i-1}\cdots P_iP_0 Pi:0=PiPi−1⋯PiP0
- 因此块的生成和传播信号可由 C j − 1 C_{j-1} Cj−1、 G i : j G_{i:j} Gi:j和 P i : j P_{i:j} Pi:j快速算出: C i = G i : j + P i : j C j − 1 C_i=G_{i:j}+P_{i:j}C_{j-1} Ci=Gi:j+Pi:jCj−1
延时: t CLA = t pg + t pg_block + ( N k − 1 ) t AND_OR + k t FA t_{\text{CLA}}=t_{\text{pg}}+t_{\text{pg\_block}}+\left(\frac Nk-1\right)t_{\text{AND\_OR}}+kt_{\text{FA}} tCLA=tpg+tpg_block+(kN−1)tAND_OR+ktFA
- t pg t_{\text{pg}} tpg:计算 P i P_i Pi和 G i G_i Gi所需要的时间(即单独的 AND \text{AND} AND或 OR \text{OR} OR门的延时)
- t pg_block t_{\text{pg\_block}} tpg_block:计算 P i : j P_{i:j} Pi:j和 G i : j G_{i:j} Gi:j所需要的时间
- t AND_OR t_{\text{AND\_OR}} tAND_OR:在 k k k位CLA块中计算 C out = G i : j + P i : j C in C_{\text{out}}=G_{i:j}+P_{i:j}C_{\text{in}} Cout=Gi:j+Pi:jCin的时间(共有 N k \frac Nk kN个 C L A CLA CLA块,但位数最高的块不需要进位给下一个块,所以这个块直接用行波进位加法器即可)
- t FA t_{\text{FA}} tFA:全加器的延迟(关键路径有 k k k个全加器,就是位数最高的块的行波进位加法器里面的;其他块都可以提前结束计算,对总延迟没有影响)
当 N > 16 N>16 N>16时,CLA会比行波进位加法器快很多。然而,加法器的延迟仍然随 N N N的增长而线性增长。
图示:
3. 前缀加法器(Prefix Adder)
- 策略:
- 回顾 S i S_i Si的表达式: S i = ( A i ⊕ B i ) ⊕ C i − 1 S_i=(A_i\oplus B_i)\oplus C_{i-1} Si=(Ai⊕Bi)⊕Ci−1
- 定义第 − 1 -1 −1列以包含 C in C_{\text{in}} Cin,则 G − 1 = C in G_{-1}=C_{\text{in}} G−1=Cin( C in = 1 C_{\text{in}}=1 Cin=1就是有进位), P − 1 = 0 P_{-1}=0 P−1=0(不可能有传播进位)
- 若从 − 1 -1 −1到 i − 1 i-1 i−1位中生成一个进位,则第 i − 1 i-1 i−1位会有进位输出,故 C i − 1 = G i − 1 : − 1 C_{i-1}=G_{i-1:-1} Ci−1=Gi−1:−1
- 生成的位要么在第 i − 1 i-1 i−1位生成,要么从之前的位中生成并传播到第 i − 1 i-1 i−1位
- 因此 S i = ( A i ⊕ B i ) ⊕ G i − 1 : − 1 S_i=(A_i\oplus B_i)\oplus G_{i-1:-1} Si=(Ai⊕Bi)⊕Gi−1:−1
核心问题:快速计算
G
−
1
:
−
1
,
G
0
:
−
1
,
G
2
:
−
1
,
⋯
,
G
N
−
2
:
−
1
G_{-1:-1},G_{0:-1},G_{2:-1},\cdots,G_{N-2:-1}
G−1:−1,G0:−1,G2:−1,⋯,GN−2:−1
前缀:
G
−
1
:
−
1
,
G
0
:
−
1
,
G
2
:
−
1
,
⋯
,
G
N
−
2
:
−
1
G_{-1:-1},G_{0:-1},G_{2:-1},\cdots,G_{N-2:-1}
G−1:−1,G0:−1,G2:−1,⋯,GN−2:−1和
P
−
1
:
−
1
,
P
0
:
−
1
,
P
2
:
−
1
,
⋯
,
P
N
−
2
:
−
1
P_{-1:-1},P_{0:-1},P_{2:-1},\cdots,P_{N-2:-1}
P−1:−1,P0:−1,P2:−1,⋯,PN−2:−1
思想:二分法(与线段树类似)
计算
G
G
G、
P
P
P的方法:
- G i : j = G i : k + P i : k G k − 1 : j G_{i:j}=G_{i:k}+P_{i:k}G_{k-1:j} Gi:j=Gi:k+Pi:kGk−1:j
- P i : j = P i : k P k − 1 : j P_{i:j}=P_{i:k}P_{k-1:j} Pi:j=Pi:kPk−1:j
证明:
(1) 根据我们前面提到的“连锁反应”,第 j − 1 j-1 j−1位的进位传播到第 i i i位需要 P j P_j Pj到 P i P_i Pi均为 1 1 1,故 P i : j = P i : k P k − 1 : j P_{i:j}=P_{i:k}P_{k-1:j} Pi:j=Pi:kPk−1:j。
(2) 在第 j j j到第 i i i位产生进位的条件是第 i i i位本身能产生进位,或第 j j j到 i − 1 i-1 i−1位能传播进位且第 i i i位能传播进位。所以我们有递推公式 G i : j = G i + P i G i − 1 : j G_{i:j}=G_i+P_iG_{i-1:j} Gi:j=Gi+PiGi−1:j。同理,条件也可以是第 j + 1 j+1 j+1到第 i i i位能产生进位,或第 j j j位能产生进位且第 j + 1 j+1 j+1到第 i i i位能传播进位,所以有 G i : j = G i : j + 1 + P i : j + 1 G j G_{i:j}=G_{i:j+1}+P_{i:j+1}G_j Gi:j=Gi:j+1+Pi:j+1Gj。
下面采用数学归纳法证明 G i : j = G i : k + P i : k G k − 1 : j G_{i:j}=G_{i:k}+P_{i:k}G_{k-1:j} Gi:j=Gi:k+Pi:kGk−1:j。
①当 k = i k=i k=i时,注意到 G i : k = G i : i = G i G_{i:k}=G_{i:i}=G_i Gi:k=Gi:i=Gi, P i : k = P i : i = P i P_{i:k}=P_{i:i}=P_i Pi:k=Pi:i=Pi,故结论显然成立。
②假设当 k = u k=u k=u时成立。则当 k = u − 1 k=u-1 k=u−1时, G i : j = G i : u + P i : u G u − 1 : j = G i : u + P i : u ( G u − 1 + P u − 1 G u − 2 : j ) = ( G i : u + P i : u G u − 1 ) + P i : u P u − 1 G u − 2 : j = G i : u − 1 + P i : u − 1 G u − 2 : j = G i : k + P i : k G k − 1 : j G_{i:j}=G_{i:u}+P_{i:u}G_{u-1:j}=G_{i:u}+P_{i:u}(G_{u-1}+P_{u-1}G_{u-2:j})=(G_{i:u}+P_{i:u}G_{u-1})+P_{i:u}P_{u-1}G_{u-2:j}=G_{i:u-1}+P_{i:u-1}G_{u-2:j}=G_{i:k}+P_{i:k}G_{k-1:j} Gi:j=Gi:u+Pi:uGu−1:j=Gi:u+Pi:u(Gu−1+Pu−1Gu−2:j)=(Gi:u+Pi:uGu−1)+Pi:uPu−1Gu−2:j=Gi:u−1+Pi:u−1Gu−2:j=Gi:k+Pi:kGk−1:j,结论成立。
综上,计算 G G G、 P P P的方法是正确的。
因此,我们取 k k k为 j j j到 i i i的区间中点即可完成二分计算。
图示(16位前缀加法器):
例如,
G
14
:
−
1
=
G
14
:
7
+
P
14
:
7
G
6
:
−
1
G_{14:-1}=G_{14:7}+P_{14:7}G_{6:-1}
G14:−1=G14:7+P14:7G6:−1,
P
14
:
7
=
P
14
:
11
P
10
:
7
P_{14:7}=P_{14:11}P_{10:7}
P14:7=P14:11P10:7。并且
G
0
:
−
1
=
G
0
+
P
0
G
−
1
G_{0:-1}=G_0+P_0G_{-1}
G0:−1=G0+P0G−1,
P
0
:
−
1
=
P
0
P
−
1
P_{0:-1}=P_0P_{-1}
P0:−1=P0P−1。
黑色单元构成的网络成为前缀树(prefix tree)。
延迟: N N N位前缀加法器的关键路径:
- 各 P i P_i Pi和 G i G_i Gi的预计算(是同时进行的): t pg t_{\text{pg}} tpg
- 获得前缀 G i : j G_{i:j} Gi:j和 P i : j P_{i:j} Pi:j: log 2 N ⋅ t pg_prefix \log_2{N}\cdot t_{\text{pg\_prefix}} log2N⋅tpg_prefix
- 通过XOR门计算 S i S_i Si: t XOR t_{\text{XOR}} tXOR
故总延迟 t PA = t pg + log 2 N ⋅ t pg_prefix + t XOR t_{\text{PA}}=t_{\text{pg}}+\log_2{N}\cdot t_{\text{pg\_prefix}}+t_{\text{XOR}} tPA=tpg+log2N⋅tpg_prefix+tXOR,以 N N N的对数增长。这明显提高了速度,但需消耗更多的硬件资源。
四、减法器
用补码表示负数:正数
B
B
B的相反数是
B
B
B的二进制表示取反再加
1
1
1。
故
A
−
B
=
A
+
B
A-B=A+B
A−B=A+B的补码。
因此,减法器可以将输入 B B B取反,设置 C in = 1 C_{\text{in}}=1 Cin=1,与 A A A相加即可。
图示:
参考书目
《数字设计和计算机体系结构》机械工业出版社