Free Tools · Full Workflow

Open-Source EDA Tools

The complete free VLSI toolchain — from your first RTL file to a verified, synthesised netlist. Git, iverilog, GTKWave, Verilator, cocotb, Yosys, and SymbiYosys — every tool explained with real commands.

📁 Git
✏️ Write RTL
⚙️ iverilog
📊 GTKWave
🚀 Verilator
🐍 cocotb
🔧 Yosys
✅ SymbiYosys
Toolchain Overview
What Each Tool Does
#ToolCategoryWhat It DoesInstall
1GitVersion ControlTrack RTL changes, branches, collaboration — the backbone of every serious projectgit-scm.com
2Icarus Verilog (iverilog)SimulatorCompile and run Verilog/SV simulations; dumps VCD waveformsiverilog.icarus.com
3GTKWaveWaveform ViewerOpen VCD/FST files and visualise signal timing — your simulation debuggergtkwave.sourceforge.net
4VerilatorFast SimulatorConverts SV/Verilog to C++ — 10–100× faster than iverilog; ideal for large designs and CIverilator.org
5cocotbVerification FrameworkPython-based testbench — write UVM-equivalent tests in Python with full regression supportcocotb.org
6YosysSynthesisRTL synthesis: read Verilog → optimise → map to cells → write netlistyosyshq.net
7SymbiYosys (sby)Formal VerificationProves SVA properties correct using open-source SMT solvers; finds bugs simulation missessymbiyosys.readthedocs.io
+SlangLinter / LSPSystemVerilog language server — real-time lint in VS Code as you typesv-lang.com
📁
Step 1 — Git: Version Control for RTL
Track every change to your Verilog files. Branch freely. Never lose work. Collaborate on IP without overwriting each other.

Install Git

Ubuntu / Debian
sudo apt update && sudo apt install git -y
macOS
brew install git
Windows
# Download Git for Windows: https://git-scm.com/download/win
# Or via winget:
winget install --id Git.Git

Repository Structure for an IP Project

Shellproject layout
my-dma-ip/
├── rtl/                  # Synthesisable RTL source
│   ├── axi4_dma_top.sv
│   ├── axi4_dma_engine.sv
│   └── axi4_dma_irq.sv
├── tb/                   # Testbenches (not shipped to customer)
│   ├── tb_top.sv
│   └── test_m2m.sv
├── cocotb/               # Python testbenches
│   ├── Makefile
│   └── test_dma.py
├── formal/               # SymbiYosys property files
│   └── dma_props.sby
├── synth/                # Synthesis scripts
│   └── synth.tcl
├── docs/                 # Datasheet, app notes
│   └── datasheet.pdf
├── .gitignore
└── README.md

Essential Git Commands for RTL Work

Shell
# Initialise a new IP repo
git init my-dma-ip && cd my-dma-ip
git remote add origin https://github.com/yourname/my-dma-ip.git

# Daily workflow
git status                        # see what changed
git diff rtl/axi4_dma_engine.sv  # see exact line changes
git add rtl/axi4_dma_engine.sv   # stage specific file (not git add .)
git commit -m "fix: AXI burst length calculation for 128-bit mode"
git push

# Feature branch — never work directly on main
git checkout -b feature/scatter-gather
# ... make changes, test ...
git checkout main
git merge feature/scatter-gather

# Tag a release for customer delivery
git tag -a v1.2.0 -m "AXI4-DMA v1.2.0 — adds scatter-gather, 128-bit support"
git push origin v1.2.0

# .gitignore — exclude simulation artifacts
echo "*.vcd
*.fst
*.log
obj_dir/
__pycache__/
*.pyc" > .gitignore
RTL Git tip: Never commit generated files (VCD waveforms, synthesis outputs, simulation logs). They're large, change every run, and create diff noise. Commit only source files that a human wrote.
⚙️
Step 2 — Icarus Verilog: Compile & Simulate
The classic free Verilog/SystemVerilog simulator. Write a testbench, compile, run, get a VCD waveform file.

Install iverilog

Ubuntu / Debian
sudo apt install iverilog -y
macOS
brew install icarus-verilog
Windows (MSYS2)
pacman -S mingw-w64-x86_64-iverilog

Write RTL — A Simple Counter

