Rework symbol_search function.
There are too many ad hoc handlers of symbol_search partial results. Rewrite symbol_search to clean up things like partial results and member/method detections. Use this reworked symbol_search function to rewrite expression elaborate for the PECallFunction expressions.
This commit is contained in:
parent
555a2e703a
commit
38b3c8efb2
|
|
@ -111,6 +111,7 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \
|
|||
load_module.o netlist.o netmisc.o nettypes.o net_analog.o net_assign.o \
|
||||
net_design.o netclass.o netdarray.o \
|
||||
netenum.o netparray.o netqueue.o netscalar.o netstruct.o netvector.o \
|
||||
make_ivl_type.o \
|
||||
net_event.o net_expr.o net_func.o \
|
||||
net_func_eval.o net_link.o net_modulo.o \
|
||||
net_nex_input.o net_nex_output.o net_proc.o net_scope.o net_tran.o \
|
||||
|
|
|
|||
15
PExpr.h
15
PExpr.h
|
|
@ -35,6 +35,7 @@ class NetNet;
|
|||
class NetExpr;
|
||||
class NetScope;
|
||||
class PPackage;
|
||||
struct symbol_search_results;
|
||||
|
||||
/*
|
||||
* The PExpr class hierarchy supports the description of
|
||||
|
|
@ -932,13 +933,12 @@ class PECallFunction : public PExpr {
|
|||
|
||||
NetExpr*elaborate_expr_pkg_(Design*des, NetScope*scope,
|
||||
unsigned expr_wid, unsigned flags)const;
|
||||
NetExpr*elaborate_expr_method_(Design*des, NetScope*scope,
|
||||
unsigned expr_wid,
|
||||
bool add_this_flag = false) const;
|
||||
NetExpr*elaborate_expr_method_net_(Design*des, NetScope*scope,
|
||||
NetNet*net, unsigned expr_wid) const;
|
||||
NetExpr*elaborate_expr_method_par_(Design*des, NetScope*scope,
|
||||
const NetExpr *par, ivl_type_t par_type,
|
||||
|
||||
NetExpr* elaborate_expr_method_(Design*des, NetScope*scope,
|
||||
symbol_search_results&search_results,
|
||||
unsigned expr_wid) const;
|
||||
NetExpr* elaborate_expr_method_par_(Design*des, NetScope*scope,
|
||||
symbol_search_results&search_results,
|
||||
unsigned expr_wid) const;
|
||||
|
||||
|
||||
|
|
@ -950,6 +950,7 @@ class PECallFunction : public PExpr {
|
|||
unsigned test_width_sfunc_(Design*des, NetScope*scope,
|
||||
width_mode_t&mode);
|
||||
unsigned test_width_method_(Design*des, NetScope*scope,
|
||||
symbol_search_results&search_results,
|
||||
width_mode_t&mode);
|
||||
|
||||
NetExpr*elaborate_base_(Design*des, NetScope*scope, NetScope*dscope,
|
||||
|
|
|
|||
1093
elab_expr.cc
1093
elab_expr.cc
File diff suppressed because it is too large
Load Diff
40
elab_sig.cc
40
elab_sig.cc
|
|
@ -913,6 +913,7 @@ bool test_ranges_eeq(const vector<netrange_t>&lef, const vector<netrange_t>&rig)
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Elaborate a source wire. The "wire" is the declaration of wires,
|
||||
* registers, ports and memories. The parser has already merged the
|
||||
|
|
@ -950,6 +951,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
<< ", wtype=" << wtype
|
||||
<< ", data_type_=" << data_type_
|
||||
<< ", is_implicit_scalar=" << (is_implicit_scalar?"true":"false")
|
||||
<< ", unpacked_.size()=" << unpacked_.size()
|
||||
<< endl;
|
||||
}
|
||||
|
||||
|
|
@ -1086,8 +1088,8 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
// dimensions, then turn this into a dynamic array and
|
||||
// put all the packed dimensions there.
|
||||
if (use_lidx==0 && use_ridx==0) {
|
||||
netvector_t*vec = new netvector_t(packed_dimensions, data_type_);
|
||||
vec->set_signed(get_signed());
|
||||
ivl_type_t vec = make_ivl_type(data_type_, packed_dimensions,
|
||||
get_signed());
|
||||
packed_dimensions.clear();
|
||||
ivl_assert(*this, netdarray==0);
|
||||
netdarray = new netdarray_t(vec);
|
||||
|
|
@ -1097,8 +1099,8 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
// Special case: Detect the mark for a QUEUE
|
||||
// declaration, which is the dimensions [null:max_idx].
|
||||
if (dynamic_cast<PENull*>(use_lidx)) {
|
||||
netvector_t*vec = new netvector_t(packed_dimensions, data_type_);
|
||||
vec->set_signed(get_signed());
|
||||
ivl_type_t vec = make_ivl_type(data_type_, packed_dimensions,
|
||||
get_signed());
|
||||
packed_dimensions.clear();
|
||||
ivl_assert(*this, netdarray==0);
|
||||
long max_idx;
|
||||
|
|
@ -1232,7 +1234,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
const netenum_t*use_enum = base_type_scope->find_enumeration_for_name(des, sample_name->name);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": " << __func__ << ": "
|
||||
cerr << get_fileline() << ": PWire::elaborate_sig: "
|
||||
<< "Create signal " << wtype
|
||||
<< " enumeration "
|
||||
<< name_ << " in scope " << scope_path(scope)
|
||||
|
|
@ -1247,9 +1249,10 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
} else if (netdarray) {
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": " << __func__ << ": "
|
||||
<< "Create signal " << wtype
|
||||
<< " dynamic array " << name_
|
||||
cerr << get_fileline() << ": PWire::elaborate_sig: "
|
||||
<< "Create signal wtype=" << wtype
|
||||
<< " name=" << name_
|
||||
<< " netdarray=" << *netdarray
|
||||
<< " in scope " << scope_path(scope) << endl;
|
||||
}
|
||||
|
||||
|
|
@ -1271,6 +1274,21 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
sig = new NetNet(scope, name_, wtype, unpacked_dimensions,
|
||||
&netstring_t::type_string);
|
||||
|
||||
} else if (set_data_type_==0 && data_type_==IVL_VT_STRING) {
|
||||
|
||||
// Signal declared as: string foo;
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PWire::elaborate_sig: "
|
||||
<< "Create signal " << wtype
|
||||
<< " string "
|
||||
<< name_ << " in scope " << scope_path(scope)
|
||||
<< " without set_data_type_"
|
||||
<< endl;
|
||||
}
|
||||
|
||||
sig = new NetNet(scope, name_, wtype, unpacked_dimensions,
|
||||
&netstring_t::type_string);
|
||||
|
||||
} else if (parray_type_t*parray_type = dynamic_cast<parray_type_t*>(set_data_type_)) {
|
||||
// The pform gives us a parray_type_t for packed arrays
|
||||
// that show up in type definitions. This can be handled
|
||||
|
|
@ -1295,8 +1313,8 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
|
||||
} else {
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": " << __func__ << ": "
|
||||
<< "Create signal " << wtype
|
||||
cerr << get_fileline() << ": PWire::elaborate_sig: "
|
||||
<< "Create vector signal " << wtype
|
||||
<< " data_type=" << data_type_;
|
||||
if (!get_scalar()) {
|
||||
cerr << " " << packed_dimensions;
|
||||
|
|
@ -1309,7 +1327,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
if (use_data_type == IVL_VT_NO_TYPE) {
|
||||
use_data_type = IVL_VT_LOGIC;
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": " << __func__ << ": "
|
||||
cerr << get_fileline() << ": PWire::elaborate_sig: "
|
||||
<< "Signal " << name_
|
||||
<< " in scope " << scope_path(scope)
|
||||
<< " defaults to data type " << use_data_type << endl;
|
||||
|
|
|
|||
|
|
@ -3371,7 +3371,8 @@ NetProc* PCondit::elaborate(Design*des, NetScope*scope) const
|
|||
assert(scope);
|
||||
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: Elaborate condition statement"
|
||||
cerr << get_fileline() << ": PCondit::elaborate: "
|
||||
<< "Elaborate condition statement"
|
||||
<< " with conditional: " << *expr_ << endl;
|
||||
|
||||
// Elaborate and try to evaluate the conditional expression.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 2012-2014 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
# include "nettypes.h"
|
||||
# include "netscalar.h"
|
||||
# include "netvector.h"
|
||||
|
||||
ivl_type_t make_ivl_type(ivl_variable_type_t vt,
|
||||
const std::vector<netrange_t>&packed_dimensions,
|
||||
bool signed_flag, bool isint_flag)
|
||||
{
|
||||
netvector_t*vec;
|
||||
|
||||
if (packed_dimensions.size() > 0) {
|
||||
vec = new netvector_t(packed_dimensions, vt);
|
||||
vec->set_signed(signed_flag);
|
||||
return vec;
|
||||
}
|
||||
|
||||
switch (vt) {
|
||||
case IVL_VT_REAL:
|
||||
return &netreal_t::type_real;
|
||||
case IVL_VT_STRING:
|
||||
return &netstring_t::type_string;
|
||||
default:
|
||||
vec = new netvector_t(packed_dimensions, vt);
|
||||
vec->set_signed(signed_flag);
|
||||
vec->set_isint(isint_flag);
|
||||
return vec;
|
||||
}
|
||||
}
|
||||
87
netmisc.h
87
netmisc.h
|
|
@ -23,6 +23,93 @@
|
|||
|
||||
class netsarray_t;
|
||||
|
||||
/*
|
||||
* Search for a hierarchical name. The input path is one or more name
|
||||
* components (name_component_t) which describe a path to the object. The
|
||||
* simplest case is the path is a single name_component_t. This is the most
|
||||
* usual case. More complex cases might include a string of name components
|
||||
* that end in an item or scope, like this:
|
||||
*
|
||||
* a.b[1].c
|
||||
*
|
||||
* In this case, the "path input would include a.b.c, with index expressions
|
||||
* on name_component_t for "b". In this case, usually "c" is the found item
|
||||
* and "a" and "b" are scopes that lead up to the item.
|
||||
*
|
||||
* The search will stop when it finds a component in the path that is an
|
||||
* object of some sort (other then a scope. So for example, if a.b is an
|
||||
* array, then the search for a.b[1].c will stop at a.b, leave b[1] in
|
||||
* path_item, and "c" in path_tail. It is up to the caller to then note that
|
||||
* "c" must be a method of some sort.
|
||||
*/
|
||||
struct symbol_search_results {
|
||||
inline symbol_search_results() {
|
||||
scope = 0;
|
||||
net = 0;
|
||||
par_val = 0;
|
||||
par_type = 0;
|
||||
eve = 0;
|
||||
}
|
||||
|
||||
inline bool is_scope() const {
|
||||
if (net) return false;
|
||||
if (eve) return false;
|
||||
if (par_val) return false;
|
||||
if (scope) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool is_found() const {
|
||||
if (net) return true;
|
||||
if (eve) return true;
|
||||
if (par_val) return true;
|
||||
if (scope) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Scope where symbol was located. This is set in all cases,
|
||||
// assuming the search succeeded.
|
||||
NetScope*scope;
|
||||
// If this was a net, the signal itself.
|
||||
NetNet*net;
|
||||
// If this was a parameter, the value expression and the
|
||||
// optional value dimensions.
|
||||
const NetExpr*par_val;
|
||||
ivl_type_t par_type;
|
||||
// If this is a named event, ...
|
||||
NetEvent*eve;
|
||||
|
||||
// Store bread crumbs of the search here. The path_tail is the parts of
|
||||
// the original path that were not found, or are after an object (and so
|
||||
// are probably members or methods.)
|
||||
pform_name_t path_tail;
|
||||
// The path_item is the final name (possibly before the path_tail items)
|
||||
// that identifies the object. This name may contain index
|
||||
// expressions. Parts of the path left of the path_item name scopes, and
|
||||
// should have all been resolved into the "scope" member above. If the
|
||||
// search result is a scope, then this path_item is also the name of the
|
||||
// scope identified.
|
||||
name_component_t path_item;
|
||||
};
|
||||
|
||||
/*
|
||||
* Test the search results and return true if this represents a function
|
||||
* return value. That will be the case if the object is a net, the scope
|
||||
* containing the object is a FUNCtion, and the containing scope and the
|
||||
* object have the same name.
|
||||
*/
|
||||
static inline bool test_function_return_value(const symbol_search_results&search_results)
|
||||
{
|
||||
if (!search_results.net) return false;
|
||||
if (search_results.scope->type()!=NetScope::FUNC) return false;
|
||||
if (search_results.net->name() != search_results.scope->basename()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
extern bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
||||
pform_name_t path, struct symbol_search_results*res,
|
||||
NetScope*start_scope = 0);
|
||||
|
||||
/*
|
||||
* Search for a symbol using the "start" scope as the starting
|
||||
* point. If the path includes a scope part, then locate the
|
||||
|
|
|
|||
|
|
@ -59,6 +59,13 @@ class ivl_type_s {
|
|||
virtual bool test_compatibility(ivl_type_t that) const;
|
||||
};
|
||||
|
||||
/*
|
||||
* Convenience functions for making ivl_type_t objects from various inputs.
|
||||
*/
|
||||
extern ivl_type_t make_ivl_type(ivl_variable_type_t vt,
|
||||
const std::vector<netrange_t>&packed_dimensions,
|
||||
bool signed_flag =false, bool isint_flag =false);
|
||||
|
||||
/*
|
||||
* There are a couple types of array types. This class represents the
|
||||
* common bits of array types.
|
||||
|
|
|
|||
|
|
@ -111,9 +111,13 @@ struct index_component_t {
|
|||
};
|
||||
|
||||
struct name_component_t {
|
||||
explicit name_component_t(perm_string n) : name(n) { }
|
||||
inline name_component_t() { }
|
||||
inline explicit name_component_t(perm_string n) : name(n) { }
|
||||
~name_component_t() { }
|
||||
|
||||
// Return true if this component is nil.
|
||||
inline bool empty() const { return name.nil(); }
|
||||
|
||||
perm_string name;
|
||||
std::list<index_component_t>index;
|
||||
};
|
||||
|
|
|
|||
198
symbol_search.cc
198
symbol_search.cc
|
|
@ -20,49 +20,35 @@
|
|||
|
||||
# include "netlist.h"
|
||||
# include "netmisc.h"
|
||||
# include "compiler.h"
|
||||
# include "ivl_assert.h"
|
||||
|
||||
|
||||
/*
|
||||
* Search for the hierarchical name.
|
||||
* Search for the hierarchical name. The path may have multiple components. If
|
||||
* that's the case, then recursively pull the path apart until we find the
|
||||
* first item in the path, look that up, and work our way up. In most cases,
|
||||
* the path will be a string of scopes, with an object at the end. But if we
|
||||
* find an object before the end, then the tail will have to be figured out by
|
||||
* the initial caller.
|
||||
*/
|
||||
struct symbol_search_results {
|
||||
inline symbol_search_results() {
|
||||
scope = 0;
|
||||
net = 0;
|
||||
par_val = 0;
|
||||
par_type = 0;
|
||||
eve = 0;
|
||||
}
|
||||
|
||||
inline bool is_scope() const {
|
||||
if (net) return false;
|
||||
if (eve) return false;
|
||||
if (par_val) return false;
|
||||
if (scope) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Scope where symbol was located. This is set in all cases,
|
||||
// assuming the search succeeded.
|
||||
NetScope*scope;
|
||||
// If this was a net, the signal itself.
|
||||
NetNet*net;
|
||||
// If this was a parameter, the value expression and the
|
||||
// optional value dimensions.
|
||||
const NetExpr*par_val;
|
||||
ivl_type_t par_type;
|
||||
// If this is a named event, ...
|
||||
NetEvent*eve;
|
||||
};
|
||||
|
||||
static bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
||||
bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
||||
pform_name_t path, struct symbol_search_results*res,
|
||||
NetScope*start_scope = 0)
|
||||
NetScope*start_scope)
|
||||
{
|
||||
assert(scope);
|
||||
bool prefix_scope = false;
|
||||
bool recurse_flag = false;
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << li->get_fileline() << ": symbol_search: "
|
||||
<< "scope: " << scope_path(scope) << endl;
|
||||
cerr << li->get_fileline() << ": symbol_search: "
|
||||
<< "path: " << path << endl;
|
||||
if (start_scope)
|
||||
cerr << li->get_fileline() << ": symbol_search: "
|
||||
<< "start_scope: " << scope_path(start_scope) << endl;
|
||||
}
|
||||
|
||||
assert(li);
|
||||
ivl_assert(*li, ! path.empty());
|
||||
|
|
@ -74,38 +60,72 @@ static bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
|||
// recurse_flag to true if this is a recurse.
|
||||
if (start_scope==0)
|
||||
start_scope = scope;
|
||||
else
|
||||
recurse_flag = true;
|
||||
|
||||
// If there are components ahead of the tail, symbol_search
|
||||
// recursively. Ideally, the result is a scope that we search
|
||||
// for the tail key, but there are other special cases as well.
|
||||
if (! path.empty()) {
|
||||
symbol_search_results recurse;
|
||||
bool flag = symbol_search(li, des, scope, path, &recurse, start_scope);
|
||||
bool flag = symbol_search(li, des, scope, path, res, start_scope);
|
||||
if (! flag)
|
||||
return false;
|
||||
|
||||
// The prefix is found to be something besides a scope. Put the
|
||||
// tail into the path_tail of the result, and return success. The
|
||||
// caller needs to deal with that tail bit. Note that the
|
||||
// path_tail is a single item, but we might have been called
|
||||
// recursively, so the complete tail will be built up as we unwind.
|
||||
if (res->is_found() && !res->is_scope()) {
|
||||
if (!path_tail.empty())
|
||||
res->path_tail.push_back(path_tail);
|
||||
return true;
|
||||
}
|
||||
|
||||
// The prefix is found to be a scope, so switch to that
|
||||
// scope, set the hier_path to turn off upwards searches,
|
||||
// and continue our search for the tail.
|
||||
if (recurse.is_scope()) {
|
||||
scope = recurse.scope;
|
||||
if (res->is_scope()) {
|
||||
scope = res->scope;
|
||||
prefix_scope = true;
|
||||
|
||||
if (debug_scopes || debug_elaborate) {
|
||||
cerr << li->get_fileline() << ": symbol_search: "
|
||||
<< "Prefix scope " << scope_path(scope) << endl;
|
||||
}
|
||||
|
||||
if (scope->is_auto()) {
|
||||
cerr << li->get_fileline() << ": error: Hierarchical "
|
||||
"reference to automatically allocated item "
|
||||
"`" << path_tail.name << "' in path `" << path << "'" << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Prefix is present, but is NOT a scope. Fail!
|
||||
// Prefix is present, but is NOT a scope. Fail! Actually, this
|
||||
// should not happen, since this is the "not found" case, and we
|
||||
// should have returned already.
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool passed_module_boundary = false;
|
||||
|
||||
// At this point, we've stripped right-most components until the search
|
||||
// found the scope part of the path, or there is no scope part of the
|
||||
// path. For example, if the path in was s1.s2.x, we found the scope
|
||||
// s1.s2, res->is_scope() is true, and path_tail is x. We look for x
|
||||
// now. The preceeding code set prefix_scope=true to ease our test below.
|
||||
//
|
||||
// If the input was x (without prefixes) then we don't know if x is a
|
||||
// scope or item. In this case, res->is_found() is false and we may need
|
||||
// to scan upwards to find the scope or item.
|
||||
while (scope) {
|
||||
if (debug_scopes || debug_elaborate) {
|
||||
cerr << li->get_fileline() << ": symbol_search: "
|
||||
<< "Looking for " << path_tail
|
||||
<< " in scope " << scope_path(scope)
|
||||
<< " prefix_scope=" << prefix_scope << endl;
|
||||
}
|
||||
if (scope->genvar_tmp.str() && path_tail.name == scope->genvar_tmp)
|
||||
return false;
|
||||
|
||||
|
|
@ -115,36 +135,64 @@ static bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
|||
return false;
|
||||
}
|
||||
|
||||
// These items cannot be seen outside the bounding module where
|
||||
// the search starts. But we continue searching up because scope
|
||||
// names can match. For example:
|
||||
//
|
||||
// module top;
|
||||
// int not_ok;
|
||||
// dut foo(...);
|
||||
// endmodule
|
||||
// module dut;
|
||||
// ... not_ok; // <-- Should NOT match.
|
||||
// ... top.not_ok; // Matches.
|
||||
// endmodule
|
||||
if (!passed_module_boundary) {
|
||||
if (NetNet*net = scope->find_signal(path_tail.name)) {
|
||||
res->scope = scope;
|
||||
res->net = net;
|
||||
res->path_item = path_tail;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NetEvent*eve = scope->find_event(path_tail.name)) {
|
||||
res->scope = scope;
|
||||
res->eve = eve;
|
||||
res->path_item = path_tail;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (const NetExpr*par = scope->get_parameter(des, path_tail.name, res->par_type)) {
|
||||
res->scope = scope;
|
||||
res->par_val = par;
|
||||
res->path_item = path_tail;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (NetScope*import_scope = scope->find_import(des, path_tail.name)) {
|
||||
scope = import_scope;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (recurse_flag) {
|
||||
// Could not find an object. Maybe this is a child scope name? If
|
||||
// so, evaluate the path conponents to find the exact scope this
|
||||
// refers to. This item might be:
|
||||
// <scope>.s
|
||||
// <scope>.s[n]
|
||||
// etc. The scope->child_byname tests if the name exists, and if
|
||||
// it does, the eval_path_component() evaluates any [n]
|
||||
// expressions to constants to generate an hname_t object for a
|
||||
// more complete scope name search. Note that the index
|
||||
// expressions for scope names must be constant.
|
||||
if (scope->child_byname(path_tail.name)) {
|
||||
bool flag = false;
|
||||
hname_t path_item = eval_path_component(des, start_scope, path_tail, flag);
|
||||
if (flag) {
|
||||
cerr << li->get_fileline() << ": XXXXX: Errors evaluating scope index" << endl;
|
||||
} else if (NetScope*chld = des->find_scope(scope, path_item)) {
|
||||
} else if (NetScope*chld = scope->child(path_item)) {
|
||||
res->scope = chld;
|
||||
res->path_item = path_tail;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -153,19 +201,56 @@ static bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
|||
if (prefix_scope)
|
||||
break;
|
||||
|
||||
// Don't scan up past a module boundary.
|
||||
// Special case: We can match the module name of a parent
|
||||
// module. That means if the current scope is a module of type
|
||||
// "mod", then "mod" matches the current scope. This is fairly
|
||||
// obscure, but looks like this:
|
||||
//
|
||||
// module foo;
|
||||
// reg x;
|
||||
// ... foo.x; // This matches x in myself.
|
||||
// endmodule
|
||||
//
|
||||
// This feature recurses, so code in subscopes of foo can refer to
|
||||
// foo by the name "foo" as well. In general, anything within
|
||||
// "foo" can use the name "foo" to reference it.
|
||||
if (scope->type()==NetScope::MODULE && scope->module_name()==path_tail.name) {
|
||||
res->scope = scope;
|
||||
res->path_item = path_tail;
|
||||
return true;
|
||||
}
|
||||
|
||||
// If there is no prefix, then we are free to scan upwards looking
|
||||
// for a scope name. Note that only scopes can be searched for up
|
||||
// past module boundaries. To handle that, set a flag to indicate
|
||||
// that we passed a module boundary on the way up.
|
||||
if (scope->type()==NetScope::MODULE && !scope->nested_module())
|
||||
scope = 0;
|
||||
else
|
||||
passed_module_boundary = true;
|
||||
|
||||
scope = scope->parent();
|
||||
|
||||
// Last chance - try the compilation unit.
|
||||
// Last chance - try the compilation unit. Note that modules may
|
||||
// reference nets/variables in the compilation unit, even if they
|
||||
// cannot reference variables in containing scope.
|
||||
//
|
||||
// int ok = 1;
|
||||
// module top;
|
||||
// int not_ok = 2;
|
||||
// dut foo();
|
||||
// endmodule
|
||||
//
|
||||
// module dut;
|
||||
// ... = ok; // This reference is OK
|
||||
// ... = not_ok; // This reference is NOT OK.
|
||||
// endmodule
|
||||
if (scope == 0 && start_scope != 0) {
|
||||
scope = start_scope->unit();
|
||||
start_scope = 0;
|
||||
passed_module_boundary = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Last chance: this is a single name, so it might be the name
|
||||
// of a root scope. Ask the design if this is a root
|
||||
// scope. This is only possible if there is no prefix.
|
||||
|
|
@ -174,6 +259,7 @@ static bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
|||
scope = des->find_scope(path_item);
|
||||
if (scope) {
|
||||
res->scope = scope;
|
||||
res->path_item = path_tail;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -193,6 +279,23 @@ NetScope*symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
|||
{
|
||||
symbol_search_results recurse;
|
||||
bool flag = symbol_search(li, des, scope, path, &recurse);
|
||||
|
||||
net = 0;
|
||||
par = 0;
|
||||
par_type = 0;
|
||||
eve = 0;
|
||||
|
||||
// The compatible version doesn't know how to handle unmatched tail
|
||||
// components, so report them as errors.
|
||||
if (! recurse.path_tail.empty()) {
|
||||
if (debug_elaborate) {
|
||||
cerr << li->get_fileline() << ": symbol_search (compat): "
|
||||
<< "path_tail items found: " << recurse.path_tail << endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Convert the extended results to the compatible results.
|
||||
net = recurse.net;
|
||||
par = recurse.par_val;
|
||||
par_type = recurse.par_type;
|
||||
|
|
@ -201,8 +304,5 @@ NetScope*symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (recurse.is_scope())
|
||||
return recurse.scope;
|
||||
|
||||
return recurse.scope;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue