Raise/Drop objection Automatically with UVM

Variable uvm_sequence_base::starting_phase is deprecated and replaced by two new methods set_starting_phase and get_starting_phase, which prevent starting_phase from being modified in the middle of a phase. This change is not backward-compatible with UVM 1.1, though variable starting_phase, although deprecated, has not yet been removed from the base class library.

New method uvm_sequence_base::set_automatic_phase_objection causes raise_objection and drop_objection to be called automatically around a sequence, avoiding the need to call raise/drop_objection manually in one common situation.

Lets understand it through below mentioned example.

import uvm_pkg :: *;

class my_seq_item extends uvm_sequence_item;
  rand logic [7:0] addr;
  rand logic [7:0] data;

  constraint addr_range_cn {
    addr inside {[10:20]};
  }
  constraint data_range_cn {
    data inside {[100:200]};
  }
  `uvm_object_utils_begin(my_seq_item)
  `uvm_field_int(addr, UVM_ALL_ON| UVM_DEC)
  `uvm_field_int(data, UVM_ALL_ON| UVM_DEC)
  `uvm_object_utils_end

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

  virtual function string convert2string();
    convert2string = $sformatf("addr=%0d, data=%0d", addr, data);
  endfunction : convert2string
endclass : my_seq_item

class my_sequencer extends uvm_sequencer #(my_seq_item);
  `uvm_component_utils (my_sequencer)

  function new (string name="my_sequencer", uvm_component parent=null);
    super.new(name, parent);
  endfunction : new
endclass : my_sequencer

class my_driver extends uvm_driver #(my_seq_item);
  `uvm_component_utils (my_driver)

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

  function void build_phase (uvm_phase phase);
    super.build_phase(phase);
  endfunction : build_phase

  task run_phase(uvm_phase phase);
    forever begin
      seq_item_port.get_next_item(req);
      `uvm_info(get_name(),
                $sformatf("in driver after get_next_item my_seq_item= %s", req.convert2string()), UVM_LOW);
      #50;
      `uvm_info(get_name(), $sformatf("item_done called"), UVM_LOW);
      seq_item_port.item_done();
    end
  endtask : run_phase
endclass : my_driver

class my_agent extends uvm_agent;
  `uvm_component_utils (my_agent)
  my_sequencer sqr;
  my_driver    drv;
  
  function new (string name="my_agent", uvm_component parent=null);
    super.new(name, parent);
  endfunction : new

  function void build_phase (uvm_phase phase);
    super.build_phase(phase);
    sqr = my_sequencer :: type_id :: create("sqr", this);
    drv = my_driver    :: type_id :: create("drv", this);
  endfunction : build_phase

  function void connect_phase (uvm_phase phase);
    super.connect_phase(phase);
    drv.seq_item_port.connect(sqr.seq_item_export);
  endfunction : connect_phase
endclass : my_agent

class my_seq extends uvm_sequence #(my_seq_item);
  `uvm_object_utils (my_seq)
  function new(string name="my_seq");
    super.new(name);
 
  // The most common interaction with the starting phase
  // within a sequence is to simply RAISE the phase's objection
  // prior to executing the sequence, and DROP the objection
  // after ending the sequence (either naturally, or
  // via a call to <kill>). In order to 
  // simplify this interaction for the user, the UVM
  // provides the ability to perform this functionality
  // automatically.
    
  // From a timeline point of view, the automatic phase objection
  // looks like:
  //| start() is executed
  //|   --! Objection is raised !--
  //|   pre_start() is executed
  //|   pre_body() is optionally executed
  //|   body() is executed
  //|   post_body() is optionally executed
  //|   post_start() is executed
  //|   --! Objection is dropped !--
  //| start() unblocks    
    
  // NEVER set the automatic phase objection bit to 1 if your sequence
  // runs with a forever loop inside of the body, as the objection will
  // never get dropped!
  set_automatic_phase_objection(1);
  endfunction : new

  task body ();
    `uvm_create(req)
    if(!req.randomize()) begin
      `uvm_fatal(get_name(), $sformatf("Randomization failed"))
    end
    `uvm_info (get_name(),
               $sformatf("After randomizating in my_seq my_seq_item= %s",
               req.convert2string()), UVM_LOW)
    `uvm_send(req)
  endtask : body
endclass : my_seq

class my_test extends uvm_test;
  `uvm_component_utils (my_test)
  my_agent agent;

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

  function void build_phase (uvm_phase phase);
    super.build_phase(phase);
    agent = my_agent::type_id::create("agent", this);
  endfunction : build_phase

  task run_phase(uvm_phase phase);
    my_seq seq;
    uvm_phase starting_phase;
    bit automatic_phase_objection_status;
    seq = my_seq::type_id::create ("seq");
    // Function: set_starting_phase
    // Sets the 'starting phase'.
    seq.set_starting_phase(phase);
    
    // If set_automatic_phase_objection is not called in new (constructor)
    // of sequence then can be calleb from test-case
    // seq.set_automatic_phase_objection(1);
    
    fork
      begin
        #30;
        // Function: get_starting_phase
        // Returns the 'starting phase'.
        // If non-null, the starting phase specifies the phase in which this
        // sequence was started. 
        starting_phase = seq.get_starting_phase();
        `uvm_info(get_name(),
                  $sformatf("starting_phase:%s", starting_phase.get_full_name()), UVM_LOW)
        
        // Function: get_automatic_phase_objection
        // Returns (and locks) the value of the 'automatically object to 
        // starting phase' bit.
        //
        // If 1, then the sequence will automatically raise an objection
        // to the starting phase (if the starting phase is not NULL) immediately
        // prior to <pre_start> being called.  The objection will be dropped
        // after <post_start> has executed, or <kill> has been called.
        automatic_phase_objection_status = seq.get_automatic_phase_objection();
        `uvm_info(get_name(),
                  $sformatf("during seq is running, get_automatic_phase_objection returns :%b", automatic_phase_objection_status), UVM_LOW)
      end
    join_none
    seq.start(agent.sqr);
    automatic_phase_objection_status = seq.get_automatic_phase_objection();
    `uvm_info(get_name(),
              $sformatf("After seq finished, get_automatic_phase_objection returns :%b", automatic_phase_objection_status), UVM_LOW)
  endtask : run_phase
endclass : my_test

module top();
  initial begin
    run_test("my_test");
  end
endmodule : top