SystemVerilogrtl/counter.sv
// 8-bit up counter with synchronous reset
module counter #(
  parameter int WIDTH = 8
)(
  input  logic             clk,
  input  logic             rst_n,    // active-low reset
  input  logic             en,       // count enable
  output logic [WIDTH-1:0] count,
  output logic             overflow  // pulses for 1 cycle on wrap
);
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      count    <= '0;
      overflow <= 1'b0;
    end else if (en) begin
      {overflow, count} <= count + 1'b1;
    end else begin
      overflow <= 1'b0;
    end
  end
endmodule

Write a Testbench with VCD Dump

Verilogtb/tb_counter.v
`timescale 1ns/1ps

module tb_counter;
  // DUT signals
  logic       clk = 0;
  logic       rst_n, en;
  logic [7:0] count;
  logic       overflow;

  // Clock: 10ns period (100 MHz)
  always #5 clk = ~clk;

  // Instantiate DUT
  counter #(.WIDTH(8)) dut (
    .clk(clk), .rst_n(rst_n), .en(en),
    .count(count), .overflow(overflow)
  );

  // VCD dump — opens in GTKWave
  initial begin
    $dumpfile("waves/counter.vcd");
    $dumpvars(0, tb_counter);
  end

  // Stimulus
  initial begin
    rst_n = 0; en = 0;
    repeat(3) @(posedge clk);  // hold reset for 3 cycles
    rst_n = 1;

    // Count up from 0
    en = 1;
    repeat(300) @(posedge clk);   // watch overflow at 255→0

    // Pause counting
    en = 0;
    repeat(10) @(posedge clk);

    // Resume
    en = 1;
    repeat(50) @(posedge clk);

    $display("SIMULATION DONE — open waves/counter.vcd in GTKWave");
    $finish;
  end

  // Self-check: catch X state on count
  always @(posedge clk) begin
    if (rst_n && ^count === 1'bx)
      $error("X-state detected on count at time %0t", $time);
  end
endmodule

Compile and Run

Shell
# Create output directory
mkdir -p waves

# Compile RTL + TB into a simulation binary
iverilog -g2012 -o sim.out rtl/counter.sv tb/tb_counter.v

# Run the simulation
vvp sim.out

# Output:
# SIMULATION DONE — open waves/counter.vcd in GTKWave

# Common flags:
#  -g2012    : enable SystemVerilog-2012 features (always_ff, logic, etc.)
#  -Wall     : enable all warnings
#  -I rtl/   : add include path for `include files
#  -D VERBOSE: define a preprocessor macro

# With multiple RTL files:
iverilog -g2012 -o sim.out \
  rtl/counter.sv \
  rtl/another_module.sv \
  tb/tb_counter.v
Quick debug tip: If you see "noop" or unexpected zeros, add $monitor("%0t count=%0d overflow=%b", $time, count, overflow); inside your testbench initial block. It prints every time a signal changes — faster than opening GTKWave for a quick sanity check.
📊
Step 3 — GTKWave: See Your Signals
Open the VCD waveform file from your iverilog simulation and visually debug signal timing, state machines, and protocol handshakes.

Install GTKWave

Ubuntu / Debian
sudo apt install gtkwave -y
macOS
brew install --cask gtkwave
Windows
# Download installer from: https://gtkwave.sourceforge.net/
# Or via MSYS2: pacman -S mingw-w64-x86_64-gtkwave

Open a VCD File

Shell
# Open the VCD file directly
gtkwave waves/counter.vcd

# Or open with a saved signal layout (.gtkw file):
gtkwave waves/counter.vcd --rcvar "do_initial_zoom_fit yes"

GTKWave Key Workflow

ActionHow ToShortcut
Add signals to viewerLeft panel: expand hierarchy → double-click signal name (or drag to wave area)Double-click
Zoom to fit all timeView → Zoom → Best FitCtrl+Shift+F
Zoom in / outScroll wheel or + / − keys+ / −
Move cursor to timeClick anywhere on the waveform areaClick
Show value at cursorSignal value shown in left panel next to signal name
Search for edgeEdit → Find Next Edge / Find Previous EdgeCtrl+N / Ctrl+B
Display as hex/binary/decimalRight-click signal → Data Format → Hex / Binary / Decimal
Save signal layoutFile → Write Save File → saves .gtkw to reload next timeCtrl+S
Add markerClick to set cursor, then Markers → Add
Faster format: FSTReplace $dumpfile(.vcd) with $dumpfile(.fst) and use -DFST flagiverilog -DFST

