Uvm_pool get() function. Is it broken?

Hi All,

Am I missing something or is the get() method in the uvm_pool() broken?

The get() is supposed to return a pointer to a uvm_object of type T if there is no object of type T at location KEY. But it doesn’t do that. Instead it returns a null pointer.

One then things, well, I’ll extend uvm_pool #(KEY, T) and provide my own get. But this doesn’t work because of all the static functions in uvm_pool.

Unless I’m missing something the get() functionality is simply broken. It should have called ‘new()’ but instead it uses this weird ‘default_value’ variable.

Am I missing something?

Ray

In reply to raysalemi:

The documentation is misleading. What it does is return the existing value of an entry if it exists, and creates a new entry in the pool if it does not already exist, and returns the default initial value for the pool type.

uvm_pool is a carry-over from Specman, which did not have associative arrays. And one difference between SystemVerilog’s implementation of assoc array and a pool is that SV only creates an entry when you write to it, where as a pool you create a new entry when you write(add) or try to read(get) an entry.

In reply to dave_59:

In reply to raysalemi:
The documentation is misleading. What it does is return the existing value of an entry if it exists, and creates a new entry in the pool if it does not already exist, and returns the default initial value for the pool type.
uvm_pool is a carry-over from Specman, which did not have associative arrays. And one difference between SystemVerilog’s implementation of assoc array and a pool is that SV only creates an entry when you write to it, where as a pool you create a new entry when you write(add) or try to read(get) an entry.

Right, but this is completely broken for any object and cannot be overridden because of all the static functions.
Ray

In reply to raysalemi:

In reply to raysalemi:
Right, but this is completely broken for any object and cannot be overridden because of all the static functions.

If you don’t like the fact that it returns a null for objects when trying to read an entry that doesn’t exist, then you can (in theory) extend the class. The pool variables is protected and the get() function is virtual.

The question you get, though, is “how do you construct the objects?”. Classes can have different construct argument signatures, so it’s impossible to build a one-size-fits-all-solution. In UVM you can cheat and implement a variant of your pool for uvm_object and it’s children, because there the constructor argument is fixed:


class uvm_object_pool_that_allocates #(type KEY=int, T=uvm_object) extends uvm_pool #(KEY, T);
  virtual function T get (KEY key);
    if (!pool.exists(key)) begin
      T new_obj = new();  // only works because uvm_objects have optional 'name' argument
      pool[key] = new_obj;
    end
    return pool[key];
  endfunction
endclass

This only works because the UVM macros force you to specify a constructor with the signature:


class some_class extends uvm_object;
  function new(string name = "<default_value>");
  // ...
endclass

If you work with classes that have mandatory constructor arguments, then it all blows up.

In reply to Tudor Timi:

The problem is that the static nature of the class makes the extension difficult. Consider this code built from yours:


module test;	
  import uvm_pkg::*;
   class uvm_object_pool_that_allocates #(type KEY=int, T=uvm_object) extends uvm_pool #(KEY, T);
	  virtual function T get (KEY key);
	    if (!pool.exists(key)) begin
    	    T new_obj = new();  // only works because uvm_objects have optional 'name' argument
    	    pool[key] = new_obj;
    	  end	
    	  return pool[key];
    	endfunction		
    endclass

    typedef uvm_object_pool_that_allocates #(int, uvm_object) my_pool_t;

    initial begin
    	my_pool_t pool_h;
    	uvm_object object;
    	pool_h = my_pool_t::get_global_pool();  // line 19 in error message
    	object = pool_h.get(2);
    end 
endmodule


It seems that this code should do as you suggest. It should create a new uvm_object when get() is called. However, it doesn’t work:

# ** Error: (vsim-3978) test.sv(19): Illegal assignment to class work.test/uvm_object_pool_that_allocates #(int, class mtiUvm.uvm_pkg::uvm_object) from class mtiUvm.uvm_pkg::uvm_pool #(int, class mtiUvm.uvm_pkg::uvm_object)

The problem is that I can’t get a my_pool_t pool using the get_global_pool() method. Extending the class does not change the types of the static methods and the specialization of a base class is not considered an extension in terms of polymorphism.

So now I need to rewrite all the static methods in the uvm_pool in order to extend the class and it’s hardly worth it.

Of course, maybe I’m missing something simple. If so that would be great!

In reply to raysalemi:

You’re right, you do need to re-write all the static stuff if you want to use it. But I don’t recommend you do that. Using the global pool can cause problems when mixing code from different packages, because you could get collisions for the used keys. You should rather instantiate your own pool and pass it around.