• Could you explain the detail of this nonblocking?

    From Robert Willy@21:1/5 to All on Sun Sep 23 19:18:58 2018
    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,

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Gabor@21:1/5 to Robert Willy on Wed Sep 26 22:39:21 2018
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robert Willy@21:1/5 to Gabor on Sat Sep 29 13:29:31 2018
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)