|HOME |ABOUT |ARTICLES |ACK |FEEDBACK |TOC |LINKS |BLOG |JOBS |


Tutorials



UVM CALLBACK



Callback mechanism is used for altering the behavior of the transactor without modifying the transactor. One of the many promises of Object-Oriented programming is that it will allow for plug-and-play re-usable verification components. Verification Designers will hook the transactors together to make a verification environment. In SystemVerilog, this hooking together of transactors can be tricky. Callbacks provide a mechanism whereby independently developed objects may be connected together in simple steps.

This article describes uvm callbacks. uvm callback might be used for simple notification, two-way communication, or to distribute work in a process. Some requirements are often unpredictable when the transactor is first written. So a transactor should provide some kind of hooks for executing the code which is defined afterwards. In uvm, these hooks are created using callback methods. For instance, a driver is developed and an empty method is called before driving the transaction to the DUT. Initially this empty method does nothing. As the implementation goes, user may realize that he needs to print the state of the transaction or to delay the transaction driving to DUT or inject an error into transaction. Callback mechanism allows executing the user defined code in place of the empty callback method. Other example of callback usage is in monitor. Callbacks can be used in a monitor for collecting coverage information or for hooking up to scoreboard to pass transactions for self checking. With this, user is able to control the behavior of the transactor in verification environment and individual testcases without doing any modifications to the transactor itself.

Following are the steps to be followed to create a transactor with callbacks. We will see simple example of creating a Driver transactor to support callback mechanism.

Stpe 1) Define a facade class.

1) Extend the uvm_callback class to create a faced class.


class Driver_callback extends uvm_callback;

endclass : Driver_callback


2)Define required callback methods. All the callback methods must be virtual.
In this example, we will create callback methods which will be called before driving the packet and after driving the packet to DUT.


virtual task pre_send(); endtask
virtual task post_send(); endtask


3)Define the constructor and get_type_name methods and define type_name.


function new (string name = "Driver_callback");
super.new(name);
endfunction

static string type_name = "Driver_callback";

virtual function string get_type_name();
return type_name;
endfunction



Step 2) Register the facade class with driver and call the callback methods.

1)In the driver class, using `uvm_register_cb() macro, register the facade class.


class Driver extends uvm_component;

`uvm_component_utils(Driver)

`uvm_register_cb(Driver,Driver_callback)

function new (string name, uvm_component parent=null);
super.new(name,parent);
endfunction

endclass



2)Calling callback method.
Inside the transactor, callback methods should be called whenever something interesting happens.
We will call the callback method before driving the packet and after driving the packet. We defined 2 methods in facade class. We will call pre_send() method before sending the packet and post_send() method after sending the packet.

Using a `uvm_do_callbacks() macro, callback methods are called.
There are 3 argumentd to `uvm_do_callbacks(,) macro.
First argument must be the driver class and second argument is facade class.
Third argument must be the callback method in the facade class.

To call pre_send() method , use macro
`uvm_do_callbacks(Driver,Driver_callback,pre_send());
and similarly to call post_send() method,
`uvm_do_callbacks(Driver,Driver_callback,post_send());

Place the above macros before and after driving the packet.


virtual task run();

repeat(2) begin
`uvm_do_callbacks(Driver,Driver_callback,pre_send())
$display(" Driver: Started Driving the packet ...... %d",$time);
// Logic to drive the packet goes hear
// let's consider that it takes 40 time units to drive a packet.
#40;
$display(" Driver: Finished Driving the packet ...... %d",$time);
`uvm_do_callbacks(Driver,Driver_callback,post_send())
end
endtask





With this, the Driver implementation is completed with callback support.



Driver And Driver Callback Class Source Code

class Driver_callback extends uvm_callback;

function new (string name = "Driver_callback");
super.new(name);
endfunction

static string type_name = "Driver_callback";

virtual function string get_type_name();
return type_name;
endfunction

virtual task pre_send(); endtask
virtual task post_send(); endtask

endclass : Driver_callback

class Driver extends uvm_component;

`uvm_component_utils(Driver)

