New verilator_coverage and infrastructure to replace SystemPerl's vcoverage.

This commit is contained in:
Wilson Snyder 2014-11-23 21:06:10 -05:00
parent 6da13c6486
commit 9ec35a2348
40 changed files with 2737 additions and 61 deletions

1
.gitignore vendored
View File

@ -23,3 +23,4 @@ gdbrun*
internals.txt
verilator.txt
verilator_bin*
verilator_coverage_bin*

View File

@ -5,6 +5,8 @@ indicates the contributor was also the author of the fix; Thanks!
* Verilator 3.867 devel
** New verilator_coverage program added to replace SystemPerl's vcoverage.
** PSL support was removed, please use System Verilog assertions.

View File

@ -28,6 +28,7 @@ config.status$
verilator.log
verilator.tex
verilator_bin.*
verilator_coverage_bin.*
.vcsmx_rebuild$
autom4te\.cache/
nodist/

View File

@ -122,6 +122,7 @@ DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING COPYING.LESSER \
.*attributes */.*attributes */*/.*attributes \
src/.*ignore src/*.in src/*.cpp src/*.[chly] \
src/astgen src/bisonpre src/*fix src/cppcheck_filtered \
src/vlcovgen \
src/.gdbinit \
src/*.pl src/*.pod \
test_*/.*ignore test_*/Makefile* test_*/*.cpp \
@ -140,6 +141,7 @@ DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING COPYING.LESSER \
INST_PROJ_FILES = \
bin/verilator \
bin/verilator_coverage \
bin/verilator_includer \
bin/verilator_profcfunc \
include/verilated.mk \
@ -149,6 +151,7 @@ INST_PROJ_FILES = \
INST_PROJ_BIN_FILES = \
verilator_bin \
verilator_bin_dbg \
verilator_coverage_bin_dbg \
DISTFILES := $(DISTFILES_INC)
@ -165,7 +168,8 @@ all_nomsg: verilator_exe $(VL_INST_MAN_FILES)
.PHONY:verilator_exe
.PHONY:verilator_bin
.PHONY:verilator_bin_dbg
verilator_exe verilator_bin verilator_bin_dbg:
.PHONY:verilator_coverage_bin_dbg
verilator_exe verilator_bin verilator_bin_dbg verilator_coverage_bin_dbg:
@echo ------------------------------------------------------------
@echo "making verilator in src" ; \
(cd src && $(MAKE) $(OBJCACHE_JOBS) )
@ -261,8 +265,8 @@ internals.pdf: internals.pod Makefile
-rm -f internals.toc internals.aux internals.idx internals.out
# See uninstall also - don't put wildcards in this variable, it might uninstall other stuff
VL_INST_BIN_FILES = verilator verilator_bin verilator_bin_dbg \
verilator_includer verilator_profcfunc
VL_INST_BIN_FILES = verilator verilator_bin verilator_bin_dbg verilator_coverage_bin_dbg \
verilator_coverage verilator_includer verilator_profcfunc
# Some scripts go into both the search path and pkgdatadir,
# so they can be found by the user, and under $VERILATOR_ROOT.
@ -286,9 +290,11 @@ VL_INST_DATA_SRCDIR_FILES = \
installbin:
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(bindir)
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator $(DESTDIR)$(bindir)/verilator )
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_coverage $(DESTDIR)$(bindir)/verilator_coverage )
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_profcfunc $(DESTDIR)$(bindir)/verilator_profcfunc )
( $(INSTALL_PROGRAM) verilator_bin $(DESTDIR)$(bindir)/verilator_bin )
( $(INSTALL_PROGRAM) verilator_bin_dbg $(DESTDIR)$(bindir)/verilator_bin_dbg )
( $(INSTALL_PROGRAM) verilator_coverage_bin_dbg $(DESTDIR)$(bindir)/verilator_coverage_bin_dbg )
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/bin
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_includer $(DESTDIR)$(pkgdatadir)/bin/verilator_includer )
@ -351,6 +357,7 @@ INST_PROJ_CVS = cp_if_cvs_diff
install-project: dist
@echo "Install-project to $(DIRPROJECT)"
strip verilator_bin*
strip verilator_coverage_bin*
$(MAKE) install-project-quick
for p in $(VL_INST_MAN_FILES) ; do \
$(INSTALL_DATA) $$p $(DIRPROJECT_PREFIX)/man/man1/$$p; \
@ -374,6 +381,7 @@ endif
install-cadtools: dist
@echo "Install-project to $(CAD_DIR)"
strip verilator_bin*
strip verilator_coverage_bin*
$(MAKE) install-cadtools-quick
$(SHELL) ${srcdir}/mkinstalldirs $(VERILATOR_CAD_DIR)/man/man1
for p in $(VL_INST_MAN_FILES) ; do \
@ -459,7 +467,8 @@ clean mostlyclean distclean maintainer-clean::
rm -f *.tex
distclean maintainer-clean::
rm -f Makefile config.status config.cache config.log verilator_bin* TAGS
rm -f Makefile config.status config.cache config.log TAGS
rm -f verilator_bin* verilator_coverage_bin*
rm -f include/verilated.mk include/verilated_config.h
TAGFILES=${srcdir}/*/*.cpp ${srcdir}/*/*.h ${srcdir}/*/*.in \

17
TODO
View File

@ -30,23 +30,6 @@ Configure/Make/Install
* Full MSVC++ compilation (does scons support this?) (4.000?)
* Distribute with flex/bison already expanded?
Flex library not needed. Probably too difficult to be worth it.
* Integrate SystemPerl coverage
see the SystemPerl git branch coverage_only
(Note in /usr/include there are no upper cased include files.)
Coverage.pm -- Need all functionality, but in C?
Coverage/Item.pm -- Need all functionality, but in C?
Coverage/ItemKey.pm -- Need all functionality, but in C?
sp_preproc -- Some steps in here need to be moved to generated C
-- -- note uses Verilog::Getopt
src/Sp.cpp -- n/a
src/SpCommon.h -- mostly overlaps verilatedos.h
src/SpCoverage.cpp/h -- All needed
src/SpFunctor.cpp/h -- No longer used
src/SpTraceVcd.cpp/h -- MOVED
src/SpTraceVcdC.cpp/h -- MOVED
src/sp_log.cpp/h -- Not needed
src/systemperl.h -- some stuff may be cut
vcoverage -- Need all functionality, but in C?
Testing:
* Move test_c/sp/v/verilated into test_regress format (4.000?)

View File

@ -3528,9 +3528,9 @@ Verilator's, it will do this for you.)
Run your tests in different directories. Each test will create a
logs/coverage.pl file.
After running all of your tests, the vcoverage utility (from the SystemPerl
package) is executed. Vcoverage reads the logs/coverage.pl file(s), and
creates an annotated source code listing showing code coverage details.
After running all of your tests, verilator_coverage is executed.
Verilator_coverage reads the logs/coverage.pl file(s), and creates an
annotated source code listing showing code coverage details.
For an example, after running 'make test' in the Verilator distribution,
see the test_sp/logs/coverage_source directory. Grep for lines starting
@ -3825,7 +3825,7 @@ Major concepts by Paul Wasson and Duane Galbi.
=head1 SEE ALSO
L<verilator_profcfunc>, L<systemperl>, L<vcoverage>, L<make>,
L<verilator_coverage>, L<verilator_profcfunc>, L<make>,
L<verilator --help> which is the source for this document,

290
bin/verilator_coverage Executable file
View File

@ -0,0 +1,290 @@
: # -*-Mode: perl;-*- use perl, wherever it is
eval 'exec perl -wS $0 ${1+"$@"}'
if 0;
######################################################################
#
# Copyright 2003-2014 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
######################################################################
require 5.006_001;
use warnings;
BEGIN {
if ($ENV{DIRPROJECT} && $ENV{DIRPROJECT_PERL_BOOT}) {
# Magic to allow author testing of perl packages in local directory
require $ENV{DIRPROJECT}."/".$ENV{DIRPROJECT_PERL_BOOT};
}
}
use Getopt::Long;
use FindBin qw($RealBin $RealScript);
use Pod::Usage;
use Cwd qw(abs_path getcwd);
use strict;
use vars qw ($Debug @Opt_Verilator_Sw);
#######################################################################
#######################################################################
# main
autoflush STDOUT 1;
autoflush STDERR 1;
$Debug = 0;
# No arguments can't do anything useful. Give help
if ($#ARGV < 0) {
pod2usage(-exitstatus=>2, -verbose=>0);
}
# We sneak a look at the flags so we can do some pre-environment checks
# All flags will hit verilator...
foreach my $sw (@ARGV) {
$sw = "'$sw'" if $sw =~ m![^---a-zA-Z0-9_/\\:.+]!;
push @Opt_Verilator_Sw, $sw;
}
Getopt::Long::config ("no_auto_abbrev","pass_through");
if (! GetOptions (
# Major operating modes
"help" => \&usage,
"debug:s" => \&debug,
# "version!" => \&version, # Also passthru'ed
# Additional parameters
"<>" => sub {}, # Ignored
)) {
pod2usage(-exitstatus=>2, -verbose=>0);
}
# Normal, non gdb
run (verilator_coverage_bin()
." ".join(' ',@Opt_Verilator_Sw));
#----------------------------------------------------------------------
sub usage {
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
}
sub debug {
shift;
my $level = shift;
$Debug = $level||3;
}
#######################################################################
#######################################################################
# Builds
sub verilator_coverage_bin {
my $bin = "";
# Use VERILATOR_ROOT if defined, else assume verilator_bin is in the search path
my $basename = ($ENV{VERILATOR_COVERAGE_BIN}
|| "verilator_coverage_bin_dbg");
if (defined($ENV{VERILATOR_ROOT})) {
my $dir = $ENV{VERILATOR_ROOT};
if (-x "$dir/bin/$basename") { # From a "make install" into VERILATOR_ROOT
$bin = "$dir/bin/$basename";
} else {
$bin = "$dir/$basename"; # From pointing to kit directory
}
} else {
if (-x "$RealBin/$basename") {
$bin = "$RealBin/$basename"; # From path/to/verilator with verilator_bin installed
} else {
$bin = $basename; # Find in PATH
}
# Note we don't look under bin/$basename which would be right if running
# in the kit dir. Running that would likely break, since
# VERILATOR_ROOT wouldn't be set and Verilator won't find internal files.
}
return $bin;
}
#######################################################################
#######################################################################
# Utilities
sub run {
# Run command, check errors
my $command = shift;
$! = undef; # Cleanup -x
print "\t$command\n" if $Debug>=3;
system($command);
my $status = $?;
if ($status) {
if ($! =~ /no such file or directory/i) {
warn "%Error: verilator_coverage: Misinstalled, or VERILATOR_ROOT might need to be in environment\n";
}
if ($Debug) { # For easy rerunning
warn "%Error: export VERILATOR_ROOT=".($ENV{VERILATOR_ROOT}||"")."\n";
warn "%Error: $command\n";
}
if ($status & 127) {
if (($status & 127) == 8 || ($status & 127) == 11) { # SIGFPA or SIGSEGV
warn "%Error: Verilator_coverage internal fault, sorry.\n" if !$Debug;
} elsif (($status & 127) == 6) { # SIGABRT
warn "%Error: Verilator_coverage aborted.\n" if !$Debug;
} else {
warn "%Error: Verilator_coverage threw signal $status.\n" if !$Debug;
}
}
die "%Error: Command Failed $command\n";
}
}
#######################################################################
#######################################################################
package main;
__END__
=pod
=head1 NAME
verilator_coverage - Verilator coverage analyzer
=head1 SYNOPSIS
verilator_coverage --help
verilator_coverage --version
verilator_coverage --annotate <obj>
verilator_coverage -write merged.dat -read <datafiles>...
Verilator_coverage processes Verilator coverage reports.
With --anotate, it reads the specified data file and generates annotated
source code with coverage metrics annotated. If multiple coverage points
exist on the same line, additional lines will be inserted to report the
additional points.
Additional Verilog-standard arguments specify the search paths necessary to
find the source code that the coverage analysis was performed on.
To get correct coverage percentages, you may wish to read logs/coverage.pl
into Emacs and do a M-x keep-lines to include only those statistics of
interest.
For Verilog conditions that should never occur, you should add a $stop
statement. This will remove the coverage during the next build.
=head1 ARGUMENTS
=over 4
=item I<filename>
Specify input data file, may be repeated to read multiple inputs. If no
data file is specified, by default coverage.dat is read.
=item --annotate I<output_directory>
Sprcifies the directory name that source files with annotated coverage data
should be written to.
=item --annotate-all
Specifies all files should be shown. By default, only those source files
which have low coverage are written to the output directory.
=item --annotate-min I<count>
Specifies the minimum occurrence count that should be flagged if the
coverage point does not include a specified threshold. Defaults to 10.
=item --help
Displays this message and program version and exits.
=item --rank
Print an experimental report listing the relative importance of each test
in covering all of the coverage points. The report shows "Covered" which
indicates the number of points that test covers; a test is considered to
cover a point if it has a bucket count of at least 1. The "rank" column has
a higher number t indicate the test is more important, and rank 0 means the
test does not need to be run to cover the points. "RankPts" indicates the
number of coverage points this test will contribute to overall coverage if
all tests are run in the order of highest to lowest rank.
=item --unlink
When using --write to combine coverage data, unlink all input files after
the output has been created.
=item --version
Displays program version and exits.
=item --write I<filename>
Specifies the aggregate coverage results, summed across all the files,
should be written to the given filename. This is useful in scripts to
combine many sequential runs into one master coverage file.
=back
=head1 VERILOG ARGUMENTS
The following arguments are compatible with GCC, VCS and most Verilog
programs.
=over 4
=item +libext+I<ext>+I<ext>...
Defines the extensions for Verilog files.
=item +define+I<var>+I<value>
=item -DI<var>=I<value>
Defines the given variable.
=item +incdir+I<dir>
=item -II<dir>
Specifies a directory for finding include files.
=item -f I<file>
Specifies a file containing additional command line arguments.
=item -y I<dir>
Specifies a module search directory.
=back
=head1 DISTRIBUTION
The latest version is available from L<http://www.veripool.org/>.
Copyright 2003-2014 by Wilson Snyder. Verilator is free software; you can
redistribute it and/or modify the Verilator internals under the terms of
either the GNU Lesser General Public License Version 3 or the Perl Artistic
License Version 2.0.
=head1 AUTHORS
Wilson Snyder <wsnyder@wsnyder.org>
=head1 SEE ALSO
C<verilator>
L<verilator_coverage --help> which is the source for this document.
=cut
######################################################################

