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:18:06 -07:00 committed by Stephen Williams
parent 5e1546faaf
commit 4b98a50dce
4 changed files with 67 additions and 29 deletions

View File

@ -858,7 +858,7 @@ NetExpr* NetEBDiv::eval_tree(int prune_to_width)
eval_expr(right_);
if (expr_type() == IVL_VT_REAL) return eval_tree_real_();
assert(expr_type() == IVL_VT_LOGIC);
NetEConst*lc = dynamic_cast<NetEConst*>(left_);
@ -1228,6 +1228,12 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
<< *this << endl;
}
if (solving()) {
cerr << get_fileline() << ": warning: Recursive parameter "
"reference found involving " << *this << "." << endl;
return 0;
}
assert(scope_);
perm_string name = (*reference_).first;
const NetExpr*expr = (*reference_).second.expr;
@ -1239,35 +1245,35 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
<< *this << " cannot be evaluated." << endl;
return 0;
}
// ivl_assert(*this, expr);
NetExpr*nexpr = expr->dup_expr();
assert(nexpr);
// If the parameter that I refer to is already evaluated, then
// return the constant value.
if (NetEConst*tmp = dynamic_cast<NetEConst*>(nexpr)) {
if (const NetEConst*tmp = dynamic_cast<const NetEConst*>(expr)) {
verinum val = tmp->value();
NetEConstParam*ptmp = new NetEConstParam(scope_, name, val);
ptmp->set_line(*this);
delete nexpr;
return ptmp;
}
if (NetECReal*tmp = dynamic_cast<NetECReal*>(nexpr)) {
if (const NetECReal*tmp = dynamic_cast<const NetECReal*>(expr)) {
verireal val = tmp->value();
NetECRealParam*ptmp = new NetECRealParam(scope_, name, val);
ptmp->set_line(*this);
delete nexpr;
return ptmp;
}
// Try to evaluate the expression. If I cannot, then the
// expression is not a constant expression and I fail here.
solving(true);
NetExpr*nexpr = expr->dup_expr();
assert(nexpr);
NetExpr*res = nexpr->eval_tree();
solving(false);
if (res == 0) {
cerr << get_fileline() << ": internal error: Unable to evaluate "
<< "parameter " << name << " expression: "
cerr << get_fileline() << ": internal error: Unable to evaluate ";
if (expr_type() == IVL_VT_REAL) cerr << "real ";
cerr << "parameter " << name << " expression: "
<< *nexpr << endl;
delete nexpr;
return 0;

View File

@ -341,8 +341,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
eval_expr((*cur).second.msb);
if (! eval_as_long(msb, (*cur).second.msb)) {
cerr << (*cur).second.expr->get_fileline()
<< ": internal error: "
<< "unable to evaluate msb expression "
<< ": error: Unable to evaluate msb expression "
<< "for parameter " << (*cur).first << ": "
<< *(*cur).second.msb << endl;
des->errors += 1;
@ -357,8 +356,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
eval_expr((*cur).second.lsb);
if (! eval_as_long(lsb, (*cur).second.lsb)) {
cerr << (*cur).second.expr->get_fileline()
<< ": internal error: "
<< "unable to evaluate lsb expression "
<< ": error: Unable to evaluate lsb expression "
<< "for parameter " << (*cur).first << ": "
<< *(*cur).second.lsb << endl;
des->errors += 1;
@ -384,10 +382,10 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
case IVL_VT_REAL:
if (! dynamic_cast<const NetECReal*>(expr)) {
cerr << expr->get_fileline()
<< ": internal error: "
<< "unable to evaluate real parameter value: "
<< *expr << endl;
<< ": error: Unable to evaluate real parameter "
<< (*cur).first << " value: " << *expr << endl;
des->errors += 1;
(*cur).second.expr = NULL;
return;
}
break;
@ -396,11 +394,10 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
case IVL_VT_BOOL:
if (! dynamic_cast<const NetEConst*>(expr)) {
cerr << expr->get_fileline()
<< ": internal error: "
<< "unable to evaluate parameter "
<< (*cur).first
<< " value: " << *expr << endl;
<< ": error: Unable to evaluate parameter "
<< (*cur).first << " value: " << *expr << endl;
des->errors += 1;
(*cur).second.expr = NULL;
return;
}
break;
@ -408,8 +405,9 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
default:
cerr << expr->get_fileline()
<< ": internal error: "
<< "unhandled expression type?" << endl;
<< "Unhandled expression type?" << endl;
des->errors += 1;
(*cur).second.expr = NULL;
return;
}
@ -522,7 +520,13 @@ void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur)
if (NetECReal*tmp = dynamic_cast<NetECReal*>(expr)) {
res = tmp;
} 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;
@ -533,12 +537,23 @@ void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur)
res = new NetECReal(val);
res->set_line(*tmp);
} 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;
default:
ivl_assert(*expr, 0);
cerr << expr->get_fileline()
<< ": internal error: "
<< "Unhandled expression type?" << endl;
des->errors += 1;
(*cur).second.expr = NULL;
return;
break;
}
@ -586,7 +601,7 @@ void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur)
if (! from_flag) {
cerr << res->get_fileline() << ": error: "
<< "Parameter value " << value
<< " is out of range for parameter " << (*cur).first
<< " is out of range for real parameter " << (*cur).first
<< "." << endl;
des->errors += 1;
}
@ -612,7 +627,7 @@ void NetScope::evaluate_parameters(Design*des)
// Resolve the expression type (signed/unsigned) if the
// 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)
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
* 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()
: des_(0), scope_(0)
{
solving_ = false;
}
NetEParam::NetEParam(Design*d, NetScope*s, perm_string n)
: des_(d), scope_(s), reference_(scope_->find_parameter(n))
{
cast_signed_base_(reference_->second.signed_flag);
solving_ = false;
}
NetEParam::NetEParam(Design*d, NetScope*s, ref_t ref)
: des_(d), scope_(s), reference_(ref)
{
cast_signed_base_(reference_->second.signed_flag);
solving_ = false;
}
NetEParam::~NetEParam()
@ -519,10 +522,21 @@ ivl_variable_type_t NetEParam::expr_type() const
NetEParam* NetEParam::dup_expr() const
{
NetEParam*tmp = new NetEParam(des_, scope_, reference_);
tmp->solving(solving_);
tmp->set_line(*this);
return tmp;
}
void NetEParam::solving(bool arg)
{
solving_ = arg;
}
bool NetEParam::solving() const
{
return solving_;
}
NetESelect::NetESelect(NetExpr*exp, NetExpr*base, unsigned wid)
: expr_(exp), base_(base)
{

View File

@ -3574,6 +3574,8 @@ class NetEParam : public NetExpr {
virtual ivl_variable_type_t expr_type() const;
virtual NetExpr* eval_tree(int prune_to_width = -1);
virtual NetEParam* dup_expr() const;
void solving(bool arg);
bool solving() const;
virtual void dump(ostream&) const;
@ -3582,6 +3584,7 @@ class NetEParam : public NetExpr {
NetScope*scope_;
typedef map<perm_string,NetScope::param_expr_t>::iterator ref_t;
ref_t reference_;
bool solving_;
NetEParam(class Design*des, NetScope*scope, ref_t ref);
};