Heart Beat Monitor

Hi,

The below code about the heartbeat monitor is not working as expected. Can someone help me to figure out the issue for the below code?

Code:


`include "uvm_macros.svh"
  import uvm_pkg::*;

class my_catcher extends uvm_report_catcher;
	uvm_phase phase;
  `uvm_object_utils(my_catcher)
  function new(string name = "my_catcher");
		super.new(name);
  endfunction : new
  
  function action_e catch();
	if(get_severity() == UVM_FATAL && get_id() == "HBFAIL") begin
		uvm_objection obj = phase.get_objection();
		`uvm_error("HBFAIL", $psprintf("Heartbeat failure! Objections:"));
		obj.display_objections();
	end
	return THROW;
  endfunction
endclass

  class my_env extends uvm_env;
    `uvm_component_utils(my_env)
    function new(string name, uvm_component parent);
      super.new(name, parent);
    endfunction 
        
    task run_phase(uvm_phase phase);
      for(int i =0;i<20;i++) begin        
        `uvm_info("ENV", $sformatf("RAISE : Env i = %0d",i),UVM_NONE)
        phase.raise_objection(this);      
        #10;        
        phase.drop_objection(this);
        `uvm_info("ENV", $sformatf("Drop : Env i = %0d",i),UVM_NONE)
      end
    endtask     
    
  endclass

  class my_test extends uvm_test;
    `uvm_component_utils(my_test)    
    my_env env;
    function new(string name, uvm_component parent);
      super.new(name, parent);
    endfunction
    
    function void build_phase(uvm_phase phase);
      env = my_env::type_id::create("env", this);
    endfunction
    
    function void start_of_simulation_phase(uvm_phase phase);
		super.start_of_simulation_phase(phase);
		heartbeat(phase);
	endfunction
    
    task run_phase(uvm_phase phase);
      phase.raise_objection(this);
      `uvm_info("TEST", "Inside Run phase..",UVM_NONE)
      #200;
      `uvm_info("TEST", "Ended Run phase..",UVM_NONE)
      phase.drop_objection(this);
    endtask    
    
    function void heartbeat(uvm_phase phase);
      uvm_heartbeat heartbeat;
      uvm_callbacks_objection my_objection;
      uvm_event my_event = new("my_event");
      uvm_component my_comps_q[$];
      my_catcher catcher = my_catcher :: type_id :: create("catcher",this);
      uvm_phase run_phase = phase.find_by_name("run", 0);      
      catcher.phase = run_phase;
      uvm_report_cb :: add(null, catcher);     
    
      assert ($cast(my_objection, run_phase.get_objection()))
      else
       `uvm_fatal("run_phase", $psprintf("run phase objection type"));
    
      heartbeat = new("activity_heartbeat",this,my_objection);
      heartbeat.set_mode(UVM_ANY_ACTIVE);         
      heartbeat.set_heartbeat(my_event, my_comps_q);  
      heartbeat.add(env);
      fork begin
       	forever begin   
        	#25 my_event.trigger();
            `uvm_warning("heartbeat",$sformatf("event triggered"))         	       
     	end
      end join_none
    endfunction : heartbeat 
    
  endclass

// The top module that contains the DUT and interface.
// This module starts the test.
module top;
  import uvm_pkg::*;
 
  initial begin
    run_test("my_test");
  end
 endmodule

Output :
Compiler version J-2014.12-SP1-1; Runtime version J-2014.12-SP1-1; Jan 2 11:05 2019
UVM_INFO /apps/vcsmx/etc/uvm-1.2/src/base/uvm_root.svh(402) @ 0: reporter [UVM/RELNOTES]

UVM-1.2.Synopsys
(C) 2007-2014 Mentor Graphics Corporation
(C) 2007-2014 Cadence Design Systems, Inc.
(C) 2006-2014 Synopsys, Inc.
(C) 2011-2013 Cypress Semiconductor Corp.
(C) 2013-2014 NVIDIA Corporation

*********** IMPORTANT RELEASE NOTES ************

You are using a version of the UVM library that has been compiled
with `UVM_NO_DEPRECATED undefined.
See 404 for more details.

