Introduction to rustdv

What rustdv is, and a complete reference for what it provides.

The UVM

The Universal Verification Methodology (UVM) is the dominant RTL verification methodology across the IC industry. The UVM is popular because it allows engineers to reuse testbench components across testbenches, and because it provides a standardized testbench structure that engineers recognize as they move across projects, companies, and industries. If you apply for a job as a verification engineer, it is likely that the hiring team uses the UVM and will test your UVM knowledge.

IEEE defined the UVM in the IEEE Standard for Universal Verification Methodology Language Reference Manual, also known as the IEEE 1800.2 standard. While the industry defined the standard in terms of SystemVerilog, the methodology's ideas travel: pyuvm implements it in Python (on top of cocotb), and rustdv brings those same ideas to Rust.

What rustdv is

rustdv is a hardware verification framework inspired by the UVM. It is not an implementation of IEEE 1800.2 — the standard is written in terms of object-oriented class hierarchies, and Rust is not an object-oriented language — and some layers, notably TLM and the analysis layer, are deliberately done differently. What rustdv takes from the UVM is what makes the UVM valuable: the testbench structure, the phased component tree, late binding through configuration and a factory, and the sequence machinery, re-created with Rust's own tools — structs, traits, and ownership.

Where the Python story needs two projects — cocotb to talk to the simulator and pyuvm to provide the methodology — rustdv contains both layers: a simulator-driven async executor with triggers and signal handles underneath, and the component methodology on top. Testbenches compile to native shared libraries that the simulator loads over VPI, with zero external dependencies. The examples and the regression suite run on Icarus Verilog, which is free and open source.

The methodology layer provides the UVM structure a verification engineer expects:

Because rustdv components are ordinary Rust structs, the pure-software parts of a testbench — predictors, transaction operations, coverage logic — also run under cargo test with no simulator at all.

Getting started

The Getting Started page takes you from an empty directory to a running testbench in three small files, then to the complete TinyALU testbench the repository ships.

The companion book, Rust for RTL Verification, is the front door to the methodology. It assumes no prior Rust — the first fourteen chapters teach the language from zero — and then builds a complete TinyALU testbench version by version, adding one UVM capability at a time. The Interlude shows the complete testbench in one place and is the best single answer to “what does rustdv code look like?”

The framework lives at github.com/rustdv/rustdv and is published as rustdv on crates.io. Questions and discussion belong in GitHub Discussions.

What rustdv provides

Every rustdv listing in the book opens with use rustdv::prelude::* — the analog of import uvm_pkg::* and from pyuvm import *. The tables below are the complete reference for what that line brings into scope, plus the macros. The Chapter column points to where the book teaches each name; a dash means the name is provided for completeness but the book's examples never need it.

The prelude, alphabetically

