Skip to content

Tool Setup

QuestaSim, VCS, Xcelium, Verilator, EDA Playground, VS Code, GTKWave — install and first run.

Module 1 · Page 1.3 · Fundamentals

Picking Your Starting Point

The fastest path to running your first SystemVerilog simulation is a browser. No installation, no licensing, no configuration — just code and results. But at some point you'll need a local environment, and at some point after that you'll be working with professional tools on a real project. This section covers all three stages: zero-install online simulation, local free tools, and the commercial workflow used at semiconductor companies.

One important mindset: don't get attached to a specific simulator's flags and workflow. The SystemVerilog language is standardized — your code runs on QuestaSim, VCS, Xcelium, or Verilator with minimal changes. Learn the language. The tool details are something you can pick up in a day on the job.

The Simulators — Know Your Options

🌐EDA Playground OnlineFree Tier The fastest way to run SystemVerilog without installing anything. Browser-based access to real commercial simulators including Aldec Riviera-PRO, Synopsys VCS, and Cadence Xcelium. Share code via URL. Perfect for learning, quick experiments, and following along with any tutorial. URL: edaplayground.comOS: Any browserSV support: Full (via commercial backends)UVM: Yes🔷Icarus Verilog Free / Open Source The most popular free local simulator. Handles Verilog and a good subset of SystemVerilog. Not a commercial-grade tool — missing some advanced SV features like full OOP and UVM — but excellent for learning data types, always blocks, modules, and basic testbenches. Pairs with GTKWave for waveform viewing. Install:apt install iverilog (Linux)OS: Linux, Mac, WindowsSV support: Partial (good for basics)UVM: No⚡Verilator Free / Open Source Converts synthesizable Verilog/SV to C++ and compiles it for near-native execution speed. The fastest open-source simulator by a large margin — used for hardware-software co-simulation, CI/CD pipelines, and large RTL regression tests. Critical limitation: only supports synthesizable RTL. No dynamic classes, no randomization, no full testbench SV. Install:apt install verilatorOS: Linux, MacSV support: Synthesizable RTL onlyUse case: RTL unit testing, FPGA flows, CI🟦QuestaSim / ModelSim CommercialFree Starter Siemens EDA's flagship simulator. QuestaSim is the full ASIC/verification edition; ModelSim is the FPGA edition. Supports complete SystemVerilog including OOP, UVM, SVA, and all verification features. Questa Starter Edition is available free for students (with capacity limits). The go-to simulator in the Mentor/Siemens ecosystem. Website: eda.sw.siemens.comOS: Linux (primary), WindowsSV support: CompleteUVM: Full support🔴VCS — Verilog Compiled Simulator Commercial (Synopsys) Synopsys's industry-leading simulator. Known for the fastest compile-simulate cycle on large SoC testbenches. Used at virtually every major semiconductor company. Tight integration with Synopsys's RTL sign-off and CDC/lint tools. License-only — no free tier. If you're starting at an Intel, Qualcomm, Apple, or similar company, VCS will likely be your day-one tool. Vendor: SynopsysOS: LinuxSV support: CompleteCompile:vcs -sverilog🟢Xcelium Commercial (Cadence) Cadence's parallel simulation engine. Successor to Incisive/IES. Supports parallel execution across CPU cores for significant speedup on large designs. Deep integration with Cadence's JasperGold formal, Genus synthesis, and Innovus physical design. Used heavily in companies with an all-Cadence flow. Vendor: CadenceOS: LinuxSV support: CompleteCompile:xrun

SimulatorCostFull SV + UVM?Best forOS
EDA PlaygroundFree (online)Yes (via backends)Learning, sharing, zero-installBrowser
Icarus VerilogFreePartialLocal basics, beginner projectsAll
VerilatorFreeRTL onlyFast RTL tests, CI/CD, FPGALinux/Mac
QuestaSim StarterFree (limited)YesStudents, full SV/UVM learningLinux/Win
VCSCommercialYesLarge ASIC SoC teamsLinux
XceliumCommercialYesCadence ecosystem teamsLinux

Path 1 — Zero Install: EDA Playground

