RouteRTL — First Steps Tutorial
A hands-on, guided walkthrough for your very first day with RouteRTL. By the end you'll have created a project, run a simulation, explored your source tree, and generated a schematic — all from the terminal.
This tutorial is designed to be followed from top to bottom in a single sitting (~20 minutes). Each step ends with a ✅ checkpoint so you know you're on the right track.
0. What You Need
For full platform-specific installation instructions (Linux, WSL2, macOS), see the Installation Guide.
| Tool | Install |
|---|---|
| RouteRTL | pip install routertl |
| Python 3.10+ | sudo apt install python3 python3-pip python3-venv |
| Make | sudo apt install build-essential |
| Git | sudo apt install git |
| NVC | sudo apt install nvc (Ubuntu 24.04+) or build from source (22.04) |
You do not need Vivado or Quartus to try RouteRTL. The open-source simulator is enough for simulation and verification. FPGA vendor tools are only needed when you're ready to synthesize.
1. Create Your Project
# Create a fresh project directory
mkdir my_first_fpga && cd my_first_fpga
git init
# Install RouteRTL
pip install routertl
# Initialize the project
routertl init
Want a self-contained project without pulling IP? Use a template:
routertl init --template blinkyThis scaffolds a working project with anedge_counterVHDL entity and a passing cocotb test — ready to simulate immediately. Jump straight to Step 5: Lint Your Design.
The wizard will ask you a series of questions — press Enter to accept the defaults shown in brackets:
Project Name [my_fpga_project]: my_first_fpga Top Module Name [my_first_fpga_top]: Vendor (xilinx/intel/...) [xilinx]: FPGA Part [xc7z020clg400-1]: Source Directory [src]: Simulation Directory [sim]: Constraints Directory [xdc]: Verification Directory [verif]: CI/CD Platform (github/gitlab/bitbucket/none) [github]: none Does this project include embedded Linux? (y/n) [n]:
HDL Language is automatically set to
vhdlby default. To use SystemVerilog instead, pass--language systemverilogtorr init. The language is validated against the top module file extension at build time — RouteRTL handles mixed-language projects.
✅ Checkpoint: You should see ✅ Project initialized successfully!
and a directory tree like this:
my_first_fpga/ ├── project.yml ← Your project configuration ├── Makefile ← Build entry point (auto-finds SDK) ├── src/ ← RTL source files ├── sim/cocotb/tests/ ← Testbenches go here └── .venv/ ← Python env with routertl CLI
2. Activate the Environment
routertl init already created a .venv/ virtual environment and
installed all dependencies. This is a private Python environment
isolated from your system — RouteRTL uses it so that SDK tools and
versions never clash with other projects on your machine.
Activate it:
source .venv/bin/activate
✅ Checkpoint: Type routertl --help — you should see the full
command menu with groups like 🧪 Verification, 🔨 Build, and 📊 Reporting.
3. Check Your Environment
routertl doctor
This runs a health check on your system. You'll see green ✅ for tools that are installed and yellow ⚠️ for optional tools that are missing:
[✅] Python 3.10.12 [✅] make (GNU Make 4.3) [✅] nvc 1.14.2 [⚠️] vivado — not found (optional for synthesis) [✅] project.yml is valid
✅ Checkpoint: At minimum, Python, Make, and one simulator should show green.
4. Pull Your First IP
Instead of writing RTL from scratch, let's pull a production-quality IP block from the open-logic library using RouteRTL's built-in package manager.
First, discover what's available:
rr pkg search fifo
📦 IP Package Search: "fifo" open-logic/olo_base_fifo_sync Synchronous FIFO (single clock domain) open-logic/olo_base_fifo_async Asynchronous FIFO (clock domain crossing) Add with: rr pkg add <namespace>/<name>
Add the synchronous FIFO to your project:
rr pkg add open-logic/olo_base_fifo_sync
This updates your project.yml with the dependency and installs the
IP source into libs/. You'll see:
📦 Added open-logic/olo_base_fifo_sync (^2.5.0) Resolving dependencies... Installed 2 packages (olo_base_fifo_sync, olo_base_ram_sdp) Lock file written: ip.lock
The lock file (
ip.lock) pins exact versions for reproducible builds — commit it to git, just like you would apackage-lock.json.
Now tell the SDK about the new sources:
routertl workspace update --src
Inspect the entity that was pulled:
routertl info olo_base_fifo_sync
The SDK parsed the VHDL, extracted every port and generic, and mapped dependencies — all from a single command. This is what powers auto-generated tests, dependency graphs, and schematics.
✅ Checkpoint: Run routertl sources — you should see
the open-logic sources listed under Synthesis sources.
5. Lint Your Design
Shorter commands available! From here on you can use
rrinstead ofroutertl, and abbreviations likewsforworkspace,hierforhierarchy. We'll use the short forms in the examples below. Runrr --helpfor the full list.
Before writing tests, let's check that the VHDL is valid:
rr lint
The smart linter uses GHDL for VHDL analysis and Verilator for SystemVerilog. It auto-detects your design hierarchy and lints each entity in dependency order:
🔍 RouteRTL Smart Linter (Incremental Mode) ============================= Auto-Detecting Hierarchies... Detected 1 Top-Level Hierarchies. 📐 Linting Hierarchy: olo_base_fifo_sync (2 new / 2 total) ... PASS ✅ All hierarchies passed linting.
GHDL is required for VHDL linting. If you see a "GHDL not found" error, install it with
sudo apt install ghdl(Ubuntu 24.04+) or build from source. Alternatively, userr docker shell simwhich includes all tools.Verilator is only needed if your project contains SystemVerilog or Verilog files. Pure VHDL projects won't see any Verilator warnings.
✅ Checkpoint: Linting should pass with no errors.
6. Generate a Test
routertl testgen
This auto-generates a cocotb testbench skeleton for every entity that
doesn't have one yet. Check sim/cocotb/tests/ — you should see a new
test_olo_base_fifo_sync.py with a structure like this:
import cocotb
from cocotb.triggers import ClockCycles, RisingEdge
from routertl.sim import run_simulation
@cocotb.test()
async def test_basic_behavior(dut):
"""Auto-generated smoke test for olo_base_fifo_sync."""
cocotb.start_soon(cocotb.clock.Clock(dut.Clk, 10, units="ns").start())
# Reset
dut.Rst.value = 1
await ClockCycles(dut.Clk, 3)
dut.Rst.value = 0
await RisingEdge(dut.Clk)
# TODO: Add your test logic here
assert True
if __name__ == "__main__":
run_simulation(top_level="olo_base_fifo_sync", module="test_olo_base_fifo_sync")
The
if __name__block lets you run the test standalone withpython test_olo_base_fifo_sync.py. Theroutertl simcommand does the same thing but adds test discovery and reporting.
✅ Checkpoint: Run routertl scan-tests — the test should appear
in the list.
Working with AI Agents
RouteRTL is designed to work seamlessly with AI coding assistants. Once you have a scaffolded test, hand your agent the API docs and let it write production-quality verification code and build hooks:
| Document | What the agent learns |
|---|---|
| Simulation API | Tb, run_simulation(), protocol drivers (UART, SPI, I2C, AXI-Lite, Avalon-MM) |
| Hook Authoring | resolve_tool_binary(), load_project_config(), pre-build hook lifecycle |
A typical workflow:
- You scaffold the project (
rr init) and pull or write the RTL - The agent reads the API docs and writes comprehensive cocotb tests
- You review, iterate, and run
rr simto validate
Because every test uses the same Tb environment and run_simulation()
entry point, agents produce consistent, SDK-compliant code that works
out of the box — no manual wiring needed.
For the best results, include both the Simulation API and the Testbench Environment pages in the agent's context. The concrete function signatures and usage examples let it generate tests that follow your project's conventions.
7. Run Your First Simulation
# Run the specific test
routertl sim test_olo_base_fifo_sync
You'll see cocotb launch the simulator, drive your entity's ports, and report results:
🧪 Running: test_olo_base_fifo_sync Simulator: nvc ... ✅ test_olo_base_fifo_sync PASSED (0.8s)
Want to see all available tests interactively?
routertl sim
This shows a numbered menu — just pick a test by number.
✅ Checkpoint: Your first simulation passed!
Where are my waveforms and logs?
Every simulation automatically organizes its outputs into three
directories under sim/:
| Directory | Contents | Notes |
|---|---|---|
sim/waves/<test>/ | Waveform file | .fst (NVC default), .vcd, or .ghw |
sim/logs/<test>/ | Simulation log | Full cocotb transcript |
sim/results/ | Test reports | JUnit XML for CI/CD integration |
sim/work/ | Build cache | Compiled libraries — safe to delete |
Check what was generated:
ls sim/waves/test_olo_base_fifo_sync/
# → olo_base_fifo_sync.fst
Open the .fst file with your preferred waveform viewer (GTKWave,
Surfer, or rr waves when available) to inspect signal activity.
Customize output formats in
project.yml:simulation: waves: formats: [fst, vcd] # Produce both FST and VCD output_dir: sim/waves # Override output locationSee the project.yml Reference for all options.
8. Explore Your Design
Now let's use the commands we built today to explore the design:
See the full project hierarchy
rr info --forest
This is one of RouteRTL's most powerful commands. It scans your entire source tree and displays all top-level hierarchies as nested instantiation trees — showing every entity and how they connect:

