Search code examples
system-veriloguvm

How to get property of class handle after override in UVM?


I'm trying to understand UVM Override. I was made a simple Override example as the below

    module test_module ();
`include "uvm_macros.svh"
  import uvm_pkg::*;
 
  class agent_a extends uvm_agent;
    `uvm_component_utils(agent_a)
 
    function new(string name = "agent_a", uvm_component parent = null);
      super.new(name, parent);
    endfunction : new
  endclass : agent_a
 
  class agent_b extends agent_a;
    `uvm_component_utils(agent_b)
 
    string field = "agent_b.field";
 
    function new(string name = "agent_b", uvm_component parent = null);
      super.new(name, parent);
    endfunction : new
  endclass : agent_b
  
    class agent_c extends uvm_env;
      `uvm_component_utils(agent_c)
 
    string field = "agent_c.field";
 
      function new(string name = "agent_c", uvm_component parent = null);
      super.new(name, parent);
    endfunction : new
  endclass : agent_c
  
 
  agent_a agent_a_h;
 
  initial begin
    
    agent_a::type_id::set_type_override(agent_c::get_type());
    factory.print();

    agent_a_h = agent_a::type_id::create("agent_a_h", null);

    $display("field = ", agent_a_h.field);
    
  end
endmodule : test_module

When I ran the above simulation. I encounter below Error message.

    $display("field = ", agent_a_h.field);
                                       |
xmvlog: *E,NOTCLM (testbench.sv,46|39): field is not a class item.

If I understand as well about override, I can use agent_c class instead agent_a after override.

then agent_a agent_a_h; becomes agent_c agent_a_h;

then it could be displayed agent_a_h.field without error .

but why does it say as "field" is not a class item?

#update question for override from derived class

module test_module ();
`include "uvm_macros.svh"
  import uvm_pkg::*;
 
  class agent_a extends uvm_agent;
    `uvm_component_utils(agent_a)
 
    function new(string name = "agent_a", uvm_component parent = null);
      super.new(name, parent);
    endfunction : new
    
    virtual function display();
      $display("agent_a.display1");
    endfunction
    
  endclass : agent_a
 
  class agent_b extends agent_a;
    `uvm_component_utils(agent_b)
 
    string field = "agent_b.field";
 
    function new(string name = "agent_b", uvm_component parent = null);
      super.new(name, parent);
    endfunction : new
    
        
    virtual function display();
      $display("agent_b.display2");
    endfunction
    
    
  endclass : agent_b
  
    class agent_c extends uvm_agent;
      `uvm_component_utils(agent_c)
 
    string field = "agent_c.field";
 
      function new(string name = "agent_c", uvm_component parent = null);
      super.new(name, parent);
    endfunction : new
      
              
    virtual function display();
      $display("agent_c.display3");
    endfunction
    
  endclass : agent_c
  
 
  agent_a agent_a_h;


 
  initial begin

    agent_a::type_id::set_type_override(agent_c::get_type());
    factory.print();

    agent_a_h = agent_a::type_id::create("agent_a_h", null);

   // $display("field = ", agent_a_h.field);
    
    agent_a_h.display();
    
  end
endmodule : test_module

I update code as the above, for figure out What if there are 2 class extended uvm_agent, ##################################################################

What If I want drv2 class to add into old testbench( drv class),
Does it impossible to override between drv2 class and drv? Should I have to add drv2 class below to C orc D in drv class hierachy? enter image description here


Solution

  • agent_a_h is of type agent_a, and as a result, it contains no such field.

    First of all, you cannot override agetn_a with agent_c. Those classes are unrelated and there is no way to use factory override to do so. You will get run-time errors here.

    In object-oriented programming in order to do something with a derived class objects through a base class pointer, you should use a virtual function.

    I demonstrated these 2 points in modified code below.

    1. created a virtual function getField()
    2. used agent_b to override
    `include "uvm_macros.svh"
    
    module test_module ();
       import uvm_pkg::*;
       
    class agent_a extends uvm_agent;
       `uvm_component_utils(agent_a)
       
       function new(string name = "agent_a", uvm_component parent = null);
          super.new(name, parent);
       endfunction : new
       
       virtual function string getField(); //<<<<<<
          return "";
       endfunction
       
    endclass : agent_a
       
    class agent_b extends agent_a;
       `uvm_component_utils(agent_b)
       
       string  field = "agent_b.field";
       
       function new(string name = "agent_b", uvm_component parent = null);
          super.new(name, parent);
       endfunction : new
       
       virtual function string getField(); // <<<<<<<
          return field;
       endfunction
    endclass : agent_b
          
       agent_a agent_a_h;
       
       initial begin
          agent_a::type_id::set_type_override(agent_b::get_type()); // <<<<<<
          agent_a_h = agent_a::type_id::create("agent_a_h", null);
    
          $display("field = ", agent_a_h.getField());
       end
    endmodule : test_module
    

    Answering your update: there is no way to override base class drv with an non-related class drv2. The classes for override must have parent/child type relation ship in order for that.

    But in your case, they have a common uvm_agent class parent. If you use it as a base class, than you can override it either with drv or drv2.

    That means that you have to plan accordingly.

    ======================= Here is some extra explanation for your comment question. Currently you have the following type inheritance:

    uvm_agent --> agent_a
              |   |--> agent_b
              |--> agent_c
    

    You use agent_a as a base pointer: agent_a agent_a_h; This allows you to override agent_a with agent_b when you create agent_a_h. Basically the factory create an object of type agent_b and assigns it to the handle of its super class type (agent_a).

    This cannot be done with agent_c because agent_a is not its base class.

    To fix this problem you should notice that uvm_agent is eventually a base class for all of those classes. Therefore, it could be used as such in overrides:

       uvm_agent handle;
       ...
       uvm_agent::type_id::set_type_override(agent_X::get_type());
       handle = uvm_env::type_id::create("agent_X_handle", null);
    

    without uvm it could be expressed as the following.

       uvm_agent handle;
       agent_X agent_X_h = new;
       handle = agent_X_H;
    

    Now, the problem is that the uvm_agent class is a third-party library class and does not have any of the members which you care about, e.g. 'display'

    The solution I suggested is following this scheme:

    uvm_agent --> my_agent  --> agent_a
                            |   |--> agent_b
                            |--> agent_c
    

    where my_agent is a virtual class containing the functions you need:

    class my_agent extends uvm_agent;
         virtual function void display();
         endfunction
         ...
    endclass
    class agent_a extends my_agent; ...
    class agent_b extends agent_a; ...
    class agent_c extends my_agent; ...
    

    In this case you can have my_agent as a base handle and do your overrides to any of the class types in the tree:

    overrides:

       my_agent handle;
       ...
       my_agent::type_id::set_type_override(agent_X::get_type());
       handle = my_agent::type_id::create("agent_X_handle", null);