uvm_pool example with Systemverilog semaphore
Uvm support uvm_pool
, which can be understood as a global associative array. We can define the the type of index and value of this array.
By default, uvm has two pools using string as index for uvm_event
and uvm_barrier
, which are uvm_event_pool
and uvm_barrier_pool
, respectively. In this post, let’s go through examples of using uvm_pool
for Systemverilog semaphore.
uvm_pool and semaphore 101
First up, let’s briefly cover the semaphore and uvm_pool
.
What is uvm_pool
uvm_pool
allow us to store any type of data with a key as index, similar to an associative array.- It is singleton class.
- Must define a pool before use:
typedef uvm_pool(.KEY(int),.T(semaphore)) semaphore_pool
- To get the handle of uvm_pool singleton object, use static method
semaphore_pool::get_global_pool()
- Use public method
add(KEY key, T item)
,delete(KEY key)
,get(KEY key)
, to add/get object from pool - Use static method
semaphore_pool::get_global(KEY key)
to get obj from the pool.
Systemverilog semaphore
Semaphore is a class in the built-in std
package of Systemverilog. As other languages, the semaphore is a bucket with a specific number of keys. When all the keys are get from the bucket, other proccesses wishing to get the key must wait until there’s a key return to the bucket.
Semaphore most well-known application is to manage the access to the common resource.
For example, if there are only 5 slots in the memory to store data, then we create a semaphore with 5 keys to control the access to these slots. Any process wanting to grant a slot must get the key from the semaphore bucket, and return the key to the bucket when it finishes. If there is no key in the bucket, meaning all the slots are occupied, the process must wait until other processes done using the resource and return the key.
Basic methods of Systemverilog semaphore are:
new(int keyCount=0)
: Construct a semaphore object with a specific number of keys.put(int keyCount=1)
: Add keys to the bucket.get(int keyCount=1)
: Get keys from the bucket. When there are not enough keys in the bucket, this task will block the process until the keys are available.try_get(int keyCount=1)
: Similar toget()
method, but this method will not block the process. If there is not enough keys as requested, this method will return 0.
Disadvantages of Systemverilog semaphore:
There are some points which I considered as disadvantages of Systemverilog semaphore:
- Since semaphore is well-known for manage the access to common resource, it need to be accessed from many places in the environment.
- We can put more keys to the bucket, using the same function
put()
which is used to return the key. Therefore we might accidentally increase the total number of keys of the bucket, causing the conflict, since there are more keys than actual resources. - There is no built-in method for debugging.
These issues can be solved by creating a class wrapping around the Systemverilog semaphore with some custom methods and using the uvm_pool
, which will be shown in below examples.
Example
Using uvm_pool with Systemverilog semaphore directly
Firstly, let’s remember the std::semaphore
in Systemverilog is a class. Therefore so we can construct and passing it’s object handle as normal.
To create a pool of Systemverilog semaphore, we just need to define our pool for semaphore as below:
Then we contruct a pool then add/get semaphore object to this pool.
Creating uvm_semaphore to use with uvm_object_string_pool
We can create our own uvm_semaphore
class, wrap around the semaphore
of Systemverilog. This allow us having more control over the semaphore, also more information when debugging.
Besides, since we extend uvm_semaphore
from uvm_object
, we can use it with the uvm_object_string_pool
, which is easier to use compare to the uvm_pool
.
Let’s create the uvm_semaphore
class as below. You can get the full class here: uvm_semaphore
Then we can use this uvm_semaphore
with uvm_object_string_pool
, similar to the uvm_event_pool and uvm_barrier_pool .
It will be a little more simple when using this pool:
- We can call the
get_global()
function to get the semaphore in the pool, and if the semaphore object does not exist, the pool will automatically construct a semaphore object for us. - Also, we do not need to construct the pool manually, it will be construct automatically when we call
get_global()
the first time.
Finding more information
- Systemverilog LRM, section 15.3 Semaphores
- Systemverilog LRM, Annex G Std package
- uvm_pool.svh
[Tags
uvm
]