--- name: functional-verification description: > UVM-based functional verification — testbench architecture, test planning, directed and constrained-random stimulus, functional and code coverage closure, formal assist, and regression sign-off. Use when building a UVM testbench, writing tests, analysing coverage, or managing a verification regression. version: 1.0.0 author: chuanseng-ng license: MIT allowed-tools: Read, Write, Bash --- # Skill: Functional Verification (UVM) ## Invocation When this skill is loaded and a user presents a verification task, **do not execute stages directly**. Immediately spawn the `digital-chip-design-agents:verification-orchestrator` agent and pass the full user request and any available context to it. The orchestrator enforces the stage sequence, loop-back rules, and sign-off criteria defined below. Use the domain rules in this file only when the orchestrator reads this skill mid-flow for stage-specific guidance, or when the user asks a targeted reference question rather than requesting a full flow execution. ## Pre-run Context Before executing or advising on **any** stage, read the following files if they exist: 1. `memory/verification/knowledge.md` — known failure patterns, successful tool flags, PDK/tool quirks. Incorporate its guidance into every stage decision. If absent, proceed without it. 2. `memory/verification/run_state.md` — current run identity (`run_id`, `design_name`, `tool`, `last_stage`). Use this to resume correctly after interruption. If absent, a new run is starting; the orchestrator will create this file before the first stage. This pre-run read applies whether this skill is loaded by a user or called by the orchestrator mid-flow. It ensures the fix database is consulted before any diagnosis step. ## Purpose Guide the complete UVM functional verification flow from testbench architecture through coverage-closed regression sign-off. Produces a verified RTL package with documented coverage and a clean regression. --- ## Supported EDA Tools ### Open-Source - **Verilator** (`verilator`) — fast cycle-accurate simulator; UVM support via verilator+UVM - **Icarus Verilog** (`iverilog`) — event-driven simulation for quick testbench checks - **cocotb** — Python-based co-simulation framework (`pip install cocotb`) - **PyUVM** — UVM implementation in Python for cocotb environments - **UVVM** — VHDL verification methodology library ### Proprietary - **Synopsys VCS** (`vcs`, dialect `synopsys`) — industry-standard SV/UVM simulator - **Cadence Xcelium** (`xrun`, dialect `cadence`) — multi-language simulator with coverage engine - **Siemens Questa** (`vsim` / `vlog` / `vcom`, dialect `siemens`) — mixed-language simulation with UVM support --- ## Stage: tb_architecture ### Domain Rules 1. Follow UVM 1.2 standard (IEEE 1800.2) 2. One UVM agent per DUT interface (driver, monitor, sequencer) 3. Active agents: drive stimulus; passive agents: monitor only 4. Scoreboard: checks DUT output against reference model output 5. Reference model: functional model of DUT — SystemVerilog or C++ via DPI 6. Coverage collector: separate component from scoreboard 7. Virtual sequencer: coordinates multi-agent stimulus scenarios 8. All TB parameters via uvm_config_db — no hardcoded values in components ### UVM Hierarchy Template ``` uvm_test └─ uvm_env ├─ agent_A (active) driver + monitor + sequencer ├─ agent_B (passive) monitor only ├─ scoreboard ├─ coverage_collector └─ virtual_sequencer ``` ### QoR Metrics to Evaluate - All DUT interfaces covered by an agent - Reference model: adequate to check all DUT outputs - TB compile: 0 errors ### Output Required - TB architecture diagram - UVM component list and hierarchy - Interface-to-agent mapping table --- ## Stage: test_planning ### Domain Rules 1. Every functional requirement → at least one directed test 2. Every interface → protocol compliance test 3. Error/exception cases: explicit directed tests (not left to random) 4. Corner cases: boundary values, max/min, overflow, underflow 5. Concurrency: multi-threaded stimulus for pipeline stress 6. Back-pressure: tests under flow control conditions 7. Reset: in-operation resets, reset during active transaction 8. Define covergroups before writing tests 9. Plan the corner cases a directed test rarely reaches, one V-plan entry each: - simultaneous events — load and increment, read and write when empty, flush and enable, full and empty together - the first cycle out of reset - sustained back-pressure (`ready` low for many cycles) and maximum-rate input with no gaps - an input deasserting mid-transaction - both extremes of the clock ratio for a multi-clock block 10. Test at boundary parameter values, not only the default configuration: `WIDTH=1`, `DEPTH=1` and `2`, `N=1`, and a non-power-of-two value. A value the RTL is meant to reject gets a test that it refuses to elaborate 11. Take the RTL hand-off as an input: each entry in `design_state.rtl.unverified[]` (claims the RTL flow concluded without a tool run) gets a test or is marked as assigned to formal. `cdc` and `reset` entries cannot be closed by functional simulation — record them as needing a CDC/RDC tool run rather than as covered ### V-Plan Entry Template (per feature) ``` feature_id: F001 description: AXI write burst handling tests: [direct_single_write, burst_len_256, narrow_transfer] assertions: [axi_valid_stable, axi_handshake_check] covergroups: [burst_len_cg, burst_type_cg] priority: P0 ``` ### QoR Metrics to Evaluate - Requirement coverage: 100% of spec features mapped - P0 tests: must pass before random testing begins - Estimated test count: reasonable vs schedule ### Output Required - V-plan document - Covergroup definitions - Assertion list with expected behaviour --- ## Stage: uvm_tb_build ### Domain Rules — Sequences 1. Base sequence: minimum valid transaction 2. Extended sequences: specific scenarios from V-plan 3. Sequence library: register all sequences for random selection 4. Never hardcode values — use randomised fields with constraints ### Domain Rules — Testbench Coding Testbench code is exempt from the RTL synthesis rules — `initial`, `#delay` and blocking assignments are correct here — but it is still SystemVerilog that has to elaborate the same way in every simulator. 1. `` `default_nettype none `` at the top of every testbench, interface and bind file, restored with `` `default_nettype wire `` at the end so library code compiled after it is unaffected; a typo in a DUT connection must be an error, not an implicit one-bit net 2. Instantiate the DUT with named port connections and named parameter overrides (`#(.WIDTH(8))`), never positional — a positional connection mis-wires silently when a port list is reordered 3. Type every parameter and constant (`int unsigned`, `logic [W-1:0]`). An untyped parameter and a size-cast bare literal (`WIDTH'(1)`) are signed; in a scoreboard comparison that yields a false pass or a false mismatch on values with the top bit set 4. Compare expected and actual at the same width and signedness, and compare with `!==` so an X or Z on the DUT output is a mismatch, not a silent pass 5. Comment the why: each assumption about the DUT, each waiver, each deliberately illegal stimulus ### Domain Rules — Drivers 1. Drive signals cycle-accurate to protocol specification 2. Handle back-pressure per the ready/valid contract. As a source: assert `valid` without waiting for `ready`, then hold `valid` and the payload stable until the beat is accepted. As a sink: `ready` may depend on `valid`. A driver that waits for `ready` before asserting `valid` deadlocks against a DUT that waits for `valid`, and hides DUT bugs that only appear under back-pressure 3. Protocol assertion in driver to catch illegal stimulus early ### Domain Rules — Scoreboard 1. Predict expected output from reference model before DUT output arrives 2. Report mismatches with full context (stimulus, expected, actual) 3. Track: total checks, pass, fail, untriggered ### Domain Rules — SVA Assertions 1. Protocol assertions: in interface bind, not DUT 2. Functional assertions: in checker or bind module 3. All assertions: clearly named with descriptive failure message 4. Every ready/valid interface carries the contract as assertions: transfer only on `valid && ready`; `valid` not retracted before the beat is accepted; payload stable while `valid && !ready`; `valid` and `ready` deasserted (not X) in reset ### QoR Metrics to Evaluate - TB compile: 0 errors, 0 warnings - Sanity test: passes with known-good RTL - All components active in simulation log ### Output Required - UVM component source files - SVA assertion files (bind-based) - Compile script --- ## Stage: directed_tests ### Domain Rules 1. Implement one directed test per V-plan entry — tests must be deterministic 2. Each test: verify the exact functional requirement it targets (no catch-all tests) 3. Error/exception paths: explicit stimulus to trigger each one 4. Corner cases: boundary values, max/min, overflow, underflow — one test each 5. Reset during active transaction: at least one test per interface 6. P0 tests must all pass before constrained-random phase begins 7. DUT bug found during directed test: write a `fix_request` entry to `design_state.fix_requests[]` per the schema in the verification-orchestrator Design State section; terminate with `decision=escalate`. The pipeline-orchestrator (`chip-design-meta`) handles RTL re-invocation — do not loop locally or wait for user confirmation. 8. Before filing, classify the failure as DUT bug or testbench bug, and name the mechanism, not just the location — the reported symptom is not necessarily the bug. Set `suspected_rtl.basis` to `traced` only when you followed the mismatch back to that signal in the waveform; otherwise `hypothesis`. Start from the symptom: | Symptom | Look first at | |---|---| | Intermittent, rate scales with clock ratio | Clock-domain crossing | | Fails at bring-up, fine once running | Reset release and reset values | | Hangs until reset | FSM state with no exit, protocol wait-for cycle | | Wrong only for large values | Width truncation, arithmetic overflow | | Wrong only for negative values | Signed/unsigned mix | | Fails only under sustained load | Arbitration fairness, retracted `valid`, unstable payload | | Passes in RTL sim, fails in gate sim | Blocking assignment in clocked block, incomplete sensitivity list, X-optimism | | Degrades slowly over a long run | Leaked credit or token | 9. Never make a failing test pass by weakening the check: do not loosen the scoreboard comparison, disable or waive an assertion, or constrain stimulus away from the failing case unless that stimulus was illegal per the spec. A fix to the testbench must leave every other test's checking at least as strict as before ### QoR Metrics to Evaluate - All V-plan features covered by at least one directed test - P0 directed tests: 100% pass before proceeding - 0 UVM FATAL or ERROR during directed test phase ### Output Required - Directed test source files (one UVM sequence per feature) - Directed test pass/fail report - Bug report (if any DUT bugs found) --- ## Stage: constrained_random ### Domain Rules 1. Constraint blocks: randomise all stimulus fields within protocol-legal ranges 2. Bias constraints: weight toward uncovered coverage bins identified in prior runs 3. Seeds: use at least 10 distinct seeds before evaluating coverage 4. Scoreboards active throughout: every transaction checked against reference model 5. Any UVM FATAL: stop immediately — do not accumulate errors across seeds 6. Any scoreboard mismatch: classify as DUT bug or testbench bug before continuing, using the symptom table in `directed_tests` rule 8 7. Run until coverage targets are met or max seed budget exhausted ### QoR Metrics to Evaluate - Functional coverage: trending toward 100% across seeds - No persistent scoreboard mismatches (classify and fix before more seeds) - Regression pass rate: 100% (no failing seeds) ### Output Required - Coverage report (merged across all seeds run so far) - Uncovered bin list for directed test closure - Seed log (seed number, pass/fail, coverage achieved) --- ## Stage: coverage_analysis ### Coverage Targets | Type | Target | Priority | |------|--------|----------| | Functional (V-plan) | `design_state.constraints.coverage.functional_pct`% (default: 100%) | P0 | | Code Line | ≥ `design_state.constraints.coverage.line_pct`% (default: 95%) | P1 | | Code Branch | ≥ `design_state.constraints.coverage.branch_pct`% (default: 90%) | P1 | | Code Toggle | ≥ `design_state.constraints.coverage.toggle_pct`% (default: 85%) | P2 | | FSM State | `design_state.constraints.coverage.fsm_state_pct`% (default: 100%) | P0 | | FSM Transition | ≥ `design_state.constraints.coverage.fsm_transition_pct`% (default: 95%) | P0 | | Assertion triggered | `design_state.constraints.coverage.assertion_pct`% (default: 100%) | P1 | ### Closure Strategy 1. Identify uncovered bins after N random seeds 2. Write targeted directed tests for hard-to-hit bins 3. Adjust constraints to bias toward uncovered areas 4. Waive unreachable bins with justification (dead code) ### QoR Metrics to Evaluate - Functional coverage: 100% (no unwaived misses) - Code coverage: per targets above - Waiver file: all entries approved by verification lead ### Output Required - Coverage report (merged across all seeds) - Uncovered bin list with closure plan - Waiver file --- ## Stage: formal_assist ### Use Cases for Formal 1. Protocol compliance: prove handshake never violates 2. Deadlock freedom: prove no state where valid=1 and ready never comes 3. Liveness: every request eventually gets a response 4. One-hot FSM: state encoding never has 0 or >1 bits set 5. Coverage closure: hit bins unreachable by simulation ### Domain Rules 1. Write properties in concurrent SVA 2. Group properties by feature in separate .sva files 3. Constrain environment with assumptions that match valid stimulus 4. Run vacuity check: assumption disabled → property should NOT hold 5. Bound liveness properties (##[1:BOUND]) ### QoR Metrics to Evaluate - All properties: PROVEN or clearly UNREACHABLE - No vacuous proofs - Additional coverage bins closed vs simulation baseline ### Output Required - SVA property file - Formal run report (proven/failed/vacuous per property) - CEX waveform descriptions for any failures --- ## Stage: regression_signoff ### Regression Tiers | Tier | Trigger | Duration | Contents | |------|---------|----------|----------| | Smoke | Every RTL commit | < 30 min | P0 directed tests | | Nightly | Every night | < 8 hr | All directed + 100 random seeds | | Weekly | Weekly gate | < 48 hr | Full suite, 1000 seeds | | Sign-off | Tape-out gate | Unlimited | Full suite, 10,000 seeds | ### Pass Criteria - 0 simulation failures (excluding waived known bugs) - 0 UVM FATAL or UVM ERROR messages - All coverage targets met (see `coverage_analysis` targets; driven by `design_state.constraints.coverage.*`) - Formal: all P0 properties proven - All P0/P1 bugs: closed ### Output Required - Regression pass/fail report - Final merged coverage report - Open bug list - Sign-off checklist --- ## Constraint Validation See `plugins/meta/skills/pipeline-orchestration/SKILL.md` §Constraints Schema for the authoritative schema and stage-entry validation rule. **No required keys** for functional verification — all constraints in this domain are optional with schema defaults. **Optional (schema defaults apply when absent):** - `constraints.coverage.functional_pct` (default: 100) — functional/V-plan coverage target % - `constraints.coverage.line_pct` (default: 95) — code line coverage target % - `constraints.coverage.branch_pct` (default: 90) — code branch coverage target % - `constraints.coverage.toggle_pct` (default: 85) — toggle coverage target % - `constraints.coverage.fsm_state_pct` (default: 100) — FSM state coverage target % - `constraints.coverage.fsm_transition_pct` (default: 95) — FSM transition coverage target % - `constraints.coverage.assertion_pct` (default: 100) — assertion trigger coverage target % Tag `constraint_ref` in history entries when evaluating QoR against these values (e.g. `"coverage.functional_pct"`). --- ## Memory ### Write on stage completion After each stage completes (regardless of whether an orchestrator session is active), write or overwrite one JSON record in `memory/verification/experiences.jsonl` keyed by `run_id`. This ensures data is persisted even if the flow is interrupted or called without full orchestrator context. Use `run_id` = `verification__` (set once at flow start; reuse on each stage update). Set `signoff_achieved: false` until the final sign-off stage completes. ### Run state (write before first stage, update after each stage) Write `memory/verification/run_state.md` as the **first action** before launching any tool: ```markdown run_id: verification__ design_name: tool: start_time: last_stage: ``` Update `last_stage` after each stage completes. This file lets wakeup-loop prompts and resumed sessions identify the correct run without relying on in-memory state. Create the file and parent directories if they do not exist. ### Optional: claude-mem index If `mcp__plugin_ecc_memory__add_observations` is available in this session, emit each applied fix as an observation to entity `chip-design-verification-fixes` after writing to `experiences.jsonl`. Skip silently if the tool is absent — JSONL is the canonical record.