Monday, June 5, 2017

Difference between copy and clone method in UVM

I've been confused for a while about how copy and clone method works in UVM.
The confusion is about whether clone = create+deep copy?
In my code, when I used clone method, it was not deep copy by default. I've to explicitly write do_copy method.

Today I spent some time to explore about it and found the answer.

Please note that if you implement do_copy in your derived object, clone will have deep copy else it only copies the fields mentioned in `uvm_object_utils*.

Here is the mimicking behavior of copy and clone method of UVM
typedef base_class;
typedef derived_class;
function base_class create();
  derived_class tmp;
  tmp = new();
  return tmp;
endfunction
class base_class;
  int A = 7;
  virtual function do_copy(base_class rhs);
  endfunction
  virtual function copy(base_class rhs);
    do_copy(rhs);
  endfunction
  virtual function base_class clone();
    base_class base;
    base = create();
    base.copy(this);
    return (base);
  endfunction
endclass
class derived_class extends base_class;
  int A = 5;
  function do_copy(base_class rhs);
    derived_class derived;
    $cast(derived,rhs);
    super.do_copy(rhs);
    A = derived.A;
  endfunction
endclass

module test();
  derived_class d1,d2,d3;
  initial
  begin
    d1 = new();
    d1.A = 10;
    d3 = new();
    d3.copy(d1);
    $cast(d2,d1.clone());
    $display("A in d1 is %0d",d1.A);
    $display("A in d2 is %0d",d2.A);
    $display("A in d3 is %0d",d3.A);
    d1.A = 20;
    $display("A in d1 is %0d",d1.A);
    $display("A in d2 is %0d",d2.A);
    $display("A in d3 is %0d",d3.A);
  end 
endmodule
Output : 
A in d1 is 10 A in d2 is 10 A in d3 is 10 A in d1 is 20 A in d2 is 10A in d3 is 10
There are two function used here copy and clone.
copy : d3.copy(d1); which is simply deep copy of d1 to d3. It works as below.
1. d3 calls copy function which is defined in base_class.
2. copy function calls do_copy, as do_copy is virtual method, always latest definition of function will be executed. There is only one implementation of a virtual method per class hierarchy, and it is always the one in the latest derived class. So do_copy from "derived class" will be called.

clone : $cast(d2,d1.clone()); This method works as below.
1. d1.clone() calls definition of clone from base class.
2. clone calls create method which, returns handle of type derived_class.
3. A child class handle can be directly assign to base class.
4. base.copy(this); This is basically deep copy of this(here d1) to base.
5. So clone method return class variable of type "base_class" which we need to cast in derived_class, then only we can access member of class.

If you have noticed, here there is one dilemma. 
base.copy(this); calls copy function from base class , which call do_copy of derived class. So in turn do_copy is called from handle of object of type base_class. So how in do_copy it can access variable A, since it is not defined in base_class.
Reason is that "A" is being used by do_copy function which is in derived class. So context of A will be derived_class.