SystemVerilog中三元运算与一元归约或运算结合异常的底层原因咨询
SystemVerilog三元运算中归约或(|b)导致异常的底层原因
问题代码
module tb(); bit signed [0:3] a = 5; bit signed [0:3] b = -3; bit [0:1] op; bit signed [0:4] result; initial begin op = 0; result = 0; result = (op == 0)? a+b : (op == 1)? a-b: (op == 2)? ~a : |b; $display("%0p %0p %0p", result, a, b); op = 1; result = 0; result = (op == 0)? a+b : (op == 1)? a-b: (op == 2)? ~a : |b; $display("%0p %0p %0p", result, a, b); op = 2; result = 0; result = (op == 0)? a+b : (op == 1)? a-b: (op == 2)? ~a : |b; $display("%0b %0b %0p", result, a, b); op = 3; result = 0; result = (op == 0)? a+b : (op == 1)? a-b: (op == 2)? a : |b; $display("%0p %0p %0p", result, a, b); end endmodule
底层原因
SystemVerilog的三元运算符?:有个核心规则:所有分支表达式会被统一转换为同一个公共类型,这个转换在编译阶段就完成,和运行时实际执行哪个分支无关。
具体到你的代码,问题出在三个关键点:
- 归约运算的类型特性:归约或
|b属于归约运算,不管输入的b是几位带符号数,归约运算的结果永远是1位无符号的bit类型。 - 公共类型的确定:当分支中同时存在带符号多bit类型(比如
a+b、~a,都是带符号位宽的数值)和无符号单bit类型(|b)时,SystemVerilog会把整个三元表达式的公共类型定为无符号类型,位宽取所有分支的最大位宽(这里是5位)。 - 符号信息丢失:所有带符号的分支表达式会被强制转成无符号类型,再赋值给带符号的
result。这会导致带符号数的符号位被当作普通数据位处理,直接丢失符号信息:- 比如
~a原本是带符号4位的1010(对应十进制-6),转成无符号5位后变成01010(十进制10),最终result得到的是10而非预期的-6。 - 当你把
|b替换为b时,所有分支都是带符号类型,公共类型保持带符号,转换过程保留符号信息,代码自然正常运行。
- 比如
内容的提问来源于stack exchange,提问作者Md Mashur Shalehin 152420
相关产品推荐
相关产品推荐

