Search code examples
veriloghdl

Verilog LRM Nondeterminism


I am facing some doubts regarding the nondeterminism in Verilog Scheduling Semantics mentioned in the Verilog LRM. Below is the excerpt which I am unable to understand:

"Another source of nondeterminism is that statements without time-control constructs in behavioral blocks do not have to be executed as one event. Time control statements are the # expression and @ expression constructs (see 9.7). At any time while evaluating a behavioral statement, the simulator may suspend execution and place the partially completed event as a pending active event on the event queue. The effect of this is to allow the interleaving of process execution. Note that the order of interleaved execution is non-deterministic and not under control of the user."

The only inference I could make was that statements in a behavioral block may be paused for the execution of other behavioral blocks (which are active in the same timestep) so as to interleave process execution though I am not sure.

Also, I don't understand the line "statements without time-control constructs in behavioral blocks do not have to be executed as one event". What does the LRM mean by saying it doesn't execute as one event and what would happen if a behavioral block would contain all time-controlled statements?

Can anyone please explain this with the help of some examples? Thanks in advance.


Solution

  • The only thing which simulation guarantees is that all statements in the always blocks will be executed sequentially. Say, as in the following block:

    always @(b,c,e,f) begin
       a = b | c;
       d = e & f;
       g = a ^ d ^ x;
       ...
    end
    

    However, the simulator can decide to execute first 2 statements in a row, but then stop execution of this block before the last statement and let other blocks to continue. Then it will return to the last statement. In this sense you have a non-deterministic order of the execution of the statements.

    Guess what?! Value of x can definitely change while it is waiting. a and d can potentially also change while other statements are executed. So, result of g could be non-deterministic. Good programming will help to remove this type of non-determinism: list all events in the sensitivity list, do not multiply-drive signals, ... The simulator then will do the best to avoid those situations.

    The need for this interleave simulation is to allow simulators to do better optimization for performance reasons and allow other blocks to progress in case of the very long and loopy statements.

    Answering the comment about time and event controls

    In the above block a simulator can decide when to break the execution. From the point of view of the programmer, it is non-deterministic. You do not know when it can happen. The only thing that is known that it would happen in the same simulation (time) tick. A good simulator will try its best to avoid any side effect of this.

    Timing and delay controls provide deterministic stops. For example,

    always @(b,c,e,f) begin
       a = b | c;
       d = e & f;
       #1 g = a ^ d ^ x;
       ...
    end
    

    In the above statement with #1 you actually tell the simulator to stop execution of the statements and wait till the next time tick.

    always @(b,c,e,f) begin
       a = b | c;
       d = e & f;
       @(posedge clk)
       g = a ^ d ^ x;
       ...
    end
    

    Here it will stop execution and wait for the posedge clk event.

    Note that above examples are not synthesizable and should be used in behavioral code (test bench) only. For synthesis you have to stick with the very first example and make sure that your code is written in accordance to the good Verilog coding practices.