Iteration Order for Class Indexes of Associative Array

Associative arrays allow class type as indexes .

LRM-2017 7.8.3 Class index reads ::
Associative arrays that specify a class index have the following properties:
— Indices can be objects of that particular type or derived from that type. Any other type is illegal and shall result in a type check error.
— A null index is valid.
— The ordering is deterministic but arbitrary.

I am curious about the meaning of the last line and tried the below code ::


`include "uvm_pkg.sv"
`include "uvm_macros.svh" 

import uvm_pkg::*;


class user_comp1 extends uvm_component ;

 `uvm_component_utils(user_comp1)

 function new ( string name , uvm_component parent ) ;
  super.new(name,parent);
  `uvm_info(get_name,$sformatf("In constructor of %0s",get_type_name()),UVM_NONE)
 endfunction

endclass

class user_comp2 extends uvm_component ;

 `uvm_component_utils(user_comp2)

 function new ( string name , uvm_component parent ) ;
  super.new(name,parent);
  `uvm_info(get_name,$sformatf("In constructor of %0s",get_type_name()),UVM_NONE)
 endfunction

endclass

class user_test extends uvm_test ;

 `uvm_component_utils(user_test)

 function new ( string name , uvm_component parent ) ;
  super.new(name,parent);
  `uvm_info(get_name,$sformatf("In constructor of %0s",get_type_name()),UVM_NONE)
 endfunction

endclass

class user_agent extends uvm_agent ;

 `uvm_component_utils(user_agent)

 function new ( string name , uvm_component parent ) ;
  super.new(name,parent);
  `uvm_info(get_name,$sformatf("In constructor of %0s",get_type_name()),UVM_NONE)
 endfunction

endclass


module top_tb ;

  user_agent  user_agent_h ;
  user_comp2  user_comp2_h ;
  user_test   user_test_h ;
  user_comp1  user_comp1_h ;
   
  bit         assoc[uvm_component];

  initial begin
    
    user_comp2_h = user_comp2::type_id::create("user_comp2_h",null);
    user_comp1_h = user_comp1::type_id::create("user_comp1_h",null);
    user_test_h  = user_test::type_id::create("user_test_h",null);
    user_agent_h = user_agent::type_id::create("user_agent_h",null);
  
  `ifdef M1  // Same  Order  as  creation

    assoc[user_comp1_h] = 1 ;
    assoc[user_comp2_h] = 1 ;
    assoc[user_test_h]  = 1 ;
    assoc[user_agent_h] = 1 ;

  `elsif M2  //  Different  Order  than  Creation

    assoc[user_test_h]  = 1 ;
    assoc[user_agent_h] = 1 ;
    assoc[user_comp2_h] = 1 ;
    assoc[user_comp1_h] = 1 ;

  `endif
    
    foreach(assoc[ind])
      $display("assoc[%0s] is %0s",ind.get_name(),ind.get_type_name());
     
  end

endmodule

 

In both cases ( +define+M1 / +define+M2 ) the Order of Iteration is the same in the output .

i.e From left to right :: user_comp1 => user_comp2 => user_test => user_agent

What decides the Order of index iteration ( for class type indexes ) ?

( I tried changing the order of declaring handles , order of calling create but the output was the same )

On changing the $display to ::


 $display("assoc[%0d] is %0s",ind,ind.get_type_name()); // Format  specifier  changed  to   %0d  and  1st  argument to  ind

Now in the output the number displayed as Index of associative array**( due to %0d ) is in Ascending order** .

What does the number denote ? Is it the address of the variable after calling new() ?

In reply to ABD_91:
“deterministic but arbitrary” means a tool can chose any ordering as long as it is consistent. If you iterate of the array multiple times, you always get the elements in the same order. That is also for random and debug stability; when you re-run a simulation, you always get the same ordering.

The ordering you are seeing is based on the creation order of the object. But creation order of the element would also be acceptable.

The LRM does not define (might to even allow) how a class handle should be display. That is a tool specific extension.

In reply to dave_59:

The ordering you are seeing is based on the creation order of the object. But creation order of the element would also be acceptable.

Shouldn’t this be same as the order of calling create( ) ?

( However this isn’t the case in the above code where user_comp2_h is created first )

Or is it up to the tool to decide which object gets created first which could be independent of the order in which create() is actually called for the object .

In reply to ABD_91:

It is pointless to discuss what ordering is being used to iterate. A different tool or a different version of the same tool might produce different results. The key point is the tool must preserve the ordering each time the same code is run on the same tool.

In reply to dave_59:

Thanks Dave ,

As you mentioned the LRM doesn’t decide the exact order I believe it’s better to change index type to string .


   bit         assoc[string];  
  
 // Within  the  initial  block  after  creating  the  components  in  Same  order  as  above
     `ifdef M1

    assoc[user_comp1_h.get_name()] = 1 ;
    assoc[user_comp2_h.get_name()] = 1 ;
    assoc[ user_test_h.get_name()] = 1 ;
    assoc[user_agent_h.get_name()] = 1 ;

  `elsif M2

    assoc[ user_test_h.get_name()]  = 1 ;
    assoc[user_agent_h.get_name()] = 1 ;
    assoc[user_comp2_h.get_name()] = 1 ;
    assoc[user_comp1_h.get_name()] = 1 ;
 
 `endif
    
    foreach(assoc[ind])
      $display("assoc[%0s] is %0s",ind,ind);

 

Now I am certain the Order would be Lexicographical ( independent of the tool )