目录
Half adder
创建一个半加法器。半加器将两个输入(不带低位的进位)相加产生和和向高位的进位。
solution:
module top_module(
input a, b,
output cout, sum );
assign sum = a ^ b;
assign cout = a & b;
endmodule
better solution:
module top_module(
input a, b, cin,
output cout, sum );
//assign sum = a ^ b ^ cin;
//assign cout = a & b | a & cin | b & cin;
assign {cout,sum} = a + b + cin;
endmodule
Full adder
创建一个全加法器。一个全加法器将三个位(包括进位)相加,并产生一个总和与一个进位。
solution:
module top_module(
input a, b, cin,
output cout, sum );
assign sum = a^b^cin;
assign cout = a&b | a&cin | b&cin;
endmodule
better solution:
module top_module(
input a, b, cin,
output cout, sum );
assign {cout,sum} = a+b+cin;
endmodule
3-bit binary adder
实例化3次一位全加器来创建一个3位二进制行波进位加法器。该加法器有两个3位输入和一个低位的进位,产生一个3位的和和一个输出。
为了验证这里确实实例化了全加器,行波进位加法器也输出每个一位全加器进位的输出。
cout[2]是最后一个一位全加器的进位输出,也是我们通常看到的进位输出。
什么是行波进位加法器?
HDLBits-Verilog学习小结(四)Module中有介绍。
solution:
module top_module(
input [2:0] a, b,
input cin,
output [2:0] cout,
output [2:0] sum );
full_adder f0 (a[0],b[0],cin,cout[0],sum[0]);
full_adder f1 (a[1],b[1],cout[0],cout[1],sum[1]);
full_adder f2 (a[2],b[2],cout[1],cout[2],sum[2]);
endmodule
module full_adder(
input a, b, cin,
output cout, sum );
assign {cout,sum} = a+b+cin;
endmodule
Adder
实现以下电路((“ FA”是全加法器)):
solution:
module top_module (
input [3:0] x,
input [3:0] y,
output [4:0] sum);
reg [2:0] cout;
wire cin;
assign cin = 0;
full_adder f0 (x[0],y[0],cin,cout[0],sum[0]);
full_adder f1 (x[1],y[1],cout[0],cout[1],sum[1]);
full_adder f2 (x[2],y[2],cout[1],cout[2],sum[2]);
full_adder f3 (x[3],y[3],cout[2],sum[4],sum[3]);
endmodule
module full_adder(
input a, b, cin,
output cout, sum );
assign {cout,sum} = a+b+cin;
endmodule
official solution(⭐️):
module top_module (
input [3:0] x,
input [3:0] y,
output [4:0] sum
);
// This circuit is a 4-bit ripple-carry adder with carry-out.
assign sum = x+y; // Verilog addition automatically produces the carry-out bit.
// Verilog quirk: Even though the value of (x+y) includes the carry-out, (x+y) is still considered to be a 4-bit number (The max width of the two operands).
// This is correct:
// assign sum = (x+y);
// But this is incorrect:
// assign sum = {x+y}; // Concatenation operator: This discards the carry-out
endmodule
Signed addition overflow
⭐️
假设有2个8位二进制数a[7:0]和b[7:0]。他们相加得到s[7:0]。判断是否发生了(有符号的)溢出。
参考二进制有符号数运算及溢出判别这篇文章,可以知道:
补码加法运算溢出判断的方法:
- [方法一]
Xf、Yf分别两个数的符号位,Zf为运算结果符号位。
当Xf =Yf =0(两数同为正),而Zf=1(结果为负)时,负溢出;
当出现Xf =Yf =1(两数同为负),而Zf=0(结果为正),正溢出. - [方法二]
Cs表示符号位的进位,Cp表示最高数值位进位,⊕表示异或。
若 Cs⊕Cp =0 ,无溢出;
若 Cs⊕Cp =1 ,有溢出。
solution:
module top_module (
input [7:0] a,
input [7:0] b,
output [7:0] s,
output overflow
); //
wire s_1;
assign {s_1,s} = a + b;
always @(*) begin
if (a[7]^b[7])//一正一负必然是不溢出的
overflow = 0;
else if (a[7]==0 & b[7]==0 & s[7]==0)//这个容易被忽略。要考虑最高数值位的进位不是s[7]的情况
overflow = 0;
else if (s_1^s[7]==0) //同方法二
overflow = 0;
else
overflow = 1;
end
endmodule
better solution:
module top_module (
input [7:0] a,
input [7:0] b,
output [7:0] s,
output overflow
); //
assign s = a + b;
assign overflow = (a[7] & b[7] & ~s[7]) | (~a[7] & ~b[7] & s[7]); //同方法一
endmodule
100-bit binary adder
创建一个100位二进制加法器。加法器将两个100位数字和一个进位相加,以产生100位和。
提示:要实例化的完整加法器太多,但是行为代码在这里效果很好。另请参阅Adder解决方案。
solution:
module top_module(
input [99:0] a, b,
input cin,
output cout,
output [99:0] sum );
assign {cout,sum} = a + b + cin;
endmodule
4-digit BCD adder
⭐️
这里提供了一个名为bcd_fadd的BCD(二进制编码的十进制)一位数字加法器,该加法器将两个BCD数字和进位相加,并产生总和和进位。
module bcd_fadd {
input [3:0] a,
input [3:0] b,
input cin,
output cout,
output [3:0] sum );
实例化bcd_fadd的4个副本以创建一个4位数的BCD脉动进位加法器。待设计的加法器应将两个4位的BCD编号(打包为16位向量)相加,并加上一个进位以产生4位的总和并执行。
提示:
- 5位十进制数字12345的BCD表示为20’h12345。这与14’d12345(即14’h3039)不同。
- 该电路的结构类似于二进制纹波加法器,只是加法器的基数为10,而不是基数2。
solution:
module top_module(
input [15:0] a, b,
input cin,
output cout,
output [15:0] sum );
reg [2:0] temp;
bcd_fadd f0 (a[3:0],b[3:0],cin,temp[0],sum[3:0]);
bcd_fadd f1 (a[7:4],b[7:4],temp[0],temp[1],sum[7:4]);
bcd_fadd f2 (a[11:8],b[11:8],temp[1],temp[2],sum[11:8]);
bcd_fadd f3 (a[15:12],b[15:12],temp[2],cout,sum[15:12]);
endmodule