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
| Simulator | Where it runs | Used for |
|---|---|---|
| Icarus Verilog 12 | In your browser | Four-state behaviour: x, z and how they spread. Lessons and problems that need no classes or assertions. |
| Verilator 5.052 | On the simulator server | Most lessons and problems: classes, randomization (with the Z3 constraint solver), processes, interfaces and assertions. |
Verilator development build b8e7f1e (5.053-devel) | On the simulator server | Functional coverage only. It is pinned to one exact commit, so results do not drift. |
| Verilator 5.052 with uvm-core 2020.3.1 | On the simulator server | UVM. 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.
| Topic | The standard says | The simulator does | Where the course notes it |
|---|---|---|---|
| Unknown values | logic holds 0, 1, x and z | Verilator stores every x and z as 0 | Module 1 runs on Icarus |
disable fork inside a task | Stops every child of the calling process, including ones it started earlier | Icarus 12 leaves the caller's earlier children running | Lesson 3.3 |
Loop variable in fork ... join_none | A variable declared in the for header is shared by all the children | Verilator gives each child its own copy, so code that should fail works | Lesson 3.2 |
| Out-of-range array write | Ignored; a read returns the default value | Verilator keeps the low index bits and writes another element; Icarus ignores the write but reads x from an int array | Lessons 2.1 and 2.5 |
sum() with (cond) | The sum is 1 bit wide, so a count wraps | Verilator widens it and returns the full count | Lesson 2.4 |
solve ... before | The first field's values become equally likely | Verilator 5.052 gives about the same mix as with no order | Lesson 5.3 |
dist naming a forbidden value | Weights apply among legal values only | Verilator 5.052 fails many of the calls | Lesson 5.2 |
post_randomize() | Not called when randomize() fails | Verilator 5.052 calls it anyway | Lesson 5.6 |
| Overriding a virtual method | Arguments must match; a mismatch is an error | Verilator 5.052 accepts it, and calls through a base handle never reach the override | Lesson 4.4 |
$error | Reports an error and continues | Verilator stops the simulation | Lesson A1.1 |
Goto repetition [->n] | Fails when the counted event is not followed correctly | Verilator never reports a failure in a consequent | Lesson A2.2 |
Sequence or, [*m:n] followed by more, throughout over a goto | Defined pass and fail results | Verilator misses failures or reports false ones | Lessons A2.1, A2.2 and A3.2 |
##[m:n] followed by more sequence, first_match over a range, nested implications | Each attempt fails when no thread can complete | Verilator 5.052 misses some of these failures | Lessons A1.3 and A2.1 |
Sequence and with both operands failing | One failure per attempt | Verilator 5.052 reports the attempt twice | Lesson A2.1 |
A repetition range such as b[*2:4] at the end of a sequence | One success per attempt | Verilator 5.052 runs the pass action once per matching length | Lesson A2.2 |
assert #0 and assert final | A pending report is dropped when the process runs again in the same time step | Verilator 5.052 reports it anyway | Lesson A1.1 |
disable iff and a short reset pulse | A pulse between two edges disables attempts in progress | Verilator only sees the reset at a clock edge | Lesson A3.5 |
cover property pass action | Runs on each match | Verilator never runs it | Lesson A1.3 |
| Two failures of one assertion at one edge | Each attempt reports | Verilator reports one | Lesson A1.3 |
| Covergroup coverage | get_coverage() returns the percentage of bins hit | Verilator 5.052 always returns 0 | Lesson 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.