You are using a version of the UVM library that has been compiled
with `UVM_OBJECT_DO_NOT_NEED_CONSTRUCTOR undefined.
See 404 for more details.

  (Specify +UVM_NO_RELNOTES to turn off this notice)

UVM_INFO @ 0: reporter [RNTST] Running test my_test…
UVM_INFO testbench.sv(36) @ 0: uvm_test_top.env [ENV] RAISE : Env i = 0
UVM_INFO testbench.sv(64) @ 0: uvm_test_top [TEST] Inside Run phase…
UVM_INFO testbench.sv(40) @ 10: uvm_test_top.env [ENV] Drop : Env i = 0
UVM_INFO testbench.sv(36) @ 10: uvm_test_top.env [ENV] RAISE : Env i = 1
UVM_INFO testbench.sv(40) @ 20: uvm_test_top.env [ENV] Drop : Env i = 1
UVM_INFO testbench.sv(36) @ 20: uvm_test_top.env [ENV] RAISE : Env i = 2
UVM_WARNING testbench.sv(91) @ 25: uvm_test_top [heartbeat] event triggered
UVM_INFO testbench.sv(40) @ 30: uvm_test_top.env [ENV] Drop : Env i = 2
UVM_INFO testbench.sv(36) @ 30: uvm_test_top.env [ENV] RAISE : Env i = 3
UVM_INFO testbench.sv(40) @ 40: uvm_test_top.env [ENV] Drop : Env i = 3
UVM_INFO testbench.sv(36) @ 40: uvm_test_top.env [ENV] RAISE : Env i = 4
UVM_WARNING testbench.sv(91) @ 50: uvm_test_top [heartbeat] event triggered
UVM_INFO testbench.sv(40) @ 50: uvm_test_top.env [ENV] Drop : Env i = 4
UVM_INFO testbench.sv(36) @ 50: uvm_test_top.env [ENV] RAISE : Env i = 5
UVM_ERROR testbench.sv(21) @ 50: uvm_test_top [HBFAIL] Heartbeat failure! Objections:
UVM_INFO /apps/vcsmx/etc/uvm-1.2/src/base/uvm_objection.svh(1072) @ 50: run [UVM/OBJ/DISPLAY] The total objection count is 2

Source Total
Count Count Object

0 2 uvm_top
1 2 uvm_test_top
1 1 env

UVM_FATAL @ 50: uvm_test_top [HBFAIL] Did not recieve an update of run on any component since last event trigger at time 25. The list of registered components is:
uvm_test_top
uvm_test_top.env
UVM_INFO /apps/vcsmx/etc/uvm-1.2/src/base/uvm_report_catcher.svh(705) @ 50: reporter [UVM/REPORT/CATCHER]
— UVM Report catcher Summary —

Number of demoted UVM_FATAL reports : 0
Number of demoted UVM_ERROR reports : 0
Number of demoted UVM_WARNING reports: 0
Number of caught UVM_FATAL reports : 0
Number of caught UVM_ERROR reports : 0
Number of caught UVM_WARNING reports : 0

UVM_INFO /apps/vcsmx/etc/uvm-1.2/src/base/uvm_report_server.svh(847) @ 50: reporter [UVM/REPORT/SERVER]
— UVM Report Summary —

** Report counts by severity
UVM_INFO : 16
UVM_WARNING : 2
UVM_ERROR : 1
UVM_FATAL : 1
** Report counts by id
[ENV] 11
[HBFAIL] 2
[RNTST] 1
[TEST] 1
[UVM/OBJ/DISPLAY] 1
[UVM/RELNOTES] 1
[UVM/REPORT/CATCHER] 1
[heartbeat] 2

Thanks in Advance,
SANJAIKUMAR K

In reply to SANJAIKUMAR:

Why is run_phase defined in my_env?

Hi,

Here in this code, my_env acts as a uvm_component. In the add method of the uvm_heartbeat requires a component to add, so just for testing purpose we instantiated my_env as component & added in the heartbeat.add() method.

Thanks,
SANJAIKUMAR K

In reply to SANJAIKUMAR:

Hello, SANJAIKUMAR.
It does not work as you expect and honestly not as I expected.
Heartbeat monitor could watch for certain objection that raised (or dropped) from one and the only uvm_component. Components that could be passed through methods set_heartbeat() or add() do not play any role.
In your code example watched uvm_component is uvm_test_top with the objection that raised (or dropped) in run_phase. This set has determined by the choice of arguments for uvm_heartbeat`s constructor.

One of the ways to make uvm_heartbeat useful for your example is to raise (or drop) key objections on behalf of one special uvm_component. And set this uvm_component as context for uvm_heartbeat.
For example:


class my_env extends uvm_env;
  // .....................................
  task run_phase(uvm_phase phase);
    for(int i = 0; i < 20; i++) begin
      phase.raise_objection(this);
      #10;
      phase.drop_objection(this);
    end
  endtask
  // .....................................
