UVM Set type/inst override: extended class with additional ports

Hello,

I am starting to use the UVM set_type_override in order to allow different designers to use the same Verification environment with different DUTs.

The problem I have encountered in a specific UVC is that I need to have in the base class for example 2 ports while in the extended one I need more (let’s say 4).
Where do I connect them? In the extended version of the environment class (this one overridden, too). At compilation/elaboration time connection is not accepted since such additional ports are not declared in the base class, since before the “create” method execution it is not known which class is going to be used.

At the same time if I use directly the custom class for the block with 4 ports, without using the base one already present in the environment, I have 2 modules with the same function and I have seen some conflicts while passing configuration objects thorough the hierarchy.

Is there any way to solve this problem with additional class ports for the best?

I hope I have made the question clear enough. Thanks in advance,

Sara

In reply to smarconi:

What do you mean by ports? Some code might be helpful in understanding the problem.

In reply to Tudor Timi:

I mean uvm_analysis_export/ports that are additional fields in the extended class (not present in the parent one) and that need to be connected in the connect_phase of the (extended) environment wrapper class.

As far as I see, set_type_override is just useful for modifying class task/functions behaviour, but variables (and for this reason also uvm_analysis_export/ports) cannot be referred.

For example:
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// class a_ref_model
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class a_ref_model extends uvm_component;

`uvm_component_utils_begin(analysis_ref_model)
`uvm_component_utils_end
	
uvm_analysis_export #(trans1) 		monitor1_export;
uvm_analysis_export #(trans2) 	        monitor2_export;
	
// Analysis FIFOs to provide blocking capabilities to each kind of transaction
uvm_tlm_analysis_fifo #(trans1)         container_1;
uvm_tlm_analysis_fifo #(trans2)         container_2;

function new(string name, uvm_component parent);
	super.new(name, parent);
endfunction: new

function void build_phase(uvm_phase phase);
	super.build_phase(phase);
            ....
endfunction: build_phase

function void connect_phase(uvm_phase phase);
....
endfunction: connect_phase

task run_phase(uvm_phase phase);
    ....
    endfunction: run_phase

endclass: a_ref_model

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// class a_custom_ref_model
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class a_custom_ref_model extends a_ref_model;

// configuration object
analysis_config cfg;

`uvm_component_utils_begin(a_custom_ref_model)
	`uvm_field_object(cfg, UVM_DEFAULT)
`uvm_component_utils_end



uvm_analysis_export #(trans3) 		a_monitor_export; 	
uvm_analysis_port #(trans3)             updated_a_ap; 

function new(string name, uvm_component parent);
	super.new(name, parent);
endfunction: new

function void build_phase(uvm_phase phase);
	super.build_phase(phase);
            ....
endfunction: build_phase

function void connect_phase(uvm_phase phase);
....
endfunction: connect_phase

task run_phase(uvm_phase phase);
    ....
    endfunction: run_phase

endclass: a_custom_ref_model

This are the 2 classes. While creating the wrapper a_custom_env as an extension of a_env it is needed to connect for example a_monitor_export to something. Using the a_ref_model (and then set_type_override in the test) it generates a compilation error since such export it is not part of the base class.

Thanks, sorry if the problem is unusual or not standard.

In reply to smarconi:

As far as I see, set_type_override is just useful for modifying class task/functions behaviour, but variables (and for this reason also uvm_analysis_export/ports) cannot be referred.

This isn’t necessarily true. What you need to do in that case is use a cast statement:


class a_custom_env;
  function void connect_phase(uvm_phase phase);
    a_custom_ref_model custom_ref_model;
    
    // I assume the ref model instance is called "ref_model")
    if(!$cast(custom_ref_model, ref_model)
      `uvm_fatal("CASTERR", "You forgot to set a type override on a_ref_model");

    // same for the monitor
    // ...
    
    custom_monitor.aport2.connect(custom_ref_model.monitor3_export);
  end
endclass

The reason you get the compile error is because, even though the instance is of type a_custom_ref_model, the compiler doesn’t know that. You have to tell it this using a cast statement. After telling it that you’re actually working with an instance of type “a_custom_ref_model”, you can access the new fields/functions/etc. defined in the extended class.

In reply to Tudor Timi:

You might also be able to use arrays of handles {exports / fifos} to make the hookup and usage of differing numbers of connection points more programmatic, and have a ‘size’ parameter (specified using parameterization or with an override) if you are using fixed size arrays, or a soft configuration value if dynamic arrays.

In reply to gordon:

@Gordon I see from Sara’s code that the ports are parameterized with different items, so using arrays isn’t possible. For ports of the same type this is for sure a good idea that would make the code cleaner.

In reply to Tudor Timi:

 class a_custom_env;
function void connect_phase(uvm_phase phase);
a_custom_ref_model custom_ref_model;
// I assume the ref model instance is called "ref_model")
if(!$cast(custom_ref_model, ref_model)
`uvm_fatal("CASTERR", "You forgot to set a type override on a_ref_model");
// same for the monitor
// ...
custom_monitor.aport2.connect(custom_ref_model.monitor3_export);
end
endclass 

I tried this and the compilation goes clearly fine, but the connection ( something like

 a_export.connect(custom_ref_model.b_monitor_export); 

) of the first port of custom ref model fails.
Are you sure that this is not just a reference model handle that exists only in the connect_phase function?

Otherwise I solved just not overriding the reference model and only overriding the env (where the custom ref model is created). Even if the base ref model is inherited from the basic env, it is not connected to anything and creates no conflicts.

You might also be able to use arrays of handles {exports / fifos} to make the hookup and usage of differing numbers of connection points more programmatic, and have a ‘size’ parameter (specified using parameterization or with an override) if you are using fixed size arrays, or a soft configuration value if dynamic arrays.

This could also be interesting but for such few ports I would prefer to solve in a more simple way.

Thanks you all.

In reply to smarconi:

Doing a $cast doesn’t create a copy; it just makes the destination handle point to the same object as the source handle. What does “it fails” mean exactly?

In reply to Tudor Timi:

Right. Sorry for answering too fast without checking. In order to avoid creating the basic ref model in the custom env I had totally re-written the build_phase, without using the super.build_phase(phase).
So no reference model was built, this is why no port of the ref model was found in the connect_phase!

Now it works also with the cast. Thanks a lot for your help (and understanding :-) )