Skip to content Skip to footer

SystemVerilog Concepts: All About Semaphores

Challenges faced by the Verification industry

Design engineers are already facing the heat owing to the unquenchable demands for faster, sleeker and smarter electronics. While they burn the midnight oil to define strategies and methods that shorten design time and effort, the verification teams aren’t napping either. They continually need to scale up their testbenches to verify the increasingly complex designs. While modern-day testbenches are required to support coverage, constraints and assertions to seep through nook and corner of the labyrinthine code. They are also required to be plug and play in nature, easy to build, configure and maintain. Additionally, they are required to be built at a much higher level of abstraction than their legacy counterparts. With such a bevvy of ‘specifications’ to meet, verification has moved on from the procedural legacy testbenches and embraced HVLs (Hardware Verification Languages), Verification Methodologies and the layered testbench approach.

SystemVerilog is the most widely accepted HVL. It is also known as Super Verilog for it is built on top of Verilog 2001. Besides Verilog, it also borrows concepts from  VHDL and OOPS(Object Oriented Programming System) and previous generations of HVLs. With inbuilt support for assertions, coverage and constrained randomization, SystemVerilog meets the current verification needs well. Since it has ingrained key concepts from OOPS such as Polymorphism, Inheritance, Abstraction and Encapsulation, SystemVerilog makes the job of building reusable, scalable, plug and play testbenches a lot simpler. Although a multitude of concepts and features make SystemVerilog so popular and useful, we shall talk here about ‘semaphores’ at length. Let us take a sneak peek into the world of semaphores and why they are such a boon to DV engineers.

What Is A Semaphore?

A ‘Semaphore’ is a ‘built-in-class’ in SystemVerilog that is used to control the access to a common shared resource from two or more concurrent threads. It also plays a significant role in ‘interprocess synchronization’ for it allows a given process to access the resource only when no other process is accessing it. Besides access control and some basic synchronization, a semaphore also guards the integrity of the shared resource and keeps data contention at bay.

A semaphore can be viewed as a container with keys. A given process can access the shared resource only if there is a key available. Each process at the beginning must scout for a key, and once the key is available it can begin to execute. Each process must return the key it procured to allow the remaining concurrent process to avail access.

Why do we need a semaphore?

As we discussed earlier, technology is growing by leaps and bounds. The yardstick of smartness of a design not just lies in the complexity of functions that it can execute, but also in the concurrency (parallel processing) that it can handle. Scenarios wherein multiple drivers driving a bunch of signals or a couple of processes sharing a common memory are ubiquitous in the current digital scenario. If one concurrent process reads from the memory before the other process has not finished/begun writing to it, the data read is unexpected and incorrect. Similarly, if multiple drivers that drive a common bunch of signals, bus contention is unavoidable in the absence of a regulatory mechanism. ‘Semaphores’ thus are inevitable as they hold the key both literally and figuratively in managing and synchronizing concurrent processes.

As depicted in the diagram above, John and Joanna have a common car. When John is using the car, Joanna must wait and vice-versa. Both John and Joanna need to keep an eye for the car keys to be back in its place, similarly, they also must ensure that once they are done using the car, the key must be promptly kept back in place. They thus share the same car (resource) and in a mutually exclusive fashion. A parallel can be drawn here between John as process A and Joanna as process B, while the car represents a ‘shared’ resource and the car key signifies a ‘semaphore’. In the scenario wherein there are multiple concurrent processes and a single shared resource such as a memory, a ‘semaphore’ creates a sense of ‘mutual exclusiveness’ and allows each process to access the shared resource albeit in a mutually exclusive and controlled fashion. Thus, a semaphore is often dubbed as a ‘mutex’.

It is also possible for a semaphore to contain more than one keys. In such a case, a process cannot access the resource until the ‘requested’ number of keys are available. To understand this better, let us take a look again at the example of John (process A) and Joanna (process B) sharing a car which is now kept safe in a garage. Now that the car is kept in a garage, the key stand (semaphore) would have two keys; car key and garage key. In the absence of anyone key, John and Joanna cannot use the car.

Here is a ‘semaphore’ in a nutshell for quick reference!

