2000-03-08 05:36:53 +01:00
|
|
|
/*
|
2025-10-21 07:45:05 +02:00
|
|
|
* Copyright (c) 2000-2025 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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-23 18:58:49 +02:00
|
|
|
static bool is_design_unit(const NetScope*scope)
|
2017-10-21 16:04:25 +02:00
|
|
|
{
|
|
|
|
|
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
|
|
|
|
Add initial support for packed arrays/vector assignment pattern
SystemVerilog allows to use assignment patterns to assign a value to a
packed array.
This is similar to using a concatenation, with the difference that for
concatenations the values are evaluated in a self-determined context and
for assignment patterns they are evaluated in a context defined by the
element type of the packed array. This means that the value is for example
automatically width expanded or truncated if it does not have the same size
as the element type. Automatic type conversion is also done when allowed. E.g.
```
bit [3:0][3:0] x = '{1'b1, 32'h2, 3.0, "TEST"};
$display("%x", x); // -> 1234
```
Nested assignment patterns are also supported. E.g.
```
bit [1:0][3:0][3:0] x = '{'{1, 2, 3, 4.0}, '{5, 6, 7, 8}};
$display("%x", x); // -> 12345678
```
Add support for using assignment patterns as the right hand side value.
Since the complete type of the target variable is required to correctly
evaluate the assignment pattern it is handled as a special case in
`elab_rval_expression()`. For other types of expressions for packed values
only the total width of the target value is provided to the rvalue
elaboration function.
SystemVerilog also supports assignment patterns for the left hand side in
assignments. This is not yet supported.
Also not yet supported is specifying array elements by index, including
`default`.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-09-26 11:53:49 +02:00
|
|
|
NetExpr *expr;
|
|
|
|
|
|
|
|
|
|
// Handle assignment patterns as a special case as they need the type to
|
|
|
|
|
// be evaluated correctly.
|
|
|
|
|
if (param_type && dynamic_cast<PEAssignPattern*>(val_expr)) {
|
|
|
|
|
expr = elab_and_eval(des, val_scope, val_expr, param_type, true);
|
|
|
|
|
} else {
|
|
|
|
|
expr = elab_and_eval(des, val_scope, val_expr, lv_width, true,
|
|
|
|
|
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;
|
|
|
|
|
|
2025-10-21 07:45:05 +02:00
|
|
|
const 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) {
|
2025-10-21 07:45:05 +02:00
|
|
|
const NetEConst*tmp = dynamic_cast<NetEConst*>(value_range->low_expr);
|
2008-05-18 01:25:58 +02:00
|
|
|
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) {
|
2025-10-21 07:45:05 +02:00
|
|
|
const NetEConst*tmp = dynamic_cast<NetEConst*>(value_range->high_expr);
|
2008-05-18 01:25:58 +02:00
|
|
|
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_);
|
|
|
|
|
}
|