1. What are half adders and full adders?
A half adder circuit refers to an adder circuit that adds two input data bits, outputs a result bit and a carry bit, and has no carry input. It is an addition operation circuit that implements two one-bit binary numbers.
The full adder is an upgraded version on the basis of the half adder. In addition to the addition of the addend and the summand, it also adds the carry signal from the previous stage.
2. How to write a half adder module?
2.1. Design method
The half adder has two 1-bit binary inputs and outputs 1 carry and 1 result bit. The truth table is as follows:
According to the truth table, the waveform of the half adder can be drawn:
- in1 : Addend 1, binary, 1 bit
- in2 : addend 2, binary, 1 bit
- sum : result bit, binary, 1 bit
- cout : carry, binary, 1 bit
2.2, Verilog implementation
According to the above waveform diagram, the Verilog code can be written as follows:
/* //方法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
Three ways to achieve this are provided here. The RTL views generated by the three methods are as follows:
- The RTL views generated by method 1 and method 2 are the same, which means that these two methods are two different expressions of combinational logic circuits.
- Methods 1 and 2 use bit splicing and addition operations, so the generated circuit contains a half adder
- Method 3 uses combinational logic: XOR generates the result bit, AND logic generates the carry
2.3、Testbench
The Testbench file is as follows:
`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. Simulation results
The simulation is performed using ModelSim, and the simulated waveform is as follows:
Because the incentives are randomly generated, we will randomly take three points here to verify. As can be seen from the waveform diagram:
- L1: in1 in2 sum cout is 1010 respectively
- L1: in1 in2 sum cout is 1101 respectively
- L1: in1 in2 sum cout is 0110 respectively
- The outputs of the three points L1, L2, and L3 conform to the truth table
3. How to write a full adder module?
3.1. Design method
The full adder has two 1-bit binary input and a carry from the low-order bit; it outputs 1 carry and 1 result bit. The truth table of the full adder is as follows:
It is not difficult to find that the low-order carry input is actually equivalent to an input (it can be called input 3).
According to the truth table, the waveform of the full adder can be drawn:
3.2, Verilog implementation
According to the above waveform diagram, the Verilog code can be written as follows:
//全加器
module full_adder(
input in1, //加数1
input in2, //加数2
input cin, //低位向高位的进位
output sum, //两个数的加和
output cout //加数和的进位
);
assign {cout,sum} = in1 + in2 + cin; //使用位拼接 和 加法运算
endmodule
The RTL view is as follows:
3.3、Testbench
The Testbench file is as follows:
`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. Simulation results
The simulation is performed using ModelSim, and the simulated waveform is as follows:
Because the incentives are randomly generated, we will randomly take three points here to verify. As can be seen from the waveform diagram:
- L1: in1 in2 cin sum cout are 10101 respectively
- L1: in1 in2 cin sum cout are 10010 respectively
- L1: in1 in2 cin sum cout are 11111 respectively
- The outputs of the three points L1, L2, and L3 conform to the truth table
4. Call the half adder to implement the full adder
4.1. Design method
As mentioned earlier, the full adder is just an addition of a low-order carry signal (this signal can be regarded as an addend 3) on the basis of the half adder. The output is the same as a half adder.
Then the full adder can be seen as adding three inputs, then we can first use a half adder to calculate the result of the two addends 1 and 2, and then use the low-order carry (addend 3) and the previous result Add them together to get the result of the full adder.
In short, we can implement a full adder by calling two half adder modules.
Let's look at the truth table of the half adder and the full adder again:
Instantiate the first half adder module, the input is addend 1, addend 2, then its output is nothing more than four cases:
- The input is in1 = 0, in2 = 0; the output is sum1 = 0, cout1 = 0, instantiate the second half adder module, the input is sum1, the low-order carry cin, the following situation:
1.1 cin =0, then sum2= 0, cout2 = 0
1.2 cin =1 , then sum2 = 1, cout2 = 0 - The input is in1= 0, in2 = 1; the output sum1 = 1, cout1 = 0, instantiate the second half adder module, the input is sum1, the low-order carry cin, the following situation:
2.1 cin =0, then sum2= 1, cout2 = 0
2.2 cin =1 , then sum2 = 0, cout2 = 1 - Input is in1=1, in2=0; output sum1=1, cout1=0. Same as 2
- The input is in1 = 1, in2 = 1; the output sum1 = 0, cout1 = 1, instantiate the second half adder module, the input is sum1, low-order carry cin, the following situations:
4.1 cin =0, then sum2= 0, cout2 = 1
4.2 cin =1 , then sum2 = 1, cout2 = 1
Comparing the above with the truth table of the full adder, we find that:
- sum2 is the same as the result of the full adder as sum
- cout is cou1 || cout 2
According to this, the block diagram of the instantiation can be drawn:
4.2, Verilog implementation
According to the above block diagram, the Verilog code can be written as follows:
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
The resulting RTL view is as follows:
This is consistent with the previous theoretical block diagram, instantiating two half-adder modules separately.
4.3. Others
Testbench files are the same as 3.3. The simulation results are the same as 3.4.