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

AboutRoadmapCareersInternshipsFAQContactPrivacyTerms
Skip to lesson

Course contents

  • Start Here5
  • SystemVerilog Language Foundations28
  • Object-Oriented SystemVerilog for Verification30
  • Constraint Randomization — Interview-Critical Deep Dive39
  • SystemVerilog Assertions — Interview-Critical Deep Dive41
  • Functional Coverage in SystemVerilog25
    • Covergroups & Coverpoints
      • Covergroup Anatomy
      • Sampling: Clocked, Event & sample()
      • Coverpoint Expressions & Types
      • Your First Coverage Model: Three Bins and a Report
      • An ALU Coverage Plan as a Covergroup
      • Sign-Off Needs Both: Code and Functional Coverage
      • The Bins Model: Counting Covergroups on Open Tools
    • Bins: Explicit, Auto, Illegal & Ignore
    • Cross Coverage
    • Coverage Options & Methods
    • Coverage Closure & Sign-Off
  • Testbench Architecture in SystemVerilog24
  • Advanced Language & Integration26
  • Senior & Interview Preparation23
  • Principal-Level Verification34
Loading lesson

←Covergroups & Coverpoints
  1. Topics
  2. SystemVerilog
  3. Functional Coverage in SystemVerilog
  4. Covergroups & Coverpoints
  5. Sign-Off Needs Both: Code and Functional Coverage

Part 5 of 9, lesson 6 of 25Part 5 of 9/Functional Coverage/Lesson 6 of 25Intermediate

Sign-Off Needs Both: Code and Functional Coverage

Why full line coverage can sit beside a 0% functional corner, shown on one FIFO, and how to read the four quadrants.

A block signed off at 100% line coverage with a FIFO corner never exercised: every line ran, but never with the FIFO full and a write arriving together.

After this lesson you can: explain why code coverage is not enough, read the four code and functional quadrants, and name the unhit corner a covergroup would show.

Sign-off needs both

Code coverage is extracted automatically from RTL structure: lines, branches, toggles. It answers whether the implementation ran. Functional coverage is written from the spec. It answers whether required scenarios happened.

Code coverage

Functional coverage

Source

RTL structure

The specification

Written

Automatically, by the tool

By the verification engineer

Measures

Implementation exercised

Scenarios that occurred

100% means

All written code ran

All planned scenarios hit

Blind to

Missing code, scenario meaning

Anything not in the coverage model

Effort

A switch

A plan and covergroups

The FIFO corner below is the classic proof. Both lines run, yet the killing combination never occurs.

The next listing is not run in this course's checks: the open simulators do not count covergroups. The bench at the end of the lesson counts the same bins with the course's bins model, listed on the Bins Model page of this topic.

