diff --git a/test_regress/t/t_cover_branch_option.info.out b/test_regress/t/t_cover_branch_option.info.out new file mode 100644 index 000000000..45d5b4627 --- /dev/null +++ b/test_regress/t/t_cover_branch_option.info.out @@ -0,0 +1,127 @@ +TN:verilator_coverage +SF:t/t_cover_line.v +DA:56,10 +BRDA:56,0,0,10 +BRDA:56,0,1,0 +DA:57,10 +DA:58,10 +DA:60,9 +BRDA:60,0,0,1 +BRDA:60,0,1,9 +DA:61,9 +BRDA:61,0,0,1 +BRDA:61,0,1,9 +DA:62,1 +DA:63,1 +DA:66,9 +BRDA:66,0,0,1 +BRDA:66,0,1,9 +DA:67,9 +BRDA:67,0,0,1 +BRDA:67,0,1,9 +DA:69,9 +DA:70,9 +DA:73,9 +BRDA:73,0,0,1 +BRDA:73,0,1,9 +DA:74,9 +BRDA:74,0,0,1 +BRDA:74,0,1,9 +DA:75,1 +DA:76,1 +DA:79,9 +DA:80,9 +DA:105,10 +DA:106,10 +DA:120,7 +BRDA:120,0,0,1 +BRDA:120,0,1,7 +DA:121,1 +DA:122,1 +DA:141,18 +BRDA:141,0,0,2 +BRDA:141,0,1,18 +DA:142,2 +DA:166,20 +BRDA:166,0,0,0 +BRDA:166,0,1,20 +DA:168,0 +DA:170,18 +BRDA:170,0,0,2 +BRDA:170,0,1,18 +DA:172,2 +DA:190,1 +BRDA:190,0,0,1 +BRDA:190,0,1,0 +DA:191,1 +DA:195,11 +BRDA:195,0,0,11 +BRDA:195,0,1,0 +DA:196,11 +DA:200,11 +BRDA:200,0,0,11 +BRDA:200,0,1,0 +DA:201,11 +DA:222,10 +BRDA:222,0,0,1 +BRDA:222,0,1,10 +DA:223,1 +DA:225,10 +BRDA:225,0,0,1 +BRDA:225,0,1,10 +DA:226,1 +DA:253,9 +BRDA:253,0,0,1 +BRDA:253,0,1,9 +DA:255,1 +DA:256,1 +BRDA:256,0,0,0 +BRDA:256,0,1,1 +DA:288,0 +BRDA:288,0,0,0 +BRDA:288,0,1,0 +DA:289,0 +DA:291,0 +DA:292,0 +DA:327,31 +BRDA:327,0,0,0 +BRDA:327,0,1,31 +DA:328,28 +BRDA:328,0,0,3 +BRDA:328,0,1,28 +DA:329,21 +BRDA:329,0,0,21 +BRDA:329,0,1,0 +DA:331,7 +BRDA:331,0,0,3 +BRDA:331,0,1,7 +DA:332,10 +BRDA:332,0,0,0 +BRDA:332,0,1,10 +DA:334,19 +BRDA:334,0,0,12 +BRDA:334,0,1,19 +BRDA:334,0,2,7 +BRDA:334,0,3,5 +DA:337,11 +BRDA:337,0,0,11 +BRDA:337,0,1,0 +DA:343,11 +BRDA:343,0,0,10 +BRDA:343,0,1,11 +DA:347,10 +BRDA:347,0,0,0 +BRDA:347,0,1,1 +BRDA:347,0,2,1 +BRDA:347,0,3,10 +DA:348,10 +DA:350,10 +BRDA:350,0,0,1 +BRDA:350,0,1,10 +DA:360,11 +BRDA:360,0,0,0 +BRDA:360,0,1,11 +DA:361,11 +BRF:64 +BRH:20 +end_of_record diff --git a/test_regress/t/t_cover_branch_option.out b/test_regress/t/t_cover_branch_option.out new file mode 100644 index 000000000..167e21908 --- /dev/null +++ b/test_regress/t/t_cover_branch_option.out @@ -0,0 +1,457 @@ +// // verilator_coverage annotation + // DESCRIPTION: Verilator: Verilog Test module + // + // This file ONLY is placed under the Creative Commons Public Domain, for + // any use, without warranty, 2008 by Wilson Snyder. + // SPDX-License-Identifier: CC0-1.0 + + module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + reg toggle; + initial toggle=0; + + integer cyc; + initial cyc=1; + + wire [7:0] cyc_copy = cyc[7:0]; + + alpha a1 (/*AUTOINST*/ + // Inputs + .clk (clk), + .toggle (toggle)); + alpha a2 (/*AUTOINST*/ + // Inputs + .clk (clk), + .toggle (toggle)); + beta b1 (/*AUTOINST*/ + // Inputs + .clk (clk), + .toggle (toggle)); + beta b2 (/*AUTOINST*/ + // Inputs + .clk (clk), + .toggle (toggle)); + tsk t1 (/*AUTOINST*/ + // Inputs + .clk (clk), + .toggle (toggle)); + off o1 (/*AUTOINST*/ + // Inputs + .clk (clk), + .toggle (toggle)); + tab tab1 (/*AUTOINST*/ + // Inputs + .clk (clk)); + par par1 (/*AUTOINST*/); + cond cond1 (/*AUTOINST*/ + // Inputs + .clk (clk), + .cyc (cyc)); + + always @ (posedge clk) begin +~000010 if (cyc!=0) begin ++000010 point: comment=if hier=top.t +-000000 point: comment=else hier=top.t + 000010 cyc <= cyc + 1; ++000010 point: comment=if hier=top.t + 000010 toggle <= '0; ++000010 point: comment=if hier=top.t + // Single and multiline if +%000009 if (cyc==3) $write(""); +-000001 point: comment=if hier=top.t +-000009 point: comment=else hier=top.t +%000009 if (cyc==3) +-000001 point: comment=if hier=top.t +-000009 point: comment=else hier=top.t +%000001 begin +-000001 point: comment=if hier=top.t +%000001 $write(""); +-000001 point: comment=if hier=top.t + end + // Single and multiline else +%000009 if (cyc==3) ; else $write(""); +-000001 point: comment=if hier=top.t +-000009 point: comment=else hier=top.t +%000009 if (cyc==3) ; +-000001 point: comment=if hier=top.t +-000009 point: comment=else hier=top.t + else +%000009 begin +-000009 point: comment=else hier=top.t +%000009 $write(""); +-000009 point: comment=else hier=top.t + end + // Single and multiline if else +%000009 if (cyc==3) $write(""); else $write(""); +-000001 point: comment=if hier=top.t +-000009 point: comment=else hier=top.t +%000009 if (cyc==3) +-000001 point: comment=if hier=top.t +-000009 point: comment=else hier=top.t +%000001 begin +-000001 point: comment=if hier=top.t +%000001 $write(""); +-000001 point: comment=if hier=top.t + end + else +%000009 begin +-000009 point: comment=else hier=top.t +%000009 $write(""); +-000009 point: comment=else hier=top.t + end + // multiline elseif + if (cyc==3) + begin + $write(""); + end + else if (cyc==4) + begin + $write(""); + end + else if (cyc==5) + begin + $write(""); + end + else + begin + $write(""); + end + // Single and multiline while + while (0); + while (0) begin + $write(""); + end + do ; while (0); + 000010 do begin ++000010 point: comment=if hier=top.t + 000010 $write(""); ++000010 point: comment=if hier=top.t + end while (0); + //=== + // Task and complicated + if (cyc==3) begin + toggle <= '1; + end + else if (cyc==5) begin + `ifdef VERILATOR + $c("this->call_task();"); + `else + call_task(); + `endif + end +%000007 else if (cyc==10) begin +-000001 point: comment=if hier=top.t +-000007 point: comment=else hier=top.t +%000001 $write("*-* All Finished *-*\n"); +-000001 point: comment=if hier=top.t +%000001 $finish; +-000001 point: comment=if hier=top.t + end + end + end + + task call_task; + /* verilator public */ + t1.center_task(1'b1); + endtask + + endmodule + + module alpha (/*AUTOARG*/ + // Inputs + clk, toggle + ); + input clk; + input toggle; + always @ (posedge clk) begin +~000018 if (toggle) begin // CHECK_COVER(0,"top.t.a*",18) +-000002 point: comment=if hier=top.t.a* ++000018 point: comment=else hier=top.t.a* +%000002 $write(""); +-000002 point: comment=if hier=top.t.a* + // t.a1 and t.a2 collapse to a count of 2 + end + if (toggle) begin // *** t_cover_line.vlt turns this off + $write(""); // CHECK_COVER_MISSING(0) + // This doesn't even get added + `ifdef ATTRIBUTE + // verilator coverage_block_off + `endif + end + end + endmodule + + module beta (/*AUTOARG*/ + // Inputs + clk, toggle + ); + input clk; + input toggle; + + /* verilator public_module */ + + always @ (posedge clk) begin + $write(""); // Always covered +~000020 if (0) begin // CHECK_COVER(0,"top.t.b*",0) +-000000 point: comment=if hier=top.t.b* ++000020 point: comment=else hier=top.t.b* + // Make sure that we don't optimize away zero buckets +%000000 $write(""); +-000000 point: comment=if hier=top.t.b* + end +~000018 if (toggle) begin // CHECK_COVER(0,"top.t.b*",2) +-000002 point: comment=if hier=top.t.b* ++000018 point: comment=else hier=top.t.b* + // t.b1 and t.b2 collapse to a count of 2 +%000002 $write(""); +-000002 point: comment=if hier=top.t.b* + end + if (toggle) begin : block + // This doesn't + `ifdef ATTRIBUTE + // verilator coverage_block_off + `endif + begin end // *** t_cover_line.vlt turns this off (so need begin/end) + if (1) begin end // CHECK_COVER_MISSING(0) + $write(""); // CHECK_COVER_MISSING(0) + end + end + endmodule + + class Cls; + bit m_toggle; + function new(bit toggle); + m_toggle = toggle; +%000001 if (m_toggle) begin // CHECK_COVER(0,"top.$unit::Cls",1) +-000001 point: comment=if hier=top.$unit::Cls__Vclpkg +-000000 point: comment=else hier=top.$unit::Cls__Vclpkg +%000001 $write(""); +-000001 point: comment=if hier=top.$unit::Cls__Vclpkg + end + endfunction + static function void fstatic(bit toggle); +~000011 if (1) begin // CHECK_COVER(0,"top.$unit::Cls",1) ++000011 point: comment=if hier=top.$unit::Cls__Vclpkg +-000000 point: comment=else hier=top.$unit::Cls__Vclpkg + 000011 $write(""); ++000011 point: comment=if hier=top.$unit::Cls__Vclpkg + end + endfunction + function void fauto(); +~000011 if (m_toggle) begin // CHECK_COVER(0,"top.$unit::Cls",11) ++000011 point: comment=if hier=top.$unit::Cls__Vclpkg +-000000 point: comment=else hier=top.$unit::Cls__Vclpkg + 000011 $write(""); ++000011 point: comment=if hier=top.$unit::Cls__Vclpkg + end + endfunction + endclass + + module tsk (/*AUTOARG*/ + // Inputs + clk, toggle + ); + input clk; + input toggle; + + /* verilator public_module */ + + always @ (posedge clk) begin + center_task(1'b0); + end + + task center_task; + input external; + begin +~000010 if (toggle) begin // CHECK_COVER(0,"top.t.t1",1) +-000001 point: comment=if hier=top.t.t1 ++000010 point: comment=else hier=top.t.t1 +%000001 $write(""); +-000001 point: comment=if hier=top.t.t1 + end +~000010 if (external) begin // CHECK_COVER(0,"top.t.t1",1) +-000001 point: comment=if hier=top.t.t1 ++000010 point: comment=else hier=top.t.t1 +%000001 $write("[%0t] Got external pulse\n", $time); +-000001 point: comment=if hier=top.t.t1 + end + end + begin + Cls c = new(1'b1); + c.fauto(); + Cls::fstatic(1'b1); + end + endtask + endmodule + + module off (/*AUTOARG*/ + // Inputs + clk, toggle + ); + input clk; + input toggle; + + // verilator coverage_off + always @ (posedge clk) begin + if (toggle) begin + $write(""); // CHECK_COVER_MISSING(0) + // because under coverage_module_off + end + end + // verilator coverage_on + always @ (posedge clk) begin +%000009 if (toggle) begin +-000001 point: comment=if hier=top.t.o1 +-000009 point: comment=else hier=top.t.o1 + // because under coverage_module_off +%000001 $write(""); +-000001 point: comment=if hier=top.t.o1 +%000001 if (0) ; // CHECK_COVER(0,"top.t.o1",1) +-000000 point: comment=if hier=top.t.o1 +-000001 point: comment=else hier=top.t.o1 + end + end + endmodule + + module tab (input clk); + bit [3:0] cyc4; + int decoded; + + always @ (posedge clk) begin + case (cyc4) + 1: decoded = 10; + 2: decoded = 20; + 3: decoded = 30; + 4: decoded = 40; + 5: decoded = 50; + default: decoded = 0; + endcase + end + + always @ (posedge clk) begin + cyc4 <= cyc4 + 1; + end + endmodule + + module par(); + localparam int CALLS_FUNC = param_func(1); + + // We don't currently count elaboration time use towards coverage. This + // seems safer for functions used both at elaboration time and not - but may + // revisit this. + function automatic int param_func(int i); +%000000 if (i == 0) begin +-000000 point: comment=if hier=top.t.par1 +-000000 point: comment=else hier=top.t.par1 +%000000 i = 99; // Uncovered +-000000 point: comment=if hier=top.t.par1 + end +%000000 else begin +-000000 point: comment=else hier=top.t.par1 +%000000 i = i + 1; +-000000 point: comment=else hier=top.t.par1 + end + return i; + endfunction + + endmodule + + package my_pkg; + int x = 1 ? 1 : 0; + endpackage + + class Getter1; + function int get_1; + return 1; + endfunction + endclass + + module cond(input logic clk, input int cyc); + logic a, b, c, d, e, f, g, h, k, l, m; + logic [5:0] tab; + typedef logic [7:0] arr_t[1:0]; + arr_t data[1:0]; + Getter1 getter1 = new; + string s; + + function logic func_side_effect; + $display("SIDE EFFECT"); + return 1; + endfunction + + function arr_t get_arr; + arr_t arr; + return arr; + endfunction + +~000031 assign a = (cyc == 0) ? clk : 1'bz; +-000000 point: comment=cond_then hier=top.t.cond1 ++000031 point: comment=cond_else hier=top.t.cond1 +~000028 assign b = (cyc == 1) ? clk : 0; +-000003 point: comment=cond_then hier=top.t.cond1 ++000028 point: comment=cond_else hier=top.t.cond1 +~000021 assign c = func_side_effect() ? clk : 0; ++000021 point: comment=cond_then hier=top.t.cond1 +-000000 point: comment=cond_else hier=top.t.cond1 + always @(posedge clk) begin +%000007 d = (cyc % 3 == 0) ? 1 : 0; +-000003 point: comment=cond_then hier=top.t.cond1 +-000007 point: comment=cond_else hier=top.t.cond1 +~000010 s = (getter1.get_1() == 0) ? "abcd" : $sformatf("%d", getter1.get_1()[4:0]); +-000000 point: comment=cond_then hier=top.t.cond1 ++000010 point: comment=cond_else hier=top.t.cond1 + end +~000019 assign e = (cyc % 3 == 1) ? (clk ? 1 : 0) : 1; ++000012 point: comment=cond_then hier=top.t.cond1 ++000019 point: comment=cond_else hier=top.t.cond1 +-000007 point: comment=cond_then hier=top.t.cond1 +-000005 point: comment=cond_else hier=top.t.cond1 + + // ternary operator in condition shouldn't be included to the coverae +~000011 assign f = (cyc != 0 ? 1 : 0) ? 1 : 0; ++000011 point: comment=cond_then hier=top.t.cond1 +-000000 point: comment=cond_else hier=top.t.cond1 + // the same as in index + assign tab[clk ? 1 : 0] = 1; + assign m = tab[clk ? 3 : 4]; + + for (genvar i = 0; i < 2; i++) begin + 000011 assign g = clk ? 1 : 0; ++000010 point: comment=cond_then hier=top.t.cond1 ++000011 point: comment=cond_else hier=top.t.cond1 + end + + always begin +~000010 if (cyc == 5) h = cyc > 5 ? 1 : 0; +-000000 point: comment=cond_then hier=top.t.cond1 +-000001 point: comment=cond_else hier=top.t.cond1 +-000001 point: comment=if hier=top.t.cond1 ++000010 point: comment=else hier=top.t.cond1 + 000010 else h = 1; ++000010 point: comment=else hier=top.t.cond1 + +~000010 data[0] = (cyc == 2) ? '{8'h01, 8'h02} : get_arr(); +-000001 point: comment=cond_then hier=top.t.cond1 ++000010 point: comment=cond_else hier=top.t.cond1 + + // ternary operator in conditions should be skipped + for (int i = 0; (i < 5) ? 1 : 0; i++) begin + k = 1'(i); + end + for (int i = 0; i < 7; i = (i > 4) ? i + 1 : i + 2) begin + k = 1'(i); + end + +~000011 if (k ? 1 : 0) k = 1; +-000000 point: comment=if hier=top.t.cond1 ++000011 point: comment=else hier=top.t.cond1 + 000011 else k = 0; ++000011 point: comment=else hier=top.t.cond1 + end + endmodule + diff --git a/test_regress/t/t_cover_branch_option.py b/test_regress/t/t_cover_branch_option.py new file mode 100755 index 000000000..a699cf538 --- /dev/null +++ b/test_regress/t/t_cover_branch_option.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') +test.top_filename = "t/t_cover_line.v" +test.golden_filename = "t/t_cover_branch_option.out" + +test.compile(verilator_flags2=['--cc --coverage +define+ATTRIBUTE']) + +test.execute() + +test.run(cmd=[os.environ["VERILATOR_ROOT"] + "/bin/verilator_coverage", + "--annotate-points", + "--annotate", test.obj_dir + "/annotated", + "--filter-type branch", + test.obj_dir + "/coverage.dat"], + verilator_run=True) # yapf:disable + +test.files_identical(test.obj_dir + "/annotated/t_cover_line.v", test.golden_filename) + +# Also try lcov +test.run(cmd=[os.environ["VERILATOR_ROOT"] + "/bin/verilator_coverage", + "--write-info", test.obj_dir + "/coverage.info", + "--filter-type branch", + test.obj_dir + "/coverage.dat"], + verilator_run=True) # yapf:disable + +test.files_identical(test.obj_dir + "/coverage.info", "t/" + test.name + ".info.out") + +# If installed +nout = test.run_capture("lcov --version", check=False) +version_match = re.search(r'version ([0-9.]+)', nout, re.IGNORECASE) +if not version_match: + test.skip("lcov or genhtml not installed") + +if float(version_match.group(1)) < 1.14: + test.skip("lcov or genhtml too old (version " + version_match.group(1) + + ", need version >= 1.14") + +test.run(cmd=[ + "genhtml", test.obj_dir + "/coverage.info", "--branch-coverage", "--output-directory " + + test.obj_dir + "/html" +]) + +test.passes()