Reputation: 11
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
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
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
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