fifo_wr.sv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// not-run: Verilator 5.048 ignores covergroups (COVERIGN) and Icarus 13 has none; the bins model counts it
module fifo_wr (input logic clk, input logic rst_n,
                input logic push, pop, input logic full, input logic empty,
                input logic [7:0] wdata, input logic [2:0] wr_ptr,
                output logic [2:0] rd_ptr);
  logic [7:0] mem [8];

  // Line A runs on any normal push; line B on any normal pop.
  // Pushes until full plus pops until empty give 100% line,
  // toggle and branch coverage: yet push && pop && full NEVER OCCURS.
  // BUG: simultaneous push && pop while FULL corrupts the count
  // elsewhere in the design.
  always_ff @(posedge clk) begin
    if (push && !full)
      mem[wr_ptr] <= wdata;
    if (pop && !empty)
      rd_ptr <= rd_ptr + 1;
  end

  // The functional coverage that names the gap:
  covergroup cg_fifo @(posedge clk);
    cp_corner : coverpoint {push, pop, full} iff (rst_n) {
      bins push_pop_full = {3'b111};   // unhit means the scenario was never tried
    }
  endgroup

  cg_fifo cg_inst = new();
endmodule

The unhit bin points at the exact stimulus gap. Line coverage had no vocabulary to even ask the question.

Verilator measures code coverage for real, so the claim can be checked. The bench fills a small FIFO, drains it, and samples the corner bin with the bins model:

fifo4.sv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// uses: covmodel
// A 4-deep FIFO, a test that fills it and drains it, and the one corner both miss.
module fifo4 (
  input  logic clk, rst_n, push, pop,
  input  logic [7:0] wdata,
  output logic [7:0] rdata,
  output logic full, empty
);
  logic [7:0] mem [4];
  logic [1:0] wp, rp;
  logic [2:0] count;
  assign full  = (count == 4);
  assign empty = (count == 0);
  assign rdata = mem[rp];
  always_ff @(posedge clk or negedge rst_n)
    if (!rst_n) begin wp <= 0; rp <= 0; count <= 0; end
    else begin
      if (push && !full) begin mem[wp] <= wdata; wp <= wp + 1; end
      if (pop && !empty) rp <= rp + 1;
      count <= count + (push && !full) - (pop && !empty);
    end
endmodule

module tb_fifo_codecov;
  logic clk = 0, rst_n = 0, push = 0, pop = 0;
  logic [7:0] wdata = 0, rdata;
  logic full, empty;
  always #5 clk = ~clk;
  fifo4 dut (.*);
  cm_point cp_corner = new("cp_corner {push, pop, full}");
  always @(posedge clk) if (rst_n) cp_corner.sample({push, pop, full});
  initial begin
    cp_corner.add("push_pop_full", 3'b111, 3'b111);
    repeat (2) @(negedge clk);
    rst_n = 1;
    repeat (5) begin @(negedge clk) push = 1; wdata = wdata + 1; end   // fill, and one push while full
    @(negedge clk) push = 0;
    repeat (5) begin @(negedge clk) pop = 1; end                        // drain, and one pop while empty
    @(negedge clk) pop = 0;
    repeat (2) @(negedge clk);
    cp_corner.report();
    $display("PASS: the fill-and-drain test finished; compare the corner bin with the line coverage of fifo4");
    $finish;
  end
endmodule
Terminal
  coverpoint cp_corner {push, pop, full}: 0.00% (0 of 1 bins)  below goal 100
    push_pop_full  0     <- hole
PASS: the fill-and-drain test finished; compare the corner bin with the line coverage of fifo4

Built a second time with line coverage on (verilator --binary --coverage-line, with the FIFO in its own file fifo4.sv), the same test writes coverage.dat, and verilator_coverage --annotate-min 1 --annotate-all --annotate annot coverage.dat annotates the FIFO. Every line ran, both branches of every if included, while the corner bin above reads 0:

Terminal
//      // verilator_coverage annotation
        module fifo4 (
          input  logic clk, rst_n, push, pop,
          input  logic [7:0] wdata,
          output logic [7:0] rdata,
          output logic full, empty
        );
          logic [7:0] mem [4];
          logic [1:0] wp, rp;
          logic [2:0] count;
          assign full  = (count == 4);
          assign empty = (count == 0);
          assign rdata = mem[rp];
 000016   always_ff @(posedge clk or negedge rst_n)
 000014     if (!rst_n) begin wp <= 0; rp <= 0; count <= 0; end
 000014     else begin
 000010       if (push && !full) begin mem[wp] <= wdata; wp <= wp + 1; end
 000010       if (pop && !empty) rp <= rp + 1;
 000014       count <= count + (push && !full) - (pop && !empty);
            end
        endmodule

Recorded with Verilator 5.048 on 2026-10-18. The counts at the left margin are how many times each line ran; a line that never ran would show %000000. Line coverage is complete and the FIFO's one dangerous scenario was never tried. That is the whole argument for functional coverage, measured on one design.

Functional coverage low

Functional coverage high

Code coverage high

Stimulus wanders; scenarios never formed

Sign-off candidate: review waivers, then close

Code coverage low

Early bring-up: keep testing

Coverage model too thin, or dead RTL: investigate

An assertion counter is a different construct: SystemVerilog cover property counts assertion matches, not covergroup bins. Both appear in reports, so name which one each number came from.

Reporting full line coverage as verification complete is the classic trap. Missing code has no line to cover, and covered lines never promise that their combinations happened.

“Do code and functional coverage agree at sign-off?”

Define each in one sentence, give the FIFO miss as the example, and close with both metrics at goal plus reviewed waivers.

Check yourself Random stimulus hits every opcode and both zero outcomes, yet x_op_zero sits at 83.3 percent. What is missing?

One opcode never produced a zero result: five of six asserted bins hit. Add the directed case the hole names.

Check yourself Code coverage reads high and functional coverage reads low. What does the quadrant say?

Stimulus wanders without forming planned scenarios. Steer it with constraints or directed cases instead of running longer.

  • Full line coverage can sit beside a 0% functional corner.

  • Missing code has no line to cover.

  • Sign off on functional and code coverage together.

Rule of thumb: sign off on functional and code coverage together.

How this was checked

Counted with the course's bins model (rich/coverage/cov_model.sv, listed on The Bins Model page) on Verilator 5.048 (--binary --timing) on 2026-10-18; every bench printed the PASS line shown. Verilator 5.048 parses covergroups with a COVERIGN warning and ignores their bins, and Icarus 13 has none, so each covergroup listing is marked not run and its bench counts the same bins with the model.

The FIFO test was also built with verilator --binary --coverage-line and annotated with verilator_coverage on 2026-10-18: every line and both sides of every branch ran while the corner bin read 0.

Related topics

  • Coverage plan

  • Sign-off and metrics

Previous

149 / 275

Next: The Bins Model: Counting Covergroups on Open Tools

Up next

Up nextThe Bins Model: Counting Covergroups on Open Tools

Sign in to save progress

Practice this lessonPrevious lessonReport an error

See also

  • Covergroup Anatomy
  • Sampling: Clocked, Event & sample()
  • Coverpoint Expressions & Types