Difficulty: Easy · Puzzle 5 of 6 · Topic: Handle and Copy Puzzles
Two packets have identical `addr`, yet `a == b` is false. A teammate switches to `a.compare(b)`, sees it return 1, then changes `b.addr` and still sees 1. Predict all three prints and explain both effects.
class pkt extends uvm_object;
`uvm_object_utils(pkt)
rand bit [31:0] addr;
function new(string name="pkt"); super.new(name); endfunction
endclass
initial begin
pkt a = pkt::type_id::create("a");
pkt b = pkt::type_id::create("b");
a.addr = 'h100;
b.addr = 'h100;
$display("eq=%0d cmp_same=%0d", (a == b), a.compare(b));
b.addr = 'h200;
$display("cmp_diff=%0d", a.compare(b));
endClass `==` is not like packed-struct equality, and `compare()` can only compare what the class tells it about.
1) For class handles, `==` checks handle identity (same object), not field-by-field data. `a` and `b` are distinct objects, so `eq=0` even with matching `addr`.
2) `compare()` runs the field-macro automation and then `do_compare`. `pkt` has no `uvm_field_*` macros and no `do_compare`, and the default `do_compare` returns 1, so nothing is checked.
3) Therefore `cmp_same=1` and, after `b.addr` changes, `cmp_diff=1` as well: a silent always-pass comparison.
4) Fix: register the field (`uvm_object_utils_begin(pkt) `uvm_field_int(addr, UVM_DEFAULT) `uvm_object_utils_end`) or override `do_compare` to compare `addr`. Then `cmp_diff=0`.Answer: Prints `eq=0 cmp_same=1` then `cmp_diff=1`. `==` compares handle identity; `compare()` on a class with no field macros and no `do_compare` compares nothing and always returns 1, so add `uvm_field_int(addr, ...)` or a `do_compare`.
Checked by running the code in Verilator 5; the printed output supports the answer above. A hand-written model of compare/do_compare (not the UVM library): == compares handles, and a default do_compare that returns 1 never fails.
The dangerous half is `compare()` returning 1 for different packets: a scoreboard built on it never fails, which is worse than the visible `==` false negative.
What comparer settings would you tune to ignore volatile fields like timestamps? Model answer: mark the field `UVM_NOCOMPARE` in its field macro (`uvm_field_int(ts, UVM_DEFAULT | UVM_NOCOMPARE)`) or leave it out of a hand-written `do_compare`; a comparer object (`comparer.show_max`, `comparer.policy`) only changes reporting and matching policy, so the exclusion belongs on the field.
It prints eq equals 0, then cmp_same equals 1, and after the change cmp_diff is still 1. The double-equals operator compares handle identity, so two distinct objects are never equal. The compare method checks nothing here, because the class has no field macros and no do_compare, so it always returns 1. That is a silent always-pass comparison, and I would register the field or write do_compare, then confirm cmp_diff becomes 0.