Could you explain the detail of this nonblocking?

R

Robert Willy

Guest
Hello,
When I run the simulation of the below code, I am surprised after thinking
in more detail. nonblocking has two parts in operation: evaluation and
assignment. In this code snippet, delay 5 units is on the left assignment.
Although I looks like understanding it, I get puzzled after thinking it in
detail: Both C and D change to '02' after 5 delay units of C being '01':


Note: I use clock period=20 units
reg [2:0] C, D;

always @(posedge clk)
begin
#5 C <= 1;
#5 C <= 1+C;
D <= C + 1;
end


The even more puzzling thing is after I comment out the second '#5' line:

always @(posedge clk)
begin
#5 C <= 1;
D <= C + 1;
end

It is found D changes to '02' after 20 delay units of C being '01'!
That is, D changes to '02' after 5 delay units of the second clock rising
edge.
I don't find a useful explanation yet. Could you give me a short description
of the above two examples on the events to C and D?

Best Regards,
 
On Sunday, 9/23/2018 10:18 PM, Robert Willy wrote:
Hello,
When I run the simulation of the below code, I am surprised after thinking
in more detail. nonblocking has two parts in operation: evaluation and
assignment. In this code snippet, delay 5 units is on the left assignment.
Although I looks like understanding it, I get puzzled after thinking it in
detail: Both C and D change to '02' after 5 delay units of C being '01':


Note: I use clock period=20 units
reg [2:0] C, D;

always @(posedge clk)
begin
#5 C <= 1;
#5 C <= 1+C;
D <= C + 1;
end


The even more puzzling thing is after I comment out the second '#5' line:

always @(posedge clk)
begin
#5 C <= 1;
D <= C + 1;
end

It is found D changes to '02' after 20 delay units of C being '01'!
That is, D changes to '02' after 5 delay units of the second clock rising
edge.
I don't find a useful explanation yet. Could you give me a short description
of the above two examples on the events to C and D?

Best Regards,

It helps to understand how the simulator performs your code. It's a
bit unusual to use #delays before a non-blocking statement, but the
delay will affect the output as you noticed. A simulator runs each
always block as a sequential program. A #delay before a statement
creates a time delay before executing the statement. For a non-blocking
assignment, this means you wait 5 time units and then schedule the
assignment to take place when the sequence is complete. It's much more
common to code the #delay after the assignment operator like:
c <= #5 1;
This way the sequence flows without any time delay, but the scheduled
assignment happens 5 time units after the sequence completes. Looking
at your code:

always @(posedge clk)
begin
#5 C <= 1;
D <= C + 1;
end

at the first rising edge of clock, the simulator waits 5 time units
then schedules C to become 1 immediately following the execution of
the always block. Then it schedules D to become C + 1 (where C is
the value of C upon entering the block), again as soon as the block
completes. So if C were 0 initially, what you would see is that
5 time units after the first rising clock edge C would become 1
and D would also become 1 (0 + 1). On the next rising edge of
clock, C is already 1 so the scheduled assignment makes no changes.
However now the second assignment to D sees the value 1, and so
D becomes 2 (1 + 1). You'll see this 5 time units after the clock
edge because of the #5 in the first assignment.

Generally speaking, this code does not represent the behavior of
typical logic. The more typical approach is to use only delays
after the non-blocking assignment so the whole block completes in
0 time. Delays are scheduled rather than waited for sequentially.
In fact in your first code:

always @(posedge clk)
begin
#5 C <= 1;
#5 C <= 1+C;
D <= C + 1;
end

the two #5 delays are additive, so actions would occur 10 time
units after the clock edge. The code is interpreted as:

Wait for rising clock edge
wait for 5 time units
schedule C to become 1
wait 5 more time units
schedule C to become C + 1 (using value of C before the clock edge)
schedule D to become C + 1
Apply all scheduled assignments immediately

Note that the first assignment to C is overriden by the second
one. So if you started with C = 0, it would become 1 after the
first clock edge + 10 time units, then 2 after the next edge
plus 10 time units and so on. But if C started as unknown (X)
it would remain X forever.

--
Gabor
 
On Wednesday, September 26, 2018 at 9:39:28 PM UTC-5, Gabor wrote:
On Sunday, 9/23/2018 10:18 PM, Robert Willy wrote:
Hello,
When I run the simulation of the below code, I am surprised after thinking
in more detail. nonblocking has two parts in operation: evaluation and
assignment. In this code snippet, delay 5 units is on the left assignment.
Although I looks like understanding it, I get puzzled after thinking it in
detail: Both C and D change to '02' after 5 delay units of C being '01':


Note: I use clock period=20 units
reg [2:0] C, D;

always @(posedge clk)
begin
#5 C <= 1;
#5 C <= 1+C;
D <= C + 1;
end


The even more puzzling thing is after I comment out the second '#5' line:

always @(posedge clk)
begin
#5 C <= 1;
D <= C + 1;
end

It is found D changes to '02' after 20 delay units of C being '01'!
That is, D changes to '02' after 5 delay units of the second clock rising
edge.
I don't find a useful explanation yet. Could you give me a short description
of the above two examples on the events to C and D?

Best Regards,


It helps to understand how the simulator performs your code. It's a
bit unusual to use #delays before a non-blocking statement, but the
delay will affect the output as you noticed. A simulator runs each
always block as a sequential program. A #delay before a statement
creates a time delay before executing the statement. For a non-blocking
assignment, this means you wait 5 time units and then schedule the
assignment to take place when the sequence is complete. It's much more
common to code the #delay after the assignment operator like:
c <= #5 1;
This way the sequence flows without any time delay, but the scheduled
assignment happens 5 time units after the sequence completes. Looking
at your code:

always @(posedge clk)
begin
#5 C <= 1;
D <= C + 1;
end

at the first rising edge of clock, the simulator waits 5 time units
then schedules C to become 1 immediately following the execution of
the always block. Then it schedules D to become C + 1 (where C is
the value of C upon entering the block), again as soon as the block
completes. So if C were 0 initially, what you would see is that
5 time units after the first rising clock edge C would become 1
and D would also become 1 (0 + 1). On the next rising edge of
clock, C is already 1 so the scheduled assignment makes no changes.
However now the second assignment to D sees the value 1, and so
D becomes 2 (1 + 1). You'll see this 5 time units after the clock
edge because of the #5 in the first assignment.

Generally speaking, this code does not represent the behavior of
typical logic. The more typical approach is to use only delays
after the non-blocking assignment so the whole block completes in
0 time. Delays are scheduled rather than waited for sequentially.
In fact in your first code:

always @(posedge clk)
begin
#5 C <= 1;
#5 C <= 1+C;
D <= C + 1;
end

the two #5 delays are additive, so actions would occur 10 time
units after the clock edge. The code is interpreted as:

Wait for rising clock edge
wait for 5 time units
schedule C to become 1
wait 5 more time units
schedule C to become C + 1 (using value of C before the clock edge)
schedule D to become C + 1
Apply all scheduled assignments immediately

Note that the first assignment to C is overriden by the second
one. So if you started with C = 0, it would become 1 after the
first clock edge + 10 time units, then 2 after the next edge
plus 10 time units and so on. But if C started as unknown (X)
it would remain X forever.

--
Gabor

Thanks Gabor. The above code snippet is from a Verilog tutorial. I learn
from you and my simulation as well. It helps a lot.
 

Welcome to EDABoard.com

Sponsor

Back
Top