FACTORY - NISHUNISARGA/UVM_notes GitHub Wiki
What is a Factory in UVM?
A factory in UVM is a mechanism that dynamically and flexibly creates objects or components. It allows you to substitute one implementation of an element or object with another without modifying the original code.
Key Features
Dynamic Object Creation:
- Instead of hardcoding
new()
to create objects, the factory usescreate()
to determine the type of object to instantiate dynamically.
Type Overrides:
- The factory allows you to replace a base type with a derived type at runtime using
set_type_override()
orset_inst_override()
.
Polymorphism:
- It enables runtime polymorphism, which is a cornerstone of object-oriented programming.
Flexibility:
- Useful for creating modular and reusable test benches that can adapt to different configurations or use cases.
Why is the Factory Used?
Reusability:
- The same testbench can be used for different DUT configurations by replacing components or objects dynamically.
Debugging:
- You can replace components with debugging versions without changing the testbench code.
Runtime Customization:
- Enables testbench customization based on the simulation environment or command-line arguments.
Scalability:
- Makes it easy to extend testbenches for future features or designs.
Example for Explanation
Without Factory:
Hardcoded object creation:
my_component comp;
comp = my_component::new("comp");
Problem: If you want to replace my_component with derived_component, you must modify the code.
With Factory:
Dynamic object creation:
my_component::type_id::set_type_override(derived_component::get_type());
my_component comp;
comp = my_component::type_id::create("comp");
Now, the testbench automatically uses derived_component instead of my_component, without code changes.
How to Answer in an Interview
1. Definition
The UVM factory is a mechanism for dynamic and flexible object creation. It allows components or objects to be replaced at runtime without changing the original code, enhancing reusability and flexibility.
2. Benefits
- Dynamic replacement: Easily switch components at runtime.
- Reusability: Testbench can handle multiple configurations.
- Debugging flexibility: Swap components for debug or production versions.
- Scalability: Makes it easy to extend testbenches for future requirements.
3. Example (Optional)
Suppose I have a testbench with a base_component. Later, I want to replace it with a derived_component for testing additional features. Using the factory, I can set a type override dynamically like this:
base_component::type_id::set_type_override(derived_component::get_type());
When the testbench runs, it creates the derived_component instead of base_component, all without modifying the original code.
Bonus Tip
If you're asked what happens if you don't use the factory, mention:
- Hardcoding object types limits reusability and flexibility.
- Debugging becomes difficult as you can't dynamically switch to debug components.
- The testbench becomes tightly coupled to specific implementations, making it harder to adapt to new requirements.
Mock Q&A: Factory in UVM
Q1: What is the purpose of the UVM factory?
A: The UVM factory is a mechanism that dynamically creates and configures objects or components at runtime.
It allows for:
- Type substitution (overriding a base type with a derived type).
- Reusability by avoiding hardcoding object types.
- Test flexibility, as you can dynamically change behavior for different scenarios.
Q2: How do you create an object using the UVM factory?
A: You use the create() method provided by the factory. Instead of new(), the factory dynamically resolves the type of the object.
Example:
packet pkt = packet::type_id::create("pkt");
This allows the factory to override the packet type with a derived type, if configured.
Q3: What is the difference between set_type_override_by_type and set_inst_override_by_type?
A:
-
set_type_override_by_type: Replaces all instances of a base type with a derived type globally. Example:
packet::type_id::set_type_override_by_type(special_packet::get_type());
-
set_inst_override_by_type: Replaces a specific instance of a base type with a derived type. Example:
packet::type_id::set_inst_override_by_type(special_packet::get_type(), "pkt1");
Q4: Can you configure an object's properties dynamically using the factory?
A: Yes, after creating an object, you can randomize or set its properties dynamically. For example:
packet pkt = packet::type_id::create("pkt");
pkt.randomize() with { addr == 0x1000; data == 0x1234; };
Q5: How does the UVM factory improve testbench flexibility?
A:
- Dynamic Polymorphism: Allows swapping implementations without modifying source code.
- Reusability: Testbenches can reuse the same base structure with different configurations.
- Centralized Control: Overrides allow global or instance-level customization for different test scenarios.
Advanced Concepts
Q6: What happens if a class isn’t registered with the factory?
A: If you try to create an object of an unregistered class using the factory, UVM will throw an error. Registration macros like uvm_object_utils
or uvm_component_utils
are necessary for factory use.
Q7: Can you override types after the testbench has started?
A: No, overrides must be set during the build phase or earlier. After the testbench starts running, the factory locks its configuration to ensure consistency.