Semaphore in System Verilog

Semaphore

A semaphore in SystemVerilog is a synchronization mechanism used to control access to shared resources among multiple processes.

It is particularly useful in testbenches to prevent race conditions when multiple threads try to access the same resource.

A semaphore consists of a fixed number of keys (or tokens), which can be acquired and released by processes. If a process wants to use a resource, it must acquire a key; once it is done, it releases the key, allowing other processes to access the resource.

Real-Life Analogy

Consider a public restroom with three stalls. If three people are using the stalls, others must wait until a stall is free. This scenario can be modeled using a semaphore with three keys:

  • Each person (process) acquires one key before using a stall.
  • If no keys are available, they must wait.
  • Once done, they release the key, making a stall available for the next person.

Semaphore Methods

SystemVerilog provides a built-in semaphore class with the following key methods:

  • new() – Creates a semaphore with a defined number of keys.
  • get(n) – Acquires n keys from the semaphore before accessing a shared resource.
  • put(n) – Releases n keys back to the semaphore after resource usage.
  • try_get(n) – Attempts to acquire n keys without blocking the process if keys are unavailable.

Important things to consider before writing semaphore code in System Verilog:

  1. Understand the Need for Synchronization
    Identify the shared resources in your testbench that multiple processes will access.

Determine if resource contention could cause race conditions.

  1. Decide the Number of Keys
    Set the number of semaphore keys based on the number of available resources.

Example: If you have three memory blocks that can be accessed concurrently, initialize the semaphore with three keys.

  1. Proper Use of get() and put() Methods
    Use get(n) to acquire n keys before accessing a shared resource.

Use put(n) to release n keys after completing the resource usage.

Ensure that every get(n) has a corresponding put(n) to avoid deadlocks.

  1. Avoid Deadlocks
    Deadlocks occur when multiple processes are waiting indefinitely for keys that are never released.

Ensure that resources are always released after use.

  1. Use try_get() for Non-blocking Access
    If a process should proceed even if it fails to acquire a key, use try_get(n) instead of get(n).

Example: If try_get(1) fails, the process can take an alternative action instead of waiting.

  1. Consider the Impact of fork-join
    When using fork-join, be aware of concurrent processes trying to access the semaphore.

Use fork-join_none or fork-join_any if required to avoid unnecessary blocking.

  1. Debugging with num()
    Use the num() method to check the current number of available keys for debugging purposes.

Example: $display(“Available keys: %0d”, sem.num());

Example:- Simple Semaphore Example



module restroom_semaphore;
    semaphore restroom; // Declare semaphore
    
    initial begin
        restroom = new(3); // Initialize semaphore with 3 keys (3 stalls available)
    end
    
    task use_restroom(int person_id);

        restroom.get(1); // Acquire one stall
        $display("Person %0d entered the washroom at time %0t", person_id, $time);
        #5; // Simulate washroom usage
        $display("Person %0d exited the washroom at time %0t", person_id, $time);
        restroom.put(1); // Release the stall
    endtask
    
    initial begin
        fork
            use_restroom(1);

            use_restroom(2);

            use_restroom(3);

            use_restroom(4);

            use_restroom(5);
        join
    end
endmodule


Output:
xcelium> run
Person 1 entered the washroom at time 0
Person 2 entered the washroom at time 0
Person 3 entered the washroom at time 0
Person 5 exited the washroom at time 5
Person 5 exited the washroom at time 5
Person 5 exited the washroom at time 5
Person 5 entered the washroom at time 5
Person 5 entered the washroom at time 5
Person 5 exited the washroom at time 10
Person 5 exited the washroom at time 10
xmsim: *W,RNQUIE: Simulation is complete.
xcelium> exit

Explanation of the code:

The given SystemVerilog code models a scenario where multiple people attempt to use a restroom with limited stalls, using a semaphore to manage access.

The module is named restroom_semaphore. It encapsulates the entire functionality of the semaphore-based restroom simulation.

A semaphore named restroom is declared.

Inside the initial block, the semaphore is instantiated with 3 keys, representing 3 restroom stalls.

This means that at any given time, only 3 people (processes) can use the restroom.

