Why the message inside a transaction created in its parent transaction is printed twice

Hi forks:
I have the following 2 transactions. When a_transaction is instantiated and randomized, messages inside the function post_randomize of b_transaction are
printed twice. I don’t know why. It seems that b_transaction was instantiated twice.

   class b_transaction extends uvm_sequence_item;
       ...
       
       function void post_randomize();
           `uvm_info("TRACE", $sformatf("%m"), UVM_LOW) 
           
       endfunction
   endclass
    
   class a_transaction extends uvm_sequence_item;
       rand b_transaction  b_xact_queue[$];
       
       ...
       constraint c_xact_queue_size {
           b_xact_queue.size == 0;
       }
       ...
       
       function void post_randomize();
           b_transaction b_xact;

           `uvm_info("TRACE", $sformatf("%m"), UVM_LOW) 
           
           b_xact = b_transaction ::type_id::create("b_xact", m_sequencer);
           b_xact.randomize();
           b_xact_queue.push_back(b_xact);

       endfunction
       
   endclass

   class a_sequence extends uvm_sequence #(a_xaction);
       ...
       task body();
           repeat(1) begin
               `uvm_do_with(req, {
                   id == local::id
               });
               id++;
           end
           
       endtask
   endclass

Note that in following testcases, a_transaction and b_transaction will be overrided by their derived classes.

In reply to hungtaowu:

When you randomize a_transaction, b_transaction is randomized since it is declared ‘rand’, hence the first message. Then, in the post_randomize() function of a_transaction, b_transaction is randomized again, hence the second message.

In reply to cgales:

Thanks for your reply, cgales.

Based on you answer, I delete the ~rand~ keyword before b_transaction declared in a_transaction. The simulation result shows that the ~post_randmize~ function of b_transaction is only printed once, which is exactly the same as what you said!

Still I am little confused. If ~b_transaction~ is decared as rand in ~a_transaction~ and the size of ~b_xact_queue~ is contrained to 0, do it mean that during the randomization process ~b_transaction~ will be created and randomized but not pushed into b_xact_queue? Is that the truth ?

In reply to hungtaowu:

This is likely a tool-specific behavior on how it creates the randomization state space. The following self-contained example will have different behavior depending on which simulator is used on EDA Playground. As long as the end result is valid, I don’t think that the intermediate results will have any detrimental effects.


import uvm_pkg::*;
`include "uvm_macros.svh"
class b_transaction extends uvm_sequence_item;
  `uvm_object_utils(b_transaction)

  rand int a;
  
  function void post_randomize();
    `uvm_info("TRACE", $sformatf("%m"), UVM_LOW)
  endfunction
endclass
 
class a_transaction extends uvm_sequence_item;
  `uvm_object_utils(a_transaction)
  rand b_transaction  b_xact_queue[$];

  constraint c_xact_queue_size {
    b_xact_queue.size == 0;
  }

  function void post_randomize();
    b_transaction b_xact;
    `uvm_info("TRACE", $sformatf("%m"), UVM_LOW)
    b_xact = b_transaction ::type_id::create("b_xact", m_sequencer);
    if (!b_xact.randomize()) begin
      `uvm_fatal("ERR", "Unable to randomize b_transaction");
    end
    else begin
      b_xact_queue.push_back(b_xact);
    end
  endfunction
endclass
 
module top();
  a_transaction a;
  
  initial begin
    a = a_transaction::type_id::create("a");
    if (!a.randomize()) `uvm_fatal("ERR", "Unable to randomize");
  end
endmodule

In reply to cgales:

Thank you, cgales. You help me a lot.