UVM Heartbeat - Detecting Hung Components

In complex UVM testbenches, components can become unresponsive due to deadlocks, infinite loops, or protocol violations. Without proper monitoring, these issues may cause simulations to hang indefinitely. The uvm_heartbeat class provides a watchdog mechanism to detect when components stop making progress.

What is uvm_heartbeat?

uvm_heartbeat monitors registered components for activity within specified time windows. If a component fails to signal activity before a heartbeat event triggers, UVM raises a fatal error - catching hangs early rather than waiting for simulation timeouts.

Key Concepts

  • Heartbeat Event: A recurring trigger that checks if monitored components are active
  • Activity Signal: Components raise/drop objections on a shared objection object to indicate they're alive
  • Heartbeat Modes: Control whether all, any, or specific components must show activity

Heartbeat Architecture

The heartbeat mechanism uses three key elements:

  1. uvm_heartbeat: The monitor that tracks component activity
  2. uvm_callbacks_objection: Components raise/drop objections to signal they're active
  3. uvm_event: Triggers the heartbeat check at regular intervals
sequenceDiagram
    participant T as Test
    participant HB as uvm_heartbeat
    participant C as Component
    participant O as Objection
    
    T->>HB: add(component)
    T->>HB: start(heartbeat_event)
    
    loop Every heartbeat window
        C->>O: raise_objection()
        Note over C: Do work...
        C->>O: drop_objection()
        T->>HB: trigger heartbeat_event
        HB->>O: Check activity
        alt Activity detected
            HB-->>T: Continue
        else No activity
            HB-->>T: UVM_FATAL
        end
    end

Implementation Example

Let's walk through a complete example demonstrating heartbeat monitoring.

Test Class - Setting Up the Heartbeat

class my_test extends uvm_test;
   `uvm_component_utils(my_test)

   my_component component;

   uvm_heartbeat           heartbeat;
   uvm_event#(uvm_object)  heartbeat_e;
   uvm_callbacks_objection hb_objection;

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

   function void build_phase(uvm_phase phase);
      component = my_component::type_id::create("component", this);

      // Create objection for heartbeat signaling
      hb_objection = new("hb_objection");
      heartbeat    = new("heartbeat", this, hb_objection);

      // Share objection with monitored components
      uvm_config_db#(uvm_objection)::set(this, "*", "hb_objection", hb_objection);
   endfunction

   task run_phase(uvm_phase phase);
      phase.raise_objection(this);

      heartbeat_e = new("heartbeat_e");
      
      // Register components to monitor
      heartbeat.add(component);
      
      // Set mode: UVM_ANY_ACTIVE, UVM_ALL_ACTIVE, or UVM_ONE_ACTIVE
      void'(heartbeat.set_mode(UVM_ANY_ACTIVE));

      // Start heartbeat monitoring
      heartbeat.start(heartbeat_e);

      // Trigger heartbeat checks at regular intervals
      repeat(10) begin
         #120 heartbeat_e.trigger(this);
         `uvm_info("TEST/HB", "Trigger HB Event", UVM_NONE)
      end

      heartbeat.stop();
      heartbeat.remove(component);
      
      phase.drop_objection(this);
   endtask

endclass

Component Class - Signaling Activity

Each monitored component must periodically raise and drop the heartbeat objection to indicate it's still processing:

class my_component extends uvm_component;
   `uvm_component_utils(my_component)

   // Objection to signal heartbeat activity
   uvm_objection hb_objection;

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

   function void connect_phase(uvm_phase phase);
      // Get shared heartbeat objection
      if(!uvm_config_db#(uvm_objection)::get(this, "", "hb_objection", hb_objection))
         `uvm_fatal("NOHBOBJ", "Cannot find Heartbeat Objection setting")
   endfunction

   task run_phase(uvm_phase phase);
      int count;

      // Initial delay before starting work
      #50;

      forever begin
         count++;

         // Signal: "I'm alive and working"
         hb_objection.raise_objection(this);
         `uvm_info("COMP", "Heartbeat Objection Raised", UVM_NONE)

         // Simulate doing work
         #100;

         // Signal: "Done with this cycle"
         hb_objection.drop_objection(this);
         `uvm_info("COMP", "Heartbeat Objection Dropped", UVM_NONE)

         #20;
      end
   endtask