`uvm_register_cb(Driver,Driver_callback)

function new (string name, uvm_component parent=null);
super.new(name,parent);
endfunction


virtual task run();

repeat(2) begin
`uvm_do_callbacks(Driver,Driver_callback,pre_send())
$display(" Driver: Started Driving the packet ...... %d",$time);
// Logic to drive the packet goes hear
// let's consider that it takes 40 time units to drive a packet.
#40;
$display(" Driver: Finished Driving the packet ...... %d",$time);
`uvm_do_callbacks(Driver,Driver_callback,post_send())
end
endtask

endclass



Let's run the driver in simple testcase. In this testcase, we are not changing any callback methods definitions.


Testcase Source Code


module test;

Driver drvr;

initial begin
drvr = new("drvr");
run_test();
end

endmodule

(S) Download files


uvm_callback_1.tar
Browse the code in uvm_callback_1.tar


(S) Command to run the simulation


VCS Users : make vcs
Questa Users: make questa


(S) Log report

UVM_INFO @ 0: reporter [RNTST] Running test ...
Driver: Started Driving the packet ...... 0
Driver: Finished Driving the packet ...... 40
Driver: Started Driving the packet ...... 40
Driver: Finished Driving the packet ...... 80
UVM_ERROR @ 9200: reporter [TIMOUT] Watchdog timeout of '9200' expired.



Following steps are to be performed for using callback mechanism to do required functionality.
We will see how to use the callbacks which are implemented in the above defined driver in a testcase.

1) Implement the user defined callback method by extending facade class of the driver class.
We will delay the driving of packet be 20 time units using the pre_send() call back method.
We will just print a message from post_send() callback method.


class Custom_Driver_callbacks_1 extends Driver_callback;

function new (string name = "Driver_callback");
super.new(name);
endfunction

virtual task pre_send();
$display("CB_1:pre_send: Delaying the packet driving by 20 time units. %d",$time);
#20;
endtask

virtual task post_send();
$display("CB_1:post_send: Just a message from post send callback method \n");
endtask

endclass


2) Construct the user defined facade class object.


Custom_Driver_callbacks_1 cb_1;
cb_1 = new("cb_1");


3) Register the callback method with the driver component. uvm_callback class has static method add() which is used to register the callback.



uvm_callbacks #(Driver,Driver_callback)::add(drvr,cb_1);


Testcase 2 Source Code

class Custom_Driver_callbacks_1 extends Driver_callback;

function new (string name = "Driver_callback");
super.new(name);
endfunction

virtual task pre_send();
$display("CB_1:pre_send: Delaying the packet driving by 20 time units. %d",$time);
#20;
endtask

virtual task post_send();
$display("CB_1:post_send: Just a message from post send callback method \n");
endtask

endclass

module test;

initial begin
Driver drvr;
Custom_Driver_callbacks_1 cb_1;
drvr = new("drvr");
cb_1 = new("cb_1");
uvm_callbacks #(Driver,Driver_callback)::add(drvr,cb_1);
uvm_callbacks #(Driver,Driver_callback)::display();
run_test();
end

endmodule

(S) Download the example


uvm_callback_2.tar
Browse the code in uvm_callback_2.tar


(S) Simulation Command


VCS Users : make vcs
Questa Users: make questa

Run the testcase. See the log results; We delayed the driving of packet by 20 time units using callback mechanism. See the difference between the previous testcase log and this log.


(S) Log report

cb_1 on drvr ON
UVM_INFO @ 0: reporter [RNTST] Running test ...
CB_1:pre_send: Delaying the packet driving by 20 time units. 0
Driver: Started Driving the packet ...... 20
Driver: Finished Driving the packet ...... 60
CB_1:post_send: Just a message from post send callback method

CB_1:pre_send: Delaying the packet driving by 20 time units. 60
Driver: Started Driving the packet ...... 80
Driver: Finished Driving the packet ...... 120
CB_1:post_send: Just a message from post send callback method

UVM_ERROR @ 9200: reporter [TIMOUT] Watchdog timeout of '9200' expired.





Now we will see registering 2 callback methods.
1) Define another user defined callback methods by extending facade class.


class Custom_Driver_callbacks_2 extends Driver_callback;

function new (string name = "Driver_callback");
super.new(name);
endfunction

virtual task pre_send();
$display("CB_2:pre_send: Hai .... this is from Second callback %d",$time);
endtask

endclass


2) Construct the user defined facade class object.


Custom_Driver_callbacks_2 cb_2;
cb_2 = new("cb_2");


3) Register the object


uvm_callbacks #(Driver,Driver_callback)::add(drvr,cb_2);

Testcase 3 Source Code


class Custom_Driver_callbacks_1 extends Driver_callback;

function new (string name = "Driver_callback");
super.new(name);
endfunction

virtual task pre_send();
$display("CB_1:pre_send: Delaying the packet driving by 20 time units. %d",$time);
#20;
endtask

virtual task post_send();
$display("CB_1:post_send: Just a message from post send callback method \n");
endtask

endclass

class Custom_Driver_callbacks_2 extends Driver_callback;

function new (string name = "Driver_callback");
super.new(name);
endfunction

virtual task pre_send();
$display("CB_2:pre_send: Hai .... this is from Second callback %d",$time);
endtask


endclass
module test;

initial begin
Driver drvr;
Custom_Driver_callbacks_1 cb_1;
Custom_Driver_callbacks_2 cb_2;
drvr = new("drvr");
cb_1 = new("cb_1");
cb_2 = new("cb_2");
uvm_callbacks #(Driver,Driver_callback)::add(drvr,cb_1);
uvm_callbacks #(Driver,Driver_callback)::add(drvr,cb_2);
uvm_callbacks #(Driver,Driver_callback)::display();
run_test();
end

endmodule

(S) Download source code


uvm_callback_3.tar
Browse the code in uvm_callback_3.tar


(S) Command to run the simulation


VCS Users : make vcs
Questa Users: make questa

Run the testcase and analyze the result.


(S) Log report

UVM_INFO @ 0: reporter [RNTST] Running test ...
CB_1:pre_send: Delaying the packet driving by 20 time units. 0
CB_2:pre_send: Hai .... this is from Second callback 20
Driver: Started Driving the packet ...... 20
Driver: Finished Driving the packet ...... 60
CB_1:post_send: Just a message from post send callback method

CB_1:pre_send: Delaying the packet driving by 20 time units. 60
CB_2:pre_send: Hai .... this is from Second callback 80
Driver: Started Driving the packet ...... 80
Driver: Finished Driving the packet ...... 120
CB_1:post_send: Just a message from post send callback method

UVM_ERROR @ 9200: reporter [TIMOUT] Watchdog timeout of '9200' expired.



The log results show that pre_send() method of CDc_1 is called first and then pre_send() method of Cdc_2. This is because of the order of the registering callbacks.


uvm_callbacks #(Driver,Driver_callback)::add(drvr,cb_1);
uvm_callbacks #(Driver,Driver_callback)::add(drvr,cb_2);



Now we will see how to change the order of the callback method calls.
By changing the sequence of calls to add() method, order of callback method calling can be changed.


Testcase 4 Source Code

module test;

initial begin
Driver drvr;
Custom_Driver_callbacks_1 cb_1;
Custom_Driver_callbacks_2 cb_2;
drvr = new("drvr");
cb_1 = new("cb_1");
cb_2 = new("cb_2");
uvm_callbacks #(Driver,Driver_callback)::add(drvr,cb_2);
uvm_callbacks #(Driver,Driver_callback)::add(drvr,cb_1);
uvm_callbacks #(Driver,Driver_callback)::display();
run_test();
end

endmodule


(S) Download the source code


uvm_callback_4.tar
Browse the code in uvm_callback_4.tar


(S) Command to run the simulation


VCS Users : make vcs
Questa Users: make questa

Run and analyze the results.
Log results show that, pre_send() method of CDs_1 is called after calling CDs_2 pre_send() method.


(S) Log file report

UVM_INFO @ 0: reporter [RNTST] Running test ...
CB_2:pre_send: Hai .... this is from Second callback 0
CB_1:pre_send: Delaying the packet driving by 20 time units. 0
Driver: Started Driving the packet ...... 20
Driver: Finished Driving the packet ...... 60
CB_1:post_send: Just a message from post send callback method

CB_2:pre_send: Hai .... this is from Second callback 60
CB_1:pre_send: Delaying the packet driving by 20 time units. 60
Driver: Started Driving the packet ...... 80
Driver: Finished Driving the packet ...... 120
CB_1:post_send: Just a message from post send callback method

UVM_ERROR @ 9200: reporter [TIMOUT] Watchdog timeout of '9200' expired.



Methods:


(S)add_by_name:


We have seen, the usage of add() method which requires object.
Using add_by_name() method, callback can be registered with object name.


static function void add_by_name(string name,
uvm_callback cb,
uvm_component root,
uvm_apprepend ordering = UVM_APPEND)

(S)delete:


uvm also provides uvm_callbacks::delete() method to remove the callback methods which are registered.
Similar to delete, delete_by_name() method is used to remove the callback using the object name.



static function void delete_by_name(string name,
uvm_callback cb,
uvm_component root )

Macros:


`uvm_register_cb


Registers the given CB callback type with the given T object type.


`uvm_set_super_type


Defines the super type of T to be ST.


`uvm_do_callbacks


Calls the given METHOD of all callbacks of type CB registered with the calling object


`uvm_do_obj_callbacks


Calls the given METHOD of all callbacks based on type CB registered with the given object, OBJ, which is or is based on type T.


`uvm_do_callbacks_exit_on


Calls the given METHOD of all callbacks of type CB registered with the calling object


`uvm_do_obj_callbacks_exit_on


Calls the given METHOD of all callbacks of type CB registered with the given object OBJ, which must be or be based on type T, and returns upon the first callback that returns the bit value given by VAL.

Index
Introduction
Uvm Testbench
Uvm Reporting
Uvm Transaction
Uvm Configuration
Uvm Factory
Uvm Sequence 1
Uvm Sequence 2
Uvm Sequence 3
Uvm Sequence 4
Uvm Sequence 5
Uvm Sequence 6
Uvm Tlm 1
Uvm Tlm 2
Uvm Callback

Report a Bug or Comment on This section - Your input is what keeps Testbench.in improving with time!





<< PREVIOUS PAGE

TOP

NEXT PAGE >>

copyright © 2007-2017 :: all rights reserved www.testbench.in::Disclaimer