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: Symbol table
|
|
|
|
|
//
|
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.
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
|
|
|
|
#ifndef _V3LINKSYMTABLE_H_
|
|
|
|
|
#define _V3LINKSYMTABLE_H_ 1
|
|
|
|
|
|
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>
|
2009-11-07 04:16:06 +00:00
|
|
|
|
#include <iomanip>
|
2012-06-20 10:13:28 +00:00
|
|
|
|
#include <memory>
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
|
|
#include "V3Global.h"
|
2011-11-30 03:09:50 +00:00
|
|
|
|
#include "V3Ast.h"
|
2012-06-20 10:13:28 +00:00
|
|
|
|
#include "V3File.h"
|
|
|
|
|
|
|
|
|
|
class VSymGraph;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Symbol table
|
|
|
|
|
|
2012-06-20 10:13:28 +00:00
|
|
|
|
class VSymEnt {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// Symbol table that can have a "superior" table for resolving upper references
|
2012-06-20 10:13:28 +00:00
|
|
|
|
private:
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// MEMBERS
|
2012-06-20 10:13:28 +00:00
|
|
|
|
typedef std::map<string,VSymEnt*> IdNameMap;
|
2009-10-31 14:14:04 +00:00
|
|
|
|
IdNameMap m_idNameMap; // Hash of variables by name
|
2012-06-20 10:13:28 +00:00
|
|
|
|
AstNode* m_nodep; // Node that entry belongs to
|
|
|
|
|
VSymEnt* m_fallbackp; // Table "above" this one in name scope, for fallback resolution
|
|
|
|
|
VSymEnt* m_parentp; // Table that created this table, dot notation needed to resolve into it
|
|
|
|
|
string m_symPrefix; // String to prefix symbols with (for V3LinkDot, unused here)
|
|
|
|
|
static int debug() { return 0; } // NOT runtime, too hot of a function
|
|
|
|
|
private:
|
|
|
|
|
void dumpIterate(ostream& os, const string& indent, int numLevels, const string& searchName) const {
|
|
|
|
|
os<<indent<<left<<setw(30)<<searchName<<setw(0)<<right;
|
|
|
|
|
os<<" "<<setw(16)<<(void*)(this)<<setw(0);
|
|
|
|
|
os<<" n="<<nodep();
|
|
|
|
|
os<<endl;
|
|
|
|
|
for (IdNameMap::const_iterator it=m_idNameMap.begin(); it!=m_idNameMap.end(); ++it) {
|
|
|
|
|
if (numLevels >= 1) {
|
|
|
|
|
it->second->dumpIterate(os, indent+"+ ", numLevels-1, it->first);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// METHODS
|
2012-06-20 10:13:28 +00:00
|
|
|
|
VSymEnt(VSymGraph* graphp, AstNode* nodep); // Below
|
|
|
|
|
~VSymEnt() {}
|
|
|
|
|
void fallbackp(VSymEnt* entp) { m_fallbackp = entp; }
|
|
|
|
|
void parentp(VSymEnt* entp) { m_parentp = entp; }
|
|
|
|
|
VSymEnt* parentp() const { return m_parentp; }
|
|
|
|
|
AstNode* nodep() const { if (!this) return NULL; else return m_nodep; } // null check so can call .findId(...)->nodep()
|
|
|
|
|
string symPrefix() const { return m_symPrefix; }
|
|
|
|
|
void symPrefix(const string& name) { m_symPrefix = name; }
|
|
|
|
|
void insert(const string& name, VSymEnt* entp) {
|
|
|
|
|
UINFO(9, " SymInsert "<<this<<" '"<<name<<"' "<<(void*)entp<<" "<<entp->nodep()<<endl);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
if (m_idNameMap.find(name) != m_idNameMap.end()) {
|
|
|
|
|
if (!V3Error::errorCount()) { // Else may have just reported warning
|
2012-06-20 10:13:28 +00:00
|
|
|
|
if (debug()>=9 || V3Error::debugDefault()) dump(cout,"- err-dump: ", 1);
|
|
|
|
|
entp->nodep()->v3fatalSrc("Inserting two symbols with same name: "<<name<<endl);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2012-06-20 10:13:28 +00:00
|
|
|
|
m_idNameMap.insert(make_pair(name, entp));
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2012-06-20 10:13:28 +00:00
|
|
|
|
void reinsert(const string& name, VSymEnt* entp) {
|
2009-10-31 14:14:04 +00:00
|
|
|
|
IdNameMap::iterator it = m_idNameMap.find(name);
|
|
|
|
|
if (it != m_idNameMap.end()) {
|
2012-06-20 10:13:28 +00:00
|
|
|
|
UINFO(9, " SymReinsert "<<this<<" '"<<name<<"' "<<(void*)entp<<" "<<entp->nodep()<<endl);
|
|
|
|
|
it->second = entp; // Replace
|
2009-10-31 14:14:04 +00:00
|
|
|
|
} else {
|
2012-06-20 10:13:28 +00:00
|
|
|
|
insert(name,entp);
|
2009-10-31 14:14:04 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2012-06-20 10:13:28 +00:00
|
|
|
|
VSymEnt* findIdFlat(const string& name) const {
|
2009-03-24 13:22:58 +00:00
|
|
|
|
// Find identifier without looking upward through symbol hierarchy
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// First, scan this begin/end block or module for the name
|
2009-10-31 14:14:04 +00:00
|
|
|
|
IdNameMap::const_iterator iter = m_idNameMap.find(name);
|
2012-06-20 10:13:28 +00:00
|
|
|
|
UINFO(9, " SymFind "<<this<<" '"<<name<<"' -> "<<(iter == m_idNameMap.end() ? "NONE" : cvtToStr((void*)(iter->second->nodep())))<<endl);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
if (iter != m_idNameMap.end()) return (iter->second);
|
2009-03-23 18:57:15 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2012-06-20 10:13:28 +00:00
|
|
|
|
VSymEnt* findIdFallback(const string& name) const {
|
2009-03-24 13:22:58 +00:00
|
|
|
|
// Find identifier looking upward through symbol hierarchy
|
2009-03-23 18:57:15 +00:00
|
|
|
|
// First, scan this begin/end block or module for the name
|
2012-06-20 10:13:28 +00:00
|
|
|
|
if (VSymEnt* entp = findIdFlat(name)) return entp;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// Then scan the upper begin/end block or module for the name
|
2012-06-20 10:09:07 +00:00
|
|
|
|
if (m_fallbackp) return m_fallbackp->findIdFallback(name);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2012-06-20 10:13:28 +00:00
|
|
|
|
bool import(const VSymEnt* srcp, const string& id_or_star) {
|
2009-11-10 00:07:59 +00:00
|
|
|
|
// Import tokens from source symbol table into this symbol table
|
|
|
|
|
// Returns true if successful
|
|
|
|
|
bool any = false;
|
|
|
|
|
if (id_or_star != "*") {
|
|
|
|
|
IdNameMap::const_iterator it = srcp->m_idNameMap.find(id_or_star);
|
|
|
|
|
if (it != m_idNameMap.end()) {
|
|
|
|
|
reinsert(it->first, it->second);
|
|
|
|
|
any = true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
for (IdNameMap::const_iterator it=srcp->m_idNameMap.begin(); it!=srcp->m_idNameMap.end(); ++it) {
|
|
|
|
|
reinsert(it->first, it->second);
|
|
|
|
|
any = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return any;
|
|
|
|
|
}
|
2012-06-20 10:13:28 +00:00
|
|
|
|
void cellErrorScopes(AstNode* lookp) {
|
|
|
|
|
string scopes;
|
|
|
|
|
for (IdNameMap::iterator it = m_idNameMap.begin(); it!=m_idNameMap.end(); ++it) {
|
|
|
|
|
AstNode* nodep = it->second->nodep();
|
|
|
|
|
if (nodep->castCell()
|
|
|
|
|
|| (nodep->castModule() && nodep->castModule()->isTop())) {
|
|
|
|
|
if (scopes != "") scopes += ", ";
|
|
|
|
|
scopes += AstNode::prettyName(it->first);
|
2009-10-31 14:14:04 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2012-06-20 10:13:28 +00:00
|
|
|
|
cerr<<V3Error::msgPrefix()<<" Known scopes under '"<<lookp->prettyName()<<"': "
|
|
|
|
|
<<scopes<<endl;
|
|
|
|
|
if (debug()) dump(cerr,"\t\t KnownScope: ", 1);
|
|
|
|
|
}
|
|
|
|
|
void dump(ostream& os, const string& indent="", int numLevels=1) const {
|
|
|
|
|
dumpIterate(os,indent,numLevels,"TOP");
|
2009-10-31 14:14:04 +00:00
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
};
|
|
|
|
|
|
2012-06-20 10:13:28 +00:00
|
|
|
|
//######################################################################
|
|
|
|
|
// Symbol tables
|
|
|
|
|
|
|
|
|
|
class VSymGraph {
|
|
|
|
|
// Collection of symbol tables
|
|
|
|
|
// TYPES
|
|
|
|
|
typedef vector<VSymEnt*> SymStack;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
// MEMBERS
|
|
|
|
|
VSymEnt* m_symRootp; // Root symbol table
|
|
|
|
|
SymStack m_symsp; // All symbol tables, to cleanup
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
friend class VSymEnt;
|
|
|
|
|
void pushNewEnt(VSymEnt* entp) { m_symsp.push_back(entp); }
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
VSymEnt* rootp() const { return m_symRootp; }
|
|
|
|
|
// Debug
|
|
|
|
|
void dump(ostream& os, const string& indent="") {
|
|
|
|
|
os<<"SymEnt Dump:\n";
|
|
|
|
|
m_symRootp->dump(os, indent, 9999);
|
|
|
|
|
}
|
|
|
|
|
void dumpFilePrefixed(const string& nameComment) {
|
|
|
|
|
if (v3Global.opt.dumpTree()) {
|
|
|
|
|
string filename = v3Global.debugFilename(nameComment)+".txt";
|
|
|
|
|
const auto_ptr<ofstream> logp (V3File::new_ofstream(filename));
|
|
|
|
|
if (logp->fail()) v3fatalSrc("Can't write "<<filename);
|
|
|
|
|
dump(*logp, "");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public:
|
|
|
|
|
// CREATORS
|
|
|
|
|
VSymGraph(AstNetlist* nodep) {
|
|
|
|
|
m_symRootp = new VSymEnt(this, nodep);
|
|
|
|
|
}
|
|
|
|
|
~VSymGraph() {
|
|
|
|
|
for (SymStack::iterator it = m_symsp.begin(); it != m_symsp.end(); ++it) {
|
|
|
|
|
delete (*it);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
|
|
|
|
|
inline VSymEnt::VSymEnt(VSymGraph* m_graphp, AstNode* nodep)
|
|
|
|
|
: m_nodep(nodep) {
|
|
|
|
|
// No argument to set fallbackp, as generally it's wrong to set it in the new call,
|
|
|
|
|
// Instead it needs to be set on a "findOrNew()" return, as it may have been new'ed
|
|
|
|
|
// by an earlier search insertion.
|
|
|
|
|
m_fallbackp = NULL;
|
|
|
|
|
m_parentp = NULL;
|
|
|
|
|
m_graphp->pushNewEnt(this);
|
|
|
|
|
}
|
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
|
#endif // guard
|