Why UVM copy actually clones the object members?


import uvm_pkg::*;
`include "uvm_macros.svh"
//ENV Configuration
class env_cfg extends uvm_object;
   rand bit a;
   rand bit b;
   `uvm_object_utils_begin(env_cfg)
     `uvm_field_int (a, UVM_DEFAULT)
     `uvm_field_int (b, UVM_DEFAULT)
   `uvm_object_utils_end

  function new (string name="env_cfg");
    super.new (name);
  endfunction
endclass

//Test Configuration
class test_cfg extends uvm_object;
 
  rand env_cfg m_env_cfg;
  rand bit c;
 
  `uvm_object_utils_begin(test_cfg)
     `uvm_field_int (c, UVM_DEFAULT)
     `uvm_field_object (m_env_cfg, UVM_DEFAULT)
  `uvm_object_utils_end 
 
  function new (string name="test_cfg");
    super.new (name);
    m_env_cfg = new ();
  endfunction
endclass

//Top
module top;
 
  initial
  begin
    test_cfg m_test1_cfg = new ("m_test1_cfg");
    test_cfg m_test2_cfg = new ("m_test1_cfg");

    //Share the m_test2_cfg.m_env_cfg
    //Say m_env_cfg2 is used by some monitor
    env_cfg  m_env_cfg2;
    m_env_cfg2 = m_test2_cfg.m_env_cfg;
 
    m_test1_cfg.randomize ();
    m_test2_cfg.copy (m_test1_cfg);
     
    m_test2_cfg.print ();
    
    //Changes in m_test2_cfg.m_env_cfg will no more reflect on m_env_cfg2.
    //Both become two different objects after .copy
    m_env_cfg2.print ();  
  end 
 
endmodule

In the above example, both m_test1_cfg and m_test2_cfg are constructed explicitly which in turn will also construct m_test1_cfg.m_env_cfg and m_test2_cfg.m_env_cfg.

I observed the ‘copy’ call will make the m_test2_cfg.m_env_cfg to be constructed again thereby losing the memory allocated by explicit construction. This is because the field automation macro actually invokes ‘clone’ internally for object members instead of ‘copy’

Can anyone please explain the reasoning behind it?

I expect the automation macro to invoke copy for its object members. It shall invoke clone only if the member object on LHS is null.

In reply to run2prem:

The `uvm_field* macros typically don’t work the way that the user wants, hence they are not recommended.

You should implement the transaction methods in a manner that meets your requirements.