SystemVerilog and Verilog X Optimism – You May Not Be Simulating What You Think

Verilog and SystemVerilog define 4 different logic values for modeling hardware: 1, 0, X, and Z. 1 and 0 are obviously real logic levels that can exist in silicon. Z and X, however, are modeling abstractions: Z represents a high-impedance (an un-driven or tri-stated signal) state, while X represents an unknown or indeterminate logic value.

X’s can be created intentionally or unintentionally. The most common occurrence of X is in uninitialized registers or memories; X is used to represent the unknown value of these memory elements prior to a reset. Other conditions that can generate X include signals that are being simultaneously driven to different logic values by different drivers, to indicate logic that is shutdown in low power simulations, out of range bit selects and array indices. Some designers assign X to signals to show that they are “don’t care” values, as a hint to the synthesis tool so it can assign either 1 or 0 to the signals during logic optimization. To aid debug, some designers also assign X to signals in code paths that are impossible to reach, causing the simulator to flag erroneous execution of these paths by corrupting signals to X. Intentionally assigning X to signals is a controversial practice, however, and may be flagged by linting tools.

Verilog X optimism refers to how simulations may incorrectly exhibit determinate behaviour even when inputs to logic are X and have indeterminate value. It can be dangerous and can mask real RTL bugs.

The first example of Verilog X optimism is a simple if…else statement:

always_ff @(posedge clk) begin
  if (cond)
    c <= a;
  else
    c <= b;
end

Verilog (and SystemVerilog) LRM states that when the condition of an if…else statement is X, the condition is interpreted as false, and the code following the else statement must be executed.

A very real potential design bug is imagine if cond is directly generated from the contents of a memory, for example a combinationally generated error signal from a SECDED decoder, the always block is trying to set an error interrupt to 1 using the decoder error signal as cond. In simulation, the memory contents are X prior to being written. The X can propagate through the decoder to cond, causing the else statement to be executed, assigning 0 to the error interrupt. Contrast this with real silicon behaviour, where upon power on, the memory contents are truly unknown and will likely immediately trigger a SECDED decoder error. cond is true, and the interrupt fires.

The second example of Verilog X optimism is a case statement:

always_ff @(posedge clk) begin
  case (cond)
    1'b0 : c = a;
    1'b1 : c = b;
  endcase
end

X logic value in the select input actually causes c to retain the value of the previous clock, a completely different behaviour than the desired multiplexer.

A third example of Verilog X optimism is how Verilog and SystemVerilog treats transitions to X or Z. The following are all valid logic transitions that will trigger a posedge operator

  • 0->1, 0->X, 0->Z, X->1, Z->1

A 0->X or X->1 transition may or may not be a real posedge transition in silicon. But in simulation, the simulator will behave as though a positive edge on the clock has occurred, latching data into any registers triggered by posedge.

This post described three different Verilog and SystemVerilog constructs that can cause simulation and synthesis mismatch due to Verilog X optimism. Some material for further reading are X-Optimism Elimination during RTL Verification and I’m Still In Love With My X!.

In part 2 of the series, Are You A Pessimist? Mitigating Risk of SystemVerilog and Verilog X Optimism, I will describe several ways to avoid X optimism in simulation, and uncover design bugs that may be masked by Verilog X optimism.

1 thought on “SystemVerilog and Verilog X Optimism – You May Not Be Simulating What You Think”

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.