Inspect a specific entity
rr info olo_base_fifo_sync
This shows the entity's source file, port list, generics, dependencies, reverse dependents, and related tests — all in one view.
View the dependency graph
rr deps
rr deps --graph mermaid # Export as Mermaid diagram
✅ Checkpoint: You can see your design's structure from the terminal!
9. Generate a Schematic (Optional)
If you have Yosys + netlistsvg installed (both are in the Docker image):
routertl schematic edge_counter
This generates an SVG schematic at sim/schematics/edge_counter.svg.
Open it in your browser to see the synthesized logic.
10. Clean Up
# Clean only simulation artifacts (fast)
routertl workspace clean --sim
# Or clean everything
routertl workspace clean
11. What's Next?
Now that you've completed the basics, here's where to go deeper:
| Topic | Document | Command |
|---|---|---|
| Writing real tests | Cocotb Quickstart | routertl help sim |
| Project configuration | project.yml Reference | routertl help workspace |
| Dependency analysis | Dependency Resolver | routertl deps --graph |
| Docker development | Architecture Overview | routertl docker shell sim |
| Vivado/Quartus builds | Vendor Tutorials | routertl bitstream |
| CI/CD integration | SDK User Guide | routertl workspace cicd |
Useful everyday commands
routertl sim --all # Run all tests
routertl sim --tag smoke # Run only smoke-tagged tests
routertl diff # See what tests are affected by your changes
routertl watch # Re-run tests on file save
routertl report # Generate a test report
routertl doctor # Environment health check
routertl help <command> # Built-in documentation
Enable shell completion for tab-complete on all commands:
routertl completion bash >> ~/.bashrc # or zsh/fish source ~/.bashrc
Happy hacking! 🚀