A complex SoC cannot be verified as a single monolithic unit — the design is too large, too interconnected, and too slow to simulate all at once from day one. Instead, verification is structured in stages, each targeting a different level of the design hierarchy with a different focus and a different set of tests. Understanding these stages and what they are responsible for is fundamental to how verification projects are planned and executed.

10 min read | Beginner Level

What You'll Learn

  • The three main verification stages — block, subsystem, and system — and what each targets
  • What regression suites look like at each stage and what they are designed to catch
  • Why bugs found at later stages are significantly more expensive to fix
  • How the stages fit together across a real chip development timeline

Why Stages Exist

When a chip is designed, the RTL is written block by block — a memory controller, an interrupt handler, a DMA engine, a CPU core. Each block is developed by a different engineer or team, often in parallel. Waiting until the entire SoC is assembled before running any simulation would mean discovering bugs only at the point where they are most expensive and slowest to fix.

Staged verification solves this by applying verification at each level of the hierarchy as it becomes available:

StageWhat is verifiedWho drives itPrimary concern
Block levelA single IP block in isolationBlock DV engineerInternal logic correctness
Subsystem levelTwo or more blocks connected togetherSubsystem DV engineerInterface behavior between blocks
System / SoC levelFull chip including softwareSoC DV / validation teamEnd-to-end scenarios, boot, performance

Block-Level Verification

Block-level verification — sometimes called unit-level verification — is the first and most intensive stage. Each IP block is verified in isolation: the DUT is a single module, and the testbench provides all the stimulus that would normally come from surrounding logic.

The testbench at this stage is self-contained. It drives the block's inputs directly, checks its outputs, and has no dependency on other blocks being ready. This isolation is valuable: when a test fails, the bug is known to be inside this one block, not buried in an interaction between multiple blocks across the chip.

What Block-Level Verification Targets

  • All functional behavior specified for the block — every register, every control signal, every state machine transition
  • Interface protocol compliance — if the block has an AXI slave port, every aspect of AXI handshake behavior is verified here
  • Corner cases and boundary conditions — counter overflow, FIFO full/empty, reset mid-operation, back-to-back transactions with no gaps
  • Error handling — illegal inputs, timeout conditions, error flag generation and clearing
  • Reset behavior — every register must reach its specified reset value; the FSM must reach its idle state

Coverage at Block Level

Block-level verification carries the highest coverage requirements of any stage. Code coverage targets of 95–100% are typical, with full functional coverage closure required against the block's verification plan. The reasoning is straightforward: if a bug is not caught here, it will only be discovered later when it is far harder to isolate and fix.

Block-level verification is where the most engineering effort is spent. A well-verified block is a reliable building block — the integration team can focus on interface behavior rather than re-discovering bugs that should have been caught upstream.

Block-Level Verification in Practice

A DMA controller block might have a dedicated verification environment with a full UVM testbench, a reference model that tracks expected transfer state, a scoreboard comparing DUT outputs against the reference, and a functional coverage model with hundreds of coverage points. The block DV engineer may spend weeks running constrained random tests, closing coverage gaps with directed tests, and iterating through RTL fixes before the block is signed off and handed to the integration team.

Quick Check

Q: A block-level testbench achieves 98% code coverage but the verification plan lists 15 functional coverage points, of which only 12 are closed. Is block-level sign-off complete?

Show Answer

No. Both code coverage and functional coverage must meet their targets before sign-off. The 3 unclosed functional coverage points represent design-level scenarios from the specification that have not been exercised. Each must either be closed with additional tests or formally waived with documented justification. Code coverage alone does not confirm that the right scenarios were tested.

Subsystem-Level Verification

Once individual blocks pass their block-level sign-off, they are assembled into larger subsystems — and subsystem-level verification begins. At this stage, the DUT is no longer a single block but a cluster of connected blocks: perhaps a CPU core connected to a cache, a memory controller connected to a DMA engine and an AXI interconnect, or a video pipeline with multiple processing stages.

The focus shifts from internal block behavior to interface behavior between blocks. Block-level verification confirmed that each block handles its own protocol correctly. Integration verification confirms that the blocks work correctly when actually connected and communicating with each other.

What Subsystem-Level Verification Targets

  • Inter-block communication — does the AXI master in block A correctly exchange transactions with the AXI slave in block B?
  • Shared resource contention — what happens when two blocks simultaneously request access to a shared bus, memory port, or interrupt line?
  • Reset sequencing — in a subsystem with multiple reset domains, do the blocks come out of reset in the correct order without deadlocking?
  • Datapath integrity across block boundaries — data written by one block and read by another must maintain integrity through the interconnect
  • Clock domain crossings (CDC) — signals crossing between blocks clocked by different frequencies must be properly synchronized

