You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SystemVerilog中三元运算符与always_comb实现乘法的差异及错误原因问询

问题:SystemVerilog有符号/无符号乘法实现差异分析

模块定义

我设计了一个支持有符号/无符号乘法的SystemVerilog模块,模块代码如下:

module signed_or_unsigned_mul
# (
  parameter n = 8
)
(
  input  [    n - 1:0] a, b,
  input                signed_mul,
  output [2 * n - 1:0] res
);

两种实现及问题

三元运算符实现(结果错误)

使用三元运算符实现时,部分测试用例结果错误,例如-8 * -7得到72,代码如下:

assign res = signed_mul ? ($signed(a) * $signed(b)) : (a * b) ;

always_comb+if实现(结果正确)

采用always_comb结合if语句的实现能得到正确结果,代码如下:

logic [2 * n - 1:0]  res_stub;
  assign res = res_stub;
  always_comb
    if (signed_mul)
      res_stub = $signed(a) * $signed(b);
    else 
      res_stub = a * b;

我不清楚这两种实现的差异所在,也不明白为何结果不同,请求指出原因,是否是中间变量导致的?


原因分析

两种实现的核心差异在于SystemVerilog的类型处理规则不同,和中间变量无关:

1. 三元运算符的类型统一规则

SystemVerilog要求三元运算符? :的两个分支表达式必须转换为同一类型,转换遵循以下逻辑:

  • 若两个分支位宽不同,窄位宽的表达式会被扩展到宽位宽。
  • 若位宽相同但符号性不同,有符号类型会被强制转换为无符号类型。

在你的代码中:

  • $signed(a) * $signed(b)的结果是有符号16位值。
  • a * b的结果是无符号16位值。

由于两者位宽相同、符号性不同,编译器会将有符号乘法的结果隐式转换为无符号数。如果有符号乘法的结果是负数,转换后会得到一个远大于预期的无符号数值;即使结果是正数,某些边界场景也可能因类型转换逻辑出现异常(比如你的测试用例中出现的错误)。

2. always_comb赋值的位模式直接复制

在always_comb的实现中,res_stub是无符号16位logic变量,赋值操作会直接将右边表达式的二进制位模式复制到左边变量中,不会进行隐式的类型转换:

  • 当执行有符号乘法时,$signed(a)*$signed(b)的补码结果会直接作为二进制位存储到res_stub中,这和有符号数的预期结果在二进制上是一致的(只是解释方式不同,但res作为输出位宽足够,能正确保留补码信息)。
  • 无符号乘法的结果则直接以无符号二进制位存储,符合预期。

这种赋值方式跳过了三元运算符的强制类型转换步骤,因此能得到正确结果。

内容的提问来源于stack exchange,提问作者Aleksandr Grigorev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 13:55:55