【计算机组成与结构】加减法器的设计

1,030 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 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,详见表。

image.png

1 )可变位宽的加减法器 IP 核的设计

1、 新建一个项目,名为addsub

image.png

1、 设计源文件

被操作数为a,操作数为b,加减法控制信号为sub,当sub为1的时候做减法,为0的时候做加法。另外输出为运算结果sum,还有进位/借位标志cf,有符号数溢出标志 ovf,符号标志 sf以及结果为0标志zf。将该加减法器封装成 IP 核 addsub。****

2、 添加仿真代码

image.png

利用仿真程序进行仿真:

image.png

仿真截图如上:

image.png

image.png

4 、封装ip核

image.png

image.png

image.png

将ip核文件复制到ipcore/caculate文件夹下,并且解压。


2 )8 位加减法器的设计

1、首先新建addsub8项目,然后倒入ip核

2、点击Ip catalog,在选中导入的ip核,双击然后设置数据宽度,generate。

image.png

image.png

1、添加源文件,代码如下

image.png

1、添加仿真文件

2、点击Run Synthesis进行综合,综合完成后点击open Synthesized Design,再点击layout-i/o planning进行管脚分配。

image.png

6、点击Run Implement进行实现。

image.png

核心代码:

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,有借位,结果为负。