Use FST Instead of VCD (Much Faster for Big Sims)

Verilogtestbench change
// In your testbench — use FST for 5–10× smaller files
initial begin
  $dumpfile("waves/counter.fst");
  $dumpvars(0, tb_counter);
end

// Then compile with: iverilog -g2012 -DFST -o sim.out rtl/counter.sv tb/tb_counter.v
// gtkwave handles both .vcd and .fst natively
GTKWave pro tip: Save your signal layout as waves/counter.gtkw and commit it to Git. Your team can open the exact same view with gtkwave waves/counter.vcd waves/counter.gtkw.
🚀
Step 4 — Verilator: Fast Cycle-Accurate Simulation
Converts Verilog/SV to C++, then compiles to a native binary. 10–100× faster than iverilog — essential for large designs, regression runs, and cocotb.

Install Verilator

Ubuntu / Debian
sudo apt install verilator -y
# Or build latest from source for newest SV features:
git clone https://github.com/verilator/verilator
cd verilator && autoconf && ./configure && make -j$(nproc) && sudo make install
macOS
brew install verilator

Lint Your RTL First

Shell
# Run Verilator as a linter — catches mistakes before simulation
verilator --lint-only -Wall rtl/counter.sv

# Common lint warnings to fix immediately:
#   UNUSED     — declared but never used signal (often a typo)
#   UNDRIVEN   — signal never assigned (bug — will be X in sim)
#   WIDTH      — mismatched bus widths in assignment
#   CASEINCOMPLETE — case statement missing values (FSM holes)
#   LATCH      — unintended latch inferred from combinational block

# Suppress a specific warning when intentional:
verilator --lint-only -Wall -Wno-UNUSED rtl/counter.sv

Simulate with a C++ Wrapper

C++tb/sim_main.cpp
#include "Vcounter.h"        // Verilator auto-generates this
#include "verilated.h"
#include "verilated_vcd_c.h"

int main(int argc, char **argv) {
    Verilated::commandArgs(argc, argv);
    Vcounter *dut = new Vcounter;

    // VCD tracing
    Verilated::traceEverOn(true);
    VerilatedVcdC *tfp = new VerilatedVcdC;
    dut->trace(tfp, 99);
    tfp->open("waves/counter.vcd");

    // Reset
    dut->rst_n = 0; dut->en = 0; dut->clk = 0;
    for (int i = 0; i < 6; i++) {
        dut->clk = !dut->clk;
        dut->eval();
        tfp->dump(i * 5);
    }
    dut->rst_n = 1;

    // Run for 1000 clock cycles
    uint64_t t = 30;
    dut->en = 1;
    for (int i = 0; i < 2000; i++) {
        dut->clk = !dut->clk;
        dut->eval();
        tfp->dump(t);
        t += 5;
        // Simple self-check
        if (dut->clk && dut->overflow)
            printf("Overflow at cycle %d, count=%d\n", i/2, dut->count);
    }

    tfp->close();
    delete dut;
    printf("Simulation done. Open waves/counter.vcd in GTKWave.\n");
    return 0;
}
Shellcompile and run
mkdir -p waves

# Step 1: Verilator builds C++ from the RTL
verilator --cc --trace -Wall rtl/counter.sv --exe tb/sim_main.cpp

# Step 2: Compile the generated C++ to a fast binary
make -C obj_dir -f Vcounter.mk Vcounter -j$(nproc)

# Step 3: Run
./obj_dir/Vcounter
# Output: Overflow at cycle 127, count=0
#         Overflow at cycle 383, count=0  (etc.)
#         Simulation done. Open waves/counter.vcd in GTKWave.
🐍
Step 5 — cocotb: Python Testbenches
Write testbenches in Python — use asyncio coroutines, numpy for data, standard Python libraries for anything. Works with iverilog, Verilator, and commercial simulators.

Install cocotb

pip (all platforms)
pip install cocotb cocotb-bus
# For the cocotbext-* protocol libraries:
pip install cocotbext-axi cocotbext-uart cocotbext-i2c

Python Testbench for the Counter

Pythoncocotb/test_counter.py
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge, Timer, FallingEdge
from cocotb.result import TestFailure