SemaphoreYES/NO
Is a ‘semaphore’ a built-in-class in SystemVerilog?YES
Is a ‘semaphore’ a means for interprocess synchronization?YES
Does it carry data between concurrent processes?NO
Is semaphore like a bucket that contains keys?YES
Can one concurrent process access the shared resource if there is a key available in the semaphore bucket?YES (provided it has been declared containing a single key or the process requests a single key only)
Can a ‘semaphore’ contain more than one keys?YES
Is it mandatory for a given process to return the key to a semaphore once it is done accessing the shared resource?YES
Is it mandatory for a process to ‘get’ a key to the shared resource before it can begin access, incase a ‘semaphore’ is used?YES
Does a ‘semaphore’ also synchronize concurrent processes?YES
Does a ‘semaphore’ help in keeping the shared resource such as memory or data bus guarded against contention?YES

Semaphore and the in-built methods

Semaphore, as we know now is an ‘in-built’ class in SystemVerilog. Every class contains one or multiple properties as well as methods. Let us take a quick look at ‘these in-built methods inside a ‘semaphore’ and their respective functions.

Method NameFunction
function new(int KeyCount = 1)This ‘function’, when invoked creates a semaphore with the specified number of keys. The KeyCount indicates the number of keys in a semaphore, the default number of keys in a semaphore’ is 1.   This function returns the semaphore handle if the semaphore has been created successfully, or else it returns ‘null’.
  task get(int KeyCount = 1)The semaphore get() method is used to procure the specified number of keys from the semaphore. This task is invoked in the concurrent processes that are connected to a shared resource via a ‘semaphore’.   The KeyCount value signifies the number of keys requested from the semaphore. By default, this is 1. The process can only execute if it receives the requested number of keys (KeyCount) from the semaphore. This task is blocking in nature
task put(int KeyCount = 1)The semaphore put() is used to return the specified number of keys to a semaphore. This task is invoked by the concurrent processes that are connected to a shared resource via semaphore. The process returns the key to the semaphore.   KeyCount signifies the number of keys returned to the semaphore, By default, this is 1. The process that is waiting for a key/keys to be put back into the semaphore must wait until the key/keys are back into the semaphore. This task is also blocking in nature.
function int try_get(int KeyCount = 1)The try_get() tries to get the specified number of keys from the semaphore.KeyCount specifies the number of keys the process is ‘trying’ to get. By default, this value is 1.   Unlike get(), this is non-blocking in nature. If the specified number of keys are available, this method returns ‘1’. Else it returns ‘0’.

Summary

In today’s scenario, if I say that ‘Time, Tide and Technology wait for none’, then I wouldn’t be wrong, would I? The rapidly growing technology sector constantly fuels innovation to satiate the ever-growing demand for sleeker and smarter electronics. While the design engineers have been designing increasingly complex designs, the mammoth task of verifying those designs lies on the verification teams. Verification has moved onto the much more advanced layered testbench approach from the procedural approach and the introduction of power-packed HVLs and Verification Methodologies have been the breather that the verification arena so badly needed.

SystemVerilog has been ruling the roost for it is loaded with user-friendly features and powerful concepts that address almost all that a modern-day verification needs. By inculcating key OOPS concepts, SystemVerilog based testbenches are smart, easy to build, maintain and reuse. Amongst the many advantages offered by SystemVerilog, a significant one is ‘Abstraction’. It offers a huge bunch of in-built features that spare the DV engineer from writing too much code. Commonly used testbench elements such as queue, FIFO, interprocess synchronization and communication logic, testbench interconnects and a lot more are now ‘objectified’ into easy and ready to use classes. Thus saving up on time and effort significantly.

Semaphore is one such in-built class that holds the key to interprocess synchronization. A semaphore also comes equipped with in-built methods that make the job of deploying it a lot easier. Conceptually it works like a container having the key(s) inside. Multiple concurrent processes are connected to a shared resource via semaphore. Each process must wait until the key(s) is available in the semaphore, and it must also ensure that the key(s) must be returned to the semaphore once it is done executing. At any given point in time, only a single process that has the ‘requested’ number of key(s) can gain access to the shared resource via a semaphore.

A semaphore thus isolates one process from the other and their access to the shared resource, thus creating a sense of mutual exclusiveness. Hence a semaphore is often termed as a ‘mutex’. It can be easily concluded that by creating a virtual handshake between concurrent processes, a semaphore keeps contention of shared resource at bay. So, a lot more code that would otherwise have to be written to tackle interprocess synchronization has now been bundled up into a ‘semaphore. With an inherent smartness and plethora of useful features, SystemVerilog based verification is here to stay!

Leave a comment