Skip to content

UVM

extract_phase

The first cleanup phase after the run — gathering each component's final results and residual state (counts, leftover queues, coverage) into checkable form, separate from check and report.

UVM Phasing · Module 5 · Page 5.7

The Engineering Problem

The run is over — time has stopped advancing, all the concurrent run tasks have ended. Now the cleanup phases begin, and the first of them is extract_phase. Its job is narrow and specific: each component gathers its final results and state from the completed run — final counts, leftover queue contents, statistics, coverage numbers — pulling them together into a form ready to be checked.

The engineering point is the separation of cleanup into distinct steps, with extract_phase being the gather step. UVM deliberately splits the wind-down into four phases — extract, check, report, final — so that gathering results, judging them, and announcing them are separate concerns in separate phases. extract_phase only collects; it doesn't decide pass/fail (that's check_phase) or print the verdict (that's report_phase). Why does that separation matter? Because checking often needs all the data gathered first, and judging belongs apart from collecting. Mixing them — checking inside extract, before everything is gathered — produces premature or incomplete verdicts. And the most common real consequence is a missed end-of-test condition: leftover state (an unmatched transaction queue) that nobody gathered and checked, so a test "passes" while it actually ran incompletely. This chapter is about the gather step and why it's its own phase.

What is extract_phase, what does it gather from the completed run, why is gathering separated from checking and reporting, and how does using it (with check_phase) catch end-of-test conditions a "passing" run would otherwise hide?

Motivation — why gathering is its own phase

Separating "gather the results" from "judge them" and "announce them" earns its place:

  • Checking needs the data gathered first. A meaningful end-of-test check often needs results from across the environment — and possibly the combination of several components' final state. Extracting everything in one phase, before any checking, guarantees all the data is present when check_phase runs. Gather first, then judge.
  • It cleanly separates collection from judgement. Gathering final counts and leftover state is a different activity from deciding pass/fail, which is different again from printing a report. Three phases (extract, check, report) keep these concerns apart, so each is simple and each component's role is clear.
  • It's where end-of-test residual state is captured. The run leaves residue — transactions still outstanding, a scoreboard's expected queue not fully drained, counters at their final values. extract_phase is where a component gathers that residue (e.g., the size of its leftover queue), making it available for the check that catches incomplete runs.
  • It runs bottom-up, after the run. Like the other cleanup phases, extract_phase is zero-time and bottom-up — children gather their results before parents aggregate. By the time it runs, the run is fully over, so the gathered values are final and stable.

The motivation, in one line: the wind-down is split into gather/judge/announce so each is a clean step, and extract_phase is the gather — collecting the run's final results and residual state into a form the check phase can judge, which is exactly what makes end-of-test checking reliable.

Mental Model

Hold extract_phase as collecting the final scores and tallying the till after the game:

extract_phase is the after-the-game collection of all the final numbers, before any judging or announcing. The match is over (the run ended). Now, first, everyone gathers their final figures: the scorekeeper totals the score, the referee notes how many fouls stand, the till is counted, the leftover tickets are tallied. This is pure collection — nobody is yet deciding who won or making an announcement; they're just pulling together the final, settled numbers from the completed game. Only after everything is gathered does the judging happen (was it a valid result? — check_phase) and then the announcement (the official result — report_phase). Gathering first, with everyone's numbers in, is what lets the judgement be correct — you don't declare a winner while the till is still being counted.

So in an extract_phase, you collect: read your final counters, the size of your leftover queue, your coverage numbers, your statistics — and store them where the check phase can see them. You don't judge (that's check) and you don't announce (that's report). Gather the settled numbers from the finished run; leave the verdict for next.

Visual Explanation — extract in the cleanup sequence

extract_phase is the first of the four cleanup phases — extract, check, report, final — and it has a single role: gather. Its position before check and report is the whole point.

Cleanup phases: extract gathers results, check judges, report announces, final cleans upextract → check → report → finalextract → check → report → final1extract_phase — gathereach component collects its final results and state: counts,leftover queues, coverage, statistics.2check_phase — judgejudge the gathered results: pass/fail, no outstanding transactions,goals met (next chapter).3report_phase — announcereport the verdict and summary based on the checks.4final_phase — clean upany last teardown after the verdict is reported.
Figure 1 — the cleanup phase sequence, with extract first. After the run, the zero-time bottom-up cleanup phases run in order: extract_phase gathers each component's final results and state; check_phase judges them (pass/fail); report_phase announces the verdict; final_phase does last cleanup. extract is the gather step — it collects the run's final tallies, leftover state, and coverage into checkable form, so the later phases can judge and announce. Each phase is a distinct concern.