endclass
class my_test extends uvm_test;
  // .....................................
  task run_phase(uvm_phase phase);
    phase.raise_objection(env);
    #200;
    phase.drop_objection(env);
  endtask
  function void heartbeat(uvm_phase phase);
    uvm_callbacks_objection cbs_objection;
    uvm_phase got_phase = phase.find_by_name("run", 0);
    // .....................................
    if(!$cast(cbs_objection, got_run_phase.get_objection()))
      `uvm_fatal(get_full_name(), "Cast failed.")
    heartbeat = new(.name("activity_heartbeat"), .cntxt(env), .objection(cbs_objection));
    // .....................................
  endfunction
endclass

Best regards, Maksim.

In reply to maksim_kobzar:

Got your point of view. Thanks a lot.

Thanks & Regards,
SANJAIKUMAR K

The short explanation to this behavior is that if you have drop_objection() followed by a raise_objection() at exactly the same delta, they cancel each other out and the objection is not propagated beyond the specific component in which it was raised. You can see the code responsible for that behavior on github here. At a high level, I believe this is done to prevent drain_time threads from being kicked off when they’re not needed.

One way to make your code work is to add a #0 between your drop and your raise:

    
task run_phase(uvm_phase phase);
      for(int i =0;i<20;i++) begin        
        `uvm_info("ENV", $sformatf("RAISE : Env i = %0d",i),UVM_NONE)
        phase.raise_objection(this);      
        #10;        
        phase.drop_objection(this);
        `uvm_info("ENV", $sformatf("Drop : Env i = %0d",i),UVM_NONE)
        #0;
      end
endtask   

You can see that working on edaplayground here.

The long explanation (and more controversial one) is that the heartbeat mechanism uses objections in a way in which they were not originally intended to be used. Therefore, it is quite expected that it will run into corners like this one.

Avidan

BTW, if you turn on +UVM_OBJECTION_TRACE you could probably get to the bottom of this earlier, as you would have seen that first iteration propagates, while all others don’t:


UVM_INFO @ 0: reporter [RNTST] Running test my_test...
UVM_INFO @ 0: run [OBJTN_TRC] Object uvm_test_top raised 1 objection(s): count=1  total=1
UVM_INFO @ 0: run [OBJTN_TRC] Object uvm_top added 1 objection(s) to its total (raised from source object uvm_test_top): count=0  total=1
UVM_INFO testbench.sv(57) @ 0: uvm_test_top [TEST] Inside Run phase..
UVM_INFO testbench.sv(29) @ 0: uvm_test_top.env [ENV] RAISE : Env i = 0
UVM_INFO @ 0: run [OBJTN_TRC] Object uvm_test_top.env raised 1 objection(s): count=1  total=1
UVM_INFO @ 0: run [OBJTN_TRC] Object uvm_test_top added 1 objection(s) to its total (raised from source object uvm_test_top.env): count=1  total=2
UVM_INFO @ 0: run [OBJTN_TRC] Object uvm_top added 1 objection(s) to its total (raised from source object uvm_test_top.env): count=0  total=2
UVM_INFO @ 10: run [OBJTN_TRC] Object uvm_test_top.env dropped 1 objection(s): count=0  total=0
UVM_INFO testbench.sv(33) @ 10: uvm_test_top.env [ENV] Drop : Env i = 0
UVM_INFO testbench.sv(29) @ 10: uvm_test_top.env [ENV] RAISE : Env i = 1
UVM_INFO @ 10: run [OBJTN_TRC] Object uvm_test_top.env raised 1 objection(s): count=1  total=1
UVM_INFO @ 20: run [OBJTN_TRC] Object uvm_test_top.env dropped 1 objection(s): count=0  total=0
UVM_INFO testbench.sv(33) @ 20: uvm_test_top.env [ENV] Drop : Env i = 1
UVM_INFO testbench.sv(29) @ 20: uvm_test_top.env [ENV] RAISE : Env i = 2
UVM_INFO @ 20: run [OBJTN_TRC] Object uvm_test_top.env raised 1 objection(s): count=1  total=1
UVM_WARNING testbench.sv(84) @ 25: uvm_test_top [heartbeat] event triggered
UVM_INFO @ 30: run [OBJTN_TRC] Object uvm_test_top.env dropped 1 objection(s): count=0  total=0
UVM_INFO testbench.sv(33) @ 30: uvm_test_top.env [ENV] Drop : Env i = 2
UVM_INFO testbench.sv(29) @ 30: uvm_test_top.env [ENV] RAISE : Env i = 3
UVM_INFO @ 30: run [OBJTN_TRC] Object uvm_test_top.env raised 1 objection(s): count=1  total=1
UVM_INFO @ 40: run [OBJTN_TRC] Object uvm_test_top.env dropped 1 objection(s): count=0  total=0
UVM_INFO testbench.sv(33) @ 40: uvm_test_top.env [ENV] Drop : Env i = 3
UVM_INFO testbench.sv(29) @ 40: uvm_test_top.env [ENV] RAISE : Env i = 4