Simulators and known differences

Every example and problem on this site runs on a real, open-source simulator. No simulator follows the standard everywhere, so this page lists the differences you are likely to meet and where the course points them out.

Which simulator runs where

SimulatorWhere it runsUsed for
Icarus Verilog 12In your browserFour-state behaviour: x, z and how they spread. Lessons and problems that need no classes or assertions.
Verilator 5.052On the simulator serverMost lessons and problems: classes, randomization (with the Z3 constraint solver), processes, interfaces and assertions.
Verilator development build b8e7f1e (5.053-devel)On the simulator serverFunctional coverage only. It is pinned to one exact commit, so results do not drift.
Verilator 5.052 with uvm-core 2020.3.1On the simulator serverUVM. uvm-core is the Accellera library that implements IEEE 1800.2.

Each lesson and problem names its simulator. The version numbers are exact.

Why several simulators

Icarus models all four logic values, which is essential for lessons about unknown values, and it is small enough to run in a browser. It does not support most of the verification features of SystemVerilog, such as classes, constraints and concurrent assertions.

Verilator supports those features and runs fast, but it is a two-state simulator: it has no x or z. So four-state lessons run on Icarus, and everything else runs on Verilator.

Covergroups report 0% on Verilator 5.052, which makes them unusable for teaching. The development build fixes that, so coverage lessons use it, pinned to one commit. The rest of the course stays on the stable release.

Known differences

Each row was found by a small test program whose correct output was worked out by hand from IEEE 1800-2017. Runnable examples avoid these cases. Lessons that teach them describe the standard behaviour and say what the simulator does instead.

TopicThe standard saysThe simulator doesWhere the course notes it
Unknown valueslogic holds 0, 1, x and zVerilator stores every x and z as 0Module 1 runs on Icarus
disable fork inside a taskStops every child of the calling process, including ones it started earlierIcarus 12 leaves the caller's earlier children runningLesson 3.3
Loop variable in fork ... join_noneA variable declared in the for header is shared by all the childrenVerilator gives each child its own copy, so code that should fail worksLesson 3.2
Out-of-range array writeIgnored; a read returns the default valueVerilator keeps the low index bits and writes another element; Icarus ignores the write but reads x from an int arrayLessons 2.1 and 2.5
sum() with (cond)The sum is 1 bit wide, so a count wrapsVerilator widens it and returns the full countLesson 2.4
solve ... beforeThe first field's values become equally likelyVerilator 5.052 gives about the same mix as with no orderLesson 5.3
dist naming a forbidden valueWeights apply among legal values onlyVerilator 5.052 fails many of the callsLesson 5.2
post_randomize()Not called when randomize() failsVerilator 5.052 calls it anywayLesson 5.6
Overriding a virtual methodArguments must match; a mismatch is an errorVerilator 5.052 accepts it, and calls through a base handle never reach the overrideLesson 4.4
$errorReports an error and continuesVerilator stops the simulationLesson A1.1
Goto repetition [->n]Fails when the counted event is not followed correctlyVerilator never reports a failure in a consequentLesson A2.2
Sequence or, [*m:n] followed by more, throughout over a gotoDefined pass and fail resultsVerilator misses failures or reports false onesLessons A2.1, A2.2 and A3.2
##[m:n] followed by more sequence, first_match over a range, nested implicationsEach attempt fails when no thread can completeVerilator 5.052 misses some of these failuresLessons A1.3 and A2.1
Sequence and with both operands failingOne failure per attemptVerilator 5.052 reports the attempt twiceLesson A2.1
A repetition range such as b[*2:4] at the end of a sequenceOne success per attemptVerilator 5.052 runs the pass action once per matching lengthLesson A2.2
assert #0 and assert finalA pending report is dropped when the process runs again in the same time stepVerilator 5.052 reports it anywayLesson A1.1
disable iff and a short reset pulseA pulse between two edges disables attempts in progressVerilator only sees the reset at a clock edgeLesson A3.5
cover property pass actionRuns on each matchVerilator never runs itLesson A1.3
Two failures of one assertion at one edgeEach attempt reportsVerilator reports oneLesson A1.3
Covergroup coverageget_coverage() returns the percentage of bins hitVerilator 5.052 always returns 0Lesson 7.5 and the coverage track

Measured on the exact versions listed above.

Verilator 5.052 rejects some features outright, so the course teaches them without a runnable example. They are [=n], within with a ranged delay, intersect with a variable-length operand, .triggered and .matched, multiple clocks in one property, expect and the weak eventually [m:n]. Icarus 12 rejects $cast, unpacked structs and assignment patterns, which Module 1 works around in its examples.

What this means when you practise

A problem judges your code on its named simulator, and nowhere else. Code that relies on one of these differences can pass here and fail on another simulator, or in a real project.

So write the standard form even when the simulator would let something else through. For example, copy a loop variable into each forked child yourself, and check the result of every randomize() call.

When a lesson or problem depends on a behaviour listed here, it says so on the page, next to the code that is affected.

Messages you may see

Some differences only change what is printed. When randomize() fails, Verilator prints %Warning-UNSATCONSTR lines before your own messages; the standard only requires the call to return 0. Popping an empty queue prints a warning on Icarus and nothing on Verilator.

Neither changes a result, and no predict-the-output answer depends on these lines.

Keeping this list current

Every row comes from a small test program that we rerun on each simulator. Each program records the output the standard requires and the output each simulator gave.

The deviation probes fail if any simulator result changes, so a new simulator version that fixes a difference, or adds one, shows up at once. A row is removed only when a new version gives the standard result.

If a simulator does something here that this page does not mention, please report it with the code and the output.

Credits and licences

The site runs on these open-source projects. Thank you to their authors.

  • Icarus Verilog 12.0, by Stephen Williams and contributors, under the GNU General Public License version 2 (licence text). The copy that runs in your browser is compiled to WebAssembly from the upstream source (github.com/steveicarus/iverilog, tag v12_0) with a small patch and build files for WebAssembly. For three years from the date you received it, anyone may ask [email protected] for the complete corresponding source code, including that patch and those build files, at no charge.
  • Verilator 5.052 and a pinned development build, by Wilson Snyder and contributors, under the GNU Lesser General Public License version 3 or the Perl Artistic License 2.0. It runs on the server.
  • uvm-core 2020.3.1, the Accellera UVM reference library, under the Apache License 2.0.
  • Z3, Microsoft Research's constraint solver, which Verilator uses for randomization, under the MIT License.