FAQ/Frequently Asked Questions

Questions

Can I contribute?

Please contribute! Just submit a pull request, or raise an issue to discuss if you are looking for something to help on. For more information see our contributor agreement.

How widely is Verilator used?

Verilator is used by many of the largest silicon design companies, large organizations such as CERN, and even by college student projects.

Verilator is one of the “big 4” simulators, meaning one of the four leading SystemVerilog simulators available, namely the closed-source products Synopsys VCS (tm), Mentor Questa/ModelSim (tm), Cadence Xcelium/Incisive/NC-Verilog/NC-Sim (tm), and the open-source Verilator. The three closed-source offerings are often collectively called the “big 3” simulators.

Does Verilator run under Windows?

Yes, ideally, run Ubuntu under Windows Subsystem for Linux (WSL2). Alternatively, use Cygwin, though this tends to be slower and is not regularly tested. Verilated output also compiles under Microsoft Visual C++, but this is also not regularly tested.

Can you provide binaries?

You can install Verilator via the system package manager (apt, yum, etc.) on many Linux distributions, including Debian, Ubuntu, SuSE, Red Hat, and others. These packages are provided by the Linux distributions and generally will lag the version of the mainline Verilator repository. If no binary package is available for your distribution, how about you set one up?

How can it be faster than (name-a-big-3-closed-source-simulator)?

Generally, the implied part of the question is “… with all of the manpower they can put into developing it.”

Most simulators must comply with the complete IEEE 1364 (Verilog) and IEEE 1800 (SystemVerilog) standards, meaning they have to be event-driven. This prevents them from being able to reorder blocks and make netlist-style optimizations, which are where most of the gains come from.

You should not be scared by non-compliance. Your synthesis tool isn’t compliant with the whole standard to start with, so your simulator need not be either. Verilator is closer to the synthesis interpretation, which is a good thing for getting working silicon.

Why is running Verilator (to create a model) so slow?

Verilator may require more memory than the resulting simulation, as Verilator internally creates all of the state of the resulting generated simulator to optimize it. If it takes more than a few minutes or so (and you’re not using --debug since debug mode is disk bound), see if your machine is paging; most likely, you need to run it on a machine with more memory. Very large designs are known to have topped 64 GB resident set size. Alternatively, see Hierarchical Verilation.

How do I generate waveforms (traces) in C++?

See also the next question for tracing in SystemC mode.

  1. Pass the --trace option to Verilator. Then you may use $dumpfile and $dumpvars to enable traces, the same as with any Verilog simulator, although Verilator ignores the arguments to $dumpvars. See examples/make_tracing_c in the distribution.

    If writing the top-level C code, call Verilated::traceEverOn(true); this is done for you if using --binary.

  2. Or, for finer-grained control, or C++ files with multiple Verilated modules, you may also create the trace purely from C++. Create a VerilatedVcdC object, and in your main loop, right after eval() call trace_object->dump(contextp->time()) every time step, and finally call trace_object->close().

    #include "verilated_vcd_c.h"
    ...
    int main(int argc, char** argv) {
        const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
        ...
        Verilated::traceEverOn(true);
        VerilatedVcdC* tfp = new VerilatedVcdC;
        topp->trace(tfp, 99);  // Trace 99 levels of hierarchy (or see below)
        // tfp->dumpvars(1, "t");  // trace 1 level under "t"
        tfp->open("obj_dir/t_trace_ena_cc/simx.vcd");
        ...
        while (contextp->time() < sim_time && !contextp->gotFinish()) {
            contextp->timeInc(1);
            topp->eval();
            tfp->dump(contextp->time());
        }
        tfp->close();
    }
    

You also need to compile verilated_vcd_c.cpp and add it to your link, preferably by adding the dependencies in your Makefile’s $(VK_GLOBAL_OBJS) link rule. This is done for you if you are using the Verilator --binary or --exe option.

you can call trace_object->trace() on multiple Verilated objects with the same trace file if you want all data to land in the same output file.

How do I generate waveforms (traces) in SystemC?

  1. Pass the --trace option to Verilator, and in your top-level sc_main(), call Verilated::traceEverOn(true). Then you may use $dumpfile and code:$dumpvars to enable traces, as with any Verilog simulator; see the non-SystemC example in examples/make_tracing_c. This will trace only the module containing the $dumpvar.

  2. Or, you may create a trace purely from SystemC, which may trace all Verilated designs in the SystemC model. Create a VerilatedVcdSc object as you would create a standard SystemC trace file. For an example, see the call to VerilatedVcdSc in the examples/make_tracing_sc/sc_main.cpp file of the distribution, and below.

  3. Alternatively, you may use the C++ trace mechanism described in the previous question; note that the timescale and timeprecision will be inherited from your SystemC settings.

    #include "verilated_vcd_sc.h"
    ...
    int main(int argc, char** argv) {
        ...
        Verilated::traceEverOn(true);
        VerilatedVcdSc* tfp = new VerilatedVcdSc;
        topp->trace(tfp, 99);  // Trace 99 levels of hierarchy
        tfp->open("obj_dir/t_trace_ena_cc/simx.vcd");
        ...
        sc_start(1);
        ...
        tfp->close();
    }
    

