Say the following code section (same block):
A <= 1
A <= 2
Will variable A always be assigned 2? or will there be a race condition and 1 or 2 will be assigned ?
My understanding of non blocking assignment is that it is up to the hardware to assign the variable A at a future time so it could be a random result. However, this is non intuitive. Simulations show that 2 always get assigned, but I would like to know if this is definitely the case for hardware synthesis.
A would be 2 in simulation, the last defined value takes effect. If they are not in the same block then there could be a race condition depending on the simulator scheduler as to which was defined last in simulation.
I have seen this technique used quite a lot and never seen any unexpected results after synthesis, but as others have mentioned this is not guaranteed or covered by the verilog spec.
Usage of this might be a FSM which sparsely defines its outputs:
always @(posedge clk) begin
out_one <= 1'b0;
out_two <= 1'b0;
out_thr <= 1'b0;
case (state)
2'd1 : out_one <= 1'b1;
2'd2 : out_two <= 1'b1;
2'd3 : out_thr <= 1'b1;
endcase
end
There is nothing nondeterministic about the final value of A
in your code, not for simulation, not for synthesis.
However, to be absolutely exact, there is a possible simulation-synthesis-mismatch if the design contains a trigger on A
. Consider the following example:
module test(input clk, output reg a, b);
always @(posedge clk) begin
a <= 0;
a <= 1;
end
initial b = 0;
always @(posedge a) begin
b <= !b;
end
endmodule
And a test bench:
module tb;
reg clk = 0;
always #5 clk = ~clk;
wire a, b;
test uut (clk, a, b);
initial begin
$monitor("clk=%b a=%b b=%b", clk, a, b);
repeat (100) @(posedge clk);
$finish;
end
endmodule
During simulation both updates a <= 0
and a <= 1
are pushed to the NBA events region and are executed in-order, so a
always ends up being set. However, as the a <= 0
is executed as well, there is a negative pulse with zero width on a
for every clock cycle. This pulse triggers the 2nd always block. This is the simulation output (tested with Icarus Verilog and Modelsim):
clk=0 a=x b=0
clk=1 a=1 b=1
clk=0 a=1 b=1
clk=1 a=1 b=0
clk=0 a=1 b=0
clk=1 a=1 b=1
clk=0 a=1 b=1
clk=1 a=1 b=0
clk=0 a=1 b=0
clk=1 a=1 b=1
clk=0 a=1 b=1
clk=1 a=1 b=0
clk=0 a=1 b=0
...
However, in synthesis this will simply assign a
the constant value 1 and b
the constant value zero. (Tested with Yosys and Xilinx Vivado.) So the post-synthesis simulation output looks like this:
clk=0 a=1 b=0
clk=1 a=1 b=0
clk=0 a=1 b=0
clk=1 a=1 b=0
clk=0 a=1 b=0
clk=1 a=1 b=0
clk=0 a=1 b=0
clk=1 a=1 b=0
clk=0 a=1 b=0
clk=1 a=1 b=0
clk=0 a=1 b=0
clk=1 a=1 b=0
clk=0 a=1 b=0
clk=1 a=1 b=0
(Theoretically the first line could still say a=x
, but every decent synthesis tool would optimize the a
-flip-flop away, as both tools in the test did.)
Other than that there is no potential issue with that code, and as @Morgan pointed out correctly in his answer, this is a very usual coding technique for defining the "default values" of output signals before encoding the special cases using conditional assignments (using if
and/or case
).
According to the "Determinism" section in the IEEE Std (1800-2009, for example), if those statements are in a begin-end block, A will always be assigned the value 2 in simulation.
However, the Std does not guarantee how the code will be synthesized. The resultig gates probably depend on the synthesis tool. But, a good RTL linting tool will identify such bad coding. Cadence's Hal lint tool issues a warning.
from RTL point of view.
"A" will be assigned 1 and 2 ,it can be first 1 and then 2 or vice versa, but you can't really know which value will be assigned in the end of begin-end block it can be 1 or 2 (as the second value which was assigned).