451
include/verilated_cov.cpp Normal file
View File

@ -0,0 +1,451 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//=============================================================================
//
// THIS MODULE IS PUBLICLY LICENSED
//
// Copyright 2001-2014 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.
//
// This is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
//=============================================================================
///
/// \file
/// \brief Verilator coverage analysis
///
/// AUTHOR: Wilson Snyder
///
//=============================================================================
#include "verilatedos.h"
#include "verilated.h"
#include "verilated_cov.h"
#include "verilated_cov_key.h"
#include <map>
#include <deque>
#include <fstream>
//=============================================================================
// VerilatedCovImpBase
/// Implementation base class for constants
struct VerilatedCovImpBase {
// TYPES
enum { MAX_KEYS = 33 }; /// Maximum user arguments + filename+lineno
enum { KEY_UNDEF = 0 }; /// Magic key # for unspecified values
};
//=============================================================================
// VerilatedCovImpItem
/// Implementation class for a VerilatedCov item
class VerilatedCovImpItem : VerilatedCovImpBase {
public: // But only local to this file
// MEMBERS
int m_keys[MAX_KEYS]; ///< Key
int m_vals[MAX_KEYS]; ///< Value for specified key
// CONSTRUCTORS
// Derived classes should call zero() in their constructor
VerilatedCovImpItem() {
for (int i=0; i<MAX_KEYS; i++) m_keys[i]=KEY_UNDEF;
}
virtual ~VerilatedCovImpItem() {}
virtual vluint64_t count() const = 0;
virtual void zero() const = 0;
};
//=============================================================================
/// VerilatedCoverItem templated for a specific class
/// Creates a new coverage item for the specified type.
/// This isn't in the header file for auto-magic conversion because it
/// inlines to too much code and makes compilation too slow.
template <class T> class VerilatedCoverItemSpec : public VerilatedCovImpItem {
private:
// MEMBERS
T* m_countp; ///< Count value
public:
// METHODS
virtual vluint64_t count() const { return *m_countp; }
virtual void zero() const { *m_countp = 0; }
// CONSTRUCTORS
VerilatedCoverItemSpec(T* countp) : m_countp(countp) { zero(); }
virtual ~VerilatedCoverItemSpec() {}
};
//=============================================================================
// VerilatedCovImp
/// Implementation class for VerilatedCov. See that class for public method information.
/// All value and keys are indexed into a unique number. Thus we can greatly reduce
/// the storage requirements for otherwise identical keys.
class VerilatedCovImp : VerilatedCovImpBase {
private:
// TYPES
typedef map<string,int> ValueIndexMap;
typedef map<int,string> IndexValueMap;
typedef deque<VerilatedCovImpItem*> ItemList;
private:
// MEMBERS
ValueIndexMap m_valueIndexes; ///< For each key/value a unique arbitrary index value
IndexValueMap m_indexValues; ///< For each key/value a unique arbitrary index value
ItemList m_items; ///< List of all items
VerilatedCovImpItem* m_insertp; ///< Item about to insert
const char* m_insertFilenamep; ///< Filename about to insert
int m_insertLineno; ///< Line number about to insert
// CONSTRUCTORS
VerilatedCovImp() {
m_insertp = NULL;
m_insertFilenamep = NULL;
m_insertLineno = 0;
}
public:
~VerilatedCovImp() { clear(); }
static VerilatedCovImp& imp() {
static VerilatedCovImp s_singleton;
return s_singleton;
}
private:
// PRIVATE METHODS
int valueIndex(const string& value) {
static int nextIndex = KEY_UNDEF+1;
ValueIndexMap::iterator iter = m_valueIndexes.find(value);
if (iter != m_valueIndexes.end()) return iter->second;
nextIndex++; assert(nextIndex>0);
m_valueIndexes.insert(make_pair(value, nextIndex));
m_indexValues.insert(make_pair(nextIndex, value));
return nextIndex;
}
string dequote(const string& text) {
// Quote any special characters
string rtn;
for (const char* pos = text.c_str(); *pos; pos++) {
if (!isprint(*pos) || *pos=='%' || *pos=='"') {
char hex[10]; sprintf(hex,"%%%02X",pos[0]);
rtn += hex;
} else {
rtn += *pos;
}
}
return rtn;
}
bool legalKey(const string& key) {
// Because we compress long keys to a single letter, and
// don't want applications to either get confused if they use
// a letter differently, nor want them to rely on our compression...
// (Considered using numeric keys, but will remain back compatible.)
if (key.length()<2) return false;
if (key.length()==2 && isdigit(key[1])) return false;
return true;
}
string keyValueFormatter (const string& key, const string& value) {
string name;
if (key.length()==1 && isalpha(key[0])) {
name += string("\001")+key;
} else {
name += string("\001")+dequote(key);
}
name += string("\002")+dequote(value);
return name;
}
string combineHier (const string& old, const string& add) {
// (foo.a.x, foo.b.x) => foo.*.x
// (foo.a.x, foo.b.y) => foo.*
// (foo.a.x, foo.b) => foo.*
if (old == add) return add;
if (old == "") return add;
if (add == "") return old;
const char* a = old.c_str();
const char* b = add.c_str();
// Scan forward to first mismatch
const char* apre = a;
const char* bpre = b;
while (*apre == *bpre) { apre++; bpre++; }
// We used to backup and split on only .'s but it seems better to be verbose
// and not assume . is the separator
string prefix = string(a,apre-a);
// Scan backward to last mismatch
const char* apost = a+strlen(a)-1;
const char* bpost = b+strlen(b)-1;
while (*apost == *bpost
&& apost>apre && bpost>bpre) { apost--; bpost--; }
// Forward to . so we have a whole word
string suffix = *bpost ? string(bpost+1) : "";
string out = prefix+"*"+suffix;
//cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add<<"\nch o="<<out<<endl;
return out;
}
bool itemMatchesString(VerilatedCovImpItem* itemp, const string& match) {
for (int i=0; i<MAX_KEYS; i++) {
if (itemp->m_keys[i] != KEY_UNDEF) {
// We don't compare keys, only values
string val = m_indexValues[itemp->m_vals[i]];
if (string::npos != val.find(match)) { // Found
return true;
}
}
}
return false;
}
void selftest() {
// Little selftest
if (combineHier ("a.b.c","a.b.c") !="a.b.c") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier ("a.b.c","a.b") !="a.b*") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier ("a.x.c","a.y.c") !="a.*.c") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier ("a.z.z.z.c","a.b.c") !="a.*.c") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier ("z","a") !="*") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier ("q.a","q.b") !="q.*") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier ("q.za","q.zb") !="q.z*") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier ("1.2.3.a","9.8.7.a") !="*.a") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
}
public:
// PUBLIC METHODS
void clear() {
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
VerilatedCovImpItem* itemp = *(it);
delete itemp;
}
m_items.clear();
m_indexValues.clear();
m_valueIndexes.clear();
}
void clearNonMatch (const char* matchp) {
if (matchp && matchp[0]) {
ItemList newlist;
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
VerilatedCovImpItem* itemp = *(it);
if (!itemMatchesString(itemp, matchp)) {
delete itemp;
} else {
newlist.push_back(itemp);
}
}
m_items = newlist;
}
}
void zero() {
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
(*it)->zero();
}
}
// We assume there's always call to i/f/p in that order
void inserti (VerilatedCovImpItem* itemp) {
assert(!m_insertp);
m_insertp = itemp;
}
void insertf (const char* filenamep, int lineno) {
m_insertFilenamep = filenamep;
m_insertLineno = lineno;
}
void insertp (const char* ckeyps[MAX_KEYS],
const char* valps[MAX_KEYS]) {
assert(m_insertp);
// First two key/vals are filename
ckeyps[0]="filename"; valps[0]=m_insertFilenamep;
VlCovCvtToCStr linestrp (m_insertLineno);
ckeyps[1]="lineno"; valps[1]=linestrp;
// Default page if not specified
const char* fnstartp = m_insertFilenamep;
while (const char* foundp = strchr(fnstartp,'/')) fnstartp=foundp+1;
const char* fnendp = fnstartp;
while (*fnendp && *fnendp!='.') fnendp++;
string page_default = "sp_user/"+string(fnstartp,fnendp-fnstartp);
ckeyps[2]="page"; valps[2]=page_default.c_str();
// Keys -> strings
string keys[MAX_KEYS];
for (int i=0; i<MAX_KEYS; i++) {
if (ckeyps[i] && ckeyps[i][0]) {
keys[i] = ckeyps[i];
}
}
// Ignore empty keys
for (int i=0; i<MAX_KEYS; i++) {
if (keys[i]!="") {
for (int j=i+1; j<MAX_KEYS; j++) {
if (keys[i] == keys[j]) { // Duplicate key. Keep the last one
keys[i] = "";
break;
}
}
}
}
// Insert the values
int addKeynum=0;
for (int i=0; i<MAX_KEYS; i++) {
const string key = keys[i];
if (keys[i]!="") {
const string val = valps[i];
//cout<<" "<<__FUNCTION__<<" "<<key<<" = "<<val<<endl;
m_insertp->m_keys[addKeynum] = valueIndex(key);
m_insertp->m_vals[addKeynum] = valueIndex(val);
addKeynum++;
if (!legalKey(key)) {
string msg = "%Error: Coverage keys of one character, or letter+digit are illegal: "+key;
vl_fatal("",0,"",msg.c_str());
}
}
}
m_items.push_back(m_insertp);
// Prepare for next
m_insertp = NULL;
}
void write (const char* filename) {
#ifndef VM_COVERAGE
vl_fatal("",0,"","%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
#endif
selftest();
ofstream os (filename);
if (os.fail()) {
string msg = (string)"%Error: Can't write '"+filename+"'";
vl_fatal("",0,"",msg.c_str());
return;
}
os << "# SystemC::Coverage-3\n";
// Build list of events; totalize if collapsing hierarchy
typedef map<string,pair<string,vluint64_t> > EventMap;
EventMap eventCounts;
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
VerilatedCovImpItem* itemp = *(it);
string name;
string hier;
bool per_instance = false;
for (int i=0; i<MAX_KEYS; i++) {
if (itemp->m_keys[i] != KEY_UNDEF) {
string key = VerilatedCovKey::shortKey(m_indexValues[itemp->m_keys[i]]);
string val = m_indexValues[itemp->m_vals[i]];
if (key == VL_CIK_PER_INSTANCE) {
if (val != "0") per_instance = true;
}
if (key == VL_CIK_HIER) {
hier = val;
} else {
// Print it
name += keyValueFormatter(key,val);
}
}
}
if (per_instance) { // Not collapsing hierarchies
name += keyValueFormatter(VL_CIK_HIER,hier);
hier = "";
}
// Group versus point labels don't matter here, downstream
// deals with it. Seems bad for sizing though and doesn't
// allow easy addition of new group codes (would be
// inefficient)
// Find or insert the named event
EventMap::iterator cit = eventCounts.find(name);
if (cit != eventCounts.end()) {
const string& oldhier = cit->second.first;
cit->second.second += itemp->count();
cit->second.first = combineHier(oldhier, hier);
} else {
eventCounts.insert(make_pair(name, make_pair(hier,itemp->count())));
}
}
// Output body
for (EventMap::iterator it=eventCounts.begin(); it!=eventCounts.end(); ++it) {
os<<"C '"<<dec;
os<<it->first;
if (it->second.first != "") os<<keyValueFormatter(VL_CIK_HIER,it->second.first);
os<<"' "<<it->second.second;
os<<endl;
}
}
};
//=============================================================================
// VerilatedCov
void VerilatedCov::clear() {
VerilatedCovImp::imp().clear();
}
void VerilatedCov::clearNonMatch (const char* matchp) {
VerilatedCovImp::imp().clearNonMatch(matchp);
}
void VerilatedCov::zero() {
VerilatedCovImp::imp().zero();
}
void VerilatedCov::write (const char* filenamep) {
VerilatedCovImp::imp().write(filenamep);
}
void VerilatedCov::_inserti (vluint32_t* itemp) {
VerilatedCovImp::imp().inserti(new VerilatedCoverItemSpec<vluint32_t>(itemp));
}
void VerilatedCov::_inserti (vluint64_t* itemp) {
VerilatedCovImp::imp().inserti(new VerilatedCoverItemSpec<vluint64_t>(itemp));
}
void VerilatedCov::_insertf (const char* filename, int lineno) {
VerilatedCovImp::imp().insertf(filename,lineno);
}
#define K(n) const char* key ## n
#define A(n) const char* key ## n, const char* val ## n // Argument list
#define C(n) key ## n, val ## n // Calling argument list
#define N(n) "","" // Null argument list
void VerilatedCov::_insertp (A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9),
A(10),A(11),A(12),A(13),A(14),A(15),A(16),A(17),A(18),A(19),
A(20),A(21),A(22),A(23),A(24),A(25),A(26),A(27),A(28),A(29)) {
const char* keyps[VerilatedCovImpBase::MAX_KEYS]
= {NULL,NULL,NULL, // filename,lineno,page
key0,key1,key2,key3,key4,key5,key6,key7,key8,key9,
key10,key11,key12,key13,key14,key15,key16,key17,key18,key19,
key20,key21,key22,key23,key24,key25,key26,key27,key28,key29};
const char* valps[VerilatedCovImpBase::MAX_KEYS]
= {NULL,NULL,NULL, // filename,lineno,page
val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,
val10,val11,val12,val13,val14,val15,val16,val17,val18,val19,
val20,val21,val22,val23,val24,val25,val26,val27,val28,val29};
VerilatedCovImp::imp().insertp(keyps, valps);
}
// And versions with fewer arguments (oh for a language with named parameters!)
void VerilatedCov::_insertp (A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9)) {
_insertp(C(0),C(1),C(2),C(3),C(4),C(5),C(6),C(7),C(8),C(9),
N(10),N(11),N(12),N(13),N(14),N(15),N(16),N(17),N(18),N(19),
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
}
void VerilatedCov::_insertp (A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9),
A(10),A(11),A(12),A(13),A(14),A(15),A(16),A(17),A(18),A(19)) {
_insertp(C(0),C(1),C(2),C(3),C(4),C(5),C(6),C(7),C(8),C(9),
C(10),C(11),C(12),C(13),C(14),C(15),C(16),C(17),C(18),C(19),
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
}
// Backward compatibility for Verilator
void VerilatedCov::_insertp (A(0), A(1), K(2),int val2, K(3),int val3,
K(4),const string& val4, A(5),A(6)) {
_insertp(C(0),C(1),
key2,VlCovCvtToCStr(val2), key3,VlCovCvtToCStr(val3), key4, val4.c_str(),
C(5),C(6),N(7),N(8),N(9),
N(10),N(11),N(12),N(13),N(14),N(15),N(16),N(17),N(18),N(19),
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
}
#undef A
#undef C
#undef N
#undef K

146
include/verilated_cov.h Normal file
View File

@ -0,0 +1,146 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//=============================================================================
//
// THIS MODULE IS PUBLICLY LICENSED
//
// Copyright 2001-2014 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.
//
// This is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
//=============================================================================
///
/// \file
/// \brief Coverage analysis support
///
/// AUTHOR: Wilson Snyder
///
//=============================================================================
#ifndef _VERILATED_COV_H_
#define _VERILATED_COV_H_ 1
#include "verilatedos.h"
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
//=============================================================================
/// Conditionally compile coverage code
#ifdef VM_COVERAGE
# define VL_IF_COVER(stmts) do { stmts ; } while(0)
#else
# define VL_IF_COVER(stmts) do { if(0) { stmts ; } } while(0)
#endif
//=============================================================================
/// Insert a item for coverage analysis.
/// The first argument is a pointer to the count to be dumped.
/// The remaining arguments occur in pairs: A string key, and a value.
/// The value may be a string, or another type which will be auto-converted to a string.
///
/// Some typical keys:
/// filename File the recording occurs in. Defaults to __FILE__
/// lineno Line number the recording occurs in. Defaults to __LINE__
/// column Column number (or occurrence# for dup file/lines). Defaults to undef.
/// hier Hierarchical name. Defaults to name()
/// type Type of coverage. Defaults to "user"
/// Other types are 'block', 'fsm', 'toggle'.
/// comment Description of the coverage event. Should be set by the user.
/// Comments for type==block: 'if', 'else', 'elsif', 'case'
/// thresh Threshold to consider fully covered.
/// If unspecified, downstream tools will determine it.
///
/// Examples:
///
/// vluint32_t m_cases[10];
/// constructor {
/// for (int i=0; i<10; i++) { m_cases[i]=0; }
/// }
/// for (int i=0; i<10; i++) {
/// VL_COVER_INSERT(&m_cases[i], "comment", "Coverage Case", "i", cvtToNumStr(i));
/// }
#define VL_COVER_INSERT(countp,args...) \
VL_IF_COVER(VerilatedCov::_inserti(countp); \
VerilatedCov::_insertf(__FILE__,__LINE__); \
VerilatedCov::_insertp("hier", name(), args))
//=============================================================================
/// Convert VL_COVER_INSERT value arguments to strings
template< class T> std::string vlCovCvtToStr (const T& t) {
ostringstream os; os<<t; return os.str();
}
/// Usage: something(VlCovCvtToCStr(i))
/// Note the pointer will only be valid for as long as the object remains
/// in scope!
struct VlCovCvtToCStr {
string m_str;
// Casters
template< class T> VlCovCvtToCStr (const T& t) {
ostringstream os; os<<t; m_str=os.str();
}
~VlCovCvtToCStr() {}
operator const char* () const { return m_str.c_str(); };
};
//=============================================================================
// VerilatedCov
/// SystemPerl coverage global class
////
/// Global class with methods affecting all coverage data.
class VerilatedCov {
public:
// GLOBAL METHODS
/// Return default filename
static const char* defaultFilename() { return "coverage.dat"; }
/// Write all coverage data to a file
static void write (const char* filenamep = defaultFilename());
/// Insert a coverage item
/// We accept from 1-30 key/value pairs, all as strings.
/// Call _insert1, followed by _insert2 and _insert3
/// Do not call directly; use VL_COVER_INSERT or higher level macros instead
// _insert1: Remember item pointer with count. (Not const, as may add zeroing function)
static void _inserti (vluint32_t* itemp);
static void _inserti (vluint64_t* itemp);
// _insert2: Set default filename and line number
static void _insertf (const char* filename, int lineno);
// _insert3: Set parameters
// We could have just the maximum argument version, but this compiles
// much slower (nearly 2x) than having smaller versions also. However
// there's not much more gain in having a version for each number of args.
#define K(n) const char* key ## n
#define A(n) const char* key ## n, const char* valp ## n // Argument list
#define D(n) const char* key ## n = NULL, const char* valp ## n = NULL // Argument list
static void _insertp (D(0),D(1),D(2),D(3),D(4),D(5),D(6),D(7),D(8),D(9));
static void _insertp (A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9)
,A(10),D(11),D(12),D(13),D(14),D(15),D(16),D(17),D(18),D(19));
static void _insertp (A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9)
,A(10),A(11),A(12),A(13),A(14),A(15),A(16),A(17),A(18),A(19)
,A(20),D(21),D(22),D(23),D(24),D(25),D(26),D(27),D(28),D(29));
// Backward compatibility for Verilator
static void _insertp (A(0), A(1), K(2),int val2, K(3),int val3,
K(4),const string& val4, A(5),A(6));
#undef K
#undef A
#undef D
/// Clear coverage points (and call delete on all items)
static void clear();
/// Clear items not matching the provided string
static void clearNonMatch (const char* matchp);
/// Zero coverage points
static void zero();
};
#endif // guard

