![v2-91b0aeb949fe8ff14e6075fbd4457630_1440w.jpg?source=172ae18b](http://img-03.proxy.5ce.com/view/image?&type=2&guid=c6b00ea9-f02f-eb11-8da9-e4434bdf6706&url=https://pic1.zhimg.com/v2-91b0aeb949fe8ff14e6075fbd4457630_1440w.jpg?source=172ae18b)
所使用EDA软件:VIVADO2019.1.3
FPGA型号:xc7a35tcsg325-2
看完这篇文章你将收获以下内容:
- 理解什么是加法器,内容包括半加器,全加器,多位加法器。
- 联系多位加法器来理解XILINX FPGA进位链的结构以及功能。
在讲加法器之前,我们先来看个有关二进制加法的例子
我们先关注两个1位二进制数进行相加的情况,它最后只有4中结果(图1)。0+0=0,0+1=1,1+0=0,1+1=10
![v2-afdb14e3bc4c2ed2ef18736fc65b939b_b.jpg](http://img-03.proxy.5ce.com/view/image?&type=2&guid=c6b00ea9-f02f-eb11-8da9-e4434bdf6706&url=https://pic4.zhimg.com/v2-afdb14e3bc4c2ed2ef18736fc65b939b_b.jpg)
我们可以观察得到以下3点:
- 两个加数都为0,相加的结果为0。
- 两个加数1个为0,另一个为1时,它们相加的结果为1。
- 两个加数都为1时,当前位的结果会为0,但它会给下一位进1,所以最后结果为10。
求当前输出位的结果,我们会用到数电中的异或逻辑,逻辑符号为⊕。
求当前进位的结果,我们会用到数电中的与逻辑,逻辑符号位·。
假设两个加数分别为A,B 。相加后,当前位的结果为S,是否产生进位用C来描述。
那么我们可以得出:
- S=A⊕B
- C=A·B
对两个输入数据位(A、B)相加,输出一个结果位(S)和进位(C),没有进位输入的加法器电路我们将它称为半加器(图2)。上面的例子就是为了半加器中A,B,S,C是啥,以及他们之间的关系。千万别被半加器这个高大上的名字吓到,其实它就是拿来实现一个最最简单的二进制加法功能。
![v2-ff62a4681c41ac57720ba785f5f460a2_b.jpg](http://img-02.proxy.5ce.com/view/image?&type=2&guid=c6b00ea9-f02f-eb11-8da9-e4434bdf6706&url=https://pic3.zhimg.com/v2-ff62a4681c41ac57720ba785f5f460a2_b.jpg)
接下来我们看一个2位二进制加法的例子(图3)
![v2-4da61b100f79b14f2dd45e7f8fdf21aa_b.jpg](http://img-02.proxy.5ce.com/view/image?&type=2&guid=c6b00ea9-f02f-eb11-8da9-e4434bdf6706&url=https://pic3.zhimg.com/v2-4da61b100f79b14f2dd45e7f8fdf21aa_b.jpg)
对于第1位(从右往左)的1+1,由上面半加器的内容可知它相加后结果位(S1)为0,产生进位(COUT1)1。但是对于第2位的1+1来说(图3红框部分),它还需要接收由低位产生进位,才能计算当前位的结果位。多位二进制加法与十进制加法的规律是相似的,我们只需要将当前位相加,再加上低位的进位即为结果位,即1+1+1=1⊕1⊕1=1(从左往右计算,先算1⊕1=0,再算0⊕1=1)。如果当前的两个加数与进位里一共有两个或两个以上的1,那么它也会产生进位。
在第2位中我们用A2,B2,CIN2,S2,C2来分别表达两个加数,来自低位的进位,当前位的结果,当前位的进位,那么我们将得出:
- S2=A2⊕B2⊕CIN2=1⊕1⊕1=1
- C2=A2·B2+A2·CIN2+B2·CIN2+A2·B2·CIN2=A2·B2+A2·CIN2+B2·CIN2=1+1+1=1(注意这里的“+”指的是或操作)
- 同时C2也可以这样描述,C2=A2·B2+CIN2·(A2⊕B2),其实就是为了保证A2,B2,CIN2中有两个或两个以上的1。
在第3位中,两个加数A3=0,B3=0,来自低位的进位CIN3=1,用S3表示当前位的相加后的结果,C3表示当前位的进位我们可以得到
- S3=A3⊕B3⊕CIN3=0⊕0⊕1=1
- C3=A3·B3+A3·CIN3+B3·CIN3=0+0+0=0(注意这里的“+”代表着或)
由于最终没产生进位,第4位也没有相应的加数,最终的结果为{S3,S2,S1}=110
在数电中,我们用全加器(图4)来实现类似第2,3位这种加法操作。
![v2-0162dab9c867935b4252b9bda12e068c_b.jpg](http://img-02.proxy.5ce.com/view/image?&type=2&guid=c6b00ea9-f02f-eb11-8da9-e4434bdf6706&url=https://pic1.zhimg.com/v2-0162dab9c867935b4252b9bda12e068c_b.jpg)
到这里可能有人会问,是不是每次做多位加法计算时,我的最低位都要用上个半加器。其实不然,事实上,全加器只不过是比半加器多了个来自低位进位的功能而已,我们只需要将CIN置0就可以了,就可以忽视它这一功能,即将全加器当作半加器来用,再与全加器级联即可做成多位加法器(图5),A1~A4是一个加数的1到4位,B1~B4是另一个加数的1到4位,S4是结果的1到4位。(1是最低位,4是最高位)
![v2-3009f787ef12e114fa197a49dad85ee9_b.jpg](http://img-02.proxy.5ce.com/view/image?&type=2&guid=c6b00ea9-f02f-eb11-8da9-e4434bdf6706&url=https://pic2.zhimg.com/v2-3009f787ef12e114fa197a49dad85ee9_b.jpg)
那当我们将最第1个全加器的CIN置1,那么它与其他3个全加器级联将成为4位减法器(图6),A1~A4是被减数的1到4位,B1~B4是减数反码的1到4位,S4是结果的1到4位。(1是最低位,4是最高位)
![v2-f923e40f67bfe22ffb42f818540766e6_b.jpg](http://img-01.proxy.5ce.com/view/image?&type=2&guid=c6b00ea9-f02f-eb11-8da9-e4434bdf6706&url=https://pic3.zhimg.com/v2-f923e40f67bfe22ffb42f818540766e6_b.jpg)
此时的减法指的的补码形式的“减法”。不是指被减数 - 减数 ,而是指被减数的补码+减数负数形式的补码(即减数的反码+1)。所以图6中A[4:1]指的是被减数,B[4:1]指的是减数的反码,CIN1置1的目的就是为了减数的反码+1变成减数负数形式的补码。特别注意这里的A[4]、B[4]指的是符号位!!!。
拿0101-0010=0011(这里最高位(第4位)的0指的是符号位,0101的补码为0101,-0010的补码为1110,0011的补码为0011)作为个例子(图7)。最后的结果为0011(结果应为4位,忽略第5位,第5位“1”的作用就是为了告诉高位它要继续减,相当于第一位的CIN)。
![v2-2ba50501d0440d3c92c6a39d868abfd8_b.jpg](http://img-02.proxy.5ce.com/view/image?&type=2&guid=c6b00ea9-f02f-eb11-8da9-e4434bdf6706&url=https://pic1.zhimg.com/v2-2ba50501d0440d3c92c6a39d868abfd8_b.jpg)
好的,哔哔了那么多,下面我开开始讲我们今天的主角进位链。首先我们看一下XILINX 7系中进位链的结构(图8)。
![v2-d229f908e873eaa31dc98e0c0dd569b9_b.jpg](http://img-02.proxy.5ce.com/view/image?&type=2&guid=c6b00ea9-f02f-eb11-8da9-e4434bdf6706&url=https://pic2.zhimg.com/v2-d229f908e873eaa31dc98e0c0dd569b9_b.jpg)
红框框住的部分为它的1个基本单元(本质上是1个全加器)。
- CIN=进位输入(当它在最低位时,置0做加法,置1做减法)
- S0=A0⊕B0 (这里和全加器中的S有些区别),它来自LUTA的O6
- O0=S0 ⊕CIN=A0⊕B0 ⊕CIN(这里的O才是全加器的S),它来自LUTA的O5或外面外部输入AX
- DI0 = A0 或者 B0 (这里指的是两个加数中的一个,它的作用要配合S0)
- AX 是预置数,这里我们不过多关注
我们知道产生进位的条件在A B以及 CIN中有两个或两个以上的1。
- 当S0=0时,有两种情况,即两个加数都为0和两个加数都为1。此时,MUXCY选择DI0作为数据输入,CO0的结果由DI0决定。因为S0=0时,DI0为0等价于A0,B0,COUT0都为0。DI0为1等价于A0,B0,COUT0都为1。
- 当S0=1时,即A0与B0中有1个为1。此时,MUXCY选择CIN0作为数据输入,CO0的结果由CIN0决定。因为S0=1时,A0与B0中只有1个1,还缺1个1才能进位,进位所需的那个1就看CIN1肯不肯施舍了。
然后我们看一下1个8位加法的例子(例1),综合后的结果如图9所示。
//以下是例1
![v2-611c8c85e6f90cdcdace1f00dad5fe97_b.jpg](http://img-02.proxy.5ce.com/view/image?&type=2&guid=c6b00ea9-f02f-eb11-8da9-e4434bdf6706&url=https://pic4.zhimg.com/v2-611c8c85e6f90cdcdace1f00dad5fe97_b.jpg)
图9我们可以看到
- 进位链1的CO[3]连到进位链2的CI,两者级联产生更大位宽的进位链。
- 两个加数的低四位异或后连入进位链1的S[3:0],两个加数的高四位异或后连入进位链2的S[3:0]。
- 其中一个加数低四位(a[3:0])连入进位链1的DIN[3:0],a[6:4]连到了进位链2的DIN[2:0]。此时进位链2的DIN[3]直接置0,因为我们输出位只有8位所以无需关注最高位进位(进位链2的CO3),将DIN[3]置0来一来可以减小输入的翻转来降低功耗,二来可以减小输入数据的延迟不一致产生毛刺的概率。
- 进位链1 O[3:0]连到输出的低4位,进位链2的O[3:0]连到输出的高4位。
有关进位链的内容就大概说到这里,再补充两点。
- 进位链级联数有限制,它取决于当前列SLICE的个数,而且不能跨逻辑区域。如图10所示,两个逻辑区域间是有条“楚河汉界”的,逻辑区域里进位链最大级数等于绿框中的SLICE的高度(如果是多位全加器的位宽就是SLICE的高度x4,因为1个SLICE里有4个级联的全加器)。
![v2-af4e8c80dc4f16ef117d9f6aa8132885_b.jpg](http://img-02.proxy.5ce.com/view/image?&type=2&guid=c6b00ea9-f02f-eb11-8da9-e4434bdf6706&url=https://pic2.zhimg.com/v2-af4e8c80dc4f16ef117d9f6aa8132885_b.jpg)
- 进位链级联数越多,造成的路径延迟就会越大,这样会让时序十分的紧张。所以在使用进位链时要综合考虑级联数与整个系统速率的关系。例如在设计位宽较大的计数器,可以选择用DSP替换,也可以选择将位宽分隔。(如32位计数器,可将它分成高16位,与低16位,低16位计数到16'hffff,高16位计数才+1)
好的本节就到这里,又到了一节一度的求赞求关注环节,谢谢老板们!!!
公众号关注 FPGA说,你的关注将引来更多的优质好文。
http://weixin.qq.com/r/ZDlOVuvE5Labra8192x2 (二维码自动识别)