Skip to content

UVM

final_phase

The terminal cleanup phase — true teardown (closing files, releasing resources) that must happen last, and why releasing resources earlier strands the phases that still need them.

UVM Phasing · Module 5 · Page 5.10

The Engineering Problem

The verdict is decided and announced; one phase remains. final_phase is the last phase in the entire schedule — the absolute final thing UVM runs before the simulation ends. After build, connect, the run, extract, check, and report, final_phase is the terminal step, and its job is true teardown: closing files, releasing external or DPI resources, flushing buffers — any cleanup that must happen after everything else is done.

The engineering point is precisely that position: final_phase is where teardown belongs because it's the only phase guaranteed to run after all the others. This matters because teardown done too early — releasing a resource in an earlier phase that a later phase still needs — breaks the later phase. Close a log file in report_phase and the automatic report summary (or another component's reporting) that runs afterward has nothing to write to; free a reference-model handle in check_phase and report_phase can't read it. The reason final_phase exists as a distinct, terminal phase is to give resource teardown a home where nothing else will need the resource afterward. This short chapter is about the last phase and the discipline of doing teardown last.

What is final_phase, why is it the terminal phase, what teardown belongs there, and why does doing that teardown in an earlier phase break the phases that still need the resource?

Motivation — why teardown belongs in the last phase

final_phase being the terminal phase is exactly what makes it the right home for teardown:

  • It's the only phase guaranteed to run after all others. Resource teardown must happen when nothing else will use the resource — and the only such moment is after the last phase that uses it, which is final_phase. Anywhere earlier, some later phase might still need what you released.
  • Premature cleanup breaks later phases. Close a file, free a handle, or release a resource in extract, check, or report, and any subsequent phase (or the automatic report summary) that depends on it fails — lost output, a null handle, a crash. The bug is position: the cleanup was correct, just too early.
  • Reporting and the auto-summary run before final. UVM's automatic report summary and each component's report_phase produce output up to and including report_phase; final_phase runs after. So resources those use (log files, result sinks) must survive until final_phase to release.
  • It's the last hook for anything. Beyond resource release, final_phase is the final opportunity for any action that should happen at the very end — a last flush, a closing message, post-processing that needs the whole run complete.

The motivation, in one line: resource teardown must happen after everything that uses the resource, and final_phase — the terminal phase — is the only place guaranteed to be after all the rest, so it's where cleanup belongs and why releasing early breaks the phases that still need the resource.

Mental Model

Hold final_phase as turning off the lights and locking up — only after everyone has left:

final_phase is locking up the building at the very end — after the last person has gone. Throughout the day, rooms were used (the phases ran, each needing its resources — files open, the heating on, the doors unlocked). The performance ended, the audit finished, the results were announced. Now, last of all, you do the closing-up: switch off the lights, shut down the heating, lock the doors, take out the trash. The whole point is that this happens after everyone has left and everything is done — if you locked the doors while the audit was still running, you'd lock people in; if you cut the power before the announcement, no one would hear the result. Closing-up is correct only as the final act, because anything done earlier strands a later activity that still needed the lights on. So you tear down last, when nothing remains that depends on what you're shutting off.

So in a final_phase, you do the closing-up: release resources, close files, flush and shut down — knowing nothing runs after you, so nothing will miss what you released. And the corollary: never do this closing-up in an earlier phase, or you cut the power on something still working.

Visual Explanation — final, the terminal phase

final_phase is the last of the four cleanup phases and the last phase overall — the terminal teardown after the verdict is reported.

final_phase is the last phase, for teardown after the verdict is reportedextract → check → report → final (terminal)extract → check → report → final (terminal)1extract_phase — gatheredfinal results collected.2check_phase — decidedpass/fail set.3report_phase — announcedresults and verdict communicated.4final_phase — teardown (last)close files, release resources, flush — the absolute last thing UVMruns.
Figure 1 — final_phase, the terminal phase. After extract (gather), check (judge), and report (announce), final_phase is the absolute last phase UVM runs — for true teardown: closing files, releasing external/DPI resources, flushing buffers, final cleanup. Nothing runs after it, which is exactly why it's the safe place to release resources. It is a zero-time, bottom-up function phase, like the other cleanup phases.

