在用SystemVerilog码代码的时候,经常会遇到逻辑和算术运算表达式,除了之前提到的运算符优先级问题,还有一个头疼的问题就是符号位扩展。
什么时候会自动进行符号位扩展?
什么时候需要人工扩展?
不知道大家是否了然于胸呢?
先来想想下面这几个问题,热热身:
对有符号数进行截位,会得到有符号数吗?
有符号数和无符号数相加,结果是有符号数吗?
操作数都是有符号数,结果一定是有符号数吗?
别担心,今天Q哥跟大家一起梳理一遍。
先说两个概念,context-determined操作数
和self-determined操作数
。
context-determined
操作数是指进行运算的时候,需要根据当前的上下文对操作数先进行扩展,然后再运算。
举个例子 :
代码片段1
求a+b然后赋值给c的时候,会先判断a b c的位宽,找出他们中的最大位宽,对其余的进行扩展。
这里c是16位最大,那么会先把a和b扩展到16位,然后求加法, 再赋值给c。
self-determined
操作数是指不需要根据当前的上下文对操作数进行扩展,直接运算。
再举个例子:
代码片段2
这里直接对b求缩位与运算得到1’b1, 然后 c = a | 1‘b1;
之后的按位或以及赋值都是context-determined运算符。
这里根据context-determined还是self-determined,整理了一下各种运算符:
表1
这张表格Q哥不建议大家死记硬背,只是想引起大家注意符号位扩展问题,在写代码的时候,能够提前避免写出容易出错的代码。
接下来给大家把开头的几个误区掰开揉碎。
误区1:对有符号数进行截位,会得到有符号数吗?
代码片段3
如上面代码片段3所示,a和b都是16比特有符号数,截取b的高8位赋给a时,会自动扩展符号位吗?
答案是否定的。
根据上面表格1可知,位选择操作数b是self-determined,不受上下文影响,结果b[15:8]是无符号数。
而赋值操作符号位由右侧决定,所以a最终得到的是无符号数b[15:8]高位补0进行扩展后得到的{8‘h0, b[15:8]},即16‘h00ff。
误区2:有符号数和无符号数相加,结果是有符号数吗?
代码片段4
如上面代码片段4所示,a是16比特有符号数,b是16比特无符号数,d是32位有符号数。
a+b会进行符号位扩展吗?
答案是否定的。
根据上面表格1可知,算术运算中如果一个是有符号数,一个是无符号数,则视为两个无符号数运算。
因此会先对a和b的高位补0将它们扩展为32位(即32’h0000_ffff和32’h0000_0001),然后计算,最后把结果赋值给d。
所以d最终得到的是32’h0001_0000.
误区3:操作数都是有符号数,结果一定是有符号数吗?
代码片段5
如上面代码片段5所示,a c都是16比特有符号数,d是32比特有符号数。
a会扩展符号位吗?
答案是否定的。
根据上面表格可知,缩进或运算是self-determined,因此不会进行符号扩展,其结果是1比特无符号数。
相当于a加上一个1比特无符号数(如下面代码片段6所示)。
根据上面表格1可知,算术运算时,一个有符号数,一个是无符号数,则视为两个无符号数运算。
因此会先对a和e高位补0将它们扩展为32位(32’h0000_ffff和32’h0000_0001),然后进行加法计算,最后把结果赋值给d。
所以d最终结果是32’h0001_0000.
代码片段6
看到这里是不是有些晕?
Q哥给大家支一招。
在进行运算的时候,加上signed关键字就好了。
比如上面前两个个误区,可以写成:
代码片段7
但是需要特别强调一点,如果原本操作数只有一比特,那么需要高位先补一个0,再加上signed关键字。
因为1‘b1直接当作signed扩展,会变成-1。
这点大家一定要注意!
总结
在运算和条件表达式里面出现操作数位宽不一致时,可能会自动进行位宽扩展。
如果出现有符号数时,一定要慎之又慎。
对于拿不准的,最好根据实际需求,手动补齐高位,或者添加signed关键字。
验证无难事,只要肯积累。我们下期再见!
来源| 杰瑞IC验证(ID:Jerry_IC)
|原创作者| Q哥