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
//
//*************************************************************************
//
2014-01-06 19:28:57 -05:00
// Copyright 2003-2014 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"
2008-06-30 13:11:25 -04:00
#include <cstdio>
#include <cstdarg>
2006-08-26 11:35:28 +00:00
#include <unistd.h>
#include <map>
#include <algorithm>
#include <vector>
#include "V3Global.h"
#include "V3LinkDot.h"
#include "V3SymTable.h"
#include "V3Graph.h"
#include "V3Ast.h"
//######################################################################
// LinkDot state, as a visitor of each AstNode
class LinkDotState {
private :
// NODE STATE
// Cleared on Netlist
2012-07-21 17:12:42 -04:00
// AstNodeModule::user1p() // VSymEnt*. Last symbol created for this node
// ... Note maybe more than one, as can be multiple hierarchy places
// AstVarScope::user2p() // AstVarScope*. Base alias for AstInline of this signal
// AstVar::user2p() // AstFTask*. If a function variable, the task that links to the variable
// AstVar::user4() // bool. True if port set for this variable
// AstBegin::user4() // bool. Did name processing
// AstNodeModule::user4() // bool. Live module
2008-11-25 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
2013-05-27 21:39:19 -04:00
typedef multimap < string , VSymEnt *> NameScopeSymMap ;
typedef map < VSymEnt * , VSymEnt *> ScopeAliasMap ;
typedef set < pair < AstNodeModule * , string > > ImplicitNameSet ;
typedef vector < VSymEnt *> IfaceVarSyms ;
typedef vector < pair < AstIface * , VSymEnt *> > IfaceModSyms ;
2012-07-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
static int debug () {
static int level = - 1 ;
if ( VL_UNLIKELY ( level < 0 )) level = v3Global . opt . debugSrcLevel ( __FILE__ );
return level ;
}
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" ;
2014-03-15 14:50:03 -04:00
const VL_UNIQUE_PTR < ofstream > logp ( V3File :: new_ofstream ( filename ));
2013-05-27 20:56:20 -04:00
if ( logp -> fail ()) v3fatalSrc ( "Can't write " << filename );
ostream & os = * logp ;
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 );
2013-02-02 14:11:50 -05: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 ) {
if ( nodep -> castVar ()) return "variable" ;
else if ( nodep -> castCell ()) return "cell" ;
else if ( nodep -> castTask ()) return "task" ;
else if ( nodep -> castFunc ()) return "function" ;
else if ( nodep -> castBegin ()) return "block" ;
2013-05-27 21:39:19 -04:00
else if ( nodep -> castIface ()) return "interface" ;
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 );
AstNode * fnodep = foundp -> nodep ();
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
2012-07-21 17:12:42 -04:00
} else if ( nodep -> castBegin () && fnodep -> castBegin ()
&& nodep -> castBegin () -> generate ()) {
// Begin: ... blocks often replicate under genif/genfor, so simply suppress duplicate checks
// See t_gen_forif.v for an example.
} else {
2012-09-07 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 );
UINFO ( 9 , " INSERTdunit se" << ( void * ) symp << endl );
symp -> parentp ( rootEntp ()); // Needed so backward search can find name of top module
symp -> fallbackp ( NULL );
rootEntp () -> insert ( "$unit " , symp ); // Space so can never name conflict with user code
//
if ( m_dunitEntp ) nodep -> v3fatalSrc ( "Call insertDUnit only once" );
m_dunitEntp = symp ;
2012-06-20 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 );
2012-07-19 21:18:39 -04:00
UINFO ( 9 , " INSERTtop se" << ( void * ) 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 );
2012-07-19 21:18:39 -04:00
UINFO ( 9 , " INSERTcel se" << ( void * ) symp << " " << scopename << " above=se" << ( void * ) abovep << " mods=se" << ( void * ) 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 );
2012-07-19 21:18:39 -04:00
UINFO ( 9 , " INSERTinl se" << ( void * ) symp << " " << basename << " above=se" << ( void * ) abovep << " mods=se" << ( void * ) 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 );
2012-07-19 21:18:39 -04:00
UINFO ( 9 , " INSERTblk se" << ( void * ) symp << " above=se" << ( void * ) 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 );
2012-07-21 17:12:42 -04:00
UINFO ( 9 , " INSERTsym se" << ( void * ) symp << " name='" << name << "' above=se" << ( void * ) abovep << " node=" << nodep << endl );
// We don't remember the ent associated with each node, because we need a unique scope entry for each instantiation
symp -> packagep ( packagep );
symp -> parentp ( abovep );
symp -> fallbackp ( abovep );
nodep -> user1p ( symp );
checkDuplicate ( abovep , nodep , name );
2013-01-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
2012-06-20 06:13:28 -04:00
VSymEnt * symp = nodep -> user1p () -> castSymEnt ();
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 );
}
void computeIfaceVarSyms () {
for ( IfaceVarSyms :: iterator it = m_ifaceVarSyms . begin (); it != m_ifaceVarSyms . end (); ++ it ) {
VSymEnt * varSymp = * it ;
AstVar * varp = varSymp -> nodep () -> castVar ();
UINFO ( 9 , " insAllIface se" << ( void * ) varSymp << " " << varp << endl );
AstIfaceRefDType * ifacerefp = varp -> subDTypep () -> castIfaceRefDType ();
if ( ! ifacerefp ) varp -> v3fatalSrc ( "Non-ifacerefs on list!" );
if ( ! ifacerefp -> ifaceViaCellp ()) ifacerefp -> v3fatalSrc ( "Unlinked interface" );
VSymEnt * ifaceSymp = getNodeSym ( ifacerefp -> ifaceViaCellp ());
VSymEnt * ifOrPortSymp = ifaceSymp ;
// Link Modport names to the Modport Node under the Interface
if ( ifacerefp -> isModport ()) {
VSymEnt * foundp = ifaceSymp -> findIdFallback ( ifacerefp -> modportName ());
bool ok = false ;
if ( foundp ) {
if ( AstModport * modportp = foundp -> nodep () -> castModport ()) {
UINFO ( 4 , "Link Modport: " << modportp << endl );
ifacerefp -> modportp ( modportp );
ifOrPortSymp = foundp ;
ok = true ;
}
}
if ( ! ok ) ifacerefp -> v3error ( "Modport not found under interface '"
<< ifacerefp -> prettyName ( ifacerefp -> ifaceName ())
<< "': " << ifacerefp -> prettyName ( ifacerefp -> modportName ()));
}
// Alias won't expand until interfaces and modport names are known; see notes at top
2014-04-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
2013-05-27 21:39:19 -04:00
UINFO ( 9 , " insertScopeAlias se" << ( void * ) lhsp << " se" << ( void * ) rhsp << endl );
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 );
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
UINFO ( 8 , " dottedFind se" << ( void * ) 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 ;
if (( pos = leftname . find ( "." )) != string :: npos ) {
ident = leftname . substr ( 0 , pos );
leftname = leftname . substr ( pos + 1 );
} else {
ident = leftname ;
leftname = "" ;
}
baddot = ident ; // So user can see where they botched it
2012-07-19 21:18:39 -04:00
okSymp = lookupSymp ;
2006-09-06 17:48:41 +00:00
string altIdent = "" ;
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 );
2006-08-26 11:35:28 +00:00
// Spec says; Look at exiting module (cellnames then modname),
// then look up (inst name or modname)
if ( firstId ) {
// Check this module - subcellnames
2012-07-19 21:18:39 -04:00
AstCell * cellp = lookupSymp -> nodep () -> castCell (); // Replicated below
AstCellInline * inlinep = lookupSymp -> nodep () -> castCellInline (); // Replicated below
if ( VSymEnt * findSymp = findWithAltFallback ( lookupSymp , ident , altIdent )) {
lookupSymp = findSymp ;
2006-08-26 11:35:28 +00:00
}
// Check this module - cur modname
2012-06-20 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 {
2012-07-19 21:18:39 -04:00
while ( lookupSymp ) {
lookupSymp = lookupSymp -> parentp ();
cellp = lookupSymp -> nodep () -> castCell (); // Replicated above
inlinep = lookupSymp -> nodep () -> castCellInline (); // Replicated above
if ( lookupSymp ) {
UINFO ( 9 , " \t\t Up to " << lookupSymp << endl );
2012-06-20 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 ;
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
}
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
2012-07-21 17:12:42 -04:00
<< " under se" << ( void * ) 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 );
2012-07-21 17:12:42 -04:00
VSymEnt * foundp = lookupSymp -> findIdFallback ( lookupSymp -> symPrefix () + dotname ); // Might be NULL
if ( ! foundp ) baddot = dotname ;
return foundp ;
}
2006-08-26 11:35:28 +00:00
};
2013-05-25 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
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 (); }
// VISITs
virtual void visit ( AstNetlist * nodep , AstNUser * ) {
2009-11-07 21:05:02 -05:00
// Process $unit or other packages
// Not needed - dotted references not allowed from inside packages
//for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep; nodep=nodep->nextp()->castNodeModule()) {
// if (nodep->castPackage()) {}}
2012-07-21 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
nodep -> iterateChildrenBackwards ( * this );
2006-08-26 11:35:28 +00:00
// The first module in the list is always the top module (sorted before this is called).
// This may not be the module with isTop() set, as early in the steps,
// wrapTop may have not been created yet.
2009-11-07 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
{
topmodp -> accept ( * this );
}
m_scope = "" ;
2012-07-17 21:29:10 -04:00
m_curSymp = m_modSymp = NULL ;
2006-08-26 11:35:28 +00:00
}
}
2012-07-21 17:12:42 -04:00
virtual void visit ( AstTypeTable * nodep , AstNUser * ) {}
2009-11-07 06:20:20 -05:00
virtual void visit ( AstNodeModule * nodep , AstNUser * ) {
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
bool standalonePkg = ! m_modSymp && ( m_statep -> forPrearray () && nodep -> castPackage ());
bool doit = ( m_modSymp || standalonePkg );
string oldscope = m_scope ;
VSymEnt * oldModSymp = m_modSymp ;
VSymEnt * oldCurSymp = m_curSymp ;
2012-11-02 20:30:47 -04:00
int oldParamNum = m_paramNum ;
int oldBeginNum = m_beginNum ;
int oldModBeginNum = m_modBeginNum ;
2012-07-21 17:12:42 -04:00
if ( doit ) {
UINFO ( 2 , " Link Module: " << nodep << endl );
if ( nodep -> dead ()) nodep -> v3fatalSrc ( "Module in cell tree mislabeled as dead?" );
VSymEnt * upperSymp = m_curSymp ? m_curSymp : m_statep -> rootEntp ();
m_packagep = nodep -> castPackage ();
if ( standalonePkg ) {
if ( m_packagep -> isDollarUnit ()) {
m_curSymp = m_modSymp = m_statep -> dunitEntp ();
nodep -> user1p ( m_curSymp );
} else {
m_scope = nodep -> name ();
m_curSymp = m_modSymp = m_statep -> insertBlock ( upperSymp , nodep -> name () + "::" , nodep , m_packagep );
UINFO ( 9 , "New module scope " << m_curSymp << endl );
}
}
//
m_paramNum = 0 ;
m_beginNum = 0 ;
m_modBeginNum = 0 ;
// m_modSymp/m_curSymp for non-packages set by AstCell above this module
// Iterate
2006-08-26 11:35:28 +00:00
nodep -> iterateChildren ( * this );
2012-07-21 17:12:42 -04:00
nodep -> user4 ( true );
2013-05-27 21:39:19 -04:00
// Interfaces need another pass when signals are resolved
if ( AstIface * ifacep = nodep -> castIface ()) {
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
}
virtual void visit ( AstScope * nodep , AstNUser * ) {
if ( ! m_statep -> forScopeCreation ()) v3fatalSrc ( "Scopes should only exist right after V3Scope" );
// Ignored. Processed in next step
}
virtual void visit ( AstCell * nodep , AstNUser * ) {
UINFO ( 5 , " CELL under " << m_scope << " is " << nodep << endl );
2012-07-17 21:29:10 -04:00
// Process XREFs/etc inside pins
2006-12-12 18:25:33 +00:00
nodep -> iterateChildren ( * this );
2006-08-26 11:35:28 +00:00
// Recurse in, preserving state
string oldscope = m_scope ;
2006-12-12 18:25:33 +00:00
AstBegin * oldbeginp = m_beginp ;
2012-07-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 ;
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 ;
if (( pos = origname . rfind ( "." )) != string :: npos ) {
// Flattened, find what CellInline it should live under
string scope = origname . substr ( 0 , pos );
string baddot ;
2012-06-20 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 ;
2006-08-26 11:35:28 +00:00
if ( nodep -> modp ()) nodep -> modp () -> accept ( * this );
}
m_scope = oldscope ;
2006-12-12 18:25:33 +00:00
m_beginp = oldbeginp ;
2012-07-17 21:29:10 -04:00
m_modSymp = oldModSymp ;
m_curSymp = oldCurSymp ;
2012-09-07 19:51:41 -04:00
m_paramNum = oldParamNum ;
2006-08-26 11:35:28 +00:00
}
virtual void visit ( AstCellInline * nodep , AstNUser * ) {
UINFO ( 5 , " CELLINLINE under " << m_scope << " is " << nodep << endl );
2012-07-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
}
}
2012-08-07 18:24:51 -04:00
virtual void visit ( AstDefParam * nodep , AstNUser * ) {
nodep -> user1p ( m_curSymp );
nodep -> iterateChildren ( * this );
}
2012-07-21 17:12:42 -04:00
virtual void visit ( AstGenerate * nodep , AstNUser * ) {
// Begin: ... blocks often replicate under genif/genfor, so simply suppress duplicate checks
// See t_gen_forif.v for an example.
bool lastInGen = m_inGenerate ;
{
m_inGenerate = true ;
nodep -> iterateChildren ( * this );
}
m_inGenerate = lastInGen ;
}
2006-08-26 11:35:28 +00:00
virtual void visit ( AstBegin * nodep , AstNUser * ) {
UINFO ( 5 , " " << nodep << endl );
2012-07-21 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 ()) {
if ( stmtp -> castVar ()) {
++ m_modBeginNum ;
nodep -> name ( "unnamedblk" + cvtToStr ( m_modBeginNum ));
break ;
}
}
}
int oldNum = m_beginNum ;
2006-08-26 11:35:28 +00:00
AstBegin * oldbegin = m_beginp ;
2012-07-21 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
nodep -> iterateChildren ( * this );
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
}
2012-05-28 09:18:18 -04:00
virtual void visit ( AstNodeFTask * nodep , AstNUser * ) {
2012-07-21 17:12:42 -04:00
// NodeTask: Remember its name for later resolution
UINFO ( 5 , " " << nodep << endl );
if ( ! m_curSymp || ! m_modSymp ) nodep -> v3fatalSrc ( "Function/Task not under module?? \n " );
// Remember the existing symbol table scope
VSymEnt * oldCurSymp = m_curSymp ;
{
// Create symbol table for the task's vars
m_curSymp = m_statep -> insertBlock ( m_curSymp , nodep -> name (), nodep , m_packagep );
m_curSymp -> fallbackp ( oldCurSymp );
// Convert the func's range to the output variable
// This should probably be done in the Parser instead, as then we could
// just attact normal signal attributes to it.
if ( nodep -> fvarp ()
&& ! nodep -> fvarp () -> castVar ()) {
AstNodeDType * dtypep = nodep -> fvarp () -> castNodeDType ();
// If unspecified, function returns one bit; however when we support NEW() it could
// also return the class reference.
if ( dtypep ) dtypep -> unlinkFrBack ();
else dtypep = new AstBasicDType ( nodep -> fileline (), AstBasicDTypeKwd :: LOGIC );
AstVar * newvarp = new AstVar ( nodep -> fileline (), AstVarType :: OUTPUT , nodep -> name (),
VFlagChildDType (), dtypep ); // Not dtype resolved yet
newvarp -> funcReturn ( true );
newvarp -> trace ( false ); // Not user visible
newvarp -> attrIsolateAssign ( nodep -> attrIsolateAssign ());
nodep -> addFvarp ( newvarp );
// Explicit insert required, as the var name shadows the upper level's task name
m_statep -> insertSym ( m_curSymp , newvarp -> name (), newvarp , NULL /*packagep*/ );
}
m_ftaskp = nodep ;
nodep -> iterateChildren ( * this );
m_ftaskp = NULL ;
2012-05-28 09:18:18 -04:00
}
2012-07-21 17:12:42 -04:00
m_curSymp = oldCurSymp ;
}
2006-08-26 11:35:28 +00:00
virtual void visit ( AstVar * nodep , AstNUser * ) {
2012-07-21 17:12:42 -04:00
// Var: Remember its name for later resolution
if ( ! m_curSymp || ! m_modSymp ) nodep -> v3fatalSrc ( "Var not under module?? \n " );
nodep -> iterateChildren ( * this );
if ( ! m_statep -> forScopeCreation ()) {
// Find under either a task or the module's vars
VSymEnt * foundp = m_curSymp -> findIdFallback ( nodep -> name ());
if ( ! foundp && m_modSymp && nodep -> name () == m_modSymp -> nodep () -> name ()) foundp = m_modSymp ; // Conflicts with modname?
2013-02-03 13:27:37 -05:00
AstVar * findvarp = foundp ? foundp -> nodep () -> castVar () : 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 );
UINFO ( 4 , " found cur=se" << ( void * ) m_curSymp << " ;; parent=se" << ( void * ) 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 ());
AstBasicDType * bdtypep = findvarp -> childDTypep () -> castBasicDType ();
if ( bdtypep && bdtypep -> implicit ()) {
// Then have "input foo" and "real foo" so the dtype comes from the other side.
AstNodeDType * newdtypep = nodep -> subDTypep ();
if ( ! newdtypep || ! nodep -> childDTypep ()) findvarp -> v3fatalSrc ( "No child type?" );
bdtypep -> unlinkFrBack () -> deleteTree ();
newdtypep -> unlinkFrBack ();
findvarp -> childDTypep ( newdtypep );
}
nodep -> unlinkFrBack () -> deleteTree (); nodep = NULL ;
} else {
nodep -> v3error ( "Duplicate declaration of signal: " << nodep -> prettyName () << endl
<< findvarp -> warnMore () << "... Location of original declaration" );
}
} else {
// User can disable the message at either point
if ( ! ( m_ftaskp && m_ftaskp -> dpiImport ())
&& ( ! m_ftaskp || m_ftaskp != foundp -> nodep ()) // Not the function's variable hiding function
&& ! nodep -> fileline () -> warnIsOff ( V3ErrorCode :: VARHIDDEN )
&& ! foundp -> nodep () -> fileline () -> warnIsOff ( V3ErrorCode :: VARHIDDEN )) {
2013-03-12 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 ) {
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 ++ ;
2012-12-17 19:07:23 -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
}
2013-05-27 21:39:19 -04:00
if ( nodep -> subDTypep () -> castIfaceRefDType ()) {
// Can't resolve until interfaces and modport names are known; see notes at top
m_statep -> insertIfaceVarSym ( insp );
}
2012-07-21 17:12:42 -04:00
}
2006-08-26 11:35:28 +00:00
}
}
2012-07-21 17:12:42 -04:00
virtual void visit ( AstTypedef * nodep , AstNUser * ) {
// Remember its name for later resolution
if ( ! m_curSymp ) nodep -> v3fatalSrc ( "Typedef not under module?? \n " );
nodep -> iterateChildren ( * this );
m_statep -> insertSym ( m_curSymp , nodep -> name (), nodep , m_packagep );
}
2006-08-26 11:35:28 +00:00
virtual void visit ( AstCFunc * nodep , AstNUser * ) {
2012-07-21 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" );
}
virtual void visit ( AstEnumItem * nodep , AstNUser * ) {
// EnumItem: Remember its name for later resolution
nodep -> iterateChildren ( * this );
// Find under either a task or the module's vars
VSymEnt * foundp = m_curSymp -> findIdFallback ( nodep -> name ());
if ( ! foundp && m_modSymp && nodep -> name () == m_modSymp -> nodep () -> name ()) foundp = m_modSymp ; // Conflicts with modname?
2013-02-03 13:27:37 -05:00
AstEnumItem * findvarp = foundp ? foundp -> nodep () -> castEnumItem () : 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 );
}
}
virtual void visit ( AstPackageImport * nodep , AstNUser * ) {
UINFO ( 2 , " Link: " << nodep << endl );
VSymEnt * srcp = m_statep -> getNodeSym ( nodep -> packagep ());
if ( nodep -> name () != "*" ) {
VSymEnt * impp = srcp -> findIdFlat ( nodep -> name ());
if ( ! impp ) {
nodep -> v3error ( "Import object not found: " << nodep -> packagep () -> prettyName () << "::" << nodep -> prettyName ());
}
}
2013-05-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
}
virtual void visit ( AstNode * nodep , AstNUser * ) {
// Default: Just iterate
nodep -> iterateChildren ( * this );
}
public :
// CONSTUCTORS
LinkDotFindVisitor ( AstNetlist * rootp , LinkDotState * statep ) {
UINFO ( 4 , __FUNCTION__ << ": " << endl );
2012-07-21 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 ;
m_paramNum = 0 ;
m_beginNum = 0 ;
m_modBeginNum = 0 ;
2006-08-26 11:35:28 +00:00
//
rootp -> accept ( * this );
}
virtual ~ LinkDotFindVisitor () {}
};
2012-07-21 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
2012-07-24 06:26:35 -04:00
if ( nodep -> castDot ()) { // Not creating a simple implied type,
// and implying something else would just confuse later errors
}
2012-12-31 17:05:13 -05:00
else if ( nodep -> castVarRef () || nodep -> castParseRef ()) {
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
virtual void visit ( AstTypeTable * nodep , AstNUser * ) {}
virtual void visit ( AstNodeModule * nodep , AstNUser * ) {
UINFO ( 5 , " " << nodep << endl );
if ( nodep -> dead () || ! nodep -> user4 ()) {
UINFO ( 4 , "Mark dead module " << nodep << endl );
if ( ! m_statep -> forPrearray ()) nodep -> v3fatalSrc ( "Dead module persisted past where should have removed" );
// Don't remove now, because we may have a tree of parameterized modules with VARXREFs into the deleted module region
// V3Dead should cleanup.
// Downstream visitors up until V3Dead need to check for nodep->dead.
nodep -> dead ( true );
} else {
m_modp = nodep ;
nodep -> iterateChildren ( * this );
m_modp = NULL ;
}
}
virtual void visit ( AstPin * nodep , AstNUser * ) {
// Pin: Link to submodule's port
// Deal with implicit definitions - do before Resolve visitor as may be referenced above declaration
if ( nodep -> exprp () // Else specifically unconnected pin
&& ! nodep -> svImplicit ()) { // SV 19.11.3: .name pins don't allow implicit decls
pinImplicitExprRecurse ( nodep -> exprp ());
}
}
virtual void visit ( AstDefParam * nodep , AstNUser * ) {
nodep -> iterateChildren ( * this );
2013-03-12 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 ());
2012-07-21 17:12:42 -04:00
AstCell * cellp = foundp -> nodep () -> castCell ();
if ( ! cellp ) {
nodep -> v3error ( "In defparam, cell " << nodep -> path () << " never declared" );
} else {
AstNode * exprp = nodep -> rhsp () -> unlinkFrBack ();
UINFO ( 9 , "Defparam cell " << nodep -> path () << "." << nodep -> name ()
2012-08-07 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.
AstPin * pinp = new AstPin ( nodep -> fileline (),
- 1 , // Pin# not relevant
nodep -> name (),
exprp );
cellp -> addParamsp ( pinp );
nodep -> unlinkFrBack () -> deleteTree (); nodep = NULL ;
}
}
virtual void visit ( AstPort * nodep , AstNUser * ) {
// Port: Stash the pin number
// Need to set pin numbers after varnames are created
// But before we do the final resolution based on names
VSymEnt * foundp = m_statep -> getNodeSym ( m_modp ) -> findIdFlat ( nodep -> name ());
AstVar * refp = foundp -> nodep () -> castVar ();
if ( ! refp ) {
nodep -> v3error ( "Input/output/inout declaration not found for port: " << nodep -> prettyName ());
2013-05-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
nodep -> unlinkFrBack () -> deleteTree (); nodep = NULL ;
}
virtual void visit ( AstAssignW * nodep , AstNUser * ) {
// Deal with implicit definitions
// We used to nodep->allowImplicit() here, but it turns out
// normal "assigns" can also make implicit wires. Yuk.
pinImplicitExprRecurse ( nodep -> lhsp ());
nodep -> iterateChildren ( * this );
}
virtual void visit ( AstAssignAlias * nodep , AstNUser * ) {
// tran gates need implicit creation
2012-07-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" );
2012-07-21 17:12:42 -04:00
if ( AstVarRef * forrefp = nodep -> lhsp () -> castVarRef ()) {
pinImplicitExprRecurse ( forrefp );
}
if ( AstVarRef * forrefp = nodep -> rhsp () -> castVarRef ()) {
pinImplicitExprRecurse ( forrefp );
}
nodep -> iterateChildren ( * this );
}
virtual void visit ( AstImplicit * nodep , AstNUser * ) {
// Unsupported gates need implicit creation
pinImplicitExprRecurse ( nodep );
// We're done with implicit gates
nodep -> unlinkFrBack () -> deleteTree (); nodep = NULL ;
}
virtual void visit ( AstNode * nodep , AstNUser * ) {
// Default: Just iterate
nodep -> iterateChildren ( * this );
}
public :
// CONSTUCTORS
LinkDotParamVisitor ( AstNetlist * rootp , LinkDotState * statep ) {
UINFO ( 4 , __FUNCTION__ << ": " << endl );
m_statep = statep ;
m_modp = NULL ;
//
rootp -> accept ( * this );
}
virtual ~ LinkDotParamVisitor () {}
};
2006-08-26 11:35:28 +00:00
//======================================================================
class LinkDotScopeVisitor : public AstNVisitor {
2013-05-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
2012-07-21 17:12:42 -04:00
virtual void visit ( AstNetlist * nodep , AstNUser * vup ) {
// Recurse..., backward as must do packages before using packages
nodep -> iterateChildrenBackwards ( * this );
}
2006-08-26 11:35:28 +00:00
virtual void visit ( AstScope * nodep , AstNUser * ) {
UINFO ( 8 , " SCOPE " << nodep << endl );
if ( ! m_statep -> forScopeCreation ()) v3fatalSrc ( "Scopes should only exist right after V3Scope" );
2007-05-22 12:15:01 +00:00
// Using the CELL names, we created all hierarchy. We now need to match this Scope
// up with the hierarchy created by the CELL names.
2012-07-17 21:29:10 -04:00
m_modSymp = m_statep -> getScopeSym ( nodep );
2013-05-27 21:39:19 -04:00
m_scopep = nodep ;
2006-08-26 11:35:28 +00:00
nodep -> iterateChildren ( * this );
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
}
virtual void visit ( AstVarScope * nodep , AstNUser * ) {
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
AstIfaceRefDType * dtypep = nodep -> varp () -> dtypep () -> castIfaceRefDType ();
if ( ! dtypep ) nodep -> v3fatalSrc ( "Non AstIfaceRefDType on isIfaceRef() var" );
UINFO ( 9 , "Iface parent dtype " << dtypep << endl );
string ifcellname = dtypep -> cellName ();
string baddot ; VSymEnt * okSymp ;
VSymEnt * cellSymp = m_statep -> findDotted ( m_modSymp , ifcellname , baddot , okSymp );
if ( ! cellSymp ) nodep -> v3fatalSrc ( "No symbol for interface cell: " << nodep -> prettyName ( ifcellname ));
UINFO ( 5 , " Found interface cell: se" << ( void * ) cellSymp << " " << cellSymp -> nodep () << endl );
if ( dtypep -> modportName () != "" ) {
VSymEnt * mpSymp = m_statep -> findDotted ( m_modSymp , ifcellname , baddot , okSymp );
if ( ! mpSymp ) { nodep -> v3fatalSrc ( "No symbol for interface modport: " << nodep -> prettyName ( dtypep -> modportName ())); }
else cellSymp = mpSymp ;
UINFO ( 5 , " Found modport cell: se" << ( void * ) cellSymp << " " << mpSymp -> nodep () << endl );
}
// Interface reference; need to put whole thing into symtable, but can't clone it now
// as we may have a later alias for it.
2014-04-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
}
}
virtual void visit ( AstNodeFTask * nodep , AstNUser * ) {
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
}
virtual void visit ( AstAssignAlias * nodep , AstNUser * ) {
// Track aliases created by V3Inline; if we get a VARXREF(aliased_from)
// we'll need to replace it with a VARXREF(aliased_to)
2013-05-27 20:56:20 -04:00
if ( debug () >= 9 ) nodep -> dumpTree ( cout , "- \t\t\t\t alias: " );
AstVarScope * fromVscp = nodep -> lhsp () -> castVarRef () -> varScopep ();
AstVarScope * toVscp = nodep -> rhsp () -> castVarRef () -> varScopep ();
if ( ! fromVscp || ! toVscp ) nodep -> v3fatalSrc ( "Bad alias scopes" );
fromVscp -> user2p ( toVscp );
2006-08-26 11:35:28 +00:00
nodep -> iterateChildren ( * this );
}
2013-05-27 21:39:19 -04:00
virtual void visit ( AstAssignVarScope * nodep , AstNUser * ) {
UINFO ( 5 , "ASSIGNVARSCOPE " << nodep << endl );
if ( debug () >= 9 ) nodep -> dumpTree ( cout , "- \t\t\t\t avs: " );
VSymEnt * rhsSymp ;
{
AstVarRef * refp = nodep -> rhsp () -> castVarRef ();
if ( ! refp ) nodep -> v3fatalSrc ( "Unsupported: Non VarRef attached to interface pin" );
string scopename = refp -> name ();
string baddot ; VSymEnt * okSymp ;
VSymEnt * symp = m_statep -> findDotted ( m_modSymp , scopename , baddot , okSymp );
if ( ! symp ) nodep -> v3fatalSrc ( "No symbol for interface alias rhs" );
UINFO ( 5 , " Found a linked scope RHS: " << scopename << " se" << ( void * ) symp << " " << symp -> nodep () << endl );
rhsSymp = symp ;
}
VSymEnt * lhsSymp ;
{
AstVarXRef * refp = nodep -> lhsp () -> castVarXRef ();
if ( ! refp ) nodep -> v3fatalSrc ( "Unsupported: Non VarXRef attached to interface pin" );
string scopename = refp -> dotted () + "." + refp -> name ();
string baddot ; VSymEnt * okSymp ;
VSymEnt * symp = m_statep -> findDotted ( m_modSymp , scopename , baddot , okSymp );
if ( ! symp ) nodep -> v3fatalSrc ( "No symbol for interface alias lhs" );
UINFO ( 5 , " Found a linked scope LHS: " << scopename << " se" << ( void * ) symp << " " << symp -> nodep () << endl );
lhsSymp = symp ;
}
// Remember the alias - can't do it yet because we may have additional symbols to be added,
// or maybe an alias of an alias
2014-04-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
nodep -> unlinkFrBack () -> deleteTree (); nodep = NULL ;
}
2006-08-26 11:35:28 +00:00
// For speed, don't recurse things that can't have scope
2006-12-12 18:25:33 +00:00
// Note we allow AstNodeStmt's as generates may be under them
2006-08-26 11:35:28 +00:00
virtual void visit ( AstCell * , AstNUser * ) {}
virtual void visit ( AstVar * , AstNUser * ) {}
virtual void visit ( AstNodeMath * , AstNUser * ) {}
virtual void visit ( AstNode * nodep , AstNUser * ) {
// Default: Just iterate
nodep -> iterateChildren ( * this );
}
public :
// CONSTUCTORS
LinkDotScopeVisitor ( AstNetlist * rootp , LinkDotState * statep ) {
UINFO ( 4 , __FUNCTION__ << ": " << endl );
2012-07-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 ;
//
rootp -> accept ( * this );
}
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
virtual void visit ( AstModport * nodep , AstNUser * ) {
// Modport: Remember its name for later resolution
UINFO ( 5 , " fiv: " << nodep << endl );
VSymEnt * oldCurSymp = m_curSymp ;
{
// Create symbol table for the vars
m_curSymp = m_statep -> insertBlock ( m_curSymp , nodep -> name (), nodep , NULL );
m_curSymp -> fallbackp ( oldCurSymp );
nodep -> iterateChildren ( * this );
}
m_curSymp = oldCurSymp ;
}
2013-12-21 06:51:15 -05:00
virtual void visit ( AstModportFTaskRef * nodep , AstNUser * ) {
UINFO ( 5 , " fif: " << nodep << endl );
nodep -> iterateChildren ( * this );
if ( nodep -> isExport ()) nodep -> v3error ( "Unsupported: modport export" );
VSymEnt * symp = m_curSymp -> findIdFallback ( nodep -> name ());
if ( ! symp ) {
nodep -> v3error ( "Modport item not found: " << nodep -> prettyName ());
} else if ( AstNodeFTask * ftaskp = symp -> nodep () -> castNodeFTask ()) {
// Make symbol under modport that points at the _interface_'s var, not the modport.
nodep -> ftaskp ( ftaskp );
2014-04-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
nodep -> unlinkFrBack (); pushDeletep ( nodep ); nodep = NULL ;
}
}
2013-05-27 21:39:19 -04:00
virtual void visit ( AstModportVarRef * nodep , AstNUser * ) {
UINFO ( 5 , " fiv: " << nodep << endl );
nodep -> iterateChildren ( * this );
VSymEnt * symp = m_curSymp -> findIdFallback ( nodep -> name ());
if ( ! symp ) {
nodep -> v3error ( "Modport item not found: " << nodep -> prettyName ());
} else if ( AstVar * varp = symp -> nodep () -> castVar ()) {
// Make symbol under modport that points at the _interface_'s var, not the modport.
nodep -> varp ( varp );
m_statep -> insertSym ( m_curSymp , nodep -> name (), varp , NULL /*package*/ );
} else if ( AstVarScope * vscp = symp -> nodep () -> castVarScope ()) {
// Make symbol under modport that points at the _interface_'s var, not the modport.
nodep -> varp ( vscp -> varp ());
m_statep -> insertSym ( m_curSymp , nodep -> name (), vscp , NULL /*package*/ );
} else {
nodep -> v3error ( "Modport item is not a variable: " << nodep -> prettyName ());
}
if ( m_statep -> forScopeCreation ()) {
// Done with AstModportVarRef.
// Delete to prevent problems if we dead-delete pointed to variable
nodep -> unlinkFrBack (); pushDeletep ( nodep ); nodep = NULL ;
}
}
virtual void visit ( AstNode * nodep , AstNUser * ) {
// Default: Just iterate
nodep -> iterateChildren ( * this );
}
public :
// CONSTUCTORS
LinkDotIfaceVisitor ( AstIface * nodep , VSymEnt * curSymp , LinkDotState * statep ) {
UINFO ( 4 , __FUNCTION__ << ": " << endl );
m_curSymp = curSymp ;
m_statep = statep ;
nodep -> accept ( * this );
}
virtual ~ LinkDotIfaceVisitor () {}
};
void LinkDotState :: computeIfaceModSyms () {
for ( IfaceModSyms :: iterator it = m_ifaceModSyms . begin (); it != m_ifaceModSyms . end (); ++ it ) {
AstIface * nodep = it -> first ;
VSymEnt * symp = it -> second ;
LinkDotIfaceVisitor ( nodep , symp , this );
}
m_ifaceModSyms . clear ();
}
//======================================================================
2006-08-26 11:35:28 +00:00
class LinkDotResolveVisitor : public AstNVisitor {
private :
2012-07-21 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
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 = "" ;
}
string ascii () const {
static const char * names [] = { "NONE" , "PACKAGE" , "SCOPE" , "FINAL" , "MEMBER" };
ostringstream sstr ;
sstr << "ds=" << names [ m_dotPos ];
sstr << " dse" << ( void * ) m_dotSymp ;
sstr << " txt=" << m_dotText ;
return sstr . str ();
}
2012-12-31 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
void createImplicitVar ( VSymEnt * lookupSymp , AstVarRef * nodep , AstNodeModule * modp , VSymEnt * moduleSymp , bool noWarn ) {
// Create implicit after warning
if ( ! nodep -> varp ()) {
if ( ! noWarn ) {
if ( nodep -> fileline () -> warnIsOff ( V3ErrorCode :: I_DEF_NETTYPE_WIRE )) {
nodep -> v3error ( "Signal definition not found, and implicit disabled with `default_nettype: " << nodep -> prettyName ());
} else {
nodep -> v3warn ( IMPLICIT , "Signal definition not found, creating implicitly: " << nodep -> prettyName ());
}
}
AstVar * newp = new AstVar ( nodep -> fileline (), AstVarType :: WIRE ,
nodep -> name (), VFlagLogicPacked (), 1 );
newp -> trace ( modp -> modTrace ());
nodep -> varp ( newp );
modp -> addStmtp ( newp );
// Link it to signal list, must add the variable under the module; current scope might be lower now
m_statep -> insertSym ( moduleSymp , newp -> name (), newp , NULL /*packagep*/ );
}
}
2012-07-22 22:48:39 -04:00
void taskFuncSwapCheck ( AstNodeFTaskRef * nodep ) {
if ( nodep -> taskp () && nodep -> taskp () -> castTask ()
&& nodep -> castFuncRef ()) nodep -> v3error ( "Illegal call of a task as a function: " << nodep -> prettyName ());
}
2012-12-31 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);
2012-12-31 17:05:13 -05:00
nodep -> v3error ( "Syntax Error: Not expecting " << nodep -> type () << " under a " << nodep -> backp () -> type () << " in dotted expression" );
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 ;
}
2012-07-21 21:18:07 -04:00
2006-08-26 11:35:28 +00:00
// VISITs
2012-07-21 17:12:42 -04:00
virtual void visit ( AstNetlist * nodep , AstNUser * vup ) {
// Recurse..., backward as must do packages before using packages
nodep -> iterateChildrenBackwards ( * this );
}
virtual void visit ( AstTypeTable * nodep , AstNUser * ) {}
2009-11-07 06:20:20 -05:00
virtual void visit ( AstNodeModule * nodep , AstNUser * ) {
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 ;
2006-08-26 11:35:28 +00:00
nodep -> iterateChildren ( * this );
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
}
virtual void visit ( AstScope * nodep , AstNUser * ) {
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 );
2006-08-26 11:35:28 +00:00
nodep -> iterateChildren ( * this );
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
}
virtual void visit ( AstCellInline * nodep , AstNUser * ) {
2012-12-31 17:05:13 -05:00
checkNoDot ( nodep );
2006-08-26 11:35:28 +00:00
if ( m_statep -> forScopeCreation ()) {
nodep -> unlinkFrBack (); pushDeletep ( nodep ); nodep = NULL ;
}
}
2012-07-21 17:12:42 -04:00
virtual void visit ( AstCell * nodep , AstNUser * ) {
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 {
if ( nodep -> modp () -> castNotFoundModule ()) {
// Prevent warnings about missing pin connects
if ( nodep -> pinsp ()) nodep -> pinsp () -> unlinkFrBackWithNext () -> deleteTree ();
if ( nodep -> paramsp ()) nodep -> paramsp () -> unlinkFrBackWithNext () -> deleteTree ();
}
// Need to pass the module info to this cell, so we can link up the pin names
// However can't use m_curSymp as pin connections need to use the instantiator's symbols
else {
m_pinSymp = m_statep -> getNodeSym ( nodep -> modp ());
UINFO ( 4 , "(Backto) Link Cell: " << nodep << endl );
//if (debug()) { nodep->dumpTree(cout,"linkcell:"); }
//if (debug()) { nodep->modp()->dumpTree(cout,"linkcemd:"); }
nodep -> iterateChildren ( * this );
m_pinSymp = NULL ;
}
}
m_cellp = NULL ;
// Parent module inherits child's publicity
// This is done bottom up in the LinkBotupVisitor stage
}
virtual void visit ( AstPin * nodep , AstNUser * ) {
// Pin: Link to submodule's port
2012-12-31 17:05:13 -05:00
checkNoDot ( nodep );
2014-05-28 07:33:40 -04:00
nodep -> iterateChildren ( * this );
2012-07-21 17:12:42 -04:00
if ( ! nodep -> modVarp ()) {
if ( ! m_pinSymp ) nodep -> v3fatalSrc ( "Pin not under cell? \n " );
VSymEnt * foundp = m_pinSymp -> findIdFlat ( nodep -> name ());
AstVar * refp = foundp -> nodep () -> castVar ();
2013-12-14 18:04:10 -05:00
const char * whatp = nodep -> param () ? "parameter pin" : "pin" ;
2012-07-21 17:12:42 -04:00
if ( ! refp ) {
if ( nodep -> name () == "__paramNumber1" && m_cellp -> modp () -> castPrimitive ()) {
// Primitive parameter is really a delay we can just ignore
nodep -> unlinkFrBack () -> deleteTree (); nodep = NULL ;
return ;
}
2014-04-29 21:11:57 -04:00
nodep -> v3error ( ucfirst ( whatp ) << " not found: " << nodep -> prettyName ());
2013-05-27 21:39:19 -04:00
} else if ( ! refp -> isIO () && ! refp -> isParam () && ! refp -> isIfaceRef ()) {
2014-04-29 21:11:57 -04:00
nodep -> v3error ( ucfirst ( whatp ) << " is not an in/out/inout/param/interface: " << nodep -> prettyName ());
2012-07-21 17:12:42 -04:00
} else {
nodep -> modVarp ( refp );
if ( refp -> user5p () && refp -> user5p () -> castNode () != nodep ) {
2013-12-14 18:04:10 -05:00
nodep -> v3error ( "Duplicate " << whatp << " connection: " << nodep -> prettyName () << endl
2012-07-21 17:12:42 -04:00
<< refp -> user5p () -> castNode () -> warnMore ()
2013-12-14 18:04:10 -05:00
<< "... Location of original " << whatp << " connection" );
2012-07-21 17:12:42 -04:00
} else {
refp -> user5p ( nodep );
}
}
}
// Early return() above when deleted
}
2012-07-24 06:26:35 -04:00
virtual void visit ( AstDot * nodep , AstNUser * ) {
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 ;
2012-12-31 17:05:13 -05:00
bool start = ! m_ds . m_dotp ; // 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
2012-12-31 17:05:13 -05:00
if ( nodep -> lhsp () -> castPackageRef ()) {
if ( ! start ) { nodep -> lhsp () -> v3error ( "Package reference may not be embedded in dotted reference" ); m_ds . m_dotErr = true ; }
m_ds . m_dotPos = DP_PACKAGE ;
} else {
m_ds . m_dotPos = DP_SCOPE ;
nodep -> lhsp () -> iterateAndNext ( * this );
2013-05-27 20:56:20 -04:00
//if (debug()>=9) nodep->dumpTree("-dot-lho: ");
2012-12-31 17:05:13 -05:00
}
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
2012-07-24 06:26:35 -04:00
nodep -> rhsp () -> iterateAndNext ( * this );
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 );
pushDeletep ( nodep ); nodep = NULL ;
} else { // Dot midpoint
AstNode * newp = nodep -> rhsp () -> unlinkFrBack ();
nodep -> replaceWith ( newp );
pushDeletep ( nodep ); nodep = NULL ;
}
}
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
}
}
virtual void visit ( AstParseRef * nodep , AstNUser * ) {
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 ;
2012-12-31 17:05:13 -05:00
bool start = ! m_ds . m_dotp ;
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 );
pushDeletep ( nodep ); nodep = NULL ;
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
AstPackage * packagep = NULL ;
if ( m_ds . m_dotPos == DP_PACKAGE ) {
// {package}::{a}
expectWhat = "scope/variable" ;
allowScope = true ;
allowVar = true ;
if ( ! m_ds . m_dotp -> lhsp () -> castPackageRef ()) m_ds . m_dotp -> lhsp () -> v3fatalSrc ( "Bad package link" );
packagep = m_ds . m_dotp -> lhsp () -> castPackageRef () -> packagep ();
if ( ! packagep ) m_ds . m_dotp -> lhsp () -> v3fatalSrc ( "Bad package link" );
m_ds . m_dotSymp = m_statep -> getNodeSym ( packagep );
m_ds . m_dotPos = DP_SCOPE ;
} else if ( m_ds . m_dotPos == DP_SCOPE ) {
2012-07-24 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
}
2013-05-27 20:56:20 -04:00
if ( foundp ) UINFO ( 9 , " found=se" << ( void * ) foundp << " exp=" << expectWhat
<< " n=" << foundp -> nodep () << endl );
2012-07-24 06:26:35 -04:00
// What fell out?
bool ok = false ;
if ( foundp -> nodep () -> castCell () || foundp -> nodep () -> castBegin ()
|| foundp -> nodep () -> castModule ()) { // if top
if ( allowScope ) {
ok = true ;
2012-12-31 14:00:04 -05:00
if ( m_ds . m_dotText != "" ) m_ds . m_dotText += "." ;
m_ds . m_dotText += nodep -> name ();
m_ds . m_dotSymp = foundp ;
m_ds . m_dotPos = DP_SCOPE ;
2012-07-24 06:26:35 -04:00
// Upper AstDot visitor will handle it from here
}
2013-05-27 21:39:19 -04:00
else if ( foundp -> nodep () -> castCell ()
&& allowVar && m_cellp
&& foundp -> nodep () -> castCell () -> modp () -> castIface ()) {
// Interfaces can be referenced like a variable for interconnect
AstCell * cellp = foundp -> nodep () -> castCell ();
VSymEnt * cellEntp = m_statep -> getNodeSym ( cellp ); if ( ! cellEntp ) nodep -> v3fatalSrc ( "No interface sym entry" );
VSymEnt * parentEntp = cellEntp -> parentp (); // Container of the var; probably a module or generate begin
string findName = nodep -> name () + "__Viftop" ;
AstVar * ifaceRefVarp = parentEntp -> findIdFallback ( findName ) -> nodep () -> castVar ();
if ( ! ifaceRefVarp ) nodep -> v3fatalSrc ( "Can't find interface var ref: " << findName );
//
ok = true ;
if ( m_ds . m_dotText != "" ) m_ds . m_dotText += "." ;
m_ds . m_dotText += nodep -> name ();
m_ds . m_dotSymp = foundp ;
m_ds . m_dotPos = DP_SCOPE ;
UINFO ( 9 , " cell -> iface varref " << foundp -> nodep () << endl );
AstNode * newp = new AstVarRef ( ifaceRefVarp -> fileline (), ifaceRefVarp , false );
nodep -> replaceWith ( newp ); pushDeletep ( nodep ); nodep = NULL ;
}
2012-07-24 06:26:35 -04:00
}
else if ( AstVar * varp = foundp -> nodep () -> castVar ()) {
2013-05-27 21:39:19 -04:00
if ( AstIfaceRefDType * ifacerefp = varp -> subDTypep () -> castIfaceRefDType ()) {
if ( ! ifacerefp -> ifaceViaCellp ()) ifacerefp -> v3fatalSrc ( "Unlinked interface" );
// Really this is a scope reference into an interface
UINFO ( 9 , "varref-ifaceref " << m_ds . m_dotText << " " << nodep << endl );
if ( m_ds . m_dotText != "" ) m_ds . m_dotText += "." ;
m_ds . m_dotText += nodep -> name ();
m_ds . m_dotSymp = m_statep -> getNodeSym ( ifacerefp -> ifaceViaCellp ());
m_ds . m_dotPos = DP_SCOPE ;
ok = true ;
AstNode * newp = new AstVarRef ( nodep -> fileline (), varp , false );
nodep -> replaceWith ( newp ); pushDeletep ( nodep ); nodep = NULL ;
}
else if ( allowVar ) {
2012-07-24 06:26:35 -04:00
AstNodeVarRef * newp ;
2012-12-31 14:00:04 -05:00
if ( m_ds . m_dotText != "" ) {
newp = new AstVarXRef ( nodep -> fileline (), nodep -> name (), m_ds . m_dotText , false ); // lvalue'ness computed later
2012-07-24 06:26:35 -04:00
newp -> varp ( varp );
2012-12-31 14:00:04 -05:00
m_ds . m_dotText = "" ;
2012-07-24 06:26:35 -04:00
} else {
newp = new AstVarRef ( nodep -> fileline (), nodep -> name (), false ); // lvalue'ness computed later
newp -> varp ( varp );
newp -> packagep ( foundp -> packagep ());
2013-02-21 23:38:29 -05:00
UINFO ( 9 , " new " << newp << endl );
2012-07-24 06:26:35 -04:00
}
nodep -> replaceWith ( newp ); pushDeletep ( nodep ); nodep = NULL ;
2012-12-31 14:00:04 -05:00
m_ds . m_dotPos = DP_MEMBER ;
2012-07-24 06:26:35 -04:00
ok = true ;
}
}
2013-05-27 21:39:19 -04:00
else if ( AstModport * modportp = foundp -> nodep () -> castModport ()) {
// A scope reference into an interface's modport (not necessarily at a pin connection)
UINFO ( 9 , "cell-ref-to-modport " << m_ds . m_dotText << " " << nodep << endl );
UINFO ( 9 , "dotSymp " << m_ds . m_dotSymp << " " << m_ds . m_dotSymp -> nodep () << endl );
// Iface was the previously dotted component
if ( ! m_ds . m_dotSymp
|| ! m_ds . m_dotSymp -> nodep () -> castCell ()
|| ! m_ds . m_dotSymp -> nodep () -> castCell () -> modp ()
|| ! m_ds . m_dotSymp -> nodep () -> castCell () -> modp () -> castIface ()) {
nodep -> v3error ( "Modport not referenced as <interface>." << modportp -> prettyName ());
} else if ( ! m_ds . m_dotSymp -> nodep () -> castCell () -> modp ()
|| ! m_ds . m_dotSymp -> nodep () -> castCell () -> modp () -> castIface ()) {
nodep -> v3error ( "Modport not referenced from underneath an interface: " << modportp -> prettyName ());
} else {
AstCell * cellp = m_ds . m_dotSymp -> nodep () -> castCell ();
if ( ! cellp ) nodep -> v3fatalSrc ( "Modport not referenced from a cell" );
AstIface * ifacep = cellp -> modp () -> castIface ();
//string cellName = m_ds.m_dotText; // Use cellp->name
if ( m_ds . m_dotText != "" ) m_ds . m_dotText += "." ;
m_ds . m_dotText += nodep -> name ();
m_ds . m_dotSymp = m_statep -> getNodeSym ( modportp );
m_ds . m_dotPos = DP_SCOPE ;
ok = true ;
AstVar * varp = makeIfaceModportVar ( nodep -> fileline (), cellp , ifacep , modportp );
AstVarRef * refp = new AstVarRef ( varp -> fileline (), varp , false );
nodep -> replaceWith ( refp ); pushDeletep ( nodep ); nodep = NULL ;
}
}
2012-07-24 06:26:35 -04:00
else if ( AstEnumItem * valuep = foundp -> nodep () -> castEnumItem ()) {
if ( allowVar ) {
AstNode * newp = new AstEnumItemRef ( nodep -> fileline (), valuep , foundp -> packagep ());
nodep -> replaceWith ( newp ); pushDeletep ( nodep ); nodep = NULL ;
ok = true ;
2012-12-31 14:00:04 -05:00
m_ds . m_dotText = "" ;
2012-07-24 06:26:35 -04:00
}
}
//
if ( ! ok ) {
2012-12-31 17:05:13 -05:00
bool checkImplicit = ( ! m_ds . m_dotp && m_ds . m_dotText == "" );
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 == "" ) {
2012-12-31 17:05:13 -05:00
UINFO ( 7 , " ErrParseRef curSymp=se" << ( void * ) 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 );
pushDeletep ( nodep ); nodep = NULL ;
createImplicitVar ( m_curSymp , newp , m_modp , m_modSymp , err );
}
}
}
if ( start ) {
2012-12-31 14:00:04 -05:00
m_ds = lastStates ;
2012-07-24 06:26:35 -04:00
}
}
2012-07-21 17:12:42 -04:00
virtual void visit ( AstVarRef * nodep , AstNUser * ) {
// 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
2012-07-21 17:12:42 -04:00
nodep -> iterateChildren ( * this );
if ( ! nodep -> varp ()) {
2012-07-24 06:26:35 -04:00
UINFO ( 9 , " linkVarRef se" << ( void * ) m_curSymp << " n=" << nodep << endl );
if ( ! m_curSymp ) nodep -> v3fatalSrc ( "NULL lookup symbol table" );
VSymEnt * foundp = m_curSymp -> findIdFallback ( nodep -> name ());
if ( AstVar * varp = foundp -> nodep () -> castVar ()) {
nodep -> varp ( varp );
nodep -> packagep ( foundp -> packagep ()); // Generally set by parse, but might be an import
}
2012-07-21 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
}
}
}
2006-08-26 11:35:28 +00:00
virtual void visit ( AstVarXRef * nodep , AstNUser * ) {
// VarRef: Resolve its reference
// We always link even if varp() is set, because the module we choose may change
// due to creating new modules, flattening, etc.
2012-07-24 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 );
AstVar * varp = foundp -> nodep () -> castVar (); // maybe NULL
2006-08-26 11:35:28 +00:00
nodep -> varp ( varp );
UINFO ( 7 , " Resolved " << nodep << endl ); // Also prints varp
if ( ! nodep -> varp ()) {
nodep -> v3error ( "Can't find definition of '" << baddot << "' in dotted signal: " << nodep -> dotted () + "." + nodep -> prettyName ());
2012-06-20 06:13:28 -04:00
okSymp -> cellErrorScopes ( 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 );
AstVarScope * vscp = foundp -> nodep () -> castVarScope (); // maybe NULL
2006-08-26 11:35:28 +00:00
if ( ! vscp ) {
nodep -> v3error ( "Can't find varpin scope of '" << baddot << "' in dotted signal: " << nodep -> dotted () + "." + nodep -> prettyName ());
2012-06-20 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
vscp = vscp -> user2p () -> castNode () -> castVarScope ();
}
// Convert the VarXRef to a VarRef, so we don't need later optimizations to deal with VarXRef.
nodep -> varp ( vscp -> varp ());
nodep -> varScopep ( vscp );
UINFO ( 7 , " Resolved " << nodep << endl ); // Also prints taskp
AstVarRef * newvscp = new AstVarRef ( nodep -> fileline (), vscp , nodep -> lvalue ());
nodep -> replaceWith ( newvscp );
nodep -> deleteTree (); nodep = NULL ;
2013-02-21 23:38:29 -05:00
UINFO ( 9 , " new " << newvscp << endl ); // Also prints taskp
2006-08-26 11:35:28 +00:00
}
}
}
}
2013-02-02 14:11:50 -05:00
virtual void visit ( AstEnumItemRef * nodep , AstNUser * ) {
// EnumItemRef may be under a dot. Should already be resolved.
nodep -> iterateChildren ( * this );
}
2012-07-21 17:12:42 -04:00
virtual void visit ( AstVar * nodep , AstNUser * ) {
2012-12-31 17:05:13 -05:00
checkNoDot ( nodep );
2012-07-21 17:12:42 -04:00
nodep -> iterateChildren ( * this );
if ( m_statep -> forPrimary () && nodep -> isIO () && ! m_ftaskp && ! nodep -> user4 ()) {
nodep -> v3error ( "Input/output/inout does not appear in port list: " << nodep -> prettyName ());
}
}
2006-08-26 11:35:28 +00:00
virtual void visit ( AstNodeFTaskRef * nodep , AstNUser * ) {
2012-07-24 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 ) {
if ( ! m_ds . m_dotp -> lhsp () -> castPackageRef ()) m_ds . m_dotp -> lhsp () -> v3fatalSrc ( "Bad package link" );
if ( ! m_ds . m_dotp -> lhsp () -> castPackageRef () -> packagep ()) m_ds . m_dotp -> lhsp () -> v3fatalSrc ( "Bad package link" );
nodep -> packagep ( m_ds . m_dotp -> lhsp () -> castPackageRef () -> packagep ());
m_ds . m_dotPos = DP_SCOPE ;
m_ds . m_dotp = NULL ;
} else if ( m_ds . m_dotp && m_ds . m_dotPos == DP_FINAL ) {
nodep -> dotted ( m_ds . m_dotText ); // Maybe ""
} 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
}
2012-07-21 17:12:42 -04:00
VSymEnt * foundp = NULL ;
AstNodeFTask * taskp = NULL ;
foundp = m_statep -> findSymPrefixed ( dotSymp , nodep -> name (), baddot );
2013-02-03 13:27:37 -05:00
taskp = foundp ? foundp -> nodep () -> castNodeFTask () : 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
UINFO ( 7 , " ErrFtask curSymp=se" << ( void * ) m_curSymp << " dotSymp=se" << ( void * ) 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 {
nodep -> v3error ( "Can't find definition of '" << baddot << "' in dotted task/function: " << nodep -> dotted () + "." + nodep -> prettyName ());
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 );
nodep -> iterateChildren ( * this );
}
m_ds = lastStates ;
2012-07-21 17:12:42 -04:00
}
2012-07-24 06:26:35 -04:00
virtual void visit ( AstSelBit * nodep , AstNUser * ) {
if ( nodep -> user3SetOnce ()) return ;
2012-11-03 09:17:42 -04:00
nodep -> lhsp () -> iterateAndNext ( * this );
2012-12-31 14:00:04 -05:00
if ( m_ds . m_dotPos == DP_SCOPE ) { // Already under dot, so this is {modulepart} DOT {modulepart}
2012-07-24 06:26:35 -04:00
if ( AstConst * constp = nodep -> rhsp () -> castConst ()) {
string index = AstNode :: encodeNumber ( constp -> toSInt ());
2012-12-31 14:00:04 -05:00
m_ds . m_dotText += "__BRA__" + index + "__KET__" ;
2012-07-24 06:26:35 -04:00
} else {
nodep -> v3error ( "Unsupported: Non-constant inside []'s in the cell part of a dotted reference" );
}
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()
2012-11-03 09:17:42 -04:00
nodep -> fromp () -> iterateAndNext ( * this );
2012-12-31 17:05:13 -05:00
DotStates lastStates = m_ds ;
{
m_ds . init ( m_curSymp );
nodep -> bitp () -> iterateAndNext ( * this );
nodep -> attrp () -> iterateAndNext ( * this );
}
m_ds = lastStates ;
}
virtual void visit ( AstNodePreSel * nodep , AstNUser * ) {
// Excludes simple AstSelBit, see above
if ( nodep -> user3SetOnce ()) return ;
if ( m_ds . m_dotPos == DP_SCOPE ) { // Already under dot, so this is {modulepart} DOT {modulepart}
nodep -> v3error ( "Syntax Error: Range ':', '+:' etc are not allowed in the cell part of a dotted reference" );
m_ds . m_dotErr = true ;
return ;
}
nodep -> lhsp () -> iterateAndNext ( * this );
DotStates lastStates = m_ds ;
{
m_ds . init ( m_curSymp );
nodep -> rhsp () -> iterateAndNext ( * this );
nodep -> thsp () -> iterateAndNext ( * this );
2013-01-25 21:27:19 -05:00
nodep -> attrp () -> iterateAndNext ( * this );
2012-12-31 17:05:13 -05:00
}
m_ds = lastStates ;
}
virtual void visit ( AstMemberSel * nodep , AstNUser * ) {
// checkNoDot not appropriate, can be under a dot
nodep -> iterateChildren ( * this );
2012-07-24 06:26:35 -04:00
}
2012-07-21 17:12:42 -04:00
virtual void visit ( AstBegin * nodep , AstNUser * ) {
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 );
2012-07-21 17:12:42 -04:00
UINFO ( 5 , " cur=se" << ( void * ) m_curSymp << endl );
nodep -> iterateChildren ( * this );
}
2012-12-31 14:00:04 -05:00
m_ds . m_dotSymp = m_curSymp = oldCurSymp ;
2012-07-21 17:12:42 -04:00
UINFO ( 5 , " cur=se" << ( void * ) m_curSymp << endl );
}
virtual void visit ( AstNodeFTask * nodep , AstNUser * ) {
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 );
2012-07-21 17:12:42 -04:00
nodep -> iterateChildren ( * this );
}
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 ;
}
virtual void visit ( AstRefDType * nodep , AstNUser * ) {
// 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 ) {
if ( ! m_ds . m_dotp -> lhsp () -> castPackageRef ()) m_ds . m_dotp -> lhsp () -> v3fatalSrc ( "Bad package link" );
if ( ! m_ds . m_dotp -> lhsp () -> castPackageRef () -> packagep ()) m_ds . m_dotp -> lhsp () -> v3fatalSrc ( "Bad package link" );
nodep -> packagep ( m_ds . m_dotp -> lhsp () -> castPackageRef () -> packagep ());
m_ds . m_dotPos = DP_SCOPE ;
m_ds . m_dotp = NULL ;
} else {
checkNoDot ( nodep );
}
2012-07-21 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 ());
}
if ( AstTypedef * defp = foundp -> nodep () -> castTypedef ()) {
nodep -> refDTypep ( defp -> subDTypep ());
nodep -> packagep ( foundp -> packagep ());
} else {
nodep -> v3error ( "Can't find typedef: " << nodep -> prettyName ());
2006-08-26 11:35:28 +00:00
}
}
nodep -> iterateChildren ( * this );
}
2012-07-21 17:12:42 -04:00
virtual void visit ( AstDpiExport * nodep , AstNUser * ) {
// AstDpiExport: Make sure the function referenced exists, then dump it
nodep -> iterateChildren ( * this );
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 ());
AstNodeFTask * taskp = foundp -> nodep () -> castNodeFTask ();
if ( ! taskp ) { nodep -> v3error ( "Can't find definition of exported task/function: " << nodep -> prettyName ()); }
else if ( taskp -> dpiExport ()) {
nodep -> v3error ( "Function was already DPI Exported, duplicate not allowed: " << nodep -> prettyName ());
} else {
taskp -> dpiExport ( true );
if ( nodep -> cname () != "" ) taskp -> cname ( nodep -> cname ());
}
nodep -> unlinkFrBack () -> deleteTree ();
}
2012-08-08 21:59:17 -04:00
virtual void visit ( AstPackageImport * nodep , AstNUser * ) {
// No longer needed
2012-12-31 17:05:13 -05:00
checkNoDot ( nodep );
2012-08-08 21:59:17 -04:00
nodep -> unlinkFrBack () -> deleteTree (); nodep = NULL ;
}
2006-08-26 11:35:28 +00:00
virtual void visit ( AstNode * nodep , AstNUser * ) {
// Default: Just iterate
2012-12-31 17:05:13 -05:00
checkNoDot ( nodep );
2006-08-26 11:35:28 +00:00
nodep -> iterateChildren ( * this );
}
public :
// CONSTUCTORS
LinkDotResolveVisitor ( AstNetlist * rootp , LinkDotState * statep ) {
UINFO ( 4 , __FUNCTION__ << ": " << endl );
m_statep = statep ;
2012-07-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
//
rootp -> accept ( * this );
}
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 ) {
2012-06-20 06:13:28 -04: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 );
2012-06-20 06:13:28 -04: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 );
if ( LinkDotState :: debug () >= 5 || v3Global . opt . dumpTree () >= 9 ) v3Global . rootp () -> dumpTreeFile ( v3Global . debugFilename ( "prelinkdot-param.tree" ));
}
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 );
2012-06-20 06:13:28 -04: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 );
}