Why Learn Functional Coverage? Randomized stimulus is only half the story — once your testbench is generating thousands of random transactions, how do you know which scenarios actually got exercised, and which ones never showed up at all? SystemVerilog's functional coverage lets you measure exactly that, turning "we ran a lot of tests" into a concrete, trackable answer to "have we tested everything that matters?"

Before writing any coverage code, it helps to know what you're actually trying to measure. This article covers what functional coverage means in practice, where it tends to fall short, and the three pieces — covergroup, coverpoint, and bins — that every coverage model is built from.

7 min read | Intermediate Level

What You'll Learn

  • What functional coverage measures, and why it matters in constrained-random verification
  • Why functional coverage is only as complete as the code written for it
  • The basic building blocks: covergroup, coverpoint, and bins
  • How to control when and under what conditions a covergroup samples

What Is Functional Coverage?

Functional coverage is a measure of what functionalities or features of the design have been exercised by the tests. This is especially useful in constrained random verification (CRV), where it tells you what features a set of tests in a regression has actually covered — rather than just trusting that "enough" random stimulus was generated.

What Are Its Limitations?

Functional coverage is only as good as the code written for it. Say a design document lists 10 features, and 3 of them were overlooked, missed, or simply not known about when the coverage model was written — you'll only end up with coverage code for the other 7. If all 7 are hit during testing, it's easy to conclude the design is fully covered, when in reality 3 features were never measured at all. Make sure everything relevant from the design specification actually makes it into the functional coverage block.

How Is Functional Coverage Done in SystemVerilog?

The idea is to sample interesting variables in the testbench and analyze whether they've reached a certain set of values:


module test;
	bit [3:0] mode;
	bit [1:0] key;

	// Other testbench code
endmodule

mode can take 16 values (it's 4 bits wide), while key can take 4 values (2 bits wide). If something monitors these two variables during simulation and reports which values were actually exercised, you'll know whether a test covered a particular feature or not. Simulators typically let you dump these coverage details to a file for review after the run finishes, and you can merge coverage files from different tests into a single database and review them as a whole — if test A covered feature X and test B covered feature Y, the merged database shows both X and Y as covered.

The Building Blocks: Covergroup, Coverpoint, and Bins

Three pieces work together to turn "monitor these variables" into an actual coverage measurement:

  • A coverpoint tracks one variable or expression and records which of its legal values have actually occurred
  • A covergroup is the container that groups one or more coverpoints together, along with the event that decides when they're sampled
  • A bin represents one value, or a group of values, that a coverpoint is tracking — by default, SystemVerilog creates one automatic bin per legal value

Default bins aren't always what you want. A bin can also be defined explicitly to cover a single value or a whole range at once:


coverpoint mode {
	bins featureA = {0};
	bins featureB = {[1:3]};
}

Here, featureA is a single bin that's hit only when mode equals 0, while featureB is one bin covering the whole range 1 through 3. SystemVerilog also supports array bins (one bin per value across a range), a catch-all default bin, and more — SystemVerilog Coverpoint Bins covers all of that in depth, and SystemVerilog Covergroup and Coverpoint walks through a complete worked example with actual coverage percentages.

Quick Check

Q: A coverpoint has no custom bins defined for a 2-bit variable. How many bins does it get by default?

Show Answer

4 — one automatic bin per legal value, since a 2-bit variable has exactly 4 possible values (0 through 3).

Why Are Coverage Metrics Missing From My Simulation?

By default, most simulators don't dump coverage data unless you ask for it. You'll need to enable a tool-vendor-specific command-line switch to dump coverage details, then open a coverage viewer tool (such as Cadence ICCR/IMC) to load and review the resulting coverage dump file.

How Do You Control When a Covergroup Samples?

There are two ways to trigger coverage collection in a covergroup.

The first is to call the covergroup instance's built-in sample() method yourself, wherever in your code makes sense:


class myCov;
	covergroup CovGrp;
	 	...
	endgroup

	function new ();
		CovGrp = new; 	        // Create an instance of the covergroup
	endfunction
endclass

module tb_top;
	myCov myCov0 = new ();   	// Create an instance of the class

	initial begin
		myCov0.CovGrp.sample ();
	end
endmodule

The second is to specify an event when the covergroup is declared, and let it sample automatically every time that event occurs:


covergroup CovGrp @ (posedge clk); 	// Sample coverpoints at posedge clk
covergroup CovGrp @ (eventA); 			// eventA can be triggered with ->eventA;

How Do You Conditionally Enable Coverage?

There are two ways to conditionally enable or disable coverage collection.

The first is the iff construct, attached directly to a coverpoint so it only samples when a condition holds:


covergroup CovGrp;
	coverpoint mode iff (!_if.reset) {
	    // bins for mode
	}
endgroup

The second is to call the covergroup instance's built-in start() and stop() functions to toggle sampling for the whole group:


CovGrp cg = new;

initial begin
	#1 _if.reset = 0;
	cg.stop ();
	#10 _if.reset = 1;
	cg.start();
end

Where Does This Fit Into a Verification Flow?

Coverage-driven verification uses exactly these mechanisms to decide where to focus effort next — a regression's merged coverage database highlights which bins are still unhit, pointing directly at the scenarios that need more targeted random constraints or a dedicated directed test, rather than just running more of the same stimulus and hoping for the best.

Common Beginner Mistakes

Mistake #1: Treating full coverage code as full feature coverage

Hitting every bin you've written doesn't mean every feature in the design specification has been tested. Why? Coverage can only measure what someone remembered to write a coverpoint for — features that were missed when the coverage model was written stay invisible no matter how many tests you run.

Mistake #2: Forgetting to guard coverage during reset or invalid states

Without an iff condition or a stop()/start() pair around reset, a coverpoint happily samples whatever garbage or default values exist during reset. Why? This can pollute your coverage results with bins that were only ever hit by an uninitialized or reset value, not by any meaningful stimulus.

Mistake #3: Assuming a covergroup samples automatically with no event specified

If a covergroup is declared without a sampling event, nothing samples it unless you explicitly call sample() yourself. Why? It's easy to declare a covergroup, forget the @ (event) clause, and never notice coverage staying at 0% because there's no error — it's simply never being sampled.

Practice Exercise

Challenge: Split key Into Two Custom Bins

Instead of letting key use its 4 default automatic bins, write a bins block that groups it into two custom bins: low for values 0 and 1, and high for values 2 and 3.

Hint

Use the same bins name = {range}; pattern shown for featureA and featureB above.

Solution

coverpoint key {
	bins low  = {[0:1]};
	bins high = {[2:3]};
}

This replaces the 4 default automatic bins with just 2 custom ones, so key reaches 100% coverage as soon as at least one value from each half of its range has been seen — useful when you only care about which half of the range was exercised, not every individual value.

Summary

In this tutorial, you learned:

  • Functional coverage measures what features of a design have actually been exercised by testing, which is especially useful in constrained-random verification
  • Coverage is only as complete as the code written for it — a missed feature in the coverage model stays invisible even at 100% reported coverage
  • A coverpoint tracks a variable or expression, a covergroup groups coverpoints together, and a bin represents the values being tracked
  • A covergroup samples either through an explicit sample() call or automatically via a declared event
  • iff, and the start()/stop() functions, let you conditionally control when coverage is collected
Did you find what you were looking for?

Quiz

Test Your Knowledge

1 of 5 Score: 0 / 5