The Ultimate Hitchhiker's Guide to Verification

Dumping ground of useful links/articles/tips/tricks on System Verilog/VMM/OVM as and when I stumble upon them and some of my views on it :)

Advanced SystemVerilog Process Control – Beyond fork-join_X


Abstract— All the Hardware Verification Languages (HVL) have an inherent requirement to have process control capabilities like creation, control and destruction of process. Although Verilog language has incorporated such capabilities like named blocks and fork-join statements, but SystemVerilog has further extended these properties of verilog with introduction of fork-join_X, disable fork and fine grain process control. ―Fine grain process control is the least understood and least used capability amongst all the SystemVerilog process control capabilities. The main reason behind the same is due to the fact that SV LRM[1] has very brief and concise description (about two pages) of fine grain process control. This paper aims in de-mystifying the above constructs and shows the use of fine grain process control for much more flexible processes creation, their control as well as destruction capabilities. It discusses how per-instance-based process control and decoupling of ―how and when can be done using SV fine grain process control

Index Terms—Fine grain process control, Inbuilt process class of SystemVerilog, Per-instance based process control, Decoupling of how and when of processes.

I. INTRODUCTION
Process control capabilities like creation, control and destruction of processes are inherent requirements of any Hardware Verification Language. Verilog has named block, fork-join construct for controlling process creation, control and destruction. Below example will show some of the capabilities of verilog process control.

always @(posedge req) begin 
  fork 
  begin : Label1 
    wait(a); 
    disable Label2; 
  end 
  begin : Label2 
    wait(b); 
  end 
  join 
end

In the above mentioned code snippet, we are creating two threads named “Label1” and “Label2” at every posedge of req. In the thread “Label1”, as soon as signal “a” becomes HIGH, it kills the thread “Label2”.

But, there are few limitations in Verilog’s process creation, control as well as destruction. The main limitation of verilog’s fork-join statement is that there is very less flexibility in terms of when it should get out of fork loop. In addition, disabling of named block is not a good way of killing a process.

SystemVerilog solved the 1st limitation of verilog’s process control capabilities by adding new constructs like join_any, join_none, disable fork and wait fork. These constructs are widely used for controlling process creation/control/destruction.

However these constructs have further few limitations for finer control of process. Using the above constructs, we cannot suspend/resume/kill only a specific single process. SystemVerilog has a feature called “Fine grain process control” using which we can have much finer control on creation/control/destruction of process.

II. FINE GRAIN PROCESS CONTROL
Fine grain process control is meant for having finer control on processes compared to the control one can get using fork/join_x constructs. This is done using SystemVerilog’s inbuilt class called ’process’. Let’s look at the various feature of the above class and how to use them for finer control of processes.

A. Handle Creation and status check
To control any process/thread, we need to get the handle of the above thread using calling “process::self()” method of process class. Below code snippet will show how to do the same.

task abc(…); 
  process P; 
  process::state Pstate; 
  … 
  fork 
  begin 
    P = process::self(); 
    … 
    Pstate = P.status(); 
  end 
  join_none 
endtask : abc

A process can be created for each always, initial block, and begin…end statement inside fork…join_X and dynamic processes. In addition, we can check the status of any process by calling status() method. A process can be in either of these 5 states (FINISHED, RUNNING, WAITING, SUSPENDED, KIL). “process::state” is a enumerated value and its content can be displayed using .name() method.

B. Process Suspension, Resumption, Await and Kill
Any process can be suspended or resumed by calling suspend() and resume() task of process class. Similarly, the process can be terminated by calling kill() method. The await() method blocks till the process is terminated. SystemVerilog code snippet given in section “USE-CASE: FINER CONTROL OF PROCESS”.

