V0.9: Report and fail gracefully for recursive parameter definitions.
If someone accidentally makes a parameter depend on itself we need to report this not crash. This patch fixes the crash and prints an appropriate string of messages to figure out the loop. Icarus currently supports forward references of parameters so more complicated loops can be created. These are also caught.
This commit is contained in:
parent
7c4d07bda6
commit
97a3bf5aeb
28
eval_tree.cc
28
eval_tree.cc
|
|
@ -858,7 +858,7 @@ NetExpr* NetEBDiv::eval_tree(int prune_to_width)
|
||||||
eval_expr(right_);
|
eval_expr(right_);
|
||||||
|
|
||||||
if (expr_type() == IVL_VT_REAL) return eval_tree_real_();
|
if (expr_type() == IVL_VT_REAL) return eval_tree_real_();
|
||||||
|
|
||||||
assert(expr_type() == IVL_VT_LOGIC);
|
assert(expr_type() == IVL_VT_LOGIC);
|
||||||
|
|
||||||
NetEConst*lc = dynamic_cast<NetEConst*>(left_);
|
NetEConst*lc = dynamic_cast<NetEConst*>(left_);
|
||||||
|
|
@ -1228,6 +1228,12 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||||
<< *this << endl;
|
<< *this << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (solving()) {
|
||||||
|
cerr << get_fileline() << ": warning: Recursive parameter "
|
||||||
|
"reference found involving " << *this << "." << endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
assert(scope_);
|
assert(scope_);
|
||||||
perm_string name = (*reference_).first;
|
perm_string name = (*reference_).first;
|
||||||
const NetExpr*expr = (*reference_).second.expr;
|
const NetExpr*expr = (*reference_).second.expr;
|
||||||
|
|
@ -1239,35 +1245,35 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||||
<< *this << " cannot be evaluated." << endl;
|
<< *this << " cannot be evaluated." << endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// ivl_assert(*this, expr);
|
|
||||||
|
|
||||||
NetExpr*nexpr = expr->dup_expr();
|
|
||||||
assert(nexpr);
|
|
||||||
|
|
||||||
// If the parameter that I refer to is already evaluated, then
|
// If the parameter that I refer to is already evaluated, then
|
||||||
// return the constant value.
|
// return the constant value.
|
||||||
if (NetEConst*tmp = dynamic_cast<NetEConst*>(nexpr)) {
|
if (const NetEConst*tmp = dynamic_cast<const NetEConst*>(expr)) {
|
||||||
verinum val = tmp->value();
|
verinum val = tmp->value();
|
||||||
NetEConstParam*ptmp = new NetEConstParam(scope_, name, val);
|
NetEConstParam*ptmp = new NetEConstParam(scope_, name, val);
|
||||||
ptmp->set_line(*this);
|
ptmp->set_line(*this);
|
||||||
delete nexpr;
|
|
||||||
return ptmp;
|
return ptmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NetECReal*tmp = dynamic_cast<NetECReal*>(nexpr)) {
|
if (const NetECReal*tmp = dynamic_cast<const NetECReal*>(expr)) {
|
||||||
verireal val = tmp->value();
|
verireal val = tmp->value();
|
||||||
NetECRealParam*ptmp = new NetECRealParam(scope_, name, val);
|
NetECRealParam*ptmp = new NetECRealParam(scope_, name, val);
|
||||||
ptmp->set_line(*this);
|
ptmp->set_line(*this);
|
||||||
delete nexpr;
|
|
||||||
return ptmp;
|
return ptmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to evaluate the expression. If I cannot, then the
|
// Try to evaluate the expression. If I cannot, then the
|
||||||
// expression is not a constant expression and I fail here.
|
// expression is not a constant expression and I fail here.
|
||||||
|
|
||||||
|
solving(true);
|
||||||
|
NetExpr*nexpr = expr->dup_expr();
|
||||||
|
assert(nexpr);
|
||||||
NetExpr*res = nexpr->eval_tree();
|
NetExpr*res = nexpr->eval_tree();
|
||||||
|
solving(false);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
cerr << get_fileline() << ": internal error: Unable to evaluate "
|
cerr << get_fileline() << ": internal error: Unable to evaluate ";
|
||||||
<< "parameter " << name << " expression: "
|
if (expr_type() == IVL_VT_REAL) cerr << "real ";
|
||||||
|
cerr << "parameter " << name << " expression: "
|
||||||
<< *nexpr << endl;
|
<< *nexpr << endl;
|
||||||
delete nexpr;
|
delete nexpr;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2000-2009 Stephen Williams (steve@icarus.com)
|
* Copyright (c) 2000-2010 Stephen Williams (steve@icarus.com)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -319,8 +319,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
|
||||||
eval_expr((*cur).second.msb);
|
eval_expr((*cur).second.msb);
|
||||||
if (! eval_as_long(msb, (*cur).second.msb)) {
|
if (! eval_as_long(msb, (*cur).second.msb)) {
|
||||||
cerr << (*cur).second.expr->get_fileline()
|
cerr << (*cur).second.expr->get_fileline()
|
||||||
<< ": internal error: "
|
<< ": error: Unable to evaluate msb expression "
|
||||||
<< "unable to evaluate msb expression "
|
|
||||||
<< "for parameter " << (*cur).first << ": "
|
<< "for parameter " << (*cur).first << ": "
|
||||||
<< *(*cur).second.msb << endl;
|
<< *(*cur).second.msb << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
|
|
@ -335,8 +334,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
|
||||||
eval_expr((*cur).second.lsb);
|
eval_expr((*cur).second.lsb);
|
||||||
if (! eval_as_long(lsb, (*cur).second.lsb)) {
|
if (! eval_as_long(lsb, (*cur).second.lsb)) {
|
||||||
cerr << (*cur).second.expr->get_fileline()
|
cerr << (*cur).second.expr->get_fileline()
|
||||||
<< ": internal error: "
|
<< ": error: Unable to evaluate lsb expression "
|
||||||
<< "unable to evaluate lsb expression "
|
|
||||||
<< "for parameter " << (*cur).first << ": "
|
<< "for parameter " << (*cur).first << ": "
|
||||||
<< *(*cur).second.lsb << endl;
|
<< *(*cur).second.lsb << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
|
|
@ -362,10 +360,10 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
|
||||||
case IVL_VT_REAL:
|
case IVL_VT_REAL:
|
||||||
if (! dynamic_cast<const NetECReal*>(expr)) {
|
if (! dynamic_cast<const NetECReal*>(expr)) {
|
||||||
cerr << expr->get_fileline()
|
cerr << expr->get_fileline()
|
||||||
<< ": internal error: "
|
<< ": error: Unable to evaluate real parameter "
|
||||||
<< "unable to evaluate real parameter value: "
|
<< (*cur).first << " value: " << *expr << endl;
|
||||||
<< *expr << endl;
|
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
|
(*cur).second.expr = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -374,11 +372,10 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
|
||||||
case IVL_VT_BOOL:
|
case IVL_VT_BOOL:
|
||||||
if (! dynamic_cast<const NetEConst*>(expr)) {
|
if (! dynamic_cast<const NetEConst*>(expr)) {
|
||||||
cerr << expr->get_fileline()
|
cerr << expr->get_fileline()
|
||||||
<< ": internal error: "
|
<< ": error: Unable to evaluate parameter "
|
||||||
<< "unable to evaluate parameter "
|
<< (*cur).first << " value: " << *expr << endl;
|
||||||
<< (*cur).first
|
|
||||||
<< " value: " << *expr << endl;
|
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
|
(*cur).second.expr = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -386,8 +383,9 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
|
||||||
default:
|
default:
|
||||||
cerr << expr->get_fileline()
|
cerr << expr->get_fileline()
|
||||||
<< ": internal error: "
|
<< ": internal error: "
|
||||||
<< "unhandled expression type?" << endl;
|
<< "Unhandled expression type?" << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
|
(*cur).second.expr = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -500,7 +498,13 @@ void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur)
|
||||||
if (NetECReal*tmp = dynamic_cast<NetECReal*>(expr)) {
|
if (NetECReal*tmp = dynamic_cast<NetECReal*>(expr)) {
|
||||||
res = tmp;
|
res = tmp;
|
||||||
} else {
|
} else {
|
||||||
ivl_assert(*expr, 0);
|
cerr << expr->get_fileline()
|
||||||
|
<< ": error: "
|
||||||
|
<< "Unable to evaluate real parameter "
|
||||||
|
<< (*cur).first << " value: " << *expr << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
(*cur).second.expr = NULL;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -511,12 +515,23 @@ void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur)
|
||||||
res = new NetECReal(val);
|
res = new NetECReal(val);
|
||||||
res->set_line(*tmp);
|
res->set_line(*tmp);
|
||||||
} else {
|
} else {
|
||||||
ivl_assert(*expr, 0);
|
cerr << expr->get_fileline()
|
||||||
|
<< ": error: "
|
||||||
|
<< "Unable to evaluate parameter "
|
||||||
|
<< (*cur).first << " value: " << *expr << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
(*cur).second.expr = NULL;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ivl_assert(*expr, 0);
|
cerr << expr->get_fileline()
|
||||||
|
<< ": internal error: "
|
||||||
|
<< "Unhandled expression type?" << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
(*cur).second.expr = NULL;
|
||||||
|
return;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -564,7 +579,7 @@ void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur)
|
||||||
if (! from_flag) {
|
if (! from_flag) {
|
||||||
cerr << res->get_fileline() << ": error: "
|
cerr << res->get_fileline() << ": error: "
|
||||||
<< "Parameter value " << value
|
<< "Parameter value " << value
|
||||||
<< " is out of range for parameter " << (*cur).first
|
<< " is out of range for real parameter " << (*cur).first
|
||||||
<< "." << endl;
|
<< "." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
}
|
}
|
||||||
|
|
@ -592,7 +607,7 @@ void NetScope::evaluate_parameters(Design*des)
|
||||||
|
|
||||||
// Resolve the expression type (signed/unsigned) if the
|
// Resolve the expression type (signed/unsigned) if the
|
||||||
// expression is present. It is possible to not be
|
// expression is present. It is possible to not be
|
||||||
// present if there are earlier errors en elaboration.
|
// present if there are earlier errors in elaboration.
|
||||||
if (cur->second.expr)
|
if (cur->second.expr)
|
||||||
cur->second.expr->resolve_pexpr_type();
|
cur->second.expr->resolve_pexpr_type();
|
||||||
|
|
||||||
|
|
|
||||||
16
net_expr.cc
16
net_expr.cc
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2002-2009 Stephen Williams (steve@icarus.com)
|
* Copyright (c) 2002-2010 Stephen Williams (steve@icarus.com)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -488,18 +488,21 @@ const NetScope* NetECRealParam::scope() const
|
||||||
NetEParam::NetEParam()
|
NetEParam::NetEParam()
|
||||||
: des_(0), scope_(0)
|
: des_(0), scope_(0)
|
||||||
{
|
{
|
||||||
|
solving_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetEParam::NetEParam(Design*d, NetScope*s, perm_string n)
|
NetEParam::NetEParam(Design*d, NetScope*s, perm_string n)
|
||||||
: des_(d), scope_(s), reference_(scope_->find_parameter(n))
|
: des_(d), scope_(s), reference_(scope_->find_parameter(n))
|
||||||
{
|
{
|
||||||
cast_signed_base_(reference_->second.signed_flag);
|
cast_signed_base_(reference_->second.signed_flag);
|
||||||
|
solving_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetEParam::NetEParam(Design*d, NetScope*s, ref_t ref)
|
NetEParam::NetEParam(Design*d, NetScope*s, ref_t ref)
|
||||||
: des_(d), scope_(s), reference_(ref)
|
: des_(d), scope_(s), reference_(ref)
|
||||||
{
|
{
|
||||||
cast_signed_base_(reference_->second.signed_flag);
|
cast_signed_base_(reference_->second.signed_flag);
|
||||||
|
solving_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetEParam::~NetEParam()
|
NetEParam::~NetEParam()
|
||||||
|
|
@ -519,10 +522,21 @@ ivl_variable_type_t NetEParam::expr_type() const
|
||||||
NetEParam* NetEParam::dup_expr() const
|
NetEParam* NetEParam::dup_expr() const
|
||||||
{
|
{
|
||||||
NetEParam*tmp = new NetEParam(des_, scope_, reference_);
|
NetEParam*tmp = new NetEParam(des_, scope_, reference_);
|
||||||
|
tmp->solving(solving_);
|
||||||
tmp->set_line(*this);
|
tmp->set_line(*this);
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetEParam::solving(bool arg)
|
||||||
|
{
|
||||||
|
solving_ = arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NetEParam::solving() const
|
||||||
|
{
|
||||||
|
return solving_;
|
||||||
|
}
|
||||||
|
|
||||||
NetESelect::NetESelect(NetExpr*exp, NetExpr*base, unsigned wid)
|
NetESelect::NetESelect(NetExpr*exp, NetExpr*base, unsigned wid)
|
||||||
: expr_(exp), base_(base)
|
: expr_(exp), base_(base)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3563,6 +3563,8 @@ class NetEParam : public NetExpr {
|
||||||
virtual ivl_variable_type_t expr_type() const;
|
virtual ivl_variable_type_t expr_type() const;
|
||||||
virtual NetExpr* eval_tree(int prune_to_width = -1);
|
virtual NetExpr* eval_tree(int prune_to_width = -1);
|
||||||
virtual NetEParam* dup_expr() const;
|
virtual NetEParam* dup_expr() const;
|
||||||
|
void solving(bool arg);
|
||||||
|
bool solving() const;
|
||||||
|
|
||||||
virtual void dump(ostream&) const;
|
virtual void dump(ostream&) const;
|
||||||
|
|
||||||
|
|
@ -3571,6 +3573,7 @@ class NetEParam : public NetExpr {
|
||||||
NetScope*scope_;
|
NetScope*scope_;
|
||||||
typedef map<perm_string,NetScope::param_expr_t>::iterator ref_t;
|
typedef map<perm_string,NetScope::param_expr_t>::iterator ref_t;
|
||||||
ref_t reference_;
|
ref_t reference_;
|
||||||
|
bool solving_;
|
||||||
|
|
||||||
NetEParam(class Design*des, NetScope*scope, ref_t ref);
|
NetEParam(class Design*des, NetScope*scope, ref_t ref);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue