Callback Example
Table of Contents
Callback to corrupt the stimulus
Let’s consider an example of a Slave Driver (Slave Driver: drives response to the master).
For simplicity, one callback hook is implemented and only response generation logic is captured in the code.
Components of slave_driver example are,
- slave_driver – Normal driver to drive response
- response types are OKAY, EXOKAY, SLVERR, DECERR
- slave_driver is constrained to send OKAY response always to see to the callback usage difference
- slave_env – Environment which has a slave driver created in it
- basic_test – Which sends the normal response
- driver_callback – Callback class
- slv_err_test – Testcase with callback used to generate an error response
- err_error_callback – extended callback class to implement callback method
By using a callback, will write the testcase to drive the SLVERR response.
For easy understanding will see through below steps,
- Adding callback support
- Implementing the callback methods
- Using callback
Adding Callback Support
In order to have user-defined callbacks,
- User has to write user-defined callback class by extending the uvm_callback class
class driver_callback extends uvm_callback; ... endclass
- Define the callback method in user-defined callback class
- In this example update_resp() is the callback method.
virtual task update_resp(ref resp_type resp); endtask
Complete user-defined class code
class driver_callback extends uvm_callback; `uvm_object_utils(driver_callback) function new(string name = "driver_callback"); super.new(name); endfunction virtual task update_resp(ref resp_type resp); endtask endclass
In order to use callbacks defined,
- Callback class has to be registered with the object/component where callbacks are going to be used.
- Callback class can be registered by using macro `uvm_register_cb
`uvm_register_cb(slave_driver,driver_callback)
In order to call the callback methods,
- Need to place method call’s (callback hook) to methods defined in user-defined callback class (update_resp())
- Callback methods can be called by using macro `uvm_do_callbacks
`uvm_do_callbacks(slave_driver,driver_callback,update_resp(resp));
Complete driver code
class slave_driver extends uvm_component; resp_type resp; `uvm_component_utils(slave_driver) `uvm_register_cb(slave_driver,driver_callback) function new(string name, uvm_component parent); super.new(name,parent); endfunction task run_phase(uvm_phase phase); repeat(2) begin //{ std::randomize(resp) with { resp == OKAY;}; `uvm_do_callbacks(slave_driver,driver_callback,update_resp(resp)); `uvm_info("DRIVER",$sformatf("Generated response is %s",resp.name()),UVM_LOW); end //} endtask endclass
Implementing Callback Method
We have looked into, how to define the callback methods (In user-defined callback class) and placing hook to callback methods (In driver class using `uvm_do_callbacks macro)
Here will see how to add logic to callback methods.
- Need to extend the user-defined callback class and write one more callback class slv_error_callback
class slv_error_callback extends driver_callback; ... endclass
- Implement the methods with logic in it (this example we are adding only display’s)
task update_resp(ref resp_type resp); resp = SLVERR; endtask
Complete callback class code
class slv_error_callback extends driver_callback; `uvm_object_utils(slv_error_callback) function new(string name = "slv_error_callback"); super.new(name); endfunction task update_resp(ref resp_type resp); resp = SLVERR; endtask endclass
Using Callback
In the testcase where callbacks need to be applied,
- Declare and create an object of callback class in which methods are implemented (slv_error_callback).
slv_error_callback err_callback; err_callback = slv_error_callback::type_id::create("err_callback", this);
- In order to execute the callback method, register the callback object to the driver using the ‘add’ method
uvm_callbacks#(slave_driver,driver_callback)::add(env.driver,err_callback);
Complete test case code
class slv_err_test extends basic_test; slv_error_callback err_callback; `uvm_component_utils(slv_err_test) function new(string name = "slv_err_test", uvm_component parent=null); super.new(name,parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); err_callback = slv_error_callback::type_id::create("err_callback", this); uvm_callbacks#(slave_driver,driver_callback)::add(env.driver,err_callback); endfunction endclass
slv_err_test is the test with callbacks added, and basic_test is without callbacks.
basic_test simulator output (Without Callback)
UVM_INFO @ 0: reporter [RNTST] Running test basic_test... UVM_INFO slave_driver.sv(19) @ 0: uvm_test_top.env.driver [DRIVER] Generated response is OKAY UVM_INFO slave_driver.sv(19) @ 0: uvm_test_top.env.driver [DRIVER] Generated response is OKAY UVM_INFO /apps/vcsmx/etc/uvm-1.2/src/base/uvm_report_server.svh(847) @ 0: reporter [UVM/REPORT/SERVER]
callback_test simulator output (With Callback)
UVM_INFO @ 0: reporter [RNTST] Running test slv_err_test... UVM_INFO slave_driver.sv(19) @ 0: uvm_test_top.env.driver [DRIVER] Generated response is SLVERR UVM_INFO slave_driver.sv(19) @ 0: uvm_test_top.env.driver [DRIVER] Generated response is SLVERR UVM_INFO /apps/vcsmx/etc/uvm-1.2/src/base/uvm_report_server.svh(847) @ 0: reporter [UVM/REPORT/SERVER]
Click to execute on
In order to execute the particular testcase, change the inline argument.
- +UVM_TESTNAME=basic_test
- +UVM_TESTNAME=slv_err_test