2012-04-13 01:08:20 +00:00
|
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2006-08-26 11:35:28 +00:00
|
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Rename scope references to module-local references
|
|
|
|
|
//
|
2008-04-25 12:14:27 +00:00
|
|
|
|
// Code available from: http://www.veripool.org/verilator
|
2006-08-26 11:35:28 +00:00
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2013-01-01 14:42:59 +00:00
|
|
|
|
// Copyright 2003-2013 by Wilson Snyder. This program is free software; you can
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// redistribute it and/or modify it under the terms of either the GNU
|
2009-05-04 21:07:57 +00:00
|
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
|
// Version 2.0.
|
2006-08-26 11:35:28 +00: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.
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCOPE TRANSFORMATIONS:
|
|
|
|
|
// All modules:
|
|
|
|
|
// Each VARREF/FUNCCALL
|
|
|
|
|
// Change varref name() to be relative to current module
|
|
|
|
|
// Remove varScopep()
|
|
|
|
|
// This allows for better V3Combine'ing.
|
2008-06-10 01:25:10 +00:00
|
|
|
|
//
|
2006-08-26 11:35:28 +00:00
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
2006-12-18 19:20:45 +00:00
|
|
|
|
#include "config_build.h"
|
|
|
|
|
#include "verilatedos.h"
|
2008-06-30 17:11:25 +00:00
|
|
|
|
#include <cstdio>
|
|
|
|
|
#include <cstdarg>
|
2006-08-26 11:35:28 +00:00
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <map>
|
|
|
|
|
|
|
|
|
|
#include "V3Global.h"
|
|
|
|
|
#include "V3Descope.h"
|
|
|
|
|
#include "V3Ast.h"
|
2006-08-30 21:07:55 +00:00
|
|
|
|
#include "V3EmitCBase.h"
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
|
|
|
|
|
class DescopeVisitor : public AstNVisitor {
|
|
|
|
|
private:
|
|
|
|
|
// NODE STATE
|
|
|
|
|
// Cleared entire netlist
|
|
|
|
|
// AstCFunc::user() // bool. Indicates processing completed
|
2008-11-25 14:03:49 +00:00
|
|
|
|
AstUser1InUse m_inuser1;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
|
|
// TYPES
|
|
|
|
|
typedef multimap<string,AstCFunc*> FuncMmap;
|
|
|
|
|
|
|
|
|
|
// STATE
|
2009-11-07 11:20:20 +00:00
|
|
|
|
AstNodeModule* m_modp; // Current module
|
2006-08-26 11:35:28 +00:00
|
|
|
|
AstScope* m_scopep; // Current scope
|
|
|
|
|
bool m_needThis; // Add thisp to function
|
|
|
|
|
FuncMmap m_modFuncs; // Name of public functions added
|
|
|
|
|
|
|
|
|
|
// METHODS
|
2009-01-21 21:56:50 +00:00
|
|
|
|
static int debug() {
|
|
|
|
|
static int level = -1;
|
|
|
|
|
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
|
|
|
|
|
return level;
|
|
|
|
|
}
|
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
|
string descopedName(AstScope* scopep, bool& hierThisr, AstVar* varp=NULL) {
|
|
|
|
|
UASSERT(scopep, "Var/Func not scoped\n");
|
|
|
|
|
hierThisr = true;
|
|
|
|
|
if (varp && varp->isFuncLocal()) {
|
|
|
|
|
return ""; // Relative to function, not in this
|
2006-08-30 21:07:55 +00:00
|
|
|
|
} else if (scopep == m_scopep && m_modp->isTop()) {
|
|
|
|
|
//return ""; // Reference to scope we're in, no need to HIER-> it
|
|
|
|
|
return "vlTOPp->";
|
|
|
|
|
} else if (scopep == m_scopep && !m_modp->isTop()
|
|
|
|
|
&& 0) { // We no longer thisp-> as still get ambiguation problems
|
|
|
|
|
m_needThis = true;
|
|
|
|
|
return "thisp->"; // this-> but with restricted aliasing
|
2006-08-26 11:35:28 +00:00
|
|
|
|
} else if (scopep->aboveScopep() && scopep->aboveScopep()==m_scopep
|
|
|
|
|
&& 0 // DISABLED: GCC considers the pointers ambiguous, so goes ld/store crazy
|
|
|
|
|
) {
|
|
|
|
|
// Reference to scope of cell directly under this module, can just "cell->"
|
|
|
|
|
string name = scopep->name();
|
|
|
|
|
string::size_type pos;
|
|
|
|
|
if ((pos = name.rfind(".")) != string::npos) {
|
|
|
|
|
name.erase(0,pos+1);
|
|
|
|
|
}
|
|
|
|
|
hierThisr = false;
|
|
|
|
|
return name+"->";
|
|
|
|
|
} else {
|
|
|
|
|
// Reference to something else, use global variable
|
|
|
|
|
UINFO(8," Descope "<<scopep<<endl);
|
|
|
|
|
UINFO(8," to "<<scopep->name()<<endl);
|
|
|
|
|
UINFO(8," under "<<m_scopep->name()<<endl);
|
|
|
|
|
hierThisr = false;
|
|
|
|
|
if (!scopep->aboveScopep()) { // Top
|
2006-08-30 21:07:55 +00:00
|
|
|
|
return "vlTOPp->"; // == "vlSymsp->TOPp->", but GCC would suspect aliases
|
2006-08-26 11:35:28 +00:00
|
|
|
|
} else {
|
|
|
|
|
return scopep->nameVlSym()+".";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void makePublicFuncWrappers() {
|
|
|
|
|
// We recorded all public functions in m_modFuncs.
|
|
|
|
|
// If for any given name only one function exists, we can use that function directly.
|
|
|
|
|
// If multiple functions exist, we need to select the appropriate scope.
|
|
|
|
|
for (FuncMmap::iterator it = m_modFuncs.begin(); it!=m_modFuncs.end(); ++it) {
|
|
|
|
|
string name = it->first;
|
|
|
|
|
AstCFunc* topFuncp = it->second;
|
|
|
|
|
FuncMmap::iterator nextIt1 = it; ++nextIt1;
|
|
|
|
|
bool moreOfSame1 = (nextIt1!=m_modFuncs.end() && nextIt1->first == name);
|
|
|
|
|
if (moreOfSame1) {
|
|
|
|
|
// Multiple functions under this name, need a wrapper function
|
|
|
|
|
UINFO(6," Wrapping "<<name<<" multifuncs\n");
|
2008-11-20 01:15:05 +00:00
|
|
|
|
AstCFunc* newfuncp = topFuncp->cloneTree(false);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
if (newfuncp->initsp()) newfuncp->initsp()->unlinkFrBackWithNext()->deleteTree();
|
|
|
|
|
if (newfuncp->stmtsp()) newfuncp->stmtsp()->unlinkFrBackWithNext()->deleteTree();
|
|
|
|
|
if (newfuncp->finalsp()) newfuncp->finalsp()->unlinkFrBackWithNext()->deleteTree();
|
|
|
|
|
newfuncp->name(name);
|
2006-08-30 22:00:55 +00:00
|
|
|
|
newfuncp->isStatic(false);
|
2006-08-30 21:07:55 +00:00
|
|
|
|
newfuncp->addInitsp(
|
|
|
|
|
new AstCStmt(newfuncp->fileline(),
|
2009-12-03 00:32:41 +00:00
|
|
|
|
EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
|
2009-12-02 02:55:56 +00:00
|
|
|
|
newfuncp->addInitsp(new AstCStmt(newfuncp->fileline(), EmitCBaseVisitor::symTopAssign()+"\n"));
|
2006-08-26 11:35:28 +00:00
|
|
|
|
topFuncp->addNextHere(newfuncp);
|
|
|
|
|
// In the body, call each function if it matches the given scope
|
|
|
|
|
for (FuncMmap::iterator eachIt = it; eachIt!=m_modFuncs.end() && eachIt->first==name; ++eachIt) {
|
|
|
|
|
it = eachIt;
|
|
|
|
|
AstCFunc* funcp = eachIt->second;
|
|
|
|
|
FuncMmap::iterator nextIt2 = eachIt; ++nextIt2;
|
|
|
|
|
bool moreOfSame = (nextIt2!=m_modFuncs.end() && nextIt2->first == name);
|
|
|
|
|
if (!funcp->scopep()) funcp->v3fatalSrc("Not scoped");
|
|
|
|
|
|
|
|
|
|
UINFO(6," Wrapping "<<name<<" "<<funcp<<endl);
|
|
|
|
|
UINFO(6," at "<<newfuncp->argTypes()<<" und "<<funcp->argTypes()<<endl);
|
|
|
|
|
funcp->declPrivate(true);
|
|
|
|
|
AstNode* argsp = NULL;
|
|
|
|
|
for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp=stmtp->nextp()) {
|
|
|
|
|
if (AstVar* portp = stmtp->castVar()) {
|
|
|
|
|
if (portp->isIO() && !portp->isFuncReturn()) {
|
|
|
|
|
argsp = argsp->addNextNull(new AstVarRef(portp->fileline(), portp,
|
|
|
|
|
portp->isOutput()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AstNode* returnp = new AstCReturn (funcp->fileline(),
|
|
|
|
|
new AstCCall (funcp->fileline(),
|
|
|
|
|
funcp,
|
|
|
|
|
argsp));
|
|
|
|
|
|
|
|
|
|
if (moreOfSame) {
|
|
|
|
|
AstIf* ifp = new AstIf (funcp->fileline(),
|
|
|
|
|
new AstEq(funcp->fileline(),
|
|
|
|
|
new AstCMath(funcp->fileline(),
|
|
|
|
|
"this", 64),
|
|
|
|
|
new AstCMath(funcp->fileline(),
|
|
|
|
|
string("&(")
|
|
|
|
|
+funcp->scopep()->nameVlSym()
|
|
|
|
|
+")", 64)),
|
|
|
|
|
returnp, NULL);
|
|
|
|
|
newfuncp->addStmtsp(ifp);
|
|
|
|
|
} else {
|
|
|
|
|
newfuncp->addStmtsp(returnp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Not really any way the user could do this, and we'd need to come up with some return value
|
2010-02-02 01:15:48 +00:00
|
|
|
|
//newfuncp->addStmtsp(new AstDisplay (newfuncp->fileline(), AstDisplayType::DT_DISPLAY,
|
2007-03-06 21:43:38 +00:00
|
|
|
|
// string("%%Error: ")+name+"() called with bad scope", NULL));
|
2006-08-26 11:35:28 +00:00
|
|
|
|
//newfuncp->addStmtsp(new AstStop (newfuncp->fileline()));
|
|
|
|
|
if (debug()>=9) newfuncp->dumpTree(cout," newfunc: ");
|
|
|
|
|
} else {
|
|
|
|
|
// Only a single function under this name, we can simply rename it
|
|
|
|
|
UINFO(6," Wrapping "<<name<<" just one "<<topFuncp<<endl);
|
|
|
|
|
topFuncp->name(name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// VISITORS
|
2009-11-07 11:20:20 +00:00
|
|
|
|
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
m_modp = nodep;
|
|
|
|
|
m_modFuncs.clear();
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
makePublicFuncWrappers();
|
2008-11-12 20:32:09 +00:00
|
|
|
|
m_modp = NULL;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstScope* nodep, AstNUser*) {
|
|
|
|
|
m_scopep = nodep;
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
m_scopep = NULL;
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstVarScope* nodep, AstNUser*) {
|
|
|
|
|
// Delete the varscope when we're finished
|
|
|
|
|
nodep->unlinkFrBack();
|
|
|
|
|
pushDeletep(nodep);
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstNodeVarRef* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
// Convert the hierch name
|
|
|
|
|
if (!m_scopep) nodep->v3fatalSrc("Node not under scope");
|
|
|
|
|
bool hierThis;
|
|
|
|
|
nodep->hiername(descopedName(nodep->varScopep()->scopep(), hierThis/*ref*/, nodep->varScopep()->varp()));
|
|
|
|
|
nodep->hierThis(hierThis);
|
|
|
|
|
nodep->varScopep(NULL);
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstCCall* nodep, AstNUser*) {
|
|
|
|
|
//UINFO(9," "<<nodep<<endl);
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
// Convert the hierch name
|
|
|
|
|
if (!m_scopep) nodep->v3fatalSrc("Node not under scope");
|
|
|
|
|
if (!nodep->funcp()->scopep()) nodep->v3fatalSrc("CFunc not under scope");
|
|
|
|
|
bool hierThis;
|
|
|
|
|
nodep->hiername(descopedName(nodep->funcp()->scopep(), hierThis/*ref*/));
|
|
|
|
|
// Can't do this, as we may have more calls later
|
|
|
|
|
// nodep->funcp()->scopep(NULL);
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstCFunc* nodep, AstNUser*) {
|
2008-11-25 14:03:49 +00:00
|
|
|
|
if (!nodep->user1()) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
m_needThis = false;
|
|
|
|
|
nodep->iterateChildren(*this);
|
2008-11-25 14:03:49 +00:00
|
|
|
|
nodep->user1(true);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
if (m_needThis) {
|
2006-08-30 21:07:55 +00:00
|
|
|
|
nodep->v3fatalSrc("old code");
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// Really we should have more node types for backend optimization of this stuff
|
2009-12-03 00:32:41 +00:00
|
|
|
|
string text = v3Global.opt.modPrefix() + "_" + m_modp->name()
|
2006-08-26 11:35:28 +00:00
|
|
|
|
+"* thisp = &("+m_scopep->nameVlSym()+");\n";
|
|
|
|
|
nodep->addInitsp(new AstCStmt(nodep->fileline(), text));
|
|
|
|
|
}
|
|
|
|
|
// If it's under a scope, move it up to the top
|
|
|
|
|
if (m_scopep) {
|
|
|
|
|
nodep->unlinkFrBack();
|
|
|
|
|
m_modp->addStmtp(nodep);
|
2006-10-06 16:08:46 +00:00
|
|
|
|
|
|
|
|
|
if (nodep->funcPublic()) {
|
|
|
|
|
// There may be multiple public functions by the same name;
|
|
|
|
|
// record for later correction or making of shells
|
|
|
|
|
m_modFuncs.insert(make_pair(nodep->name(), nodep));
|
|
|
|
|
nodep->name(m_scopep->nameDotless() +"__" + nodep->name());
|
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstVar*, AstNUser*) {}
|
|
|
|
|
virtual void visit(AstNode* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
}
|
|
|
|
|
public:
|
|
|
|
|
// CONSTRUCTORS
|
|
|
|
|
DescopeVisitor(AstNetlist* nodep) {
|
|
|
|
|
m_modp = NULL;
|
|
|
|
|
m_scopep = NULL;
|
|
|
|
|
m_needThis = false;
|
|
|
|
|
nodep->accept(*this);
|
|
|
|
|
}
|
|
|
|
|
virtual ~DescopeVisitor() {}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Descope class functions
|
|
|
|
|
|
|
|
|
|
void V3Descope::descopeAll(AstNetlist* nodep) {
|
|
|
|
|
UINFO(2,__FUNCTION__<<": "<<endl);
|
|
|
|
|
DescopeVisitor visitor (nodep);
|
|
|
|
|
}
|