uvm_object & uvm_component
The two base classes of UVM — understand when to extend uvm_object vs uvm_component and the utility macros.
uvm_object & uvm_component
Everything in UVM inherits from one of two base classes. Knowing which to use is essential.
The Class Hierarchy
textuvm_void │ uvm_object ← Data / transient items ┌─────┴──────┐ uvm_transaction uvm_component ← Structural / persistent │ ┌────┴─────┐ uvm_sequence_item uvm_driver uvm_monitor uvm_env ...
uvm_object — For Data Items
Use uvm_object for things that represent data or configuration:
- Sequence items (transactions)
- Configuration objects
- Register models
- Anything created, used, and discarded
systemverilogclass apb_transaction extends uvm_sequence_item; `uvm_object_utils(apb_transaction) rand bit [31:0] addr; rand bit [31:0] data; rand bit write; function new(string name = "apb_transaction"); super.new(name); endfunction // Convert to human-readable string for debug function string convert2string(); return $sformatf("addr=0x%08h data=0x%08h %s", addr, data, write ? "WR" : "RD"); endfunction endclass
Key characteristics of uvm_object:
| Property | Value |
|---|---|
| Constructor | Takes only name |
| Phases | ❌ No phases |
| Lifetime | Transient — created and destroyed |
| Hierarchy | ❌ No parent-child tree |
| Copy/Compare | ✅ Supports clone(), copy(), compare() |
uvm_component — For Structural Elements
Use uvm_component for things that are part of the testbench structure:
- Drivers, monitors, sequencers
- Agents, environments
- Scoreboards, coverage collectors
systemverilogclass apb_driver extends uvm_driver #(apb_transaction); `uvm_component_utils(apb_driver) virtual apb_if vif; function new(string name, uvm_component parent); super.new(name, parent); // Note: takes parent! endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); if (!uvm_config_db#(virtual apb_if)::get(this, "", "vif", vif)) `uvm_fatal("NOVIF", "Virtual interface not found") endfunction task run_phase(uvm_phase phase); // Drive signals... endtask endclass
Key characteristics of uvm_component:
| Property | Value |
|---|---|
| Constructor | Takes name and parent |
| Phases | ✅ build, connect, run, report, etc. |
| Lifetime | Persistent — lives for entire simulation |
| Hierarchy | ✅ Forms a parent-child tree |
| Copy/Compare | ❌ Not supported |
The Utility Macros
| Macro | Use With | What It Does |
|---|---|---|
\uvm_object_utils(T) | uvm_object subclasses | Registers type T with the factory |
\uvm_component_utils(T) | uvm_component subclasses | Registers type T with the factory |
Always register your classes. Without registration, the factory can't create or override them.
Quick Decision Guide
| Question | Answer |
|---|---|
| Does it have a parent in the hierarchy? | → uvm_component |
| Is it data flowing through the testbench? | → uvm_object |
| Does it need build/connect/run phases? | → uvm_component |
| Is it a transaction or config? | → uvm_object |
Field Automation (Optional)
UVM provides field macros for automatic copy(), compare(), print(), pack():
systemverilogclass my_txn extends uvm_sequence_item; `uvm_object_utils_begin(my_txn) `uvm_field_int(addr, UVM_ALL_ON) `uvm_field_int(data, UVM_ALL_ON) `uvm_field_enum(op_t, op, UVM_ALL_ON) `uvm_object_utils_end rand bit [31:0] addr; rand bit [31:0] data; rand op_t op; function new(string name = "my_txn"); super.new(name); endfunction endclass
Now you can do:
systemverilogmy_txn a, b; a = my_txn::type_id::create("a"); a.randomize(); // Clone b = my_txn::type_id::create("b"); b.copy(a); // Compare if (!a.compare(b)) `uvm_error("CMP", "Mismatch!") // Print a.print();
Performance note: Field macros add overhead. In high-performance simulations, implement
do_copy()anddo_compare()manually.