@cocotb.test()
async def test_reset_clears_count(dut):
    """Count must be 0 after reset, regardless of any prior state."""
    clock = Clock(dut.clk, 10, units="ns")  # 100 MHz
    cocotb.start_soon(clock.start())

    dut.rst_n.value = 0
    dut.en.value = 0
    await Timer(50, units="ns")
    await RisingEdge(dut.clk)

    assert dut.count.value == 0, f"Expected 0 after reset, got {dut.count.value}"
    dut._log.info("PASS: reset test")

@cocotb.test()
async def test_count_increments(dut):
    """Counter increments by 1 each enabled clock cycle."""
    clock = Clock(dut.clk, 10, units="ns")
    cocotb.start_soon(clock.start())

    dut.rst_n.value = 0
    await Timer(30, units="ns")
    dut.rst_n.value = 1
    dut.en.value = 1

    for expected in range(1, 20):
        await RisingEdge(dut.clk)
        await FallingEdge(dut.clk)  # sample after clock edge settles
        actual = int(dut.count.value)
        assert actual == expected, f"Cycle {expected}: expected {expected} got {actual}"

    dut._log.info("PASS: increment test (20 cycles)")

@cocotb.test()
async def test_overflow_flag(dut):
    """Overflow must pulse exactly at 255→0 wrap."""
    clock = Clock(dut.clk, 10, units="ns")
    cocotb.start_soon(clock.start())

    dut.rst_n.value = 0
    await Timer(30, units="ns")
    dut.rst_n.value = 1
    dut.en.value = 1

    # Fast-forward to just before overflow
    for _ in range(254):
        await RisingEdge(dut.clk)

    await RisingEdge(dut.clk)  # cycle 255 → overflow
    await FallingEdge(dut.clk)
    assert dut.overflow.value == 1, "Expected overflow=1 at wrap"

    await RisingEdge(dut.clk)  # next cycle — overflow should clear
    await FallingEdge(dut.clk)
    assert dut.overflow.value == 0, "Expected overflow=0 after wrap cycle"

    dut._log.info("PASS: overflow flag test")

@cocotb.test()
async def test_enable_holds_count(dut):
    """Count must not change when en=0."""
    clock = Clock(dut.clk, 10, units="ns")
    cocotb.start_soon(clock.start())

    dut.rst_n.value = 0
    await Timer(30, units="ns")
    dut.rst_n.value = 1
    dut.en.value = 1

    # Count up to 50
    for _ in range(50):
        await RisingEdge(dut.clk)

    # Pause
    dut.en.value = 0
    frozen_count = int(dut.count.value)
    for _ in range(20):
        await RisingEdge(dut.clk)
        assert int(dut.count.value) == frozen_count, "Count changed while en=0!"

    dut._log.info(f"PASS: enable hold test (count frozen at {frozen_count})")

Makefile to Run cocotb

Makefilecocotb/Makefile
SIM       ?= icarus          # or: verilator, vcs, xcelium
TOPLEVEL_LANG ?= verilog

VERILOG_SOURCES  = $(PWD)/../rtl/counter.sv
TOPLEVEL         = counter
MODULE           = test_counter

include $(shell cocotb-config --makefiles)/Makefile.sim
Shellrun tests
cd cocotb

# Run all tests with Icarus Verilog backend
make SIM=icarus

# Run with Verilator (faster for large designs)
make SIM=verilator

# Run a specific test only
make SIM=icarus TESTCASE=test_overflow_flag

# Output (all passing):
# test_reset_clears_count           PASS
# test_count_increments             PASS
# test_overflow_flag                PASS
# test_enable_holds_count           PASS
# --- 4 passed in 0.82s ---
🔧
Step 6 — Yosys: RTL Synthesis
Reads Verilog/SV, applies synthesis transformations (optimise, map to gates), and writes a gate-level netlist. Also the engine under SymbiYosys formal verification.

Install Yosys

Ubuntu / Debian
sudo apt install yosys -y
# Or latest from YosysHQ OSS CAD Suite (recommended):
# https://github.com/YosysHQ/oss-cad-suite-build/releases
macOS
brew install yosys

Interactive Mode — Understand Your Design

Yosys Interactive
# Launch yosys interactive shell
yosys

# Inside yosys shell:
read_verilog -sv rtl/counter.sv    # read the RTL
hierarchy -check -top counter      # set top module, check hierarchy
proc                               # convert always blocks to netlists
opt                                # basic optimisation pass
stat                               # print gate count
show                               # open a graphical view (requires xdot)
exit

Synthesis Script (Non-Interactive)

Tclsynth/synth_counter.tcl
# Full synthesis script for the counter
yosys -import

