HomeProblemsTheoryUVM
Beginner3 min readChapter 5

Factory & Overrides

Master the UVM factory pattern — create objects/components via the factory and use type overrides for flexibility.

UVM Factory & Overrides

The UVM factory is one of the most powerful features of UVM. It lets you create objects and components indirectly — and swap implementations without changing any testbench code.


The Problem Without a Factory

systemverilog
// Hard-coded type — can't change without editing source my_driver drv = new("drv", this);

The Solution With a Factory

systemverilog
// Indirect creation — type can be overridden at runtime my_driver drv = my_driver::type_id::create("drv", this);

The factory sits between your code and the actual constructor, allowing you to substitute a derived class without touching existing code.


How to Use the Factory

Step 1: Register your class

systemverilog
class my_driver extends uvm_driver #(my_txn); `uvm_component_utils(my_driver) // ← Register! // ... endclass

Step 2: Always create via the factory

systemverilog
// For components (in build_phase): my_driver drv = my_driver::type_id::create("drv", this); // For objects (transactions, configs): my_txn txn = my_txn::type_id::create("txn");

Type Overrides

Global Override — Replace All Instances

systemverilog
class error_driver extends my_driver; `uvm_component_utils(error_driver) // Override run_phase to inject errors task run_phase(uvm_phase phase); // ... error injection logic ... endtask endclass // In the test's build_phase: function void build_phase(uvm_phase phase); // Every my_driver::type_id::create() now returns error_driver my_driver::type_id::set_type_override( error_driver::get_type() ); super.build_phase(phase); endfunction

Instance Override — Replace One Specific Instance

systemverilog
function void build_phase(uvm_phase phase); // Only "env.agent.driver" is overridden my_driver::type_id::set_inst_override( error_driver::get_type(), "env.agent.driver" ); super.build_phase(phase); endfunction

Practical Example: Error Injection

systemverilog
// Base transaction class base_txn extends uvm_sequence_item; `uvm_object_utils(base_txn) rand bit [7:0] data; function new(string name = "base_txn"); super.new(name); endfunction endclass // Extended: adds error injection capability class error_txn extends base_txn; `uvm_object_utils(error_txn) rand bit inject_error; // 10% of transactions will have errors constraint err_c { inject_error dist { 0 := 90, 1 := 10 }; } function new(string name = "error_txn"); super.new(name); endfunction endclass // Error test: override base_txn → error_txn globally class error_test extends base_test; `uvm_component_utils(error_test) function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); base_txn::type_id::set_type_override( error_txn::get_type() ); super.build_phase(phase); endfunction endclass

Every base_txn::type_id::create() call anywhere in the testbench now produces an error_txn — without editing a single line of existing code!


Debugging the Factory

Print all registered types and active overrides:

systemverilog
// In any phase: factory.print();

Factory Rules Summary

RuleWhy
Always use type_id::create(), never new()Enables overrides
Always register with utility macrosFactory needs to know about your class
Override type must extend the originalLiskov substitution principle
Set overrides before super.build_phase()Components are created in super