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
5e1546faaf
commit
4b98a50dce
28
eval_tree.cc
28
eval_tree.cc
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
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
|
||||
* 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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue