数字集成电路课程设计16位加法器
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
数字集成电路课程设计
——16位加法器
设计参数:
*输入两个16位的补码
*输出一个17位的补码
*允许采用流水线、单元复用等技术实现
设计要求:
*使用RTL级Verilog描述加法器架构
*使用门级验证加法器功能(ModelSim等仿真)
*优化方向:加法器等效总门数最少
*等效门数计算示例:INV=1, NOR2=NAND2=2, DFF=4
最终优化结果:
图1.1单个全加器单元的最终优化方案
图1.2 第17位结果的运算电路
最终总共等效门数= 16 X 17 + 7 = 279仿真结果:
1 2 3 4 5
图2. ModelSim仿真结果
如图2所示,箭头1所指区域为两个16位全0的加数,无进位,输出和为0;
箭头2所指区域为0与1000000000000000(-32768)相加,无进位,输出和为11000000000000000(-32768);
箭头3所指区域为0与1111111111111111(-1)相加,无进位,输出和为11111111111111111(-1);
箭头4所指区域为-1与1000000000000000(-32768)相加,无进位,输出和为10111111111111111(-32769);
箭头4所指区域为-1与1000000000000000(-32768)相加,进位为1,输出和为11000000000000000(-32768)。
可见已正确实现了16位补码加法器的功能。
设计思路:
首先,我们需要明确加法器的设计。
按照题目的要求,我们的加法器必须满足以下几个
原则:
1、16位加法器,且可以计算出第17位的进位;
2、可以计算补码;
3、设计出的结构门数最少.
由上面的要求,我们可以有对应的设计:
1.我们假定16位数据本身就是以补码形式储存的,那么最高位就是符号位,0代表正数,
1代表负数;由此,我们可以根据二进制加法的规则得知,计算补码不需要对储存的补码进
行任何形式的修改,利用正常的全加器结构就可以计算出正确的结论,包括位数扩展的要求
也能满足;
2.要完成17位的补码计算,需要进行符号位扩展,也就是将加数和被加数的最高位重复
一次变成17位的数据,如1000000000000000变为11000000000000000;在编码的时候,需要17个加法器,但是最后一个加法器的加数和被加数重复使用16位的数据,而进位则采用16位得到的进位;
3.加法器必须是一般意义上的加法器,除非采用流水线结构,否则不应使用时序逻辑,如下图所示的设计就不合理。
图3. 不合理的结构
上图中,一位全加器虽然只使用了一次,而计时器和选择器的器件代价也不大,但是计算一次16位加法却要等待16个时钟周期,这显然与加法器本身的要求不符合。
尤其是当这样的加法器集成在乘法器当中时,时间代价就将变得非常巨大。
因而我们在设计的时候不使用这样的加法器。
4.需要的门数最少,那么就在牺牲速度的情况下采用最简单的设计结构。
从上面的一些分析我们可以看出,原始的行波进位加法器相比超前进位加法器、流水线加法器等结构而言,虽然延时问题非常大,但是采用的门数却是最少的。
于是我们就在原始的全加器的结构上进行改进,再级联成17位行波进位加法器。
行波进位加法器
原始行波进位加法器统计:
Cell Usage :
# BELS : 136
# AND2 : 51
# INV : 17
# OR2 : 34
# XOR2 : 34
# IO Buffers : 50
# IBUF : 33
# OBUF : 17
将异或门的等效门数当作6,则总共等效门数为:
51 X 3 + 17 + 34 X 3 + 34 X 6 = 476
优化后RTL级Verilog代码:
moduletop_adder(c_in,a,b,s);
input[15:0] a,b;
inputc_in;
output[16:0] s;
wire c_0,c_1,c_2,c_3,c_4,c_5,c_6,c_7,c_8,c_9,c_10,c_11,c_12,c_13,c_14,c_15;
adder adder0(c_in,a[0],b[0],s[0],c_0);
adder adder1(c_0,a[1],b[1],s[1],c_1);
adder adder2(c_1,a[2],b[2],s[2],c_2);
adder adder3(c_2,a[3],b[3],s[3],c_3);
adder adder4(c_3,a[4],b[4],s[4],c_4);
adder adder5(c_4,a[5],b[5],s[5],c_5);
adder adder6(c_5,a[6],b[6],s[6],c_6);
adder adder7(c_6,a[7],b[7],s[7],c_7);
adder adder8(c_7,a[8],b[8],s[8],c_8);
adder adder9(c_8,a[9],b[9],s[9],c_9);
adder adder10(c_9,a[10],b[10],s[10],c_10);
adder adder11(c_10,a[11],b[11],s[11],c_11);
adder adder12(c_11,a[12],b[12],s[12],c_12);
adder adder13(c_12,a[13],b[13],s[13],c_13);
adder adder14(c_13,a[14],b[14],s[14],c_14);
adder adder15(c_14,a[15],b[15],s[15],c_15);
adder adder16(c_15,a[15],b[15],s[16],);
endmodule
module adder(c_in,a,b,s,c_out);
inputc_in,a,b;
outputs,c_out;
wire inter;
assign inter=a^b;
assign s=inter^c_in;
assignc_out=a*b + inter*c_in;
endmodule
其中module adder部分进行了一次小优化:在每个单独的一位加法器里这样设计,可以少一个与门。
最后只需要计算c_15^(a[15]^b[15]),而(a[15]^b[15])是上一级计算的结果,只需引入即可,因此只比16级的级联多一个异或门。
但即便一个异或门等效成6个门,与门和非门均视为一个与非门或者一个或非门加上一
个非门,那么每个1位加法器结构需要21个门;即便将一个异或门等效成5个门,这个结构也需要19个门。
考虑最高位只需要一个异或门,则总共使用与门32个、或门16个、异或门33个,等效门数为:
32*(2+1)+16*(2+1)+33*6= 342
优化后统计:
Cell Usage :
# BELS : 81
# AND2 : 32
# OR2 : 16
# XOR2 : 33
# IO Buffers : 50
# IBUF : 33
# OBUF : 17
于是,我们重新审视一下异或的计算公式:
a⊕b=ab+a b=ab∙a b=(a+b)(a+b)=a b+ab=a+b+ab 可以看到,上面语句assign c_out=a*b + inter*c_in中所要求的a*b以及inter*c_in已经自然包含在了异或的求值过程当中。
为此,我们的电路就可以完全省去两个与非门和两个非门。
因而,单个加法器单元可进一步进行优化(如图1.1)。
最高一位的运算电路如图1.2
最终优化后统计:
Cell Usage :
# BELS : 164
# NAND2 : 33
# NOR2 : 82
# INV : 49
# IO Buffers : 50
# IBUF : 33
# OBUF : 17
等效门数统计结果再次列出如下:
33 X 2+ 82 X 2 + 49 = 279
其他尝试
超前进位加法器:
图4. 超前进位加法器原理图
C i = G i+ P i C i-1
G i= A i B i
P i = A i + B i
P* = P3P2P1P0
G* = G3 + P3G2 + P3P2G1 + P3P2P1G0
超前进位加法器同样需要在最高位补上一个只算出和、而不要进位的一位加法器。
RTL级verilog代码:
module
full_adder(ci,a_03,b_03,s_03,a_47,b_47,s_47,a_811,b_811,s_811,a_1215,b_1215,s_1215,s_16); input[3:0] a_03;
input[3:0] a_47;
input[3:0] a_811;
input[3:0] a_1215;
input[3:0] b_03;
input[3:0] b_47;
input[3:0] b_811;
input[3:0] b_1215;
input ci;
output[3:0] s_03;
output[3:0] s_47;
output[3:0] s_811;
output[3:0] s_1215;
output s_16;
wire pp0,gg0,pp1,gg1,pp2,gg2,pp3,gg3,c3,c7,c11;
assign c3=gg0+pp0*ci;
assign c7=gg1+pp1*c3;
assign c11=gg2+pp2*c7;
assignc_sum=gg3+pp3*c11;
数字集成电路课程设计
carry_lookaheadadder0(ci,a_03,b_03,s_03,pp0,gg0);
carry_lookaheadadder1(c3,a_47,b_47,s_47,pp1,gg1);
carry_lookaheadadder2(c7,a_811,b_811,s_811,pp2,gg2);
carry_lookaheadadder3(c11,a_1215,b_1215,s_1215,pp3,gg3);
adder1 adder4(c_sum,a_1215[3],b_1215[3],s_16);
endmodule
modulecarry_lookahead(ci,a,b,s,pp,gg);
input ci;
input[3:0] a;
input[3:0] b;
output[3:0] s;
outputpp,gg;
wire c0,c1,c2;
wire p0,p1,p2,p3;
wire g0,g1,g2,g3;
assign p0=a[0]^b[0];
assign p1=a[1]^b[1];
assign p2=a[2]^b[2];
assign p3=a[3]^b[3];
assign g0=a[0]&b[0];
assign g1=a[1]&b[1];
assign g2=a[2]&b[2];
assign g3=a[3]&b[3];
assign c0=g0+p0*ci;
assign c1=g1+p1*c0;
assign c2=g2+p2*c1;
assignpp=p0*p1*p2*p3;
assigngg=g3+p3*g2+p3*p2*g1+p3*p2*p1*g0;
assign s[0]=p0^ci;
assign s[1]=p1^c0;
assign s[2]=p2^c1;
assign s[3]=p3^c2;
endmodule
module adder1(c_in,a,b,s);
inputc_in,a,b;
output s;
assign s=c_in^a^b;
endmodule
超前进位逻辑门数统计:
Cell Usage :
# BELS : 110
# AND2 : 36
# AND3 : 4
# AND4 : 8
# XOR2 : 62
# IO Buffers : 50
# IBUF : 33
# OBUF : 17
4级流水线加法器:
图5. 流水线加法器原理图
流水线加法器在有大量的计算的时候显示出自己的优势。
一个n级的流水线需要有n个加法器,4级的16位加法器就需要4个4位全加器(每个全加器为了节省时间可以用超前进位加法器实现)。
以4级流水线为例:这个流水线将计算的加数(比如a)和被加数(比如b)各分成4段(我们这里不考虑完成了17位补码的运算而只考虑16位来举例,若要完成17位的补码运算,需要扩展),分别是a[3-0],a[7-4],a[11-8],a[15-12],b[3-0],b[7-4],b[11-8],b[15-12].
在第一个时钟周期,a[3-0]和b[3-0]被读入并通过第一个加法器计算出来。
在第二个时钟周期,得到的结果被存入s1[3-0],同时a[7-4]和b[7-4]被读入第二个加法器计算出来;这个时候如果有加数c和被加数d,那么它们的最低四位就可以调入第一个加法器计算出来了。
在第三个时钟周期,上面计算的结果存入s2[7-4],为了保证s1[3-0]空出来留给其他的结果储存,s1[3-0]的数据会调入s2[7-4]中;同时调入a[11-8]和b[11-8]在第三个加法器求值。
依次类推,第四个周期存入第三个周期的结果并调入a和b的最高3位到第四个加法器求值。
在第五个时钟周期,第四个加法器的结果与之前存储的值将并行输出得到想要的求值。
通过这样的方法,一旦流水线满载,没一个时钟周期就可以得到一个结果,就大大增加了加法器的效率。
RTL级verilog代码
由于篇幅限制,见附件:4_stage_pipelined.v
流水线方式仿真结果:
图6. 流水线加法器仿真图
由图中可以看出:进位信号始终为1,在时钟周期(1),先计算出了低四位的正确结果,存在寄存器sum0中;在时钟周期(2)计算出了从最低位数起第5到第8位的部分和,连同sum0中的结果一起存到寄存器sum1中;时钟周期(3)的情况也类似,sum2存了12位的结果;在时钟周期(4),最后的完整计算结果被送至输出。
4级流水逻辑门数统计: Cell Usage : # BELS : 80 # AND2 : 32 # XOR2 : 48
# FlipFlops/Latches : 92 # FD : 92
# IO Buffers : 51 # IBUF : 34 # OBUF : 17
设计总结
从上面的设计和化简的过程来看,我们可以得出以下的结论:
1. 回归数字逻辑的本原是电路化简的一个重要的手段,比如我们学习数字逻辑时采用的卡诺图,就是经典的化简方式。
电路的结构越是仔细规划,就越能够得到简单的结果。
即便是异或门这样的基础门电路,由于其是更简单的“与或非”的组合,在必要的时候把其拆开,有的时候也可以得到很好的化简效果。
2. 手工化简的方式对于小规模的电路是适用的,电路的结构越复杂就越不合适。
在我们现今工业上使用的超大规模集成电路设计时使用这样的方式显然是不可能的,这也是为什么我们现在使用top-down 的设计的原因。
1
2
3
4
3.器件代价和时间代价有的时候是需要做出折衷的。
就比如这个加法器电路,越是简单的设计就越节省门的数量,但是延时也是巨大的;16位的加法器可能不同的设计方法得到的延时还不是很悬殊,但一旦位数增加,延时上的巨大差别就会立刻体现出来。
相反的,如果采用流水线、超前进位等方法来减少时间上的成本,那就势必要增加电路的复杂程度。
在当今电路的设计上,很多的时候我们必须兼顾时间成本和器件成本,因而超前进位和4级流水等都是比较划算的设计。
4.最后,设计和化简电路需要耐心和不断的尝试,这个在设计的过程当中深有体会。
我们也需要耐心才能很好地完成设计的要求。