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: Resolve module/signal name 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
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2012-01-15 15:26:28 +00:00
|
|
|
|
// Copyright 2003-2012 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.
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// LinkDot TRANSFORMATIONS:
|
|
|
|
|
// Top-down traversal
|
|
|
|
|
// Cells:
|
2007-05-22 12:15:01 +00:00
|
|
|
|
// Make graph of cell hierarchy
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// Var/Funcs's:
|
|
|
|
|
// Collect all names into symtable under appropriate cell
|
|
|
|
|
// Top-down traversal
|
|
|
|
|
// VarXRef/Func's:
|
|
|
|
|
// Find appropriate named cell and link to var they reference
|
|
|
|
|
//*************************************************************************
|
2012-06-20 10:13:28 +00:00
|
|
|
|
// TOP
|
|
|
|
|
// {name-of-top-modulename}
|
|
|
|
|
// a (VSymEnt->AstCell)
|
|
|
|
|
// {name-of-cell}
|
|
|
|
|
// {name-of-cell-module}
|
|
|
|
|
// aa (VSymEnt->AstCell)
|
|
|
|
|
// var (AstVar) -- no sub symbol table needed
|
|
|
|
|
// beg (VSymEnt->AstBegin) -- can see "upper" a's symbol table
|
|
|
|
|
// a__DOT__aa (VSymEnt->AstCellInline) -- points to a.aa's symbol table
|
|
|
|
|
// b (VSymEnt->AstCell)
|
2012-06-20 10:09:07 +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 <algorithm>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
#include "V3Global.h"
|
|
|
|
|
#include "V3LinkDot.h"
|
|
|
|
|
#include "V3SymTable.h"
|
|
|
|
|
#include "V3Graph.h"
|
|
|
|
|
#include "V3Ast.h"
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// LinkDot state, as a visitor of each AstNode
|
|
|
|
|
|
|
|
|
|
class LinkDotState {
|
|
|
|
|
private:
|
|
|
|
|
// NODE STATE
|
|
|
|
|
// Cleared on Netlist
|
2012-06-20 10:13:28 +00:00
|
|
|
|
// AstNodeModule::user1p() -> VSymEnt*. Last cell that uses this module
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// AstVarScope::user2p() -> AstVarScope*. Base alias for this signal
|
2008-11-25 14:03:49 +00:00
|
|
|
|
AstUser1InUse m_inuser1;
|
|
|
|
|
AstUser2InUse m_inuser2;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
|
|
// TYPES
|
2012-06-20 10:13:28 +00:00
|
|
|
|
typedef std::multimap<string,VSymEnt*> NameScopeMap;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// MEMBERS
|
2012-06-20 10:13:28 +00:00
|
|
|
|
VSymGraph m_syms; // Symbol table
|
2006-12-22 15:06:13 +00:00
|
|
|
|
NameScopeMap m_nameScopeMap; // Hash of scope referenced by non-pretty textual name
|
2006-09-06 17:48:41 +00:00
|
|
|
|
bool m_forPrearray; // Compress cell__[array] refs
|
2006-08-26 11:35:28 +00:00
|
|
|
|
bool m_forScopeCreation; // Remove VarXRefs for V3Scope
|
|
|
|
|
public:
|
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
|
|
|
|
|
|
|
|
|
// CONSTRUCTORS
|
2012-06-20 10:13:28 +00:00
|
|
|
|
LinkDotState(AstNetlist* rootp, bool forPrearray, bool forScopeCreation)
|
|
|
|
|
: m_syms(rootp) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
UINFO(4,__FUNCTION__<<": "<<endl);
|
2006-09-06 17:48:41 +00:00
|
|
|
|
m_forPrearray = forPrearray;
|
|
|
|
|
m_forScopeCreation = forScopeCreation;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
~LinkDotState() {}
|
2008-06-10 01:25:10 +00:00
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// ACCESSORS
|
|
|
|
|
bool forScopeCreation() const { return m_forScopeCreation; }
|
|
|
|
|
|
|
|
|
|
// METHODS
|
2012-06-20 10:13:28 +00:00
|
|
|
|
private:
|
|
|
|
|
VSymEnt* findSubcell(VSymEnt* symp, const string& name, const string& altname) {
|
|
|
|
|
VSymEnt* findp = symp->findIdFallback(name);
|
|
|
|
|
if (findp) return findp;
|
|
|
|
|
findp = symp->findIdFallback(altname);
|
|
|
|
|
return findp;
|
|
|
|
|
}
|
|
|
|
|
public:
|
|
|
|
|
VSymEnt* insertTopCell(AstNodeModule* nodep, const string& scopename) {
|
2009-11-08 02:05:02 +00:00
|
|
|
|
// Only called on the module at the very top of the hierarchy
|
2012-06-20 10:13:28 +00:00
|
|
|
|
UINFO(9," INSERTtop "<<scopename<<" "<<nodep<<endl);
|
|
|
|
|
VSymEnt* symp = new VSymEnt(&m_syms, nodep);
|
|
|
|
|
symp->parentp(m_syms.rootp()); // Needed so backward search can find name of top module
|
|
|
|
|
nodep->user1p(symp);
|
|
|
|
|
m_syms.rootp()->insert(nodep->origName(),symp);
|
|
|
|
|
if (forScopeCreation()) m_nameScopeMap.insert(make_pair(scopename, symp));
|
|
|
|
|
return symp;
|
|
|
|
|
}
|
|
|
|
|
VSymEnt* insertCell(VSymEnt* abovep, VSymEnt* cellSymp,
|
|
|
|
|
AstCell* nodep, const string& scopename) {
|
|
|
|
|
UINFO(9," INSERTcel "<<scopename<<" above="<<(void*)abovep<<" cells="<<(void*)cellSymp<<" node="<<nodep<<endl);
|
|
|
|
|
VSymEnt* symp = new VSymEnt(&m_syms, nodep);
|
|
|
|
|
symp->parentp(abovep);
|
|
|
|
|
symp->fallbackp(cellSymp);
|
|
|
|
|
if (nodep->modp()) nodep->modp()->user1p(symp);
|
|
|
|
|
abovep->reinsert(nodep->origName(), symp);
|
|
|
|
|
if (abovep != cellSymp) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// If it's foo_DOT_bar, we need to be able to find it under that too.
|
2012-06-20 10:13:28 +00:00
|
|
|
|
// Duplicates are possible, as until resolve generates might have 2 same cells under an if
|
|
|
|
|
cellSymp->reinsert(nodep->name(), symp);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
2012-06-20 10:13:28 +00:00
|
|
|
|
if (forScopeCreation()) m_nameScopeMap.insert(make_pair(scopename, symp));
|
|
|
|
|
return symp;
|
|
|
|
|
}
|
|
|
|
|
VSymEnt* insertInline(VSymEnt* abovep, VSymEnt* cellSymp,
|
|
|
|
|
AstCellInline* nodep, const string& basename) {
|
|
|
|
|
// A fake point in the hierarchy, corresponding to an inlined module
|
|
|
|
|
// This refrences to another Sym, and eventually resolves to a module with a prefix
|
|
|
|
|
UINFO(9," INSERTcel "<<basename<<" above="<<(void*)abovep<<" cells="<<(void*)cellSymp<<" node="<<nodep<<endl);
|
|
|
|
|
VSymEnt* symp = new VSymEnt(&m_syms, nodep);
|
|
|
|
|
symp->parentp(abovep);
|
|
|
|
|
symp->fallbackp(cellSymp);
|
|
|
|
|
symp->symPrefix(nodep->name()+"__DOT__");
|
|
|
|
|
abovep->reinsert(basename, symp);
|
|
|
|
|
if (abovep != cellSymp) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// If it's foo_DOT_bar, we need to be able to find it under that too.
|
2012-06-20 10:13:28 +00:00
|
|
|
|
cellSymp->reinsert(nodep->name(), symp);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
2012-06-20 10:13:28 +00:00
|
|
|
|
return symp;
|
|
|
|
|
}
|
|
|
|
|
VSymEnt* insertBegin(VSymEnt* abovep, VSymEnt* cellSymp,
|
|
|
|
|
AstBegin* nodep) {
|
|
|
|
|
// A fake point in the hierarchy, corresponding to a begin block
|
|
|
|
|
// After we remove begins these will go away
|
|
|
|
|
// Note we fallback to the symbol table of the parent, as we want to find variables there
|
|
|
|
|
// However, cells walk the graph, so cells will appear under the begin itself
|
|
|
|
|
UINFO(9," INSERTbeg above="<<(void*)abovep<<" cells="<<(void*)cellSymp<<" node="<<nodep<<endl);
|
|
|
|
|
VSymEnt* symp = new VSymEnt(&m_syms, nodep);
|
|
|
|
|
symp->parentp(abovep);
|
|
|
|
|
symp->symPrefix(nodep->name()+"__DOT__");
|
|
|
|
|
if (nodep->name() != "") {
|
|
|
|
|
// Duplicates are possible, as until resolve generates might have 2 same cells under an if
|
|
|
|
|
abovep->reinsert(nodep->name(), symp);
|
|
|
|
|
}
|
|
|
|
|
return symp;
|
2006-12-18 18:14:53 +00:00
|
|
|
|
}
|
2012-06-20 10:13:28 +00:00
|
|
|
|
void insertSym(VSymEnt* abovep, const string& name, AstNode* nodep) {
|
|
|
|
|
UINFO(9," INSERTsym name='"<<name<<"' above="<<(void*)abovep<<" node="<<nodep<<endl);
|
|
|
|
|
// We don't remember the ent associated with each node, because we need a unique scope entry for each instantiation
|
|
|
|
|
VSymEnt* symp = new VSymEnt(&m_syms, nodep);
|
|
|
|
|
abovep->insert(name, symp);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
2009-11-07 11:20:20 +00:00
|
|
|
|
bool existsModScope(AstNodeModule* nodep) {
|
2008-11-25 14:03:49 +00:00
|
|
|
|
return nodep->user1p()!=NULL;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
2012-06-20 10:13:28 +00:00
|
|
|
|
VSymEnt* findModScope(AstNodeModule* nodep) {
|
|
|
|
|
VSymEnt* symp = nodep->user1p()->castSymEnt();
|
|
|
|
|
if (!symp) nodep->v3fatalSrc("Module never assigned a symbol entry?");
|
|
|
|
|
return symp;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
2012-06-20 10:13:28 +00:00
|
|
|
|
VSymEnt* findScopeSym(AstScope* nodep) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
NameScopeMap::iterator iter = m_nameScopeMap.find(nodep->name());
|
|
|
|
|
if (iter == m_nameScopeMap.end()) {
|
2012-06-20 10:13:28 +00:00
|
|
|
|
nodep->v3fatalSrc("Scope never assigned a symbol entry?");
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
return iter->second;
|
|
|
|
|
}
|
|
|
|
|
void dump() {
|
2012-06-20 10:13:28 +00:00
|
|
|
|
if (debug()>=6) m_syms.dumpFilePrefixed("linkdot");
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
2012-06-20 10:13:28 +00:00
|
|
|
|
void preErrorDump() {
|
|
|
|
|
static bool diddump = false;
|
|
|
|
|
if (!diddump && v3Global.opt.dumpTree()) {
|
|
|
|
|
diddump = true;
|
|
|
|
|
m_syms.dumpFilePrefixed("linkdot-preerr");
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2012-06-20 10:13:28 +00:00
|
|
|
|
VSymEnt* findDotted(VSymEnt* cellSymp, const string& dotname,
|
|
|
|
|
string& baddot, VSymEnt*& okSymp) {
|
2007-05-22 12:15:01 +00:00
|
|
|
|
// Given a dotted hierarchy name, return where in scope it is
|
2012-06-20 10:13:28 +00:00
|
|
|
|
// Note when dotname=="" we just fall through and return cellSymp
|
2006-08-26 11:35:28 +00:00
|
|
|
|
UINFO(8," dottedFind "<<dotname<<endl);
|
|
|
|
|
bool firstId = true;
|
|
|
|
|
string leftname = dotname;
|
2012-06-20 10:13:28 +00:00
|
|
|
|
okSymp = cellSymp; // So can list bad scopes
|
2006-08-26 11:35:28 +00:00
|
|
|
|
while (leftname != "") { // foreach dotted part of xref name
|
|
|
|
|
string::size_type pos;
|
|
|
|
|
string ident;
|
|
|
|
|
if ((pos = leftname.find(".")) != string::npos) {
|
|
|
|
|
ident = leftname.substr(0,pos);
|
|
|
|
|
leftname = leftname.substr(pos+1);
|
|
|
|
|
} else {
|
|
|
|
|
ident = leftname;
|
|
|
|
|
leftname = "";
|
|
|
|
|
}
|
|
|
|
|
baddot = ident; // So user can see where they botched it
|
2012-06-20 10:13:28 +00:00
|
|
|
|
okSymp = cellSymp;
|
2006-09-06 17:48:41 +00:00
|
|
|
|
string altIdent = "";
|
|
|
|
|
if (m_forPrearray) {
|
|
|
|
|
// Cell foo__[array] before we've expanded arrays is just foo.
|
2006-12-22 15:06:13 +00:00
|
|
|
|
if ((pos = ident.find("__BRA__")) != string::npos) {
|
2006-09-06 17:48:41 +00:00
|
|
|
|
altIdent = ident.substr(0,pos);
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-06-20 10:13:28 +00:00
|
|
|
|
UINFO(8," id "<<ident<<" left "<<leftname<<" at "<<cellSymp<<endl);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// Spec says; Look at exiting module (cellnames then modname),
|
|
|
|
|
// then look up (inst name or modname)
|
|
|
|
|
if (firstId) {
|
|
|
|
|
// Check this module - subcellnames
|
2012-06-20 10:13:28 +00:00
|
|
|
|
AstCell* cellp = cellSymp->nodep()->castCell(); // Replicated below
|
|
|
|
|
AstCellInline* inlinep = cellSymp->nodep()->castCellInline(); // Replicated below
|
|
|
|
|
if (VSymEnt* findSymp = findSubcell(cellSymp, ident, altIdent)) {
|
|
|
|
|
cellSymp = findSymp;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
// Check this module - cur modname
|
2012-06-20 10:13:28 +00:00
|
|
|
|
else if ((cellp && cellp->modp()->origName() == ident)
|
|
|
|
|
|| (inlinep && inlinep->origModName() == ident)) {}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// Move up and check cellname + modname
|
|
|
|
|
else {
|
2012-06-20 10:13:28 +00:00
|
|
|
|
while (cellSymp) {
|
|
|
|
|
cellSymp = cellSymp->parentp();
|
|
|
|
|
cellp = cellSymp->nodep()->castCell(); // Replicated above
|
|
|
|
|
inlinep = cellSymp->nodep()->castCellInline(); // Replicated above
|
|
|
|
|
if (cellSymp) {
|
|
|
|
|
UINFO(9,"\t\tUp to "<<cellSymp<<endl);
|
|
|
|
|
if ((cellp && cellp->modp()->origName() == ident)
|
|
|
|
|
|| (inlinep && inlinep->origModName() == ident)) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2012-06-20 10:13:28 +00:00
|
|
|
|
else if (VSymEnt* findSymp = findSubcell(cellSymp, ident, altIdent)) {
|
|
|
|
|
cellSymp = findSymp;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2012-06-20 10:13:28 +00:00
|
|
|
|
} else break;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
2012-06-20 10:13:28 +00:00
|
|
|
|
if (!cellSymp) return NULL; // Not found
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
} else { // Searching for middle submodule, must be a cell name
|
2012-06-20 10:13:28 +00:00
|
|
|
|
if (VSymEnt* findSymp = findSubcell(cellSymp, ident, altIdent)) {
|
|
|
|
|
cellSymp = findSymp;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
} else {
|
|
|
|
|
return NULL; // Not found
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
firstId = false;
|
|
|
|
|
}
|
2012-06-20 10:13:28 +00:00
|
|
|
|
return cellSymp;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-06-20 10:13:28 +00:00
|
|
|
|
AstNode* findSym(VSymEnt* cellSymp, const string& dotname, string& baddot) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// Find symbol in given point in hierarchy
|
2012-06-20 10:13:28 +00:00
|
|
|
|
// For simplicity cellSymp may be passed NULL result from findDotted
|
|
|
|
|
if (!cellSymp) return NULL;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
UINFO(8,"\t\tfindSym "<<dotname
|
2012-06-20 10:13:28 +00:00
|
|
|
|
<<((cellSymp->symPrefix()=="") ? "" : " as ")
|
|
|
|
|
<<((cellSymp->symPrefix()=="") ? "" : cellSymp->symPrefix()+dotname)
|
|
|
|
|
<<" at "<<cellSymp
|
2006-08-26 11:35:28 +00:00
|
|
|
|
<<endl);
|
2012-06-20 10:13:28 +00:00
|
|
|
|
AstNode* nodep = cellSymp->findIdFallback(cellSymp->symPrefix() + dotname)->nodep(); // Might be NULL
|
2006-08-26 11:35:28 +00:00
|
|
|
|
if (!nodep) baddot = dotname;
|
|
|
|
|
return nodep;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
|
|
|
|
|
|
class LinkDotFindVisitor : public AstNVisitor {
|
|
|
|
|
private:
|
|
|
|
|
// STATE
|
|
|
|
|
LinkDotState* m_statep; // State to pass between visitors, including symbol table
|
2012-06-20 10:13:28 +00:00
|
|
|
|
VSymEnt* m_cellSymp; // Symbol Entry for current module
|
|
|
|
|
VSymEnt* m_inlineSymp; // Symbol Entry for current module, possibly a fake inlined one
|
2006-08-26 11:35:28 +00:00
|
|
|
|
string m_scope; // Scope text
|
|
|
|
|
AstBegin* m_beginp; // Current Begin/end block
|
2009-01-21 21:56:50 +00:00
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
|
int debug() { return LinkDotState::debug(); }
|
|
|
|
|
|
|
|
|
|
// VISITs
|
|
|
|
|
virtual void visit(AstNetlist* nodep, AstNUser*) {
|
2009-11-08 02:05:02 +00:00
|
|
|
|
// Process $unit or other packages
|
|
|
|
|
// Not needed - dotted references not allowed from inside packages
|
|
|
|
|
//for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep; nodep=nodep->nextp()->castNodeModule()) {
|
|
|
|
|
// if (nodep->castPackage()) {}}
|
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// The first module in the list is always the top module (sorted before this is called).
|
|
|
|
|
// This may not be the module with isTop() set, as early in the steps,
|
|
|
|
|
// wrapTop may have not been created yet.
|
2009-11-07 11:20:20 +00:00
|
|
|
|
AstNodeModule* topmodp = nodep->modulesp();
|
2008-03-25 13:42:48 +00:00
|
|
|
|
if (!topmodp) {
|
|
|
|
|
nodep->v3error("No top level module found");
|
|
|
|
|
} else {
|
|
|
|
|
UINFO(8,"Top Module: "<<topmodp<<endl);
|
|
|
|
|
m_scope = "TOP";
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_cellSymp = m_statep->insertTopCell(topmodp, m_scope);
|
|
|
|
|
m_inlineSymp = m_cellSymp;
|
2008-03-25 13:42:48 +00:00
|
|
|
|
{
|
|
|
|
|
topmodp->accept(*this);
|
|
|
|
|
}
|
|
|
|
|
m_scope = "";
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_cellSymp = NULL;
|
|
|
|
|
m_inlineSymp = m_cellSymp;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2009-11-07 11:20:20 +00:00
|
|
|
|
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
2009-11-08 02:05:02 +00:00
|
|
|
|
// Called on top module from Netlist, other modules from the cell creating them,
|
|
|
|
|
// and packages
|
2006-08-26 11:35:28 +00:00
|
|
|
|
UINFO(8," "<<nodep<<endl);
|
2012-06-20 10:13:28 +00:00
|
|
|
|
if (!m_cellSymp) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// Will be optimized away later
|
|
|
|
|
UINFO(5, "Module not under any CELL or top - dead module\n");
|
|
|
|
|
} else {
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstScope* nodep, AstNUser*) {
|
|
|
|
|
if (!m_statep->forScopeCreation()) v3fatalSrc("Scopes should only exist right after V3Scope");
|
|
|
|
|
// Ignored. Processed in next step
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstCell* nodep, AstNUser*) {
|
|
|
|
|
UINFO(5," CELL under "<<m_scope<<" is "<<nodep<<endl);
|
2006-12-12 18:25:33 +00:00
|
|
|
|
// Process XREFs inside pins
|
|
|
|
|
nodep->iterateChildren(*this);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// Recurse in, preserving state
|
|
|
|
|
string oldscope = m_scope;
|
2006-12-12 18:25:33 +00:00
|
|
|
|
AstBegin* oldbeginp = m_beginp;
|
2012-06-20 10:13:28 +00:00
|
|
|
|
VSymEnt* oldSymp = m_cellSymp;
|
|
|
|
|
VSymEnt* oldInlineSymp = m_inlineSymp;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// Where do we add it?
|
2012-06-20 10:13:28 +00:00
|
|
|
|
VSymEnt* aboveSymp = m_inlineSymp;
|
2006-12-22 15:06:13 +00:00
|
|
|
|
string origname = AstNode::dedotName(nodep->name());
|
2006-08-26 11:35:28 +00:00
|
|
|
|
string::size_type pos;
|
|
|
|
|
if ((pos = origname.rfind(".")) != string::npos) {
|
|
|
|
|
// Flattened, find what CellInline it should live under
|
|
|
|
|
string scope = origname.substr(0,pos);
|
|
|
|
|
string baddot;
|
2012-06-20 10:13:28 +00:00
|
|
|
|
VSymEnt* okSymp;
|
|
|
|
|
aboveSymp = m_statep->findDotted(aboveSymp, scope, baddot, okSymp);
|
|
|
|
|
if (!aboveSymp) nodep->v3fatalSrc("Can't find cell insertion point at '"<<baddot<<"' in: "<<nodep->prettyName());
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
m_scope = m_scope+"."+nodep->name();
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_cellSymp = m_statep->insertCell(aboveSymp, m_cellSymp, nodep, m_scope);
|
|
|
|
|
m_inlineSymp = m_cellSymp;
|
2006-12-12 18:25:33 +00:00
|
|
|
|
m_beginp = NULL;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
if (nodep->modp()) nodep->modp()->accept(*this);
|
|
|
|
|
}
|
|
|
|
|
m_scope = oldscope;
|
2006-12-12 18:25:33 +00:00
|
|
|
|
m_beginp = oldbeginp;
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_cellSymp = oldSymp;
|
|
|
|
|
m_inlineSymp = oldInlineSymp;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstCellInline* nodep, AstNUser*) {
|
|
|
|
|
UINFO(5," CELLINLINE under "<<m_scope<<" is "<<nodep<<endl);
|
2012-06-20 10:13:28 +00:00
|
|
|
|
VSymEnt* aboveSymp = m_inlineSymp;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// If baz__DOT__foo__DOT__bar, we need to find baz__DOT__foo and add bar to it.
|
|
|
|
|
string dottedname = nodep->name();
|
|
|
|
|
string::size_type pos;
|
|
|
|
|
if ((pos=dottedname.rfind("__DOT__")) != string::npos) {
|
|
|
|
|
string dotted = dottedname.substr(0, pos);
|
|
|
|
|
string ident = dottedname.substr(pos+strlen("__DOT__"));
|
|
|
|
|
string baddot;
|
2012-06-20 10:13:28 +00:00
|
|
|
|
VSymEnt* okSymp;
|
|
|
|
|
aboveSymp = m_statep->findDotted(aboveSymp, dotted, baddot, okSymp);
|
|
|
|
|
if (!aboveSymp) nodep->v3fatalSrc("Can't find cellinline insertion point at '"<<baddot<<"' in: "<<nodep->prettyName());
|
|
|
|
|
m_statep->insertInline(aboveSymp, m_cellSymp, nodep, ident);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
} else { // No __DOT__, just directly underneath
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_statep->insertInline(aboveSymp, m_cellSymp, nodep, nodep->name());
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstBegin* nodep, AstNUser*) {
|
|
|
|
|
UINFO(5," "<<nodep<<endl);
|
|
|
|
|
AstBegin* oldbegin = m_beginp;
|
2012-06-20 10:13:28 +00:00
|
|
|
|
VSymEnt* oldSymp = m_inlineSymp;
|
2006-12-18 18:14:53 +00:00
|
|
|
|
{
|
|
|
|
|
m_beginp = nodep;
|
2011-11-29 23:23:18 +00:00
|
|
|
|
// We don't pickup variables (as not supported yet), but do need to find cells
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_inlineSymp = m_statep->insertBegin(m_inlineSymp, m_cellSymp, nodep);
|
2011-11-29 23:23:18 +00:00
|
|
|
|
nodep->stmtsp()->iterateAndNext(*this);
|
2006-12-18 18:14:53 +00:00
|
|
|
|
}
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_inlineSymp = oldSymp;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
m_beginp = oldbegin;
|
2011-11-29 23:23:18 +00:00
|
|
|
|
//
|
|
|
|
|
nodep->flatsp()->iterateAndNext(*this);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
2012-05-28 13:18:18 +00:00
|
|
|
|
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
|
|
|
|
if (!m_beginp) { // For now, we don't support xrefs into functions inside begin blocks
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_statep->insertSym(m_cellSymp, nodep->name(), nodep);
|
2012-05-28 13:18:18 +00:00
|
|
|
|
}
|
|
|
|
|
// No recursion, we don't want to pick up variables
|
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
virtual void visit(AstVar* nodep, AstNUser*) {
|
|
|
|
|
if (!m_statep->forScopeCreation()
|
|
|
|
|
&& !m_beginp // For now, we don't support xrefs into begin blocks
|
|
|
|
|
&& !nodep->isFuncLocal()) {
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_statep->insertSym(m_cellSymp, nodep->name(), nodep);
|
2006-12-12 18:25:33 +00:00
|
|
|
|
} else {
|
|
|
|
|
UINFO(9," Not allowing dot refs to: "<<nodep<<endl);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstCFunc* nodep, AstNUser*) {
|
|
|
|
|
// Ignore all AstVars under functions
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// For speed, don't recurse things that can't have cells
|
2006-12-12 18:25:33 +00:00
|
|
|
|
// Note we allow AstNodeStmt's as generates may be under them
|
2006-08-26 11:35:28 +00:00
|
|
|
|
virtual void visit(AstNodeMath*, AstNUser*) {}
|
|
|
|
|
virtual void visit(AstNode* nodep, AstNUser*) {
|
|
|
|
|
// Default: Just iterate
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
// CONSTUCTORS
|
|
|
|
|
LinkDotFindVisitor(AstNetlist* rootp, LinkDotState* statep) {
|
|
|
|
|
UINFO(4,__FUNCTION__<<": "<<endl);
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_cellSymp = NULL;
|
|
|
|
|
m_inlineSymp = NULL;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
m_statep = statep;
|
|
|
|
|
m_beginp = NULL;
|
|
|
|
|
//
|
|
|
|
|
rootp->accept(*this);
|
|
|
|
|
}
|
|
|
|
|
virtual ~LinkDotFindVisitor() {}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
|
|
|
|
|
|
class LinkDotScopeVisitor : public AstNVisitor {
|
|
|
|
|
private:
|
|
|
|
|
// STATE
|
|
|
|
|
LinkDotState* m_statep; // State to pass between visitors, including symbol table
|
2012-06-20 10:13:28 +00:00
|
|
|
|
VSymEnt* m_cellSymp; // Symbol entry for current module
|
2009-01-21 21:56:50 +00:00
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
|
int debug() { return LinkDotState::debug(); }
|
|
|
|
|
|
|
|
|
|
// VISITs
|
|
|
|
|
virtual void visit(AstScope* nodep, AstNUser*) {
|
|
|
|
|
UINFO(8," SCOPE "<<nodep<<endl);
|
|
|
|
|
if (!m_statep->forScopeCreation()) v3fatalSrc("Scopes should only exist right after V3Scope");
|
2007-05-22 12:15:01 +00:00
|
|
|
|
// Using the CELL names, we created all hierarchy. We now need to match this Scope
|
|
|
|
|
// up with the hierarchy created by the CELL names.
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_cellSymp = m_statep->findScopeSym(nodep);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
nodep->iterateChildren(*this);
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_cellSymp = NULL;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstVarScope* nodep, AstNUser*) {
|
|
|
|
|
if (!nodep->varp()->isFuncLocal()) {
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_statep->insertSym(m_cellSymp, nodep->varp()->name(), nodep);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_statep->insertSym(m_cellSymp, nodep->name(), nodep);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// No recursion, we don't want to pick up variables
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstAssignAlias* nodep, AstNUser*) {
|
|
|
|
|
// Track aliases created by V3Inline; if we get a VARXREF(aliased_from)
|
|
|
|
|
// we'll need to replace it with a VARXREF(aliased_to)
|
|
|
|
|
if (m_statep->forScopeCreation()) {
|
|
|
|
|
if (debug()>=9) nodep->dumpTree(cout,"-\t\t\t\talias: ");
|
|
|
|
|
AstVarScope* fromVscp = nodep->lhsp()->castVarRef()->varScopep();
|
|
|
|
|
AstVarScope* toVscp = nodep->rhsp()->castVarRef()->varScopep();
|
|
|
|
|
if (!fromVscp || !toVscp) nodep->v3fatalSrc("Bad alias scopes");
|
|
|
|
|
fromVscp->user2p(toVscp);
|
|
|
|
|
}
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
}
|
|
|
|
|
// For speed, don't recurse things that can't have scope
|
2006-12-12 18:25:33 +00:00
|
|
|
|
// Note we allow AstNodeStmt's as generates may be under them
|
2006-08-26 11:35:28 +00:00
|
|
|
|
virtual void visit(AstCell*, AstNUser*) {}
|
|
|
|
|
virtual void visit(AstVar*, AstNUser*) {}
|
|
|
|
|
virtual void visit(AstNodeMath*, AstNUser*) {}
|
|
|
|
|
virtual void visit(AstNode* nodep, AstNUser*) {
|
|
|
|
|
// Default: Just iterate
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
// CONSTUCTORS
|
|
|
|
|
LinkDotScopeVisitor(AstNetlist* rootp, LinkDotState* statep) {
|
|
|
|
|
UINFO(4,__FUNCTION__<<": "<<endl);
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_cellSymp = NULL;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
m_statep = statep;
|
|
|
|
|
//
|
|
|
|
|
rootp->accept(*this);
|
|
|
|
|
}
|
|
|
|
|
virtual ~LinkDotScopeVisitor() {}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
|
|
|
|
|
|
class LinkDotResolveVisitor : public AstNVisitor {
|
|
|
|
|
private:
|
|
|
|
|
// STATE
|
|
|
|
|
LinkDotState* m_statep; // State, including dotted symbol table
|
2012-06-20 10:13:28 +00:00
|
|
|
|
VSymEnt* m_cellSymp; // SymEnt for current module
|
2009-01-21 21:56:50 +00:00
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
|
int debug() { return LinkDotState::debug(); }
|
|
|
|
|
|
|
|
|
|
// METHODS
|
|
|
|
|
|
|
|
|
|
// VISITs
|
2009-11-07 11:20:20 +00:00
|
|
|
|
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
UINFO(8," "<<nodep<<endl);
|
|
|
|
|
if (!m_statep->existsModScope(nodep)) {
|
|
|
|
|
UINFO(5,"Dead module for "<<nodep<<endl);
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_cellSymp = NULL;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
} else {
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_cellSymp = m_statep->findModScope(nodep);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
nodep->iterateChildren(*this);
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_cellSymp = NULL;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstScope* nodep, AstNUser*) {
|
|
|
|
|
UINFO(8," "<<nodep<<endl);
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_cellSymp = m_statep->findScopeSym(nodep);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
nodep->iterateChildren(*this);
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_cellSymp = NULL;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstCellInline* nodep, AstNUser*) {
|
|
|
|
|
if (m_statep->forScopeCreation()) {
|
|
|
|
|
nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstVarXRef* nodep, AstNUser*) {
|
|
|
|
|
// VarRef: Resolve its reference
|
|
|
|
|
// We always link even if varp() is set, because the module we choose may change
|
|
|
|
|
// due to creating new modules, flattening, etc.
|
|
|
|
|
UINFO(8," "<<nodep<<endl);
|
2012-06-20 10:13:28 +00:00
|
|
|
|
if (!m_cellSymp) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
UINFO(9,"Dead module for "<<nodep<<endl);
|
2007-05-22 12:15:01 +00:00
|
|
|
|
nodep->varp(NULL); // Module that is not in hierarchy. We'll be dead code eliminating it later.
|
2006-08-26 11:35:28 +00:00
|
|
|
|
} else {
|
|
|
|
|
string baddot;
|
2012-06-20 10:13:28 +00:00
|
|
|
|
VSymEnt* okSymp;
|
|
|
|
|
VSymEnt* dotSymp = m_cellSymp; // Start search at current scope
|
2006-08-26 11:35:28 +00:00
|
|
|
|
if (nodep->inlinedDots()!="") { // Correct for current scope
|
2006-12-22 15:06:13 +00:00
|
|
|
|
string inl = AstNode::dedotName(nodep->inlinedDots());
|
2012-06-20 10:13:28 +00:00
|
|
|
|
dotSymp = m_statep->findDotted(dotSymp, inl, baddot, okSymp);
|
|
|
|
|
if (!dotSymp) {
|
|
|
|
|
m_statep->preErrorDump();
|
|
|
|
|
nodep->v3fatalSrc("Couldn't resolve inlined scope '"<<baddot<<"' in: "<<nodep->inlinedDots());
|
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
2012-06-20 10:13:28 +00:00
|
|
|
|
dotSymp = m_statep->findDotted(dotSymp, nodep->dotted(), baddot, okSymp); // Maybe NULL
|
2006-08-26 11:35:28 +00:00
|
|
|
|
if (!m_statep->forScopeCreation()) {
|
2012-06-20 10:13:28 +00:00
|
|
|
|
AstVar* varp = (m_statep->findSym(dotSymp, nodep->name(), baddot)
|
2006-08-26 11:35:28 +00:00
|
|
|
|
->castVar()); // maybe NULL
|
|
|
|
|
nodep->varp(varp);
|
|
|
|
|
UINFO(7," Resolved "<<nodep<<endl); // Also prints varp
|
|
|
|
|
if (!nodep->varp()) {
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_statep->preErrorDump();
|
2006-08-26 11:35:28 +00:00
|
|
|
|
nodep->v3error("Can't find definition of '"<<baddot<<"' in dotted signal: "<<nodep->dotted()+"."+nodep->prettyName());
|
2012-06-20 10:13:28 +00:00
|
|
|
|
okSymp->cellErrorScopes(nodep);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
string baddot;
|
2012-06-20 10:13:28 +00:00
|
|
|
|
AstVarScope* vscp = (m_statep->findSym(dotSymp, nodep->name(), baddot)
|
2006-08-26 11:35:28 +00:00
|
|
|
|
->castVarScope()); // maybe NULL
|
|
|
|
|
if (!vscp) {
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_statep->preErrorDump();
|
2006-08-26 11:35:28 +00:00
|
|
|
|
nodep->v3error("Can't find varpin scope of '"<<baddot<<"' in dotted signal: "<<nodep->dotted()+"."+nodep->prettyName());
|
2012-06-20 10:13:28 +00:00
|
|
|
|
okSymp->cellErrorScopes(nodep);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
} else {
|
|
|
|
|
while (vscp->user2p()) { // If V3Inline aliased it, pick up the new signal
|
|
|
|
|
UINFO(7," Resolved pre-alias "<<vscp<<endl); // Also prints taskp
|
|
|
|
|
vscp = vscp->user2p()->castNode()->castVarScope();
|
|
|
|
|
}
|
|
|
|
|
// Convert the VarXRef to a VarRef, so we don't need later optimizations to deal with VarXRef.
|
|
|
|
|
nodep->varp(vscp->varp());
|
|
|
|
|
nodep->varScopep(vscp);
|
|
|
|
|
UINFO(7," Resolved "<<nodep<<endl); // Also prints taskp
|
|
|
|
|
AstVarRef* newvscp = new AstVarRef(nodep->fileline(), vscp, nodep->lvalue());
|
|
|
|
|
nodep->replaceWith(newvscp);
|
|
|
|
|
nodep->deleteTree(); nodep=NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
|
|
|
|
|
UINFO(8," "<<nodep<<endl);
|
2009-11-08 02:05:02 +00:00
|
|
|
|
if (nodep->packagep()) {
|
|
|
|
|
// References into packages don't care about cell hierarchy.
|
2012-06-20 10:13:28 +00:00
|
|
|
|
} else if (!m_cellSymp) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
UINFO(9,"Dead module for "<<nodep<<endl);
|
2007-05-22 12:15:01 +00:00
|
|
|
|
nodep->taskp(NULL); // Module that is not in hierarchy. We'll be dead code eliminating it later.
|
2012-02-22 03:23:06 +00:00
|
|
|
|
} else if (nodep->dotted()=="" && nodep->taskp()) {
|
|
|
|
|
// V3Link should have setup the links
|
|
|
|
|
// Might be under a BEGIN we're not processing, so don't relink it
|
2006-08-26 11:35:28 +00:00
|
|
|
|
} else {
|
|
|
|
|
string baddot;
|
2012-06-20 10:13:28 +00:00
|
|
|
|
VSymEnt* okSymp;
|
|
|
|
|
VSymEnt* dotSymp = m_cellSymp; // Start search at current scope
|
2006-08-26 11:35:28 +00:00
|
|
|
|
if (nodep->inlinedDots()!="") { // Correct for current scope
|
2006-12-22 15:06:13 +00:00
|
|
|
|
string inl = AstNode::dedotName(nodep->inlinedDots());
|
2006-09-08 16:16:30 +00:00
|
|
|
|
UINFO(8,"\t\tInlined "<<inl<<endl);
|
2012-06-20 10:13:28 +00:00
|
|
|
|
dotSymp = m_statep->findDotted(dotSymp, inl, baddot, okSymp);
|
|
|
|
|
if (!dotSymp) {
|
|
|
|
|
m_statep->preErrorDump();
|
|
|
|
|
okSymp->cellErrorScopes(nodep);
|
2006-12-22 15:06:13 +00:00
|
|
|
|
nodep->v3fatalSrc("Couldn't resolve inlined scope '"<<baddot<<"' in: "<<nodep->inlinedDots());
|
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
2012-06-20 10:13:28 +00:00
|
|
|
|
dotSymp = m_statep->findDotted(dotSymp, nodep->dotted(), baddot, okSymp); // Maybe NULL
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
2012-06-20 10:13:28 +00:00
|
|
|
|
AstNodeFTask* taskp = (m_statep->findSym(dotSymp, nodep->name(), baddot)
|
|
|
|
|
->castNode()->castNodeFTask()); // maybe NULL
|
2006-08-26 11:35:28 +00:00
|
|
|
|
nodep->taskp(taskp);
|
|
|
|
|
UINFO(7," Resolved "<<nodep<<endl); // Also prints taskp
|
|
|
|
|
if (!nodep->taskp()) {
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_statep->preErrorDump();
|
2006-08-26 11:35:28 +00:00
|
|
|
|
nodep->v3error("Can't find definition of '"<<baddot<<"' in dotted task/function: "<<nodep->dotted()+"."+nodep->prettyName());
|
2012-06-20 10:13:28 +00:00
|
|
|
|
okSymp->cellErrorScopes(nodep);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstNode* nodep, AstNUser*) {
|
|
|
|
|
// Default: Just iterate
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
}
|
|
|
|
|
public:
|
|
|
|
|
// CONSTUCTORS
|
|
|
|
|
LinkDotResolveVisitor(AstNetlist* rootp, LinkDotState* statep) {
|
|
|
|
|
UINFO(4,__FUNCTION__<<": "<<endl);
|
|
|
|
|
m_statep = statep;
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_cellSymp = NULL;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
//
|
|
|
|
|
rootp->accept(*this);
|
|
|
|
|
}
|
|
|
|
|
virtual ~LinkDotResolveVisitor() {}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Link class functions
|
|
|
|
|
|
2006-09-06 17:48:41 +00:00
|
|
|
|
void V3LinkDot::linkDotGuts(AstNetlist* rootp, bool prearray, bool scoped) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
UINFO(2,__FUNCTION__<<": "<<endl);
|
2012-06-20 10:13:28 +00:00
|
|
|
|
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot.tree"));
|
|
|
|
|
LinkDotState state (rootp, prearray, scoped);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
LinkDotFindVisitor visitor(rootp,&state);
|
2012-06-20 10:13:28 +00:00
|
|
|
|
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-find.tree"));
|
2006-09-06 17:48:41 +00:00
|
|
|
|
if (scoped) {
|
2012-05-24 23:15:28 +00:00
|
|
|
|
// Well after the initial link when we're ready to operate on the flat design,
|
|
|
|
|
// process AstScope's. This needs to be separate pass after whole hierarchy graph created.
|
2006-09-06 17:48:41 +00:00
|
|
|
|
LinkDotScopeVisitor visitors(rootp,&state);
|
2012-06-20 10:13:28 +00:00
|
|
|
|
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-scoped.tree"));
|
2006-09-06 17:48:41 +00:00
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
state.dump();
|
|
|
|
|
LinkDotResolveVisitor visitorb(rootp,&state);
|
|
|
|
|
}
|