Uvm_component_utils with parameters

Hi All,

I’m looking for a way to get a
“my_agent::type_id::create(“name”, this, parameter1, parameter2);”
in place.
Is that possible with the uvm macros?
And if so how?
If not what would be the way to go?

Thanks,

Frodus

I am having the exact same problem. I don’t think there is a way to pass a parameter into a uvm class as an arguement (in the software sense), but you can “parameterize” a class like you would parameterize an RTL module. I have an open case with Mentor to discuss this… In my case, I am trying to pull an array of virtual interfaces from the configuration table, and I need to get the string names (used as the key into the table) from the environment down to the driver. If you get any further responses, I would love to hear them.

Check this out…

http://www.doulos.com/knowhow/sysverilog/uvm/easier_uvm/configuration/

When you are dealing with parameterized classes in UVM, you need to use the “param” version of the factory registration macros to register with the factory. You can then set the parameters when you create an object. Example code would look something like this:

class my_param_class #(int paramA = 5, string paramB = "hello") extends uvm_component;
   `uvm_component_param_utils(my_param_class#(paramA, paramB))

   //The rest of the class

endclass : my_param_class

class another_class extends uvm_component;
   `uvm_component_utils(another_class)

   my_param_class #(10, "goodbye")  my_class_h;

   //Constructor, etc.

   function void build_phase(uvm_phase phase);
      super.build_phase(phase);
    
      my_class_h = my_param_class #(10, "goodbye")::type_id::create("my_class_h", this);

   endfunction : build_phase

endclass : another_class
1 Like

In reply to Michael Horn:

Thanks a lot this looks like the implementation I was looking for.

Bye,

Frodus

I using a parameterized class in for loop, and I got the error saying:
“Class Specialization Parameter must be constant”

I am trying to give the Agent, Driver, and Monitor an ID Number, and I am creating the Agents in a for loop inside the Environment. When I use the for loop variable as the ID Number, I get the error.

The ID numbers have to be generated on the fly because I don’t know how many Agents will be created in the test until the test is run.

In reply to aaron:

An ID number is something you probably not parametrize in a class. Make it a property of the class instead.

See the following DVCon paper for more details: http://go.mentor.com/yin-and-yang

Dave,

I read the paper, but I don’t fully understand. I need an ID in the driver class to pick the correct virtual interface from the config table. There could be any number of parallel drivers all with the exact same code, but pointing to different virtual interfaces and getting direction from different sequencers. It would be nice to be able to give the agent and all it’s children one ID number, so that agent N contains driver N and sequencer N. Could you please show some example code of what you mean? Thank you!

In reply to aaron:

Aaron,

You don’t need to the agents or its children additional IDs. When you create each agent in a for loop, you will need to give each agent a unique name that will become a path name that can be used by the config database to target specific overrides.

class my_env extends uvm_env;
my_agent agents_h[]
function void build_phase(uvm_phase phase);
  ...
  for (int i;i<N;i++)
      agents_h[i] = my_agent::type_id::create($sformatf("agent_%0d",i),this);
  ...
endfunction
endclass

When you set up your virtual interfaces, you can do

uvm_config_db#(virtual my_itf)::set(null, "*.agent_0", "v_itf", DUT.my_itf_instance);

Dave,

Thank you for the response. I am a newbie to configuration tables, so please be patient with me :). I will need some spoon feeding.

In my top level, I put my virtual interfaces in the config table like this:
************** top.sv ********************

