Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutRoadmapCareersInternshipsFAQContactPrivacyTerms
Skip to lesson

Course contents

  • Start Here4
  • UVM Foundations14
  • UVM Phases & Simulation Lifecycle26
    • The Phase System
      • Why Phases Exist
      • The Phase Schedule: Common and Runtime Phases
      • Traversal Order Rules
      • Function Phases vs Task Phases
      • Signatures, Super Calls, and Debug
      • Inside the Phaser: Nodes, Imps and Schedules
    • UVM Phases: Build, Connect, Elaborate and Run
    • Objections Deep Dive: Drain Time and Propagation
    • Phase Debugging and End-of-Test Signoff
  • Factory & Configuration15
  • Transaction-Level Modeling (TLM)13
  • UVM Sequences & Stimulus21
  • UVM Agents & Protocol VIP21
  • Environment & Test Classes11
  • Checking & Coverage in UVM21
  • UVM Register Abstraction Layer (RAL)22
  • Advanced UVM in Practice13
  • Debug & Regression10
  • Coding Practice47
  • Verification in Industry Practice10
  • Senior Prep: Architecture, Leadership and Interviews32
Loading lesson

←The Phase System
  1. Topics
  2. UVM Verification
  3. UVM Phases & Simulation Lifecycle
  4. The Phase System
  5. Signatures, Super Calls, and Debug
