Code coverage is a crucial component of verification, and it is used to ensure that the design-under-test (DUT) is properly tested. Code coverage helps to identify untested or under-tested parts of the design, which may contain bugs or errors that could impact the functionality of the design.

Code coverage is also helpful in ensuring that all test cases have been executed and that the verification environment has adequately exercised the DUT. It can identify situations where a test case has failed to cover a particular branch, condition, or statement in the code.

How is code coverage measured ?

Code coverage is a metric used to determine the degree to which the code has been executed by a set of test cases. In RTL design, code coverage is generated using specialized tools that can track the signals and statements in the RTL code that have been executed during simulation.

To generate code coverage in RTL, a testbench is created that contains the RTL design and a set of test vectors that exercise the design. The testbench is then run through a simulation tool, and the coverage data is collected and analyzed. The simulation tool uses a coverage database to keep track of which parts of the design have been exercised during simulation.

Once the simulation is complete, the coverage data is analyzed to determine different metrics like branch, condition, expression and toggle coverage.

Types of RTL code coverage

There are several types of RTL (register transfer level) code coverage that can be used in SystemVerilog verification, including:

  • Statement coverage: This measures the percentage of code statements that have been executed during the simulation.
  • Branch coverage: This measures the percentage of decision points in the code that have been exercised by the testbench.
  • Condition coverage: This measures the percentage of Boolean conditions in the code that have been tested.
  • Expression coverage: This measures the percentage of expressions that have been executed.
  • Toggle coverage: This measures the percentage of signal transitions that have been observed during the simulation.
  • Path coverage: This measures the percentage of paths through the code that have been executed.
  • Finite State Machine (FSM) coverage: This measures the percentage of states and transitions in the FSM that have been exercised.

Each of these types of coverage provides different insights into the quality and completeness of the verification process, allowing the verification team to identify areas of the design that require further testing and improvement.

100% code coverage - Fact vs Myth

In theory, it is possible to achieve 100% code coverage in RTL. However, in practice, it is difficult to achieve due to the complexity of modern designs and the limitations of simulation technology. It is also important to note that achieving 100% code coverage does not guarantee the absence of bugs, as it only measures the percentage of code that has been executed by the test cases. It is still important to have functional and performance testing to ensure the correct operation of the design.

Why code coverage alone is not enough

Code coverage is an important metric in verification, but it is not a sufficient metric to determine the completeness of the verification process. Achieving high code coverage does not guarantee the correctness of the design or the absence of bugs. It is possible to have high code coverage but still have functional bugs that were not exercised during testing.

  • Code coverage does not ensure that the functionality of the design is correct. It only tells us that a certain line of code or condition was executed, but it does not guarantee that the output is correct.
  • Code coverage may not cover all the possible scenarios that a design can encounter. It only measures the code that has been executed during simulation.
  • Code coverage does not consider the quality of the test cases. A poorly designed test case that only executes a small portion of the code may still result in a high code coverage score.
  • Code coverage does not take into account the design's corner cases and error handling. These scenarios may be difficult to simulate, but they are important to ensure that the design behaves as expected in all possible scenarios.
  • Code coverage does not provide any information about the quality of the design itself. It only measures the amount of code that has been executed and does not indicate whether the design is efficient, maintainable, or scalable.

Therefore, a good verification strategy should include multiple metrics and techniques, such as functional coverage, assertion-based verification, constrained-random testing, and formal verification. The decision to stop verification should be based on a combination of these metrics and the confidence level achieved in the design's correctness.