197 lines
5.6 KiB
C++
197 lines
5.6 KiB
C++
/*
|
|
* Copyright (c) 2003-2015 Stephen Williams (steve@icarus.com)
|
|
* Copyright CERN 2012 / 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 "netlist.h"
|
|
# include "netmisc.h"
|
|
# include "ivl_assert.h"
|
|
|
|
|
|
/*
|
|
* Search for the hierarchical name.
|
|
*/
|
|
struct symbol_search_results {
|
|
inline symbol_search_results() {
|
|
scope = 0;
|
|
net = 0;
|
|
par_val = 0;
|
|
par_msb = 0;
|
|
par_lsb = 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;
|
|
const NetExpr*par_msb;
|
|
const NetExpr*par_lsb;
|
|
// If this is a named event, ...
|
|
NetEvent*eve;
|
|
};
|
|
|
|
static bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
|
pform_name_t path, struct symbol_search_results*res,
|
|
NetScope*start_scope = 0)
|
|
{
|
|
assert(scope);
|
|
bool prefix_scope = false;
|
|
bool recurse_flag = false;
|
|
|
|
assert(li);
|
|
ivl_assert(*li, ! path.empty());
|
|
name_component_t path_tail = path.back();
|
|
path.pop_back();
|
|
|
|
// If this is a recursive call, then we need to know that so
|
|
// that we can enable the search for scopes. Set the
|
|
// 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);
|
|
if (! flag)
|
|
return false;
|
|
|
|
// 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;
|
|
prefix_scope = true;
|
|
|
|
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!
|
|
return false;
|
|
}
|
|
}
|
|
|
|
while (scope) {
|
|
if (path_tail.name == "#") {
|
|
cerr << li->get_fileline() << ": sorry: "
|
|
<< "Implicit class handle \"super\" not supported." << endl;
|
|
return false;
|
|
}
|
|
|
|
if (NetNet*net = scope->find_signal(path_tail.name)) {
|
|
res->scope = scope;
|
|
res->net = net;
|
|
return true;
|
|
}
|
|
|
|
if (NetEvent*eve = scope->find_event(path_tail.name)) {
|
|
res->scope = scope;
|
|
res->eve = eve;
|
|
return true;
|
|
}
|
|
|
|
if (const NetExpr*par = scope->get_parameter(des, path_tail.name, res->par_msb, res->par_lsb)) {
|
|
res->scope = scope;
|
|
res->par_val = par;
|
|
return true;
|
|
}
|
|
|
|
if (recurse_flag) {
|
|
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)) {
|
|
res->scope = chld;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Don't scan up past a module boundary.
|
|
if (scope->type()==NetScope::MODULE && !scope->nested_module())
|
|
break;
|
|
// Don't scan up if we are searching within a prefixed scope.
|
|
if (prefix_scope)
|
|
break;
|
|
|
|
scope = scope->parent();
|
|
}
|
|
|
|
// 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.
|
|
if (prefix_scope==false) {
|
|
hname_t path_item (path_tail.name);
|
|
scope = des->find_scope(path_item);
|
|
if (scope) {
|
|
res->scope = scope;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* Compatibility version. Remove me!
|
|
*/
|
|
NetScope*symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
|
pform_name_t path,
|
|
NetNet*&net,
|
|
const NetExpr*&par,
|
|
NetEvent*&eve,
|
|
const NetExpr*&ex1, const NetExpr*&ex2)
|
|
{
|
|
symbol_search_results recurse;
|
|
bool flag = symbol_search(li, des, scope, path, &recurse);
|
|
net = recurse.net;
|
|
par = recurse.par_val;
|
|
ex1 = recurse.par_msb;
|
|
ex2 = recurse.par_lsb;
|
|
eve = recurse.eve;
|
|
if (! flag) {
|
|
return 0;
|
|
}
|
|
|
|
if (recurse.is_scope())
|
|
return recurse.scope;
|
|
|
|
return recurse.scope;
|
|
}
|