UVM Translation Tables
Your working vocabulary, mapped onto rustdv — whichever language you come from. These tables are Appendices B, C, and A of Rust for RTL Verification; the Chapter column points to where the book teaches each translation.
Python → Rust (for cocotb and pyuvm readers)
For readers coming from cocotb and pyuvm (and Python for RTL Verification): the working translations the book uses, gathered for reference. SystemVerilog readers want the next section, this table's twin. Legend: [C] cocotb, [P] pyuvm.
Language and runtime
| Python | Rust | Chapter |
|---|---|---|
async def coroutine, resumed via send(None) | async fn → Future, resumed via poll() | 15 |
@cocotb.test() | #[rustdv::test] | 15, 21 |
| exceptions fail the test | Result<(), TestError>; panics = testbench bugs | 9, 18 |
cocotb.start_soon(coro) | spawn(future) -> TaskHandle<T> | 16 |
await task | task.await → Result<T, TaskError> | 16 |
task.kill() | handle.cancel() — the future is dropped; cleanup in Drop | 16 |
Combine(...) / First(...) | join2/join! / first2/first! | 16 |
try/except QueueFull | try_put → Result<(), T> (rejected item handed back) | 16, 31 |
| decorator registration at import time | link-section registration at compile time | 21 |
| metaclass class registration | not needed — constructor injection | 21, 29 |
getattr(obj, name) dispatch | pass the function/closure itself | 33 |
logging levels + handlers | log:: levels, set_level_for(prefix), log_to_file | 26 |
cocotb layer
| Python (cocotb) | Rust (rustdv-sim) | Chapter |
|---|---|---|
Timer(2, units="ns") | Timer::ns(2).await | 15 |
RisingEdge(sig) / FallingEdge(sig) | sig.rising_edge().await / sig.falling_edge().await | 17 |
ClockCycles(clk, n) | for _ in 0..n { clk.rising_edge().await; } | 17 |
dut.sig attribute magic | dut.signal("sig")? → Result<LogicHandle, _> | 17 |
sig.value = x / int(sig.value) | sig.set_u64(x) / sig.get_u64()? | 17 |
Clock(dut.clk, 10, units="ns").start() | Clock::new(&clk, SimDuration::ns(10)).start() | 17 |
cocotb.queue.Queue(maxsize=1) | Queue::new(Some(1)); Queue::unbounded() | 16 |
Event / Lock | sim::Event / sim::Lock (FIFO-fair, RAII guard) | 16 |
pyuvm layer
| Python (pyuvm) | Rust (rustdv) | Chapter |
|---|---|---|
@pyuvm.test() on a class, uvm_test_top | #[rustdv::test] on a struct; the root is named after your test | 23 |
raise_objection()/drop_objection() | ctx.raise_objection(..) → RAII ObjectionGuard; drop releases | 23 |
uvm_component(name, parent) tree | children are struct fields; #[derive(Component)]; paths derived | 24 |
| the nine phases, pyuvm's traversal order | the nine phases, same order: build, connect, ... final_phase | 24 |
self.logger, [uvm_test_top.comp] | ctx.info(..), same bracket format, path supplied by the walk | 26 |
ConfigDB().set/get, wildcards, globals | ConfigDb::set/get — same paths, same globs, Result answers | 25, 27 |
except UVMConfigItemNotFound | match on ConfigError::NotFound { .. } | 28 |
metaclass registration + create() | #[derive(Component)] registers; Foo::create_comp() | 21, 29 |
set_type_override_by_type | Factory::set_type_override::<A, B>() (also by name, by instance) | 29, 30 |
| TLM-1 put/get/peek port classes | PutPort/GetPort/PeekPort, wired export-to-port through a TlmFifo | 31 |
UVMTLMConnectionError (lazy, at first use) | elaboration sweep names every unwired port before run | 31 |
uvm_analysis_port.write() | PublishPort<T>::write(&T) through an AnalysisBus hub | 32 |
uvm_subscriber (one write per class) | a Subscriber<T> impl per stream — two streams, two impls | 32, 34 |
uvm_tlm_analysis_fifo | absent — the subscriber owns its storage | 32 |
uvm_object do_copy/do_compare/__str__ | #[derive(Clone, PartialEq, Debug)] + hand-written Display | 35 |
copy(other) / clone() | clone_from(&mut self, src) / clone() | 35 |
uvm_sequence.body() | impl Sequence — type Req/type Rsp, async fn body(ctx) | 36 |
start_item/finish_item | ctx.start_item(&mut req) / ctx.finish_item(req) → ticket | 36 |
seq_item_port.get_next_item() | port.get_next_item().await → SeqItem<REQ> | 36 |
item_done() / item_done(rsp) + set_id_info | item_done(None) / item_done(Some(rsp)) — auto-tagged | 36, 38 |
get_response() | get_response(Some(ticket)) / try_get_response — in order or by ticket | 37, 38 |
(no pyuvm counterpart) try_next_item | try_next_item() → Option — the UVM's non-blocking accept, kept | 37 |
seq.start(seqr) / start(None) for virtual | seq.start(&seqr) / start_virtual() | 36, 39 |
is_active int from ConfigDB | Active enum from the ConfigDb; a passive env skips building the driver | 40 |
SystemVerilog-UVM → rustdv
For readers coming from SystemVerilog UVM (and The UVM Primer): where each piece of your working vocabulary went. Python readers want the previous section, this table's twin.
Language level
| SystemVerilog | Rust | Chapter |
|---|---|---|
byte, shortint, int | u8/i8, u16/i16, u32/i32 — no silent truncation | 3 |
logic four-state values | Logic enum / LogicArray — no x in arithmetic | 7, 17 |
typedef enum (an int in disguise) | enum — a real type; exhaustively matched | 7 |
case + default (+ unique warnings) | match — missing cases are compile errors | 4 |
class ... extends, virtual, super.new() | traits, default methods, composition + delegation | 10 |
pure virtual function in a virtual class | a required trait method, checked at the impl | 10 |
parameterized class #(type T = int) | generics <T: Bound>, checked at definition | 11 |
class ... #(type REQ, type RSP = REQ) | SeqItemPort<REQ, RSP = REQ> — same convention | 11 |
local / protected | private-by-default, pub to export | 14 |
null handle, $cast | Option<T>, exhaustive match — no null, no cast | 9 |
| status flags and sentinel returns | Result<T, E> + ? — failure in the signature | 9 |
$sformatf | format! | 8 |
fork / join_none / disable | spawn(future) → TaskHandle; handle.cancel() | 16 |
forever | loop (an expression — it can break with a value) | 4 |
mailbox #(T), try_put/try_get | sim::Queue<T> — same names, Result/Option answers | 16 |
named event, ->done, @(done) | sim::Event — set() / wait().await | 16 |
semaphore (one key) | sim::Lock — FIFO-fair, RAII guard | 16 |
@(posedge clk), #2ns | clk.rising_edge().await, Timer::ns(2).await | 15, 17 |
`define-style codegen (`uvm_*_utils) | attribute + derive macros — syntax trees, not text | 21 |
package + .f file + vendor tarball | crate + Cargo.toml + crates.io | 14 |
| (no equivalent) | cargo test — unit tests with no simulator | 14 |
Methodology level
| SystemVerilog UVM | rustdv | Chapter |
|---|---|---|
class my_test extends uvm_test + run_test() | #[rustdv::test] on a struct; the runner drives its phases | 23 |
phase.raise_objection(this) / drop_objection | ctx.raise_objection(..) → RAII ObjectionGuard; drop releases | 23 |
uvm_component(name, parent) tree | children are struct fields; #[derive(Component)]; paths derived by the walk | 24 |
build_phase (top-down) / connect_phase (bottom-up) | fn build(&mut self, ctx) / fn connect(&mut self, ctx) — real phases, same directions | 24 |
run_phase (objection-gated task) | async fn run — concurrent across the tree; ends when objections drain | 24, 31 |
| elaboration + post-run phases | same names; top-down, where SV runs them bottom-up | 24 |
`uvm_info(id, msg, verbosity) | ctx.info(..) — same time/level/[path] line format | 26 |
set_report_verbosity_level_hier() | ctx.set_logging_level_hier(..) | 26 |
uvm_config_db#(T)::set/get, wildcards | ConfigDb::set(ctx, glob, key, v) / get → Result — one key, no type in the address | 25, 27 |
| virtual interface via config database | Rc<TinyAluBfm> in the ConfigDb | 25 |
a failed get() (silent return 0) | ConfigError naming which failure; #[must_use] | 27, 28 |
print_config() / +UVM_CONFIG_DB_TRACE | ConfigDb::print() / ConfigDb::set_tracing(true) | 28 |
`uvm_component_utils registration | #[derive(Component)] registers by name, universally | 21, 29 |
type_id::create("name", this) | Foo::create_comp() — overridable (new_comp() = new, fixed) | 29 |
set_type_override_by_type / _by_name / instance | Factory::set_type_override::<A, B>() / _by_name / set_inst_override | 29, 30 |
uvm_factory::get().print() | Factory::print() | 29 |
TLM-1 put/get/peek port + export + connect() | PutPort/GetPort/PeekPort + fifo.put_export().connect(comp, PORT_NAME) | 31 |
uvm_tlm_fifo (with built-in taps) | TlmFifo<T> (with put_ap()/get_ap()) | 31 |
try_put() returns a bit | try_put(T) → Result<(), T> — a refused item comes back | 31 |
| unconnected port found at first use | elaboration sweep names every unwired port before run | 31 |
uvm_analysis_port.write() | PublishPort<T>::write(&T), brokered by an AnalysisBus hub | 32 |
uvm_subscriber (one write per class) | a Subscriber<T> impl per stream — two streams, two impls, no imp_decl | 32, 34 |
uvm_tlm_analysis_fifo in scoreboards | absent — the subscriber owns its storage | 32 |
uvm_agent + is_active | env reads Active from the ConfigDb; a passive env leaves the driver slot empty | 40 |
do_copy / do_compare / convert2string | #[derive(Clone, PartialEq, Debug)] + hand-written Display | 10, 35 |
copy(other) / clone() | clone_from(&mut self, src) / clone() | 35 |
uvm_field_* macros (runtime field walking) | derive — the same generation, at compile time | 21, 35 |
uvm_sequence #(REQ, RSP), body() | impl Sequence — type Req/type Rsp, async fn body(ctx) | 36 |
start_item(req) / finish_item(req) | ctx.start_item(&mut req) / ctx.finish_item(req) → ticket | 36 |
seq_item_port.get_next_item() / item_done() | same names; item_done(Some(rsp)) answers | 36, 38 |
try_next_item() (absent from pyuvm) | try_next_item() → Option<SeqItem<REQ>> | 37 |
rsp.set_id_info(req) + get_response() | auto-tagged; get_response(Some(ticket)) / try_get_response | 37, 38 |
seq.start(seqr) / virtual sequence with no sequencer | seq.start(&seqr) / start_virtual() | 36, 39 |
| sequencer grab/lock/priority arbitration | unported (FIFO arbitration only) — a recorded gap | 36 |
assert (prints, simulation continues) | assert! (panic = test fails, on the spot) | 9 |
uvm_error vs uvm_fatal (convention) | CheckSink::error = DUT check; panic! = testbench bug | 9, 24 |
Chapter map to the earlier books
Two books precede Rust for RTL Verification, and either prepares you for it: The UVM Primer (SystemVerilog) and Python for RTL Verification (Python/cocotb/pyuvm). This table maps every chapter to its companion chapters in both, for readers who want to compare treatments — or to lend the right book to a colleague. A dash means the topic has no mirror in that book.
| Rust for RTL Verification | The UVM Primer | Python for RTL Verification |
|---|---|---|
| Ch. 1: Why Rust? | Ch. 1: Introduction | Why Python and why UVM? |
| Ch. 2: Rust Concepts | — | Python concepts |
| Ch. 3: Rust Basics | — | Python basics |
| Ch. 4: Conditions, Loops, and match | — | Conditions and loops / Ranges |
| Ch. 5: Ownership | (no mirror — GC did this silently) | (no mirror) |
| Ch. 6: Borrowing and References | (no mirror) | (no mirror) |
| Ch. 7: Structs, Enums, and Methods | Ch. 4: OOP; Ch. 7: Static Methods | Classes |
| Ch. 8: Collections | — | Python sequences / Lists / Strings / Dictionaries |
| Ch. 9: Result, Option, and the End of Exceptions | — | Exceptions |
| Ch. 10: Traits | Ch. 5: Classes and Extension; Ch. 6: Polymorphism | Inheritance / super() / protocols |
| Ch. 11: Generics | Ch. 8: Parameterized Class Definitions | (duck typing, throughout) |
| Ch. 12: Closures and Iterators | — | Generators / comprehensions |
| Ch. 13: Smart Pointers | — | Protecting attributes |
| Ch. 14: Modules, Crates, and Cargo | — | Modules |
| Interlude: The Complete TinyALU Testbench | (the destination, previewed) | (testbench 8.0, previewed) |
| Ch. 15: async/await and the Executor | (the simulator's scheduler, opened up) | Coroutines |
| Ch. 16: Tasks, Channels, and Sim-Aware Queues | Ch. 17: Interthread Communication | cocotb Queue |
| Ch. 17: Simulating with rustdv-sim | — | Simulating with cocotb |
| Ch. 18: Basic Testbench: 1.0 | Ch. 2: A Conventional Testbench | Basic testbench: 1.0 |
| Ch. 19: TinyAluBfm | Ch. 3: Interfaces and BFMs | TinyAluBfm |
| Ch. 20: Struct-Based Testbench: 2.0 | Ch. 10: An Object-Oriented Testbench | Class-based testbench: 2.0 |
| Ch. 21: Macros | (the `uvm_*_utils macros, demystified) | (decorators; design patterns) |
| Ch. 22: Why UVM? | Ch. 1: Introduction | Why UVM? |
| Ch. 23: uvm_test Testbench: 3.0 | Ch. 11: UVM Tests | uvm_test testbench: 3.0 |
| Ch. 24: Components | Ch. 12: UVM Components | uvm_component |
| Ch. 25: uvm_env Testbench: 4.0 | Ch. 13: UVM Environments | uvm_env testbench: 4.0 |
| Ch. 26: Logging | Ch. 19: UVM Reporting | Logging |
| Ch. 27: Configuration | (uvm_config_db, in passing) | ConfigDB() |
| Ch. 28: Configuration Debugging | — | Debugging the ConfigDB() |
| Ch. 29: The Factory | Ch. 9: The Factory Pattern | The UVM factory |
| Ch. 30: Variation-Point Testbench: 5.0 | — | UVM factory testbench: 5.0 |
| Ch. 31: Component Communications | Ch. 14: A New Paradigm; Ch. 18: Put and Get Ports | Component communications |
| Ch. 32: Analysis Ports | Ch. 15: Talking to Multiple Objects | Analysis ports |
| Ch. 33: Components in Testbench 6.0 | Ch. 16: Analysis Ports in a Testbench | Components in testbench 6.0 |
| Ch. 34: Connections in Testbench 6.0 | Ch. 18: Put and Get in Action; Ch. 22: UVM Agents | Connections in testbench 6.0 |
| Ch. 35: Transactions | Ch. 20: Deep Operations; Ch. 21: UVM Transactions | uvm_object in Python |
| Ch. 36: Sequence Testbench: 7.0 | Ch. 23: UVM Sequences | Sequence testbench: 7.0 |
| Ch. 37: Out-of-Order Transactions: Testbench 7.1 | Ch. 23: UVM Sequences | Fibonacci testbench: 7.1 / get_response() testbench: 7.2 |
| Ch. 38: Fibonacci Testbench: 7.2 | Ch. 23: UVM Sequences | Fibonacci testbench: 7.1 |
| Ch. 39: Virtual Sequence Testbench: 8.0 | Ch. 23: UVM Sequences | Virtual sequence testbench: 8.0 |
| Ch. 40: The Complete TinyALU Testbench | (no mirror) | (no mirror) |
rustdv