Verilog simulation consists of micro-steps (or delta cycles), related to the events. Event is actually any change of a value of a variable which causes re-evaluation of other blocks. So, the delta cycle is a step which requires for the model to get quiescent.
The delta cycle itself consists of multiple scheduling buckets, executed one after another in the cycle. In the very simplified view there are at least a blocking bucket and non-blocking bucket. All blocking assignment are evaluated in the first bucket, all non-blocking - in the second.
So, in your case
always @(posedge clk)
begin
b = a;
c = b;
end
b
gets evaluated in the first bucket and c
is too, so it becomes the value of a
. So, a
was 1 then value of b
will be 1, and the value c
will also become '1' in the first bucket.
it you use non-blocking assignments, verilog will run in the first bucket but it will just schedules execution of the non-blocking assignments to be performed in the second bucket. So, in this code
always @(posedge clk)
begin
b <= a;
c <= b;
end
b
will be scheduled to get value of a
int he second bucket, c
will be scheduled to become value of b
in the second bucket. But the latter schedules an assignment of the current value of b
, not the one which will be evaluated in the second bucket.
So, in above case the value of a
was 1 and the value of b
was 0, c
will become 0 in the second bucket.
Of course, if c
causes more first-bucket types of events, verilog will return to the first bucket and evaluate all events again. In reality there are more than 2 buckets in verilog and even more in system verilog.
There are certain reasoning for using blocking and non-blocking assignments and why they exist in verilog. But for simplicity you should follow a simple methodology: all outputs of state elements, like flops and latches must be assigned using non-blocking assignments, all combinatorial logic and clocks should use blocking assignments. This would save you from tidious debugging of races and glitch effects. So, in your case, assuming that b
is just an intermidiate node in your flop, the following code should be used:
always @(posedge clk)
begin
b = a;
c <= b;
end
In this case, b
will become value of a
immediately int he first bucket, but the output of this flop c
will be assigned using the non-blocking assignment according to the industry-wide methodology,