Monday, December 7, 2015

What is difference between copy and clone method in UVM

There are two methods we use to copy data of one uvm_object (transaction or sequence item) to another.
Copy and
Clone.

Here I will explain you difference between copy and clone.

See below code.
========================================================================
// do_copy method:
function void do_copy(uvm_object rhs);
  bus_item rhs_;
  if(!$cast(rhs_, rhs)) begin
  uvm_report_error("do_copy:", "Cast failed");
  return;
  end
  super.do_copy(rhs); // Chain the copy with parent classes
  delay = rhs_.delay;
  addr = rhs_.addr;
  op_code = rhs_.op_code;
  slave_name = rhs_.slave_name;
  data = rhs_.data;
  response = rhs_.response;
endfunction: do_copy

// Example of how do_copy would be used:
// Directly:
bus_item A, B;
A.copy(B); // A becomes a deep copy of B
// Indirectly:
$cast(A, B.clone()); // Clone returns an uvm_object which needs
// to be cast to the actual type
========================================================================
A.copy(B); is deep copy of  B. 
While B.clone() returns a new object of type uvm_object which we cast to type "bus_items". So in a way A becomes deep copy of B.

Below here I am 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 10
A 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. 
If I have written base.A then it would not work

No comments:

Post a Comment