Menu

#981 VCD waveform problem with v 0.9.6

devel
closed-invalid
nobody
None
5
2015-06-09
2015-06-06
No

Running Icarus Verilog version 0.9.6 on Linux. I have a test case with 2 Verilog modules - 'tb.v' and 'delay.v' and this test case is producing incorrect VCD waveforms. See comment on lines 22 and 23 on source file 'tb.v'. Execute only one of these lines in 'tb.v' and inspect VCD waves ( I am using GTKwave) on signal 'y1'. The #10 delay in line 22 of 'tb.v', seems to break the waveform for signal 'y1'. #15 or larger delay values produce correct waveforms (or meets my expectation of a correct waveform).

1 Attachments

Related

Bugs: #981

Discussion

  • Martin Whitaker

    Martin Whitaker - 2015-06-08

    The problem is a race in your code. Simplifying it, you have

    always @(in) begin
      y1 <= #15 in;         
      #10 y2 <= in;         
    end
    
    initial begin
      in = 0;
      #10 in = 1;
    end
    

    The initial block sets in=0, goes to sleep for 10 time units, then sets in=1. The always block is triggered by in=0, schedules the assignment to y1, goes to sleep for 10 time units, schedules the assignment to y2, then goes back to waiting for a trigger.

    At time 10, the simulator has a choice of which action it executes first. Icarus chooses the in=1 action, thus that event occurs before the always block is waiting for it.

    There's another potential race in this code, and you should really write

    #0 in = 0;
    

    to ensure the always block is waiting for an event before the first trigger occurs.

     
  • Martin Whitaker

    Martin Whitaker - 2015-06-08
    • status: open --> closed-invalid
     
    • Dave Williams

      Dave Williams - 2015-06-08

      Martin

      Sorry, but I'm not understanding your explanation.

      The problem is with operation on y1. I see no problem with y2 - it
      operates as expected. It is true that there are simultaneous
      events at time unit 10 - and this could possibly affect the y2 output - but
      I'm wondering why does this affect y1? If I delay the high assertion
      of 'in' to 15 time units - both y1 and y2 look correct.

      The following is my understanding of how 'y1' should function (and I see
      found no difference using "#0 in = 0")

      1) At time unit 0, 'in' is assigned a value of 0. This is verified
      correct on the waveform.

      2) This triggers the always block. The new value of 'in' is sampled at
      the current time unit (0) and after 15 time units
      y1 is updated to the sampled value of 'in' (or the 0 value). This is
      verified correct on the waveform. I can see that 'y1' transitions from
      'x' to a 0. So, I don't see any issues around the 0 time value - as you
      mention. I believe you were implying that by adding
      the #0 in = 0 statement this would enforce a fixed sequence of execution?
      Perhaps, but I don't see a problem here with 'y1'.

      2) At time unit 10, 'in' is assigned a value of 1. This is verified
      correct on the waveform.

      2) This triggers the always block. My expectation is the new value of
      'in' is sampled and found to be 1, at the current time unit (i.e. 10).
      And after 15 time units, y1 is driven to the sampled value of 'in' (or the
      1 value). This would agree with your statement that Icarus
      chooses the in=1 action before execution of the always block. This doesn't
      look to be the situation when viewed in the waveform - y1 is still at the 0
      value.
      It appears that the old value of 'in' (0) is being used and has not been
      updated to a 1 value. I would assume the always block was triggered, but
      was the old
      value of 'in' was used? And later in the simulation, the operation of 'y1'
      looks correct.

      Thank you for your detailed response.

      Dave

      On Mon, Jun 8, 2015 at 2:11 AM, Martin Whitaker <martinwhitaker@users.sf.net

      wrote:

      • status: open --> closed-invalid
      • Comment:

      The problem is a race in your code. Simplifying it, you have

      always @(in) begin
      y1 <= #15 in;
      #10 y2 <= in;
      end

      initial begin
      in = 0;
      #10 in = 1;
      end

      The initial block sets in=0, goes to sleep for 10 time units, then sets
      in=1. The always block is triggered by in=0, schedules the assignment to
      y1, goes to sleep for 10 time units, schedules the assignment to y2, then
      goes back to waiting for a trigger.

      At time 10, the simulator has a choice of which action it executes first.
      Icarus chooses the in=1 action, thus that event occurs before the always
      block is waiting for it.

      There's another potential race in this code, and you should really write

      0 in = 0;

      to ensure the always block is waiting for an event before the first
      trigger occurs.


      Status: closed-invalid

      Group: devel
      Created: Sat Jun 06, 2015 04:38 AM UTC by Dave Williams
      Last Updated: Sat Jun 06, 2015 04:38 AM UTC
      Owner: nobody

      Running Icarus Verilog version 0.9.6 on Linux. I have a test case with 2
      Verilog modules - 'tb.v' and 'delay.v' and this test case is producing
      incorrect VCD waveforms. See comment on lines 22 and 23 on source file
      'tb.v'. Execute only one of these lines in 'tb.v' and inspect VCD waves ( I
      am using GTKwave) on signal 'y1'. The #10 delay in line 22 of 'tb.v', seems
      to break the waveform for signal 'y1'. #15 or larger delay values produce
      correct waveforms (or meets my expectation of a correct waveform).


      Sent from sourceforge.net because you indicated interest in
      https://sourceforge.net/p/iverilog/bugs/981/

      To unsubscribe from further messages, please visit
      https://sourceforge.net/auth/subscriptions/

       

      Related

      Bugs: #981

  • Martin Whitaker

    Martin Whitaker - 2015-06-08

    Ignore the #0 for the moment - that's a separate issue. Perhaps it will be clearer if you consider the alternative (but functionally equivalent) way of writing your 'always' block

    initial
      forever begin
        @(in);  // wait for in to change
        y1 <= #15 in;
        #10;    // wait for 10ns
        y2 <= in;
      end
    

    So if 'in' changes at time 0, the assignment to 'y1' is executed at time 0 (with the write delayed to time 15) and the assignment to 'y2' is executed at time 10 (with the write delayed to the end of time 10). But your next assignment to 'in' is also executed at time 10. The simulator is single-threaded, and has a choice of which statement to execute first. If it chooses to execute the assignment to 'in' first (as Icarus is doing), the other block won't have got back to the '@(in)' statement, so will miss the change.

    The IEEE standard allows a simulator to choose either order, so you might find your example worked in another simulator.

    You could fix your code for this particular case by changing the assignments to 'in' to be non-blocking. But if the time between changes to 'in' is less than 10ns, it will still break.

    Back to the #0. There's a similar problem at time 0, because there is no required order for 'initial' and 'always' statements to be executed at time 0. So if a simulator chose to execute your 'initial' block first, the 'always' block would miss the first change to in. In fact Icarus protects you from this by giving priority to 'always' blocks. Other simulators don't necessarily do this, so it's good practice to add the #0 to guarantee execution order.

     
    • Dave Williams

      Dave Williams - 2015-06-08

      Martin

      See my comments below.

      Thanks,

      Dave

      On Mon, Jun 8, 2015 at 12:52 PM, Martin Whitaker martinwhitaker@users.sf.net wrote:

      Ignore the #0 for the moment - that's a separate issue. Perhaps it will be
      clearer if you consider the alternative (but functionally equivalent) way
      of writing your 'always' block

      initial
      forever begin
      @(in); // wait for in to change
      y1 <= #15 in;
      #10; // wait for 10ns
      y2 <= in;
      end

      So if 'in' changes at time 0, the assignment to 'y1' is executed at time 0
      (with the write delayed to time 15) and the assignment to 'y2' is executed
      at time 10 (with the write delayed to the end of time 10).

      Not sure our understanding of how delays work when they are on the RHS
      (right hand side) of a NBA (non blocking assignment) are in agreement.
      There is a significant difference.

      But your next assignment to 'in' is also executed at time 10. The
      simulator is single-threaded, and has a choice of which statement to
      execute first.

      Please see page 5 and particularly the top of page 6 of the attachment.
      Yes it is true that Active Events (1-3) happen in any order, but they can
      trigger Active Events (4-6) which are scheduled in any order and ultimately
      this can create updates to NBA's. I think that is the crux of the problem
      we are discussing. That updates can trigger other updates in the same time
      step. Cliff Cummings says this on the bottom of page 5. The blocking
      assignment that sets the value of 'in' at time unit 10 is not being updated
      in the RHS of the NBA for 'y1'. And I believe it should be updated based
      on my understanding of this paper and the author's presentation of the
      Verilog spec. In fact, my code sample is lifted from this paper - with
      some minor timing changes.

      I have a lot of respect for the Verilog guys at Sunburst Design - I was
      lucky enough to attend one of their 3 day training sessions around 2002.
      And as someone who has used Icarus Verilog for over 10 years and has a few
      shipping commercial designs using Icarus Verilog - I have a lot of respect
      for you guys at Icarus also.

      If it chooses to execute the assignment to 'in' first (as Icarus is
      doing), the other block won't have got back to the '@(in)' statement, so
      will miss the change.

      The IEEE standard allows a simulator to choose either order,

      I don't entirely agree with this statement - refer to Figure 5 on page 6.
      Can you point me to where you find this topic in the IEEE standard?

      so you might find your example worked in another simulator.

      If you remove the 'y2' signal from the test case - the 'y1' operation is
      correct. If you add back 'y2' - operation on 'y1' is different. And that
      is what I consider the bug. Icarus doesn't handle these simultaneous
      events consistently.

      You could fix your code for this particular case by changing the
      assignments to 'in' to be non-blocking. But if the time between changes to
      'in' is less than 10ns, it will still break.

      Back to the #0. There's a similar problem at time 0, because there is no
      required order for 'initial' and 'always' statements to be executed at time
      0. So if a simulator chose to execute your 'initial' block first, the
      'always' block would miss the first change to in. In fact Icarus protects
      you from this by giving priority to 'always' blocks. Other simulators don't
      necessarily do this, so it's good practice to add the #0 to guarantee
      execution order.

      See attachment for recommendations on using #0 delays.


      Status: closed-invalid
      Group: devel
      Created: Sat Jun 06, 2015 04:38 AM UTC by Dave Williams
      Last Updated: Mon Jun 08, 2015 08:11 AM UTC
      Owner: nobody

      Running Icarus Verilog version 0.9.6 on Linux. I have a test case with 2
      Verilog modules - 'tb.v' and 'delay.v' and this test case is producing
      incorrect VCD waveforms. See comment on lines 22 and 23 on source file
      'tb.v'. Execute only one of these lines in 'tb.v' and inspect VCD waves ( I
      am using GTKwave) on signal 'y1'. The #10 delay in line 22 of 'tb.v', seems
      to break the waveform for signal 'y1'. #15 or larger delay values produce
      correct waveforms (or meets my expectation of a correct waveform).


      Sent from sourceforge.net because you indicated interest in
      https://sourceforge.net/p/iverilog/bugs/981/

      To unsubscribe from further messages, please visit
      https://sourceforge.net/auth/subscriptions/

       

      Related

      Bugs: #981

  • Martin Whitaker

    Martin Whitaker - 2015-06-08

    I'm not sure how to explain this more clearly. Taking my simplified example

    always @(in) begin
      y1 <= #15 in;         
      #10 y2 <= in;         
    end
    
    initial begin
      in = 0;
      #10 in = 1;
    end
    

    the sequence of steps Icarus performs is

    time 0:
    thread 1 : wait for in
    thread 2 : assign in=0
    update in=0
    thread 2 : suspend until time 10
    thread 1 : evaluate RHS of y1 assignment, schedule y1=0 @ time 15
    thread 1 : suspend until time 10

    time 10:
    thread 2 : assign in=1
    update in=1
    thread 2 : finished
    thread 1 : evaluate RHS of y2 assignment, schedule y2=1 @ end of time 10
    thread 1 : wait for in
    update y2=1

    time 15:
    update y1=0

    (where thread 1 is the always block, thread 2 is the initial block).

    Thread 1 doesn't get triggered again because 'in' was updated before it started waiting on it.

    What part of this sequence do you think violates the standard?

    P.S. Please can you trim off any unnecessary text in your replies - it makes the bug discussion on SourceForge hard to read.

     
  • Cary R.

    Cary R. - 2015-06-09

    Since most Verilog simulators are single threaded only one block is usually execute at a time. Note that SystemVerilog allows some of these race conditions at time zero to be fixed by defining the order that certain blocks are executed, but Icarus does not currently have this implemented.

    Here is my interpretation of the races in this example code:

    There is a time zero race between the initial block executing the in = 0; and the sensitizing of the always block to "in" changing. If the initial block runs first then "in" is assigned a value of zero and then it waits at the #10 statement. The always would run next and would wait at the @(in) statement for "in" to change to one at time 10.

    If they are run in the opposite order then the always would be run and the @(in) would be waiting when the initial block ran the in = 0; so that would trigger the body of the always to run. This order creates the second race case. y1 would get assign the current value of "in" at time 15, but at time 10 you again have a choice of which statement runs first. Is it the assignment to "in" of one in the initial block or the non-blocking assignment of y2 to "in"?

    Again depending on the order you will get different results. If the initial block assignment runs first then the value of "in" will be updated and then the non-blocking assignment will run using the new value of "in" (one). since we were not waiting at the @(in) statement the always block will only be run once. If the always block run first then the non-blocking assignment will trigger assigning the original value of "in" to y2 (zero) and it will then start waiting at the @(in) statement. Now when the initial block runs the assignment the always block will be executed a second time.

    As a note: normally blocking delays should not be used in an always block because the @() will not respond while waiting for the blocking delay to finish. This is a great source of confusion for most people. Also, to avoid missing changes at time zero because an @() statement may not be activated initial values should be delayed using a blocking or non blocking delay. Even a #0 delay like Martin suggested is enough.

    Note that I only looked at the reduced code not the original code. This reduced/example code certainly does have timing races and can generate unexpected result that may not match your thinking. I will also note that the order a block is executed can even change from activation to activation (e.g. two always block may run in a different order even when they both depend on the same activation signal).

     
    • Dave Williams

      Dave Williams - 2015-06-09

      I see this whole discussion bouncing back and forth between what is
      currently implemented in Icarus and what is the correct operation of a
      Verilog simulator.
      I believe the correct operation was outlined in Figure 5 on page 6 of the
      paper I sent to Martin earlier today.

      I'd like to focus on what is correct operation - I am not considering
      threads or how Icarus is currently implemented. Call this the ideal case.

      There are 2 blocks - the initial block and the always block. The initial
      blocks assigns values to 'in' at different times - that is all it does.
      When a simulator assigns a new value to 'in' during
      the time between a time step - doesn't matter. The always block ONLY
      executes its 2 statements ONLY IF there is a change on 'in'. That is how I
      consider an always block 'should' work. Therefore, I don't understand how
      the always block can execute the 2 statements (y1 <= #15 in, etc) before
      the initial block assigns a new value to 'in' (or before the initial block
      creates a change to a value in the sensitivity list of an always block).
      If we only consider these 2 blocks - the execution order should be fixed by
      the Verilog code. And I don't understand how the order of execution of the
      initial and always blocks can be random - for this ideal case. Of course,
      the executing code in Icarus could skip executing the statements in the
      always block, if it has determined there has been no change on 'in' and
      then later, during the same time step - 'in' gets updated. I can
      understand how this could happen, BUT, I would not call this correct
      operation.

      Can we agree that this is the ideal case? This is how things should work -
      there would be no 'race' conditions?

      Dave

      On Mon, Jun 8, 2015 at 6:49 PM, Cary R. caryr@users.sf.net wrote:

      Since most Verilog simulators are single threaded only one block is
      usually execute at a time. Note that SystemVerilog allows some of these
      race conditions at time zero to be fixed by defining the order that certain
      blocks are executed, but Icarus does not currently have this implemented.

      Here is my interpretation of the races in this example code:

      There is a time zero race between the initial block executing the in = 0;
      and the sensitizing of the always block to "in" changing. If the initial
      block runs first then "in" is assigned a value of zero and then it waits at
      the #10 statement. The always would run next and would wait at the @(in)
      statement for "in" to change to one at time 10.

      If they are run in the opposite order then the always would be run and the
      @(in) would be waiting when the initial block ran the in = 0; so that would
      trigger the body of the always to run. This order creates the second race
      case. y1 would get assign the current value of "in" at time 15, but at time
      10 you again have a choice of which statement runs first. Is it the
      assignment to "in" of one in the initial block or the non-blocking
      assignment of y2 to "in"?

      Again depending on the order you will get different results. If the
      initial block assignment runs first then the value of "in" will be updated
      and then the non-blocking assignment will run using the new value of "in"
      (one). since we were not waiting at the @(in) statement the always block
      will only be run once. If the always block run first then the non-blocking
      assignment will trigger assigning the original value of "in" to y2 (zero)
      and it will then start waiting at the @(in) statement. Now when the initial
      block runs the assignment the always block will be executed a second time.

      As a note: normally blocking delays should not be used in an always block
      because the @() will not respond while waiting for the blocking delay to
      finish. This is a great source of confusion for most people. Also, to avoid
      missing changes at time zero because an @() statement may not be activated
      initial values should be delayed using a blocking or non blocking delay.
      Even a #0 delay like Martin suggested is enough.

      Note that I only looked at the reduced code not the original code. This
      reduced/example code certainly does have timing races and can generate
      unexpected result that may not match your thinking. I will also note that
      the order a block is executed can even change from activation to activation
      (e.g. two always block may run in a different order even when they both
      depend on the same activation signal).


      Status: closed-invalid
      Group: devel
      Created: Sat Jun 06, 2015 04:38 AM UTC by Dave Williams
      Last Updated: Mon Jun 08, 2015 09:41 PM UTC
      Owner: nobody

      Running Icarus Verilog version 0.9.6 on Linux. I have a test case with 2
      Verilog modules - 'tb.v' and 'delay.v' and this test case is producing
      incorrect VCD waveforms. See comment on lines 22 and 23 on source file
      'tb.v'. Execute only one of these lines in 'tb.v' and inspect VCD waves ( I
      am using GTKwave) on signal 'y1'. The #10 delay in line 22 of 'tb.v', seems
      to break the waveform for signal 'y1'. #15 or larger delay values produce
      correct waveforms (or meets my expectation of a correct waveform).


      Sent from sourceforge.net because you indicated interest in
      https://sourceforge.net/p/iverilog/bugs/981/

      To unsubscribe from further messages, please visit
      https://sourceforge.net/auth/subscriptions/

       

      Related

      Bugs: #981

  • Cary R.

    Cary R. - 2015-06-09

    I don't see the attachment you are referring to. Giving the name of the paper may be enough. The only attachment I see is the original test code. The point Martin and I are both trying to make is that Icarus is working correctly. I was describing what the standard allows. My only comment regarding the new SystemVerilog functionality was to note that it was not currently implemented.

    I believe I understand what you are missing so maybe this will help.

    We are looking at two control constructs: always and initial. The always construct will execute its statement continually which is why you need to have something that blocks time in the statement it executes to prevent an infinite loop. The @(in) is the statement that is being executed by the always construct. An initial construct only executes its statement once and then terminates. The standard does not define the order the constructs should execute so the always constructs do not have to execute before the initial constructs.

    From 1364-2005:

    The initial and always constructs are enabled at the beginning of a simulation. The initial construct shall execute only once, and its activity shall cease when the statement has finished. In contrast, the always construct shall execute repeatedly. Its activity shall cease only when the simulation is terminated. There shall be no implied order of execution between initial and always constructs.

    This is what gives the race between the initial construct executing the first statement in the block attached to it, in = 0; and the always construct executing its only statement @(in) which then wait for a change in the "in" signal before running the statement attached to it. Depending on which executes first you will get different results (i.e. the @(in) statement will run its statement at time zero if the always construct runs first, otherwise it will not run until time 10).

     
    • Dave Williams

      Dave Williams - 2015-06-09

      Title is "Verilog Nonblocking Assignments with Delays, Myths & Mysteries"
      Clifford Cummings, Sunburst Design, SNUG Boston 2002.
      See pages 5 and 6.

      On Mon, Jun 8, 2015 at 9:59 PM, Cary R. caryr@users.sf.net wrote:

      I don't see the attachment you are referring to. Giving the name of the
      paper may be enough. The only attachment I see is the original test code.
      The point Martin and I are both trying to make is that Icarus is working
      correctly. I was describing what the standard allows. My only comment
      regarding the new SystemVerilog functionality was to note that it was not
      currently implemented.

      I believe I understand what you are missing so maybe this will help.

      We are looking at two control constructs: always and initial. The always
      construct will execute its statement continually which is why you need to
      have something that blocks time in the statement it executes to prevent an
      infinite loop. The @(in) is the statement that is being executed by the
      always construct. An initial construct only executes its statement once and
      then terminates. The standard does not define the order the constructs
      should execute so the always constructs do not have to execute before the
      initial constructs.

      From 1364-2005:

      The initial and always constructs are enabled at the beginning of a
      simulation. The initial construct shall execute only once, and its activity
      shall cease when the statement has finished. In contrast, the always
      construct shall execute repeatedly. Its activity shall cease only when the
      simulation is terminated. There shall be no implied order of execution
      between initial and always constructs.

      This is what gives the race between the initial construct executing the
      first statement in the block attached to it, in = 0; and the always
      construct executing its only statement @(in) which then wait for a change
      in the "in" signal before running the statement attached to it. Depending
      on which executes first you will get different results (i.e. the @(in)
      statement will run its statement at time zero if the always construct runs
      first, otherwise it will not run until time 10).


      Status: closed-invalid
      Group: devel
      Created: Sat Jun 06, 2015 04:38 AM UTC by Dave Williams
      Last Updated: Tue Jun 09, 2015 12:49 AM UTC
      Owner: nobody

      Running Icarus Verilog version 0.9.6 on Linux. I have a test case with 2
      Verilog modules - 'tb.v' and 'delay.v' and this test case is producing
      incorrect VCD waveforms. See comment on lines 22 and 23 on source file
      'tb.v'. Execute only one of these lines in 'tb.v' and inspect VCD waves ( I
      am using GTKwave) on signal 'y1'. The #10 delay in line 22 of 'tb.v', seems
      to break the waveform for signal 'y1'. #15 or larger delay values produce
      correct waveforms (or meets my expectation of a correct waveform).


      Sent from sourceforge.net because you indicated interest in
      https://sourceforge.net/p/iverilog/bugs/981/

      To unsubscribe from further messages, please visit
      https://sourceforge.net/auth/subscriptions/

       

      Related

      Bugs: #981

  • Cary R.

    Cary R. - 2015-06-09

    I looked at pages 5 and 6 of the paper. They just describe the stratified event queue that Verilog uses (specified in Chapter 11 of 1364-2005). I do not see an example or how anything Martin and I have written is inconsistent with what the standard or this paper specifies regarding the event queue. So using the simple example Martin gave, how exactly do you see a hypothetical reference simulator executing the statements? Answering that should help us resolve this issue.

     
    • Dave Williams

      Dave Williams - 2015-06-09

      On Tue, Jun 9, 2015 at 12:58 AM, Cary R. caryr@users.sf.net wrote:

      I looked at pages 5 and 6 of the paper. They just describe the stratified
      event queue that Verilog uses (specified in Chapter 11 of 1364-2005). I do
      not see an example or how anything Martin and I have written is
      inconsistent with what the standard or this paper specifies regarding the
      event queue. So using the simple example Martin gave, how exactly do you
      see a hypothetical reference simulator executing the statements?

      First there have been quite a few recent posts - I'm trying to catch up.

      Anyway, at the top of page 6, there is this wording "This blocking
      assignment or this continuous assignment can trigger additional events in
      the same time step". When the initial block executes the blocking
      statement (#10 in = 1;) - anytime during the 10 time step - why wouldn't
      this trigger the always block to be executed?

      Answering that should help us resolve this issue.

      Status: closed-invalid
      Group: devel
      Created: Sat Jun 06, 2015 04:38 AM UTC by Dave Williams
      Last Updated: Tue Jun 09, 2015 03:59 AM UTC
      Owner: nobody

      Running Icarus Verilog version 0.9.6 on Linux. I have a test case with 2
      Verilog modules - 'tb.v' and 'delay.v' and this test case is producing
      incorrect VCD waveforms. See comment on lines 22 and 23 on source file
      'tb.v'. Execute only one of these lines in 'tb.v' and inspect VCD waves ( I
      am using GTKwave) on signal 'y1'. The #10 delay in line 22 of 'tb.v', seems
      to break the waveform for signal 'y1'. #15 or larger delay values produce
      correct waveforms (or meets my expectation of a correct waveform).


      Sent from sourceforge.net because you indicated interest in
      https://sourceforge.net/p/iverilog/bugs/981/

      To unsubscribe from further messages, please visit
      https://sourceforge.net/auth/subscriptions/

       

      Related

      Bugs: #981

      • Cary R.

        Cary R. - 2015-06-09

        "why wouldn't this trigger the always block to be executed?" Read my follow up post for the answer to that question. I believe you have a common misunderstanding regarding how "always @(in) ..." works.

         
        • Dave Williams

          Dave Williams - 2015-06-09

          Cary, yes, there could be a miss understanding on the operation of an
          always @(..) block.

          Here is a cut from Doulos (www.doulos.com) and my understanding agrees with
          their explanation below.


          always @(sensitivity-list)
          begin
          // statements
          end

          The sensitivity list consists of one or more signals. When at least one of
          these signals changes, the always block executes through to the end keyword
          as before. Except that now, the sensitivity list prevents the always
          block from executing again until another change occurs on a signal in the
          sensitivity list.


          Based on this explanation - I'm struggling to understand how the always
          @(in) executes before a change on 'in'.

          On Tue, Jun 9, 2015 at 12:02 PM, Cary R. caryr@users.sf.net wrote:

          "why wouldn't this trigger the always block to be executed?" Read my
          follow up post for the answer to that question. I believe you have a common
          misunderstanding regarding how "always @(in) ..." works.


          Status: closed-invalid
          Group: devel
          Created: Sat Jun 06, 2015 04:38 AM UTC by Dave Williams
          Last Updated: Tue Jun 09, 2015 07:51 AM UTC
          Owner: nobody

          Running Icarus Verilog version 0.9.6 on Linux. I have a test case with 2
          Verilog modules - 'tb.v' and 'delay.v' and this test case is producing
          incorrect VCD waveforms. See comment on lines 22 and 23 on source file
          'tb.v'. Execute only one of these lines in 'tb.v' and inspect VCD waves ( I
          am using GTKwave) on signal 'y1'. The #10 delay in line 22 of 'tb.v', seems
          to break the waveform for signal 'y1'. #15 or larger delay values produce
          correct waveforms (or meets my expectation of a correct waveform).


          Sent from sourceforge.net because you indicated interest in
          https://sourceforge.net/p/iverilog/bugs/981/

          To unsubscribe from further messages, please visit
          https://sourceforge.net/auth/subscriptions/

           

          Related

          Bugs: #981

          • Martin Whitaker

            Martin Whitaker - 2015-06-09

            Dave, please take the time to study and understand the example in my last comment. That is the key to understanding what is wrong with your code. Hint - if you haven't reached the end of the always block before the next trigger event occurs, you will miss that trigger event and have to wait for the next one.

             
            • Dave Williams

              Dave Williams - 2015-06-10

              OK, you and Cary are saying that the always block may or may not complete
              execution by the time the 'in' signal is being updated. Is that correct?
              But what I have been saying is you should only execute the always block if
              and only if the 'in' signal has changed value. Therefore, the execution
              sequence is
              guaranteed to be correct. Why do I say this? Because the initial block
              establishes new values for 'in' and this results in triggering the always
              @(in) block to execute.

              But, in a previous post, Cary indicated that I may not have a complete
              understanding the operation of the always @(,,) statement, so I posted what
              I consider
              a common explanation of the always @(,,,) construct and now Cary is saying
              that is not entirely correct? (I did see Cary's post of the difference
              between "always' and
              "always @(,,)"

              Is the always block waiting 10 time steps to complete in your
              implementation in Icarus? And during this time, another thread could be
              changing the value of 'in'?

              On Tue, Jun 9, 2015 at 3:58 PM, Martin Whitaker <martinwhitaker@users.sf.net

              wrote:

              Dave, please take the time to study and understand the example in my last
              comment. That is the key to understanding what is wrong with your code.
              Hint - if you haven't reached the end of the always block before the next
              trigger event occurs, you will miss that trigger event and have to wait for
              the next one.


              Status: closed-invalid
              Group: devel
              Created: Sat Jun 06, 2015 04:38 AM UTC by Dave Williams
              Last Updated: Tue Jun 09, 2015 07:51 AM UTC
              Owner: nobody

              Running Icarus Verilog version 0.9.6 on Linux. I have a test case with 2
              Verilog modules - 'tb.v' and 'delay.v' and this test case is producing
              incorrect VCD waveforms. See comment on lines 22 and 23 on source file
              'tb.v'. Execute only one of these lines in 'tb.v' and inspect VCD waves ( I
              am using GTKwave) on signal 'y1'. The #10 delay in line 22 of 'tb.v', seems
              to break the waveform for signal 'y1'. #15 or larger delay values produce
              correct waveforms (or meets my expectation of a correct waveform).


              Sent from sourceforge.net because you indicated interest in
              https://sourceforge.net/p/iverilog/bugs/981/

              To unsubscribe from further messages, please visit
              https://sourceforge.net/auth/subscriptions/

               

              Related

              Bugs: #981

              • Cary R.

                Cary R. - 2015-06-10

                OK, you and Cary are saying that the always block may or may not complete execution by the time the 'in' signal is being updated. Is that correct?

                Yes, that is exactly what we are saying.

                Is the always block waiting 10 time steps to complete in your
                implementation in Icarus?

                Every simulator that is following the standard will wait ten time units before finishing the block attached to the @(...) statement. That is the point of a blocking delay and why we usually use non-blocking delays in conjunction with @(...) statements.

                And during this time, another thread could be changing the value of 'in'?

                That is exactly the reason your example is giving results you do not expect. The block attached to the @(...) has not finished when "in" is changed.

                 
          • Cary R.

            Cary R. - 2015-06-10

            The sensitivity list consists of one or more signals. When at least one of these signals changes, the always block executes through to the end keyword as before. Except that now, the sensitivity list prevents the always block from executing again until another change occurs on a signal in the sensitivity list.

            This is correct though imprecise and the key part you are likely missing in their description is that the always block must executes through to the end before the sensitivity list comes into play again.

            Remember always @(...) is not a single construct. You have an always construct that has its automatic repeat controlled by an @(..) statement.

            Hopefully the following examples will make it more clear:

            always begin  // This runs the enclosed code forever.
              @(in) begin // This waits here until "in" changes.
                y1 <= #15 in;
                #10 y2 <= in;
              end
            end
            

            Maybe even slightly more obvious you could also write this as:

            always begin    // This runs the enclosed code forever.
              @(in);        // This waits here until "in" changes.
              y1 <= #15 in; // This assigns y1 to in at t+15 in the future
              #10 y2 <= in; // This waits #10 and then assigns y2 to in at t+10
            end
            

            Using the first example we often omit the begin/end pair associated with the always construct since @(in) is a single statement it does not need to be inside a block statement. Removing the block statement gives the reduced example Martin originally posted. Every always and initial construct is run at time zero and the order is not deterministic. A delay or event control of some kind must be in every always construct statement or it will create a zero time infinite loop. I actually added checking code to the Icarus compiler to warn users about this because it is hard to debug Verilog when time does not advance.

             
  • Cary R.

    Cary R. - 2015-06-09

    I just read your replies again and I think this is the crux of the problem.

    "I'm wondering why does this affect y1? If I delay the high assertion
    of 'in' to 15 time units - both y1 and y2 look correct."

    A delay of 11 would also work, but a delay of 10 causes a race and a delay less than 10 will break in the same way and it may be more obvious why.

    Here is the race described again and it assumes that the "@(in)" fired at time zero. At time 10 you can execute the "in = 1;" or the "y2 <= in;" statements. Icarus executes the "in = 1;" statement which updates "in" and then executes the "y2 <= in;" statement. Once the non-blocking assignment RHS is evaluated the statement attached to the always has finishes so the always construct starts over and the "@(in)" becomes active again. This is after "in" has changed so the change is missed. The "always @(in)" does not continuously sit there waiting for events to happen. The process represented by the always construct has to be waiting at the "@(in)" statement for it to be sensitive to changes. This is the reason people suggest not using blocking delays in an always construct like this. It needs to execute atomically so it is ready to run whenever a signal in the sensitivity list changes.

    I will also note that the time zero race is still there, but Icarus is doing what you expect so nothing is needed for it, though other simulators may generate a different result.

     
  • Martin Whitaker

    Martin Whitaker - 2015-06-09

    Dave, maybe this example will make it clear:

    module example();
    
    event trigger;
    
    always @(trigger) begin
      $display("triggered at time %0t", $time);
      #11;
      $display("completed at time %0t", $time);
    end
    
    initial begin
      #10 ->trigger;
      #10 ->trigger;
      #10 ->trigger;
      #10 ->trigger;
      #20 $finish;
    end
    
    endmodule
    

    This example has no timing races and will produce the same output with any standard-conformant simulator:

    triggered at time 10
    completed at time 21
    triggered at time 30
    completed at time 41
    

    If you change the #11 to #10, you introduce a race, and different simulators may give different results.

     
  • Cary R.

    Cary R. - 2015-06-09

    And changing the #11 to #9 will not miss a trigger.

     

Log in to post a comment.