A class of bugs is uniquely discoverable at subsystem level: bugs that only manifest when two correctly-behaving blocks interact. Each block passes all its own tests. The bug appears only when they are connected — caused by a subtle mismatch in protocol interpretation, timing assumption, or reset dependency between the two blocks.

Testbench Architecture at Subsystem Level

Integration testbenches are typically assembled from the block-level verification components — the same drivers, monitors, and protocol checkers used at block level are reused at subsystem level, now driving the subsystem's external interfaces rather than individual block ports. This reuse is one of the key reasons industry methodologies like UVM invest heavily in modular, reusable testbench components.

Subsystem-Level Verification in Practice

An integration testbench for a memory subsystem (CPU core + L2 cache + memory controller) would drive CPU read/write requests at the top-level interface and check that the correct data is returned — without needing to know the internal state of the cache or the memory controller individually. Protocol checkers on the interconnect buses monitor every transaction for protocol compliance, catching any violations that arise from how the blocks interact.

System-Level / SoC Verification

System-level verification operates on the full chip — all subsystems assembled together, running realistic end-to-end scenarios. At this point, the simulation model includes processors, memory controllers, peripheral IP blocks, DMA engines, interrupt controllers, and all the interconnect that ties them together.

The nature of testing changes significantly at this stage. RTL simulation becomes very slow for a full SoC — billions of clock cycles are needed to run a realistic software stack. System-level verification therefore relies more heavily on emulation for software bring-up and FPGA prototyping for real-interface testing, while RTL simulation is reserved for targeted scenarios that cannot be run elsewhere. See Verification Techniques for a detailed comparison.

What System-Level Verification Targets

  • End-to-end functional scenarios — a full DMA transfer from a peripheral to system memory, an interrupt being raised and serviced by the CPU, a boot sequence completing successfully
  • Software and firmware behavior — device drivers, firmware initialization sequences, and OS-level interactions are exercised for the first time in the full chip context
  • Performance — throughput, latency, and bandwidth measurements under realistic workloads; performance regressions are caught before tapeout
  • Power behavior — power domain transitions, clock gating, retention register behavior during sleep/wake sequences
  • Multi-block interactions at scale — scenarios involving many blocks simultaneously, such as a network packet being received, processed by a CPU, written to memory, and transmitted through a different interface

Quick Check

Q: Why can't system-level verification simply replace block-level and subsystem-level verification? If the full chip passes system tests, isn't that sufficient?

Show Answer

No, for two reasons. First, system-level simulation is extremely slow — it cannot feasibly run the thousands of constrained random tests needed for thorough functional coverage of each individual block. System tests exercise a tiny fraction of the state space that block-level random testing explores. Second, when a system-level test fails, isolating the root cause is much harder. A failure in a system test could be caused by any block in the chip, any interface between them, or any software/firmware component. A bug that would be trivially isolated in a block-level testbench can take days to debug at system level. Block and subsystem-level verification are prerequisites that make system-level testing tractable.

Regression Suites at Each Stage

At every verification stage, the tests that have been developed are organized into a regression suite — a curated set of tests that is run automatically whenever the RTL changes. Regression suites serve as a safety net: any RTL change that breaks a previously passing scenario is caught immediately rather than silently accumulating.

The character of each regression suite reflects the stage it belongs to:

  • Block-level regression: Thousands of tests, dominated by constrained random seeds. Runs nightly on a compute farm. Covers the full functional coverage model for the block. Any new RTL commit triggers at minimum a smoke regression — a fast subset of the most critical directed tests — before the full nightly regression runs.
  • Subsystem-level regression: Smaller test count than block level, focused on inter-block integration scenarios and interface compliance. Tests are typically longer in simulation time than block-level tests because they exercise multi-block transaction sequences.
  • System-level regression: The smallest number of tests but the longest simulation time per test. Focuses on end-to-end scenarios, boot sequences, and performance benchmarks. Often supplemented by emulation runs that cannot be tracked by the RTL simulation regression infrastructure.

A regression failure at any stage must be triaged before new RTL is committed on top of it. Allowing failing tests to accumulate in regression — "we'll fix it later" — masks new failures and makes root cause analysis progressively harder.

The Cost of Finding Bugs Late