147
include/verilated_cov_key.h Normal file
View File

@ -0,0 +1,147 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//=============================================================================
//
// THIS MODULE IS PUBLICLY LICENSED
//
// Copyright 2001-2014 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.
//
// This is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
//=============================================================================
///
/// \file
/// \brief Coverage item keys
///
/// AUTHOR: Wilson Snyder
///
//=============================================================================
#ifndef _VERILATED_COV_KEY_H_
#define _VERILATED_COV_KEY_H_ 1
#include "verilatedos.h"
#include <string>
using namespace std;
//=============================================================================
// Data used to edit below file, using vlcovgen
#define VLCOVGEN_ITEM(string_parsed_by_vlcovgen)
VLCOVGEN_ITEM("name=>'col0_name', short=>'C0', group=>1, default=>undef, descr=>'The column title for the header line of this column'")
VLCOVGEN_ITEM("name=>'col1_name', short=>'C1', group=>1, default=>undef, ")
VLCOVGEN_ITEM("name=>'col2_name', short=>'C2', group=>1, default=>undef, ")
VLCOVGEN_ITEM("name=>'col3_name', short=>'C3', group=>1, default=>undef, ")
VLCOVGEN_ITEM("name=>'column', short=>'n', group=>1, default=>0, descr=>'Column number for the item. Used to disambiguate multiple coverage points on the same line number'")
VLCOVGEN_ITEM("name=>'filename', short=>'f', group=>1, default=>undef, descr=>'Filename of the item'")
VLCOVGEN_ITEM("name=>'groupdesc', short=>'d', group=>1, default=>'', descr=>'Description of the covergroup this item belongs to'")
VLCOVGEN_ITEM("name=>'groupname', short=>'g', group=>1, default=>'', descr=>'Group name of the covergroup this item belongs to'")
VLCOVGEN_ITEM("name=>'groupcmt', short=>'O', group=>1, default=>'', ")
VLCOVGEN_ITEM("name=>'per_instance',short=>'P', group=>1, default=>0, descr=>'True if every hierarchy is independently counted; otherwise all hierarchies will be combined into a single count'")
VLCOVGEN_ITEM("name=>'row0_name', short=>'R0', group=>1, default=>undef, descr=>'The row title for the header line of this row'")
VLCOVGEN_ITEM("name=>'row1_name', short=>'R1', group=>1, default=>undef, ")
VLCOVGEN_ITEM("name=>'row2_name', short=>'R2', group=>1, default=>undef, ")
VLCOVGEN_ITEM("name=>'row3_name', short=>'R3', group=>1, default=>undef, ")
VLCOVGEN_ITEM("name=>'table', short=>'T', group=>1, default=>undef, descr=>'The name of the table for automatically generated tables'")
VLCOVGEN_ITEM("name=>'thresh', short=>'s', group=>1, default=>undef, ")
VLCOVGEN_ITEM("name=>'type', short=>'t', group=>1, default=>'', descr=>'Type of coverage (block, line, fsm, etc)'")
// Bin attributes
VLCOVGEN_ITEM("name=>'col0', short=>'c0', group=>0, default=>undef, descr=>'The (enumeration) value name for this column in a table cross' ")
VLCOVGEN_ITEM("name=>'col1', short=>'c1', group=>0, default=>undef, ")
VLCOVGEN_ITEM("name=>'col2', short=>'c2', group=>0, default=>undef, ")
VLCOVGEN_ITEM("name=>'col3', short=>'c3', group=>0, default=>undef, ")
VLCOVGEN_ITEM("name=>'comment', short=>'o', group=>0, default=>'', descr=>'Textual description for the item'")
VLCOVGEN_ITEM("name=>'hier', short=>'h', group=>0, default=>'', descr=>'Hierarchy path name for the item'")
VLCOVGEN_ITEM("name=>'limit', short=>'L', group=>0, default=>undef, ")
VLCOVGEN_ITEM("name=>'lineno', short=>'l', group=>0, default=>0, descr=>'Line number for the item'")
VLCOVGEN_ITEM("name=>'row0', short=>'r0', group=>0, default=>undef, descr=>'The (enumeration) value name for this row in a table cross'")
VLCOVGEN_ITEM("name=>'row1', short=>'r1', group=>0, default=>undef, ")
VLCOVGEN_ITEM("name=>'row2', short=>'r2', group=>0, default=>undef, ")
VLCOVGEN_ITEM("name=>'row3', short=>'r3', group=>0, default=>undef, ")
VLCOVGEN_ITEM("name=>'weight', short=>'w', group=>0, default=>undef, descr=>'For totaling items, weight of this item'")
//=============================================================================
// VerilatedCovKey
/// SystemPerl coverage global class
////
/// Global class with methods affecting all coverage data.
// VLCOVGEN_CIK_AUTO_EDIT_BEGIN
#define VL_CIK_COL0 "c0"
#define VL_CIK_COL0_NAME "C0"
#define VL_CIK_COL1 "c1"
#define VL_CIK_COL1_NAME "C1"
#define VL_CIK_COL2 "c2"
#define VL_CIK_COL2_NAME "C2"
#define VL_CIK_COL3 "c3"
#define VL_CIK_COL3_NAME "C3"
#define VL_CIK_COLUMN "n"
#define VL_CIK_COMMENT "o"
#define VL_CIK_FILENAME "f"
#define VL_CIK_GROUPCMT "O"
#define VL_CIK_GROUPDESC "d"
#define VL_CIK_GROUPNAME "g"
#define VL_CIK_HIER "h"
#define VL_CIK_LIMIT "L"
#define VL_CIK_LINENO "l"
#define VL_CIK_PER_INSTANCE "P"
#define VL_CIK_ROW0 "r0"
#define VL_CIK_ROW0_NAME "R0"
#define VL_CIK_ROW1 "r1"
#define VL_CIK_ROW1_NAME "R1"
#define VL_CIK_ROW2 "r2"
#define VL_CIK_ROW2_NAME "R2"
#define VL_CIK_ROW3 "r3"
#define VL_CIK_ROW3_NAME "R3"
#define VL_CIK_TABLE "T"
#define VL_CIK_THRESH "s"
#define VL_CIK_TYPE "t"
#define VL_CIK_WEIGHT "w"
// VLCOVGEN_CIK_AUTO_EDIT_END
class VerilatedCovKey {
public:
static string shortKey(const string& key) {
// VLCOVGEN_SHORT_AUTO_EDIT_BEGIN
if (key == "col0") return VL_CIK_COL0;
if (key == "col0_name") return VL_CIK_COL0_NAME;
if (key == "col1") return VL_CIK_COL1;
if (key == "col1_name") return VL_CIK_COL1_NAME;
if (key == "col2") return VL_CIK_COL2;
if (key == "col2_name") return VL_CIK_COL2_NAME;
if (key == "col3") return VL_CIK_COL3;
if (key == "col3_name") return VL_CIK_COL3_NAME;
if (key == "column") return VL_CIK_COLUMN;
if (key == "comment") return VL_CIK_COMMENT;
if (key == "filename") return VL_CIK_FILENAME;
if (key == "groupcmt") return VL_CIK_GROUPCMT;
if (key == "groupdesc") return VL_CIK_GROUPDESC;
if (key == "groupname") return VL_CIK_GROUPNAME;
if (key == "hier") return VL_CIK_HIER;
if (key == "limit") return VL_CIK_LIMIT;
if (key == "lineno") return VL_CIK_LINENO;
if (key == "per_instance") return VL_CIK_PER_INSTANCE;
if (key == "row0") return VL_CIK_ROW0;
if (key == "row0_name") return VL_CIK_ROW0_NAME;
if (key == "row1") return VL_CIK_ROW1;
if (key == "row1_name") return VL_CIK_ROW1_NAME;
if (key == "row2") return VL_CIK_ROW2;
if (key == "row2_name") return VL_CIK_ROW2_NAME;
if (key == "row3") return VL_CIK_ROW3;
if (key == "row3_name") return VL_CIK_ROW3_NAME;
if (key == "table") return VL_CIK_TABLE;
if (key == "thresh") return VL_CIK_THRESH;
if (key == "type") return VL_CIK_TYPE;
if (key == "weight") return VL_CIK_WEIGHT;
// VLCOVGEN_SHORT_AUTO_EDIT_END
return key;
}
};
#endif // guard

