#949 Blocking to non-blocking, events lost

devel
closed-invalid
nobody
None
7
2014-08-19
2014-03-06
No

/*
$ iverilog -V
Icarus Verilog version 0.10.0 (devel) (s20121218-9-g81ba404)

  • with delay, works
    $ iverilog example.v -o example
    $ vvp example
    00 01 02 03 04 05 06 07

  • without delay, does not work
    $ iverilog example.v -o example
    $ vvp example
    00 02 02 04 04 06 06 08

What happened to 01, 03 and 05 ????

*/

module example();

reg clk = 0;
reg [7:0] data = 0;
reg [7:0] mem [7:0];
reg [2:0] write_pointer = 0;

initial forever #5 clk = ~clk;

initial begin
#80
$display("%h %h %h %h %h %h %h %h",
mem[0], mem[1], mem[2], mem[3], mem[4], mem[5], mem[6], mem[7]);
$finish;
end

initial begin
repeat (8) begin
@(posedge clk)
//#1 //without this, every second data value gets lost!!
data = data + 1;
end
end

always@(posedge clk)
begin
mem[write_pointer] <= data;
write_pointer <= write_pointer + 1;
end

endmodule

Discussion

  • Cary R.

    Cary R. - 2014-03-06
    • status: open --> closed-invalid
     
  • Cary R.

    Cary R. - 2014-03-06

    There is a race condition in your code. You have two blocks that are activated on the positive edge of clock and which one executes first is not deterministic. Since one of the blocks depends on the output of the other if the blocks are executed in a different order you will get different results. To make this deterministic you can add a delay like shown, update the data value using a non-blocking assignment or change the data on the negative edge of the clock. To understand this race you need to understand Verilog event scheduling and how blocking and non-blocking assignments work in that context.

    I am closing this report as invalid.

     
  • Conor Santifort

    Conor Santifort - 2014-03-07

    Thanks for the quick response.

    So Icarus does not schedule non-blocking RHS value calculation over blocking assignments on same event? Is this allowed by the standard? I have run this code without strange behavior on other simulators, but perhaps those simulators are more conservative than required by the standard.

     
  • Cary R.

    Cary R. - 2014-03-07

    SystemVerilog may specify this (I have not looked), but as I remember Verilog (which is what Icarus is currently based on) does not, so yes the RHS and blocking assignment are evaluated in the same delta cycle. The non-blocking assignment basically samples in the current delta cycle and assigns in the next one. If the order the blocks are evaluated is always consistent you will get something that appears to work, but you would get different results (e.g. start at 0 vs 1) if the simulator started the list of processes at the end of the file vs the beginning (possible simulator differences). If you can find somewhere in the standard where a specific order is required please let us know. I will look at the latest SystemVerilog standard to see if it has been added. I know there are some event scheduling changes that I have not looked at in detail. As you may have figured out it looks like Icarus reverses the order of the processes in the event list each time they are processed.

    To be safe I believe the only thing you can count on is that a non-blocking assignment will update the LHS a delta cycle after it is executed/RHS sampled. Without further timing control everything else triggered runs in the same delta cycle and possibly in any order.

     
  • Conor Santifort

    Conor Santifort - 2014-03-07

    I did some digging and found a SNUG paper that discusses event ordering in reference to the Verilog standard. This supports the idea that blocking assigning and non-blocking RHS update order can be random. http://www.deepchip.com/items/0347-01.html

    ACTIVE EVENTS (These events may be scheduled in any order)
      +--------------------------------------------------+
      | Blocking assignments                             |
      | Evaluate RHS of nonblocking assignments          |
      | Continuous assignments                           |
      | $display command execution                       |
      | Evaluate inputs and change outputs of primitives |
      +--------------------------------------------------+
    

    I was under the impression that non-blocking RHS should be done first. This impression came from how other simulators handle this, and also the concept that a non-blocking assignment should model a flipflop where only values from before the clock edge affect the value output after the clock edge (ignoring metastability issues).

    This issue came up in the interface between testbench and RTL code, with a task creating a complex data pattern in the testbench, where it is convenient to use blocking assignments.

     
  • Cary R.

    Cary R. - 2014-03-07

    You can find the PDF for that paper here:

    http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA_rev1_2.pdf

    It is about the original Verilog event queue which is what Icarus currently implements. Here is a link to a paper that discusses some of the enhancements created by an earlier version (1800-2005) of SystemVerilog:

    http://www.sunburst-design.com/papers/CummingsSNUG2006Boston_SystemVerilog_Events.pdf

    I believe future versions of SystemVerilog have tweaked this a bit. You can get the latest SystemVerilog standard (1800-2012) for free here:

    http://standards.ieee.org/getieee/1800/download/1800-2012.pdf

    Depending on the flip-flop implementation the real sampling data point can be slightly before or after the clock edge and you then still need to satisfy setup and hold requirements, so assuming you can change the input value at the same time as the sampling clock edge is dangerous. It may work correctly for RTL simulations, but will likely fail for a gate level simulation. Metastability is only an issue if you cannot satisfy the setup and hold times for the flip-flop and in a normal synchronous design this should only need to be handled when passing data across non-synchronized clock domains. In asynchronous designs things can get significantly more complicated.

     
  • Cary R.

    Cary R. - 2014-03-07

    I will also say my preferred method for handling test bench to circuit data generation is to use the opposite edge of the clock to generate the test data or if I want to make it supper robust I make the data undefined except during the setup and hold region around the sampling clock edge. This works well if this region encompasses the clock edge, but requires some extra work at the RTL interface if it doesn't.

     
  • Martin Whitaker

    Martin Whitaker - 2014-03-07

    To provide further confirmation that there is no preferential ordering of non-blocking vs. blocking RHS evaluation, try the following simplification to your example on another simulator:

    always @(posedge clk) begin 
      mem[write_pointer] <= data;
      write_pointer <= write_pointer + 1;
    end
    
    always @(posedge clk) begin
      data = data + 1;
    end
    

    (leaving the rest of the module as is). Now swap the order of the two 'always' blocks in the source file. With another simulator I have access to, the order shown above results in

    00 01 02 03 04 05 06 07
    

    and the swapped order results in

    01 02 03 04 05 06 07 08
    

    i.e. the output depends on the order in which the 'always' blocks are executed.

     

Log in to post a comment.

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:

JavaScript is required for this form.





No, thanks