From 97a3bf5aeb3ecd0a014921c4d3c4bb192c1ed0d7 Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 7 Sep 2010 16:31:53 -0700 Subject: [PATCH] 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. --- eval_tree.cc | 28 +++++++++++++++++----------- net_design.cc | 51 +++++++++++++++++++++++++++++++++------------------ net_expr.cc | 16 +++++++++++++++- netlist.h | 3 +++ 4 files changed, 68 insertions(+), 30 deletions(-) diff --git a/eval_tree.cc b/eval_tree.cc index 6f744f452..993025568 100644 --- a/eval_tree.cc +++ b/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(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(nexpr)) { + if (const NetEConst*tmp = dynamic_cast(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(nexpr)) { + if (const NetECReal*tmp = dynamic_cast(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; diff --git a/net_design.cc b/net_design.cc index 0e09642e4..cded937b8 100644 --- a/net_design.cc +++ b/net_design.cc @@ -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 * 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); 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; @@ -335,8 +334,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; @@ -362,10 +360,10 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur) case IVL_VT_REAL: if (! dynamic_cast(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; @@ -374,11 +372,10 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur) case IVL_VT_BOOL: if (! dynamic_cast(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; @@ -386,8 +383,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; } @@ -500,7 +498,13 @@ void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur) if (NetECReal*tmp = dynamic_cast(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; @@ -511,12 +515,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; } @@ -564,7 +579,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; } @@ -592,7 +607,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(); diff --git a/net_expr.cc b/net_expr.cc index 3b5890caa..1dc1c3cb1 100644 --- a/net_expr.cc +++ b/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) { diff --git a/netlist.h b/netlist.h index c6fef28e3..6f8955c5f 100644 --- a/netlist.h +++ b/netlist.h @@ -3563,6 +3563,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; @@ -3571,6 +3573,7 @@ class NetEParam : public NetExpr { NetScope*scope_; typedef map::iterator ref_t; ref_t reference_; + bool solving_; NetEParam(class Design*des, NetScope*scope, ref_t ref); };