EDA Playground is the fastest way to run SystemVerilog code right now. Open a browser, go to edaplayground.com, and you can have a simulation running in 2 minutes. No sign-up required for basic use, though creating a free account lets you save your designs.

  1. Go to edaplayground.com — No installation needed. Works on any browser on any device.
  2. Select your simulator — Under "Tools & Simulators" in the left panel, choose Aldec Riviera-PRO 2023 or Cadence Xcelium for full SystemVerilog support. Add +access+r to enable waveform dumping.
  3. Write your code — Two editor panes: "design" (your RTL/DUT) and "testbench". Paste your SystemVerilog code in the appropriate pane.
  4. Click Run — The simulator compiles and runs. Output appears in the log pane on the right. If you added waveform dumping, an EPWave button appears to view signals.
  5. Share your design — Save it and share the URL. Great for asking questions, submitting assignments, or demonstrating bugs to colleagues.
EDA Playground — Waveform Dump Setup
// Add this to your testbench initial block for waveform viewing in EPWave:
`timescale 1ns/1ps
 
module tb_with_waves;
 
logic       clk = 0;
logic [7:0] count = 0;
 
always #5 clk = ~clk;
always @(posedge clk) count <= count + 1;
 
initial begin
// Dump waveforms — required for EPWave viewer in EDA Playground
$dumpfile("dump.vcd");   // VCD output file
$dumpvars(0, tb_with_waves); // dump all signals in this module and below
 
#100;
$display("Final count = %0d", count);
$finish;
end
 
endmodule

Path 2 — Local Free Setup: Icarus + GTKWave + VS Code

For a local environment you own and control, this stack is the fastest to set up and works on all operating systems. Icarus Verilog handles compilation and simulation; GTKWave provides waveform visualization; VS Code with the right extensions gives you syntax highlighting, linting, and navigation.

Installation by Platform

Installation Commands — All Platforms
# ── Ubuntu / Debian Linux ─────────────────────────────────────────
sudo apt update
sudo apt install iverilog gtkwave
iverilog -V   # verify: Icarus Verilog version X.Y.Z
 
# ── macOS (Homebrew) ──────────────────────────────────────────────
brew install icarus-verilog
brew install --cask gtkwave
 
# ── Windows ───────────────────────────────────────────────────────
# Download installer from bleyer.org/icarus
# GTKWave: gtkwave.sourceforge.net
# Both include installers — add to PATH during install
 
# ── VS Code Extensions (all platforms) ───────────────────────────
# Open VS Code → Extensions (Ctrl+Shift+X) → Search and install:
# 1. "SystemVerilog" by eirikpre (syntax highlighting + hover)
# 2. "Verilog-HDL/SystemVerilog/Bluespec SystemVerilog" (linting)
# 3. "GitLens" (if using git for project tracking)

Your First Simulation with Icarus

Icarus Verilog — Compile, Run, View Waves
# Step 1: Save your SystemVerilog file
# File: hello.sv
`timescale 1ns/1ps
module hello;
initial begin
$dumpfile("hello.vcd"); $dumpvars(0, hello);
$display("Hello, SystemVerilog! Time=%0t", $time);
#100; $finish;
end
endmodule
 
# Step 2: Compile
iverilog -g2012 -o hello_sim hello.sv
#         ^---- SystemVerilog mode   ^---- output executable
 
# Step 3: Run simulation
./hello_sim
# Output: Hello, SystemVerilog! Time=0
 
# Step 4: Open waveform (if $dumpfile was used)
gtkwave hello.vcd
 
# ── Common Icarus flags ───────────────────────────────────────────
# -g2012     → enable SystemVerilog (IEEE 1364-2012 subset)
# -g2005-sv  → SV-2005 mode
# -o file    → output executable name
# -Wall      → enable all warnings
# -I dir     → add include directory
# -s modulespecify top-level module
 
# ── Compiling multiple files ──────────────────────────────────────
iverilog -g2012 -o sim design.sv testbench.sv pkg.sv
# Or use a file list:
iverilog -g2012 -o sim -f filelist.f

Path 3 — QuestaSim Starter Edition

For full SystemVerilog including OOP, UVM, and assertions, QuestaSim Starter Edition is the recommended free option. It has capacity limits (maximum design size) but handles all the code in this course and most student/training projects.

  1. Download QuestaSim Starter — Search "Questa Starter Edition" on eda.sw.siemens.com. Requires account registration. Available for Linux and Windows.
  2. Request a free license — The starter edition requires a license file but it's free. Follow the license request process on the Siemens EDA portal. License is node-locked to your machine's host ID.
  3. Set environment variables — Add QUESTA_HOME to your shell profile and add $QUESTA_HOME/bin to your PATH. Also set LM_LICENSE_FILE to point to your license file.
  4. Verify installation — Run vsim -version in terminal. You should see QuestaSim version output.
