加减法器的设计
一、实验目的和要求
1.通过实验,使学生进一步理解原码、补码的概念,学会用加法器做减法的方法,进一步理解无符号数进位与借位,有符号数溢出的判断方法以及符号位和结果为 0 标志赋值方法。
2.通过实验,加深对 IP 核使用的熟练程度,同时在实际板子上体验加减法器。
二、实验内容和原理
实验内容:
1.使用 Verilog HDL 语言实现一个可适应从 4 位到 32 位数据运算的加减法器,其中被操作数为 a,操作数为 b,加减法控制信号为 sub,当 sub 为 1 的时候做减法,为 0 的时候做加法。另外输出为运算结果 sum,还有进位/借位标志 cf,有符号数溢出标志 ovf,符号标志 sf 以及结果为 0 标志 zf。将该加减法器封装成 IP 核 addsub。
2.使用 Verilog HDL 语言以及 2.5.1 中实现的加减法器 IP 核,实现一个 8 位的加减法器addsub8
实验原理:
关于加减法器的 CF 和 OF 的问题
1.关于无符号数的进位 CF: 如果是加法,则 CF 就是二进制运算的进位位,由于减法是将减数取反加 1(求补)后(假设减数 b 求补后为 subb)与被减数 a 相加,因此,当够减的时候反而有进位,不够减的时候反而无进位(其实是无符号数溢出),因此, CF 需要在进位位基础上取反才能表示借位(实际上是让 CF 为 1 表示被减数 a 小于减数 b, CF=0 表示被减数 a 大于减数 b)。因此 CF 在做加法的时候不将加法进位取反,做减法的时候要将加法进位取反。
2.关于有符号数的溢出问题(OF) 在组成原理中对于有符号数溢出有一个规则就是两数相加最高位和次高位都进位或者都不进位的时候没有溢出,否则就有溢出。但这必须去看最高位和次高位是不是有进位。下面我们换一个简单的方法来判断。
(1) 对于加法,有符号数加法溢出的规则其实很简单,就是两个正数相加得到负数,或者两个负数相加得到正数的时候,有符号数加法就溢出了。
(2) 对于减法 ,有符号数减法溢出的规则也很简单:一个正数减去一个负数得到一个负数或者一个负数减去一个正数得到一个正数的时候,就产生了溢出。 考虑一下:我们是要用加法器做减法,因此我们会将减数 b取补后的 subb 作为加数和被加数 a 相加,因此,最终,判断溢出应该是判断 a 和 subb 相加的溢出规则。 如果我们在做加法的时候让 subb=b,在做减法的时候用 subb=b 的补数,那么最终无论加法或减法,都化作了 sum=a+subb,因此只要判断 a 和 subb 相加的溢出规则。
三、主要仪器设备
个人电脑:Huawei Matebook 14 Windows 11 家庭中文版
类型:64位
处理器:Intel® Core™ i5-10210U CPU @ 1.60GHz 2.11 GHz
内存:16GB
四、操作方法与实验步骤
1. 可变位宽的加减法器 IP 核的设计
- 建立好工程项目addsub
图2-1 建立工程项目addsub - 向项目中添加设计文件addsub.v,并向其中写入如下内容:
`timescale 1ns / 1ps
module addsub
#(parameter WIDTH=8) //指定数据宽度参数,缺省值是 8
(
input [(WIDTH-1):0] a, // 被操作数,位宽由参数 WIDTH 决定
input [(WIDTH-1):0] b, // 操作数,位宽由参数 WIDTH 决定
input sub, // =1 为减法
output [(WIDTH-1):0] sum, // 结果
output cf, // 进位标志
output ovf, // 溢出标志
output sf, // 符号标志
output zf // 为 0 标志
);
// 输入的a和b本就是补码
// 要输出的结果sum也要是补码形式的
wire [(WIDTH - 1) : 0] subb;
assign subb = sub ? ~b + 1 : b;
wire flag;
assign {flag, sum} = a + subb;
assign cf = sub ? ~flag : flag;
assign ovf = (a[WIDTH - 1] & subb[WIDTH - 1] & ~sum[WIDTH - 1]) |
(~a[WIDTH - 1] & ~subb[WIDTH - 1] & sum[WIDTH - 1]);
assign sf = sum[WIDTH - 1];
assign zf = (sum == 0);
endmodule
图2-2 编写addsub.v文件
3. 建立仿真文件addsub_sim.v,并向其中写入如下内容:
`timescale 1ns / 1ps
module addsub_sim( );
// input
reg [31:0] a = 32'd16;
reg [31:0] b = 32'd12;
reg sub = 0;
//output
wire [31:0] sum;
wire cf;
wire ovf;
wire sf;
wire zf;
// initial
addsub #(32) U (a,b,sub,sum,cf,ovf,sf,zf);
initial begin
#200 sub = 1;
#200 begin a = 32'h7f; b = 32'h2; sub = 0; end
#200 begin a = 32'hff; b = 32'h2; sub = 0; end
#200 begin a = 32'h7fffffff; b = 32'h2; sub = 0; end
#200 begin a = 32'h16; b = 32'h17; sub = 1; end
#200 begin a = 32'hffff; b = 32'h1; sub = 0; end
#200 begin a = 32'hffffffff; b = 32'h1; sub = 0; end
end
endmodule
图2-3 建立仿真文件addsub_sim.v
4. 仿真之后得到如下波形
图2-4 可变位宽的加减法器仿真波形
8 位加减法器的设计
实验目的
通过实验,加深对 IP 核使用的熟练程度,同时在实际板子上体验加减法器。
实验内容
使用 Verilog HDL 语言以及 2.5.1 中实现的加减法器 IP 核,实现一个 8 位的加减法器 addsub8,并下载到板子上进行验证。其中输入 a[7]~a[0]分别接 SW15~SW8, b[7]~b[0]分别接 SW7~SW0, sub 接 SW23, sum[7]~sum[0]分别接 YLD7~YLD0。ovf 接 GLD7,cf 接 GLD6, sf 接 GLD5,zf 接 YLD4,详见表 2-11。
实验目的
通过实验,加深对 IP 核使用的熟练程度,同时在实际板子上体验加减法器。
实验内容
使用 Verilog HDL 语言以及 2.5.1 中实现的加减法器 IP 核,实现一个 8 位的加减法器 addsub8,并下载到板子上进行验证。其中输入 a[7]~a[0]分别接 SW15~SW8, b[7]~b[0]分别接 SW7~SW0, sub 接 SW23, sum[7]~sum[0]分别接 YLD7~YLD0。ovf 接 GLD7,cf 接 GLD6, sf 接 GLD5,zf 接 YLD4,详见表 2-11。
- 建立好工程项目addsub8
- 向工程中导入设计好的addsubIP核,并设置宽度参数WIDTH为16,如下图所示: 图2-5 导入设计addsubIP核
- 在工程中创建仿真文件addsub_sim.v,并向文件中写入如下内容:
`timescale 1ns / 1ps
module addsub_sim( );
// input
reg [7:0] a = 8'h16;
reg [7:0] b = 8'h12;
reg sub = 0;
//output
wire [7:0] sum;
wire cf;
wire ovf;
wire sf;
wire zf;
// initial
addsub_0 U (a,b,sub,sum,cf,ovf,sf,zf);
initial begin
#200 sub = 1;
#200 begin a = 8'h7f; b = 8'h2; sub = 0; end
#200 begin a = 8'hff; b = 8'h2; sub = 0; end
#200 begin a = 8'h16; b = 8'h17; sub = 1; end
#200 begin a = 8'hfe; b = 8'hff; sub = 1; end
end
endmodule
图2-5 创建仿真文件addsub_sim.v
4. 仿真之后得到如下结果: 图2-6 8 位加减法器的设计仿真波形
五、实验数据记录和处理
- 设计addsubIP核的过程中所用到的仿真文件addsub_sim.v:
`timescale 1ns / 1ps
module addsub_sim( );
// input
reg [31:0] a = 32'd16;
reg [31:0] b = 32'd12;
reg sub = 0;
//output
wire [31:0] sum;
wire cf;
wire ovf;
wire sf;
wire zf;
// initial
addsub #(32) U (a,b,sub,sum,cf,ovf,sf,zf);
initial begin
#200 sub = 1;
#200 begin a = 32'h7f; b = 32'h2; sub = 0; end
#200 begin a = 32'hff; b = 32'h2; sub = 0; end
#200 begin a = 32'h7fffffff; b = 32'h2; sub = 0; end
#200 begin a = 32'h16; b = 32'h17; sub = 1; end
#200 begin a = 32'hffff; b = 32'h1; sub = 0; end
#200 begin a = 32'hffffffff; b = 32'h1; sub = 0; end
end
endmodule
- 调用IP核设计的8位加减法器中使用的仿真文件addsub_sim.v:
`timescale 1ns / 1ps
module addsub_sim( );
// input
reg [7:0] a = 8'h16;
reg [7:0] b = 8'h12;
reg sub = 0;
//output
wire [7:0] sum;
wire cf;
wire ovf;
wire sf;
wire zf;
// initial
addsub_0 U (a,b,sub,sum,cf,ovf,sf,zf);
initial begin
#200 sub = 1;
#200 begin a = 8'h7f; b = 8'h2; sub = 0; end
#200 begin a = 8'hff; b = 8'h2; sub = 0; end
#200 begin a = 8'h16; b = 8'h17; sub = 1; end
#200 begin a = 8'hfe; b = 8'hff; sub = 1; end
end
endmodule
六、实验结果与分析
- 设计加减法器的IP核实验中仿真文件运行的结果:
图2-7 可变位宽的加减法器仿真波形 - 调用IP核设计8位加减法器实验中仿真文件运行的结果:
图2-8 8 位加减法器的设计仿真波形
七、讨论、心得
- 有符号数在计算机中以补码形式存储。因此在我们设计的有符号数加减法器中,输入的数据本就是数据的补码,不需要再做转换之类的操作。
- 如果要调用进行有符号的加减法的运算器,就要保证输入的数据形式就是有符号数补码形式的。如果输入其他形式的数据,就可能会因运算规则不正确而得出错误的结果。
- 通过本次加减法器 IP 核的实验,我也在 Vivado 软件上利用 Verilog 语句实现了带有进/借位(CF)、溢出位(OF)的一个加减运算器,并通过设置 8位位宽,仿真了 8 位数的加减法,最后将其封装成模块,放在工程文件中。
- 很多课本上的东西与实践相结合,有了很多新的感悟与体会。在实验过程中, 我也充分感受到一定要认真认真再认真,要不然一点小小的低级错误,会导致很长时间无法前进。从源头上杜绝这些小错误,能大大提高实验效率。
- IP:vivado中的ip就是已经编好的模块,可以直接用(天知道我第一节课听杨老师讲了一节课的ip有多迷茫。。。)。有别人编好的自带的ip,如加法器,乘法器,bram(存储器)。自己编好的verliog也可以制作成ip(相当于封装了一个硬件“函数”),下面是一些ip的使用事项
BRAM:双口bram有两个时钟的延迟。设计的时候要看一下深度和宽度,防止存不下(前期应该都没问题)。
乘法器:可以调延迟周期。会根据输入有推荐的延迟周期。
system:
自定义ip:
方法:
IP的修改:
经验:不要急着封装成ip,因为改起来麻烦,还难保证正确性。使用add model。
注意:IP和model更改后vivado会自己检测和更新接口等,不用手动删了重新加。
(3)仿真
想办法仿真,每一步都是可以仿真的。
子模块仿真:
顶层仿真(数据通路,实际实现需要ps控制的):