Regression and Bug Management
The Verification Plan names what needs checking. This page covers the operational machinery that actually runs those checks continuously, catches when a previously-working feature breaks, and tracks a found bug from discovery to actually being fixed.
Regression tiers
Running every test, at full length, on every single RTL change is rarely practical — a full suite can take hours, and most changes only touch a small part of the design. Real flows tier the test suite by how often each tier runs:
- Smoke tests — a small, fast subset covering basic functionality, run on essentially every change, catching an obviously broken build within minutes rather than hours.
- Nightly regression — a much broader run, including longer constrained-random tests with many seeds, scheduled to run unattended overnight so results are ready by the next morning.
- Weekly / full regression — the most exhaustive tier, often including the longest-running stress tests and the widest seed counts, run less frequently precisely because of the time cost.
The tiering exists for the same reason linting runs before simulation at all: catch what's cheap to catch, fast, and reserve the most expensive checks for a cadence where their cost is actually affordable.
Seed management: reproducibility isn't automatic
Every constrained-random test in the CDV loop depends on a random seed — and a bug a nightly regression finds with seed 47291 has to be reproducible on demand, or it's effectively unfixable, since no one can re-run the exact scenario that exposed it. This makes seed logging a hard requirement, not an optional nicety: every regression run records which seed produced which result, so a failure can be replayed exactly, and a fix can be verified against the identical scenario that originally broke. Seed control is a deliberate test-design decision, not an incidental detail — treating it as an afterthought is how a real, found bug quietly becomes unreproducible and unfixable.
The bug lifecycle
A found bug moves through a real, trackable sequence, not an informal "someone mentioned it in chat":
Triage is worth pausing on specifically — not every reported failure is a real RTL bug. It might be a testbench bug (the checker itself is wrong), an environment issue (a tool version mismatch), or a genuinely flaky test (a race in the testbench, not the DUT). Triage's job is sorting these apart before anyone spends time "fixing" a bug that isn't actually in the design — and assigning a severity (a corner-case cosmetic issue is not the same priority as a data-corruption bug in a core datapath) that determines how urgently it gets addressed.
Regressed, specifically, means re-running the exact seed that originally exposed the bug (confirming the fix actually addresses it) and the surrounding regression suite (confirming the fix didn't break anything else) — closing a bug without both checks is how a "fixed" issue quietly comes back.
Severity and priority are two independent axes, not one field, worth separating explicitly: severity is the technical impact — how badly the bug breaks correctness (a data-corruption bug in a core datapath is high severity regardless of anything else); priority is how urgently it needs fixing given the project's actual situation — schedule pressure, how many other things depend on the broken path, whether a workaround exists. They usually move together, but not always: a high-severity bug in a rarely-instantiated debug-only mode might reasonably get lower priority than a lower-severity bug blocking every other team's regression from running at all. Triage has to set both, not treat "severity" as if it alone answers "how urgent is this."
What's next
With the plan defining what to check and this page covering how checking runs continuously, the final page in this section covers the actual decision every project eventually has to make: combining every metric from every technique in this curriculum into one real signoff call.