QuestaSim — Compile and Simulate Workflow
# ── QuestaSim two-step workflow ───────────────────────────────────
 
# Step 1: Create a work library (once per project)
vlib work
 
# Step 2: Compile — vlog compiles SV files into the work library
vlog -sv hello.sv
vlog -sv pkg.sv dut.sv tb.sv   # multiple files
 
# Step 3: Simulate — vsim runs the compiled design
vsim -c hello -do "run -all; quit"
#     -c = command line mode (no GUI)  -do = run script
 
# ── GUI mode (interactive waveform viewer) ─────────────────────────
vsim hello
# Opens QuestaSim GUI — add signals to wave window, run simulation
 
# ── Common vlog flags ─────────────────────────────────────────────
# -sv          → enable SystemVerilog mode
# +incdir+dir  → add include directory
# -work lib    → specify library (default: work)
 
# ── Common vsim flags ─────────────────────────────────────────────
# -c           → command-line mode (no GUI)
# -do "script" → run a TCL script or commands
# +UVM_TESTNAME=test_name → pass test name to UVM
# -coverage    → enable coverage collection

Professional Project Structure

How you organize your project matters from day one. A flat directory with all files dumped together works for two files, not for twenty. Here's the structure that scales from learning projects to real SoC verification environments. my_sv_project/rtl/ # synthesizable RTL filescounter.svfifo.svtb/ # testbench filestb_counter.svtb_top.svpkg/ # shared packages and typesproject_types.svaxi_pkg.svsim/ # simulation run directoryMakefilefilelist.fwaves/ # waveform output (generated)docs/ # design specs, notes

The filelist.f — Compilation Order Matters

SystemVerilog files must be compiled in dependency order — packages before modules that use them, lower-level modules before higher-level instantiators. A filelist.f file specifies this order and keeps your compile command clean.

filelist.f — Compilation Order
// filelist.f — compile order: dependencies first
// Packages must come before any module that imports them
 
+incdir+../pkg         // include directory for header files
 
// Packages first
../pkg/project_types.sv
../pkg/axi_pkg.sv
 
// RTL modules (lower-level first)
../rtl/fifo.sv
../rtl/counter.sv
 
// Testbench components
../tb/tb_counter.sv
../tb/tb_top.sv
 
// Compile with filelist:
// Icarus:   iverilog -g2012 -o sim -f filelist.f
// QuestaSim: vlog -sv -f filelist.f
// VCS:       vcs -sverilog -f filelist.f

The Makefile — Automation From Day One

Typing the same compile and run commands repeatedly is a waste of time and a source of mistakes. A Makefile captures your workflow and lets you run a full simulation with make sim. Industry teams have Makefiles (or equivalent build scripts) for every project.

Makefile — Icarus + QuestaSim Targets
# Makefile for SystemVerilog simulation
# Usage: make sim    (run simulation)
#        make waves  (open GTKWave)
#        make clean  (remove build artifacts)
 
TOP     = tb_top
SRCS    = ../pkg/project_types.sv ../rtl/counter.sv ../tb/$(TOP).sv
IVFLAGS = -g2012 -Wall
 
# ── Icarus Verilog targets ────────────────────────────────────────
.PHONY: sim waves clean
 
sim: compile
./sim_out
 
compile: $(SRCS)
iverilog $(IVFLAGS) -o sim_out $(SRCS)
 
waves:
gtkwave dump.vcd &
 
clean:
rm -f sim_out dump.vcd *.vcd
 
# ── QuestaSim targets (uncomment to use) ─────────────────────────
# questa_sim:
# 	vlib work && vlog -sv -f filelist.f && \
# 	vsim -c $(TOP) -do "run -all; quit"
 
# ── VCS targets (uncomment to use) ───────────────────────────────
# vcs_sim:
# 	vcs -sverilog -f filelist.f -o sim_vcs && ./sim_vcs

VS Code — Your Engineering IDE

