UVM Hands-On
Build a UVM environment piece by piece the way an interview drills it: driver/monitor/agent and scoreboard, phasing and objections, the factory and config_db, reporting, sequences and virtual sequences, TLM analysis ports, and a register model with an adapter and predictor.
By the end you can
- Assemble an agent (driver, monitor, sequencer) and a scoreboard
- Use the factory and config_db to configure and override components
- Drive stimulus with sequences and a virtual sequence
- Model registers with RAL and access them front- and backdoor
0 / 15 assignments done
Move each assignment through the stages — progress saves automatically.
UVM components & phasing
0/4The core hierarchy — driver, monitor, agent, scoreboard — wired up and brought to life through phases and objections.
Driver, monitor and agent
Build a driver that pulls items from the sequencer and wiggles the interface, a monitor that reconstructs observed transactions and publishes them, and an agent that instantiates and connects the driver, monitor and sequencer.
Requirements
- Driver get_next_item/item_done handshake with the sequencer
- Monitor samples the interface and writes to an analysis port
- Agent builds and connects its sub-components
- An is_active switch that omits the driver/sequencer when passive
You'll be able to
- Explain each component's responsibility
- Wire an agent together in the connect phase
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Scoreboard with an analysis FIFO
Write a scoreboard that receives monitored transactions through an analysis export, compares each against an expected value from a small reference model, and reports pass/fail with a running mismatch count.
Requirements
- An analysis imp or uvm_tlm_analysis_fifo to receive transactions
- A reference model producing the expected result
- Automatic compare with an error tally
- A report_phase summary
You'll be able to
- Receive transactions with the analysis interface
- Structure a self-checking scoreboard
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Phases and objections
Use objections so a test runs exactly as long as its stimulus needs: raise an objection before starting a sequence and drop it when done, and add a drain time so trailing activity is captured. Explain the phase order.
Requirements
- raise_objection/drop_objection around the run-phase stimulus
- A set_drain_time to catch tail activity
- A note on build → connect → run → report ordering
- The test ends on its own (no manual $finish)
You'll be able to
- Control run-phase lifetime with objections
- Order top-down vs bottom-up phases correctly
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Field automation and do_ methods
Give a transaction the field automation macros so copy/compare/print/pack come for free, then re-implement do_compare and do_print by hand on a second class and compare the two approaches.
Requirements
- uvm_object_utils_begin with uvm_field macros
- A hand-written do_compare using the comparer policy
- A hand-written do_print
- copy()/compare()/print() shown working both ways
You'll be able to
- Use field automation for boilerplate
- Override do_ methods when you need control
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Factory, configuration & reporting
0/4Make the environment configurable and swappable — pass handles through config_db, override types with the factory, and control message noise.
config_db: pass the interface and a config object
Use uvm_config_db to hand the virtual interface from the top module to the driver/monitor, and to pass a configuration object (mode, address range, enables) from the test down to the agent. Fetch them safely with error checks.
Requirements
- set() the virtual interface at the top level, get() in components
- A config object passed test → env → agent
- Guarded get() calls that fatal on a missing entry
- Wildcards used sensibly in the scopes
You'll be able to
- Move handles and settings without hard wiring
- Debug a missing config_db entry
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Factory override: swap a type without editing the env
Register components and transactions with the factory, then from a test use a type or instance override to replace the base transaction (or driver) with an error-injecting subclass — without touching the environment code.
Requirements
- Components/objects created via type_id::create()
- A type override and an instance override from the test
- The override subclass actually changes behavior
- The env code is unchanged between the two runs
You'll be able to
- Use the factory to make the env swappable
- Choose between type and instance overrides
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Reporting: verbosity, severity and message IDs
Instrument components with `uvm_info at sensible verbosities, use the right severities, and then from the test raise/lower verbosity globally and filter one noisy message ID so logs stay readable.
Requirements
- `uvm_info/`uvm_warning/`uvm_error/`uvm_fatal used appropriately
- Verbosity levels (LOW/MEDIUM/HIGH/DEBUG) chosen deliberately
- A runtime verbosity change from the test
- One message ID filtered or demoted
You'll be able to
- Produce logs that scale from summary to debug
- Control message noise at runtime
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
uvm_event and uvm_barrier synchronization
Coordinate components that don't hold each other's handles: share a uvm_event through the uvm_event_pool (one triggers with data, another waits and reads it), and gate several components with a uvm_barrier until all arrive.
Requirements
- A shared uvm_event fetched from the event pool
- trigger(data) on one side, wait_trigger_data on the other
- A uvm_barrier with a threshold gating progress
- No direct component-to-component handles used
You'll be able to
- Synchronize components without wiring handles
- Use uvm_event data passing and barriers
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Sequences & TLM
0/4Generate stimulus with sequences, coordinate multiple agents with a virtual sequence, and move data between components with TLM.
Sequence and sequencer
Write a sequence that generates a constrained series of transactions and starts on an agent's sequencer, plus a second sequence that reuses the first. Show the body()/start_item/finish_item handshake.
Requirements
- A sequence using start_item/finish_item in body()
- Constrained randomization inside the sequence
- A sequence that calls another (layered) sequence
- Started from the test via seq.start(sequencer)
You'll be able to
- Generate stimulus with sequences
- Layer sequences for reuse
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Virtual sequence coordinating two agents
Build a virtual sequence (running on a virtual sequencer) that orchestrates two agents — for example, program a config on one bus while driving traffic on another — with a defined ordering between them.
Requirements
- A virtual sequencer holding handles to both agent sequencers
- A virtual sequence starting sub-sequences on each
- A defined ordering/synchronization between the two streams
- No direct pin access — everything through sequences
You'll be able to
- Coordinate multi-agent stimulus centrally
- Separate 'what scenario' from 'which bus'
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
TLM analysis port to scoreboard and coverage
Broadcast monitored transactions on a single analysis port to two subscribers — a scoreboard and a functional-coverage collector — using analysis_imp/exports so both receive every transaction.
Requirements
- One monitor analysis port, two subscribers
- A coverage subscriber sampling a covergroup on write()
- The scoreboard and coverage both see all transactions
- Connections made in connect_phase
You'll be able to
- Fan out transactions with analysis ports
- Attach coverage as a subscriber
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Sequence response handling and p_sequencer
Extend a sequence to consume the driver's response: the driver returns an rsp via put_response, the sequence collects it with get_response, and the sequence reaches a config object on the sequencer through a declared p_sequencer.
Requirements
- Driver returns a response tied to the request
- Sequence calls get_response(rsp)
- A declared p_sequencer used to reach a sequencer member
- A note on response ordering and rsp id
You'll be able to
- Handle driver responses in a sequence
- Access sequencer state via p_sequencer
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Register layer (RAL) & integration
0/3Model the DUT's registers and access them through the register abstraction layer — the last big UVM interview topic.
RAL model with adapter and predictor
Build a small register block (a couple of config/status registers) as a uvm_reg_block, connect it to your bus agent with a reg adapter, and add a predictor so the model tracks the DUT as the monitor observes bus activity.
Requirements
- A uvm_reg_block with fields and access policies (RW/RO/W1C)
- A reg2bus/bus2reg adapter for your protocol
- A predictor fed from the monitor's analysis port
- A test doing reg.write()/reg.read() and a mirror check
You'll be able to
- Model registers with RAL
- Keep the model mirror in sync with a predictor
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Frontdoor vs backdoor register access
Access the same register two ways: a frontdoor write/read that runs real bus cycles through the adapter, and a backdoor peek/poke that reaches the DUT register directly. Compare timing and when each is appropriate.
Requirements
- A frontdoor access driving actual bus transactions
- A backdoor access via an hdl_path (no bus cycles)
- A mirror/predict check that both agree
- A note on when backdoor is and isn't valid
You'll be able to
- Use frontdoor and backdoor access correctly
- Explain the timing and coverage trade-offs
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Register access APIs: desired vs mirrored
Exercise the RAL access API on one register: write/read over the bus, peek/poke via backdoor, set() plus update() to push a desired value, and get()/mirror() to read the model — explaining the difference between desired and mirrored values.
Requirements
- write/read and peek/poke used correctly
- set() then update() to push only changed registers
- get()/mirror() reading model vs DUT
- An explanation of desired vs mirrored
You'll be able to
- Use the full RAL access API
- Explain desired vs mirrored register state
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Put it to work
Drill the matching interview questions, then see where this module sits in the full Design Verification roadmap.