# 1. Read RTL
read_verilog -sv ../rtl/counter.sv

# 2. Set top module and check
hierarchy -check -top counter

# 3. Run full synthesis (generic cells)
synth -top counter

# 4. Print statistics — gate count, flip-flop count, memory
stat

# 5. Write output netlist
write_verilog -noattr synth_out/counter_netlist.v

# To target Sky130 standard cells:
# read_liberty -lib /path/to/sky130_fd_sc_hd__tt_025C_1v80.lib
# abc -liberty  /path/to/sky130_fd_sc_hd__tt_025C_1v80.lib
# write_verilog -noattr synth_out/counter_sky130.v
Shellrun synthesis
mkdir -p synth_out

# Run the script
yosys synth/synth_counter.tcl

# Expected stat output (generic cells):
# === counter ===
#    Number of wires:              12
#    Number of cells:              11
#      $_DFF_PP0_                   9    ← 9 flip-flops (8-bit count + overflow)
#      $_NOT_                       1
#      $_XOR_                       1
#    Number of cells (excluding ...): 11
Yosys tip: Run yosys -p "synth; stat" rtl/counter.sv as a one-liner to quickly check gate count without a script file. Add this to your CI as a sanity check that gate count doesn't blow up unexpectedly.
Step 7 — SymbiYosys: Formal Verification
Prove your RTL correct using SVA properties and open-source SMT solvers. Catches bugs that thousands of simulation cycles miss — because it checks ALL possible inputs simultaneously.

Install SymbiYosys

Ubuntu / Debian (easiest)
# Install via YosysHQ OSS CAD Suite — includes sby + all solvers
curl -L https://github.com/YosysHQ/oss-cad-suite-build/releases/latest/download/oss-cad-suite-linux-x64-latest.tgz | tar xz
export PATH=$PWD/oss-cad-suite/bin:$PATH
# Now sby, yosys, verilator, nextpnr are all available

Add SVA Properties to the RTL

SystemVerilogrtl/counter_props.sv
// Formal properties — compiled only during formal flow, not synthesis
`ifdef FORMAL

  // 1. After reset, count must be zero
  prop_reset_zero: assert property (
    @(posedge clk) !rst_n |=> (count == '0)
  );

  // 2. When disabled, count must never change
  prop_no_count_when_disabled: assert property (
    @(posedge clk) disable iff (!rst_n)
    !en |=> $stable(count)
  );

  // 3. Overflow must only pulse when count wraps 255→0
  prop_overflow_only_on_wrap: assert property (
    @(posedge clk) disable iff (!rst_n)
    overflow |-> ($past(count) == 8'hFF && en)
  );

  // 4. Count must never be X while out of reset
  prop_no_x: assert property (
    @(posedge clk) rst_n |-> !$isunknown(count)
  );

  // Cover: make sure count actually reaches 255 (reachability)
  cov_max_count: cover property (
    @(posedge clk) count == 8'hFF
  );

`endif

SymbiYosys Configuration File

INIformal/counter.sby
[options]
mode prove         # prove assertions hold for all time (unbounded)
# mode bmc         # bounded model check: try to find bug within N cycles
# depth 30         # number of steps for bmc mode

[engines]
smtbmc boolector   # use Boolector SMT solver (fast for bit-vector problems)
# smtbmc z3       # Z3 solver — more powerful but slower
# aiger avy       # for sequential miter checks

[script]
read -formal rtl/counter.sv
read -formal rtl/counter_props.sv
prep -top counter

[files]
rtl/counter.sv
rtl/counter_props.sv
Shellrun formal verification
# Run formal proof
sby -f formal/counter.sby

# Successful output:
# [prop_reset_zero]             PROVED (depth 2)
# [prop_no_count_when_disabled] PROVED (depth 5)
# [prop_overflow_only_on_wrap]  PROVED (depth 258)
# [prop_no_x]                   PROVED (depth 1)
# [cov_max_count]               COVERED (in 256 steps)
# SBY ... DONE (PASS)

# If a property FAILS, sby creates a counterexample VCD:
# gtkwave formal/counter/engine_0/trace.vcd
Why formal beats simulation: Simulation tests specific inputs you thought of. Formal verification tests every possible input at every possible time simultaneously. The overflow property above — "overflow only when count=255 and en=1" — would take 4 billion random test cases to cover exhaustively by simulation. SymbiYosys proves it in seconds.
Bringing It Together
GitHub Actions CI Pipeline