VS Code has become the default IDE for engineers who aren't using a full EDA GUI. It's fast, extensible, and the SystemVerilog extensions provide syntax highlighting, hover documentation, and lint integration.

  • eirikpre.systemverilog — Best syntax highlighting for SystemVerilog. Hover documentation for built-in system tasks. Code navigation. The first extension to install.
  • mshr-h.veriloghdl — Integrates iVerilog lint directly in VS Code. Underlines errors as you type. Works with Icarus, Verilator, and HDL syntax checkers.
  • eamodio.gitlens — Git blame, history, and compare in the editor. Useful when working on multi-engineer projects or tracking design changes.
  • Task Runner — Configure VS Code tasks (Ctrl+Shift+B) to run your Makefile targets directly from the editor. No terminal switching needed.
VS Code — tasks.json for Build Integration
// .vscode/tasks.json — run Makefile targets from VS Code
{
"version": "2.0.0",
"tasks": [
{
"label": "Compile & Simulate",
"type": "shell",
"command": "make sim",
"group": { "kind": "build", "isDefault": true },
"problemMatcher": [],
"presentation": { "reveal": "always", "panel": "shared" }
},
{
"label": "Open Waveform",
"type": "shell",
"command": "make waves",
"problemMatcher": []
}
]
}

GTKWave — Free Waveform Viewer

GTKWave reads VCD (Value Change Dump) files generated by your simulation and displays signal waveforms. It's not as polished as commercial waveform viewers like QuestaSim's integrated viewer or Synopsys's DVE, but it's free, it works, and for learning purposes it gives you everything you need.

Generating and Viewing Waveforms
// In your testbench: generate VCD for GTKWave
initial begin
$dumpfile("sim.vcd");        // creates the VCD file
$dumpvars(0, tb_top);        // dump all signals: 0=all levels, tb_top=root
// OR: dump only specific hierarchy level:
$dumpvars(1, tb_top);        // only top-level signals
$dumpvars(0, tb_top.dut);    // DUT and everything below it
end
 
# Open in GTKWave after simulation
gtkwave sim.vcd
 
# GTKWave Quick Reference:
# - Left panel: signal hierarchy tree
# - Drag signals to waveform view to display them
# - Use '+' and '-' keys or scroll to zoom time axis
# - Middle-click on waveform to jump to that time
# - File > Write Save File to save signal selection (.gtkw)
 
# Save and reload signal configuration:
gtkwave sim.vcd config.gtkw

Complete Simulation Workflow

Here's a complete working example that ties everything together — a simple counter DUT, a testbench, and the full workflow to compile, simulate, and view waveforms.

Complete Example — counter.sv (DUT)
// counter.sv — 8-bit up counter with synchronous reset
`timescale 1ns/1ps
 
module counter (
input  logic       clk,
input  logic       rst_n,    // active-low reset
input  logic       en,       // count enable
output logic [7:0] count
);
 
always_ff @(posedge clk) begin
if (!rst_n)
count <= 8'h00;
else if (en)
count <= count + 8'h01;
end
 
endmodule
Complete Example — tb_counter.sv (Testbench)
// tb_counter.sv — testbench for the counter module
`timescale 1ns/1ps
 
module tb_counter;
 
// Signal declarations
logic       clk   = 0;
logic       rst_n = 0;   // start in reset
logic       en    = 0;
logic [7:0] count;
 
// DUT instantiation
counter dut (.*);         // .* connects by name automatically
 
// Clock: 10ns period (100 MHz)
always #5 clk = ~clk;
 
// Waveform dump
initial begin
$dumpfile("waves.vcd");
$dumpvars(0, tb_counter);
end
 
// Test sequence
initial begin
$display("=== Counter Test Start ===");
 
// Apply reset for 2 clocks
rst_n = 0; en = 0;
@(posedge clk); @(posedge clk);
$display("After reset:  count = %0d (expect 0)", count);
 
// Release reset, enable counting
rst_n = 1; en = 1;
repeat(5) @(posedge clk);
$display("After 5 clks: count = %0d (expect 5)", count);
 
// Disable enable — count should hold
en = 0;
@(posedge clk); @(posedge clk);
$display("Enable off:   count = %0d (expect 5)", count);
 
// Re-apply reset
rst_n = 0;
@(posedge clk);
$display("After reset2: count = %0d (expect 0)", count);
 
$display("=== Test Complete ===");
$finish;
end
 
