Example of UVM hearbeat based on example and UVM heartbeat docs

Introduction Link to heading

UVM reference manual defines Heart Beat as

Heartbeats provide a way for environments to easily ensure that their descendants are alive. A uvm_heartbeat is associated with a specific objection object. A component that is being tracked by the heartbeat object must raise (or drop) the synchronizing objection during the heartbeat window. The synchronizing objection must be a uvm_callbacks_objection type.

which means a component can monitor a another component and expect “keep alive” objection in a given window. If we don’t receive signal, a fatal will be generated.

It’s useful to detect hanging component and make sure that specific tasks complete in a given window.

Step 1: create uvm_callbacks_object Link to heading

A objection object is shared by the environment and the component.

uvm_callbacks_objection obj = new("obj");

uvm_callbacks_object is defined as

The uvm_callbacks_objection is a specialized uvm_objection which contains callbacks for the raised and dropped events. Callbacks happend for the three standard callback activities, raised, dropped, and all_dropped.

which is not the same as uvm_objection_callback. Anyway, We won’t use callbacks raised and dropped and all_dropped in this example.

Step 2: Raise objections Link to heading

The run_phase(or whatever tasks consuming time) of component needs to periodically raise objection to obj.

	task run_phase(uvm_phase phase);
	repeat(10) begin
        `uvm_info(get_type_name(),$sformatf("raise objections "),UVM_LOW)
		obj.raise_objection(this);
        // A delay is used to simulate time consuming tasks
        [....]
	end

Step 3: setup the environment Link to heading

according to UVM reference manual, we need to pass 2 things to uvm_heartbeat

  • shared objection define above
  • uvm_event to synchronize the window

we define heartbeat and event in env class

	uvm_heartbeat hb = new("hb", this, obj);
	uvm_event hb_event= new("hb_event");

Add the component to list monitored components. In this case, m_drv is component with heartbeat.

		hb.add(m_drv);

Finally, hb needs to start by calling .start and passing the synchronization event hb_event. In this example, i am defining a window of 100 units. If the m_drv doesn’t raise object in the window, the heartbeat will throw FATAL.

	hb.start(hb_event);
    repeat(10) begin
      `uvm_info(get_type_name(),$sformatf("Triggering hb_event"),UVM_LOW)
      hb_event.trigger();
      #100;
    end

Using #50 Link to heading

Using #50 means that driver will stop raising objections after 500 units. and the heatbeat will trigger at 500 and 600. And generates the FATAL message.

testbench.sv(54) @ 0: uvm_test_top.m_env [env] Triggering hb_event
testbench.sv(17) @ 0: uvm_test_top.m_env.m_drv [driver] raise objections
testbench.sv(17) @ 50: uvm_test_top.m_env.m_drv [driver] raise objections
testbench.sv(54) @ 100: uvm_test_top.m_env [env] Triggering hb_event
testbench.sv(17) @ 100: uvm_test_top.m_env.m_drv [driver] raise objections
testbench.sv(17) @ 150: uvm_test_top.m_env.m_drv [driver] raise objections
testbench.sv(54) @ 200: uvm_test_top.m_env [env] Triggering hb_event
testbench.sv(17) @ 200: uvm_test_top.m_env.m_drv [driver] raise objections
testbench.sv(17) @ 250: uvm_test_top.m_env.m_drv [driver] raise objections
testbench.sv(54) @ 300: uvm_test_top.m_env [env] Triggering hb_event
testbench.sv(17) @ 300: uvm_test_top.m_env.m_drv [driver] raise objections
testbench.sv(17) @ 350: uvm_test_top.m_env.m_drv [driver] raise objections
testbench.sv(54) @ 400: uvm_test_top.m_env [env] Triggering hb_event
testbench.sv(17) @ 400: uvm_test_top.m_env.m_drv [driver] raise objections
testbench.sv(17) @ 450: uvm_test_top.m_env.m_drv [driver] raise objections
testbench.sv(54) @ 500: uvm_test_top.m_env [env] Triggering hb_event
testbench.sv(54) @ 600: uvm_test_top.m_env [env] Triggering hb_event
 UVM_FATAL @ 600: uvm_test_top.m_env [HBFAIL] Did not recieve an update of obj for component uvm_test_top.m_env.m_drv since last event trigger at time 500 : last update time was 450

Using #100 Link to heading

Using #100 means that driver will raise objections in 100-unit window until the end of run_task where env stops triggering uvm_event. And simulation completes successfully.

testbench.sv(51) @ 0: uvm_test_top.m_env [env] Triggering hb_event
testbench.sv(17) @ 0: uvm_test_top.m_env.m_drv [driver] raise objections
testbench.sv(51) @ 100: uvm_test_top.m_env [env] Triggering hb_event
testbench.sv(17) @ 100: uvm_test_top.m_env.m_drv [driver] raise
testbench.sv(51) @ 200: uvm_test_top.m_env [env] Triggering hb_event
testbench.sv(17) @ 200: uvm_test_top.m_env.m_drv [driver] raise
testbench.sv(51) @ 300: uvm_test_top.m_env [env] Triggering hb_event
testbench.sv(17) @ 300: uvm_test_top.m_env.m_drv [driver] raise
testbench.sv(51) @ 400: uvm_test_top.m_env [env] Triggering hb_event
testbench.sv(17) @ 400: uvm_test_top.m_env.m_drv [driver] raise
testbench.sv(51) @ 500: uvm_test_top.m_env [env] Triggering hb_event
testbench.sv(17) @ 500: uvm_test_top.m_env.m_drv [driver] raise
testbench.sv(51) @ 600: uvm_test_top.m_env [env] Triggering hb_event
testbench.sv(17) @ 600: uvm_test_top.m_env.m_drv [driver] raise
testbench.sv(51) @ 700: uvm_test_top.m_env [env] Triggering hb_event
testbench.sv(17) @ 700: uvm_test_top.m_env.m_drv [driver] raise
testbench.sv(51) @ 800: uvm_test_top.m_env [env] Triggering hb_event
testbench.sv(17) @ 800: uvm_test_top.m_env.m_drv [driver] raise
testbench.sv(51) @ 900: uvm_test_top.m_env [env] Triggering hb_event
testbench.sv(17) @ 900: uvm_test_top.m_env.m_drv [driver] raise objections

Putting all together Link to heading

`include "uvm_macros.svh"

import uvm_pkg::*;


uvm_callbacks_objection obj = new("obj");

class driver extends uvm_driver;
	`uvm_component_utils(driver)

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

	task run_phase(uvm_phase phase);
      repeat(10) begin
      `uvm_info(get_type_name(),$sformatf("raise objections "),UVM_LOW)
		obj.raise_objection(this);
		#100;

	end
	endtask
endclass

class env extends uvm_env;
	`uvm_component_utils(env)

	driver m_drv;
	uvm_heartbeat hb = new("hb", this, obj);
	uvm_event hb_event= new("hb_event");

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


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

	function void connect_phase(uvm_phase phase);
		hb.add(m_drv);

	endfunction

	task run_phase(uvm_phase phase);
	phase.raise_objection(this);
		hb.start(hb_event);
    repeat(10) begin
      `uvm_info(get_type_name(),$sformatf("Triggering hb_event"),UVM_LOW)
      hb_event.trigger();
      #100;
    end
      #1000;
	phase.drop_objection(this);
	endtask

endclass

class test extends uvm_test;
`uvm_component_utils(test)

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

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

task run_phase(uvm_phase phase);
	phase.raise_objection(this);
  `uvm_warning("Test","Hello World!")
	phase.drop_objection(this);
endtask
endclass
module top;
initial run_test("test");
endmodule