【问题标题】:Unexpected behaviour using the ternary operator (Verilog)使用三元运算符 (Verilog) 的意外行为
【发布时间】:2018-11-26 04:06:02
【问题描述】:

在下面的 Verilog 模块中,我想了解为什么使用串联的阻塞赋值与 2 个注释掉的阻塞赋值的结果不同。

当我在 FPGA 上运行程序时,它给出了预期的结果,有 2 个阻塞分配(LED 闪烁),但没有使用串联的阻塞分配(LED 保持关闭)。

针对 Verilog 规范解释此处所起作用的答案的奖励积分!

/* Every second, the set of leds that are lit will change */
module blinky(
input clk,
output [3:0] led
);
    reg [3:0] count = 0;
    reg [27:0] i = 0;
    localparam [27:0] nTicksPerSecond = 100000000;

    assign led = {count[3],count[2],count[1],count[0]};

    always @ (posedge(clk)) begin
        // This works:
        //count = i==nTicksPerSecond ? (count + 1) : count;
        //i     = i==nTicksPerSecond ? 0 : i+1;

        // But this doesn't:
        {count,i} = i==nTicksPerSecond ? 
          {count+1, 28'b0  } :
          {count  , i+1};
    end
endmodule

PS:我使用 Vivado 2018.2

【问题讨论】:

  • 1/ 你应该使用非阻塞赋值。 2/ i+1 将是 32 位宽,并打乱您的 {count , i+1} 位顺序。
  • @Oldfart 我认为使用阻塞或非阻塞赋值不会改变任何东西,因为只有一个赋值。对吗?
  • 始终在时钟部分使用非阻塞分配。 (是的,即使它是一个单一的任务!)
  • @Oldfart 你能解释一下为什么或者给我一些相关的解释吗?
  • 因为这是与实际硬件相匹配的行为。搜索阻塞/非阻塞。有几十篇关于这个主题的帖子。

标签: verilog


【解决方案1】:

原因是count+1i+1的宽度都是32位。一个未指定大小的数字是 32 位宽(1800-2017 LRM 第 5.7.1 节),加法运算符的宽度是最大操作数的大小(LRM 第 11.6.1 节)。为了使您的代码正常工作,请为您的数字文字添加适当的大小

 {count,i} = i==nTicksPerSecond ? 
          {count+4'd1, 28'b0  } :
          {count  , i+28'd1};

编写此代码的更简单方法是

  always @ (posedge clk) 
      if (i== nTicksPerSecond)
         begin 
           count <= count + 1;
           i <= 0;
         end
      else
         begin
           i <= i + 1;
         end

【讨论】:

  • 谢谢!你知道在这种情况下编译器是否有办法生成警告(比如“右边的东西比左边的东西大”)?您将如何简化此代码?
  • 不幸的是,大多数工具不会生成警告,因为 Verilog 是弱类型的。
  • 那真是太不幸了……我猜VHDL会很好地处理这种情况(我听说它是​​强类型的)
  • 你发布的问题是一个完美的例子,说明连接很容易出错
  • 一个代码检查工具应该能解决这类问题
猜你喜欢
  • 2017-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-08
  • 2023-03-09
  • 2014-01-18
  • 2011-12-31
  • 1970-01-01
相关资源
最近更新 更多