AVL Coverage
Overview
AVL provides functional coverage, similar to the featured provided in SystemVerilog.
avl.Covergroup - The covergroup class provides a way to define coverage points in a class.
avl.Coverpoint - The coverpoint class provides a way to define coverage points in a class.
avl.Covercross - The covercross class provides a way to define cross coverage in a class.
Unlike SystemVerilog, AVL coverage is implemented in classes, not native data types. This allows for more flexibility and control over the coverage model.
For example, coverage bins can be defined by a variable. This variable can be set by the factory, allowing for easy coverage model changes at runtime.
Equally, coverage bins are added via function calls. Therefore the used can used inspection, loops or any other software construct to add coverage bins.
Bins
A bin can be defined by 3 definitions:
Value - The sampled values matches any one of the given values (stored as a list)
Range - The sampled value is within the given range (stored as a python range)
Lambda Function: The lambda function returns True (stored as a lambda function)
Bins can be marked as illegal. This bins assert when a matching value is sampled.
Unlike SystemVerilog, bins are never ignored. As bins can be systematically added and removed, the user can ignore a bin by removing it from the coverage model.
Statistics
AVL adds a significant enhancement to SystemVerilog coverage, allowing the user to collect statistics to avl.Coverbin.
When enabled, the rolling min, max, mean, variance and standard deviation of the sampled values is stored. Welford’s Algorithm is used to minimize the footprint.
The use of statistics allows users to collect more information than just that a bin has been satisfied. Data such as performance, latency, statistical distribution and other metrics can be collected.
Reports
When Covergroups are added they are automatically registered with the global avl.Coverage container.
On exit, all coverage is converted to a pandas dataframe and exported to a .json file.
This allows the user to easily merge, format and export coverage using the rich set of tools provided by the pandas library.
Examples
# Copyright 2024 Apheleia
#
# Description:
# Apheleia coverage example
import avl
import cocotb
class example_env(avl.Env):
def __init__(self, name, parent):
super().__init__(name, parent)
self.a = avl.Int8(0)
self.b = 0
self.cg = avl.Covergroup("cg", self)
self.cp_a = self.cg.add_coverpoint("cp_a", lambda: self.a)
self.cp_a.add_bin("bin", 1, 2, range(100, 200))
self.cp_b = self.cg.add_coverpoint("cp_b", lambda: self.b)
self.cp_b.add_bin("bin", lambda x: x == 10)
self.cg.sample()
print(self.cg.report(full=True))
self.a = 101
self.b = 10
self.cg.sample()
print(self.cg.report(full=True))
print(self.cg.report())
@cocotb.test
async def test(dut):
example_env("env", None)
# Copyright 2024 Apheleia
#
# Description:
# Apheleia coverage example
import avl
import cocotb
class example_env(avl.Env):
def __init__(self, name, parent):
super().__init__(name, parent)
self.a = 0
self.b = 0
self.cg = avl.Covergroup("cg", self)
self.cp_a = self.cg.add_coverpoint("cp_a", lambda: self.a)
self.cp_a.add_bin("a1", 1)
self.cp_a.add_bin("a2", 2)
self.cp_a.add_bin("a3", 3)
self.cp_b = self.cg.add_coverpoint("cp_b", lambda: self.b)
self.cp_b.add_bin("b10", 10)
self.cp_b.add_bin("b20", 20)
self.cc = self.cg.add_covercross("cc", self.cp_a, self.cp_b)
self.a = 2
self.b = 10
self.cg.sample()
print(self.cg.report(full=True))
print(self.cg.report(full=False))
@cocotb.test
async def my_test(dut):
example_env("env", None)
# Copyright 2024 Apheleia
#
# Description:
# Apheleia coverage example
import random
import avl
import cocotb
class example_env(avl.Env):
def __init__(self, name, parent):
super().__init__(name, parent)
self.a = avl.Int64(0)
self.cg = avl.Covergroup("cg", self)
# Add a traditional coverpoint
self.cp_a = self.cg.add_coverpoint("cp_a", lambda: self.a)
for i in range(10):
self.cp_a.add_bin(f"bin[{i}]", i)
# Add a coverstat
self.cp_b = self.cg.add_coverpoint("cp_b", lambda: self.a)
self.cp_b.add_bin("bin", range(0, 10), stats=True)
for _ in range(10):
self.a.value = random.randint(2, 8)
self.cg.sample()
print(self.cg.report(full=False))
print(self.cg.report(full=True))
@cocotb.test
async def test(dut):
example_env("env", None)