NameWhat it isChapter
Activethe active/passive agent knob, read from the ConfigDb (pyuvm's is_active int, as an enum)40
AnalysisBusthe broadcast hub; it stores nothing32
build_alldrive build across a component tree (the runner's job)24
channelmake a (Sender, Receiver) queue pair with a capacity
check_alldrive check across a tree24
CheckSinkthe collector check phases write failures into24
Clocka software clock driver — taught once, then retired in favor of BFMs that wait on edges17
Componentthe lifecycle trait: build, connect, run, and the other phase methods24
ComponentNodethe tree-traversal trait #[derive(Component)] implements21, 24
ConfigDbpath-addressed runtime configuration; get returns a Result naming the cause25, 27
connect_alldrive connect across a tree24
create_seqbuild a sequence through the sequence factory36
Eitherthe answer from racing two differently-typed futures
end_of_elaboration_allphase driver24
Eventset once; everyone waiting wakes (SV: named event)16
extract_allphase driver24
Factorythe component registry: build by type or name, override by type, name, or instance29
final_allphase driver24
first2, first!race futures; the first to finish wins (SV: fork...join_any)16
GetPortthe consuming end of a TLM connection31
HandleErrorwhat signal access returns instead of a crash17, 19
HierarchyHandlea handle to a scope in the design hierarchy
join2, join!run futures together; wait for all (SV: fork...join)16
Lockmutual exclusion with an RAII guard (SV: a one-key semaphore)16
logthe logging facade; policy is per hierarchy15, 26
Logic, LogicArrayfour-state values, scalar and vector17
LogicHandlea named DUT signal: read it, drive it; a typo'd name is an Err17
next_time_steptrigger for the simulator's next time step
NullTriggerthe trigger that is ready the next time it is polled15
ObjectionGuardreturned by ctx.raise_objection; the run phase ends when the last guard drops23
PeekPortthe look-without-taking end of a TLM connection31
PortName, PortOwnerhow the elaboration check names an unconnected port31
print_hierarchydump a component tree
PublishPortthe publishing end a component declares32
PutPortthe producing end of a TLM connection31
Queuethe sim-aware mailbox: bounded puts and empty gets block in simulated time (SV: mailbox#(T))16
read_only, read_writescheduler-region triggers (cocotb's ReadOnly/ReadWrite)
Receiverthe getting end channel returns
report_allphase driver24
Rngthe deterministic per-test random source behind ctx.rng()20
run_component_testrun a component tree as a self-contained test
run_extract_check_reportdrive the closing phases together
RustdvCompa slot holding any factory-built component29
RustdvCtxthe context: path, logging, rng, DUT handle, objection — the framework, handed as an argument15
RustdvSeqa slot holding any factory-built sequence — RustdvComp's parallel36
RustdvShareda cloneable handle to one shared object — Rc<RefCell> wearing the framework's name32
Senderthe putting end channel returns
SeqCtxthe context a sequence body receives36
SeqErrorwhat a sequence can fail with36
SeqItemthe bounds a sequence-item type must meet36
SeqItemExport, SeqItemPortthe driver's side of the sequencer handshake36
Sequencethe trait with one method, body — a test program, not a component36
Sequencergrants sequences their turns; feeds the driver36
set_seq_overridechange which sequence create_seq builds36
sim_time_nsthe current simulated time
SimDurationan amount of simulated time17
spawn, spawn_namedlaunch a concurrent task; the named form stamps its log lines16
start_alldrive the run phase across a tree24
start_of_simulation_allphase driver24
SubscribePortthe subscribing end a component declares32
Subscriberthe trait a subscriber implements once per stream32
TaskHandlewhat spawn returns: await it for the result, or cancel() it16
TestErrorthe error a failing test returns; Ok(()) is a pass15
Timerthe simulated-time trigger: Timer::ns(2).await15
TlmFifothe FIFO two components share without learning each other's names31
TxnIdthe ticket finish_item returns; claims a response37, 38
with_timeoutwrap an await with a deadline

The macros

NameWhat it doesChapter
#[rustdv::test]registers a test with the runner (cocotb: @cocotb.test())15, 21
#[derive(Component)]writes the component-tree plumbing (SV: the uvm_component_utils family)21, 24
vpi_bootstrap!()one line per testbench crate: exports the entry points the simulator loads17
first!, join!variadic race and join16

On the surface, outside the prelude

A few names live on the crate but not in the prelude; reach them as rustdv::Name.

NameWhat it isChapter
ConfigErrorwhy a ConfigDb get failed, as a value28
ConnectErrorwhy a connection could not be made31
TlmFull, TlmEmpty, TlmErrorthe channel layer's refusals: what Sender::try_send and Receiver::try_recv answer
Makerthe closure type the factory stores per registration29
ResponseQueuethe store behind get_response — responses held for claiming, in order or by ticket (pyuvm's ResponseQueue)
TimeoutError, TaskError, ValueError, AnyHandle, Executor, TestRegistration, top_moduleinfrastructure corners a testbench rarely touches

The whole of each layer is also re-exported for power users: rustdv::sim, rustdv::runner, rustdv::gpi.

Coming from pyuvm or SystemVerilog UVM? The UVM translation tables map your working vocabulary — Python idioms, cocotb calls, and SystemVerilog UVM classes — onto their rustdv equivalents, name by name.