Wednesday 28 September 2016

Synchronization using uvm_objection

In this blog, we will see how to do synchronization using uvm_objection.

UVM provides "raise_objection" method for raising objections and "drop_objection" method for dropping objections in the testbench. These methods are the part of "uvm_objection" class. We will see, how these methods synchronizes various tasks in the component.

Below is an example of a normal code where an objection is raised and then the two tasks (response and process_txn) are executed in parallel. One can assume that, after getting transaction from "seq_item_port", the driver is executing that transaction and receiving response for the same. In "process_txn" task, two tasks are called in a serial way, "process_header" followed by "process_data". Once execution of "process_header" task is completed, "process_resp" event is triggered which executes "response" task (from waiting state of the same event). In parallel with that, "process_data" task is executed. Once "response" and "process_txn" tasks are completed, an objection is dropped. 

Method 1:
  event process_resp;
  task run_phase(uvm_phase phase);
    ...
    for(int i = 0; i < 10; ++i) 
    begin
      phase.raise_objection(this);
      fork
        response();
        process_txn();
      join
      phase.drop_objection(this);
    `uvm_info("run_phase","Done", UVM_LOW)
    end
    `uvm_info("run_phase","Run phase completed", UVM_LOW)
  endtask : run_phase

  task process_txn();

    process_header();
    -> process_resp;
    process_data();
  endtask : process_txn

  task process_header();

    ...
    #20;
  endtask

  task process_data();

    ...
    #15;
  endtask

  task response();

     ... 
    @(process_resp);
    `uvm_info(get_full_name(),$sformatf("Processing Response"), UVM_LOW)
    #25;
  endtask : response


The same thing can be achieved by using "uvm_objection" methods.

"raise_objection" and "drop_objection" methods has three arguments:
    obj - Handle of the calling class usually "this"
    description - String for indicating specific objection
    count - Raise or drop number of objection, default value is 1.

Whenever "raise_objection" method is called, by default it raise one objection and one objection is dropped while calling "drop_objection" method. On 3rd argument, we can pass any number which raise/drop that many objections. 

UVM objection class has two methods which helps you to synchronize the processes based on these objections. You can wait on objection raise/drop event or on objection count value. Below are the two methods:

(1) "wait_for" method is used for event based waiting. Event can be raising an objection, dropping an objection or dropping all objections.  It has two arguments:
    objt_event - It is an enum having values "UVM_RAISED" (triggers when an objection raised), "UVM_DROPPED" (triggers when an objection dropped) and "UVM_ALL_DROPPED" (triggers when all objection dropped). 
    obj - Handle of uvm_object class on which triggering of event depends

(2) "wait_for_total_count" method is used for waiting until objection count reaches to a specific value. It also has two arguments:
    obj - Handle of uvm_object class usually this 
    count - Wait until the objection count of the obj object reaches to this value

By using these features, above example code could be written in following way:

Method 2:
  uvm_objection obj;
  task run_phase(uvm_phase phase);
    obj = phase.get_objection();
    for(int i = 0; i < 10; ++i) 
    begin
      phase.raise_objection(this, "Rasing Objection", 2);
      fork
        response();
        process_txn(phase);
      join
      phase.drop_objection(this);
    `uvm_info("run_phase","Done", UVM_LOW)
    end
    `uvm_info("run_phase","Run phase completed", UVM_LOW)
  endtask : run_phase

  task process_txn(uvm_phase phase);

    process_header();
    phase.drop_objection(this);
    process_data();
  endtask : process_txn

  task process_header();

    ...
    #20;
  endtask

  task process_data();

    ...
    #15;
  endtask

  task response();

    ...
    obj.wait_for(UVM_DROPPED, this) // or "obj.wait_for_total_count(this, 1);"
    `uvm_info(get_full_name(),$sformatf("Processing Response"), UVM_LOW)
    #25;
  endtask : response

Note that, 2 objections are raised in the above example. An objection is dropped after executing "process_header" task. So, total raised objection count is set to 1. In "response" task, "wait_for" method is used for waiting on objection drop event in this class ("wait_for_total_count" method is used for waiting objection count reaches to 1). So, it starts execution in parallel to "process_data" task. Once "response" and "process_txn" tasks are completed, an objection will be dropped.  

Here, both methods give same output result.

No comments:

Post a Comment