You also need to compile verilated_vcd_sc.cpp and verilated_vcd_c.cpp and add them to your link, preferably by adding the dependencies in your Makefile’s $(VK_GLOBAL_OBJS) link rule. This is done for you if you are using the Verilator --binary or --exe option.

You can call ->trace() on multiple Verilated objects with the same trace file if you want all data to land in the same output file.

How do I generate FST waveforms (traces) in C++ or SystemC?

FST is a trace file format developed by GTKWave. Verilator provides basic FST support. To dump traces in FST format, add the --trace-fst option to Verilator and either:

Use $dumpfile & $dumpvars in Verilog as described in the VCD example above,

Or, in C++ change the include described in the VCD example above:

#include "verilated_fst_c.h"
VerilatedFstC* tfp = new VerilatedFstC;

Or, in SystemC, change the include described in the VCD example above:

#include "verilated_fst_sc.h"
VerilatedFstC* tfp = new VerilatedFstSc;

Currently, supporting FST and VCD in a single simulation is not supported, but such usage should be unlikely. You can however ifdef around the trace format in your C++ main loop, and select VCD or FST at compile time.

How do I view waveforms (aka dumps or traces)?

Verilator creates standard VCD (Value Change Dump) and FST files. VCD files are viewable with the open-source GTKWave, Surfer, Dinotrace (legacy), or any of the many closed-source viewer offerings; FST is supported only by GTKWave and Surfer.

How do I speed up writing large waveform (trace) files?

  1. Instead of calling VerilatedVcdC->open or $dumpvars at the beginning of time, delay calling it until the time stamp where you want tracing to begin.

  2. Add the /*verilator tracing_off*/ metacomment to any very low-level modules you never want to trace (such as perhaps library cells).

  3. Use the --trace-depth option to limit the tracing depth, for example --trace-depth 1 to see only the top-level signals.

  4. You can also consider using FST tracing instead of VCD. FST dumps are a fraction of the size of the equivalent VCD. FST tracing can be slower than VCD tracing, but it might be the only option if the VCD file size is prohibitively large.

  5. Write your trace files to a machine-local solid-state drive instead of a network drive. Network drives are generally far slower.

Where is the translate_off command? (How do I ignore a construct?)

Translate on/off pragmas are generally a bad idea, as it’s easy to have mismatched pairs, and you can’t see what another tool sees by just preprocessing the code. Instead, use the preprocessor; Verilator defines the \`VERILATOR define for you, so just wrap the code in an ifndef region:

`ifndef VERILATOR
   Something_Verilator_Dislikes;
`endif

Most synthesis tools similarly define SYNTHESIS for you.

Why do I get “unexpected ‘do’” or “unexpected ‘bit’” errors?

The words do, bit, ref, return, and others are reserved keywords in SystemVerilog. Older Verilog code might use these as identifiers, and you should change your code to not use them to ensure it works with newer tools. Alternatively, surround them by the Verilog 2005/SystemVerilog begin_keywords pragma to indicate Verilog 2001 code.

`begin_keywords "1364-2001"
   integer bit; initial bit = 1;
