1 verilog中数据的符号属性(有符号数和无符号数)探究根源-德赢Vwin官网 网
0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

verilog中数据的符号属性(有符号数和无符号数)探究根源

FPGA开源工坊 来源:FPGA开源工坊 2023-12-10 10:50 次阅读

不知道有没有人像我一样,长久以来将verilog中的有符号数视为不敢触碰的禁区。不过俗话说啊解决恐惧的最好办法就是直面恐惧,又有俗话说要想工其事必先利其器,还有俗话说磨刀不误砍柴工,也有俗话说The only thing we have to fear is fear itself,所以今天咱们就尝试对verilog中数据的符号属性(有符号数和无符号数)探究根源。

本文的验证环境基于VCS通过auto_testbench生成,相关的vcs命令行细节请在auto_testbench工程目录下查询。

先说明一个大前提,有符号数即补码表示,无符号数即原码表示或者说必然是整数的补码表示,因此有符号数和无符号数均可以认为是数值的补码。

为了省流,还是先甩结论。有符号数和无符号数的最本质区别就是:符号位的识别和高位拓展。除此之外,另一个区别就是从人的角度如何如何读这个数,或者说$display(%d)打印时打印的值是什么(而从机器的角度它压根就不区分signed和unsigned)。也就是说,如果不涉及到位宽拓展的事,有符号数和无符号数在verilog运算中可以说毫无差别。

所以先给出两个结论,verilog中数据的符号属性会影响两件事:

1.符号位的识别和位宽拓展,有符号数最高位被识别为符号位,高位拓展时拓展符号位,无符号数高位拓展0;

2.数据的实际值(人的角度如何如何读这个数);

显然,这个这个结论和固有的认知出入有点大,不急咱们先看一个实验。下面的代码是一段不涉及到位宽拓展的运算,t0_va0为有符号数-1,也就是16'hffff:


	

	
logic signed[15:0]t0_va0 = -1;//16'hffff wire signed[15:0]t0_en0 = t0_va0 + 16'hffff; wire [15:0]t0_en1 = t0_va0 + 16'hffff; wire signed[15:0]t0_en2 = t0_va0 + $signed(16'hffff); wire [15:0]t0_en3 = t0_va0 + $signed(16'hffff); wire signed[15:0]t0_en4 = t0_va0 - 16'h1; wire signed[15:0]t0_en5 = t0_va0 - $unsigned(16'h1); wire [15:0]t0_en6 = t0_va0 - 16'h1; wire [15:0]t0_en7 = t0_va0 - $unsigned(16'h1);

仿真的结果如下:

0a9fb1d4-9699-11ee-8b88-92fbcf53809c.png

