Difficulty: Medium · Puzzle 6 of 6 · Topic: Handle and Copy Puzzles
A class has a nested handle member but registers only its scalar with field macros. After `clone()`, does the clone share `h` with the original, and what does `c.h.opcode` hold? Predict the print.
class hdr extends uvm_object;
`uvm_object_utils(hdr)
int opcode;
function new(string name="hdr"); super.new(name); endfunction
endclass
class tr extends uvm_sequence_item;
int addr;
hdr h;
`uvm_object_utils_begin(tr)
`uvm_field_int(addr, UVM_DEFAULT)
`uvm_object_utils_end
function new(string name="tr");
super.new(name);
h = hdr::type_id::create("h");
endfunction
// no do_copy override
endclass
initial begin
tr t, c;
uvm_object o;
t = tr::type_id::create("t");
t.addr = 'h40;
t.h.opcode = 7;
o = t.clone();
void'($cast(c, o));
$display("addr=%0h opcode=%0d same_h=%0d", c.addr, c.h.opcode, (c.h == t.h));
end`clone()` builds a brand-new object first (running `new()`), then copies only what automation or `do_copy` covers.
1) `clone()` = the class's `create()` (which calls `new()`) followed by `copy(this)`. `new()` already allocated a fresh `hdr` for the clone.
2) The field macro registers only `addr`, so `copy` writes `addr` and never touches `h`.
3) Result: `c.h` is a distinct, default-constructed `hdr` with `opcode == 0`. Nothing is aliased; the data is silently lost.
4) Aliasing would only appear if someone wrote `h = r.h` in `do_copy`, or registered `h` with `UVM_REFERENCE`.
5) Fix: `uvm_field_object(h, UVM_DEFAULT)` (deep copy) or a `do_copy` that does `h.copy(r.h)` with null handling.Answer: Prints `addr=40 opcode=0 same_h=0`: the clone does not share `h`, it gets a fresh `hdr` whose contents were never copied (data lost, not aliased). Register `h` with `uvm_field_object(h, UVM_DEFAULT)` or copy it in `do_copy`.
Checked by running the code in Verilator 5; the printed output supports the answer above. A hand-written model of clone = new + copy (not the UVM library): the clone gets a fresh empty h, nothing is shared and the opcode is lost.
The failure is the opposite of the aliasing most candidates expect: `new()` hides it by giving the clone a plausible-looking but empty `h`, so a compare of `addr` passes and only `h.opcode` is wrong.
Would you prefer field macros or hand-written copy for high-performance scoreboards, and why? Model answer: hand-written `do_copy`/`do_compare`. The macros go through the generic automation path (per-field checks, comparer and printer plumbing) and are noticeably slower, and they hide exactly the nested-handle decisions (deep vs reference, null handling) this puzzle is about; the macros are fine for low-rate or debug-only objects.
The clone prints addr 40 and opcode 0, and it does not share the header. Clone is create followed by copy, so the constructor gave the clone a fresh header, and the field macro only copied addr. The result is data silently lost, not aliased, and the trap is expecting aliasing. I would register the header with the object field macro or copy it in do_copy with null handling, then check opcode survives.