Logic Design - Functional Coverage in SystemVerilog

[Edit of Image1]

Introduction

Hey it's a me again @drifter1!

Today we continue with the Logic Design series on SystemVerilog in order to talk about Functional Coverage.

So, without further ado, let's get straight into it!


Functional Coverage

For years, measuring the quality of verification has been done using an approach known as Functional Coverage. When combined with constrained random verification (CRV) that we've explained thoroughly in the previous parts, it's possible to identify which set of features has been covered by the tests.

Limitations

Of course, there are limitations to this approach. It will only be as good as the code written for it by the programmer. This means that unimplemented features of the system can be overlooked by the tests very easily as no functional coverage code will be written for them. It is important for the design specification to be analyzed correctly, so that all the required information is extracted from it.

Types

The functional coverage code is written alongside the testbench and there are 4 main places for it to be coded in. This basically gives us 4 types of functional coverage points, which are:

  • F1 : Near randomization
  • F2 : At the Input interface of the DUT
  • F3 : Internal DUT States
  • F4 : At the Output interface of the DUT

Covergroups

Coverage models in SystemVerilog are enclosed within the covergroup and endgroup keywords. Such a covergroup is quite similar to a class, and so once defined (basically anywhere) it can then be instantiated just like any object using new().

A covergroup definition is associated to the identifier that is provided along with it and contains:

  • Coverage points - which define what needs to be covered
  • Clocking event - which defines when to sample
  • Cross coverage between coverage points
  • Various coverage options
  • Optional Arguments - which are given values through the constructor

Sampling

There are two ways of triggering when to sample:

  • Clocking Event
  • Build-in sample() method

The clocking event of a covergroup is specified similar to how the trigger event is specified in always blocks. So, it's a @ followed by the event, which can be something like posedge clk (on every positive edge of the clock signal) or a completely custom event:

covergroup covergroup_name @ (customEvent);

When left unspecified, coverage sampling must be triggered manually through the build-in sample() method. The method is called on the specific coverpoint that needs to be sampled within the group:

covergroup_name.coverpoint_name.sample();

Coverage Points

Within a coverage group multiple coverage points are defined. They can be variables or expressions, and are mentioned using the coverpoint keyword. Each coverpoint can also include an optional label, which is put before the coverpoint keyword and is followed by a colon (:).

opt_cp_label : coverpoint var;
opt_cp_label2 : coverpoint (expr);

Coverpoint Bins

Each coverpoint can include bins which basically separate the range of possible values. The bins will be "covered" when the coverpoint variable or expression is equal to the corresponding values. So, they can be used as a sort of feature "hit".

The various bins are enclosed within { } that follow the coverpoint's variable or expression. Each separate bin starts with the bins keyword, followed by an identifier and then the valid range. This range can be expressed in many ways, some of which are shown below.

coverpoint var {
    // separate bin for a given value
    bins zero = {0};

    // separate bin for a given range
    bins range = {[1 : 2]}

    // automatic separate bins for a given range
    bins separate[] = {[3 : 7]}

    // fixed number of automatic bins (range is split into 3) 
    bins fixed_auto[3] = {[0 : $]}

    // store remaining values that haven't been covered
    bins remaining = default;
}

Conditional Coverage

There are two main ways of conditionally enabling coverage:

  • adding the iff construct in the corresponding coverpoint
  • calling the start() and stop() functions on the covergroup object

The iff construct looks like this:

covergroup covergroup_name;
    coverpoint var iff (condition) {
        // bins
    }
endgroup

Cross Coverage

A cross coverage between coverpoints is specified using the cross construct followed by the labels of the crosspoints separated by comma (,). It can also optionally include a label on its own.

opt_cc_label : cross cp_label1, cp_label2;

Coverage Options

SystemVerilog includes various options that can be added to coverage groups and points. They can affect either a specific instance or all of the instances, and are accessed through the option sub-object with dot (.) notation.

covergroup covergroup_name;
    option.option_name = option_value;
    ...
endgroup

Getting the Coverage

The percentage of coverage is returned by the get_coverage() method, which needs to be called on the corresponding covergroup object. It's also possible to call the $get_coverage() system task to get the coverage for all coverage groups.


RESOURCES:

References

  1. https://www.chipverify.com/systemverilog/systemverilog-tutorial
  2. https://www.asic-world.com/systemverilog/tutorial.html

Images

  1. https://www.flickr.com/photos/creative_stock/5227842611

Block diagrams and other visualizations were made using draw.io


Previous articles of the series

Verilog

SystemVerilog

  • From Verilog To SystemVerilog → Data Types, Arrays, Structures, Operators and Expressions
  • Control Flow → Additional Procedural Blocks, Loops, Conditional Statements, Functions and Task Features
  • Processes → Fork - Join in Verilog and SystemVerilog, Process Control (wait fork, disable fork)
  • Events → Interprocess Communication, Events (Definition, Triggering, Waiting, Sequencing, Merging, as Arguments)
  • Semaphores and Mailboxes → Semaphores (Creation, Methods), Mailboxes (Definition, Methods)
  • Interfaces (part 1) → Interfaces (Definition, Port and Signal Lists, Instantiation), Modports
  • Interfaces (part 2) → Parameters, Tasks and Functions (Importing, Exporting), Clocking Blocks (Input and Output Skews)
  • Classes (part 1) → Classes (Definition, Constructor Function, Creating Objects, Accessing Class Members, Static and Constant Class Members, Arrays)
  • Classes (part 2) → Copying Objects (Shallow and Deep Copy), Inheritance, Polymorphism, Virtual Methods
  • Classes (part 3) → Parameterized Classes, Out-of-Block Method Declaration, Data Accessibility, Abstract / Virtual Classes
  • Program Blocks → Design and Testbench, Program Block (Reactive Region, Allowed Constructs)
  • Packages → Design Hierarchy, Packages (Definition, Importing, Definition Collision)
  • Constraints and Randomization → Testing and Verification, Random Variables (Standard, Random-Cyclic), Randomize Method (Constraint and Random Mode, Pre / Post Randomize)
  • Constraint Blocks → Constraint Blocks (Syntax, Rules), External (Explicit, Implicit), Static, Soft and In-Line Constraints
  • Constraint Types (part 1) → Simple Expressions, Set Membership (Inside Operator, Range, Set, Inverted), Weighted Distributions (Dist Operator, := and :/)
  • Constraint Types (part 2) → Conditional Relations (Implication Operator, If-Else), Iterative Constraints, Solve - Before, Random Case

Final words | Next up

And this is actually it for today's post!

It was basically only an overview of what Functional Coverage is and what tools SystemVerilog provides us with in order to implement it. For more in-depth information on the various constructs head over to ASIC World.

Next time we will cover Assertions in a similar fashion...

See Ya!

Keep on drifting!

H2
H3
H4
3 columns
2 columns
1 column
Join the conversation now
Logo
Center