• Verilog 加法器和减法器(5)


          前面二进制加法运算,我们并没有提操作数是有符号数,还是无符号数。其实前面的二进制加法对于有符号数和无符号数都成立。比如前面的8位二进制加法运算,第一张图我们选radix是unsigned,表示无符号加法,第二张图我们选radix是decimal,表示有符号数,从图中可知结果都是正确的。对于有符号数来说,负数默认是补码的形式存在。假设二进制数是n位,则对于无符号数来说,表示范围是0~(2^n) -1 ,对于有符号数,表示的范围是-(2^(n-1))~2^(n-1) - 1


    image


    image

    对于有符号数来说,通常还要知道加法结果数据是否溢出。有一种直观的方法判断结果是否溢出,就是如果两个加数有相同的符号,但是它们的和与它们有不同的符号,则产生溢出。假设有n位有符号二进制数x,y,它们的和为s,则它们和溢出判断公式是 overflow = xn_1&yn-1&~sn-1 + ~xn_1&~yn-1&sn-1

    修改后的有符号数加法代码为:

    module addern_signed(x, y, s, cout, overflow);
      parameter n=8;
      input [n-1:0] x;
      input [n-1:0] y;
      output reg[n-1:0] s;
      output reg cout;
      output reg overflow;
      reg [n:0] c;
      integer k;
    
    
      always @(x,y) begin
        c[0] = 1'b0;
    	 for(k = 0; k < n; k = k + 1) begin
    	   s[k] = x[k]^y[k]^c[k];
    		c[k+1] = (x[k]&y[k])|(x[k]&c[k])|(y[k]&c[k]);
    	 end
    	 cout = c[n];
    	 overflow = (x[n-1]&y[n-1]&~s[n-1])|(~x[n-1]&~y[n-1]&s[n-1]);
    	end
    
    endmodule
    module addern_signed(x, y, s, cout, overflow);
      parameter n=8;
      input [n-1:0] x;
      input [n-1:0] y;
      output [n-1:0] s;
      output  cout;
      output  overflow;
      integer k;
    
      assign {cout, s} = x + y ;
      assign overflow = (x[n-1]&y[n-1]&~s[n-1])|(~x[n-1]&~y[n-1]&s[n-1]);
    
     endmodule


    修改后的testbench文件为:

    `timescale 1ns/1ns
    `define clock_period 20
    
    module addern_signed_tb;
      reg [7:0] x,y;
    
      wire cout;
      wire [7:0] s;
      reg clk;
    
      addern_signed #(.n(8)) addern_signed_0(
    						.x(x),
    						.y(y),
    						.s(s),
    						.cout(cout)
                      );
    
      initial clk = 0;
      always #(`clock_period/2) clk = ~clk;
    
      initial begin
         x = 0;
         repeat(20)
    	    #(`clock_period) x = $random;
    
      end
    
      initial begin
         y = 0;
         repeat(20)
    	    #(`clock_period) y = $random;
    
      end
    
    
      initial begin
         #(`clock_period*20)
    	  $stop;
      end
    
    
    endmodule


    功能验证的波形图如下:


    image

    对于有符号数的减法,我们也可以用加法来做,但是对于减数,我们要做以下变化,如果减数为正数,则变其为补码表示的负数,如果其为补码表示的负数,则把它转化为正数。

    assign y1 = y[n-1]?(~{y[n-1:0]}+1'b1):(~{1'b0,y[n-2:0]}+1'b1);

    module subn_signed(x, y, s, cout, overflow);
      parameter n=8;
      input [n-1:0] x;
      input [n-1:0] y;
      output reg[n-1:0] s;
      output reg cout;
      output reg overflow;
      wire [n-1:0] y1;
      reg [n:0] c;
      integer k;
    
      //y commplement, if y=0, to negative with commplement,if y=1, to positive number. 
      assign y1 = y[n-1]?(~{y[n-1:0]}+1'b1):(~{1'b0,y[n-2:0]}+1'b1);
    
      always @(x,y1) begin
        c[0] = 1'b0;
    	 for(k = 0; k < n; k = k + 1) begin
    	   s[k] = x[k]^y1[k]^c[k];
    		c[k+1] = (x[k]&y1[k])|(x[k]&c[k])|(y1[k]&c[k]);
    	 end
    	 cout = c[n];
    	 overflow = (x[n-1]&y1[n-1]&~s[n-1])|(~x[n-1]&~y1[n-1]&s[n-1]);
    	end
    
    endmodule

    module subn_signed(x, y, s, cout, overflow);
      parameter n=8;
      input [n-1:0] x;
      input [n-1:0] y;
      output [n-1:0] s;
      output  cout;
      output  overflow;
      wire [n-1:0] y1;
      integer k;
      //y commplement, if y=0, to negative with commplement,if y=1, to positive number. 
      assign y1 = y[n-1]?(~{y[n-1:0]}+1'b1):(~{1'b0,y[n-2:0]}+1'b1);
      assign {cout, s} = x + y1 ;
      assign overflow = (x[n-1]&y1[n-1]&~s[n-1])|(~x[n-1]&~y1[n-1]&s[n-1]);
    
     endmodule

    testbench代码为:

    `timescale 1ns/1ns
    `define clock_period 20
    
    module subn_signed_tb;
      reg [7:0] x,y;
    
      wire cout;
      wire overflow;
      wire [7:0] s;
      reg clk;
    
      subn_signed #(.n(8)) subn_signed_0(
    						.x(x),
    						.y(y),
    						.s(s),
    						.cout(cout),
    						.overflow(overflow)
                      );
    
      initial clk = 0;
      always #(`clock_period/2) clk = ~clk;
    
      initial begin
         x = 0;
         repeat(20)
    	    #(`clock_period) x = $random;
    
      end
    
      initial begin
         y = 0;
         repeat(20)
    	    #(`clock_period) y = $random;
    
      end
    
    
      initial begin
         #(`clock_period*20)
    	  $stop;
      end
    
    
    endmodule

    从功能验证的波形图中,我们可以看到见过是正确的。


    image




































  • 相关阅读:
    纸牌游戏
    万圣节派对
    士兵杀敌(三)简单线段树
    百度之星2016资格赛之部分题解
    hdu Simpsons’Hidden Talents(kmp)
    滑梯理论
    PAP认证方式原理和实现
    Google的Protobuf协议分析
    HMac基本介绍
    为Tcl编写C的扩展库
  • 原文地址:https://www.cnblogs.com/mikewolf2002/p/10086552.html
Copyright © 2020-2023  润新知