`end_keywords

If you want the whole design parsed as Verilog 2001, see the --default-language option.

How do I prevent my assertions from firing during reset?

Call Verilated::assertOn(false) before you first call the model, then turn it back on after reset. It defaults to true. When false, all assertions controlled by --assert are disabled.

Why do I get “undefined reference to sc_time_stamp()?

In Verilator 4.200 and later, using the timeInc function is recommended instead. See the Connecting to C++ examples. Some linkers (MSVC++) still require sc_time_stamp() to be defined; either define this with double sc_time_stamp() { return 0; } or compile the Verilated code with -CFLAGS -DVL_TIME_CONTEXT.

Before Verilator 4.200, the sc_time_stamp() function needs to be defined in C++ (non SystemC) to return the current simulation time.

Why do I get “undefined reference to `VL_RAND_RESET_I’ or `Verilated::…’”?

You need to link your compiled Verilated code against the verilated.cpp file found in the include directory of the Verilator kit. This is one target in the $(VK_GLOBAL_OBJS) make variable, which should be part of your Makefile’s link rule. If you use --exe or --binary, this is done for you.

Is the PLI supported?

Only somewhat. More specifically, the common PLI-ish calls $display, $finish, $stop, $time, $write are converted to C++ equivalents. You can also use the “import DPI” SystemVerilog feature to call C code (see the chapter above). There is also limited VPI access to public signals.

If you want something more complex, since Verilator emits standard C++ code, you can write C++ routines that can access and modify signal values without needing any PLI interface code, and call it with $c(“{any_c++_statement}”).

See the Connecting to Verilated Models section.

How do I make a Verilog module that contains a C++ object?

You need to add the object to the structure Verilator creates, then use $c to call a method inside your object. The test_regress/t/t_extend_class files in the distribution show an example of how to do this.

How do I get faster build times?

  • When running make, pass the make variable VM_PARALLEL_BUILDS=1, so that builds occur in parallel. Note this is now set by default if an output file is large enough to be split due to the --output-split option.

  • Verilator emits any infrequently executed “cold” routines into separate __Slow.cpp files. This can accelerate compilation as optimization can be disabled on these routines. See the OPT_FAST and OPT_SLOW make variables and Benchmarking & Optimization.

  • Use a recent compiler. Newer compilers tend to be faster.

  • Compile in parallel on many machines and use caching; see the web for the ccache, sccache, distcc, or icecream packages. ccache will skip GCC runs between identical source builds, even across different users. If ccache was installed when Verilator was built, it is used, or see OBJCACHE environment variable to override this. Also see the --output-split option and :ref: Profiling ccache efficiency.

  • To reduce the compile time of classes that use a Verilated module (e.g., a top CPP file) you may wish to add a /*verilator no_inline_module*/ metacomment to your top-level module. This will decrease the amount of code in the model’s Verilated class, improving compile times of any instantiating top-level C++ code, at a relatively small cost of execution performance.

  • Use Hierarchical Verilation.

Why do so many files need to recompile when I add a signal?

Adding a new signal requires the symbol table to be recompiled. Verilator uses one large symbol table, resulting in 2-3 fewer assembly instructions for each signal access. This makes the execution time 10-15% faster, but can result in more compilations when something changes.

How do I access Verilog functions/tasks in C?

Use the SystemVerilog Direct Programming Interface. You write a Verilog function or task with input/outputs that match what you want to call in with C. Then mark that function as a DPI export function. See the DPI chapter in the IEEE Standard.

How do I access C++ functions/tasks in Verilog?

Use the SystemVerilog Direct Programming Interface. You write a Verilog function or task with input/outputs that match what you want to call in with C. Then mark that function as a DPI import function. See the DPI chapter in the IEEE Standard.

How do I access signals in C?

The best thing to do is to make a SystemVerilog “export DPI” task or function that accesses that signal, as described in the DPI chapter in the manual and DPI tutorials on the web. This will allow Verilator to optimize the model better and should be portable across simulators.

If you really want raw access to the signals, declare the signals you will be accessing with a /*verilator public*/ metacomment before the closing semicolon. Then scope into the C++ class to read the value of the signal, as you would any other member variable.

Signals are the smallest of 8-bit unsigned chars (equivalent to uint8_t), 16-bit unsigned shorts (uint16_t), 32-bit unsigned longs (uint32_t), or 64-bit unsigned long longs (uint64_t) that fit the width of the signal. Generally, you can use just uint32_t’s for 1 to 32 bits, or uint64_t for 1 to 64 bits, and the compiler will properly up-convert smaller entities. Note that even signed ports are declared as unsigned; you must sign extend yourself to the appropriate signal width.

Signals wider than 64 bits are stored as an array of 32-bit uint32_t’s. Thus, to read bits 31:0, access signal[0], and for bits 63:32, access signal[1]. Unused bits (for example, bit numbers 65-96 of a 65-bit vector) will always be zero. If you change the value, you must pack zeros in the unused bits, or core-dumps may result because Verilator strips array bound checks where it believes them to be unnecessary to improve performance.

In the SYSTEMC example above, if you had in our.v:

input clk /*verilator public*/;
// Note the placement of the semicolon above

From the sc_main.cpp file, you’d then:

#include "Vour.h"
#include "Vour_our.h"
std::cout << "clock is " << top->our->clk << std::endl;

In this example, clk is a bool you can read or set as any other variable. The value of normal signals may be set, though your code shouldn’t change clocks, or you’ll get strange results.

Should a module be in Verilog or SystemC?

Sometimes there is a block that only interconnects instances, and you have a choice if you write it in Verilog or SystemC. Everything else being equal, the best performance is when Verilator sees all of the design. So, look at the hierarchy of your design, labeling instances as to if they are SystemC or Verilog. Then:

  • A module with only SystemC instances below must be SystemC.

  • A module with a mix of Verilog and SystemC instances below must be SystemC. (As Verilator cannot connect to lower-level SystemC instances.)

  • A module with only Verilog instances below can be either, but for best performance should be Verilog. (The exception is if you have a design that is instantiated many times; in this case, Verilating one of the lower modules and instantiating that Verilated instances multiple times into a SystemC module may be faster.)