Wire the entire toolchain into a CI pipeline. Every push automatically lints, simulates, and formally verifies your RTL. This is the quality signal that makes customers trust your IP.

YAML.github/workflows/rtl-ci.yml
name: RTL Verification CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  lint:
    name: Verilator Lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install Verilator
        run: sudo apt-get install -y verilator
      - name: Lint RTL
        run: verilator --lint-only -Wall rtl/counter.sv

  simulate-iverilog:
    name: iverilog Simulation
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install iverilog
        run: sudo apt-get install -y iverilog
      - name: Compile and simulate
        run: |
          mkdir -p waves
          iverilog -g2012 -o sim.out rtl/counter.sv tb/tb_counter.v
          vvp sim.out

  cocotb-tests:
    name: cocotb Regression
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      - name: Install deps
        run: pip install cocotb iverilog
      - name: Install iverilog (system)
        run: sudo apt-get install -y iverilog
      - name: Run cocotb tests
        run: make SIM=icarus
        working-directory: cocotb

  synthesise:
    name: Yosys Synthesis (Gate Count)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install Yosys
        run: sudo apt-get install -y yosys
      - name: Synthesise
        run: |
          mkdir -p synth_out
          yosys synth/synth_counter.tcl

  formal-verify:
    name: SymbiYosys Formal Proof
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install OSS CAD Suite
        run: |
          curl -L https://github.com/YosysHQ/oss-cad-suite-build/releases/latest/download/oss-cad-suite-linux-x64-latest.tgz | tar xz -C $HOME
          echo "$HOME/oss-cad-suite/bin" >> $GITHUB_PATH
      - name: Run formal verification
        run: sby -f formal/counter.sby
Quick Reference
Every Command You Need
What You WantCommand
Initialize a Git repogit init && git remote add origin URL
Stage and commitgit add rtl/myfile.sv && git commit -m "fix: ..."
Compile with iverilogiverilog -g2012 -o sim.out rtl/design.sv tb/tb.v && vvp sim.out
Open waveformsgtkwave waves/output.vcd
Lint with Verilatorverilator --lint-only -Wall rtl/design.sv
Build Verilator simverilator --cc --trace -Wall rtl/design.sv --exe tb/main.cpp && make -C obj_dir -f Vdesign.mk
Run cocotb testsmake SIM=icarus (in cocotb/ dir with Makefile)
Quick Yosys gate countyosys -p "synth; stat" rtl/design.sv
Run formal proofsby -f formal/design.sby
View formal counterexamplegtkwave formal/design/engine_0/trace.vcd
Install everything (Ubuntu)sudo apt install git iverilog gtkwave verilator yosys

The Open-Source EDA Revolution — Why This Matters for Engineers

Until recently, doing professional-grade VLSI work required expensive licences for Synopsys VCS, Mentor ModelSim, or Cadence NC-Sim — tools that cost tens of thousands of dollars per seat per year. A student or independent engineer simply could not access the same quality of tools used in production silicon development. That era is over.

The tools described on this page — iverilog, Verilator, GTKWave, cocotb, Yosys, and SymbiYosys — are not toys. Verilator is used inside Google, Tesla, and numerous semiconductor companies for RTL simulation at scale. Yosys powers the synthesis in hundreds of academic and commercial tape-outs. SymbiYosys catches bugs that escape multi-million-cycle simulation suites. And cocotb has been adopted by major IP vendors and EDA companies because Python testbenches are genuinely more productive than UVM for many verification tasks.

How to use this as a learning path

Start with iverilog and GTKWave — they have the simplest setup and the most immediate visual feedback. Write a counter, a FIFO, an FSM. Simulate it, see the waveforms, fix bugs. This builds the fundamental skill of reading waveforms and tracing RTL behaviour.

Once comfortable, add Verilator for lint checking — it catches RTL mistakes that iverilog silently ignores. Then move to cocotb to replace your Verilog testbenches with Python: you gain access to all Python libraries for generating test vectors, checking outputs, and automating test sequences.

Yosys and SymbiYosys are the professional finishing touch. Synthesising your design with Yosys tells you the real gate count and catches constructs that won't survive commercial synthesis. SymbiYosys proves your design correct mathematically — a capability that was previously available only to engineers at large companies with formal verification budgets. Today, you can do the same from your laptop, for free.