View File

@ -46,7 +46,7 @@ obj_opt:
obj_dbg:
mkdir $@
.PHONY: ../verilator_bin ../verilator_bin_dbg
.PHONY: ../verilator_bin ../verilator_bin_dbg ../verilator_coverage_bin_dbg
opt: ../verilator_bin
ifeq ($(VERILATOR_NO_OPT_BUILD),1) # Faster laptop development... One build
@ -59,11 +59,15 @@ else
cd obj_opt && $(MAKE) TGT=../$@ -f ../Makefile_obj
endif
dbg: ../verilator_bin_dbg
dbg: ../verilator_bin_dbg ../verilator_coverage_bin_dbg
../verilator_bin_dbg: obj_dbg prefiles
cd obj_dbg && $(MAKE) -j 1 TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj serial
cd obj_dbg && $(MAKE) TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj
../verilator_coverage_bin_dbg: obj_dbg prefiles
cd obj_dbg && $(MAKE) TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj serial_vlcov
cd obj_dbg && $(MAKE) TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj
prefiles::
prefiles:: config_rev.h
ifneq ($(UNDER_GIT),) # If local git tree... Else don't burden users

View File

@ -127,6 +127,7 @@ HEADERS = $(wildcard V*.h v*.h)
ASTGEN = $(srcdir)/astgen
BISONPRE = $(srcdir)/bisonpre
FLEXFIX = $(srcdir)/flexfix
VLCOVGEN = $(srcdir)/vlcovgen
######################################################################
#### Top level
@ -234,26 +235,30 @@ RAW_OBJS = \
V3WidthSel.o \
# Non-concatable
OBJS += \
NC_OBJS += \
V3ParseImp.o \
V3ParseGrammar.o \
V3ParseLex.o \
V3PreProc.o \
# verilator_coverage
VLCOV_OBJS = \
VlcMain.o \
#### Linking
ifeq ($(VL_DEBUG),)
# Building with fewer objects to better optimize
#OBJS += V3__CONCAT.o
OBJS += $(RAW_OBJS)
ifeq ($(VL_VLCOV),)
PREDEP_H = V3Ast__gen_classes.h
OBJS += $(RAW_OBJS) $(NC_OBJS)
else
OBJS += $(RAW_OBJS)
PREDEP_H =
OBJS += $(VLCOV_OBJS)
endif
V3__CONCAT.cpp: $(addsuffix .cpp, $(basename $(RAW_OBJS)))
$(PERL) $(srcdir)/../bin/verilator_includer $^ > $@
$(TGT): V3Ast__gen_classes.h $(OBJS)
$(TGT): $(PREDEP_H) $(OBJS)
@echo " Linking $@..."
-rm -rf $@ $@.exe
${LINK} ${LDFLAGS} -o $@ $(OBJS) $(CCMALLOC) ${LIBS}
@ -288,6 +293,12 @@ V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp
# Target rule called before parallel build to make generated files
serial:: V3Ast__gen_classes.h V3ParseBison.c
serial_vlcov:: vlcovgen.d
vlcovgen.d: $(VLCOVGEN) $(srcdir)/include/verilated_cov_key.h
$(PERL) $(VLCOVGEN) --srcdir $(srcdir)
touch $@
V3Ast__gen_classes.h : $(ASTGEN) V3Ast.h V3AstNodes.h
$(PERL) $(ASTGEN) -I$(srcdir) --classes

View File

