Confused virtual method down casting problem

HI,
I’m trying to understand between Down cast functionality and virtual methods.
And I was made simple example for test it as the below.



 class base_class;
  
  virtual function void display;
    $display("Inside base_class 0\n");
  endfunction
  
  virtual function void display2;
    $display("Inside base_class 2\n");
    
endfunction
  
  
endclass
 
class extended_class extends base_class;
  
   function void display;
    $display("Inside extended_class 1\n");
  endfunction
  
  function void display3;
    $display("Inside extended_class 3\n");
  endfunction
  
  function void display5;
    $display("Inside extended_class 5\n");
  endfunction
  
endclass

class extended_class2 extends extended_class;
  
   function void display;
    $display("Inside extended2_class 1\n");
  endfunction
  
  function void display3;
    $display("Inside extended2_class 3\n");
  endfunction
  
  function void display5;
    $display("Inside extended2_class 5\n");
  endfunction
  
endclass

 
module virtual_class;
  initial begin
    base_class     b_c;
    extended_class e_c;
    extended_class2 e2_c;
    
    b_c = new();
    e_c = new();

    $cast(e_c, b_c);
    b_c.display(); /Error Why?
    e_c.display(); /Error Why?
  end
endmodule

When I ran this code, I encounter

$cast(e_c, b_c);
|
xmsim: *E,BCLCST (./testbench.sv,61|8): Invalid cast: a value with the class datatype ‘$unit_0x4ccdf83b::base_class’ cannot be assigned to a class variable with the datatype ‘$unit_0x4ccdf83b::extended_class’.
Inside base_class 0

Could you let me know why I can’t down-cast?
I think there is no issue because they are hierarchically same. so I though it will work but this Down-cast make error.

In reply to UVM_LOVE:

Your $cast has to fail, because the classes you are casting are of different types.
Doing this :

module virtual_class;
  initial begin
    base_class     b_c;
    extended_class e_c;
    extended_class2 e2_c;
 
    e_c = new();
    b_c = e_c;

    $cast(e_c, b_c);
    b_c.display();
  end
endmodule

works perfectly, because e_c and b_c are now of the same type.
See an explanation also here:

In reply to chr_sue:

In reply to UVM_LOVE:
Your $cast has to fail, because the classes you are casting are of different types.
Doing this :

module virtual_class;
initial begin
base_class     b_c;
extended_class e_c;
extended_class2 e2_c;
e_c = new();
b_c = e_c;
$cast(e_c, b_c);
b_c.display();
end
endmodule

works perfectly, because e_c and b_c are now of the same type.
See an explanation also here:

Thanks SIr, I got it.
In Up-casting, I don’t need to assigning =. just I can casting between them.
But Down Casting, after assigning become same type, I can use $cast.

In reply to UVM_LOVE:

In reply to chr_sue:

Sir can you explain this?

module test_module ();
`include "uvm_macros.svh"
  import uvm_pkg::*;
 
class A; endclass
class B extends A; endclass
class C extends A; endclass

A a_h;
B b_h;
C c_h;


  
  initial begin
b_h = new;
a_h = b_h; // always legal to go up the inheritance tree
$cast(b_h, a_h); // $cast required - will succeed
    c_h = new();
    b_h = c_h;
    $cast(c_h, b_h); 

  end
endmodule : test_module

I got xrun: 20.09-s003: (c) Copyright 1995-2020 Cadence Design Systems, Inc.
    b_h = c_h;
            |
xmvlog: *E,TYCMPAT (testbench.sv,20|12): assignment operator type check failed (expecting datatype compatible with 'class test_module::B' but found 'class test_module::C' instead).
Error message.

I thought b_h and c_h are extended by same class.
But b_h and c_h are not same class type so.
I assign b_h = c_h;
But why does assign make error?

In reply to UVM_LOVE:

This is because classes B and C are 2 different types. The extension from class A does not matter.

In reply to chr_sue:

In reply to UVM_LOVE:
This is because classes B and C are 2 different types. The extension from class A does not matter.

Thus so I assign b_c = c_h;.
Did I something miss?

In reply to UVM_LOVE:

Yes this is the problem:

b_c = c_h;

In reply to chr_sue:

In reply to UVM_LOVE:
Yes this is the problem:

b_c = c_h;

I pass the simulation with only commented out b_c = c_h line
But I still didn’t get it.
Is there any special rule? I can’t find any illegal rule for this b_c = c_h line.
Could you give some guidance?

Can’t assign between different class type ? Only can between Family relationship (parents and child)?

In reply to UVM_LOVE:

As I said, B and C are 2 different classes. Then the handles b_c and c_h are also different objects you cannot assign. Finally it is limited to the family.

In reply to chr_sue:

In reply to UVM_LOVE:
As I said, B and C are 2 different classes. Then the handles b_c and c_h are also different objects you cannot assign. Finally it is limited to the family.

Sir,
What if they were registered by UVM Factory not $cast, then Can I override between b_h and c_h?

I think this will be one method for can’t casting class handles situation. what if b_h and c_h each they has the same methods and properties. I think UVM OVERRIDE will be the one way using $cast instead. Does this conceptually make sense?

In reply to UVM_LOVE:

You are mixing 2 different constructs.
(1) $cast is a SystemVerilog task/function. This is a language feature.
(2) override is a UVM methodology construct using SystemVerilog.

It would be great to know what your intention is to use $cast an override.

In reply to chr_sue:

In reply to UVM_LOVE:
You are mixing 2 different constructs.
(1) $cast is a SystemVerilog task/function. This is a language feature.
(2) override is a UVM methodology construct using SystemVerilog.
It would be great to know what your intention is to use $cast an override.

For understanding 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.

Does UVM Override has also limitation ? I checked https://verificationacademy.com/sessions/inheritance-and-polymorphism

it said that override must have the same prototype.
What does prototype mean?
Does prototype mean that they class must have the relationship between parents and child as $cast?

In reply to UVM_LOVE:

You cannot override objects/components which do not belong together and have a different function.
This is not a limitation. It helps you to do bad things.
See your example here

In reply to chr_sue:

In reply to UVM_LOVE:
You cannot override objects/components which do not belong together and have a different function.
This is not a limitation. It helps you to do bad things.
See your example here
Edit code - EDA Playground

Thanks for Great example Sir, How to change uvm_factory factory; to 1.1d version not 1.2?

In reply to UVM_LOVE:

And here is the solution for uvm-1.1d:

In reply to chr_sue:

In reply to UVM_LOVE:
And here is the solution for uvm-1.1d:
Edit code - EDA Playground

Sir, What if I want to override with some class they have the same parents, then can I override between them? such as Serge override(2) - EDA Playground ?

In reply to UVM_LOVE:

You can see your example fails. What you are doing means you could override an spi_agent with an apb_agent (as an example). And this is useless. Believe me.