无符号数的减法_2补方式数的表示与加减乘设计要点

2补方式数的表示与加减乘设计要点

2补方式数的表示

       一个n位二进制数b[n-1:0]可以表示无符号数的范围为0~(2^n)-1 (2^n表示2的n次方)。其表示的十进制数d为:

d=b[0]*(2^0) + b[1]*(2^1) + b[2]*(2^2) + ... + b[n-2]*(2^(n-2)) + b[n-1]*(2^(n-1))

 比如8位二进制数0001_0011表示的无符号十进制数为:

2^4 + 2^1 + 2^0 = 19

      一个n位二进制数可以表示有符号数的范围为 -(2^(n-1))~(2^(n-1))-1 。比如8位二进制数可以表示有符号数范围为 -128~+127 。其对应的二进制及其表示的十进制数如下图所示。

fed383fbd11a94179bac5ccd3adf6065.png

图片来自《Verilog HDL 高级数字设计》

      怎么得到一个有符号数其对应的二进制表示呢?方法如下:

      1. 先根据2补方式表示的数,判断最少需要几位来表示我们需要表示的数。比如:-128 最少需要9位二进制来表示。

      2. 如果待表示的数为正数,则正常用二进制数来表示即可;如果待表示的数为负数,则先得到其正数的二进制表示,再将其正数的二进制表示按位取反之后,最后再加上1。比如:18的8位二进制表示为0001_0010, 那么-18的二进制表示为:~(0001_0010)+ 1 = 1110_1101 + 1 = 1110_1110。

(    

       反观一下:1110_1110表示的无符号数是 

2^7 + 2^6 + 2^5 + 2^3 + 2^2 + 2^1

= 128+64+32+8+4+2 = 238 = 256 - 18 

为啥要反观一下呢,这里告诉大家,一个负数a的n位二进制表示,等于无符号数 2^n - |a| 的二进制表示。

       8位二进制数1110_1110表示有符号数-18。我们可以发现:

-18 =128+64+32+8+4+2-256 = 238 - 256 

= 64+32+8+4+2-128 

=2^6 + 2^5 + 2^3 + 2^2 + 2^1 - 2^7

通过这个例子告诉大家一个现象就是n位二进制有符号数b[n-1:0]表示的十进制数为:

 d = b[0]*(2^0) + b[1]*(2^1) + b[2]*(2^2) + ... + b[n-2]*(2^(n-2)) - b[n-1]*(2^(n-1))

提到这个是为了让大家更好理解有符号整数乘法器的设计原理。

)

加减法描述要点

      问题:为什么采用2补方式数的表示?

      答:就是为了利于加法的实现。比如两个 -18跟8的8位二进制数相加,如下(相同位相加等于2,则向高位产生进位):

      1110_1110 + 0000_1000 = 1111_0110

8位二进制的加法结果1111_0110表示的数为:

      d = 2^1 + 2^2 + 2^4 + 2^5 + 2^6 - 2^7 = -10

看到没有,其表示的结果正好正确,不管是做有符号数加法还是无符号数加法,无需做任何其他修改。

       但是特别注意,当相加的两个数位宽不匹配,一定要先将位宽少的数做符号位扩充,否则就会出错。比如:

a[7:0] = 1110_1110,b[8:0] = 00000_1000

将a,b送入一个9位的加法器相加,一定要先对a做符号位扩充。因为不做符号位扩充,在写Verilog时,默认将a最高位补0,a变成了9位二进制数,其表示的是238:

01110_1110 = 238

自然运算结果就会出错。

       当我们在写Verilog时,可以采用如下方式进行符号位填充(填充到与输出结果数据位宽一致的位宽)再加,同时避免加法结果产生溢出,其加法的结果信号可以定义成比最高位宽加数的位宽多1bit:

module add #(  parameter D_W_A = 7,  parameter D_W_B = 5)(   input [D_W_A-1:0]  a,   input [D_W_B-1:0]  b,   output [D_W_A:0] c);   wire [D_W_A:0] a_b = { {(1){a[D_W_A-1]}}, a};   wire [D_W_A:0] b_b = { {(D_W_A-D_W_B+1){b[D_W_B-1]}}, b};   assign c = a_b + b_b;endmodul

      对于减法,减去一个数等于加上这个数的负数,也就是减去一个数,等于加上这个数的补码(取反加1)。a[D_W-1:0]-b[D_W-1:0]可以采用如下方式描述:

module div #(   parameter D_W = 7)(  input  [D_W-1:0] a,  input  [D_W-1:0] b,  output [D_W-1:0] c);  wire b_b = ~b;  assign c = a + b_b + 1'b1; //类似于带进位输入的加法器endmodule

      二进制加法器的门级实现方式最常见的有逐位进位链、超前进位两种方式(笔试常见),具体实现电路可以参考书籍《Verilog HDL 高级数字设计》,或继续关注公众号接下来的文章。

乘法器设计与描述要点

无符号乘法器设计可以直接采用移位加操作即可。比如n位二进制数a[n-1:0]乘以m位二进制数b[m-1:0],其原理如下:

a*b = a * (b[0]*(2^0) + b[1]*(2^1) + b[2]*(2^2) + ... + b[n-2]*(2^(n-2)) + b[n-1]*(2^(n-1)) ) 

= a*b[0]*(2^0) + a*b[1]*(2^1) + a*b[2]*(2^2) + ... + a*b[n-2]*(2^(n-2)) + a*b[n-1]*(2^(n-1))

乘以2^n等于左移n位。

      对于无符号数乘法可以直接采用*描述,我们知道一个D_W_A位的数乘以一个D_W_B位的数,其结果最多为D_W_A+D_W_B位,故可以将其结果定义成D_W_A+D_W_B位,以避免产生结果溢出。

module mul #(  parameter D_W_A = 7,  parameter D_W_B = 5)(   input [D_W_A-1:0]  a,   input [D_W_B-1:0]  b,   output [D_W_A+D_W_B-1:0] c);   assign c = a * b;endmodule

     有符号数乘法原理如下(结合上面有符号数的表示来理解),比如n位有符号二进制数a[n-1:0]乘以m位有符号二进制数b[m-1:0]:

a*b = a * (b[0]*(2^0) + b[1]*(2^1) + b[2]*(2^2) + ... + b[n-2]*(2^(n-2)) - b[n-1]*(2^(n-1)) ) 

= a*b[0]*(2^0) + a*b[1]*(2^1) + a*b[2]*(2^2) + ... + a*b[n-2]*(2^(n-2)) - a*b[n-1]*(2^(n-1))

      但是对于有符号数乘法,我们必须先将待乘数做符号位填充,填充到n+m位,因为乘法是基于加法操作,而有符号数加法操作不做符号位填充,其结果就会出错。当采用 * 描述乘法操作时,其描述方式可以如下(位宽分别为D_W_A、D_W_B的两个数据相乘):

module mul #(  parameter D_W_A = 7,  parameter D_W_B = 5)(   input [D_W_A-1:0]  a,   input [D_W_B-1:0]  b,   output [D_W_A+D_W_B-1:0] c);   wire [D_W_A+D_W_B-1:0] a_b = { {D_W_B{a[D_W_A-1]}}, a};   wire [D_W_A+D_W_B-1:0] b_b = { {D_W_A{b[D_W_B-1]}}, b};   assign c = a_b * b_b;endmodule

      对于具体的乘法器的电路设计大家可以参考书籍《Verilog HDL 高级数字设计》的内容,或继续关注公众号接下来的文章。

推荐参考书籍:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值