@ -1508,7 +1508,7 @@ void EmitCImp::emitConfigureImp(AstNodeModule* modp) {
void EmitCImp::emitCoverageImp(AstNodeModule* modp) {
if (v3Global.opt.coverage() ) {
puts("\n// Coverage\n");
// Rather than putting out SP_COVER_INSERT calls directly, we do it via this function
// Rather than putting out VL_COVER_INSERT calls directly, we do it via this function
// This gets around gcc slowness constructing all of the template arguments
// SystemPerl 1.301 is much faster, but it's nice to remain back
// compatible, and have a common wrapper.
@ -1517,7 +1517,7 @@ void EmitCImp::emitCoverageImp(AstNodeModule* modp) {
puts( "static uint32_t fake_zero_count = 0;\n"); // static doesn't need save-restore as constant
puts( "if (!enable) countp = &fake_zero_count;\n"); // Used for second++ instantiation of identical bin
puts( "*countp = 0;\n");
puts( "SP_COVER_INSERT(countp,");
puts( "VL_COVER_INSERT(countp,");
puts( " \"filename\",filenamep,");
puts( " \"lineno\",lineno,");
puts( " \"column\",column,\n");
@ -1827,7 +1827,7 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
puts("#include \"verilated_save.h\"\n");
}
if (v3Global.opt.coverage()) {
puts("#include \"SpCoverage.h\"\n");
puts("#include \"verilated_cov.h\"\n");
if (v3Global.opt.savable()) v3error("--coverage and --savable not supported together");
}
if (v3Global.needHInlines()) { // Set by V3EmitCInlines; should have been called before us

View File

@ -83,13 +83,13 @@ public:
if (v3Global.opt.savable()) {
putMakeClassEntry(of, "verilated_save.cpp");
}
if (v3Global.opt.coverage()) {
putMakeClassEntry(of, "verilated_cov.cpp");
}
if (v3Global.opt.systemPerl()) {
putMakeClassEntry(of, "Sp.cpp"); // Note Sp.cpp includes SpTraceVcdC
}
else {
if (v3Global.opt.coverage()) {
putMakeClassEntry(of, "SpCoverage.cpp");
}
if (v3Global.opt.trace()) {
putMakeClassEntry(of, "verilated_vcd_c.cpp");
if (v3Global.opt.systemC()) {

View File

@ -23,7 +23,6 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3Error.h"
#include "V3FileLine.h"
#include <cstdio>
#include <stack>
#include <set>

View File

@ -275,18 +275,18 @@ bool V3Options::filenameIsRel(const string& filename) {
}
bool V3Options::fileStatDir(const string& filename) {
struct stat m_stat; // Stat information
int err = stat(filename.c_str(), &m_stat);
struct stat sstat; // Stat information
int err = stat(filename.c_str(), &sstat);
if (err!=0) return false;
if (!S_ISDIR(m_stat.st_mode)) return false;
if (!S_ISDIR(sstat.st_mode)) return false;
return true;
}
bool V3Options::fileStatNormal(const string& filename) {
struct stat m_stat; // Stat information
int err = stat(filename.c_str(), &m_stat);
struct stat sstat; // Stat information
int err = stat(filename.c_str(), &sstat);
if (err!=0) return false;
if (S_ISDIR(m_stat.st_mode)) return false;
if (S_ISDIR(sstat.st_mode)) return false;
return true;
}

133
src/VlcBucket.h Normal file
View File

@ -0,0 +1,133 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: verilator_coverage: Bucket container
//
// Code available from: http://www.veripool.org/verilator
//
//*************************************************************************
//
// Copyright 2003-2014 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.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _VLCBUCKET_H_
#define _VLCBUCKET_H_ 1
#include "config_build.h"
#include "verilatedos.h"
//********************************************************************
// VlcBuckets - Container of all coverage point hits for a given test
// This is a bitmap array - we store a single bit to indicate a test
// has hit that point with sufficient coverage.
class VlcBuckets {
private:
// MEMBERS
vluint64_t* m_datap; ///< Pointer to first bucket (dynamically allocated)
vluint64_t m_dataSize; ///< Current entries in m_datap
vluint64_t m_bucketsCovered; ///< Num buckets with sufficient coverage
private:
static inline vluint64_t covBit(vluint64_t point) { return 1ULL<<(point & 63); }
inline vluint64_t allocSize() const { return sizeof(vluint64_t) * m_dataSize / 64; }
void allocate(vluint64_t point) {
vluint64_t oldsize = m_dataSize;
if (m_dataSize<point) m_dataSize=(point+64) & ~63ULL; // Keep power of two
m_dataSize *= 2;
//UINFO(9, "Realloc "<<allocSize()<<" for "<<point<<" "<<(void*)(m_datap)<<endl);
m_datap = (vluint64_t*)realloc(m_datap, allocSize());
if (!m_datap) {v3fatal("Out of memory increasing buckets"); }
for (vluint64_t i=oldsize; i<m_dataSize; i+=64) m_datap[i/64] = 0;
}
public:
// CONSTRUCTORS
VlcBuckets() {
m_dataSize = 0;
m_datap = NULL;
m_bucketsCovered = 0;
allocate(1024);
}
~VlcBuckets() {
m_dataSize = 0;
free(m_datap); m_datap=NULL;
}
// ACCESSORS
static vluint64_t sufficient() { return 1; }
vluint64_t bucketsCovered() const { return m_bucketsCovered; }
// METHODS
void addData(vluint64_t point, vluint64_t hits) {
if (hits >= sufficient()) {
//UINFO(9," addData "<<point<<" "<<hits<<" size="<<m_dataSize<<endl);
if (point >= m_dataSize) allocate(point);
m_datap[point/64] |= covBit(point);
m_bucketsCovered++;
}
}
void clearHits(vluint64_t point) const {
if (point >= m_dataSize) {
return;
} else {
m_datap[point/64] &= ~covBit(point);
}
}
bool exists(vluint64_t point) const {
if (point >= m_dataSize) {
return false;
} else {
return (m_datap[point/64] & covBit(point)) ? 1:0;
}
}
vluint64_t hits(vluint64_t point) const {
if (point >= m_dataSize) {
return 0;
} else {
return (m_datap[point/64] & covBit(point)) ? 1:0;
}
}
vluint64_t popCount() const {
vluint64_t pop = 0;
for (vluint64_t i=0; i<m_dataSize; i++) {
if (hits(i)) pop++;
}
return pop;
}
vluint64_t dataPopCount(const VlcBuckets& remaining) {
vluint64_t pop = 0;
for (vluint64_t i=0; i<m_dataSize; i++) {
if (hits(i) && remaining.hits(i)) pop++;
}
return pop;
}
void orData(const VlcBuckets& ordata) {
for (vluint64_t i=0; i<m_dataSize; i++) {
if (hits(i) && ordata.hits(i)) {
clearHits(i);
}
}
}
void dump() const {
cout<<"# ";
for (vluint64_t i=0; i<m_dataSize; i++) {
if (hits(i)) cout<<","<<i;
}
cout<<endl;
}
};
//######################################################################
#endif // guard

202
src/VlcMain.cpp Normal file
View File

@ -0,0 +1,202 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: verilator_coverage: main()
//
// Code available from: http://www.veripool.org/verilator
//
//*************************************************************************
//
// Copyright 2003-2014 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.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
// Cheat for speed and compile .cpp files into one object
#define _V3ERROR_NO_GLOBAL_ 1
#include "V3Error.cpp"
#include "VlcTop.cpp"
#include "VlcOptions.h"
#include "VlcTop.h"
#include <fstream>
#include <algorithm>
//######################################################################
// VlcOptions
void VlcOptions::addReadFile(const string& filename) {
if (m_readFiles.find(filename) == m_readFiles.end()) {
m_readFiles.insert(filename);
}
}
string VlcOptions::version() {
string ver = DTVERSION;
ver += " rev "+cvtToStr(DTVERSION_rev);
return ver;
}
bool VlcOptions::onoff(const char* sw, const char* arg, bool& flag) {
// if sw==arg, then return true (found it), and flag=true
// if sw=="-no-arg", then return true (found it), and flag=false
// if sw=="-noarg", then return true (found it), and flag=false
// else return false
if (arg[0]!='-') v3fatalSrc("OnOff switches must have leading dash.\n");
if (0==strcmp(sw,arg)) { flag=true; return true; }
else if (0==strncmp(sw,"-no",3) && (0==strcmp(sw+3,arg+1))) { flag=false; return true; }
else if (0==strncmp(sw,"-no-",4) && (0==strcmp(sw+4,arg+1))) { flag=false; return true; }
return false;
}
void VlcOptions::parseOptsList(int argc, char** argv) {
// Parse parameters
// Note argc and argv DO NOT INCLUDE the filename in [0]!!!
// May be called recursively when there are -f files.
#define shift { ++i; }
for (int i=0; i<argc; ) {
UINFO(9, " Option: "<<argv[i]<<endl);
if (argv[i][0]=='-') {
const char *sw = argv[i];
bool flag = true;
// Allow gnu -- switches
if (sw[0]=='-' && sw[1]=='-') ++sw;
if (0) {}
// Single switches
else if ( onoff (sw, "-annotate-all", flag/*ref*/) ) { m_annotateAll = flag; }
else if ( onoff (sw, "-rank", flag/*ref*/) ) { m_rank = flag; }
else if ( onoff (sw, "-unlink", flag/*ref*/) ) { m_unlink = flag; }
// Parameterized switches
else if ( !strcmp (sw, "-annotate") && (i+1)<argc ) {
shift;
m_annotateOut = argv[i];
}
else if ( !strcmp (sw, "-debug") ) {
V3Error::debugDefault(3);
}
else if ( !strcmp (sw, "-debugi") && (i+1)<argc ) {
shift;
V3Error::debugDefault(atoi(argv[i]));
}
else if ( !strcmp (sw, "-V") ) {
showVersion(true);
exit(0);
}
else if ( !strcmp (sw, "-version") ) {
showVersion(false);
exit(0);
}
else if ( !strcmp (sw, "-write") && (i+1)<argc ) {
shift;
m_writeFile = argv[i];
}
else {
v3fatal ("Invalid option: "<<argv[i]);
}
shift;
} // - options
else if (1) {
addReadFile(argv[i]);
shift;
}
else {
v3fatal ("Invalid argument: "<<argv[i]);
shift;
}
}
#undef shift
}
void VlcOptions::showVersion(bool verbose) {
cout <<version();
cout <<endl;
if (!verbose) return;
cout <<endl;
cout << "Copyright 2003-2014 by Wilson Snyder. Verilator is free software; you can\n";
cout << "redistribute it and/or modify the Verilator internals under the terms of\n";
cout << "either the GNU Lesser General Public License Version 3 or the Perl Artistic\n";
cout << "License Version 2.0.\n";
cout <<endl;
cout << "See http://www.veripool.org/verilator for documentation\n";
}
//######################################################################
// File searching
// (TODO: Make a V3Os with these functions and share with Verilator)
string VlcOptions::filenameNonDir (const string& filename) {
string::size_type pos;
if ((pos = filename.rfind("/")) != string::npos) {
return filename.substr(pos+1);
} else {
return filename;
}
}
//######################################################################
int main(int argc, char** argv, char** env) {
// General initialization
ios::sync_with_stdio();
VlcTop top;
// Command option parsing
top.opt.parseOptsList(argc-1, argv+1);
if (top.opt.readFiles().empty()) {
top.opt.addReadFile("vlt_coverage.pl");
}
const VlStringSet& readFiles = top.opt.readFiles();
for (VlStringSet::iterator it = readFiles.begin(); it != readFiles.end(); ++it) {
string filename = *it;
top.readCoverage(filename);
}
if (debug() >= 9) {
top.tests().dump(true);
top.points().dump();
}
V3Error::abortIfWarnings();
if (top.opt.annotateOut() != "") {
top.annotate(top.opt.annotateOut());
}
if (top.opt.rank()) {
top.rank();
top.tests().dump(false);
}
if (top.opt.writeFile() != "") {
top.writeCoverage(top.opt.writeFile());
V3Error::abortIfWarnings();
if (top.opt.unlink()) {
const VlStringSet& readFiles = top.opt.readFiles();
for (VlStringSet::iterator it = readFiles.begin(); it != readFiles.end(); ++it) {
string filename = *it;
unlink(filename.c_str());
}
}
}
// Final writing shouldn't throw warnings, but...
V3Error::abortIfWarnings();
UINFO(1,"Done, Exiting...\n");
}
// Local Variables:
// compile-command: "v4make bin/verilator_coverage --debugi 9 test_regress/t/t_vlcov_data_*.dat"
// End:

87
src/VlcOptions.h Normal file
View File

@ -0,0 +1,87 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: verilator_coverage: Command line options
//
// Code available from: http://www.veripool.org/verilator
//
//*************************************************************************
//
// Copyright 2003-2014 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.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _VLCOPTIONS_H_
#define _VLCOPTIONS_H_ 1
#include "config_build.h"
#include "verilatedos.h"
#include <string>
#include <vector>
#include <map>
#include <set>
#include "config_rev.h"
//######################################################################
// V3Options - Command line options
typedef vector<string> VlStringList;
typedef set<string> VlStringSet;
class VlcOptions {
// MEMBERS (general options)
string m_annotateOut; // main switch: --annotate I<output_directory>
bool m_annotateAll; // main switch: --annotate-all
int m_annotateMin; // main switch: --annotate-min I<count>
VlStringSet m_readFiles; // main switch: --read
bool m_rank; // main switch: --rank
bool m_unlink; // main switch: --unlink
string m_writeFile; // main switch: --write
private:
// METHODS
void showVersion(bool verbose);
bool onoff(const char* sw, const char* arg, bool& flag);
public:
// CREATORS
VlcOptions() {
m_annotateAll = false;
m_annotateMin = 10;
m_rank = false;
m_unlink = false;
}
~VlcOptions() {}
void setDebugMode(int level);
// METHODS
void parseOptsList(int argc, char** argv);
void addReadFile(const string& filename);
// ACCESSORS (options)
const VlStringSet& readFiles() const { return m_readFiles; }
string annotateOut() const { return m_annotateOut; }
bool annotateAll() const { return m_annotateAll; }
int annotateMin() const { return m_annotateMin; }
bool rank() const { return m_rank; }
bool unlink() const { return m_unlink; }
string writeFile() const { return m_writeFile; }
// METHODS (from main)
static string version();
// METHODS (file searching)
static string filenameNonDir(const string& filename);
};
//######################################################################
#endif // guard

152
src/VlcPoint.h Normal file
View File

@ -0,0 +1,152 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: verilator_coverage: Coverage points
//
// Code available from: http://www.veripool.org/verilator
//
//*************************************************************************
//
// Copyright 2003-2014 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.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _VLCPOINT_H_
#define _VLCPOINT_H_ 1
#include "config_build.h"
#include "verilatedos.h"
#include "verilated_cov_key.h"
#include <map>
#include <vector>
#include <iomanip>
//********************************************************************
// VlcPoint - A coverage point (across all tests)
class VlcPoint {
private:
// MEMBERS
string m_name; //< Name of the point
vluint64_t m_pointNum; //< Point number
vluint64_t m_testsCovering;//< Number tests with non-zero coverage of this point
vluint64_t m_count; //< Count of hits across all tests
public:
// CONSTRUCTORS
VlcPoint(const string& name, int pointNum) {
m_name = name;
m_pointNum = pointNum;
m_testsCovering = 0;
m_count = 0;
}
~VlcPoint() {}
// ACCESSORS
const string& name() const { return m_name; }
vluint64_t pointNum() const { return m_pointNum; }
vluint64_t testsCovering() const { return m_testsCovering; }
void countInc(vluint64_t inc) { m_count += inc; }
vluint64_t count() const { return m_count; }
void testsCoveringInc() { m_testsCovering++; }
// KEY ACCESSORS
string filename() const { return keyExtract(VL_CIK_FILENAME); }
string comment() const { return keyExtract(VL_CIK_COMMENT); }
string type() const { return keyExtract(VL_CIK_TYPE); }
string thresh() const { return keyExtract(VL_CIK_THRESH); } // string as maybe ""
int lineno() const { return atoi(keyExtract(VL_CIK_LINENO).c_str()); }
int column() const { return atoi(keyExtract(VL_CIK_COLUMN).c_str()); }
// METHODS
string keyExtract(const char* shortKey) const {
// Hot function
size_t shortLen = strlen(shortKey);
const string namestr = name();
for (const char* cp = namestr.c_str(); *cp; ++cp) {
if (*cp == '\001') {
if (0==strncmp(cp+1, shortKey, shortLen)
&& cp[shortLen+1] == '\002') {
cp += shortLen+2; // Skip \001+short+\002
const char* ep = cp;
while (*ep && *ep != '\001') ++ep;
return string(cp, ep-cp);
}
}
}
return "";
}
static void dumpHeader() {
cout<<"Points:\n";
cout<<" Num, TestsCover, Count, Name"<<endl;
}
void dump() const {
cout<<" "<<setw(8)<<setfill('0')<<pointNum()
<<", "<<setw(7)<<setfill(' ')<<testsCovering()
<<", "<<setw(7)<<setfill(' ')<<count()
<<", \""<<name()<<"\""<<endl;
}
};
//********************************************************************
// VlcPoints - Container of all points
class VlcPoints {
private:
// MEMBERS
typedef std::map<string,vluint64_t> NameMap;
NameMap m_nameMap; //< Name to point-number
vector<VlcPoint> m_points; //< List of all points
vluint64_t m_numPoints; //< Total unique points
public:
// ITERATORS
typedef NameMap ByName;
typedef ByName::iterator iterator;
ByName::iterator begin() { return m_nameMap.begin(); }
ByName::iterator end() { return m_nameMap.end(); }
public:
// CONSTRUCTORS
VlcPoints() {
m_numPoints = 0;
}
~VlcPoints() {}
// METHODS
void dump() {
UINFO(2,"dumpPoints...\n");
VlcPoint::dumpHeader();
for (VlcPoints::ByName::iterator it=begin(); it!=end(); ++it) {
const VlcPoint& point = pointNumber(it->second);
point.dump();
}
}
VlcPoint& pointNumber(vluint64_t num) {
return m_points[num];
}
vluint64_t findAddPoint(const string& name, vluint64_t count) {
vluint64_t pointnum;
NameMap::iterator iter = m_nameMap.find(name);
if (iter != m_nameMap.end()) {
pointnum = iter->second;
m_points[pointnum].countInc(count);
}
else {
pointnum = m_numPoints++;
VlcPoint point (name, pointnum);
point.countInc(count);
m_points.push_back(point);
m_nameMap.insert(make_pair(point.name(), point.pointNum()));
}
return pointnum;
}
};
//######################################################################
#endif // guard

145
src/VlcSource.h Normal file
View File

@ -0,0 +1,145 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: verilator_coverage: Source file to annotate with line coverage
//
// Code available from: http://www.veripool.org/verilator
//
//*************************************************************************
//
// Copyright 2003-2014 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.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _VLCSOURCE_H_
#define _VLCSOURCE_H_ 1
#include "config_build.h"
#include "verilatedos.h"
#include <map>
#include <vector>
//********************************************************************
// VlcColumnCount - count at specific source file, line and column
class VlcSourceCount {
private:
// MEMBERS
int m_lineno; ///< Line number
int m_column; ///< Column number
vluint64_t m_count; ///< Count
bool m_ok; ///< Coverage is above threshold
public:
// CONSTRUCTORS
VlcSourceCount(int lineno, int column) {
m_lineno = lineno;
m_column = column;
m_count = 0;
m_ok = false;
}
~VlcSourceCount() {}
// ACCESSORS
int lineno() const { return m_lineno; }
int column() const { return m_column; }
vluint64_t count() const { return m_count; }
bool ok() const { return m_ok; }
// METHODS
void incCount(vluint64_t count, bool ok) {
m_count += count;
if (ok) m_ok = true;
}
};
//********************************************************************
// VlcSource - source file to annotate
class VlcSource {
public:
// TYPES
typedef map<int,VlcSourceCount> ColumnMap; // Map of {column}
typedef map<int,ColumnMap> LinenoMap; // Map of {lineno}{column}
private:
// MEMBERS
string m_name; //< Name of the source file
bool m_needed; //< Need to annotate; has low coverage
LinenoMap m_lines; //< Map of each annotated line
public:
// CONSTRUCTORS
VlcSource(const string& name) {
m_name = name;
m_needed = false;
}
~VlcSource() {}
// ACCESSORS
const string& name() const { return m_name; }
void needed(bool flag) { m_needed = flag; }
bool needed() const { return m_needed; }
LinenoMap& lines() { return m_lines; }
// METHODS
void incCount(int lineno, int column, vluint64_t count, bool ok) {
LinenoMap::iterator lit = m_lines.find(lineno);
if (lit == m_lines.end()) {
lit = m_lines.insert(make_pair(lineno,ColumnMap())).first;
}
ColumnMap& cmap = lit->second;
ColumnMap::iterator cit = cmap.find(column);
if (cit == cmap.end()) {
cit = cmap.insert(make_pair(column,VlcSourceCount(lineno, column))).first;
}
VlcSourceCount& sc = cit->second;
sc.incCount(count,ok);
}
};
//********************************************************************
// VlcSources - Container of all source files
class VlcSources {
public:
// TYPES
typedef map<string,VlcSource> NameMap;
private:
// MEMBERS
NameMap m_sources; //< List of all sources
public:
// ITERATORS
typedef NameMap::iterator iterator;
NameMap::iterator begin() { return m_sources.begin(); }
NameMap::iterator end() { return m_sources.end(); }
public:
// CONSTRUCTORS
VlcSources() {}
~VlcSources() {}
// METHODS
VlcSource& findNewSource(const string& name) {
NameMap::iterator iter = m_sources.find(name);
if (iter != m_sources.end()) {
return iter->second;
}
else {
iter = m_sources.insert(make_pair(name, VlcSource(name))).first;
return iter->second;
}
}
};
//######################################################################
#endif // Guard

137
src/VlcTest.h Normal file
View File

@ -0,0 +1,137 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: verilator_coverage: Test/coverage file container
//
// Code available from: http://www.veripool.org/verilator
//
//*************************************************************************
//
// Copyright 2003-2014 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.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _VLCTEST_H_
#define _VLCTEST_H_ 1
#include "config_build.h"
#include "verilatedos.h"
#include "VlcPoint.h"
#include "VlcBucket.h"
#include <map>
#include <vector>
//********************************************************************
// VlcTest - a single testrun i.e. a file containing coverage data
class VlcTest {
private:
// MEMBERS
string m_name; //< Name of the test
double m_computrons; //< Runtime for the test
vluint64_t m_testrun; //< Test run number, for database use
vluint64_t m_rank; //< Execution rank suggestion
vluint64_t m_rankPoints; //< Ranked additional points
vluint64_t m_user; //< User data for algorithms (not persisted in .dat file)
VlcBuckets m_buckets; //< Coverage data for each coverage point
public:
// CONSTRUCTORS
VlcTest(const string& name, vluint64_t testrun, double comp) {
m_name = name;
m_computrons = comp;
m_testrun = testrun;
m_rank = 0;
m_rankPoints = 0;
m_user = 0;
}
~VlcTest() {}
// ACCESSORS
const string& name() const { return m_name; }
double computrons() const { return m_computrons; }
vluint64_t testrun() const { return m_testrun; }
VlcBuckets& buckets() { return m_buckets; }
vluint64_t bucketsCovered() const { return m_buckets.bucketsCovered(); }
vluint64_t rank() const { return m_rank; }
void rank(vluint64_t flag) { m_rank = flag; }
vluint64_t rankPoints() const { return m_rankPoints; }
void rankPoints(vluint64_t flag) { m_rankPoints = flag; }
vluint64_t user() const { return m_user; }
void user(vluint64_t flag) { m_user = flag; }
// METHODS
static void dumpHeader() {
cout<<"Tests:\n";
//cout<<" Testrun, Computrons,"; // Currently not loaded
cout<<" Covered, Rank, RankPts, Filename"<<endl;
}
void dump(bool bucketsToo) {
if (testrun() || computrons()) {
cout<<" "<<setw(8)<<setfill('0')<<testrun()
<<", "<<setw(7)<<setfill(' ')<<computrons()<<",";
}
cout<<" "<<setw(7)<<setfill(' ')<<bucketsCovered()
<<", "<<setw(7)<<setfill(' ')<<rank()
<<", "<<setw(7)<<setfill(' ')<<rankPoints()
<<", \""<<name()<<"\""<<endl;
if (bucketsToo) m_buckets.dump();
}
};
//********************************************************************
// VlcTests - Container of all tests
class VlcTests {
public:
// TYPES
typedef vector<VlcTest*> ByName;
private:
// MEMBERS
ByName m_tests; //< List of all tests
public:
// ITERATORS
typedef ByName::iterator iterator;
ByName::iterator begin() { return m_tests.begin(); }
ByName::iterator end() { return m_tests.end(); }
public:
// CONSTRUCTORS
VlcTests() {}
~VlcTests() {
for (VlcTests::ByName::iterator it=begin(); it!=end(); ++it) {
delete *it; *it=NULL;
}
}
// METHODS
void dump(bool bucketsToo) {
UINFO(2,"dumpTests...\n");
VlcTest::dumpHeader();
for (VlcTests::ByName::iterator it=begin(); it!=end(); ++it) {
(*it)->dump(bucketsToo);
}
}
VlcTest* newTest(const string& name, vluint64_t testrun, double comp) {
VlcTest* testp = new VlcTest(name, testrun, comp);
m_tests.push_back(testp);
return testp;
}
void clearUser() {
for (ByName::iterator it = m_tests.begin(); it != m_tests.end(); ++it) {
(*it)->user(0);
}
}
};
//######################################################################
#endif // Guard

263
src/VlcTop.cpp Normal file
View File

@ -0,0 +1,263 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: verilator_coverage: top implementation
//
// Code available from: http://www.veripool.org/verilator
//
//*************************************************************************
//
// Copyright 2003-2014 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.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
// Cheat for speed and compile .cpp files into one object
#include "V3Error.h"
#include "VlcOptions.h"
#include "VlcTop.h"
#include <sys/stat.h>
#include <fstream>
#include <algorithm>
//######################################################################
void VlcTop::readCoverage(const string& filename, bool nonfatal) {
UINFO(2,"readCoverage "<<filename<<endl);
ifstream is (filename.c_str());
if (!is) {
if (!nonfatal) v3fatal("Can't read "<<filename);
return;
}
// Testrun and computrons argument unsupported as yet
VlcTest* testp = tests().newTest(filename, 0, 0);
while (!is.eof()) {
string line;
getline(is, line);
//UINFO(9," got "<<line<<endl);
if (line[0] == 'C') {
string::size_type secspace=3;
for (; secspace<line.length(); secspace++) {
if (line[secspace]=='\'' && line[secspace+1]==' ') break;
}
string point = line.substr(3,secspace-3);
vluint64_t hits = atoll(line.c_str()+secspace+1);
//UINFO(9," point '"<<point<<"'"<<" "<<hits<<endl);
vluint64_t pointnum = points().findAddPoint(point, hits);
if (pointnum) {} // Prevent unused
if (opt.rank()) { // Only if ranking - uses a lot of memory
if (hits >= VlcBuckets::sufficient()) {
points().pointNumber(pointnum).testsCoveringInc();
testp->buckets().addData(pointnum, hits);
}
}
}
}
}
void VlcTop::writeCoverage(const string& filename) {
UINFO(2,"writeCoverage "<<filename<<endl);
ofstream os (filename.c_str());
if (!os) {
v3fatal("Can't write "<<filename);
return;
}
os << "# SystemC::Coverage-3" << endl;
for (VlcPoints::ByName::iterator it=m_points.begin(); it!=m_points.end(); ++it) {
const VlcPoint& point = m_points.pointNumber(it->second);
os <<"C '"<<point.name()<<"' " << point.count()<<endl;
}
}
//********************************************************************
struct CmpComputrons {
inline bool operator () (const VlcTest* lhsp, const VlcTest* rhsp) const {
if (lhsp->computrons() != rhsp->computrons()) {
return lhsp->computrons() < rhsp->computrons();
}
return lhsp->bucketsCovered() > rhsp->bucketsCovered();
}
};
void VlcTop::rank() {
UINFO(2,"rank...\n");
vluint64_t nextrank=1;
// Sort by computrons, so fast tests get selected first
vector<VlcTest*> bytime;
for (VlcTests::ByName::iterator it=m_tests.begin(); it!=m_tests.end(); ++it) {
VlcTest* testp = *it;
if (testp->bucketsCovered()) { // else no points, so can't help us
bytime.push_back(*it);
}
}
sort(bytime.begin(), bytime.end(), CmpComputrons()); // Sort the vector
VlcBuckets remaining;
for (VlcPoints::ByName::iterator it=m_points.begin(); it!=m_points.end(); ++it) {
VlcPoint* pointp = &points().pointNumber(it->second);
// If any tests hit this point, then we'll need to cover it.
if (pointp->testsCovering()) { remaining.addData(pointp->pointNum(), 1); }
}
// Additional Greedy algorithm
// O(n^2) Ouch. Probably the thing to do is randomize the order of data
// then hierarchically solve a small subset of tests, and take resulting
// solution and move up to larger subset of tests. (Aka quick sort.)
while (1) {
if (debug()) { UINFO(9,"Left on iter"<<nextrank<<": "); remaining.dump(); }
VlcTest* bestTestp = NULL;
vluint64_t bestRemain = 0;
for (vector<VlcTest*>::iterator it=bytime.begin(); it!=bytime.end(); ++it) {
VlcTest* testp = *it;
if (!testp->rank()) {
vluint64_t remain = testp->buckets().dataPopCount(remaining);
if (remain > bestRemain) {
bestTestp = testp;
bestRemain = remain;
}
}
}
if (VlcTest* testp = bestTestp) {
testp->rank(nextrank++);
testp->rankPoints(bestRemain);
remaining.orData(bestTestp->buckets());
} else {
break; // No test covering more stuff found
}
}
}
//######################################################################
void VlcTop::annotateCalc() {
// Calculate per-line information into filedata structure
for (VlcPoints::ByName::iterator it=m_points.begin(); it!=m_points.end(); ++it) {
const VlcPoint& point = m_points.pointNumber(it->second);
string filename = point.filename();
int lineno = point.lineno();
if (filename!="" && lineno!=0) {
int column = point.column();
VlcSource& source = sources().findNewSource(filename);
string threshStr = point.thresh();
unsigned thresh = (threshStr!="") ? atoi(threshStr.c_str()) : opt.annotateMin();
bool ok = (point.count() >= thresh);
UINFO(9, "AnnoCalc count "<<filename<<" "<<lineno<<" "<<point.count()<<endl);
source.incCount(lineno, column, point.count(), ok);
}
}
}
void VlcTop::annotateCalcNeeded() {
// Compute which files are needed. A file isn't needed if it has appropriate
// coverage in all categories
int totCases = 0;
int totOk = 0;
for (VlcSources::NameMap::iterator sit=m_sources.begin(); sit!=m_sources.end(); ++sit) {
VlcSource& source = sit->second;
//UINFO(1,"Source "<<source.name()<<endl);
if (opt.annotateAll()) source.needed(true);
VlcSource::LinenoMap& lines = source.lines();
for (VlcSource::LinenoMap::iterator lit=lines.begin(); lit!=lines.end(); ++lit) {
VlcSource::ColumnMap& cmap = lit->second;
for (VlcSource::ColumnMap::iterator cit=cmap.begin(); cit!=cmap.end(); ++cit) {
VlcSourceCount& col = cit->second;
//UINFO(0,"Source "<<source.name()<<" lineno="<<col.lineno()<<" col="<<col.column()<<endl);
++totCases;
if (col.ok()) {
++totOk;
} else {
source.needed(true);
}
}
}
}
float pct = totCases ? (100*totOk / totCases) : 0;
cout<<"Total coverage ("<<totOk<<"/"<<totCases<<") "
<<fixed<<setw(3)<<setprecision(2)<<pct<<"%"<<endl;
if (totOk != totCases) cout<<"See lines with '%00' in "<<opt.annotateOut()<<endl;
}
void VlcTop::annotateOutputFiles(const string& dirname) {
// Create if uncreated, ignore errors
mkdir(dirname.c_str(), 0777);
for (VlcSources::NameMap::iterator sit=m_sources.begin(); sit!=m_sources.end(); ++sit) {
VlcSource& source = sit->second;
if (!source.needed()) continue;
string filename = source.name();
string outfilename = dirname+"/"+VlcOptions::filenameNonDir(filename);
UINFO(1,"annotateOutputFile "<<filename<<" -> "<<outfilename<<endl);
ifstream is (filename.c_str());
if (!is) {
v3error("Can't read "<<filename);
return;
}
ofstream os (outfilename.c_str());
if (!os) {
v3fatal("Can't write "<<outfilename);
return;
}
os << "\t// verilator_coverage annotation"<<endl;
int lineno = 0;
while (!is.eof()) {
lineno++;
string line;
getline(is, line);
bool first = true;
VlcSource::LinenoMap& lines = source.lines();
VlcSource::LinenoMap::iterator lit=lines.find(lineno);
if (lit != lines.end()) {
VlcSource::ColumnMap& cmap = lit->second;
for (VlcSource::ColumnMap::iterator cit=cmap.begin(); cit!=cmap.end(); ++cit) {
VlcSourceCount& col = cit->second;
//UINFO(0,"Source "<<source.name()<<" lineno="<<col.lineno()<<" col="<<col.column()<<endl);
os<<(col.ok()?" ":"%")
<<setfill('0')<<setw(6)<<col.count()
<<"\t"<<line<<endl;
if (first) {
first = false;
// Multiple columns on same line; print line just once
string indent = "";
for (const char* cp=line.c_str(); isspace(*cp); ++cp) {
indent += *cp;
}
line = indent + "verilator_coverage: (next point on previous line)\n";
}
}
}
if (first) {
os<<"\t"<<line<<endl;
}
}
}
}
void VlcTop::annotate(const string& dirname) {
// Calculate per-line information into filedata structure
annotateCalc();
annotateCalcNeeded();
annotateOutputFiles(dirname);
}

69
src/VlcTop.h Normal file
View File

@ -0,0 +1,69 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: verilator_coverage: Top global container
//
// Code available from: http://www.veripool.org/verilator
//
//*************************************************************************
//
// Copyright 2003-2014 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.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _VLCTOP_H_
#define _VLCTOP_H_ 1
#include "config_build.h"
#include "verilatedos.h"
#include "VlcOptions.h"
#include "VlcTest.h"
#include "VlcPoint.h"
#include "VlcSource.h"
//######################################################################
// VlcTop - Top level options container
class VlcTop {
public:
// PUBLIC MEMBERS
VlcOptions opt; //< Runtime options
private:
// MEMBERS
VlcTests m_tests; //< List of all tests (all coverage files)
VlcPoints m_points; //< List of all points
VlcSources m_sources; //< List of all source files to annotate
// METHODS
void annotateCalc();
void annotateCalcNeeded();
void annotateOutputFiles(const string& dirname);
public:
// CONSTRUCTORS
VlcTop() {}
~VlcTop() {}
// ACCESSORS
VlcTests& tests() { return m_tests; }
VlcPoints& points() { return m_points; }
VlcSources& sources() { return m_sources; }
// METHODS
void annotate(const string& dirname);
void readCoverage(const string& filename, bool nonfatal=false);
void writeCoverage(const string& filename);
void rank();
};
//######################################################################
#endif // guard

View File

@ -19,8 +19,8 @@ my @Opt_Cpt;
my @Opt_I;
Getopt::Long::config ("pass_through", "no_auto_abbrev");
if (! GetOptions (
"help" => \&report,
"debug" => \&debug,
"help" => \&usage,
"debug" => sub { $Debug = 1; },
"classes!" => \$opt_classes,
"report!" => \$opt_report,
"<>" => \&parameter,
@ -54,10 +54,6 @@ sub usage {
exit (1);
}
sub debug {
$Debug = 1;
}
sub parameter {
my $param = shift;
if ($param =~ /^-+I(\S+)/) {

173
src/vlcovgen Executable file
View File

@ -0,0 +1,173 @@
#!/usr/bin/perl -w
# See copyright, etc in below POD section.
######################################################################
#require 5.006_001;
use Getopt::Long;
use IO::File;
use Pod::Usage;
use strict;
use vars qw ($Debug);
our @Items;
#======================================================================
# main
$Debug = 0;
my $Opt_Srcdir = ".";
Getopt::Long::config ("pass_through", "no_auto_abbrev");
if (! GetOptions (
"help" => \&usage,
"debug" => sub { $Debug = 1; },
"srcdir=s" => \$Opt_Srcdir,
"<>" => sub { die "%Error: Unknown parameter: $_[0],"; },
)) {
usage();
}
read_keys("$Opt_Srcdir/../include/verilated_cov_key.h");
lint();
write_keys("$Opt_Srcdir/../include/verilated_cov_key.h");
#----------------------------------------------------------------------
sub usage {
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
exit (1);
}
#######################################################################
sub read_keys {
my $filename = shift;
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename,";
while (defined (my $line = $fh->getline())) {
$line =~ s/\/\/.*$//;
next if $line =~ /^\s*$/;
if ($line =~ /^\s*VLCOVGEN_ITEM/) {
$line =~ /^\s*VLCOVGEN_ITEM *\( *"([^"]+)" *\)/
or die "%Error: $filename:$.: Misformed VLCOVGEN_ITEM line,";
my @data;
my $code = "\@data = ($1);";
eval $code;
die "%Error: $filename:$.: Parsing '$code': $@," if $@;
push @Items, {@data};
}
}
}
#######################################################################
sub lint {
my %shorts;
my $ok = 1;
foreach my $itemref (@Items) {
if ($shorts{$itemref->{short}}) {
warn "%Error: Duplicate short code: $itemref->{short},";
$ok = 0;
}
$shorts{$itemref->{short}} = 1;
}
return $ok;
}
sub write_keys {
my $filename = shift;
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename\n";
my @in;
my @out;
my $deleting;
while (defined(my $line = $fh->getline)) {
push @in, $line;
if ($line =~ /VLCOVGEN_CIK_AUTO_EDIT_BEGIN/) {
$deleting = 1;
push @out, $line;
foreach my $keyref (sort {$a->{name} cmp $b->{name}} @Items) {
push @out, sprintf("#define VL_CIK_%s \"%s\"\n",
uc $keyref->{name}, $keyref->{short});
}
}
elsif ($line =~ /VLCOVGEN_SHORT_AUTO_EDIT_BEGIN/) {
$deleting = 1;
push @out, $line;
foreach my $keyref (sort {$a->{name} cmp $b->{name}} @Items) {
push @out, sprintf("\tif (key == \"%s\") return VL_CIK_%s;\n",
$keyref->{name}, uc $keyref->{name});
}
}
elsif ($line =~ /VLCOVGEN_.*AUTO_EDIT_END/) {
$deleting = 0;
push @out, $line;
}
elsif ($deleting) {
}
else {
push @out, $line;
}
}
$fh->close;
my $ok = join("", @out) eq join("", @in);
if (!$ok) {
my $fh = IO::File->new(">$filename") or die "%Error: $! writing $filename\n";
$fh->print(join "", @out);
$fh->close;
}
}
#######################################################################
__END__
=pod
=head1 NAME
vlcovgen - Generate verilated_cov headers to reduce C++ code duplication
=head1 SYNOPSIS
(called from make rules)
vlcovgen
=head1 DESCRIPTION
Generates several files for Verilator compilations.
=head1 ARGUMENTS
=over 4
=item --help
Displays this message and program version and exits.
=back
=head1 DISTRIBUTION
Copyright 2002-2014 by Wilson Snyder. Verilator 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.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
=head1 AUTHORS
Wilson Snyder <wsnyder@wsnyder.org>
=head1 SEE ALSO
=cut
######################################################################
### Local Variables:
### compile-command: "./vlcovgen --srcdir ."
### End:

View File

@ -388,7 +388,7 @@ sub new {
$self->{stats} ||= "$self->{obj_dir}/V".$self->{name}."__stats.txt";
$self->{status_filename} ||= "$self->{obj_dir}/V".$self->{name}.".status";
$self->{run_log_filename} ||= "$self->{obj_dir}/vlt_sim.log";
$self->{coverage_filename} ||= "$self->{obj_dir}/vlt_coverage.pl";
$self->{coverage_filename} ||= "$self->{obj_dir}/coverage.dat";
$self->{vcd_filename} ||= "$self->{obj_dir}/sim.vcd";
$self->{main_filename} ||= "$self->{obj_dir}/$self->{VM_PREFIX}__main.cpp";
($self->{top_filename} = $self->{pl_filename}) =~ s/\.pl$//;
@ -1143,7 +1143,7 @@ sub _make_main {
if ($self->{coverage}) {
$fh->print("#if VM_COVERAGE\n");
$fh->print(" SpCoverage::write(\"",$self->{coverage_filename},"\");\n");
$fh->print(" VerilatedCov::write(\"",$self->{coverage_filename},"\");\n");
$fh->print("#endif //VM_COVERAGE\n");
}
if ($self->{trace}) {

View File

@ -0,0 +1,170 @@
// verilator_coverage annotation
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2008 by Wilson Snyder.
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));
always @ (posedge clk) begin
000010 if (cyc!=0) begin
cyc <= cyc + 1;
toggle <= '0;
%000001 if (cyc==3) begin
toggle <= '1;
end
%000001 else if (cyc==5) begin
`ifdef VERILATOR
$c("call_task();");
`else
call_task();
`endif
end
%000001 else if (cyc==10) begin
$write("*-* All Finished *-*\n");
$finish;
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
%000002 if (toggle) begin
// CHECK_COVER(-1,"top.v.a*",2)
// t.a1 and t.a2 collapse to a count of 2
end
if (toggle) begin
// CHECK_COVER_MISSING(-1)
// This doesn't even get added
// verilator coverage_block_off
$write("");
end
end
endmodule
module beta (/*AUTOARG*/
// Inputs
clk, toggle
);
input clk;
input toggle;
/* verilator public_module */
always @ (posedge clk) begin
%000000 if (0) begin
// CHECK_COVER(-1,"top.v.b*",0)
// Make sure that we don't optimize away zero buckets
end
%000002 if (toggle) begin
// CHECK_COVER(-1,"top.v.b*",2)
// t.b1 and t.b2 collapse to a count of 2
end
if (toggle) begin
// CHECK_COVER_MISSING(-1)
// This doesn't
// verilator coverage_block_off
$write("");
end
end
endmodule
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
%000001 if (toggle) begin
// CHECK_COVER(-1,"top.v.t1",1)
end
%000001 if (external) begin
// CHECK_COVER(-1,"top.v.t1",1)
$write("[%0t] Got external pulse\n", $time);
end
end
endtask
endmodule
module off (/*AUTOARG*/
// Inputs
clk, toggle
);
input clk;
input toggle;
// verilator coverage_off
always @ (posedge clk) begin
if (toggle) begin
// CHECK_COVER_MISSING(-1)
// because under coverage_module_off
end
end
// verilator coverage_on
always @ (posedge clk) begin
%000001 if (toggle) begin
// CHECK_COVER(-1,"top.v.o1",1)
// because under coverage_module_off
end
end
endmodule

View File

@ -20,5 +20,12 @@ execute (
# Read the input .v file and do any CHECK_COVER requests
inline_checks();
ok(1);
$Self->_run(cmd=>["../bin/verilator_coverage",
"--annotate", "$Self->{obj_dir}/annotated",
"$Self->{obj_dir}/coverage.dat",
],
);
ok(files_identical("$Self->{obj_dir}/annotated/t_cover_line.v", "t/t_cover_line.out"));
1;

View File

@ -11,6 +11,7 @@ $Self->{vlt} or $Self->skip("Verilator only test");
foreach my $prog (
"../bin/verilator",
"../bin/verilator_coverage",
"../bin/verilator_difftree",
"../bin/verilator_profcfunc",
) {

View File

@ -0,0 +1,5 @@
# SystemC::Coverage-3
C 'CoverPoint0ffile1.sphl159' 0
C 'CoverPoint1ffile1.sphl159' 1
C 'CoverPoint2ffile1.sphl159' 10
C 'CoverPoint3ffile1.sphl159' 0

View File

@ -0,0 +1,5 @@
# SystemC::Coverage-3
C 'CoverPoint2ffile1.sphl159' 10
C 'CoverPoint3ffile1.sphl159' 0
C 'CoverPoint4ffile1.sphl159' 1
C 'CoverPoint5ffile1.sphl159' 9

View File

@ -0,0 +1,2 @@
# SystemC::Coverage-3
C 'CoverPoint6ffile1.sphl159' 10

View File

@ -0,0 +1,2 @@
# SystemC::Coverage-3
C 'CoverPoint6ffile1.sphl159' 12

View File

@ -0,0 +1,8 @@
# SystemC::Coverage-3
C 'CoverPoint0ffile1.sphl159' 0
C 'CoverPoint1ffile1.sphl159' 1
C 'CoverPoint2ffile1.sphl159' 20
C 'CoverPoint3ffile1.sphl159' 0
C 'CoverPoint4ffile1.sphl159' 1
C 'CoverPoint5ffile1.sphl159' 9
C 'CoverPoint6ffile1.sphl159' 22

21
test_regress/t/t_vlcov_merge.pl Executable file
View File

@ -0,0 +1,21 @@
#!/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.
$Self->{vlt} or $Self->skip("Verilator only test");
$Self->_run(cmd=>["../bin/verilator_coverage",
"--write", "$Self->{obj_dir}/coverage.dat",
"t/t_vlcov_data_a.dat",
"t/t_vlcov_data_b.dat",
"t/t_vlcov_data_c.dat",
"t/t_vlcov_data_d.dat",
],
);
ok(files_identical("$Self->{obj_dir}/coverage.dat", "t/$Self->{name}.out"));
1;

View File

@ -0,0 +1,6 @@
Tests:
Covered, Rank, RankPts, Filename
2, 2, 1, "t/t_vlcov_data_a.dat"
3, 1, 3, "t/t_vlcov_data_b.dat"
1, 3, 1, "t/t_vlcov_data_c.dat"
1, 0, 0, "t/t_vlcov_data_d.dat"

23
test_regress/t/t_vlcov_rank.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-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.
$Self->{vlt} or $Self->skip("Verilator only test");
$Self->_run(cmd=>["../bin/verilator_coverage",
"--rank",
"t/t_vlcov_data_a.dat",
"t/t_vlcov_data_b.dat",
"t/t_vlcov_data_c.dat",
"t/t_vlcov_data_d.dat",
],
logfile=>"$Self->{obj_dir}/vlcov.log",
tee => 0,
);
ok(files_identical("$Self->{obj_dir}/vlcov.log", "t/$Self->{name}.out"));
1;

View File

@ -0,0 +1,25 @@
#!/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.
$Self->{vlt} or $Self->skip("Verilator only test");
foreach my $basename ("t_vlcov_data_a.dat",
"t_vlcov_data_b.dat",
"t_vlcov_data_c.dat",
"t_vlcov_data_d.dat",
) {
$Self->_run(cmd=>["../bin/verilator_coverage",
"t/${basename}",
"--write", "$Self->{obj_dir}/${basename}"
],
tee=>0,
);
ok(files_identical("$Self->{obj_dir}/${basename}", "t/${basename}"));
}
1;

View File

@ -25,9 +25,9 @@ DEBUG_ON = --debug --trace-dups
######################################################################
ifneq ($(SYSTEMPERL),)
test_default: precopy prep preproc compile run coverage
test_debug: precopy prep_dbg preproc compile_dbg run coverage
test_nopublic: precopy prep_dbg_np preproc compile_dbg run coverage
test_default: precopy prep preproc compile run
test_debug: precopy prep_dbg preproc compile_dbg run
test_nopublic: precopy prep_dbg_np preproc compile_dbg run
else
test_default: nosp
test_debug: nosp
@ -39,7 +39,7 @@ V_FLAGS = -f $(VERILATOR_ROOT)/test_v/input.vc
# Note the --public --output-split-cfunc is here for testing only,
# Avoid using these settings in real application Makefiles!
VERILATOR_FLAGS = --public --output-split-cfuncs 1000 --output-split 1000 \
--sp --coverage --stats --trace $(V_FLAGS) top.v
--sp --stats --trace $(V_FLAGS) top.v
precopy: obj_dir obj_dir/sc_main.cpp
obj_dir/sc_main.cpp: ../test_sc/sc_main.cpp
@ -66,7 +66,7 @@ run:
obj_dir/simx
coverage:
vcoverage $(V_FLAGS)
$(VERILATOR_ROOT)/bin/verilator_coverage $(V_FLAGS)
######################################################################