Additional lcov code coverage.

This commit is contained in:
Wilson Snyder 2019-07-05 22:28:34 -04:00
parent a4b9745e6e
commit 7e54ff1b37
18 changed files with 145 additions and 37 deletions

View File

@ -285,6 +285,7 @@ IData VL_RANDOM_I(int obits) VL_MT_SAFE {
QData VL_RANDOM_Q(int obits) VL_MT_SAFE {
return vl_rand64() & VL_MASK_Q(obits);
}
// VL_RANDOM_W currently unused as $random always 32 bits
WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE {
for (int i=0; i<VL_WORDS_I(obits); ++i) {
if (i<(VL_WORDS_I(obits)-1)) {

View File

@ -318,8 +318,8 @@ public: // But internals only - called from VerilatedModule's
if (VL_LIKELY(funcnum < scopep->m_funcnumMax)) {
// m_callbacksp must be declared, as Max'es are > 0
return scopep->m_callbacksp[funcnum];
} else {
return scopep->exportFindError(funcnum);
} else { // LCOV_EXCL_LINE
return scopep->exportFindError(funcnum); // LCOV_EXCL_LINE
}
}
};

View File

@ -53,6 +53,7 @@ sub test {
if ($Opt_Stage <= 1) {
print "Stage 1: make examples (with coverage on)\n";
run("make examples");
run("make test_regress");
}
my $cc_dir = "nodist/obj_dir/coverage";
@ -68,7 +69,7 @@ sub test {
}
foreach my $dir (sort keys %dirs) {
(my $outname = $dir) =~ s![^a-zA-Z0-9]+!_!g;
run("cd $cc_dir/info ; lcov -c -d ../../../$dir -o app_test_${outname}.info");
run("cd $cc_dir/info ; lcov -c -d ../../../../$dir -o app_test_${outname}.info");
}
}
@ -145,7 +146,7 @@ sub clone_sources {
chomp $line;
if ($line !~ m!// LCOV_EXCL_LINE!
&& $line =~ /$Exclude_Line_Regexp/) {
$line .= " //code_coverage: // LCOV_EXCL_LINE\n";
$line .= " //code_coverage: // LCOV_EXCL_LINE";
$excluded_lines++;
#print "$infile:$lineno: $line";
} else {
@ -164,9 +165,11 @@ sub cleanup_abs_paths {
my $fh = IO::File->new("<$infile") or die "%Error: $! $infile,";
my @lines;
while (defined(my $line = $fh->getline)) {
if ($line =~ m!^SF:/!) {
if ($line =~ m!^SF:!) {
$line =~ s!$ENV{VERILATOR_ROOT}/!!;
$line =~ s!$cc_dir/!!;
$line =~ s!obj_dbg/verilog.y$!verilog.y!;
#print "Remaining SF: ",$line;
}
push @lines, $line;
}

View File

@ -101,7 +101,7 @@ private:
// Move the active's contents to the other active
UINFO(4," merge active "<<sensesp<<" into "<<wantp<<endl);
if (nodep->sensesStorep()) {
if (sensesp != nodep->sensesStorep()) {
if (VL_UNCOVERABLE(sensesp != nodep->sensesStorep())) {
nodep->v3fatalSrc("sensesStore should have been deleted earlier if different");
}
sensesp->unlinkFrBack();

View File

@ -60,7 +60,7 @@ public:
// Called by operator delete on any node - only if VL_LEAK_CHECKS
if (debug()>=9) cout<<"-nodeDel: "<<cvtToHex(nodep)<<endl;
NodeMap::iterator iter = s_nodes.find(nodep);
if (iter==s_nodes.end() || !(iter->second & FLAG_ALLOCATED)) {
if (VL_UNCOVERABLE(iter==s_nodes.end() || !(iter->second & FLAG_ALLOCATED))) {
reinterpret_cast<const AstNode*>(nodep)
->v3fatalSrc("Deleting AstNode object that was never tracked or already deleted");
}
@ -74,7 +74,7 @@ public:
// Called by operator new on any node - only if VL_LEAK_CHECKS
if (debug()>=9) cout<<"-nodeNew: "<<cvtToHex(nodep)<<endl;
NodeMap::iterator iter = s_nodes.find(nodep);
if (iter !=s_nodes.end() && (iter->second & FLAG_ALLOCATED)) {
if (VL_UNCOVERABLE(iter !=s_nodes.end() && (iter->second & FLAG_ALLOCATED))) {
nodep->v3fatalSrc("Newing AstNode object that is already allocated");
}
if (iter == s_nodes.end()) {
@ -96,17 +96,17 @@ public:
if (!linkable) return; // save some time, else the map will get huge!
#endif
NodeMap::iterator iter = s_nodes.find(nodep);
if (iter == s_nodes.end()) {
if (VL_UNCOVERABLE(iter == s_nodes.end())) {
#ifdef VL_LEAK_CHECKS
nodep->v3fatalSrc("AstNode is in tree, but not allocated");
#endif
} else {
if (!(iter->second & FLAG_ALLOCATED)) {
if (VL_UNCOVERABLE(!(iter->second & FLAG_ALLOCATED))) {
#ifdef VL_LEAK_CHECKS
nodep->v3fatalSrc("AstNode is in tree, but not allocated");
#endif
}
if (iter->second & FLAG_IN_TREE) {
if (VL_UNCOVERABLE(iter->second & FLAG_IN_TREE)) {
nodep->v3fatalSrc("AstNode is already in tree at another location");
}
}
@ -230,34 +230,35 @@ public:
class BrokenCheckVisitor : public AstNVisitor {
private:
void checkWidthMin(const AstNode* nodep) {
if (nodep->width() != nodep->widthMin()
&& v3Global.widthMinUsage()==VWidthMinUsage::MATCHES_WIDTH) {
if (VL_UNCOVERABLE(nodep->width() != nodep->widthMin()
&& v3Global.widthMinUsage()==VWidthMinUsage::MATCHES_WIDTH)) {
nodep->v3fatalSrc("Width != WidthMin");
}
}
void processAndIterate(AstNode* nodep) {
BrokenTable::setUnder(nodep, true);
if (const char* whyp=nodep->broken()) {
const char* whyp = nodep->broken();
if (VL_UNCOVERABLE(whyp)) {
nodep->v3fatalSrc("Broken link in node (or something without maybePointedTo): "<<whyp);
}
if (nodep->dtypep()) {
if (!nodep->dtypep()->brokeExists()) {
if (VL_UNCOVERABLE(!nodep->dtypep()->brokeExists())) {
nodep->v3fatalSrc("Broken link in node->dtypep() to "
<<cvtToHex(nodep->dtypep()));
} else if (!VN_IS(nodep->dtypep(), NodeDType)) {
} else if (VL_UNCOVERABLE(!VN_IS(nodep->dtypep(), NodeDType))) {
nodep->v3fatalSrc("Non-dtype link in node->dtypep() to "
<<cvtToHex(nodep->dtypep()));
}
}
if (v3Global.assertDTypesResolved()) {
if (nodep->hasDType()) {
if (!nodep->dtypep()) nodep->v3fatalSrc(
if (VL_UNCOVERABLE(!nodep->dtypep())) nodep->v3fatalSrc(
"No dtype on node with hasDType(): "<<nodep->prettyTypeName());
} else {
if (nodep->dtypep()) nodep->v3fatalSrc(
if (VL_UNCOVERABLE(nodep->dtypep())) nodep->v3fatalSrc(
"DType on node without hasDType(): "<<nodep->prettyTypeName());
}
if (nodep->getChildDTypep()) nodep->v3fatalSrc(
if (VL_UNCOVERABLE(nodep->getChildDTypep())) nodep->v3fatalSrc(
"childDTypep() non-null on node after should have removed");
if (const AstNodeDType* dnodep = VN_CAST(nodep, NodeDType)) checkWidthMin(dnodep);
}
@ -267,10 +268,10 @@ private:
}
virtual void visit(AstNodeAssign* nodep) {
processAndIterate(nodep);
if (v3Global.assertDTypesResolved()
&& nodep->brokeLhsMustBeLvalue()
&& VN_IS(nodep->lhsp(), NodeVarRef)
&& !VN_CAST(nodep->lhsp(), NodeVarRef)->lvalue()) {
if (VL_UNCOVERABLE(v3Global.assertDTypesResolved()
&& nodep->brokeLhsMustBeLvalue()
&& VN_IS(nodep->lhsp(), NodeVarRef)
&& !VN_CAST(nodep->lhsp(), NodeVarRef)->lvalue())) {
nodep->v3fatalSrc("Assignment LHS is not an lvalue");
}
}
@ -291,9 +292,9 @@ public:
void V3Broken::brokenAll(AstNetlist* nodep) {
//UINFO(9,__FUNCTION__<<": "<<endl);
static bool inBroken = false;
if (inBroken) {
if (VL_UNCOVERABLE(inBroken)) {
// A error called by broken can recurse back into broken; avoid this
UINFO(1,"Broken called under broken, skipping recursion.\n");
UINFO(1,"Broken called under broken, skipping recursion.\n"); // LCOV_EXCL_LINE
} else {
inBroken = true;
BrokenTable::prepForTree();

View File

@ -109,7 +109,7 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep,
if (prevp) nrangep->unlinkFrBack();
AstRange* rangep = VN_CAST(nrangep, Range);
if (!rangep) {
if (!VN_IS(nrangep, UnsizedRange)) {
if (VL_UNCOVERABLE(!VN_IS(nrangep, UnsizedRange))) {
nrangep->v3fatalSrc("Expected range or unsized range");
}
arrayp = new AstUnsizedArrayDType

View File

@ -219,7 +219,7 @@ private:
nodeap->bodysp()->unlinkFrBackWithNext()->deleteTree();
nodeap->addStmtp(stmtsp);
if (debug()>=6) nodeap->dumpTree(cout, " table_new: ");
} else {
} else { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Creating table under unknown node type");
}
@ -316,7 +316,7 @@ private:
// Simulate
simvis.mainTableEmulate(nodep);
if (!simvis.optimizable()) {
if (VL_UNCOVERABLE(!simvis.optimizable())) {
simvis.whyNotNodep()->v3fatalSrc("Optimizable cleared, even though earlier test run said not: "
<<simvis.whyNotMessage());
}
@ -348,8 +348,9 @@ private:
}
{ // Set changed table
if (inValue != inValueNextInitArray++)
if (VL_UNCOVERABLE(inValue != inValueNextInitArray++)) {
nodep->v3fatalSrc("InitArray requires us to have the values in inValue order");
}
AstNode* setp = new AstConst(nodep->fileline(), outputChgMask);
VN_CAST(chgVscp->varp()->valuep(), InitArray)->addValuep(setp);
}

View File

@ -227,9 +227,11 @@ private:
subp = newSubNeg(subp, fromRange.lo());
}
}
if (!fromRange.elements() || (adtypep->width() % fromRange.elements())!=0)
if (VL_UNCOVERABLE(!fromRange.elements()
|| (adtypep->width() % fromRange.elements())!=0)) {
adtypep->v3fatalSrc("Array extraction with width miscomputed "
<<adtypep->width()<<"/"<<fromRange.elements());
}
int elwidth = adtypep->width() / fromRange.elements();
AstSel* newp
= new AstSel(nodep->fileline(),
@ -316,9 +318,11 @@ private:
else if (AstPackArrayDType* adtypep = VN_CAST(ddtypep, PackArrayDType)) {
// SELEXTRACT(array, msb, lsb) -> SEL(array,
// lsb*width-of-subindex, width-of-subindex*(msb-lsb))
if (!fromRange.elements() || (adtypep->width() % fromRange.elements())!=0)
if (VL_UNCOVERABLE(!fromRange.elements()
|| (adtypep->width() % fromRange.elements())!=0)) {
adtypep->v3fatalSrc("Array extraction with width miscomputed "
<<adtypep->width()<<"/"<<fromRange.elements());
}
if (fromRange.littleEndian()) {
// Below code assumes big bit endian; just works out if we swap
int x = msb; msb = lsb; lsb = x;
@ -478,7 +482,7 @@ private:
//--------------------
// Default
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) { // LCOV_EXCL_LINE
// See notes above; we never iterate
nodep->v3fatalSrc("Shouldn't iterate in V3WidthSel");
}

View File

@ -76,9 +76,9 @@ public:
cout<<" Covered, Rank, RankPts, Filename"<<endl;
}
void dump(bool bucketsToo) {
if (testrun() || computrons()!=0.0) {
cout<<" "<<std::setw(8)<<std::setfill('0')<<testrun()
<<", "<<std::setw(7)<<std::setfill(' ')<<computrons()<<",";
if (testrun() || computrons()!=0.0) { // currently unused // LCOV_EXCL_LINE
cout<<" "<<std::setw(8)<<std::setfill('0')<<testrun() // LCOV_EXCL_LINE
<<", "<<std::setw(7)<<std::setfill(' ')<<computrons()<<","; // LCOV_EXCL_LINE
}
cout<<" "<<std::setw(7)<<std::setfill(' ')<<bucketsCovered()
<<", "<<std::setw(7)<<std::setfill(' ')<<rank()

View File

@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
scenarios(vlt_all => 1);
compile(
v_flags2 => ["--debugi 9"],
v_flags2 => ["--debug --debugi 9"],
tee => 0,
verilator_make_gcc => 0,
make_top_shell => 0,

View File

@ -3,7 +3,18 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2008 by Wilson Snyder.
module t;
module t (/*AUTOARG*/
// Outputs
o,
// Inputs
i
);
// Need some logic to get mtask debug fully covered
input i;
output wire o;
assign o = i;
initial begin
$write("*-* All Finished *-*\n");
$finish;

View File

@ -0,0 +1,3 @@
Intentional stop
%Error: t/t_stop_bad.v:9: Verilog $stop
Aborting...

23
test_regress/t/t_stop_bad.pl Executable file
View File

@ -0,0 +1,23 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 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.
scenarios(simulator => 1);
compile(
);
execute(
fails => 1,
check_finished => 0,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,11 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2019 by Wilson Snyder.
module t;
initial begin
$write("Intentional stop\n");
$stop;
end
endmodule

View File

@ -22,6 +22,8 @@ module t;
if (i!==0) $stop;
i = $system("exit 10");
if (i!==10) $stop;
i = $system("exit 20"); // Wide
if (i!==20) $stop;
`endif
$write("*-* All Finished *-*\n");

View File

@ -0,0 +1,26 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2009 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.
scenarios(dist => 1);
foreach my $basename ("t_vlcov_data_a.dat",
"t_vlcov_data_b.dat",
"t_vlcov_data_c.dat",
"t_vlcov_data_d.dat",
) {
run(cmd => ["../bin/verilator_coverage",
"t/${basename}",
"--debugi 9",
],
tee => $Self->{verbose},
);
}
ok(1);
1;

View File

@ -0,0 +1,2 @@
%Error: Can't read t/t_NOT_FOUND
%Error: Command Failed

View File

@ -0,0 +1,20 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2009 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.
scenarios(dist => 1);
run(fails => 1,
cmd => ["../bin/verilator_coverage",
"t/t_NOT_FOUND",],
logfile => $Self->{run_log_filename},
expect_filename => $Self->{golden_filename},
);
ok(1);
1;