Expand description
§rustdv
A hardware verification framework in Rust: cocotb-style simulator coroutines plus a UVM-analog testbench library, rethought for Rust’s ownership model.
This is the facade crate (design-doc D2.5): it re-exports the public API so a testbench needs one dependency and one import:
ⓘ
use rustdv::prelude::*;
rustdv::vpi_bootstrap!();
#[rustdv::test]
async fn my_test(ctx: RustdvCtx) -> Result<(), TestError> {
let dut = ctx.dut();
// ...
Ok(())
}Re-exports§
pub use rustdv_gpi as gpi;pub use rustdv_runner as runner;pub use rustdv_sim as sim;
Modules§
- channel
- Channels: the TLM-1 replacement (design-doc §5.6, review-memo R6). Twelve pyuvm port classes become six methods on two types; direction lives in the type name; a mismatch is a compile error.
- log
- Sim-time-stamped logging in the book’s format:
2.00ns INFO ...(design-doc OQ-8: thetracingmapping is deferred; this minimal zero-dependency logger reproduces the output format the book teaches). - prelude
- One-line import for testbenches (the
from pyuvm import *analog).
Macros§
- first
first!(a, b, ...)— first completed future wins; losers are dropped.- join
join!(a, b, ...)— wait for all.- vpi_
bootstrap - Export the VPI entry points from the testbench cdylib. The simulator
(vvp) dlopens the library and calls each routine in
vlog_startup_routines; ours registers the start-of-simulation callback that launches the regression (design-doc §3.2, as deviated — see rustdv-runner docs and STATUS.md).
Structs§
- Analysis
Bus - A broadcast hub: one publisher in, every subscriber out.
- Check
Sink - Collector for
check-phase failures (design-doc §5.3 signature). - Clock
Clock::new(&dut_clk, SimDuration::ns(10)).start().- Component
Reg - One registered component: its name and its maker. Emitted by
#[derive(Component)]for every component, universally (D73). - Config
Db - The configuration database. All methods are associated functions over an ambient per-test store (D11, D16).
- Event
- Manual-reset event;
wait()completes immediately if already set. - Executor
- The executor (design-doc §4.3).
!Send— it never leaves the sim thread. - Factory
- The factory. Ambient, like the ConfigDb it is built on; every method is an associated function.
- GetExport
- The FIFO’s get side.
- Hierarchy
Handle - A module/scope handle:
dut.child("name")?(OQ-6 dynamic-first lean). - Lock
- Lock
Guard - RAII lock guard; drop releases (fair handoff to the next waiter).
- Logic
Array - A fixed-width vector of 4-state bits, MSB first (binstr order).
- Logic
Handle - A value-bearing signal. Explicit
get()/set()(mapping row 20 — cocotb 2.x itself moved off the.valueproperty). - Null
Trigger - Yield once to the scheduler. Kept for parity but documented as a smell —
prefer
Event(cocotb NullTrigger docstring; book: Coroutines chapter). - Objection
Guard - RAII objection. Drop = drop_objection (mapping row 32).
- Objection
Registry - Peek
Export - The FIFO’s peek side.
- Port
- A port: a component’s request for an interface it does not own.
- Port
Info - One declared port, for the elaboration report.
- Port
Name - The name a port is declared under, carrying the interface it demands.
- Publish
Export - The publish side of a hub: connect it to a source’s
PublishPort. - PutExport
- The FIFO’s put side, handed to a component that needs to put.
- Queue
- FIFO queue with optional bound; cloning shares the queue.
- Receiver
- The get/peek families (pyuvm: _s12, 12.2.5).
- Response
Queue - Responses, retrievable in order or by ticket (pyuvm’s
ResponseQueue). - Rng
- Rustdv
Comp - A slot that holds any component. It says nothing about position in the
tree and nothing about overridability; the build line decides that
(
new_comp()fixed,create_comp()overridable). Every child field a block may want to override is anRustdvComp. - Rustdv
Ctx - The one context every testbench is handed (D47:
TestCtxandRunCtxmerged). Named for the framework, not for a phase, because Part II teaches testbenches that have no phases. Everything a running testbench is handed: the DUT, randomization, the objection registry, and the component’s path. - Rustdv
Path - Rustdv
Seq - A slot holding any sequence with these request/response types — what
create_seq()returns, and what a component declares when the factory chooses the type. The parallel ofRustdvComp. - Rustdv
Shared - A handle to state shared between a component and its analysis port.
- Sender
- The put family (pyuvm: _s12, 12.2.5).
- SeqCtx
- What a running sequence is handed. Its equivalent of a component’s
crate::RustdvCtx: it can log, it has a seeded RNG, and it knows its sequencer — if it has one. - SeqError
- SeqItem
- What a driver receives: the framework’s id plus the user’s plain payload.
- SeqItem
Export - The sequencer’s side, handed to
connect. - Sequencer
- The sequencer: a queue of items feeding one driver.
- SimDuration
- A span of simulation time in simulator precision steps. Unit-safe
constructors (mapping row 13):
SimDuration::ns(2). - Subscribe
Export - The subscribe side of a hub. Connect as many subscribers to it as you like — that is what makes the write a broadcast.
- TapExport
- One of a FIFO’s analysis taps (D23): connect a subscriber to watch the traffic without joining the data path.
- Task
Handle - Public task control surface; also a Future (
handle.await== awaiting completion, as in cocotb 2.x). Port of cocotbTask(design-doc §4.3). - Test
Error - Test
Registration - One registered test (design-doc §6.1: the cocotb
Testoption set). - Timeout
Error - Timer
- One-shot timed trigger (port of cocotb
Timer, mapping row 13). Construction rejects zero durations, as cocotb’s does. - TlmEmpty
- TlmFifo
- A bounded (or unbounded) FIFO that is also a component in the hierarchy.
- TlmFull
try_sendfailure: returns the item (pyuvm try_put returning False).- TxnId
- A transaction’s ticket. Assigned by the sequencer, carried in the envelope, and echoed on the response so a sequence gets the answer to the question it asked.
Enums§
- Active
- Agent activity (pyuvm’s ConfigDB
is_activeint becomes an enum — mapping row 42; illegal values are unrepresentable). - AnyHandle
- Config
Error - Why a
getfailed. SystemVerilog collapses all of these intoreturn 0and leaves your variable untouched; naming them is the point. - Connect
Error - Errors from wiring. Every one is a testbench bug found during elaboration, so the exports panic on them — but the message says exactly which port, on which component, and why.
- Either
- Handle
Error - Logic
- One 4-state bit.
- Task
Error - Task
State - The seven task states, per cocotb (mapping row 5).
- TlmError
- Value
Error
Traits§
- Component
- The UVM phase lifecycle (design-doc §5.3, D51), restored in full. Nine
phases, each a method with a default no-op body — override only what you
use, exactly as pyuvm’s
uvm_componentdoes.buildandconnectare real phases again, not the “constructor conventions” R3 collapsed them into; restoring them is the point of this chapter. - Component
Node - Structural traversal over the ownership tree (design-doc D5.2).
Generated by
#[derive(Component)]for structs whose children are fields marked#[component]; hand-implementable by design (OQ-15: the derive is convenience, not requirement). - Component
Trait - The UVM phase lifecycle (design-doc §5.3, D51), restored in full. Nine
phases, each a method with a default no-op body — override only what you
use, exactly as pyuvm’s
uvm_componentdoes.buildandconnectare real phases again, not the “constructor conventions” R3 collapsed them into; restoring them is the point of this chapter. - DynPhases
- Dyn-safe mirror of
Component’s non-async phases (D48). - GetIf
- What a
getexport offers: take the item out. - PeekIf
- What a
peekexport offers: copy the item and leave it there, so whoever gets it next still finds it. That is why peek needsT: Clonewhere get does not. - Port
Field - The bridge between a port field and the generated
ComponentNodemethods. - Port
Owner - Whatever
connectis pointed at: a child slot, or a component itself. - Publish
If - What a publish export offers: hand an item to everyone, immediately.
- PutIf
- What a
putexport offers. Implemented by the FIFO’s put side; aPutPortholds one of these once connected. - SeqItem
If - What a sequencer’s export offers a driver. Behind
dyn, so the port can hold it without knowing which sequencer it came from. - Sequence
- A sequence: a program that produces stimulus.
- Sink
Handle - The erased handle a subscribe port hands to the hub.
- Subscriber
- What a component does with an item it was handed by an analysis broadcast
— the port of
uvm_subscriber’swrite.
Functions§
- build_
all - Top-down:
builda node, then build the children it just created (D6). Readingchildren_mutafterbuildis what lets a parent construct them in its own build phase and have the walk descend into them. - channel
- Create a bounded channel (design-doc §5.6 signature). The UVM TLM FIFO
default depth is 1;
capacity = 0is coerced to 1. - check_
all - Top-down.
- check_
connections - Run the connection sweep and turn any misses into one error listing them
all. Called by the runner between
connectandend_of_elaboration. - connect_
all - Bottom-up: children
connectbefore parents. - create_
seq - Build a sequence of this type, honouring any override installed for it.
- end_
of_ elaboration_ all - Top-down.
- extract_
all - Top-down.
- final_
all - Top-down.
- first2
- join2
- next_
time_ step - Await the next simulator time step (port of
NextTimeStep()). - print_
hierarchy - Debug printer: the child walker serving pyuvm’s hierarchy print (design-doc §5.2).
- read_
only - Await the next ReadOnly phase (port of
ReadOnly()). - read_
write - Await the next ReadWrite phase (port of
ReadWrite()). - report_
all - Top-down.
- run_all
- Bottom-up: every component’s
runfires, children first (D48). The walk is boxed-recursive becausedyn_runyields a boxed future we await, and the children’s borrows are held across those awaits. - run_
component_ test - The full phaser: drive every UVM phase over a component tree, in order
(D51) — the analog of pyuvm handing the test class to its phaser. The
runner calls this for a
#[rustdv::test]struct, so the test body is just the phase methods; no hand-rolledstart_all. - run_
extract_ check_ report - The standard post-run tail: extract → check → report → final, returning
Errif any check failed (anErrfails the test, design-doc §0.6). - set_
seq_ override - Install a sequence override: wherever
From::create_seq()is called, build aToinstead. - sim_
time_ ns - Current simulation time in nanoseconds (for log formatting).
- sim_
time_ steps - Current simulation time in precision steps.
- spawn
- Port of
cocotb.start_soon(mapping row 4). - spawn_
named - start_
all - Bottom-up: children start before parents (transitional spawn hook).
- start_
of_ simulation_ all - Top-down.
- top_
module - The first top-level module (the DUT in single-top designs).
- unconnected_
ports - Every required port in the tree that nobody connected, as
path.name (kind). - with_
timeout - Run
futwith a simulation-time timeout.
Type Aliases§
- GetPort
- A port that takes items out of something it does not own.
- Maker
- A maker: builds a component with no arguments (its name and parent come
from the tree, D7). Non-capturing, so it is an ordinary
fnpointer. - Peek
Port - A port that copies items without removing them.
- Publish
Port - A port that broadcasts items to whoever is listening — or to nobody.
- PutPort
- A port that puts items into something it does not own.
- SeqItem
Port - A driver’s request for items. Declared
#[port(seq_item)]. - Subscribe
Port - A port that receives broadcast items. It is the odd one out: instead of
the export writing an interface into it, the component fills it with its
subscriber (
subscribe) and the hub reads it out at connect time. Broadcast runs the other way, so the wiring does too.
Attribute Macros§
- test
#[rustdv::test]— port of@cocotb.test()(design-doc §6.1). Both front doors (design-doc §6.1, D46). Registers at link time either
Derive Macros§
- Component
#[derive(Component)]— ComponentNode traversal (design-doc §6.3). Generates theComponentNodeimpl (design-doc §6.3, revised per R2): traversal of#[component]fields, includingOption<T>andVec<T>; names synthesized from field names. Emits no factory registration (R5) — but R5 is reversed: the factory returns in ch29, and this derive is where its registration will land. The impl is hand-writable; the derive is convenience.