FSIMX ENGINE SERIES · PART 03 · FOUR-STATE (X/Z)

What Does Two-State Simulation Hide?

Different modeling approach, different answer. Here is where, and by how much.
WIOWIZ Technologies • August 2026 • 9 min read

A two-state simulator answers a different question than a four-state one.
Where that difference matters - reset-X, X in a case selector, X in a link-training register - the answer diverges.
This article measures the divergence, and what carrying X and Z as first-class values costs on a compute-bound loop.

Reset and initialization behaviour is where the difference between two-state and four-state modelling shows up sharpest: registers that come up unknown, muxes that select on an X, values that propagate through arithmetic before anything drives them. IEEE 1800 four-state semantics express those situations with X and Z as first-class values. Verilator (a compiled two-state simulator) does not preserve the fourth state - that is its documented design point, chosen for compile-time throughput. This article measures where FSimX and Icarus Verilog agree byte-for-byte on the semantics, where the two-state answer diverges from the four-state answer at a scale that stops a testbench, and what carrying X and Z costs on a compute-bound loop.

A note on how this series treats Icarus Verilog and Verilator. They are the open-source reference simulators FSimX corrects itself against. Where FSimX and Icarus agree byte-for-byte on four-state semantics, that agreement is how FSimX shows it is right. Where FSimX and Verilator disagree on X propagation, the disagreement is measured, not argued. The reference tells us the standard; where we scale past it - and by how much, and at what cost - is what the numbers report.

Five X-semantics checks, side by side

The probe is a WIOWIZ-original test, bench_xprop, that exercises five basic four-state behaviors from IEEE 1800: an uninitialized register, the logical identities on X, a conditional with an X select, a case statement with an X selector, and X in arithmetic. FSimX and Icarus Verilog (iverilog, the reference four-state event-driven simulator) agree byte-for-byte on all five. Verilator produces a different value on every one, with no warning and no error.

Check (bench_xprop)IEEE 1800 four-state
(FSimX = iverilog)
Compiled two-state simulator
uninitialized regX00000000
X&0, X|1, X^v0, 1, X00000000, 11111111, 10101010
conditional with X select00xxxx11 (bitwise merge)00110011
case with X selectordefault arm (7f)01 (took the 00 arm)
X in arithmeticxxxxxxxx00000001

Read the case-statement row. With an X in the selector, four-state semantics fall through to the default arm; Verilator's two-state model takes the zero arm and continues as if the selector were known. On this probe the divergence is one line in a table; on a reset controller with an uninitialised state machine it is the difference between hitting the default arm and taking a valid-looking path. Verilator's behaviour here is its documented design point, not a defect; the point of the probe is to make the difference visible where it matters.

When four-state changes the outcome, not just a value

Individual value differences are one thing. The more consequential case is when carrying X versus assuming zero changes whether a testbench finishes at all. The chiplet designs in this study show both directions of that.

The chiplet S3 (L2) adapter testbench, a WIOWIZ-original TileLink-to-UCIe adapter with an SVA checker, runs to a clean verdict on both four-state simulators, check for check:

$ # chiplet S3 (L2) adapter, four-state (FSimX and iverilog)
SVA_SUMMARY: checks_pass=766 checks_fail=0
VERDICT: PASS   FSimX total 0.07 s

$ # chiplet S3 (L2) adapter, compiled two-state simulator
SVA_SUMMARY: checks_pass=99937 checks_fail=0
VERDICT: PARTIAL_TIMEOUT   loops to its 200 us watchdog, deterministic x3

FSimX and Icarus Verilog agree at 766 of 766 checks. Verilator builds the model and then never reaches the end condition: its differing initialization changes the stimulus progression, and the checker spins to its watchdog. The four-state pair agrees; Verilator does not finish.

The chiplet S3 (L4) two-die design - one configuration in a family of WIOWIZ chiplet build points - shows the two-state failure mode even more starkly, and it is also where FSimX itself still has an open divergence, so it is not presented here as a clean win. It runs RV32I firmware on a picorv32 core across a die-to-die link to a remote die. Under two-state, the link never trains:

$ # chiplet S3 (L4) two-die, compiled two-state simulator
%Error: WATCHDOG: no trap after 30000 cycles
        (link_up cpu=0 mem=0 cpu_run=1 pc~0x00006ffc)  -> Aborting...