dut_if_client         difc[`NUM_MEM_CLIENTS] (.reset(reset), .clk(clk));
dut_if_client_wrapper vifc[`NUM_MEM_CLIENTS];  

  generate
    // Construct the virtual interfaces...
    for (genvar i = 0; i < `NUM_MEM_CLIENTS; i++)
      initial vifc [i] = new (difc[i]);
  endgenerate

  initial begin
    string my_vif_name; 
    for (integer i = 0; i < `NUM_MEM_CLIENTS; i++) begin
      my_vif_name = $sformatf("vif_c%0d", i);
      `ovm_info("top.sv; virtual interface name", my_vif_name, OVM_MEDIUM)
      set_config_object("*", my_vif_name, vifc[i], 0);
    end // for loop    
     run_test(); 
  end

Then in the environment I create the agents like this:
****************** env.sv ************************

virtual function void build;
    super.build(); 
    for (integer i = 0; i < `NUM_MEM_CLIENTS; i++) begin
      string my_agnt_name;
      my_agnt_name  = $sformatf("agnt_drv%0d", i);  
      $display("ENV:  Create Loop %0d", i);
      agnt_drv[i]   = tb_agent_mem_client::type_id::create(my_agnt_name, this);
    end // for loop
  endfunction

Then in each of the drivers, I connect to the virtual interface like this:
********************* tb_driver_mem_client.sv ****************************

class tb_driver_mem_client extends ovm_driver #(trans_item_mem_client);
  `ovm_component_utils(tb_driver_mem_client)

  static int id_static = 0;
  int id;
  
  virtual dut_if_client vif_client;


  function new (string name, ovm_component parent);
    super.new(name, parent);
    id = id_static++;
  endfunction


  function void build ();
    super.build();
    assign_vi;
  endfunction

  function void assign_vi;
    string my_vif_name;
    ovm_object     obj;
    dut_if_client_wrapper w;
    //---------------------------------------
    
    my_vif_name = $psprintf("vif_c%0d", id);
    assert (get_config_object(my_vif_name, obj, 0));
    assert ($cast(w, obj));
    vif_client = w.vif;
  endfunction
  
 // Other functions...
endclass

I currently use a static integer as a way to loop through the different virtual interface names “vif_cN”, where N is the ID number. It works, but it seems like what you are trying to explain to me in the last post is a much better technique.

When you said to use uvm_config_db, did you mean at the top level where the virtual interfaces are declared? If so, I still do not see how to do a “get_config” by name in the driver class (even though we named the agents). Can you please explain?

Again, thank you for the help!

In reply to aaron:

Oh, I see you are using OVM, not UVM. They work pretty much the same here, but you must use set/get_config_object instead of uvm_config_db.

In any case, the key difference between what you wrote versus what I suggested is that you are embedding the instance information into the field name. The field name that you get should always be the same and you should just change the instance name when you apply the set. That way your driver will not need an id.

So your top level module should have

initial begin
    string my_instance_name;
    for (int i = 0; i < `NUM_MEM_CLIENTS; i++) begin
      my_instance_name = $sformatf("whatever_env.agnt_drv%0d.*", i);
      `ovm_info("top.sv; virtual interface name", my_instance_name, OVM_MEDIUM)
      set_config_object(my_instance_name, "vif", vifc[i], 0);
    end // for loop    
     run_test(); 
  end

Then your driver code will be much simpler because it will get the specific setting depending on which instance it is part of.

class tb_driver_mem_client extends ovm_driver #(trans_item_mem_client);
  `ovm_component_utils(tb_driver_mem_client)
 
  virtual dut_if_client vif_client;
 
  function new (string name, ovm_component parent);
    super.new(name, parent);
  endfunction
 
  function void build ();
    super.build();
    if (!get_config_object("vifc", obj, 0)) `ovm_error("NOVIFC","No virtual interface provided")
    if($cast(w, obj)) `ovm_error("NOVIFC","vifc provided is not compatible with vifc required")
    vif_client = w.vif;
  endfunction
 
 // Other functions...
endclass

That did it. There were a few minor bugs in your example, but I am sure they were there just to test me :). Thank you so much!

In reply to Michael Horn:

The main difference between uvm_component_utils and uvm_component_param_utils is that -
initial one register the components without parameters and the latter one does it with parameters.
Is that all?

So, when uvm_component_utils is used, the argument used - class name is registered here.
and,
when uvm_component_param_utils is used, arguments used - parameterized class is registered here.
Is that all??

In reply to Sang :

Actually, the only difference is uvm_component_utils registers a string name, and the other macro doesn’t. The macro does not know whether your class is parameterized or not.