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:
Cary R 2010-09-07 16:31:53 -07:00 committed by Stephen Williams
parent 7c4d07bda6
commit 97a3bf5aeb
4 changed files with 68 additions and 30 deletions

View File

@ -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;

View File

@ -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();

View File

@ -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)
{ {

View File

@ -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);
}; };