yongarius
yongarius

Reputation: 11

Blocked and non-blocking assignment error in verilator

I'm testing SystemVerilog code using verilator, and it looks like below.

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

It has two always blocks, and in each block, data_out1 is assigned in non-blocking. But, it shows a "Blocked and non-blocking assignments to same variable" error.

I do not use blocking assignment, and I can't understand why such an error occurs. I would appreciate if anyone can help.

Upvotes: 1

Views: 904

Answers (3)

toolic
toolic

Reputation: 61937

When I run verilator on your code snippet, I get messages like the following:

%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

The 1st warning message indicates that verilator interprets your 1st always block as combinational logic, not sequential logic, and it treats the nonblocking assignment operator (<=) as a blocking assignment.

Since your 1st block does not use @(posedge clk), it is treated as combinational logic.

Also, you should not make assignments to the same signal from multiple blocks.

Lastly, you should not use nonblocking assignments to infer combinational logic.

Upvotes: 0

Min-An Chao
Min-An Chao

Reputation: 1

The 2nd always block is ok (but not clean, because the rst_b is not at the first condition alone, it might cause problem for some simulator), working as a FF with sync low-active reset. The problem is the 1st always block.

Based on your modeling with <= in the 1st block, if write_mask1 changes to trigger the sensitivity list, you want to assign data_out1 depending on the old value of write_mask1 at the time point that write_mask1 has been updated with the new value. This behavior is inferred latch, because it needs the memory to hold the old value before the event, but it is also not a valid behavior of a FF. It seems that Verilator interprets this inferred latch still as "blocking assignment". (By the way, latch itself won't cause error, because it is indeed a right way to model if you have latches for purposes like clock gating)

If it is SystemVerilog (instead of Verilog), i would try to use always_comb for combinational logic, and always_ff for sequential. (and always_latch for latch). In your case, the simplest clean way to model is to be aware of which part is combitional and which sequential. I'd model it as:

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

If you really mean to have 2 blocks, one doing combinational, one sequential, here we are:

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

Upvotes: -1

Mikef
Mikef

Reputation: 2508

There are two issues:

The code in the post is assigning the same signal from two always blocks. This can't be done, data_out1 must be driven from a single always block.

The always block without the clock infers combinational logic. The correct way to model combinational logic is by using blocking assignments (=).

Upvotes: 0

Related Questions