UVM callback in UVM Sequence is similar to using callback in UVM driver. Before going through this article, I will suggest you to refer UVM Callbacks.
In a verification environment, sequences generate stimulus for the DUT (Device Under Test). Sometimes, test scenarios require modifications to a base sequence without modifying it directly. Callbacks enable this by injecting custom behaviors, such as error injection, monitoring, or modifying transactions dynamically. UVM callbacks in sequences offer a powerful way to modify sequence behavior dynamically without altering the core sequence implementation. They enable greater flexibility and reusability in testbenches, making it easier to handle variations in test scenarios.
Common Use Cases
- Error injection – Modify data before sending it to the driver.
- Protocol variations – Implement slight variations without creating multiple sequences.
- Coverage enhancement – Inject specific corner cases dynamically.
Example:
Let’s take a simple example similar we took in previous chapter uvm callback driver. We will define some functions in callback class and these functions will be called by the sequence. We can make changes according to our needs in callback functions which can alter the result of the sequence without changing the original code of sequence.
In this example, we are taking a simple transaction class with ‘data’ field and calling it in sequence. Let’s go step by step.
- Callback Class (my_callback):
- Defines
pre_item()andpost_item()virtual functions. - These functions will be called by the sequence.
- Uses
uvm_object_utilsfor UVM object functionalities.
- Defines
class my_sequence_callback extends uvm_callback;
`uvm_object_utils(my_sequence_callback)
function new(string name = "my_sequence_callback");
super.new(name);
endfunction
virtual function void pre_item(my_transaction item);
`uvm_info("SEQUENCE_CALLBACK", $sformatf("Pre-item callback called with data: %0d", item.data), UVM_LOW)
endfunction
virtual function void post_item(my_transaction item);
`uvm_info("SEQUENCE_CALLBACK", $sformatf("Post-item callback called with data: %0d", item.data), UVM_LOW)
endfunction
endclass
- Transaction (my_transaction):
- A simple transaction class with a
datafield. - Uses
uvm_object_utils_begin/endanduvm_field_intfor UVM object and field automation.
- A simple transaction class with a
- Sequence (my_sequence):
- Randomize data in sequence.
- Callback Execution:
- Uses `
uvm_do_callbacks#(my_sequence, my_callback, functions) to get the registered callback instances. - Calls
pre_item()before sending data. - Calls
post_item()after sending data.
- Uses `
class my_sequence extends uvm_sequence#(my_transaction);
`uvm_object_utils(my_sequence)
`uvm_register_cb(my_sequence, my_sequence_callback)
my_transaction req;
function new(string name = "my_sequence");
super.new(name);
endfunction
virtual task body();
req = my_transaction::type_id::create("req");
repeat (5) begin
start_item(req);
assert(req.randomize());
// Pre-item callback
`uvm_do_callbacks(my_sequence, my_sequence_callback, pre_item(req))
`uvm_info("MY_SEQUENCE", $sformatf("Sequence sending data: %0d", req.data), UVM_LOW);
// Post-item callback
`uvm_do_callbacks(my_sequence, my_sequence_callback, post_item(req))
finish_item(req);
end
endtask
endclass
- Sequencer (my_sequencer):
- Standard UVM sequencer.
- Driver (my_driver):
- drive transactions and receives data from the sequencer.
- Agent (my_agent):
- Instantiates the driver and sequencer.
- Connects the driver and sequencer ports.
- Environment (my_env):
- Instantiates the agent.
- Test (my_test):
- Instantiates the environment and sequence.
- Creates an instance of the callback class.
- Callback Registration:
- Uses
uvm_callbacks#(my_driver, my_callback)::add(env.agt.drv, my_cb_instance);to register the callback instance with the driver.
- Uses
- Starts the sequence.
class my_test extends uvm_test;
my_env env;
my_sequence seq;
my_sequence_callback seq_cb_instance;
`uvm_component_utils(my_test)
function new(string name = "my_test", uvm_component parent = null);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = my_env::type_id::create("env", this);
seq = my_sequence::type_id::create("seq");
seq_cb_instance = my_sequence_callback::type_id::create("seq_cb_instance");
endfunction
virtual function void end_of_elaboration_phase(uvm_phase phase);
super.end_of_elaboration_phase(phase);
uvm_callbacks#(my_sequence, my_sequence_callback)::add(seq, seq_cb_instance);
endfunction
virtual task run_phase(uvm_phase phase);
phase.raise_objection(this);
seq.start(env.agt.seqr);
phase.drop_objection(this);
endtask
endclass
- Top Module (top):
- Runs the test.
Output:
UVM_INFO @ 0: reporter [RNTST] Running test my_test...
UVM_INFO seqcallback.sv(10) @ 0: reporter [SEQUENCE_CALLBACK] Pre-item callback called with data: -517620205
UVM_INFO sequence.sv(21) @ 0: uvm_test_top.env.agt.seqr@@seq [MY_SEQUENCE] Sequence sending data: -517620205
UVM_INFO seqcallback.sv(14) @ 0: reporter [SEQUENCE_CALLBACK] Post-item callback called with data: -517620205
UVM_INFO driver.sv(13) @ 0: uvm_test_top.env.agt.drv [MY_DRIVER] Driving transaction with data: -517620205
UVM_INFO seqcallback.sv(10) @ 0: reporter [SEQUENCE_CALLBACK] Pre-item callback called with data: 774544662
UVM_INFO sequence.sv(21) @ 0: uvm_test_top.env.agt.seqr@@seq [MY_SEQUENCE] Sequence sending data: 774544662
UVM_INFO seqcallback.sv(14) @ 0: reporter [SEQUENCE_CALLBACK] Post-item callback called with data: 774544662
UVM_INFO driver.sv(13) @ 0: uvm_test_top.env.agt.drv [MY_DRIVER] Driving transaction with data: 774544662
UVM_INFO seqcallback.sv(10) @ 0: reporter [SEQUENCE_CALLBACK] Pre-item callback called with data: 1471791918
UVM_INFO sequence.sv(21) @ 0: uvm_test_top.env.agt.seqr@@seq [MY_SEQUENCE] Sequence sending data: 1471791918
UVM_INFO seqcallback.sv(14) @ 0: reporter [SEQUENCE_CALLBACK] Post-item callback called with data: 1471791918
UVM_INFO driver.sv(13) @ 0: uvm_test_top.env.agt.drv [MY_DRIVER] Driving transaction with data: 1471791918
UVM_INFO seqcallback.sv(10) @ 0: reporter [SEQUENCE_CALLBACK] Pre-item callback called with data: 459431653
UVM_INFO sequence.sv(21) @ 0: uvm_test_top.env.agt.seqr@@seq [MY_SEQUENCE] Sequence sending data: 459431653
UVM_INFO seqcallback.sv(14) @ 0: reporter [SEQUENCE_CALLBACK] Post-item callback called with data: 459431653
UVM_INFO driver.sv(13) @ 0: uvm_test_top.env.agt.drv [MY_DRIVER] Driving transaction with data: 459431653
UVM_INFO seqcallback.sv(10) @ 0: reporter [SEQUENCE_CALLBACK] Pre-item callback called with data: -377759977
UVM_INFO sequence.sv(21) @ 0: uvm_test_top.env.agt.seqr@@seq [MY_SEQUENCE] Sequence sending data: -377759977
UVM_INFO seqcallback.sv(14) @ 0: reporter [SEQUENCE_CALLBACK] Post-item callback called with data: -377759977
UVM_INFO driver.sv(13) @ 0: uvm_test_top.env.agt.drv [MY_DRIVER] Driving transaction with data: -377759977
UVM_INFO /apps/vcsmx/vcs/U-2023.03-SP2//etc/uvm-1.2/src/base/uvm_objection.svh(1276) @ 0: reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase
UVM_INFO /apps/vcsmx/vcs/U-2023.03-SP2//etc/uvm-1.2/src/base/uvm_report_server.svh(904) @ 0: reporter [UVM/REPORT/SERVER]
--- UVM Report Summary ---
** Report counts by severity
UVM_INFO : 23
UVM_WARNING : 0
UVM_ERROR : 0
UVM_FATAL : 0
** Report counts by id
[MY_DRIVER] 5
[MY_SEQUENCE] 5
[RNTST] 1
[SEQUENCE_CALLBACK] 10
[TEST_DONE] 1
[UVM/RELNOTES] 1
