2000-03-08 05:36:53 +01:00
|
|
|
/*
|
2022-12-28 08:59:39 +01:00
|
|
|
* Copyright (c) 2000-2022 Stephen Williams (steve@icarus.com)
|
2000-03-08 05:36:53 +01:00
|
|
|
*
|
|
|
|
|
* 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
|
2012-08-29 03:41:23 +02:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2000-03-08 05:36:53 +01:00
|
|
|
*/
|
|
|
|
|
|
2001-07-25 05:10:48 +02:00
|
|
|
# include "config.h"
|
|
|
|
|
|
|
|
|
|
# include <iostream>
|
2008-06-30 03:46:46 +02:00
|
|
|
# include <set>
|
2008-05-19 17:26:56 +02:00
|
|
|
# include <cstdlib>
|
2001-07-25 05:10:48 +02:00
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
/*
|
|
|
|
|
* This source file contains all the implementations of the Design
|
|
|
|
|
* class declared in netlist.h.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
# include "netlist.h"
|
2020-12-25 03:12:06 +01:00
|
|
|
# include "netscalar.h"
|
|
|
|
|
# include "netvector.h"
|
2000-04-28 18:50:53 +02:00
|
|
|
# include "util.h"
|
2004-02-20 07:22:56 +01:00
|
|
|
# include "compiler.h"
|
2007-06-02 05:42:12 +02:00
|
|
|
# include "netmisc.h"
|
2010-12-05 22:28:17 +01:00
|
|
|
# include "PExpr.h"
|
2011-04-05 21:43:54 +02:00
|
|
|
# include "PTask.h"
|
2003-01-14 22:16:18 +01:00
|
|
|
# include <sstream>
|
2008-05-14 06:56:57 +02:00
|
|
|
# include "ivl_assert.h"
|
2000-03-08 05:36:53 +01:00
|
|
|
|
2021-11-04 17:12:04 +01:00
|
|
|
using namespace std;
|
|
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
Design:: Design()
|
2008-11-10 06:42:12 +01:00
|
|
|
: errors(0), nodes_(0), procs_(0), aprocs_(0)
|
2000-03-08 05:36:53 +01:00
|
|
|
{
|
2008-11-10 02:11:04 +01:00
|
|
|
branches_ = 0;
|
2000-07-16 06:56:07 +02:00
|
|
|
procs_idx_ = 0;
|
2000-07-23 00:09:03 +02:00
|
|
|
des_precision_ = 0;
|
2002-08-16 07:18:27 +02:00
|
|
|
nodes_functor_cur_ = 0;
|
|
|
|
|
nodes_functor_nxt_ = 0;
|
2010-07-24 00:58:00 +02:00
|
|
|
des_delay_sel_ = Design::TYP;
|
2000-03-08 05:36:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Design::~Design()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2000-07-23 00:09:03 +02:00
|
|
|
void Design::set_precision(int val)
|
|
|
|
|
{
|
|
|
|
|
if (val < des_precision_)
|
|
|
|
|
des_precision_ = val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int Design::get_precision() const
|
|
|
|
|
{
|
|
|
|
|
return des_precision_;
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-14 05:22:45 +01:00
|
|
|
void Design::set_delay_sel(delay_sel_t sel)
|
|
|
|
|
{
|
|
|
|
|
des_delay_sel_ = sel;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* Design::get_delay_sel() const
|
|
|
|
|
{
|
|
|
|
|
switch (des_delay_sel_) {
|
|
|
|
|
case Design::MIN:
|
|
|
|
|
return "MINIMUM";
|
|
|
|
|
break;
|
|
|
|
|
case Design::TYP:
|
|
|
|
|
return "TYPICAL";
|
|
|
|
|
break;
|
|
|
|
|
case Design::MAX:
|
|
|
|
|
return "MAXIMUM";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
return "TYPICAL";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2006-08-08 07:11:37 +02:00
|
|
|
uint64_t Design::scale_to_precision(uint64_t val,
|
|
|
|
|
const NetScope*scope) const
|
2000-07-23 00:09:03 +02:00
|
|
|
{
|
|
|
|
|
int units = scope->time_unit();
|
2000-07-23 04:41:32 +02:00
|
|
|
assert( units >= des_precision_ );
|
2000-07-23 00:09:03 +02:00
|
|
|
|
|
|
|
|
while (units > des_precision_) {
|
|
|
|
|
units -= 1;
|
|
|
|
|
val *= 10;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-21 16:04:25 +02:00
|
|
|
NetScope* Design::make_root_scope(perm_string root, NetScope*unit_scope,
|
|
|
|
|
bool program_block, bool is_interface)
|
2000-03-08 05:36:53 +01:00
|
|
|
{
|
2001-10-19 23:53:24 +02:00
|
|
|
NetScope *root_scope_;
|
2017-10-21 16:04:25 +02:00
|
|
|
root_scope_ = new NetScope(0, hname_t(root), NetScope::MODULE, unit_scope,
|
2014-12-20 00:10:14 +01:00
|
|
|
false, program_block, is_interface);
|
2003-03-06 05:37:12 +01:00
|
|
|
/* This relies on the fact that the basename return value is
|
|
|
|
|
permallocated. */
|
|
|
|
|
root_scope_->set_module_name(root_scope_->basename());
|
2001-10-19 23:53:24 +02:00
|
|
|
root_scopes_.push_back(root_scope_);
|
2000-03-08 05:36:53 +01:00
|
|
|
return root_scope_;
|
|
|
|
|
}
|
|
|
|
|
|
2000-05-02 02:58:11 +02:00
|
|
|
NetScope* Design::find_root_scope()
|
|
|
|
|
{
|
2001-10-19 23:53:24 +02:00
|
|
|
assert(root_scopes_.front());
|
|
|
|
|
return root_scopes_.front();
|
2000-05-02 02:58:11 +02:00
|
|
|
}
|
2000-03-08 05:36:53 +01:00
|
|
|
|
2013-02-17 23:42:07 +01:00
|
|
|
list<NetScope*> Design::find_root_scopes() const
|
2001-10-19 23:53:24 +02:00
|
|
|
{
|
|
|
|
|
return root_scopes_;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-21 16:04:25 +02:00
|
|
|
NetScope* Design::make_package_scope(perm_string name, NetScope*unit_scope,
|
|
|
|
|
bool is_unit)
|
2001-10-19 23:53:24 +02:00
|
|
|
{
|
2013-02-17 23:42:07 +01:00
|
|
|
NetScope*scope;
|
|
|
|
|
|
2017-10-21 16:04:25 +02:00
|
|
|
scope = new NetScope(0, hname_t(name), NetScope::PACKAGE, unit_scope,
|
|
|
|
|
false, false, false, is_unit);
|
2013-02-17 23:42:07 +01:00
|
|
|
scope->set_module_name(scope->basename());
|
|
|
|
|
packages_[name] = scope;
|
|
|
|
|
return scope;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetScope* Design::find_package(perm_string name) const
|
|
|
|
|
{
|
|
|
|
|
map<perm_string,NetScope*>::const_iterator cur = packages_.find(name);
|
|
|
|
|
if (cur == packages_.end())
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return cur->second;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
list<NetScope*> Design::find_package_scopes() const
|
|
|
|
|
{
|
|
|
|
|
list<NetScope*>res;
|
|
|
|
|
for (map<perm_string,NetScope*>::const_iterator cur = packages_.begin()
|
|
|
|
|
; cur != packages_.end() ; ++cur) {
|
|
|
|
|
res.push_back (cur->second);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
2000-08-26 02:54:03 +02:00
|
|
|
}
|
|
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
/*
|
|
|
|
|
* This method locates a scope in the design, given its rooted
|
2003-01-27 06:09:17 +01:00
|
|
|
* hierarchical name. Each component of the key is used to scan one
|
2000-03-08 05:36:53 +01:00
|
|
|
* more step down the tree until the name runs out or the search
|
|
|
|
|
* fails.
|
|
|
|
|
*/
|
2007-06-02 05:42:12 +02:00
|
|
|
NetScope* Design::find_scope(const std::list<hname_t>&path) const
|
2000-03-08 05:36:53 +01:00
|
|
|
{
|
2007-05-24 06:07:11 +02:00
|
|
|
if (path.empty())
|
2002-06-25 04:39:34 +02:00
|
|
|
return 0;
|
|
|
|
|
|
2001-12-03 05:47:14 +01:00
|
|
|
for (list<NetScope*>::const_iterator scope = root_scopes_.begin()
|
2010-10-23 23:57:59 +02:00
|
|
|
; scope != root_scopes_.end(); ++ scope ) {
|
2000-03-08 05:36:53 +01:00
|
|
|
|
2001-10-19 23:53:24 +02:00
|
|
|
NetScope*cur = *scope;
|
2007-06-02 05:42:12 +02:00
|
|
|
if (path.front() != cur->fullname())
|
2001-10-19 23:53:24 +02:00
|
|
|
continue;
|
2000-03-08 05:36:53 +01:00
|
|
|
|
2007-06-02 05:42:12 +02:00
|
|
|
std::list<hname_t> tmp = path;
|
2007-05-24 06:07:11 +02:00
|
|
|
tmp.pop_front();
|
|
|
|
|
|
2001-10-19 23:53:24 +02:00
|
|
|
while (cur) {
|
2007-05-24 06:07:11 +02:00
|
|
|
if (tmp.empty()) return cur;
|
2001-12-03 05:47:14 +01:00
|
|
|
|
2007-06-02 05:42:12 +02:00
|
|
|
cur = cur->child( tmp.front() );
|
2007-05-24 06:07:11 +02:00
|
|
|
|
|
|
|
|
tmp.pop_front();
|
2001-10-19 23:53:24 +02:00
|
|
|
}
|
2014-10-01 01:06:32 +02:00
|
|
|
}
|
|
|
|
|
|
2001-10-19 23:53:24 +02:00
|
|
|
return 0;
|
2000-03-08 05:36:53 +01:00
|
|
|
}
|
|
|
|
|
|
2012-08-26 05:12:30 +02:00
|
|
|
/*
|
|
|
|
|
* This method locates a scope in the design, given its rooted
|
|
|
|
|
* hierarchical name. Each component of the key is used to scan one
|
|
|
|
|
* more step down the tree until the name runs out or the search
|
|
|
|
|
* fails.
|
|
|
|
|
*/
|
|
|
|
|
NetScope* Design::find_scope(const hname_t&path) const
|
|
|
|
|
{
|
|
|
|
|
for (list<NetScope*>::const_iterator scope = root_scopes_.begin()
|
|
|
|
|
; scope != root_scopes_.end(); ++ scope ) {
|
|
|
|
|
|
|
|
|
|
NetScope*cur = *scope;
|
|
|
|
|
if (path.peek_name() == cur->basename())
|
|
|
|
|
return cur;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-21 16:04:25 +02:00
|
|
|
static bool is_design_unit(NetScope*scope)
|
|
|
|
|
{
|
|
|
|
|
return (scope->type() == NetScope::MODULE && !scope->nested_module())
|
|
|
|
|
|| (scope->type() == NetScope::PACKAGE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool is_subroutine(NetScope::TYPE type)
|
|
|
|
|
{
|
|
|
|
|
return type == NetScope::TASK || type == NetScope::FUNC;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This method locates a scope within another scope, given its relative
|
|
|
|
|
* hierarchical name. Each component of the key is used to scan one
|
|
|
|
|
* more step down the tree until the name runs out or the search
|
|
|
|
|
* fails.
|
|
|
|
|
*/
|
|
|
|
|
NetScope* Design::find_scope_(NetScope*scope, const std::list<hname_t>&path,
|
|
|
|
|
NetScope::TYPE type) const
|
|
|
|
|
{
|
|
|
|
|
std::list<hname_t> tmp = path;
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
hname_t key = tmp.front();
|
|
|
|
|
/* If we are looking for a module or we are not
|
|
|
|
|
* looking at the last path component check for
|
|
|
|
|
* a name match (second line). */
|
|
|
|
|
if (scope->type() == NetScope::MODULE
|
|
|
|
|
&& (type == NetScope::MODULE || tmp.size() > 1)
|
|
|
|
|
&& scope->module_name()==key.peek_name()) {
|
|
|
|
|
|
|
|
|
|
/* Up references may match module name */
|
|
|
|
|
|
|
|
|
|
} else {
|
2019-09-22 00:09:48 +02:00
|
|
|
NetScope*found_scope = scope->child(key);
|
|
|
|
|
if (found_scope == 0) {
|
|
|
|
|
found_scope = scope->find_import(this, key.peek_name());
|
|
|
|
|
if (found_scope)
|
|
|
|
|
found_scope = found_scope->child(key);
|
|
|
|
|
}
|
|
|
|
|
scope = found_scope;
|
2017-10-21 16:04:25 +02:00
|
|
|
if (scope == 0) break;
|
|
|
|
|
}
|
|
|
|
|
tmp.pop_front();
|
|
|
|
|
} while (! tmp.empty());
|
|
|
|
|
|
|
|
|
|
return scope;
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-10 07:20:48 +01:00
|
|
|
/*
|
|
|
|
|
* This is a relative lookup of a scope by name. The starting point is
|
2007-05-24 06:07:11 +02:00
|
|
|
* the scope parameter within which I start looking for the scope. If
|
|
|
|
|
* I do not find the scope within the passed scope, start looking in
|
|
|
|
|
* parent scopes until I find it, or I run out of parent scopes.
|
2000-03-10 07:20:48 +01:00
|
|
|
*/
|
2007-12-08 00:10:13 +01:00
|
|
|
NetScope* Design::find_scope(NetScope*scope, const std::list<hname_t>&path,
|
|
|
|
|
NetScope::TYPE type) const
|
2000-03-10 07:20:48 +01:00
|
|
|
{
|
|
|
|
|
assert(scope);
|
2007-05-24 06:07:11 +02:00
|
|
|
if (path.empty())
|
2002-06-25 04:39:34 +02:00
|
|
|
return scope;
|
2000-03-10 07:20:48 +01:00
|
|
|
|
2017-10-21 16:04:25 +02:00
|
|
|
// Record the compilation unit scope for use later.
|
|
|
|
|
NetScope*unit_scope = scope->unit();
|
2007-05-24 06:07:11 +02:00
|
|
|
|
2017-10-21 16:04:25 +02:00
|
|
|
// First search upwards through the hierarchy.
|
|
|
|
|
while (scope) {
|
|
|
|
|
NetScope*found_scope = find_scope_(scope, path, type);
|
|
|
|
|
if (found_scope)
|
|
|
|
|
return found_scope;
|
2000-03-10 07:20:48 +01:00
|
|
|
|
2017-10-21 16:04:25 +02:00
|
|
|
// Avoid searching the unit scope twice.
|
|
|
|
|
if (scope == unit_scope)
|
|
|
|
|
unit_scope = 0;
|
|
|
|
|
|
|
|
|
|
// Special case - see IEEE 1800-2012 section 23.8.1.
|
|
|
|
|
if (unit_scope && is_design_unit(scope) && is_subroutine(type)) {
|
|
|
|
|
found_scope = find_scope_(unit_scope, path, type);
|
|
|
|
|
if (found_scope)
|
|
|
|
|
return found_scope;
|
|
|
|
|
|
|
|
|
|
unit_scope = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
scope = scope->parent();
|
|
|
|
|
}
|
2000-03-10 07:20:48 +01:00
|
|
|
|
2017-10-21 16:04:25 +02:00
|
|
|
// If we haven't already done so, search the compilation unit scope.
|
|
|
|
|
if (unit_scope) {
|
|
|
|
|
NetScope*found_scope = find_scope_(unit_scope, path, type);
|
|
|
|
|
if (found_scope)
|
|
|
|
|
return found_scope;
|
2000-03-10 07:20:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Last chance. Look for the name starting at the root.
|
2001-12-03 05:47:14 +01:00
|
|
|
return find_scope(path);
|
2000-03-10 07:20:48 +01:00
|
|
|
}
|
|
|
|
|
|
2017-10-21 16:04:25 +02:00
|
|
|
/*
|
|
|
|
|
* This method locates a scope within another scope, given its relative
|
|
|
|
|
* hierarchical name. Each component of the key is used to scan one
|
|
|
|
|
* more step down the tree until the name runs out or the search
|
|
|
|
|
* fails.
|
|
|
|
|
*/
|
|
|
|
|
NetScope* Design::find_scope_(NetScope*scope, const hname_t&path,
|
|
|
|
|
NetScope::TYPE type) const
|
|
|
|
|
{
|
|
|
|
|
/* If we are looking for a module or we are not
|
|
|
|
|
* looking at the last path component check for
|
|
|
|
|
* a name match (second line). */
|
|
|
|
|
if ((scope->type() == NetScope::MODULE) && (type == NetScope::MODULE)
|
|
|
|
|
&& (scope->module_name() == path.peek_name())) {
|
|
|
|
|
/* Up references may match module name */
|
|
|
|
|
return scope;
|
|
|
|
|
}
|
2019-09-22 00:09:48 +02:00
|
|
|
NetScope*found_scope = scope->child(path);
|
|
|
|
|
if (found_scope == 0) {
|
|
|
|
|
found_scope = scope->find_import(this, path.peek_name());
|
|
|
|
|
if (found_scope)
|
|
|
|
|
found_scope = found_scope->child(path);
|
|
|
|
|
}
|
|
|
|
|
return found_scope;
|
2017-10-21 16:04:25 +02:00
|
|
|
}
|
|
|
|
|
|
2012-08-26 05:12:30 +02:00
|
|
|
/*
|
|
|
|
|
* This is a relative lookup of a scope by name. The starting point is
|
|
|
|
|
* the scope parameter within which I start looking for the scope. If
|
|
|
|
|
* I do not find the scope within the passed scope, start looking in
|
|
|
|
|
* parent scopes until I find it, or I run out of parent scopes.
|
|
|
|
|
*/
|
|
|
|
|
NetScope* Design::find_scope(NetScope*scope, const hname_t&path,
|
|
|
|
|
NetScope::TYPE type) const
|
|
|
|
|
{
|
|
|
|
|
assert(scope);
|
|
|
|
|
|
2017-10-21 16:04:25 +02:00
|
|
|
// Record the compilation unit scope for use later.
|
|
|
|
|
NetScope*unit_scope = scope->unit();
|
2012-08-26 05:12:30 +02:00
|
|
|
|
2017-10-21 16:04:25 +02:00
|
|
|
// First search upwards through the hierarchy.
|
|
|
|
|
while (scope) {
|
|
|
|
|
NetScope*found_scope = find_scope_(scope, path, type);
|
|
|
|
|
if (found_scope)
|
|
|
|
|
return found_scope;
|
2012-08-26 05:12:30 +02:00
|
|
|
|
2017-10-21 16:04:25 +02:00
|
|
|
// Avoid searching the unit scope twice.
|
|
|
|
|
if (scope == unit_scope)
|
|
|
|
|
unit_scope = 0;
|
2012-08-26 05:12:30 +02:00
|
|
|
|
2017-10-21 16:04:25 +02:00
|
|
|
// Special case - see IEEE 1800-2012 section 23.8.1.
|
|
|
|
|
if (unit_scope && is_design_unit(scope) && is_subroutine(type)) {
|
|
|
|
|
found_scope = find_scope_(unit_scope, path, type);
|
|
|
|
|
if (found_scope)
|
|
|
|
|
return found_scope;
|
2012-08-26 05:12:30 +02:00
|
|
|
|
2017-10-21 16:04:25 +02:00
|
|
|
unit_scope = 0;
|
2012-08-26 05:12:30 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-21 16:04:25 +02:00
|
|
|
scope = scope->parent();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we haven't already done so, search the compilation unit scope.
|
|
|
|
|
if (unit_scope) {
|
|
|
|
|
NetScope*found_scope = find_scope_(unit_scope, path, type);
|
|
|
|
|
if (found_scope)
|
|
|
|
|
return found_scope;
|
2012-08-26 05:12:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Last chance. Look for the name starting at the root.
|
|
|
|
|
list<hname_t>path_list;
|
|
|
|
|
path_list.push_back(path);
|
|
|
|
|
return find_scope(path_list);
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
/*
|
|
|
|
|
* This method runs through the scope, noticing the defparam
|
|
|
|
|
* statements that were collected during the elaborate_scope pass and
|
|
|
|
|
* applying them to the target parameters. The implementation actually
|
|
|
|
|
* works by using a specialized method from the NetScope class that
|
|
|
|
|
* does all the work for me.
|
|
|
|
|
*/
|
|
|
|
|
void Design::run_defparams()
|
|
|
|
|
{
|
2004-10-04 03:10:51 +02:00
|
|
|
for (list<NetScope*>::const_iterator scope = root_scopes_.begin();
|
2010-10-23 23:57:59 +02:00
|
|
|
scope != root_scopes_.end(); ++ scope )
|
2001-10-19 23:53:24 +02:00
|
|
|
(*scope)->run_defparams(this);
|
2000-03-08 05:36:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NetScope::run_defparams(Design*des)
|
|
|
|
|
{
|
2009-12-09 00:14:55 +01:00
|
|
|
for (map<hname_t,NetScope*>::const_iterator cur = children_.begin()
|
2010-10-23 23:57:59 +02:00
|
|
|
; cur != children_.end() ; ++ cur )
|
2009-12-09 00:14:55 +01:00
|
|
|
cur->second->run_defparams(des);
|
2000-03-08 05:36:53 +01:00
|
|
|
|
2008-06-26 07:02:22 +02:00
|
|
|
while (! defparams.empty()) {
|
2010-12-05 22:28:17 +01:00
|
|
|
pair<pform_name_t,PExpr*> pp = defparams.front();
|
2008-06-26 07:02:22 +02:00
|
|
|
defparams.pop_front();
|
|
|
|
|
|
|
|
|
|
pform_name_t path = pp.first;
|
2010-12-05 22:28:17 +01:00
|
|
|
PExpr*val = pp.second;
|
2001-12-03 05:47:14 +01:00
|
|
|
|
2007-05-24 06:07:11 +02:00
|
|
|
perm_string perm_name = peek_tail_name(path);
|
|
|
|
|
path.pop_back();
|
2000-03-08 05:36:53 +01:00
|
|
|
|
2007-06-02 05:42:12 +02:00
|
|
|
list<hname_t> eval_path = eval_scope_path(des, this, path);
|
|
|
|
|
|
2002-06-25 04:39:34 +02:00
|
|
|
/* If there is no path on the name, then the targ_scope
|
|
|
|
|
is the current scope. */
|
2007-06-02 05:42:12 +02:00
|
|
|
NetScope*targ_scope = des->find_scope(this, eval_path);
|
2000-03-08 05:36:53 +01:00
|
|
|
if (targ_scope == 0) {
|
2008-06-26 07:02:22 +02:00
|
|
|
|
|
|
|
|
// Push the defparam onto a list for retry
|
|
|
|
|
// later. It is possible for the scope lookup to
|
|
|
|
|
// fail if the scope being defparam'd into is
|
|
|
|
|
// generated by an index array for generate.
|
|
|
|
|
eval_path.push_back(hname_t(perm_name));
|
|
|
|
|
defparams_later.push_back(make_pair(eval_path,val));
|
2000-03-08 05:36:53 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-20 17:00:24 +01:00
|
|
|
targ_scope->replace_parameter(des, perm_name, val, this, true);
|
2000-03-08 05:36:53 +01:00
|
|
|
}
|
2008-06-30 03:46:46 +02:00
|
|
|
|
|
|
|
|
// If some of the defparams didn't find a scope in the name,
|
|
|
|
|
// then try again later. It may be that the target scope is
|
|
|
|
|
// created later by generate scheme or instance array.
|
|
|
|
|
if (! defparams_later.empty())
|
|
|
|
|
des->defparams_later.insert(this);
|
2008-06-26 07:02:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NetScope::run_defparams_later(Design*des)
|
|
|
|
|
{
|
2008-06-30 03:46:46 +02:00
|
|
|
set<NetScope*> target_scopes;
|
2010-12-05 22:28:17 +01:00
|
|
|
list<pair<list<hname_t>,PExpr*> > defparams_even_later;
|
2008-06-30 03:46:46 +02:00
|
|
|
|
2008-06-26 07:02:22 +02:00
|
|
|
while (! defparams_later.empty()) {
|
2010-12-05 22:28:17 +01:00
|
|
|
pair<list<hname_t>,PExpr*> cur = defparams_later.front();
|
2008-06-26 07:02:22 +02:00
|
|
|
defparams_later.pop_front();
|
|
|
|
|
|
|
|
|
|
list<hname_t>eval_path = cur.first;
|
|
|
|
|
perm_string name = eval_path.back().peek_name();
|
|
|
|
|
eval_path.pop_back();
|
|
|
|
|
|
2010-12-05 22:28:17 +01:00
|
|
|
PExpr*val = cur.second;
|
2008-06-26 07:02:22 +02:00
|
|
|
|
|
|
|
|
NetScope*targ_scope = des->find_scope(this, eval_path);
|
|
|
|
|
if (targ_scope == 0) {
|
2008-06-30 03:46:46 +02:00
|
|
|
// If a scope in the target path is not found,
|
|
|
|
|
// then push this defparam for handling even
|
|
|
|
|
// later. Maybe a later generate scheme or
|
|
|
|
|
// instance array will create the scope.
|
|
|
|
|
defparams_even_later.push_back(cur);
|
2008-06-26 07:02:22 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-20 17:00:24 +01:00
|
|
|
targ_scope->replace_parameter(des, name, val, this, true);
|
2008-06-30 03:46:46 +02:00
|
|
|
|
|
|
|
|
// We'll need to re-evaluate parameters in this scope
|
|
|
|
|
target_scopes.insert(targ_scope);
|
2008-06-26 07:02:22 +02:00
|
|
|
}
|
2008-06-30 03:46:46 +02:00
|
|
|
|
2012-05-18 17:07:27 +02:00
|
|
|
// The scopes that this defparam set touched will be
|
|
|
|
|
// re-evaluated later it a top_defparams work item. So do not
|
|
|
|
|
// do the evaluation now.
|
2008-06-30 03:46:46 +02:00
|
|
|
|
|
|
|
|
// If there are some scopes that still have missing scopes,
|
2011-03-11 20:27:54 +01:00
|
|
|
// then save them back into the defparams_later list for a
|
2008-06-30 03:46:46 +02:00
|
|
|
// later pass.
|
|
|
|
|
defparams_later = defparams_even_later;
|
|
|
|
|
if (! defparams_later.empty())
|
|
|
|
|
des->defparams_later.insert(this);
|
2000-03-08 05:36:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Design::evaluate_parameters()
|
|
|
|
|
{
|
2013-04-07 02:38:36 +02:00
|
|
|
for (map<perm_string,NetScope*>::const_iterator cur = packages_.begin()
|
|
|
|
|
; cur != packages_.end() ; ++ cur) {
|
|
|
|
|
cur->second->evaluate_parameters(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (list<NetScope*>::const_iterator scope = root_scopes_.begin()
|
|
|
|
|
; scope != root_scopes_.end() ; ++ scope ) {
|
2001-10-19 23:53:24 +02:00
|
|
|
(*scope)->evaluate_parameters(this);
|
2013-04-07 02:38:36 +02:00
|
|
|
}
|
2000-03-08 05:36:53 +01:00
|
|
|
}
|
|
|
|
|
|
2008-05-18 01:25:58 +02:00
|
|
|
void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
|
2000-03-08 05:36:53 +01:00
|
|
|
{
|
2010-12-05 22:28:17 +01:00
|
|
|
/* Evaluate the parameter expression. */
|
|
|
|
|
PExpr*val_expr = (*cur).second.val_expr;
|
|
|
|
|
NetScope*val_scope = (*cur).second.val_scope;
|
2000-03-08 05:36:53 +01:00
|
|
|
|
2020-12-25 03:12:06 +01:00
|
|
|
// The param_type may be nil if the parameter has no declared type. In
|
|
|
|
|
// this case, we'll try to take our type from the r-value.
|
|
|
|
|
ivl_type_t param_type = cur->second.ivl_type;
|
|
|
|
|
|
|
|
|
|
// Most parameter declarations are packed vectors, of the form:
|
|
|
|
|
// parameter [H:L] foo == bar;
|
|
|
|
|
// so get the netvector_t. Note that this may also be the special
|
|
|
|
|
// case of a netvector_t with no dimensions, that exists only to carry
|
|
|
|
|
// signed-ness, e.g.:
|
|
|
|
|
// parameter signed foo = bar;
|
2022-03-26 10:45:00 +01:00
|
|
|
// These will be marked as scalar, but also have the implict flag set.
|
2020-12-25 03:12:06 +01:00
|
|
|
const netvector_t* param_vect = dynamic_cast<const netvector_t*> (param_type);
|
|
|
|
|
|
|
|
|
|
if (debug_elaborate) {
|
|
|
|
|
cerr << val_expr->get_fileline() << ": " << __func__ << ": "
|
|
|
|
|
<< "parameter=" << cur->first << endl;
|
|
|
|
|
if (param_type)
|
|
|
|
|
cerr << val_expr->get_fileline() << ": " << __func__ << ": "
|
|
|
|
|
<< "param_type=" << *param_type << endl;
|
|
|
|
|
else
|
|
|
|
|
cerr << val_expr->get_fileline() << ": " << __func__ << ": "
|
|
|
|
|
<< "param_type=(nil)" << endl;
|
|
|
|
|
cerr << val_expr->get_fileline() << ": " << __func__ << ": "
|
|
|
|
|
<< "val_expr=" << *val_expr << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ivl_variable_type_t use_type;
|
2011-02-26 23:59:52 +01:00
|
|
|
int lv_width = -2;
|
2020-12-25 03:12:06 +01:00
|
|
|
if (param_type) {
|
|
|
|
|
use_type = param_type->base_type();
|
2022-03-26 10:45:00 +01:00
|
|
|
// Is this an implicit netvector_t with no dimenions?
|
|
|
|
|
if (param_vect && param_vect->get_implicit() &&
|
|
|
|
|
param_vect->get_scalar())
|
2020-12-25 03:12:06 +01:00
|
|
|
lv_width = -2;
|
|
|
|
|
else if (param_type->packed())
|
|
|
|
|
lv_width = param_type->packed_width();
|
|
|
|
|
} else {
|
|
|
|
|
use_type = val_expr->expr_type();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (debug_elaborate) {
|
|
|
|
|
cerr << val_expr->get_fileline() << ": " << __func__ << ": "
|
|
|
|
|
<< "use_type = " << use_type << endl;
|
|
|
|
|
}
|
2000-03-08 05:36:53 +01:00
|
|
|
|
2012-05-07 00:11:26 +02:00
|
|
|
NetExpr*expr = elab_and_eval(des, val_scope, val_expr, lv_width, true,
|
2020-12-25 03:12:06 +01:00
|
|
|
cur->second.is_annotatable, use_type);
|
2011-03-03 05:23:02 +01:00
|
|
|
if (! expr)
|
2010-12-05 22:28:17 +01:00
|
|
|
return;
|
2008-05-21 05:32:42 +02:00
|
|
|
|
2020-12-25 03:12:06 +01:00
|
|
|
// Make sure to carry the signed-ness from a vector type.
|
|
|
|
|
if (param_vect)
|
|
|
|
|
expr->cast_signed(param_vect->get_signed());
|
|
|
|
|
|
|
|
|
|
if (debug_elaborate) {
|
|
|
|
|
cerr << val_expr->get_fileline() << ": " << __func__ << ": "
|
|
|
|
|
<< "expr = " << *expr << endl;
|
|
|
|
|
cerr << val_expr->get_fileline() << ": " << __func__ << ": "
|
|
|
|
|
<< "expr type = " << expr->expr_type() << endl;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-18 01:25:58 +02:00
|
|
|
switch (expr->expr_type()) {
|
|
|
|
|
case IVL_VT_REAL:
|
|
|
|
|
if (! dynamic_cast<const NetECReal*>(expr)) {
|
2008-05-21 05:32:42 +02:00
|
|
|
cerr << expr->get_fileline()
|
2010-10-02 20:02:27 +02:00
|
|
|
<< ": error: Unable to evaluate real parameter "
|
|
|
|
|
<< (*cur).first << " value: " << *expr << endl;
|
2008-05-18 01:25:58 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-12-25 03:12:06 +01:00
|
|
|
|
|
|
|
|
// If the parameter has no type, then infer its type from the
|
|
|
|
|
// r-value expression.
|
|
|
|
|
if (param_type==0) {
|
|
|
|
|
param_type = &netreal_t::type_real;
|
|
|
|
|
cur->second.ivl_type = param_type;
|
|
|
|
|
}
|
2008-05-18 01:25:58 +02:00
|
|
|
break;
|
2002-10-20 00:59:49 +02:00
|
|
|
|
2008-05-18 01:25:58 +02:00
|
|
|
case IVL_VT_LOGIC:
|
|
|
|
|
case IVL_VT_BOOL:
|
|
|
|
|
if (! dynamic_cast<const NetEConst*>(expr)) {
|
2008-05-21 05:32:42 +02:00
|
|
|
cerr << expr->get_fileline()
|
2010-10-02 20:02:27 +02:00
|
|
|
<< ": error: Unable to evaluate parameter "
|
|
|
|
|
<< (*cur).first << " value: " << *expr << endl;
|
2008-05-18 01:25:58 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2014-02-12 03:24:12 +01:00
|
|
|
|
2020-12-25 03:12:06 +01:00
|
|
|
// If the parameter has no type, then infer its type from the
|
|
|
|
|
// r-value expression.
|
|
|
|
|
if (param_type==0) {
|
|
|
|
|
param_type = new netvector_t(expr->expr_type(), expr->expr_width()-1,
|
|
|
|
|
0, expr->has_sign());
|
|
|
|
|
cur->second.ivl_type = param_type;
|
2014-02-12 03:24:12 +01:00
|
|
|
}
|
|
|
|
|
|
2020-12-25 03:12:06 +01:00
|
|
|
if (param_type->base_type() != IVL_VT_NO_TYPE)
|
|
|
|
|
expr->cast_signed(param_type->get_signed());
|
|
|
|
|
|
|
|
|
|
if (!expr->has_width()) {
|
|
|
|
|
expr = pad_to_width(expr, integer_width, *expr);
|
|
|
|
|
} else if (param_type->slice_dimensions().size()==0 && !expr->has_width()) {
|
2014-02-12 03:24:12 +01:00
|
|
|
expr = pad_to_width(expr, integer_width, *expr);
|
|
|
|
|
}
|
2008-05-18 01:25:58 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2008-05-21 05:32:42 +02:00
|
|
|
cerr << expr->get_fileline()
|
2008-05-18 01:25:58 +02:00
|
|
|
<< ": internal error: "
|
2020-12-25 03:12:06 +01:00
|
|
|
<< "Unhandled expression type "
|
|
|
|
|
<< expr->expr_type() << "?" << endl;
|
|
|
|
|
cerr << expr->get_fileline()
|
|
|
|
|
<< ": : "
|
|
|
|
|
<< "param_type: " << *param_type << endl;
|
2008-05-18 01:25:58 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2014-02-12 03:24:12 +01:00
|
|
|
|
2020-12-25 03:12:06 +01:00
|
|
|
// By the time we're done with the above, we should certainly know the
|
|
|
|
|
// type of the parameter.
|
|
|
|
|
ivl_assert(*expr, cur->second.ivl_type);
|
|
|
|
|
|
2014-02-12 03:24:12 +01:00
|
|
|
cur->second.val = expr;
|
2002-10-20 00:59:49 +02:00
|
|
|
|
2008-05-18 01:55:00 +02:00
|
|
|
// If there are no value ranges to test the value against,
|
|
|
|
|
// then we are done.
|
2020-12-25 03:12:06 +01:00
|
|
|
if ((*cur).second.range == 0)
|
2008-05-18 01:55:00 +02:00
|
|
|
return;
|
|
|
|
|
|
2010-12-05 22:28:17 +01:00
|
|
|
NetEConst*val = dynamic_cast<NetEConst*>((*cur).second.val);
|
2021-11-03 19:07:15 +01:00
|
|
|
ivl_assert(*expr, val);
|
2002-10-20 00:59:49 +02:00
|
|
|
|
2008-05-18 01:25:58 +02:00
|
|
|
verinum value = val->value();
|
2002-10-20 00:59:49 +02:00
|
|
|
|
2008-05-18 01:25:58 +02:00
|
|
|
bool from_flag = (*cur).second.range == 0? true : false;
|
|
|
|
|
for (range_t*value_range = (*cur).second.range
|
|
|
|
|
; value_range ; value_range = value_range->next) {
|
2002-10-20 00:59:49 +02:00
|
|
|
|
2008-05-18 01:25:58 +02:00
|
|
|
// If we already know that the value is
|
|
|
|
|
// within a "from" range, then do not test
|
|
|
|
|
// any more of the from ranges.
|
|
|
|
|
if (from_flag && value_range->exclude_flag==false)
|
|
|
|
|
continue;
|
2002-10-20 00:59:49 +02:00
|
|
|
|
2008-05-18 01:25:58 +02:00
|
|
|
if (value_range->low_expr) {
|
|
|
|
|
NetEConst*tmp = dynamic_cast<NetEConst*>(value_range->low_expr);
|
|
|
|
|
ivl_assert(*value_range->low_expr, tmp);
|
|
|
|
|
if (value_range->low_open_flag && value <= tmp->value())
|
|
|
|
|
continue;
|
|
|
|
|
else if (value < tmp->value())
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2002-10-20 00:59:49 +02:00
|
|
|
|
2008-05-18 01:25:58 +02:00
|
|
|
if (value_range->high_expr) {
|
|
|
|
|
NetEConst*tmp = dynamic_cast<NetEConst*>(value_range->high_expr);
|
|
|
|
|
ivl_assert(*value_range->high_expr, tmp);
|
|
|
|
|
if (value_range->high_open_flag && value >= tmp->value())
|
|
|
|
|
continue;
|
|
|
|
|
else if (value > tmp->value())
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2002-10-20 00:59:49 +02:00
|
|
|
|
2008-05-18 01:25:58 +02:00
|
|
|
// Within the range. If this is a "from"
|
|
|
|
|
// range, then set the from_flag and continue.
|
|
|
|
|
if (value_range->exclude_flag == false) {
|
|
|
|
|
from_flag = true;
|
|
|
|
|
continue;
|
2000-03-08 05:36:53 +01:00
|
|
|
}
|
|
|
|
|
|
2008-05-18 01:25:58 +02:00
|
|
|
// OH NO! In an excluded range. signal an error.
|
|
|
|
|
from_flag = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2002-10-20 00:59:49 +02:00
|
|
|
|
2008-05-18 01:25:58 +02:00
|
|
|
// If we found no from range that contains the
|
|
|
|
|
// value, then report an error.
|
|
|
|
|
if (! from_flag) {
|
|
|
|
|
cerr << val->get_fileline() << ": error: "
|
|
|
|
|
<< "Parameter value " << value
|
|
|
|
|
<< " is out of range for parameter " << (*cur).first
|
|
|
|
|
<< "." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-10-20 00:59:49 +02:00
|
|
|
|
2008-05-18 01:25:58 +02:00
|
|
|
void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur)
|
|
|
|
|
{
|
2010-12-05 22:28:17 +01:00
|
|
|
PExpr*val_expr = (*cur).second.val_expr;
|
|
|
|
|
NetScope*val_scope = (*cur).second.val_scope;
|
2020-12-25 03:12:06 +01:00
|
|
|
ivl_type_t param_type = cur->second.ivl_type;
|
2010-12-05 22:28:17 +01:00
|
|
|
|
2020-12-25 03:12:06 +01:00
|
|
|
ivl_assert(*val_expr, param_type);
|
2012-05-07 00:11:26 +02:00
|
|
|
NetExpr*expr = elab_and_eval(des, val_scope, val_expr, -1, true,
|
2020-12-25 03:12:06 +01:00
|
|
|
cur->second.is_annotatable,
|
|
|
|
|
param_type->base_type());
|
2011-03-03 05:23:02 +01:00
|
|
|
if (! expr)
|
2010-12-05 22:28:17 +01:00
|
|
|
return;
|
2008-05-18 01:25:58 +02:00
|
|
|
|
|
|
|
|
NetECReal*res = 0;
|
|
|
|
|
|
|
|
|
|
switch (expr->expr_type()) {
|
|
|
|
|
case IVL_VT_REAL:
|
|
|
|
|
if (NetECReal*tmp = dynamic_cast<NetECReal*>(expr)) {
|
|
|
|
|
res = tmp;
|
|
|
|
|
} else {
|
2010-10-02 20:02:27 +02:00
|
|
|
cerr << expr->get_fileline()
|
|
|
|
|
<< ": error: "
|
|
|
|
|
<< "Unable to evaluate real parameter "
|
|
|
|
|
<< (*cur).first << " value: " << *expr << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
2008-05-18 01:25:58 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2010-10-02 20:02:27 +02:00
|
|
|
cerr << expr->get_fileline()
|
|
|
|
|
<< ": internal error: "
|
2013-02-26 23:36:37 +01:00
|
|
|
<< "Failed to cast expression?" << endl;
|
2010-10-02 20:02:27 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
2008-05-18 01:25:58 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2003-02-02 00:37:34 +01:00
|
|
|
|
2010-12-05 22:28:17 +01:00
|
|
|
(*cur).second.val = res;
|
2008-05-18 01:25:58 +02:00
|
|
|
double value = res->value().as_double();
|
|
|
|
|
|
|
|
|
|
bool from_flag = (*cur).second.range == 0? true : false;
|
|
|
|
|
for (range_t*value_range = (*cur).second.range
|
|
|
|
|
; value_range ; value_range = value_range->next) {
|
|
|
|
|
|
|
|
|
|
if (from_flag && value_range->exclude_flag==false)
|
2003-02-02 00:37:34 +01:00
|
|
|
continue;
|
2008-05-18 01:25:58 +02:00
|
|
|
|
|
|
|
|
if (value_range->low_expr) {
|
|
|
|
|
double tmp;
|
|
|
|
|
bool flag = eval_as_double(tmp, value_range->low_expr);
|
|
|
|
|
ivl_assert(*value_range->low_expr, flag);
|
|
|
|
|
if (value_range->low_open_flag && value <= tmp)
|
|
|
|
|
continue;
|
|
|
|
|
else if (value < tmp)
|
|
|
|
|
continue;
|
2002-10-20 00:59:49 +02:00
|
|
|
}
|
|
|
|
|
|
2008-05-18 01:25:58 +02:00
|
|
|
if (value_range->high_expr) {
|
|
|
|
|
double tmp;
|
|
|
|
|
bool flag = eval_as_double(tmp, value_range->high_expr);
|
|
|
|
|
ivl_assert(*value_range->high_expr, flag);
|
|
|
|
|
if (value_range->high_open_flag && value >= tmp)
|
|
|
|
|
continue;
|
|
|
|
|
else if (value > tmp)
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2002-10-20 00:59:49 +02:00
|
|
|
|
2008-05-18 01:25:58 +02:00
|
|
|
if (value_range->exclude_flag == false) {
|
|
|
|
|
from_flag = true;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2002-10-20 00:59:49 +02:00
|
|
|
|
2008-05-18 01:25:58 +02:00
|
|
|
// All the above tests failed, so we must have tripped
|
|
|
|
|
// an exclude rule.
|
|
|
|
|
from_flag = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2002-10-20 00:59:49 +02:00
|
|
|
|
2008-05-18 01:25:58 +02:00
|
|
|
if (! from_flag) {
|
|
|
|
|
cerr << res->get_fileline() << ": error: "
|
|
|
|
|
<< "Parameter value " << value
|
2010-10-02 20:02:27 +02:00
|
|
|
<< " is out of range for real parameter " << (*cur).first
|
2008-05-18 01:25:58 +02:00
|
|
|
<< "." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-10-20 00:59:49 +02:00
|
|
|
|
2020-12-28 03:53:34 +01:00
|
|
|
/*
|
|
|
|
|
* Evaluate a parameter that is forced to type string. This comes to pass when
|
|
|
|
|
* the input is something like this:
|
|
|
|
|
*
|
|
|
|
|
* parameter string foo = <expr>;
|
|
|
|
|
*
|
|
|
|
|
* The param_type should be netstring_t, the val_expr is the pform of the
|
|
|
|
|
* input <expr>, and we try to elaborate/evaluate down to a IVL_VT_STRING
|
|
|
|
|
* expression.
|
|
|
|
|
*/
|
|
|
|
|
void NetScope::evaluate_parameter_string_(Design*des, param_ref_t cur)
|
|
|
|
|
{
|
|
|
|
|
PExpr*val_expr = (*cur).second.val_expr;
|
|
|
|
|
NetScope*val_scope = (*cur).second.val_scope;
|
|
|
|
|
ivl_type_t param_type = cur->second.ivl_type;
|
|
|
|
|
|
|
|
|
|
ivl_assert(cur->second, val_expr);
|
|
|
|
|
ivl_assert(cur->second, param_type);
|
|
|
|
|
|
|
|
|
|
NetExpr*expr = elab_and_eval(des, val_scope, val_expr, param_type, true);
|
|
|
|
|
if (! expr)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
cur->second.val = expr;
|
|
|
|
|
|
|
|
|
|
if (debug_elaborate) {
|
|
|
|
|
cerr << cur->second.get_fileline() << ": " << __func__ << ": "
|
|
|
|
|
<< "Parameter type: " << *param_type << endl;
|
|
|
|
|
cerr << cur->second.get_fileline() << ": " << __func__ << ": "
|
|
|
|
|
<< "Parameter value: " << *val_expr << endl;
|
|
|
|
|
cerr << cur->second.get_fileline() << ": " << __func__ << ": "
|
|
|
|
|
<< "Elaborated value: " << *expr << endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-20 17:00:24 +01:00
|
|
|
void NetScope::evaluate_type_parameter_(Design *des, param_ref_t cur)
|
2010-12-05 22:28:17 +01:00
|
|
|
{
|
2021-12-20 17:00:24 +01:00
|
|
|
const PETypename *type_expr = dynamic_cast<const PETypename*>(cur->second.val_expr);
|
|
|
|
|
if (!type_expr) {
|
|
|
|
|
cerr << this->get_fileline() << ": error: "
|
|
|
|
|
<< "Type parameter `" << cur->first << "` value `"
|
|
|
|
|
<< *cur->second.val_expr << "` is not a type."
|
|
|
|
|
<< endl;
|
|
|
|
|
des->errors++;
|
2020-12-25 03:12:06 +01:00
|
|
|
|
2021-12-20 17:00:24 +01:00
|
|
|
// Recover
|
|
|
|
|
cur->second.ivl_type = netvector_t::integer_type();
|
|
|
|
|
return;
|
2020-12-25 03:12:06 +01:00
|
|
|
}
|
|
|
|
|
|
2022-12-28 08:59:39 +01:00
|
|
|
data_type_t *ptype = type_expr->get_type();
|
2021-12-20 17:00:24 +01:00
|
|
|
NetScope *type_scope = cur->second.val_scope;
|
2022-12-28 08:59:39 +01:00
|
|
|
cur->second.ivl_type = ptype->elaborate_type(des, type_scope);
|
2021-12-20 17:00:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NetScope::evaluate_parameter_(Design*des, param_ref_t cur)
|
|
|
|
|
{
|
|
|
|
|
|
2020-12-25 03:12:06 +01:00
|
|
|
// If the parameter has already been evaluated, quietly return.
|
2021-12-20 17:00:24 +01:00
|
|
|
if (cur->second.val || cur->second.ivl_type)
|
2010-12-05 22:28:17 +01:00
|
|
|
return;
|
|
|
|
|
|
2022-02-10 14:03:46 +01:00
|
|
|
if (cur->second.val_expr == 0) {
|
|
|
|
|
cerr << this->get_fileline() << ": error: "
|
|
|
|
|
<< "Missing value for parameter `"
|
|
|
|
|
<< cur->first << "`." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
|
|
|
|
|
cur->second.val = new NetEConst(verinum(verinum::Vx));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-20 17:00:24 +01:00
|
|
|
if (cur->second.type_flag) {
|
|
|
|
|
evaluate_type_parameter_(des, cur);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ivl_type_t param_type = cur->second.ivl_type;
|
|
|
|
|
|
|
|
|
|
// If the parameter type is present, then elaborate it now. Elaborate
|
|
|
|
|
// the type in the current scope, and not the scope of the expression.
|
|
|
|
|
if (cur->second.val_type) {
|
|
|
|
|
param_type = cur->second.val_type->elaborate_type(des, this);
|
|
|
|
|
cur->second.ivl_type = param_type;
|
|
|
|
|
cur->second.val_type = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-25 03:12:06 +01:00
|
|
|
// Guess the varaiable type of the parameter. If the parameter has no
|
|
|
|
|
// given type, then guess the type from the expression and use that to
|
2022-08-24 16:21:16 +02:00
|
|
|
// evaluate (this is currently handled in evaluate_parameter_logic_()).
|
2020-12-25 03:12:06 +01:00
|
|
|
ivl_variable_type_t use_type;
|
|
|
|
|
if (param_type)
|
|
|
|
|
use_type = param_type->base_type();
|
|
|
|
|
else
|
2022-08-24 16:21:16 +02:00
|
|
|
use_type = IVL_VT_NO_TYPE;
|
2020-12-25 03:12:06 +01:00
|
|
|
|
2010-12-05 22:28:17 +01:00
|
|
|
if (cur->second.solving) {
|
|
|
|
|
cerr << cur->second.get_fileline() << ": error: "
|
|
|
|
|
<< "Recursive parameter reference found involving "
|
|
|
|
|
<< cur->first << "." << endl;
|
|
|
|
|
des->errors += 1;
|
2020-12-25 03:12:06 +01:00
|
|
|
|
2010-12-05 22:28:17 +01:00
|
|
|
} else {
|
|
|
|
|
cur->second.solving = true;
|
2020-12-25 03:12:06 +01:00
|
|
|
switch (use_type) {
|
2013-02-26 23:36:37 +01:00
|
|
|
case IVL_VT_NO_TYPE:
|
2010-12-05 22:28:17 +01:00
|
|
|
case IVL_VT_BOOL:
|
|
|
|
|
case IVL_VT_LOGIC:
|
|
|
|
|
evaluate_parameter_logic_(des, cur);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IVL_VT_REAL:
|
|
|
|
|
evaluate_parameter_real_(des, cur);
|
|
|
|
|
break;
|
|
|
|
|
|
2020-12-28 03:53:34 +01:00
|
|
|
case IVL_VT_STRING:
|
|
|
|
|
evaluate_parameter_string_(des, cur);
|
|
|
|
|
break;
|
|
|
|
|
|
2010-12-05 22:28:17 +01:00
|
|
|
default:
|
|
|
|
|
cerr << cur->second.get_fileline() << ": internal error: "
|
2020-12-28 03:53:34 +01:00
|
|
|
<< "Unexpected parameter type " << use_type
|
2010-12-05 22:28:17 +01:00
|
|
|
<< "." << endl;
|
|
|
|
|
cerr << cur->second.get_fileline() << ": : "
|
|
|
|
|
<< "Parameter name: " << cur->first << endl;
|
2020-12-28 03:53:34 +01:00
|
|
|
if (param_type)
|
|
|
|
|
cerr << cur->second.get_fileline() << ": : "
|
|
|
|
|
<< "Parameter ivl_type: " << *param_type << endl;
|
2010-12-05 22:28:17 +01:00
|
|
|
cerr << cur->second.get_fileline() << ": : "
|
|
|
|
|
<< "Expression is: " << *cur->second.val_expr << endl;
|
|
|
|
|
ivl_assert(cur->second, 0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
cur->second.solving = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we have failed to evaluate the expression, create a dummy
|
|
|
|
|
// value. This prevents spurious error messages being output.
|
|
|
|
|
if (cur->second.val == 0) {
|
|
|
|
|
verinum val(verinum::Vx);
|
|
|
|
|
cur->second.val = new NetEConst(val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Flag that the expression has been evaluated.
|
|
|
|
|
cur->second.val_expr = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-18 01:25:58 +02:00
|
|
|
void NetScope::evaluate_parameters(Design*des)
|
|
|
|
|
{
|
2009-12-09 00:14:55 +01:00
|
|
|
for (map<hname_t,NetScope*>::const_iterator cur = children_.begin()
|
2010-10-23 23:57:59 +02:00
|
|
|
; cur != children_.end() ; ++ cur )
|
2009-12-09 00:14:55 +01:00
|
|
|
cur->second->evaluate_parameters(des);
|
2008-05-14 06:56:57 +02:00
|
|
|
|
2008-06-30 03:46:46 +02:00
|
|
|
if (debug_scopes)
|
2012-01-02 19:11:56 +01:00
|
|
|
cerr << "debug: "
|
|
|
|
|
<< "Evaluating parameters in " << scope_path(this) << endl;
|
2008-05-14 06:56:57 +02:00
|
|
|
|
2008-05-18 01:25:58 +02:00
|
|
|
for (param_ref_t cur = parameters.begin()
|
2011-01-05 02:41:19 +01:00
|
|
|
; cur != parameters.end() ; ++ cur) {
|
2008-05-18 01:25:58 +02:00
|
|
|
|
2010-12-05 22:28:17 +01:00
|
|
|
evaluate_parameter_(des, cur);
|
2000-03-08 05:36:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-06-30 03:46:46 +02:00
|
|
|
void Design::residual_defparams()
|
|
|
|
|
{
|
|
|
|
|
for (list<NetScope*>::const_iterator scope = root_scopes_.begin();
|
2010-10-23 23:57:59 +02:00
|
|
|
scope != root_scopes_.end(); ++ scope )
|
2008-06-30 03:46:46 +02:00
|
|
|
(*scope)->residual_defparams(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NetScope::residual_defparams(Design*des)
|
|
|
|
|
{
|
|
|
|
|
// Clean out the list of defparams that never managed to match
|
|
|
|
|
// a scope. Print a warning for each.
|
|
|
|
|
while (! defparams_later.empty()) {
|
2010-12-05 22:28:17 +01:00
|
|
|
pair<list<hname_t>,PExpr*> cur = defparams_later.front();
|
2008-06-30 03:46:46 +02:00
|
|
|
defparams_later.pop_front();
|
|
|
|
|
|
|
|
|
|
cerr << cur.second->get_fileline() << ": warning: "
|
|
|
|
|
<< "Scope of " << cur.first << " not found." << endl;
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-09 00:14:55 +01:00
|
|
|
for (map<hname_t,NetScope*>::const_iterator cur = children_.begin()
|
2010-10-23 23:57:59 +02:00
|
|
|
; cur != children_.end() ; ++ cur )
|
2009-12-09 00:14:55 +01:00
|
|
|
cur->second->residual_defparams(des);
|
2008-06-30 03:46:46 +02:00
|
|
|
}
|
|
|
|
|
|
2003-11-10 21:59:03 +01:00
|
|
|
const char* Design::get_flag(const string&key) const
|
2000-03-08 05:36:53 +01:00
|
|
|
{
|
2003-11-10 21:59:03 +01:00
|
|
|
map<string,const char*>::const_iterator tmp = flags_.find(key);
|
2000-03-08 05:36:53 +01:00
|
|
|
if (tmp == flags_.end())
|
|
|
|
|
return "";
|
|
|
|
|
else
|
|
|
|
|
return (*tmp).second;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2000-08-12 19:59:48 +02:00
|
|
|
* This method looks for a signal (reg, wire, whatever) starting at
|
|
|
|
|
* the specified scope. If the name is hierarchical, it is split into
|
|
|
|
|
* scope and name and the scope used to find the proper starting point
|
|
|
|
|
* for the real search.
|
|
|
|
|
*
|
|
|
|
|
* It is the job of this function to properly implement Verilog scope
|
|
|
|
|
* rules as signals are concerned.
|
2000-03-08 05:36:53 +01:00
|
|
|
*/
|
2007-05-24 06:07:11 +02:00
|
|
|
NetNet* Design::find_signal(NetScope*scope, pform_name_t path)
|
2000-03-08 05:36:53 +01:00
|
|
|
{
|
|
|
|
|
assert(scope);
|
|
|
|
|
|
2007-05-24 06:07:11 +02:00
|
|
|
perm_string key = peek_tail_name(path);
|
|
|
|
|
path.pop_back();
|
2007-06-02 05:42:12 +02:00
|
|
|
if (! path.empty()) {
|
|
|
|
|
list<hname_t> eval_path = eval_scope_path(this, scope, path);
|
|
|
|
|
scope = find_scope(scope, eval_path);
|
|
|
|
|
}
|
2000-05-02 18:27:38 +02:00
|
|
|
|
2000-05-02 02:58:11 +02:00
|
|
|
while (scope) {
|
2007-04-26 05:06:21 +02:00
|
|
|
if (NetNet*net = scope->find_signal(key))
|
2000-05-02 02:58:11 +02:00
|
|
|
return net;
|
2000-08-12 19:59:48 +02:00
|
|
|
|
2019-09-22 00:09:48 +02:00
|
|
|
if (NetScope*import_scope = scope->find_import(this, key)) {
|
|
|
|
|
scope = import_scope;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2000-08-12 19:59:48 +02:00
|
|
|
if (scope->type() == NetScope::MODULE)
|
|
|
|
|
break;
|
2007-04-26 05:06:21 +02:00
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
scope = scope->parent();
|
|
|
|
|
}
|
2000-05-02 02:58:11 +02:00
|
|
|
|
|
|
|
|
return 0;
|
2000-03-08 05:36:53 +01:00
|
|
|
}
|
|
|
|
|
|
2007-05-24 06:07:11 +02:00
|
|
|
NetFuncDef* Design::find_function(NetScope*scope, const pform_name_t&name)
|
2000-03-08 05:36:53 +01:00
|
|
|
{
|
2000-07-30 20:25:43 +02:00
|
|
|
assert(scope);
|
2000-03-08 05:36:53 +01:00
|
|
|
|
2007-06-02 05:42:12 +02:00
|
|
|
std::list<hname_t> eval_path = eval_scope_path(this, scope, name);
|
2007-12-08 00:10:13 +01:00
|
|
|
NetScope*func = find_scope(scope, eval_path, NetScope::FUNC);
|
2011-04-05 21:43:54 +02:00
|
|
|
if (func && (func->type() == NetScope::FUNC)) {
|
|
|
|
|
// If a function is used in a parameter definition or in
|
|
|
|
|
// a signal declaration, it is possible to get here before
|
|
|
|
|
// the function's signals have been elaborated. If this is
|
|
|
|
|
// the case, elaborate them now.
|
|
|
|
|
if (func->elab_stage() < 2) {
|
2015-06-20 22:39:45 +02:00
|
|
|
func->need_const_func(true);
|
2011-04-05 21:43:54 +02:00
|
|
|
const PFunction*pfunc = func->func_pform();
|
|
|
|
|
assert(pfunc);
|
|
|
|
|
pfunc->elaborate_sig(this, func);
|
|
|
|
|
}
|
2000-07-30 20:25:43 +02:00
|
|
|
return func->func_def();
|
2011-04-05 21:43:54 +02:00
|
|
|
}
|
2000-07-30 20:25:43 +02:00
|
|
|
return 0;
|
2000-03-08 05:36:53 +01:00
|
|
|
}
|
|
|
|
|
|
2007-05-24 06:07:11 +02:00
|
|
|
NetScope* Design::find_task(NetScope*scope, const pform_name_t&name)
|
2000-03-08 05:36:53 +01:00
|
|
|
{
|
2007-06-02 05:42:12 +02:00
|
|
|
std::list<hname_t> eval_path = eval_scope_path(this, scope, name);
|
2007-12-08 00:10:13 +01:00
|
|
|
NetScope*task = find_scope(scope, eval_path, NetScope::TASK);
|
2000-07-30 20:25:43 +02:00
|
|
|
if (task && (task->type() == NetScope::TASK))
|
2001-04-02 04:28:12 +02:00
|
|
|
return task;
|
2000-03-08 05:36:53 +01:00
|
|
|
|
2000-07-30 20:25:43 +02:00
|
|
|
return 0;
|
2000-03-08 05:36:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Design::add_node(NetNode*net)
|
|
|
|
|
{
|
|
|
|
|
assert(net->design_ == 0);
|
|
|
|
|
if (nodes_ == 0) {
|
|
|
|
|
net->node_next_ = net;
|
|
|
|
|
net->node_prev_ = net;
|
|
|
|
|
} else {
|
|
|
|
|
net->node_next_ = nodes_->node_next_;
|
|
|
|
|
net->node_prev_ = nodes_;
|
|
|
|
|
net->node_next_->node_prev_ = net;
|
|
|
|
|
net->node_prev_->node_next_ = net;
|
|
|
|
|
}
|
|
|
|
|
nodes_ = net;
|
|
|
|
|
net->design_ = this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Design::del_node(NetNode*net)
|
|
|
|
|
{
|
2002-08-16 07:18:27 +02:00
|
|
|
assert(net != 0);
|
2015-12-20 02:18:15 +01:00
|
|
|
assert(net->design_ == this);
|
2002-08-16 07:18:27 +02:00
|
|
|
|
2003-08-28 06:11:17 +02:00
|
|
|
/* Interact with the Design::functor method by manipulating the
|
|
|
|
|
cur and nxt pointers that it is using. */
|
2002-08-16 07:18:27 +02:00
|
|
|
if (net == nodes_functor_nxt_)
|
|
|
|
|
nodes_functor_nxt_ = nodes_functor_nxt_->node_next_;
|
|
|
|
|
if (net == nodes_functor_nxt_)
|
|
|
|
|
nodes_functor_nxt_ = 0;
|
|
|
|
|
|
|
|
|
|
if (net == nodes_functor_cur_)
|
|
|
|
|
nodes_functor_cur_ = 0;
|
|
|
|
|
|
|
|
|
|
/* Now perform the actual delete. */
|
2000-03-08 05:36:53 +01:00
|
|
|
if (nodes_ == net)
|
|
|
|
|
nodes_ = net->node_prev_;
|
|
|
|
|
|
|
|
|
|
if (nodes_ == net) {
|
|
|
|
|
nodes_ = 0;
|
|
|
|
|
} else {
|
|
|
|
|
net->node_next_->node_prev_ = net->node_prev_;
|
|
|
|
|
net->node_prev_->node_next_ = net->node_next_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
net->design_ = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-10 02:11:04 +01:00
|
|
|
void Design::add_branch(NetBranch*bra)
|
|
|
|
|
{
|
|
|
|
|
bra->next_ = branches_;
|
|
|
|
|
branches_ = bra;
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
void Design::add_process(NetProcTop*pro)
|
|
|
|
|
{
|
|
|
|
|
pro->next_ = procs_;
|
|
|
|
|
procs_ = pro;
|
|
|
|
|
}
|
|
|
|
|
|
2008-10-22 07:15:49 +02:00
|
|
|
void Design::add_process(NetAnalogTop*pro)
|
|
|
|
|
{
|
|
|
|
|
pro->next_ = aprocs_;
|
|
|
|
|
aprocs_ = pro;
|
|
|
|
|
}
|
2000-03-08 05:36:53 +01:00
|
|
|
void Design::delete_process(NetProcTop*top)
|
|
|
|
|
{
|
|
|
|
|
assert(top);
|
|
|
|
|
if (procs_ == top) {
|
|
|
|
|
procs_ = top->next_;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
NetProcTop*cur = procs_;
|
|
|
|
|
while (cur->next_ != top) {
|
|
|
|
|
assert(cur->next_);
|
|
|
|
|
cur = cur->next_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cur->next_ = top->next_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (procs_idx_ == top)
|
|
|
|
|
procs_idx_ = top->next_;
|
|
|
|
|
|
|
|
|
|
delete top;
|
|
|
|
|
}
|
|
|
|
|
|
2008-06-04 05:21:39 +02:00
|
|
|
void Design::join_islands(void)
|
|
|
|
|
{
|
|
|
|
|
if (nodes_ == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
NetNode*cur = nodes_->node_next_;
|
|
|
|
|
do {
|
|
|
|
|
join_island(cur);
|
|
|
|
|
cur = cur->node_next_;
|
|
|
|
|
} while (cur != nodes_->node_next_);
|
|
|
|
|
}
|