赞
踩
目录
【实验四】设计一个16-bit 8421-BCD码全加器模块
此次实验为设计一个16位全加器模块并对其进行测试,本实验是以数据流的方式描述全加器模块,其中16位全加器有一个进位输入端和一个进位输出端,以及16位的数据输入和输出端,实现16位数据的计算,具体的实验如下。
由分析可知,该实验的逻辑表达式如下所示:
s+cout=cin+A+B
cout=A+B+cin
s=A+B+cin
该设计模块的实验框图如下:
(1) 设计模块Design Block
- module bit16FullAdder(cout,s,A,B,cin);
- output[15:0] s;
- output cout;
- input[15:0] A,B;
- input cin;
- assign {cout,s}=A+B+cin;
- endmodule
(2) 激励模块Test Bench
- // Generated on "04/01/2022 16:31:02"
- // Verilog Test Bench template for design : bit16FullAdder
- // Simulation tool : ModelSim (Verilog)
- `timescale 1ns/1ns
- module bit16FullAdder_vlg_tst();
- wire[15:0] s;
- wire cout;
- reg[15:0] A,B;
- reg cin;
- bit16FullAdder bit16FullAdder(.cout(cout),.s(s),.A(A),.B(B),.cin(cin));
- initial
- begin
- #0 A = 16'b0000_0000_0000_0000; B = 16'b0000_0000_0000_0000; cin = 1'b0;
- #5 A = 16'b0000_0000_1000_0000; B = 16'b0000_0000_1000_0001; cin = 1'b1;
- #5 A = 16'b1000_1000_1000_1000; B = 16'b1000_1000_1000_1000; cin = 1'b0;
- #5 A = 16'b1111_1111_1111_1111; B = 16'b1111_1111_1111_1111; cin = 1'b1;
- #5 $finish;
- end
-
- initial
- $monitor("At time %t, A(%b) + B(%b) + cin(%b) = s(%b)(%2d),cout(%b)",$time, A, B, cin, s, s, cout);
- endmodule
【实验具体内容】
本实验实现一个16位全加器的设计和调试,在这个实验中实现的是从元件例化的方面进行说明和描述,所谓16位全加器就是需要有一个进位输入端和一个进位输出端,以及16位的数据输入和输出端,实现16位数据的计算。所实现的数据计算如下:
s+cout = cin+a+b
s=a+b+cin
cout = a+b +cin
其中,全加器的真值表如下所示:
其逻辑表达式为:
S = A⊕B⊕CI
CO=AB+CI(A+B)
按照自底向上的逻辑逐级设计,四位全加器可对两个多位二进制数进行加法运算,同时产生进位。当两个二进制数相加时,较高位相加时必须加入较低位的进位项(CI),以得到输出为和(S)和进位(C0)。其中CIN表示输入进位位,COUT表示输出进位位,输入A和B分别表示加数和被加数。输出SUM=A+B+CIN,当SUM大于255时,COUT置‘1’。四位加法器原理图如下:
再由四位加法器按层次封装即可形成十六位加法器。
- module half(a,b,sum,co);//首先定义半加器模块
- input a;//定义输入端口
- input b;
- output sum;//定义输出端
- output co;//定义进位信号co
- assign sum=a ^ b;//采用数据流的方式表达逻辑表达式
- assign co=a & b;
-
- endmodule
-
- module full1(a,b,cin,co,sum);//然后定义一位全加器
- input a;//定义输入端口
- input b;
- input cin;//定义进位信号cin
- output sum;//定义输出端
- output co;//定义进位输出信号co
-
- wire s0,c0,c1;//定义三条wire类型的连线,其中s0是第一个半加器结果和第二个半加器输入的连接,c0是第一个半加器的进位输出,c1是第二个半加器的进位输出信号
-
- half half_inst1(.a(a),.b(b),.sum(s0),.co(c0));
- half half_inst2(.a(s0),.b(cin),.sum(sum),.co(c1));//定义两个半加器,将其元件例化并连接相应的端口
- assign co=c0|c1;//采用数据流描述输出的进位输出信号co
-
- endmodule
-
- module full4(a,b,cin,sum,co);//定义4为的加法器
- input[3:0] a;
- input[3:0] b;//两个4位的输入信号a和b
- input cin;//定义输入的进位信号cin
- output[3:0] sum;//定义输出的和sum
- output co;//定义输出的进位信号
-
- wire c0;
- wire c1;//定义三条wire类型的连线
- wire c2;//分别是前一个一位加法器的进位输出与后一个一位加法器的进位输入之间的连线
-
- full1 full1_inst1(.a(a[0]),.b(b[0]),.cin(cin),.sum(sum[0]),.co(c0));
- full1 full1_inst2(.a(a[1]),.b(b[1]),.cin(c0),.sum(sum[1]),.co(c1));
- full1 full1_inst3(.a(a[2]),.b(b[2]),.cin(c1),.sum(sum[2]),.co(c2));
- full1 full1_inst4(.a(a[3]),.b(b[3]),.cin(c2),.sum(sum[3]),.co(co));//四位的加法器是由四个一位的加法器组成的,分别进行元件例化和端口的连接
-
- endmodule
-
- module bit16Level(a,b,cin,sum,co);//定义十六位的加法器
- input[15:0] a;
- input[15:0] b;//定义两个十六位的加数输入
- input cin;//定义一个进位输入
- output[15:0] sum;//定义sum为十六位的和的输出
- output co;//定义co为进位输出
-
- wire c0;//定义wire型的连线
- wire c1;//是前一个四位加法器的进位输出
- wire c2;//与后一个四位加法器的进位输入之间的连线
-
- full4 full4_inst1(.a(a[3:0]),.b(b[3:0]),.cin(cin),.sum(sum[3:0]),.co(c0));
- full4 full4_inst2(.a(a[7:4]),.b(b[7:4]),.cin(c0),.sum(sum[7:4]),.co(c1));
- full4 full4_inst3(.a(a[11:8]),.b(b[11:8]),.cin(c1),.sum(sum[11:8]),.co(c2));
- full4 full4_inst4(.a(a[15:12]),.b(b[15:12]),.cin(c2),.sum(sum[15:12]),.co(co));//十六位的加法器是由四个四位的加法器组成的,分别进行元件例化和端口的连接
-
- endmodule
- `timescale 1 ps/ 1 ps
- module bit16Level_vlg_tst();
- // constants
- // general purpose registers
- reg eachvec;
- // test vector input registers
- reg [15:0] a;
- reg [15:0] b;
- reg cin;
- // wires
- wire co;
- wire [15:0] sum;
-
- // assign statements (if any)
- bit16Level i1 (
- // port map - connection between master ports and signals/registers
- .a(a),
- .b(b),
- .cin(cin),
- .co(co),
- .sum(sum)
- );
- initial
- begin
- a<=16'h0001;
- b<=16'h0001;
- cin<=1;
- //经过150ps后停止仿真
- #150 $stop;
- end
-
- always #10 a={$random}%17'h10000;
- always #10 b={$random}%17'h10000;
- //每经过10ps,为a、b和cin赋一个随机的值
- always #10 cin={$random}%2;
- endmodule
本实验设计一个16位二进制的超前进位全加器模块,用来实现16位二进制的加法,超前进位加法器的结构如下图。下图为一个四位超前进位加法器的结构图。信号经过pi和gi产生一级时延,经过计算C产生一级时延,则A,B输入一旦产生,首先经过两级时延算出第1轮进位值C’不过这个值是不正确的。C’再次送入加法器,进行第2轮2级时延的计算,算出第2轮进位值C,这一次是正确的进位值。这里的4个4位超前进位加法器仍是串行的,所以一次计算经过4级加法器,一级加法器有2级时延,因此1次计算一共经过8级时延,相比串行加法器里的16级时延,速度提高很多。
设计封装模块如下:
超前进位全加器的真值表如下:
Ai | Bi | Ci | Si | Ci+1 |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 1 | 0 |
0 | 1 | 0 | 1 | 0 |
0 | 1 | 1 | 0 | 1 |
1 | 0 | 0 | 1 | 0 |
1 | 0 | 1 | 0 | 1 |
1 | 1 | 0 | 0 | 1 |
1 | 1 | 1 | 1 | 1 |
由上,可以求得两个输出的表达式为:
对于i=0~3的代入,得到每一级的进位输出表达式如下:
- //定义一位超前加法器
- module bit1Advanced(ain,bin,cin,sum,gi,pi);
- input ain;
- input bin;
- input cin;//定义进位信号
- output sum;//输出信号
- output gi;//每位的进位产生信号
- output pi;//每位的进位传播信号
-
- assign gi=ain&bin;//数据流的方式描述逻辑式
- assign pi=ain|bin;//数据流的方式描述逻辑式
-
- assign sum=ain^bin^cin;//数据流的方式描述逻辑式
-
- endmodule
-
- //定义四位超前加法器
- module bit4Advanced(ain,bin,cin,sum,pm,gm,co);
- input[3:0] ain;
- input[3:0] bin;//定义两个四位的输入
- input cin;//定义进位信号
- output[3:0] sum;//定义输出信号
- output gm;//定义进位产生信号
- output pm;//定义进位传播信号
- output co;//定义输出的进位信号
-
- //定义三条wire类型,连接四个一位超前加法器之间的端口
- wire[4:1] ci;
- wire[3:0] pi;
- wire[3:0] gi;
-
- bit1Advanced u0(.ain(ain[0]),.bin(bin[0]),.cin(cin),.sum(sum[0]),.gi(gi[0]),.pi(pi[0]));
- bit1Advanced u1(.ain(ain[1]),.bin(bin[1]),.cin(ci[1]),.sum(sum[1]),.gi(gi[1]),.pi(pi[1]));
- bit1Advanced u2(.ain(ain[2]),.bin(bin[2]),.cin(ci[2]),.sum(sum[2]),.gi(gi[2]),.pi(pi[2]));
- bit1Advanced u3(.ain(ain[3]),.bin(bin[3]),.cin(ci[3]),.sum(sum[3]),.gi(gi[3]),.pi(pi[3]));//对四个一位的超前加法器进行元件例化,并连接对应的端口
- CLA_4 uut(.p(pi),.g(gi),.cin(cin),.ci(ci),.gm(gm),.pm(pm));//对CLA_4进行元件例化
-
- assign co=ci[4];//赋值进位信号co
-
- endmodule
-
- module CLA_4(p,g,cin,ci,gm,pm);//定义CLA_4模块,也就是超前进位信号产生的模块
- input[3:0] p;//定义输入的进位传播信号
- input[3:0] g;//定义输入的进位产生信号
- input cin;//定义模块的输入进位信号
- output[4:1] ci;//定义模块的输出进位信号
- output gm;//定义模块本身产生的进位产生信号
- output pm;//定义模块本身产生的进位传播信号
-
- assign ci[1]=g[0]|p[0]&cin;
- assign ci[2]=g[1]|p[1]&g[0]|p[1]&p[0]&cin;
- assign ci[3]=g[2]|p[2]&g[1]|p[2]&p[1]&g[0]|p[2]&p[1]&p[0]&cin;
- assign ci[4]=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;//根据对应的公式和对应的进位产生信号和进位传播信号赋值进位信号
-
- assign gm=g[3]|p[3]&g[2]|p[3]&p[2]&g[1]|p[3]&p[2]&p[1]&g[0];
- assign pm=p[3]&p[2]&p[1]&p[0];//根据对应的公式赋值模块本身的进位产生信号和进位传播信号
-
- endmodule
-
- //定义16位的超前进位加法器
- module bit16Advanced(ain,bin,cin,sum,co,gm,pm);
- input[15:0] ain;
- input[15:0] bin;//定义两个加数
- input cin;//定义输入的进位信号
- output [15:0] sum;//定义输出的和信号
- output co;//定义输出的进位信号
- output gm;//定义进位产生信号
- output pm;//定义进位传播信号
-
- //定义三个wire类型的变量
- wire[3:0] gi;
- wire[3:0] pi;
- wire[4:1] ci;
-
- bit4Advanced U0(.ain(ain[3:0]),.bin(bin[3:0]),.cin(cin),.sum(sum[3:0]),.gm(gi[0]),.pm(pi[0]));
- bit4Advanced U1(.ain(ain[7:4]),.bin(bin[7:4]),.cin(ci[1]),.sum(sum[7:4]),.gm(gi[1]),.pm(pi[1]));
- bit4Advanced U2(.ain(ain[11:8]),.bin(bin[11:8]),.cin(ci[2]),.sum(sum[11:8]),.gm(gi[2]),.pm(pi[2]));
- //根据实例化关系实例化三个模块,并且根据逻辑关系将其端口连接起来
- bit4Advanced U3(.ain(ain[15:12]),.bin(bin[15:12]),.cin(ci[3]),.sum(sum[15:12]),.gm(gi[3]),.pm(pi[3]));
-
- //将四位超前进位加法器产生的进位输出送到进位信号处理器中
- //以产生新的进位信号
- CLA_4 CLA_4(.p(pi),.g(gi),.cin(cin),.ci(ci),.gm(gm),.pm(pm));
-
- assign co=ci[4];
-
- endmodule
- // Verilog Test Bench template for design : bit16Advanced
- //
- // Simulation tool : ModelSim (Verilog)
- //
-
- `timescale 1 ps/ 1 ps
- module bit16Advanced_vlg_tst();
- // constants
- // general purpose registers
- reg eachvec;
- // test vector input registers
- reg [15:0] ain;
- reg [15:0] bin;
- reg cin;
- // wires
- wire co;
- wire gm;
- wire pm;
- wire [15:0] sum;
-
- // assign statements (if any)
- bit16Advanced i1 (
- // port map - connection between master ports and signals/registers
- .ain(ain),
- .bin(bin),
- .cin(cin),
- .co(co),
- .gm(gm),
- .pm(pm),
- .sum(sum)
- );
- initial
- begin
- ain=16'b0001_1111_1010_0101;
- bin=16'b1010_1010_1110_0110;
- cin=0;
- //50ps后停止
- #50 $stop;
-
- end
-
- always #10 ain={$random}%17'h10000;
- always #10 bin={$random}%17'h10000;
- always #10 cin={$random}%2;
-
- endmodule
本实验实现一个16位二进制的BCD码全加器模块,用来实现16位二进制的加法,由于两个1位十进制数相加时,和的取值范围是0—18,将该范围内各数值对应的二进制数和8421BCD码列表,以便寻找何时应对结果修正以及如何修正。
实验封装设计框图如下:
同时,我们知道当两个BCD码相加时,如果得到的结果为10以内,则显示的BCD码即为相加得到的结果,比如0001+0010=0011即3;但是当两个BCD码相加结果大于10,则应当加上6,即为显示的BCD码,即1001+0001 =9+1=1010=10,但应当显示0,于是将1010+0110=10000=0000,即显示为0。
下面详细地列出了真值表:
- //定义一位BCD码的加法器
- module BCD1bit(co,sum,a,b,cin);
- input cin;//定义进位信号
- input[3:0] a;
- input[3:0] b;//定义两个BCD码的加数
- output reg [3:0] sum;//定义输出和
- output reg co;//定义输出的进位信号
- reg[4:0] temp;//定义一个寄存器temp用来暂存计算结果
-
- always@(a,b,cin) begin//每当a,b或者cin变化时
- temp<=a+b+cin; //令temp为三者相加,也就是以二进制相加
- end
-
- always@(temp) begin//每当temp变化时
- if(temp>4'd9) begin//判断temp是否大于10
- sum<=temp-10;//如果大于10需要减去10,同时输出进位信号,这也就是十进制体现所在
- co<=1;
- end
- else begin //如果不大于10
- sum<=temp;
- co<=0;//将进位信号清零,将temp送给输出sum
- end
-
- end
- endmodule
-
- //定义16位的BCD加法器
- module BCD16bit(a,b,cin,sum,co);
- //定义两个16位的输入信号
- input[15:0] a;
- input[15:0] b;
- input cin;//定义输入进位信号
- output[15:0] sum;//定义16位的加法之和
- output co;//定义输出的进位信号
-
- //定义三个wire类型的变量,作为端口之间的连接线
- wire carry1,carry2,carry3;
-
- BCD1bit U0(.co(carry1),.sum(sum[3:0]),.a(a[3:0]),.b(b[3:0]),.cin(cin));
- BCD1bit U1(.co(carry2),.sum(sum[7:4]),.a(a[7:4]),.b(b[7:4]),.cin(carry1));
- BCD1bit U2(.co(carry3),.sum(sum[11:8]),.a(a[11:8]),.b(b[11:8]),.cin(carry2));
- BCD1bit U3(.co(co),.sum(sum[15:12]),.a(a[15:12]),.b(b[15:12]),.cin(carry3));//根据对应的连接线关系,将四个实例化之后的模块连接起来,形成16位的BCD加法器
-
- endmodule
- // Verilog Test Bench template for design : BCD16bit
- //
- // Simulation tool : ModelSim (Verilog)
- //
-
- `timescale 1 ps/ 1 ps
- module BCD16bit_vlg_tst();
- // constants
- // general purpose registers
- reg eachvec;
- // test vector input registers
- reg [3:0] a;
- reg [3:0] b;
- reg cin;
- // wires
- wire co;
- wire [3:0] sum;
-
- // assign statements (if any)
- BCD16bit i1 (
- // port map - connection between master ports and signals/registers
- .a(a),
- .b(b),
- .cin(cin),
- .co(co),
- .sum(sum)
- );
- initial
- begin
- a<=16'h0001;
- b<=16'h0001;
- cin<=0;
- #150 $stop;
- end
-
- always #10 a[3:0]={$random}%10;
- always #10 a[7:4]={$random}%10;
- always #10 a[11:8]={$random}%10;
- always #10 a[15:12]={$random}%10;
- always #10 b[3:0]={$random}%10;
- always #10 b[7:4]={$random}%10;
- always #10 b[11:8]={$random}%10;
- always #10 b[15:12]={$random}%10;
- //每经过10ps,对每一位十进制数进行复赋值
- always #10 cin={$random}%2;
- endmodule
本次实验分别对16位二进制全加器模块,16位超前进位二进制全加器模块,16-bit 8421-BCD码全加器模块进行了设计与实现。其中在设计16位二进制全加器模块的过程中,分别使用了按照行为描述的方式以及按照数据流的方式建模,让我从实践的角度理解了建模方式的不同,掌握了包括门级电路,数据流以及行为描述这三种建模方法。
全加器是常用的组合逻辑模块中的一种,对全加器的分析和对组合逻辑电路的分析一样。组合逻辑电路的分析,就是找出给定电路输入和输出之间的逻辑关系,从而了解给定逻辑电路的逻辑功能。组合逻辑电路的分析方法通常采用代数法,我的设计过程按照老师所给出的步骤进行:先根据所需要的功能,列出真值表。然后根据真值表,写出相应的逻辑函数表达式。再根据真值表或逻辑函数表达式,画出相应的组合逻辑电路的逻辑图。之后用编写程序在QuartusⅡ上进行仿真并在Modelsim上测试,分析结果的正确性。
印象较深的是在数据流描述中,通过层次化设计方法实现的结构,这个加法器是使用了16个全加器进行连接和信号传递组成的,而一位全加器是由两个半加器以及一个或门所构成,这个全加器的组成和描述频繁使用了元件例化语句,就是为了能够完整的描述这16个全加器在结构上的关系以及和所对应输入输出之间的关系。
全加器是组合逻辑电路中最常见也最实用的一种,考虑低位进位的加法运算就是全加运算,实现全加运算的电路称为全加器。它主要实现加法的运算,其中分为并行全加器和串行全加器,所谓并行就是指向高位进位时是并行执行的,而串行就是从低位到高位按顺序执行,为了提高运算,必须设法减小或消除由于进位信号逐级传递所消耗的时间,为了提高运算速度,制成了超前进位加法器,这是对全加器的一种创新。这也正是超前进位二进制全加器的思想。
在16位的BCD码加法器的设计中,用4个数与4个数进行加和,通过BCD码输出结果。但是实验中需要注意很多细节,例如BCD码的最大范围就是1001也就是9,因此需要将二进制改为10进制,判断得到的结果是否需要进位,如果不需要进位的话,显示的结果就为真实结果,如果需要进位,则应当将得到的结果加上6,即对数字进行修正,以此实现显示信号的输出。
通过此次设计对全加器的设计和实现,积累和总结了不少的经验,锻炼了我的独立工作和实际动手能力,加深了对计算机中的全加器工作原理的认识,提高了对复杂的综合性实践环节具有分析问题、解决问题、概括总结的实际工作能力,对涉及全加器项目的开发、设计过程有初步认识。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。