AVL Coverage Reports

AVL provides a simple script to generate coverage reports in HTML format. The script exported as a project script and added to your path automatically. To generate a coverage report, you need to run the script with the following command:

$ avl-coverage-analysis --path <search path> --output <output_directory>

An index page will be created in the specified output directory, and it will contain links to all the coverage reports found in the specified path. The script will search for all files with the .json extension in the specified path and its subdirectories. The generated HTML files will be placed in the specified output directory, and the index page will link to them.

Merging Coverage Reports

Adding the –merge option to the command will merge all the coverage reports found in the specified path and its subdirectories into a single report. The merged report will be generated in the specified output directory, and the index page will link to it. The merged report will contain the coverage data from all the individual reports, allowing you to see the overall coverage of your design.

Merging is performed on a per bin basis. If the cumulative total exceeds the at_least for the bin, the bin is considered covered. The merged report will show the total coverage for each bin.

For statistical bins the min of mins, max of maxes and combined average and standard deviation based on weighted count is calculated. A minimum of 2 samples is required to compute the statistics.

The command to generate a merged coverage report is as follows:

$ avl-coverage-analysis --path <search path> --output <output_directory> --merge

Ranking Coverage Reports

Adding the –rank option to the command will rank the coverage reports found in the specified path and its subdirectories based on their coverage percentage. The ranked reports will be generated in the specified output directory, and the index page will link to them. Ranking provides 2 additional reports:

  1. A report that shows the list of tests that contributed to the coverage of each bin.

  2. A report that applies a score to the value of each test.

The score is calculated as follows:

  • (1000 * number of unique bins) + (10 * number of rare bins (i.e. < 10 tests contributed)) + number of total bins

$ avl-coverage-analysis --path <search path> --output <output_directory> --rank

The rank and merge options are orthogonal and can be used together.

Index Page

../_images/avl_coverage_index.png

Report Page

../_images/avl_coverage_report.png ../_images/avl_coverage_report_stats.png ../_images/avl_coverage_report_stats_normal.png

Example

# Copyright 2024 Apheleia
#
# Description:
# Apheleia coverage example


import os
import random

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)
        for i in range(20):
            self.cp_a.add_bin(f"a{i}", i)

        self.cp_b = self.cg.add_coverpoint("cp_b", lambda: self.b)
        for i in range(20):
            self.cp_b.add_bin(f"b{i}", i)

    async def run_phase(self):
        """
        Run phase for the example environment.
        """
        for i in range(8):
            self.cg.clear()

            for _ in range(random.randint(1, 10)):
                self.a = random.randint(0, 19)
                self.b = random.randint(0, 19)
                self.cg.sample()
            df = self.cg.report(full=True)
            df.to_json(f"coverage_{i}.json", mode="w", orient="records")

    async def report_phase(self):
        """
        Report phase for the example environment.
        """
        self.info("Removing combined coverage")
        avl.Coverage().remove_covergroup(self.cg)

        self.info("Generating html report")
        os.system("avl-coverage-analysis --path . --output html --merge --rank")


@cocotb.test
async def my_test(dut):
    e = example_env("env", None)
    await e.start()
# Copyright 2024 Apheleia
#
# Description:
# Apheleia coverage example


import os
import random

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("a", range(0,20), stats=True)

        self.cp_b = self.cg.add_coverpoint("cp_b", lambda: self.b)
        self.cp_b.add_bin("b", range(0,20), stats=True)

        self.cp_c = self.cg.add_coverpoint("cp_c", lambda: self.a + self.b)
        for i in range(0,40):
            self.cp_c.add_bin(f"c{i}", i)

    async def run_phase(self):
        """
        Run phase for the example environment.
        """
        for i in range(8):
            self.cg.clear()

            for _ in range(random.randint(5, 10)):
                self.a = random.randint(0, 15)
                self.b = random.randint(5, 19)
                self.cg.sample()
            df = self.cg.report(full=True)
            df.to_json(f"coverage_{i}.json", mode="w", orient="records")

    async def report_phase(self):
        """
        Report phase for the example environment.
        """
        self.info("Removing combined coverage")
        avl.Coverage().remove_covergroup(self.cg)

        self.info("Generating html report")
        os.system("avl-coverage-analysis --path . --output html --merge --rank --stats")


@cocotb.test
async def my_test(dut):
    e = example_env("env", None)
    await e.start()