Four-state simulation resolves some unknowns away. 1'bx & 1'b0 is 0, and 1'bx | 1'b1 is 1, by the ordinary truth tables.
An x in an if condition takes the else branch in simulation. Real hardware holds a 0 or a 1 there, so it may take the path simulation skipped.
Expression | Simulation | Hardware reality |
|---|---|---|
`x & 0` |
| One leg is 0, so the gate agrees |
`x | 1` |
| One leg is 1, so the gate agrees |
`if (x)` | Else branch | Whichever value the wire really holds |
`x ^ x` |
| Always |
Elsewhere simulation keeps the unknown. A case with an x selector matches no plain item and falls to default, while the gate takes a concrete branch.
The program below checks both directions on small values: resolving AND, an x select falling to default, and the self-XOR that hardware always resolves.
import sys
bad = 0
def check(name, got, want):
global bad
if got != want:
print("FAIL: " + name + " got " + str(got) + " want " + str(want))
bad = bad + 1
def case_mux(sel, a, b):
if sel == 0:
return a
if sel == 1:
return b
return "x"
def and2(a, b):
if a == 0 or b == 0:
return 0
if a == "x" or b == "x":
return "x"
return 1
check("x-select-takes-default", case_mux("x", 0, 0), "x")
check("select-zero", case_mux(0, 0, 1), 0)
check("select-one", case_mux(1, 0, 1), 1)
check("optimistic-and", and2("x", 0), 0)
check("and-x1", and2("x", 1), "x")
check("and-11", and2(1, 1), 1)
agree = 0
for a in (0, 1):
if case_mux("x", a, a) == "x":
agree = agree + 1
if agree != 2:
print("FAIL: agree count got " + str(agree) + " want 2")
bad = bad + 1
if bad != 0:
sys.exit(1)
print("PASS: pessimistic select and optimistic AND agree on 7 checks")A flop without reset powers up x in simulation. Synthesis has no universal power-up value, and whether an initial value survives into gates varies by flow.
Until the first reset, every decision made from that state is an x decision. Tests that skip reset check hardware that cannot exist yet.
Give every state that must start known a reset or initial value that both simulation and gates honour; for intentionally unreset flops (pipelined datapaths, memories) apply reset before real vectors and show the result is X-tolerant.
y = x & 0 and the testbench is happy. What may the gates do differently?Nothing here: one leg is 0, so the gate agrees. The danger is the reverse case, where simulation keeps an x that hardware resolves.
An x machine. Every branch from uninitialised state is an x decision, so the test checks decisions the gates never face after reset.