1、什么是半加器、全加器?
半加器电路是指对两个输入数据位相加,输出一个结果位和进位,没有进位输入的加法器电路。 是实现两个一位二进制数的加法运算电路。
全加器是在半加器的基础上的升级版,除了加数和被加数加和外还要加前上一级传进来的进位信号。
2、如何写一个半加器模块?
2.1、设计方法
半加器有两个1位2进制数输入,输出1个进位、1个结果位。真值表如下:
根据真值表,可以绘制出半加器的波形图:
- in1:加数1,2进制,1位
- in2:加数2,2进制,1位
- sum:结果位,2进制,1位
- cout:进位,2进制,1位
2.2、Verilog实现
根据上面的波形图可以编写Verilog代码如下:
/* //方法1:直接使用加法(assign语句)进行计算
module half_adder(
input in1, //加数1
input in2, //加数2
output sum, //两个数的加和
output cout //加数和的进位
);
//使用拼接运算符分别表示:和 与 进位
assign {cout,sum} = in1 + in2;
endmodule */
/* //方法2:使用always块
module half_adder(
input in1, //加数1
input in2, //加数2
output reg sum, //两个数的加和
output reg cout //加数和的进位
);
//使用拼接运算符分别表示:和 与 进位
always@(*)begin
{cout,sum} = in1 + in2;
end
endmodule */
//方法3:根据真值表把组合逻辑电路化简成与非门的形式
/**************真值表
in1 in2 summ cout
0 0 0 0
0 1 1 0
1 0 1 0
1 1 0 1
******/
//与非门化简有 sum = in1 ^ in2; cout = in1 & in2
module half_adder(
input in1, //加数1
input in2, //加数2
output sum, //两个数的加和
output cout //加数和的进位
);
//根据化简结果分别表示:和 与 进位
assign sum = in1 ^ in2;
assign cout = in1 & in2;
endmodule
在这里提供了三种实现的方法。三种方法分别生成的RTL视图如下:
- 方法1、方法2生成的RTL视图相同,这说明这两种方法是组合逻辑电路的两种不同表达形式
- 方法1、2因为使用了位拼接、加法运算,所以生成的电路里含有半加器
- 方法3使用组合逻辑:异或生成结果位、与逻辑生成进位
2.3、Testbench
Testbench文件如下:
`timescale 1ns/1ns //时间刻度:单位1ns,精度1ns
module tb_half_adder(); //仿真模块
//输入reg 定义
reg in1;
reg in2;
//输出wire定义
wire cout;
wire sum;
//设置初始化条件
initial begin
in1<=1'b0; //初始化为0
in2<=1'b0; //初始化为0
end
//产生激励条件
//always #10:表示每10个时钟周期实现后面的操作
always #10 in1<= $random %2; //每10个时钟周期产生1个随机数
//然后对随机数模2(结果要么0、要么1),再将其赋值给加数1
always #10 in2<= $random %2; //同上
//例化被测试模块
half_adder u_half_adder(
.in1(in1),
.in2(in2),
.sum(sum),
.cout(cout)
);
endmodule
2.4、仿真结果
使用ModelSim执行仿真,仿真出来的波形如下所示:
因为激励是随机产生的,我们这里就随便取三个点来验证。从波形图可以看到:
- L1:in1 in2 sum cout 分别为1010
- L1:in1 in2 sum cout 分别为1101
- L1:in1 in2 sum cout 分别为0110
- L1、L2、L3 这三个点的输出都是符合真值表的
3、如何写一个全加器模块?
3.1、设计方法
全加器有两个1位2进制数输入,一个低位传来的进位;输出1个进位、1个结果位。全加器的真值表如下:
不难发现,低位的进位输入其实就相当于一个输入(可以称之为输入3)。
根据真值表,可以绘制出全加器的波形图:
3.2、Verilog实现
根据上面的波形图可以编写Verilog代码如下:
//全加器
module full_adder(
input in1, //加数1
input in2, //加数2
input cin, //低位向高位的进位
output sum, //两个数的加和
output cout //加数和的进位
);
assign {cout,sum} = in1 + in2 + cin; //使用位拼接 和 加法运算
endmodule
RTL视图如下:
3.3、Testbench
Testbench文件如下:
`timescale 1ns/1ns //时间刻度:单位1ns,精度1ns
module tb_full_adder(); //仿真模块
//输入reg 定义
reg in1;
reg in2;
reg cin;
//输出wire定义
wire cout;
wire sum;
//设置初始化条件
initial begin
in1<=1'b0; //初始化为0
in2<=1'b0; //初始化为0
cin<=1'b0; //初始化为0
end
//产生激励条件
//always #10:表示每10个时钟周期实现后面的操作
always #10 in1<= $random %2; //每10个时钟周期产生1个随机数
//然后对随机数模2(结果要么0、要么1),再将其赋值给加数1
always #10 in2<= $random %2; //同上
always #10 cin<= $random %2; //同上
//例化被测试模块
full_adder u_full_adder(
.in1(in1),
.in2(in2),
.cin(cin),
.sum(sum),
.cout(cout)
);
endmodule
3.4、仿真结果
使用ModelSim执行仿真,仿真出来的波形如下所示:
因为激励是随机产生的,我们这里就随便取三个点来验证。从波形图可以看到:
- L1:in1 in2 cin sum cout 分别为10101
- L1:in1 in2 cin sum cout 分别为10010
- L1:in1 in2 cin sum cout 分别为11111
- L1、L2、L3 这三个点的输出都是符合真值表的
4、调用半加器实现全加器
4.1、设计方法
前面讲过,全加器不过是在半加器的基础上多了一个低位进位信号(这个信号可以看作是一个加数3)。输出与半加器相同。
那么全加器可以看是三个输入在做加法,那么我们可以先使用一个半加器计算出两个加数1、加数2的结果,在用低位进位(加数3)与之前的结果相加,就可以得到全加器的结果了。
简而言之,我们可以通过调用两个半加器模块来实现全加器。
再来看一遍半加器和全加器的真值表:
例化第1个半加器模块,输入分别为加数1、加数2、则其输出无外乎4种情况:
- 输入为in1= 0 ,in2 = 0;输出 sum1 = 0,cout1 = 0 ,例化第2个半加器模块,输入分别为sum1 、低位进位cin ,有如下情况:
1.1 cin =0 ,那么 sum2= 0,cout2 = 0
1.2 cin =1 ,那么 sum2= 1,cout2 = 0 - 输入为in1= 0 ,in2 = 1;输出 sum1 = 1,cout1 = 0 ,例化第2个半加器模块,输入分别为sum1 、低位进位cin ,有如下情况:
2.1 cin =0 ,那么 sum2= 1,cout2 = 0
2.2 cin =1 ,那么 sum2= 0,cout2 = 1 - 输入为in1= 1 ,in2 = 0;输出 sum1 = 1,cout1 = 0 。情况同2
- 输入为in1= 1 ,in2 = 1;输出 sum1 = 0,cout1 = 1,例化第2个半加器模块,输入分别为sum1 、低位进位cin ,有如下情况:
4.1 cin =0 ,那么 sum2= 0,cout2 = 1
4.2 cin =1 ,那么 sum2= 1,cout2 = 1
将上述情况与全加器的真值表对比,发现:
- sum2与全加器的结果为sum相同
- cout则为 cou1 || cout 2
据此,可以画出实例化的框图:
4.2、Verilog实现
根据上面的模块框图可以编写Verilog代码如下:
module full_adder(
input in1, //加数1
input in2, //加数2
input cin, //低位向高位的进位
output sum, //两个数的加和
output cout //加数和的进位
);
//wire define
//模块之间的连线,结合模块图理解
wire h0_cout;
wire h1_cout;
wire h0_sum;
assign cout = h0_cout || h1_cout;
//例化半加器1
half_adder u1_half_adder(
.in1(in1),
.in2(in2),
.sum(h0_sum),
.cout(h0_cout)
);
//例化半加器2
half_adder u2_half_adder(
.in1(h0_sum),
.in2(cin),
.sum(sum),
.cout(h1_cout)
);
endmodule
生成的RTL视图如下:
这与之前理论上的框图一致,分别例化了两个半加器模块。
4.3、其他
Testbench文件同3.3。仿真结果同3.4.