欢迎各位朋友关注“郝旭帅电子设计团队”公众号,本公众号会定时更新相关技术类资料、软件等等,感兴趣的朋友可以浏览一下本公众号的其他“模块”,希望各位朋友都能在本公众号获得一些自己想要的“东西”。
本篇主要是讨论Verilog中有符号数表示方法
定义
reg [3:0] cnt;// cnt 为无符号位,表示的范围为0到15reg signed [3:0] cnt;//cnt为有符号位,表示的范围为-8到+7
注:定义时重点有两个:关键字(signed)和位宽。
有符号数的能够表示的范围为:-2的(N-1)次幂到+2的(N-1)次幂-1.
例:reg signed [3:0] cnt。表示范围-2的(4-1)次幂为-8到2的(4-1)次幂-1为7.
直接赋值有符号数
reg [7:0] unsigned_var;reg signed [7:0] signed_var;initial beginunsigned_var = 8'b1000_0000; // 无符号:128signed_var = 8'b1000_0000; // 有符号:-128signed_var = -42; // 直接赋负值signed_var = 8'sd170; // 有符号十进制表示end
有符号数的具体bit说明
最高位为符号位:1表示负数;0表示非负数(0或者正数)。
非负数利用原码来表示有符号数。
负数利用补码来表示有符号数。
原码:
+5 的原码是 0000 0101
-5 的原码是 1000 0101
最直观的表示方法。
最高位为符号位:0表示正数,1表示负数。
其余位为数值位的绝对值。
例如,在8位系统中:
补码:
现代计算机系统中表示有符号整数的标准方式。
优点:可以将减法运算转换为加法运算,简化CPU设计。
正数的补码与其原码相同。
负数的补码是其对应正数原码“按位取反后加1”。
换算方法
我们以一个8位的数为例来说明整个过程。
1. 从 负数的原码 求其 补码
方法:符号位不变,数值位取反,然后整个数加1。
例子:求 -5 的补码。
找到对应正数的原码: +5 的原码是 0000 0101
写出负数的原码: -5 的原码是 1000 0101(符号位变为1)
符号位不变,数值位取反:
原码: 1 000 0101
符号位 1 不变。
数值位 000 0101 取反变为 111 1010。
得到: 1111 1010(这一步得到的结果称为反码)。
整个数加1:
1111 1010 + 1 = 1111 1011
最终结果: 1111 1011 就是 -5 在8位系统中的补码。
2. 从 负数的补码 求其 原码
方法:同样是“符号位不变,数值位取反,然后整个数加1”。 这个运算是可逆的。
例子:已知补码是 1111 1011,求其原码(即它代表的负数的原码形式)。
补码: 1111 1011
符号位不变,数值位取反:
补码: 1 111 1011
符号位 1 不变。
数值位 111 1011 取反变为 000 0100。
得到: 1000 0100。
整个数加1:
1000 0100 + 1 = 1000 0101
最终结果: 1000 0101 就是这个数的原码。根据原码定义,最高位1表示负数,数值位是 000 0101(即5),所以这个补码表示的数是 -5。
注:上面罗里吧嗦的说了一堆,其实我们使用的时候,并不需要了解那么多。在计算原码时,我们也可以利用verilog的功能性的语句进行计算。
例:dy为有符号数,dyabs为dy的绝对值。
always @ (posedge clk) beginif (dy < 0)dyabs <= -dy;elsedyabs <= dy;end
有符号数拓展位宽
reg signed [7:0] a;reg signed [15:0] extended_sum;// 符号扩展extended_sum = { {8{a[7]}}, a }; // 手动符号扩展extended_sum = $signed(a); // 系统函数符号扩展
有符号数,拓展位宽时,需要拓展的是符号位(不能直接加0呦)。
利用仿真工具仿真时
对于有符号数的变量,不能直接设置为Unsigned,而是需要设置为Decimal(有符号的十进制)。
本篇内容中有部分资源来源于网络,如有侵权,请联系作者。
1718