可以看到所有的结果都是一致的。而如果将va0信号改成无符号数:


	

	
logic [15:0]t1_va0 = 16'hffff; wire signed[15:0]t1_en0 = t1_va0 + 16'hffff; wire [15:0]t1_en1 = t1_va0 + 16'hffff; wire signed[15:0]t1_en2 = t1_va0 + $signed(16'hffff); wire [15:0]t1_en3 = t1_va0 + $signed(16'hffff); wire signed[15:0]t1_en4 = t1_va0 - 16'h1; wire signed[15:0]t1_en5 = t1_va0 - $unsigned(16'h1); wire [15:0]t1_en6 = t1_va0 - 16'h1; wire [15:0]t1_en7 = t1_va0 - $unsigned(16'h1);

其仿真结果也是一致的:

0ab7e54c-9699-11ee-8b88-92fbcf53809c.png

而一旦涉及到运算结果位宽拓展结果就有所差别了,比如将结果的位宽都改成18bit:


	

	
logic signed[15:0]t2_va0 = -1; wire signed[17:0]t2_en0 = t2_va0 + 16'hffff; wire [17:0]t2_en1 = t2_va0 + 16'hffff; wire signed[17:0]t2_en2 = t2_va0 + $signed(16'hffff); wire [17:0]t2_en3 = t2_va0 + $signed(16'hffff); wire signed[17:0]t2_en4 = t2_va0 - 16'h1; wire signed[17:0]t2_en5 = t2_va0 - $unsigned(16'h1); wire [17:0]t2_en6 = t2_va0 - 16'h1; wire [17:0]t2_en7 = t2_va0 - $unsigned(16'h1);

看到的波形就是这样:

0ac61630-9699-11ee-8b88-92fbcf53809c.png

这个事就有些神奇了,所以后面就是说明下这里面的区别,或者说在完成运算后工具是如何识别这个数的符号性以决定位宽拓展的结果的。在开始之前必须明确下一个有符号数(补码),'h1fffe和'hfffe对于机器是没有区别的,都是-2。

仿真工具在对一个运算结果进行位宽拓展时,会先识别这个数的符号属性,那么具体是怎么识别的呢?

1.有符号数和有符号数运算,结果为有符号数;

2.有符号数和无符号数运算,结果为无符号数;

3.无符号数和无符号数运算,结果为无符号数;

4.运算结果外又通过$signed和$unsigned定向指定时,最终的符号属性遵照指定结果;

5.等号左侧信号声明中的signed/unsigned不影响右侧运算结果的符号数属性;

好,咱们一个一个看。

有符号数和有符号数运算,结果为有符号数。


	

	
logic signed[15:0]t3_va0 = -1; wire signed[17:0]t3_en0 = t3_va0 - $signed(16'h1); wire signed[17:0]t3_en1 = t3_va0 + $signed(16'hffff); wire [17:0]t3_en2 = t3_va0 - $signed(16'h1); wire [17:0]t3_en3 = t3_va0 + $signed(16'hffff);

0ad7a044-9699-11ee-8b88-92fbcf53809c.png

很显然,两个有符号数进行操作结果是有符号数,位宽拓展时拓展符号位。同时这个波形还说明了等号左侧信号声明中的signed/unsigned不影响右侧运算结果的符号数属性

有符号数和无符号数运算,结果为无符号数。


	

	
wire signed[17:0]t3_en4 = t3_va0 - 16'h1; wire signed[17:0]t3_en5 = t3_va0 + 16'hffff; wire [17:0]t3_en6 = t3_va0 - 16'h1; wire [17:0]t3_en7 = t3_va0 + 16'hffff;
0aeab6de-9699-11ee-8b88-92fbcf53809c.png显然结果是无符号数,高位拓展时拓展的都是0。

无符号数和无符号数运算,结果为无符号数。这个不说了,显而易见的事情。

运算结果外又通过$signed和$unsigned定向指定时,最终的符号属性遵照指定结果。


	

	
wire signed[17:0]t3_en8 = $unsigned(t3_va0 - $signed(16'h1)); wire signed[17:0]t3_en9 = $unsigned(t3_va0 + $signed(16'hffff)); wire [17:0]t3_en10 = $signed(t3_va0 - 16'h1); wire [17:0]t3_en11 = $signed(t3_va0 + 16'hffff);
0afc075e-9699-11ee-8b88-92fbcf53809c.png因为在运算之后又通过$signed和$unsigned指定了符号属性,所以后面的位宽拓展就按照对应的属性来了。再次进一步的佐证,等号左侧信号声明中的signed/unsigned不影响右侧运算结果的符号数属性。

好了现在我们再把前文的结论翻出来,verilog中的符号属性会影响两件事情:

1.符号位的识别和位宽拓展,有符号数最高位被识别为符号位,高位拓展时拓展符号位,无符号数高位拓展0;

2.数据的实际值(人的角度如何如何读这个数);

再看这个测试就很好解释了:


	

	
logic signed[15:0]t2_va0 = -1; wire signed[17:0]t2_en0 = t2_va0 + 16'hffff; //就是'hffff+'hffff = 'h1fffe wire [17:0]t2_en1 = t2_va0 + 16'hffff; //同上 wire signed[17:0]t2_en2 = t2_va0 + $signed(16'hffff); //本质还是'hffff+'hffff = 'h1fffe,不过因为结果是有符号数,拓展位宽为18bit时拓展为18'h3fffe wire [17:0]t2_en3 = t2_va0 + $signed(16'hffff); //同上 wire signed[17:0]t2_en4 = t2_va0 - 16'h1; //本质是'hffff-'h1,或者理解成'hffff+'hffff,加上一个负数位宽一定不需要高位拓展,所以结果是'hfffe //再根据等号左侧的需求拓展为18bit,无符号数拓展0,结果为18'fffe wire signed[17:0]t2_en5 = t2_va0 - $unsigned(16'h1); //同上 wire [17:0]t2_en6 = t2_va0 - 16'h1; //同上 wire [17:0]t2_en7 = t2_va0 - $unsigned(16'h1); //同上

0b10ff92-9699-11ee-8b88-92fbcf53809c.png

