Unfortunately, even these macros will not create the necessary routines to print and override using the factory. You will need to register the class manually by writing this simple piece of code!
Well you anyway need the macro to do factory registration. What the second article recommends is that you not use the field macros.
So, this is OK:
class some_class #(type T) extends uvm_component;
T some_field;
int some_other_field;
`uvm_component_param_utils(some_class #(T))
// implement the utility functions by hand
// ... do_print, do_pack, do_copy, etc.
endclass
This should be avoided:
class some_class #(type T) extends uvm_component;
T some_field;
int some_other_field;
`uvm_component_param_utils_begin(some_class #(T))
`uvm_field_int(some_other_field);
// for 'some_field' you anyway can't do any automation
`uvm_component_param_utils_end
// implement the utility functions by hand
// ... do_print, do_pack, do_copy, etc.
endclass
Browsing a bit further (especially) looking to the section “ParameterizedTests” in the cookbook is that you would need to write the registration manually if string based factory lookup would be required?
The problem with uvm_*_utils (not uvm_params_util) is that as a macro, it only gets compiled once before any parameter overriding takes place. This macro defines a type that associates a type and a string to be registered with the factory. (See http://go.mentor.com/mcem for more details). The problem is that the macro only gets compiled once and will associate the same string with each class parametrization. This works fine if there is only one specialization of the class parameters, but as soon as there are multiple specializations, you will get an error. The `uvm_params_util macro works around this by only registering the class type with the factory without an associated string name. The manual registration process without using any macros allows you to create a unique string name for each
Error-[STASKEC_IAFSTC] Illegal argument to system task
testbench.sv, 7
“T::type_name”
Illegal argument T::type_name is passed to system task $sformatf.
Please correct the system task call and recompile.
Error-[CEPO] Cannot evaluate parameter override
testbench.sv, 7
The parameter override should be an expression containing only constant
numbers and previously defined parameters.
The override was applied to parameter ‘type_name’ of instance
‘_vcs_unit__1778430441.my_test_build_phase_drv’.
Source info: $sformatf(“driverB#(%s)”, T::type_name)
You did not override your driver’s
T parameter, leaving it as an
int. You should leave out the default
= int to force an parameter override. The trick of assigning an
int type to force an override is leftover from very early versions of SystemVerilog that did not allow declarations of a parameter without a default assignments.
The example from the second article inserted the factory registration code directly instead of using the `uvm_object_utils macro fixing a problem with the UVM macro. It declares
type_name as a
const static variable instead of a
localparam/parameter. You cannot use a variable, const or not in the declaration of another parameter.
In reply to justrajdeep:
You have removed the error, but your fix is not useful as the driver would normally be overridden with a class derived from the base class
uvm_sequence_item, not the base class itself.
You are correct that the article has a mistake. The packet and packetD classes cannot use the `uvm_object_utils macro and must register with the factory the same way as the driver does.