2012-04-13 03:08:20 +02:00
|
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2006-08-26 13:35:28 +02:00
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
// DESCRIPTION: Verilator: Removal of named begin blocks
|
|
|
|
|
|
//
|
2008-04-25 14:14:27 +02:00
|
|
|
|
// Code available from: http://www.veripool.org/verilator
|
2006-08-26 13:35:28 +02:00
|
|
|
|
//
|
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
//
|
2016-01-07 02:36:41 +01:00
|
|
|
|
// Copyright 2003-2016 by Wilson Snyder. This program is free software; you can
|
2006-08-26 13:35:28 +02:00
|
|
|
|
// redistribute it and/or modify it under the terms of either the GNU
|
2009-05-04 23:07:57 +02:00
|
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
|
|
// Version 2.0.
|
2006-08-26 13:35:28 +02:00
|
|
|
|
//
|
|
|
|
|
|
// 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.
|
|
|
|
|
|
//
|
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
// V3Begin's Transformations:
|
2008-06-10 03:25:10 +02:00
|
|
|
|
//
|
2006-08-26 13:35:28 +02:00
|
|
|
|
// Each module:
|
|
|
|
|
|
// Look for BEGINs
|
|
|
|
|
|
// BEGIN(VAR...) -> VAR ... {renamed}
|
2006-09-05 22:06:23 +02:00
|
|
|
|
// FOR -> WHILEs
|
2006-08-26 13:35:28 +02:00
|
|
|
|
//
|
2009-10-12 02:50:31 +02:00
|
|
|
|
// There are two scopes; named BEGINs change %m and variable scopes.
|
|
|
|
|
|
// Unnamed BEGINs change only variable, not $display("%m") scope.
|
|
|
|
|
|
//
|
2006-08-26 13:35:28 +02:00
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
|
2006-12-18 20:20:45 +01:00
|
|
|
|
#include "config_build.h"
|
|
|
|
|
|
#include "verilatedos.h"
|
2008-06-30 19:11:25 +02:00
|
|
|
|
#include <cstdio>
|
|
|
|
|
|
#include <cstdarg>
|
2006-08-26 13:35:28 +02:00
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
|
|
#include "V3Global.h"
|
|
|
|
|
|
#include "V3Begin.h"
|
|
|
|
|
|
#include "V3Inst.h"
|
|
|
|
|
|
#include "V3Ast.h"
|
|
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
|
|
2012-02-22 04:23:06 +01:00
|
|
|
|
class BeginState {
|
|
|
|
|
|
private:
|
|
|
|
|
|
// NODE STATE
|
|
|
|
|
|
//Entire netlist:
|
|
|
|
|
|
// AstNodeFTask::user1 -> bool, 1=processed
|
|
|
|
|
|
AstUser1InUse m_inuser1;
|
|
|
|
|
|
bool m_anyFuncInBegin;
|
|
|
|
|
|
public:
|
|
|
|
|
|
BeginState() {
|
|
|
|
|
|
m_anyFuncInBegin = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
~BeginState() {}
|
2015-11-14 15:06:09 +01:00
|
|
|
|
void userMarkChanged(AstNode* nodep) {
|
2012-02-22 04:23:06 +01:00
|
|
|
|
nodep->user1(true);
|
|
|
|
|
|
m_anyFuncInBegin = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
bool anyFuncInBegin() const { return m_anyFuncInBegin; }
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
|
class BeginVisitor : public AstNVisitor {
|
|
|
|
|
|
private:
|
|
|
|
|
|
// STATE
|
2012-02-22 04:23:06 +01:00
|
|
|
|
BeginState* m_statep; // Current global state
|
2009-11-07 12:20:20 +01:00
|
|
|
|
AstNodeModule* m_modp; // Current module
|
2006-08-26 13:35:28 +02:00
|
|
|
|
AstNodeFTask* m_ftaskp; // Current function/task
|
2009-10-12 02:50:31 +02:00
|
|
|
|
string m_namedScope; // Name of begin blocks above us
|
|
|
|
|
|
string m_unnamedScope; // Name of begin blocks, including unnamed blocks
|
2009-02-26 04:06:59 +01:00
|
|
|
|
int m_repeatNum; // Repeat counter
|
2010-12-26 15:31:09 +01:00
|
|
|
|
int m_ifDepth; // Current if depth
|
2009-01-21 22:56:50 +01:00
|
|
|
|
|
|
|
|
|
|
// METHODS
|
|
|
|
|
|
static int debug() {
|
|
|
|
|
|
static int level = -1;
|
|
|
|
|
|
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
|
|
|
|
|
|
return level;
|
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
|
|
// VISITORS
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstNodeModule* nodep) {
|
2006-08-26 13:35:28 +02:00
|
|
|
|
m_modp = nodep;
|
2009-02-26 04:06:59 +01:00
|
|
|
|
m_repeatNum = 0;
|
2006-08-26 13:35:28 +02:00
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
m_modp = NULL;
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstNodeFTask* nodep) {
|
2012-02-22 03:25:11 +01:00
|
|
|
|
UINFO(8," "<<nodep<<endl);
|
2012-02-22 04:23:06 +01:00
|
|
|
|
// Rename it
|
|
|
|
|
|
if (m_unnamedScope != "") {
|
|
|
|
|
|
nodep->name(m_unnamedScope+"__DOT__"+nodep->name());
|
|
|
|
|
|
UINFO(8," rename to "<<nodep->name()<<endl);
|
|
|
|
|
|
m_statep->userMarkChanged(nodep);
|
|
|
|
|
|
}
|
2012-02-22 03:25:11 +01:00
|
|
|
|
// BEGIN wrapping a function rename that function, but don't affect the inside function's variables
|
|
|
|
|
|
// We then restart with empty naming; so that any begin's inside the function will rename inside the function
|
2012-02-22 04:23:06 +01:00
|
|
|
|
// Process children
|
2012-02-22 03:25:11 +01:00
|
|
|
|
string oldScope = m_namedScope;
|
|
|
|
|
|
string oldUnnamed = m_unnamedScope;
|
|
|
|
|
|
{
|
|
|
|
|
|
m_namedScope = "";
|
|
|
|
|
|
m_unnamedScope = "";
|
|
|
|
|
|
m_ftaskp = nodep;
|
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
m_ftaskp = NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
m_namedScope = oldScope;
|
|
|
|
|
|
m_unnamedScope = oldUnnamed;
|
2006-08-26 13:35:28 +02:00
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstBegin* nodep) {
|
2006-08-26 13:35:28 +02:00
|
|
|
|
// Begin blocks were only useful in variable creation, change names and delete
|
|
|
|
|
|
UINFO(8," "<<nodep<<endl);
|
2009-10-12 02:50:31 +02:00
|
|
|
|
string oldScope = m_namedScope;
|
|
|
|
|
|
string oldUnnamed = m_unnamedScope;
|
2006-08-26 13:35:28 +02:00
|
|
|
|
{
|
2012-02-22 03:25:11 +01:00
|
|
|
|
UINFO(8,"nname "<<m_namedScope<<endl);
|
2009-10-12 02:50:31 +02:00
|
|
|
|
if (nodep->name() != "") { // Else unneeded unnamed block
|
|
|
|
|
|
// Create data for dotted variable resolution
|
|
|
|
|
|
string dottedname = nodep->name() + "__DOT__"; // So always found
|
|
|
|
|
|
string::size_type pos;
|
|
|
|
|
|
while ((pos=dottedname.find("__DOT__")) != string::npos) {
|
|
|
|
|
|
string ident = dottedname.substr(0,pos);
|
|
|
|
|
|
dottedname = dottedname.substr(pos+strlen("__DOT__"));
|
|
|
|
|
|
if (!nodep->unnamed()) {
|
|
|
|
|
|
if (m_namedScope=="") m_namedScope = ident;
|
|
|
|
|
|
else m_namedScope = m_namedScope + "__DOT__"+ident;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (m_unnamedScope=="") m_unnamedScope = ident;
|
|
|
|
|
|
else m_unnamedScope = m_unnamedScope + "__DOT__"+ident;
|
|
|
|
|
|
// Create CellInline for dotted var resolution
|
2012-08-11 01:39:18 +02:00
|
|
|
|
if (!m_ftaskp) {
|
|
|
|
|
|
AstCellInline* inlinep = new AstCellInline(nodep->fileline(),
|
|
|
|
|
|
m_unnamedScope, "__BEGIN__");
|
|
|
|
|
|
m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells
|
|
|
|
|
|
}
|
2009-10-12 02:50:31 +02:00
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2009-10-12 02:50:31 +02:00
|
|
|
|
// Remap var names and replace lower Begins
|
2011-11-30 00:23:18 +01:00
|
|
|
|
nodep->stmtsp()->iterateAndNext(*this);
|
2012-07-21 23:12:42 +02:00
|
|
|
|
if (nodep->genforp()) nodep->v3fatalSrc("GENFORs should have been expanded earlier");
|
2006-08-26 13:35:28 +02:00
|
|
|
|
}
|
2009-10-12 02:50:31 +02:00
|
|
|
|
m_namedScope = oldScope;
|
|
|
|
|
|
m_unnamedScope = oldUnnamed;
|
2011-11-30 00:23:18 +01:00
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
|
|
|
|
|
AstNode* addsp = NULL;
|
|
|
|
|
|
if (AstNode* stmtsp = nodep->stmtsp()) {
|
|
|
|
|
|
stmtsp->unlinkFrBackWithNext();
|
2013-02-03 19:27:37 +01:00
|
|
|
|
if (addsp) { addsp = addsp->addNextNull(stmtsp); } else { addsp = stmtsp; }
|
2011-11-30 00:23:18 +01:00
|
|
|
|
}
|
|
|
|
|
|
if (addsp) {
|
|
|
|
|
|
nodep->replaceWith(addsp);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
nodep->unlinkFrBack();
|
|
|
|
|
|
}
|
2015-10-04 19:16:35 +02:00
|
|
|
|
pushDeletep(nodep); VL_DANGLING(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstVar* nodep) {
|
2009-10-12 02:50:31 +02:00
|
|
|
|
if (m_unnamedScope != "") {
|
2006-08-26 13:35:28 +02:00
|
|
|
|
// Rename it
|
2009-10-12 02:50:31 +02:00
|
|
|
|
nodep->name(m_unnamedScope+"__DOT__"+nodep->name());
|
2015-11-14 15:06:09 +01:00
|
|
|
|
m_statep->userMarkChanged(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
|
// Move to module
|
|
|
|
|
|
nodep->unlinkFrBack();
|
|
|
|
|
|
if (m_ftaskp) m_ftaskp->addStmtsp(nodep); // Begins under funcs just move into the func
|
|
|
|
|
|
else m_modp->addStmtp(nodep);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstCell* nodep) {
|
2006-08-26 13:35:28 +02:00
|
|
|
|
UINFO(8," CELL "<<nodep<<endl);
|
2009-10-12 02:50:31 +02:00
|
|
|
|
if (m_namedScope != "") {
|
2015-11-14 15:06:09 +01:00
|
|
|
|
m_statep->userMarkChanged(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
|
// Rename it
|
2009-10-12 02:50:31 +02:00
|
|
|
|
nodep->name(m_namedScope+"__DOT__"+nodep->name());
|
2006-08-26 13:35:28 +02:00
|
|
|
|
UINFO(8," rename to "<<nodep->name()<<endl);
|
|
|
|
|
|
// Move to module
|
|
|
|
|
|
nodep->unlinkFrBack();
|
|
|
|
|
|
m_modp->addStmtp(nodep);
|
|
|
|
|
|
}
|
2015-11-14 15:06:09 +01:00
|
|
|
|
nodep->iterateChildren(*this);
|
2006-08-26 13:35:28 +02:00
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstVarXRef* nodep) {
|
2015-12-06 01:39:40 +01:00
|
|
|
|
UINFO(9, " VARXREF "<<nodep<<endl);
|
|
|
|
|
|
if (m_namedScope != "" && nodep->inlinedDots() == "") {
|
|
|
|
|
|
nodep->inlinedDots(m_namedScope);
|
|
|
|
|
|
UINFO(9, " rescope to "<<nodep<<endl);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstScopeName* nodep) {
|
2007-03-06 19:53:24 +01:00
|
|
|
|
// If there's a %m in the display text, we add a special node that will contain the name()
|
|
|
|
|
|
// Similar code in V3Inline
|
2012-08-11 01:39:18 +02:00
|
|
|
|
if (nodep->user1SetOnce()) return; // Don't double-add text's
|
2009-10-12 02:50:31 +02:00
|
|
|
|
if (m_namedScope != "") {
|
2007-03-06 19:53:24 +01:00
|
|
|
|
// To keep correct visual order, must add before other Text's
|
|
|
|
|
|
AstNode* afterp = nodep->scopeAttrp();
|
|
|
|
|
|
if (afterp) afterp->unlinkFrBackWithNext();
|
2009-12-05 16:38:49 +01:00
|
|
|
|
nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"__DOT__"+m_namedScope));
|
2007-03-06 19:53:24 +01:00
|
|
|
|
if (afterp) nodep->scopeAttrp(afterp);
|
|
|
|
|
|
}
|
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstCoverDecl* nodep) {
|
2008-11-05 16:23:03 +01:00
|
|
|
|
// Don't need to fix path in coverage statements, they're not under
|
|
|
|
|
|
// any BEGINs, but V3Coverage adds them all under the module itself.
|
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
}
|
2010-12-26 15:31:09 +01:00
|
|
|
|
// VISITORS - LINT CHECK
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstIf* nodep) { // Note not AstNodeIf; other types don't get covered
|
2010-12-26 15:31:09 +01:00
|
|
|
|
// Check IFDEPTH warning - could be in other transform files if desire
|
|
|
|
|
|
int prevIfDepth = m_ifDepth;
|
|
|
|
|
|
if (m_ifDepth == -1 || v3Global.opt.ifDepth()<1) { // Turned off
|
|
|
|
|
|
} else if (nodep->uniquePragma() || nodep->unique0Pragma() || nodep->priorityPragma()) {
|
|
|
|
|
|
m_ifDepth = -1;
|
|
|
|
|
|
} else if (++m_ifDepth > v3Global.opt.ifDepth()) {
|
|
|
|
|
|
nodep->v3warn(IFDEPTH,"Deep 'if' statement; suggest unique/priority to avoid slow logic");
|
2011-01-19 03:28:51 +01:00
|
|
|
|
nodep->fileline()->modifyWarnOff(V3ErrorCode::IFDEPTH, true); // Warn only once
|
2010-12-26 15:31:09 +01:00
|
|
|
|
m_ifDepth = -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
m_ifDepth = prevIfDepth;
|
2015-12-06 01:39:40 +01:00
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstNode* nodep) {
|
2006-08-26 13:35:28 +02:00
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
}
|
|
|
|
|
|
public:
|
|
|
|
|
|
// CONSTUCTORS
|
2012-02-22 04:23:06 +01:00
|
|
|
|
BeginVisitor(AstNetlist* nodep, BeginState* statep) {
|
|
|
|
|
|
m_statep = statep;
|
2006-08-26 13:35:28 +02:00
|
|
|
|
m_modp = NULL;
|
|
|
|
|
|
m_ftaskp = NULL;
|
2009-02-26 04:06:59 +01:00
|
|
|
|
m_repeatNum = 0;
|
2010-12-26 15:31:09 +01:00
|
|
|
|
m_ifDepth = 0;
|
2006-08-26 13:35:28 +02:00
|
|
|
|
nodep->accept(*this);
|
|
|
|
|
|
}
|
|
|
|
|
|
virtual ~BeginVisitor() {}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2012-02-22 04:23:06 +01:00
|
|
|
|
//######################################################################
|
|
|
|
|
|
|
|
|
|
|
|
class BeginRelinkVisitor : public AstNVisitor {
|
|
|
|
|
|
// Replace tasks with new pointer
|
|
|
|
|
|
private:
|
|
|
|
|
|
// NODE STATE
|
|
|
|
|
|
// Input:
|
|
|
|
|
|
// AstNodeFTask::user1p // Node replaced, rename it
|
|
|
|
|
|
|
|
|
|
|
|
// VISITORS
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstNodeFTaskRef* nodep) {
|
2012-02-22 04:23:06 +01:00
|
|
|
|
if (nodep->taskp()->user1()) { // It was converted
|
|
|
|
|
|
UINFO(9, " relinkFTask "<<nodep<<endl);
|
|
|
|
|
|
nodep->name(nodep->taskp()->name());
|
|
|
|
|
|
}
|
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstVarRef* nodep) {
|
2015-11-14 15:06:09 +01:00
|
|
|
|
if (nodep->varp()->user1()) { // It was converted
|
|
|
|
|
|
UINFO(9, " relinVarRef "<<nodep<<endl);
|
|
|
|
|
|
nodep->name(nodep->varp()->name());
|
|
|
|
|
|
}
|
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstIfaceRefDType* nodep) {
|
2015-11-14 15:06:09 +01:00
|
|
|
|
// May have changed cell names
|
|
|
|
|
|
// TypeTable is always after all modules, so names are stable
|
|
|
|
|
|
UINFO(8," IFACEREFDTYPE "<<nodep<<endl);
|
|
|
|
|
|
if (nodep->cellp()) nodep->cellName(nodep->cellp()->name());
|
|
|
|
|
|
UINFO(8," rename to "<<nodep<<endl);
|
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
}
|
2012-02-22 04:23:06 +01:00
|
|
|
|
//--------------------
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstNode* nodep) {
|
2012-02-22 04:23:06 +01:00
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
}
|
|
|
|
|
|
public:
|
|
|
|
|
|
// CONSTUCTORS
|
|
|
|
|
|
BeginRelinkVisitor(AstNetlist* nodep, BeginState*) {
|
|
|
|
|
|
nodep->accept(*this);
|
|
|
|
|
|
}
|
|
|
|
|
|
virtual ~BeginRelinkVisitor() {}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
|
//######################################################################
|
|
|
|
|
|
// Task class functions
|
|
|
|
|
|
|
|
|
|
|
|
void V3Begin::debeginAll(AstNetlist* nodep) {
|
|
|
|
|
|
UINFO(2,__FUNCTION__<<": "<<endl);
|
2012-02-22 04:23:06 +01:00
|
|
|
|
BeginState state;
|
|
|
|
|
|
{ BeginVisitor bvisitor (nodep,&state); }
|
|
|
|
|
|
if (state.anyFuncInBegin()) {
|
|
|
|
|
|
BeginRelinkVisitor brvisitor (nodep,&state);
|
|
|
|
|
|
}
|
2015-03-13 00:47:54 +01:00
|
|
|
|
V3Global::dumpCheckGlobalTree("begin.tree", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
2006-08-26 13:35:28 +02:00
|
|
|
|
}
|