再来补充一个,大家看看结果应该是啥:


	

	
wire [17:0]t2_en8 = t2_va0 - $signed(16'h1);

显然结果应该是18'h3fffe,因为左侧的运算结果是有符号数的16'hfffe,拓展成18bit时拓展符号位1:

0b254614-9699-11ee-8b88-92fbcf53809c.png

最后呢再看一组额外的实验,感兴趣的可以分析一下结果:

	

	
//test logic [1:0]va_u; logic signed[1:0]va_s; logic [2:0]vb_u; logic [2:0]vb_s; logic [31:0]vc_u; logic [31:0]vc_s; initial begin va_u = -1; va_s = -1;//signed $display("va_u='b%0b, va_s='b%0b", va_u, va_s); $display("va_u=%0d, va_s=%0d", va_u, va_s); vb_u = -va_u; vb_s = -va_s; $display("vb_u='b%0b, vb_s='b%0b", vb_u, vb_s); $display("vb_u=%0d, vb_s=%0d", vb_u, vb_s); vc_u = va_u; vc_s = va_s; $display("vc_u='b%0b, vc_s='b%0b", vc_u, vc_s); end

仿真的结果为:


	

	
va_u='b11, va_s='b11 va_u=3, va_s=-1 vb_u='b101, vb_s='b1 vb_u=5, vb_s=1 vc_u='b11, vc_s='b11111111111111111111111111111111



声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表德赢Vwin官网 网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Verilog
    +关注

    关注

    28

    文章

    1351

    浏览量

    110074
  • 运算
    +关注

    关注

    0

    文章

    130

    浏览量

    25785
  • 符号
    +关注

    关注

    0

    文章

    55

    浏览量

    4332

原文标题:【芯片设计】verilog中有符号数和无符号数的本质探究

文章出处:【微信号:FPGA开源工坊,微信公众号:FPGA开源工坊】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    关于verilog符号数符号数

    在数字电路,出于应用的需要,我们可以使用符号数,即包括0及整数的集合;也可以使用符号数,即包括0和正负数的集合。在更加复杂的系统
    的头像 发表于 11-18 17:46 1.7w次阅读

    verilog中有符号数符号数的本质探究

    不知道有没有人像我一样,长久以来将verilog符号数视为不敢触碰的禁区。
    的头像 发表于 12-04 16:13 1182次阅读
    <b class='flag-5'>verilog</b>中有<b class='flag-5'>符号数</b>和<b class='flag-5'>无</b><b class='flag-5'>符号数</b>的本质<b class='flag-5'>探究</b>

    采集的数据转换成符号数的问题

    的时候怎么都不正确,具体原因如下,字符串转数值的时候只发现可以转换成符号数,而采集下来的数据符号数,转换成
    发表于 05-02 11:55

    原码、补码、反码、符号数符号数概念.pdf

    原码、补码、反码、符号数符号数概念.pdf
    发表于 11-15 08:44

    符号数符号数,浮点数探讨

    本帖最后由 hq1987 于 2015-4-29 11:52 编辑 对于符号数大家都基本理解,我主要说说符号数,浮点数在机器世界里到底是怎么表示的。1、
    发表于 04-29 10:15

    关于符号数符号数的困惑

    ,存储符号数)Tab = -4'd12;//整数Tab的十进制数为-12,位形式为110100.(因为Tab是整数寄存器变量,存储符号数)我的困惑是,-12的二进制补码应该是101
    发表于 11-02 14:13

    请问AFE5801 AD转换后数字信号是用符号数还是符号数表示?

    请问AFE5801 AD转换后数字信号是用符号数还是符号数表示的啊?
    发表于 05-24 08:04

    双状态符号/符号数据类型

    双状态符号数据类型双状态符号数据类型四状态数据类型
    发表于 01-18 06:03

    单字节符号数据块排序(增序)

    单字节符号数据块排序(增序)   入口条件:数据块的首址在R0,字节数在R7。出口信息:完成排序(增序)影响资
    发表于 01-19 22:58 1139次阅读

    fpga 符号数符号数

     在设计,所有的算数运算符都是按照符号数进行的。如果要完成符号数计算,对于加、减操作通过补码处理即可用
    的头像 发表于 10-09 15:22 6065次阅读
    fpga <b class='flag-5'>有</b><b class='flag-5'>符号数</b>、<b class='flag-5'>无</b><b class='flag-5'>符号数</b>

    FPGA符号数乘法操作指南

    FPGA乘法器是很稀缺的资源,但也是我们做算法必不可少的资源。7系列及之前的FPGA都是25x18的DSP,UltraScale是27x18,我们可以通过调IP Core的方式或者原语的方式来进行乘法操作。在里面可以设置
    的头像 发表于 03-08 17:14 6666次阅读
    FPGA<b class='flag-5'>有</b><b class='flag-5'>符号数</b>乘法操作指南

    详细分析Verilog编写程序测试符号数符号数的乘法

    符号数的计算在 Verilog 是一个很重要的问题(也很容易会被忽视),在使用 Verilog 语言编写 FIR 滤波器时,需要涉及到
    的头像 发表于 05-02 10:48 7502次阅读
    详细分析<b class='flag-5'>Verilog</b>编写程序测试<b class='flag-5'>无</b><b class='flag-5'>符号数</b>和<b class='flag-5'>有</b><b class='flag-5'>符号数</b>的乘法

    C语言中符号数符号数的左移和右移

    。那么对于符号数符号数,对于左移和右移的操作分别是如何呢?下面通过实验来进行验证:对于符号数
    发表于 01-13 13:17 2次下载
    C语言中<b class='flag-5'>无</b><b class='flag-5'>符号数</b>和<b class='flag-5'>有</b><b class='flag-5'>符号数</b>的左移和右移

    FPGA符号数乘法说明

    FPGA乘法器是很稀缺的资源,但也是我们做算法必不可少的资源。7系列及之前的FPGA都是25x18的DSP,UltraScale是27x18,我们可以通过调IP Core的方式或者原语的方式来进行乘法操作。在里面可以设置
    的头像 发表于 02-16 16:21 4868次阅读
    FPGA<b class='flag-5'>中</b>的<b class='flag-5'>有</b><b class='flag-5'>符号数</b>乘法说明

    关于符号数据类型的示例

    我们学习一下Systemverilog符号数据类型的赋值。
    的头像 发表于 10-17 14:40 1022次阅读