UVM callbacks


// I hope it helps. put it all in a file and run it.
package tb_env;
  import uvm_pkg::*;
  `include "uvm_macros.svh"
  
  // Basic sequence item
  class shift_reg_item extends uvm_sequence_item;
    rand bit [7:0] data;
    rand bit [2:0] shift;
    
    `uvm_object_utils_begin(shift_reg_item)
    `uvm_field_int(data, UVM_ALL_ON)
    `uvm_field_int(shift, UVM_ALL_ON)
    `uvm_object_utils_end
    
    function new (string name="shift_reg_item");
      super.new(name);
    endfunction
    
  endclass
  
  // Basic sequence
  class shift_reg_seq extends uvm_sequence #(shift_reg_item);
    `uvm_object_utils(shift_reg_seq)
    
    shift_reg_item req;
    
    function new(string name="shift_req_seq");
      super.new(name);
    endfunction
    
    task body();
      req=shift_reg_item::type_id::create("req");
      start_item(req);
      if(!req.randomize())
      `uvm_fatal("shift_reg_seq","Failed to randomize shift_reg item")
      finish_item(req);
      // `uvm_do(req)
      // `uvm_do_with(req, {req.data==8'hAA; req.shift==3'b101;})
    endtask
  endclass
  
  // Sequencer
  class shift_reg_sqr extends uvm_sequencer #(shift_reg_item);
    
    `uvm_component_utils(shift_reg_sqr)
    
    function new (string name, uvm_component parent);
      super.new(name, parent);
    endfunction
    
  endclass
  
  typedef class shift_reg_drv;
  
  // Callback parent class
  // here you define the method that will change the sequence
  // Implementation will be done in child class
  class driver_cb extends uvm_callback;
    `uvm_object_utils (driver_cb)
    
    function new (string name = "driver_cb");
      super.new(name);
    endfunction
    
    virtual function void set_seq_item_value (shift_reg_drv drv, shift_reg_item item);
    endfunction : set_seq_item_value
    
  endclass : driver_cb
  
  // Driver 
  class shift_reg_drv extends uvm_driver #(shift_reg_item);
    `uvm_component_utils(shift_reg_drv)

    // Register the callback class with this  driver class
    `uvm_register_cb (shift_reg_drv, driver_cb)
    
    function new (string name, uvm_component parent);
      super.new(name, parent);
    endfunction
    
    // If the callback is added to this driver, this method
    // will call the method defined in the callback class (child callback class)
    virtual function void set_seq_item_value (shift_reg_item item);
      `uvm_do_callbacks(shift_reg_drv, driver_cb, set_seq_item_value(this, item))
    endfunction : set_seq_item_value
    
    task run_phase (uvm_phase phase);
      forever begin
        seq_item_port.get_next_item(req);
        // Call the callback method
        set_seq_item_value(req);
        req.print();
        seq_item_port.item_done();
      end
    endtask
  endclass
  
  // This class set data bit to ones
  // You can have many of this classes, each can do something else
  // make sure that they are all extend driver cb
  class set_seq_item_all_ones_cb extends driver_cb;
    `uvm_object_utils(set_seq_item_all_ones_cb)
    
    function new (string name = "set_seq_item_all_ones_cb");
      super.new(name);
    endfunction
    
    // Override the the method that was declared in driver_cb
    virtual function void set_seq_item_value (shift_reg_drv drv, shift_reg_item item);
      item.data = 8'hFF;
      item.shift = 3'h3;
    endfunction : set_seq_item_value
    
  endclass : set_seq_item_all_ones_cb
  
  class shift_reg_test extends uvm_test;
    
    shift_reg_seq seq;
    shift_reg_drv drv;
    shift_reg_sqr sqr;
    set_seq_item_all_ones_cb cb;
    
    `uvm_component_utils(shift_reg_test)
    
    function new(string name, uvm_component parent);
      super.new(name, parent);
    endfunction
    
    function void build_phase (uvm_phase phase);
      super.build_phase(phase);
      sqr=shift_reg_sqr::type_id::create("sqr", this);
      drv=shift_reg_drv::type_id::create("drv", this);
      seq=shift_reg_seq::type_id::create("seq");
      cb=set_seq_item_all_ones_cb::type_id::create("cb");
    endfunction
    
    function void connect_phase (uvm_phase phase);
      super.connect_phase(phase);
      drv.seq_item_port.connect(sqr.seq_item_export);
    endfunction
    
    task run_phase (uvm_phase phase);
      super.run_phase(phase);
      phase.raise_objection(this);
      // Start sequence with out callback
      seq.start(sqr);
      // Here is where you add the callback functionality to the driver
      // if you want to change is behaviour
      uvm_callbacks #(shift_reg_drv, driver_cb)::add(drv, cb);
      // Start the sequence with add callback functionality to the driver
      seq.start(sqr);
      // If you want you can remove to callback functionality fro the driver
      uvm_callbacks #(shift_reg_drv, driver_cb)::delete(drv, cb);
      // Start sequence without callback
      seq.start(sqr);
      phase.drop_objection(this);
    endtask
    
  endclass
endpackage : tb_env

module top;
  import uvm_pkg::*;
  `include "uvm_macros.svh"
  import tb_env::*;
  
  initial run_test("shift_reg_test");
endmodule