The use_restroom task represents a person using a restroom stall.

The person_id argument helps differentiate between different individuals.

The process follows these steps:

  1. Acquire a stall using restroom.get(1). If no stalls (keys) are available, the person waits.
  2. Print a message indicating that the person has entered the washroom.
  3. Wait for 5 time units (#5) to simulate using the restroom.
  4. Print a message indicating that the person has exited.
  5. Release the stall using restroom.put(1), making it available for others.
  • The initial block starts executing at simulation time 0.
  • The fork-join block launches five parallel processes, representing five different people trying to use the restroom.
  • Since the semaphore has only 3 keys, at most 3 people can enter the restroom at a time.
  • The remaining 2 people must wait until someone exits and releases a stall.

Execution Flow

  1. At time 0, the first three people acquire a key and enter the restroom.
  2. They stay inside for 5 time units (#5).
  3. Once they exit, they release their keys.
  4. The remaining two people can now acquire a key and enter the restroom.
  5. This continues until all five processes are completed.

Key Takeaways

  • Concurrency Control: The semaphore ensures that no more than 3 people use the restroom at the same time.
  • Blocking Mechanism: If a process tries to acquire a key but none are available, it waits until one is released.
  • Efficient Resource Management: Using get() and put(), the restroom stalls are efficiently managed without conflicts.

Using a Class to Modify Semaphore Keys Dynamically

In real-world scenarios, the number of restroom users may increase. Below is an updated version using a System Verilog class to allow dynamic key allocation.


class RestroomControl;
    semaphore restroom;
    
    function new(int num_stalls);
        restroom = new(num_stalls); // Initialize semaphore with dynamic keys
    endfunction
    
    task use_restroom(int person_id);

        restroom.get(1); // Acquire one stall
        $display("Person %0d entered the restroom at time %0t", person_id, $time);
        #5; // Simulate washroom usage
        $display("Person %0d exited the restroom at time %0t", person_id, $time);
        restroom.put(1); // Release the stall
    endtask
endclass

module restroom_semaphore_class;
    RestroomControl rc;
    
    initial begin
        rc = new(3); // Initially, only 3 stalls
        #10;
        rc = new(5); // Later, increase to 5 stalls
    end
    
    initial begin
        fork
            rc.use_restroom(1);

            rc.use_restroom(2);

            rc.use_restroom(3);

            rc.use_restroom(4);

            rc.use_restroom(5);

            rc.use_restroom(6);

            rc.use_restroom(7);

            rc.use_restroom(8);
        join
    end
endmodule

Output:-
xcelium> run
Person 1 entered the restroom at time 0
Person 2 entered the restroom at time 0
Person 3 entered the restroom at time 0
Person 1 exited the restroom at time 5
Person 2 exited the restroom at time 5
Person 3 exited the restroom at time 5
Person 4 entered the restroom at time 5
Person 5 entered the restroom at time 5
Person 6 entered the restroom at time 5
Person 4 exited the restroom at time 10
Person 5 exited the restroom at time 10
Person 6 exited the restroom at time 10
Person 7 entered the restroom at time 10
Person 8 entered the restroom at time 10
Person 7 exited the restroom at time 15
Person 8 exited the restroom at time 15
xmsim: *W,RNQUIE: Simulation is complete.
xcelium> exit

Explanation:

Explanation of the Code

  1. The RestroomControl class encapsulates the semaphore functionality.
  2. The new(int num_stalls) constructor allows dynamic allocation of stalls.
  3. The use_restroom task ensures synchronized access using semaphore methods.
  4. The restroom_semaphore_class module initializes the class with 3 stalls and later increases it to 5 as demand grows.
  5. Eight people try to use the restroom, demonstrating controlled access as per the updated semaphore keys.

Conclusion

Semaphores in SystemVerilog are crucial for synchronizing multiple processes and preventing resource conflicts. The use of a class-based approach provides flexibility, allowing the semaphore size to be adjusted dynamically as the number of users increases.

Leave a Comment

Your email address will not be published. Required fields are marked *

The US Hits China With a Huge Microchip Bill FPGA Design Engineer Interview Questions Semiconductor Industry the huge break through