UVM ports max_size argument

I was looking at the UVM source code for ports and found that there are arguments like min_size and max_size which denotes maximum and minimum number of ports that must be connected to a given port. I made a sample code with two connections of a single blocking put port with two different implementation ports. EDAPlayground link here.

// uvm_ports_base.svh
221 // The ~min_size~ and ~max_size~ specify the minimum and maximum number of
222 // implementation (imp) ports that must be connected to this port base by the
223 // end of elaboration. Setting ~max_size~ to ~UVM_UNBOUNDED_CONNECTIONS~ sets no
224 // maximum, i.e., an unlimited number of connections are allowed.

But the display statement from only one port comes and the other one was not at all executed. Looking at the source code of uvm_port_base.svh, the resolve_bindings API (which is invoked before end_of_elaboration_phase) sets the interface m_if only to the first indexed implementation port (from m_imp_list array).


  728   virtual function void resolve_bindings();
  //.. Resolve bindings for Implementation port first
  758     if (size())
  759       set_if(0); // -->>> This sends a "0"th index only
  760   
  761   endfunction

On observing, the 0th element of m_imp_list array depends on which component comes first in alphabetical order. In other words, the put task of that component is invoked which comes first in alphabetical order in this array. This sounds unrealistic. So, what is the aim of having max_size argument when one can call only single imp task? Am I interpreting the max_size in a wrong manner?

P.S.: We can use analysis ports for one-to-many connections, but this doubt is just out of curiosity about max_size argument.

In reply to sharvil111:

 
  if (size())
    set_if(0); // used to set default index of implementation port 

Here , index 0 is used to set default implementation port (UVM_IMPLEMENTATION) to your UVM_PORT.

On observing, the 0th element of m_imp_list array depends on which component comes first in alphabetical order. In other words, the put task of that component is invoked which comes first in alphabetical order in this array. This sounds unrealistic. So, what is the aim of having max_size argument when one can call only single imp task? Am I interpreting the max_size in a wrong manner?

m_imp_list[string] is associative array and for 0 th element will give lowest ASCII value of index string (i.e. eventually it can be interpreted as alphabetical).

You have used put → put_imp which is one to one connection, Though you can connect multiple imp port to single put port based on max_size , but at time you can supply packets to only single imp port.

Suppose , you have single Initiator and multiple Target (lets say 5 Target) , but the constraint is Initiator must communicate only one Target (which can be any) at time. By default it is communicating 0th Target (i.e Target[0]) based on set_if(0) task. If in certain cases Initiator needs to communicate Target[1] , then it will first set index of Target[1] through set_if(1) before invoking Initiator.put() task.

Here is EDA Playground Link Code.

Thus, max_size puts restriction to user not to connect additional IMP/EXP port to UVM_PORT.

In reply to kerulmodi:

I didn’t thought from perspective of changing m_if pointer. Thanks for the insight.

Just a small query. ;-) Here, in the pseudo code, the test class knows how many interfaces are there. But let’s say we have three agents in env. Agent 1 has put port and Agent 2,3 have their respective imp ports. So, Agent 1 port will be created with max_size=2. Agent 1 wants to send a specific packet to Agent 2 (let’s say good packets) and some other specific packet to Agent 3 (let’s say erroneous packets). Now, how does Agent 1 come to know that what should be the index value to propagate a packet to Agent 2 or Agent 3? Since, the interface index depends upon the alphabetical order (ASCII value) of the object name of Agent 2 and Agent 3 (whose information is available in env).

I believe there can be many workarounds to this scenario like taking two ports or sending the packet to all consumers and let the consumers decide what to do with the packets etc. But, setting default implementation by considering a get_full_name() of objects seemed a bit bewildering to me.

In reply to sharvil111:

Absolutely, as associative array index is string and get_full_name() would be index of associative array of connected imp ports. Thus leaf level component doesn’t have information about at which index which component’s implementation port is connected.

Eventually , somehow Agent1 requires routing hook up information to make it aware about connection index.

Due to this limitation , we usually use analysis port/import to let implementer (Target) decide whether packet is required for its component or not :).

setting default implementation by considering a get_full_name() of objects seemed a bit bewildering to me.

Connected implementation port’s index string should not be identical, if it is identical then, it would be hazardous. I can recall only one thing which does not give identical value i.e get_full_name() , Thus they have used get_full_name() in index to ensure that array should not override previous pointer value of implementation port.

Hope, it should be clear. If you have an idea about index type to overcome this limitation , feel free to suggest better option. :)

In reply to kerulmodi:

Sure. It is very clear now. :) This may be the reason that led to the usage of analysis ports. Thanks for making it lucid.

In reply to sharvil111:

Thanks, Happy Debugging !!
Keep posting such advance and deep level questions.