开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第31天,点击查看活动详情
1 、可变位宽的加减法器 IP 核的设计
使用Verilog HDL语言实现一个可适应从4位到32位数据运算的加减法器,其中被操作 数为 a,操作数为 b,加减法控制信号为 sub,当 sub 为 1 的时候做减法,为 0 的时候做加 法。另外输出为运算结果sum,还有进位/借位标志cf,有符号数溢出标志ovf,符号标志sf 以及结果为0标志zf。将该加减法器封装成IP核addsub。
2 、8 位加减法器的设计
使用 Verilog HDL 语言以及 2.2.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,详见表。
1 )可变位宽的加减法器 IP 核的设计
1、 新建一个项目,名为addsub
1、 设计源文件
被操作数为a,操作数为b,加减法控制信号为sub,当sub为1的时候做减法,为0的时候做加法。另外输出为运算结果sum,还有进位/借位标志cf,有符号数溢出标志 ovf,符号标志 sf以及结果为0标志zf。将该加减法器封装成 IP 核 addsub。****
2、 添加仿真代码
利用仿真程序进行仿真:
仿真截图如上:
4 、封装ip核
将ip核文件复制到ipcore/caculate文件夹下,并且解压。
2 )8 位加减法器的设计
1、首先新建addsub8项目,然后倒入ip核
2、点击Ip catalog,在选中导入的ip核,双击然后设置数据宽度,generate。
1、添加源文件,代码如下
1、添加仿真文件
2、点击Run Synthesis进行综合,综合完成后点击open Synthesized Design,再点击layout-i/o planning进行管脚分配。
6、点击Run Implement进行实现。
核心代码:
module addsub
#(parameter WIDTH=8)
//指定数据宽度参数,缺省值是8
(
input [(WIDTH-1):0] a,
// 缺省位数由参数WIDTH决定
input [(WIDTH-1):0] b,
input sub,
// =1为减法
output [(WIDTH-1):0] sum,
output cf, // 进位标志
output ovf,// 溢出标志
output sf, // 符号标志
output zf // 为0标志
);
// 添加自己的代码
reg cf2,cf3;
reg[(WIDTH-1):0] sum1;
reg[(WIDTH-1):0] subb,subb1;
always @(a,b,sub)
begin
**if**(sub==0)begin//为加法时,直接a+b
{cf2,sum1}=a+b;end
**if**(sub==1) begin//为减法时,先将b取反,然后加1,求其负数的补码,最后将进位取反。
subb1=~b;
subb=subb1+1;
{cf3,sum1}=a+subb;
cf2=~cf3;
end
end
assign cf=cf2;
assign sum=sum1;
assign sf=sum1[WIDTH-1];
assign zf=(sum==0)?1:0;
assign ovf=(sub==0)?(a[WIDTH-1]^sum[WIDTH-1]&b[WIDTH-1]^sum[WIDTH-1]):(a[WIDTH-1]^sum[WIDTH-1]&subb[WIDTH-1]^sum[WIDTH-1]);//若为加法则判断b与sum,若为减法,则判断b取反加一后的值与sum。
endmodule
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
module addsub8(
input [7:0] a,
input [7:0] b,
input sub,
output [7:0] sum,
output cf,
output ovf,
output sf,
output zf
);
addsub_0 U1(a,b,sub,sum,cf,ovf,sf,zf);
Endmodule
module addsub8_sim();
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;
addsub8 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
四、 结果与分析。
当a=00000010,b=0000000c,进行加法运算时,结果为0000001c,正确。
200ns时,进行减法运算,结果为00000004,正确。
400ns时,sub变为0,加法运算,a=0000007f,b=00000002,结果为00000081,正确。
600ns时,a=000000ff,b=00000002,加法运算,结果为00000101,正确。
800ns时,当a=7fffffff,b=00000002,加法运算,结果为80000001,有溢出,符号为负。
1000ns时,a=00000016,b=00000017,做减法,结果为ffffffff,有借位,符号为负,正确。
1200ns时,a=0000ffff,b=00000001,结果为0010000,正确。
1400ns时,a=ffffffff,b=00000001,加法运算,结果为00000000,有进位,有溢出,结果为0。
当a=16,b=12时,做加法,结果为28,正确,当200ns时,做减法,结果为04,正确。当400ns时,a=7f,b=02,做加法,结果为81,有溢出,符号为负,正确。600ns时,a=ff,b=02,加法,结果为01,有进位,有溢出。800ns时,a=16,b=17,做减法,结果为ff,有借位,结果为负。a=fe,b=ff,做减法,结果为ff,有借位,结果为负。