verilator/src/V3Coverage.cpp
Wilson Snyder b5b1d94d4a Copyright date update
git-svn-id: file://localhost/svn/verilator/trunk/verilator@864 77ca24e4-aefa-0310-84f0-b9a241c72d87
2007-01-02 22:06:40 +00:00

166 lines
5.3 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// $Id$
//*************************************************************************
// DESCRIPTION: Verilator: Netlist (top level) functions
//
// Code available from: http://www.veripool.com/verilator
//
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
//
//*************************************************************************
//
// Copyright 2003-2007 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// General Public License or the Perl Artistic License.
//
// 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.
//
//*************************************************************************
// COVERAGE TRANSFORMATIONS:
// At each IF/(IF else)/CASEITEM,
// If there's no coverage off on the block below it,
// or a $stop
// Insert a COVERDECL node in the module.
// (V3Emit reencodes into per-module numbers for emitting.)
// Insert a COVERINC node at the end of the statement list
// for that if/else/case.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <map>
#include "V3Global.h"
#include "V3Coverage.h"
#include "V3Ast.h"
#include "V3Const.h"
//######################################################################
// Coverage state, as a visitor of each AstNode
class CoverageVisitor : public AstNVisitor {
private:
// TYPES
typedef map<FileLine*,int> FileMap;
// STATE
bool m_checkBlock; // Should this block get covered?
AstModule* m_modp; // Current module to add statement to
FileMap m_fileps; // Column counts for each fileline
//int debug() { return 9; }
// METHODS
AstCoverInc* newCoverInc(FileLine* fl, const string& type, const string& comment) {
int column = 0;
FileMap::iterator it = m_fileps.find(fl);
if (it == m_fileps.end()) {
m_fileps.insert(make_pair(fl,column+1));
} else {
column = (it->second)++;
}
AstCoverDecl* declp = new AstCoverDecl(fl, column, type, comment);
m_modp->addStmtp(declp);
return new AstCoverInc(fl, declp);
}
// VISITORS
virtual void visit(AstModule* nodep, AstNUser*) {
m_modp = nodep;
m_fileps.clear();
nodep->iterateChildren(*this);
m_modp = NULL;
}
virtual void visit(AstIf* nodep, AstNUser*) {
UINFO(4," IF: "<<nodep<<endl);
if (m_checkBlock) {
nodep->ifsp()->iterateAndNext(*this);
if (m_checkBlock && v3Global.opt.coverageLine()) { // if a "if" branch didn't disable it
if (!nodep->backp()->castIf()
|| nodep->backp()->castIf()->elsesp()!=nodep) { // Ignore if else; did earlier
UINFO(4," COVER: "<<nodep<<endl);
nodep->addIfsp(newCoverInc(nodep->fileline(), "block", "if"));
}
}
// Don't do empty else's, only empty if/case's
if (nodep->elsesp()) {
m_checkBlock = true;
nodep->elsesp()->iterateAndNext(*this);
if (m_checkBlock && v3Global.opt.coverageLine()) { // if a "else" branch didn't disable it
UINFO(4," COVER: "<<nodep<<endl);
if (nodep->elsesp()->castIf()) {
nodep->addElsesp(newCoverInc(nodep->elsesp()->fileline(), "block", "elsif"));
} else {
nodep->addElsesp(newCoverInc(nodep->elsesp()->fileline(), "block", "else"));
}
}
}
m_checkBlock = true; // Reset as a child may have cleared it
}
}
virtual void visit(AstCaseItem* nodep, AstNUser*) {
UINFO(4," CASEI: "<<nodep<<endl);
if (m_checkBlock && v3Global.opt.coverageLine()) {
nodep->bodysp()->iterateAndNext(*this);
if (m_checkBlock) { // if the case body didn't disable it
UINFO(4," COVER: "<<nodep<<endl);
nodep->addBodysp(newCoverInc(nodep->fileline(), "block", "case"));
}
m_checkBlock = true; // Reset as a child may have cleared it
}
}
virtual void visit(AstPslCover* nodep, AstNUser*) {
UINFO(4," PSLCOVER: "<<nodep<<endl);
nodep->iterateChildren(*this);
if (!nodep->coverincp()) {
// Note the name may be overridden by V3Assert processing
nodep->coverincp(newCoverInc(nodep->fileline(), "psl_cover", "cover"));
}
}
virtual void visit(AstStop* nodep, AstNUser*) {
UINFO(4," STOP: "<<nodep<<endl);
m_checkBlock = false;
}
virtual void visit(AstPragma* nodep, AstNUser*) {
if (nodep->pragType() == AstPragmaType::COVERAGE_BLOCK_OFF) {
// Skip all NEXT nodes under this block, and skip this if/case branch
UINFO(4," OFF: "<<nodep<<endl);
m_checkBlock = false;
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
}
if (m_checkBlock) nodep->iterateChildren(*this);
}
virtual void visit(AstNode* nodep, AstNUser*) {
// Default: Just iterate
if (m_checkBlock) {
nodep->iterateChildren(*this);
m_checkBlock = true; // Reset as a child may have cleared it
}
}
public:
// CONSTUCTORS
CoverageVisitor(AstNetlist* rootp) {
// Operate on all modules
m_checkBlock = true;
rootp->iterateChildren(*this);
}
virtual ~CoverageVisitor() {}
};
//######################################################################
// Coverage class functions
void V3Coverage::coverage(AstNetlist* rootp) {
UINFO(2,__FUNCTION__<<": "<<endl);
CoverageVisitor visitor (rootp);
}