endclass

Heartbeat Modes

The set_mode() method controls how heartbeat checks are evaluated:

ModeDescriptionUse Case
UVM_ALL_ACTIVEAll registered components must show activityStrict monitoring - every component must be alive
UVM_ANY_ACTIVEAt least one component must show activityFlexible monitoring - system is alive if any component works
UVM_ONE_ACTIVEExactly one component must show activityMutex-style exclusive access patterns

Simulating a Hung Component

To test the heartbeat mechanism, you can inject a bug that causes a component to miss its heartbeat window:

task run_phase(uvm_phase phase);
   int count;
   #50;

   forever begin
      count++;

      hb_objection.raise_objection(this);
      #100;

      // Inject hang on iteration 8
      `ifdef BUG
         if(count == 8) begin
            #100; // Extra delay causes heartbeat timeout
            `uvm_info("COMP/BUG", "[8] Extra delay for HB to expire..", UVM_NONE)
         end
      `endif

      hb_objection.drop_objection(this);
      #20;
   end
endtask

When compiled with +define+BUG, the component takes too long on iteration 8, and the heartbeat mechanism catches this:

UVM_FATAL @ 960: uvm_test_top.heartbeat [HBFAIL] Heartbeat failure for component 'uvm_test_top.component'

Best Practices

Choosing Heartbeat Intervals

  • Too short: False positives from legitimate processing delays
  • Too long: Slow detection of actual hangs
  • Recommendation: Set interval to 2-3x your expected maximum processing time

What to Monitor

  • Drivers: Should complete transactions within bounded time
  • Monitors: Should see activity on interfaces
  • Scoreboards: Should receive and process transactions
  • Sequences: Long-running sequences should signal progress

Integration Tips

// In base_test for all tests
class base_test extends uvm_test;
   uvm_heartbeat hb;
   uvm_callbacks_objection hb_obj;
   uvm_event#(uvm_object) hb_event;
   
   // Configurable heartbeat window
   int heartbeat_window = 1000;
   
   function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      hb_obj = new("hb_objection");
      hb = new("heartbeat", this, hb_obj);
      uvm_config_db#(uvm_objection)::set(this, "*", "hb_objection", hb_obj);
   endfunction
   
   task run_phase(uvm_phase phase);
      hb_event = new("hb_event");
      // Add components in extended tests
      configure_heartbeat();
      hb.start(hb_event);
      
      fork
         trigger_heartbeat();
      join_none
   endtask
   
   virtual function void configure_heartbeat();
      // Override in derived tests to add components
   endfunction
   
   task trigger_heartbeat();
      forever begin
         #(heartbeat_window);
         hb_event.trigger(this);
      end
   endtask
endclass

Key Takeaways

  • uvm_heartbeat detects hung components by monitoring objection activity
  • Components signal "alive" status by raising/dropping objections on a shared objection object
  • Heartbeat events trigger checks at configurable intervals
  • Three modes control how multi-component activity is evaluated
  • Essential for catching deadlocks and infinite loops early
  • Integrate into base test class for project-wide monitoring

The heartbeat mechanism is invaluable for long-running verification - it catches hangs within seconds rather than waiting for hour-long simulation timeouts.


Part of the UVM Examples series. See also: UVM Barrier for synchronizing parallel components.

Author
Mayur Kubavat
VLSI Design and Verification Engineer sharing knowledge about SystemVerilog, UVM, and hardware verification methodologies.

Comments (0)

Leave a Comment