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
//
//*************************************************************************
//
2015-01-07 23:25:53 +00:00
// Copyright 2003-2015 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:
2012-12-31 19:00:04 +00:00
// Top-down traversal in LinkDotFindVisitor
2006-08-26 11:35:28 +00:00
// 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
2012-12-31 19:00:04 +00:00
// Top-down traversal in LinkDotScopeVisitor
// Find VarScope versions of signals (well past original link)
// Top-down traversal in LinkDotParamVisitor
// Create implicit signals
// Top-down traversal in LinkDotResolveVisitor
2006-08-26 11:35:28 +00:00
// VarXRef/Func's:
// Find appropriate named cell and link to var they reference
//*************************************************************************
2013-05-28 01:39:19 +00:00
// Interfaces:
// CELL (.port (ifref)
// ^--- cell -> IfaceDTypeRef(iface)
// ^--- cell.modport -> IfaceDTypeRef(iface,modport)
// ^--- varref(input_ifref) -> IfaceDTypeRef(iface)
// ^--- varref(input_ifref).modport -> IfaceDTypeRef(iface,modport)
// FindVisitor:
// #1: Insert interface Vars
// #2: Insert ModPort names
// IfaceVisitor:
// #3: Update ModPortVarRef to point at interface vars (after #1)
// #4: Create ModPortVarRef symbol table entries
// FindVisitor-insertIfaceRefs()
// #5: Resolve IfaceRefDtype modport names (after #2)
// #7: Record sym of IfaceRefDType and aliased interface and/or modport (after #4,#5)
// insertAllScopeAliases():
// #8: Insert modport's symbols under IfaceRefDType (after #7)
// ResolveVisitor:
// #9: Resolve general variables, which may point into the interface or modport (after #8)
//*************************************************************************
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-07-21 21:12:42 +00:00
// AstNodeModule::user1p() // VSymEnt*. Last symbol created for this node
// ... Note maybe more than one, as can be multiple hierarchy places
// AstVarScope::user2p() // AstVarScope*. Base alias for AstInline of this signal
// AstVar::user2p() // AstFTask*. If a function variable, the task that links to the variable
// AstVar::user4() // bool. True if port set for this variable
// AstBegin::user4() // bool. Did name processing
// AstNodeModule::user4() // bool. Live module
2008-11-25 14:03:49 +00:00
AstUser1InUse m_inuser1 ;
AstUser2InUse m_inuser2 ;
2012-07-21 21:12:42 +00:00
AstUser4InUse m_inuser4 ;
2006-08-26 11:35:28 +00:00
2014-04-04 01:53:39 +00:00
public :
// ENUMS
// In order of priority, compute first ... compute last
enum SAMNum { SAMN_MODPORT , SAMN_IFTOP , SAMN__MAX } ; // Values for m_scopeAliasMap
private :
2006-08-26 11:35:28 +00:00
// TYPES
2013-05-28 01:39:19 +00:00
typedef multimap < string , VSymEnt * > NameScopeSymMap ;
typedef map < VSymEnt * , VSymEnt * > ScopeAliasMap ;
typedef set < pair < AstNodeModule * , string > > ImplicitNameSet ;
typedef vector < VSymEnt * > IfaceVarSyms ;
typedef vector < pair < AstIface * , VSymEnt * > > IfaceModSyms ;
2012-07-22 01:18:07 +00:00
2013-05-25 16:15:38 +00:00
static LinkDotState * s_errorThisp ; // Last self, for error reporting only
2006-08-26 11:35:28 +00:00
// MEMBERS
2012-06-20 10:13:28 +00:00
VSymGraph m_syms ; // Symbol table
2012-07-21 21:12:42 +00:00
VSymEnt * m_dunitEntp ; // $unit entry
2013-05-18 23:45:40 +00:00
NameScopeSymMap m_nameScopeSymMap ; // Map of scope referenced by non-pretty textual name
2012-07-22 01:18:07 +00:00
ImplicitNameSet m_implicitNameSet ; // For [module][signalname] if we can implicitly create it
2014-04-04 01:53:39 +00:00
ScopeAliasMap m_scopeAliasMap [ SAMN__MAX ] ; // Map of <lhs,rhs> aliases
2013-05-28 01:39:19 +00:00
IfaceVarSyms m_ifaceVarSyms ; // List of AstIfaceRefDType's to be imported
IfaceModSyms m_ifaceModSyms ; // List of AstIface+Symbols to be processed
2012-07-21 21:12:42 +00:00
bool m_forPrimary ; // First link
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
2013-05-25 16:15:38 +00:00
2006-08-26 11:35:28 +00:00
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 ;
}
2013-05-28 00:56:20 +00:00
void dump ( const string & nameComment = " linkdot " , bool force = false ) {
if ( debug ( ) > = 6 | | force ) {
string filename = v3Global . debugFilename ( nameComment ) + " .txt " ;
2014-03-15 18:50:03 +00:00
const VL_UNIQUE_PTR < ofstream > logp ( V3File : : new_ofstream ( filename ) ) ;
2013-05-28 00:56:20 +00:00
if ( logp - > fail ( ) ) v3fatalSrc ( " Can't write " < < filename ) ;
ostream & os = * logp ;
m_syms . dump ( os ) ;
2014-04-04 01:53:39 +00:00
bool first = true ;
for ( int samn = 0 ; samn < SAMN__MAX ; + + samn ) {
if ( ! m_scopeAliasMap [ samn ] . empty ( ) ) {
if ( first ) os < < " \n ScopeAliasMap: \n " ;
first = false ;
for ( ScopeAliasMap : : iterator it = m_scopeAliasMap [ samn ] . begin ( ) ;
it ! = m_scopeAliasMap [ samn ] . end ( ) ; + + it ) {
// left side is what we will import into
os < < " \t " < < samn < < " \t " < < it - > first < < " ( " < < it - > first - > nodep ( ) - > typeName ( )
< < " ) <- " < < it - > second < < " " < < it - > second - > nodep ( ) < < endl ;
}
}
2013-05-28 01:39:19 +00:00
}
2013-05-28 00:56:20 +00:00
}
2012-07-21 13:27:57 +00:00
}
2013-05-25 16:15:38 +00:00
static void preErrorDumpHandler ( ) {
if ( s_errorThisp ) s_errorThisp - > preErrorDump ( ) ;
}
2012-07-21 13:27:57 +00:00
void preErrorDump ( ) {
static bool diddump = false ;
if ( ! diddump & & v3Global . opt . dumpTree ( ) ) {
diddump = true ;
2013-05-28 00:56:20 +00:00
dump ( " linkdot-preerr " , true ) ;
2013-02-02 19:11:50 +00:00
v3Global . rootp ( ) - > dumpTreeFile ( v3Global . debugFilename ( " linkdot-preerr.tree " ) ) ;
2012-07-21 13:27:57 +00:00
}
}
2006-08-26 11:35:28 +00:00
// CONSTRUCTORS
2012-07-21 13:27:57 +00:00
LinkDotState ( AstNetlist * rootp , VLinkDotStep step )
2012-06-20 10:13:28 +00:00
: m_syms ( rootp ) {
2006-08-26 11:35:28 +00:00
UINFO ( 4 , __FUNCTION__ < < " : " < < endl ) ;
2012-07-21 21:12:42 +00:00
m_forPrimary = ( step = = LDS_PRIMARY ) ;
2012-07-21 13:27:57 +00:00
m_forPrearray = ( step = = LDS_PARAMED | | step = = LDS_PRIMARY ) ;
m_forScopeCreation = ( step = = LDS_SCOPED ) ;
2012-07-21 21:12:42 +00:00
m_dunitEntp = NULL ;
2013-05-25 16:15:38 +00:00
s_errorThisp = this ;
V3Error : : errorExitCb ( preErrorDumpHandler ) ; // If get error, dump self
}
~ LinkDotState ( ) {
V3Error : : errorExitCb ( NULL ) ;
s_errorThisp = NULL ;
2006-08-26 11:35:28 +00:00
}
2008-06-10 01:25:10 +00:00
2006-08-26 11:35:28 +00:00
// ACCESSORS
2012-12-18 01:26:40 +00:00
VSymGraph * symsp ( ) { return & m_syms ; }
2012-07-21 21:12:42 +00:00
bool forPrimary ( ) const { return m_forPrimary ; }
bool forPrearray ( ) const { return m_forPrearray ; }
2006-08-26 11:35:28 +00:00
bool forScopeCreation ( ) const { return m_forScopeCreation ; }
// METHODS
2012-07-21 21:12:42 +00:00
static string nodeTextType ( AstNode * nodep ) {
if ( nodep - > castVar ( ) ) return " variable " ;
else if ( nodep - > castCell ( ) ) return " cell " ;
else if ( nodep - > castTask ( ) ) return " task " ;
else if ( nodep - > castFunc ( ) ) return " function " ;
else if ( nodep - > castBegin ( ) ) return " block " ;
2013-05-28 01:39:19 +00:00
else if ( nodep - > castIface ( ) ) return " interface " ;
2012-07-21 21:12:42 +00:00
else return nodep - > prettyTypeName ( ) ;
}
VSymEnt * rootEntp ( ) const { return m_syms . rootp ( ) ; }
VSymEnt * dunitEntp ( ) const { return m_dunitEntp ; }
void checkDuplicate ( VSymEnt * lookupSymp , AstNode * nodep , const string & name ) {
// Lookup the given name under current symbol table
// Insert if not found
// Report error if there's a duplicate
//
// Note we only check for conflicts at the same level; it's ok if one block hides another
// We also wouldn't want to not insert it even though it's lower down
VSymEnt * foundp = lookupSymp - > findIdFlat ( name ) ;
AstNode * fnodep = foundp - > nodep ( ) ;
if ( ! fnodep ) {
// Not found, will add in a moment.
} else if ( nodep = = fnodep ) { // Already inserted.
// Good.
2013-01-09 00:06:52 +00:00
} else if ( foundp - > imported ( ) ) { // From package
// We don't throw VARHIDDEN as if the import is later the symbol table's import wouldn't warn
2012-07-21 21:12:42 +00:00
} else if ( nodep - > castBegin ( ) & & fnodep - > castBegin ( )
& & nodep - > castBegin ( ) - > generate ( ) ) {
// Begin: ... blocks often replicate under genif/genfor, so simply suppress duplicate checks
// See t_gen_forif.v for an example.
} else {
2012-09-07 23:51:41 +00:00
UINFO ( 4 , " name " < < name < < endl ) ; // Not always same as nodep->name
2012-07-21 21:12:42 +00:00
UINFO ( 4 , " Var1 " < < nodep < < endl ) ;
UINFO ( 4 , " Var2 " < < fnodep < < endl ) ;
if ( nodep - > type ( ) = = fnodep - > type ( ) ) {
nodep - > v3error ( " Duplicate declaration of " < < nodeTextType ( fnodep ) < < " : " < < nodep - > prettyName ( ) < < endl
< < fnodep - > warnMore ( ) < < " ... Location of original declaration " ) ;
} else {
nodep - > v3error ( " Unsupported in C: " < < ucfirst ( nodeTextType ( nodep ) ) < < " has the same name as "
< < nodeTextType ( fnodep ) < < " : " < < nodep - > prettyName ( ) < < endl
< < fnodep - > warnMore ( ) < < " ... Location of original declaration " ) ;
}
}
}
void insertDUnit ( AstNetlist * nodep ) {
// $unit on top scope
VSymEnt * symp = new VSymEnt ( & m_syms , nodep ) ;
UINFO ( 9 , " INSERTdunit se " < < ( void * ) symp < < endl ) ;
symp - > parentp ( rootEntp ( ) ) ; // Needed so backward search can find name of top module
symp - > fallbackp ( NULL ) ;
rootEntp ( ) - > insert ( " $unit " , symp ) ; // Space so can never name conflict with user code
//
if ( m_dunitEntp ) nodep - > v3fatalSrc ( " Call insertDUnit only once " ) ;
m_dunitEntp = symp ;
2012-06-20 10:13:28 +00:00
}
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
VSymEnt * symp = new VSymEnt ( & m_syms , nodep ) ;
2012-07-20 01:18:39 +00:00
UINFO ( 9 , " INSERTtop se " < < ( void * ) symp < < " " < < scopename < < " " < < nodep < < endl ) ;
2012-07-21 21:12:42 +00:00
symp - > parentp ( rootEntp ( ) ) ; // Needed so backward search can find name of top module
symp - > fallbackp ( dunitEntp ( ) ) ; // Needed so can find $unit stuff
2012-06-20 10:13:28 +00:00
nodep - > user1p ( symp ) ;
2012-07-21 21:12:42 +00:00
checkDuplicate ( rootEntp ( ) , nodep , nodep - > origName ( ) ) ;
rootEntp ( ) - > insert ( nodep - > origName ( ) , symp ) ;
2013-05-18 23:45:40 +00:00
if ( forScopeCreation ( ) ) m_nameScopeSymMap . insert ( make_pair ( scopename , symp ) ) ;
2012-06-20 10:13:28 +00:00
return symp ;
}
2012-07-20 01:18:39 +00:00
VSymEnt * insertCell ( VSymEnt * abovep , VSymEnt * modSymp ,
2012-06-20 10:13:28 +00:00
AstCell * nodep , const string & scopename ) {
2012-07-21 21:12:42 +00:00
if ( ! abovep ) nodep - > v3fatalSrc ( " Null symbol table inserting node " ) ;
2012-06-20 10:13:28 +00:00
VSymEnt * symp = new VSymEnt ( & m_syms , nodep ) ;
2012-07-20 01:18:39 +00:00
UINFO ( 9 , " INSERTcel se " < < ( void * ) symp < < " " < < scopename < < " above=se " < < ( void * ) abovep < < " mods=se " < < ( void * ) modSymp < < " node= " < < nodep < < endl ) ;
2012-06-20 10:13:28 +00:00
symp - > parentp ( abovep ) ;
2012-07-21 21:12:42 +00:00
symp - > fallbackp ( dunitEntp ( ) ) ; // Needed so can find $unit stuff
nodep - > user1p ( symp ) ;
2012-06-20 10:13:28 +00:00
if ( nodep - > modp ( ) ) nodep - > modp ( ) - > user1p ( symp ) ;
2012-07-21 21:12:42 +00:00
checkDuplicate ( abovep , nodep , nodep - > origName ( ) ) ;
2012-06-20 10:13:28 +00:00
abovep - > reinsert ( nodep - > origName ( ) , symp ) ;
2014-06-10 02:00:45 +00:00
if ( forScopeCreation ( ) & & abovep ! = modSymp & & ! modSymp - > findIdFlat ( nodep - > name ( ) ) ) {
// If it's foo_DOT_bar, we need to be able to find it under "foo_DOT_bar" too.
2012-06-20 10:13:28 +00:00
// Duplicates are possible, as until resolve generates might have 2 same cells under an if
2012-07-20 01:18:39 +00:00
modSymp - > reinsert ( nodep - > name ( ) , symp ) ;
2006-08-26 11:35:28 +00:00
}
2013-05-18 23:45:40 +00:00
if ( forScopeCreation ( ) ) m_nameScopeSymMap . insert ( make_pair ( scopename , symp ) ) ;
2012-06-20 10:13:28 +00:00
return symp ;
}
2012-07-20 01:18:39 +00:00
VSymEnt * insertInline ( VSymEnt * abovep , VSymEnt * modSymp ,
2012-06-20 10:13:28 +00:00
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
2012-07-20 01:18:39 +00:00
if ( ! abovep ) nodep - > v3fatalSrc ( " Null symbol table inserting node " ) ;
2012-06-20 10:13:28 +00:00
VSymEnt * symp = new VSymEnt ( & m_syms , nodep ) ;
2012-07-20 01:18:39 +00:00
UINFO ( 9 , " INSERTinl se " < < ( void * ) symp < < " " < < basename < < " above=se " < < ( void * ) abovep < < " mods=se " < < ( void * ) modSymp < < " node= " < < nodep < < endl ) ;
2012-06-20 10:13:28 +00:00
symp - > parentp ( abovep ) ;
2012-07-20 01:18:39 +00:00
symp - > fallbackp ( modSymp ) ;
2012-06-20 10:13:28 +00:00
symp - > symPrefix ( nodep - > name ( ) + " __DOT__ " ) ;
2012-07-21 21:12:42 +00:00
nodep - > user1p ( symp ) ;
checkDuplicate ( abovep , nodep , nodep - > name ( ) ) ;
2012-06-20 10:13:28 +00:00
abovep - > reinsert ( basename , symp ) ;
2012-07-21 21:12:42 +00:00
if ( abovep ! = modSymp & & ! modSymp - > findIdFlat ( nodep - > name ( ) ) ) {
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-07-20 01:18:39 +00:00
modSymp - > reinsert ( nodep - > name ( ) , symp ) ;
2006-08-26 11:35:28 +00:00
}
2012-06-20 10:13:28 +00:00
return symp ;
}
2012-07-21 21:12:42 +00:00
VSymEnt * insertBlock ( VSymEnt * abovep , const string & name , AstNode * nodep , AstPackage * packagep ) {
// A fake point in the hierarchy, corresponding to a begin or function/task block
2012-06-20 10:13:28 +00:00
// 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
2012-07-21 13:27:57 +00:00
// However, cells walk the graph, so cells will appear under the begin/ftask itself
2012-07-20 01:18:39 +00:00
if ( ! abovep ) nodep - > v3fatalSrc ( " Null symbol table inserting node " ) ;
2012-06-20 10:13:28 +00:00
VSymEnt * symp = new VSymEnt ( & m_syms , nodep ) ;
2012-07-20 01:18:39 +00:00
UINFO ( 9 , " INSERTblk se " < < ( void * ) symp < < " above=se " < < ( void * ) abovep < < " node= " < < nodep < < endl ) ;
2012-06-20 10:13:28 +00:00
symp - > parentp ( abovep ) ;
2012-07-21 21:12:42 +00:00
symp - > packagep ( packagep ) ;
2013-05-28 00:56:20 +00:00
symp - > fallbackp ( abovep ) ;
2012-07-21 21:12:42 +00:00
nodep - > user1p ( symp ) ;
if ( name ! = " " ) {
checkDuplicate ( abovep , nodep , name ) ;
2012-06-20 10:13:28 +00:00
}
2012-07-21 21:12:42 +00:00
// Duplicates are possible, as until resolve generates might have 2 same cells under an if
abovep - > reinsert ( name , symp ) ;
2012-06-20 10:13:28 +00:00
return symp ;
2006-12-18 18:14:53 +00:00
}
2012-12-18 00:07:23 +00:00
VSymEnt * insertSym ( VSymEnt * abovep , const string & name , AstNode * nodep , AstPackage * packagep ) {
2012-07-20 01:18:39 +00:00
if ( ! abovep ) nodep - > v3fatalSrc ( " Null symbol table inserting node " ) ;
2012-06-20 10:13:28 +00:00
VSymEnt * symp = new VSymEnt ( & m_syms , nodep ) ;
2012-07-21 21:12:42 +00:00
UINFO ( 9 , " INSERTsym se " < < ( void * ) symp < < " name=' " < < name < < " ' above=se " < < ( 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
symp - > packagep ( packagep ) ;
symp - > parentp ( abovep ) ;
symp - > fallbackp ( abovep ) ;
nodep - > user1p ( symp ) ;
checkDuplicate ( abovep , nodep , name ) ;
2013-01-09 00:06:52 +00:00
abovep - > reinsert ( name , symp ) ;
2012-12-18 00:07:23 +00:00
return symp ;
2006-08-26 11:35:28 +00:00
}
2012-07-20 01:18:39 +00:00
static 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-07-21 13:27:57 +00:00
static VSymEnt * getNodeSym ( AstNode * nodep ) {
2012-07-21 21:12:42 +00:00
// Don't use this in ResolveVisitor, as we need to pick up the proper reference under each SCOPE
2012-06-20 10:13:28 +00:00
VSymEnt * symp = nodep - > user1p ( ) - > castSymEnt ( ) ;
2012-07-21 13:27:57 +00:00
if ( ! symp ) nodep - > v3fatalSrc ( " Module/etc never assigned a symbol entry? " ) ;
2012-06-20 10:13:28 +00:00
return symp ;
2006-08-26 11:35:28 +00:00
}
2012-07-18 01:29:10 +00:00
VSymEnt * getScopeSym ( AstScope * nodep ) {
2013-05-18 23:45:40 +00:00
NameScopeSymMap : : iterator it = m_nameScopeSymMap . find ( nodep - > name ( ) ) ;
if ( it = = m_nameScopeSymMap . 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
}
2013-05-18 23:45:40 +00:00
return it - > second ;
2006-08-26 11:35:28 +00:00
}
2012-07-22 01:18:07 +00:00
void implicitOkAdd ( AstNodeModule * nodep , const string & varname ) {
// Mark the given variable name as being allowed to be implicitly declared
if ( nodep ) {
2013-05-18 23:45:40 +00:00
ImplicitNameSet : : iterator it = m_implicitNameSet . find ( make_pair ( nodep , varname ) ) ;
if ( it = = m_implicitNameSet . end ( ) ) {
2012-07-22 01:18:07 +00:00
m_implicitNameSet . insert ( make_pair ( nodep , varname ) ) ;
}
}
}
bool implicitOk ( AstNodeModule * nodep , const string & varname ) {
return nodep
& & ( m_implicitNameSet . find ( make_pair ( nodep , varname ) ) ! = m_implicitNameSet . end ( ) ) ;
}
2013-05-28 01:39:19 +00:00
// Track and later recurse interface modules
void insertIfaceModSym ( AstIface * nodep , VSymEnt * symp ) {
m_ifaceModSyms . push_back ( make_pair ( nodep , symp ) ) ;
}
void computeIfaceModSyms ( ) ;
// Track and later insert interface references
void insertIfaceVarSym ( VSymEnt * symp ) { // Where sym is for a VAR of dtype IFACEREFDTYPE
m_ifaceVarSyms . push_back ( symp ) ;
}
void computeIfaceVarSyms ( ) {
for ( IfaceVarSyms : : iterator it = m_ifaceVarSyms . begin ( ) ; it ! = m_ifaceVarSyms . end ( ) ; + + it ) {
VSymEnt * varSymp = * it ;
AstVar * varp = varSymp - > nodep ( ) - > castVar ( ) ;
UINFO ( 9 , " insAllIface se " < < ( void * ) varSymp < < " " < < varp < < endl ) ;
AstIfaceRefDType * ifacerefp = varp - > subDTypep ( ) - > castIfaceRefDType ( ) ;
if ( ! ifacerefp ) varp - > v3fatalSrc ( " Non-ifacerefs on list! " ) ;
if ( ! ifacerefp - > ifaceViaCellp ( ) ) ifacerefp - > v3fatalSrc ( " Unlinked interface " ) ;
VSymEnt * ifaceSymp = getNodeSym ( ifacerefp - > ifaceViaCellp ( ) ) ;
VSymEnt * ifOrPortSymp = ifaceSymp ;
// Link Modport names to the Modport Node under the Interface
if ( ifacerefp - > isModport ( ) ) {
VSymEnt * foundp = ifaceSymp - > findIdFallback ( ifacerefp - > modportName ( ) ) ;
bool ok = false ;
if ( foundp ) {
if ( AstModport * modportp = foundp - > nodep ( ) - > castModport ( ) ) {
UINFO ( 4 , " Link Modport: " < < modportp < < endl ) ;
ifacerefp - > modportp ( modportp ) ;
ifOrPortSymp = foundp ;
ok = true ;
}
}
if ( ! ok ) ifacerefp - > v3error ( " Modport not found under interface ' "
< < ifacerefp - > prettyName ( ifacerefp - > ifaceName ( ) )
< < " ': " < < ifacerefp - > prettyName ( ifacerefp - > modportName ( ) ) ) ;
}
// Alias won't expand until interfaces and modport names are known; see notes at top
2014-04-04 01:53:39 +00:00
insertScopeAlias ( SAMN_IFTOP , varSymp , ifOrPortSymp ) ;
2013-05-28 01:39:19 +00:00
}
m_ifaceVarSyms . clear ( ) ;
}
2014-04-04 01:53:39 +00:00
void insertScopeAlias ( SAMNum samn , VSymEnt * lhsp , VSymEnt * rhsp ) {
// Track and later insert scope aliases; an interface referenced by a child cell connecting to that interface
// Typically lhsp=VAR w/dtype IFACEREF, rhsp=IFACE cell
2013-05-28 01:39:19 +00:00
UINFO ( 9 , " insertScopeAlias se " < < ( void * ) lhsp < < " se " < < ( void * ) rhsp < < endl ) ;
2014-04-04 01:53:39 +00:00
m_scopeAliasMap [ samn ] . insert ( make_pair ( lhsp , rhsp ) ) ;
2013-05-28 01:39:19 +00:00
}
void computeScopeAliases ( ) {
UINFO ( 9 , " computeIfaceAliases \n " ) ;
2014-04-04 01:53:39 +00:00
for ( int samn = 0 ; samn < SAMN__MAX ; + + samn ) {
for ( ScopeAliasMap : : iterator it = m_scopeAliasMap [ samn ] . begin ( ) ;
it ! = m_scopeAliasMap [ samn ] . end ( ) ; + + it ) {
VSymEnt * lhsp = it - > first ;
VSymEnt * srcp = lhsp ;
while ( 1 ) { // Follow chain of aliases up to highest level non-alias
ScopeAliasMap : : iterator it2 = m_scopeAliasMap [ samn ] . find ( srcp ) ;
if ( it2 ! = m_scopeAliasMap [ samn ] . end ( ) ) { srcp = it2 - > second ; continue ; }
else break ;
}
UINFO ( 9 , " iiasa: Insert alias se " < < lhsp < < " ( " < < lhsp - > nodep ( ) - > typeName ( )
< < " ) <- se " < < srcp < < " " < < srcp - > nodep ( ) < < endl ) ;
// srcp should be an interface reference pointing to the interface we want to import
lhsp - > importFromIface ( symsp ( ) , srcp ) ;
2013-05-28 01:39:19 +00:00
}
2014-04-04 01:53:39 +00:00
//m_scopeAliasMap[samn].clear(); // Done with it, but put into debug file
2013-05-28 01:39:19 +00:00
}
}
2012-07-21 21:12:42 +00:00
private :
VSymEnt * findWithAltFallback ( VSymEnt * symp , const string & name , const string & altname ) {
VSymEnt * findp = symp - > findIdFallback ( name ) ;
if ( findp ) return findp ;
if ( altname ! = " " ) {
UINFO ( 8 , " alt fallback \n " ) ;
findp = symp - > findIdFallback ( altname ) ;
}
return findp ;
}
public :
2012-07-20 01:18:39 +00:00
VSymEnt * findDotted ( VSymEnt * lookupSymp , const string & dotname ,
2012-06-20 10:13:28 +00:00
string & baddot , VSymEnt * & okSymp ) {
2007-05-22 12:15:01 +00:00
// Given a dotted hierarchy name, return where in scope it is
2012-07-20 01:18:39 +00:00
// Note when dotname=="" we just fall through and return lookupSymp
UINFO ( 8 , " dottedFind se " < < ( void * ) lookupSymp < < " ' " < < dotname < < " ' " < < endl ) ;
2006-08-26 11:35:28 +00:00
bool firstId = true ;
string leftname = dotname ;
2012-07-20 01:18:39 +00:00
okSymp = lookupSymp ; // 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-07-20 01:18:39 +00:00
okSymp = lookupSymp ;
2006-09-06 17:48:41 +00:00
string altIdent = " " ;
if ( m_forPrearray ) {
2012-07-21 21:12:42 +00:00
// GENFOR Begin is foo__BRA__##__KET__ after we've genloop unrolled,
// but presently should be just "foo".
// Likewise cell foo__[array] before we've expanded arrays is just foo
if ( ( pos = ident . rfind ( " __BRA__ " ) ) ! = string : : npos ) {
2006-09-06 17:48:41 +00:00
altIdent = ident . substr ( 0 , pos ) ;
}
}
2012-07-21 13:27:57 +00:00
UINFO ( 8 , " id " < < ident < < " alt " < < altIdent < < " left " < < leftname < < " at se " < < lookupSymp < < 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-07-20 01:18:39 +00:00
AstCell * cellp = lookupSymp - > nodep ( ) - > castCell ( ) ; // Replicated below
AstCellInline * inlinep = lookupSymp - > nodep ( ) - > castCellInline ( ) ; // Replicated below
if ( VSymEnt * findSymp = findWithAltFallback ( lookupSymp , ident , altIdent ) ) {
lookupSymp = 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-07-20 01:18:39 +00:00
while ( lookupSymp ) {
lookupSymp = lookupSymp - > parentp ( ) ;
cellp = lookupSymp - > nodep ( ) - > castCell ( ) ; // Replicated above
inlinep = lookupSymp - > nodep ( ) - > castCellInline ( ) ; // Replicated above
if ( lookupSymp ) {
UINFO ( 9 , " \t \t Up to " < < lookupSymp < < endl ) ;
2012-06-20 10:13:28 +00:00
if ( ( cellp & & cellp - > modp ( ) - > origName ( ) = = ident )
| | ( inlinep & & inlinep - > origModName ( ) = = ident ) ) {
2006-08-26 11:35:28 +00:00
break ;
}
2012-07-20 01:18:39 +00:00
else if ( VSymEnt * findSymp = findWithAltFallback ( lookupSymp , ident , altIdent ) ) {
lookupSymp = 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-07-20 01:18:39 +00:00
if ( ! lookupSymp ) return NULL ; // Not found
2006-08-26 11:35:28 +00:00
}
} else { // Searching for middle submodule, must be a cell name
2012-07-20 01:18:39 +00:00
if ( VSymEnt * findSymp = findWithAltFallback ( lookupSymp , ident , altIdent ) ) {
lookupSymp = findSymp ;
2006-08-26 11:35:28 +00:00
} else {
return NULL ; // Not found
}
}
firstId = false ;
}
2012-07-20 01:18:39 +00:00
return lookupSymp ;
2006-08-26 11:35:28 +00:00
}
2012-07-21 21:12:42 +00:00
VSymEnt * findSymPrefixed ( VSymEnt * lookupSymp , const string & dotname , string & baddot ) {
2012-07-23 02:48:39 +00:00
// Find symbol in given point in hierarchy, allowing prefix (post-Inline)
2012-07-20 01:18:39 +00:00
// For simplicity lookupSymp may be passed NULL result from findDotted
if ( ! lookupSymp ) return NULL ;
2012-07-18 01:29:10 +00:00
UINFO ( 8 , " \t \t findSymPrefixed " < < dotname
2012-07-21 21:12:42 +00:00
< < " under se " < < ( void * ) lookupSymp
2012-07-20 01:18:39 +00:00
< < ( ( lookupSymp - > symPrefix ( ) = = " " ) ? " " : " as " )
< < ( ( lookupSymp - > symPrefix ( ) = = " " ) ? " " : lookupSymp - > symPrefix ( ) + dotname )
< < " at se " < < lookupSymp
2006-08-26 11:35:28 +00:00
< < endl ) ;
2012-07-21 21:12:42 +00:00
VSymEnt * foundp = lookupSymp - > findIdFallback ( lookupSymp - > symPrefix ( ) + dotname ) ; // Might be NULL
if ( ! foundp ) baddot = dotname ;
return foundp ;
}
2006-08-26 11:35:28 +00:00
} ;
2013-05-25 16:15:38 +00:00
LinkDotState * LinkDotState : : s_errorThisp = NULL ;
2006-08-26 11:35:28 +00:00
//======================================================================
class LinkDotFindVisitor : public AstNVisitor {
// STATE
LinkDotState * m_statep ; // State to pass between visitors, including symbol table
2012-07-21 21:12:42 +00:00
AstPackage * m_packagep ; // Current package
2012-07-18 01:29:10 +00:00
VSymEnt * m_modSymp ; // Symbol Entry for current module
2012-07-21 21:12:42 +00:00
VSymEnt * m_curSymp ; // Symbol Entry for current table, where to lookup/insert
2006-08-26 11:35:28 +00:00
string m_scope ; // Scope text
AstBegin * m_beginp ; // Current Begin/end block
2012-07-21 21:12:42 +00:00
AstNodeFTask * m_ftaskp ; // Current function/task
bool m_inGenerate ; // Inside a generate
int m_paramNum ; // Parameter number, for position based connection
int m_beginNum ; // Begin block number, 0=none seen
int m_modBeginNum ; // Begin block number in module, 0=none seen
2009-01-21 21:56:50 +00:00
2012-07-21 21:12:42 +00:00
// METHODS
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()) {}}
2012-07-21 21:12:42 +00:00
m_statep - > insertDUnit ( nodep ) ;
// First back iterate, to find all packages. Backward as must do base packages before using packages
nodep - > iterateChildrenBackwards ( * this ) ;
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-07-18 01:29:10 +00:00
m_curSymp = m_modSymp = m_statep - > insertTopCell ( topmodp , m_scope ) ;
2008-03-25 13:42:48 +00:00
{
topmodp - > accept ( * this ) ;
}
m_scope = " " ;
2012-07-18 01:29:10 +00:00
m_curSymp = m_modSymp = NULL ;
2006-08-26 11:35:28 +00:00
}
}
2012-07-21 21:12:42 +00:00
virtual void visit ( AstTypeTable * nodep , AstNUser * ) { }
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-07-21 21:12:42 +00:00
// m_curSymp/m_modSymp maybe NULL for packages and non-top modules
// Packages will be under top after the initial phases, but until then need separate handling
bool standalonePkg = ! m_modSymp & & ( m_statep - > forPrearray ( ) & & nodep - > castPackage ( ) ) ;
bool doit = ( m_modSymp | | standalonePkg ) ;
string oldscope = m_scope ;
VSymEnt * oldModSymp = m_modSymp ;
VSymEnt * oldCurSymp = m_curSymp ;
2012-11-03 00:30:47 +00:00
int oldParamNum = m_paramNum ;
int oldBeginNum = m_beginNum ;
int oldModBeginNum = m_modBeginNum ;
2012-07-21 21:12:42 +00:00
if ( doit ) {
UINFO ( 2 , " Link Module: " < < nodep < < endl ) ;
if ( nodep - > dead ( ) ) nodep - > v3fatalSrc ( " Module in cell tree mislabeled as dead? " ) ;
VSymEnt * upperSymp = m_curSymp ? m_curSymp : m_statep - > rootEntp ( ) ;
m_packagep = nodep - > castPackage ( ) ;
if ( standalonePkg ) {
if ( m_packagep - > isDollarUnit ( ) ) {
m_curSymp = m_modSymp = m_statep - > dunitEntp ( ) ;
nodep - > user1p ( m_curSymp ) ;
} else {
m_scope = nodep - > name ( ) ;
m_curSymp = m_modSymp = m_statep - > insertBlock ( upperSymp , nodep - > name ( ) + " :: " , nodep , m_packagep ) ;
UINFO ( 9 , " New module scope " < < m_curSymp < < endl ) ;
}
}
//
m_paramNum = 0 ;
m_beginNum = 0 ;
m_modBeginNum = 0 ;
// m_modSymp/m_curSymp for non-packages set by AstCell above this module
// Iterate
2006-08-26 11:35:28 +00:00
nodep - > iterateChildren ( * this ) ;
2012-07-21 21:12:42 +00:00
nodep - > user4 ( true ) ;
2013-05-28 01:39:19 +00:00
// Interfaces need another pass when signals are resolved
if ( AstIface * ifacep = nodep - > castIface ( ) ) {
m_statep - > insertIfaceModSym ( ifacep , m_curSymp ) ;
}
2012-07-21 21:12:42 +00:00
} else { //!doit
// Will be optimized away later
// Can't remove now, as our backwards iterator will throw up
UINFO ( 5 , " Module not under any CELL or top - dead module: " < < nodep < < endl ) ;
2006-08-26 11:35:28 +00:00
}
2012-07-21 21:12:42 +00:00
m_scope = oldscope ;
m_modSymp = oldModSymp ;
m_curSymp = oldCurSymp ;
2012-11-03 00:30:47 +00:00
m_paramNum = oldParamNum ;
m_beginNum = oldBeginNum ;
m_modBeginNum = oldModBeginNum ;
2012-07-21 21:12:42 +00:00
// Prep for next
m_packagep = NULL ;
2006-08-26 11:35:28 +00:00
}
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 ) ;
2012-07-18 01:29:10 +00:00
// Process XREFs/etc inside pins
2006-12-12 18:25:33 +00:00
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-07-18 01:29:10 +00:00
VSymEnt * oldModSymp = m_modSymp ;
VSymEnt * oldCurSymp = m_curSymp ;
2012-09-07 23:51:41 +00:00
int oldParamNum = m_paramNum ;
2006-08-26 11:35:28 +00:00
// Where do we add it?
2012-07-18 01:29:10 +00:00
VSymEnt * aboveSymp = m_curSymp ;
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 ) ;
2012-07-21 13:27:57 +00:00
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-07-18 01:29:10 +00:00
m_curSymp = m_modSymp = m_statep - > insertCell ( aboveSymp , m_modSymp , nodep , m_scope ) ;
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-07-18 01:29:10 +00:00
m_modSymp = oldModSymp ;
m_curSymp = oldCurSymp ;
2012-09-07 23:51:41 +00:00
m_paramNum = oldParamNum ;
2006-08-26 11:35:28 +00:00
}
virtual void visit ( AstCellInline * nodep , AstNUser * ) {
UINFO ( 5 , " CELLINLINE under " < < m_scope < < " is " < < nodep < < endl ) ;
2012-07-18 01:29:10 +00:00
VSymEnt * aboveSymp = m_curSymp ;
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 ) ;
2012-07-21 13:27:57 +00:00
if ( ! aboveSymp ) {
nodep - > v3fatalSrc ( " Can't find cellinline insertion point at ' " < < baddot < < " ' in: " < < nodep - > prettyName ( ) ) ;
}
2012-07-18 01:29:10 +00:00
m_statep - > insertInline ( aboveSymp , m_modSymp , nodep , ident ) ;
2006-08-26 11:35:28 +00:00
} else { // No __DOT__, just directly underneath
2012-07-18 01:29:10 +00:00
m_statep - > insertInline ( aboveSymp , m_modSymp , nodep , nodep - > name ( ) ) ;
2006-08-26 11:35:28 +00:00
}
}
2012-08-07 22:24:51 +00:00
virtual void visit ( AstDefParam * nodep , AstNUser * ) {
nodep - > user1p ( m_curSymp ) ;
nodep - > iterateChildren ( * this ) ;
}
2012-07-21 21:12:42 +00:00
virtual void visit ( AstGenerate * nodep , AstNUser * ) {
// Begin: ... blocks often replicate under genif/genfor, so simply suppress duplicate checks
// See t_gen_forif.v for an example.
bool lastInGen = m_inGenerate ;
{
m_inGenerate = true ;
nodep - > iterateChildren ( * this ) ;
}
m_inGenerate = lastInGen ;
}
2006-08-26 11:35:28 +00:00
virtual void visit ( AstBegin * nodep , AstNUser * ) {
UINFO ( 5 , " " < < nodep < < endl ) ;
2012-07-21 21:12:42 +00:00
// Rename "genblk"s to include a number
if ( m_statep - > forPrimary ( ) & & ! nodep - > user4SetOnce ( ) ) {
if ( nodep - > name ( ) = = " genblk " ) {
+ + m_beginNum ;
nodep - > name ( nodep - > name ( ) + cvtToStr ( m_beginNum ) ) ;
}
// Just for loop index, make special name. The [00] is so it will "dearray" to same
// name as after we expand the GENFOR
if ( nodep - > genforp ( ) ) nodep - > name ( nodep - > name ( ) ) ;
}
// All blocks are numbered in the standard, IE we start with "genblk1" even if only one.
if ( nodep - > name ( ) = = " " & & nodep - > unnamed ( ) ) {
// Unnamed blocks are only important when they contain var
// decls, so search for them. (Otherwise adding all the
// unnamed#'s would just confuse tracing variables in
// places such as tasks, where "task ...; begin ... end"
// are common.
for ( AstNode * stmtp = nodep - > stmtsp ( ) ; stmtp ; stmtp = stmtp - > nextp ( ) ) {
if ( stmtp - > castVar ( ) ) {
+ + m_modBeginNum ;
nodep - > name ( " unnamedblk " + cvtToStr ( m_modBeginNum ) ) ;
break ;
}
}
}
int oldNum = m_beginNum ;
2006-08-26 11:35:28 +00:00
AstBegin * oldbegin = m_beginp ;
2012-07-21 13:27:57 +00:00
VSymEnt * oldCurSymp = m_curSymp ;
2006-12-18 18:14:53 +00:00
{
2012-07-21 21:12:42 +00:00
m_beginNum = 0 ;
2006-12-18 18:14:53 +00:00
m_beginp = nodep ;
2012-07-21 21:12:42 +00:00
m_curSymp = m_statep - > insertBlock ( m_curSymp , nodep - > name ( ) , nodep , m_packagep ) ;
m_curSymp - > fallbackp ( oldCurSymp ) ;
// Iterate
nodep - > iterateChildren ( * this ) ;
2006-12-18 18:14:53 +00:00
}
2012-07-21 13:27:57 +00:00
m_curSymp = oldCurSymp ;
2006-08-26 11:35:28 +00:00
m_beginp = oldbegin ;
2012-07-21 21:12:42 +00:00
m_beginNum = oldNum ;
2006-08-26 11:35:28 +00:00
}
2012-05-28 13:18:18 +00:00
virtual void visit ( AstNodeFTask * nodep , AstNUser * ) {
2012-07-21 21:12:42 +00:00
// NodeTask: Remember its name for later resolution
UINFO ( 5 , " " < < nodep < < endl ) ;
if ( ! m_curSymp | | ! m_modSymp ) nodep - > v3fatalSrc ( " Function/Task not under module?? \n " ) ;
// Remember the existing symbol table scope
VSymEnt * oldCurSymp = m_curSymp ;
{
// Create symbol table for the task's vars
m_curSymp = m_statep - > insertBlock ( m_curSymp , nodep - > name ( ) , nodep , m_packagep ) ;
m_curSymp - > fallbackp ( oldCurSymp ) ;
// Convert the func's range to the output variable
// This should probably be done in the Parser instead, as then we could
// just attact normal signal attributes to it.
if ( nodep - > fvarp ( )
& & ! nodep - > fvarp ( ) - > castVar ( ) ) {
AstNodeDType * dtypep = nodep - > fvarp ( ) - > castNodeDType ( ) ;
// If unspecified, function returns one bit; however when we support NEW() it could
// also return the class reference.
if ( dtypep ) dtypep - > unlinkFrBack ( ) ;
else dtypep = new AstBasicDType ( nodep - > fileline ( ) , AstBasicDTypeKwd : : LOGIC ) ;
AstVar * newvarp = new AstVar ( nodep - > fileline ( ) , AstVarType : : OUTPUT , nodep - > name ( ) ,
VFlagChildDType ( ) , dtypep ) ; // Not dtype resolved yet
newvarp - > funcReturn ( true ) ;
newvarp - > trace ( false ) ; // Not user visible
newvarp - > attrIsolateAssign ( nodep - > attrIsolateAssign ( ) ) ;
nodep - > addFvarp ( newvarp ) ;
// Explicit insert required, as the var name shadows the upper level's task name
m_statep - > insertSym ( m_curSymp , newvarp - > name ( ) , newvarp , NULL /*packagep*/ ) ;
}
m_ftaskp = nodep ;
nodep - > iterateChildren ( * this ) ;
m_ftaskp = NULL ;
2012-05-28 13:18:18 +00:00
}
2012-07-21 21:12:42 +00:00
m_curSymp = oldCurSymp ;
}
2006-08-26 11:35:28 +00:00
virtual void visit ( AstVar * nodep , AstNUser * ) {
2012-07-21 21:12:42 +00:00
// Var: Remember its name for later resolution
if ( ! m_curSymp | | ! m_modSymp ) nodep - > v3fatalSrc ( " Var not under module?? \n " ) ;
nodep - > iterateChildren ( * this ) ;
if ( ! m_statep - > forScopeCreation ( ) ) {
// Find under either a task or the module's vars
VSymEnt * foundp = m_curSymp - > findIdFallback ( nodep - > name ( ) ) ;
if ( ! foundp & & m_modSymp & & nodep - > name ( ) = = m_modSymp - > nodep ( ) - > name ( ) ) foundp = m_modSymp ; // Conflicts with modname?
2013-02-03 18:27:37 +00:00
AstVar * findvarp = foundp ? foundp - > nodep ( ) - > castVar ( ) : NULL ;
2012-07-21 21:12:42 +00:00
bool ins = false ;
if ( ! foundp ) {
ins = true ;
} else if ( ! findvarp & & foundp & & m_curSymp - > findIdFlat ( nodep - > name ( ) ) ) {
nodep - > v3error ( " Unsupported in C: Variable has same name as "
< < LinkDotState : : nodeTextType ( foundp - > nodep ( ) ) < < " : " < < nodep - > prettyName ( ) ) ;
} else if ( findvarp ! = nodep ) {
UINFO ( 4 , " DupVar: " < < nodep < < " ;; " < < foundp - > nodep ( ) < < endl ) ;
UINFO ( 4 , " found cur=se " < < ( void * ) m_curSymp < < " ;; parent=se " < < ( void * ) foundp - > parentp ( ) < < endl ) ;
2013-01-09 00:06:52 +00:00
if ( foundp & & foundp - > parentp ( ) = = m_curSymp // Only when on same level
& & ! foundp - > imported ( ) ) { // and not from package
2012-07-21 21:12:42 +00:00
if ( ( findvarp - > isIO ( ) & & nodep - > isSignal ( ) )
| | ( findvarp - > isSignal ( ) & & nodep - > isIO ( ) ) ) {
findvarp - > combineType ( nodep ) ;
nodep - > fileline ( ) - > modifyStateInherit ( nodep - > fileline ( ) ) ;
AstBasicDType * bdtypep = findvarp - > childDTypep ( ) - > castBasicDType ( ) ;
if ( bdtypep & & bdtypep - > implicit ( ) ) {
// Then have "input foo" and "real foo" so the dtype comes from the other side.
AstNodeDType * newdtypep = nodep - > subDTypep ( ) ;
if ( ! newdtypep | | ! nodep - > childDTypep ( ) ) findvarp - > v3fatalSrc ( " No child type? " ) ;
bdtypep - > unlinkFrBack ( ) - > deleteTree ( ) ;
newdtypep - > unlinkFrBack ( ) ;
findvarp - > childDTypep ( newdtypep ) ;
}
nodep - > unlinkFrBack ( ) - > deleteTree ( ) ; nodep = NULL ;
} else {
nodep - > v3error ( " Duplicate declaration of signal: " < < nodep - > prettyName ( ) < < endl
< < findvarp - > warnMore ( ) < < " ... Location of original declaration " ) ;
}
} else {
// User can disable the message at either point
if ( ! ( m_ftaskp & & m_ftaskp - > dpiImport ( ) )
& & ( ! m_ftaskp | | m_ftaskp ! = foundp - > nodep ( ) ) // Not the function's variable hiding function
& & ! nodep - > fileline ( ) - > warnIsOff ( V3ErrorCode : : VARHIDDEN )
& & ! foundp - > nodep ( ) - > fileline ( ) - > warnIsOff ( V3ErrorCode : : VARHIDDEN ) ) {
2013-03-12 11:27:17 +00:00
nodep - > v3warn ( VARHIDDEN , " Declaration of signal hides declaration in upper scope: " < < nodep - > prettyName ( ) < < endl
2012-07-21 21:12:42 +00:00
< < foundp - > nodep ( ) - > warnMore ( ) < < " ... Location of original declaration " ) ;
}
ins = true ;
}
}
if ( ins ) {
2013-05-28 01:39:19 +00:00
VSymEnt * insp = m_statep - > insertSym ( m_curSymp , nodep - > name ( ) , nodep , m_packagep ) ;
2012-07-21 21:12:42 +00:00
if ( m_statep - > forPrimary ( ) & & nodep - > isGParam ( ) ) {
m_paramNum + + ;
2012-12-18 00:07:23 +00:00
VSymEnt * symp = m_statep - > insertSym ( m_curSymp , " __paramNumber " + cvtToStr ( m_paramNum ) , nodep , m_packagep ) ;
2012-12-18 01:26:40 +00:00
symp - > exported ( false ) ;
2012-07-21 21:12:42 +00:00
}
2013-05-28 01:39:19 +00:00
if ( nodep - > subDTypep ( ) - > castIfaceRefDType ( ) ) {
// Can't resolve until interfaces and modport names are known; see notes at top
m_statep - > insertIfaceVarSym ( insp ) ;
}
2012-07-21 21:12:42 +00:00
}
2006-08-26 11:35:28 +00:00
}
}
2012-07-21 21:12:42 +00:00
virtual void visit ( AstTypedef * nodep , AstNUser * ) {
// Remember its name for later resolution
if ( ! m_curSymp ) nodep - > v3fatalSrc ( " Typedef not under module?? \n " ) ;
nodep - > iterateChildren ( * this ) ;
m_statep - > insertSym ( m_curSymp , nodep - > name ( ) , nodep , m_packagep ) ;
}
2006-08-26 11:35:28 +00:00
virtual void visit ( AstCFunc * nodep , AstNUser * ) {
2012-07-21 21:12:42 +00:00
// For dotted resolution, ignore all AstVars under functions, otherwise shouldn't exist
if ( m_statep - > forScopeCreation ( ) ) nodep - > v3fatalSrc ( " No CFuncs expected in tree yet " ) ;
}
virtual void visit ( AstEnumItem * nodep , AstNUser * ) {
// EnumItem: Remember its name for later resolution
nodep - > iterateChildren ( * this ) ;
// Find under either a task or the module's vars
VSymEnt * foundp = m_curSymp - > findIdFallback ( nodep - > name ( ) ) ;
if ( ! foundp & & m_modSymp & & nodep - > name ( ) = = m_modSymp - > nodep ( ) - > name ( ) ) foundp = m_modSymp ; // Conflicts with modname?
2013-02-03 18:27:37 +00:00
AstEnumItem * findvarp = foundp ? foundp - > nodep ( ) - > castEnumItem ( ) : NULL ;
2012-07-21 21:12:42 +00:00
bool ins = false ;
if ( ! foundp ) {
ins = true ;
} else if ( findvarp ! = nodep ) {
UINFO ( 4 , " DupVar: " < < nodep < < " ;; " < < foundp < < endl ) ;
2013-01-09 00:06:52 +00:00
if ( foundp & & foundp - > parentp ( ) = = m_curSymp // Only when on same level
& & ! foundp - > imported ( ) ) { // and not from package
2012-07-21 21:12:42 +00:00
nodep - > v3error ( " Duplicate declaration of enum value: " < < nodep - > prettyName ( ) < < endl
< < findvarp - > warnMore ( ) < < " ... Location of original declaration " ) ;
} else {
// User can disable the message at either point
if ( ! nodep - > fileline ( ) - > warnIsOff ( V3ErrorCode : : VARHIDDEN )
& & ! foundp - > nodep ( ) - > fileline ( ) - > warnIsOff ( V3ErrorCode : : VARHIDDEN ) ) {
2013-03-12 11:27:17 +00:00
nodep - > v3warn ( VARHIDDEN , " Declaration of enum value hides declaration in upper scope: " < < nodep - > prettyName ( ) < < endl
2012-07-21 21:12:42 +00:00
< < foundp - > nodep ( ) - > warnMore ( ) < < " ... Location of original declaration " ) ;
}
ins = true ;
}
}
if ( ins ) {
m_statep - > insertSym ( m_curSymp , nodep - > name ( ) , nodep , m_packagep ) ;
}
}
virtual void visit ( AstPackageImport * nodep , AstNUser * ) {
UINFO ( 2 , " Link: " < < nodep < < endl ) ;
VSymEnt * srcp = m_statep - > getNodeSym ( nodep - > packagep ( ) ) ;
if ( nodep - > name ( ) ! = " * " ) {
VSymEnt * impp = srcp - > findIdFlat ( nodep - > name ( ) ) ;
if ( ! impp ) {
nodep - > v3error ( " Import object not found: " < < nodep - > packagep ( ) - > prettyName ( ) < < " :: " < < nodep - > prettyName ( ) ) ;
}
}
2013-05-28 00:56:20 +00:00
m_curSymp - > importFromPackage ( m_statep - > symsp ( ) , srcp , nodep - > name ( ) ) ;
2013-01-09 00:06:52 +00:00
UINFO ( 9 , " Link Done: " < < nodep < < endl ) ;
2012-08-09 01:59:17 +00:00
// No longer needed, but can't delete until any multi-instantiated modules are expanded
2006-08-26 11:35:28 +00:00
}
virtual void visit ( AstNode * nodep , AstNUser * ) {
// Default: Just iterate
nodep - > iterateChildren ( * this ) ;
}
public :
// CONSTUCTORS
LinkDotFindVisitor ( AstNetlist * rootp , LinkDotState * statep ) {
UINFO ( 4 , __FUNCTION__ < < " : " < < endl ) ;
2012-07-21 21:12:42 +00:00
m_packagep = NULL ;
2012-07-18 01:29:10 +00:00
m_curSymp = m_modSymp = NULL ;
2006-08-26 11:35:28 +00:00
m_statep = statep ;
m_beginp = NULL ;
2012-07-21 21:12:42 +00:00
m_ftaskp = NULL ;
m_inGenerate = false ;
m_paramNum = 0 ;
m_beginNum = 0 ;
m_modBeginNum = 0 ;
2006-08-26 11:35:28 +00:00
//
rootp - > accept ( * this ) ;
}
virtual ~ LinkDotFindVisitor ( ) { }
} ;
2012-07-21 21:12:42 +00:00
//======================================================================
class LinkDotParamVisitor : public AstNVisitor {
private :
// NODE STATE
// Cleared on global
2012-07-24 10:26:35 +00:00
// *::user1p() -> See LinkDotState
// *::user2p() -> See LinkDotState
// *::user4() -> See LinkDotState
2012-07-21 21:12:42 +00:00
// STATE
LinkDotState * m_statep ; // State to pass between visitors, including symbol table
AstNodeModule * m_modp ; // Current module
int debug ( ) { return LinkDotState : : debug ( ) ; }
void pinImplicitExprRecurse ( AstNode * nodep ) {
// Under a pin, Check interconnect expression for a pin reference or a concat.
// Create implicit variable as needed
2012-07-24 10:26:35 +00:00
if ( nodep - > castDot ( ) ) { // Not creating a simple implied type,
// and implying something else would just confuse later errors
}
2012-12-31 22:05:13 +00:00
else if ( nodep - > castVarRef ( ) | | nodep - > castParseRef ( ) ) {
2012-07-21 21:12:42 +00:00
// To prevent user errors, we should only do single bit
// implicit vars, however some netlists (MIPS) expect single
// bit implicit wires to get created with range 0:0 etc.
2012-07-22 01:18:07 +00:00
m_statep - > implicitOkAdd ( m_modp , nodep - > name ( ) ) ;
2012-07-21 21:12:42 +00:00
}
// These are perhaps a little too generous, as a SELect of siga[sigb]
// perhaps shouldn't create an implicit variable. But, we've warned...
else {
if ( nodep - > op1p ( ) ) pinImplicitExprRecurse ( nodep - > op1p ( ) ) ;
if ( nodep - > op2p ( ) ) pinImplicitExprRecurse ( nodep - > op2p ( ) ) ;
if ( nodep - > op3p ( ) ) pinImplicitExprRecurse ( nodep - > op3p ( ) ) ;
if ( nodep - > op4p ( ) ) pinImplicitExprRecurse ( nodep - > op4p ( ) ) ;
if ( nodep - > nextp ( ) ) pinImplicitExprRecurse ( nodep - > nextp ( ) ) ;
}
}
// VISITs
virtual void visit ( AstTypeTable * nodep , AstNUser * ) { }
virtual void visit ( AstNodeModule * nodep , AstNUser * ) {
UINFO ( 5 , " " < < nodep < < endl ) ;
if ( nodep - > dead ( ) | | ! nodep - > user4 ( ) ) {
UINFO ( 4 , " Mark dead module " < < nodep < < endl ) ;
if ( ! m_statep - > forPrearray ( ) ) nodep - > v3fatalSrc ( " Dead module persisted past where should have removed " ) ;
// Don't remove now, because we may have a tree of parameterized modules with VARXREFs into the deleted module region
// V3Dead should cleanup.
// Downstream visitors up until V3Dead need to check for nodep->dead.
nodep - > dead ( true ) ;
} else {
m_modp = nodep ;
nodep - > iterateChildren ( * this ) ;
m_modp = NULL ;
}
}
virtual void visit ( AstPin * nodep , AstNUser * ) {
// Pin: Link to submodule's port
// Deal with implicit definitions - do before Resolve visitor as may be referenced above declaration
if ( nodep - > exprp ( ) // Else specifically unconnected pin
& & ! nodep - > svImplicit ( ) ) { // SV 19.11.3: .name pins don't allow implicit decls
pinImplicitExprRecurse ( nodep - > exprp ( ) ) ;
}
}
virtual void visit ( AstDefParam * nodep , AstNUser * ) {
nodep - > iterateChildren ( * this ) ;
2013-03-12 11:27:17 +00:00
nodep - > v3warn ( DEFPARAM , " Suggest replace defparam with Verilog 2001 #(. " < < nodep - > prettyName ( ) < < " (...etc...)) " ) ;
2012-08-07 22:24:51 +00:00
VSymEnt * foundp = m_statep - > getNodeSym ( nodep ) - > findIdFallback ( nodep - > path ( ) ) ;
2012-07-21 21:12:42 +00:00
AstCell * cellp = foundp - > nodep ( ) - > castCell ( ) ;
if ( ! cellp ) {
nodep - > v3error ( " In defparam, cell " < < nodep - > path ( ) < < " never declared " ) ;
} else {
AstNode * exprp = nodep - > rhsp ( ) - > unlinkFrBack ( ) ;
UINFO ( 9 , " Defparam cell " < < nodep - > path ( ) < < " . " < < nodep - > name ( )
2012-08-07 22:24:51 +00:00
< < " attach-to " < < cellp
< < " <= " < < exprp < < endl ) ;
2012-07-21 21:12:42 +00:00
// Don't need to check the name of the defparam exists. V3Param does.
AstPin * pinp = new AstPin ( nodep - > fileline ( ) ,
- 1 , // Pin# not relevant
nodep - > name ( ) ,
exprp ) ;
cellp - > addParamsp ( pinp ) ;
nodep - > unlinkFrBack ( ) - > deleteTree ( ) ; nodep = NULL ;
}
}
virtual void visit ( AstPort * nodep , AstNUser * ) {
// Port: Stash the pin number
// Need to set pin numbers after varnames are created
// But before we do the final resolution based on names
VSymEnt * foundp = m_statep - > getNodeSym ( m_modp ) - > findIdFlat ( nodep - > name ( ) ) ;
AstVar * refp = foundp - > nodep ( ) - > castVar ( ) ;
if ( ! refp ) {
nodep - > v3error ( " Input/output/inout declaration not found for port: " < < nodep - > prettyName ( ) ) ;
2013-05-28 01:39:19 +00:00
} else if ( ! refp - > isIO ( ) & & ! refp - > isIfaceRef ( ) ) {
nodep - > v3error ( " Pin is not an in/out/inout/interface: " < < nodep - > prettyName ( ) ) ;
2012-07-21 21:12:42 +00:00
} else {
refp - > user4 ( true ) ;
2012-12-18 00:07:23 +00:00
VSymEnt * symp = m_statep - > insertSym ( m_statep - > getNodeSym ( m_modp ) ,
" __pinNumber " + cvtToStr ( nodep - > pinNum ( ) ) , refp , NULL /*packagep*/ ) ;
2012-12-18 01:26:40 +00:00
symp - > exported ( false ) ;
2012-07-21 21:12:42 +00:00
}
// Ports not needed any more
nodep - > unlinkFrBack ( ) - > deleteTree ( ) ; nodep = NULL ;
}
virtual void visit ( AstAssignW * nodep , AstNUser * ) {
// Deal with implicit definitions
// We used to nodep->allowImplicit() here, but it turns out
// normal "assigns" can also make implicit wires. Yuk.
pinImplicitExprRecurse ( nodep - > lhsp ( ) ) ;
nodep - > iterateChildren ( * this ) ;
}
virtual void visit ( AstAssignAlias * nodep , AstNUser * ) {
// tran gates need implicit creation
2012-07-22 00:33:24 +00:00
// As VarRefs don't exist in forPrimary, sanity check
if ( m_statep - > forPrimary ( ) ) nodep - > v3fatalSrc ( " Assign aliases unexpected pre-dot " ) ;
2012-07-21 21:12:42 +00:00
if ( AstVarRef * forrefp = nodep - > lhsp ( ) - > castVarRef ( ) ) {
pinImplicitExprRecurse ( forrefp ) ;
}
if ( AstVarRef * forrefp = nodep - > rhsp ( ) - > castVarRef ( ) ) {
pinImplicitExprRecurse ( forrefp ) ;
}
nodep - > iterateChildren ( * this ) ;
}
virtual void visit ( AstImplicit * nodep , AstNUser * ) {
// Unsupported gates need implicit creation
pinImplicitExprRecurse ( nodep ) ;
// We're done with implicit gates
nodep - > unlinkFrBack ( ) - > deleteTree ( ) ; nodep = NULL ;
}
virtual void visit ( AstNode * nodep , AstNUser * ) {
// Default: Just iterate
nodep - > iterateChildren ( * this ) ;
}
public :
// CONSTUCTORS
LinkDotParamVisitor ( AstNetlist * rootp , LinkDotState * statep ) {
UINFO ( 4 , __FUNCTION__ < < " : " < < endl ) ;
m_statep = statep ;
m_modp = NULL ;
//
rootp - > accept ( * this ) ;
}
virtual ~ LinkDotParamVisitor ( ) { }
} ;
2006-08-26 11:35:28 +00:00
//======================================================================
class LinkDotScopeVisitor : public AstNVisitor {
2013-05-28 01:39:19 +00:00
2006-08-26 11:35:28 +00:00
// STATE
LinkDotState * m_statep ; // State to pass between visitors, including symbol table
2013-05-28 01:39:19 +00:00
AstScope * m_scopep ; // The current scope
2012-07-18 01:29:10 +00:00
VSymEnt * m_modSymp ; // 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
2012-07-21 21:12:42 +00:00
virtual void visit ( AstNetlist * nodep , AstNUser * vup ) {
// Recurse..., backward as must do packages before using packages
nodep - > iterateChildrenBackwards ( * this ) ;
}
2006-08-26 11:35:28 +00:00
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-07-18 01:29:10 +00:00
m_modSymp = m_statep - > getScopeSym ( nodep ) ;
2013-05-28 01:39:19 +00:00
m_scopep = nodep ;
2006-08-26 11:35:28 +00:00
nodep - > iterateChildren ( * this ) ;
2012-07-18 01:29:10 +00:00
m_modSymp = NULL ;
2013-05-28 01:39:19 +00:00
m_scopep = NULL ;
2006-08-26 11:35:28 +00:00
}
virtual void visit ( AstVarScope * nodep , AstNUser * ) {
if ( ! nodep - > varp ( ) - > isFuncLocal ( ) ) {
2013-05-28 01:39:19 +00:00
VSymEnt * varSymp = m_statep - > insertSym ( m_modSymp , nodep - > varp ( ) - > name ( ) , nodep , NULL ) ;
if ( nodep - > varp ( ) - > isIfaceRef ( )
& & nodep - > varp ( ) - > isIfaceParent ( ) ) {
UINFO ( 9 , " Iface parent ref var " < < nodep - > varp ( ) - > name ( ) < < " " < < nodep < < endl ) ;
// Find the interface cell the var references
AstIfaceRefDType * dtypep = nodep - > varp ( ) - > dtypep ( ) - > castIfaceRefDType ( ) ;
if ( ! dtypep ) nodep - > v3fatalSrc ( " Non AstIfaceRefDType on isIfaceRef() var " ) ;
UINFO ( 9 , " Iface parent dtype " < < dtypep < < endl ) ;
string ifcellname = dtypep - > cellName ( ) ;
string baddot ; VSymEnt * okSymp ;
VSymEnt * cellSymp = m_statep - > findDotted ( m_modSymp , ifcellname , baddot , okSymp ) ;
if ( ! cellSymp ) nodep - > v3fatalSrc ( " No symbol for interface cell: " < < nodep - > prettyName ( ifcellname ) ) ;
UINFO ( 5 , " Found interface cell: se " < < ( void * ) cellSymp < < " " < < cellSymp - > nodep ( ) < < endl ) ;
if ( dtypep - > modportName ( ) ! = " " ) {
VSymEnt * mpSymp = m_statep - > findDotted ( m_modSymp , ifcellname , baddot , okSymp ) ;
if ( ! mpSymp ) { nodep - > v3fatalSrc ( " No symbol for interface modport: " < < nodep - > prettyName ( dtypep - > modportName ( ) ) ) ; }
else cellSymp = mpSymp ;
UINFO ( 5 , " Found modport cell: se " < < ( void * ) cellSymp < < " " < < mpSymp - > nodep ( ) < < endl ) ;
}
// Interface reference; need to put whole thing into symtable, but can't clone it now
// as we may have a later alias for it.
2014-04-04 01:53:39 +00:00
m_statep - > insertScopeAlias ( LinkDotState : : SAMN_IFTOP , varSymp , cellSymp ) ;
2013-05-28 01:39:19 +00:00
}
2006-08-26 11:35:28 +00:00
}
}
virtual void visit ( AstNodeFTask * nodep , AstNUser * ) {
2012-07-21 21:12:42 +00:00
VSymEnt * symp = m_statep - > insertBlock ( m_modSymp , nodep - > name ( ) , nodep , NULL ) ;
symp - > fallbackp ( m_modSymp ) ;
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)
2013-05-28 00:56:20 +00:00
if ( debug ( ) > = 9 ) nodep - > dumpTree ( cout , " - \t \t \t \t alias: " ) ;
AstVarScope * fromVscp = nodep - > lhsp ( ) - > castVarRef ( ) - > varScopep ( ) ;
AstVarScope * toVscp = nodep - > rhsp ( ) - > castVarRef ( ) - > varScopep ( ) ;
if ( ! fromVscp | | ! toVscp ) nodep - > v3fatalSrc ( " Bad alias scopes " ) ;
fromVscp - > user2p ( toVscp ) ;
2006-08-26 11:35:28 +00:00
nodep - > iterateChildren ( * this ) ;
}
2013-05-28 01:39:19 +00:00
virtual void visit ( AstAssignVarScope * nodep , AstNUser * ) {
UINFO ( 5 , " ASSIGNVARSCOPE " < < nodep < < endl ) ;
if ( debug ( ) > = 9 ) nodep - > dumpTree ( cout , " - \t \t \t \t avs: " ) ;
VSymEnt * rhsSymp ;
{
AstVarRef * refp = nodep - > rhsp ( ) - > castVarRef ( ) ;
if ( ! refp ) nodep - > v3fatalSrc ( " Unsupported: Non VarRef attached to interface pin " ) ;
string scopename = refp - > name ( ) ;
string baddot ; VSymEnt * okSymp ;
VSymEnt * symp = m_statep - > findDotted ( m_modSymp , scopename , baddot , okSymp ) ;
if ( ! symp ) nodep - > v3fatalSrc ( " No symbol for interface alias rhs " ) ;
UINFO ( 5 , " Found a linked scope RHS: " < < scopename < < " se " < < ( void * ) symp < < " " < < symp - > nodep ( ) < < endl ) ;
rhsSymp = symp ;
}
VSymEnt * lhsSymp ;
{
AstVarXRef * refp = nodep - > lhsp ( ) - > castVarXRef ( ) ;
if ( ! refp ) nodep - > v3fatalSrc ( " Unsupported: Non VarXRef attached to interface pin " ) ;
string scopename = refp - > dotted ( ) + " . " + refp - > name ( ) ;
string baddot ; VSymEnt * okSymp ;
VSymEnt * symp = m_statep - > findDotted ( m_modSymp , scopename , baddot , okSymp ) ;
if ( ! symp ) nodep - > v3fatalSrc ( " No symbol for interface alias lhs " ) ;
UINFO ( 5 , " Found a linked scope LHS: " < < scopename < < " se " < < ( void * ) symp < < " " < < symp - > nodep ( ) < < endl ) ;
lhsSymp = symp ;
}
// Remember the alias - can't do it yet because we may have additional symbols to be added,
// or maybe an alias of an alias
2014-04-04 01:53:39 +00:00
m_statep - > insertScopeAlias ( LinkDotState : : SAMN_IFTOP , lhsSymp , rhsSymp ) ;
2013-05-28 01:39:19 +00:00
// We have stored the link, we don't need these any more
nodep - > unlinkFrBack ( ) - > deleteTree ( ) ; nodep = NULL ;
}
2006-08-26 11:35:28 +00:00
// 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-07-18 01:29:10 +00:00
m_modSymp = NULL ;
2013-05-28 01:39:19 +00:00
m_scopep = NULL ;
2006-08-26 11:35:28 +00:00
m_statep = statep ;
//
rootp - > accept ( * this ) ;
}
virtual ~ LinkDotScopeVisitor ( ) { }
} ;
//======================================================================
2013-05-28 01:39:19 +00:00
// Iterate an interface to resolve modports
class LinkDotIfaceVisitor : public AstNVisitor {
// STATE
LinkDotState * m_statep ; // State to pass between visitors, including symbol table
VSymEnt * m_curSymp ; // Symbol Entry for current table, where to lookup/insert
// METHODS
int debug ( ) { return LinkDotState : : debug ( ) ; }
// VISITs
virtual void visit ( AstModport * nodep , AstNUser * ) {
// Modport: Remember its name for later resolution
UINFO ( 5 , " fiv: " < < nodep < < endl ) ;
VSymEnt * oldCurSymp = m_curSymp ;
{
// Create symbol table for the vars
m_curSymp = m_statep - > insertBlock ( m_curSymp , nodep - > name ( ) , nodep , NULL ) ;
m_curSymp - > fallbackp ( oldCurSymp ) ;
nodep - > iterateChildren ( * this ) ;
}
m_curSymp = oldCurSymp ;
}
2013-12-21 11:51:15 +00:00
virtual void visit ( AstModportFTaskRef * nodep , AstNUser * ) {
UINFO ( 5 , " fif: " < < nodep < < endl ) ;
nodep - > iterateChildren ( * this ) ;
if ( nodep - > isExport ( ) ) nodep - > v3error ( " Unsupported: modport export " ) ;
VSymEnt * symp = m_curSymp - > findIdFallback ( nodep - > name ( ) ) ;
if ( ! symp ) {
nodep - > v3error ( " Modport item not found: " < < nodep - > prettyName ( ) ) ;
} else if ( AstNodeFTask * ftaskp = symp - > nodep ( ) - > castNodeFTask ( ) ) {
// Make symbol under modport that points at the _interface_'s var, not the modport.
nodep - > ftaskp ( ftaskp ) ;
2014-04-04 01:53:39 +00:00
VSymEnt * subSymp = m_statep - > insertSym ( m_curSymp , nodep - > name ( ) , ftaskp , NULL /*package*/ ) ;
m_statep - > insertScopeAlias ( LinkDotState : : SAMN_MODPORT , subSymp , symp ) ;
2013-12-21 11:51:15 +00:00
} else {
nodep - > v3error ( " Modport item is not a function/task: " < < nodep - > prettyName ( ) ) ;
}
if ( m_statep - > forScopeCreation ( ) ) {
// Done with AstModportFTaskRef.
// Delete to prevent problems if we dead-delete pointed to ftask
nodep - > unlinkFrBack ( ) ; pushDeletep ( nodep ) ; nodep = NULL ;
}
}
2013-05-28 01:39:19 +00:00
virtual void visit ( AstModportVarRef * nodep , AstNUser * ) {
UINFO ( 5 , " fiv: " < < nodep < < endl ) ;
nodep - > iterateChildren ( * this ) ;
VSymEnt * symp = m_curSymp - > findIdFallback ( nodep - > name ( ) ) ;
if ( ! symp ) {
nodep - > v3error ( " Modport item not found: " < < nodep - > prettyName ( ) ) ;
} else if ( AstVar * varp = symp - > nodep ( ) - > castVar ( ) ) {
// Make symbol under modport that points at the _interface_'s var, not the modport.
nodep - > varp ( varp ) ;
m_statep - > insertSym ( m_curSymp , nodep - > name ( ) , varp , NULL /*package*/ ) ;
} else if ( AstVarScope * vscp = symp - > nodep ( ) - > castVarScope ( ) ) {
// Make symbol under modport that points at the _interface_'s var, not the modport.
nodep - > varp ( vscp - > varp ( ) ) ;
m_statep - > insertSym ( m_curSymp , nodep - > name ( ) , vscp , NULL /*package*/ ) ;
} else {
nodep - > v3error ( " Modport item is not a variable: " < < nodep - > prettyName ( ) ) ;
}
if ( m_statep - > forScopeCreation ( ) ) {
// Done with AstModportVarRef.
// Delete to prevent problems if we dead-delete pointed to variable
nodep - > unlinkFrBack ( ) ; pushDeletep ( nodep ) ; nodep = NULL ;
}
}
virtual void visit ( AstNode * nodep , AstNUser * ) {
// Default: Just iterate
nodep - > iterateChildren ( * this ) ;
}
public :
// CONSTUCTORS
LinkDotIfaceVisitor ( AstIface * nodep , VSymEnt * curSymp , LinkDotState * statep ) {
UINFO ( 4 , __FUNCTION__ < < " : " < < endl ) ;
m_curSymp = curSymp ;
m_statep = statep ;
nodep - > accept ( * this ) ;
}
virtual ~ LinkDotIfaceVisitor ( ) { }
} ;
void LinkDotState : : computeIfaceModSyms ( ) {
for ( IfaceModSyms : : iterator it = m_ifaceModSyms . begin ( ) ; it ! = m_ifaceModSyms . end ( ) ; + + it ) {
AstIface * nodep = it - > first ;
VSymEnt * symp = it - > second ;
LinkDotIfaceVisitor ( nodep , symp , this ) ;
}
m_ifaceModSyms . clear ( ) ;
}
//======================================================================
2006-08-26 11:35:28 +00:00
class LinkDotResolveVisitor : public AstNVisitor {
private :
2012-07-21 21:12:42 +00:00
// NODE STATE
// Cleared on global
2012-07-24 10:26:35 +00:00
// *::user1p() -> See LinkDotState
// *::user2p() -> See LinkDotState
// *::user3() // bool. Processed
// *::user4() -> See LinkDotState
2012-07-21 21:12:42 +00:00
// Cleared on Cell
2012-07-24 10:26:35 +00:00
// AstVar::user5() // bool. True if pin used in this cell
AstUser3InUse m_inuser3 ;
2012-07-21 21:12:42 +00:00
AstUser5InUse m_inuser5 ;
2012-07-24 10:26:35 +00:00
// TYPES
2012-12-31 22:05:13 +00:00
enum DotPosition { DP_NONE = 0 , // Not under a DOT
DP_PACKAGE , // {package}:: DOT
DP_SCOPE , // [DOT...] {scope-or-var} DOT
DP_FINAL , // [DOT...] {var-or-func-or-dtype} with no following dots
DP_MEMBER } ; // DOT {member-name} [DOT...]
2012-07-24 10:26:35 +00:00
2006-08-26 11:35:28 +00:00
// STATE
LinkDotState * m_statep ; // State, including dotted symbol table
2012-07-21 21:12:42 +00:00
VSymEnt * m_curSymp ; // SymEnt for current lookup point
2012-07-18 01:29:10 +00:00
VSymEnt * m_modSymp ; // SymEnt for current module
2012-07-21 21:12:42 +00:00
VSymEnt * m_pinSymp ; // SymEnt for pin lookups
AstCell * m_cellp ; // Current cell
AstNodeModule * m_modp ; // Current module
AstNodeFTask * m_ftaskp ; // Current function/task
2013-05-28 01:39:19 +00:00
int m_modportNum ; // Uniqueify modport numbers
2012-12-31 19:00:04 +00:00
struct DotStates {
2012-12-31 22:05:13 +00:00
DotPosition m_dotPos ; // Scope part of dotted resolution
2012-12-31 19:00:04 +00:00
VSymEnt * m_dotSymp ; // SymEnt for dotted AstParse lookup
AstDot * m_dotp ; // Current dot
bool m_dotErr ; // Error found in dotted resolution, ignore upwards
string m_dotText ; // String of dotted names found in below parseref
DotStates ( ) { init ( NULL ) ; }
~ DotStates ( ) { }
2012-12-31 22:05:13 +00:00
void init ( VSymEnt * curSymp ) {
m_dotPos = DP_NONE ; m_dotSymp = curSymp ; m_dotp = NULL ; m_dotErr = false ; m_dotText = " " ;
}
string ascii ( ) const {
static const char * names [ ] = { " NONE " , " PACKAGE " , " SCOPE " , " FINAL " , " MEMBER " } ;
ostringstream sstr ;
sstr < < " ds= " < < names [ m_dotPos ] ;
sstr < < " dse " < < ( void * ) m_dotSymp ;
sstr < < " txt= " < < m_dotText ;
return sstr . str ( ) ;
}
2012-12-31 19:00:04 +00:00
} m_ds ; // State to preserve across recursions
2009-01-21 21:56:50 +00:00
2006-08-26 11:35:28 +00:00
int debug ( ) { return LinkDotState : : debug ( ) ; }
2012-07-22 01:18:07 +00:00
// METHODS - Variables
void createImplicitVar ( VSymEnt * lookupSymp , AstVarRef * nodep , AstNodeModule * modp , VSymEnt * moduleSymp , bool noWarn ) {
// Create implicit after warning
if ( ! nodep - > varp ( ) ) {
if ( ! noWarn ) {
if ( nodep - > fileline ( ) - > warnIsOff ( V3ErrorCode : : I_DEF_NETTYPE_WIRE ) ) {
nodep - > v3error ( " Signal definition not found, and implicit disabled with `default_nettype: " < < nodep - > prettyName ( ) ) ;
} else {
nodep - > v3warn ( IMPLICIT , " Signal definition not found, creating implicitly: " < < nodep - > prettyName ( ) ) ;
}
}
AstVar * newp = new AstVar ( nodep - > fileline ( ) , AstVarType : : WIRE ,
nodep - > name ( ) , VFlagLogicPacked ( ) , 1 ) ;
newp - > trace ( modp - > modTrace ( ) ) ;
nodep - > varp ( newp ) ;
modp - > addStmtp ( newp ) ;
// Link it to signal list, must add the variable under the module; current scope might be lower now
m_statep - > insertSym ( moduleSymp , newp - > name ( ) , newp , NULL /*packagep*/ ) ;
}
}
2012-07-23 02:48:39 +00:00
void taskFuncSwapCheck ( AstNodeFTaskRef * nodep ) {
if ( nodep - > taskp ( ) & & nodep - > taskp ( ) - > castTask ( )
& & nodep - > castFuncRef ( ) ) nodep - > v3error ( " Illegal call of a task as a function: " < < nodep - > prettyName ( ) ) ;
}
2012-12-31 22:05:13 +00:00
inline void checkNoDot ( AstNode * nodep ) {
if ( VL_UNLIKELY ( m_ds . m_dotPos ! = DP_NONE ) ) {
2013-05-28 00:56:20 +00:00
//UINFO(9,"ds="<<m_ds.ascii()<<endl);
2012-12-31 22:05:13 +00:00
nodep - > v3error ( " Syntax Error: Not expecting " < < nodep - > type ( ) < < " under a " < < nodep - > backp ( ) - > type ( ) < < " in dotted expression " ) ;
m_ds . m_dotErr = true ;
}
}
2013-05-28 01:39:19 +00:00
AstVar * makeIfaceModportVar ( FileLine * fl , AstCell * cellp , AstIface * ifacep , AstModport * modportp ) {
// Create iface variable, using duplicate var when under same module scope
string varName = ifacep - > name ( ) + " __Vmp__ " + modportp - > name ( ) + " __Viftop " + cvtToStr ( + + m_modportNum ) ;
AstIfaceRefDType * idtypep = new AstIfaceRefDType ( fl , cellp - > name ( ) , ifacep - > name ( ) , modportp - > name ( ) ) ;
idtypep - > cellp ( cellp ) ;
AstVar * varp = new AstVar ( fl , AstVarType : : IFACEREF , varName , VFlagChildDType ( ) , idtypep ) ;
varp - > isIfaceParent ( true ) ;
m_modp - > addStmtp ( varp ) ;
return varp ;
}
2012-07-22 01:18:07 +00:00
2006-08-26 11:35:28 +00:00
// VISITs
2012-07-21 21:12:42 +00:00
virtual void visit ( AstNetlist * nodep , AstNUser * vup ) {
// Recurse..., backward as must do packages before using packages
nodep - > iterateChildrenBackwards ( * this ) ;
}
virtual void visit ( AstTypeTable * nodep , AstNUser * ) { }
2009-11-07 11:20:20 +00:00
virtual void visit ( AstNodeModule * nodep , AstNUser * ) {
2012-07-21 21:12:42 +00:00
if ( nodep - > dead ( ) ) return ;
2012-12-31 22:05:13 +00:00
checkNoDot ( nodep ) ;
2006-08-26 11:35:28 +00:00
UINFO ( 8 , " " < < nodep < < endl ) ;
2012-12-31 19:00:04 +00:00
m_ds . init ( m_curSymp ) ;
m_ds . m_dotSymp = m_curSymp = m_modSymp = m_statep - > getNodeSym ( nodep ) ; // Until overridden by a SCOPE
2012-07-21 21:12:42 +00:00
m_cellp = NULL ;
m_modp = nodep ;
2013-05-28 01:39:19 +00:00
m_modportNum = 0 ;
2006-08-26 11:35:28 +00:00
nodep - > iterateChildren ( * this ) ;
2012-07-21 21:12:42 +00:00
m_modp = NULL ;
2012-12-31 19:00:04 +00:00
m_ds . m_dotSymp = m_curSymp = m_modSymp = NULL ;
2006-08-26 11:35:28 +00:00
}
virtual void visit ( AstScope * nodep , AstNUser * ) {
UINFO ( 8 , " " < < nodep < < endl ) ;
2013-02-22 04:38:29 +00:00
VSymEnt * oldModSymp = m_modSymp ;
VSymEnt * oldCurSymp = m_curSymp ;
2012-12-31 22:05:13 +00:00
checkNoDot ( nodep ) ;
2013-02-22 04:38:29 +00:00
m_ds . m_dotSymp = m_curSymp = m_modSymp = m_statep - > getScopeSym ( nodep ) ;
2006-08-26 11:35:28 +00:00
nodep - > iterateChildren ( * this ) ;
2013-02-22 04:38:29 +00:00
m_ds . m_dotSymp = m_curSymp = m_modSymp = NULL ;
m_modSymp = oldModSymp ;
m_curSymp = oldCurSymp ;
2006-08-26 11:35:28 +00:00
}
virtual void visit ( AstCellInline * nodep , AstNUser * ) {
2012-12-31 22:05:13 +00:00
checkNoDot ( nodep ) ;
2006-08-26 11:35:28 +00:00
if ( m_statep - > forScopeCreation ( ) ) {
nodep - > unlinkFrBack ( ) ; pushDeletep ( nodep ) ; nodep = NULL ;
}
}
2012-07-21 21:12:42 +00:00
virtual void visit ( AstCell * nodep , AstNUser * ) {
2013-05-28 00:56:20 +00:00
// Cell: Recurse inside or cleanup not founds
2012-12-31 22:05:13 +00:00
checkNoDot ( nodep ) ;
2012-07-21 21:12:42 +00:00
m_cellp = nodep ;
AstNode : : user5ClearTree ( ) ;
if ( ! nodep - > modp ( ) ) {
nodep - > v3fatalSrc ( " Cell has unlinked module " ) ; // V3LinkCell should have errored out
}
else {
if ( nodep - > modp ( ) - > castNotFoundModule ( ) ) {
// Prevent warnings about missing pin connects
if ( nodep - > pinsp ( ) ) nodep - > pinsp ( ) - > unlinkFrBackWithNext ( ) - > deleteTree ( ) ;
if ( nodep - > paramsp ( ) ) nodep - > paramsp ( ) - > unlinkFrBackWithNext ( ) - > deleteTree ( ) ;
}
// Need to pass the module info to this cell, so we can link up the pin names
// However can't use m_curSymp as pin connections need to use the instantiator's symbols
else {
m_pinSymp = m_statep - > getNodeSym ( nodep - > modp ( ) ) ;
UINFO ( 4 , " (Backto) Link Cell: " < < nodep < < endl ) ;
//if (debug()) { nodep->dumpTree(cout,"linkcell:"); }
//if (debug()) { nodep->modp()->dumpTree(cout,"linkcemd:"); }
nodep - > iterateChildren ( * this ) ;
m_pinSymp = NULL ;
}
}
m_cellp = NULL ;
// Parent module inherits child's publicity
// This is done bottom up in the LinkBotupVisitor stage
}
virtual void visit ( AstPin * nodep , AstNUser * ) {
// Pin: Link to submodule's port
2012-12-31 22:05:13 +00:00
checkNoDot ( nodep ) ;
2014-05-28 11:33:40 +00:00
nodep - > iterateChildren ( * this ) ;
2012-07-21 21:12:42 +00:00
if ( ! nodep - > modVarp ( ) ) {
if ( ! m_pinSymp ) nodep - > v3fatalSrc ( " Pin not under cell? \n " ) ;
VSymEnt * foundp = m_pinSymp - > findIdFlat ( nodep - > name ( ) ) ;
AstVar * refp = foundp - > nodep ( ) - > castVar ( ) ;
2013-12-14 23:04:10 +00:00
const char * whatp = nodep - > param ( ) ? " parameter pin " : " pin " ;
2012-07-21 21:12:42 +00:00
if ( ! refp ) {
if ( nodep - > name ( ) = = " __paramNumber1 " & & m_cellp - > modp ( ) - > castPrimitive ( ) ) {
// Primitive parameter is really a delay we can just ignore
nodep - > unlinkFrBack ( ) - > deleteTree ( ) ; nodep = NULL ;
return ;
}
2014-04-30 01:11:57 +00:00
nodep - > v3error ( ucfirst ( whatp ) < < " not found: " < < nodep - > prettyName ( ) ) ;
2013-05-28 01:39:19 +00:00
} else if ( ! refp - > isIO ( ) & & ! refp - > isParam ( ) & & ! refp - > isIfaceRef ( ) ) {
2014-04-30 01:11:57 +00:00
nodep - > v3error ( ucfirst ( whatp ) < < " is not an in/out/inout/param/interface: " < < nodep - > prettyName ( ) ) ;
2012-07-21 21:12:42 +00:00
} else {
nodep - > modVarp ( refp ) ;
if ( refp - > user5p ( ) & & refp - > user5p ( ) - > castNode ( ) ! = nodep ) {
2013-12-14 23:04:10 +00:00
nodep - > v3error ( " Duplicate " < < whatp < < " connection: " < < nodep - > prettyName ( ) < < endl
2012-07-21 21:12:42 +00:00
< < refp - > user5p ( ) - > castNode ( ) - > warnMore ( )
2013-12-14 23:04:10 +00:00
< < " ... Location of original " < < whatp < < " connection " ) ;
2012-07-21 21:12:42 +00:00
} else {
refp - > user5p ( nodep ) ;
}
}
}
// Early return() above when deleted
}
2012-07-24 10:26:35 +00:00
virtual void visit ( AstDot * nodep , AstNUser * ) {
2012-12-31 22:05:13 +00:00
// Legal under a DOT: AstDot, AstParseRef, AstPackageRef, AstNodeSel
// also a DOT can be part of an expression, but only above plus AstFTaskRef are legal children
// DOT(PACKAGEREF, PARSEREF(text))
// DOT(DOT(DOT(PARSEREF(text), ...
2012-07-24 10:26:35 +00:00
if ( nodep - > user3SetOnce ( ) ) return ;
UINFO ( 8 , " " < < nodep < < endl ) ;
2012-12-31 19:00:04 +00:00
DotStates lastStates = m_ds ;
2012-12-31 22:05:13 +00:00
bool start = ! m_ds . m_dotp ; // Save, as m_dotp will be changed
2012-07-24 10:26:35 +00:00
{
if ( start ) { // Starting dot sequence
if ( debug ( ) > = 9 ) nodep - > dumpTree ( " -dot-in: " ) ;
2012-12-31 19:00:04 +00:00
m_ds . init ( m_curSymp ) ; // Start from current point
2012-07-24 10:26:35 +00:00
}
2012-12-31 19:00:04 +00:00
m_ds . m_dotp = nodep ; // Always, not just at start
m_ds . m_dotPos = DP_SCOPE ;
2012-12-31 22:05:13 +00:00
2012-12-31 19:00:04 +00:00
// m_ds.m_dotText communicates the cell prefix between stages
2012-12-31 22:05:13 +00:00
if ( nodep - > lhsp ( ) - > castPackageRef ( ) ) {
if ( ! start ) { nodep - > lhsp ( ) - > v3error ( " Package reference may not be embedded in dotted reference " ) ; m_ds . m_dotErr = true ; }
m_ds . m_dotPos = DP_PACKAGE ;
} else {
m_ds . m_dotPos = DP_SCOPE ;
nodep - > lhsp ( ) - > iterateAndNext ( * this ) ;
2013-05-28 00:56:20 +00:00
//if (debug()>=9) nodep->dumpTree("-dot-lho: ");
2012-12-31 22:05:13 +00:00
}
2012-12-31 19:00:04 +00:00
if ( ! m_ds . m_dotErr ) { // Once something wrong, give up
2012-12-31 22:05:13 +00:00
if ( start & & m_ds . m_dotPos = = DP_SCOPE ) m_ds . m_dotPos = DP_FINAL ; // Top 'final' dot RHS is final RHS, else it's a DOT(DOT(x,*here*),real-rhs) which we consider a RHS
2012-07-24 10:26:35 +00:00
nodep - > rhsp ( ) - > iterateAndNext ( * this ) ;
2013-05-28 00:56:20 +00:00
//if (debug()>=9) nodep->dumpTree("-dot-rho: ");
2012-07-24 10:26:35 +00:00
}
if ( start ) {
AstNode * newp ;
2012-12-31 19:00:04 +00:00
if ( m_ds . m_dotErr ) {
2012-07-24 10:26:35 +00:00
newp = new AstConst ( nodep - > fileline ( ) , AstConst : : LogicFalse ( ) ) ;
} else {
// RHS is what we're left with
newp = nodep - > rhsp ( ) - > unlinkFrBack ( ) ;
}
if ( debug ( ) > = 9 ) newp - > dumpTree ( " -dot-out: " ) ;
nodep - > replaceWith ( newp ) ;
pushDeletep ( nodep ) ; nodep = NULL ;
} else { // Dot midpoint
AstNode * newp = nodep - > rhsp ( ) - > unlinkFrBack ( ) ;
nodep - > replaceWith ( newp ) ;
pushDeletep ( nodep ) ; nodep = NULL ;
}
}
if ( start ) {
2012-12-31 19:00:04 +00:00
m_ds = lastStates ;
} else {
m_ds . m_dotp = lastStates . m_dotp ;
2012-07-24 10:26:35 +00:00
}
}
virtual void visit ( AstParseRef * nodep , AstNUser * ) {
if ( nodep - > user3SetOnce ( ) ) return ;
2012-12-31 22:05:13 +00:00
UINFO ( 9 , " linkPARSEREF " < < m_ds . ascii ( ) < < " n= " < < nodep < < endl ) ;
2012-07-24 10:26:35 +00:00
// m_curSymp is symbol table of outer expression
2012-12-31 19:00:04 +00:00
// m_ds.m_dotSymp is symbol table relative to "."'s above now
if ( ! m_ds . m_dotSymp ) nodep - > v3fatalSrc ( " NULL lookup symbol table " ) ;
2012-07-24 10:26:35 +00:00
if ( ! m_statep - > forPrimary ( ) ) nodep - > v3fatalSrc ( " ParseRefs should no longer exist " ) ;
2012-12-31 19:00:04 +00:00
DotStates lastStates = m_ds ;
2012-12-31 22:05:13 +00:00
bool start = ! m_ds . m_dotp ;
2012-12-31 19:00:04 +00:00
if ( start ) {
m_ds . init ( m_curSymp ) ;
2012-12-31 22:05:13 +00:00
// Note m_ds.m_dot remains NULL; this is a reference not under a dot
2012-07-24 10:26:35 +00:00
}
2012-12-31 19:00:04 +00:00
if ( m_ds . m_dotPos = = DP_MEMBER ) {
2012-07-29 14:16:20 +00:00
// Found a Var, everything following is membership. {scope}.{var}.HERE {member}
2012-12-31 19:00:04 +00:00
AstNode * varEtcp = m_ds . m_dotp - > lhsp ( ) - > unlinkFrBack ( ) ;
2012-07-29 14:16:20 +00:00
AstNode * newp = new AstMemberSel ( nodep - > fileline ( ) , varEtcp , VFlagChildDType ( ) , nodep - > name ( ) ) ;
nodep - > replaceWith ( newp ) ;
pushDeletep ( nodep ) ; nodep = NULL ;
2012-07-24 10:26:35 +00:00
}
else {
//
string expectWhat ;
bool allowScope = false ;
bool allowVar = false ;
2012-12-31 22:05:13 +00:00
if ( m_ds . m_dotPos = = DP_PACKAGE ) {
// {package}::{a}
2015-02-10 02:05:27 +00:00
AstPackage * packagep = NULL ;
2012-12-31 22:05:13 +00:00
expectWhat = " scope/variable " ;
allowScope = true ;
allowVar = true ;
if ( ! m_ds . m_dotp - > lhsp ( ) - > castPackageRef ( ) ) m_ds . m_dotp - > lhsp ( ) - > v3fatalSrc ( " Bad package link " ) ;
packagep = m_ds . m_dotp - > lhsp ( ) - > castPackageRef ( ) - > packagep ( ) ;
if ( ! packagep ) m_ds . m_dotp - > lhsp ( ) - > v3fatalSrc ( " Bad package link " ) ;
m_ds . m_dotSymp = m_statep - > getNodeSym ( packagep ) ;
m_ds . m_dotPos = DP_SCOPE ;
} else if ( m_ds . m_dotPos = = DP_SCOPE ) {
2012-07-24 10:26:35 +00:00
// {a}.{b}, where {a} maybe a module name
2012-12-31 19:00:04 +00:00
// or variable, where dotting into structure member
2012-07-24 10:26:35 +00:00
expectWhat = " scope/variable " ;
allowScope = true ;
allowVar = true ;
2012-12-31 22:05:13 +00:00
} else if ( m_ds . m_dotPos = = DP_NONE
| | m_ds . m_dotPos = = DP_FINAL ) {
2012-07-24 10:26:35 +00:00
expectWhat = " variable " ;
allowVar = true ;
} else {
2012-12-31 22:05:13 +00:00
UINFO ( 1 , " ds= " < < m_ds . ascii ( ) < < endl ) ;
2012-07-24 10:26:35 +00:00
nodep - > v3fatalSrc ( " Unhandled AstParseRefExp " ) ;
}
// Lookup
VSymEnt * foundp ;
string baddot ;
VSymEnt * okSymp = NULL ;
if ( allowScope ) {
2012-12-31 19:00:04 +00:00
foundp = m_statep - > findDotted ( m_ds . m_dotSymp , nodep - > name ( ) , baddot , okSymp ) ; // Maybe NULL
2012-07-24 10:26:35 +00:00
} else {
2012-12-31 19:00:04 +00:00
foundp = m_ds . m_dotSymp - > findIdFallback ( nodep - > name ( ) ) ;
2012-07-24 10:26:35 +00:00
}
2013-05-28 00:56:20 +00:00
if ( foundp ) UINFO ( 9 , " found=se " < < ( void * ) foundp < < " exp= " < < expectWhat
< < " n= " < < foundp - > nodep ( ) < < endl ) ;
2012-07-24 10:26:35 +00:00
// What fell out?
bool ok = false ;
if ( foundp - > nodep ( ) - > castCell ( ) | | foundp - > nodep ( ) - > castBegin ( )
| | foundp - > nodep ( ) - > castModule ( ) ) { // if top
if ( allowScope ) {
ok = true ;
2012-12-31 19:00:04 +00:00
if ( m_ds . m_dotText ! = " " ) m_ds . m_dotText + = " . " ;
m_ds . m_dotText + = nodep - > name ( ) ;
m_ds . m_dotSymp = foundp ;
m_ds . m_dotPos = DP_SCOPE ;
2012-07-24 10:26:35 +00:00
// Upper AstDot visitor will handle it from here
}
2013-05-28 01:39:19 +00:00
else if ( foundp - > nodep ( ) - > castCell ( )
& & allowVar & & m_cellp
& & foundp - > nodep ( ) - > castCell ( ) - > modp ( ) - > castIface ( ) ) {
// Interfaces can be referenced like a variable for interconnect
AstCell * cellp = foundp - > nodep ( ) - > castCell ( ) ;
VSymEnt * cellEntp = m_statep - > getNodeSym ( cellp ) ; if ( ! cellEntp ) nodep - > v3fatalSrc ( " No interface sym entry " ) ;
VSymEnt * parentEntp = cellEntp - > parentp ( ) ; // Container of the var; probably a module or generate begin
string findName = nodep - > name ( ) + " __Viftop " ;
AstVar * ifaceRefVarp = parentEntp - > findIdFallback ( findName ) - > nodep ( ) - > castVar ( ) ;
if ( ! ifaceRefVarp ) nodep - > v3fatalSrc ( " Can't find interface var ref: " < < findName ) ;
//
ok = true ;
if ( m_ds . m_dotText ! = " " ) m_ds . m_dotText + = " . " ;
m_ds . m_dotText + = nodep - > name ( ) ;
m_ds . m_dotSymp = foundp ;
m_ds . m_dotPos = DP_SCOPE ;
UINFO ( 9 , " cell -> iface varref " < < foundp - > nodep ( ) < < endl ) ;
AstNode * newp = new AstVarRef ( ifaceRefVarp - > fileline ( ) , ifaceRefVarp , false ) ;
nodep - > replaceWith ( newp ) ; pushDeletep ( nodep ) ; nodep = NULL ;
}
2012-07-24 10:26:35 +00:00
}
else if ( AstVar * varp = foundp - > nodep ( ) - > castVar ( ) ) {
2013-05-28 01:39:19 +00:00
if ( AstIfaceRefDType * ifacerefp = varp - > subDTypep ( ) - > castIfaceRefDType ( ) ) {
if ( ! ifacerefp - > ifaceViaCellp ( ) ) ifacerefp - > v3fatalSrc ( " Unlinked interface " ) ;
// Really this is a scope reference into an interface
UINFO ( 9 , " varref-ifaceref " < < m_ds . m_dotText < < " " < < nodep < < endl ) ;
if ( m_ds . m_dotText ! = " " ) m_ds . m_dotText + = " . " ;
m_ds . m_dotText + = nodep - > name ( ) ;
m_ds . m_dotSymp = m_statep - > getNodeSym ( ifacerefp - > ifaceViaCellp ( ) ) ;
m_ds . m_dotPos = DP_SCOPE ;
ok = true ;
AstNode * newp = new AstVarRef ( nodep - > fileline ( ) , varp , false ) ;
nodep - > replaceWith ( newp ) ; pushDeletep ( nodep ) ; nodep = NULL ;
}
else if ( allowVar ) {
2012-07-24 10:26:35 +00:00
AstNodeVarRef * newp ;
2012-12-31 19:00:04 +00:00
if ( m_ds . m_dotText ! = " " ) {
newp = new AstVarXRef ( nodep - > fileline ( ) , nodep - > name ( ) , m_ds . m_dotText , false ) ; // lvalue'ness computed later
2012-07-24 10:26:35 +00:00
newp - > varp ( varp ) ;
2012-12-31 19:00:04 +00:00
m_ds . m_dotText = " " ;
2012-07-24 10:26:35 +00:00
} else {
newp = new AstVarRef ( nodep - > fileline ( ) , nodep - > name ( ) , false ) ; // lvalue'ness computed later
newp - > varp ( varp ) ;
newp - > packagep ( foundp - > packagep ( ) ) ;
2013-02-22 04:38:29 +00:00
UINFO ( 9 , " new " < < newp < < endl ) ;
2012-07-24 10:26:35 +00:00
}
nodep - > replaceWith ( newp ) ; pushDeletep ( nodep ) ; nodep = NULL ;
2012-12-31 19:00:04 +00:00
m_ds . m_dotPos = DP_MEMBER ;
2012-07-24 10:26:35 +00:00
ok = true ;
}
}
2013-05-28 01:39:19 +00:00
else if ( AstModport * modportp = foundp - > nodep ( ) - > castModport ( ) ) {
// A scope reference into an interface's modport (not necessarily at a pin connection)
UINFO ( 9 , " cell-ref-to-modport " < < m_ds . m_dotText < < " " < < nodep < < endl ) ;
UINFO ( 9 , " dotSymp " < < m_ds . m_dotSymp < < " " < < m_ds . m_dotSymp - > nodep ( ) < < endl ) ;
// Iface was the previously dotted component
if ( ! m_ds . m_dotSymp
| | ! m_ds . m_dotSymp - > nodep ( ) - > castCell ( )
| | ! m_ds . m_dotSymp - > nodep ( ) - > castCell ( ) - > modp ( )
| | ! m_ds . m_dotSymp - > nodep ( ) - > castCell ( ) - > modp ( ) - > castIface ( ) ) {
nodep - > v3error ( " Modport not referenced as <interface>. " < < modportp - > prettyName ( ) ) ;
} else if ( ! m_ds . m_dotSymp - > nodep ( ) - > castCell ( ) - > modp ( )
| | ! m_ds . m_dotSymp - > nodep ( ) - > castCell ( ) - > modp ( ) - > castIface ( ) ) {
nodep - > v3error ( " Modport not referenced from underneath an interface: " < < modportp - > prettyName ( ) ) ;
} else {
AstCell * cellp = m_ds . m_dotSymp - > nodep ( ) - > castCell ( ) ;
if ( ! cellp ) nodep - > v3fatalSrc ( " Modport not referenced from a cell " ) ;
AstIface * ifacep = cellp - > modp ( ) - > castIface ( ) ;
//string cellName = m_ds.m_dotText; // Use cellp->name
if ( m_ds . m_dotText ! = " " ) m_ds . m_dotText + = " . " ;
m_ds . m_dotText + = nodep - > name ( ) ;
m_ds . m_dotSymp = m_statep - > getNodeSym ( modportp ) ;
m_ds . m_dotPos = DP_SCOPE ;
ok = true ;
AstVar * varp = makeIfaceModportVar ( nodep - > fileline ( ) , cellp , ifacep , modportp ) ;
AstVarRef * refp = new AstVarRef ( varp - > fileline ( ) , varp , false ) ;
nodep - > replaceWith ( refp ) ; pushDeletep ( nodep ) ; nodep = NULL ;
}
}
2012-07-24 10:26:35 +00:00
else if ( AstEnumItem * valuep = foundp - > nodep ( ) - > castEnumItem ( ) ) {
if ( allowVar ) {
AstNode * newp = new AstEnumItemRef ( nodep - > fileline ( ) , valuep , foundp - > packagep ( ) ) ;
nodep - > replaceWith ( newp ) ; pushDeletep ( nodep ) ; nodep = NULL ;
ok = true ;
2012-12-31 19:00:04 +00:00
m_ds . m_dotText = " " ;
2012-07-24 10:26:35 +00:00
}
}
//
if ( ! ok ) {
2012-12-31 22:05:13 +00:00
bool checkImplicit = ( ! m_ds . m_dotp & & m_ds . m_dotText = = " " ) ;
2012-07-24 10:26:35 +00:00
bool err = ! ( checkImplicit & & m_statep - > implicitOk ( m_modp , nodep - > name ( ) ) ) ;
if ( err ) {
if ( foundp ) {
2012-12-31 19:00:04 +00:00
nodep - > v3error ( " Found definition of ' " < < m_ds . m_dotText < < ( m_ds . m_dotText = = " " ? " " : " . " ) < < nodep - > prettyName ( )
2012-07-24 10:26:35 +00:00
< < " ' " < < " as a " < < foundp - > nodep ( ) - > typeName ( )
< < " but expected a " < < expectWhat ) ;
2012-12-31 19:00:04 +00:00
} else if ( m_ds . m_dotText = = " " ) {
2012-12-31 22:05:13 +00:00
UINFO ( 7 , " ErrParseRef curSymp=se " < < ( void * ) m_curSymp < < " ds= " < < m_ds . ascii ( ) < < endl ) ;
2012-07-24 10:26:35 +00:00
nodep - > v3error ( " Can't find definition of " < < expectWhat
< < " : " < < nodep - > prettyName ( ) ) ;
} else {
nodep - > v3error ( " Can't find definition of ' " < < ( baddot ! = " " ? baddot : nodep - > prettyName ( ) ) < < " ' in dotted "
2012-12-31 19:00:04 +00:00
< < expectWhat < < " : " < < m_ds . m_dotText + " . " + nodep - > prettyName ( ) ) ;
okSymp - > cellErrorScopes ( nodep , AstNode : : prettyName ( m_ds . m_dotText ) ) ;
2012-07-24 10:26:35 +00:00
}
2012-12-31 19:00:04 +00:00
m_ds . m_dotErr = true ;
2012-07-24 10:26:35 +00:00
}
if ( checkImplicit ) { // Else if a scope is allowed, making a signal won't help error cascade
// Create if implicit, and also if error (so only complain once)
AstVarRef * newp = new AstVarRef ( nodep - > fileline ( ) , nodep - > name ( ) , false ) ;
nodep - > replaceWith ( newp ) ;
pushDeletep ( nodep ) ; nodep = NULL ;
createImplicitVar ( m_curSymp , newp , m_modp , m_modSymp , err ) ;
}
}
}
if ( start ) {
2012-12-31 19:00:04 +00:00
m_ds = lastStates ;
2012-07-24 10:26:35 +00:00
}
}
2012-07-21 21:12:42 +00:00
virtual void visit ( AstVarRef * nodep , AstNUser * ) {
// VarRef: Resolve its reference
2012-07-24 10:26:35 +00:00
// ParseRefs are used the first pass (forPrimary) so we shouldn't get can't find
// errors here now that we have a VarRef.
2012-12-31 22:05:13 +00:00
// No checkNoDot; created and iterated from a parseRef
2012-07-21 21:12:42 +00:00
nodep - > iterateChildren ( * this ) ;
if ( ! nodep - > varp ( ) ) {
2012-07-24 10:26:35 +00:00
UINFO ( 9 , " linkVarRef se " < < ( void * ) m_curSymp < < " n= " < < nodep < < endl ) ;
if ( ! m_curSymp ) nodep - > v3fatalSrc ( " NULL lookup symbol table " ) ;
VSymEnt * foundp = m_curSymp - > findIdFallback ( nodep - > name ( ) ) ;
if ( AstVar * varp = foundp - > nodep ( ) - > castVar ( ) ) {
nodep - > varp ( varp ) ;
nodep - > packagep ( foundp - > packagep ( ) ) ; // Generally set by parse, but might be an import
}
2012-07-21 21:12:42 +00:00
if ( ! nodep - > varp ( ) ) {
2012-07-24 10:26:35 +00:00
nodep - > v3error ( " Can't find definition of signal, again: " < < nodep - > prettyName ( ) ) ;
2012-07-21 21:12:42 +00:00
}
}
}
2006-08-26 11:35:28 +00:00
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.
2012-07-24 10:26:35 +00:00
if ( nodep - > user3SetOnce ( ) ) return ;
2006-08-26 11:35:28 +00:00
UINFO ( 8 , " " < < nodep < < endl ) ;
2012-12-31 22:05:13 +00:00
// No checkNoDot; created and iterated from a parseRef
2012-07-18 01:29:10 +00:00
if ( ! m_modSymp ) {
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 ;
2012-07-21 21:12:42 +00:00
VSymEnt * dotSymp = m_curSymp ; // Start search at current scope
2006-08-26 11:35:28 +00:00
if ( nodep - > inlinedDots ( ) ! = " " ) { // Correct for current scope
2012-11-03 12:01:19 +00:00
dotSymp = m_modSymp ; // Dotted lookup is always relative to module, as maybe variable name lower down with same scope name we want to ignore (t_math_divw)
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 ) {
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-07-21 21:12:42 +00:00
VSymEnt * foundp = m_statep - > findSymPrefixed ( dotSymp , nodep - > name ( ) , baddot ) ;
AstVar * varp = foundp - > nodep ( ) - > castVar ( ) ; // maybe NULL
2006-08-26 11:35:28 +00:00
nodep - > varp ( varp ) ;
UINFO ( 7 , " Resolved " < < nodep < < endl ) ; // Also prints varp
if ( ! nodep - > varp ( ) ) {
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-07-21 21:12:42 +00:00
VSymEnt * foundp = m_statep - > findSymPrefixed ( dotSymp , nodep - > name ( ) , baddot ) ;
AstVarScope * vscp = foundp - > nodep ( ) - > castVarScope ( ) ; // maybe NULL
2006-08-26 11:35:28 +00:00
if ( ! vscp ) {
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 ;
2013-02-22 04:38:29 +00:00
UINFO ( 9 , " new " < < newvscp < < endl ) ; // Also prints taskp
2006-08-26 11:35:28 +00:00
}
}
}
}
2013-02-02 19:11:50 +00:00
virtual void visit ( AstEnumItemRef * nodep , AstNUser * ) {
// EnumItemRef may be under a dot. Should already be resolved.
nodep - > iterateChildren ( * this ) ;
}
2014-11-29 01:34:23 +00:00
virtual void visit ( AstMethodSel * nodep , AstNUser * ) {
// Created here so should already be resolved.
DotStates lastStates = m_ds ;
{
m_ds . init ( m_curSymp ) ;
nodep - > iterateChildren ( * this ) ;
}
m_ds = lastStates ;
}
2012-07-21 21:12:42 +00:00
virtual void visit ( AstVar * nodep , AstNUser * ) {
2012-12-31 22:05:13 +00:00
checkNoDot ( nodep ) ;
2012-07-21 21:12:42 +00:00
nodep - > iterateChildren ( * this ) ;
if ( m_statep - > forPrimary ( ) & & nodep - > isIO ( ) & & ! m_ftaskp & & ! nodep - > user4 ( ) ) {
nodep - > v3error ( " Input/output/inout does not appear in port list: " < < nodep - > prettyName ( ) ) ;
}
}
2006-08-26 11:35:28 +00:00
virtual void visit ( AstNodeFTaskRef * nodep , AstNUser * ) {
2012-07-24 10:26:35 +00:00
if ( nodep - > user3SetOnce ( ) ) return ;
2006-08-26 11:35:28 +00:00
UINFO ( 8 , " " < < nodep < < endl ) ;
2012-12-31 22:05:13 +00:00
if ( m_ds . m_dotp & & m_ds . m_dotPos = = DP_PACKAGE ) {
if ( ! m_ds . m_dotp - > lhsp ( ) - > castPackageRef ( ) ) m_ds . m_dotp - > lhsp ( ) - > v3fatalSrc ( " Bad package link " ) ;
if ( ! m_ds . m_dotp - > lhsp ( ) - > castPackageRef ( ) - > packagep ( ) ) m_ds . m_dotp - > lhsp ( ) - > v3fatalSrc ( " Bad package link " ) ;
nodep - > packagep ( m_ds . m_dotp - > lhsp ( ) - > castPackageRef ( ) - > packagep ( ) ) ;
m_ds . m_dotPos = DP_SCOPE ;
m_ds . m_dotp = NULL ;
} else if ( m_ds . m_dotp & & m_ds . m_dotPos = = DP_FINAL ) {
nodep - > dotted ( m_ds . m_dotText ) ; // Maybe ""
2014-11-29 01:34:23 +00:00
} else if ( m_ds . m_dotp & & m_ds . m_dotPos = = DP_MEMBER ) {
// Found a Var, everything following is method call. {scope}.{var}.HERE {method} ( ARGS )
AstNode * varEtcp = m_ds . m_dotp - > lhsp ( ) - > unlinkFrBack ( ) ;
AstNode * argsp = NULL ; if ( nodep - > pinsp ( ) ) argsp = nodep - > pinsp ( ) - > unlinkFrBackWithNext ( ) ;
AstNode * newp = new AstMethodSel ( nodep - > fileline ( ) , varEtcp , VFlagChildDType ( ) , nodep - > name ( ) , argsp ) ;
nodep - > replaceWith ( newp ) ;
pushDeletep ( nodep ) ; nodep = NULL ;
return ;
2012-12-31 22:05:13 +00:00
} else {
checkNoDot ( nodep ) ;
}
2012-07-21 21:12:42 +00:00
if ( nodep - > packagep ( ) & & nodep - > taskp ( ) ) {
2009-11-08 02:05:02 +00:00
// References into packages don't care about cell hierarchy.
2012-07-18 01:29:10 +00:00
} else if ( ! m_modSymp ) {
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 ( ) ) {
2012-07-18 01:29:10 +00:00
// Earlier should have setup the links
2012-02-22 03:23:06 +00:00
// 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-07-21 21:12:42 +00:00
VSymEnt * okSymp = NULL ;
VSymEnt * dotSymp = m_curSymp ; // Start search at module, as a variable of same name under a subtask isn't a relevant hit
// // however a function under a begin/end is. So we want begins, but not the function
if ( nodep - > packagep ( ) ) { // Look only in specified package
dotSymp = m_statep - > getNodeSym ( nodep - > packagep ( ) ) ;
} else {
if ( nodep - > inlinedDots ( ) ! = " " ) { // Correct for current scope
dotSymp = m_modSymp ; // Dotted lookup is always relative to module, as maybe variable name lower down with same scope name we want to ignore (t_math_divw)
string inl = AstNode : : dedotName ( nodep - > inlinedDots ( ) ) ;
UINFO ( 8 , " \t \t Inlined " < < inl < < endl ) ;
dotSymp = m_statep - > findDotted ( dotSymp , inl , baddot , okSymp ) ;
if ( ! dotSymp ) {
okSymp - > cellErrorScopes ( nodep ) ;
nodep - > v3fatalSrc ( " Couldn't resolve inlined scope ' " < < baddot < < " ' in: " < < nodep - > inlinedDots ( ) ) ;
}
2006-12-22 15:06:13 +00:00
}
2012-07-21 21:12:42 +00:00
dotSymp = m_statep - > findDotted ( dotSymp , nodep - > dotted ( ) , baddot , okSymp ) ; // Maybe NULL
2006-08-26 11:35:28 +00:00
}
2012-07-21 21:12:42 +00:00
VSymEnt * foundp = NULL ;
AstNodeFTask * taskp = NULL ;
foundp = m_statep - > findSymPrefixed ( dotSymp , nodep - > name ( ) , baddot ) ;
2013-02-03 18:27:37 +00:00
taskp = foundp ? foundp - > nodep ( ) - > castNodeFTask ( ) : NULL ; // Maybe NULL
2012-07-21 21:12:42 +00:00
if ( taskp ) {
nodep - > taskp ( taskp ) ;
nodep - > packagep ( foundp - > packagep ( ) ) ;
UINFO ( 7 , " Resolved " < < nodep < < endl ) ; // Also prints taskp
} else {
2012-08-09 01:59:17 +00:00
// Note ParseRef has similar error handling/message output
UINFO ( 7 , " ErrFtask curSymp=se " < < ( void * ) m_curSymp < < " dotSymp=se " < < ( void * ) dotSymp < < endl ) ;
2012-12-31 22:05:13 +00:00
if ( foundp ) {
nodep - > v3error ( " Found definition of ' " < < m_ds . m_dotText < < ( m_ds . m_dotText = = " " ? " " : " . " ) < < nodep - > prettyName ( )
< < " ' " < < " as a " < < foundp - > nodep ( ) - > typeName ( )
< < " but expected a task/function " ) ;
} else if ( nodep - > dotted ( ) = = " " ) {
2012-07-21 21:12:42 +00:00
nodep - > v3error ( " Can't find definition of task/function: " < < nodep - > prettyName ( ) ) ;
} else {
nodep - > v3error ( " Can't find definition of ' " < < baddot < < " ' in dotted task/function: " < < nodep - > dotted ( ) + " . " + nodep - > prettyName ( ) ) ;
okSymp - > cellErrorScopes ( nodep ) ;
}
}
2012-07-23 02:48:39 +00:00
taskFuncSwapCheck ( nodep ) ;
2012-07-21 21:12:42 +00:00
}
2012-12-31 22:05:13 +00:00
DotStates lastStates = m_ds ;
{
m_ds . init ( m_curSymp ) ;
nodep - > iterateChildren ( * this ) ;
}
m_ds = lastStates ;
2012-07-21 21:12:42 +00:00
}
2012-07-24 10:26:35 +00:00
virtual void visit ( AstSelBit * nodep , AstNUser * ) {
if ( nodep - > user3SetOnce ( ) ) return ;
2012-11-03 13:17:42 +00:00
nodep - > lhsp ( ) - > iterateAndNext ( * this ) ;
2012-12-31 19:00:04 +00:00
if ( m_ds . m_dotPos = = DP_SCOPE ) { // Already under dot, so this is {modulepart} DOT {modulepart}
2012-07-24 10:26:35 +00:00
if ( AstConst * constp = nodep - > rhsp ( ) - > castConst ( ) ) {
string index = AstNode : : encodeNumber ( constp - > toSInt ( ) ) ;
2012-12-31 19:00:04 +00:00
m_ds . m_dotText + = " __BRA__ " + index + " __KET__ " ;
2012-07-24 10:26:35 +00:00
} else {
nodep - > v3error ( " Unsupported: Non-constant inside []'s in the cell part of a dotted reference " ) ;
}
2012-12-31 19:00:04 +00:00
// And pass up m_ds.m_dotText
2012-07-24 10:26:35 +00:00
}
2012-12-31 22:05:13 +00:00
// Pass dot state down to fromp()
2012-11-03 13:17:42 +00:00
nodep - > fromp ( ) - > iterateAndNext ( * this ) ;
2012-12-31 22:05:13 +00:00
DotStates lastStates = m_ds ;
{
m_ds . init ( m_curSymp ) ;
nodep - > bitp ( ) - > iterateAndNext ( * this ) ;
nodep - > attrp ( ) - > iterateAndNext ( * this ) ;
}
m_ds = lastStates ;
}
virtual void visit ( AstNodePreSel * nodep , AstNUser * ) {
// Excludes simple AstSelBit, see above
if ( nodep - > user3SetOnce ( ) ) return ;
if ( m_ds . m_dotPos = = DP_SCOPE ) { // Already under dot, so this is {modulepart} DOT {modulepart}
nodep - > v3error ( " Syntax Error: Range ':', '+:' etc are not allowed in the cell part of a dotted reference " ) ;
m_ds . m_dotErr = true ;
return ;
}
nodep - > lhsp ( ) - > iterateAndNext ( * this ) ;
DotStates lastStates = m_ds ;
{
m_ds . init ( m_curSymp ) ;
nodep - > rhsp ( ) - > iterateAndNext ( * this ) ;
nodep - > thsp ( ) - > iterateAndNext ( * this ) ;
2013-01-26 02:27:19 +00:00
nodep - > attrp ( ) - > iterateAndNext ( * this ) ;
2012-12-31 22:05:13 +00:00
}
m_ds = lastStates ;
}
virtual void visit ( AstMemberSel * nodep , AstNUser * ) {
// checkNoDot not appropriate, can be under a dot
nodep - > iterateChildren ( * this ) ;
2012-07-24 10:26:35 +00:00
}
2012-07-21 21:12:42 +00:00
virtual void visit ( AstBegin * nodep , AstNUser * ) {
UINFO ( 5 , " " < < nodep < < endl ) ;
2012-12-31 22:05:13 +00:00
checkNoDot ( nodep ) ;
2012-07-21 21:12:42 +00:00
VSymEnt * oldCurSymp = m_curSymp ;
{
2012-12-31 19:00:04 +00:00
m_ds . m_dotSymp = m_curSymp = m_statep - > getNodeSym ( nodep ) ;
2012-07-21 21:12:42 +00:00
UINFO ( 5 , " cur=se " < < ( void * ) m_curSymp < < endl ) ;
nodep - > iterateChildren ( * this ) ;
}
2012-12-31 19:00:04 +00:00
m_ds . m_dotSymp = m_curSymp = oldCurSymp ;
2012-07-21 21:12:42 +00:00
UINFO ( 5 , " cur=se " < < ( void * ) m_curSymp < < endl ) ;
}
virtual void visit ( AstNodeFTask * nodep , AstNUser * ) {
UINFO ( 5 , " " < < nodep < < endl ) ;
2012-12-31 22:05:13 +00:00
checkNoDot ( nodep ) ;
2012-07-21 21:12:42 +00:00
VSymEnt * oldCurSymp = m_curSymp ;
{
m_ftaskp = nodep ;
2012-12-31 19:00:04 +00:00
m_ds . m_dotSymp = m_curSymp = m_statep - > getNodeSym ( nodep ) ;
2012-07-21 21:12:42 +00:00
nodep - > iterateChildren ( * this ) ;
}
2012-12-31 19:00:04 +00:00
m_ds . m_dotSymp = m_curSymp = oldCurSymp ;
2012-07-21 21:12:42 +00:00
m_ftaskp = NULL ;
}
virtual void visit ( AstRefDType * nodep , AstNUser * ) {
// Resolve its reference
2012-07-24 10:26:35 +00:00
if ( nodep - > user3SetOnce ( ) ) return ;
2012-12-31 22:05:13 +00:00
if ( m_ds . m_dotp & & m_ds . m_dotPos = = DP_PACKAGE ) {
if ( ! m_ds . m_dotp - > lhsp ( ) - > castPackageRef ( ) ) m_ds . m_dotp - > lhsp ( ) - > v3fatalSrc ( " Bad package link " ) ;
if ( ! m_ds . m_dotp - > lhsp ( ) - > castPackageRef ( ) - > packagep ( ) ) m_ds . m_dotp - > lhsp ( ) - > v3fatalSrc ( " Bad package link " ) ;
nodep - > packagep ( m_ds . m_dotp - > lhsp ( ) - > castPackageRef ( ) - > packagep ( ) ) ;
m_ds . m_dotPos = DP_SCOPE ;
m_ds . m_dotp = NULL ;
} else {
checkNoDot ( nodep ) ;
}
2012-07-21 21:12:42 +00:00
if ( ! nodep - > defp ( ) ) {
VSymEnt * foundp ;
if ( nodep - > packagep ( ) ) {
foundp = m_statep - > getNodeSym ( nodep - > packagep ( ) ) - > findIdFlat ( nodep - > name ( ) ) ;
} else {
foundp = m_curSymp - > findIdFallback ( nodep - > name ( ) ) ;
}
if ( AstTypedef * defp = foundp - > nodep ( ) - > castTypedef ( ) ) {
nodep - > refDTypep ( defp - > subDTypep ( ) ) ;
nodep - > packagep ( foundp - > packagep ( ) ) ;
} else {
nodep - > v3error ( " Can't find typedef: " < < nodep - > prettyName ( ) ) ;
2006-08-26 11:35:28 +00:00
}
}
nodep - > iterateChildren ( * this ) ;
}
2012-07-21 21:12:42 +00:00
virtual void visit ( AstDpiExport * nodep , AstNUser * ) {
// AstDpiExport: Make sure the function referenced exists, then dump it
nodep - > iterateChildren ( * this ) ;
2012-12-31 22:05:13 +00:00
checkNoDot ( nodep ) ;
2012-07-21 21:12:42 +00:00
VSymEnt * foundp = m_curSymp - > findIdFallback ( nodep - > name ( ) ) ;
AstNodeFTask * taskp = foundp - > nodep ( ) - > castNodeFTask ( ) ;
if ( ! taskp ) { nodep - > v3error ( " Can't find definition of exported task/function: " < < nodep - > prettyName ( ) ) ; }
else if ( taskp - > dpiExport ( ) ) {
nodep - > v3error ( " Function was already DPI Exported, duplicate not allowed: " < < nodep - > prettyName ( ) ) ;
} else {
taskp - > dpiExport ( true ) ;
if ( nodep - > cname ( ) ! = " " ) taskp - > cname ( nodep - > cname ( ) ) ;
}
nodep - > unlinkFrBack ( ) - > deleteTree ( ) ;
}
2012-08-09 01:59:17 +00:00
virtual void visit ( AstPackageImport * nodep , AstNUser * ) {
// No longer needed
2012-12-31 22:05:13 +00:00
checkNoDot ( nodep ) ;
2012-08-09 01:59:17 +00:00
nodep - > unlinkFrBack ( ) - > deleteTree ( ) ; nodep = NULL ;
}
2006-08-26 11:35:28 +00:00
virtual void visit ( AstNode * nodep , AstNUser * ) {
// Default: Just iterate
2012-12-31 22:05:13 +00:00
checkNoDot ( nodep ) ;
2006-08-26 11:35:28 +00:00
nodep - > iterateChildren ( * this ) ;
}
public :
// CONSTUCTORS
LinkDotResolveVisitor ( AstNetlist * rootp , LinkDotState * statep ) {
UINFO ( 4 , __FUNCTION__ < < " : " < < endl ) ;
m_statep = statep ;
2012-07-18 01:29:10 +00:00
m_modSymp = NULL ;
2012-07-21 21:12:42 +00:00
m_curSymp = NULL ;
m_pinSymp = NULL ;
m_cellp = NULL ;
m_modp = NULL ;
m_ftaskp = NULL ;
2013-05-28 01:39:19 +00:00
m_modportNum = 0 ;
2006-08-26 11:35:28 +00:00
//
rootp - > accept ( * this ) ;
}
virtual ~ LinkDotResolveVisitor ( ) { }
} ;
//######################################################################
// Link class functions
2012-07-21 13:27:57 +00:00
int V3LinkDot : : debug ( ) { return LinkDotState : : debug ( ) ; }
void V3LinkDot : : linkDotGuts ( AstNetlist * rootp , VLinkDotStep step ) {
2012-06-20 10:13:28 +00:00
if ( LinkDotState : : debug ( ) > = 5 | | v3Global . opt . dumpTree ( ) > = 9 ) v3Global . rootp ( ) - > dumpTreeFile ( v3Global . debugFilename ( " prelinkdot.tree " ) ) ;
2012-07-21 13:27:57 +00:00
LinkDotState state ( rootp , step ) ;
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 " ) ) ;
2012-07-21 21:12:42 +00:00
if ( step = = LDS_PRIMARY | | step = = LDS_PARAMED ) {
// Initial link stage, resolve parameters
LinkDotParamVisitor visitors ( rootp , & state ) ;
if ( LinkDotState : : debug ( ) > = 5 | | v3Global . opt . dumpTree ( ) > = 9 ) v3Global . rootp ( ) - > dumpTreeFile ( v3Global . debugFilename ( " prelinkdot-param.tree " ) ) ;
}
2013-05-28 01:39:19 +00:00
else if ( step = = LDS_ARRAYED ) { }
2012-07-21 21:12:42 +00:00
else if ( step = = LDS_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
}
2013-05-28 01:39:19 +00:00
else v3fatalSrc ( " Bad case " ) ;
state . dump ( ) ;
state . computeIfaceModSyms ( ) ;
state . computeIfaceVarSyms ( ) ;
state . computeScopeAliases ( ) ;
2006-08-26 11:35:28 +00:00
state . dump ( ) ;
LinkDotResolveVisitor visitorb ( rootp , & state ) ;
}