Both $cast and Factory Overrides enable polymorphism in UVM, but they work at
different times and serve different purposes.
Understanding when to use each is crucial for writing flexible, maintainable testbenches.
What is $cast?
$cast is a SystemVerilog feature for run-time type checking
and conversion.
It allows you to safely convert a base class handle to a derived class handle.
// Base class handle
uvm_sequence_item item;
// Derived class handle
my_packet pkt;
// Get an item from the sequencer (returns base class)
seq_item_port.get_next_item(item);
// Cast it to the derived type to access specific fields
if (!$cast(pkt, item)) begin
`uvm_fatal("CAST", "Failed to cast item to my_packet")
end
// Now you can access derived class fields
pkt.payload_data = 8'hFF;
What are Factory Overrides?
Factory Overrides are a UVM feature for build-time component substitution.
They allow you to replace one class with another before objects are created.
// In your test's build_phase
function void build_phase(uvm_phase phase);
// Replace all instances of standard_driver with error_driver
standard_driver::type_id::set_type_override(error_driver::get_type());
super.build_phase(phase);
endfunction
// Now when the agent creates the driver:
driver = standard_driver::type_id::create("driver", this);
// UVM actually creates an error_driver instead!
Key Differences
|
Aspect |
$cast |
Factory Override |
|
When it happens
|
Run-time
(during simulation) |
Build-time
(before simulation starts) |
|
What it does
|
Converts an
existing handle from base to derived type |
Replaces
which class gets created |
|
Scope
|
Local
(affects only the specific handle) |
Global or
instance-specific (affects all or targeted creations) |
|
Typical use case
|
Accessing
derived class fields from a base class handle |
Swapping
components for different test scenarios |
When to Use $cast
- Receiving base class handles: When a function returns
uvm_sequence_item but you need to access fields in your derived
my_packet class.
- Callback implementations: When implementing
do_copy() or
do_compare() methods that receive uvm_object handles.
- TLM ports: When pulling items from a FIFO that stores base class types.
When to Use Factory Overrides
- Test-specific behavior: Replacing a standard driver with an
error-injection driver for negative testing.
- Configuration variations: Swapping a simple scoreboard with an advanced
one for specific tests.
- Debugging: Replacing a component with a debug version that has extra
logging.
- Reusability: Using the same environment code with different component
implementations.
Rule of Thumb
Use $cast when you're working with handles that already exist and need
to access derived class features.
Use Factory Overrides when you want to change what type of object gets
created in the first place.
Think of it this way: $cast is like putting on different glasses to see an object
differently.
Factory Override is like ordering a different product from the factory.