endmodule
Expected Simulation Output
=== Counter Test Start ===
After reset:  count = 0 (expect 0)
After 5 clks: count = 5 (expect 5)
Enable off:   count = 5 (expect 5)
After reset2: count = 0 (expect 0)
=== Test Complete ===
Run Commands — All Three Simulators
# ── Icarus Verilog ─────────────────────────────────────────────────
iverilog -g2012 -o counter_sim counter.sv tb_counter.sv
./counter_sim
gtkwave waves.vcd
 
# ── QuestaSim ─────────────────────────────────────────────────────
vlib work
vlog -sv counter.sv tb_counter.sv
vsim -c tb_counter -do "run -all; quit"
 
# ── VCS ───────────────────────────────────────────────────────────
vcs -sverilog -o counter_sim counter.sv tb_counter.sv
./counter_sim
 
# ── Xcelium ───────────────────────────────────────────────────────
xrun -sv counter.sv tb_counter.sv

Common Setup Errors & Fixes

Error: "module not found" or "undefined module"

Cause: The module being instantiated isn't in the file list, or the files are compiled in the wrong order.

Fix: Ensure all required .sv files are on the compile command line. Compile packages and low-level modules before modules that use them. Check that your module name exactly matches the filename (case-sensitive on Linux).

Warning: "implicit wire" or port direction mismatch

Cause: A signal connected to a port wasn't declared in the testbench, so it got an implicit wire declaration. Or the connected signal's width/type differs from the port.

Fix: Declare all signals explicitly in your testbench. Use -implicit_ports warnings to catch this. In SystemVerilog, declare all ports as logic and ensure widths match.

Simulation runs but produces no output

Cause 1: Missing $display statements. Cause 2: The initial block never executes (check for a combinational loop preventing time advancement). Cause 3: Simulator is waiting at an @(signal) that never changes value.

Fix: Add $display("TB start %0t", $time) as the very first line of your initial block. If that doesn't print, something is wrong before time 0 starts.

Simulation hangs / never reaches $finish

Most common causes: (1) An always block with no delay or sensitivity list — zero-time loop. (2) A wait(signal) where the signal never becomes true. (3) A fork with no join condition met. (4) Deadlock between two processes waiting for each other.

Fix: Add a global timeout: initial #1_000_000 $fatal(1, "SIMULATION TIMEOUT"). Then find where time stops progressing in the waveform.

GTKWave shows no signals or empty file

Cause: The VCD file wasn't generated — either $dumpfile/$dumpvars was missing, or the simulation crashed before reaching those lines, or the simulator doesn't support VCD output.

Fix: Verify the VCD file exists and has non-zero size. Put $dumpfile/$dumpvars as the very first statements in your initial block, before any clock waits.

Interview Questions

Q1: What are the three phases of SystemVerilog simulation, and what can go wrong in each?

Compilation: Source files are parsed, syntax checked, and types resolved. Errors: syntax mistakes, undefined identifiers, type mismatches. Elaboration: Design hierarchy is built, parameters resolved, port connections verified. Errors: width mismatches, missing modules, unresolved parameters. Simulation: Event-driven execution proceeds. Errors: X-propagation from uninitialized signals, zero-time feedback loops, $finish never reached, race conditions.

Q2: What is a VCD file and how is it generated?

VCD (Value Change Dump) is a standard text format for recording signal value changes during simulation. Generated by adding $dumpfile("output.vcd") to specify the output filename and $dumpvars(depth, scope) to specify which signals to capture. The depth (0=all levels, 1=current module only, N=N levels deep) controls how much hierarchy is captured. VCD files are read by waveform viewers like GTKWave. For large designs, targeted VCD dumping is essential to avoid gigabyte-sized files.

Q3: What does the . port connection syntax do in SystemVerilog?*

.* (implicit port connections by name) automatically connects module ports to signals in the instantiating scope that have exactly matching names and compatible types. So counter dut (.*) connects all of dut's ports to same-named signals in the testbench. This eliminates verbose port lists for testbench instantiation. Important limitation: if any port needs a different connection (e.g., connecting a signal with a different name), you mix explicit connections: counter dut (.clk(sys_clk), .*); — explicit connections take priority.

Summary

You now have a complete picture of the SystemVerilog simulation environment: from zero-install online simulation through local free tools to professional commercial simulators. The most important thing to take from this section is not the specific commands — those you can look up — but the mental model: write code, compile, simulate, view waveforms, fix bugs, repeat. That cycle is the same regardless of which simulator you're using.