2012-04-13 03:08:20 +02:00
// -*- mode: C++; c-file-style: "cc-mode" -*-
2006-08-26 13:35:28 +02:00
//*************************************************************************
// DESCRIPTION: Verilator: Resolve module/signal name references
//
2019-11-08 04:33:59 +01:00
// Code available from: https://verilator.org
2006-08-26 13:35:28 +02:00
//
//*************************************************************************
//
2020-01-07 00:05:53 +01:00
// Copyright 2003-2020 by Wilson Snyder. This program is free software; you can
2006-08-26 13:35:28 +02:00
// redistribute it and/or modify it under the terms of either the GNU
2009-05-04 23:07:57 +02:00
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
2006-08-26 13:35:28 +02:00
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
// LinkDot TRANSFORMATIONS:
2019-05-19 22:13:13 +02:00
// Top-down traversal in LinkDotFindVisitor
// Cells:
// Make graph of cell hierarchy
// Var/Funcs's:
// Collect all names into symtable under appropriate cell
// 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
// VarXRef/Func's:
// Find appropriate named cell and link to var they reference
2006-08-26 13:35:28 +02:00
//*************************************************************************
2013-05-28 03:39:19 +02:00
// Interfaces:
2019-05-19 22:13:13 +02:00
// 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)
2013-05-28 03:39:19 +02:00
//*************************************************************************
2012-06-20 12:13:28 +02:00
// TOP
// {name-of-top-modulename}
// a (VSymEnt->AstCell)
2019-05-19 22:13:13 +02:00
// {name-of-cell}
// {name-of-cell-module}
2012-06-20 12:13:28 +02:00
// 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 12:09:07 +02:00
//*************************************************************************
2019-10-05 02:17:11 +02:00
2006-12-18 20:20:45 +01:00
# include "config_build.h"
# include "verilatedos.h"
2006-08-26 13:35:28 +02:00
# include "V3Global.h"
# include "V3LinkDot.h"
# include "V3SymTable.h"
# include "V3Graph.h"
# include "V3Ast.h"
2016-03-25 00:14:15 +01:00
# include "V3ParseImp.h"
2018-03-16 00:46:05 +01:00
# include "V3String.h"
2006-08-26 13:35:28 +02:00
2018-10-14 19:43:24 +02:00
# include <algorithm>
# include <cstdarg>
# include <map>
# include <vector>
2019-07-14 02:30:32 +02:00
//######################################################################
// Matcher classes (for suggestion matching)
class LinkNodeMatcherFTask : public VNodeMatcher {
public :
virtual bool nodeMatch ( const AstNode * nodep ) const {
return VN_IS ( nodep , NodeFTask ) ;
}
} ;
class LinkNodeMatcherModport : public VNodeMatcher {
public :
virtual bool nodeMatch ( const AstNode * nodep ) const {
return VN_IS ( nodep , Modport ) ;
}
} ;
class LinkNodeMatcherVar : public VNodeMatcher {
public :
virtual bool nodeMatch ( const AstNode * nodep ) const {
return VN_IS ( nodep , Var ) ;
}
} ;
class LinkNodeMatcherVarIO : public VNodeMatcher {
public :
virtual bool nodeMatch ( const AstNode * nodep ) const {
const AstVar * varp = VN_CAST_CONST ( nodep , Var ) ;
if ( ! varp ) return false ;
return varp - > isIO ( ) ;
}
} ;
class LinkNodeMatcherVarParam : public VNodeMatcher {
public :
virtual bool nodeMatch ( const AstNode * nodep ) const {
const AstVar * varp = VN_CAST_CONST ( nodep , Var ) ;
if ( ! varp ) return false ;
return varp - > isParam ( ) ;
}
} ;
class LinkNodeMatcherVarOrScope : public VNodeMatcher {
public :
virtual bool nodeMatch ( const AstNode * nodep ) const {
return VN_IS ( nodep , Var ) | | VN_IS ( nodep , Scope ) ;
}
} ;
2006-08-26 13:35:28 +02:00
//######################################################################
// LinkDot state, as a visitor of each AstNode
class LinkDotState {
private :
// NODE STATE
// Cleared on Netlist
2019-05-19 22:13:13 +02:00
// AstNodeModule::user1p() // VSymEnt*. Last symbol created for this node
// AstNodeModule::user2() // bool. Currently processing for recursion check
// ... 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
AstUser1InUse m_inuser1 ;
AstUser2InUse m_inuser2 ;
AstUser4InUse m_inuser4 ;
2006-08-26 13:35:28 +02:00
2014-04-04 03:53:39 +02:00
public :
// ENUMS
// In order of priority, compute first ... compute last
2019-05-19 22:13:13 +02:00
enum SAMNum { SAMN_MODPORT , SAMN_IFTOP , SAMN__MAX } ; // Values for m_scopeAliasMap
2014-04-04 03:53:39 +02:00
private :
2006-08-26 13:35:28 +02:00
// TYPES
2018-02-02 03:24:41 +01:00
typedef std : : multimap < string , VSymEnt * > NameScopeSymMap ;
typedef std : : map < VSymEnt * , VSymEnt * > ScopeAliasMap ;
typedef std : : set < std : : pair < AstNodeModule * , string > > ImplicitNameSet ;
typedef std : : vector < VSymEnt * > IfaceVarSyms ;
typedef std : : vector < std : : pair < AstIface * , VSymEnt * > > IfaceModSyms ;
2012-07-22 03:18:07 +02:00
2019-05-19 22:13:13 +02:00
static LinkDotState * s_errorThisp ; // Last self, for error reporting only
2013-05-25 18:15:38 +02:00
2006-08-26 13:35:28 +02:00
// MEMBERS
2019-05-19 22:13:13 +02:00
VSymGraph m_syms ; // Symbol table
VSymEnt * m_dunitEntp ; // $unit entry
NameScopeSymMap m_nameScopeSymMap ; // Map of scope referenced by non-pretty textual name
ImplicitNameSet m_implicitNameSet ; // For [module][signalname] if we can implicitly create it
ScopeAliasMap m_scopeAliasMap [ SAMN__MAX ] ; // Map of <lhs,rhs> aliases
IfaceVarSyms m_ifaceVarSyms ; // List of AstIfaceRefDType's to be imported
IfaceModSyms m_ifaceModSyms ; // List of AstIface+Symbols to be processed
bool m_forPrimary ; // First link
bool m_forPrearray ; // Compress cell__[array] refs
bool m_forScopeCreation ; // Remove VarXRefs for V3Scope
2013-05-25 18:15:38 +02:00
2006-08-26 13:35:28 +02:00
public :
2009-01-21 22:56:50 +01:00
2018-05-14 12:50:47 +02:00
// METHODS
VL_DEBUG_FUNC ; // Declare debug()
2013-05-28 02:56:20 +02:00
void dump ( const string & nameComment = " linkdot " , bool force = false ) {
2019-05-19 22:13:13 +02:00
if ( debug ( ) > = 6 | | force ) {
string filename = v3Global . debugFilename ( nameComment ) + " .txt " ;
2018-02-02 03:24:41 +01:00
const vl_unique_ptr < std : : ofstream > logp ( V3File : : new_ofstream ( filename ) ) ;
2018-07-15 01:22:50 +02:00
if ( logp - > fail ( ) ) v3fatal ( " Can't write " < < filename ) ;
2018-02-02 03:24:41 +01:00
std : : ostream & os = * logp ;
2019-05-19 22:13:13 +02:00
m_syms . dump ( os ) ;
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 ;
}
}
}
}
2012-07-21 15:27:57 +02:00
}
2013-05-25 18:15:38 +02:00
static void preErrorDumpHandler ( ) {
2019-05-19 22:13:13 +02:00
if ( s_errorThisp ) s_errorThisp - > preErrorDump ( ) ;
2013-05-25 18:15:38 +02:00
}
2012-07-21 15:27:57 +02:00
void preErrorDump ( ) {
2019-05-19 22:13:13 +02:00
static bool diddump = false ;
if ( ! diddump & & v3Global . opt . dumpTree ( ) ) {
diddump = true ;
dump ( " linkdot-preerr " , true ) ;
v3Global . rootp ( ) - > dumpTreeFile ( v3Global . debugFilename ( " linkdot-preerr.tree " ) ) ;
}
2012-07-21 15:27:57 +02:00
}
2006-08-26 13:35:28 +02:00
// CONSTRUCTORS
2012-07-21 15:27:57 +02:00
LinkDotState ( AstNetlist * rootp , VLinkDotStep step )
2019-05-19 22:13:13 +02:00
: m_syms ( rootp ) {
UINFO ( 4 , __FUNCTION__ < < " : " < < endl ) ;
m_forPrimary = ( step = = LDS_PRIMARY ) ;
m_forPrearray = ( step = = LDS_PARAMED | | step = = LDS_PRIMARY ) ;
m_forScopeCreation = ( step = = LDS_SCOPED ) ;
m_dunitEntp = NULL ;
s_errorThisp = this ;
V3Error : : errorExitCb ( preErrorDumpHandler ) ; // If get error, dump self
2013-05-25 18:15:38 +02:00
}
~ LinkDotState ( ) {
2019-05-19 22:13:13 +02:00
V3Error : : errorExitCb ( NULL ) ;
s_errorThisp = NULL ;
2006-08-26 13:35:28 +02:00
}
2008-06-10 03:25:10 +02:00
2006-08-26 13:35:28 +02:00
// ACCESSORS
2012-12-18 02:26:40 +01:00
VSymGraph * symsp ( ) { return & m_syms ; }
2012-07-21 23:12:42 +02:00
bool forPrimary ( ) const { return m_forPrimary ; }
bool forPrearray ( ) const { return m_forPrearray ; }
2006-08-26 13:35:28 +02:00
bool forScopeCreation ( ) const { return m_forScopeCreation ; }
// METHODS
2012-07-21 23:12:42 +02:00
static string nodeTextType ( AstNode * nodep ) {
2018-02-02 03:32:58 +01:00
if ( VN_IS ( nodep , Var ) ) return " variable " ;
else if ( VN_IS ( nodep , Cell ) ) return " cell " ;
else if ( VN_IS ( nodep , Task ) ) return " task " ;
else if ( VN_IS ( nodep , Func ) ) return " function " ;
else if ( VN_IS ( nodep , Begin ) ) return " block " ;
else if ( VN_IS ( nodep , Iface ) ) return " interface " ;
else if ( VN_IS ( nodep , ParamTypeDType ) ) return " parameter type " ;
2019-05-19 22:13:13 +02:00
else return nodep - > prettyTypeName ( ) ;
2012-07-21 23:12:42 +02:00
}
VSymEnt * rootEntp ( ) const { return m_syms . rootp ( ) ; }
VSymEnt * dunitEntp ( ) const { return m_dunitEntp ; }
void checkDuplicate ( VSymEnt * lookupSymp , AstNode * nodep , const string & name ) {
2019-05-19 22:13:13 +02:00
// 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 ? foundp - > nodep ( ) : NULL ;
if ( ! fnodep ) {
// Not found, will add in a moment.
} else if ( nodep = = fnodep ) { // Already inserted.
// Good.
} 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
2018-02-02 03:32:58 +01:00
} else if ( VN_IS ( nodep , Begin ) & & VN_IS ( fnodep , Begin )
& & VN_CAST ( nodep , Begin ) - > generate ( ) ) {
2019-05-19 22:13:13 +02:00
// Begin: ... blocks often replicate under genif/genfor, so simply
// suppress duplicate checks. See t_gen_forif.v for an example.
} else {
UINFO ( 4 , " name " < < name < < endl ) ; // Not always same as nodep->name
UINFO ( 4 , " Var1 " < < nodep < < endl ) ;
UINFO ( 4 , " Var2 " < < fnodep < < endl ) ;
if ( nodep - > type ( ) = = fnodep - > type ( ) ) {
nodep - > v3error ( " Duplicate declaration of " < < nodeTextType ( fnodep )
2019-07-12 04:09:30 +02:00
< < " : " < < nodep - > prettyNameQ ( ) < < endl
2019-06-22 23:01:39 +02:00
< < nodep - > warnContextPrimary ( ) < < endl
2019-07-12 01:15:40 +02:00
< < fnodep - > warnOther ( ) < < " ... Location of original declaration \n "
2019-06-22 23:01:39 +02:00
< < fnodep - > warnContextSecondary ( ) ) ;
2019-05-19 22:13:13 +02:00
} else {
nodep - > v3error ( " Unsupported in C: " < < ucfirst ( nodeTextType ( nodep ) )
< < " has the same name as "
2019-07-12 04:09:30 +02:00
< < nodeTextType ( fnodep ) < < " : " < < nodep - > prettyNameQ ( ) < < endl
2019-06-22 23:01:39 +02:00
< < nodep - > warnContextPrimary ( ) < < endl
2019-07-12 01:15:40 +02:00
< < fnodep - > warnOther ( ) < < " ... Location of original declaration \n "
2019-06-22 23:01:39 +02:00
< < fnodep - > warnContextSecondary ( ) ) ;
2019-05-19 22:13:13 +02:00
}
}
2012-07-21 23:12:42 +02:00
}
void insertDUnit ( AstNetlist * nodep ) {
2019-05-19 22:13:13 +02:00
// $unit on top scope
VSymEnt * symp = new VSymEnt ( & m_syms , nodep ) ;
2018-10-14 22:25:36 +02:00
UINFO ( 9 , " INSERTdunit se " < < cvtToHex ( symp ) < < endl ) ;
2019-05-19 22:13:13 +02:00
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
//
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( ! m_dunitEntp , nodep , " Call insertDUnit only once " ) ;
2019-05-19 22:13:13 +02:00
m_dunitEntp = symp ;
2012-06-20 12:13:28 +02:00
}
VSymEnt * insertTopCell ( AstNodeModule * nodep , const string & scopename ) {
2019-05-19 22:13:13 +02:00
// Only called on the module at the very top of the hierarchy
VSymEnt * symp = new VSymEnt ( & m_syms , nodep ) ;
2018-10-14 22:25:36 +02:00
UINFO ( 9 , " INSERTtop se " < < cvtToHex ( symp ) < < " " < < scopename < < " " < < nodep < < endl ) ;
2019-05-19 22:13:13 +02:00
symp - > parentp ( rootEntp ( ) ) ; // Needed so backward search can find name of top module
symp - > fallbackp ( dunitEntp ( ) ) ; // Needed so can find $unit stuff
nodep - > user1p ( symp ) ;
checkDuplicate ( rootEntp ( ) , nodep , nodep - > origName ( ) ) ;
rootEntp ( ) - > insert ( nodep - > origName ( ) , symp ) ;
if ( forScopeCreation ( ) ) m_nameScopeSymMap . insert ( make_pair ( scopename , symp ) ) ;
return symp ;
2012-06-20 12:13:28 +02:00
}
2012-07-20 03:18:39 +02:00
VSymEnt * insertCell ( VSymEnt * abovep , VSymEnt * modSymp ,
2019-05-19 22:13:13 +02:00
AstCell * nodep , const string & scopename ) {
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( abovep , nodep , " Null symbol table inserting node " ) ;
2019-05-19 22:13:13 +02:00
VSymEnt * symp = new VSymEnt ( & m_syms , nodep ) ;
UINFO ( 9 , " INSERTcel se " < < cvtToHex ( symp ) < < " " < < scopename
< < " above=se " < < cvtToHex ( abovep )
2018-10-14 22:25:36 +02:00
< < " mods=se " < < cvtToHex ( modSymp ) < < " node= " < < nodep < < endl ) ;
2019-05-19 22:13:13 +02:00
symp - > parentp ( abovep ) ;
symp - > fallbackp ( dunitEntp ( ) ) ; // Needed so can find $unit stuff
nodep - > user1p ( symp ) ;
if ( nodep - > modp ( ) ) nodep - > modp ( ) - > user1p ( symp ) ;
checkDuplicate ( abovep , nodep , nodep - > origName ( ) ) ;
abovep - > reinsert ( nodep - > origName ( ) , symp ) ;
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.
// Duplicates are possible, as until resolve generates might
// have 2 same cells under an if
modSymp - > reinsert ( nodep - > name ( ) , symp ) ;
}
if ( forScopeCreation ( ) ) m_nameScopeSymMap . insert ( make_pair ( scopename , symp ) ) ;
return symp ;
2012-06-20 12:13:28 +02:00
}
2012-07-20 03:18:39 +02:00
VSymEnt * insertInline ( VSymEnt * abovep , VSymEnt * modSymp ,
2019-05-19 22:13:13 +02:00
AstCellInline * nodep , const string & basename ) {
// A fake point in the hierarchy, corresponding to an inlined module
2019-09-09 13:50:21 +02:00
// This references to another Sym, and eventually resolves to a module with a prefix
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( abovep , nodep , " Null symbol table inserting node " ) ;
2019-05-19 22:13:13 +02:00
VSymEnt * symp = new VSymEnt ( & m_syms , nodep ) ;
UINFO ( 9 , " INSERTinl se " < < cvtToHex ( symp )
< < " " < < basename < < " above=se " < < cvtToHex ( abovep )
2018-10-14 22:25:36 +02:00
< < " mods=se " < < cvtToHex ( modSymp ) < < " node= " < < nodep < < endl ) ;
2019-05-19 22:13:13 +02:00
symp - > parentp ( abovep ) ;
symp - > fallbackp ( modSymp ) ;
symp - > symPrefix ( nodep - > name ( ) + " __DOT__ " ) ;
nodep - > user1p ( symp ) ;
checkDuplicate ( abovep , nodep , nodep - > name ( ) ) ;
abovep - > reinsert ( basename , symp ) ;
if ( abovep ! = modSymp & & ! modSymp - > findIdFlat ( nodep - > name ( ) ) ) {
// If it's foo_DOT_bar, we need to be able to find it under that too.
modSymp - > reinsert ( nodep - > name ( ) , symp ) ;
}
return symp ;
}
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
// After we remove begins these will go away
// Note we fallback to the symbol table of the parent, as we want to find variables there
// However, cells walk the graph, so cells will appear under the begin/ftask itself
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( abovep , nodep , " Null symbol table inserting node " ) ;
2019-05-19 22:13:13 +02:00
VSymEnt * symp = new VSymEnt ( & m_syms , nodep ) ;
UINFO ( 9 , " INSERTblk se " < < cvtToHex ( symp )
< < " above=se " < < cvtToHex ( abovep ) < < " node= " < < nodep < < endl ) ;
symp - > parentp ( abovep ) ;
symp - > packagep ( packagep ) ;
symp - > fallbackp ( abovep ) ;
nodep - > user1p ( symp ) ;
if ( name ! = " " ) {
checkDuplicate ( abovep , nodep , name ) ;
}
// Duplicates are possible, as until resolve generates might have 2 same cells under an if
abovep - > reinsert ( name , symp ) ;
return symp ;
}
VSymEnt * insertSym ( VSymEnt * abovep , const string & name ,
AstNode * nodep , AstPackage * packagep ) {
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( abovep , nodep , " Null symbol table inserting node " ) ;
2019-05-19 22:13:13 +02:00
VSymEnt * symp = new VSymEnt ( & m_syms , nodep ) ;
2018-10-14 22:25:36 +02:00
UINFO ( 9 , " INSERTsym se " < < cvtToHex ( symp ) < < " name=' " < < name
< < " ' above=se " < < cvtToHex ( abovep ) < < " node= " < < nodep < < endl ) ;
2019-05-19 22:13:13 +02:00
// 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 ) ;
abovep - > reinsert ( name , symp ) ;
return symp ;
2006-08-26 13:35:28 +02:00
}
2012-07-20 03:18:39 +02:00
static bool existsModScope ( AstNodeModule * nodep ) {
2019-05-19 22:13:13 +02:00
return nodep - > user1p ( ) ! = NULL ;
2006-08-26 13:35:28 +02:00
}
2012-07-21 15:27:57 +02:00
static VSymEnt * getNodeSym ( AstNode * nodep ) {
2019-05-19 22:13:13 +02:00
// Don't use this in ResolveVisitor, as we need to pick up the proper
// reference under each SCOPE
VSymEnt * symp = nodep - > user1u ( ) . toSymEnt ( ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( symp , nodep , " Module/etc never assigned a symbol entry? " ) ;
2019-05-19 22:13:13 +02:00
return symp ;
2006-08-26 13:35:28 +02:00
}
2012-07-18 03:29:10 +02:00
VSymEnt * getScopeSym ( AstScope * nodep ) {
2019-05-19 22:13:13 +02:00
NameScopeSymMap : : iterator it = m_nameScopeSymMap . find ( nodep - > name ( ) ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( it ! = m_nameScopeSymMap . end ( ) , nodep ,
" Scope never assigned a symbol entry? " ) ;
2019-05-19 22:13:13 +02:00
return it - > second ;
2006-08-26 13:35:28 +02:00
}
2012-07-22 03:18:07 +02:00
void implicitOkAdd ( AstNodeModule * nodep , const string & varname ) {
2019-05-19 22:13:13 +02:00
// Mark the given variable name as being allowed to be implicitly declared
if ( nodep ) {
ImplicitNameSet : : iterator it = m_implicitNameSet . find ( make_pair ( nodep , varname ) ) ;
if ( it = = m_implicitNameSet . end ( ) ) {
m_implicitNameSet . insert ( make_pair ( nodep , varname ) ) ;
}
}
2012-07-22 03:18:07 +02:00
}
bool implicitOk ( AstNodeModule * nodep , const string & varname ) {
2019-05-19 22:13:13 +02:00
return nodep
& & ( m_implicitNameSet . find ( make_pair ( nodep , varname ) )
! = m_implicitNameSet . end ( ) ) ;
2012-07-22 03:18:07 +02:00
}
2013-05-28 03:39:19 +02:00
// Track and later recurse interface modules
void insertIfaceModSym ( AstIface * nodep , VSymEnt * symp ) {
2019-05-19 22:13:13 +02:00
m_ifaceModSyms . push_back ( make_pair ( nodep , symp ) ) ;
2013-05-28 03:39:19 +02:00
}
void computeIfaceModSyms ( ) ;
// Track and later insert interface references
void insertIfaceVarSym ( VSymEnt * symp ) { // Where sym is for a VAR of dtype IFACEREFDTYPE
2019-05-19 22:13:13 +02:00
m_ifaceVarSyms . push_back ( symp ) ;
2013-05-28 03:39:19 +02:00
}
2015-12-06 01:39:40 +01:00
// Iface for a raw or arrayed iface
static AstIfaceRefDType * ifaceRefFromArray ( AstNodeDType * nodep ) {
2018-02-02 03:32:58 +01:00
AstIfaceRefDType * ifacerefp = VN_CAST ( nodep , IfaceRefDType ) ;
2019-05-19 22:13:13 +02:00
if ( ! ifacerefp ) {
2018-02-02 03:32:58 +01:00
if ( AstUnpackArrayDType * arrp = VN_CAST ( nodep , UnpackArrayDType ) ) {
ifacerefp = VN_CAST ( arrp - > subDTypep ( ) , IfaceRefDType ) ;
2019-05-19 22:13:13 +02:00
}
}
return ifacerefp ;
2015-12-06 01:39:40 +01:00
}
2013-05-28 03:39:19 +02:00
void computeIfaceVarSyms ( ) {
2019-05-19 22:13:13 +02:00
for ( IfaceVarSyms : : iterator it = m_ifaceVarSyms . begin ( ) ; it ! = m_ifaceVarSyms . end ( ) ; + + it ) {
VSymEnt * varSymp = * it ;
2018-02-02 03:32:58 +01:00
AstVar * varp = varSymp ? VN_CAST ( varSymp - > nodep ( ) , Var ) : NULL ;
2018-10-14 22:25:36 +02:00
UINFO ( 9 , " insAllIface se " < < cvtToHex ( varSymp ) < < " " < < varp < < endl ) ;
2019-05-19 22:13:13 +02:00
AstIfaceRefDType * ifacerefp = ifaceRefFromArray ( varp - > subDTypep ( ) ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( ifacerefp , varp , " Non-ifacerefs on list! " ) ;
2019-05-19 22:13:13 +02:00
if ( ! ifacerefp - > ifaceViaCellp ( ) ) {
if ( ! ifacerefp - > cellp ( ) ) { // Probably a NotFoundModule, or a normal module if made mistake
ifacerefp - > v3error ( " Cannot find file containing interface: "
2019-07-12 04:09:30 +02:00
< < AstNode : : prettyNameQ ( ifacerefp - > ifaceName ( ) ) ) ;
2019-05-19 22:13:13 +02:00
continue ;
} else {
ifacerefp - > v3fatalSrc ( " Unlinked interface " ) ;
}
} else if ( ifacerefp - > ifaceViaCellp ( ) - > dead ( ) ) {
ifacerefp - > v3error ( " Parent cell's interface is not found: "
2019-07-12 04:09:30 +02:00
< < AstNode : : prettyNameQ ( ifacerefp - > ifaceName ( ) ) ) ;
2019-05-19 22:13:13 +02:00
continue ;
}
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 ) {
2018-02-02 03:32:58 +01:00
if ( AstModport * modportp = VN_CAST ( foundp - > nodep ( ) , Modport ) ) {
2019-05-19 22:13:13 +02:00
UINFO ( 4 , " Link Modport: " < < modportp < < endl ) ;
ifacerefp - > modportp ( modportp ) ;
ifOrPortSymp = foundp ;
ok = true ;
}
}
2019-07-14 02:30:32 +02:00
if ( ! ok ) {
string suggest = suggestSymFallback (
ifaceSymp , ifacerefp - > modportName ( ) , LinkNodeMatcherModport ( ) ) ;
2019-07-14 21:06:49 +02:00
ifacerefp - > modportFileline ( )
- > v3error ( " Modport not found under interface "
< < ifacerefp - > prettyNameQ ( ifacerefp - > ifaceName ( ) ) < < " : "
< < ifacerefp - > prettyNameQ ( ifacerefp - > modportName ( ) ) < < endl
< < ( suggest . empty ( ) ? " " : ifacerefp - > warnMore ( ) + suggest ) ) ;
2019-07-14 02:30:32 +02:00
}
2019-05-19 22:13:13 +02:00
}
// Alias won't expand until interfaces and modport names are known; see notes at top
insertScopeAlias ( SAMN_IFTOP , varSymp , ifOrPortSymp ) ;
}
m_ifaceVarSyms . clear ( ) ;
2013-05-28 03:39:19 +02:00
}
2014-04-04 03:53:39 +02:00
void insertScopeAlias ( SAMNum samn , VSymEnt * lhsp , VSymEnt * rhsp ) {
2019-05-19 22:13:13 +02:00
// 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
2018-10-14 22:25:36 +02:00
UINFO ( 9 , " insertScopeAlias se " < < cvtToHex ( lhsp ) < < " se " < < cvtToHex ( rhsp ) < < endl ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( ! ( VN_IS ( rhsp - > nodep ( ) , Cell )
& & ! VN_IS ( VN_CAST ( rhsp - > nodep ( ) , Cell ) - > modp ( ) , Iface ) ) ,
rhsp - > nodep ( ) , " Got a non-IFACE alias RHS " ) ;
2019-05-19 22:13:13 +02:00
m_scopeAliasMap [ samn ] . insert ( make_pair ( lhsp , rhsp ) ) ;
2013-05-28 03:39:19 +02:00
}
void computeScopeAliases ( ) {
2019-05-19 22:13:13 +02:00
UINFO ( 9 , " computeIfaceAliases \n " ) ;
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 ) ;
// Allow access to objects not permissible to be listed in a modport
2018-02-02 03:32:58 +01:00
if ( VN_IS ( srcp - > nodep ( ) , Modport ) ) {
2019-05-19 22:13:13 +02:00
lhsp - > importFromIface ( symsp ( ) , srcp - > parentp ( ) , true ) ;
}
}
//m_scopeAliasMap[samn].clear(); // Done with it, but put into debug file
}
2013-05-28 03:39:19 +02:00
}
2012-07-21 23:12:42 +02:00
private :
VSymEnt * findWithAltFallback ( VSymEnt * symp , const string & name , const string & altname ) {
2019-05-19 22:13:13 +02:00
VSymEnt * findp = symp - > findIdFallback ( name ) ;
if ( findp ) return findp ;
if ( altname ! = " " ) {
UINFO ( 8 , " alt fallback \n " ) ;
findp = symp - > findIdFallback ( altname ) ;
}
return findp ;
2012-07-21 23:12:42 +02:00
}
public :
2012-07-20 03:18:39 +02:00
VSymEnt * findDotted ( VSymEnt * lookupSymp , const string & dotname ,
2019-05-19 22:13:13 +02:00
string & baddot , VSymEnt * & okSymp ) {
// Given a dotted hierarchy name, return where in scope it is
// Note when dotname=="" we just fall through and return lookupSymp
2018-10-14 22:25:36 +02:00
UINFO ( 8 , " dottedFind se " < < cvtToHex ( lookupSymp ) < < " ' " < < dotname < < " ' " < < endl ) ;
2019-05-19 22:13:13 +02:00
bool firstId = true ;
string leftname = dotname ;
okSymp = lookupSymp ; // So can list bad scopes
while ( leftname ! = " " ) { // foreach dotted part of xref name
string : : size_type pos ;
string ident ;
2018-10-14 04:28:59 +02:00
if ( ( pos = leftname . find ( ' . ' ) ) ! = string : : npos ) {
2019-05-19 22:13:13 +02:00
ident = leftname . substr ( 0 , pos ) ;
leftname = leftname . substr ( pos + 1 ) ;
} else {
ident = leftname ;
leftname = " " ;
}
baddot = ident ; // So user can see where they botched it
okSymp = lookupSymp ;
2018-10-14 05:06:36 +02:00
string altIdent ;
2019-05-19 22:13:13 +02:00
if ( m_forPrearray ) {
// 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 ) {
altIdent = ident . substr ( 0 , pos ) ;
}
}
UINFO ( 8 , " id " < < ident < < " alt " < < altIdent
< < " left " < < leftname < < " at se " < < lookupSymp < < endl ) ;
// Spec says; Look at existing module (cellnames then modname),
// then look up (inst name or modname)
if ( firstId ) {
// Check this module - subcellnames
2018-02-02 03:32:58 +01:00
AstCell * cellp = lookupSymp ? VN_CAST ( lookupSymp - > nodep ( ) , Cell ) : NULL ; // Replicated below
AstCellInline * inlinep = lookupSymp ? VN_CAST ( lookupSymp - > nodep ( ) , CellInline ) : NULL ; // Replicated below
2019-05-19 22:13:13 +02:00
if ( VSymEnt * findSymp = findWithAltFallback ( lookupSymp , ident , altIdent ) ) {
lookupSymp = findSymp ;
}
// Check this module - cur modname
else if ( ( cellp & & cellp - > modp ( ) - > origName ( ) = = ident )
| | ( inlinep & & inlinep - > origModName ( ) = = ident ) ) { }
// Move up and check cellname + modname
else {
bool crossedCell = false ; // Crossed a cell boundary
while ( lookupSymp ) {
lookupSymp = lookupSymp - > parentp ( ) ;
2018-02-02 03:32:58 +01:00
cellp = lookupSymp ? VN_CAST ( lookupSymp - > nodep ( ) , Cell ) : NULL ; // Replicated above
inlinep = lookupSymp ? VN_CAST ( lookupSymp - > nodep ( ) , CellInline ) : NULL ; // Replicated above
2019-05-19 22:13:13 +02:00
if ( lookupSymp ) {
2019-10-05 23:35:08 +02:00
UINFO ( 9 , " Up to " < < lookupSymp < < endl ) ;
2019-05-19 22:13:13 +02:00
if ( cellp | | inlinep ) {
crossedCell = true ;
}
if ( ( cellp & & cellp - > modp ( ) - > origName ( ) = = ident )
| | ( inlinep & & inlinep - > origModName ( ) = = ident ) ) {
break ;
}
else if ( VSymEnt * findSymp
= findWithAltFallback ( lookupSymp , ident , altIdent ) ) {
lookupSymp = findSymp ;
2018-02-02 03:32:58 +01:00
if ( crossedCell & & VN_IS ( lookupSymp - > nodep ( ) , Var ) ) {
2019-10-05 23:35:08 +02:00
UINFO ( 9 , " Not found but matches var name in parent "
2019-05-19 22:13:13 +02:00
< < lookupSymp < < endl ) ;
return NULL ; // Not found (but happens to be var name in parent)
}
break ;
}
} else break ;
}
if ( ! lookupSymp ) return NULL ; // Not found
}
} else { // Searching for middle submodule, must be a cell name
if ( VSymEnt * findSymp = findWithAltFallback ( lookupSymp , ident , altIdent ) ) {
lookupSymp = findSymp ;
} else {
return NULL ; // Not found
}
}
firstId = false ;
}
return lookupSymp ;
2006-08-26 13:35:28 +02:00
}
2015-12-06 01:39:40 +01:00
static string removeLastInlineScope ( const string & name ) {
2019-05-19 22:13:13 +02:00
string out = name ;
string dot = " __DOT__ " ;
size_t dotPos = out . rfind ( dot , out . size ( ) - dot . length ( ) - 2 ) ;
if ( dotPos = = string : : npos ) {
return " " ;
} else {
return out . erase ( dotPos + dot . length ( ) , string : : npos ) ;
}
2015-12-06 01:39:40 +01:00
}
2012-07-21 23:12:42 +02:00
VSymEnt * findSymPrefixed ( VSymEnt * lookupSymp , const string & dotname , string & baddot ) {
2019-05-19 22:13:13 +02:00
// Find symbol in given point in hierarchy, allowing prefix (post-Inline)
// For simplicity lookupSymp may be passed NULL result from findDotted
if ( ! lookupSymp ) return NULL ;
2019-10-05 23:35:08 +02:00
UINFO ( 8 , " findSymPrefixed " < < dotname
2018-10-14 22:25:36 +02:00
< < " under se " < < cvtToHex ( lookupSymp )
2019-05-19 22:13:13 +02:00
< < ( ( lookupSymp - > symPrefix ( ) = = " " ) ? " " : " as " )
< < ( ( lookupSymp - > symPrefix ( ) = = " " ) ? " " : lookupSymp - > symPrefix ( ) + dotname )
< < " at se " < < lookupSymp
< < endl ) ;
string prefix = lookupSymp - > symPrefix ( ) ;
VSymEnt * foundp = NULL ;
while ( ! foundp ) {
foundp = lookupSymp - > findIdFallback ( prefix + dotname ) ; // Might be NULL
if ( prefix = = " " ) {
break ;
}
prefix = removeLastInlineScope ( prefix ) ;
}
if ( ! foundp ) baddot = dotname ;
return foundp ;
2012-07-21 23:12:42 +02:00
}
2019-07-14 02:30:32 +02:00
string suggestSymFallback ( VSymEnt * lookupSymp , const string & name ,
const VNodeMatcher & matcher ) {
// Suggest alternative symbol in given point in hierarchy
// Does not support inline, as we find user-level errors before inlining
// For simplicity lookupSymp may be passed NULL result from findDotted
if ( ! lookupSymp ) return " " ;
VSpellCheck speller ;
lookupSymp - > candidateIdFallback ( & speller , & matcher ) ;
return speller . bestCandidateMsg ( name ) ;
}
string suggestSymFlat ( VSymEnt * lookupSymp , const string & name ,
const VNodeMatcher & matcher ) {
if ( ! lookupSymp ) return " " ;
VSpellCheck speller ;
lookupSymp - > candidateIdFlat ( & speller , & matcher ) ;
return speller . bestCandidateMsg ( name ) ;
}
2006-08-26 13:35:28 +02:00
} ;
2013-05-25 18:15:38 +02:00
LinkDotState * LinkDotState : : s_errorThisp = NULL ;
2006-08-26 13:35:28 +02:00
//======================================================================
class LinkDotFindVisitor : public AstNVisitor {
// STATE
2019-05-19 22:13:13 +02:00
LinkDotState * m_statep ; // State to pass between visitors, including symbol table
AstPackage * m_packagep ; // Current package
VSymEnt * m_modSymp ; // Symbol Entry for current module
VSymEnt * m_curSymp ; // Symbol Entry for current table, where to lookup/insert
string m_scope ; // Scope text
AstBegin * m_beginp ; // Current Begin/end block
AstNodeFTask * m_ftaskp ; // Current function/task
bool m_inGenerate ; // Inside a generate
bool m_inRecursion ; // Inside a recursive module
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 22:56:50 +01:00
2012-07-21 23:12:42 +02:00
// METHODS
2006-08-26 13:35:28 +02:00
int debug ( ) { return LinkDotState : : debug ( ) ; }
2018-02-08 01:31:21 +01:00
virtual AstConst * parseParamLiteral ( FileLine * fl , const string & literal ) {
2019-05-19 22:13:13 +02:00
bool success = false ;
2016-03-25 00:14:15 +01:00
if ( literal [ 0 ] = = ' " ' ) {
2019-05-19 22:13:13 +02:00
// This is a string
2016-03-25 00:14:15 +01:00
string v = literal . substr ( 1 , literal . find ( ' " ' , 1 ) - 1 ) ;
2019-05-10 02:03:19 +02:00
return new AstConst ( fl , AstConst : : VerilogStringLiteral ( ) , v ) ;
2018-10-14 04:28:59 +02:00
} else if ( ( literal . find ( ' . ' ) ! = string : : npos )
| | ( literal . find ( ' e ' ) ! = string : : npos ) ) {
2019-05-19 22:13:13 +02:00
// This may be a real
2016-03-25 00:14:15 +01:00
double v = V3ParseImp : : parseDouble ( literal . c_str ( ) , literal . length ( ) , & success ) ;
if ( success ) {
return new AstConst ( fl , AstConst : : RealDouble ( ) , v ) ;
}
}
if ( ! success ) {
// This is either an integer or an error
// We first try to convert it as C literal. If strtol returns
// 0 this is either an error or 0 was parsed. But in any case
// we will try to parse it as a verilog literal, hence having
// the false negative for 0 is okay. If anything remains in
// the string after the number, this is invalid C and we try
// the Verilog literal parser.
char * endp ;
int v = strtol ( literal . c_str ( ) , & endp , 0 ) ;
2019-05-10 02:03:19 +02:00
if ( ( v ! = 0 ) & & ( endp [ 0 ] = = 0 ) ) { // C literal
return new AstConst ( fl , AstConst : : WidthedValue ( ) , 32 , v ) ;
} else { // Try a Verilog literal (fatals if not)
return new AstConst ( fl , AstConst : : StringToParse ( ) , literal . c_str ( ) ) ;
2016-03-25 00:14:15 +01:00
}
}
2019-05-19 22:13:13 +02:00
return NULL ;
2016-03-25 00:14:15 +01:00
}
2006-08-26 13:35:28 +02:00
// VISITs
2020-01-21 23:35:56 +01:00
virtual void visit ( AstNetlist * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// Process $unit or other packages
// Not needed - dotted references not allowed from inside packages
//for (AstNodeModule* nodep = v3Global.rootp()->modulesp();
// nodep; nodep=VN_CAST(nodep->nextp(), NodeModule)) {
2018-02-02 03:32:58 +01:00
// if (VN_IS(nodep, Package)) {}}
2009-11-08 03:05:02 +01:00
2019-05-19 22:13:13 +02:00
m_statep - > insertDUnit ( nodep ) ;
2012-07-21 23:12:42 +02:00
2019-05-19 22:13:13 +02:00
// First back iterate, to find all packages. Backward as must do base
// packages before using packages
2018-05-11 02:55:37 +02:00
iterateChildrenBackwards ( nodep ) ;
2012-07-21 23:12:42 +02:00
2019-06-30 22:46:48 +02:00
// The first modules in the list are always the top modules
// (sorted before this is called).
2019-05-19 22:13:13 +02:00
// This may not be the module with isTop() set, as early in the steps,
// wrapTop may have not been created yet.
2019-06-30 22:46:48 +02:00
if ( ! nodep - > modulesp ( ) ) {
2019-05-19 22:13:13 +02:00
nodep - > v3error ( " No top level module found " ) ;
2019-06-30 22:46:48 +02:00
}
for ( AstNodeModule * modp = nodep - > modulesp ( ) ; modp & & modp - > level ( ) < = 2 ;
modp = VN_CAST ( modp - > nextp ( ) , NodeModule ) ) {
UINFO ( 8 , " Top Module: " < < modp < < endl ) ;
2019-05-19 22:13:13 +02:00
m_scope = " TOP " ;
2019-06-30 22:46:48 +02:00
m_curSymp = m_modSymp = m_statep - > insertTopCell ( modp , m_scope ) ;
2019-05-19 22:13:13 +02:00
{
2019-06-30 22:46:48 +02:00
iterate ( modp ) ;
2019-05-19 22:13:13 +02:00
}
m_scope = " " ;
m_curSymp = m_modSymp = NULL ;
}
2006-08-26 13:35:28 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstTypeTable * nodep ) VL_OVERRIDE { }
virtual void visit ( AstNodeModule * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// Called on top module from Netlist, other modules from the cell creating them,
// and packages
UINFO ( 8 , " " < < nodep < < endl ) ;
// 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
2018-02-02 03:32:58 +01:00
bool standalonePkg = ! m_modSymp & & ( m_statep - > forPrearray ( ) & & VN_IS ( nodep , Package ) ) ;
2019-05-19 22:13:13 +02:00
bool doit = ( m_modSymp | | standalonePkg ) ;
string oldscope = m_scope ;
VSymEnt * oldModSymp = m_modSymp ;
VSymEnt * oldCurSymp = m_curSymp ;
2012-11-03 01:30:47 +01:00
int oldParamNum = m_paramNum ;
int oldBeginNum = m_beginNum ;
int oldModBeginNum = m_modBeginNum ;
2019-05-19 22:13:13 +02:00
if ( doit & & nodep - > user2 ( ) ) {
nodep - > v3error ( " Unsupported: Identically recursive module (module instantiates itself, without changing parameters): "
2019-07-12 04:09:30 +02:00
< < AstNode : : prettyNameQ ( nodep - > origName ( ) ) ) ;
2019-05-19 22:13:13 +02:00
} else if ( doit ) {
UINFO ( 4 , " Link Module: " < < nodep < < endl ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( ! nodep - > dead ( ) , nodep , " Module in cell tree mislabeled as dead? " ) ;
2019-05-19 22:13:13 +02:00
VSymEnt * upperSymp = m_curSymp ? m_curSymp : m_statep - > rootEntp ( ) ;
2018-02-02 03:32:58 +01:00
m_packagep = VN_CAST ( nodep , Package ) ;
2019-05-19 22:13:13 +02:00
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
nodep - > user2 ( true ) ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
nodep - > user2 ( false ) ;
nodep - > user4 ( true ) ;
// Interfaces need another pass when signals are resolved
2018-02-02 03:32:58 +01:00
if ( AstIface * ifacep = VN_CAST ( nodep , Iface ) ) {
2019-05-19 22:13:13 +02:00
m_statep - > insertIfaceModSym ( ifacep , m_curSymp ) ;
}
} 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 ) ;
}
m_scope = oldscope ;
m_modSymp = oldModSymp ;
m_curSymp = oldCurSymp ;
2012-11-03 01:30:47 +01:00
m_paramNum = oldParamNum ;
m_beginNum = oldBeginNum ;
m_modBeginNum = oldModBeginNum ;
2019-05-19 22:13:13 +02:00
// Prep for next
m_packagep = NULL ;
2006-08-26 13:35:28 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstScope * nodep ) VL_OVERRIDE {
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( m_statep - > forScopeCreation ( ) , nodep ,
" Scopes should only exist right after V3Scope " ) ;
2019-05-19 22:13:13 +02:00
// Ignored. Processed in next step
2006-08-26 13:35:28 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstCell * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
UINFO ( 5 , " CELL under " < < m_scope < < " is " < < nodep < < endl ) ;
// Process XREFs/etc inside pins
if ( nodep - > recursive ( ) & & m_inRecursion ) return ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
// Recurse in, preserving state
string oldscope = m_scope ;
AstBegin * oldbeginp = m_beginp ;
VSymEnt * oldModSymp = m_modSymp ;
VSymEnt * oldCurSymp = m_curSymp ;
int oldParamNum = m_paramNum ;
bool oldRecursion = m_inRecursion ;
// Where do we add it?
VSymEnt * aboveSymp = m_curSymp ;
string origname = AstNode : : dedotName ( nodep - > name ( ) ) ;
string : : size_type pos ;
2018-10-14 04:28:59 +02:00
if ( ( pos = origname . rfind ( ' . ' ) ) ! = string : : npos ) {
2019-05-19 22:13:13 +02:00
// Flattened, find what CellInline it should live under
string scope = origname . substr ( 0 , pos ) ;
string baddot ;
VSymEnt * okSymp ;
aboveSymp = m_statep - > findDotted ( aboveSymp , scope , baddot , okSymp ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( aboveSymp , nodep ,
2019-11-05 03:16:07 +01:00
" Can't find cell insertion point at "
< < AstNode : : prettyNameQ ( baddot ) < < " in: " < < nodep - > prettyNameQ ( ) ) ;
2019-05-19 22:13:13 +02:00
}
{
m_scope = m_scope + " . " + nodep - > name ( ) ;
m_curSymp = m_modSymp = m_statep - > insertCell ( aboveSymp , m_modSymp , nodep , m_scope ) ;
m_beginp = NULL ;
m_inRecursion = nodep - > recursive ( ) ;
// We don't report NotFoundModule, as may be a unused module in a generate
2018-05-11 02:55:37 +02:00
if ( nodep - > modp ( ) ) iterate ( nodep - > modp ( ) ) ;
2019-05-19 22:13:13 +02:00
}
m_scope = oldscope ;
m_beginp = oldbeginp ;
m_modSymp = oldModSymp ;
m_curSymp = oldCurSymp ;
m_paramNum = oldParamNum ;
m_inRecursion = oldRecursion ;
2006-08-26 13:35:28 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstCellInline * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
UINFO ( 5 , " CELLINLINE under " < < m_scope < < " is " < < nodep < < endl ) ;
VSymEnt * aboveSymp = m_curSymp ;
// 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 ;
VSymEnt * okSymp ;
aboveSymp = m_statep - > findDotted ( aboveSymp , dotted , baddot , okSymp ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( aboveSymp , nodep ,
2019-11-05 03:16:07 +01:00
" Can't find cellinline insertion point at "
< < AstNode : : prettyNameQ ( baddot ) < < " in: " < < nodep - > prettyNameQ ( ) ) ;
2019-05-19 22:13:13 +02:00
m_statep - > insertInline ( aboveSymp , m_modSymp , nodep , ident ) ;
} else { // No __DOT__, just directly underneath
m_statep - > insertInline ( aboveSymp , m_modSymp , nodep , nodep - > name ( ) ) ;
}
2006-08-26 13:35:28 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstDefParam * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
nodep - > user1p ( m_curSymp ) ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2012-08-08 00:24:51 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstGenerate * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// 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 ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
}
m_inGenerate = lastInGen ;
2012-07-21 23:12:42 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstBegin * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
UINFO ( 5 , " " < < nodep < < endl ) ;
// 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 ( ) ) {
2018-02-02 03:32:58 +01:00
if ( VN_IS ( stmtp , Var ) ) {
2019-05-19 22:13:13 +02:00
+ + m_modBeginNum ;
nodep - > name ( " unnamedblk " + cvtToStr ( m_modBeginNum ) ) ;
break ;
}
}
}
int oldNum = m_beginNum ;
AstBegin * oldbegin = m_beginp ;
VSymEnt * oldCurSymp = m_curSymp ;
{
m_beginNum = 0 ;
m_beginp = nodep ;
m_curSymp = m_statep - > insertBlock ( m_curSymp , nodep - > name ( ) , nodep , m_packagep ) ;
m_curSymp - > fallbackp ( oldCurSymp ) ;
// Iterate
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
}
m_curSymp = oldCurSymp ;
m_beginp = oldbegin ;
m_beginNum = oldNum ;
2006-08-26 13:35:28 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstNodeFTask * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// NodeTask: Remember its name for later resolution
UINFO ( 5 , " " < < nodep < < endl ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( m_curSymp & & m_modSymp , nodep , " Function/Task not under module? " ) ;
2019-05-19 22:13:13 +02:00
// 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
2019-09-09 13:50:21 +02:00
// just attach normal signal attributes to it.
2019-05-19 22:13:13 +02:00
if ( nodep - > fvarp ( )
2018-02-02 03:32:58 +01:00
& & ! VN_IS ( nodep - > fvarp ( ) , Var ) ) {
AstNodeDType * dtypep = VN_CAST ( nodep - > fvarp ( ) , NodeDType ) ;
2019-05-19 22:13:13 +02:00
// If unspecified, function returns one bit; however when we
// support NEW() it could also return the class reference.
2018-11-26 01:50:53 +01:00
if ( dtypep ) dtypep - > unlinkFrBack ( ) ;
else dtypep = new AstBasicDType ( nodep - > fileline ( ) , AstBasicDTypeKwd : : LOGIC ) ;
AstVar * newvarp = new AstVar ( nodep - > fileline ( ) , AstVarType : : VAR , nodep - > name ( ) ,
2018-10-27 23:29:00 +02:00
VFlagChildDType ( ) , dtypep ) ; // Not dtype resolved yet
newvarp - > direction ( VDirection : : OUTPUT ) ;
2019-05-19 22:13:13 +02:00
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 ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
m_ftaskp = NULL ;
}
m_curSymp = oldCurSymp ;
2012-07-21 23:12:42 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstVar * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// Var: Remember its name for later resolution
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( m_curSymp & & m_modSymp , nodep , " Var not under module? " ) ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-12-07 00:50:41 +01:00
if ( m_ftaskp & & nodep - > isParam ( ) ) {
nodep - > v3error ( " Unsupported: Parameters in functions. " ) ; // Big3 unsupported too
2020-01-17 02:17:11 +01:00
VL_DO_DANGLING ( nodep - > unlinkFrBack ( ) - > deleteTree ( ) , nodep ) ;
2019-12-07 00:50:41 +01:00
return ;
}
2019-05-19 22:13:13 +02:00
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?
}
2018-02-02 03:32:58 +01:00
AstVar * findvarp = foundp ? VN_CAST ( foundp - > nodep ( ) , Var ) : NULL ;
2019-05-19 22:13:13 +02: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 ( ) )
2019-07-12 04:09:30 +02:00
< < " : " < < nodep - > prettyNameQ ( ) ) ;
2019-05-19 22:13:13 +02:00
} else if ( findvarp ! = nodep ) {
UINFO ( 4 , " DupVar: " < < nodep < < " ;; " < < foundp - > nodep ( ) < < endl ) ;
2018-10-14 22:25:36 +02:00
UINFO ( 4 , " found cur=se " < < cvtToHex ( m_curSymp )
< < " ;; parent=se " < < cvtToHex ( foundp - > parentp ( ) ) < < endl ) ;
2019-05-19 22:13:13 +02:00
if ( foundp & & foundp - > parentp ( ) = = m_curSymp // Only when on same level
& & ! foundp - > imported ( ) ) { // and not from package
2019-06-22 18:43:48 +02:00
bool nansiBad = ( ( findvarp - > isDeclTyped ( ) & & nodep - > isDeclTyped ( ) )
| | ( findvarp - > isIO ( ) & & nodep - > isIO ( ) ) ) ; // e.g. !(output && output)
bool ansiBad = findvarp - > isAnsi ( ) | | nodep - > isAnsi ( ) ; // dup illegal with ANSI
if ( ansiBad | | nansiBad ) {
bool ansiWarn = ansiBad & & ! nansiBad ;
2019-10-06 14:20:02 +02:00
if ( ansiWarn ) {
static int didAnsiWarn = false ;
if ( didAnsiWarn + + ) ansiWarn = false ;
}
2019-06-22 18:43:48 +02:00
nodep - > v3error ( " Duplicate declaration of signal: "
2019-07-12 04:09:30 +02:00
< < nodep - > prettyNameQ ( ) < < endl
2019-06-22 18:43:48 +02:00
< < ( ansiWarn
2019-06-29 03:42:49 +02:00
? nodep - > warnMore ( ) + " ... note: ANSI ports must have type declared with the I/O (IEEE 2017 23.2.2.2) \n "
2019-06-22 22:09:10 +02:00
: " " )
2019-06-22 23:01:39 +02:00
< < nodep - > warnContextPrimary ( ) < < endl
2019-07-12 01:15:40 +02:00
< < findvarp - > warnOther ( ) < < " ... Location of original declaration " < < endl
2019-06-22 23:01:39 +02:00
< < findvarp - > warnContextSecondary ( ) ) ;
2019-06-22 18:43:48 +02:00
// Combining most likely reduce other errors
findvarp - > combineType ( nodep ) ;
findvarp - > fileline ( ) - > modifyStateInherit ( nodep - > fileline ( ) ) ;
} else {
2019-05-19 22:13:13 +02:00
findvarp - > combineType ( nodep ) ;
2019-06-13 01:17:10 +02:00
findvarp - > fileline ( ) - > modifyStateInherit ( nodep - > fileline ( ) ) ;
2018-02-02 03:32:58 +01:00
AstBasicDType * bdtypep = VN_CAST ( findvarp - > childDTypep ( ) , BasicDType ) ;
2019-05-19 22:13:13 +02:00
if ( bdtypep & & bdtypep - > implicit ( ) ) {
// Then have "input foo" and "real foo" so the
// dtype comes from the other side.
AstNodeDType * newdtypep = nodep - > subDTypep ( ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( newdtypep & & nodep - > childDTypep ( ) , findvarp ,
" No child type? " ) ;
2020-01-17 02:17:11 +01:00
VL_DO_DANGLING ( bdtypep - > unlinkFrBack ( ) - > deleteTree ( ) , bdtypep ) ;
2019-05-19 22:13:13 +02:00
newdtypep - > unlinkFrBack ( ) ;
findvarp - > childDTypep ( newdtypep ) ;
}
}
2020-01-17 02:17:11 +01:00
VL_DO_DANGLING ( nodep - > unlinkFrBack ( ) - > deleteTree ( ) , nodep ) ;
2019-05-19 22:13:13 +02:00
} 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 ) ) {
nodep - > v3warn ( VARHIDDEN , " Declaration of signal hides declaration in upper scope: "
2019-07-12 04:09:30 +02:00
< < nodep - > prettyNameQ ( ) < < endl
2019-06-22 23:01:39 +02:00
< < nodep - > warnContextPrimary ( ) < < endl
2019-07-12 01:15:40 +02:00
< < foundp - > nodep ( ) - > warnOther ( )
2019-06-22 23:01:39 +02:00
< < " ... Location of original declaration \n "
< < foundp - > nodep ( ) - > warnContextSecondary ( ) ) ;
2019-05-19 22:13:13 +02:00
}
ins = true ;
}
}
if ( ins ) {
if ( m_statep - > forPrimary ( ) & & nodep - > isGParam ( )
& & ( m_statep - > rootEntp ( ) - > nodep ( ) = = m_modSymp - > parentp ( ) - > nodep ( ) ) ) {
// This is the toplevel module. Check for command line overwrites of parameters
// We first search if the parameter is overwritten and then replace it with a
// new value. It will keep the same FileLine information.
if ( v3Global . opt . hasParameter ( nodep - > name ( ) ) ) {
AstVar * newp = new AstVar ( nodep - > fileline ( ) ,
AstVarType ( AstVarType : : GPARAM ) ,
nodep - > name ( ) , nodep ) ;
string svalue = v3Global . opt . parameter ( nodep - > name ( ) ) ;
if ( AstNode * valuep = parseParamLiteral ( nodep - > fileline ( ) , svalue ) ) {
newp - > valuep ( valuep ) ;
UINFO ( 9 , " replace parameter " < < nodep < < endl ) ;
UINFO ( 9 , " with " < < newp < < endl ) ;
2020-01-17 02:17:11 +01:00
nodep - > replaceWith ( newp ) ; VL_DO_DANGLING ( pushDeletep ( nodep ) , nodep ) ;
2019-05-19 22:13:13 +02:00
nodep = newp ;
}
}
}
VSymEnt * insp = m_statep - > insertSym ( m_curSymp , nodep - > name ( ) , nodep , m_packagep ) ;
if ( m_statep - > forPrimary ( ) & & nodep - > isGParam ( ) ) {
m_paramNum + + ;
VSymEnt * symp = m_statep - > insertSym ( m_curSymp ,
" __paramNumber " + cvtToStr ( m_paramNum ) ,
nodep , m_packagep ) ;
symp - > exported ( false ) ;
}
AstIfaceRefDType * ifacerefp = LinkDotState : : ifaceRefFromArray ( nodep - > subDTypep ( ) ) ;
if ( ifacerefp ) {
// Can't resolve until interfaces and modport names are
// known; see notes at top
m_statep - > insertIfaceVarSym ( insp ) ;
}
}
}
2006-08-26 13:35:28 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstTypedef * nodep ) VL_OVERRIDE {
2020-01-20 22:53:27 +01:00
UASSERT_OBJ ( m_curSymp , nodep , " Typedef not under module/package/$unit " ) ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
m_statep - > insertSym ( m_curSymp , nodep - > name ( ) , nodep , m_packagep ) ;
2012-07-21 23:12:42 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstParamTypeDType * nodep ) VL_OVERRIDE {
2020-01-20 22:53:27 +01:00
UASSERT_OBJ ( m_curSymp , nodep , " Parameter type not under module/package/$unit " ) ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
m_statep - > insertSym ( m_curSymp , nodep - > name ( ) , nodep , m_packagep ) ;
2016-03-15 02:51:31 +01:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstCFunc * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// For dotted resolution, ignore all AstVars under functions, otherwise shouldn't exist
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( ! m_statep - > forScopeCreation ( ) , nodep , " No CFuncs expected in tree yet " ) ;
2012-07-21 23:12:42 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstEnumItem * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// EnumItem: Remember its name for later resolution
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
// 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?
}
2018-02-02 03:32:58 +01:00
AstEnumItem * findvarp = foundp ? VN_CAST ( foundp - > nodep ( ) , EnumItem ) : NULL ;
2019-05-19 22:13:13 +02:00
bool ins = false ;
if ( ! foundp ) {
ins = true ;
} else if ( findvarp ! = nodep ) {
UINFO ( 4 , " DupVar: " < < nodep < < " ;; " < < foundp < < endl ) ;
2019-10-25 03:48:45 +02:00
if ( foundp - > parentp ( ) = = m_curSymp // Only when on same level
2019-05-19 22:13:13 +02:00
& & ! foundp - > imported ( ) ) { // and not from package
nodep - > v3error ( " Duplicate declaration of enum value: " < < nodep - > prettyName ( ) < < endl
2019-06-22 23:01:39 +02:00
< < nodep - > warnContextPrimary ( ) < < endl
2019-10-16 01:06:00 +02:00
< < foundp - > nodep ( ) - > warnOther ( ) < < " ... Location of original declaration \n "
< < foundp - > nodep ( ) - > warnContextSecondary ( ) ) ;
2019-05-19 22:13:13 +02:00
} else {
// User can disable the message at either point
if ( ! nodep - > fileline ( ) - > warnIsOff ( V3ErrorCode : : VARHIDDEN )
& & ! foundp - > nodep ( ) - > fileline ( ) - > warnIsOff ( V3ErrorCode : : VARHIDDEN ) ) {
nodep - > v3warn ( VARHIDDEN , " Declaration of enum value hides declaration in upper scope: "
< < nodep - > prettyName ( ) < < endl
2019-06-22 23:01:39 +02:00
< < nodep - > warnContextPrimary ( ) < < endl
2019-07-12 01:15:40 +02:00
< < foundp - > nodep ( ) - > warnOther ( )
2019-06-22 23:01:39 +02:00
< < " ... Location of original declaration \n "
< < nodep - > warnContextSecondary ( ) ) ;
2019-05-19 22:13:13 +02:00
}
ins = true ;
}
}
if ( ins ) {
m_statep - > insertSym ( m_curSymp , nodep - > name ( ) , nodep , m_packagep ) ;
}
2012-07-21 23:12:42 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstPackageImport * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
UINFO ( 4 , " Link: " < < nodep < < endl ) ;
VSymEnt * srcp = m_statep - > getNodeSym ( nodep - > packagep ( ) ) ;
2018-11-29 00:25:34 +01:00
if ( nodep - > name ( ) = = " * " ) {
if ( m_curSymp = = m_statep - > dunitEntp ( ) ) {
2019-05-19 22:13:13 +02:00
nodep - > v3warn ( IMPORTSTAR , " Import::* in $unit scope may pollute global namespace " ) ;
2018-11-29 00:25:34 +01:00
}
} else {
2019-05-19 22:13:13 +02:00
VSymEnt * impp = srcp - > findIdFlat ( nodep - > name ( ) ) ;
if ( ! impp ) {
2019-07-12 04:09:30 +02:00
nodep - > v3error ( " Import object not found: ' "
< < nodep - > packagep ( ) - > prettyName ( ) < < " :: " < < nodep - > prettyName ( ) < < " ' " ) ;
2019-05-19 22:13:13 +02:00
}
}
m_curSymp - > importFromPackage ( m_statep - > symsp ( ) , srcp , nodep - > name ( ) ) ;
UINFO ( 9 , " Link Done: " < < nodep < < endl ) ;
// No longer needed, but can't delete until any multi-instantiated modules are expanded
2006-08-26 13:35:28 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstPackageExport * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
UINFO ( 9 , " Link: " < < nodep < < endl ) ;
VSymEnt * srcp = m_statep - > getNodeSym ( nodep - > packagep ( ) ) ;
if ( nodep - > name ( ) ! = " * " ) {
VSymEnt * impp = srcp - > findIdFlat ( nodep - > name ( ) ) ;
if ( ! impp ) {
2019-07-12 04:09:30 +02:00
nodep - > v3error ( " Export object not found: ' "
< < nodep - > packagep ( ) - > prettyName ( ) < < " :: " < < nodep - > prettyName ( ) < < " ' " ) ;
2019-05-19 22:13:13 +02:00
}
}
m_curSymp - > exportFromPackage ( m_statep - > symsp ( ) , srcp , nodep - > name ( ) ) ;
UINFO ( 9 , " Link Done: " < < nodep < < endl ) ;
// No longer needed, but can't delete until any multi-instantiated modules are expanded
2017-09-21 03:04:59 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstPackageExportStarStar * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
UINFO ( 4 , " Link: " < < nodep < < endl ) ;
m_curSymp - > exportStarStar ( m_statep - > symsp ( ) ) ;
// No longer needed, but can't delete until any multi-instantiated modules are expanded
2017-09-21 03:04:59 +02:00
}
2006-08-26 13:35:28 +02:00
2020-01-21 23:35:56 +01:00
virtual void visit ( AstNode * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// Default: Just iterate
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2006-08-26 13:35:28 +02:00
}
public :
2019-09-12 13:22:22 +02:00
// CONSTRUCTORS
2006-08-26 13:35:28 +02:00
LinkDotFindVisitor ( AstNetlist * rootp , LinkDotState * statep ) {
2019-05-19 22:13:13 +02:00
UINFO ( 4 , __FUNCTION__ < < " : " < < endl ) ;
m_packagep = NULL ;
m_curSymp = m_modSymp = NULL ;
m_statep = statep ;
m_beginp = NULL ;
m_ftaskp = NULL ;
m_inGenerate = false ;
m_inRecursion = false ;
m_paramNum = 0 ;
m_beginNum = 0 ;
m_modBeginNum = 0 ;
//
2018-05-11 02:55:37 +02:00
iterate ( rootp ) ;
2006-08-26 13:35:28 +02:00
}
virtual ~ LinkDotFindVisitor ( ) { }
} ;
2012-07-21 23:12:42 +02:00
//======================================================================
class LinkDotParamVisitor : public AstNVisitor {
private :
// NODE STATE
// Cleared on global
2019-05-19 22:13:13 +02:00
// *::user1p() -> See LinkDotState
// *::user2p() -> See LinkDotState
// *::user4() -> See LinkDotState
2012-07-21 23:12:42 +02:00
// STATE
2019-05-19 22:13:13 +02:00
LinkDotState * m_statep ; // State to pass between visitors, including symbol table
AstNodeModule * m_modp ; // Current module
2012-07-21 23:12:42 +02:00
int debug ( ) { return LinkDotState : : debug ( ) ; }
void pinImplicitExprRecurse ( AstNode * nodep ) {
2019-05-19 22:13:13 +02:00
// Under a pin, Check interconnect expression for a pin reference or a concat.
// Create implicit variable as needed
2018-02-02 03:32:58 +01:00
if ( VN_IS ( nodep , Dot ) ) { // Not creating a simple implied type,
2019-05-19 22:13:13 +02:00
// and implying something else would just confuse later errors
}
2018-02-02 03:32:58 +01:00
else if ( VN_IS ( nodep , VarRef ) | | VN_IS ( nodep , ParseRef ) ) {
2019-05-19 22:13:13 +02: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.
m_statep - > implicitOkAdd ( m_modp , nodep - > name ( ) ) ;
}
// 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 ( ) ) ;
}
2012-07-21 23:12:42 +02:00
}
// VISITs
2020-01-21 23:35:56 +01:00
virtual void visit ( AstTypeTable * nodep ) VL_OVERRIDE { }
virtual void visit ( AstNodeModule * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
UINFO ( 5 , " " < < nodep < < endl ) ;
if ( nodep - > dead ( ) | | ! nodep - > user4 ( ) ) {
UINFO ( 4 , " Mark dead module " < < nodep < < endl ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( m_statep - > forPrearray ( ) , nodep ,
" Dead module persisted past where should have removed " ) ;
2019-05-19 22:13:13 +02:00
// 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 ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
m_modp = NULL ;
}
2012-07-21 23:12:42 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstPin * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// 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 ( ) ) ;
}
2012-07-21 23:12:42 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstDefParam * nodep ) VL_OVERRIDE {
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-07-15 02:59:56 +02:00
nodep - > v3warn ( DEFPARAM , " Suggest replace defparam assignment with Verilog 2001 #(. "
2019-05-19 22:13:13 +02:00
< < nodep - > prettyName ( ) < < " (...etc...)) " ) ;
VSymEnt * foundp = m_statep - > getNodeSym ( nodep ) - > findIdFallback ( nodep - > path ( ) ) ;
2018-02-02 03:32:58 +01:00
AstCell * cellp = foundp ? VN_CAST ( foundp - > nodep ( ) , Cell ) : NULL ;
2019-05-19 22:13:13 +02:00
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 ( )
< < " attach-to " < < cellp
< < " <= " < < exprp < < endl ) ;
// Don't need to check the name of the defparam exists. V3Param does.
2018-08-25 15:52:45 +02:00
AstPin * pinp = new AstPin ( nodep - > fileline ( ) ,
- 1 , // Pin# not relevant
nodep - > name ( ) ,
exprp ) ;
2019-05-19 22:13:13 +02:00
cellp - > addParamsp ( pinp ) ;
2020-01-17 02:17:11 +01:00
VL_DO_DANGLING ( nodep - > unlinkFrBack ( ) - > deleteTree ( ) , nodep ) ;
2019-05-19 22:13:13 +02:00
}
2012-07-21 23:12:42 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstPort * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// 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 ( ) ) ;
2018-02-02 03:32:58 +01:00
AstVar * refp = foundp ? VN_CAST ( foundp - > nodep ( ) , Var ) : NULL ;
2019-05-19 22:13:13 +02:00
if ( ! refp ) {
nodep - > v3error ( " Input/output/inout declaration not found for port: "
2019-07-12 04:09:30 +02:00
< < nodep - > prettyNameQ ( ) ) ;
2019-05-19 22:13:13 +02:00
} else if ( ! refp - > isIO ( ) & & ! refp - > isIfaceRef ( ) ) {
2019-07-12 04:09:30 +02:00
nodep - > v3error ( " Pin is not an in/out/inout/interface: " < < nodep - > prettyNameQ ( ) ) ;
2019-05-19 22:13:13 +02:00
} else {
2019-06-22 18:43:48 +02:00
if ( refp - > user4 ( ) ) {
2019-07-12 04:09:30 +02:00
nodep - > v3error ( " Duplicate declaration of port: " < < nodep - > prettyNameQ ( ) < < endl
2019-06-22 23:01:39 +02:00
< < nodep - > warnContextPrimary ( ) < < endl
2019-07-12 01:15:40 +02:00
< < refp - > warnOther ( ) < < " ... Location of original declaration \n "
2019-06-22 23:01:39 +02:00
< < refp - > warnContextSecondary ( ) ) ;
2019-06-22 18:43:48 +02:00
}
2019-05-19 22:13:13 +02:00
refp - > user4 ( true ) ;
VSymEnt * symp = m_statep - > insertSym ( m_statep - > getNodeSym ( m_modp ) ,
" __pinNumber " + cvtToStr ( nodep - > pinNum ( ) ) ,
refp , NULL /*packagep*/ ) ;
symp - > exported ( false ) ;
}
// Ports not needed any more
2020-01-17 02:17:11 +01:00
VL_DO_DANGLING ( nodep - > unlinkFrBack ( ) - > deleteTree ( ) , nodep ) ;
2012-07-21 23:12:42 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstAssignW * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// 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 ( ) ) ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2012-07-21 23:12:42 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstAssignAlias * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// tran gates need implicit creation
// As VarRefs don't exist in forPrimary, sanity check
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( ! m_statep - > forPrimary ( ) , nodep , " Assign aliases unexpected pre-dot " ) ;
2018-02-02 03:32:58 +01:00
if ( AstVarRef * forrefp = VN_CAST ( nodep - > lhsp ( ) , VarRef ) ) {
2019-05-19 22:13:13 +02:00
pinImplicitExprRecurse ( forrefp ) ;
}
2018-02-02 03:32:58 +01:00
if ( AstVarRef * forrefp = VN_CAST ( nodep - > rhsp ( ) , VarRef ) ) {
2019-05-19 22:13:13 +02:00
pinImplicitExprRecurse ( forrefp ) ;
}
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2012-07-21 23:12:42 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstImplicit * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// Unsupported gates need implicit creation
pinImplicitExprRecurse ( nodep ) ;
// We're done with implicit gates
2020-01-17 02:17:11 +01:00
VL_DO_DANGLING ( nodep - > unlinkFrBack ( ) - > deleteTree ( ) , nodep ) ;
2012-07-21 23:12:42 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstNode * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// Default: Just iterate
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2012-07-21 23:12:42 +02:00
}
public :
2019-09-12 13:22:22 +02:00
// CONSTRUCTORS
2012-07-21 23:12:42 +02:00
LinkDotParamVisitor ( AstNetlist * rootp , LinkDotState * statep ) {
2019-05-19 22:13:13 +02:00
UINFO ( 4 , __FUNCTION__ < < " : " < < endl ) ;
m_statep = statep ;
m_modp = NULL ;
//
2018-05-11 02:55:37 +02:00
iterate ( rootp ) ;
2012-07-21 23:12:42 +02:00
}
virtual ~ LinkDotParamVisitor ( ) { }
} ;
2006-08-26 13:35:28 +02:00
//======================================================================
class LinkDotScopeVisitor : public AstNVisitor {
2013-05-28 03:39:19 +02:00
2006-08-26 13:35:28 +02:00
// STATE
2019-05-19 22:13:13 +02:00
LinkDotState * m_statep ; // State to pass between visitors, including symbol table
AstScope * m_scopep ; // The current scope
VSymEnt * m_modSymp ; // Symbol entry for current module
2009-01-21 22:56:50 +01:00
2006-08-26 13:35:28 +02:00
int debug ( ) { return LinkDotState : : debug ( ) ; }
// VISITs
2020-01-21 23:35:56 +01:00
virtual void visit ( AstNetlist * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// Recurse..., backward as must do packages before using packages
2018-05-11 02:55:37 +02:00
iterateChildrenBackwards ( nodep ) ;
2012-07-21 23:12:42 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstScope * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
UINFO ( 8 , " SCOPE " < < nodep < < endl ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( m_statep - > forScopeCreation ( ) , nodep ,
" Scopes should only exist right after V3Scope " ) ;
2019-05-19 22:13:13 +02: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.
m_modSymp = m_statep - > getScopeSym ( nodep ) ;
m_scopep = nodep ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
m_modSymp = NULL ;
m_scopep = NULL ;
2006-08-26 13:35:28 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstVarScope * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
if ( ! nodep - > varp ( ) - > isFuncLocal ( ) ) {
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
= LinkDotState : : ifaceRefFromArray ( nodep - > varp ( ) - > dtypep ( ) ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( dtypep , nodep , " Non AstIfaceRefDType on isIfaceRef() var " ) ;
2019-05-19 22:13:13 +02:00
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 ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( cellSymp , nodep ,
2019-07-12 04:09:30 +02:00
" No symbol for interface cell: " < < nodep - > prettyNameQ ( ifcellname ) ) ;
2019-05-19 22:13:13 +02:00
UINFO ( 5 , " Found interface cell: se " < < cvtToHex ( cellSymp )
< < " " < < cellSymp - > nodep ( ) < < endl ) ;
if ( dtypep - > modportName ( ) ! = " " ) {
VSymEnt * mpSymp = m_statep - > findDotted ( m_modSymp , ifcellname , baddot , okSymp ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( mpSymp , nodep ,
" No symbol for interface modport: "
2019-07-12 04:09:30 +02:00
< < nodep - > prettyNameQ ( dtypep - > modportName ( ) ) ) ;
2019-07-06 18:57:50 +02:00
cellSymp = mpSymp ;
2019-05-19 22:13:13 +02:00
UINFO ( 5 , " Found modport cell: se "
< < cvtToHex ( 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.
m_statep - > insertScopeAlias ( LinkDotState : : SAMN_IFTOP , varSymp , cellSymp ) ;
}
}
2006-08-26 13:35:28 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstNodeFTask * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
VSymEnt * symp = m_statep - > insertBlock ( m_modSymp , nodep - > name ( ) , nodep , NULL ) ;
symp - > fallbackp ( m_modSymp ) ;
// No recursion, we don't want to pick up variables
2006-08-26 13:35:28 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstAssignAlias * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// Track aliases created by V3Inline; if we get a VARXREF(aliased_from)
// we'll need to replace it with a VARXREF(aliased_to)
2019-10-05 23:35:08 +02:00
if ( debug ( ) > = 9 ) nodep - > dumpTree ( cout , " - alias: " ) ;
2018-02-02 03:32:58 +01:00
AstVarScope * fromVscp = VN_CAST ( nodep - > lhsp ( ) , VarRef ) - > varScopep ( ) ;
AstVarScope * toVscp = VN_CAST ( nodep - > rhsp ( ) , VarRef ) - > varScopep ( ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( fromVscp & & toVscp , nodep , " Bad alias scopes " ) ;
2019-05-19 22:13:13 +02:00
fromVscp - > user2p ( toVscp ) ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2006-08-26 13:35:28 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstAssignVarScope * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
UINFO ( 5 , " ASSIGNVARSCOPE " < < nodep < < endl ) ;
2019-10-05 23:35:08 +02:00
if ( debug ( ) > = 9 ) nodep - > dumpTree ( cout , " - avs: " ) ;
2019-05-19 22:13:13 +02:00
VSymEnt * rhsSymp ;
{
2018-02-02 03:32:58 +01:00
AstVarRef * refp = VN_CAST ( nodep - > rhsp ( ) , VarRef ) ;
AstVarXRef * xrefp = VN_CAST ( nodep - > rhsp ( ) , VarXRef ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( refp | | xrefp , nodep ,
" Unsupported: Non Var(X)Ref attached to interface pin " ) ;
2019-05-19 22:13:13 +02:00
string inl = ( ( xrefp & & xrefp - > inlinedDots ( ) . size ( ) )
? ( xrefp - > inlinedDots ( ) + " __DOT__ " ) : " " ) ;
VSymEnt * symp = NULL ;
string scopename ;
while ( ! symp ) {
scopename = refp ? refp - > name ( ) : ( inl . size ( ) ? ( inl + xrefp - > name ( ) )
: xrefp - > name ( ) ) ;
string baddot ; VSymEnt * okSymp ;
symp = m_statep - > findDotted ( m_modSymp , scopename , baddot , okSymp ) ;
if ( inl = = " " )
break ;
inl = LinkDotState : : removeLastInlineScope ( inl ) ;
}
if ( ! symp ) UINFO ( 9 , " No symbol for interface alias rhs ( "
< < string ( refp ? " VARREF " : " VARXREF " ) < < scopename < < " ) " < < endl ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( symp , nodep , " No symbol for interface alias rhs " ) ;
2019-05-19 22:13:13 +02:00
UINFO ( 5 , " Found a linked scope RHS: " < < scopename < < " se "
< < cvtToHex ( symp ) < < " " < < symp - > nodep ( ) < < endl ) ;
rhsSymp = symp ;
}
VSymEnt * lhsSymp ;
{
2018-02-02 03:32:58 +01:00
const AstVarXRef * xrefp = VN_CAST ( nodep - > lhsp ( ) , VarXRef ) ;
const AstVarRef * refp = VN_CAST ( nodep - > lhsp ( ) , VarRef ) ;
2016-01-22 01:11:53 +01:00
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( refp | | xrefp , nodep ,
" Unsupported: Non Var(X)Ref attached to interface pin " ) ;
2019-05-19 22:13:13 +02:00
string scopename = refp ? refp - > varp ( ) - > name ( ) : xrefp - > dotted ( ) + " . " + xrefp - > name ( ) ;
string baddot ; VSymEnt * okSymp ;
VSymEnt * symp = m_statep - > findDotted ( m_modSymp , scopename , baddot , okSymp ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( symp , nodep , " No symbol for interface alias lhs " ) ;
2019-05-19 22:13:13 +02:00
UINFO ( 5 , " Found a linked scope LHS: " < < scopename
< < " se " < < cvtToHex ( 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
m_statep - > insertScopeAlias ( LinkDotState : : SAMN_IFTOP , lhsSymp , rhsSymp ) ;
// We have stored the link, we don't need these any more
2020-01-17 02:17:11 +01:00
VL_DO_DANGLING ( nodep - > unlinkFrBack ( ) - > deleteTree ( ) , nodep ) ;
2013-05-28 03:39:19 +02:00
}
2006-08-26 13:35:28 +02:00
// For speed, don't recurse things that can't have scope
2006-12-12 19:25:33 +01:00
// Note we allow AstNodeStmt's as generates may be under them
2020-01-21 23:35:56 +01:00
virtual void visit ( AstCell * ) VL_OVERRIDE { }
virtual void visit ( AstVar * ) VL_OVERRIDE { }
virtual void visit ( AstNodeMath * ) VL_OVERRIDE { }
virtual void visit ( AstNode * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// Default: Just iterate
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2006-08-26 13:35:28 +02:00
}
public :
2019-09-12 13:22:22 +02:00
// CONSTRUCTORS
2006-08-26 13:35:28 +02:00
LinkDotScopeVisitor ( AstNetlist * rootp , LinkDotState * statep ) {
2019-05-19 22:13:13 +02:00
UINFO ( 4 , __FUNCTION__ < < " : " < < endl ) ;
m_modSymp = NULL ;
m_scopep = NULL ;
m_statep = statep ;
//
2018-05-11 02:55:37 +02:00
iterate ( rootp ) ;
2006-08-26 13:35:28 +02:00
}
virtual ~ LinkDotScopeVisitor ( ) { }
} ;
//======================================================================
2013-05-28 03:39:19 +02:00
// Iterate an interface to resolve modports
class LinkDotIfaceVisitor : public AstNVisitor {
// STATE
2019-05-19 22:13:13 +02:00
LinkDotState * m_statep ; // State to pass between visitors, including symbol table
VSymEnt * m_curSymp ; // Symbol Entry for current table, where to lookup/insert
2013-05-28 03:39:19 +02:00
// METHODS
int debug ( ) { return LinkDotState : : debug ( ) ; }
// VISITs
2020-01-21 23:35:56 +01:00
virtual void visit ( AstModport * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// 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 ) ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
}
m_curSymp = oldCurSymp ;
2013-05-28 03:39:19 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstModportFTaskRef * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
UINFO ( 5 , " fif: " < < nodep < < endl ) ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
if ( nodep - > isExport ( ) ) nodep - > v3error ( " Unsupported: modport export " ) ;
VSymEnt * symp = m_curSymp - > findIdFallback ( nodep - > name ( ) ) ;
if ( ! symp ) {
2019-07-12 04:09:30 +02:00
nodep - > v3error ( " Modport item not found: " < < nodep - > prettyNameQ ( ) ) ;
2018-02-02 03:32:58 +01:00
} else if ( AstNodeFTask * ftaskp = VN_CAST ( symp - > nodep ( ) , NodeFTask ) ) {
2019-05-19 22:13:13 +02:00
// Make symbol under modport that points at the _interface_'s var, not the modport.
nodep - > ftaskp ( ftaskp ) ;
VSymEnt * subSymp = m_statep - > insertSym ( m_curSymp , nodep - > name ( ) ,
ftaskp , NULL /*package*/ ) ;
m_statep - > insertScopeAlias ( LinkDotState : : SAMN_MODPORT , subSymp , symp ) ;
} else {
2019-07-12 04:09:30 +02:00
nodep - > v3error ( " Modport item is not a function/task: " < < nodep - > prettyNameQ ( ) ) ;
2019-05-19 22:13:13 +02:00
}
if ( m_statep - > forScopeCreation ( ) ) {
// Done with AstModportFTaskRef.
// Delete to prevent problems if we dead-delete pointed to ftask
2020-01-17 02:17:11 +01:00
nodep - > unlinkFrBack ( ) ; VL_DO_DANGLING ( pushDeletep ( nodep ) , nodep ) ;
2019-05-19 22:13:13 +02:00
}
2013-12-21 12:51:15 +01:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstModportVarRef * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
UINFO ( 5 , " fiv: " < < nodep < < endl ) ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
VSymEnt * symp = m_curSymp - > findIdFallback ( nodep - > name ( ) ) ;
if ( ! symp ) {
2019-07-12 04:09:30 +02:00
nodep - > v3error ( " Modport item not found: " < < nodep - > prettyNameQ ( ) ) ;
2018-02-02 03:32:58 +01:00
} else if ( AstVar * varp = VN_CAST ( symp - > nodep ( ) , Var ) ) {
2019-05-19 22:13:13 +02:00
// Make symbol under modport that points at the _interface_'s var via the modport.
// (Need modport still to test input/output markings)
nodep - > varp ( varp ) ;
m_statep - > insertSym ( m_curSymp , nodep - > name ( ) , nodep , NULL /*package*/ ) ;
2018-02-02 03:32:58 +01:00
} else if ( AstVarScope * vscp = VN_CAST ( symp - > nodep ( ) , VarScope ) ) {
2019-05-19 22:13:13 +02:00
// 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 {
2019-07-12 04:09:30 +02:00
nodep - > v3error ( " Modport item is not a variable: " < < nodep - > prettyNameQ ( ) ) ;
2019-05-19 22:13:13 +02:00
}
if ( m_statep - > forScopeCreation ( ) ) {
// Done with AstModportVarRef.
// Delete to prevent problems if we dead-delete pointed to variable
2020-01-17 02:17:11 +01:00
nodep - > unlinkFrBack ( ) ; VL_DO_DANGLING ( pushDeletep ( nodep ) , nodep ) ;
2019-05-19 22:13:13 +02:00
}
2013-05-28 03:39:19 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstNode * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// Default: Just iterate
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2013-05-28 03:39:19 +02:00
}
public :
2019-09-12 13:22:22 +02:00
// CONSTRUCTORS
2013-05-28 03:39:19 +02:00
LinkDotIfaceVisitor ( AstIface * nodep , VSymEnt * curSymp , LinkDotState * statep ) {
2019-05-19 22:13:13 +02:00
UINFO ( 4 , __FUNCTION__ < < " : " < < endl ) ;
m_curSymp = curSymp ;
m_statep = statep ;
2018-05-11 02:55:37 +02:00
iterate ( nodep ) ;
2013-05-28 03:39:19 +02:00
}
virtual ~ LinkDotIfaceVisitor ( ) { }
} ;
void LinkDotState : : computeIfaceModSyms ( ) {
for ( IfaceModSyms : : iterator it = m_ifaceModSyms . begin ( ) ; it ! = m_ifaceModSyms . end ( ) ; + + it ) {
2019-05-19 22:13:13 +02:00
AstIface * nodep = it - > first ;
VSymEnt * symp = it - > second ;
LinkDotIfaceVisitor ( nodep , symp , this ) ;
2013-05-28 03:39:19 +02:00
}
m_ifaceModSyms . clear ( ) ;
}
//======================================================================
2006-08-26 13:35:28 +02:00
class LinkDotResolveVisitor : public AstNVisitor {
private :
2012-07-21 23:12:42 +02:00
// NODE STATE
// Cleared on global
2019-05-19 22:13:13 +02:00
// *::user1p() -> See LinkDotState
// *::user2p() -> See LinkDotState
// *::user3() // bool. Processed
// *::user4() -> See LinkDotState
2012-07-21 23:12:42 +02:00
// Cleared on Cell
2019-05-19 22:13:13 +02:00
// AstVar::user5() // bool. True if pin used in this cell
AstUser3InUse m_inuser3 ;
AstUser5InUse m_inuser5 ;
2012-07-21 23:12:42 +02:00
2012-07-24 12:26:35 +02:00
// TYPES
2019-05-19 22:13:13 +02: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 12:26:35 +02:00
2006-08-26 13:35:28 +02:00
// STATE
2019-05-19 22:13:13 +02:00
LinkDotState * m_statep ; // State, including dotted symbol table
VSymEnt * m_curSymp ; // SymEnt for current lookup point
VSymEnt * m_modSymp ; // SymEnt for current module
VSymEnt * m_pinSymp ; // SymEnt for pin lookups
AstCell * m_cellp ; // Current cell
AstNodeModule * m_modp ; // Current module
AstNodeFTask * m_ftaskp ; // Current function/task
int m_modportNum ; // Uniqueify modport numbers
2012-12-31 20:00:04 +01:00
struct DotStates {
2019-05-19 22:13:13 +02:00
DotPosition m_dotPos ; // Scope part of dotted resolution
VSymEnt * m_dotSymp ; // SymEnt for dotted AstParse lookup
AstDot * m_dotp ; // Current dot
bool m_unresolved ; // Unresolved, needs help from V3Param
AstNode * m_unlinkedScope ; // Unresolved scope, needs corresponding VarXRef
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 ( ) { }
void init ( VSymEnt * curSymp ) {
m_dotPos = DP_NONE ; m_dotSymp = curSymp ; m_dotp = NULL ;
m_dotErr = false ; m_dotText = " " ;
m_unresolved = false ; m_unlinkedScope = NULL ;
}
string ascii ( ) const {
static const char * const names [ ]
= { " NONE " , " PACKAGE " , " SCOPE " , " FINAL " , " MEMBER " } ;
2018-02-02 03:24:41 +01:00
std : : ostringstream sstr ;
2019-05-19 22:13:13 +02:00
sstr < < " ds= " < < names [ m_dotPos ] ;
2018-10-14 22:25:36 +02:00
sstr < < " dse " < < cvtToHex ( m_dotSymp ) ;
2019-05-19 22:13:13 +02:00
sstr < < " txt= " < < m_dotText ;
sstr < < " unr= " < < m_unresolved ;
return sstr . str ( ) ;
}
2012-12-31 20:00:04 +01:00
} m_ds ; // State to preserve across recursions
2009-01-21 22:56:50 +01:00
2006-08-26 13:35:28 +02:00
int debug ( ) { return LinkDotState : : debug ( ) ; }
2012-07-22 03:18:07 +02:00
// METHODS - Variables
2019-05-19 22:13:13 +02:00
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 ) ) {
2019-07-14 02:30:32 +02:00
string suggest = m_statep - > suggestSymFallback (
moduleSymp , nodep - > name ( ) , LinkNodeMatcherVar ( ) ) ;
2019-05-19 22:13:13 +02:00
nodep - > v3error ( " Signal definition not found, and implicit disabled with `default_nettype: "
2019-07-14 02:30:32 +02:00
< < nodep - > prettyNameQ ( ) < < endl
< < ( suggest . empty ( ) ? " " : nodep - > warnMore ( ) + suggest ) ) ;
}
// Bypass looking for suggestions if IMPLICIT is turned off
// as there could be thousands of these suppressed in large netlists
else if ( ! nodep - > fileline ( ) - > warnIsOff ( V3ErrorCode : : IMPLICIT ) ) {
string suggest = m_statep - > suggestSymFallback (
moduleSymp , nodep - > name ( ) , LinkNodeMatcherVar ( ) ) ;
2019-05-19 22:13:13 +02:00
nodep - > v3warn ( IMPLICIT , " Signal definition not found, creating implicitly: "
2019-07-14 02:30:32 +02:00
< < nodep - > prettyNameQ ( ) < < endl
< < ( suggest . empty ( ) ? " " : nodep - > warnMore ( ) + suggest ) ) ;
2019-05-19 22:13:13 +02:00
}
}
2018-08-25 15:52:45 +02:00
AstVar * newp = new AstVar ( nodep - > fileline ( ) , AstVarType : : WIRE ,
nodep - > name ( ) , VFlagLogicPacked ( ) , 1 ) ;
2019-05-19 22:13:13 +02:00
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-22 03:18:07 +02:00
}
2017-11-15 01:50:31 +01:00
AstVar * foundToVarp ( const VSymEnt * symp , AstNode * nodep , bool lvalue ) {
// Return a variable if possible, auto converting a modport to variable
if ( ! symp ) {
return NULL ;
2018-02-02 03:32:58 +01:00
} else if ( VN_IS ( symp - > nodep ( ) , Var ) ) {
return VN_CAST ( symp - > nodep ( ) , Var ) ;
} else if ( VN_IS ( symp - > nodep ( ) , ModportVarRef ) ) {
AstModportVarRef * snodep = VN_CAST ( symp - > nodep ( ) , ModportVarRef ) ;
2017-11-15 01:50:31 +01:00
AstVar * varp = snodep - > varp ( ) ;
2018-10-27 23:29:00 +02:00
if ( lvalue & & snodep - > direction ( ) . isReadOnly ( ) ) {
2019-07-12 04:09:30 +02:00
nodep - > v3error ( " Attempt to drive input-only modport: " < < nodep - > prettyNameQ ( ) ) ;
2019-05-19 22:13:13 +02:00
} // else other simulators don't warn about reading, and IEEE doesn't say illegal
2018-10-27 23:29:00 +02:00
return varp ;
2017-11-15 01:50:31 +01:00
} else {
return NULL ;
}
}
2012-07-23 04:48:39 +02:00
void taskFuncSwapCheck ( AstNodeFTaskRef * nodep ) {
2018-02-02 03:32:58 +01:00
if ( nodep - > taskp ( ) & & VN_IS ( nodep - > taskp ( ) , Task )
2019-05-19 22:13:13 +02:00
& & VN_IS ( nodep , FuncRef ) ) nodep - > v3error ( " Illegal call of a task as a function: "
2019-07-12 04:09:30 +02:00
< < nodep - > prettyNameQ ( ) ) ;
2012-07-23 04:48:39 +02:00
}
2012-12-31 23:05:13 +01:00
inline void checkNoDot ( AstNode * nodep ) {
2019-05-19 22:13:13 +02:00
if ( VL_UNLIKELY ( m_ds . m_dotPos ! = DP_NONE ) ) {
//UINFO(9,"ds="<<m_ds.ascii()<<endl);
2018-03-10 22:32:04 +01:00
nodep - > v3error ( " Syntax Error: Not expecting " < < nodep - > type ( ) < < " under a "
< < nodep - > backp ( ) - > type ( ) < < " in dotted expression " ) ;
2019-05-19 22:13:13 +02:00
m_ds . m_dotErr = true ;
}
}
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
2019-07-14 21:06:49 +02:00
= new AstIfaceRefDType ( fl , modportp - > fileline ( ) ,
cellp - > name ( ) , ifacep - > name ( ) , modportp - > name ( ) ) ;
2019-05-19 22:13:13 +02:00
idtypep - > cellp ( cellp ) ;
AstVar * varp = new AstVar ( fl , AstVarType : : IFACEREF , varName , VFlagChildDType ( ) , idtypep ) ;
varp - > isIfaceParent ( true ) ;
m_modp - > addStmtp ( varp ) ;
return varp ;
2013-05-28 03:39:19 +02:00
}
2016-03-13 02:54:52 +01:00
void markAndCheckPinDup ( AstNode * nodep , AstNode * refp , const char * whatp ) {
2019-05-19 22:13:13 +02:00
if ( refp - > user5p ( ) & & refp - > user5p ( ) ! = nodep ) {
2019-07-12 04:09:30 +02:00
nodep - > v3error ( " Duplicate " < < whatp < < " connection: " < < nodep - > prettyNameQ ( ) < < endl
2019-06-22 23:01:39 +02:00
< < nodep - > warnContextPrimary ( ) < < endl
2019-07-12 01:15:40 +02:00
< < refp - > user5p ( ) - > warnOther ( )
2019-06-22 23:01:39 +02:00
< < " ... Location of original " < < whatp < < " connection \n "
2019-07-15 02:59:56 +02:00
< < refp - > user5p ( ) - > warnContextSecondary ( ) ) ;
2019-05-19 22:13:13 +02:00
} else {
refp - > user5p ( nodep ) ;
}
2016-03-13 02:54:52 +01:00
}
2012-07-22 03:18:07 +02:00
2006-08-26 13:35:28 +02:00
// VISITs
2020-01-21 23:35:56 +01:00
virtual void visit ( AstNetlist * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// Recurse..., backward as must do packages before using packages
2018-05-11 02:55:37 +02:00
iterateChildrenBackwards ( nodep ) ;
2012-07-21 23:12:42 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstTypeTable * nodep ) VL_OVERRIDE { }
virtual void visit ( AstNodeModule * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
if ( nodep - > dead ( ) ) return ;
checkNoDot ( nodep ) ;
UINFO ( 8 , " " < < nodep < < endl ) ;
m_ds . init ( m_curSymp ) ;
m_ds . m_dotSymp = m_curSymp = m_modSymp = m_statep - > getNodeSym ( nodep ) ; // Until overridden by a SCOPE
m_cellp = NULL ;
m_modp = nodep ;
m_modportNum = 0 ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
m_modp = NULL ;
m_ds . m_dotSymp = m_curSymp = m_modSymp = NULL ;
2006-08-26 13:35:28 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstScope * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
UINFO ( 8 , " " < < nodep < < endl ) ;
VSymEnt * oldModSymp = m_modSymp ;
VSymEnt * oldCurSymp = m_curSymp ;
checkNoDot ( nodep ) ;
m_ds . m_dotSymp = m_curSymp = m_modSymp = m_statep - > getScopeSym ( nodep ) ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
m_ds . m_dotSymp = m_curSymp = m_modSymp = NULL ;
m_modSymp = oldModSymp ;
m_curSymp = oldCurSymp ;
2006-08-26 13:35:28 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstCellInline * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
checkNoDot ( nodep ) ;
2019-10-02 03:57:45 +02:00
if ( m_statep - > forScopeCreation ( ) & & ! v3Global . opt . vpi ( ) ) {
2020-01-17 02:17:11 +01:00
nodep - > unlinkFrBack ( ) ; VL_DO_DANGLING ( pushDeletep ( nodep ) , nodep ) ;
2019-05-19 22:13:13 +02:00
}
2006-08-26 13:35:28 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstCell * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// Cell: Recurse inside or cleanup not founds
checkNoDot ( nodep ) ;
m_cellp = nodep ;
AstNode : : user5ClearTree ( ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( nodep - > modp ( ) , nodep ,
" Cell has unlinked module " ) ; // V3LinkCell should have errored out
{
2018-02-02 03:32:58 +01:00
if ( VN_IS ( nodep - > modp ( ) , NotFoundModule ) ) {
2019-05-19 22:13:13 +02:00
// 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:"); }
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
m_pinSymp = NULL ;
}
}
m_cellp = NULL ;
// Parent module inherits child's publicity
// This is done bottom up in the LinkBotupVisitor stage
2012-07-21 23:12:42 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstPin * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// Pin: Link to submodule's port
checkNoDot ( nodep ) ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
if ( ! nodep - > modVarp ( ) ) {
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( m_pinSymp , nodep , " Pin not under cell? " ) ;
2019-05-19 22:13:13 +02:00
VSymEnt * foundp = m_pinSymp - > findIdFlat ( nodep - > name ( ) ) ;
const char * whatp = nodep - > param ( ) ? " parameter pin " : " pin " ;
if ( ! foundp ) {
2018-02-02 03:32:58 +01:00
if ( nodep - > name ( ) = = " __paramNumber1 " & & VN_IS ( m_cellp - > modp ( ) , Primitive ) ) {
2019-05-19 22:13:13 +02:00
// Primitive parameter is really a delay we can just ignore
2020-01-17 02:17:11 +01:00
VL_DO_DANGLING ( nodep - > unlinkFrBack ( ) - > deleteTree ( ) , nodep ) ;
2019-05-19 22:13:13 +02:00
return ;
}
2019-07-14 02:30:32 +02:00
string suggest
= ( nodep - > param ( )
? m_statep - > suggestSymFlat (
m_pinSymp , nodep - > name ( ) , LinkNodeMatcherVarParam ( ) )
: m_statep - > suggestSymFlat (
m_pinSymp , nodep - > name ( ) , LinkNodeMatcherVarIO ( ) ) ) ;
nodep - > v3error ( ucfirst ( whatp ) < < " not found: " < < nodep - > prettyNameQ ( ) < < endl
< < ( suggest . empty ( ) ? " " : nodep - > warnMore ( ) + suggest ) ) ;
2019-05-19 22:13:13 +02:00
}
2018-02-02 03:32:58 +01:00
else if ( AstVar * refp = VN_CAST ( foundp - > nodep ( ) , Var ) ) {
2019-05-19 22:13:13 +02:00
if ( ! refp - > isIO ( ) & & ! refp - > isParam ( ) & & ! refp - > isIfaceRef ( ) ) {
nodep - > v3error ( ucfirst ( whatp ) < < " is not an in/out/inout/param/interface: "
2019-07-12 04:09:30 +02:00
< < nodep - > prettyNameQ ( ) ) ;
2019-05-19 22:13:13 +02:00
} else {
nodep - > modVarp ( refp ) ;
markAndCheckPinDup ( nodep , refp , whatp ) ;
}
}
2018-02-02 03:32:58 +01:00
else if ( AstParamTypeDType * refp = VN_CAST ( foundp - > nodep ( ) , ParamTypeDType ) ) {
2019-05-19 22:13:13 +02:00
nodep - > modPTypep ( refp ) ;
markAndCheckPinDup ( nodep , refp , whatp ) ;
}
else {
2019-07-12 04:09:30 +02:00
nodep - > v3error ( ucfirst ( whatp ) < < " not found: " < < nodep - > prettyNameQ ( ) ) ;
2019-05-19 22:13:13 +02:00
}
}
// Early return() above when deleted
2012-07-21 23:12:42 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstDot * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02: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), ...
if ( nodep - > user3SetOnce ( ) ) return ;
UINFO ( 8 , " " < < nodep < < endl ) ;
DotStates lastStates = m_ds ;
bool start = ( m_ds . m_dotPos = = DP_NONE ) ; // Save, as m_dotp will be changed
{
if ( start ) { // Starting dot sequence
if ( debug ( ) > = 9 ) nodep - > dumpTree ( " -dot-in: " ) ;
m_ds . init ( m_curSymp ) ; // Start from current point
}
m_ds . m_dotp = nodep ; // Always, not just at start
m_ds . m_dotPos = DP_SCOPE ;
// m_ds.m_dotText communicates the cell prefix between stages
2018-02-02 03:32:58 +01:00
if ( VN_IS ( nodep - > lhsp ( ) , PackageRef ) ) {
2019-05-19 22:13:13 +02:00
//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 ;
2018-05-11 02:55:37 +02:00
iterateAndNextNull ( nodep - > lhsp ( ) ) ;
2019-05-19 22:13:13 +02:00
//if (debug()>=9) nodep->dumpTree("-dot-lho: ");
}
if ( m_ds . m_unresolved & & ( VN_IS ( nodep - > lhsp ( ) , CellRef )
| | VN_IS ( nodep - > lhsp ( ) , CellArrayRef ) ) ) {
m_ds . m_unlinkedScope = nodep - > lhsp ( ) ;
}
if ( ! m_ds . m_dotErr ) { // Once something wrong, give up
// Top 'final' dot RHS is final RHS, else it's a
// DOT(DOT(x,*here*),real-rhs) which we consider a RHS
if ( start & & m_ds . m_dotPos = = DP_SCOPE ) m_ds . m_dotPos = DP_FINAL ;
2018-05-11 02:55:37 +02:00
iterateAndNextNull ( nodep - > rhsp ( ) ) ;
2019-05-19 22:13:13 +02:00
//if (debug()>=9) nodep->dumpTree("-dot-rho: ");
}
if ( start ) {
AstNode * newp ;
if ( m_ds . m_dotErr ) {
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 ) ;
2020-01-17 02:17:11 +01:00
VL_DO_DANGLING ( pushDeletep ( nodep ) , nodep ) ;
2019-05-19 22:13:13 +02:00
} else { // Dot midpoint
AstNode * newp = nodep - > rhsp ( ) - > unlinkFrBack ( ) ;
if ( m_ds . m_unresolved ) {
AstCellRef * crp = new AstCellRef ( nodep - > fileline ( ) , nodep - > name ( ) ,
nodep - > lhsp ( ) - > unlinkFrBack ( ) , newp ) ;
newp = crp ;
}
nodep - > replaceWith ( newp ) ;
2020-01-17 02:17:11 +01:00
VL_DO_DANGLING ( pushDeletep ( nodep ) , nodep ) ;
2019-05-19 22:13:13 +02:00
}
}
if ( start ) {
m_ds = lastStates ;
} else {
m_ds . m_dotp = lastStates . m_dotp ;
}
2012-07-24 12:26:35 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstParseRef * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
if ( nodep - > user3SetOnce ( ) ) return ;
UINFO ( 9 , " linkPARSEREF " < < m_ds . ascii ( ) < < " n= " < < nodep < < endl ) ;
// m_curSymp is symbol table of outer expression
// m_ds.m_dotSymp is symbol table relative to "."'s above now
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( m_ds . m_dotSymp , nodep , " NULL lookup symbol table " ) ;
2019-12-05 01:25:45 +01:00
// Generally resolved during Primay, but might be at param time under AstUnlinkedRef
UASSERT_OBJ ( m_statep - > forPrimary ( ) | | m_statep - > forPrearray ( ) ,
nodep , " ParseRefs should no longer exist " ) ;
2019-05-19 22:13:13 +02:00
DotStates lastStates = m_ds ;
bool start = ( m_ds . m_dotPos = = DP_NONE ) ; // Save, as m_dotp will be changed
if ( start ) {
m_ds . init ( m_curSymp ) ;
// Note m_ds.m_dot remains NULL; this is a reference not under a dot
}
if ( m_ds . m_dotPos = = DP_MEMBER ) {
// Found a Var, everything following is membership. {scope}.{var}.HERE {member}
AstNode * varEtcp = m_ds . m_dotp - > lhsp ( ) - > unlinkFrBack ( ) ;
AstNode * newp = new AstMemberSel ( nodep - > fileline ( ) , varEtcp ,
VFlagChildDType ( ) , nodep - > name ( ) ) ;
2019-11-20 01:23:40 +01:00
if ( m_ds . m_dotErr ) nodep - > unlinkFrBack ( ) ; // Avoid circular node loop on errors
else nodep - > replaceWith ( newp ) ;
2020-01-17 02:17:11 +01:00
VL_DO_DANGLING ( pushDeletep ( nodep ) , nodep ) ;
2019-05-19 22:13:13 +02:00
}
else {
//
string expectWhat ;
bool allowScope = false ;
bool allowVar = false ;
if ( m_ds . m_dotPos = = DP_PACKAGE ) {
// {package}::{a}
AstPackage * packagep = NULL ;
expectWhat = " scope/variable " ;
allowScope = true ;
allowVar = true ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( VN_IS ( m_ds . m_dotp - > lhsp ( ) , PackageRef ) ,
m_ds . m_dotp - > lhsp ( ) , " Bad package link " ) ;
2018-02-02 03:32:58 +01:00
packagep = VN_CAST ( m_ds . m_dotp - > lhsp ( ) , PackageRef ) - > packagep ( ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( packagep , m_ds . m_dotp - > lhsp ( ) , " Bad package link " ) ;
2019-05-19 22:13:13 +02:00
m_ds . m_dotSymp = m_statep - > getNodeSym ( packagep ) ;
m_ds . m_dotPos = DP_SCOPE ;
} else if ( m_ds . m_dotPos = = DP_SCOPE ) {
// {a}.{b}, where {a} maybe a module name
// or variable, where dotting into structure member
expectWhat = " scope/variable " ;
allowScope = true ;
allowVar = true ;
} else if ( m_ds . m_dotPos = = DP_NONE
| | m_ds . m_dotPos = = DP_FINAL ) {
expectWhat = " variable " ;
allowVar = true ;
} else {
UINFO ( 1 , " ds= " < < m_ds . ascii ( ) < < endl ) ;
2019-10-05 13:54:14 +02:00
nodep - > v3fatalSrc ( " Unhandled VParseRefExp " ) ;
2019-05-19 22:13:13 +02:00
}
// Lookup
VSymEnt * foundp ;
string baddot ;
VSymEnt * okSymp = NULL ;
if ( allowScope ) {
foundp = m_statep - > findDotted ( m_ds . m_dotSymp ,
nodep - > name ( ) , baddot , okSymp ) ; // Maybe NULL
} else {
foundp = m_ds . m_dotSymp - > findIdFallback ( nodep - > name ( ) ) ;
}
2018-10-14 22:25:36 +02:00
if ( foundp ) UINFO ( 9 , " found=se " < < cvtToHex ( foundp ) < < " exp= " < < expectWhat
2019-05-19 22:13:13 +02:00
< < " n= " < < foundp - > nodep ( ) < < endl ) ;
// What fell out?
bool ok = false ;
if ( ! foundp ) {
2018-02-02 03:32:58 +01:00
} else if ( VN_IS ( foundp - > nodep ( ) , Cell )
| | VN_IS ( foundp - > nodep ( ) , Begin )
| | VN_IS ( foundp - > nodep ( ) , Module ) ) { // if top
2019-05-19 22:13:13 +02:00
if ( allowScope ) {
ok = true ;
2018-03-16 00:46:05 +01:00
m_ds . m_dotText = VString : : dot ( m_ds . m_dotText , " . " , nodep - > name ( ) ) ;
2019-05-19 22:13:13 +02:00
m_ds . m_dotSymp = foundp ;
m_ds . m_dotPos = DP_SCOPE ;
// Upper AstDot visitor will handle it from here
}
2018-02-02 03:32:58 +01:00
else if ( VN_IS ( foundp - > nodep ( ) , Cell )
2019-05-19 22:13:13 +02:00
& & allowVar & & m_cellp ) {
2018-02-02 03:32:58 +01:00
AstCell * cellp = VN_CAST ( foundp - > nodep ( ) , Cell ) ;
if ( VN_IS ( cellp - > modp ( ) , Iface ) ) {
2017-03-17 23:35:53 +01:00
// Interfaces can be referenced like a variable for interconnect
2018-03-10 22:32:04 +01:00
VSymEnt * cellEntp = m_statep - > getNodeSym ( cellp ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( cellEntp , nodep , " No interface sym entry " ) ;
2017-03-17 23:35:53 +01:00
VSymEnt * parentEntp = cellEntp - > parentp ( ) ; // Container of the var; probably a module or generate begin
string findName = nodep - > name ( ) + " __Viftop " ;
VSymEnt * ifaceSymp = parentEntp - > findIdFallback ( findName ) ;
2018-02-02 03:32:58 +01:00
AstVar * ifaceRefVarp = ifaceSymp ? VN_CAST ( ifaceSymp - > nodep ( ) , Var ) : NULL ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( ifaceRefVarp , nodep ,
" Can't find interface var ref: " < < findName ) ;
2017-03-17 23:35:53 +01:00
//
ok = true ;
2018-03-16 00:46:05 +01:00
m_ds . m_dotText = VString : : dot ( m_ds . m_dotText , " . " , nodep - > name ( ) ) ;
2017-03-17 23:35:53 +01:00
m_ds . m_dotSymp = foundp ;
m_ds . m_dotPos = DP_SCOPE ;
UINFO ( 9 , " cell -> iface varref " < < foundp - > nodep ( ) < < endl ) ;
2019-05-19 22:13:13 +02:00
AstNode * newp = new AstVarRef ( ifaceRefVarp - > fileline ( ) ,
ifaceRefVarp , false ) ;
2020-01-17 02:17:11 +01:00
nodep - > replaceWith ( newp ) ; VL_DO_DANGLING ( pushDeletep ( nodep ) , nodep ) ;
2018-02-02 03:32:58 +01:00
} else if ( VN_IS ( cellp - > modp ( ) , NotFoundModule ) ) {
2019-07-14 21:06:49 +02:00
cellp - > modNameFileline ( ) - > v3error ( " Cannot find file containing interface: "
< < cellp - > modp ( ) - > prettyNameQ ( ) ) ;
2017-03-17 23:35:53 +01:00
}
}
2019-05-19 22:13:13 +02:00
}
else if ( AstVar * varp = foundToVarp ( foundp , nodep , false ) ) {
AstIfaceRefDType * ifacerefp = LinkDotState : : ifaceRefFromArray ( varp - > subDTypep ( ) ) ;
if ( ifacerefp ) {
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( ifacerefp - > ifaceViaCellp ( ) , ifacerefp , " Unlinked interface " ) ;
2019-05-19 22:13:13 +02:00
// Really this is a scope reference into an interface
UINFO ( 9 , " varref-ifaceref " < < m_ds . m_dotText < < " " < < nodep < < endl ) ;
2018-03-16 00:46:05 +01:00
m_ds . m_dotText = VString : : dot ( m_ds . m_dotText , " . " , nodep - > name ( ) ) ;
2019-05-19 22:13:13 +02:00
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 ) ;
2020-01-17 02:17:11 +01:00
nodep - > replaceWith ( newp ) ; VL_DO_DANGLING ( pushDeletep ( nodep ) , nodep ) ;
2019-05-19 22:13:13 +02:00
}
else if ( allowVar ) {
AstNode * newp ;
if ( m_ds . m_dotText ! = " " ) {
AstVarXRef * refp = new AstVarXRef ( nodep - > fileline ( ) , nodep - > name ( ) ,
m_ds . m_dotText , false ) ; // lvalue'ness computed later
refp - > varp ( varp ) ;
m_ds . m_dotText = " " ;
if ( m_ds . m_unresolved & & m_ds . m_unlinkedScope ) {
2018-02-02 03:32:58 +01:00
newp = new AstUnlinkedRef ( nodep - > fileline ( ) , VN_CAST ( refp , VarXRef ) ,
2019-05-19 22:13:13 +02:00
refp - > name ( ) ,
m_ds . m_unlinkedScope - > unlinkFrBack ( ) ) ;
m_ds . m_unlinkedScope = NULL ;
m_ds . m_unresolved = false ;
} else {
newp = refp ;
}
} else {
AstVarRef * refp = new AstVarRef ( nodep - > fileline ( ) , varp , false ) ; // lvalue'ness computed later
refp - > packagep ( foundp - > packagep ( ) ) ;
newp = refp ;
}
UINFO ( 9 , " new " < < newp < < endl ) ;
2020-01-17 02:17:11 +01:00
nodep - > replaceWith ( newp ) ; VL_DO_DANGLING ( pushDeletep ( nodep ) , nodep ) ;
2019-05-19 22:13:13 +02:00
m_ds . m_dotPos = DP_MEMBER ;
ok = true ;
}
}
2018-02-02 03:32:58 +01:00
else if ( AstModport * modportp = VN_CAST ( foundp - > nodep ( ) , Modport ) ) {
2019-05-19 22:13:13 +02:00
// 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
2018-02-02 03:32:58 +01:00
| | ! VN_IS ( m_ds . m_dotSymp - > nodep ( ) , Cell )
| | ! VN_CAST ( m_ds . m_dotSymp - > nodep ( ) , Cell ) - > modp ( )
| | ! VN_IS ( VN_CAST ( m_ds . m_dotSymp - > nodep ( ) , Cell ) - > modp ( ) , Iface ) ) {
2019-05-19 22:13:13 +02:00
nodep - > v3error ( " Modport not referenced as <interface>. "
2019-07-12 04:09:30 +02:00
< < modportp - > prettyNameQ ( ) ) ;
2018-02-02 03:32:58 +01:00
} else if ( ! VN_CAST ( m_ds . m_dotSymp - > nodep ( ) , Cell ) - > modp ( )
| | ! VN_IS ( VN_CAST ( m_ds . m_dotSymp - > nodep ( ) , Cell ) - > modp ( ) , Iface ) ) {
2019-05-19 22:13:13 +02:00
nodep - > v3error ( " Modport not referenced from underneath an interface: "
2019-07-12 04:09:30 +02:00
< < modportp - > prettyNameQ ( ) ) ;
2019-05-19 22:13:13 +02:00
} else {
2018-02-02 03:32:58 +01:00
AstCell * cellp = VN_CAST ( m_ds . m_dotSymp - > nodep ( ) , Cell ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( cellp , nodep , " Modport not referenced from a cell " ) ;
2018-02-02 03:32:58 +01:00
AstIface * ifacep = VN_CAST ( cellp - > modp ( ) , Iface ) ;
2019-05-19 22:13:13 +02:00
//string cellName = m_ds.m_dotText; // Use cellp->name
2018-03-16 00:46:05 +01:00
m_ds . m_dotText = VString : : dot ( m_ds . m_dotText , " . " , nodep - > name ( ) ) ;
2019-05-19 22:13:13 +02:00
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 ) ;
2020-01-17 02:17:11 +01:00
nodep - > replaceWith ( refp ) ; VL_DO_DANGLING ( pushDeletep ( nodep ) , nodep ) ;
2019-05-19 22:13:13 +02:00
}
}
2018-02-02 03:32:58 +01:00
else if ( AstEnumItem * valuep = VN_CAST ( foundp - > nodep ( ) , EnumItem ) ) {
2019-05-19 22:13:13 +02:00
if ( allowVar ) {
AstNode * newp = new AstEnumItemRef ( nodep - > fileline ( ) ,
valuep , foundp - > packagep ( ) ) ;
2020-01-17 02:17:11 +01:00
nodep - > replaceWith ( newp ) ; VL_DO_DANGLING ( pushDeletep ( nodep ) , nodep ) ;
2019-05-19 22:13:13 +02:00
ok = true ;
m_ds . m_dotText = " " ;
}
}
//
if ( ! ok ) {
2017-04-28 12:10:14 +02:00
// Cells/interfaces can't be implicit
2018-02-02 03:32:58 +01:00
bool isCell = foundp ? VN_IS ( foundp - > nodep ( ) , Cell ) : false ;
2019-05-19 22:13:13 +02:00
bool checkImplicit = ( ! m_ds . m_dotp & & m_ds . m_dotText = = " " & & ! isCell ) ;
bool err = ! ( checkImplicit & & m_statep - > implicitOk ( m_modp , nodep - > name ( ) ) ) ;
if ( err ) {
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 " < < expectWhat ) ;
} else if ( m_ds . m_dotText = = " " ) {
UINFO ( 7 , " ErrParseRef curSymp=se " < < cvtToHex ( m_curSymp )
< < " ds= " < < m_ds . ascii ( ) < < endl ) ;
2019-07-14 02:30:32 +02:00
string suggest = m_statep - > suggestSymFallback (
m_ds . m_dotSymp , nodep - > name ( ) , VNodeMatcher ( ) ) ;
2019-05-19 22:13:13 +02:00
nodep - > v3error ( " Can't find definition of " < < expectWhat
2019-07-14 02:30:32 +02:00
< < " : " < < nodep - > prettyNameQ ( ) < < endl
< < ( suggest . empty ( ) ? " " : nodep - > warnMore ( ) + suggest ) ) ;
2019-05-19 22:13:13 +02:00
} else {
2019-11-05 03:16:07 +01:00
nodep - > v3error ( " Can't find definition of "
< < ( ! baddot . empty ( ) ? AstNode : : prettyNameQ ( baddot )
: nodep - > prettyNameQ ( ) )
< < " in dotted " < < expectWhat
2019-07-12 04:09:30 +02:00
< < " : ' " < < m_ds . m_dotText + " . " + nodep - > prettyName ( ) < < " ' " ) ;
2019-10-31 02:49:25 +01:00
if ( okSymp ) {
okSymp - > cellErrorScopes ( nodep , AstNode : : prettyName ( m_ds . m_dotText ) ) ;
}
2019-05-19 22:13:13 +02:00
}
m_ds . m_dotErr = true ;
}
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 ) ;
2020-01-17 02:17:11 +01:00
VL_DO_DANGLING ( pushDeletep ( nodep ) , nodep ) ;
2018-08-25 15:52:45 +02:00
createImplicitVar ( m_curSymp , newp , m_modp , m_modSymp , err ) ;
2019-05-19 22:13:13 +02:00
}
}
}
if ( start ) {
m_ds = lastStates ;
}
2012-07-24 12:26:35 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstVarRef * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// VarRef: Resolve its reference
// ParseRefs are used the first pass (forPrimary) so we shouldn't get can't find
// errors here now that we have a VarRef.
// No checkNoDot; created and iterated from a parseRef
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
if ( ! nodep - > varp ( ) ) {
2018-10-14 22:25:36 +02:00
UINFO ( 9 , " linkVarRef se " < < cvtToHex ( m_curSymp ) < < " n= " < < nodep < < endl ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( m_curSymp , nodep , " NULL lookup symbol table " ) ;
2019-05-19 22:13:13 +02:00
VSymEnt * foundp = m_curSymp - > findIdFallback ( nodep - > name ( ) ) ;
if ( AstVar * varp = foundp ? foundToVarp ( foundp , nodep , nodep - > lvalue ( ) ) : NULL ) {
nodep - > varp ( varp ) ;
nodep - > packagep ( foundp - > packagep ( ) ) ; // Generally set by parse, but might be an import
}
if ( ! nodep - > varp ( ) ) {
2019-07-12 04:09:30 +02:00
nodep - > v3error ( " Can't find definition of signal, again: " < < nodep - > prettyNameQ ( ) ) ;
2019-05-19 22:13:13 +02:00
}
}
2012-07-21 23:12:42 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstVarXRef * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// 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.
if ( nodep - > user3SetOnce ( ) ) return ;
UINFO ( 8 , " " < < nodep < < endl ) ;
// No checkNoDot; created and iterated from a parseRef
if ( ! m_modSymp ) {
UINFO ( 9 , " Dead module for " < < nodep < < endl ) ;
nodep - > varp ( NULL ) ; // Module that is not in hierarchy. We'll be dead code eliminating it later.
} else {
string baddot ;
VSymEnt * okSymp ;
VSymEnt * dotSymp = m_curSymp ; // Start search at current scope
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 ( ) ) ;
dotSymp = m_statep - > findDotted ( dotSymp , inl , baddot , okSymp ) ;
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( dotSymp , nodep ,
2019-11-05 03:16:07 +01:00
" Couldn't resolve inlined scope "
< < AstNode : : prettyNameQ ( baddot ) < < " in: " < < nodep - > inlinedDots ( ) ) ;
2019-05-19 22:13:13 +02:00
}
dotSymp = m_statep - > findDotted ( dotSymp , nodep - > dotted ( ) , baddot , okSymp ) ; // Maybe NULL
if ( ! m_statep - > forScopeCreation ( ) ) {
VSymEnt * foundp = m_statep - > findSymPrefixed ( dotSymp , nodep - > name ( ) , baddot ) ;
AstVar * varp = foundp ? foundToVarp ( foundp , nodep , nodep - > lvalue ( ) ) : NULL ;
nodep - > varp ( varp ) ;
UINFO ( 7 , " Resolved " < < nodep < < endl ) ; // Also prints varp
if ( ! nodep - > varp ( ) ) {
2019-11-05 03:16:07 +01:00
nodep - > v3error ( " Can't find definition of "
< < AstNode : : prettyNameQ ( baddot ) < < " in dotted signal: ' "
2019-07-12 04:09:30 +02:00
< < nodep - > dotted ( ) + " . " + nodep - > prettyName ( ) < < " ' " ) ;
2019-05-19 22:13:13 +02:00
okSymp - > cellErrorScopes ( nodep ) ;
2019-11-05 03:16:07 +01:00
return ;
2019-05-19 22:13:13 +02:00
}
// V3Inst may have expanded arrays of interfaces to
// AstVarXRef's even though they are in the same module detect
// this and convert to normal VarRefs
if ( ! m_statep - > forPrearray ( ) & & ! m_statep - > forScopeCreation ( ) ) {
2018-02-02 03:32:58 +01:00
if ( VN_IS ( nodep - > dtypep ( ) , IfaceRefDType ) ) {
2019-05-19 22:13:13 +02:00
AstVarRef * newrefp = new AstVarRef ( nodep - > fileline ( ) ,
nodep - > varp ( ) , nodep - > lvalue ( ) ) ;
nodep - > replaceWith ( newrefp ) ;
2020-01-17 02:17:11 +01:00
VL_DO_DANGLING ( nodep - > deleteTree ( ) , nodep ) ;
2019-05-19 22:13:13 +02:00
}
}
} else {
string baddot ;
VSymEnt * foundp = m_statep - > findSymPrefixed ( dotSymp , nodep - > name ( ) , baddot ) ;
2018-02-02 03:32:58 +01:00
AstVarScope * vscp = foundp ? VN_CAST ( foundp - > nodep ( ) , VarScope ) : NULL ;
2019-05-19 22:13:13 +02:00
if ( ! vscp ) {
2019-11-05 03:16:07 +01:00
nodep - > v3error ( " Can't find varpin scope of "
< < AstNode : : prettyNameQ ( baddot )
< < " in dotted signal: ' "
2019-07-12 04:09:30 +02:00
< < nodep - > dotted ( ) + " . " + nodep - > prettyName ( ) < < " ' " ) ;
2019-05-19 22:13:13 +02:00
okSymp - > cellErrorScopes ( nodep ) ;
} else {
while ( vscp - > user2p ( ) ) { // If V3Inline aliased it, pick up the new signal
UINFO ( 7 , " Resolved pre-alias " < < vscp < < endl ) ; // Also prints taskp
2018-02-02 03:32:58 +01:00
vscp = VN_CAST ( vscp - > user2p ( ) , VarScope ) ;
2019-05-19 22:13:13 +02:00
}
// 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 ) ;
2020-01-17 02:17:11 +01:00
VL_DO_DANGLING ( nodep - > deleteTree ( ) , nodep ) ;
2019-05-19 22:13:13 +02:00
UINFO ( 9 , " new " < < newvscp < < endl ) ; // Also prints taskp
}
}
}
2006-08-26 13:35:28 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstEnumItemRef * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// EnumItemRef may be under a dot. Should already be resolved.
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2013-02-02 20:11:50 +01:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstMethodCall * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// Created here so should already be resolved.
DotStates lastStates = m_ds ;
{
m_ds . init ( m_curSymp ) ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
}
m_ds = lastStates ;
2014-11-29 02:34:23 +01:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstVar * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
checkNoDot ( nodep ) ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
if ( m_statep - > forPrimary ( ) & & nodep - > isIO ( ) & & ! m_ftaskp & & ! nodep - > user4 ( ) ) {
nodep - > v3error ( " Input/output/inout does not appear in port list: "
2019-07-12 04:09:30 +02:00
< < nodep - > prettyNameQ ( ) ) ;
2019-05-19 22:13:13 +02:00
}
2012-07-21 23:12:42 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstNodeFTaskRef * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
if ( nodep - > user3SetOnce ( ) ) return ;
UINFO ( 8 , " " < < nodep < < endl ) ;
if ( m_ds . m_dotp & & m_ds . m_dotPos = = DP_PACKAGE ) {
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( VN_IS ( m_ds . m_dotp - > lhsp ( ) , PackageRef ) ,
m_ds . m_dotp - > lhsp ( ) , " Bad package link " ) ;
UASSERT_OBJ ( VN_CAST ( m_ds . m_dotp - > lhsp ( ) , PackageRef ) - > packagep ( ) ,
m_ds . m_dotp - > lhsp ( ) , " Bad package link " ) ;
2018-02-02 03:32:58 +01:00
nodep - > packagep ( VN_CAST ( m_ds . m_dotp - > lhsp ( ) , PackageRef ) - > packagep ( ) ) ;
2019-05-19 22:13:13 +02:00
m_ds . m_dotPos = DP_SCOPE ;
m_ds . m_dotp = NULL ;
} else if ( m_ds . m_dotp & & m_ds . m_dotPos = = DP_FINAL ) {
if ( m_ds . m_unresolved & & m_ds . m_unlinkedScope ) {
AstNodeFTaskRef * newftaskp = nodep - > cloneTree ( false ) ;
newftaskp - > dotted ( m_ds . m_dotText ) ;
AstNode * newp = new AstUnlinkedRef ( nodep - > fileline ( ) , newftaskp ,
nodep - > name ( ) ,
m_ds . m_unlinkedScope - > unlinkFrBack ( ) ) ;
m_ds . m_unlinkedScope = NULL ;
m_ds . m_unresolved = false ;
nodep - > replaceWith ( newp ) ;
return ;
} else {
nodep - > dotted ( m_ds . m_dotText ) ; // Maybe ""
}
} 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 ( ) ;
2019-11-17 14:51:25 +01:00
AstNode * newp = new AstMethodCall ( nodep - > fileline ( ) , varEtcp ,
VFlagChildDType ( ) , nodep - > name ( ) , argsp ) ;
2019-05-19 22:13:13 +02:00
nodep - > replaceWith ( newp ) ;
2020-01-17 02:17:11 +01:00
VL_DO_DANGLING ( pushDeletep ( nodep ) , nodep ) ;
2019-05-19 22:13:13 +02:00
return ;
} else {
checkNoDot ( nodep ) ;
}
if ( nodep - > packagep ( ) & & nodep - > taskp ( ) ) {
// References into packages don't care about cell hierarchy.
} else if ( ! m_modSymp ) {
UINFO ( 9 , " Dead module for " < < nodep < < endl ) ;
nodep - > taskp ( NULL ) ; // Module that is not in hierarchy. We'll be dead code eliminating it later.
} else if ( nodep - > dotted ( ) = = " " & & nodep - > taskp ( ) ) {
// Earlier should have setup the links
// Might be under a BEGIN we're not processing, so don't relink it
} else {
string baddot ;
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 ( ) ) ;
2019-10-05 23:35:08 +02:00
UINFO ( 8 , " Inlined " < < inl < < endl ) ;
2019-05-19 22:13:13 +02:00
dotSymp = m_statep - > findDotted ( dotSymp , inl , baddot , okSymp ) ;
if ( ! dotSymp ) {
okSymp - > cellErrorScopes ( nodep ) ;
2019-11-05 03:16:07 +01:00
nodep - > v3fatalSrc ( " Couldn't resolve inlined scope "
< < AstNode : : prettyNameQ ( baddot )
< < " in: " < < nodep - > inlinedDots ( ) ) ;
2019-05-19 22:13:13 +02:00
}
}
dotSymp = m_statep - > findDotted ( dotSymp , nodep - > dotted ( ) ,
baddot , okSymp ) ; // Maybe NULL
}
2018-02-08 02:29:58 +01:00
VSymEnt * foundp = m_statep - > findSymPrefixed ( dotSymp , nodep - > name ( ) , baddot ) ;
2018-02-27 13:24:31 +01:00
AstNodeFTask * taskp = foundp ? VN_CAST ( foundp - > nodep ( ) , NodeFTask ) : NULL ; // Maybe NULL
2019-05-19 22:13:13 +02:00
if ( taskp ) {
nodep - > taskp ( taskp ) ;
nodep - > packagep ( foundp - > packagep ( ) ) ;
UINFO ( 7 , " Resolved " < < nodep < < endl ) ; // Also prints taskp
} else {
// Note ParseRef has similar error handling/message output
2018-10-14 22:25:36 +02:00
UINFO ( 7 , " ErrFtask curSymp=se " < < cvtToHex ( m_curSymp )
< < " dotSymp=se " < < cvtToHex ( dotSymp ) < < endl ) ;
2019-05-19 22:13:13 +02: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 ( ) = = " " ) {
2019-07-14 02:30:32 +02:00
string suggest = m_statep - > suggestSymFallback (
dotSymp , nodep - > name ( ) , LinkNodeMatcherFTask ( ) ) ;
2019-05-19 22:13:13 +02:00
nodep - > v3error ( " Can't find definition of task/function: "
2019-07-14 02:30:32 +02:00
< < nodep - > prettyNameQ ( ) < < endl
< < ( suggest . empty ( ) ? " " : nodep - > warnMore ( ) + suggest ) ) ;
2019-05-19 22:13:13 +02:00
} else {
2019-07-14 02:30:32 +02:00
string suggest = m_statep - > suggestSymFallback (
dotSymp , nodep - > name ( ) , LinkNodeMatcherFTask ( ) ) ;
2019-11-05 03:16:07 +01:00
nodep - > v3error ( " Can't find definition of "
< < AstNode : : prettyNameQ ( baddot )
< < " in dotted task/function: ' "
2019-07-14 02:30:32 +02:00
< < nodep - > dotted ( ) + " . " + nodep - > prettyName ( ) < < " ' \n "
< < ( suggest . empty ( ) ? " " : nodep - > warnMore ( ) + suggest ) ) ;
2019-05-19 22:13:13 +02:00
okSymp - > cellErrorScopes ( nodep ) ;
}
}
taskFuncSwapCheck ( nodep ) ;
}
DotStates lastStates = m_ds ;
{
m_ds . init ( m_curSymp ) ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
}
m_ds = lastStates ;
2012-07-21 23:12:42 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstSelBit * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
if ( nodep - > user3SetOnce ( ) ) return ;
2018-05-11 02:55:37 +02:00
iterateAndNextNull ( nodep - > lhsp ( ) ) ;
2019-05-19 22:13:13 +02:00
if ( m_ds . m_dotPos = = DP_SCOPE ) { // Already under dot, so this is {modulepart} DOT {modulepart}
UINFO ( 9 , " deferring until after a V3Param pass: " < < nodep < < endl ) ;
m_ds . m_dotText + = " __BRA__??__KET__ " ;
m_ds . m_unresolved = true ;
// And pass up m_ds.m_dotText
}
// Pass dot state down to fromp()
2018-05-11 02:55:37 +02:00
iterateAndNextNull ( nodep - > fromp ( ) ) ;
2019-05-19 22:13:13 +02:00
DotStates lastStates = m_ds ;
{
m_ds . init ( m_curSymp ) ;
2018-05-11 02:55:37 +02:00
iterateAndNextNull ( nodep - > bitp ( ) ) ;
iterateAndNextNull ( nodep - > attrp ( ) ) ;
2019-05-19 22:13:13 +02:00
}
m_ds = lastStates ;
if ( m_ds . m_unresolved & & m_ds . m_dotPos = = DP_SCOPE ) {
AstNode * exprp = nodep - > bitp ( ) - > unlinkFrBack ( ) ;
AstCellArrayRef * newp
= new AstCellArrayRef ( nodep - > fileline ( ) , nodep - > fromp ( ) - > name ( ) , exprp ) ;
2020-01-17 02:17:11 +01:00
nodep - > replaceWith ( newp ) ; VL_DO_DANGLING ( pushDeletep ( nodep ) , nodep ) ;
2019-05-19 22:13:13 +02:00
}
2012-12-31 23:05:13 +01:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstNodePreSel * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// 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 ;
}
2018-05-11 02:55:37 +02:00
iterateAndNextNull ( nodep - > lhsp ( ) ) ;
2019-05-19 22:13:13 +02:00
DotStates lastStates = m_ds ;
{
m_ds . init ( m_curSymp ) ;
2018-05-11 02:55:37 +02:00
iterateAndNextNull ( nodep - > rhsp ( ) ) ;
iterateAndNextNull ( nodep - > thsp ( ) ) ;
iterateAndNextNull ( nodep - > attrp ( ) ) ;
2019-05-19 22:13:13 +02:00
}
m_ds = lastStates ;
2012-12-31 23:05:13 +01:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstMemberSel * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// checkNoDot not appropriate, can be under a dot
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2012-07-24 12:26:35 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstBegin * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
UINFO ( 5 , " " < < nodep < < endl ) ;
checkNoDot ( nodep ) ;
VSymEnt * oldCurSymp = m_curSymp ;
{
m_ds . m_dotSymp = m_curSymp = m_statep - > getNodeSym ( nodep ) ;
2018-10-14 22:25:36 +02:00
UINFO ( 5 , " cur=se " < < cvtToHex ( m_curSymp ) < < endl ) ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
}
m_ds . m_dotSymp = m_curSymp = oldCurSymp ;
2018-10-14 22:25:36 +02:00
UINFO ( 5 , " cur=se " < < cvtToHex ( m_curSymp ) < < endl ) ;
2012-07-21 23:12:42 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstNodeFTask * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
UINFO ( 5 , " " < < nodep < < endl ) ;
checkNoDot ( nodep ) ;
VSymEnt * oldCurSymp = m_curSymp ;
{
m_ftaskp = nodep ;
m_ds . m_dotSymp = m_curSymp = m_statep - > getNodeSym ( nodep ) ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
}
m_ds . m_dotSymp = m_curSymp = oldCurSymp ;
m_ftaskp = NULL ;
2012-07-21 23:12:42 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstRefDType * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// Resolve its reference
if ( nodep - > user3SetOnce ( ) ) return ;
if ( m_ds . m_dotp & & m_ds . m_dotPos = = DP_PACKAGE ) {
2019-07-06 18:57:50 +02:00
UASSERT_OBJ ( VN_IS ( m_ds . m_dotp - > lhsp ( ) , PackageRef ) ,
m_ds . m_dotp - > lhsp ( ) , " Bad package link " ) ;
UASSERT_OBJ ( VN_CAST ( m_ds . m_dotp - > lhsp ( ) , PackageRef ) - > packagep ( ) ,
m_ds . m_dotp - > lhsp ( ) , " Bad package link " ) ;
2018-02-02 03:32:58 +01:00
nodep - > packagep ( VN_CAST ( m_ds . m_dotp - > lhsp ( ) , PackageRef ) - > packagep ( ) ) ;
2019-05-19 22:13:13 +02:00
m_ds . m_dotPos = DP_SCOPE ;
m_ds . m_dotp = NULL ;
} else {
checkNoDot ( nodep ) ;
}
if ( ! nodep - > defp ( ) ) {
VSymEnt * foundp ;
if ( nodep - > packagep ( ) ) {
foundp = m_statep - > getNodeSym ( nodep - > packagep ( ) ) - > findIdFlat ( nodep - > name ( ) ) ;
} else {
foundp = m_curSymp - > findIdFallback ( nodep - > name ( ) ) ;
}
2018-02-02 03:32:58 +01:00
if ( AstTypedef * defp = foundp ? VN_CAST ( foundp - > nodep ( ) , Typedef ) : NULL ) {
2019-05-19 22:13:13 +02:00
nodep - > refDTypep ( defp - > subDTypep ( ) ) ;
nodep - > packagep ( foundp - > packagep ( ) ) ;
}
else if ( AstParamTypeDType * defp = foundp ? VN_CAST ( foundp - > nodep ( ) , ParamTypeDType )
: NULL ) {
nodep - > refDTypep ( defp ) ;
nodep - > packagep ( foundp - > packagep ( ) ) ;
}
else {
2019-07-12 04:09:30 +02:00
nodep - > v3error ( " Can't find typedef: " < < nodep - > prettyNameQ ( ) ) ;
2019-05-19 22:13:13 +02:00
}
}
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2006-08-26 13:35:28 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstDpiExport * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// AstDpiExport: Make sure the function referenced exists, then dump it
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2019-05-19 22:13:13 +02:00
checkNoDot ( nodep ) ;
VSymEnt * foundp = m_curSymp - > findIdFallback ( nodep - > name ( ) ) ;
2018-02-02 03:32:58 +01:00
AstNodeFTask * taskp = foundp ? VN_CAST ( foundp - > nodep ( ) , NodeFTask ) : NULL ;
2019-05-19 22:13:13 +02:00
if ( ! taskp ) { nodep - > v3error ( " Can't find definition of exported task/function: "
2019-07-12 04:09:30 +02:00
< < nodep - > prettyNameQ ( ) ) ; }
2019-05-19 22:13:13 +02:00
else if ( taskp - > dpiExport ( ) ) {
nodep - > v3error ( " Function was already DPI Exported, duplicate not allowed: "
2019-07-12 04:09:30 +02:00
< < nodep - > prettyNameQ ( ) ) ;
2019-05-19 22:13:13 +02:00
} else {
taskp - > dpiExport ( true ) ;
if ( nodep - > cname ( ) ! = " " ) taskp - > cname ( nodep - > cname ( ) ) ;
}
2020-01-17 02:17:11 +01:00
VL_DO_DANGLING ( nodep - > unlinkFrBack ( ) - > deleteTree ( ) , nodep ) ;
2012-07-21 23:12:42 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstPackageImport * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// No longer needed
checkNoDot ( nodep ) ;
2020-01-17 02:17:11 +01:00
VL_DO_DANGLING ( nodep - > unlinkFrBack ( ) - > deleteTree ( ) , nodep ) ;
2012-08-09 03:59:17 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstPackageExport * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// No longer needed
checkNoDot ( nodep ) ;
2020-01-17 02:17:11 +01:00
VL_DO_DANGLING ( nodep - > unlinkFrBack ( ) - > deleteTree ( ) , nodep ) ;
2017-09-21 03:04:59 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstPackageExportStarStar * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// No longer needed
checkNoDot ( nodep ) ;
2020-01-17 02:17:11 +01:00
VL_DO_DANGLING ( nodep - > unlinkFrBack ( ) - > deleteTree ( ) , nodep ) ;
2017-09-21 03:04:59 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstCellRef * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
UINFO ( 5 , " AstCellRef: " < < nodep < < " " < < m_ds . ascii ( ) < < endl ) ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2015-10-23 02:13:49 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstCellArrayRef * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
UINFO ( 5 , " AstCellArrayRef: " < < nodep < < " " < < m_ds . ascii ( ) < < endl ) ;
// Expression already iterated
2015-10-23 02:13:49 +02:00
}
2020-01-21 23:35:56 +01:00
virtual void visit ( AstUnlinkedRef * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
UINFO ( 5 , " AstCellArrayRef: " < < nodep < < " " < < m_ds . ascii ( ) < < endl ) ;
// No need to iterate, if we have a UnlinkedVarXRef, we're already done
2015-10-23 02:13:49 +02:00
}
2015-12-06 01:39:40 +01:00
2020-01-21 23:35:56 +01:00
virtual void visit ( AstNode * nodep ) VL_OVERRIDE {
2019-05-19 22:13:13 +02:00
// Default: Just iterate
checkNoDot ( nodep ) ;
2018-05-11 02:55:37 +02:00
iterateChildren ( nodep ) ;
2006-08-26 13:35:28 +02:00
}
public :
2019-09-12 13:22:22 +02:00
// CONSTRUCTORS
2006-08-26 13:35:28 +02:00
LinkDotResolveVisitor ( AstNetlist * rootp , LinkDotState * statep ) {
2019-05-19 22:13:13 +02:00
UINFO ( 4 , __FUNCTION__ < < " : " < < endl ) ;
m_statep = statep ;
m_modSymp = NULL ;
m_curSymp = NULL ;
m_pinSymp = NULL ;
m_cellp = NULL ;
m_modp = NULL ;
m_ftaskp = NULL ;
m_modportNum = 0 ;
//
2018-05-11 02:55:37 +02:00
iterate ( rootp ) ;
2006-08-26 13:35:28 +02:00
}
virtual ~ LinkDotResolveVisitor ( ) { }
} ;
//######################################################################
// Link class functions
2012-07-21 15:27:57 +02:00
int V3LinkDot : : debug ( ) { return LinkDotState : : debug ( ) ; }
void V3LinkDot : : linkDotGuts ( AstNetlist * rootp , VLinkDotStep step ) {
2018-03-10 22:32:04 +01:00
if ( LinkDotState : : debug ( ) > = 5 | | v3Global . opt . dumpTree ( ) > = 9 ) {
v3Global . rootp ( ) - > dumpTreeFile ( v3Global . debugFilename ( " prelinkdot.tree " ) ) ;
}
2012-07-21 15:27:57 +02:00
LinkDotState state ( rootp , step ) ;
2006-08-26 13:35:28 +02:00
LinkDotFindVisitor visitor ( rootp , & state ) ;
2018-03-10 22:32:04 +01:00
if ( LinkDotState : : debug ( ) > = 5 | | v3Global . opt . dumpTree ( ) > = 9 ) {
v3Global . rootp ( ) - > dumpTreeFile ( v3Global . debugFilename ( " prelinkdot-find.tree " ) ) ;
}
2012-07-21 23:12:42 +02:00
if ( step = = LDS_PRIMARY | | step = = LDS_PARAMED ) {
2019-05-19 22:13:13 +02:00
// Initial link stage, resolve parameters
LinkDotParamVisitor visitors ( rootp , & state ) ;
2018-03-10 22:32:04 +01:00
if ( LinkDotState : : debug ( ) > = 5 | | v3Global . opt . dumpTree ( ) > = 9 ) {
v3Global . rootp ( ) - > dumpTreeFile ( v3Global . debugFilename ( " prelinkdot-param.tree " ) ) ;
}
2012-07-21 23:12:42 +02:00
}
2013-05-28 03:39:19 +02:00
else if ( step = = LDS_ARRAYED ) { }
2012-07-21 23:12:42 +02:00
else if ( step = = LDS_SCOPED ) {
2019-05-19 22:13:13 +02: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.
LinkDotScopeVisitor visitors ( rootp , & state ) ;
2018-03-10 22:32:04 +01:00
if ( LinkDotState : : debug ( ) > = 5 | | v3Global . opt . dumpTree ( ) > = 9 ) {
v3Global . rootp ( ) - > dumpTreeFile ( v3Global . debugFilename ( " prelinkdot-scoped.tree " ) ) ;
}
2006-09-06 19:48:41 +02:00
}
2013-05-28 03:39:19 +02:00
else v3fatalSrc ( " Bad case " ) ;
state . dump ( ) ;
state . computeIfaceModSyms ( ) ;
state . computeIfaceVarSyms ( ) ;
state . computeScopeAliases ( ) ;
2006-08-26 13:35:28 +02:00
state . dump ( ) ;
LinkDotResolveVisitor visitorb ( rootp , & state ) ;
}