Tuesday 21 February 2017

Lock and Grab of sequencer in UVM

There are a number of modelling scenarios where one sequence needs to have exclusive access to a driver via a sequencer. One example of this type of scenario is a sequence which is responding to an interrupt.
In order to accommodate this requirement, the uvm_sequencer provides 2 types of mechanism called lock()-unlock() and grab()-ungrab().

If sequencer is doing some sequence and based on some external events if user wants sequencer to pause the current sequence, he/she can grab/lock sequencer and start another sequence. Once the started sequence finishes sequencer can resume the normal operation, upon ungrab/unlock.
This mechanism is generally used to mimic CPU behavior, where CPU is doing a normal bus operation and when interrupt comes, CPU needs to suspend the normal operation and start interrupt handling. Once interrupt handling is over, CPU should resume the normal operation from where it was suspended.

A lock might be used to model a prioritized interrupt and a grab might be used to model a non-mask able interrupt (NMI).
The lock() and grab() calls have antidote calls to release a lock and these are unlock() and ungrab().

Lock()
1) A lock() request is put in back of the arbitration queue . A lock request will be arbitrated the same as any other request.
2) A lock is granted after all earlier requests are completed and no other locks or grabs are blocking this sequence.
3) A lock() is blocking task and when access is granted, it will unblock.
4) If no argument is supplied, then current default sequencer is chosen.

Grab()
1) A grab() request is put in front of the arbitration queue. A grab() request will be arbitrated before any other requests.
2) A grab() is granted when no other grabs or locks are blocking this sequence. (The only thing that stops a sequence from grabbing a sequencer is a pre-existing lock() or grab() condition.)
3) A grab() is blocking task and when access is granted, it will unblock.
4) If no argument is supplied, then current default sequencer is chosen.

Unlock()
The unlock sequencer function is called from within a sequence to give up its lock or grab. A locking sequence must call unlock before completion; otherwise the sequencer will remain locked.

Ungrab()
An alias of function unlock().


What happens if 2 sequences try to grab or lock the same sequencer?
The most recent grab goes to the front of the queue; the most recent lock goes to the back of the queue.

Priority in lock() and grab().
The most recent grab comes first, then the previous grab... then the oldest lock, then the most recent lock.

Let’s go through basic example of lock() and grab()
1) Lock
---------------------------------------------
---------------------------------------------

2) Grab
---------------------------------------------
---------------------------------------------
From output of above two examples, we can see the difference between lock() and grab() as mentioned above.


When a hierarchical sequence locks/grab a sequencer, then its child sequences will have access to the sequencer.
If one of the child sequences issues a lock/grab, then the parent sequence will not be able to start any parallel sequences or send any sequence_items until the child sequence has unlocked.
---------------------------------------------
---------------------------------------------


A locking or grabbing sequence must always unlock before it completes,
---------------------------------------------
---------------------------------------------

Now let’s go through one example where 2 virtual sequences are running in parallel and one virtual sequence put lock/grab on agent’s sequencer.

---------------------------------------------
---------------------------------------------

Thursday 16 February 2017

Difference between @event and wait(event.triggered) in SystemVerilog and usage of non-blocking event

The event data type provides a handle to a synchronization object.

There are two ways through which we can wait for particular event to be triggered.
So let's understand what is the exact difference between those 2 ways.

-----------------------------------------------

-----------------------------------------------

An event trigger ->e is an instantaneous event. The event waiting process @ shall execute before the triggering process -> executes. If the trigger executes first, then the waiting process remains blocked.

The triggered event property evaluates to true (1'b1) if the given event has been triggered in the current time step and false (1'b0) otherwise.
Now you no longer have to worry which came first, the triggering process –> or the waiting process @ statement. But you still have to execute the waiting process @ in the current time slot to catch the event.

Let’s see the behavior with examples,
-----------------------------------------------

-----------------------------------------------

-----------------------------------------------

-----------------------------------------------

The other workaround is to use nonblocking event

Non-blocking event ->>
Nonblocking events are triggered using the ->> operator.

The effect of the ->> operator is that the statement executes without blocking, and it creates a nonblocking assign update event in the time in which the delay control expires or the event control occurs. The effect of this update event shall be to trigger the referenced event in the nonblocking assignment region of the simulation cycle.

-----------------------------------------------
-----------------------------------------------