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