Given a base class that has multiple derivatives, is there a way to receive those children types (as strings for example) through the base class or some partial name match via the factory?
I’ll give a concrete example complete with a use case:
class example_a_b_class_base extends uvm_object;
`uvm_object_utils(example_a_b_class_base)
rand int a;
rand int b;
//constructor and whatnot
endclass : example_a_b_class_base
class a_bigger_than_b extends example_a_b_class_base;
`uvm_object_utils(a_bigger_than_b)
constraint a_bigger_than_b_c {
a > b;
}
//constructor and whatnot
endclass : a_bigger_than_b
class a_smaller_than_b extends example_a_b_class_base;
`uvm_object_utils(a_smaller_than_b)
constraint a_smaller_than_b_c {
a < b;
}
//constructor and whatnot
endclass : a_smaller_than_b
class a_b_equal extends example_a_b_class_base;
`uvm_object_utils(a_b_equal)
constraint a_b_equal_c{
a == b;
}
//constructor and whatnot
endclass : a_b_equal
class random_a_b_type_generator extends uvm_object;
`uvm_object_utils(random_a_b_generator)
string a_b_class_names_q[$];
virtual function example_a_b_class_base get_random_a_b_class_type();
example_a_b_class_base return_obj;
//magic that would make a_b_class_names_q = {"a_bigger_than_b", "a_smaller_than_b", "a_b_equal"};
a_b_class_names_q.shuffle();
return_obj = uvm_factory::create_by_name(a_b_class_names_q[0]);
return (return_obj);
endfunction : get_random_a_b_class_type
endclass : random_a_b_generator
I’m looking for that “magic” function (in the comment of the last class)
I can create that string queue by myself, but if in the future there’s a new derived class of the base class, we might not not remember to put the string in the queue.
Use uvm_object_wrapper objects instead of strings.
You can use a static variable initialization in each class to “register” each object in the queue.
import uvm_pkg::*;
`include "uvm_macros.svh"
class example_a_b_class_base extends uvm_object;
`uvm_object_utils(example_a_b_class_base)
rand int a;
rand int b;
function new(string name=""); super.new(name);endfunction
local static uvm_object_wrapper base_q[$];
protected static function bit qregister(uvm_object_wrapper me);
base_q.push_back(me);
endfunction
// static varialbe makes sure qregister get called once before construcion.
local static bit qreg = qregister(example_a_b_class_base::get_type);
static function example_a_b_class_base get_random_a_b_class_type();
base_q.shuffle();
$cast(get_random_a_b_class_type,base_q[0].create_object());
endfunction
endclass : example_a_b_class_base
class a_bigger_than_b extends example_a_b_class_base;
`uvm_object_utils(a_bigger_than_b)
constraint a_bigger_than_b_c {
a > b;
}
function new(string name=""); super.new(name);endfunction
local static bit qreg = qregister(a_bigger_than_b::get_type);
endclass : a_bigger_than_b
class a_smaller_than_b extends example_a_b_class_base;
`uvm_object_utils(a_smaller_than_b)
constraint a_smaller_than_b_c {
a < b;
}
function new(string name=""); super.new(name);endfunction
local static bit qreg = qregister(a_smaller_than_b::get_type);
endclass : a_smaller_than_b
class a_b_equal extends example_a_b_class_base;
`uvm_object_utils(a_b_equal)
constraint a_b_equal_c{
a == b;
}
function new(string name=""); super.new(name);endfunction
local static bit qbit = qregister(a_b_equal::get_type);
endclass : a_b_equal
module top;
example_a_b_class_base handle;
initial repeat (10) begin
handle = example_a_b_class_base::get_random_a_b_class_type();
$display(handle.get_type_name());
end
endmodule
If you have a number of different base classes to randomly select their extensions, you can put this registration code in a pair of parameterized classes.
import uvm_pkg::*;
`include "uvm_macros.svh"
class register_base#(type base);
// one base_q for each base class type
local static uvm_object_wrapper base_q[$];
protected static function bit qregister(uvm_object_wrapper me);
base_q.push_back(me);
endfunction
// static varialbe makes sure qregister get called once before construcion.
static function base get_random_type();
base_q.shuffle();
$cast(get_random_type,base_q[0].create_object());
endfunction
endclass
class register#(type base, ext) extends register_base#(base);
local static bit qreg = qregister(ext::get_type);
endclass
class example_a_b_class_base extends uvm_object;
`uvm_object_utils(example_a_b_class_base)
rand int a;
rand int b;
function new(string name=""); super.new(name);endfunction
typedef register#(example_a_b_class_base,example_a_b_class_base) r;
endclass : example_a_b_class_base
class a_bigger_than_b extends example_a_b_class_base;
`uvm_object_utils(a_bigger_than_b)
constraint a_bigger_than_b_c {
a > b;
}
function new(string name=""); super.new(name);endfunction
typedef register#(example_a_b_class_base,a_bigger_than_b) r;
endclass : a_bigger_than_b
class a_smaller_than_b extends example_a_b_class_base;
`uvm_object_utils(a_smaller_than_b)
constraint a_smaller_than_b_c {
a < b;
}
function new(string name=""); super.new(name);endfunction
typedef register#(example_a_b_class_base,a_smaller_than_b) r;
endclass : a_smaller_than_b
class a_b_equal extends example_a_b_class_base;
`uvm_object_utils(a_b_equal)
constraint a_b_equal_c{
a == b;
}
function new(string name=""); super.new(name);endfunction
typedef register#(example_a_b_class_base,a_smaller_than_b) r;
endclass : a_b_equal
module top;
example_a_b_class_base handle;
initial repeat (10) begin
handle = register_base#(example_a_b_class_base)::get_random_type();
$display(handle.get_type_name());
end
endmodule
Now assume I register every object type in my env to the factory with this new macro.
Is it possible to write the “magic” part in a way that would allow me to grab any object type in my env (let’s say, “some_type”) and call
some_type::get_random_derivative()
and get a random derivative of that type?
The challenge here is each derivative has to fill a queue in super, but a different queue in super-super etc.
Couldn’t really figure this one out, but I think it could be useful for generating random stimulus if inheritance is used a lot to get different behaviors.