final_phase is the terminal step — there is no phase after it. By the time it runs, everything is done: the run is over, the results gathered, the verdict decided and announced, the automatic report summary printed. So final_phase is where teardown is safe, because nothing remains that could need the resources you're about to release. Its content is true cleanup: closing the log or results file you wrote to, releasing an external model or DPI handle, flushing any buffered output, freeing allocated resources. It is a zero-time, bottom-up function phase like the other cleanup phases, so it does no time-consuming work and no behaviour — just the final closing-up. The reason it exists as its own phase, separate from report_phase, is exactly so this teardown has a guaranteed after-everything moment, which the next sections make concrete.

RTL / Simulation Perspective — true teardown in code

A final_phase releases resources — closes files, frees handles, flushes — that the earlier phases used. It runs after report, so those resources were available throughout reporting and are released only now.

final_phase — release resources after everything else is done
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
class my_env extends uvm_env;
  `uvm_component_utils(my_env)
  int results_file;                 // opened earlier, written to through report_phase
 
  function void final_phase(uvm_phase phase);
    super.final_phase(phase);
    // TRUE TEARDOWN — last of all, after report and the auto-summary:
    if (results_file) $fclose(results_file);   // close the results file (report wrote to it)
    // release external / DPI resources, flush buffers, free allocations ...
    `uvm_info("ENV", "final cleanup complete", UVM_LOW)
  endfunction
endclass

The teardown here is deliberately last. The results_file was opened earlier and written to throughout the run and the reporting (the scoreboard's report_phase may have written its tallies to it, and UVM's automatic summary prints around this time) — so it had to stay open until now. final_phase closes it, after all the writing is done, because closing it any earlier would strand a later write. The same logic applies to any resource: an external reference-model handle used through check_phase and report_phase, a DPI/C resource, a buffered output stream — they're released in final_phase precisely because that's the first moment nothing else needs them. The phase does only this closing-up: no checking (done in check_phase), no announcing (done in report_phase), no behaviour (the run is over) — just the terminal release of resources, and call super.final_phase as with any phase override.

Verification Perspective — why teardown must be last

Releasing a resource before the last phase that uses it breaks that later phase. final_phase is the terminal phase, so teardown there is safe; teardown earlier is a use-after-release waiting to happen.

