Search code examples
verilogsystem-veriloghdl

What is the nondeterminism in Verilog and simulator? Can control flow switch back and forth between multiple events at a time-step?


enter image description here

I have read the chapter on scheduling semantics and can understand what the standard is saying. As the standard says, the simulator can suspend an upcoming activity event to execute another activity event, so the value displayed is indeterminate.

But I quickly thought of the following code, If the signals in a sensitive list change at the same time-step, this will lead to uncertainty.

module test;
    reg [1 : 0]c, d;
    reg a, b;
    initial #5 begin
        a = 0;
        b = 0;
    end

    always@(*)begin
        d = {a ,b};
        c = {a, b};
    end
endmodule

As I understand it, a change in the A signal will result in entering the always block. It is not certain whether the following b assignment is performed or the always block is executed. If the always block is executed, the value of d is {0x} after the first statement is executed. At this time, the control flow may perform the assignment of b, and @ will not be triggered again because the always block is not finished, which leads to the result that {0,0} is not {0,0} as I thought, but {0x}, (although the simulation gives the result {0,0}) This behavior of always block should be very common, that is, multiple sensitive signals change at the same time. I think the simulator's behavior should be deterministic because it's so common, but my analysis tells me that this is an indeterminate behavior determined by the simulator, is my analysis wrong?


Solution

  • Your analysis is technically correct, but you will never see a simulator behave that way. Normally, any events created by a process go onto a queue, and each process would have to suspend or finish before retrieving the next event in the queue. The purpose of this nondeterminism is allowing the simulator interleave processes by merging them into one as an optimization.

    A better example would be

    always @(*) x1 = y1 + z;
    always @(*) x2 = y2 + z;
    
    always @(*) begin
        z = a * b;
        y1 = a + b;
        w = b + d;
        y2 = w + a;
    end
    

    As an optimization, a simulator might merge these three always processes into one.

    always @(*) begin
        z = a * b;
        y1 = a + b;
        x1 = y1 + z;
        w = b + d;
        y2 = w + a;
        x2 = y2 + z;
    end
    

    This greatly reduces the amount of event management as well as the total number of processes.

    BTW, the IEEE 1800-2017 SystemVerilog LRM is current.