VHDL Functional Coverage is more capable than SystemVerilog

This is a continuing series of posts on OSVVM and functional coverage. If you are just getting started, you may wish to start with the OSVVM page.

When writing functional coverage it is important to be able to capture all the details of a model. With item (aka point) coverage, both VHDL and SystemVerilog do a good job. However with cross coverage, if the model requires more than a simple Cartesian product, SystemVerilog falls short. OSVVM, on the other hand, offers a rich cross coverage capability.

In SystemVerilog functional coverage is modeled as a language based declaration. To model cross coverage in SystemVerilog, one starts by declaring item (aka point) coverage for each dimension in the cross. The cross coverage is then declared in terms of the defined item coverage. If the cross coverage is more complicated than a simple Cartesian product, a set of “and” and “or” masking operations are used to filter out items from the cross product. This results in an awkward, limited, and verbose capture of the functional coverage model.

In VHDL’s OSVVM, functional coverage is implemented as a data structure.  The functional coverage model is captured incrementally using any sequential code (if, loop, …).  As long as the entire model is captured before we start collecting coverage, we can use as many calls to AddBins or AddCross as needed.

Simple Cartesian product type coverage can be captured in a concise, single line call, such as the one used in my blog post Functional Coverage Made Easy with VHDL’s OSVVM. Note that item coverage did not need to be declared first.

ACov.AddCross( GenBin(0,7), GenBin(0,7) );

When the coverage modeling is more complicated, we can solve it piecewise using multiple calls to Addbins or AddCross to define the model. The following item coverage example uses three calls to create item coverage.

Bin1.AddBins(GenBin( 1, 3 )) ;
Bin1.AddBins(GenBin( 4, 252, 2 )) ;
Bin1.AddBins(GenBin(253, 255 )) ;

The output of GenBin is a single dimensional array value. As a result, concatenation can be used to join bins. Hence we can rewrite the above bins in a single line as shown below. Note I only recommend doing something like this when it increases readability.

Bin1.AddBins( GenBin(1, 3) & GenBin(4, 252, 2) & GenBin(253, 255)) ;

Since functional coverage is modeled using sequential code, writing conditional coverage or using iteration is simply a matter of writing the code. The following uses a boolean generic, gFAST_TEST, to determine whether to cover the entire input space or just a subset of it for a fast test.

if gFAST_TEST then
  ACov.AddCross( GenBin(0,3), GenBin(0,3) ); -- 4x4 Fast Model
  ACov.AddCross( GenBin(0,7), GenBin(0,7) ); -- 8x8 Complete Model
end if ;

In our VHDL Testbenches and Verification class you will get hands on experience writing functional coverage and using it to shape stimulus generation.