There can be few race conditions when a process is waiting for some event/variable change and we suspend the process. The question is on what condition the process shall resume its execution. These are simple rules to know when the process shall get unblocked from the waiting event[2]
  1. If the process is waiting for a delay like (#100 or #20ns) while going to suspend state, it will not count the time spent while in suspend state as the delay.
  2. If the process is waiting for an event (@(SV_event)) while going for suspend state, and the event has occurred when the process is at suspend state, then the process will be unblocked, and will start executing from the next while after resuming.
  3. If the process is waiting for variable change (@(SV_variable) or wait(SV_variable)) : Check for change of the variable is not performed when the process is suspended and hence any variable change happened during the time when the process is in suspended state shall not unblock the process if it is waiting for variable change and is put to suspend state
 
 III. USE-CASE: PER-INSTANCE BASED FINER CONTROL OF PROCESSES.
Consider a scenario where we have created some N numbers of thread/process in one task. From another task, we want to suspend/resume/kill selected few tasks depending upon some other external conditions. Fine grain process control is extremely well suited for these kinds of tasks. Let see an example code snippet to understand how it can be done.

class fine_grain_process_ctrl_example;
 
  // Data members
  process p[20];        
  …

  task spawn_thread;
    for(int i=0; i<20; i++)
    begin
      fork
      begin
        p[i] = process::self();
        run_thread();
      end
      join_none
    end       
  endtask: spawn_thread
 
  task control_thread;
    …
    // condition met for suspending p[i]
    p[i].suspend();
    …
    // condition met for resuming p[j]
    p[j].resume();
    …
    // condition met for killing p[k]
    p[k].kill();
    …
    // Wait for completion of p[l]
    p[l].await();
  endtask: control_thread
endclass: fine_grain_process_ctrl_example

In the above code snippet, we have a class called fine_grain_process_ctrl, which has an array of process handles. In the task spawan_thread, where we are creating 20 parallel threads (by calling some external task run_thread()), we are also storing the handle of the process into the process array. Now in the task control_thread, we are controlling the suspension/resumption/termination of the above threads (which can be done in per-instance basis) depending upon some condition).

There is another advantage of the above way of doing the process control. Here effectively, we are de-coupling what to do in the thread, and how to handle thread. This decoupling is very useful for code-reuse. The details of the above aspect are described in more detail in next section.

IV. USE-CASE: DECOUPLING HOW AND WHEN


Consider a case where you have already written a transactor which sends packets according to your requirements. Now you need to change your code to make it work in the low-power-world where you need to stop sending packets whenever the system enters low-power state and resume sending packet once you are out of it. You have coded “HOW” to send your packet, and now you need to incorporate “WHEN” to send it, which itself can be far more complex that the simple “HOW”.

You can directly go and modify the transactor code to incorporate “WHEN” aspect of the packet transmission. There are quite a few reasons why you would rather not touch the code and do the same in another way.

Fine grain process control can be very nicely used in such scenario. You can have a handle of the process of sending packet. Now using this handle, we can stop/resume execution of the process (thereby stopping/resuming sending of packet) by calling suspend/resume method. We can have another piece of code where we can code the logic which will have the logic that shall control “WHEN” to send the packet.

REFERENCES
[1] "IEEE Standard For SystemVerilog - Unified Hardware Design, Specification and Verification Language," IEEE Computer Society, IEEE, New York, NY, IEEE Std 1800-2009
[2] Article on “Fine Grain Process Control” at Synopsys Solvenet
  1. https://solvnet.synopsys.com/retrieve/025656.html
  2. https://solvnet.synopsys.com/retrieve/025657.html
  3. https://solvnet.synopsys.com/retrieve/025658.html

0 comments:

Post a Comment

About Me

My photo
I am from Sambalpur, Orissa, India. Have done Btech and Mtech in ECE from IIT Kharagpur. Currently working as Lead Member Technical Staff at Mentor Graphics Noida

My Feedburner

Followers

Search This Blog

My Shelfari Bookshelf

Shelfari: Book reviews on your book blog

 

Traffic Summary