Releasing a resource in report_phase breaks the later auto-summary; releasing in final_phase after all uses is safereleased early (report)releasedearly…later use failsreleased in finalnothing needs itafterResource (file/handle)used through reportReleased in report_phasebut report/summary not doneLater use failsclosed file / null handle — lostoutput or crashReleased in final_phaseafter all usesSafe teardownnothing remains to need it12
Figure 2 — teardown early breaks later phases; teardown in final is safe. A resource (a log file, an external handle) is used by phases up through report_phase and the auto-summary. Releasing it in an earlier phase (e.g., report_phase, before the auto-summary or another component's report) leaves the later use with a closed file or null handle — a failure. Releasing it in final_phase, after everything that uses it, is safe — nothing remains to need it. Tear down last.

The contrast is the whole lesson. A resource — say a results file or an external model handle — is used by phases up to and including report_phase (and the automatic report summary that prints around then). If you release it in report_phase, you've cut it off while later reporting still needs it: the auto-summary or another component's report_phase finds a closed file or a null handle, and you lose output or crash — a use-after-release. If you release it in final_phase, after every phase that uses it, the release is safe, because nothing runs afterward to need it. This is why final_phase is a distinct, terminal phase: it provides the guaranteed after-everything moment that resource teardown requires. The discipline is simple and absolute — resource cleanup goes in final_phase, not in an earlier phase, because only final_phase is certain to be after the last use.

Runtime / Execution Flow — the last thing that runs

final_phase is the terminal node of the entire phase schedule. Tracing the schedule to its end shows final_phase as the closing act, after which the simulation ends.

final_phase is the terminal phase of the schedule, after which the simulation ends…report → final → simulation ends…report → final → simulation ends1report_phaseresults and verdict announced; auto-summary printed.2final_phasethe terminal phase: true teardown — close files, release resources,flush.3Simulation endsnothing runs after final_phase; the run is complete.4So teardown is safe herebeing last means releasing resources can't strand any later phase.
Figure 3 — final_phase at the end of the whole schedule. The schedule runs build → connect → end_of_elaboration → start_of_simulation → run → extract → check → report → final. final_phase is the terminal node: after it, the simulation ends. This is why it's where teardown belongs — it's the last moment anything runs, so releasing resources here cannot strand a later phase. The closing act of the entire run.

This is the end of the whole schedule (Module 5.1) — final_phase is its last node, and after it the simulation terminates. Everything you've learned across this module funnels here: the environment was built, wired, validated, announced, run, and its results gathered, judged, and reported — and final_phase closes it out. The single property that defines the phase is being last, and that property is what makes it the correct home for teardown: because nothing runs after final_phase, any resource you release in it cannot possibly be needed afterward. Conversely, this is why teardown in any earlier phase is risky — there's always a later phase that might need the resource. So the rule that falls out of the schedule's shape is: do final cleanup in the final phase. It's the closing act, and closing acts go last.

Waveform Perspective — the closing act

On a timeline, final_phase is the very last zero-time sliver — the terminal cleanup after report, after which the simulation ends.

final_phase is the last zero-time sliver — teardown, then the simulation ends

10 cycles
final_phase is the last zero-time sliver — teardown, then the simulation endscleanup begins: extract (EXT) gathers, check (CHK) judges, report (RPT) announcescleanup begins: extrac…final_phase (FIN): terminal teardown — close files, release resources (last)final_phase (FIN): ter…nothing runs after final_phase — the simulation endsnothing runs after fin…clkphaseRUNRUNRUNEXTCHKRPTRPTFINFIN---validdata00A0A100000000000000t0t1t2t3t4t5t6t7t8t9
Figure 4 — after the run, the zero-time cleanup phases run in order: extract (EXT) gathered, check (CHK) decided, report (RPT) announced, and final (FIN) does the terminal teardown — closing files, releasing resources. final_phase is the last cell on the track; after it the simulation ends. No pin activity in any cleanup phase (all zero-time); final is the closing act, where resources used through reporting are safely released because nothing runs afterward.

The phase track ends with FIN — the last cell before the simulation terminates. Through the cleanup region, no pins move (all zero-time), and the phases run in their fixed order: gather (EXT), judge (CHK), announce (RPT), and finally tear down (FIN). final_phase's placement at the very end is the entire point: it's the last moment anything runs, so resources used through report_phase (a log file, an external handle) are safely released here because nothing follows to need them. The waveform closes the whole phase story from Module 5.1: a thin setup sliver, the wide run, and a thin cleanup sliver ending in final_phase — the run's closing act, after which the schedule, and the simulation, are done.

DebugLab — the results file closed one phase too early

Lost report output — a results file closed in report_phase, before the summary that still wrote to it

Symptom

A test wrote its results to a custom file, and a component closed that file in its report_phase right after writing its own summary. But the final portion of the results — written by UVM's end-of-test summary and another component's later reporting — was missing from the file, and on some runs the simulation emitted a "write to closed file" error near the end. The file had everything up to one component's report, then nothing.

Root cause

The file was closed too early — in report_phase — while later reporting still needed to write to it:

why the final output was lost
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
component A.report_phase:  write summary to results_file; $fclose(results_file);   // ✗ too early
later (still to come):     component B.report_phase writes; UVM auto-summary writes
result:                    those writes hit a CLOSED file → lost output / "write to closed file"
fix:                       close the file in FINAL_PHASE — after ALL reporting is done:
                           function void final_phase(...); $fclose(results_file); endfunction

report_phase is not the last phase — other components' report_phase methods and UVM's automatic summary run around and after it, and final_phase runs after all of them. So closing the file in report_phase released it while later writers still needed it, losing their output (and erroring on the write-to-closed-file). The teardown logic was correct; its phase was wrong. The file had to stay open until final_phase, the terminal phase, where closing it is safe because nothing writes afterward.

Diagnosis

The tell is lost end-of-run output, or a use-after-release near simulation end — resource teardown done before the last user. Diagnose premature-cleanup bugs:

  1. Check the phase of resource release. Closing a file, freeing a handle, or releasing a resource belongs in final_phase (the terminal phase). If it's in report_phase (or earlier), a later phase that uses the resource will fail.
  2. Identify who uses the resource after the release point. If anything — another component's report, the auto-summary, final_phase itself — uses the resource after where it's released, the release is too early. The resource must outlive its last user.
  3. Look for "write to closed file" / null-handle at end-of-run. These errors near the end signal a resource released before the last phase that needed it; move the release to final_phase.
Prevention

Release resources in the terminal phase, after their last use:

  1. Do resource teardown in final_phase. Close files, release external/DPI handles, and flush buffers in final_phase — the last phase — so nothing runs afterward to need them. Never release them in an earlier phase.
  2. Let the resource outlive its last user. Identify the latest phase that uses a resource (often report_phase or the auto-summary) and release it strictly after — which, being safe, means final_phase.
  3. Keep cleanup phases to their roles. Extract gathers, check judges, report announces, final tears down. Releasing resources during gather/judge/announce risks stranding the phases that follow; confine teardown to final.

The one-sentence lesson: final_phase is the only phase guaranteed to run after all others, so resource teardown (closing files, releasing handles) belongs there — releasing a resource in report_phase or earlier strands the later phases that still use it, losing output or crashing.

Common Mistakes

  • Releasing resources before final_phase. Closing a file or freeing a handle in extract/check/report strands the later phases (and the auto-summary) that still use it — lost output or a crash. Do teardown in final_phase, the terminal phase.
  • Confusing report with the last phase. report_phase is not last — other components' reporting, the auto-summary, and final_phase follow it. Resources used by reporting must survive until final_phase.
  • Doing checking or announcing in final_phase. Judgement is check_phase, announcement is report_phase; final_phase is teardown only. (Issuing a late error in final still counts toward the verdict, but the natural place to check is check_phase.)
  • Time-consuming work in final. It's a zero-time function phase; nothing time-consuming belongs here — just instantaneous cleanup.
  • Forgetting super.final_phase. Call super as with other phase overrides to preserve base-class behaviour.
  • Leaving resources unreleased. The flip side: failing to close files or free external resources at all can leak or corrupt output. final_phase is where you ensure clean release.

Senior Design Review Notes

Interview Insights

final_phase is the terminal cleanup phase — the absolute last phase UVM runs, after the verdict has been reported — and its job is true teardown: closing log and results files, releasing external or DPI resources, flushing buffers, and any final cleanup that must happen after everything else. It's a zero-time, bottom-up function phase like the other cleanup phases. Its defining property is simply that it's last: nothing runs after final_phase, which is exactly why it's the safe place to release resources — because nothing remains that could need them. This is the reason it exists as a distinct phase separate from report_phase: resource teardown must happen after the last phase that uses the resource, and final_phase provides that guaranteed after-everything moment. The classic mistake it prevents is premature cleanup — closing a file in report_phase, before another component's report or UVM's automatic summary writes to it — which loses output or crashes. So final_phase is where you put resource release, knowing it's the closing act of the entire run.

Exercises

  1. Tear it down. Write a final_phase for an env that closes a results file opened earlier, and explain why this belongs in final_phase rather than report_phase.
  2. Find the early release. A results file is closed in report_phase; the auto-summary's output is missing from it. State the cause and the corrected phase.
  3. Place the concern. For each cleanup action, name the phase: (a) gather the final outstanding count; (b) assert no transactions are outstanding; (c) print the PASS/FAIL summary; (d) close the log file and release the DPI handle.
  4. Resource lifetime. Explain the rule "a resource must outlive its last user," and how it determines that resource release belongs in final_phase.

Summary

  • final_phase is the terminal cleanup phase — zero-time, bottom-up — the absolute last thing UVM runs, after the verdict is reported. It is for true teardown: closing files, releasing external/DPI resources, flushing buffers, final cleanup.
  • Its value is precisely its position: being last means nothing runs afterward, so releasing a resource there cannot strand any later phase — it's the safe, guaranteed after-everything moment for cleanup.
  • Teardown done earlier breaks later phases: closing a file in report_phase strands the auto-summary or another component's later reporting (lost output, write-to-closed-file); freeing a handle in check_phase leaves report_phase with a null. A resource must outlive its last user.
  • It is the end of the whole schedule — after final_phase, the simulation terminates. Keep it to teardown only (no checking, no announcing, nothing time-consuming), and ensure resources are actually released (the flip side of premature cleanup is a leak).
  • The durable rule of thumb: do final cleanup in the final phase — release resources in final_phase, after every phase that uses them, because it's the only phase guaranteed to be last, so teardown there strands nothing.

Next — Phase Ordering: you've seen all the phases individually; the last chapter of this module steps back to the ordering itself — how the framework sequences the whole schedule across the component tree, the top-down/bottom-up directions, and how the run-time sub-phases synchronise — consolidating phasing into one ordered picture.