2012-04-13 03:08:20 +02:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2006-08-26 13:35:28 +02:00
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Resolve module/signal name references
|
|
|
|
|
//
|
2019-11-08 04:33:59 +01:00
|
|
|
// Code available from: https://verilator.org
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2023-01-01 16:18:39 +01:00
|
|
|
// Copyright 2003-2023 by Wilson Snyder. This program is free software; you
|
2020-03-21 16:24:24 +01:00
|
|
|
// can redistribute it and/or modify it under the terms of either the GNU
|
2009-05-04 23:07:57 +02:00
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
|
// Version 2.0.
|
2020-03-21 16:24:24 +01:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// LinkDot TRANSFORMATIONS:
|
2019-05-19 22:13:13 +02:00
|
|
|
// Top-down traversal in LinkDotFindVisitor
|
|
|
|
|
// Cells:
|
|
|
|
|
// Make graph of cell hierarchy
|
|
|
|
|
// Var/Funcs's:
|
|
|
|
|
// Collect all names into symtable under appropriate cell
|
|
|
|
|
// Top-down traversal in LinkDotScopeVisitor
|
|
|
|
|
// Find VarScope versions of signals (well past original link)
|
|
|
|
|
// Top-down traversal in LinkDotParamVisitor
|
|
|
|
|
// Create implicit signals
|
|
|
|
|
// Top-down traversal in LinkDotResolveVisitor
|
|
|
|
|
// VarXRef/Func's:
|
|
|
|
|
// Find appropriate named cell and link to var they reference
|
2006-08-26 13:35:28 +02:00
|
|
|
//*************************************************************************
|
2013-05-28 03:39:19 +02:00
|
|
|
// Interfaces:
|
2019-05-19 22:13:13 +02:00
|
|
|
// CELL (.port (ifref)
|
|
|
|
|
// ^--- cell -> IfaceDTypeRef(iface)
|
|
|
|
|
// ^--- cell.modport -> IfaceDTypeRef(iface,modport)
|
|
|
|
|
// ^--- varref(input_ifref) -> IfaceDTypeRef(iface)
|
|
|
|
|
// ^--- varref(input_ifref).modport -> IfaceDTypeRef(iface,modport)
|
|
|
|
|
// FindVisitor:
|
|
|
|
|
// #1: Insert interface Vars
|
|
|
|
|
// #2: Insert ModPort names
|
|
|
|
|
// IfaceVisitor:
|
|
|
|
|
// #3: Update ModPortVarRef to point at interface vars (after #1)
|
|
|
|
|
// #4: Create ModPortVarRef symbol table entries
|
|
|
|
|
// FindVisitor-insertIfaceRefs()
|
|
|
|
|
// #5: Resolve IfaceRefDtype modport names (after #2)
|
|
|
|
|
// #7: Record sym of IfaceRefDType and aliased interface and/or modport (after #4,#5)
|
|
|
|
|
// insertAllScopeAliases():
|
|
|
|
|
// #8: Insert modport's symbols under IfaceRefDType (after #7)
|
|
|
|
|
// ResolveVisitor:
|
|
|
|
|
// #9: Resolve general variables, which may point into the interface or modport (after #8)
|
2020-11-09 04:43:32 +01:00
|
|
|
// LinkResolve:
|
|
|
|
|
// #10: Unlink modports, not needed later except for XML/Lint
|
2013-05-28 03:39:19 +02:00
|
|
|
//*************************************************************************
|
2012-06-20 12:13:28 +02:00
|
|
|
// TOP
|
|
|
|
|
// {name-of-top-modulename}
|
|
|
|
|
// a (VSymEnt->AstCell)
|
2019-05-19 22:13:13 +02:00
|
|
|
// {name-of-cell}
|
|
|
|
|
// {name-of-cell-module}
|
2012-06-20 12:13:28 +02:00
|
|
|
// aa (VSymEnt->AstCell)
|
|
|
|
|
// var (AstVar) -- no sub symbol table needed
|
|
|
|
|
// beg (VSymEnt->AstBegin) -- can see "upper" a's symbol table
|
|
|
|
|
// a__DOT__aa (VSymEnt->AstCellInline) -- points to a.aa's symbol table
|
|
|
|
|
// b (VSymEnt->AstCell)
|
2012-06-20 12:09:07 +02:00
|
|
|
//*************************************************************************
|
2019-10-05 02:17:11 +02:00
|
|
|
|
2006-12-18 20:20:45 +01:00
|
|
|
#include "config_build.h"
|
|
|
|
|
#include "verilatedos.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
#include "V3LinkDot.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Ast.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
#include "V3Global.h"
|
|
|
|
|
#include "V3Graph.h"
|
2018-03-16 00:46:05 +01:00
|
|
|
#include "V3String.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
#include "V3SymTable.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2018-10-14 19:43:24 +02:00
|
|
|
#include <algorithm>
|
|
|
|
|
#include <map>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
2022-09-18 21:53:42 +02:00
|
|
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
// Matcher classes (for suggestion matching)
|
2019-07-14 02:30:32 +02:00
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class LinkNodeMatcherClass final : public VNodeMatcher {
|
2020-08-24 01:37:56 +02:00
|
|
|
public:
|
2022-09-16 12:22:11 +02:00
|
|
|
bool nodeMatch(const AstNode* nodep) const override { return VN_IS(nodep, Class); }
|
2020-08-24 01:37:56 +02:00
|
|
|
};
|
2020-11-19 03:32:16 +01:00
|
|
|
class LinkNodeMatcherFTask final : public VNodeMatcher {
|
2019-07-14 02:30:32 +02:00
|
|
|
public:
|
2022-09-16 12:22:11 +02:00
|
|
|
bool nodeMatch(const AstNode* nodep) const override { return VN_IS(nodep, NodeFTask); }
|
2019-07-14 02:30:32 +02:00
|
|
|
};
|
2020-11-19 03:32:16 +01:00
|
|
|
class LinkNodeMatcherModport final : public VNodeMatcher {
|
2019-07-14 02:30:32 +02:00
|
|
|
public:
|
2022-09-16 12:22:11 +02:00
|
|
|
bool nodeMatch(const AstNode* nodep) const override { return VN_IS(nodep, Modport); }
|
2019-07-14 02:30:32 +02:00
|
|
|
};
|
2020-11-19 03:32:16 +01:00
|
|
|
class LinkNodeMatcherVar final : public VNodeMatcher {
|
2019-07-14 02:30:32 +02:00
|
|
|
public:
|
2022-09-16 12:22:11 +02:00
|
|
|
bool nodeMatch(const AstNode* nodep) const override {
|
2020-11-01 16:56:07 +01:00
|
|
|
return VN_IS(nodep, Var) || VN_IS(nodep, LambdaArgRef);
|
|
|
|
|
}
|
2019-07-14 02:30:32 +02:00
|
|
|
};
|
2020-11-19 03:32:16 +01:00
|
|
|
class LinkNodeMatcherVarIO final : public VNodeMatcher {
|
2019-07-14 02:30:32 +02:00
|
|
|
public:
|
2022-09-16 12:22:11 +02:00
|
|
|
bool nodeMatch(const AstNode* nodep) const override {
|
2021-11-13 19:50:44 +01:00
|
|
|
const AstVar* const varp = VN_CAST(nodep, Var);
|
2019-07-14 02:30:32 +02:00
|
|
|
if (!varp) return false;
|
|
|
|
|
return varp->isIO();
|
|
|
|
|
}
|
|
|
|
|
};
|
2020-11-19 03:32:16 +01:00
|
|
|
class LinkNodeMatcherVarParam final : public VNodeMatcher {
|
2019-07-14 02:30:32 +02:00
|
|
|
public:
|
2022-09-16 12:22:11 +02:00
|
|
|
bool nodeMatch(const AstNode* nodep) const override {
|
2021-11-13 19:50:44 +01:00
|
|
|
const AstVar* const varp = VN_CAST(nodep, Var);
|
2019-07-14 02:30:32 +02:00
|
|
|
if (!varp) return false;
|
|
|
|
|
return varp->isParam();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//######################################################################
|
|
|
|
|
// LinkDot state, as a visitor of each AstNode
|
|
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class LinkDotState final {
|
2006-08-26 13:35:28 +02:00
|
|
|
private:
|
|
|
|
|
// NODE STATE
|
|
|
|
|
// Cleared on Netlist
|
2019-05-19 22:13:13 +02:00
|
|
|
// AstNodeModule::user1p() // VSymEnt*. Last symbol created for this node
|
|
|
|
|
// AstNodeModule::user2() // bool. Currently processing for recursion check
|
|
|
|
|
// ... Note maybe more than one, as can be multiple hierarchy places
|
|
|
|
|
// AstVarScope::user2p() // AstVarScope*. Base alias for AstInline of this signal
|
|
|
|
|
// AstVar::user2p() // AstFTask*. If a function variable, the task
|
|
|
|
|
// that links to the variable
|
|
|
|
|
// AstVar::user4() // bool. True if port set for this variable
|
2020-04-23 03:31:40 +02:00
|
|
|
// AstNodeBlock::user4() // bool. Did name processing
|
2019-05-19 22:13:13 +02:00
|
|
|
// AstNodeModule::user4() // bool. Live module
|
2022-01-02 19:56:40 +01:00
|
|
|
const VNUser1InUse m_inuser1;
|
|
|
|
|
const VNUser2InUse m_inuser2;
|
|
|
|
|
const VNUser4InUse m_inuser4;
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2014-04-04 03:53:39 +02:00
|
|
|
public:
|
|
|
|
|
// ENUMS
|
|
|
|
|
// In order of priority, compute first ... compute last
|
2020-08-16 18:05:35 +02:00
|
|
|
enum SAMNum : uint8_t { SAMN_MODPORT, SAMN_IFTOP, SAMN__MAX }; // Values for m_scopeAliasMap
|
2014-04-04 03:53:39 +02:00
|
|
|
|
|
|
|
|
private:
|
2006-08-26 13:35:28 +02:00
|
|
|
// TYPES
|
2021-03-13 00:10:45 +01:00
|
|
|
using ScopeAliasMap = std::unordered_map<VSymEnt*, VSymEnt*>;
|
|
|
|
|
using IfaceModSyms = std::vector<std::pair<AstIface*, VSymEnt*>>;
|
2012-07-22 03:18:07 +02:00
|
|
|
|
2020-04-15 13:58:34 +02:00
|
|
|
static LinkDotState* s_errorThisp; // Last self, for error reporting only
|
2013-05-25 18:15:38 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
// MEMBERS
|
2020-04-15 13:58:34 +02:00
|
|
|
VSymGraph m_syms; // Symbol table
|
2022-01-01 17:46:49 +01:00
|
|
|
VSymEnt* m_dunitEntp = nullptr; // $unit entry
|
2021-03-12 23:26:53 +01:00
|
|
|
std::multimap<std::string, VSymEnt*>
|
|
|
|
|
m_nameScopeSymMap; // Map of scope referenced by non-pretty textual name
|
|
|
|
|
std::set<std::pair<AstNodeModule*, std::string>>
|
|
|
|
|
m_implicitNameSet; // For [module][signalname] if we can implicitly create it
|
2020-11-15 22:21:26 +01:00
|
|
|
std::array<ScopeAliasMap, SAMN__MAX> m_scopeAliasMap; // Map of <lhs,rhs> aliases
|
2021-03-12 23:26:53 +01:00
|
|
|
std::vector<VSymEnt*> m_ifaceVarSyms; // List of AstIfaceRefDType's to be imported
|
2020-04-15 13:58:34 +02:00
|
|
|
IfaceModSyms m_ifaceModSyms; // List of AstIface+Symbols to be processed
|
|
|
|
|
bool m_forPrimary; // First link
|
|
|
|
|
bool m_forPrearray; // Compress cell__[array] refs
|
|
|
|
|
bool m_forScopeCreation; // Remove VarXRefs for V3Scope
|
2022-10-20 03:59:26 +02:00
|
|
|
bool m_removeVoidParamedClasses; // Remove classes with void params
|
2013-05-25 18:15:38 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
public:
|
2018-05-14 12:50:47 +02:00
|
|
|
// METHODS
|
2022-09-18 21:53:42 +02:00
|
|
|
|
|
|
|
|
void dumpSelf(const string& nameComment = "linkdot", bool force = false) {
|
|
|
|
|
if (dump() >= 6 || force) {
|
2021-06-21 00:32:57 +02:00
|
|
|
const string filename = v3Global.debugFilename(nameComment) + ".txt";
|
2021-07-12 00:42:01 +02:00
|
|
|
const std::unique_ptr<std::ofstream> logp{V3File::new_ofstream(filename)};
|
2020-04-15 13:58:34 +02:00
|
|
|
if (logp->fail()) v3fatal("Can't write " << filename);
|
2018-02-02 03:24:41 +01:00
|
|
|
std::ostream& os = *logp;
|
2022-09-18 21:53:42 +02:00
|
|
|
m_syms.dumpSelf(os);
|
2019-05-19 22:13:13 +02:00
|
|
|
bool first = true;
|
2020-04-15 13:58:34 +02:00
|
|
|
for (int samn = 0; samn < SAMN__MAX; ++samn) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!m_scopeAliasMap[samn].empty()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (first) os << "\nScopeAliasMap:\n";
|
2019-05-19 22:13:13 +02:00
|
|
|
first = false;
|
|
|
|
|
for (ScopeAliasMap::iterator it = m_scopeAliasMap[samn].begin();
|
|
|
|
|
it != m_scopeAliasMap[samn].end(); ++it) {
|
|
|
|
|
// left side is what we will import into
|
2020-04-15 13:58:34 +02:00
|
|
|
os << "\t" << samn << "\t" << it->first << " ("
|
|
|
|
|
<< it->first->nodep()->typeName() << ") <- " << it->second << " "
|
2020-11-19 03:03:23 +01:00
|
|
|
<< it->second->nodep() << '\n';
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-07-21 15:27:57 +02:00
|
|
|
}
|
2013-05-25 18:15:38 +02:00
|
|
|
static void preErrorDumpHandler() {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (s_errorThisp) s_errorThisp->preErrorDump();
|
2013-05-25 18:15:38 +02:00
|
|
|
}
|
2012-07-21 15:27:57 +02:00
|
|
|
void preErrorDump() {
|
2019-05-19 22:13:13 +02:00
|
|
|
static bool diddump = false;
|
2022-09-18 21:53:42 +02:00
|
|
|
if (!diddump && dumpTree()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
diddump = true;
|
2022-09-18 21:53:42 +02:00
|
|
|
dumpSelf("linkdot-preerr", true);
|
2019-05-19 22:13:13 +02:00
|
|
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkdot-preerr.tree"));
|
|
|
|
|
}
|
2012-07-21 15:27:57 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// CONSTRUCTORS
|
2012-07-21 15:27:57 +02:00
|
|
|
LinkDotState(AstNetlist* rootp, VLinkDotStep step)
|
2020-08-16 15:55:36 +02:00
|
|
|
: m_syms{rootp} {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, __FUNCTION__ << ": " << endl);
|
|
|
|
|
m_forPrimary = (step == LDS_PRIMARY);
|
|
|
|
|
m_forPrearray = (step == LDS_PARAMED || step == LDS_PRIMARY);
|
2019-05-19 22:13:13 +02:00
|
|
|
m_forScopeCreation = (step == LDS_SCOPED);
|
2022-10-20 03:59:26 +02:00
|
|
|
m_removeVoidParamedClasses = (step == LDS_PARAMED);
|
2019-05-19 22:13:13 +02:00
|
|
|
s_errorThisp = this;
|
|
|
|
|
V3Error::errorExitCb(preErrorDumpHandler); // If get error, dump self
|
2013-05-25 18:15:38 +02:00
|
|
|
}
|
|
|
|
|
~LinkDotState() {
|
2020-08-15 16:12:55 +02:00
|
|
|
V3Error::errorExitCb(nullptr);
|
|
|
|
|
s_errorThisp = nullptr;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2008-06-10 03:25:10 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
// ACCESSORS
|
2012-12-18 02:26:40 +01:00
|
|
|
VSymGraph* symsp() { return &m_syms; }
|
2012-07-21 23:12:42 +02:00
|
|
|
bool forPrimary() const { return m_forPrimary; }
|
|
|
|
|
bool forPrearray() const { return m_forPrearray; }
|
2006-08-26 13:35:28 +02:00
|
|
|
bool forScopeCreation() const { return m_forScopeCreation; }
|
2022-10-20 03:59:26 +02:00
|
|
|
bool removeVoidParamedClasses() const { return m_removeVoidParamedClasses; }
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// METHODS
|
2012-07-21 23:12:42 +02:00
|
|
|
static string nodeTextType(AstNode* nodep) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (VN_IS(nodep, Var)) {
|
|
|
|
|
return "variable";
|
|
|
|
|
} else if (VN_IS(nodep, Cell)) {
|
2020-12-13 04:43:55 +01:00
|
|
|
return "instance";
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (VN_IS(nodep, Task)) {
|
|
|
|
|
return "task";
|
|
|
|
|
} else if (VN_IS(nodep, Func)) {
|
|
|
|
|
return "function";
|
|
|
|
|
} else if (VN_IS(nodep, Begin)) {
|
|
|
|
|
return "block";
|
|
|
|
|
} else if (VN_IS(nodep, Iface)) {
|
|
|
|
|
return "interface";
|
|
|
|
|
} else if (VN_IS(nodep, ParamTypeDType)) {
|
|
|
|
|
return "parameter type";
|
|
|
|
|
} else {
|
|
|
|
|
return nodep->prettyTypeName();
|
|
|
|
|
}
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VSymEnt* rootEntp() const { return m_syms.rootp(); }
|
|
|
|
|
VSymEnt* dunitEntp() const { return m_dunitEntp; }
|
|
|
|
|
void checkDuplicate(VSymEnt* lookupSymp, AstNode* nodep, const string& name) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Lookup the given name under current symbol table
|
|
|
|
|
// Insert if not found
|
|
|
|
|
// Report error if there's a duplicate
|
|
|
|
|
//
|
|
|
|
|
// Note we only check for conflicts at the same level; it's ok if one block hides another
|
|
|
|
|
// We also wouldn't want to not insert it even though it's lower down
|
2021-11-26 23:55:36 +01:00
|
|
|
const VSymEnt* const foundp = lookupSymp->findIdFlat(name);
|
2021-11-13 19:50:44 +01:00
|
|
|
AstNode* const fnodep = foundp ? foundp->nodep() : nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!fnodep) {
|
|
|
|
|
// Not found, will add in a moment.
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (nodep == fnodep) { // Already inserted.
|
2019-05-19 22:13:13 +02:00
|
|
|
// Good.
|
|
|
|
|
} else if (foundp->imported()) { // From package
|
|
|
|
|
// We don't throw VARHIDDEN as if the import is later the symbol
|
|
|
|
|
// table's import wouldn't warn
|
2018-02-02 03:32:58 +01:00
|
|
|
} else if (VN_IS(nodep, Begin) && VN_IS(fnodep, Begin)
|
2021-10-22 14:56:48 +02:00
|
|
|
&& VN_AS(nodep, Begin)->generate()) {
|
2022-03-31 02:17:59 +02:00
|
|
|
// Begin: ... blocks often replicate under genif/genfor, so
|
2019-05-19 22:13:13 +02:00
|
|
|
// suppress duplicate checks. See t_gen_forif.v for an example.
|
|
|
|
|
} else {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, "name " << name << endl); // Not always same as nodep->name
|
|
|
|
|
UINFO(4, "Var1 " << nodep << endl);
|
|
|
|
|
UINFO(4, "Var2 " << fnodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
if (nodep->type() == fnodep->type()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3error("Duplicate declaration of "
|
2023-01-28 17:55:44 +01:00
|
|
|
<< nodeTextType(fnodep) << ": " << AstNode::prettyNameQ(name)
|
|
|
|
|
<< '\n'
|
2020-11-19 03:03:23 +01:00
|
|
|
<< nodep->warnContextPrimary() << '\n'
|
2020-04-15 13:58:34 +02:00
|
|
|
<< fnodep->warnOther() << "... Location of original declaration\n"
|
|
|
|
|
<< fnodep->warnContextSecondary());
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3error("Unsupported in C: "
|
|
|
|
|
<< ucfirst(nodeTextType(nodep)) << " has the same name as "
|
2023-01-28 17:55:44 +01:00
|
|
|
<< nodeTextType(fnodep) << ": " << AstNode::prettyNameQ(name)
|
|
|
|
|
<< '\n'
|
2020-11-19 03:03:23 +01:00
|
|
|
<< nodep->warnContextPrimary() << '\n'
|
2020-04-15 13:58:34 +02:00
|
|
|
<< fnodep->warnOther() << "... Location of original declaration\n"
|
|
|
|
|
<< fnodep->warnContextSecondary());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
|
|
|
|
void insertDUnit(AstNetlist* nodep) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// $unit on top scope
|
2022-11-20 23:40:38 +01:00
|
|
|
VSymEnt* const symp = new VSymEnt{&m_syms, nodep};
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, " INSERTdunit se" << cvtToHex(symp) << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
symp->parentp(rootEntp()); // Needed so backward search can find name of top module
|
2020-08-15 16:12:55 +02:00
|
|
|
symp->fallbackp(nullptr);
|
2019-05-19 22:13:13 +02:00
|
|
|
rootEntp()->insert("$unit ", symp); // Space so can never name conflict with user code
|
|
|
|
|
//
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(!m_dunitEntp, nodep, "Call insertDUnit only once");
|
2019-05-19 22:13:13 +02:00
|
|
|
m_dunitEntp = symp;
|
2012-06-20 12:13:28 +02:00
|
|
|
}
|
|
|
|
|
VSymEnt* insertTopCell(AstNodeModule* nodep, const string& scopename) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Only called on the module at the very top of the hierarchy
|
2022-11-20 23:40:38 +01:00
|
|
|
VSymEnt* const symp = new VSymEnt{&m_syms, nodep};
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9,
|
|
|
|
|
" INSERTtop se" << cvtToHex(symp) << " " << scopename << " " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
symp->parentp(rootEntp()); // Needed so backward search can find name of top module
|
|
|
|
|
symp->fallbackp(dunitEntp()); // Needed so can find $unit stuff
|
|
|
|
|
nodep->user1p(symp);
|
|
|
|
|
checkDuplicate(rootEntp(), nodep, nodep->origName());
|
|
|
|
|
rootEntp()->insert(nodep->origName(), symp);
|
2020-12-19 00:24:47 +01:00
|
|
|
if (forScopeCreation()) m_nameScopeSymMap.emplace(scopename, symp);
|
2019-05-19 22:13:13 +02:00
|
|
|
return symp;
|
2012-06-20 12:13:28 +02:00
|
|
|
}
|
2022-10-01 16:48:37 +02:00
|
|
|
VSymEnt* insertTopIface(AstCell* nodep, const string& scopename) {
|
|
|
|
|
VSymEnt* const symp = new VSymEnt{&m_syms, nodep};
|
2022-10-01 16:53:40 +02:00
|
|
|
UINFO(9, " INSERTtopiface se" << cvtToHex(symp) << " " << scopename << " " << nodep
|
|
|
|
|
<< endl);
|
2022-10-01 16:48:37 +02:00
|
|
|
symp->parentp(rootEntp()); // Needed so backward search can find name of top module
|
|
|
|
|
symp->fallbackp(dunitEntp()); // Needed so can find $unit stuff
|
|
|
|
|
nodep->user1p(symp);
|
|
|
|
|
if (nodep->modp()) nodep->modp()->user1p(symp);
|
|
|
|
|
checkDuplicate(rootEntp(), nodep, nodep->origName());
|
|
|
|
|
rootEntp()->insert(nodep->origName(), symp);
|
|
|
|
|
if (forScopeCreation()) m_nameScopeSymMap.emplace(scopename, symp);
|
|
|
|
|
return symp;
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
VSymEnt* insertCell(VSymEnt* abovep, VSymEnt* modSymp, AstCell* nodep,
|
|
|
|
|
const string& scopename) {
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(abovep, nodep, "Null symbol table inserting node");
|
2022-11-20 23:40:38 +01:00
|
|
|
VSymEnt* const symp = new VSymEnt{&m_syms, nodep};
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, " INSERTcel se" << cvtToHex(symp) << " " << scopename << " above=se"
|
|
|
|
|
<< cvtToHex(abovep) << " mods=se" << cvtToHex(modSymp)
|
|
|
|
|
<< " node=" << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
symp->parentp(abovep);
|
|
|
|
|
symp->fallbackp(dunitEntp()); // Needed so can find $unit stuff
|
|
|
|
|
nodep->user1p(symp);
|
|
|
|
|
if (nodep->modp()) nodep->modp()->user1p(symp);
|
|
|
|
|
checkDuplicate(abovep, nodep, nodep->origName());
|
|
|
|
|
abovep->reinsert(nodep->origName(), symp);
|
|
|
|
|
if (forScopeCreation() && abovep != modSymp && !modSymp->findIdFlat(nodep->name())) {
|
|
|
|
|
// If it's foo_DOT_bar, we need to be able to find it under "foo_DOT_bar" too.
|
|
|
|
|
// Duplicates are possible, as until resolve generates might
|
|
|
|
|
// have 2 same cells under an if
|
|
|
|
|
modSymp->reinsert(nodep->name(), symp);
|
|
|
|
|
}
|
2020-12-19 00:24:47 +01:00
|
|
|
if (forScopeCreation()) m_nameScopeSymMap.emplace(scopename, symp);
|
2019-05-19 22:13:13 +02:00
|
|
|
return symp;
|
2012-06-20 12:13:28 +02:00
|
|
|
}
|
2020-04-05 15:30:23 +02:00
|
|
|
void insertMap(VSymEnt* symp, const string& scopename) {
|
2020-12-19 00:24:47 +01:00
|
|
|
if (forScopeCreation()) m_nameScopeSymMap.emplace(scopename, symp);
|
2020-04-05 15:30:23 +02:00
|
|
|
}
|
|
|
|
|
|
2020-04-15 13:58:34 +02:00
|
|
|
VSymEnt* insertInline(VSymEnt* abovep, VSymEnt* modSymp, AstCellInline* nodep,
|
|
|
|
|
const string& basename) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// A fake point in the hierarchy, corresponding to an inlined module
|
2019-09-09 13:50:21 +02:00
|
|
|
// This references to another Sym, and eventually resolves to a module with a prefix
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(abovep, nodep, "Null symbol table inserting node");
|
2022-11-20 23:40:38 +01:00
|
|
|
VSymEnt* const symp = new VSymEnt{&m_syms, nodep};
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, " INSERTinl se" << cvtToHex(symp) << " " << basename << " above=se"
|
|
|
|
|
<< cvtToHex(abovep) << " mods=se" << cvtToHex(modSymp)
|
|
|
|
|
<< " node=" << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
symp->parentp(abovep);
|
|
|
|
|
symp->fallbackp(modSymp);
|
2020-04-15 13:58:34 +02:00
|
|
|
symp->symPrefix(nodep->name() + "__DOT__");
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->user1p(symp);
|
|
|
|
|
checkDuplicate(abovep, nodep, nodep->name());
|
|
|
|
|
abovep->reinsert(basename, symp);
|
|
|
|
|
if (abovep != modSymp && !modSymp->findIdFlat(nodep->name())) {
|
|
|
|
|
// If it's foo_DOT_bar, we need to be able to find it under that too.
|
|
|
|
|
modSymp->reinsert(nodep->name(), symp);
|
|
|
|
|
}
|
|
|
|
|
return symp;
|
|
|
|
|
}
|
2020-04-12 20:53:10 +02:00
|
|
|
VSymEnt* insertBlock(VSymEnt* abovep, const string& name, AstNode* nodep,
|
2020-11-25 03:56:03 +01:00
|
|
|
AstNodeModule* classOrPackagep) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// A fake point in the hierarchy, corresponding to a begin or function/task block
|
|
|
|
|
// After we remove begins these will go away
|
|
|
|
|
// Note we fallback to the symbol table of the parent, as we want to find variables there
|
|
|
|
|
// However, cells walk the graph, so cells will appear under the begin/ftask itself
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(abovep, nodep, "Null symbol table inserting node");
|
2022-11-20 23:40:38 +01:00
|
|
|
VSymEnt* const symp = new VSymEnt{&m_syms, nodep};
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, " INSERTblk se" << cvtToHex(symp) << " above=se" << cvtToHex(abovep)
|
2020-11-26 02:05:44 +01:00
|
|
|
<< " pkg=" << cvtToHex(classOrPackagep) << " node=" << nodep
|
|
|
|
|
<< endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
symp->parentp(abovep);
|
2020-11-25 03:56:03 +01:00
|
|
|
symp->classOrPackagep(classOrPackagep);
|
2019-05-19 22:13:13 +02:00
|
|
|
symp->fallbackp(abovep);
|
|
|
|
|
nodep->user1p(symp);
|
2021-02-22 03:25:21 +01:00
|
|
|
if (name != "") checkDuplicate(abovep, nodep, name);
|
2019-05-19 22:13:13 +02:00
|
|
|
// Duplicates are possible, as until resolve generates might have 2 same cells under an if
|
|
|
|
|
abovep->reinsert(name, symp);
|
|
|
|
|
return symp;
|
|
|
|
|
}
|
2020-04-12 20:53:10 +02:00
|
|
|
VSymEnt* insertSym(VSymEnt* abovep, const string& name, AstNode* nodep,
|
2020-11-25 03:56:03 +01:00
|
|
|
AstNodeModule* classOrPackagep) {
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(abovep, nodep, "Null symbol table inserting node");
|
2022-11-20 23:40:38 +01:00
|
|
|
VSymEnt* const symp = new VSymEnt{&m_syms, nodep};
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, " INSERTsym se" << cvtToHex(symp) << " name='" << name << "' above=se"
|
2020-11-26 02:05:44 +01:00
|
|
|
<< cvtToHex(abovep) << " pkg=" << cvtToHex(classOrPackagep)
|
|
|
|
|
<< " node=" << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
// We don't remember the ent associated with each node, because we
|
|
|
|
|
// need a unique scope entry for each instantiation
|
2020-11-25 03:56:03 +01:00
|
|
|
symp->classOrPackagep(classOrPackagep);
|
2019-05-19 22:13:13 +02:00
|
|
|
symp->parentp(abovep);
|
|
|
|
|
symp->fallbackp(abovep);
|
|
|
|
|
nodep->user1p(symp);
|
|
|
|
|
checkDuplicate(abovep, nodep, name);
|
|
|
|
|
abovep->reinsert(name, symp);
|
|
|
|
|
return symp;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-08-15 16:12:55 +02:00
|
|
|
static bool existsModScope(AstNodeModule* nodep) { return nodep->user1p() != nullptr; }
|
2012-07-21 15:27:57 +02:00
|
|
|
static VSymEnt* getNodeSym(AstNode* nodep) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Don't use this in ResolveVisitor, as we need to pick up the proper
|
|
|
|
|
// reference under each SCOPE
|
2021-11-13 19:50:44 +01:00
|
|
|
VSymEnt* const symp = nodep->user1u().toSymEnt();
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(symp, nodep, "Module/etc never assigned a symbol entry?");
|
2019-05-19 22:13:13 +02:00
|
|
|
return symp;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2012-07-18 03:29:10 +02:00
|
|
|
VSymEnt* getScopeSym(AstScope* nodep) {
|
2020-08-16 17:43:49 +02:00
|
|
|
const auto it = m_nameScopeSymMap.find(nodep->name());
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(it != m_nameScopeSymMap.end(), nodep,
|
2020-01-25 16:19:59 +01:00
|
|
|
"Scope never assigned a symbol entry '" << nodep->name() << "'");
|
2019-05-19 22:13:13 +02:00
|
|
|
return it->second;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2012-07-22 03:18:07 +02:00
|
|
|
void implicitOkAdd(AstNodeModule* nodep, const string& varname) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Mark the given variable name as being allowed to be implicitly declared
|
|
|
|
|
if (nodep) {
|
2021-03-13 00:17:49 +01:00
|
|
|
const auto it = m_implicitNameSet.find(std::make_pair(nodep, varname));
|
2021-02-22 03:25:21 +01:00
|
|
|
if (it == m_implicitNameSet.end()) m_implicitNameSet.emplace(nodep, varname);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2012-07-22 03:18:07 +02:00
|
|
|
}
|
|
|
|
|
bool implicitOk(AstNodeModule* nodep, const string& varname) {
|
2019-05-19 22:13:13 +02:00
|
|
|
return nodep
|
2021-03-13 00:17:49 +01:00
|
|
|
&& (m_implicitNameSet.find(std::make_pair(nodep, varname))
|
|
|
|
|
!= m_implicitNameSet.end());
|
2012-07-22 03:18:07 +02:00
|
|
|
}
|
|
|
|
|
|
2013-05-28 03:39:19 +02:00
|
|
|
// Track and later recurse interface modules
|
|
|
|
|
void insertIfaceModSym(AstIface* nodep, VSymEnt* symp) {
|
2021-03-13 00:17:49 +01:00
|
|
|
m_ifaceModSyms.push_back(std::make_pair(nodep, symp));
|
2013-05-28 03:39:19 +02:00
|
|
|
}
|
|
|
|
|
void computeIfaceModSyms();
|
|
|
|
|
|
|
|
|
|
// Track and later insert interface references
|
|
|
|
|
void insertIfaceVarSym(VSymEnt* symp) { // Where sym is for a VAR of dtype IFACEREFDTYPE
|
2019-05-19 22:13:13 +02:00
|
|
|
m_ifaceVarSyms.push_back(symp);
|
2013-05-28 03:39:19 +02:00
|
|
|
}
|
2015-12-06 01:39:40 +01:00
|
|
|
// Iface for a raw or arrayed iface
|
|
|
|
|
static AstIfaceRefDType* ifaceRefFromArray(AstNodeDType* nodep) {
|
2018-02-02 03:32:58 +01:00
|
|
|
AstIfaceRefDType* ifacerefp = VN_CAST(nodep, IfaceRefDType);
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!ifacerefp) {
|
2021-11-26 23:55:36 +01:00
|
|
|
if (const AstBracketArrayDType* const arrp = VN_CAST(nodep, BracketArrayDType)) {
|
2020-07-15 23:58:26 +02:00
|
|
|
ifacerefp = VN_CAST(arrp->subDTypep(), IfaceRefDType);
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const AstUnpackArrayDType* const arrp = VN_CAST(nodep, UnpackArrayDType)) {
|
2018-02-02 03:32:58 +01:00
|
|
|
ifacerefp = VN_CAST(arrp->subDTypep(), IfaceRefDType);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ifacerefp;
|
2015-12-06 01:39:40 +01:00
|
|
|
}
|
2013-05-28 03:39:19 +02:00
|
|
|
void computeIfaceVarSyms() {
|
2020-08-16 17:43:49 +02:00
|
|
|
for (VSymEnt* varSymp : m_ifaceVarSyms) {
|
2022-10-20 12:31:00 +02:00
|
|
|
AstVar* const varp = varSymp ? VN_AS(varSymp->nodep(), Var) : nullptr;
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, " insAllIface se" << cvtToHex(varSymp) << " " << varp << endl);
|
2021-11-13 19:50:44 +01:00
|
|
|
AstIfaceRefDType* const ifacerefp = ifaceRefFromArray(varp->subDTypep());
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(ifacerefp, varp, "Non-ifacerefs on list!");
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!ifacerefp->ifaceViaCellp()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!ifacerefp->cellp()) { // Probably a NotFoundModule, or a normal module if
|
|
|
|
|
// made mistake
|
2020-11-02 04:27:27 +01:00
|
|
|
UINFO(1, "Associated cell " << AstNode::prettyNameQ(ifacerefp->cellName())
|
|
|
|
|
<< endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
ifacerefp->v3error("Cannot find file containing interface: "
|
2020-04-15 13:58:34 +02:00
|
|
|
<< AstNode::prettyNameQ(ifacerefp->ifaceName()));
|
2019-05-19 22:13:13 +02:00
|
|
|
continue;
|
|
|
|
|
} else {
|
|
|
|
|
ifacerefp->v3fatalSrc("Unlinked interface");
|
|
|
|
|
}
|
|
|
|
|
} else if (ifacerefp->ifaceViaCellp()->dead()) {
|
2022-10-20 12:31:00 +02:00
|
|
|
if (varp->isIfaceRef()) {
|
|
|
|
|
ifacerefp->v3error("Parent instance's interface is not found: "
|
|
|
|
|
<< AstNode::prettyNameQ(ifacerefp->ifaceName()));
|
|
|
|
|
} else {
|
|
|
|
|
ifacerefp->v3warn(
|
|
|
|
|
E_UNSUPPORTED,
|
|
|
|
|
"Unsupported: virtual interface never assigned any actual interface");
|
|
|
|
|
varp->dtypep(ifacerefp->findCHandleDType());
|
|
|
|
|
VL_DO_DANGLING(ifacerefp->unlinkFrBack()->deleteTree(), ifacerefp);
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
2021-11-13 19:50:44 +01:00
|
|
|
VSymEnt* const ifaceSymp = getNodeSym(ifacerefp->ifaceViaCellp());
|
2019-05-19 22:13:13 +02:00
|
|
|
VSymEnt* ifOrPortSymp = ifaceSymp;
|
|
|
|
|
// Link Modport names to the Modport Node under the Interface
|
|
|
|
|
if (ifacerefp->isModport()) {
|
2021-11-13 19:50:44 +01:00
|
|
|
VSymEnt* const foundp = ifaceSymp->findIdFallback(ifacerefp->modportName());
|
2019-05-19 22:13:13 +02:00
|
|
|
bool ok = false;
|
|
|
|
|
if (foundp) {
|
2021-11-13 19:50:44 +01:00
|
|
|
if (AstModport* const modportp = VN_CAST(foundp->nodep(), Modport)) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, "Link Modport: " << modportp << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
ifacerefp->modportp(modportp);
|
|
|
|
|
ifOrPortSymp = foundp;
|
|
|
|
|
ok = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-07-14 02:30:32 +02:00
|
|
|
if (!ok) {
|
2021-06-21 00:32:57 +02:00
|
|
|
const string suggest = suggestSymFallback(ifaceSymp, ifacerefp->modportName(),
|
2022-11-20 23:40:38 +01:00
|
|
|
LinkNodeMatcherModport{});
|
2020-04-15 13:58:34 +02:00
|
|
|
ifacerefp->modportFileline()->v3error(
|
|
|
|
|
"Modport not found under interface "
|
|
|
|
|
<< ifacerefp->prettyNameQ(ifacerefp->ifaceName()) << ": "
|
2020-11-19 03:03:23 +01:00
|
|
|
<< ifacerefp->prettyNameQ(ifacerefp->modportName()) << '\n'
|
2020-04-15 13:58:34 +02:00
|
|
|
<< (suggest.empty() ? "" : ifacerefp->warnMore() + suggest));
|
2019-07-14 02:30:32 +02:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
// Alias won't expand until interfaces and modport names are known; see notes at top
|
|
|
|
|
insertScopeAlias(SAMN_IFTOP, varSymp, ifOrPortSymp);
|
|
|
|
|
}
|
|
|
|
|
m_ifaceVarSyms.clear();
|
2013-05-28 03:39:19 +02:00
|
|
|
}
|
|
|
|
|
|
2014-04-04 03:53:39 +02:00
|
|
|
void insertScopeAlias(SAMNum samn, VSymEnt* lhsp, VSymEnt* rhsp) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Track and later insert scope aliases; an interface referenced by
|
|
|
|
|
// a child cell connecting to that interface
|
|
|
|
|
// Typically lhsp=VAR w/dtype IFACEREF, rhsp=IFACE cell
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, " insertScopeAlias se" << cvtToHex(lhsp) << " se" << cvtToHex(rhsp) << endl);
|
|
|
|
|
UASSERT_OBJ(
|
2021-10-22 14:56:48 +02:00
|
|
|
!(VN_IS(rhsp->nodep(), Cell) && !VN_IS(VN_AS(rhsp->nodep(), Cell)->modp(), Iface)),
|
2020-04-15 13:58:34 +02:00
|
|
|
rhsp->nodep(), "Got a non-IFACE alias RHS");
|
2020-12-19 00:24:47 +01:00
|
|
|
m_scopeAliasMap[samn].emplace(lhsp, rhsp);
|
2013-05-28 03:39:19 +02:00
|
|
|
}
|
|
|
|
|
void computeScopeAliases() {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, "computeIfaceAliases\n");
|
|
|
|
|
for (int samn = 0; samn < SAMN__MAX; ++samn) {
|
|
|
|
|
for (ScopeAliasMap::iterator it = m_scopeAliasMap[samn].begin();
|
|
|
|
|
it != m_scopeAliasMap[samn].end(); ++it) {
|
2021-11-13 19:50:44 +01:00
|
|
|
VSymEnt* const lhsp = it->first;
|
2019-05-19 22:13:13 +02:00
|
|
|
VSymEnt* srcp = lhsp;
|
2020-04-04 04:31:54 +02:00
|
|
|
while (true) { // Follow chain of aliases up to highest level non-alias
|
2020-08-16 17:43:49 +02:00
|
|
|
const auto it2 = m_scopeAliasMap[samn].find(srcp);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (it2 != m_scopeAliasMap[samn].end()) {
|
|
|
|
|
srcp = it2->second;
|
|
|
|
|
continue;
|
2022-01-08 18:01:39 +01:00
|
|
|
} else {
|
2020-04-15 13:58:34 +02:00
|
|
|
break;
|
2022-01-08 18:01:39 +01:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
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
|
2019-05-19 22:13:13 +02:00
|
|
|
lhsp->importFromIface(symsp(), srcp);
|
|
|
|
|
// Allow access to objects not permissible to be listed in a modport
|
2018-02-02 03:32:58 +01:00
|
|
|
if (VN_IS(srcp->nodep(), Modport)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
lhsp->importFromIface(symsp(), srcp->parentp(), true);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
// m_scopeAliasMap[samn].clear(); // Done with it, but put into debug file
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2013-05-28 03:39:19 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
|
2012-07-21 23:12:42 +02:00
|
|
|
private:
|
|
|
|
|
VSymEnt* findWithAltFallback(VSymEnt* symp, const string& name, const string& altname) {
|
2019-05-19 22:13:13 +02:00
|
|
|
VSymEnt* findp = symp->findIdFallback(name);
|
|
|
|
|
if (findp) return findp;
|
|
|
|
|
if (altname != "") {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, " alt fallback\n");
|
2019-05-19 22:13:13 +02:00
|
|
|
findp = symp->findIdFallback(altname);
|
|
|
|
|
}
|
|
|
|
|
return findp;
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
|
2012-07-21 23:12:42 +02:00
|
|
|
public:
|
2020-08-15 15:43:53 +02:00
|
|
|
VSymEnt* findDotted(FileLine* refLocationp, VSymEnt* lookupSymp, const string& dotname,
|
2020-07-04 15:35:04 +02:00
|
|
|
string& baddot, VSymEnt*& okSymp) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Given a dotted hierarchy name, return where in scope it is
|
|
|
|
|
// Note when dotname=="" we just fall through and return lookupSymp
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, " dottedFind se" << cvtToHex(lookupSymp) << " '" << dotname << "'" << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
bool firstId = true;
|
|
|
|
|
string leftname = dotname;
|
|
|
|
|
okSymp = lookupSymp; // So can list bad scopes
|
|
|
|
|
while (leftname != "") { // foreach dotted part of xref name
|
|
|
|
|
string::size_type pos;
|
|
|
|
|
string ident;
|
2018-10-14 04:28:59 +02:00
|
|
|
if ((pos = leftname.find('.')) != string::npos) {
|
2019-05-19 22:13:13 +02:00
|
|
|
ident = leftname.substr(0, pos);
|
2020-04-15 13:58:34 +02:00
|
|
|
leftname = leftname.substr(pos + 1);
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
|
|
|
|
ident = leftname;
|
|
|
|
|
leftname = "";
|
|
|
|
|
}
|
|
|
|
|
baddot = ident; // So user can see where they botched it
|
|
|
|
|
okSymp = lookupSymp;
|
2018-10-14 05:06:36 +02:00
|
|
|
string altIdent;
|
2019-05-19 22:13:13 +02:00
|
|
|
if (m_forPrearray) {
|
|
|
|
|
// GENFOR Begin is foo__BRA__##__KET__ after we've genloop unrolled,
|
|
|
|
|
// but presently should be just "foo".
|
|
|
|
|
// Likewise cell foo__[array] before we've expanded arrays is just foo
|
|
|
|
|
if ((pos = ident.rfind("__BRA__")) != string::npos) {
|
|
|
|
|
altIdent = ident.substr(0, pos);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, " id " << ident << " alt " << altIdent << " left " << leftname
|
|
|
|
|
<< " at se" << lookupSymp << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
// Spec says; Look at existing module (cellnames then modname),
|
|
|
|
|
// then look up (inst name or modname)
|
|
|
|
|
if (firstId) {
|
|
|
|
|
// Check this module - subcellnames
|
2021-11-26 23:55:36 +01:00
|
|
|
const AstCell* cellp = lookupSymp ? VN_CAST(lookupSymp->nodep(), Cell)
|
|
|
|
|
: nullptr; // Replicated below
|
|
|
|
|
const AstCellInline* inlinep = lookupSymp
|
|
|
|
|
? VN_CAST(lookupSymp->nodep(), CellInline)
|
|
|
|
|
: nullptr; // Replicated below
|
2021-11-13 19:50:44 +01:00
|
|
|
if (VSymEnt* const findSymp = findWithAltFallback(lookupSymp, ident, altIdent)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
lookupSymp = findSymp;
|
|
|
|
|
}
|
|
|
|
|
// Check this module - cur modname
|
|
|
|
|
else if ((cellp && cellp->modp()->origName() == ident)
|
2020-04-15 13:58:34 +02:00
|
|
|
|| (inlinep && inlinep->origModName() == ident)) {
|
|
|
|
|
}
|
2020-05-02 14:29:20 +02:00
|
|
|
// $root we walk up to Netlist
|
|
|
|
|
else if (ident == "$root") {
|
|
|
|
|
lookupSymp = rootEntp();
|
Introduce model interface class, make $root part or Syms (#3036)
This patch implements #3032. Verilator creates a module representing the
SystemVerilog $root scope (V3LinkLevel::wrapTop). Until now, this was
called the "TOP" module, which also acted as the user instantiated model
class. Syms used to hold a pointer to this root module, but hold
instances of any submodule. This patch renames this root scope module
from "TOP" to "$root", and introduces a separate model class which is
now an interface class. As the root module is no longer the user
interface class, it can now be made an instance of Syms, just like any
other submodule. This allows absolute references into the root module to
avoid an additional pointer indirection resulting in a potential speedup
(about 1.5% on OpenTitan). The model class now also contains all non
design specific generated code (e.g.: eval loops, trace config, etc),
which additionally simplifies Verilator internals.
Please see the updated documentation for the model interface changes.
2021-06-21 16:30:20 +02:00
|
|
|
// We've added the '$root' module, now everything else is one lower
|
2020-05-02 14:29:20 +02:00
|
|
|
if (!m_forPrearray) {
|
Introduce model interface class, make $root part or Syms (#3036)
This patch implements #3032. Verilator creates a module representing the
SystemVerilog $root scope (V3LinkLevel::wrapTop). Until now, this was
called the "TOP" module, which also acted as the user instantiated model
class. Syms used to hold a pointer to this root module, but hold
instances of any submodule. This patch renames this root scope module
from "TOP" to "$root", and introduces a separate model class which is
now an interface class. As the root module is no longer the user
interface class, it can now be made an instance of Syms, just like any
other submodule. This allows absolute references into the root module to
avoid an additional pointer indirection resulting in a potential speedup
(about 1.5% on OpenTitan). The model class now also contains all non
design specific generated code (e.g.: eval loops, trace config, etc),
which additionally simplifies Verilator internals.
Please see the updated documentation for the model interface changes.
2021-06-21 16:30:20 +02:00
|
|
|
lookupSymp = lookupSymp->findIdFlat(ident);
|
|
|
|
|
UASSERT(lookupSymp, "Cannot find $root module under netlist");
|
2020-05-02 14:29:20 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
// Move up and check cellname + modname
|
|
|
|
|
else {
|
|
|
|
|
bool crossedCell = false; // Crossed a cell boundary
|
|
|
|
|
while (lookupSymp) {
|
|
|
|
|
lookupSymp = lookupSymp->parentp();
|
2020-04-15 13:58:34 +02:00
|
|
|
cellp = lookupSymp ? VN_CAST(lookupSymp->nodep(), Cell)
|
2020-08-15 16:12:55 +02:00
|
|
|
: nullptr; // Replicated above
|
2020-04-15 13:58:34 +02:00
|
|
|
inlinep = lookupSymp ? VN_CAST(lookupSymp->nodep(), CellInline)
|
2020-08-15 16:12:55 +02:00
|
|
|
: nullptr; // Replicated above
|
2019-05-19 22:13:13 +02:00
|
|
|
if (lookupSymp) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, " Up to " << lookupSymp << endl);
|
|
|
|
|
if (cellp || inlinep) crossedCell = true;
|
2019-05-19 22:13:13 +02:00
|
|
|
if ((cellp && cellp->modp()->origName() == ident)
|
|
|
|
|
|| (inlinep && inlinep->origModName() == ident)) {
|
|
|
|
|
break;
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (VSymEnt* const findSymp
|
2020-04-15 13:58:34 +02:00
|
|
|
= findWithAltFallback(lookupSymp, ident, altIdent)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
lookupSymp = findSymp;
|
2018-02-02 03:32:58 +01:00
|
|
|
if (crossedCell && VN_IS(lookupSymp->nodep(), Var)) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, " Not found but matches var name in parent "
|
|
|
|
|
<< lookupSymp << endl);
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2022-01-08 18:01:39 +01:00
|
|
|
} else {
|
2020-04-15 13:58:34 +02:00
|
|
|
break;
|
2022-01-08 18:01:39 +01:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2020-08-15 16:12:55 +02:00
|
|
|
if (!lookupSymp) return nullptr; // Not found
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
} else { // Searching for middle submodule, must be a cell name
|
2021-11-13 19:50:44 +01:00
|
|
|
if (VSymEnt* const findSymp = findWithAltFallback(lookupSymp, ident, altIdent)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
lookupSymp = findSymp;
|
|
|
|
|
} else {
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr; // Not found
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
2020-08-15 15:43:53 +02:00
|
|
|
if (lookupSymp) {
|
2021-11-26 23:55:36 +01:00
|
|
|
if (const AstCell* const cellp = VN_CAST(lookupSymp->nodep(), Cell)) {
|
|
|
|
|
if (const AstNodeModule* const modp = cellp->modp()) {
|
2020-08-15 15:43:53 +02:00
|
|
|
if (modp->hierBlock()) {
|
|
|
|
|
refLocationp->v3error("Cannot access inside hierarchical block");
|
2020-12-13 02:25:00 +01:00
|
|
|
} else if (VN_IS(modp, NotFoundModule)) {
|
2020-12-13 04:26:50 +01:00
|
|
|
refLocationp->v3error("Dotted reference to instance that refers to "
|
|
|
|
|
"missing module/interface: "
|
|
|
|
|
<< modp->prettyNameQ());
|
2020-08-15 15:43:53 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
firstId = false;
|
|
|
|
|
}
|
|
|
|
|
return lookupSymp;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2015-12-06 01:39:40 +01:00
|
|
|
static string removeLastInlineScope(const string& name) {
|
2019-05-19 22:13:13 +02:00
|
|
|
string out = name;
|
2021-06-21 00:32:57 +02:00
|
|
|
const string dot = "__DOT__";
|
|
|
|
|
const size_t dotPos = out.rfind(dot, out.size() - dot.length() - 2);
|
2019-05-19 22:13:13 +02:00
|
|
|
if (dotPos == string::npos) {
|
|
|
|
|
return "";
|
|
|
|
|
} else {
|
|
|
|
|
return out.erase(dotPos + dot.length(), string::npos);
|
|
|
|
|
}
|
2015-12-06 01:39:40 +01:00
|
|
|
}
|
|
|
|
|
|
2012-07-21 23:12:42 +02:00
|
|
|
VSymEnt* findSymPrefixed(VSymEnt* lookupSymp, const string& dotname, string& baddot) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Find symbol in given point in hierarchy, allowing prefix (post-Inline)
|
2020-08-15 16:12:55 +02:00
|
|
|
// For simplicity lookupSymp may be passed nullptr result from findDotted
|
|
|
|
|
if (!lookupSymp) return nullptr;
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, " findSymPrefixed "
|
|
|
|
|
<< dotname << " under se" << cvtToHex(lookupSymp)
|
|
|
|
|
<< ((lookupSymp->symPrefix() == "") ? "" : " as ")
|
|
|
|
|
<< ((lookupSymp->symPrefix() == "") ? "" : lookupSymp->symPrefix() + dotname)
|
|
|
|
|
<< " at se" << lookupSymp << endl);
|
2022-04-28 00:40:36 +02:00
|
|
|
string prefix = lookupSymp->symPrefix();
|
2020-08-15 16:12:55 +02:00
|
|
|
VSymEnt* foundp = nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
while (!foundp) {
|
2020-08-15 16:12:55 +02:00
|
|
|
foundp = lookupSymp->findIdFallback(prefix + dotname); // Might be nullptr
|
2020-04-13 00:57:12 +02:00
|
|
|
if (prefix.empty()) break;
|
2021-06-21 00:32:57 +02:00
|
|
|
const string nextPrefix = removeLastInlineScope(prefix);
|
2020-04-13 00:57:12 +02:00
|
|
|
if (prefix == nextPrefix) break;
|
2022-04-28 00:40:36 +02:00
|
|
|
prefix = nextPrefix;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
if (!foundp) baddot = dotname;
|
|
|
|
|
return foundp;
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2019-07-14 02:30:32 +02:00
|
|
|
string suggestSymFallback(VSymEnt* lookupSymp, const string& name,
|
|
|
|
|
const VNodeMatcher& matcher) {
|
|
|
|
|
// Suggest alternative symbol in given point in hierarchy
|
|
|
|
|
// Does not support inline, as we find user-level errors before inlining
|
2020-08-15 16:12:55 +02:00
|
|
|
// For simplicity lookupSymp may be passed nullptr result from findDotted
|
2019-07-14 02:30:32 +02:00
|
|
|
if (!lookupSymp) return "";
|
|
|
|
|
VSpellCheck speller;
|
|
|
|
|
lookupSymp->candidateIdFallback(&speller, &matcher);
|
|
|
|
|
return speller.bestCandidateMsg(name);
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
string suggestSymFlat(VSymEnt* lookupSymp, const string& name, const VNodeMatcher& matcher) {
|
2019-07-14 02:30:32 +02:00
|
|
|
if (!lookupSymp) return "";
|
|
|
|
|
VSpellCheck speller;
|
|
|
|
|
lookupSymp->candidateIdFlat(&speller, &matcher);
|
|
|
|
|
return speller.bestCandidateMsg(name);
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
};
|
|
|
|
|
|
2020-08-15 16:12:55 +02:00
|
|
|
LinkDotState* LinkDotState::s_errorThisp = nullptr;
|
2013-05-25 18:15:38 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//======================================================================
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
class LinkDotFindVisitor final : public VNVisitor {
|
2006-08-26 13:35:28 +02:00
|
|
|
// STATE
|
2021-11-13 19:50:44 +01:00
|
|
|
LinkDotState* const m_statep; // State to pass between visitors, including symbol table
|
2020-11-25 03:56:03 +01:00
|
|
|
AstNodeModule* m_classOrPackagep = nullptr; // Current package
|
2022-12-23 13:34:49 +01:00
|
|
|
AstClocking* m_clockingp = nullptr; // Current clocking block
|
2020-08-15 19:11:27 +02:00
|
|
|
VSymEnt* m_modSymp = nullptr; // Symbol Entry for current module
|
|
|
|
|
VSymEnt* m_curSymp = nullptr; // Symbol Entry for current table, where to lookup/insert
|
2020-04-15 13:58:34 +02:00
|
|
|
string m_scope; // Scope text
|
2021-11-26 23:55:36 +01:00
|
|
|
const AstNodeBlock* m_blockp = nullptr; // Current Begin/end block
|
|
|
|
|
const AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
2020-08-15 19:11:27 +02:00
|
|
|
bool m_inRecursion = false; // Inside a recursive module
|
|
|
|
|
int m_paramNum = 0; // Parameter number, for position based connection
|
|
|
|
|
bool m_explicitNew = false; // Hit a "new" function
|
|
|
|
|
int m_modBlockNum = 0; // Begin block number in module, 0=none seen
|
2020-10-31 15:00:55 +01:00
|
|
|
int m_modWithNum = 0; // With block number, 0=none seen
|
2009-01-21 22:56:50 +01:00
|
|
|
|
2012-07-21 23:12:42 +02:00
|
|
|
// METHODS
|
2020-04-13 00:57:12 +02:00
|
|
|
void makeImplicitNew(AstClass* nodep) {
|
2022-11-20 23:40:38 +01:00
|
|
|
AstFunc* const newp = new AstFunc{nodep->fileline(), "new", nullptr, nullptr};
|
2020-04-13 00:57:12 +02:00
|
|
|
newp->isConstructor(true);
|
|
|
|
|
nodep->addMembersp(newp);
|
|
|
|
|
UINFO(8, "Made implicit new for " << nodep->name() << ": " << nodep << endl);
|
2020-11-25 03:56:03 +01:00
|
|
|
m_statep->insertBlock(m_curSymp, newp->name(), newp, m_classOrPackagep);
|
2020-04-13 00:57:12 +02:00
|
|
|
}
|
2016-03-25 00:14:15 +01:00
|
|
|
|
2020-08-15 15:43:53 +02:00
|
|
|
bool isHierBlockWrapper(const string& name) const {
|
|
|
|
|
const V3HierBlockOptSet& hierBlocks = v3Global.opt.hierBlocks();
|
|
|
|
|
return hierBlocks.find(name) != hierBlocks.end();
|
|
|
|
|
}
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
// VISITs
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNetlist* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Process $unit or other packages
|
|
|
|
|
// Not needed - dotted references not allowed from inside packages
|
2020-04-15 13:58:34 +02:00
|
|
|
// for (AstNodeModule* nodep = v3Global.rootp()->modulesp();
|
2021-10-22 14:56:48 +02:00
|
|
|
// nodep; nodep=VN_AS(nodep->nextp(), NodeModule)) {
|
2018-02-02 03:32:58 +01:00
|
|
|
// if (VN_IS(nodep, Package)) {}}
|
2009-11-08 03:05:02 +01:00
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
m_statep->insertDUnit(nodep);
|
2012-07-21 23:12:42 +02:00
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
// First back iterate, to find all packages. Backward as must do base
|
|
|
|
|
// packages before using packages
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildrenBackwards(nodep);
|
2012-07-21 23:12:42 +02:00
|
|
|
|
2019-06-30 22:46:48 +02:00
|
|
|
// The first modules in the list are always the top modules
|
|
|
|
|
// (sorted before this is called).
|
2019-05-19 22:13:13 +02:00
|
|
|
// This may not be the module with isTop() set, as early in the steps,
|
|
|
|
|
// wrapTop may have not been created yet.
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!nodep->modulesp()) nodep->v3error("No top level module found");
|
2019-06-30 22:46:48 +02:00
|
|
|
for (AstNodeModule* modp = nodep->modulesp(); modp && modp->level() <= 2;
|
2021-10-22 14:56:48 +02:00
|
|
|
modp = VN_AS(modp->nextp(), NodeModule)) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, "Top Module: " << modp << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
m_scope = "TOP";
|
2022-10-01 16:48:37 +02:00
|
|
|
|
|
|
|
|
if (m_statep->forPrearray() && v3Global.opt.topIfacesSupported()) {
|
|
|
|
|
for (AstNode* subnodep = modp->stmtsp(); subnodep; subnodep = subnodep->nextp()) {
|
|
|
|
|
if (AstVar* const varp = VN_CAST(subnodep, Var)) {
|
|
|
|
|
if (varp->isIfaceRef()) {
|
|
|
|
|
const AstNodeDType* const subtypep = varp->subDTypep();
|
|
|
|
|
const AstIfaceRefDType* ifacerefp = nullptr;
|
|
|
|
|
if (VN_IS(subtypep, IfaceRefDType)) {
|
|
|
|
|
ifacerefp = VN_AS(varp->subDTypep(), IfaceRefDType);
|
2022-10-01 16:53:40 +02:00
|
|
|
} else if (VN_IS(subtypep, BracketArrayDType)) {
|
|
|
|
|
const AstBracketArrayDType* const arrp
|
|
|
|
|
= VN_AS(subtypep, BracketArrayDType);
|
2022-10-01 16:48:37 +02:00
|
|
|
const AstNodeDType* const arrsubtypep = arrp->subDTypep();
|
|
|
|
|
if (VN_IS(arrsubtypep, IfaceRefDType)) {
|
|
|
|
|
ifacerefp = VN_AS(arrsubtypep, IfaceRefDType);
|
|
|
|
|
}
|
2022-10-01 16:53:40 +02:00
|
|
|
} else if (VN_IS(subtypep, UnpackArrayDType)) {
|
|
|
|
|
const AstUnpackArrayDType* const arrp
|
|
|
|
|
= VN_AS(subtypep, UnpackArrayDType);
|
2022-10-01 16:48:37 +02:00
|
|
|
const AstNodeDType* const arrsubtypep = arrp->subDTypep();
|
|
|
|
|
if (VN_IS(arrsubtypep, IfaceRefDType)) {
|
|
|
|
|
ifacerefp = VN_AS(arrsubtypep, IfaceRefDType);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ifacerefp && !ifacerefp->cellp()) {
|
2022-10-01 16:53:40 +02:00
|
|
|
// A dummy cell to keep the top level interface alive and correctly
|
|
|
|
|
// optimized for default parameter values
|
|
|
|
|
AstCell* ifacecellp
|
|
|
|
|
= new AstCell{nodep->fileline(),
|
|
|
|
|
nodep->fileline(),
|
|
|
|
|
modp->name() + "__02E" + varp->name(),
|
|
|
|
|
ifacerefp->ifaceName(),
|
|
|
|
|
nullptr,
|
|
|
|
|
nullptr,
|
|
|
|
|
nullptr};
|
2022-10-01 16:48:37 +02:00
|
|
|
ifacecellp->modp(ifacerefp->ifacep());
|
2022-10-01 16:53:40 +02:00
|
|
|
m_curSymp = m_modSymp
|
|
|
|
|
= m_statep->insertTopIface(ifacecellp, m_scope);
|
2022-10-01 16:48:37 +02:00
|
|
|
{ iterate(ifacecellp); }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-30 22:46:48 +02:00
|
|
|
m_curSymp = m_modSymp = m_statep->insertTopCell(modp, m_scope);
|
2020-04-15 13:58:34 +02:00
|
|
|
{ iterate(modp); }
|
2022-10-01 16:48:37 +02:00
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
m_scope = "";
|
2020-08-15 16:12:55 +02:00
|
|
|
m_curSymp = m_modSymp = nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstTypeTable*) override {}
|
|
|
|
|
void visit(AstConstPool*) override {}
|
|
|
|
|
void visit(AstNodeModule* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Called on top module from Netlist, other modules from the cell creating them,
|
|
|
|
|
// and packages
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, " " << nodep << endl);
|
2020-08-15 16:12:55 +02:00
|
|
|
// m_curSymp/m_modSymp maybe nullptr for packages and non-top modules
|
2019-05-19 22:13:13 +02:00
|
|
|
// Packages will be under top after the initial phases, but until then
|
|
|
|
|
// need separate handling
|
2021-06-21 00:32:57 +02:00
|
|
|
const bool standalonePkg
|
|
|
|
|
= !m_modSymp && (m_statep->forPrearray() && VN_IS(nodep, Package));
|
|
|
|
|
const bool doit = (m_modSymp || standalonePkg);
|
2020-08-25 03:10:43 +02:00
|
|
|
VL_RESTORER(m_scope);
|
2020-11-25 03:56:03 +01:00
|
|
|
VL_RESTORER(m_classOrPackagep);
|
2020-08-25 03:10:43 +02:00
|
|
|
VL_RESTORER(m_modSymp);
|
|
|
|
|
VL_RESTORER(m_curSymp);
|
|
|
|
|
VL_RESTORER(m_paramNum);
|
|
|
|
|
VL_RESTORER(m_modBlockNum);
|
2020-10-31 15:00:55 +01:00
|
|
|
VL_RESTORER(m_modWithNum);
|
2019-05-19 22:13:13 +02:00
|
|
|
if (doit && nodep->user2()) {
|
2020-06-10 01:20:16 +02:00
|
|
|
nodep->v3warn(E_UNSUPPORTED,
|
|
|
|
|
"Unsupported: Identically recursive module (module instantiates "
|
|
|
|
|
"itself, without changing parameters): "
|
|
|
|
|
<< AstNode::prettyNameQ(nodep->origName()));
|
2019-05-19 22:13:13 +02:00
|
|
|
} else if (doit) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, " Link Module: " << nodep << endl);
|
2020-12-13 04:43:55 +01:00
|
|
|
UASSERT_OBJ(!nodep->dead(), nodep, "Module in instance tree mislabeled as dead?");
|
2021-11-13 19:50:44 +01:00
|
|
|
AstPackage* const pkgp = VN_CAST(nodep, Package);
|
2020-11-25 03:56:03 +01:00
|
|
|
m_classOrPackagep = pkgp;
|
2019-05-19 22:13:13 +02:00
|
|
|
if (standalonePkg) {
|
2020-04-12 20:53:10 +02:00
|
|
|
if (pkgp->isDollarUnit()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
m_curSymp = m_modSymp = m_statep->dunitEntp();
|
|
|
|
|
nodep->user1p(m_curSymp);
|
|
|
|
|
} else {
|
2022-11-17 00:58:57 +01:00
|
|
|
VSymEnt* const upperSymp = m_statep->dunitEntp();
|
2019-05-19 22:13:13 +02:00
|
|
|
m_scope = nodep->name();
|
2020-04-15 13:58:34 +02:00
|
|
|
m_curSymp = m_modSymp = m_statep->insertBlock(
|
2020-11-25 03:56:03 +01:00
|
|
|
upperSymp, nodep->name() + "::", nodep, m_classOrPackagep);
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, "New module scope " << m_curSymp << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//
|
|
|
|
|
m_paramNum = 0;
|
2020-04-23 03:31:40 +02:00
|
|
|
m_modBlockNum = 0;
|
2020-10-31 15:00:55 +01:00
|
|
|
m_modWithNum = 0;
|
2019-05-19 22:13:13 +02:00
|
|
|
// m_modSymp/m_curSymp for non-packages set by AstCell above this module
|
|
|
|
|
// Iterate
|
|
|
|
|
nodep->user2(true);
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->user2(false);
|
|
|
|
|
nodep->user4(true);
|
|
|
|
|
// Interfaces need another pass when signals are resolved
|
2021-11-13 19:50:44 +01:00
|
|
|
if (AstIface* const ifacep = VN_CAST(nodep, Iface)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
m_statep->insertIfaceModSym(ifacep, m_curSymp);
|
|
|
|
|
}
|
2020-08-15 15:43:53 +02:00
|
|
|
} else if (isHierBlockWrapper(nodep->name())) {
|
|
|
|
|
UINFO(5, "Module is hierarchical block, must not be dead: " << nodep << endl);
|
|
|
|
|
m_scope = nodep->name();
|
2021-11-13 19:50:44 +01:00
|
|
|
VSymEnt* const upperSymp = m_curSymp ? m_curSymp : m_statep->rootEntp();
|
2020-08-15 15:43:53 +02:00
|
|
|
m_curSymp = m_modSymp
|
2020-11-25 03:56:03 +01:00
|
|
|
= m_statep->insertBlock(upperSymp, nodep->name() + "::", nodep, m_classOrPackagep);
|
2020-08-15 15:43:53 +02:00
|
|
|
iterateChildren(nodep);
|
|
|
|
|
nodep->user4(true);
|
2019-05-19 22:13:13 +02:00
|
|
|
} else { // !doit
|
|
|
|
|
// Will be optimized away later
|
|
|
|
|
// Can't remove now, as our backwards iterator will throw up
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(5, "Module not under any CELL or top - dead module: " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstClass* nodep) override {
|
2020-04-05 15:30:23 +02:00
|
|
|
UASSERT_OBJ(m_curSymp, nodep, "Class not under module/package/$unit");
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, " " << nodep << endl);
|
2022-12-26 10:30:41 +01:00
|
|
|
// Remove classes that have void params, as they were only used for the parameterization
|
2022-10-20 03:59:26 +02:00
|
|
|
// step and will not be instantiated
|
|
|
|
|
if (m_statep->removeVoidParamedClasses()) {
|
|
|
|
|
for (auto* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
|
|
|
|
if (auto* dtypep = VN_CAST(stmtp, ParamTypeDType)) {
|
|
|
|
|
if (VN_IS(dtypep->subDTypep(), VoidDType)) {
|
|
|
|
|
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-08-25 03:10:43 +02:00
|
|
|
VL_RESTORER(m_scope);
|
2020-11-25 04:46:02 +01:00
|
|
|
VL_RESTORER(m_classOrPackagep);
|
2020-08-25 03:10:43 +02:00
|
|
|
VL_RESTORER(m_modSymp);
|
|
|
|
|
VL_RESTORER(m_curSymp);
|
|
|
|
|
VL_RESTORER(m_paramNum);
|
|
|
|
|
VL_RESTORER(m_modBlockNum);
|
2020-10-31 15:00:55 +01:00
|
|
|
VL_RESTORER(m_modWithNum);
|
2020-04-05 15:30:23 +02:00
|
|
|
{
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, " Link Class: " << nodep << endl);
|
2021-11-13 19:50:44 +01:00
|
|
|
VSymEnt* const upperSymp = m_curSymp;
|
2020-04-05 15:30:23 +02:00
|
|
|
m_scope = m_scope + "." + nodep->name();
|
2020-11-25 04:46:02 +01:00
|
|
|
m_classOrPackagep = nodep;
|
2020-04-05 15:30:23 +02:00
|
|
|
m_curSymp = m_modSymp
|
2020-11-25 03:56:03 +01:00
|
|
|
= m_statep->insertBlock(upperSymp, nodep->name(), nodep, m_classOrPackagep);
|
2020-04-05 15:30:23 +02:00
|
|
|
m_statep->insertMap(m_curSymp, m_scope);
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, "New module scope " << m_curSymp << endl);
|
2020-04-05 15:30:23 +02:00
|
|
|
//
|
|
|
|
|
m_paramNum = 0;
|
2020-04-23 03:31:40 +02:00
|
|
|
m_modBlockNum = 0;
|
2020-10-31 15:00:55 +01:00
|
|
|
m_modWithNum = 0;
|
2020-04-13 00:57:12 +02:00
|
|
|
m_explicitNew = false;
|
2020-04-05 15:30:23 +02:00
|
|
|
// m_modSymp/m_curSymp for non-packages set by AstCell above this module
|
|
|
|
|
// Iterate
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
nodep->user4(true);
|
2020-04-13 00:57:12 +02:00
|
|
|
// Implicit new needed?
|
|
|
|
|
if (!m_explicitNew && m_statep->forPrimary()) makeImplicitNew(nodep);
|
2020-04-05 15:30:23 +02:00
|
|
|
}
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstScope* nodep) override {
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(m_statep->forScopeCreation(), nodep,
|
|
|
|
|
"Scopes should only exist right after V3Scope");
|
2019-05-19 22:13:13 +02:00
|
|
|
// Ignored. Processed in next step
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstCell* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(5, " CELL under " << m_scope << " is " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
// Process XREFs/etc inside pins
|
|
|
|
|
if (nodep->recursive() && m_inRecursion) return;
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
// Recurse in, preserving state
|
2020-08-25 03:10:43 +02:00
|
|
|
VL_RESTORER(m_scope);
|
|
|
|
|
VL_RESTORER(m_blockp);
|
|
|
|
|
VL_RESTORER(m_modSymp);
|
|
|
|
|
VL_RESTORER(m_curSymp);
|
|
|
|
|
VL_RESTORER(m_paramNum);
|
|
|
|
|
VL_RESTORER(m_inRecursion);
|
2019-05-19 22:13:13 +02:00
|
|
|
// Where do we add it?
|
|
|
|
|
VSymEnt* aboveSymp = m_curSymp;
|
2021-06-21 00:32:57 +02:00
|
|
|
const string origname = AstNode::dedotName(nodep->name());
|
2019-05-19 22:13:13 +02:00
|
|
|
string::size_type pos;
|
2018-10-14 04:28:59 +02:00
|
|
|
if ((pos = origname.rfind('.')) != string::npos) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Flattened, find what CellInline it should live under
|
2021-06-21 00:32:57 +02:00
|
|
|
const string scope = origname.substr(0, pos);
|
2019-05-19 22:13:13 +02:00
|
|
|
string baddot;
|
|
|
|
|
VSymEnt* okSymp;
|
2020-07-04 15:35:04 +02:00
|
|
|
aboveSymp = m_statep->findDotted(nodep->fileline(), aboveSymp, scope, baddot, okSymp);
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(aboveSymp, nodep,
|
2020-12-13 04:43:55 +01:00
|
|
|
"Can't find instance insertion point at "
|
|
|
|
|
<< AstNode::prettyNameQ(baddot) << " in: " << nodep->prettyNameQ());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
{
|
2020-04-15 13:58:34 +02:00
|
|
|
m_scope = m_scope + "." + nodep->name();
|
2019-05-19 22:13:13 +02:00
|
|
|
m_curSymp = m_modSymp = m_statep->insertCell(aboveSymp, m_modSymp, nodep, m_scope);
|
2020-08-15 16:12:55 +02:00
|
|
|
m_blockp = nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
m_inRecursion = nodep->recursive();
|
|
|
|
|
// We don't report NotFoundModule, as may be a unused module in a generate
|
2018-05-11 02:55:37 +02:00
|
|
|
if (nodep->modp()) iterate(nodep->modp());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstCellInline* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(5, " CELLINLINE under " << m_scope << " is " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
VSymEnt* aboveSymp = m_curSymp;
|
|
|
|
|
// If baz__DOT__foo__DOT__bar, we need to find baz__DOT__foo and add bar to it.
|
2021-06-21 00:32:57 +02:00
|
|
|
const string dottedname = nodep->name();
|
2019-05-19 22:13:13 +02:00
|
|
|
string::size_type pos;
|
|
|
|
|
if ((pos = dottedname.rfind("__DOT__")) != string::npos) {
|
2021-06-21 00:32:57 +02:00
|
|
|
const string dotted = dottedname.substr(0, pos);
|
2022-09-15 03:10:19 +02:00
|
|
|
const string ident = dottedname.substr(pos + std::strlen("__DOT__"));
|
2019-05-19 22:13:13 +02:00
|
|
|
string baddot;
|
|
|
|
|
VSymEnt* okSymp;
|
2020-07-04 15:35:04 +02:00
|
|
|
aboveSymp = m_statep->findDotted(nodep->fileline(), aboveSymp, dotted, baddot, okSymp);
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(aboveSymp, nodep,
|
2019-11-05 03:16:07 +01:00
|
|
|
"Can't find cellinline insertion point at "
|
2020-04-15 13:58:34 +02:00
|
|
|
<< AstNode::prettyNameQ(baddot) << " in: " << nodep->prettyNameQ());
|
2019-05-19 22:13:13 +02:00
|
|
|
m_statep->insertInline(aboveSymp, m_modSymp, nodep, ident);
|
|
|
|
|
} else { // No __DOT__, just directly underneath
|
|
|
|
|
m_statep->insertInline(aboveSymp, m_modSymp, nodep, nodep->name());
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstDefParam* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->user1p(m_curSymp);
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2012-08-08 00:24:51 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeBlock* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(5, " " << nodep << endl);
|
|
|
|
|
if (nodep->name() == "" && nodep->unnamed()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// 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.
|
2020-04-15 13:58:34 +02:00
|
|
|
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
2022-03-05 23:04:52 +01:00
|
|
|
if (VN_IS(stmtp, Var) || VN_IS(stmtp, Foreach)) {
|
2023-01-19 03:48:06 +01:00
|
|
|
std::string name;
|
|
|
|
|
do {
|
|
|
|
|
++m_modBlockNum;
|
|
|
|
|
name = "unnamedblk" + cvtToStr(m_modBlockNum);
|
|
|
|
|
// Increment again if earlier pass of V3LinkDot claimed this name
|
|
|
|
|
} while (m_curSymp->findIdFlat(name));
|
|
|
|
|
nodep->name(name);
|
2019-05-19 22:13:13 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-02-26 04:21:16 +01:00
|
|
|
if (nodep->name() == "") {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2020-02-26 04:21:16 +01:00
|
|
|
} else {
|
2020-08-25 03:10:43 +02:00
|
|
|
VL_RESTORER(m_blockp);
|
|
|
|
|
VL_RESTORER(m_curSymp);
|
|
|
|
|
VSymEnt* const oldCurSymp = m_curSymp;
|
2020-02-26 04:21:16 +01:00
|
|
|
{
|
2020-04-23 03:31:40 +02:00
|
|
|
m_blockp = nodep;
|
2020-11-25 03:56:03 +01:00
|
|
|
m_curSymp
|
|
|
|
|
= m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_classOrPackagep);
|
2020-02-26 04:21:16 +01:00
|
|
|
m_curSymp->fallbackp(oldCurSymp);
|
|
|
|
|
// Iterate
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeFTask* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// NodeTask: Remember its name for later resolution
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(5, " " << nodep << endl);
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(m_curSymp && m_modSymp, nodep, "Function/Task not under module?");
|
2020-04-13 00:57:12 +02:00
|
|
|
if (nodep->name() == "new") m_explicitNew = true;
|
2019-05-19 22:13:13 +02:00
|
|
|
// Remember the existing symbol table scope
|
2020-11-26 02:05:44 +01:00
|
|
|
VL_RESTORER(m_classOrPackagep);
|
2020-08-25 03:10:43 +02:00
|
|
|
VL_RESTORER(m_curSymp);
|
2020-11-26 14:55:32 +01:00
|
|
|
VSymEnt* upSymp = m_curSymp;
|
2019-05-19 22:13:13 +02:00
|
|
|
{
|
2023-01-29 00:06:37 +01:00
|
|
|
if (VN_IS(m_curSymp->nodep(), Class)
|
|
|
|
|
&& VN_AS(m_curSymp->nodep(), Class)->isInterfaceClass() && !nodep->pureVirtual()
|
|
|
|
|
&& !nodep->isConstructor()) {
|
2023-01-28 22:30:47 +01:00
|
|
|
nodep->v3error("Interface class functions must be pure virtual"
|
2023-01-29 00:06:37 +01:00
|
|
|
<< " (IEEE 1800-2017 8.26): " << nodep->prettyNameQ());
|
2023-01-28 22:30:47 +01:00
|
|
|
}
|
2020-08-23 01:46:21 +02:00
|
|
|
// Change to appropriate package if extern declaration (vs definition)
|
2020-11-25 03:56:03 +01:00
|
|
|
if (nodep->classOrPackagep()) {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstClassOrPackageRef* const cpackagerefp
|
2020-11-25 03:56:03 +01:00
|
|
|
= VN_CAST(nodep->classOrPackagep(), ClassOrPackageRef);
|
2020-08-23 01:46:21 +02:00
|
|
|
if (!cpackagerefp) {
|
|
|
|
|
nodep->v3warn(E_UNSUPPORTED,
|
|
|
|
|
"Unsupported: extern function definition with class-in-class");
|
|
|
|
|
} else {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstClass* const classp = VN_CAST(cpackagerefp->classOrPackagep(), Class);
|
2020-08-23 01:46:21 +02:00
|
|
|
if (!classp) {
|
|
|
|
|
nodep->v3error("Extern declaration's scope is not a defined class");
|
|
|
|
|
} else {
|
|
|
|
|
m_curSymp = m_statep->getNodeSym(classp);
|
2020-11-26 14:55:32 +01:00
|
|
|
upSymp = m_curSymp;
|
2020-08-23 01:46:21 +02:00
|
|
|
if (!nodep->isExternDef()) {
|
|
|
|
|
// Move it to proper spot under the target class
|
|
|
|
|
nodep->unlinkFrBack();
|
2022-09-15 20:43:56 +02:00
|
|
|
classp->addStmtsp(nodep);
|
2020-08-23 01:46:21 +02:00
|
|
|
nodep->isExternDef(true); // So we check there's a matching extern
|
2020-11-25 03:56:03 +01:00
|
|
|
nodep->classOrPackagep()->unlinkFrBack()->deleteTree();
|
2020-08-23 01:46:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-26 02:05:44 +01:00
|
|
|
// Set the class as package for iteration
|
|
|
|
|
if (VN_IS(m_curSymp->nodep(), Class)) {
|
2021-10-22 14:56:48 +02:00
|
|
|
m_classOrPackagep = VN_AS(m_curSymp->nodep(), Class);
|
2020-11-26 02:05:44 +01:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
// Create symbol table for the task's vars
|
2022-08-30 05:50:32 +02:00
|
|
|
const string name
|
|
|
|
|
= std::string{nodep->isExternProto() ? "extern " : ""} + nodep->name();
|
2020-11-26 02:05:44 +01:00
|
|
|
m_curSymp = m_statep->insertBlock(m_curSymp, name, nodep, m_classOrPackagep);
|
2020-11-26 14:55:32 +01:00
|
|
|
m_curSymp->fallbackp(upSymp);
|
2019-05-19 22:13:13 +02:00
|
|
|
// Convert the func's range to the output variable
|
|
|
|
|
// This should probably be done in the Parser instead, as then we could
|
2019-09-09 13:50:21 +02:00
|
|
|
// just attach normal signal attributes to it.
|
2020-08-23 01:46:21 +02:00
|
|
|
if (!nodep->isExternProto() && nodep->fvarp() && !VN_IS(nodep->fvarp(), Var)) {
|
2018-02-02 03:32:58 +01:00
|
|
|
AstNodeDType* dtypep = VN_CAST(nodep->fvarp(), NodeDType);
|
2019-05-19 22:13:13 +02:00
|
|
|
// If unspecified, function returns one bit; however when we
|
|
|
|
|
// support NEW() it could also return the class reference.
|
2020-04-15 13:58:34 +02:00
|
|
|
if (dtypep) {
|
|
|
|
|
dtypep->unlinkFrBack();
|
|
|
|
|
} else {
|
2022-11-20 23:40:38 +01:00
|
|
|
dtypep = new AstBasicDType{nodep->fileline(), VBasicDTypeKwd::LOGIC};
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
2021-11-26 23:55:36 +01:00
|
|
|
AstVar* const newvarp
|
2022-11-20 23:40:38 +01:00
|
|
|
= new AstVar{nodep->fileline(), VVarType::VAR, nodep->name(),
|
|
|
|
|
VFlagChildDType{}, dtypep}; // Not dtype resolved yet
|
2018-10-27 23:29:00 +02:00
|
|
|
newvarp->direction(VDirection::OUTPUT);
|
2020-04-26 18:45:06 +02:00
|
|
|
newvarp->lifetime(VLifetime::AUTOMATIC);
|
2019-05-19 22:13:13 +02:00
|
|
|
newvarp->funcReturn(true);
|
|
|
|
|
newvarp->trace(false); // Not user visible
|
|
|
|
|
newvarp->attrIsolateAssign(nodep->attrIsolateAssign());
|
2022-09-15 20:43:56 +02:00
|
|
|
nodep->fvarp(newvarp);
|
2019-05-19 22:13:13 +02:00
|
|
|
// Explicit insert required, as the var name shadows the upper level's task name
|
2020-11-25 03:56:03 +01:00
|
|
|
m_statep->insertSym(m_curSymp, newvarp->name(), newvarp,
|
|
|
|
|
nullptr /*classOrPackagep*/);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
m_ftaskp = nodep;
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2020-08-15 16:12:55 +02:00
|
|
|
m_ftaskp = nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2022-12-23 13:34:49 +01:00
|
|
|
void visit(AstClocking* nodep) override {
|
|
|
|
|
VL_RESTORER(m_clockingp);
|
|
|
|
|
m_clockingp = nodep;
|
|
|
|
|
iterate(nodep->sensesp());
|
|
|
|
|
iterateAndNextNull(nodep->itemsp());
|
|
|
|
|
// If the block has no name, one cannot reference the clockvars
|
2023-01-28 18:22:23 +01:00
|
|
|
VSymEnt* itSymp = nullptr;
|
|
|
|
|
if (nodep->isGlobal() //
|
|
|
|
|
&& m_statep->forPrimary()) { // else flattening may see two globals
|
|
|
|
|
m_statep->checkDuplicate(m_curSymp, nodep, "__024global_clock");
|
|
|
|
|
itSymp
|
|
|
|
|
= m_statep->insertBlock(m_curSymp, "__024global_clock", nodep, m_classOrPackagep);
|
|
|
|
|
itSymp->fallbackp(nullptr);
|
|
|
|
|
}
|
|
|
|
|
if (!nodep->name().empty()) {
|
|
|
|
|
itSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_classOrPackagep);
|
|
|
|
|
itSymp->fallbackp(nullptr);
|
|
|
|
|
}
|
|
|
|
|
if (itSymp) {
|
|
|
|
|
VL_RESTORER(m_curSymp);
|
|
|
|
|
m_curSymp = itSymp;
|
|
|
|
|
iterateAndNextNull(nodep->itemsp());
|
|
|
|
|
}
|
2022-12-23 13:34:49 +01:00
|
|
|
}
|
|
|
|
|
void visit(AstClockingItem* nodep) override {
|
|
|
|
|
if (nodep->varp()) {
|
|
|
|
|
if (m_curSymp->nodep() == m_clockingp) iterate(nodep->varp());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
std::string varname;
|
|
|
|
|
AstNodeDType* dtypep;
|
|
|
|
|
if (AstAssign* const assignp = nodep->assignp()) {
|
|
|
|
|
AstNodeExpr* const rhsp = assignp->rhsp()->unlinkFrBack();
|
|
|
|
|
dtypep = new AstRefDType{nodep->fileline(), AstRefDType::FlagTypeOfExpr{},
|
|
|
|
|
rhsp->cloneTree(false)};
|
|
|
|
|
nodep->exprp(rhsp);
|
|
|
|
|
varname = assignp->lhsp()->name();
|
|
|
|
|
VL_DO_DANGLING(assignp->unlinkFrBack()->deleteTree(), assignp);
|
|
|
|
|
} else {
|
|
|
|
|
AstNodeExpr* const refp = nodep->exprp();
|
|
|
|
|
const VSymEnt* foundp = m_curSymp->findIdFallback(refp->name());
|
|
|
|
|
if (!foundp || !foundp->nodep()) {
|
|
|
|
|
refp->v3error("Corresponding variable " << refp->prettyNameQ()
|
|
|
|
|
<< " does not exist");
|
|
|
|
|
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
varname = refp->name();
|
|
|
|
|
dtypep = VN_AS(foundp->nodep(), Var)->childDTypep()->cloneTree(false);
|
|
|
|
|
}
|
|
|
|
|
AstVar* const newvarp = new AstVar{nodep->fileline(), VVarType::MODULETEMP, varname,
|
|
|
|
|
VFlagChildDType{}, dtypep};
|
|
|
|
|
nodep->varp(newvarp);
|
|
|
|
|
iterate(nodep->exprp());
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstVar* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Var: Remember its name for later resolution
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(m_curSymp && m_modSymp, nodep, "Var not under module?");
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2023-01-29 00:06:37 +01:00
|
|
|
if (VN_IS(m_curSymp->nodep(), Class)
|
|
|
|
|
&& VN_AS(m_curSymp->nodep(), Class)->isInterfaceClass() && !nodep->isParam()) {
|
2023-01-28 22:30:47 +01:00
|
|
|
nodep->v3error("Interface class cannot contain non-parameter members"
|
2023-01-29 00:06:37 +01:00
|
|
|
<< " (IEEE 1800-2017 8.26): " << nodep->prettyNameQ());
|
2023-01-28 22:30:47 +01:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!m_statep->forScopeCreation()) {
|
|
|
|
|
// Find under either a task or the module's vars
|
2021-11-26 23:55:36 +01:00
|
|
|
const VSymEnt* foundp = m_curSymp->findIdFallback(nodep->name());
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!foundp && m_modSymp && nodep->name() == m_modSymp->nodep()->name()) {
|
|
|
|
|
foundp = m_modSymp; // Conflicts with modname?
|
|
|
|
|
}
|
2021-11-26 23:55:36 +01:00
|
|
|
AstVar* const findvarp = foundp ? VN_CAST(foundp->nodep(), Var) : nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
bool ins = false;
|
|
|
|
|
if (!foundp) {
|
|
|
|
|
ins = true;
|
2022-11-27 11:52:40 +01:00
|
|
|
} else if (!findvarp && m_curSymp->findIdFlat(nodep->name())) {
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->v3error("Unsupported in C: Variable has same name as "
|
2020-04-15 13:58:34 +02:00
|
|
|
<< LinkDotState::nodeTextType(foundp->nodep()) << ": "
|
|
|
|
|
<< nodep->prettyNameQ());
|
2019-05-19 22:13:13 +02:00
|
|
|
} else if (findvarp != nodep) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, "DupVar: " << nodep << " ;; " << foundp->nodep() << endl);
|
|
|
|
|
UINFO(4, " found cur=se" << cvtToHex(m_curSymp) << " ;; parent=se"
|
|
|
|
|
<< cvtToHex(foundp->parentp()) << endl);
|
2020-04-05 02:08:58 +02:00
|
|
|
if (foundp->parentp() == m_curSymp // Only when on same level
|
2019-05-19 22:13:13 +02:00
|
|
|
&& !foundp->imported()) { // and not from package
|
2022-12-23 13:34:49 +01:00
|
|
|
if (VN_IS(m_curSymp->nodep(), Clocking)) {
|
|
|
|
|
nodep->v3error("Multiple clockvars with the same name not allowed");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-11-26 23:55:36 +01:00
|
|
|
const bool nansiBad
|
2020-04-15 13:58:34 +02:00
|
|
|
= ((findvarp->isDeclTyped() && nodep->isDeclTyped())
|
|
|
|
|
|| (findvarp->isIO() && nodep->isIO())); // e.g. !(output && output)
|
2021-06-21 00:32:57 +02:00
|
|
|
const bool ansiBad
|
|
|
|
|
= findvarp->isAnsi() || nodep->isAnsi(); // dup illegal with ANSI
|
2019-06-22 18:43:48 +02:00
|
|
|
if (ansiBad || nansiBad) {
|
|
|
|
|
bool ansiWarn = ansiBad && !nansiBad;
|
2019-10-06 14:20:02 +02:00
|
|
|
if (ansiWarn) {
|
|
|
|
|
static int didAnsiWarn = false;
|
|
|
|
|
if (didAnsiWarn++) ansiWarn = false;
|
|
|
|
|
}
|
2019-06-22 18:43:48 +02:00
|
|
|
nodep->v3error("Duplicate declaration of signal: "
|
2020-11-19 03:03:23 +01:00
|
|
|
<< nodep->prettyNameQ() << '\n'
|
2020-04-15 13:58:34 +02:00
|
|
|
<< (ansiWarn ? nodep->warnMore()
|
|
|
|
|
+ "... note: ANSI ports must have"
|
2022-11-12 04:33:17 +01:00
|
|
|
" type declared with the I/O"
|
|
|
|
|
" (IEEE 1800-2017 23.2.2.2)\n"
|
2020-04-15 13:58:34 +02:00
|
|
|
: "")
|
2020-11-19 03:03:23 +01:00
|
|
|
<< nodep->warnContextPrimary() << '\n'
|
2020-04-15 13:58:34 +02:00
|
|
|
<< findvarp->warnOther()
|
2020-11-19 03:03:23 +01:00
|
|
|
<< "... Location of original declaration\n"
|
2020-04-15 13:58:34 +02:00
|
|
|
<< findvarp->warnContextSecondary());
|
2019-06-22 18:43:48 +02:00
|
|
|
// Combining most likely reduce other errors
|
|
|
|
|
findvarp->combineType(nodep);
|
|
|
|
|
findvarp->fileline()->modifyStateInherit(nodep->fileline());
|
|
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
findvarp->combineType(nodep);
|
2019-06-13 01:17:10 +02:00
|
|
|
findvarp->fileline()->modifyStateInherit(nodep->fileline());
|
2022-02-16 06:11:38 +01:00
|
|
|
if (nodep->getChildDTypep()->numeric().isSigned()
|
|
|
|
|
&& !findvarp->getChildDTypep()->numeric().isSigned()) {
|
2022-11-20 23:40:38 +01:00
|
|
|
findvarp->getChildDTypep()->numeric(VSigning{true});
|
2022-02-16 06:10:34 +01:00
|
|
|
}
|
2021-11-26 23:55:36 +01:00
|
|
|
AstBasicDType* const bdtypep
|
|
|
|
|
= VN_CAST(findvarp->childDTypep(), BasicDType);
|
2019-05-19 22:13:13 +02:00
|
|
|
if (bdtypep && bdtypep->implicit()) {
|
|
|
|
|
// Then have "input foo" and "real foo" so the
|
|
|
|
|
// dtype comes from the other side.
|
2021-11-26 23:55:36 +01:00
|
|
|
AstNodeDType* const newdtypep = nodep->subDTypep();
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(newdtypep && nodep->childDTypep(), findvarp,
|
|
|
|
|
"No child type?");
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(bdtypep->unlinkFrBack()->deleteTree(), bdtypep);
|
2019-05-19 22:13:13 +02:00
|
|
|
newdtypep->unlinkFrBack();
|
|
|
|
|
findvarp->childDTypep(newdtypep);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
|
|
|
|
// User can disable the message at either point
|
|
|
|
|
if (!(m_ftaskp && m_ftaskp->dpiImport())
|
2020-04-15 13:58:34 +02:00
|
|
|
&& (!m_ftaskp || m_ftaskp != foundp->nodep()) // Not the function's
|
|
|
|
|
// variable hiding function
|
2019-05-19 22:13:13 +02:00
|
|
|
&& !nodep->fileline()->warnIsOff(V3ErrorCode::VARHIDDEN)
|
|
|
|
|
&& !foundp->nodep()->fileline()->warnIsOff(V3ErrorCode::VARHIDDEN)) {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3warn(VARHIDDEN,
|
|
|
|
|
"Declaration of signal hides declaration in upper scope: "
|
2020-11-19 03:03:23 +01:00
|
|
|
<< nodep->prettyNameQ() << '\n'
|
|
|
|
|
<< nodep->warnContextPrimary() << '\n'
|
2020-04-15 13:58:34 +02:00
|
|
|
<< foundp->nodep()->warnOther()
|
|
|
|
|
<< "... Location of original declaration\n"
|
|
|
|
|
<< foundp->nodep()->warnContextSecondary());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
ins = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (ins) {
|
|
|
|
|
if (m_statep->forPrimary() && nodep->isGParam()
|
2021-12-11 20:55:59 +01:00
|
|
|
&& VN_IS(m_modSymp->nodep(), Module)
|
2019-05-19 22:13:13 +02:00
|
|
|
&& (m_statep->rootEntp()->nodep() == m_modSymp->parentp()->nodep())) {
|
|
|
|
|
// This is the toplevel module. Check for command line overwrites of parameters
|
|
|
|
|
// We first search if the parameter is overwritten and then replace it with a
|
2022-11-11 02:30:10 +01:00
|
|
|
// new value.
|
2019-05-19 22:13:13 +02:00
|
|
|
if (v3Global.opt.hasParameter(nodep->name())) {
|
2021-06-21 00:32:57 +02:00
|
|
|
const string svalue = v3Global.opt.parameter(nodep->name());
|
2022-11-13 21:33:11 +01:00
|
|
|
if (AstConst* const valuep
|
2020-07-04 15:35:04 +02:00
|
|
|
= AstConst::parseParamLiteral(nodep->fileline(), svalue)) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, " replace parameter " << nodep << endl);
|
2022-11-11 02:30:10 +01:00
|
|
|
UINFO(9, " with " << valuep << endl);
|
|
|
|
|
if (nodep->valuep()) pushDeletep(nodep->valuep()->unlinkFrBack());
|
|
|
|
|
nodep->valuep(valuep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const insp
|
2020-11-25 03:56:03 +01:00
|
|
|
= m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_classOrPackagep);
|
2019-05-19 22:13:13 +02:00
|
|
|
if (m_statep->forPrimary() && nodep->isGParam()) {
|
2020-12-05 16:59:33 +01:00
|
|
|
++m_paramNum;
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const symp
|
2020-11-25 03:56:03 +01:00
|
|
|
= m_statep->insertSym(m_curSymp, "__paramNumber" + cvtToStr(m_paramNum),
|
|
|
|
|
nodep, m_classOrPackagep);
|
2019-05-19 22:13:13 +02:00
|
|
|
symp->exported(false);
|
|
|
|
|
}
|
2021-11-26 23:55:36 +01:00
|
|
|
AstIfaceRefDType* const ifacerefp
|
|
|
|
|
= LinkDotState::ifaceRefFromArray(nodep->subDTypep());
|
2019-05-19 22:13:13 +02:00
|
|
|
if (ifacerefp) {
|
|
|
|
|
// Can't resolve until interfaces and modport names are
|
|
|
|
|
// known; see notes at top
|
|
|
|
|
m_statep->insertIfaceVarSym(insp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstTypedef* nodep) override {
|
2020-01-20 22:53:27 +01:00
|
|
|
UASSERT_OBJ(m_curSymp, nodep, "Typedef not under module/package/$unit");
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2020-11-25 03:56:03 +01:00
|
|
|
m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_classOrPackagep);
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstTypedefFwd* nodep) override {
|
2020-04-02 13:39:14 +02:00
|
|
|
UASSERT_OBJ(m_curSymp, nodep, "Typedef not under module/package/$unit");
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
// No need to insert, only the real typedef matters, but need to track for errors
|
|
|
|
|
nodep->user1p(m_curSymp);
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstParamTypeDType* nodep) override {
|
2020-01-20 22:53:27 +01:00
|
|
|
UASSERT_OBJ(m_curSymp, nodep, "Parameter type not under module/package/$unit");
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2020-11-25 03:56:03 +01:00
|
|
|
m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_classOrPackagep);
|
2020-12-05 16:59:33 +01:00
|
|
|
if (m_statep->forPrimary() && nodep->isGParam()) {
|
|
|
|
|
++m_paramNum;
|
2021-11-13 19:50:44 +01:00
|
|
|
VSymEnt* const symp = m_statep->insertSym(
|
|
|
|
|
m_curSymp, "__paramNumber" + cvtToStr(m_paramNum), nodep, m_classOrPackagep);
|
2020-12-05 16:59:33 +01:00
|
|
|
symp->exported(false);
|
|
|
|
|
}
|
2016-03-15 02:51:31 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstCFunc* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// For dotted resolution, ignore all AstVars under functions, otherwise shouldn't exist
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(!m_statep->forScopeCreation(), nodep, "No CFuncs expected in tree yet");
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstEnumItem* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// EnumItem: Remember its name for later resolution
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
// Find under either a task or the module's vars
|
2021-11-26 23:55:36 +01:00
|
|
|
const VSymEnt* foundp = m_curSymp->findIdFallback(nodep->name());
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!foundp && m_modSymp && nodep->name() == m_modSymp->nodep()->name()) {
|
|
|
|
|
foundp = m_modSymp; // Conflicts with modname?
|
|
|
|
|
}
|
2021-11-26 23:55:36 +01:00
|
|
|
AstEnumItem* const findvarp = foundp ? VN_AS(foundp->nodep(), EnumItem) : nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
bool ins = false;
|
|
|
|
|
if (!foundp) {
|
|
|
|
|
ins = true;
|
|
|
|
|
} else if (findvarp != nodep) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, "DupVar: " << nodep << " ;; " << foundp << endl);
|
2019-10-25 03:48:45 +02:00
|
|
|
if (foundp->parentp() == m_curSymp // Only when on same level
|
2019-05-19 22:13:13 +02:00
|
|
|
&& !foundp->imported()) { // and not from package
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3error("Duplicate declaration of enum value: "
|
2020-11-19 03:03:23 +01:00
|
|
|
<< nodep->prettyName() << '\n'
|
|
|
|
|
<< nodep->warnContextPrimary() << '\n'
|
2020-04-15 13:58:34 +02:00
|
|
|
<< foundp->nodep()->warnOther()
|
|
|
|
|
<< "... Location of original declaration\n"
|
|
|
|
|
<< foundp->nodep()->warnContextSecondary());
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
|
|
|
|
// User can disable the message at either point
|
|
|
|
|
if (!nodep->fileline()->warnIsOff(V3ErrorCode::VARHIDDEN)
|
|
|
|
|
&& !foundp->nodep()->fileline()->warnIsOff(V3ErrorCode::VARHIDDEN)) {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3warn(VARHIDDEN,
|
|
|
|
|
"Declaration of enum value hides declaration in upper scope: "
|
2020-11-19 03:03:23 +01:00
|
|
|
<< nodep->prettyName() << '\n'
|
|
|
|
|
<< nodep->warnContextPrimary() << '\n'
|
2020-04-15 13:58:34 +02:00
|
|
|
<< foundp->nodep()->warnOther()
|
|
|
|
|
<< "... Location of original declaration\n"
|
|
|
|
|
<< nodep->warnContextSecondary());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
ins = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-25 03:56:03 +01:00
|
|
|
if (ins) m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_classOrPackagep);
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstPackageImport* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, " Link: " << nodep << endl);
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const srcp = m_statep->getNodeSym(nodep->packagep());
|
2020-04-15 13:58:34 +02:00
|
|
|
if (nodep->name() == "*") {
|
2018-11-29 00:25:34 +01:00
|
|
|
if (m_curSymp == m_statep->dunitEntp()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->v3warn(IMPORTSTAR, "Import::* in $unit scope may pollute global namespace");
|
2018-11-29 00:25:34 +01:00
|
|
|
}
|
|
|
|
|
} else {
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const impp = srcp->findIdFlat(nodep->name());
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!impp) {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3error("Import object not found: '" << nodep->packagep()->prettyName()
|
|
|
|
|
<< "::" << nodep->prettyName() << "'");
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
m_curSymp->importFromPackage(m_statep->symsp(), srcp, nodep->name());
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, " Link Done: " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
// No longer needed, but can't delete until any multi-instantiated modules are expanded
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstPackageExport* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, " Link: " << nodep << endl);
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const srcp = m_statep->getNodeSym(nodep->packagep());
|
2020-04-15 13:58:34 +02:00
|
|
|
if (nodep->name() != "*") {
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const impp = srcp->findIdFlat(nodep->name());
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!impp) {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3error("Export object not found: '" << nodep->packagep()->prettyName()
|
|
|
|
|
<< "::" << nodep->prettyName() << "'");
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
m_curSymp->exportFromPackage(m_statep->symsp(), srcp, nodep->name());
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, " Link Done: " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
// No longer needed, but can't delete until any multi-instantiated modules are expanded
|
2017-09-21 03:04:59 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstPackageExportStarStar* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, " Link: " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
m_curSymp->exportStarStar(m_statep->symsp());
|
|
|
|
|
// No longer needed, but can't delete until any multi-instantiated modules are expanded
|
2017-09-21 03:04:59 +02:00
|
|
|
}
|
2021-12-11 21:06:33 +01:00
|
|
|
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstForeach* nodep) override {
|
2021-12-11 21:06:33 +01:00
|
|
|
// Symbol table needs nodep->name() as the index variable's name
|
|
|
|
|
VL_RESTORER(m_curSymp);
|
|
|
|
|
VSymEnt* const oldCurSymp = m_curSymp;
|
|
|
|
|
{
|
|
|
|
|
++m_modWithNum;
|
|
|
|
|
m_curSymp = m_statep->insertBlock(m_curSymp, "__Vforeach" + cvtToStr(m_modWithNum),
|
|
|
|
|
nodep, m_classOrPackagep);
|
|
|
|
|
m_curSymp->fallbackp(oldCurSymp);
|
2021-12-13 02:43:15 +01:00
|
|
|
// DOT(x, SELLOOPVARS(var, loops)) -> SELLOOPVARS(DOT(x, var), loops)
|
|
|
|
|
if (AstDot* const dotp = VN_CAST(nodep->arrayp(), Dot)) {
|
|
|
|
|
if (AstSelLoopVars* const loopvarsp = VN_CAST(dotp->rhsp(), SelLoopVars)) {
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* const fromp = loopvarsp->fromp()->unlinkFrBack();
|
2021-12-13 02:43:15 +01:00
|
|
|
loopvarsp->unlinkFrBack();
|
|
|
|
|
dotp->replaceWith(loopvarsp);
|
|
|
|
|
dotp->rhsp(fromp);
|
|
|
|
|
loopvarsp->fromp(dotp);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-11 21:06:33 +01:00
|
|
|
const auto loopvarsp = VN_CAST(nodep->arrayp(), SelLoopVars);
|
|
|
|
|
if (!loopvarsp) {
|
|
|
|
|
AstNode* const warnp = nodep->arrayp() ? nodep->arrayp() : nodep;
|
|
|
|
|
warnp->v3warn(E_UNSUPPORTED,
|
|
|
|
|
"Unsupported (or syntax error): Foreach on this array's construct");
|
|
|
|
|
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (AstNode *nextp, *argp = loopvarsp->elementsp(); argp; argp = nextp) {
|
|
|
|
|
nextp = argp->nextp();
|
|
|
|
|
AstVar* argrefp = nullptr;
|
|
|
|
|
if (const auto parserefp = VN_CAST(argp, ParseRef)) {
|
|
|
|
|
// We use an int type, this might get changed in V3Width when types resolve
|
2022-01-02 19:56:40 +01:00
|
|
|
argrefp = new AstVar{parserefp->fileline(), VVarType::BLOCKTEMP,
|
2021-12-11 21:06:33 +01:00
|
|
|
parserefp->name(), argp->findSigned32DType()};
|
|
|
|
|
parserefp->replaceWith(argrefp);
|
|
|
|
|
VL_DO_DANGLING(parserefp->deleteTree(), parserefp);
|
|
|
|
|
// Insert argref's name into symbol table
|
|
|
|
|
m_statep->insertSym(m_curSymp, argrefp->name(), argrefp, nullptr);
|
|
|
|
|
} else if (const auto largrefp = VN_CAST(argp, Var)) {
|
|
|
|
|
argrefp = largrefp;
|
|
|
|
|
// Insert argref's name into symbol table
|
|
|
|
|
m_statep->insertSym(m_curSymp, argrefp->name(), argrefp, nullptr);
|
2021-12-12 02:39:58 +01:00
|
|
|
} else if (VN_IS(argp, Empty)) {
|
2021-12-11 21:06:33 +01:00
|
|
|
} else {
|
|
|
|
|
argp->v3error("'foreach' loop variable expects simple variable name");
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-13 02:43:15 +01:00
|
|
|
iterateChildren(nodep);
|
2021-12-11 21:06:33 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstWithParse* nodep) override {
|
2020-10-31 15:00:55 +01:00
|
|
|
// Change WITHPARSE(FUNCREF, equation) to FUNCREF(WITH(equation))
|
2021-10-22 14:56:48 +02:00
|
|
|
const auto funcrefp = VN_AS(nodep->funcrefp(), NodeFTaskRef);
|
2020-10-31 15:00:55 +01:00
|
|
|
UASSERT_OBJ(funcrefp, nodep, "'with' only can operate on a function/task");
|
|
|
|
|
string name = "item";
|
|
|
|
|
FileLine* argFl = nodep->fileline();
|
2021-06-21 00:32:57 +02:00
|
|
|
if (const auto argp = VN_CAST(funcrefp->pinsp(), Arg)) {
|
|
|
|
|
if (const auto parserefp = VN_CAST(argp->exprp(), ParseRef)) {
|
2020-10-31 15:00:55 +01:00
|
|
|
name = parserefp->name();
|
|
|
|
|
argFl = parserefp->fileline();
|
|
|
|
|
} else {
|
|
|
|
|
argp->v3error("'with' function expects simple variable name");
|
|
|
|
|
}
|
|
|
|
|
if (argp->nextp())
|
|
|
|
|
argp->nextp()->v3error("'with' function expects only up to one argument");
|
2020-10-31 15:33:36 +01:00
|
|
|
VL_DO_DANGLING(argp->unlinkFrBackWithNext()->deleteTree(), argp);
|
2020-10-31 15:00:55 +01:00
|
|
|
}
|
|
|
|
|
// Type depends on the method used, let V3Width figure it out later
|
2020-11-26 17:50:50 +01:00
|
|
|
if (nodep->exprp()) { // Else empty expression and pretend no "with"
|
2022-11-20 23:40:38 +01:00
|
|
|
const auto indexArgRefp = new AstLambdaArgRef{argFl, name + "__DOT__index", true};
|
|
|
|
|
const auto valueArgRefp = new AstLambdaArgRef{argFl, name, false};
|
|
|
|
|
const auto newp = new AstWith{nodep->fileline(), indexArgRefp, valueArgRefp,
|
|
|
|
|
nodep->exprp()->unlinkFrBackWithNext()};
|
2020-11-26 17:50:50 +01:00
|
|
|
funcrefp->addPinsp(newp);
|
|
|
|
|
}
|
2020-10-31 15:00:55 +01:00
|
|
|
nodep->replaceWith(funcrefp->unlinkFrBack());
|
|
|
|
|
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstWith* nodep) override {
|
2020-10-31 15:00:55 +01:00
|
|
|
// Symbol table needs nodep->name() as the index variable's name
|
|
|
|
|
// Iteration will pickup the AstVar we made under AstWith
|
|
|
|
|
VL_RESTORER(m_curSymp);
|
|
|
|
|
VSymEnt* const oldCurSymp = m_curSymp;
|
|
|
|
|
{
|
|
|
|
|
++m_modWithNum;
|
|
|
|
|
m_curSymp = m_statep->insertBlock(m_curSymp, "__Vwith" + cvtToStr(m_modWithNum), nodep,
|
2020-11-25 03:56:03 +01:00
|
|
|
m_classOrPackagep);
|
2020-10-31 15:00:55 +01:00
|
|
|
m_curSymp->fallbackp(oldCurSymp);
|
2020-11-24 05:18:58 +01:00
|
|
|
UASSERT_OBJ(nodep->indexArgRefp(), nodep, "Missing lambda argref");
|
|
|
|
|
UASSERT_OBJ(nodep->valueArgRefp(), nodep, "Missing lambda argref");
|
2020-11-01 16:56:07 +01:00
|
|
|
// Insert argref's name into symbol table
|
2020-11-24 05:18:58 +01:00
|
|
|
m_statep->insertSym(m_curSymp, nodep->valueArgRefp()->name(), nodep->valueArgRefp(),
|
|
|
|
|
nullptr);
|
2020-10-31 15:00:55 +01:00
|
|
|
}
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
public:
|
2019-09-12 13:22:22 +02:00
|
|
|
// CONSTRUCTORS
|
2020-08-15 19:11:27 +02:00
|
|
|
LinkDotFindVisitor(AstNetlist* rootp, LinkDotState* statep)
|
2020-08-16 15:55:36 +02:00
|
|
|
: m_statep{statep} {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, __FUNCTION__ << ": " << endl);
|
2020-08-15 19:11:27 +02:00
|
|
|
|
2018-05-11 02:55:37 +02:00
|
|
|
iterate(rootp);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
~LinkDotFindVisitor() override = default;
|
2006-08-26 13:35:28 +02:00
|
|
|
};
|
|
|
|
|
|
2012-07-21 23:12:42 +02:00
|
|
|
//======================================================================
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
class LinkDotParamVisitor final : public VNVisitor {
|
2012-07-21 23:12:42 +02:00
|
|
|
private:
|
|
|
|
|
// NODE STATE
|
|
|
|
|
// Cleared on global
|
2019-05-19 22:13:13 +02:00
|
|
|
// *::user1p() -> See LinkDotState
|
|
|
|
|
// *::user2p() -> See LinkDotState
|
|
|
|
|
// *::user4() -> See LinkDotState
|
2012-07-21 23:12:42 +02:00
|
|
|
|
|
|
|
|
// STATE
|
2021-11-26 23:55:36 +01:00
|
|
|
LinkDotState* const m_statep; // State to pass between visitors, including symbol table
|
2020-08-15 19:11:27 +02:00
|
|
|
AstNodeModule* m_modp = nullptr; // Current module
|
2012-07-21 23:12:42 +02:00
|
|
|
|
|
|
|
|
void pinImplicitExprRecurse(AstNode* nodep) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Under a pin, Check interconnect expression for a pin reference or a concat.
|
|
|
|
|
// Create implicit variable as needed
|
2018-02-02 03:32:58 +01:00
|
|
|
if (VN_IS(nodep, Dot)) { // Not creating a simple implied type,
|
2019-05-19 22:13:13 +02:00
|
|
|
// and implying something else would just confuse later errors
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (VN_IS(nodep, VarRef) || VN_IS(nodep, ParseRef)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// To prevent user errors, we should only do single bit
|
|
|
|
|
// implicit vars, however some netlists (MIPS) expect single
|
|
|
|
|
// bit implicit wires to get created with range 0:0 etc.
|
|
|
|
|
m_statep->implicitOkAdd(m_modp, nodep->name());
|
|
|
|
|
}
|
|
|
|
|
// These are perhaps a little too generous, as a SELect of siga[sigb]
|
|
|
|
|
// perhaps shouldn't create an implicit variable. But, we've warned...
|
|
|
|
|
else {
|
|
|
|
|
if (nodep->op1p()) pinImplicitExprRecurse(nodep->op1p());
|
|
|
|
|
if (nodep->op2p()) pinImplicitExprRecurse(nodep->op2p());
|
|
|
|
|
if (nodep->op3p()) pinImplicitExprRecurse(nodep->op3p());
|
|
|
|
|
if (nodep->op4p()) pinImplicitExprRecurse(nodep->op4p());
|
|
|
|
|
if (nodep->nextp()) pinImplicitExprRecurse(nodep->nextp());
|
|
|
|
|
}
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// VISITs
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstTypeTable*) override {}
|
|
|
|
|
void visit(AstConstPool*) override {}
|
|
|
|
|
void visit(AstNodeModule* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(5, " " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
if (nodep->dead() || !nodep->user4()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, "Mark dead module " << nodep << endl);
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(m_statep->forPrearray(), nodep,
|
|
|
|
|
"Dead module persisted past where should have removed");
|
2019-05-19 22:13:13 +02:00
|
|
|
// Don't remove now, because we may have a tree of
|
|
|
|
|
// parameterized modules with VARXREFs into the deleted module
|
|
|
|
|
// region. V3Dead should cleanup.
|
|
|
|
|
// Downstream visitors up until V3Dead need to check for nodep->dead.
|
|
|
|
|
nodep->dead(true);
|
|
|
|
|
} else {
|
|
|
|
|
m_modp = nodep;
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2020-08-15 16:12:55 +02:00
|
|
|
m_modp = nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstPin* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Pin: Link to submodule's port
|
|
|
|
|
// Deal with implicit definitions - do before Resolve visitor as may
|
|
|
|
|
// be referenced above declaration
|
|
|
|
|
if (nodep->exprp() // Else specifically unconnected pin
|
|
|
|
|
&& !nodep->svImplicit()) { // SV 19.11.3: .name pins don't allow implicit decls
|
|
|
|
|
pinImplicitExprRecurse(nodep->exprp());
|
|
|
|
|
}
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstDefParam* nodep) override {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2021-03-15 01:36:43 +01:00
|
|
|
nodep->v3warn(DEFPARAM, "defparam is deprecated (IEEE 1800-2017 C.4.1)\n"
|
|
|
|
|
<< nodep->warnMore()
|
|
|
|
|
<< "... Suggest use instantiation with #(."
|
2020-04-15 13:58:34 +02:00
|
|
|
<< nodep->prettyName() << "(...etc...))");
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const foundp = m_statep->getNodeSym(nodep)->findIdFallback(nodep->path());
|
|
|
|
|
AstCell* const cellp = foundp ? VN_AS(foundp->nodep(), Cell) : nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!cellp) {
|
2020-12-13 04:43:55 +01:00
|
|
|
nodep->v3error("In defparam, instance " << nodep->path() << " never declared");
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* const exprp = nodep->rhsp()->unlinkFrBack();
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, "Defparam cell " << nodep->path() << "." << nodep->name() << " attach-to "
|
|
|
|
|
<< cellp << " <= " << exprp << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
// Don't need to check the name of the defparam exists. V3Param does.
|
2022-11-20 23:40:38 +01:00
|
|
|
AstPin* const pinp = new AstPin{nodep->fileline(),
|
2021-11-26 23:55:36 +01:00
|
|
|
-1, // Pin# not relevant
|
2022-11-20 23:40:38 +01:00
|
|
|
nodep->name(), exprp};
|
2019-05-19 22:13:13 +02:00
|
|
|
cellp->addParamsp(pinp);
|
|
|
|
|
}
|
2022-01-03 02:54:13 +01:00
|
|
|
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstPort* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Port: Stash the pin number
|
|
|
|
|
// Need to set pin numbers after varnames are created
|
|
|
|
|
// But before we do the final resolution based on names
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const foundp = m_statep->getNodeSym(m_modp)->findIdFlat(nodep->name());
|
2022-05-25 06:50:50 +02:00
|
|
|
AstVar* const refp = foundp ? VN_CAST(foundp->nodep(), Var) : nullptr;
|
|
|
|
|
if (!foundp) {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3error(
|
|
|
|
|
"Input/output/inout declaration not found for port: " << nodep->prettyNameQ());
|
2022-05-25 06:50:50 +02:00
|
|
|
} else if (!refp || (!refp->isIO() && !refp->isIfaceRef())) {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3error("Pin is not an in/out/inout/interface: " << nodep->prettyNameQ());
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
2019-06-22 18:43:48 +02:00
|
|
|
if (refp->user4()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3error("Duplicate declaration of port: "
|
2020-11-19 03:03:23 +01:00
|
|
|
<< nodep->prettyNameQ() << '\n'
|
|
|
|
|
<< nodep->warnContextPrimary() << '\n'
|
2020-04-15 13:58:34 +02:00
|
|
|
<< refp->warnOther() << "... Location of original declaration\n"
|
|
|
|
|
<< refp->warnContextSecondary());
|
2019-06-22 18:43:48 +02:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
refp->user4(true);
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const symp = m_statep->insertSym(m_statep->getNodeSym(m_modp),
|
|
|
|
|
"__pinNumber" + cvtToStr(nodep->pinNum()),
|
|
|
|
|
refp, nullptr /*classOrPackagep*/);
|
2019-05-19 22:13:13 +02:00
|
|
|
symp->exported(false);
|
2021-06-19 19:41:19 +02:00
|
|
|
refp->pinNum(nodep->pinNum());
|
2022-09-01 00:12:14 +02:00
|
|
|
// Put the variable where the port is, so that variables stay
|
|
|
|
|
// in pin number sorted order. Otherwise hierarchical or XML
|
|
|
|
|
// may botch by-position instances.
|
|
|
|
|
nodep->addHereThisAsNext(refp->unlinkFrBack());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
// Ports not needed any more
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstAssignW* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Deal with implicit definitions
|
|
|
|
|
// We used to nodep->allowImplicit() here, but it turns out
|
|
|
|
|
// normal "assigns" can also make implicit wires. Yuk.
|
|
|
|
|
pinImplicitExprRecurse(nodep->lhsp());
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstAssignAlias* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// tran gates need implicit creation
|
|
|
|
|
// As VarRefs don't exist in forPrimary, sanity check
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(!m_statep->forPrimary(), nodep, "Assign aliases unexpected pre-dot");
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstVarRef* const forrefp = VN_CAST(nodep->lhsp(), VarRef)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
pinImplicitExprRecurse(forrefp);
|
|
|
|
|
}
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstVarRef* const forrefp = VN_CAST(nodep->rhsp(), VarRef)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
pinImplicitExprRecurse(forrefp);
|
|
|
|
|
}
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstImplicit* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Unsupported gates need implicit creation
|
|
|
|
|
pinImplicitExprRecurse(nodep);
|
|
|
|
|
// We're done with implicit gates
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstClassOrPackageRef* nodep) override {
|
2021-11-26 23:55:36 +01:00
|
|
|
if (auto* const fwdp = VN_CAST(nodep->classOrPackageNodep(), TypedefFwd)) {
|
2020-12-05 22:23:20 +01:00
|
|
|
// Relink forward definitions to the "real" definition
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const foundp = m_statep->getNodeSym(fwdp)->findIdFallback(fwdp->name());
|
2020-12-05 22:23:20 +01:00
|
|
|
if (foundp && (VN_IS(foundp->nodep(), Class) || VN_IS(foundp->nodep(), Package))) {
|
2021-10-22 14:56:48 +02:00
|
|
|
nodep->classOrPackagep(VN_AS(foundp->nodep(), NodeModule));
|
2020-12-05 22:23:20 +01:00
|
|
|
} else if (foundp && VN_IS(foundp->nodep(), ParamTypeDType)) {
|
|
|
|
|
UASSERT(m_statep->forPrimary(), "Param types should have been resolved");
|
2021-10-22 14:56:48 +02:00
|
|
|
nodep->classOrPackageNodep(VN_AS(foundp->nodep(), ParamTypeDType));
|
2020-12-05 22:23:20 +01:00
|
|
|
} else {
|
|
|
|
|
if (foundp) UINFO(1, "found nodep = " << foundp->nodep() << endl);
|
|
|
|
|
nodep->v3error(
|
|
|
|
|
"Forward typedef used as class/package does not resolve to class/package: "
|
|
|
|
|
<< nodep->prettyNameQ() << '\n'
|
|
|
|
|
<< nodep->warnContextPrimary() << '\n'
|
|
|
|
|
<< (foundp ? nodep->warnMore() + "... Object with matching name\n"
|
|
|
|
|
+ foundp->nodep()->warnContextSecondary()
|
|
|
|
|
: ""));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstTypedefFwd* nodep) override {
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const foundp = m_statep->getNodeSym(nodep)->findIdFallback(nodep->name());
|
2020-04-02 13:39:14 +02:00
|
|
|
if (!foundp && v3Global.opt.pedantic()) {
|
|
|
|
|
// We only check it was ever really defined in pedantic mode, as it
|
|
|
|
|
// might have been in a header file referring to a module we never
|
|
|
|
|
// needed so there are false positives
|
|
|
|
|
nodep->v3error(
|
|
|
|
|
"Forward typedef unused or does not resolve to a data type (IEEE 1800-2017 6.18): "
|
|
|
|
|
<< nodep->prettyNameQ());
|
|
|
|
|
}
|
|
|
|
|
// We only needed the forward declaration in order to parse correctly.
|
2020-12-05 22:23:20 +01:00
|
|
|
// Delete later as may be ClassOrPackageRef's still pointing to it
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
2020-04-02 13:39:14 +02:00
|
|
|
}
|
2020-04-04 14:31:14 +02:00
|
|
|
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
2012-07-21 23:12:42 +02:00
|
|
|
|
|
|
|
|
public:
|
2019-09-12 13:22:22 +02:00
|
|
|
// CONSTRUCTORS
|
2020-08-15 19:11:27 +02:00
|
|
|
LinkDotParamVisitor(AstNetlist* rootp, LinkDotState* statep)
|
2020-08-16 15:55:36 +02:00
|
|
|
: m_statep{statep} {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, __FUNCTION__ << ": " << endl);
|
2018-05-11 02:55:37 +02:00
|
|
|
iterate(rootp);
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
~LinkDotParamVisitor() override = default;
|
2012-07-21 23:12:42 +02:00
|
|
|
};
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//======================================================================
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
class LinkDotScopeVisitor final : public VNVisitor {
|
2013-05-28 03:39:19 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
// STATE
|
2021-11-26 23:55:36 +01:00
|
|
|
LinkDotState* const m_statep; // State to pass between visitors, including symbol table
|
|
|
|
|
const AstScope* m_scopep = nullptr; // The current scope
|
2020-08-15 19:11:27 +02:00
|
|
|
VSymEnt* m_modSymp = nullptr; // Symbol entry for current module
|
2009-01-21 22:56:50 +01:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
// VISITs
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNetlist* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Recurse..., backward as must do packages before using packages
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildrenBackwards(nodep);
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstConstPool*) override {}
|
|
|
|
|
void visit(AstScope* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, " SCOPE " << nodep << endl);
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(m_statep->forScopeCreation(), nodep,
|
|
|
|
|
"Scopes should only exist right after V3Scope");
|
2019-05-19 22:13:13 +02:00
|
|
|
// Using the CELL names, we created all hierarchy. We now need to match this Scope
|
|
|
|
|
// up with the hierarchy created by the CELL names.
|
|
|
|
|
m_modSymp = m_statep->getScopeSym(nodep);
|
|
|
|
|
m_scopep = nodep;
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2020-08-15 16:12:55 +02:00
|
|
|
m_modSymp = nullptr;
|
|
|
|
|
m_scopep = nullptr;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstVarScope* nodep) override {
|
2020-04-05 15:30:23 +02:00
|
|
|
if (!nodep->varp()->isFuncLocal() && !nodep->varp()->isClassMember()) {
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const varSymp
|
2020-08-15 16:12:55 +02:00
|
|
|
= m_statep->insertSym(m_modSymp, nodep->varp()->name(), nodep, nullptr);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (nodep->varp()->isIfaceRef() && nodep->varp()->isIfaceParent()) {
|
|
|
|
|
UINFO(9, "Iface parent ref var " << nodep->varp()->name() << " " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
// Find the interface cell the var references
|
2021-11-26 23:55:36 +01:00
|
|
|
AstIfaceRefDType* const dtypep
|
2019-05-19 22:13:13 +02:00
|
|
|
= LinkDotState::ifaceRefFromArray(nodep->varp()->dtypep());
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(dtypep, nodep, "Non AstIfaceRefDType on isIfaceRef() var");
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, "Iface parent dtype " << dtypep << endl);
|
2021-06-21 00:32:57 +02:00
|
|
|
const string ifcellname = dtypep->cellName();
|
2020-04-15 13:58:34 +02:00
|
|
|
string baddot;
|
|
|
|
|
VSymEnt* okSymp;
|
2020-07-04 15:35:04 +02:00
|
|
|
VSymEnt* cellSymp = m_statep->findDotted(nodep->fileline(), m_modSymp, ifcellname,
|
|
|
|
|
baddot, okSymp);
|
2020-12-13 04:43:55 +01:00
|
|
|
UASSERT_OBJ(
|
|
|
|
|
cellSymp, nodep,
|
|
|
|
|
"No symbol for interface instance: " << nodep->prettyNameQ(ifcellname));
|
|
|
|
|
UINFO(5, " Found interface instance: se" << cvtToHex(cellSymp) << " "
|
|
|
|
|
<< cellSymp->nodep() << endl);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (dtypep->modportName() != "") {
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const mpSymp = m_statep->findDotted(nodep->fileline(), m_modSymp,
|
|
|
|
|
ifcellname, baddot, okSymp);
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(mpSymp, nodep,
|
|
|
|
|
"No symbol for interface modport: "
|
2020-04-15 13:58:34 +02:00
|
|
|
<< nodep->prettyNameQ(dtypep->modportName()));
|
2019-07-06 18:57:50 +02:00
|
|
|
cellSymp = mpSymp;
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(5, " Found modport cell: se" << cvtToHex(cellSymp) << " "
|
|
|
|
|
<< mpSymp->nodep() << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
// Interface reference; need to put whole thing into
|
|
|
|
|
// symtable, but can't clone it now as we may have a later
|
|
|
|
|
// alias for it.
|
|
|
|
|
m_statep->insertScopeAlias(LinkDotState::SAMN_IFTOP, varSymp, cellSymp);
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeFTask* nodep) override {
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const symp = m_statep->insertBlock(m_modSymp, nodep->name(), nodep, nullptr);
|
2019-05-19 22:13:13 +02:00
|
|
|
symp->fallbackp(m_modSymp);
|
2022-11-11 00:08:15 +01:00
|
|
|
iterateChildren(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstForeach* nodep) override {
|
2021-12-11 21:06:33 +01:00
|
|
|
VSymEnt* const symp = m_statep->insertBlock(m_modSymp, nodep->name(), nodep, nullptr);
|
|
|
|
|
symp->fallbackp(m_modSymp);
|
|
|
|
|
// No recursion, we don't want to pick up variables
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstWith* nodep) override {
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const symp = m_statep->insertBlock(m_modSymp, nodep->name(), nodep, nullptr);
|
2020-11-01 16:56:07 +01:00
|
|
|
symp->fallbackp(m_modSymp);
|
|
|
|
|
// No recursion, we don't want to pick up variables
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstAssignAlias* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Track aliases created by V3Inline; if we get a VARXREF(aliased_from)
|
|
|
|
|
// we'll need to replace it with a VARXREF(aliased_to)
|
2022-11-27 14:31:22 +01:00
|
|
|
if (debug() >= 9) nodep->dumpTree("- alias: ");
|
2021-11-26 23:55:36 +01:00
|
|
|
AstVarScope* const fromVscp = VN_AS(nodep->lhsp(), VarRef)->varScopep();
|
|
|
|
|
AstVarScope* const toVscp = VN_AS(nodep->rhsp(), VarRef)->varScopep();
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(fromVscp && toVscp, nodep, "Bad alias scopes");
|
2019-05-19 22:13:13 +02:00
|
|
|
fromVscp->user2p(toVscp);
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstAssignVarScope* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(5, "ASSIGNVARSCOPE " << nodep << endl);
|
2022-11-27 14:31:22 +01:00
|
|
|
if (debug() >= 9) nodep->dumpTree("- avs: ");
|
2019-05-19 22:13:13 +02:00
|
|
|
VSymEnt* rhsSymp;
|
|
|
|
|
{
|
2021-11-26 23:55:36 +01:00
|
|
|
AstVarRef* const refp = VN_CAST(nodep->rhsp(), VarRef);
|
|
|
|
|
AstVarXRef* const xrefp = VN_CAST(nodep->rhsp(), VarXRef);
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(refp || xrefp, nodep,
|
|
|
|
|
"Unsupported: Non Var(X)Ref attached to interface pin");
|
2020-04-15 13:58:34 +02:00
|
|
|
string inl
|
|
|
|
|
= ((xrefp && xrefp->inlinedDots().size()) ? (xrefp->inlinedDots() + "__DOT__")
|
|
|
|
|
: "");
|
2020-08-15 16:12:55 +02:00
|
|
|
VSymEnt* symp = nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
string scopename;
|
|
|
|
|
while (!symp) {
|
2020-04-15 13:58:34 +02:00
|
|
|
scopename
|
|
|
|
|
= refp ? refp->name() : (inl.size() ? (inl + xrefp->name()) : xrefp->name());
|
|
|
|
|
string baddot;
|
|
|
|
|
VSymEnt* okSymp;
|
2020-07-04 15:35:04 +02:00
|
|
|
symp = m_statep->findDotted(nodep->rhsp()->fileline(), m_modSymp, scopename,
|
|
|
|
|
baddot, okSymp);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (inl == "") break;
|
2019-05-19 22:13:13 +02:00
|
|
|
inl = LinkDotState::removeLastInlineScope(inl);
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!symp) {
|
|
|
|
|
UINFO(9, "No symbol for interface alias rhs ("
|
2022-08-30 07:02:39 +02:00
|
|
|
<< std::string{refp ? "VARREF " : "VARXREF "} << scopename << ")"
|
|
|
|
|
<< endl);
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(symp, nodep, "No symbol for interface alias rhs");
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(5, " Found a linked scope RHS: " << scopename << " se" << cvtToHex(symp)
|
|
|
|
|
<< " " << symp->nodep() << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
rhsSymp = symp;
|
|
|
|
|
}
|
|
|
|
|
VSymEnt* lhsSymp;
|
|
|
|
|
{
|
2021-11-26 23:55:36 +01:00
|
|
|
const AstVarXRef* const xrefp = VN_CAST(nodep->lhsp(), VarXRef);
|
|
|
|
|
const AstVarRef* const refp = VN_CAST(nodep->lhsp(), VarRef);
|
2016-01-22 01:11:53 +01:00
|
|
|
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(refp || xrefp, nodep,
|
|
|
|
|
"Unsupported: Non Var(X)Ref attached to interface pin");
|
2021-06-21 00:32:57 +02:00
|
|
|
const string scopename
|
|
|
|
|
= refp ? refp->varp()->name() : xrefp->dotted() + "." + xrefp->name();
|
2020-04-15 13:58:34 +02:00
|
|
|
string baddot;
|
|
|
|
|
VSymEnt* okSymp;
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const symp = m_statep->findDotted(nodep->lhsp()->fileline(), m_modSymp,
|
|
|
|
|
scopename, baddot, okSymp);
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(symp, nodep, "No symbol for interface alias lhs");
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(5, " Found a linked scope LHS: " << scopename << " se" << cvtToHex(symp)
|
|
|
|
|
<< " " << symp->nodep() << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
lhsSymp = symp;
|
|
|
|
|
}
|
|
|
|
|
// Remember the alias - can't do it yet because we may have additional symbols to be added,
|
|
|
|
|
// or maybe an alias of an alias
|
|
|
|
|
m_statep->insertScopeAlias(LinkDotState::SAMN_IFTOP, lhsSymp, rhsSymp);
|
|
|
|
|
// We have stored the link, we don't need these any more
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
2013-05-28 03:39:19 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
// For speed, don't recurse things that can't have scope
|
2006-12-12 19:25:33 +01:00
|
|
|
// Note we allow AstNodeStmt's as generates may be under them
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstCell*) override {}
|
|
|
|
|
void visit(AstVar*) override {}
|
|
|
|
|
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
public:
|
2019-09-12 13:22:22 +02:00
|
|
|
// CONSTRUCTORS
|
2020-08-15 19:11:27 +02:00
|
|
|
LinkDotScopeVisitor(AstNetlist* rootp, LinkDotState* statep)
|
2020-08-16 15:55:36 +02:00
|
|
|
: m_statep{statep} {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, __FUNCTION__ << ": " << endl);
|
2018-05-11 02:55:37 +02:00
|
|
|
iterate(rootp);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
~LinkDotScopeVisitor() override = default;
|
2006-08-26 13:35:28 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
|
|
2013-05-28 03:39:19 +02:00
|
|
|
// Iterate an interface to resolve modports
|
2022-01-02 19:56:40 +01:00
|
|
|
class LinkDotIfaceVisitor final : public VNVisitor {
|
2013-05-28 03:39:19 +02:00
|
|
|
// STATE
|
2022-01-01 17:46:49 +01:00
|
|
|
LinkDotState* const m_statep; // State to pass between visitors, including symbol table
|
2020-04-15 13:58:34 +02:00
|
|
|
VSymEnt* m_curSymp; // Symbol Entry for current table, where to lookup/insert
|
2013-05-28 03:39:19 +02:00
|
|
|
|
|
|
|
|
// VISITs
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstModport* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Modport: Remember its name for later resolution
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(5, " fiv: " << nodep << endl);
|
2020-08-25 03:10:43 +02:00
|
|
|
VL_RESTORER(m_curSymp);
|
|
|
|
|
VSymEnt* const oldCurSymp = m_curSymp;
|
2019-05-19 22:13:13 +02:00
|
|
|
{
|
|
|
|
|
// Create symbol table for the vars
|
2020-08-15 16:12:55 +02:00
|
|
|
m_curSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, nullptr);
|
2019-05-19 22:13:13 +02:00
|
|
|
m_curSymp->fallbackp(oldCurSymp);
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2013-05-28 03:39:19 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstModportFTaskRef* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(5, " fif: " << nodep << endl);
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2020-06-10 01:20:16 +02:00
|
|
|
if (nodep->isExport()) nodep->v3warn(E_UNSUPPORTED, "Unsupported: modport export");
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const symp = m_curSymp->findIdFallback(nodep->name());
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!symp) {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3error("Modport item not found: " << nodep->prettyNameQ());
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (AstNodeFTask* const ftaskp = VN_CAST(symp->nodep(), NodeFTask)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Make symbol under modport that points at the _interface_'s var, not the modport.
|
|
|
|
|
nodep->ftaskp(ftaskp);
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const subSymp
|
2020-08-15 16:12:55 +02:00
|
|
|
= m_statep->insertSym(m_curSymp, nodep->name(), ftaskp, nullptr /*package*/);
|
2019-05-19 22:13:13 +02:00
|
|
|
m_statep->insertScopeAlias(LinkDotState::SAMN_MODPORT, subSymp, symp);
|
|
|
|
|
} else {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3error("Modport item is not a function/task: " << nodep->prettyNameQ());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
if (m_statep->forScopeCreation()) {
|
|
|
|
|
// Done with AstModportFTaskRef.
|
|
|
|
|
// Delete to prevent problems if we dead-delete pointed to ftask
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->unlinkFrBack();
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2013-12-21 12:51:15 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstModportVarRef* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(5, " fiv: " << nodep << endl);
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const symp = m_curSymp->findIdFallback(nodep->name());
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!symp) {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3error("Modport item not found: " << nodep->prettyNameQ());
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (AstVar* const varp = VN_CAST(symp->nodep(), Var)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Make symbol under modport that points at the _interface_'s var via the modport.
|
|
|
|
|
// (Need modport still to test input/output markings)
|
|
|
|
|
nodep->varp(varp);
|
2020-08-15 16:12:55 +02:00
|
|
|
m_statep->insertSym(m_curSymp, nodep->name(), nodep, nullptr /*package*/);
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (AstVarScope* const vscp = VN_CAST(symp->nodep(), VarScope)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Make symbol under modport that points at the _interface_'s var, not the modport.
|
|
|
|
|
nodep->varp(vscp->varp());
|
2020-08-15 16:12:55 +02:00
|
|
|
m_statep->insertSym(m_curSymp, nodep->name(), vscp, nullptr /*package*/);
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3error("Modport item is not a variable: " << nodep->prettyNameQ());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
if (m_statep->forScopeCreation()) {
|
|
|
|
|
// Done with AstModportVarRef.
|
|
|
|
|
// Delete to prevent problems if we dead-delete pointed to variable
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->unlinkFrBack();
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2013-05-28 03:39:19 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
2013-05-28 03:39:19 +02:00
|
|
|
|
|
|
|
|
public:
|
2019-09-12 13:22:22 +02:00
|
|
|
// CONSTRUCTORS
|
2022-01-01 17:46:49 +01:00
|
|
|
LinkDotIfaceVisitor(AstIface* nodep, VSymEnt* curSymp, LinkDotState* statep)
|
|
|
|
|
: m_statep{statep}
|
|
|
|
|
, m_curSymp{curSymp} {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, __FUNCTION__ << ": " << endl);
|
2018-05-11 02:55:37 +02:00
|
|
|
iterate(nodep);
|
2013-05-28 03:39:19 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
~LinkDotIfaceVisitor() override = default;
|
2013-05-28 03:39:19 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void LinkDotState::computeIfaceModSyms() {
|
2020-11-11 04:10:38 +01:00
|
|
|
for (const auto& itr : m_ifaceModSyms) {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstIface* const nodep = itr.first;
|
|
|
|
|
VSymEnt* const symp = itr.second;
|
2021-07-12 00:42:01 +02:00
|
|
|
LinkDotIfaceVisitor{nodep, symp, this};
|
2013-05-28 03:39:19 +02:00
|
|
|
}
|
|
|
|
|
m_ifaceModSyms.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
class LinkDotResolveVisitor final : public VNVisitor {
|
2006-08-26 13:35:28 +02:00
|
|
|
private:
|
2012-07-21 23:12:42 +02:00
|
|
|
// NODE STATE
|
|
|
|
|
// Cleared on global
|
2019-05-19 22:13:13 +02:00
|
|
|
// *::user1p() -> See LinkDotState
|
|
|
|
|
// *::user2p() -> See LinkDotState
|
|
|
|
|
// *::user3() // bool. Processed
|
|
|
|
|
// *::user4() -> See LinkDotState
|
2012-07-21 23:12:42 +02:00
|
|
|
// Cleared on Cell
|
2019-05-19 22:13:13 +02:00
|
|
|
// AstVar::user5() // bool. True if pin used in this cell
|
2022-01-02 19:56:40 +01:00
|
|
|
const VNUser3InUse m_inuser3;
|
|
|
|
|
const VNUser5InUse m_inuser5;
|
2012-07-21 23:12:42 +02:00
|
|
|
|
2012-07-24 12:26:35 +02:00
|
|
|
// TYPES
|
2020-08-16 18:05:35 +02:00
|
|
|
enum DotPosition : uint8_t {
|
2020-04-15 13:58:34 +02:00
|
|
|
DP_NONE = 0, // Not under a DOT
|
|
|
|
|
DP_PACKAGE, // {package}:: DOT
|
|
|
|
|
DP_SCOPE, // [DOT...] {scope-or-var} DOT
|
|
|
|
|
DP_FINAL, // [DOT...] {var-or-func-or-dtype} with no following dots
|
|
|
|
|
DP_MEMBER
|
|
|
|
|
}; // DOT {member-name} [DOT...]
|
2012-07-24 12:26:35 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
// STATE
|
2021-11-26 23:55:36 +01:00
|
|
|
LinkDotState* const m_statep; // State, including dotted symbol table
|
2020-08-15 19:11:27 +02:00
|
|
|
VSymEnt* m_curSymp = nullptr; // SymEnt for current lookup point
|
|
|
|
|
VSymEnt* m_modSymp = nullptr; // SymEnt for current module
|
|
|
|
|
VSymEnt* m_pinSymp = nullptr; // SymEnt for pin lookups
|
2021-11-26 23:55:36 +01:00
|
|
|
const AstCell* m_cellp = nullptr; // Current cell
|
2020-08-15 19:11:27 +02:00
|
|
|
AstNodeModule* m_modp = nullptr; // Current module
|
2022-01-04 00:50:41 +01:00
|
|
|
AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
2020-08-15 19:11:27 +02:00
|
|
|
int m_modportNum = 0; // Uniqueify modport numbers
|
2022-12-23 13:34:49 +01:00
|
|
|
bool m_inSens = false; // True if in senitem
|
2023-01-29 00:06:37 +01:00
|
|
|
std::set<std::string> m_ifClassImpNames; // Names imported from interface class
|
2012-12-31 20:00:04 +01:00
|
|
|
|
|
|
|
|
struct DotStates {
|
2020-04-15 13:58:34 +02:00
|
|
|
DotPosition m_dotPos; // Scope part of dotted resolution
|
|
|
|
|
VSymEnt* m_dotSymp; // SymEnt for dotted AstParse lookup
|
2021-11-26 23:55:36 +01:00
|
|
|
const AstDot* m_dotp; // Current dot
|
2020-04-15 13:58:34 +02:00
|
|
|
bool m_unresolved; // Unresolved, needs help from V3Param
|
2020-10-30 02:27:19 +01:00
|
|
|
AstNode* m_unlinkedScopep; // Unresolved scope, needs corresponding VarXRef
|
2020-04-15 13:58:34 +02:00
|
|
|
bool m_dotErr; // Error found in dotted resolution, ignore upwards
|
|
|
|
|
string m_dotText; // String of dotted names found in below parseref
|
2020-08-15 16:12:55 +02:00
|
|
|
DotStates() { init(nullptr); }
|
2020-11-17 01:56:16 +01:00
|
|
|
~DotStates() = default;
|
2019-05-19 22:13:13 +02:00
|
|
|
void init(VSymEnt* curSymp) {
|
2020-04-15 13:58:34 +02:00
|
|
|
m_dotPos = DP_NONE;
|
|
|
|
|
m_dotSymp = curSymp;
|
2020-08-15 16:12:55 +02:00
|
|
|
m_dotp = nullptr;
|
2020-04-15 13:58:34 +02:00
|
|
|
m_dotErr = false;
|
|
|
|
|
m_dotText = "";
|
|
|
|
|
m_unresolved = false;
|
2020-10-30 02:27:19 +01:00
|
|
|
m_unlinkedScopep = nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
string ascii() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
static const char* const names[] = {"NONE", "PACKAGE", "SCOPE", "FINAL", "MEMBER"};
|
2018-02-02 03:24:41 +01:00
|
|
|
std::ostringstream sstr;
|
2020-04-15 13:58:34 +02:00
|
|
|
sstr << "ds=" << names[m_dotPos];
|
|
|
|
|
sstr << " dse" << cvtToHex(m_dotSymp);
|
|
|
|
|
sstr << " txt=" << m_dotText;
|
|
|
|
|
sstr << " unr=" << m_unresolved;
|
2019-05-19 22:13:13 +02:00
|
|
|
return sstr.str();
|
|
|
|
|
}
|
2012-12-31 20:00:04 +01:00
|
|
|
} m_ds; // State to preserve across recursions
|
2009-01-21 22:56:50 +01:00
|
|
|
|
2012-07-22 03:18:07 +02:00
|
|
|
// METHODS - Variables
|
2022-07-30 16:01:25 +02:00
|
|
|
void createImplicitVar(VSymEnt* /*lookupSymp*/, AstVarRef* nodep, AstNodeModule* modp,
|
2020-04-15 13:58:34 +02:00
|
|
|
VSymEnt* moduleSymp, bool noWarn) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Create implicit after warning
|
|
|
|
|
if (!nodep->varp()) {
|
|
|
|
|
if (!noWarn) {
|
|
|
|
|
if (nodep->fileline()->warnIsOff(V3ErrorCode::I_DEF_NETTYPE_WIRE)) {
|
2021-06-21 00:32:57 +02:00
|
|
|
const string suggest = m_statep->suggestSymFallback(moduleSymp, nodep->name(),
|
2022-11-20 23:40:38 +01:00
|
|
|
LinkNodeMatcherVar{});
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3error("Signal definition not found, and implicit disabled with "
|
|
|
|
|
"`default_nettype: "
|
2020-11-19 03:03:23 +01:00
|
|
|
<< nodep->prettyNameQ() << '\n'
|
2020-04-15 13:58:34 +02:00
|
|
|
<< (suggest.empty() ? "" : nodep->warnMore() + suggest));
|
2019-07-14 02:30:32 +02:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
// Bypass looking for suggestions if IMPLICIT is turned off
|
|
|
|
|
// as there could be thousands of these suppressed in large netlists
|
|
|
|
|
else if (!nodep->fileline()->warnIsOff(V3ErrorCode::IMPLICIT)) {
|
2021-06-21 00:32:57 +02:00
|
|
|
const string suggest = m_statep->suggestSymFallback(moduleSymp, nodep->name(),
|
2022-11-20 23:40:38 +01:00
|
|
|
LinkNodeMatcherVar{});
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3warn(IMPLICIT,
|
|
|
|
|
"Signal definition not found, creating implicitly: "
|
2020-11-19 03:03:23 +01:00
|
|
|
<< nodep->prettyNameQ() << '\n'
|
2020-04-15 13:58:34 +02:00
|
|
|
<< (suggest.empty() ? "" : nodep->warnMore() + suggest));
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
2022-11-20 23:40:38 +01:00
|
|
|
AstVar* const newp = new AstVar{nodep->fileline(), VVarType::WIRE, nodep->name(),
|
|
|
|
|
VFlagLogicPacked{}, 1};
|
2019-05-19 22:13:13 +02:00
|
|
|
newp->trace(modp->modTrace());
|
|
|
|
|
nodep->varp(newp);
|
2022-09-15 20:43:56 +02:00
|
|
|
modp->addStmtsp(newp);
|
2019-05-19 22:13:13 +02:00
|
|
|
// Link it to signal list, must add the variable under the module;
|
|
|
|
|
// current scope might be lower now
|
2020-11-25 03:56:03 +01:00
|
|
|
m_statep->insertSym(moduleSymp, newp->name(), newp, nullptr /*classOrPackagep*/);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2012-07-22 03:18:07 +02:00
|
|
|
}
|
2020-11-09 04:02:35 +01:00
|
|
|
AstVar* foundToVarp(const VSymEnt* symp, AstNode* nodep, VAccess access) {
|
2017-11-15 01:50:31 +01:00
|
|
|
// Return a variable if possible, auto converting a modport to variable
|
|
|
|
|
if (!symp) {
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2018-02-02 03:32:58 +01:00
|
|
|
} else if (VN_IS(symp->nodep(), Var)) {
|
2021-10-22 14:56:48 +02:00
|
|
|
return VN_AS(symp->nodep(), Var);
|
2018-02-02 03:32:58 +01:00
|
|
|
} else if (VN_IS(symp->nodep(), ModportVarRef)) {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstModportVarRef* const snodep = VN_AS(symp->nodep(), ModportVarRef);
|
|
|
|
|
AstVar* const varp = snodep->varp();
|
2020-11-09 04:02:35 +01:00
|
|
|
if (access.isWriteOrRW() && snodep->direction().isReadOnly()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3error("Attempt to drive input-only modport: " << nodep->prettyNameQ());
|
2019-05-19 22:13:13 +02:00
|
|
|
} // else other simulators don't warn about reading, and IEEE doesn't say illegal
|
2018-10-27 23:29:00 +02:00
|
|
|
return varp;
|
2017-11-15 01:50:31 +01:00
|
|
|
} else {
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2017-11-15 01:50:31 +01:00
|
|
|
}
|
|
|
|
|
}
|
2012-07-23 04:48:39 +02:00
|
|
|
void taskFuncSwapCheck(AstNodeFTaskRef* nodep) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (nodep->taskp() && VN_IS(nodep->taskp(), Task) && VN_IS(nodep, FuncRef)) {
|
|
|
|
|
nodep->v3error("Illegal call of a task as a function: " << nodep->prettyNameQ());
|
|
|
|
|
}
|
2012-07-23 04:48:39 +02:00
|
|
|
}
|
2022-09-16 14:17:38 +02:00
|
|
|
void checkNoDot(AstNode* nodep) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (VL_UNLIKELY(m_ds.m_dotPos != DP_NONE)) {
|
2020-04-15 13:58:34 +02:00
|
|
|
// UINFO(9, "ds=" << m_ds.ascii() << endl);
|
|
|
|
|
nodep->v3error("Syntax Error: Not expecting " << nodep->type() << " under a "
|
|
|
|
|
<< nodep->backp()->type()
|
|
|
|
|
<< " in dotted expression");
|
2019-05-19 22:13:13 +02:00
|
|
|
m_ds.m_dotErr = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-09 04:43:32 +01:00
|
|
|
AstVar* findIfaceTopVarp(AstNode* nodep, VSymEnt* parentEntp, const string& name) {
|
2021-06-21 00:32:57 +02:00
|
|
|
const string findName = name + "__Viftop";
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const ifaceSymp = parentEntp->findIdFallback(findName);
|
|
|
|
|
AstVar* const ifaceTopVarp = ifaceSymp ? VN_AS(ifaceSymp->nodep(), Var) : nullptr;
|
2020-11-09 04:43:32 +01:00
|
|
|
UASSERT_OBJ(ifaceTopVarp, nodep, "Can't find interface var ref: " << findName);
|
|
|
|
|
return ifaceTopVarp;
|
2013-05-28 03:39:19 +02:00
|
|
|
}
|
2016-03-13 02:54:52 +01:00
|
|
|
void markAndCheckPinDup(AstNode* nodep, AstNode* refp, const char* whatp) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (refp->user5p() && refp->user5p() != nodep) {
|
2020-11-19 03:03:23 +01:00
|
|
|
nodep->v3error("Duplicate " << whatp << " connection: " << nodep->prettyNameQ() << '\n'
|
|
|
|
|
<< nodep->warnContextPrimary() << '\n'
|
2020-04-15 13:58:34 +02:00
|
|
|
<< refp->user5p()->warnOther()
|
|
|
|
|
<< "... Location of original " << whatp << " connection\n"
|
|
|
|
|
<< refp->user5p()->warnContextSecondary());
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
|
|
|
|
refp->user5p(nodep);
|
|
|
|
|
}
|
2016-03-13 02:54:52 +01:00
|
|
|
}
|
2022-12-23 13:34:49 +01:00
|
|
|
VSymEnt* getCreateClockingEventSymEnt(AstClocking* clockingp) {
|
|
|
|
|
if (!clockingp->eventp()) {
|
|
|
|
|
AstVar* const eventp = new AstVar{
|
|
|
|
|
clockingp->fileline(), VVarType::MODULETEMP, clockingp->name(), VFlagChildDType{},
|
|
|
|
|
new AstBasicDType{clockingp->fileline(), VBasicDTypeKwd::EVENT}};
|
|
|
|
|
clockingp->eventp(eventp);
|
|
|
|
|
// Trigger the clocking event in Observed (IEEE 1800-2017 14.13)
|
|
|
|
|
clockingp->addNextHere(new AstAlwaysObserved{
|
|
|
|
|
clockingp->fileline(),
|
|
|
|
|
new AstSenTree{clockingp->fileline(), clockingp->sensesp()->cloneTree(false)},
|
|
|
|
|
new AstFireEvent{clockingp->fileline(),
|
|
|
|
|
new AstVarRef{clockingp->fileline(), eventp, VAccess::WRITE},
|
|
|
|
|
false}});
|
|
|
|
|
v3Global.setHasEvents();
|
|
|
|
|
eventp->user1p(new VSymEnt{m_statep->symsp(), eventp});
|
|
|
|
|
}
|
|
|
|
|
return reinterpret_cast<VSymEnt*>(clockingp->eventp()->user1p());
|
|
|
|
|
}
|
2012-07-22 03:18:07 +02:00
|
|
|
|
2022-08-28 16:24:55 +02:00
|
|
|
bool isParamedClassRef(const AstNode* nodep) {
|
2022-12-26 10:30:41 +01:00
|
|
|
// Is this a parameterized reference to a class, or a reference to class parameter
|
2022-08-28 16:24:55 +02:00
|
|
|
if (const auto* classRefp = VN_CAST(nodep, ClassOrPackageRef)) {
|
|
|
|
|
if (classRefp->paramsp()) return true;
|
|
|
|
|
const auto* classp = classRefp->classOrPackageNodep();
|
|
|
|
|
while (const auto* typedefp = VN_CAST(classp, Typedef)) classp = typedefp->subDTypep();
|
2022-10-21 15:00:40 +02:00
|
|
|
return (VN_IS(classp, ClassRefDType) && VN_AS(classp, ClassRefDType)->paramsp())
|
|
|
|
|
|| VN_IS(classp, ParamTypeDType);
|
2022-08-28 16:24:55 +02:00
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-10-14 14:55:55 +02:00
|
|
|
VSymEnt* getThisClassSymp() {
|
|
|
|
|
VSymEnt* classSymp = m_ds.m_dotSymp;
|
|
|
|
|
do {
|
|
|
|
|
classSymp = classSymp->parentp();
|
|
|
|
|
} while (classSymp && !VN_IS(classSymp->nodep(), Class));
|
|
|
|
|
return classSymp;
|
|
|
|
|
}
|
2023-01-29 00:06:37 +01:00
|
|
|
void importImplementsClass(AstClass* implementsClassp, VSymEnt* interfaceSymp,
|
|
|
|
|
AstClass* interfaceClassp) {
|
|
|
|
|
UINFO(8, "importImplementsClass to " << implementsClassp << " from " << interfaceClassp
|
|
|
|
|
<< endl);
|
|
|
|
|
for (VSymEnt::const_iterator it = interfaceSymp->begin(); it != interfaceSymp->end();
|
|
|
|
|
++it) {
|
|
|
|
|
if (AstNode* interfaceSubp = it->second->nodep()) {
|
|
|
|
|
UINFO(8, " SymFunc " << interfaceSubp << endl);
|
|
|
|
|
if (VN_IS(interfaceSubp, NodeFTask)) {
|
|
|
|
|
bool existsInChild = m_curSymp->findIdFlat(interfaceSubp->name());
|
|
|
|
|
if (!existsInChild && !implementsClassp->isInterfaceClass()) {
|
|
|
|
|
implementsClassp->v3error(
|
|
|
|
|
"Class " << implementsClassp->prettyNameQ() << " implements "
|
|
|
|
|
<< interfaceClassp->prettyNameQ()
|
|
|
|
|
<< " but is missing implementation for "
|
|
|
|
|
<< interfaceSubp->prettyNameQ() << " (IEEE 1800-2017 8.26)\n"
|
|
|
|
|
<< implementsClassp->warnContextPrimary() << '\n'
|
|
|
|
|
<< interfaceSubp->warnOther()
|
|
|
|
|
<< "... Location of interface class's function\n"
|
|
|
|
|
<< interfaceSubp->warnContextSecondary());
|
|
|
|
|
}
|
|
|
|
|
if (m_ifClassImpNames.find(interfaceSubp->name()) != m_ifClassImpNames.end()
|
|
|
|
|
&& !existsInChild) {
|
|
|
|
|
implementsClassp->v3error(
|
|
|
|
|
"Class " << implementsClassp->prettyNameQ() << " implements "
|
|
|
|
|
<< interfaceClassp->prettyNameQ()
|
|
|
|
|
<< " but missing inheritance conflict resolution for "
|
|
|
|
|
<< interfaceSubp->prettyNameQ()
|
|
|
|
|
<< " (IEEE 1800-2017 8.26.6.2)\n"
|
|
|
|
|
<< implementsClassp->warnContextPrimary() << '\n'
|
|
|
|
|
<< interfaceSubp->warnOther()
|
|
|
|
|
<< "... Location of interface class's function\n"
|
|
|
|
|
<< interfaceSubp->warnContextSecondary());
|
|
|
|
|
}
|
|
|
|
|
m_ifClassImpNames.emplace(interfaceSubp->name());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
// VISITs
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNetlist* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Recurse..., backward as must do packages before using packages
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildrenBackwards(nodep);
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstTypeTable*) override {}
|
|
|
|
|
void visit(AstConstPool*) override {}
|
|
|
|
|
void visit(AstNodeModule* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (nodep->dead()) return;
|
|
|
|
|
checkNoDot(nodep);
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, " " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
m_ds.init(m_curSymp);
|
2020-04-15 13:58:34 +02:00
|
|
|
m_ds.m_dotSymp = m_curSymp = m_modSymp
|
|
|
|
|
= m_statep->getNodeSym(nodep); // Until overridden by a SCOPE
|
2020-08-15 16:12:55 +02:00
|
|
|
m_cellp = nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
m_modp = nodep;
|
|
|
|
|
m_modportNum = 0;
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2020-08-15 16:12:55 +02:00
|
|
|
m_modp = nullptr;
|
|
|
|
|
m_ds.m_dotSymp = m_curSymp = m_modSymp = nullptr;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstScope* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, " " << nodep << endl);
|
2020-08-25 03:10:43 +02:00
|
|
|
VL_RESTORER(m_modSymp);
|
|
|
|
|
VL_RESTORER(m_curSymp);
|
|
|
|
|
{
|
|
|
|
|
checkNoDot(nodep);
|
|
|
|
|
m_ds.m_dotSymp = m_curSymp = m_modSymp = m_statep->getScopeSym(nodep);
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
m_ds.m_dotSymp = m_curSymp = m_modSymp = nullptr;
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstCellInline* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
checkNoDot(nodep);
|
2019-10-02 03:57:45 +02:00
|
|
|
if (m_statep->forScopeCreation() && !v3Global.opt.vpi()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->unlinkFrBack();
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstCell* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Cell: Recurse inside or cleanup not founds
|
|
|
|
|
checkNoDot(nodep);
|
|
|
|
|
AstNode::user5ClearTree();
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(nodep->modp(), nodep,
|
|
|
|
|
"Cell has unlinked module"); // V3LinkCell should have errored out
|
2020-11-28 04:48:42 +01:00
|
|
|
VL_RESTORER(m_cellp);
|
|
|
|
|
VL_RESTORER(m_pinSymp);
|
2019-07-06 18:57:50 +02:00
|
|
|
{
|
2020-11-28 04:48:42 +01:00
|
|
|
m_cellp = nodep;
|
2018-02-02 03:32:58 +01:00
|
|
|
if (VN_IS(nodep->modp(), NotFoundModule)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Prevent warnings about missing pin connects
|
|
|
|
|
if (nodep->pinsp()) nodep->pinsp()->unlinkFrBackWithNext()->deleteTree();
|
|
|
|
|
if (nodep->paramsp()) nodep->paramsp()->unlinkFrBackWithNext()->deleteTree();
|
|
|
|
|
}
|
|
|
|
|
// Need to pass the module info to this cell, so we can link up the pin names
|
|
|
|
|
// However can't use m_curSymp as pin connections need to use the
|
|
|
|
|
// instantiator's symbols
|
|
|
|
|
else {
|
|
|
|
|
m_pinSymp = m_statep->getNodeSym(nodep->modp());
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, "(Backto) Link Cell: " << nodep << endl);
|
2022-11-27 14:31:22 +01:00
|
|
|
// if (debug()) nodep->dumpTree("- linkcell: ");
|
|
|
|
|
// if (debug()) nodep->modp()->dumpTree("- linkcemd: ");
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Parent module inherits child's publicity
|
|
|
|
|
// This is done bottom up in the LinkBotupVisitor stage
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstClassRefDType* nodep) override {
|
2020-11-28 04:48:42 +01:00
|
|
|
// Cell: Recurse inside or cleanup not founds
|
|
|
|
|
checkNoDot(nodep);
|
|
|
|
|
AstNode::user5ClearTree();
|
|
|
|
|
UASSERT_OBJ(nodep->classp(), nodep, "ClassRef has unlinked class");
|
2020-12-05 17:30:14 +01:00
|
|
|
UASSERT_OBJ(m_statep->forPrimary() || !nodep->paramsp(), nodep,
|
|
|
|
|
"class reference parameter not removed by V3Param");
|
2020-11-28 04:48:42 +01:00
|
|
|
VL_RESTORER(m_pinSymp);
|
|
|
|
|
{
|
|
|
|
|
// ClassRef's have pins, so track
|
|
|
|
|
m_pinSymp = m_statep->getNodeSym(nodep->classp());
|
|
|
|
|
UINFO(4, "(Backto) Link ClassRefDType: " << nodep << endl);
|
2022-11-27 14:31:22 +01:00
|
|
|
// if (debug()) nodep->dumpTree("- linkcell: ");
|
|
|
|
|
// if (debug()) nodep->modp()->dumpTree("- linkcemd: ");
|
2020-11-28 04:48:42 +01:00
|
|
|
iterateChildren(nodep);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstPin* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Pin: Link to submodule's port
|
|
|
|
|
checkNoDot(nodep);
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!nodep->modVarp()) {
|
2020-12-13 04:43:55 +01:00
|
|
|
UASSERT_OBJ(m_pinSymp, nodep, "Pin not under instance?");
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const foundp = m_pinSymp->findIdFlat(nodep->name());
|
|
|
|
|
const char* const whatp = nodep->param() ? "parameter pin" : "pin";
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!foundp) {
|
2020-11-28 04:48:42 +01:00
|
|
|
if (nodep->name() == "__paramNumber1" && m_cellp
|
|
|
|
|
&& VN_IS(m_cellp->modp(), Primitive)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Primitive parameter is really a delay we can just ignore
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2021-11-26 23:55:36 +01:00
|
|
|
const string suggest
|
2020-04-15 13:58:34 +02:00
|
|
|
= (nodep->param() ? m_statep->suggestSymFlat(m_pinSymp, nodep->name(),
|
2022-11-20 23:40:38 +01:00
|
|
|
LinkNodeMatcherVarParam{})
|
2020-04-15 13:58:34 +02:00
|
|
|
: m_statep->suggestSymFlat(m_pinSymp, nodep->name(),
|
2022-11-20 23:40:38 +01:00
|
|
|
LinkNodeMatcherVarIO{}));
|
2021-04-02 00:17:42 +02:00
|
|
|
nodep->v3warn(PINNOTFOUND,
|
|
|
|
|
ucfirst(whatp)
|
|
|
|
|
<< " not found: " << nodep->prettyNameQ() << '\n'
|
|
|
|
|
<< (suggest.empty() ? "" : nodep->warnMore() + suggest));
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (AstVar* const refp = VN_CAST(foundp->nodep(), Var)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!refp->isIO() && !refp->isParam() && !refp->isIfaceRef()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3error(ucfirst(whatp) << " is not an in/out/inout/param/interface: "
|
|
|
|
|
<< nodep->prettyNameQ());
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
|
|
|
|
nodep->modVarp(refp);
|
|
|
|
|
markAndCheckPinDup(nodep, refp, whatp);
|
|
|
|
|
}
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (AstParamTypeDType* const refp = VN_CAST(foundp->nodep(), ParamTypeDType)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->modPTypep(refp);
|
|
|
|
|
markAndCheckPinDup(nodep, refp, whatp);
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
|
|
|
|
nodep->v3error(ucfirst(whatp) << " not found: " << nodep->prettyNameQ());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Early return() above when deleted
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstDot* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Legal under a DOT: AstDot, AstParseRef, AstPackageRef, AstNodeSel
|
|
|
|
|
// also a DOT can be part of an expression, but only above plus
|
|
|
|
|
// AstFTaskRef are legal children
|
2022-01-02 21:03:57 +01:00
|
|
|
// Dot(PackageRef, ParseRef(text))
|
|
|
|
|
// Dot(Dot(ClassOrPackageRef,ClassOrPackageRef), ParseRef(text))
|
|
|
|
|
// Dot(Dot(Dot(ParseRef(text), ...
|
2019-05-19 22:13:13 +02:00
|
|
|
if (nodep->user3SetOnce()) return;
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, " " << nodep << endl);
|
2021-06-21 00:32:57 +02:00
|
|
|
const DotStates lastStates = m_ds;
|
|
|
|
|
const bool start = (m_ds.m_dotPos == DP_NONE); // Save, as m_dotp will be changed
|
2019-05-19 22:13:13 +02:00
|
|
|
{
|
|
|
|
|
if (start) { // Starting dot sequence
|
2022-11-27 14:31:22 +01:00
|
|
|
if (debug() >= 9) nodep->dumpTree("- dot-in: ");
|
2019-05-19 22:13:13 +02:00
|
|
|
m_ds.init(m_curSymp); // Start from current point
|
|
|
|
|
}
|
|
|
|
|
m_ds.m_dotp = nodep; // Always, not just at start
|
|
|
|
|
m_ds.m_dotPos = DP_SCOPE;
|
|
|
|
|
|
2020-10-08 13:54:01 +02:00
|
|
|
if (VN_IS(nodep->lhsp(), ParseRef) && nodep->lhsp()->name() == "this") {
|
2022-10-14 14:55:55 +02:00
|
|
|
VSymEnt* classSymp = getThisClassSymp();
|
2020-10-08 13:54:01 +02:00
|
|
|
if (!classSymp) {
|
2020-11-26 17:06:59 +01:00
|
|
|
nodep->v3error("'this' used outside class (IEEE 1800-2017 8.11)");
|
2020-10-08 13:54:01 +02:00
|
|
|
m_ds.m_dotErr = true;
|
2020-11-26 17:06:59 +01:00
|
|
|
} else {
|
|
|
|
|
m_ds.m_dotSymp = classSymp;
|
|
|
|
|
UINFO(8, " this. " << m_ds.ascii() << endl);
|
|
|
|
|
}
|
|
|
|
|
} else if (VN_IS(nodep->lhsp(), ParseRef) && nodep->lhsp()->name() == "super") {
|
2022-10-14 14:55:55 +02:00
|
|
|
const VSymEnt* classSymp = getThisClassSymp();
|
2020-11-26 17:06:59 +01:00
|
|
|
if (!classSymp) {
|
|
|
|
|
nodep->v3error("'super' used outside class (IEEE 1800-2017 8.15)");
|
|
|
|
|
m_ds.m_dotErr = true;
|
|
|
|
|
} else {
|
2021-10-22 14:56:48 +02:00
|
|
|
const auto classp = VN_AS(classSymp->nodep(), Class);
|
2020-11-26 17:06:59 +01:00
|
|
|
if (!classp->extendsp()) {
|
|
|
|
|
nodep->v3error("'super' used on non-extended class (IEEE 1800-2017 8.15)");
|
|
|
|
|
m_ds.m_dotErr = true;
|
|
|
|
|
} else {
|
2021-10-22 18:36:58 +02:00
|
|
|
const auto cextp = classp->extendsp();
|
2020-11-26 17:06:59 +01:00
|
|
|
UASSERT_OBJ(cextp, nodep, "Bad super extends link");
|
2021-06-21 00:32:57 +02:00
|
|
|
const auto sclassp = cextp->classp();
|
2020-12-23 21:21:33 +01:00
|
|
|
UASSERT_OBJ(sclassp, nodep, "Bad superclass");
|
|
|
|
|
m_ds.m_dotSymp = m_statep->getNodeSym(sclassp);
|
2020-11-26 17:06:59 +01:00
|
|
|
UINFO(8, " super. " << m_ds.ascii() << endl);
|
|
|
|
|
}
|
2020-10-08 13:54:01 +02:00
|
|
|
}
|
|
|
|
|
} else if (VN_IS(nodep->lhsp(), ClassOrPackageRef)) {
|
|
|
|
|
// m_ds.m_dotText communicates the cell prefix between stages
|
2020-04-15 13:58:34 +02:00
|
|
|
// if (!start) { nodep->lhsp()->v3error("Package reference may not be embedded in
|
|
|
|
|
// dotted reference"); m_ds.m_dotErr=true; }
|
2019-05-19 22:13:13 +02:00
|
|
|
m_ds.m_dotPos = DP_PACKAGE;
|
2022-08-28 16:24:55 +02:00
|
|
|
iterateAndNextNull(nodep->lhsp());
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
|
|
|
|
m_ds.m_dotPos = DP_SCOPE;
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateAndNextNull(nodep->lhsp());
|
2022-11-27 14:31:22 +01:00
|
|
|
// if (debug() >= 9) nodep->dumpTree("- dot-lho: ");
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2022-08-28 16:24:55 +02:00
|
|
|
if (m_statep->forPrimary() && isParamedClassRef(nodep->lhsp())) {
|
2022-12-26 10:30:41 +01:00
|
|
|
// Dots of paramed classes will be linked after deparameterization
|
2022-08-28 16:24:55 +02:00
|
|
|
m_ds.m_dotPos = DP_NONE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
if (m_ds.m_unresolved
|
|
|
|
|
&& (VN_IS(nodep->lhsp(), CellRef) || VN_IS(nodep->lhsp(), CellArrayRef))) {
|
2020-10-30 02:27:19 +01:00
|
|
|
m_ds.m_unlinkedScopep = nodep->lhsp();
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2021-02-22 03:25:21 +01:00
|
|
|
if (VN_IS(nodep->lhsp(), LambdaArgRef)) m_ds.m_unlinkedScopep = nodep->lhsp();
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!m_ds.m_dotErr) { // Once something wrong, give up
|
|
|
|
|
// Top 'final' dot RHS is final RHS, else it's a
|
|
|
|
|
// DOT(DOT(x,*here*),real-rhs) which we consider a RHS
|
2020-04-15 13:58:34 +02:00
|
|
|
if (start && m_ds.m_dotPos == DP_SCOPE) m_ds.m_dotPos = DP_FINAL;
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateAndNextNull(nodep->rhsp());
|
2022-11-27 14:31:22 +01:00
|
|
|
// if (debug() >= 9) nodep->dumpTree("- dot-rho: ");
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
if (start) {
|
|
|
|
|
AstNode* newp;
|
|
|
|
|
if (m_ds.m_dotErr) {
|
2022-11-20 23:40:38 +01:00
|
|
|
newp = new AstConst{nodep->fileline(), AstConst::BitFalse{}};
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
|
|
|
|
// RHS is what we're left with
|
|
|
|
|
newp = nodep->rhsp()->unlinkFrBack();
|
|
|
|
|
}
|
2022-11-27 14:31:22 +01:00
|
|
|
if (debug() >= 9) newp->dumpTree("- dot-out: ");
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->replaceWith(newp);
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
} else { // Dot midpoint
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* newp = nodep->rhsp()->unlinkFrBack();
|
2019-05-19 22:13:13 +02:00
|
|
|
if (m_ds.m_unresolved) {
|
2022-11-20 23:40:38 +01:00
|
|
|
AstCellRef* const crp = new AstCellRef{nodep->fileline(), nodep->name(),
|
|
|
|
|
nodep->lhsp()->unlinkFrBack(), newp};
|
2019-05-19 22:13:13 +02:00
|
|
|
newp = crp;
|
|
|
|
|
}
|
|
|
|
|
nodep->replaceWith(newp);
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (start) {
|
|
|
|
|
m_ds = lastStates;
|
|
|
|
|
} else {
|
|
|
|
|
m_ds.m_dotp = lastStates.m_dotp;
|
|
|
|
|
}
|
2012-07-24 12:26:35 +02:00
|
|
|
}
|
2022-12-23 13:34:49 +01:00
|
|
|
void visit(AstSenItem* nodep) override {
|
|
|
|
|
VL_RESTORER(m_inSens);
|
|
|
|
|
m_inSens = true;
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstParseRef* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (nodep->user3SetOnce()) return;
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, " linkPARSEREF " << m_ds.ascii() << " n=" << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
// m_curSymp is symbol table of outer expression
|
|
|
|
|
// m_ds.m_dotSymp is symbol table relative to "."'s above now
|
2020-08-15 16:12:55 +02:00
|
|
|
UASSERT_OBJ(m_ds.m_dotSymp, nodep, "nullptr lookup symbol table");
|
2019-12-05 01:25:45 +01:00
|
|
|
// Generally resolved during Primay, but might be at param time under AstUnlinkedRef
|
2020-04-15 13:58:34 +02:00
|
|
|
UASSERT_OBJ(m_statep->forPrimary() || m_statep->forPrearray(), nodep,
|
|
|
|
|
"ParseRefs should no longer exist");
|
2021-02-22 03:25:21 +01:00
|
|
|
if (nodep->name() == "super") nodep->v3warn(E_UNSUPPORTED, "Unsupported: super");
|
2021-06-21 00:32:57 +02:00
|
|
|
const DotStates lastStates = m_ds;
|
|
|
|
|
const bool start = (m_ds.m_dotPos == DP_NONE); // Save, as m_dotp will be changed
|
2019-05-19 22:13:13 +02:00
|
|
|
if (start) {
|
|
|
|
|
m_ds.init(m_curSymp);
|
2020-08-15 16:12:55 +02:00
|
|
|
// Note m_ds.m_dot remains nullptr; this is a reference not under a dot
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2020-10-08 13:54:01 +02:00
|
|
|
if (nodep->name() == "super") {
|
2020-06-30 02:02:15 +02:00
|
|
|
nodep->v3warn(E_UNSUPPORTED, "Unsupported: super");
|
|
|
|
|
m_ds.m_dotErr = true;
|
|
|
|
|
}
|
2022-10-14 14:55:55 +02:00
|
|
|
if (nodep->name() == "this") {
|
|
|
|
|
iterateChildren(nodep);
|
2022-12-26 10:30:41 +01:00
|
|
|
if (m_statep->forPrimary()) return; // The class might be parameterized somewhere
|
2022-10-14 14:55:55 +02:00
|
|
|
const VSymEnt* classSymp = getThisClassSymp();
|
|
|
|
|
if (!classSymp) {
|
|
|
|
|
nodep->v3error("'this' used outside class (IEEE 1800-2017 8.11)");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
AstClass* const classp = VN_AS(classSymp->nodep(), Class);
|
|
|
|
|
AstClassRefDType* const dtypep
|
|
|
|
|
= new AstClassRefDType{nodep->fileline(), classp, nullptr};
|
2022-11-13 17:59:40 +01:00
|
|
|
AstThisRef* const newp = new AstThisRef{nodep->fileline(), VFlagChildDType{}, dtypep};
|
2022-10-14 14:55:55 +02:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-11-23 19:15:10 +01:00
|
|
|
if (m_ds.m_dotPos == DP_MEMBER && VN_IS(m_ds.m_dotp->lhsp(), LambdaArgRef)
|
2020-11-24 05:18:58 +01:00
|
|
|
&& nodep->name() == "index") {
|
|
|
|
|
// 'with' statement's 'item.index'
|
2022-11-23 19:15:10 +01:00
|
|
|
// m_ds.dotp->lhsp() was checked to know if `index` is directly after lambda arg ref.
|
|
|
|
|
// If not, treat it as normal member select
|
2020-11-24 05:18:58 +01:00
|
|
|
iterateChildren(nodep);
|
2022-11-20 23:40:38 +01:00
|
|
|
const auto newp = new AstLambdaArgRef{
|
|
|
|
|
nodep->fileline(), m_ds.m_unlinkedScopep->name() + "__DOT__index", true};
|
2020-11-24 05:18:58 +01:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
|
|
|
return;
|
|
|
|
|
} else if (m_ds.m_dotPos == DP_MEMBER) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Found a Var, everything following is membership. {scope}.{var}.HERE {member}
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* const varEtcp = m_ds.m_dotp->lhsp()->unlinkFrBack();
|
|
|
|
|
AstNodeExpr* const newp
|
2022-11-20 23:40:38 +01:00
|
|
|
= new AstMemberSel{nodep->fileline(), varEtcp, VFlagChildDType{}, nodep->name()};
|
2020-08-16 20:55:46 +02:00
|
|
|
if (m_ds.m_dotErr) {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->unlinkFrBack(); // Avoid circular node loop on errors
|
2020-08-16 20:55:46 +02:00
|
|
|
} else {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->replaceWith(newp);
|
2020-08-16 20:55:46 +02:00
|
|
|
}
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
//
|
|
|
|
|
string expectWhat;
|
|
|
|
|
bool allowScope = false;
|
|
|
|
|
bool allowVar = false;
|
|
|
|
|
if (m_ds.m_dotPos == DP_PACKAGE) {
|
|
|
|
|
// {package}::{a}
|
2020-11-25 03:56:03 +01:00
|
|
|
AstNodeModule* classOrPackagep = nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
expectWhat = "scope/variable";
|
|
|
|
|
allowScope = true;
|
|
|
|
|
allowVar = true;
|
2020-07-11 16:29:15 +02:00
|
|
|
UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(),
|
2020-04-15 13:58:34 +02:00
|
|
|
"Bad package link");
|
2021-11-26 23:55:36 +01:00
|
|
|
AstClassOrPackageRef* const cpackagerefp
|
|
|
|
|
= VN_AS(m_ds.m_dotp->lhsp(), ClassOrPackageRef);
|
2020-11-25 03:56:03 +01:00
|
|
|
classOrPackagep = cpackagerefp->classOrPackagep();
|
|
|
|
|
UASSERT_OBJ(classOrPackagep, m_ds.m_dotp->lhsp(), "Bad package link");
|
|
|
|
|
m_ds.m_dotSymp = m_statep->getNodeSym(classOrPackagep);
|
2019-05-19 22:13:13 +02:00
|
|
|
m_ds.m_dotPos = DP_SCOPE;
|
|
|
|
|
} else if (m_ds.m_dotPos == DP_SCOPE) {
|
|
|
|
|
// {a}.{b}, where {a} maybe a module name
|
|
|
|
|
// or variable, where dotting into structure member
|
|
|
|
|
expectWhat = "scope/variable";
|
|
|
|
|
allowScope = true;
|
|
|
|
|
allowVar = true;
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (m_ds.m_dotPos == DP_NONE || m_ds.m_dotPos == DP_FINAL) {
|
2019-05-19 22:13:13 +02:00
|
|
|
expectWhat = "variable";
|
|
|
|
|
allowVar = true;
|
|
|
|
|
} else {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(1, "ds=" << m_ds.ascii() << endl);
|
2019-10-05 13:54:14 +02:00
|
|
|
nodep->v3fatalSrc("Unhandled VParseRefExp");
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
// Lookup
|
|
|
|
|
VSymEnt* foundp;
|
|
|
|
|
string baddot;
|
2020-08-15 16:12:55 +02:00
|
|
|
VSymEnt* okSymp = nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
if (allowScope) {
|
2020-07-04 15:35:04 +02:00
|
|
|
foundp = m_statep->findDotted(nodep->fileline(), m_ds.m_dotSymp, nodep->name(),
|
2020-08-15 16:12:55 +02:00
|
|
|
baddot, okSymp); // Maybe nullptr
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
|
|
|
|
foundp = m_ds.m_dotSymp->findIdFallback(nodep->name());
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
if (foundp) {
|
|
|
|
|
UINFO(9, " found=se" << cvtToHex(foundp) << " exp=" << expectWhat
|
|
|
|
|
<< " n=" << foundp->nodep() << endl);
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
// What fell out?
|
|
|
|
|
bool ok = false;
|
2022-12-23 13:34:49 +01:00
|
|
|
// Special case: waiting on clocking event
|
|
|
|
|
if (m_inSens && foundp && m_ds.m_dotPos != DP_SCOPE) {
|
|
|
|
|
if (AstClocking* const clockingp = VN_CAST(foundp->nodep(), Clocking)) {
|
|
|
|
|
foundp = getCreateClockingEventSymEnt(clockingp);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!foundp) {
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (VN_IS(foundp->nodep(), Cell) || VN_IS(foundp->nodep(), Begin)
|
2020-05-02 14:29:20 +02:00
|
|
|
|| VN_IS(foundp->nodep(), Netlist) // for $root
|
2018-02-02 03:32:58 +01:00
|
|
|
|| VN_IS(foundp->nodep(), Module)) { // if top
|
2019-05-19 22:13:13 +02:00
|
|
|
if (allowScope) {
|
|
|
|
|
ok = true;
|
2018-03-16 00:46:05 +01:00
|
|
|
m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name());
|
2019-05-19 22:13:13 +02:00
|
|
|
m_ds.m_dotSymp = foundp;
|
|
|
|
|
m_ds.m_dotPos = DP_SCOPE;
|
|
|
|
|
// Upper AstDot visitor will handle it from here
|
2022-10-20 12:31:00 +02:00
|
|
|
} else if (VN_IS(foundp->nodep(), Cell) && allowVar) {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstCell* const cellp = VN_AS(foundp->nodep(), Cell);
|
2018-02-02 03:32:58 +01:00
|
|
|
if (VN_IS(cellp->modp(), Iface)) {
|
2017-03-17 23:35:53 +01:00
|
|
|
// Interfaces can be referenced like a variable for interconnect
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const cellEntp = m_statep->getNodeSym(cellp);
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(cellEntp, nodep, "No interface sym entry");
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const parentEntp
|
2020-04-15 13:58:34 +02:00
|
|
|
= cellEntp->parentp(); // Container of the var; probably a module or
|
|
|
|
|
// generate begin
|
2021-11-26 23:55:36 +01:00
|
|
|
AstVar* const ifaceRefVarp
|
|
|
|
|
= findIfaceTopVarp(nodep, parentEntp, nodep->name());
|
2017-03-17 23:35:53 +01:00
|
|
|
//
|
|
|
|
|
ok = true;
|
2018-03-16 00:46:05 +01:00
|
|
|
m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name());
|
2017-03-17 23:35:53 +01:00
|
|
|
m_ds.m_dotSymp = foundp;
|
|
|
|
|
m_ds.m_dotPos = DP_SCOPE;
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, " cell -> iface varref " << foundp->nodep() << endl);
|
2021-11-26 23:55:36 +01:00
|
|
|
AstNode* const newp
|
2022-10-20 12:31:00 +02:00
|
|
|
= new AstVarRef{nodep->fileline(), ifaceRefVarp, VAccess::READ};
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2018-02-02 03:32:58 +01:00
|
|
|
} else if (VN_IS(cellp->modp(), NotFoundModule)) {
|
2019-07-14 21:06:49 +02:00
|
|
|
cellp->modNameFileline()->v3error("Cannot find file containing interface: "
|
2020-04-15 13:58:34 +02:00
|
|
|
<< cellp->modp()->prettyNameQ());
|
2017-03-17 23:35:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (AstVar* const varp = foundToVarp(foundp, nodep, VAccess::READ)) {
|
|
|
|
|
AstIfaceRefDType* const ifacerefp
|
|
|
|
|
= LinkDotState::ifaceRefFromArray(varp->subDTypep());
|
2022-10-20 12:31:00 +02:00
|
|
|
if (ifacerefp && varp->isIfaceRef()) {
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(ifacerefp->ifaceViaCellp(), ifacerefp, "Unlinked interface");
|
2019-05-19 22:13:13 +02:00
|
|
|
// Really this is a scope reference into an interface
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, "varref-ifaceref " << m_ds.m_dotText << " " << nodep << endl);
|
2018-03-16 00:46:05 +01:00
|
|
|
m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name());
|
2019-05-19 22:13:13 +02:00
|
|
|
m_ds.m_dotSymp = m_statep->getNodeSym(ifacerefp->ifaceViaCellp());
|
|
|
|
|
m_ds.m_dotPos = DP_SCOPE;
|
|
|
|
|
ok = true;
|
2022-11-20 23:40:38 +01:00
|
|
|
AstNode* const newp = new AstVarRef{nodep->fileline(), varp, VAccess::READ};
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
|
|
|
} else if (allowVar) {
|
2019-05-19 22:13:13 +02:00
|
|
|
AstNode* newp;
|
|
|
|
|
if (m_ds.m_dotText != "") {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstVarXRef* const refp
|
2022-11-20 23:40:38 +01:00
|
|
|
= new AstVarXRef{nodep->fileline(), nodep->name(), m_ds.m_dotText,
|
|
|
|
|
VAccess::READ}; // lvalue'ness computed later
|
2019-05-19 22:13:13 +02:00
|
|
|
refp->varp(varp);
|
2020-02-29 01:15:08 +01:00
|
|
|
if (varp->attrSplitVar()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
refp->v3warn(
|
|
|
|
|
SPLITVAR,
|
|
|
|
|
varp->prettyNameQ()
|
|
|
|
|
<< " has split_var metacomment but will not be split because"
|
|
|
|
|
<< " it is accessed from another module via a dot.");
|
2020-02-29 01:15:08 +01:00
|
|
|
varp->attrSplitVar(false);
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
m_ds.m_dotText = "";
|
2020-10-30 02:27:19 +01:00
|
|
|
if (m_ds.m_unresolved && m_ds.m_unlinkedScopep) {
|
2021-06-21 00:32:57 +02:00
|
|
|
const string dotted = refp->dotted();
|
|
|
|
|
const size_t pos = dotted.find("__BRA__??__KET__");
|
2020-02-05 22:51:33 +01:00
|
|
|
// Arrays of interfaces all have the same parameters
|
|
|
|
|
if (pos != string::npos && varp->isParam()
|
2020-10-30 02:27:19 +01:00
|
|
|
&& VN_IS(m_ds.m_unlinkedScopep, CellArrayRef)) {
|
2020-02-05 22:51:33 +01:00
|
|
|
refp->dotted(dotted.substr(0, pos));
|
|
|
|
|
newp = refp;
|
|
|
|
|
} else {
|
2022-11-20 23:40:38 +01:00
|
|
|
newp = new AstUnlinkedRef{nodep->fileline(), refp, refp->name(),
|
|
|
|
|
m_ds.m_unlinkedScopep->unlinkFrBack()};
|
2020-10-30 02:27:19 +01:00
|
|
|
m_ds.m_unlinkedScopep = nullptr;
|
2020-02-05 22:51:33 +01:00
|
|
|
m_ds.m_unresolved = false;
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
|
|
|
|
newp = refp;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2022-11-20 23:40:38 +01:00
|
|
|
AstVarRef* const refp = new AstVarRef{
|
|
|
|
|
nodep->fileline(), varp, VAccess::READ}; // lvalue'ness computed later
|
2020-11-25 03:56:03 +01:00
|
|
|
refp->classOrPackagep(foundp->classOrPackagep());
|
2019-05-19 22:13:13 +02:00
|
|
|
newp = refp;
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, " new " << newp << endl);
|
|
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
m_ds.m_dotPos = DP_MEMBER;
|
|
|
|
|
ok = true;
|
|
|
|
|
}
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const AstModport* const modportp = VN_CAST(foundp->nodep(), Modport)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// A scope reference into an interface's modport (not
|
|
|
|
|
// necessarily at a pin connection)
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, "cell-ref-to-modport " << m_ds.m_dotText << " " << nodep << endl);
|
2020-11-02 04:27:27 +01:00
|
|
|
UINFO(9, "unlinked " << m_ds.m_unlinkedScopep << endl);
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, "dotSymp " << m_ds.m_dotSymp << " " << m_ds.m_dotSymp->nodep() << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
// Iface was the previously dotted component
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!m_ds.m_dotSymp || !VN_IS(m_ds.m_dotSymp->nodep(), Cell)
|
2021-10-22 14:56:48 +02:00
|
|
|
|| !VN_AS(m_ds.m_dotSymp->nodep(), Cell)->modp()
|
|
|
|
|
|| !VN_IS(VN_AS(m_ds.m_dotSymp->nodep(), Cell)->modp(), Iface)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->v3error("Modport not referenced as <interface>."
|
2020-04-15 13:58:34 +02:00
|
|
|
<< modportp->prettyNameQ());
|
2021-10-22 14:56:48 +02:00
|
|
|
} else if (!VN_AS(m_ds.m_dotSymp->nodep(), Cell)->modp()
|
|
|
|
|
|| !VN_IS(VN_AS(m_ds.m_dotSymp->nodep(), Cell)->modp(), Iface)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->v3error("Modport not referenced from underneath an interface: "
|
2020-04-15 13:58:34 +02:00
|
|
|
<< modportp->prettyNameQ());
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstCell* const cellp = VN_AS(m_ds.m_dotSymp->nodep(), Cell);
|
2020-12-13 04:43:55 +01:00
|
|
|
UASSERT_OBJ(cellp, nodep, "Modport not referenced from an instance");
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const cellEntp = m_statep->getNodeSym(cellp);
|
2020-11-09 04:43:32 +01:00
|
|
|
UASSERT_OBJ(cellEntp, nodep, "No interface sym entry");
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const parentEntp
|
|
|
|
|
= cellEntp->parentp(); // Container of the var; probably a
|
|
|
|
|
// module or generate begin
|
2020-11-09 04:43:32 +01:00
|
|
|
// We drop __BRA__??__KET__ as cells don't have that naming yet
|
2021-11-26 23:55:36 +01:00
|
|
|
AstVar* const ifaceRefVarp
|
|
|
|
|
= findIfaceTopVarp(nodep, parentEntp, cellp->name());
|
2020-11-09 04:43:32 +01:00
|
|
|
//
|
|
|
|
|
ok = true;
|
2018-03-16 00:46:05 +01:00
|
|
|
m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name());
|
2020-11-09 04:43:32 +01:00
|
|
|
m_ds.m_dotSymp = foundp;
|
2019-05-19 22:13:13 +02:00
|
|
|
m_ds.m_dotPos = DP_SCOPE;
|
2022-10-20 12:31:00 +02:00
|
|
|
UINFO(9, " modport -> iface varref " << foundp->nodep() << endl);
|
|
|
|
|
// We lose the modport name here, so we cannot detect mismatched modports.
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* newp
|
|
|
|
|
= new AstVarRef{nodep->fileline(), ifaceRefVarp, VAccess::READ};
|
2021-11-26 23:55:36 +01:00
|
|
|
auto* const cellarrayrefp = VN_CAST(m_ds.m_unlinkedScopep, CellArrayRef);
|
2020-11-09 01:15:53 +01:00
|
|
|
if (cellarrayrefp) {
|
|
|
|
|
// iface[vec].modport became CellArrayRef(iface, lsb)
|
|
|
|
|
// Convert back to SelBit(iface, lsb)
|
|
|
|
|
UINFO(9, " Array modport to SelBit " << cellarrayrefp << endl);
|
2022-11-20 23:40:38 +01:00
|
|
|
newp = new AstSelBit{cellarrayrefp->fileline(), newp,
|
|
|
|
|
cellarrayrefp->selp()->unlinkFrBack()};
|
2020-11-09 04:43:32 +01:00
|
|
|
newp->user3(true); // Don't process again
|
2020-11-09 01:15:53 +01:00
|
|
|
VL_DO_DANGLING(cellarrayrefp->unlinkFrBack(), cellarrayrefp);
|
|
|
|
|
m_ds.m_unlinkedScopep = nullptr;
|
|
|
|
|
}
|
2020-11-09 04:43:32 +01:00
|
|
|
nodep->replaceWith(newp);
|
2020-04-15 13:58:34 +02:00
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (AstEnumItem* const valuep = VN_CAST(foundp->nodep(), EnumItem)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (allowVar) {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstNode* const newp
|
2022-11-20 23:40:38 +01:00
|
|
|
= new AstEnumItemRef{nodep->fileline(), valuep, foundp->classOrPackagep()};
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
ok = true;
|
|
|
|
|
m_ds.m_dotText = "";
|
|
|
|
|
}
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const AstLambdaArgRef* const argrefp
|
|
|
|
|
= VN_CAST(foundp->nodep(), LambdaArgRef)) {
|
2020-11-01 16:56:07 +01:00
|
|
|
if (allowVar) {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstNode* const newp
|
2022-11-20 23:40:38 +01:00
|
|
|
= new AstLambdaArgRef{nodep->fileline(), argrefp->name(), false};
|
2020-11-01 16:56:07 +01:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
|
|
|
ok = true;
|
2022-11-23 19:15:10 +01:00
|
|
|
m_ds.m_dotPos = DP_MEMBER;
|
2020-11-01 16:56:07 +01:00
|
|
|
m_ds.m_dotText = "";
|
|
|
|
|
}
|
2022-12-23 13:34:49 +01:00
|
|
|
} else if (VN_IS(foundp->nodep(), Clocking)) {
|
|
|
|
|
m_ds.m_dotSymp = foundp;
|
|
|
|
|
ok = m_ds.m_dotPos == DP_SCOPE;
|
2023-01-24 15:36:30 +01:00
|
|
|
} else if (const AstNodeFTask* const ftaskp = VN_CAST(foundp->nodep(), NodeFTask)) {
|
|
|
|
|
if (!ftaskp->isFunction()) {
|
|
|
|
|
// The condition is true for tasks, properties and void functions.
|
|
|
|
|
// In these cases, the parentheses may be skipped.
|
|
|
|
|
AstFuncRef* const funcRefp
|
|
|
|
|
= new AstFuncRef{nodep->fileline(), nodep->name(), nullptr};
|
|
|
|
|
nodep->replaceWith(funcRefp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
|
|
|
ok = m_ds.m_dotPos == DP_NONE;
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
//
|
|
|
|
|
if (!ok) {
|
2017-04-28 12:10:14 +02:00
|
|
|
// Cells/interfaces can't be implicit
|
2021-06-21 00:32:57 +02:00
|
|
|
const bool isCell = foundp ? VN_IS(foundp->nodep(), Cell) : false;
|
|
|
|
|
const bool checkImplicit = (!m_ds.m_dotp && m_ds.m_dotText == "" && !isCell);
|
|
|
|
|
const bool err = !(checkImplicit && m_statep->implicitOk(m_modp, nodep->name()));
|
2019-05-19 22:13:13 +02:00
|
|
|
if (err) {
|
|
|
|
|
if (foundp) {
|
|
|
|
|
nodep->v3error("Found definition of '"
|
2020-04-15 13:58:34 +02:00
|
|
|
<< m_ds.m_dotText << (m_ds.m_dotText == "" ? "" : ".")
|
|
|
|
|
<< nodep->prettyName() << "'"
|
|
|
|
|
<< " as a " << foundp->nodep()->typeName()
|
|
|
|
|
<< " but expected a " << expectWhat);
|
|
|
|
|
} else if (m_ds.m_dotText == "") {
|
|
|
|
|
UINFO(7, " ErrParseRef curSymp=se" << cvtToHex(m_curSymp)
|
|
|
|
|
<< " ds=" << m_ds.ascii() << endl);
|
2021-06-21 00:32:57 +02:00
|
|
|
const string suggest = m_statep->suggestSymFallback(
|
2022-09-16 01:58:01 +02:00
|
|
|
m_ds.m_dotSymp, nodep->name(), VNodeMatcher{});
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3error("Can't find definition of "
|
2020-11-19 03:03:23 +01:00
|
|
|
<< expectWhat << ": " << nodep->prettyNameQ() << '\n'
|
2020-04-15 13:58:34 +02:00
|
|
|
<< (suggest.empty() ? "" : nodep->warnMore() + suggest));
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
2019-11-05 03:16:07 +01:00
|
|
|
nodep->v3error("Can't find definition of "
|
2020-04-15 13:58:34 +02:00
|
|
|
<< (!baddot.empty() ? AstNode::prettyNameQ(baddot)
|
|
|
|
|
: nodep->prettyNameQ())
|
|
|
|
|
<< " in dotted " << expectWhat << ": '"
|
|
|
|
|
<< m_ds.m_dotText + "." + nodep->prettyName() << "'");
|
2019-10-31 02:49:25 +01:00
|
|
|
if (okSymp) {
|
|
|
|
|
okSymp->cellErrorScopes(nodep, AstNode::prettyName(m_ds.m_dotText));
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
m_ds.m_dotErr = true;
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
if (checkImplicit) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Create if implicit, and also if error (so only complain once)
|
2020-04-15 13:58:34 +02:00
|
|
|
// Else if a scope is allowed, making a signal won't help error cascade
|
2021-11-26 23:55:36 +01:00
|
|
|
AstVarRef* const newp
|
2022-11-20 23:40:38 +01:00
|
|
|
= new AstVarRef{nodep->fileline(), nodep->name(), VAccess::READ};
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->replaceWith(newp);
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2018-08-25 15:52:45 +02:00
|
|
|
createImplicitVar(m_curSymp, newp, m_modp, m_modSymp, err);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
if (start) m_ds = lastStates;
|
2012-07-24 12:26:35 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstClassOrPackageRef* nodep) override {
|
2022-08-28 16:24:55 +02:00
|
|
|
// Class: Recurse inside or cleanup not founds
|
|
|
|
|
// checkNoDot not appropriate, can be under a dot
|
|
|
|
|
AstNode::user5ClearTree();
|
2022-10-21 15:00:40 +02:00
|
|
|
UASSERT_OBJ(m_statep->forPrimary() || VN_IS(nodep->classOrPackageNodep(), ParamTypeDType)
|
|
|
|
|
|| nodep->classOrPackagep(),
|
|
|
|
|
nodep, "ClassRef has unlinked class");
|
2022-08-28 16:24:55 +02:00
|
|
|
UASSERT_OBJ(m_statep->forPrimary() || !nodep->paramsp(), nodep,
|
|
|
|
|
"class reference parameter not removed by V3Param");
|
|
|
|
|
VL_RESTORER(m_ds);
|
|
|
|
|
VL_RESTORER(m_pinSymp);
|
|
|
|
|
{
|
|
|
|
|
// ClassRef's have pins, so track
|
|
|
|
|
if (nodep->classOrPackagep()) {
|
|
|
|
|
m_pinSymp = m_statep->getNodeSym(nodep->classOrPackagep());
|
|
|
|
|
}
|
|
|
|
|
m_ds.init(m_curSymp);
|
|
|
|
|
UINFO(4, "(Backto) Link ClassOrPackageRef: " << nodep << endl);
|
|
|
|
|
iterateChildren(nodep);
|
2022-01-02 21:09:07 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstVarRef* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// VarRef: Resolve its reference
|
|
|
|
|
// ParseRefs are used the first pass (forPrimary) so we shouldn't get can't find
|
|
|
|
|
// errors here now that we have a VarRef.
|
|
|
|
|
// No checkNoDot; created and iterated from a parseRef
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!nodep->varp()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, " linkVarRef se" << cvtToHex(m_curSymp) << " n=" << nodep << endl);
|
2020-08-15 16:12:55 +02:00
|
|
|
UASSERT_OBJ(m_curSymp, nodep, "nullptr lookup symbol table");
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const foundp = m_curSymp->findIdFallback(nodep->name());
|
|
|
|
|
if (AstVar* const varp
|
|
|
|
|
= foundp ? foundToVarp(foundp, nodep, nodep->access()) : nullptr) {
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->varp(varp);
|
2020-04-15 13:58:34 +02:00
|
|
|
// Generally set by parse, but might be an import
|
2020-11-25 03:56:03 +01:00
|
|
|
nodep->classOrPackagep(foundp->classOrPackagep());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2021-03-07 19:52:37 +01:00
|
|
|
if (VL_UNCOVERABLE(!nodep->varp())) {
|
|
|
|
|
nodep->v3error("Can't find definition of signal, again: " // LCOV_EXCL_LINE
|
|
|
|
|
<< nodep->prettyNameQ());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstVarXRef* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// VarRef: Resolve its reference
|
|
|
|
|
// We always link even if varp() is set, because the module we choose may change
|
|
|
|
|
// due to creating new modules, flattening, etc.
|
|
|
|
|
if (nodep->user3SetOnce()) return;
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, " " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
// No checkNoDot; created and iterated from a parseRef
|
|
|
|
|
if (!m_modSymp) {
|
2020-04-15 13:58:34 +02:00
|
|
|
// Module that is not in hierarchy. We'll be dead code eliminating it later.
|
|
|
|
|
UINFO(9, "Dead module for " << nodep << endl);
|
2020-08-15 16:12:55 +02:00
|
|
|
nodep->varp(nullptr);
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
|
|
|
|
string baddot;
|
|
|
|
|
VSymEnt* okSymp;
|
|
|
|
|
VSymEnt* dotSymp = m_curSymp; // Start search at current scope
|
2020-04-15 13:58:34 +02:00
|
|
|
if (nodep->inlinedDots() != "") { // Correct for current scope
|
|
|
|
|
// Dotted lookup is always relative to module, as maybe
|
|
|
|
|
// variable name lower down with same scope name we want to
|
|
|
|
|
// ignore (t_math_divw)
|
|
|
|
|
dotSymp = m_modSymp;
|
2021-06-21 00:32:57 +02:00
|
|
|
const string inl = AstNode::dedotName(nodep->inlinedDots());
|
2020-07-04 15:35:04 +02:00
|
|
|
dotSymp = m_statep->findDotted(nodep->fileline(), dotSymp, inl, baddot, okSymp);
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(dotSymp, nodep,
|
2020-04-15 13:58:34 +02:00
|
|
|
"Couldn't resolve inlined scope " << AstNode::prettyNameQ(baddot)
|
|
|
|
|
<< " in: " << nodep->inlinedDots());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2020-07-04 15:35:04 +02:00
|
|
|
dotSymp = m_statep->findDotted(nodep->fileline(), dotSymp, nodep->dotted(), baddot,
|
2020-08-15 16:12:55 +02:00
|
|
|
okSymp); // Maybe nullptr
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!m_statep->forScopeCreation()) {
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot);
|
|
|
|
|
AstVar* const varp
|
|
|
|
|
= foundp ? foundToVarp(foundp, nodep, nodep->access()) : nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->varp(varp);
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(7, " Resolved " << nodep << endl); // Also prints varp
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!nodep->varp()) {
|
2019-11-05 03:16:07 +01:00
|
|
|
nodep->v3error("Can't find definition of "
|
2020-04-15 13:58:34 +02:00
|
|
|
<< AstNode::prettyNameQ(baddot) << " in dotted signal: '"
|
|
|
|
|
<< nodep->dotted() + "." + nodep->prettyName() << "'");
|
2019-05-19 22:13:13 +02:00
|
|
|
okSymp->cellErrorScopes(nodep);
|
2019-11-05 03:16:07 +01:00
|
|
|
return;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
// V3Inst may have expanded arrays of interfaces to
|
|
|
|
|
// AstVarXRef's even though they are in the same module detect
|
|
|
|
|
// this and convert to normal VarRefs
|
|
|
|
|
if (!m_statep->forPrearray() && !m_statep->forScopeCreation()) {
|
2018-02-02 03:32:58 +01:00
|
|
|
if (VN_IS(nodep->dtypep(), IfaceRefDType)) {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstVarRef* const newrefp
|
2022-11-20 23:40:38 +01:00
|
|
|
= new AstVarRef{nodep->fileline(), nodep->varp(), nodep->access()};
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->replaceWith(newrefp);
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot);
|
2021-10-22 14:56:48 +02:00
|
|
|
AstVarScope* vscp = foundp ? VN_AS(foundp->nodep(), VarScope) : nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!vscp) {
|
2019-11-05 03:16:07 +01:00
|
|
|
nodep->v3error("Can't find varpin scope of "
|
2020-04-15 13:58:34 +02:00
|
|
|
<< AstNode::prettyNameQ(baddot) << " in dotted signal: '"
|
|
|
|
|
<< nodep->dotted() + "." + nodep->prettyName() << "'");
|
2019-05-19 22:13:13 +02:00
|
|
|
okSymp->cellErrorScopes(nodep);
|
|
|
|
|
} else {
|
|
|
|
|
while (vscp->user2p()) { // If V3Inline aliased it, pick up the new signal
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(7, " Resolved pre-alias " << vscp
|
|
|
|
|
<< endl); // Also prints taskp
|
2021-10-22 14:56:48 +02:00
|
|
|
vscp = VN_AS(vscp->user2p(), VarScope);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
// Convert the VarXRef to a VarRef, so we don't need
|
|
|
|
|
// later optimizations to deal with VarXRef.
|
|
|
|
|
nodep->varp(vscp->varp());
|
|
|
|
|
nodep->varScopep(vscp);
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(7, " Resolved " << nodep << endl); // Also prints taskp
|
2021-11-26 23:55:36 +01:00
|
|
|
AstVarRef* const newvscp
|
2022-11-20 23:40:38 +01:00
|
|
|
= new AstVarRef{nodep->fileline(), vscp, nodep->access()};
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->replaceWith(newvscp);
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, " new " << newvscp << endl); // Also prints taskp
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstEnumDType* nodep) override {
|
2020-05-12 00:44:28 +02:00
|
|
|
iterateChildren(nodep);
|
2021-11-26 23:55:36 +01:00
|
|
|
AstRefDType* const refdtypep = VN_CAST(nodep->subDTypep(), RefDType);
|
2020-05-24 03:57:08 +02:00
|
|
|
if (refdtypep && (nodep == refdtypep->subDTypep())) {
|
|
|
|
|
refdtypep->v3error("Self-referential enumerated type definition");
|
|
|
|
|
}
|
2020-05-12 00:44:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstEnumItemRef* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// EnumItemRef may be under a dot. Should already be resolved.
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2013-02-02 20:11:50 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstMethodCall* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Created here so should already be resolved.
|
2020-08-25 03:10:43 +02:00
|
|
|
VL_RESTORER(m_ds);
|
2019-05-19 22:13:13 +02:00
|
|
|
{
|
|
|
|
|
m_ds.init(m_curSymp);
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2014-11-29 02:34:23 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstVar* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
checkNoDot(nodep);
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
if (m_statep->forPrimary() && nodep->isIO() && !m_ftaskp && !nodep->user4()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3error(
|
|
|
|
|
"Input/output/inout does not appear in port list: " << nodep->prettyNameQ());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeFTaskRef* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (nodep->user3SetOnce()) return;
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, " " << nodep << endl);
|
2020-11-26 17:06:59 +01:00
|
|
|
UINFO(8, " " << m_ds.ascii() << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
if (m_ds.m_dotp && m_ds.m_dotPos == DP_PACKAGE) {
|
2020-07-11 16:29:15 +02:00
|
|
|
UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(),
|
2020-04-15 13:58:34 +02:00
|
|
|
"Bad package link");
|
2021-11-26 23:55:36 +01:00
|
|
|
AstClassOrPackageRef* const cpackagerefp
|
|
|
|
|
= VN_AS(m_ds.m_dotp->lhsp(), ClassOrPackageRef);
|
2020-07-12 00:39:01 +02:00
|
|
|
if (cpackagerefp->name() == "process" || cpackagerefp->name() == "local") {
|
|
|
|
|
nodep->v3warn(E_UNSUPPORTED,
|
|
|
|
|
"Unsupported: " << AstNode::prettyNameQ(cpackagerefp->name()));
|
|
|
|
|
}
|
2020-11-07 01:51:21 +01:00
|
|
|
UASSERT_OBJ(cpackagerefp->classOrPackagep(), m_ds.m_dotp->lhsp(), "Bad package link");
|
2020-11-25 03:56:03 +01:00
|
|
|
nodep->classOrPackagep(cpackagerefp->classOrPackagep());
|
2019-05-19 22:13:13 +02:00
|
|
|
m_ds.m_dotPos = DP_SCOPE;
|
2020-08-15 16:12:55 +02:00
|
|
|
m_ds.m_dotp = nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_FINAL) {
|
2020-10-30 02:27:19 +01:00
|
|
|
if (m_ds.m_unresolved && m_ds.m_unlinkedScopep) {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstNodeFTaskRef* const newftaskp = nodep->cloneTree(false);
|
2019-05-19 22:13:13 +02:00
|
|
|
newftaskp->dotted(m_ds.m_dotText);
|
2021-11-26 23:55:36 +01:00
|
|
|
AstNode* const newp
|
2022-11-20 23:40:38 +01:00
|
|
|
= new AstUnlinkedRef{nodep->fileline(), newftaskp, nodep->name(),
|
|
|
|
|
m_ds.m_unlinkedScopep->unlinkFrBack()};
|
2020-10-30 02:27:19 +01:00
|
|
|
m_ds.m_unlinkedScopep = nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
m_ds.m_unresolved = false;
|
|
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
nodep->dotted(m_ds.m_dotText); // Maybe ""
|
|
|
|
|
}
|
|
|
|
|
} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_MEMBER) {
|
|
|
|
|
// Found a Var, everything following is method call.
|
|
|
|
|
// {scope}.{var}.HERE {method} ( ARGS )
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* const varEtcp = m_ds.m_dotp->lhsp()->unlinkFrBack();
|
|
|
|
|
AstNodeExpr* argsp = nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
if (nodep->pinsp()) argsp = nodep->pinsp()->unlinkFrBackWithNext();
|
2022-11-20 23:40:38 +01:00
|
|
|
AstNode* const newp = new AstMethodCall{nodep->fileline(), varEtcp, VFlagChildDType{},
|
|
|
|
|
nodep->name(), argsp};
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->replaceWith(newp);
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
checkNoDot(nodep);
|
|
|
|
|
}
|
2020-11-25 03:56:03 +01:00
|
|
|
if (nodep->classOrPackagep() && nodep->taskp()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// References into packages don't care about cell hierarchy.
|
|
|
|
|
} else if (!m_modSymp) {
|
2020-04-15 13:58:34 +02:00
|
|
|
// Module that is not in hierarchy. We'll be dead code eliminating it later.
|
|
|
|
|
UINFO(9, "Dead module for " << nodep << endl);
|
2020-08-15 16:12:55 +02:00
|
|
|
nodep->taskp(nullptr);
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (nodep->dotted() == "" && nodep->taskp()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Earlier should have setup the links
|
|
|
|
|
// Might be under a BEGIN we're not processing, so don't relink it
|
|
|
|
|
} else {
|
|
|
|
|
string baddot;
|
2020-08-15 16:12:55 +02:00
|
|
|
VSymEnt* okSymp = nullptr;
|
2020-11-26 17:06:59 +01:00
|
|
|
VSymEnt* dotSymp = nodep->dotted().empty()
|
|
|
|
|
? m_ds.m_dotSymp // Non-'super.' dotted reference
|
|
|
|
|
: m_curSymp; // Start search at dotted point
|
2019-05-19 22:13:13 +02:00
|
|
|
// 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
|
2020-11-25 03:56:03 +01:00
|
|
|
if (nodep->classOrPackagep()) { // Look only in specified package
|
|
|
|
|
dotSymp = m_statep->getNodeSym(nodep->classOrPackagep());
|
2020-11-26 17:06:59 +01:00
|
|
|
UINFO(8, " Override classOrPackage " << dotSymp << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (nodep->inlinedDots() != "") { // Correct for current scope
|
|
|
|
|
// Dotted lookup is always relative to module, as maybe
|
|
|
|
|
// variable name lower down with same scope name we want
|
|
|
|
|
// to ignore (t_math_divw)
|
|
|
|
|
dotSymp = m_modSymp;
|
2021-06-21 00:32:57 +02:00
|
|
|
const string inl = AstNode::dedotName(nodep->inlinedDots());
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, " Inlined " << inl << endl);
|
2020-07-04 15:35:04 +02:00
|
|
|
dotSymp
|
|
|
|
|
= m_statep->findDotted(nodep->fileline(), dotSymp, inl, baddot, okSymp);
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!dotSymp) {
|
|
|
|
|
okSymp->cellErrorScopes(nodep);
|
2019-11-05 03:16:07 +01:00
|
|
|
nodep->v3fatalSrc("Couldn't resolve inlined scope "
|
2020-04-15 13:58:34 +02:00
|
|
|
<< AstNode::prettyNameQ(baddot)
|
|
|
|
|
<< " in: " << nodep->inlinedDots());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
2020-07-04 15:35:04 +02:00
|
|
|
dotSymp = m_statep->findDotted(nodep->fileline(), dotSymp, nodep->dotted(), baddot,
|
2020-08-15 16:12:55 +02:00
|
|
|
okSymp); // Maybe nullptr
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot);
|
|
|
|
|
AstNodeFTask* const taskp
|
2020-08-15 16:12:55 +02:00
|
|
|
= foundp ? VN_CAST(foundp->nodep(), NodeFTask) : nullptr; // Maybe nullptr
|
2019-05-19 22:13:13 +02:00
|
|
|
if (taskp) {
|
|
|
|
|
nodep->taskp(taskp);
|
2020-11-25 03:56:03 +01:00
|
|
|
nodep->classOrPackagep(foundp->classOrPackagep());
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(7, " Resolved " << nodep << endl); // Also prints taskp
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
|
|
|
|
// Note ParseRef has similar error handling/message output
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(7, " ErrFtask curSymp=se" << cvtToHex(m_curSymp) << " dotSymp=se"
|
|
|
|
|
<< cvtToHex(dotSymp) << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
if (foundp) {
|
2021-06-13 18:38:31 +02:00
|
|
|
if (VN_IS(foundp->nodep(), Var) && m_ds.m_dotText == "" && m_ftaskp
|
|
|
|
|
&& m_ftaskp->name() == foundp->nodep()->name()) {
|
2022-01-04 00:50:41 +01:00
|
|
|
// This is a recursive reference to the function itself, not to the var
|
|
|
|
|
nodep->taskp(m_ftaskp);
|
|
|
|
|
nodep->classOrPackagep(foundp->classOrPackagep());
|
|
|
|
|
UINFO(7, " Resolved recursive " << nodep
|
|
|
|
|
<< endl); // Also prints taskp
|
2021-06-13 18:38:31 +02:00
|
|
|
} else {
|
|
|
|
|
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");
|
|
|
|
|
}
|
2020-04-13 00:57:12 +02:00
|
|
|
} else if (VN_IS(nodep, New) && m_statep->forPrearray()) {
|
|
|
|
|
// Resolved in V3Width
|
2019-05-19 22:13:13 +02:00
|
|
|
} else if (nodep->dotted() == "") {
|
2020-05-23 17:55:34 +02:00
|
|
|
if (nodep->pli()) {
|
|
|
|
|
if (v3Global.opt.bboxSys()) {
|
|
|
|
|
AstNode* newp;
|
|
|
|
|
if (VN_IS(nodep, FuncRef)) {
|
2022-11-20 23:40:38 +01:00
|
|
|
newp = new AstConst{nodep->fileline(), AstConst::StringToParse{},
|
|
|
|
|
"'0"};
|
2020-05-23 17:55:34 +02:00
|
|
|
} else {
|
2020-08-15 16:12:55 +02:00
|
|
|
AstNode* outp = nullptr;
|
2020-05-23 17:55:34 +02:00
|
|
|
while (nodep->pinsp()) {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstNode* const pinp = nodep->pinsp()->unlinkFrBack();
|
2020-05-23 17:55:34 +02:00
|
|
|
AstNode* addp = pinp;
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstArg* const argp = VN_CAST(pinp, Arg)) {
|
2020-05-23 17:55:34 +02:00
|
|
|
addp = argp->exprp()->unlinkFrBack();
|
|
|
|
|
VL_DO_DANGLING(pinp->deleteTree(), pinp);
|
|
|
|
|
}
|
|
|
|
|
outp = AstNode::addNext(outp, addp);
|
|
|
|
|
}
|
2022-11-20 23:40:38 +01:00
|
|
|
newp = new AstSysIgnore{nodep->fileline(), outp};
|
2022-10-12 11:19:21 +02:00
|
|
|
newp->dtypep(nodep->dtypep());
|
2020-05-23 17:55:34 +02:00
|
|
|
}
|
|
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
2020-11-19 03:03:23 +01:00
|
|
|
nodep->v3error(
|
|
|
|
|
"Unsupported or unknown PLI call: " << nodep->prettyNameQ());
|
2020-05-23 17:55:34 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
2021-06-21 00:32:57 +02:00
|
|
|
const string suggest = m_statep->suggestSymFallback(
|
2022-11-20 23:40:38 +01:00
|
|
|
dotSymp, nodep->name(), LinkNodeMatcherFTask{});
|
2020-05-23 17:55:34 +02:00
|
|
|
nodep->v3error("Can't find definition of task/function: "
|
2020-11-19 03:03:23 +01:00
|
|
|
<< nodep->prettyNameQ() << '\n'
|
2020-05-23 17:55:34 +02:00
|
|
|
<< (suggest.empty() ? "" : nodep->warnMore() + suggest));
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
2021-06-21 00:32:57 +02:00
|
|
|
const string suggest = m_statep->suggestSymFallback(dotSymp, nodep->name(),
|
2022-11-20 23:40:38 +01:00
|
|
|
LinkNodeMatcherFTask{});
|
2019-11-05 03:16:07 +01:00
|
|
|
nodep->v3error("Can't find definition of "
|
2020-04-15 13:58:34 +02:00
|
|
|
<< AstNode::prettyNameQ(baddot) << " in dotted task/function: '"
|
|
|
|
|
<< nodep->dotted() + "." + nodep->prettyName() << "'\n"
|
|
|
|
|
<< (suggest.empty() ? "" : nodep->warnMore() + suggest));
|
2019-05-19 22:13:13 +02:00
|
|
|
okSymp->cellErrorScopes(nodep);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
taskFuncSwapCheck(nodep);
|
|
|
|
|
}
|
|
|
|
|
{
|
2020-08-25 03:10:43 +02:00
|
|
|
VL_RESTORER(m_ds);
|
2019-05-19 22:13:13 +02:00
|
|
|
m_ds.init(m_curSymp);
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstSelBit* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (nodep->user3SetOnce()) return;
|
2020-12-08 00:45:54 +01:00
|
|
|
iterateAndNextNull(nodep->fromp());
|
2020-04-15 13:58:34 +02:00
|
|
|
if (m_ds.m_dotPos
|
|
|
|
|
== DP_SCOPE) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
|
|
|
|
UINFO(9, " deferring until after a V3Param pass: " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
m_ds.m_dotText += "__BRA__??__KET__";
|
|
|
|
|
m_ds.m_unresolved = true;
|
|
|
|
|
// And pass up m_ds.m_dotText
|
|
|
|
|
}
|
|
|
|
|
// Pass dot state down to fromp()
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateAndNextNull(nodep->fromp());
|
2019-05-19 22:13:13 +02:00
|
|
|
{
|
2020-08-25 03:10:43 +02:00
|
|
|
VL_RESTORER(m_ds);
|
|
|
|
|
{
|
|
|
|
|
m_ds.init(m_curSymp);
|
|
|
|
|
iterateAndNextNull(nodep->bitp());
|
|
|
|
|
iterateAndNextNull(nodep->attrp());
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
if (m_ds.m_unresolved && m_ds.m_dotPos == DP_SCOPE) {
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* const exprp = nodep->bitp()->unlinkFrBack();
|
2021-11-26 23:55:36 +01:00
|
|
|
AstCellArrayRef* const newp
|
2022-11-20 23:40:38 +01:00
|
|
|
= new AstCellArrayRef{nodep->fileline(), nodep->fromp()->name(), exprp};
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2012-12-31 23:05:13 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodePreSel* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Excludes simple AstSelBit, see above
|
|
|
|
|
if (nodep->user3SetOnce()) return;
|
2020-04-15 13:58:34 +02:00
|
|
|
if (m_ds.m_dotPos
|
|
|
|
|
== DP_SCOPE) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
2020-12-13 04:43:55 +01:00
|
|
|
nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed in the instance "
|
|
|
|
|
"part of a dotted reference");
|
2019-05-19 22:13:13 +02:00
|
|
|
m_ds.m_dotErr = true;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-12-08 00:45:54 +01:00
|
|
|
iterateAndNextNull(nodep->fromp());
|
2020-08-25 03:10:43 +02:00
|
|
|
VL_RESTORER(m_ds);
|
2019-05-19 22:13:13 +02:00
|
|
|
{
|
|
|
|
|
m_ds.init(m_curSymp);
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateAndNextNull(nodep->rhsp());
|
|
|
|
|
iterateAndNextNull(nodep->thsp());
|
|
|
|
|
iterateAndNextNull(nodep->attrp());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2012-12-31 23:05:13 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstMemberSel* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// checkNoDot not appropriate, can be under a dot
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2012-07-24 12:26:35 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeBlock* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(5, " " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
checkNoDot(nodep);
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const oldCurSymp = m_curSymp;
|
2019-05-19 22:13:13 +02:00
|
|
|
{
|
2020-02-26 04:21:16 +01:00
|
|
|
if (nodep->name() != "") {
|
|
|
|
|
m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(5, " cur=se" << cvtToHex(m_curSymp) << endl);
|
2020-02-26 04:21:16 +01:00
|
|
|
}
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
m_ds.m_dotSymp = m_curSymp = oldCurSymp;
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(5, " cur=se" << cvtToHex(m_curSymp) << endl);
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeFTask* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(5, " " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
checkNoDot(nodep);
|
2020-08-23 01:46:21 +02:00
|
|
|
if (nodep->isExternDef()) {
|
|
|
|
|
if (!m_curSymp->findIdFallback("extern " + nodep->name())) {
|
|
|
|
|
nodep->v3error("extern not found that declares " + nodep->prettyNameQ());
|
|
|
|
|
}
|
2020-07-02 14:24:35 +02:00
|
|
|
}
|
2020-08-23 01:46:21 +02:00
|
|
|
if (nodep->isExternProto()) {
|
|
|
|
|
if (!m_curSymp->findIdFallback(nodep->name())) {
|
|
|
|
|
nodep->v3error("definition not found for extern " + nodep->prettyNameQ());
|
|
|
|
|
}
|
2020-08-22 22:24:29 +02:00
|
|
|
}
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const oldCurSymp = m_curSymp;
|
2019-05-19 22:13:13 +02:00
|
|
|
{
|
|
|
|
|
m_ftaskp = nodep;
|
|
|
|
|
m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
m_ds.m_dotSymp = m_curSymp = oldCurSymp;
|
2020-08-15 16:12:55 +02:00
|
|
|
m_ftaskp = nullptr;
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstForeach* nodep) override {
|
2021-12-11 21:06:33 +01:00
|
|
|
UINFO(5, " " << nodep << endl);
|
|
|
|
|
checkNoDot(nodep);
|
|
|
|
|
VSymEnt* const oldCurSymp = m_curSymp;
|
|
|
|
|
{
|
|
|
|
|
m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
}
|
|
|
|
|
m_ds.m_dotSymp = m_curSymp = oldCurSymp;
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstWith* nodep) override {
|
2020-10-31 15:00:55 +01:00
|
|
|
UINFO(5, " " << nodep << endl);
|
|
|
|
|
checkNoDot(nodep);
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const oldCurSymp = m_curSymp;
|
2020-10-31 15:00:55 +01:00
|
|
|
{
|
|
|
|
|
m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
}
|
|
|
|
|
m_ds.m_dotSymp = m_curSymp = oldCurSymp;
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstLambdaArgRef* nodep) override {
|
2020-11-24 05:18:58 +01:00
|
|
|
UINFO(5, " " << nodep << endl);
|
|
|
|
|
// No checknodot(nodep), visit(AstScope) will check for LambdaArgRef
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstClass* nodep) override {
|
2020-04-05 15:30:23 +02:00
|
|
|
UINFO(5, " " << nodep << endl);
|
|
|
|
|
checkNoDot(nodep);
|
2020-08-25 03:10:43 +02:00
|
|
|
VL_RESTORER(m_curSymp);
|
|
|
|
|
VL_RESTORER(m_modSymp);
|
2023-01-29 00:06:37 +01:00
|
|
|
VL_RESTORER(m_ifClassImpNames);
|
2020-04-05 15:30:23 +02:00
|
|
|
{
|
|
|
|
|
m_ds.init(m_curSymp);
|
|
|
|
|
// Until overridden by a SCOPE
|
|
|
|
|
m_ds.m_dotSymp = m_curSymp = m_modSymp = m_statep->getNodeSym(nodep);
|
|
|
|
|
m_modp = nodep;
|
2023-01-29 00:06:37 +01:00
|
|
|
int next = 0;
|
2020-10-17 00:25:32 +02:00
|
|
|
for (AstNode* itemp = nodep->extendsp(); itemp; itemp = itemp->nextp()) {
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstClassExtends* const cextp = VN_CAST(itemp, ClassExtends)) {
|
2020-10-17 00:25:32 +02:00
|
|
|
// Replace abstract reference with hard pointer
|
|
|
|
|
// Will need later resolution when deal with parameters
|
2023-01-29 00:06:37 +01:00
|
|
|
if (++next == 2 && !nodep->isInterfaceClass() && !cextp->isImplements()) {
|
|
|
|
|
cextp->v3error("Multiple inheritance illegal on non-interface classes"
|
|
|
|
|
" (IEEE 1800-2017 8.13)");
|
|
|
|
|
}
|
2020-10-17 00:25:32 +02:00
|
|
|
if (cextp->childDTypep() || cextp->dtypep()) continue; // Already converted
|
2021-11-26 23:55:36 +01:00
|
|
|
AstClassOrPackageRef* const cpackagerefp
|
2020-10-17 00:25:32 +02:00
|
|
|
= VN_CAST(cextp->classOrPkgsp(), ClassOrPackageRef);
|
2022-12-29 20:18:45 +01:00
|
|
|
if (VL_UNCOVERABLE(!cpackagerefp)) {
|
|
|
|
|
// Linking the extend gives an error before this is hit
|
|
|
|
|
cextp->v3error("Attempting to extend using non-class"); // LCOV_EXCL_LINE
|
2020-10-17 00:25:32 +02:00
|
|
|
} else {
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const foundp = m_curSymp->findIdFallback(cpackagerefp->name());
|
2020-10-17 00:25:32 +02:00
|
|
|
if (foundp) {
|
2023-01-26 02:33:18 +01:00
|
|
|
AstClassRefDType* classRefDtypep = nullptr;
|
|
|
|
|
AstClass* classp = VN_CAST(foundp->nodep(), Class);
|
|
|
|
|
if (classp) {
|
|
|
|
|
AstPin* paramsp = cpackagerefp->paramsp();
|
|
|
|
|
if (paramsp) paramsp = paramsp->cloneTree(true);
|
|
|
|
|
classRefDtypep
|
|
|
|
|
= new AstClassRefDType{nodep->fileline(), classp, paramsp};
|
|
|
|
|
} else if (AstParamTypeDType* const paramp
|
|
|
|
|
= VN_CAST(foundp->nodep(), ParamTypeDType)) {
|
|
|
|
|
if (m_statep->forPrimary()) {
|
|
|
|
|
// Extending has to be handled after V3Param.cpp, but the type
|
|
|
|
|
// reference has to be visited
|
|
|
|
|
iterate(paramp);
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
AstNodeDType* const paramTypep = paramp->getChildDTypep();
|
|
|
|
|
classRefDtypep
|
|
|
|
|
= VN_CAST(paramTypep->cloneTree(false), ClassRefDType);
|
|
|
|
|
if (!classRefDtypep) {
|
|
|
|
|
paramTypep->v3error(
|
|
|
|
|
"Attempting to extend using non-class");
|
|
|
|
|
} else {
|
|
|
|
|
classp = classRefDtypep->classp();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
cextp->v3warn(E_UNSUPPORTED,
|
|
|
|
|
"Unsupported: " << foundp->nodep()->prettyTypeName()
|
|
|
|
|
<< " in AstClassExtends");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (classp) {
|
2020-10-17 00:25:32 +02:00
|
|
|
UINFO(8, "Import to " << nodep << " from export class " << classp
|
|
|
|
|
<< endl);
|
2020-11-25 00:15:49 +01:00
|
|
|
if (classp == nodep) {
|
|
|
|
|
cextp->v3error("Attempting to extend class "
|
|
|
|
|
<< nodep->prettyNameQ() << " from itself");
|
2023-01-28 22:30:47 +01:00
|
|
|
} else if (cextp->isImplements() && !classp->isInterfaceClass()) {
|
|
|
|
|
cextp->v3error(
|
|
|
|
|
"Attempting to implement from non-interface class "
|
|
|
|
|
<< classp->prettyNameQ() << '\n'
|
|
|
|
|
<< "... Suggest use 'extends'");
|
|
|
|
|
} else if (!cextp->isImplements() && !nodep->isInterfaceClass()
|
|
|
|
|
&& classp->isInterfaceClass()) {
|
|
|
|
|
cextp->v3error("Attempting to extend from interface class "
|
|
|
|
|
<< classp->prettyNameQ() << '\n'
|
|
|
|
|
<< "... Suggest use 'implements'");
|
2020-11-25 00:15:49 +01:00
|
|
|
} else {
|
2023-01-26 02:33:18 +01:00
|
|
|
cextp->childDTypep(classRefDtypep);
|
2020-11-25 00:15:49 +01:00
|
|
|
classp->isExtended(true);
|
|
|
|
|
nodep->isExtended(true);
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const srcp = m_statep->getNodeSym(classp);
|
2023-01-29 00:06:37 +01:00
|
|
|
if (classp->isInterfaceClass()) {
|
|
|
|
|
importImplementsClass(nodep, srcp, classp);
|
|
|
|
|
} else {
|
|
|
|
|
m_curSymp->importFromClass(m_statep->symsp(), srcp);
|
|
|
|
|
}
|
2020-11-25 00:15:49 +01:00
|
|
|
VL_DO_DANGLING(cpackagerefp->unlinkFrBack()->deleteTree(),
|
|
|
|
|
cpackagerefp);
|
|
|
|
|
}
|
2020-10-17 00:25:32 +02:00
|
|
|
}
|
2023-01-26 02:33:18 +01:00
|
|
|
} else {
|
2021-06-21 00:32:57 +02:00
|
|
|
const string suggest = m_statep->suggestSymFallback(
|
2020-10-17 00:25:32 +02:00
|
|
|
m_curSymp, cpackagerefp->name(), LinkNodeMatcherClass{});
|
|
|
|
|
cpackagerefp->v3error(
|
2023-01-28 22:30:47 +01:00
|
|
|
"Class for '"
|
|
|
|
|
<< cextp->verilogKwd() // extends/implements
|
|
|
|
|
<< "' not found: " << cpackagerefp->prettyNameQ() << '\n'
|
2020-10-17 00:25:32 +02:00
|
|
|
<< (suggest.empty() ? "" : cpackagerefp->warnMore() + suggest));
|
2020-08-24 01:37:56 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-10-17 00:25:32 +02:00
|
|
|
iterateChildren(nodep);
|
2020-08-24 01:37:56 +02:00
|
|
|
}
|
2020-04-05 15:30:23 +02:00
|
|
|
// V3Width when determines types needs to find enum values and such
|
|
|
|
|
// so add members pointing to appropriate enum values
|
|
|
|
|
{
|
|
|
|
|
nodep->repairCache();
|
|
|
|
|
for (VSymEnt::const_iterator it = m_curSymp->begin(); it != m_curSymp->end(); ++it) {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstNode* const itemp = it->second->nodep();
|
2020-04-05 15:30:23 +02:00
|
|
|
if (!nodep->findMember(it->first)) {
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstEnumItem* const aitemp = VN_CAST(itemp, EnumItem)) {
|
2022-11-20 23:40:38 +01:00
|
|
|
AstEnumItemRef* const newp = new AstEnumItemRef{
|
|
|
|
|
aitemp->fileline(), aitemp, it->second->classOrPackagep()};
|
2020-04-05 15:30:23 +02:00
|
|
|
UINFO(8, "Class import noderef '" << it->first << "' " << newp << endl);
|
|
|
|
|
nodep->addMembersp(newp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstRefDType* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Resolve its reference
|
|
|
|
|
if (nodep->user3SetOnce()) return;
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstNode* const cpackagep = nodep->classOrPackageOpp()) {
|
|
|
|
|
if (AstClassOrPackageRef* const cpackagerefp = VN_CAST(cpackagep, ClassOrPackageRef)) {
|
2020-11-25 03:56:03 +01:00
|
|
|
nodep->classOrPackagep(cpackagerefp->classOrPackagep());
|
|
|
|
|
if (!VN_IS(nodep->classOrPackagep(), Class)
|
|
|
|
|
&& !VN_IS(nodep->classOrPackagep(), Package)) {
|
|
|
|
|
cpackagerefp->v3error(
|
2020-12-05 22:23:20 +01:00
|
|
|
"'::' expected to reference a class/package but referenced '"
|
|
|
|
|
<< (nodep->classOrPackagep() ? nodep->classOrPackagep()->prettyTypeName()
|
|
|
|
|
: "<unresolved-object>")
|
|
|
|
|
<< "'\n"
|
2020-11-25 03:56:03 +01:00
|
|
|
<< cpackagerefp->warnMore() + "... Suggest '.' instead of '::'");
|
2020-07-12 00:39:01 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
cpackagep->v3warn(E_UNSUPPORTED,
|
|
|
|
|
"Unsupported: Multiple '::' package/class reference");
|
|
|
|
|
}
|
|
|
|
|
VL_DO_DANGLING(cpackagep->unlinkFrBack()->deleteTree(), cpackagep);
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
if (m_ds.m_dotp && m_ds.m_dotPos == DP_PACKAGE) {
|
2020-07-11 16:29:15 +02:00
|
|
|
UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(),
|
2020-04-15 13:58:34 +02:00
|
|
|
"Bad package link");
|
2021-11-26 23:55:36 +01:00
|
|
|
auto* const cpackagerefp = VN_AS(m_ds.m_dotp->lhsp(), ClassOrPackageRef);
|
2020-12-05 22:23:20 +01:00
|
|
|
UASSERT_OBJ(cpackagerefp->classOrPackagep(), m_ds.m_dotp->lhsp(), "Bad package link");
|
|
|
|
|
nodep->classOrPackagep(cpackagerefp->classOrPackagep());
|
2019-05-19 22:13:13 +02:00
|
|
|
m_ds.m_dotPos = DP_SCOPE;
|
2020-08-15 16:12:55 +02:00
|
|
|
m_ds.m_dotp = nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
|
|
|
|
checkNoDot(nodep);
|
|
|
|
|
}
|
2020-01-26 16:28:13 +01:00
|
|
|
if (nodep->typeofp()) { // Really is a typeof not a reference
|
2020-05-24 20:22:06 +02:00
|
|
|
} else if (!nodep->typedefp() && !nodep->subDTypep()) {
|
2021-11-26 23:55:36 +01:00
|
|
|
const VSymEnt* foundp;
|
2020-11-25 03:56:03 +01:00
|
|
|
if (nodep->classOrPackagep()) {
|
|
|
|
|
foundp = m_statep->getNodeSym(nodep->classOrPackagep())->findIdFlat(nodep->name());
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
|
|
|
|
foundp = m_curSymp->findIdFallback(nodep->name());
|
|
|
|
|
}
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstTypedef* const defp = foundp ? VN_CAST(foundp->nodep(), Typedef) : nullptr) {
|
2020-05-24 20:22:06 +02:00
|
|
|
nodep->typedefp(defp);
|
2020-11-25 03:56:03 +01:00
|
|
|
nodep->classOrPackagep(foundp->classOrPackagep());
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (AstParamTypeDType* const defp
|
2020-08-15 16:12:55 +02:00
|
|
|
= foundp ? VN_CAST(foundp->nodep(), ParamTypeDType) : nullptr) {
|
2021-11-23 13:27:41 +01:00
|
|
|
if (defp == nodep->backp()) { // Where backp is typically typedef
|
|
|
|
|
nodep->v3error("Reference to '" << m_ds.m_dotText
|
|
|
|
|
<< (m_ds.m_dotText == "" ? "" : ".")
|
|
|
|
|
<< nodep->prettyName() << "'"
|
|
|
|
|
<< " type would form a recursive definition");
|
|
|
|
|
nodep->refDTypep(nodep->findVoidDType()); // Try to reduce later errors
|
|
|
|
|
} else {
|
|
|
|
|
nodep->refDTypep(defp);
|
|
|
|
|
nodep->classOrPackagep(foundp->classOrPackagep());
|
|
|
|
|
}
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (AstClass* const defp = foundp ? VN_AS(foundp->nodep(), Class) : nullptr) {
|
2022-09-15 20:43:56 +02:00
|
|
|
AstPin* const paramsp = nodep->paramsp();
|
2020-11-28 04:48:42 +01:00
|
|
|
if (paramsp) paramsp->unlinkFrBackWithNext();
|
2021-11-26 23:55:36 +01:00
|
|
|
AstClassRefDType* const newp
|
|
|
|
|
= new AstClassRefDType{nodep->fileline(), defp, paramsp};
|
2020-11-25 03:56:03 +01:00
|
|
|
newp->classOrPackagep(foundp->classOrPackagep());
|
2020-04-05 15:30:23 +02:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
|
|
|
|
return;
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
2020-04-05 15:30:23 +02:00
|
|
|
if (foundp) UINFO(1, "Found sym node: " << foundp->nodep() << endl);
|
|
|
|
|
nodep->v3error("Can't find typedef: " << nodep->prettyNameQ());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstDpiExport* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// AstDpiExport: Make sure the function referenced exists, then dump it
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
checkNoDot(nodep);
|
2021-11-26 23:55:36 +01:00
|
|
|
VSymEnt* const foundp = m_curSymp->findIdFallback(nodep->name());
|
|
|
|
|
AstNodeFTask* const taskp = foundp ? VN_AS(foundp->nodep(), NodeFTask) : nullptr;
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!taskp) {
|
|
|
|
|
nodep->v3error(
|
|
|
|
|
"Can't find definition of exported task/function: " << nodep->prettyNameQ());
|
|
|
|
|
} else if (taskp->dpiExport()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->v3error("Function was already DPI Exported, duplicate not allowed: "
|
2020-04-15 13:58:34 +02:00
|
|
|
<< nodep->prettyNameQ());
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
|
|
|
|
taskp->dpiExport(true);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (nodep->cname() != "") taskp->cname(nodep->cname());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
2012-07-21 23:12:42 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstPackageImport* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// No longer needed
|
|
|
|
|
checkNoDot(nodep);
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
2012-08-09 03:59:17 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstPackageExport* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// No longer needed
|
|
|
|
|
checkNoDot(nodep);
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
2017-09-21 03:04:59 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstPackageExportStarStar* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// No longer needed
|
|
|
|
|
checkNoDot(nodep);
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
2017-09-21 03:04:59 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstCellRef* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(5, " AstCellRef: " << nodep << " " << m_ds.ascii() << endl);
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2015-10-23 02:13:49 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstCellArrayRef* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(5, " AstCellArrayRef: " << nodep << " " << m_ds.ascii() << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
// Expression already iterated
|
2015-10-23 02:13:49 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstUnlinkedRef* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(5, " AstCellArrayRef: " << nodep << " " << m_ds.ascii() << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
// No need to iterate, if we have a UnlinkedVarXRef, we're already done
|
2015-10-23 02:13:49 +02:00
|
|
|
}
|
2015-12-06 01:39:40 +01:00
|
|
|
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNode* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
checkNoDot(nodep);
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-04-04 14:31:14 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
public:
|
2019-09-12 13:22:22 +02:00
|
|
|
// CONSTRUCTORS
|
2020-08-15 19:11:27 +02:00
|
|
|
LinkDotResolveVisitor(AstNetlist* rootp, LinkDotState* statep)
|
2020-08-16 15:55:36 +02:00
|
|
|
: m_statep{statep} {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, __FUNCTION__ << ": " << endl);
|
2018-05-11 02:55:37 +02:00
|
|
|
iterate(rootp);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
~LinkDotResolveVisitor() override = default;
|
2006-08-26 13:35:28 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Link class functions
|
|
|
|
|
|
2012-07-21 15:27:57 +02:00
|
|
|
void V3LinkDot::linkDotGuts(AstNetlist* rootp, VLinkDotStep step) {
|
2022-09-18 21:53:42 +02:00
|
|
|
if (debug() >= 5 || dumpTree() >= 9) {
|
2018-03-10 22:32:04 +01:00
|
|
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot.tree"));
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
LinkDotState state(rootp, step);
|
2021-11-26 23:55:36 +01:00
|
|
|
const LinkDotFindVisitor visitor{rootp, &state};
|
2022-09-18 21:53:42 +02:00
|
|
|
if (debug() >= 5 || dumpTree() >= 9) {
|
2018-03-10 22:32:04 +01:00
|
|
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-find.tree"));
|
|
|
|
|
}
|
2012-07-21 23:12:42 +02:00
|
|
|
if (step == LDS_PRIMARY || step == LDS_PARAMED) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Initial link stage, resolve parameters
|
2021-11-26 23:55:36 +01:00
|
|
|
const LinkDotParamVisitor visitors{rootp, &state};
|
2022-09-18 21:53:42 +02:00
|
|
|
if (debug() >= 5 || dumpTree() >= 9) {
|
2018-03-10 22:32:04 +01:00
|
|
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-param.tree"));
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (step == LDS_ARRAYED) {
|
|
|
|
|
} else if (step == LDS_SCOPED) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Well after the initial link when we're ready to operate on the flat design,
|
|
|
|
|
// process AstScope's. This needs to be separate pass after whole hierarchy graph created.
|
2021-11-26 23:55:36 +01:00
|
|
|
const LinkDotScopeVisitor visitors{rootp, &state};
|
2020-11-14 22:13:06 +01:00
|
|
|
v3Global.assertScoped(true);
|
2022-09-18 21:53:42 +02:00
|
|
|
if (debug() >= 5 || dumpTree() >= 9) {
|
2018-03-10 22:32:04 +01:00
|
|
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-scoped.tree"));
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
|
|
|
|
v3fatalSrc("Bad case");
|
2006-09-06 19:48:41 +02:00
|
|
|
}
|
2022-09-18 21:53:42 +02:00
|
|
|
state.dumpSelf();
|
2013-05-28 03:39:19 +02:00
|
|
|
state.computeIfaceModSyms();
|
|
|
|
|
state.computeIfaceVarSyms();
|
|
|
|
|
state.computeScopeAliases();
|
2022-09-18 21:53:42 +02:00
|
|
|
state.dumpSelf();
|
2021-11-26 16:52:36 +01:00
|
|
|
{ LinkDotResolveVisitor{rootp, &state}; }
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-18 21:53:42 +02:00
|
|
|
|
|
|
|
|
void V3LinkDot::linkDotPrimary(AstNetlist* nodep) {
|
|
|
|
|
UINFO(2, __FUNCTION__ << ": " << endl);
|
|
|
|
|
linkDotGuts(nodep, LDS_PRIMARY);
|
|
|
|
|
V3Global::dumpCheckGlobalTree("linkdot", 0, dumpTree() >= 6);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void V3LinkDot::linkDotParamed(AstNetlist* nodep) {
|
|
|
|
|
UINFO(2, __FUNCTION__ << ": " << endl);
|
|
|
|
|
linkDotGuts(nodep, LDS_PARAMED);
|
|
|
|
|
V3Global::dumpCheckGlobalTree("linkdotparam", 0, dumpTree() >= 3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void V3LinkDot::linkDotArrayed(AstNetlist* nodep) {
|
|
|
|
|
UINFO(2, __FUNCTION__ << ": " << endl);
|
|
|
|
|
linkDotGuts(nodep, LDS_ARRAYED);
|
|
|
|
|
V3Global::dumpCheckGlobalTree("linkdot", 0, dumpTree() >= 6);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void V3LinkDot::linkDotScope(AstNetlist* nodep) {
|
|
|
|
|
UINFO(2, __FUNCTION__ << ": " << endl);
|
|
|
|
|
linkDotGuts(nodep, LDS_SCOPED);
|
|
|
|
|
V3Global::dumpCheckGlobalTree("linkdot", 0, dumpTree() >= 3);
|
|
|
|
|
}
|