One of the most important principles in verification is that the cost of a bug increases dramatically the later it is found. This is not just about the effort to fix the RTL — it is about the cascading effect on everything built on top of it.

  • Block level: The bug is in one block, the testbench is focused on that block, and the RTL designer who wrote the code is still actively working on it. Fix time: hours to days. Impact: none beyond the block itself.
  • Subsystem level: The bug may have caused incorrect behavior in a connected block, which may have masked other bugs. The integration testbench must be re-run. Depending on the bug, other blocks may need regression re-runs. Fix time: days to a week. Impact: may require re-verification of connected blocks.
  • System level: The bug manifests as a complex system failure with many potential root causes. Isolating it requires waveform analysis across multiple blocks. The RTL fix may affect integration-level and system-level regression. Fix time: days to weeks. Impact: may require sign-off re-runs at multiple levels.
  • Post-silicon (after tapeout): The chip has been fabricated. Options are a costly silicon re-spin, a software workaround, or shipping with an errata. Fix time: 3–6 months for a re-spin. Cost: potentially millions of dollars in mask costs and schedule delay.

Why Block-Level Investment Pays Off

A verification team that spends an extra two weeks closing the last 5% of block-level functional coverage may feel like they are being overly thorough. But if a bug in that 5% escapes to system level and requires a week of multi-engineer debug to isolate, the two weeks of upfront investment already paid for itself — before accounting for the risk that the same bug might have escaped to silicon.

Handoff Points Between Stages

Moving from one verification stage to the next is a formal handoff, not an informal decision. Common handoff criteria include:

  • Block-level sign-off: Code coverage targets met, functional coverage plan closed (with documented waivers), zero open critical bugs, regression green on the latest RTL snapshot
  • Subsystem readiness: All constituent blocks have passed block-level sign-off; subsystem testbench environment is ready; interface specifications between blocks are frozen
  • System-level readiness: All subsystems have passed subsystem-level sign-off; system-level simulation environment and emulation platform are ready; software/firmware is available for bring-up

In practice, these stages overlap. Subsystem-level verification often begins on subsystems that are ready while other blocks are still completing block-level verification. The stages are not strictly sequential — they run in parallel across different parts of the design.

Practice Exercise

Challenge: Assign the Bug to a Stage

For each bug description below, identify which verification stage is most likely to catch it first, and briefly explain why.

  1. An AXI slave block does not deassert RVALID correctly after the master completes a read burst
  2. The CPU and DMA engine both request the memory bus simultaneously; the arbiter grants both, corrupting memory
  3. After a full chip power-on reset, the interrupt controller's priority registers do not reset to their specified default values
  4. A peripheral device driver written for the chip fails to enumerate the device during OS boot
Show Answers

1. RVALID deassert bug: Block level. This is a protocol compliance bug internal to the AXI slave block. The block-level testbench drives AXI read bursts and checks handshake signal behavior — this exact scenario should be covered by the block's AXI protocol checker and functional coverage plan.

2. Memory bus arbiter grants both: Subsystem level. This bug requires two blocks — the CPU and DMA engine — to simultaneously request the bus. It cannot appear in either block's isolated testbench. The integration testbench, which connects both blocks to the shared arbiter, is where simultaneous bus contention scenarios are exercised.

3. Interrupt controller reset values: Block level. Reset value correctness for every register is a standard block-level verification requirement. The block-level testbench should apply reset and check every register field against its specification. If this escaped block level, it represents a gap in the block's reset verification coverage.

4. Device driver enumeration failure: System level. This bug involves software (the device driver), the peripheral IP block, the interrupt controller, and the CPU — all interacting during OS boot. It is only observable at system level when a real software stack is running against the full chip model. Block and subsystem-level verification have no visibility into OS-level device enumeration behavior.

Summary

In this tutorial, you learned:

  • Verification is structured in three stages — block, subsystem, and system — each targeting a different level of the design hierarchy
  • Block-level verification is the most intensive stage, targeting internal logic correctness with the highest coverage requirements
  • Subsystem-level verification targets inter-block behavior — bugs that only appear when correctly-verified blocks are connected and communicating
  • System-level verification targets end-to-end scenarios, software behavior, and performance — relying on emulation for scenarios too slow for RTL simulation
  • Regression suites at each stage act as safety nets, catching any RTL change that breaks previously verified behavior
  • The cost of finding a bug rises dramatically at each later stage — block-level investment is always the most cost-effective place to catch bugs
Did you find what you were looking for?

Quiz

No quiz questions available for this article.