FSimX reaches the firmware completion word 0x0000600d on this design; Verilator's two-state model, initialising the link-training register to zero rather than unknown, hangs with link_up cpu=0 mem=0 and aborts on every iteration. FSimX does not yet match Icarus Verilog end to end here, though: it diverges on 32 checks in the UCIe mainband-CRC layer (16 per die), where Icarus Verilog passes clean, so FSimX's overall verdict on this test is FAIL even though the firmware self-check still reaches 0x600d. That residual four-state divergence is under investigation (tracked as BUG_975); it does not affect the two-state result, which is that the link never trains at all. For the clean four-state agreement, read the chiplet S3 (L2) result above - 766/766 checks matching Icarus Verilog while the two-state tool times out.

Where FSimX loses on speed, with the exact number

On raw free-running RTL throughput, Verilator wins by a large multiplier on this compute-bound loop. The exact number:

Simulated cycles per second across designs and tools, log scale, with wins and the largest loss on the same axis
Simulated cycles per second on bench_lfsr, log scale. Verilator sits far to the right on this free-running RTL loop; FSimX and Icarus Verilog are within 1.3× of each other and about 148× behind.

On bench_lfsr, a WIOWIZ-original 500,000-cycle free-running linear-feedback shift register with identical checksums across all tools, the run-phase numbers are: Verilator's compiled two-state model 0.17 seconds, Icarus Verilog 20.01 seconds, FSimX 25.25 seconds. That makes Verilator about 148 times faster than FSimX on this compute-bound loop, and Icarus Verilog about 1.26 times faster. Those are the numbers, unrounded in the study.

Two framings on that gap. First, it is Verilator's design point - compile every process to optimised straight-line code, do not carry the fourth state, and on a long free-running loop with a build that amortises across many cycles, the throughput is far ahead. Second, the gap is specific to compute-bound free-running RTL; the front-end and build costs the throughput chart leaves out sit in the stage-anatomy figure below.

Stacked front-end, backend build, and simulation walls for the flagship designs across three tools
Stage anatomy for the flagship designs. Verilator pays a large backend-build wall before any cycle runs; FSimX pays none, which is why it reaches a first simulated cycle in well under a second where Verilator takes tens of seconds.

On the DeepFuse sensor-fusion testbench, FSimX reaches a running simulation in 0.69 seconds; Verilator needs 25.6 seconds to produce a runnable model, and only after dropping the covergroups it cannot compile. So on a short iterative edit-run loop, or a design where build wall dominates, FSimX wins wall-clock. On a long compute-bound run of already-built RTL, Verilator wins throughput. Blog 05 covers how FSimX narrows the throughput side without dropping four-state, and where that work has and has not paid off yet.

What the numbers say, in one line each

Four-state values are carried exactly by FSimX and match Icarus Verilog byte-for-byte across the five semantics probes. On the two chiplet workloads, Verilator's two-state initialisation causes divergence a testbench notices (766 vs 99937 checks, or hang on link training). On the free-running bench_lfsr loop, Verilator is about 148× faster than FSimX and Icarus Verilog is about 1.26× faster; that number is on the versions tested and on this loaded workstation. Which trade is right depends on which question the simulator is being asked.

148× on the free-running loop is what carrying X and Z costs FSimX today, on the versions tested.
Whether that trade is right depends on which question the simulator is being asked.
#FSimX #fourstate #Xpropagation #chiplet #SoC #performance #WIOWIZ

Backing numbers

  • bench_xprop: 5/5 X-semantics checks byte-identical to iverilog; two-state differs on all 5
  • chiplet S3 (L2): FSimX 766/766 checks PASS, matches iverilog; two-state PARTIAL_TIMEOUT
  • chiplet S3 (L4) two-die: FSimX reaches 0x0000600d but diverges from Icarus Verilog on 32 UCIe mainband-CRC checks (16 per die; verdict FAIL, under investigation, BUG_975); two-state watchdog abort, link_up cpu=0
  • bench_lfsr 500k cycles: two-state 0.17 s, event sim 20.01 s, FSimX 25.25 s (148x / 1.26x)
  • DeepFuse first cycle: FSimX 0.69 s vs 25.6 s compiled build

Run it yourself - FSiMX Studio

The native FSiMX engine described in this article ships in FSiMX Studio, a Docker bundle from the WIOWIZ website. Download it, build the image, and run the same elaboration, four-state and assertion behaviour you saw here, with vWIZ-Wave and vWIZ-Coverage in the same window.

Download FSiMX Studio on wiowiz.ai →

FSiMX Studio: compile, run, waveform debug and coverage closure in one window.
The FSiMX engine in FSiMX Studio on wiowiz.ai/fsimx-studio.html - one persistent session for compile, run, waveform debug and coverage closure.

 

#FSiMX #verification #WIOWIZ

Our Approach

We're building systems that think about specifications the way engineers do.

We build our own in-house EDA with an intelligence layer across it. Our stack covers the full flow,
from spec to comprehensive sign-off, on tools we build and control.

Walk-in ones, walk-in zeros