The four cleanup phases are the wind-down split into distinct concerns, and extract_phase is the first and most foundational: nothing can be judged or reported until it has been gathered. By the time extract_phase runs, the run is completely over — every concurrent run task has ended, so the values a component holds (its final counters, the remaining contents of its queues, its accumulated statistics) are settled and final. The phase's job is to pull those together into a form the subsequent phases can use: a scoreboard reads its final matched/mismatched tallies and the size of any leftover expected queue; a coverage component reads its final numbers. It does not decide whether the result is a pass (that's check_phase) or print anything (that's report_phase) — it gathers. This clean split is why the cleanup is four phases and not one: collect, then judge, then announce, then clean up, each in its place.

RTL / Simulation Perspective — gathering final results

A typical extract_phase reads a component's final state into member variables that the check phase will judge. It gathers; it doesn't decide.

extract_phase — gather final results and residual state
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
class my_scoreboard extends uvm_scoreboard;
  `uvm_component_utils(my_scoreboard)
  int num_matched, num_mismatched;          // accumulated during run_phase
  int unsigned num_outstanding;             // to be gathered at extract
 
  function void extract_phase(uvm_phase phase);
    super.extract_phase(phase);
    // GATHER final state from the completed run into checkable form:
    num_outstanding = expected_q.size();    // leftover EXPECTED transactions (responses never seen)
    // (also: final coverage numbers, statistics, total counts — pulled together here)
    `uvm_info("SB", $sformatf("extracted: matched=%0d mismatched=%0d outstanding=%0d",
              num_matched, num_mismatched, num_outstanding), UVM_LOW)
  endfunction
endclass

The phase's work is collection. During the run, the scoreboard accumulated num_matched/num_mismatched as it checked transactions; now, at extract_phase, it gathers the final residual state — here, num_outstanding = expected_q.size(), the number of expected transactions still sitting in the queue because their responses never arrived. That leftover count is exactly the kind of end-of-test residual that matters: a non-empty expected queue means the run didn't complete all its traffic. Crucially, extract_phase gathers this number — it does not yet decide whether a non-zero value is a failure; that judgement is check_phase's job (next chapter), which will assert num_outstanding == 0. The uvm_info here logs what was gathered (useful for debugging), but the phase's contract is to collect the final, settled figures so the check phase has everything it needs. No verdict, no report — just the gathered results.

Verification Perspective — gather, then judge, then announce

The cleanup phases embody a clean separation: extract_phase gathers, check_phase judges, report_phase announces. Keeping these in distinct phases — rather than doing everything in one — is what makes end-of-test correct and the roles clear.

extract gathers results, check judges them, report announces the verdict, as three separate cleanup concernsgathered resultsverdictextract_phase — gathercollect final counts, leftoverstate, coveragecheck_phase — judgepass/fail; queue empty? goalsmet?report_phase — announceprint the verdict and summary12
Figure 2 — the three cleanup concerns, separated. extract_phase gathers the run's final results and residual state (counts, leftover queues, coverage) — collection only. check_phase judges them against expectations (pass/fail, queue empty, goals met) — judgement only. report_phase announces the verdict and summary — communication only. Separating them ensures all data is gathered before any judgement, and the verdict is decided before it's announced. Gather → judge → announce.

The separation is a pipeline: gather → judge → announce. extract_phase collects the raw final state (all of it, across components, before any judgement), check_phase judges that collected state (deciding pass/fail), and report_phase communicates the resulting verdict. Each phase has one job, and the order matters: you gather everything before you judge (so the judgement sees complete data), and you decide the verdict before you announce it (so the report is accurate). This is why doing a check inside extract_phase is a mistake — at extract time, not every component may have gathered its data yet (extract is still running across the tree), so a check there could judge on incomplete information. The discipline is to keep each cleanup phase to its concern: extract gathers, and only gathers; check judges; report announces. The three-step pipeline is what makes the wind-down both correct and easy to reason about.

Runtime / Execution Flow — when the gathered values are final

extract_phase runs after the run is completely over, so the values it gathers are final and stable — there's no more activity to change them. This timing is what makes extraction meaningful.

run_phase changes values, run ends and values settle, extract gathers final values, check judgesRun ends → values settle → extract gathers final figuresRun ends → values settle → extract gathers final figures1run_phase — values changingcounters, queues, coverage update as transactions flow over therun.2Run ends — values settleobjections drop, run tasks stop; no more activity, so the valuesare now final.3extract_phase — gather final valuescollect the settled counts, leftover queue sizes, coverage — theywon't change now.4check_phase — judgejudge the final, complete figures (e.g., assert the leftover queueis empty).
Figure 3 — extract gathers settled, final values. During run_phase, counters and queues are changing as transactions flow. When the run ends (objections dropped), all activity stops and the values settle. extract_phase then runs — after the run — so the counts, queue sizes, and coverage it gathers are final and won't change. check_phase judges these settled values, report_phase announces. Gathering after the run is what guarantees the figures are complete.

The timing guarantees completeness. During the run, a scoreboard's counters and queues are in flux — transactions are being matched, the expected queue grows and shrinks. If you tried to read "final" results mid-run, they wouldn't be final. extract_phase runs after the run has fully ended (objections dropped, all run tasks stopped), so the activity is over and the values have settled — the matched count is the total, the leftover queue size is the true end-of-test residual, the coverage numbers are complete. Gathering at this moment captures the real, final state of the run, which is exactly what a meaningful end-of-test check needs. This is also why extraction belongs in its own phase rather than at the tail of run_phase: the run is concurrent (Module 5.6), so there's no clean "end" within it to read final values; the dedicated cleanup phase, after the run, is where the figures are guaranteed settled. Gather after the run, and the numbers are true.

Waveform Perspective — gathering after the run

On a timeline, extract_phase is the first zero-time cleanup sliver after the run region — where the now-settled final values are gathered, before check and report.

extract_phase gathers final results at zero time, after the run ends

10 cycles
extract_phase gathers final results at zero time, after the run endsrun_phase: transactions flow; counters and queues changerun_phase: transaction…extract_phase (EXT): the run is over; gather the now-settled final resultsextract_phase (EXT): t…then check (CHK) judges and report (RPT) announces — gather, judge, announcethen check (CHK) judge…clkphaseRUNRUNRUNRUNRUNRUNEXTCHKRPTRPTvaliddata00A0A100B0B100000000t0t1t2t3t4t5t6t7t8t9
Figure 4 — during run_phase (the wide region) transactions flow and counters/queues change (valid/data active). When the run ends, the values settle and the zero-time cleanup phases begin: extract_phase (EXT) gathers the final results and residual state — no pin activity, just collection — then check (CHK) judges and report (RPT) announces. The phase track shows the run followed by the zero-time cleanup; extract is the first cleanup step, gathering the settled figures the later phases will use.

The phase track shows EXT as the first cell after the run region, with no pin activity — because extract_phase is zero-time collection, not behaviour. During the RUN span, valid/data are active and the scoreboard's counters and queue are changing; once the run ends those values settle, and EXT gathers them. Then CHK and RPT follow — the judge and announce steps. This is the wind-down made concrete: the run produces the data over time, and the zero-time cleanup phases (extract first) gather it, judge it, and announce it in sequence. extract_phase's placement — immediately after the run, before check — is exactly what makes the gathered figures final and ready for judgement.

DebugLab — the passing test that left transactions unmatched

A test that reported PASS while a scoreboard queue still held unmatched transactions

Symptom

A regression reported PASS, but a later silicon issue traced to a scenario the testbench had supposedly covered. Investigation found that, at end-of-test, the scoreboard's expected-transaction queue had not been empty — several expected transactions had never been matched by a response, meaning that traffic ran incompletely. The scoreboard had checked every transaction it did match (all correct), so it reported pass — but it never checked that there were no leftover, unmatched transactions.

Root cause

The end-of-test residual state was never gathered or checked. The scoreboard matched and checked transactions during the run, but nothing at cleanup time gathered the leftover queue and verified it was empty:

why the leftover queue went unnoticed
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
during run:   scoreboard matches responses to expected txns, checks each match (all correct)
at end:       expected_q still holds N unmatched transactions (responses never arrived)
cleanup:      (no extract of the leftover queue; no check that it's empty)
result:       every MATCHED txn passed → report PASS — but N txns were never matched at all
              → incomplete run looks like a clean pass
fix:          extract_phase: num_outstanding = expected_q.size();   // GATHER the residual
              check_phase:   if (num_outstanding != 0) `uvm_error(...) // JUDGE it as a failure

The matched transactions were genuinely correct, so the per-transaction checking during the run all passed — but the completeness of the run was never verified. A non-empty expected queue at end-of-test means responses are missing, which is a real failure; it just isn't visible unless you gather that residual state (extract_phase) and check it (check_phase). Without using the cleanup phases for this, the incomplete run masqueraded as a pass.

Diagnosis

The tell is a PASS that ignored leftover end-of-test state — a missing extract-and-check of residual data. Diagnose end-of-test completeness gaps:

  1. Check whether residual state is gathered. Does extract_phase collect end-of-test residuals — leftover queue sizes, outstanding counts, unmatched items? If not, those conditions can't be judged, and an incomplete run can pass.
  2. Confirm the check exists. Even if gathered, the residual must be judged in check_phase (e.g., assert the expected queue is empty). Gathering without checking still misses it.
  3. Distinguish per-transaction correctness from run completeness. All matched transactions can be correct (per-transaction checks pass) while transactions are missing (completeness fails). Both must be verified; the second needs the extract/check of residual state.
Prevention

Use the cleanup phases to gather and judge end-of-test completeness:

  1. Gather residual state in extract_phase. Collect leftover queue sizes, outstanding transaction counts, and any end-of-test figures into checkable members — so the data exists for the check.
  2. Check completeness in check_phase. Assert that no transactions are outstanding (the expected queue is empty), that counts reconcile, and that coverage goals are met — turning "the run completed fully" into a checked condition.
  3. Verify completeness, not just correctness. A pass requires both that every observed transaction was correct (run-time checking) and that no expected transactions are missing (extract/check of residuals). Don't let per-transaction correctness alone stand in for a complete run.

The one-sentence lesson: a run can leave unmatched transactions in a scoreboard's queue, and unless extract_phase gathers that residual and check_phase judges it empty, an incomplete run reports a hollow PASS — gather end-of-test state, then check it.

Common Mistakes

  • Not gathering end-of-test residual state. Leftover queues, outstanding counts, and final figures must be collected in extract_phase so they can be judged; ungathered residuals can't be checked, and an incomplete run can pass.
  • Checking inside extract_phase. Extract gathers; judgement belongs in check_phase. Checking during extract risks judging on incomplete data, because extraction may still be in progress across the tree. Keep extract to collection only.
  • Reading "final" values during the run. During run_phase, counters and queues are in flux; final values are only settled after the run. Gather them in extract_phase, not at the tail of the concurrent run.
  • Reporting in extract. Announcing the verdict is report_phase's job, after the check. Don't print pass/fail in extract.
  • Confusing per-transaction correctness with completeness. All matched transactions can be correct while expected ones are missing. Completeness (no outstanding/unmatched) is a separate condition that needs extract-and-check of residual state.
  • Forgetting super.extract_phase. As with other phase overrides, call super to preserve base-class behaviour.

Senior Design Review Notes

Interview Insights

extract_phase is the first of the four cleanup phases (extract, check, report, final), and its job is to gather each component's final results and state from the completed run into a form the later phases can use. It runs after the run is fully over — so the values are settled and final — and it's a zero-time, bottom-up function phase, like the other cleanup phases. What it gathers is the run's residue and tallies: a scoreboard's final matched/mismatched counts, the size of any leftover expected-transaction queue (outstanding responses that never arrived), coverage numbers, and statistics. Crucially, it only gathers — it does not decide pass/fail (that's check_phase) or print the verdict (that's report_phase). The reason gathering is its own phase is separation of concerns: extract collects all the data, then check judges it, then report announces it — and gathering everything first ensures the check sees complete data. Its most important practical use is collecting end-of-test residual state, like a leftover queue size, that the check phase then judges (e.g., asserting the queue is empty), which is how an incomplete run that left transactions unmatched is caught rather than passing silently.

Exercises

  1. Gather it. Write an extract_phase for a scoreboard that gathers its final matched/mismatched counts and the size of its leftover expected queue into member variables.
  2. Catch the incomplete run. A test passes but left transactions unmatched. Describe the extract (what to gather) and the check (what to assert) that would catch it, and which phase each belongs in.
  3. Place the concern. For each, name the cleanup phase: (a) read the final outstanding-transaction count; (b) assert the expected queue is empty; (c) print the PASS/FAIL summary; (d) free any remaining resources.
  4. Correctness vs completeness. Explain why a scoreboard can report all matched transactions correct yet the run still be a failure, and which phase pair catches the completeness gap.

Summary

  • extract_phase is the first cleanup phase — zero-time, bottom-up, after the run — where each component gathers its final results and state (matched/mismatched counts, leftover queue contents, coverage numbers, statistics) into a form ready to be checked.
  • The cleanup is split into distinct concerns: extract gathers, check judges, report announces (then final cleans up). Gathering everything before judging ensures the check sees complete data; checking inside extract risks judging on incomplete information.
  • Because it runs after the run is fully over, the values extract_phase gathers are settled and final — the run's concurrent activity has stopped, so the counts and residuals are complete and won't change.
  • Its key practical role is capturing end-of-test residual state — a leftover unmatched-transaction queue, outstanding counts — so the check phase can verify completeness, not just per-transaction correctness. Without this, an incomplete run (transactions left unmatched) reports a hollow PASS.
  • The durable rule of thumb: use extract_phase to gather the run's final, settled figures and residual state (and only gather) — leaving judgement to check_phase and announcement to report_phase — so end-of-test completeness, not just correctness, becomes a checked condition.

Next — check_phase: the results are gathered; now they're judged. check_phase is the second cleanup phase — where the extracted results are evaluated for pass/fail, end-of-test conditions are asserted, and the verdict is decided before it's reported. The next chapter is the judgement step.