Code Coverage
Code coverage is a metric that measures which parts of the tested code have been executed and which parts have not. By analyzing code coverage, the effectiveness and thoroughness of testing can be evaluated.
Code coverage includes:
- Line Coverage: The number of lines executed in the tested code. This is the simplest metric, and the goal is usually 100%.
- Branch Coverage: Whether each branch of every control structure has been executed. For example, in an
if
statement, have both thetrue
andfalse
branches been executed? - FSM Coverage: Whether all states of a finite state machine have been reached.
- Toggle Coverage: Tracks the toggling of signals in the tested code, ensuring that every circuit node has both
0 -> 1
and1 -> 0
transitions. - Path Coverage: Examines the coverage of paths. In
always
orinitial
blocks,if ... else
andcase
statements can create various data paths in the circuit structure.
* The primary simulator used in this project is Verilator, with a focus on line coverage. Verilator supports coverage statistics, so when building the DUT, the -c
option must be added to the compilation options to enable coverage statistics.
Relevant Locations in This Project
To enable coverage, the -c
option must be added during compilation (when using the picker
command). Refer to the Picker Parameter Explanation. Additionally, the line coverage function must be implemented and enabled in the test files to generate coverage statistics during Toffee testing.
In conjunction with the above description, code coverage will be involved when compiling, writing and enabling line coverage functions and tests in this project:
Adding Compilation Scripts
Write the build(cfg) -> bool
Function
# Omitted earlier code
if not os.path.exists(get_root_dir("dut/RVCExpander")):
info("Exporting RVCExpander.sv")
s, out, err = exe_cmd(f'picker export --cp_lib false {get_rtl_dir("rtl/RVCExpander.sv", cfg=cfg)
} --lang python --tdir {get_root_dir("dut")}/ -w rvc.fst -c')
assert s, "Failed to export RVCExpander.sv: %s\n%s" % (out, err)
# Omitted later code
In the line s, out, err=...
, the picker
command is used with the -c
option to enable code coverage.
Set Target Coverage Files (line_coverage_files
Function)
Write the line_coverage_files(cfg) -> list[str]
function as needed, and enable test result processing (doc_result.disable = False
) to ensure it is invoked.
Building the Test Environment
set_line_coverage(request, coverage_file) # Pass the generated code coverage file to toffee-report
Use the toffee-test.set_line_coverage
function to pass the coverage file to Toffee-Test, enabling it to collect data for generating reports with line coverage.
Ignoring Specific Statistics
Sometimes, certain parts of the code may need to be excluded from coverage statistics. For example, some parts may not need to be tested, or it may be normal for certain parts to remain uncovered. Ignoring these parts can help optimize coverage reports or assist in debugging. Our framework supports two methods for ignoring coverage:
1. Using Verilator to Specify Ignored Sections
Using verilator_coverage_off/on
Directives
Verilator supports ignoring specific code sections from coverage statistics using comment directives. For example:
// *verilator coverage_off*
// Code section to ignore
...
// *verilator coverage_on*
Example:
module example;
always @(posedge clk) begin
// *verilator coverage_off*
if (debug_signal) begin
$display("This is for debugging only");
end
// *verilator coverage_on*
if (enable) begin
do_something();
end
end
endmodule
In the above example, the debug_signal
section will not be included in coverage statistics, while the enable
section will still be counted.
For more ways to ignore coverage in Verilator, refer to the Verilator Documentation.
2. Using Toffee to Specify Filters
def set_line_coverage(request, datfile, ignore=[]):
"""Pass
Args:
request (pytest.Request): Pytest's default fixture.
datfile (string): The coverage file generated by the DUT.
ignore (list[str]): Coverage filter files or directories.
"""
The ignore
parameter can specify content to be filtered out from the coverage file. For example:
...
set_line_coverage(request, coverage_file,
get_root_dir("scripts/frontend_ifu_rvc_expander"))
During coverage statistics, the line_coverage.ignore
file in the scripts/frontend_ifu_rvc_expander
directory will be searched, and its wildcard patterns will be used for filtering.
# Line coverage ignore file
# Ignore Top file
*/RVCExpander_top*%
The above file indicates that files containing the keyword RVCExpander_top
will be ignored during coverage statistics (the corresponding data is collected but excluded from the final report).
Viewing Statistics Results
After completing all the steps, including preparing the test environment (Download RTL Code, Compile DUT, Edit Configuration), and adding tests (Add Compilation Scripts, Build Test Environment, Add Test Cases):
Now, Run Tests. Afterward, an HTML version of the test report will be generated in the out/report
directory by default.
You can also view the statistics results by selecting the corresponding test report (named by test time) under “Current Version” in the Progress Overview section and clicking the link on the right.