半加器和全加器 verilog FPGA 基础练习1
发现问题,用技术解决问题。兴趣是自己的源动力 !
目录
前言
对于半加器和全加器的练习,根本目的在于理解自底向上(Bottom-Up)的设计方法和自顶向下(Top- Down)的设计方法,既学会堆积木。
一、半加器理论
半加器电路是指对两个输入数据位相加,输出一个结果位和进位,没有进位输入的加法器电路。既,1‘b1 + 1’b1,结果位1’b0,进位为1‘b1。
1.1 Verilog实现
代码如下:
module half_adder(
input in_1 , // 输入信号
input in_2 , // 输入信号
output sum , // 两个加数的求和结果(1bit位宽相加的数据,结果只有0或者1)
output count // 两个加数求和后的进位信号
);
// 这里需要注意的是单bit相加,相加后结果的位宽是等号右边决定的;
// 1'b1 + 1'b1 的结果为2,即2'b10,如果等号左边为 1bit,即 assign sum = in_1 + in_2,那么会对高位截位。
// 即:相加后的数值位宽和等式右边无关
assign {count,sum} = in_1 + in_2;
endmodule
1.2 仿真tb
`timescale 1ns/1ns
module tb_top();
// 模块的接口参数定义
reg in_1 ;
reg in_2 ;
wire sum ;
wire count ;
initial
begin
in_1 <= 1'b0;
in_2 <= 1'b0;
end
always #10 in_1 <= {$random} % 2;
always #10 in_2 <= {$random} % 2;
half_adder u0_half_adder(
.in_1 (in_1 ),
.in_2 (in_2 ),
.sum (sum ),
.count (count)
);
endmodule
1.3 仿真结果
二、全加器理论
而全加器是在半加器的基础上的升级版,除了加数和被加数加和外还要加上上一级传进来的进位信号。既,除了单bit数相加,还需要考虑进位信号(低位的进位),可以结合下面代码来理解。
2.1 Verilog实现
代码如下:
module full_adder(
input in_1 , // 输入信号
input in_2 , // 输入信号
input cin , // 进位信号
output sum , // 两个加数的求和结果(1bit位宽相加的数据,结果只有0或者1)
output count // 两个加数求和后的进位信号
);
wire sum_0 ;
wire count_0 ;
wire count_1 ;
// 第一个半加器:两个1bit数相加
half_adder u0_half_adder(
.in_1 (in_1 ),
.in_2 (in_2 ),
.sum (sum_0 ),
.count (count_0)
);
// 第二个半加器:和低位的进位相加
half_adder u1_half_adder(
.in_1 (sum_0 ),
.in_2 (cin),
.sum (sum ),
.count (count_1)
);
// 理解1:单bit数,如果count_0 = 1,那么 sum_0为0,此时如果cin为0或1,都不影响进位;
// 理解2:如果 count_0 = 0;那么sum_0为0或者1,此时,如果cin为0或1,则count_1有两种情况,分别为0或者1
// 结合上面两个理解,那么使用或判断,即可判断进位的情况。(最好通过真值表来理解)
assign count = count_0 | count_1;
endmodule
2.2 仿真tb
这里tb使用3位全加器来实现3bit位宽的数据相加,方便理解半加器和全加器的区别和理解。
`timescale 1ns/1ns
module tb_top();
// 模块的接口参数定义
reg [2:0] in_1;
reg [2:0] in_2;
wire [2:0] sum ;
wire u0_count ;
wire u1_count ;
wire u2_count ;
initial
begin
in_1 <= 3'b000;
in_2 <= 3'b000;
#200;
in_1 <= 3'b101;
in_2 <= 3'b001;
end
// 此处举例3bits数的相加:3'bxxx = 3'b101 + 3'b001,通过全加器来进行计算xxx的值是什么?
//u0_full_adder 全加器:表示3'b101 + 3'b001第0位加数结果和进位,既 1’b1 + 1'b1
full_adder u0_full_adder(
.in_1 (in_1[0] ), // 1’b1
.in_2 (in_2[0] ), // 1’b1
.cin (1'b0 ), // 最低位没有进位
.sum (sum[0] ), // 3'bxxx 0位的结果
.count (u0_count) // 3'bxxx 第0位的进位
);
//u1_full_adder 全加器:表示3'b101 + 3'b001第1位加数结果和进位,既 1’b0 + 1'b0
full_adder u1_full_adder(
.in_1 (in_1[1] ), // 1’b0
.in_2 (in_2[1] ), // 1’b0
.cin (u0_count ), // 来自u0_full_adder的进位 u0_count
.sum (sum[1] ), // 3'bxxx 1位的结果
.count (u1_count ) // 3'bxxx 第1位的进位
);
//u2_full_adder 全加器:表示3'b101 + 3'b001第2位加数结果和进位,既 1’b1 + 1'b0
full_adder u2_full_adder(
.in_1 (in_1[2] ), // 1’b1
.in_2 (in_2[2] ), // 1’b0
.cin (u1_count ), // 来自 u1_full_adder 的进位 u1_count
.sum (sum[2] ), // 3'bxxx 2位的结果
.count (u2_count) // 3'bxxx 第2位的进位
);
// 最后3‘bxxx的值为3’b110
endmodule
半加器和全加器的区别不是很大,输出都是一个sum和一个进位,主要区别在于全加器要考虑低位的进位,相当于要加两次(一次考虑自身位的相加,二是考虑要和低位的进位相加)
2.3 仿真结果
三、升华
自底向上(Bottom-Up)的设计方法和自顶向下(Top- Down)的设计方法。可以直观的去理解为搭积木原则,既,每一个module都是一个积木块,积木块的特性就是特定功能(一个积木只做一件事),可复用,最后用多个积木组建为一个城堡!