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

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • How to Use This Course
  • Reading Paths
  • Concept Map
  • Meet DCRouter
  • Glossary
  • Part 0: What Verification Is8
  • Part 1: What Can Go Wrong11
  • Part 2: Specifications as Checkable Rules8
  • Part 3: Observability and Controllability7
  • Part 4: Stimulus11
  • Part 5: Checking11
    • Self-Checking Testbenches
    • Where to Check
    • Assertions as Local Checkers
    • Scoreboards
    • How Precise a Reference Model?
    • Ordering and Timing in Checks
    • End-of-Test Checks
    • False Passes
    • Checking Performance
    • Hunting the Zoo with Checkers
    • Drills: Checking
  • Part 6: Coverage10
  • Part 7: Formal and Simulation10
  • Part 8: Verification Levels and Reuse8
  • Part 9: Planning and Risk9
  • Part 10: Emulation and Prototyping8
  • Part 11: Post-Silicon Validation8
  • Part 12: Bug Economics8
  • Part 13: Debug7
  • Part 14: Sign-Off7
  • Part 15: Verification in Context8
  • Part 16: Case Studies5
  • Part 17: Capstones5
  • Part 18: Interview Preparation6
Loading lesson

‹Part 5: Checking
  1. Topics
  2. First Principles of Verification Strategy
  3. Part 5: Checking
  4. End-of-Test Checks

Part 5 · Checking · Working (W)

End-of-Test Checks

A check that runs when an output appears cannot notice an output that never appears. End-of-test checks catch what never happened: undelivered predictions, a design that never drained, counters that disagree with what the testbench saw, credits that went missing. Six of the fifteen bugs DCRouter's random hunt catches are reported only after the traffic stops; what to check, and how to drain and audit properly.

On this page

    Note

    Level: Working (W) · Answers: How do we know the output is right?

    Before this: Scoreboards

    A router loses one packet in ten thousand. Every packet that does come out is perfect, so a scoreboard that checks each output as it arrives never reports anything. The test ends, the log shows no errors, and the regression marks it passed. The missing packet is still sitting in the scoreboard's queue of predictions, where nobody looked.

    How do you catch something that never happened?

    The obvious answer, and why it breaks

    The obvious checks are triggered by events: an output arrives, compare it. Absence triggers nothing. Lost packets, stuck transactions, counters that never incremented and credits that leaked all leave no event to check. They show up only when someone asks, at the end, whether everything that should have happened did.

    The idea: account for everything at the end

    End-of-test check

    Catches

    DCRouter

    Every prediction matched (queues empty)

    Lost, stuck or never-sent outputs

    wait_drain() fails if flits are still pending

    The design drained (idle, nothing in flight)

    Hangs and deadlocks

    The same, with a cycle limit

    Counters equal what the testbench saw

    Missed or extra counts

    PKT_CNT against packets received; ERR_CNT against faults injected

    Resources returned (credits, buffers, IDs)

    Leaks that only slow the design

    The credit audit

    Final state matches the model

    Wrong state left behind

    Register read-back

    DCRouter bugs caught only at the end

    From the Part 4 runs, each of these failures was reported by an end-of-test check, never by a per-flit comparison:

    Failure (from the Part 4 runs)

    End check

    BUG_21 caught ERROR @439965: 92 flits still pending after 40000 cycles (lost or stuck)

    Drain: predictions never matched

    BUG_11 caught ERROR @240345: PKT_CNT3: read 4a, expected 4c

    Counter against packets seen

    BUG_14 caught ERROR @240435: ERR_CNT2: read 32, expected 4

    Counter against faults injected

    BUG_9 caught ERROR @310245: credit audit: 1 flits left output 0 into a stalled sink, expected 4

    Credit audit

    BUG_10 caught ERROR @216575: credit audit: 3 flits left output 0 into a stalled sink, expected 4

    Credit audit

    BUG_22 caught ERROR @255105: credit audit: 2 flits left output 0 into a stalled sink, expected 4

    Credit audit

    Six of the random hunt's fifteen catches came from checks that ran after the traffic stopped.

    Doing the end of a test properly

    • Stop stimulus, then drain: wait until everything predicted has arrived, with a cycle limit so a hang fails instead of running forever.

    • Return the environment to neutral: fast sinks, no stalls, so leftovers are real and not just held up by the testbench (lesson 4.8's audit empties every sink first).

    • Audit hidden state through the pins: credits by counting flits into a stalled sink; buffers by filling them.

    • Read every counter and status register and compare: with what the testbench counted, not with a constant.

    • Report leftovers in detail: which flow, how many, the oldest one's identity.

    How real teams do it

    Practice

    Purpose

    A check phase after the run phase (UVM's check and report phases)

    End-of-test checks run in every test, by structure

    Objections or drain timers

    Tests end only when the design is idle, with a limit

    Scoreboards that report leftovers per queue

    Lost transactions named precisely

    What breaks

    A testbench (illustrative) ended each test with $finish as soon as the stimulus sequence completed, while the last few transactions were still in flight. Leftover checks were written but never reached. For months, any bug that lost one of the last transactions, or hung the design near the end of a test, passed. Ending on drain, with a limit, and running the checks after it closed the hole.

    Why this matters

    Senior lens. Ask of every testbench: what happens to a transaction that never comes out? If the answer is "nothing", the testbench cannot see a whole class of bugs. Make drain, leftover, counter and resource checks part of the environment, so every test gets them without remembering to.

    Interview

    Asked: "How do you catch a lost packet?"

    Weak answer: The scoreboard will see a mismatch.

    Strong answer: A per-output comparison never fires for a packet that never comes out, so it has to be an end-of-test check. I stop stimulus, drain with a cycle limit so a hang becomes a failure, put the environment in a neutral state, then require every scoreboard queue to be empty and report any leftovers by flow. I also compare counters with what the testbench saw and audit resources like credits. In the DCRouter random hunt, six of the fifteen catches came from checks that ran after the traffic stopped.

    Follow-ups: (1) Why drain with a limit? (2) What resources would you audit in a cache?

    Check yourself Why must sinks be returned to full speed before the leftover check?

    A stalled sink holds flits and credits legally; leftovers caused by the testbench's own stall would be false failures.

    Check yourself Which DCRouter bug class is invisible to per-flit checks and visible to a credit audit?

    Lost credits (BUG_9, BUG_10, BUG_22): every flit that leaves is correct; only the number of flits an output can send is wrong.

    Key takeaways

    • Event-triggered checks cannot see what never happened.

    • At the end: drain with a limit, require every prediction matched, compare counters, audit resources.

    • Build end-of-test checks into the environment so every test runs them.

    Keep going

    Next: Lesson 5.8, False Passes. Checkers that check nothing, and how to prove yours work.

    Related topics

    • Part 5 overview: Checking

    Previous

    57 / 160

    Next: False Passes

    Up next

    Up nextFalse Passes

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Self-Checking Testbenches
    • Where to Check
    • Assertions as Local Checkers