On this page

    Part 2 of 14, lesson 5 of 26Part 2 of 14/Phases & Lifecycle/Lesson 5 of 26Intermediate

    Signatures, Super Calls, and Debug

    The exact phase signatures, the old no-argument hooks, the super chain, and how to prove a phase method runs.

    You add a log line to a component's build, rerun, and it is not there. The component is in the topology, the test compiles cleanly, other components' messages appear. After an hour you notice the method is called buid_phase. Nobody told you, because from SystemVerilog's point of view nothing is wrong: you declared a new method, and nobody calls it.

    The idea: the phaser calls a virtual method by name

    The phaser does not know your class. It holds a uvm_component handle and calls, for example, comp.build_phase(phase). Because the base class declares build_phase as virtual, the call reaches your override, but only if your method has exactly the same name, kind (function or task) and argument list. It is like a dispatcher calling out a call sign over the radio: misspell your call sign and you never hear your call, while the base class quietly answers in your place.

    The picture

    Decision diagram: the phaser's virtual call reaches an exact override, falls back to the base method for a misspelled name, or fails to compile for a wrong kind or arguments.
    How a phase call reaches your code. A misspelled name compiles and is silently ignored; a wrong kind or argument list does not compile at all.

    Build it: the exact declarations

    Phase

    Exact declaration

    build

    function void build_phase(uvm_phase phase);

    connect

    function void connect_phase(uvm_phase phase);

    end of elaboration

    function void end_of_elaboration_phase(uvm_phase phase);

    start of simulation

    function void start_of_simulation_phase(uvm_phase phase);

    run

    task run_phase(uvm_phase phase);

    extract, check, report, final

    function void extract_phase(uvm_phase phase); and the same shape for check_phase, report_phase, final_phase

    the twelve runtime phases

    task main_phase(uvm_phase phase); and the same shape for the other eleven

    Three ways to get it wrong, and what each one does:

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // bad-example
    function void buld_phase(uvm_phase phase);     // compiles, never called: a brand-new method
      `uvm_info("BUILD", "custom build", UVM_LOW)
    endfunction
    
    function void run_phase(uvm_phase phase);      // compile error: the base run_phase is a task
      `uvm_info("RUN", "cannot override a task with a function", UVM_LOW)
    endfunction
    
    function void build(uvm_phase phase);          // compile error: clashes with the old build() hook
      `uvm_info("BUILD", "wrong argument list for build()", UVM_LOW)
    endfunction

    Only the first is silent. A function overriding the virtual task run_phase is illegal SystemVerilog, so it fails at compile time. The third clashes with an older method you may not know exists.

    The old no-argument hooks

    Before UVM had _phase methods, OVM components overrode build(), connect(), run() and so on, with no argument. The library still declares them, and the base phase methods call them: uvm_component::build_phase calls build(), connect_phase calls connect(), run_phase calls run(), and likewise for end_of_elaboration, start_of_simulation, extract, check and report. That is true in UVM 1.2 and in the Accellera library for IEEE 1800.2.

    Two consequences. A method declared as function void connect(); in your class does run, through the base connect_phase, even though it looks like a typo. And build() is not just an old name: it is where the base class applies automatic configuration, which is the subject of What super.build_phase() Really Does. Never write new code against the old hooks; recognise them when you inherit them.

    The super chain

    Every phase method in your class should start with super.<phase>_phase(phase). The reason is not the empty base bodies of today; it is that your parent class may not be the library class tomorrow. In a three-level hierarchy, each super call runs one level up, so a single missing call in the middle silently drops everything above it for every class below it.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    // snippet
    class base_agent extends uvm_agent;          // team-wide base: shared setup
      `uvm_component_utils(base_agent)
      function new(string name, uvm_component parent);
        super.new(name, parent);
      endfunction
      function void build_phase(uvm_phase phase);
        super.build_phase(phase);                // uvm_agent: config, is_active
        // shared monitor, coverage, checkers
      endfunction
    endclass
    
    class apb_agent_v2 extends base_agent;
      `uvm_component_utils(apb_agent_v2)
      function new(string name, uvm_component parent);
        super.new(name, parent);
      endfunction
      function void build_phase(uvm_phase phase);
        super.build_phase(phase);                // runs base_agent, which runs uvm_agent
        // APB-specific children
      endfunction
    endclass

    There is one deliberate exception to "super first": a test that registers factory overrides for components its parent creates. Those lines must come before super.build_phase. Why build_phase Is Top-Down explains exactly when "before" matters.

    Watch it run: prove the method is called

    When a phase method seems to do nothing, separate "not called" from "called but wrong" before reading any logic. Put a log line as the method's first statement, then rerun:

    design.sv
    1
    2
    3
    4
    5
    6
    // snippet
    function void build_phase(uvm_phase phase);
      `uvm_info("TRACE", $sformatf("%s entered %s", get_full_name(), phase.get_name()), UVM_NONE)
      super.build_phase(phase);
      // ...
    endfunction
    Diagram
    UVM_INFO dma_tb.sv(...) @ 0: uvm_test_top.env.in_agt [TRACE] uvm_test_top.env.in_agt entered build
    • Line present: the method runs; the bug is in what it does.

    • Line absent, component in the topology: a signature problem. Compare the name letter by letter with the table above.

    • Line absent, component missing from the topology: the component was never created, or was created as a different type. Print the factory (uvm_factory::get().print()) and look for overrides.

    • +UVM_PHASE_TRACE on the command line makes the phaser log every phase transition, which helps when the question is "did this phase run at all?" rather than "did my method run?".

    A typo check is cheap to automate. List every method in your code whose name ends in _phase and takes a uvm_phase argument, and compare the names against the twenty-one phase names: anything else is either a custom phase you meant to add or a method the phaser will never call. Several lint tools ship this rule; a ten-line script in the regression flow does the same job.

    The same reasoning applies to the three phase callbacks. phase_started, phase_ready_to_end and phase_ended are virtual functions with one uvm_phase argument, and a misspelled phase_ready_to_ends is just as silent as a misspelled build. Because those callbacks run for every phase, a log line in them is noisy; filter on the phase name before printing.

    What breaks: the report that vanished in a refactor

    A team renamed every report() method in their VIP to report_phase(uvm_phase phase) while removing OVM leftovers, and did the same for check(). One scoreboard's check_phase stopped flagging leftovers. Its author had renamed the method to check_phase but typed function void check_phase(); with no argument. That would not have compiled, so someone "fixed" the compile error by renaming it to chk_phase(uvm_phase phase). The method was never called again, and for three weeks the scoreboard could not fail a test.

    Their fix had two parts: restore the exact signature, and add a self-test that runs one deliberately broken transaction and expects exactly one error. A checker that has never been seen failing has not been tested.

    "Your phase method compiles but never runs. What do you check, in order?"

    A weak answer: "I'd check the objections and the phase trace." Objections have nothing to do with a function phase method that is never called.

    A strong answer: "First I prove it isn't called: a log line as its first statement. If the line is missing, it's a signature problem, and the only signature problem that compiles is a wrong name, because a wrong kind or argument list won't override a virtual method and fails to compile. So I compare the name against the base declaration. If the line is there, it's logic. I also check the super chain if the behaviour I'm missing comes from a base class."

    Follow-ups: Why does `function void connect();` with no argument still run? (the base connect_phase calls the old connect() hook) and When is it right to call super last? (factory overrides before super in a test).

    Check yourself A component defines task run_phase(uvm_phase phase); and also task run();. Which run?

    Both, if the component's run_phase calls super.run_phase(phase): the base run_phase calls run(). If run_phase does not call super, only run_phase runs. This is a good reason to delete old hooks when you find them.

    Check yourself A mid-level base class stops calling super.build_phase. Which classes are affected?

    Every class that extends it, directly or indirectly. Each super call runs one level up, so the chain stops at the missing call: uvm_agent's is_active lookup and the library's automatic configuration never run for any agent built on that base.

    Check yourself Is function void run_phase(uvm_phase phase); in a component a silent bug or a compile error?

    A compile error. run_phase is a virtual task in uvm_component, and a function cannot override a task. The silent case is a misspelled name, which simply declares a new method.

    Next: so far the phaser has been a black box that calls your methods. Inside the Phaser opens it, which is what you need to debug the callbacks that run around your phase methods.

    Related topics

    • Inside the Phaser: Nodes, Imps and Schedules

    • What super.build_phase() Really Does

    • Ordering Bugs and Silent Overrides

    Previous

    23 / 280

    Next: Inside the Phaser: Nodes, Imps and Schedules

    Up next

    Up nextInside the Phaser: Nodes, Imps and Schedules

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • Why Phases Exist
    • The Phase Schedule: Common and Runtime Phases
    • Traversal Order Rules