Input Languages¶
This section describes the languages Verilator takes as input. See also Configuration Files.
Language Standard Support¶
Verilog 2001 (IEEE 1364-2001) Support¶
Verilator supports most Verilog 2001 language features. This includes signed numbers, “always @*”, generate statements, multidimensional arrays, localparam, and C-style declarations inside port lists.
Verilog 2005 (IEEE 1364-2005) Support¶
Verilator supports most Verilog 2005 language features. This includes the `begin_keywords and `end_keywords compiler directives, $clog2, and the uwire keyword.
SystemVerilog 2005 (IEEE 1800-2005) Support¶
Verilator supports ==? and !=? operators, ++ and – in some contexts, $bits, $countbits, $countones, $error, $fatal, $info, $isunknown, $onehot, $onehot0, $unit, $warning, always_comb, always_ff, always_latch, bit, byte, chandle, const, do-while, enum, export, final, import, int, interface, logic, longint, modport, package, program, shortint, struct, time, typedef, union, var, void, priority case/if, and unique case/if.
It also supports .name and .* interconnection.
Verilator partially supports concurrent assert and cover statements; see the enclosed coverage tests for the allowed syntax.
Verilator has limited support for class and related object-oriented constructs.
SystemVerilog 2012 (IEEE 1800-2012) Support¶
Verilator implements a full SystemVerilog-compliant preprocessor, including function call-like preprocessor defines, default define arguments, `__FILE__, `__LINE__ and `undefineall.
SystemVerilog 2017 (IEEE 1800-2017) Support¶
Verilator supports the 2017 “for” loop constructs and several cleanups IEEE made in 1800-2017.
SystemVerilog 2023 (IEEE 1800-2023) Support¶
Verilator supports some of the 2023 improvements, including triple-quoted string blocks that may include newlines and single quotes.
Verilator implements a full IEEE 1800-2023 compliant preprocessor, including triple-quoted strings, and `ifdef expressions.
Verilog AMS Support¶
Verilator implements a very small subset of Verilog AMS (Verilog Analog and Mixed-Signal Extensions) with the subset corresponding to those VMS keywords with near-equivalents in Verilog IEEE 1364 or SystemVerilog IEEE 1800.
AMS parsing is enabled with --language VAMS
or
--language 1800+VAMS
.
Verilator implements ceil, exp, floor, ln, log, pow, sqrt, string, and wreal.
Synthesis Directive Assertion Support¶
With the --assert
option, Verilator reads any
//synopsys full_case
or //synopsys parallel_case
directives. The same applies to any //ambit synthesis
,
//cadence
or //pragma
directives of the same form.
When these synthesis directives are discovered, Verilator will either formally prove the directive to be true, or, failing that, will insert the appropriate code to detect failing cases at simulation runtime and print an “Assertion failed” error message.
Verilator likewise also asserts any “unique” or “priority” SystemVerilog keywords on case statements, as well as “unique” on if statements. However, “priority if” is currently ignored.
Time¶
With --timing
, all timing controls are supported:
delay statements,
event control statements not only at the top of a process,
intra-assignment timing controls,
net delays,
wait
statements,
as well as all flavors of fork
.
Compiling a Verilated design that uses these features requires a compiler with C++20 coroutine support, e.g. Clang 5, GCC 10, or newer.
#0
delays cause Verilator to issue the ZERODLY
warning, as
they work differently than described in the LRM. They do not schedule process
resumption in the Inactive region, though the process will get resumed in the
same time slot.
Rising/falling/turn-off delays are currently unsupported and cause the
RISEFALLDLY
warning.
Minimum/typical/maximum delays are currently unsupported. The typical delay is
always the one chosen. Such expressions cause the MINTYPMAX
warning.
Another consequence of using --timing
is that the --main
option generates a main file with a proper timing eval loop, eliminating the
need for writing any driving C++ code. You can simply compile the
simulation (perhaps using --build
) and run it.
With --no-timing
, all timing controls cause the NOTIMING
error, except:
delay statements - they are ignored (as they are in synthesis), though they do issue a
STMTDLY
warning,intra-assignment timing controls - they are ignored, though they do issue an
ASSIGNDLY
warning,net delays - they are ignored,
event controls at the top of the procedure,
Forks cause this error as well, except:
forks with no statements,
fork..join
orfork..join_any
with one statement,forks with
--bbox-unsup
.
If neither --timing
nor --no-timing
is specified, all
timing controls cause the NEEDTIMINGOPT
error, except event
controls at the top of the process. Forks cause this error as well, except:
forks with no statements,
fork..join
orfork..join_any
with one statement,forks with
--bbox-unsup
.
Timing controls and forks can also be ignored in specific files or parts of
files. The /*verilator timing_off*/
and
/*verilator timing_off*/
metacomments will make Verilator ignore
the encompassed timing controls and forks, regardless of the chosen
--timing
or --no-timing
option. This can also be achieved
using the timing_off
and timing_off
options in Verilator
configuration files.
Language Limitations¶
This section describes the language limitations of Verilator. Many of these restrictions are by intent.
Synthesis Subset¶
Verilator supports the Synthesis subset with other verification constructs being added over time. Verilator also simulates events as Synopsys’s Design Compiler would, namely given a block of the form:
always @(x) y = x & z;
This will recompute y when there is a potential for change in x or a change in z; that is when the flops computing x or z evaluate (which is what Design Compiler will synthesize.) A compliant simulator will only calculate y if x changes. We recommend using always_comb to make the code run the same everywhere. Also avoid putting $displays in combo blocks, as they may print multiple times when not desired, even on compliant simulators as event ordering is not specified.
Signal Naming¶
To avoid conflicts with C symbol naming, any character in a signal name that is not alphanumeric nor a single underscore will be replaced by __0hh where hh is the hex code of the character. To avoid conflicts with Verilator’s internal symbols, any double underscore is replaced with ___05F (5F is the hex code of an underscore.)
Bind¶
Verilator only supports bind to a target module name, not to an instance path.
Class¶
Verilator class support is limited but in active development. Verilator supports members, methods, class extend, and class parameters.
Dotted cross-hierarchy references¶
Verilator supports dotted references to variables, functions, and tasks in different modules. The portion before the dot must have a constant value; for example a[2].b is acceptable, while a[x].b is generally not.
References into generated and arrayed instances use the instance names
specified in the Verilog standard; arrayed instances are named
{instanceName}[{instanceNumber}]
in Verilog, which becomes
{instanceName}__BRA__{instanceNumber}__KET__
inside the generated C++
code.
Latches¶
Verilator is optimized for edge-sensitive (flop-based) designs. It will attempt to do the correct thing for latches, but most performance optimizations will be disabled around the latch.
Structures and Unions¶
All structures and unions are scheduled together, which means that generating one member of a structure from blocking, and another from non-blocking assignments is unsupported.
Unknown States¶
Verilator is mostly a two-state simulator, not a four-state simulator. However, it has two features that uncover most initialization bugs (including many that a four-state simulator will miss.)
Identity comparisons (=== or !==) are converted to standard ==/!= when neither side is a constant. This may make the expression yield a different result than a four-state simulator. An === comparison to X will always be false, so that Verilog code which checks for uninitialized logic will not fire.
Assigning X to a variable will assign a constant value as determined by the
--x-assign
option. This allows runtime randomization; thus, if
the value is used, the random value should cause downstream errors.
Integers also get randomized, even though the Verilog 2001 specification
says they initialize to zero. However, randomization happens at
initialization time; hence, during a single simulation run, the same
constant (but random) value will be used every time the assignment is
executed.
All variables, depending on --x-initial
setting, are typically
randomly initialized using a function. You can determine that reset is
working correctly by running several random simulation runs. On the first
run, have the function initialize variables to zero. On the second, have
it initialize variables to one. On the third and following runs, have it
initialize them randomly. If the results match, reset works. (Note that
this is what the hardware will do.) In practice, setting all variables to
one at startup finds the most problems (since control signals are typically
active-high).
--x-assign
applies to variables explicitly initialized or assigned
an X. Uninitialized clocks are initialized to zero, while all other state
holding variables are initialized to a random value. Event-driven
simulators will generally trigger an edge on a transition from X to 1
(posedge) or X to 0 (negedge). However, by default, since clocks are
initialized to zero, Verilator will not trigger an initial negedge. Some
code (particularly for reset) may rely on X->0 triggering an edge. The
--x-initial-edge
option enables this behavior. Comparing runs with
and without this option will find such problems.
Tri/Inout¶
Verilator converts some simple tristate structures into two state. Pullup,
pulldown, bufif0, bufif1, notif0, notif1, pmos, nmos, tri0 and tri1 are
also supported. Simple comparisons with === 1'bz
are also
supported.
An assignment of the form:
inout driver;
wire driver = (enable) ? output_value : 1'bz;
Will be converted to:
input driver; // Value being driven in from "external" drivers
output driver__en; // True if driven from this module
output driver__out; // Value being driven from this module
External logic will be needed to combine these signals with any external drivers.
Tristate drivers are not supported inside functions and tasks; an inout there will be considered a two-state variable that is read and written instead of a four-state variable.
Gate Primitives¶
The 2-state gate primitives (and, buf, nand, nor, not, or, xnor, xor) are directly converted to behavioral equivalents. The 3-state and MOS gate primitives are not supported. Tables are not supported.
Specify blocks¶
All specify blocks and timing checks are ignored. All min:typ:max delays use the typical value.
Array Initialization¶
When initializing a large array, you need to use non-delayed assignments. Verilator will tell you when this needs to be fixed; see the BLKLOOPINIT error for more information.
Array Out of Bounds¶
Writing a memory element outside the bounds specified for the array may cause a different memory element inside the array to be written instead. For power-of-2 sized arrays, Verilator will give a width warning and the address. For non-power-of-2-sizes arrays, index 0 will be written.
Reading a memory element outside the bounds specified for the array will give a width warning and wrap around the power-of-2 size. For non-power-of-2 sizes, it will return an unspecified constant of the appropriate width.
Assertions¶
Verilator is beginning to add support for assertions. Verilator currently
only converts assertions to simple if (...) error
statements, and
coverage statements to increment the line counters described in the
coverage section.
Verilator does not support SEREs yet. All assertion and coverage statements must be simple expressions that complete in one cycle.
Encrypted Verilog¶
Open-source simulators like Verilator cannot use encrypted RTL
(i.e. IEEE P1735). Talk to your IP vendor about delivering IP blocks via
Verilator’s --protect-lib
feature.
Language Keyword Limitations¶
This section describes specific limitations for each language keyword.
- `__FILE__, `__LINE__, `begin_keywords, `begin_keywords, `begin_keywords, `begin_keywords, `begin_keywords, `define, `else, `elsif, `end_keywords, `endif, `error, `ifdef, `ifndef, `include, `line, `systemc_ctor, `systemc_dtor, `systemc_header, `systemc_imp_header, `systemc_implementation, `systemc_interface, `undef, `verilog
Fully supported.
- always, always_comb, always_ff, always_latch, and, assign, begin, buf, byte, case, casex, casez, default, defparam, do-while, else, end, endcase, endfunction, endgenerate, endmodule, endspecify, endtask, final, for, function, generate, genvar, if, initial, inout, input, int, integer, localparam, logic, longint, macromodule, module, nand, negedge, nor, not, or, output, parameter, posedge, reg, scalared, shortint, signed, supply0, supply1, task, time, tri, typedef, var, vectored, while, wire, xnor, xor
Generally supported.
- ++, – operators
Increment/decrement can only be used as standalone statements or in certain limited cases.
- ‘{} operator
Assignment patterns with an order based, default, constant integer (array) or member identifier (struct/union) keys are supported. Data type keys and keys computed from a constant expression are not supported.
- `uselib
Uselib, a vendor-specific library specification method, is ignored along with anything following it until the end of that line.
- cast operator
Casting is supported only between simple scalar types, signed and unsigned, not arrays nor structs.
- chandle
Treated as a “longint”; does not yet warn about operations specified as illegal on chandles.
- checker
Treated as a “module”; does not yet warn about many constructs illegal inside a checker.
- disable
Disable statements may be used only if the block being disabled is a block the disable statement itself is inside. This was commonly used to provide loop break and continue functionality before SystemVerilog added the break and continue keywords.
- force, release
Verilator supports the procedural force (and corresponding release) statement. However, the behavior of the force statement does not entirely comply with IEEE 1800. According to the standard, when a procedural statement of the form force a = b; is executed, the simulation should behave as if, from that point forwards, a continuous assignment assign a = b; has been added to override the drivers of a. More specifically: the value of a should be updated whenever the value of b changes, until a release a; statement is executed. Verilator instead evaluates the current value of b when the force statement is executed, and forces a to that value, without updating it until a new force or release statement is encountered that applies to a. This non-standard behavior is nevertheless consistent with some other simulators.
- inside
Inside expressions may not include unpacked array traversal or $ as an upper bound. Case inside and case matches are also unsupported.
- interface
Interfaces and modports, including generated data types are supported. Generate blocks around modports are not supported, nor are virtual interfaces nor unnamed interfaces.
- shortreal
Short floating point (shortreal) numbers are converted to real. Most other simulators either do not support float, or convert likewise.
- specify specparam
All specify blocks and timing checks are ignored.
- uwire
Verilator does not perform warning checking on uwires; it treats the uwire keyword as if it were the normal wire keyword.
- $bits, $countbits, $countones, $finish, $isunknown, $onehot, $onehot0, $signed, $stime, $stop, $time, $unsigned,
Generally supported.
- $dump/$dumpports and related
$dumpfile or $dumpports will create a VCD or FST file (based on the
--trace
option given when the model was Verilated). This will take effect starting at the next eval() call. If you have multiple Verilated designs under the same C model, this will dump signals only from the design containing the $dumpvars.$dumpvars and $dumpports module identifier is ignored; the traced instances will always start at the top of the design. The levels argument is also ignored; use tracing_on/tracing_off pragmas instead.
$dumpportson/$dumpportsoff/$dumpportsall/$dumpportslimit filename argument is ignored; only a single trace file may be active at once.
$dumpall/$dumpportsall, $dumpon/$dumpportson, $dumpoff/$dumpportsoff, and $dumplimit/$dumpportlimit are currently ignored.
- $error, $fatal, $info, $warning.
Generally supported.
- $exit, $finish, $stop
The rarely used optional parameter to $finish and $stop is ignored; $exit is aliased to $finish.
- $fopen, $fclose, $fdisplay, $ferror, $feof, $fflush, $fgetc, $fgets, $fscanf, $fwrite, $fscanf, $sscanf
Generally supported.
- $fullskew, $hold, $nochange, $period, $recovery, $recrem, $removal, $setup, $setuphold, $skew, $timeskew, $width
All specify blocks and timing checks are ignored.
- $random, $urandom, $urandom_range
Use
+verilator+seed+<value>
runtime option to set the seed if there is no $random nor $urandom optional argument to set the seed. There is one random seed per C thread, not per module for $random, nor per object for random stability of $urandom/$urandom_range.- $readmemb, $readmemh
Read memory commands are supported. Verilator and the Verilog specification do not include support for readmem to multi-dimensional arrays.
- $test$plusargs, $value$plusargs
Supported, but the instantiating C++/SystemC wrapper must call
{VerilatedContext*} ->commandArgs(argc, argv);
to register the command line before calling $test$plusargs or $value$plusargs.