Why This Matters
The Problem: Without understanding hierarchy, you'll be confused about why components can't find each other, why configuration doesn't work, or why factory overrides fail.
The Solution: UVM's hierarchy is like a family tree—it organizes your testbench so every component knows its place and can find what it needs.
Before diving into phases and components, it's crucial to understand how UVM organizes your testbench. Think of UVM like a family tree—every component has a parent, and together they form a hierarchy.
The Root of Everything: uvm_root
At the very top of every UVM testbench sits uvm_root, also known as
uvm_top.
This is a singleton object (only one exists) that manages the entire
simulation. You never create it yourself—UVM does this automatically.
What does uvm_root do?
- Starts Phasing: It kicks off the build, connect, and run phases for all components.
- Manages the Hierarchy: It keeps track of every component in your testbench.
- Handles run_test(): When you call
run_test("my_test"), uvm_root creates your test and starts the simulation.
The Component Tree Structure
Every UVM testbench follows a standard hierarchy. Here's what a typical tree looks like:
uvm_root (uvm_top)
+-- my_test
+-- env
├-- agent
| ├-- sequencer
| ├-- driver
| +-- monitor
+-- scoreboard
Parent-Child Relationships
When you create a component using the factory (type_id::create()), you pass
this as the second argument.
This tells UVM: "I am the parent of this new component."
// Inside the Test's build_phase
function void build_phase(uvm_phase phase);
// Create the environment. "this" (the test) is the parent.
env = my_env::type_id::create("env", this);
endfunction
// Inside the Environment's build_phase
function void build_phase(uvm_phase phase);
// Create the agent. "this" (the env) is the parent.
agent = my_agent::type_id::create("agent", this);
scoreboard = my_scoreboard::type_id::create("scoreboard", this);
endfunction
// Inside the Agent's build_phase
function void build_phase(uvm_phase phase);
// Create driver, monitor, sequencer. "this" (the agent) is the parent.
sequencer = my_sequencer::type_id::create("sequencer", this);
driver = my_driver::type_id::create("driver", this);
monitor = my_monitor::type_id::create("monitor", this);
endfunction
Why Does Hierarchy Matter?
The hierarchy isn't just for organization—it's the foundation for three critical UVM features:
- Phasing: UVM uses the tree to execute phases in the correct order (top-down for build, bottom-up for connect).
- Configuration: The
uvm_config_dbuses hierarchical paths to deliver settings to the right components. - Factory Overrides: Instance overrides target specific components using
their hierarchical path (e.g.,
"env.agent.driver").
Simple Analogy
Think of the UVM hierarchy like a company org chart. The CEO (uvm_root) is at the top. Below that is the VP (Test), then the Manager (Environment), then the Team Leads (Agents), and finally the individual contributors (Driver, Monitor, Sequencer). Everyone knows who their boss is, and the company can send memos (configuration) or replace people (factory overrides) based on their position in the org chart.