verilator 中的阻塞和非阻塞赋值错误

问题描述 投票:0回答:3

我正在使用 verilator 测试 SystemVerilog 代码,如下所示。

output [31:0] data_out1;
reg [31:0] data_out1;

always @(rst_b or addr1 or data_in1 or write_mask1)
  begin
    if((write_mask1 != 32'b0) && (rst_b == 1'b1))
      begin 
        data_out1 <= 32'hxxxxxxxx;

... do something ....
  
  end

always @(posedge clk)
  begin
    if((write_mask1 != 32'b0) && (rst_b == 1'b1))
      begin
        data_out1 <= 32'hxxxxxxxx;

... do something ..

  end

它有两个

always
块,并且在每个块中,
data_out1
以非阻塞方式分配。但是,它显示“对同一变量的阻塞和非阻塞赋值”错误。

我没有使用阻塞赋值,我无法理解为什么会出现这样的错误。如果有人可以提供帮助,我将不胜感激。

verilog system-verilog verilator
3个回答
0
投票

有两个问题:

帖子中的代码从两个always块分配相同的信号。这是不可能的,data_out1 必须由单个always 块驱动。

没有时钟的always块推断组合逻辑。组合逻辑建模的正确方法是使用阻塞赋值 (=)。


0
投票

当我在您的代码片段上运行 verilator 时,我收到如下消息:

%Warning-COMBDLY: Delayed assignments (<=) in non-clocked (non flop or latch) block; suggest blocking assignments (=).
%Warning-COMBDLY: *** See the manual before disabling this,
%Warning-COMBDLY: else you may end up with different sim results.
%Error-BLKANDNBLK: Unsupported: Blocked and non-blocking assignments to same variable: data_out1

第一条警告消息表明 verilator 将您的第一个

always
块解释为组合逻辑,而不是顺序逻辑,并且它将非阻塞赋值运算符 (
<=
) 视为阻塞赋值。

由于您的第一个块不使用

@(posedge clk)
,因此它被视为组合逻辑。

此外,您不应该对多个模块中的同一信号进行分配。

最后,您不应该使用非阻塞赋值来推断组合逻辑。


-1
投票

第二个始终块没问题(但不干净,因为 rst_b 并不单独处于第一个条件,它可能会导致某些模拟器出现问题),作为具有同步低电平有效复位的 FF 工作。问题是第一个总是块。

根据您在第一个块中使用

<=
进行的建模,如果
write_mask1
更改以触发敏感度列表,您需要根据
data_out1 的时间点 
write_mask1old
 值来分配 
write_mask1
 
已更新为新值。这种行为是推断锁存,因为它需要内存来保存事件发生之前的旧值,但它也不是 FF 的有效行为。看来 Verilator 仍然将这个推断的锁解释为“阻塞分配”。 (顺便说一句,锁存器本身不会导致错误,因为如果您有锁存器用于时钟门控等目的,那么它确实是一种正确的建模方法)

如果是SystemVerilog(而不是Verilog),我会尝试使用

always_comb
进行组合逻辑,使用
always_ff
进行顺序逻辑。 (以及
always_latch
表示闩锁)。就您而言,最简单的干净建模方法是了解哪个部分是组合的,哪个部分是顺序的。我将其建模为:

always_ff @(posedge clk)  // to add "or negedge rst_b" if you want async reset
  begin
    if(!rst_b)
      begin
        data_out1 <= 32'hxxxxxxxx;  // some reset value
      end
    else if(write_mask1 != 32'b0)
      begin
        data_out1 <= 32'hxxxxxxxx;  // the value you want to update
      end
    end
    // if there is no other condition, it will keep the old value based on the FF behavior

... do something ..

  end

如果你真的想要有 2 个块,一个进行组合,一个进行顺序,我们在这里:

always_comb begin
  if(write_mask1 != 32'b0) begin
    data_out1_next = 32'hxxxxxxxx;
  end
  else begin
    // now it's necessary to write else-clause because it's not a FF -- it has no memory
    data_out1_next = data_out1;
  end
end

always_ff @(posedge clk)  // to add "or negedge rst_b" if you want async reset
begin
  if(!rst_b) begin
    data_out1 <= 32'hxxxxxxxx;  // some reset value
  end
  else begin
    data_out1 <= data_out1_next;
  end
end
© www.soinside.com 2019 - 2024. All rights reserved.