Chapter 10: UVM-SystemC

UVM Phasing, Objections, and the SystemC Kernel

How UVM phases run on top of SystemC, why objections control phase completion, and how run-time behavior maps to processes.

UVM Phasing, Objections, and the SystemC Kernel

UVM phasing gives a verification environment a shared lifecycle. SystemC gives it the simulation kernel. UVM-SystemC sits on top of SystemC and organizes verification behavior into phases. According to the IEEE 1800.2 standard, the UVM phasing mechanism is a sophisticated state machine layered over the native SystemC scheduler.

Phase Families

Common phase ideas include:

  • build
  • connect
  • end of elaboration
  • start of simulation
  • run
  • extract
  • check
  • report

Build and connect are structural. Run is time-consuming. Check and report summarize results.

Objections

Because the run_phase executes concurrently in every component across the hierarchy (using sc_spawn under the hood), UVM requires a mechanism to determine when the entire simulation is "done".

Objections prevent a run-time phase from ending while useful activity is still happening. If every component drops its objection, the phase can complete.

Complete Objections Example

Below is a fully compilable sc_main example showing two components running concurrently in the run_phase. Notice how the test waits until both components drop their objections before moving to the report_phase.

#include <systemc>
#include <uvm>
 
// 1. Fast Component: Finishes its work quickly
class fast_worker : public uvm::uvm_component {
public:
    UVM_COMPONENT_UTILS(fast_worker);
    fast_worker(uvm::uvm_component_name name) : uvm::uvm_component(name) {}
 
    void run_phase(uvm::uvm_phase& phase) override {
        phase.raise_objection(this);
        UVM_INFO("FAST", "Starting fast work (takes 20 ns)", uvm::UVM_LOW);
        
        sc_core::wait(20, sc_core::SC_NS);
        
        UVM_INFO("FAST", "Finished fast work, dropping objection", uvm::UVM_LOW);
        phase.drop_objection(this);
    }
};
 
// 2. Slow Component: Keeps the simulation alive longer
class slow_worker : public uvm::uvm_component {
public:
    UVM_COMPONENT_UTILS(slow_worker);
    slow_worker(uvm::uvm_component_name name) : uvm::uvm_component(name) {}
 
    void run_phase(uvm::uvm_phase& phase) override {
        phase.raise_objection(this);
        UVM_INFO("SLOW", "Starting slow work (takes 100 ns)", uvm::UVM_LOW);
        
        sc_core::wait(100, sc_core::SC_NS);
        
        UVM_INFO("SLOW", "Finished slow work, dropping objection", uvm::UVM_LOW);
        phase.drop_objection(this);
    }
};
 
// 3. Test Environment
class my_test : public uvm::uvm_test {
public:
    fast_worker* fast;
    slow_worker* slow;
    UVM_COMPONENT_UTILS(my_test);
 
    my_test(uvm::uvm_component_name name) : uvm::uvm_test(name) {}
 
    void build_phase(uvm::uvm_phase& phase) override {
        uvm::uvm_test::build_phase(phase);
        fast = fast_worker::type_id::create("fast", this);
        slow = slow_worker::type_id::create("slow", this);
    }
 
    void report_phase(uvm::uvm_phase& phase) override {
        // This is called automatically in zero-time AFTER all run_phase 
        // objections have been dropped.
        UVM_INFO("TEST", "Report Phase reached. Total simulation time: " 
                 + sc_core::sc_time_stamp().to_string(), uvm::UVM_LOW);
    }
};
 
int sc_main(int argc, char* argv[]) {
    uvm::run_test("my_test");
    return 0;
}

Source Implementation Shape

Useful official source paths include:

  • src/uvmsc/phasing/uvm_phase.*
  • src/uvmsc/phasing/uvm_common_phases.*
  • src/uvmsc/phasing/uvm_objection.*
  • src/uvmsc/base/uvm_root.*

The phasing system traverses component hierarchy and calls phase callbacks. Run-time phases interact with SystemC processes and simulation time.

Common Mistake

Starting a sequence without raising an objection can let the phase end too early.

Raising an objection and never dropping it can make the simulation appear hung. This happens frequently if an exception is thrown or a state machine gets deadlocked before reaching the drop_objection call.

Both failures are lifecycle bugs, not TLM bugs.

Best Practice

Raise objections at the level that owns the activity (e.g., inside sequences or tests, rather than deep in monitors). Drop them in all exit paths. Use reports around objections when debugging phase completion.

For small examples, keep the objection pattern obvious rather than clever.

Comments and Corrections