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
`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 可变位宽的加减法器仿真波形
实验目的
通过实验,加深对 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。
`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 位加减法器的设计仿真波形
`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
`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
BRAM:双口bram有两个时钟的延迟。设计的时候要看一下深度和宽度,防止存不下(前期应该都没问题)。
乘法器:可以调延迟周期。会根据输入有推荐的延迟周期。
system:
自定义ip:
方法:
IP的修改:
经验:不要急着封装成ip,因为改起来麻烦,还难保证正确性。使用add model。
注意:IP和model更改后vivado会自己检测和更新接口等,不用手动删了重新加。
(3)仿真
想办法仿真,每一步都是可以仿真的。
子模块仿真:
顶层仿真(数据通路,实际实现需要ps控制的):