【问题标题】:Why does inlining a Verilog arithmetic shift turn it into a logical one?为什么内联 Verilog 算术移位将其变成逻辑移位?
【发布时间】:2020-02-21 19:59:16
【问题描述】:

我已经阅读了multiplequestions,了解如何在 Verilog 中实现算术移位。所有人都建议使用$signed(…) >>> …。

这在直接将结果分配给线路或寄存器时有效,但在将其用作更大表达式的一部分时无效。那就是:

  • reg[2:0] a = $signed(3'b100) >>> 1 ; 产生 3'b110
  • reg[2:0] a = 1'b1 ? $signed(3'b100) >>> 1 : 3'b000; 产生 3'b010

修复似乎是将计算包装到$unsigned:

  • reg[2:0] a = $unsigned($signed(3'b100) >>> 1) ; 产生 3'b110
  • reg[2:0] a = 1'b1 ? $unsigned($signed(3'b100) >>> 1) : 3'b000; 产生 3'b110

为什么内联算术移位会使其表现得像一个逻辑移位,为什么在它周围添加$unsigned 可以解决问题?

这是一个最小的工作示例:

module puzzle();
   reg [2:0] a_u = 3'b100 >>> 1; // 3'b010
   reg [2:0] a_s = $signed(3'b100) >>> 1; // 3'b110
   reg [2:0] a_mux = 1'b1 ? $signed(3'b100) >>> 1 : 3'b000; // 3'b010

   reg [2:0] b_u = $unsigned(3'b100 >>> 1); // 3'b010
   reg [2:0] b_s = $unsigned($signed(3'b100) >>> 1); // 3'b110
   reg [2:0] b_mux = 1'b1 ? $unsigned($signed(3'b100) >>> 1) : 3'b000; // 3'b110

   initial begin
      $display("a_u = 3'b%3b", a_u);
      $display("a_s = 3'b%3b", a_s);
      $display("a_mux = 3'b%3b", a_mux);

      $display("b_u = 3'b%3b", b_u);
      $display("b_s = 3'b%3b", b_s);
      $display("b_mux = 3'b%3b", b_mux);
   end
endmodule

输出:

a_u = 3'b010
a_s = 3'b110
a_mux = 3'b010
b_u = 3'b010
b_s = 3'b110
b_mux = 3'b110

【问题讨论】:

    标签: verilog bit-shift


    【解决方案1】:

    这里有两个 Verilog 表达式规则:

    • 上下文确定的表达式与自行确定的表达式
    • 在上下文中,混合有符号和无符号操作数会导致所有内容都无符号

    当你有表达时

    C ? A : B
    

    操作数A 和B 相互关联。每个操作数都将调整为最大操作数,并且两者都必须签名才能保持签名。这发生在编译期间应用运算符之前。 S 是自定的——除了 C 之外,没有任何东西对其大小或签名有任何影响。另外,C 对A 和B 的上下文没有影响

    当你有表达式时也是如此

    A >>> S
    

    A 是上下文确定的,S 是自行确定的

    现在如果我们将这两个表达式合二为一:

    C ? A >>> S : B
    

    由于A 和B 在相同的上下文中并且B 是无符号的,A 被转换为无符号。一旦您将A>>>S 包装在函数调用中(任何类型的函数调用都一样),函数的每个输入参数都有自己的上下文,独立于它所属的表达式的其余部分。返回值将与表达式的其余部分一起在上下文中处理。

    【讨论】:

    • 太棒了,谢谢!有没有一种更简洁的方式来赋予表达式它自己的上下文,而不是使用$unsigned?
    • 我不会称它为 clean,但使用连接的字符更少。 1'b1 ? {3'sb100) >>> 1} : 3'b000。串联中的所有操作数都是自行确定的。
    【解决方案2】:

    我不知道原因,但似乎将3'b000 转换为3'sb000 也可以解决您的问题。

    reg [2:0] a_mux = 1'b1 ? $signed(3'b100) >>> 1 : 3'sb000;
    

    另外,使用$signed() 代替$unsigned() 也可以:

    reg [2:0] b_mux = 1'b1 ? $signed($signed(3'b100) >>> 1) : 3'b000;
    

    【讨论】:

      猜你喜欢
      • 2011-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-23
      • 1970-01-01
      • 2021-07-08
      • 1970-01-01
      • 2010-09-05
      相关资源
      最近更新 更多