From 707a3ebe2779ac061acd64ee1853f17c9cbc9b30 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 5 Jan 2009 19:44:52 -0800 Subject: [PATCH] Handle ternary expressions with mixed argument types. If the true and false alternatives are mixed types, then vectored arguments are treated as if in a self-determined context then cast to REAL. --- PExpr.h | 4 +++ elab_expr.cc | 70 ++++++++++++++++++++++++++++++++++++++------------- eval_tree.cc | 4 ++- expr_synth.cc | 19 ++++++++++---- netlist.cc | 15 +++++++---- 5 files changed, 83 insertions(+), 29 deletions(-) diff --git a/PExpr.h b/PExpr.h index b3d72bfc1..895d5263f 100644 --- a/PExpr.h +++ b/PExpr.h @@ -621,6 +621,10 @@ class PETernary : public PExpr { virtual NetETernary*elaborate_pexpr(Design*des, NetScope*sc) const; virtual verinum* eval_const(Design*des, NetScope*sc) const; + private: + NetExpr* elab_and_eval_alternative_(Design*des, NetScope*scope, + PExpr*expr, int use_wid) const; + private: PExpr*expr_; PExpr*tru_; diff --git a/elab_expr.cc b/elab_expr.cc index 2f2b6c643..7a8942242 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -83,20 +83,22 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_variable_type_t data_type_lv, int expr_wid_lv, PExpr*expr) { - bool unsized_flag = type_is_vectorable(data_type_lv)? false : true; - ivl_variable_type_t rval_type = IVL_VT_NO_TYPE; + bool unsized_flag = type_is_vectorable(data_type_lv)? false : true; + unsigned use_lval_wid = type_is_vectorable(data_type_lv)? expr_wid_lv : 0; + unsigned use_min_wid = expr_wid_lv; /* Find out what the r-value width is going to be. We guess it will be the l-value width, but it may turn out to be something else based on self-determined widths inside. */ - int expr_wid = expr->test_width(des, scope, expr_wid_lv, expr_wid_lv, rval_type, unsized_flag); + ivl_variable_type_t rval_type = IVL_VT_NO_TYPE; + int expr_wid = expr->test_width(des, scope, use_min_wid, use_lval_wid, rval_type, unsized_flag); if (debug_elaborate) { cerr << expr->get_fileline() << ": debug: r-value tested " << "type=" << rval_type << ", width=" << expr_wid - << ", min=" << expr_wid_lv + << ", min=" << use_min_wid << ", unsized_flag=" << (unsized_flag?"true":"false") << endl; } @@ -2799,7 +2801,7 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope, unsigned PENumber::test_width(Design*, NetScope*, unsigned min, unsigned lval, - ivl_variable_type_t&expr_type__, + ivl_variable_type_t&use_expr_type, bool&unsized_flag) { expr_type_ = IVL_VT_LOGIC; @@ -2813,7 +2815,7 @@ unsigned PENumber::test_width(Design*, NetScope*, if (lval > 0 && lval < use_wid) use_wid = lval; - expr_type__ = expr_type_; + use_expr_type = expr_type_; expr_width_ = use_wid; return use_wid; } @@ -2866,7 +2868,7 @@ NetEConst* PEString::elaborate_expr(Design*des, NetScope*, unsigned PETernary::test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, - ivl_variable_type_t&expr_type__, + ivl_variable_type_t&use_expr_type, bool&flag) { // The condition of the ternary is self-determined, but we @@ -2893,16 +2895,32 @@ unsigned PETernary::test_width(Design*des, NetScope*scope, tru_wid = tru_->test_width(des, scope, max(min,fal_wid), lval, tru_type, flag); } - if (tru_type == IVL_VT_REAL || fal_type == IVL_VT_REAL) + // If either of the alternatives is IVL_VT_REAL, then the + // expression as a whole is IVL_VT_REAL. Otherwise, if either + // of the alternatives is IVL_VT_LOGIC, then the expression as + // a whole is IVL_VT_LOGIC. The fallback assumes that the + // types are the same and we take that. + if (tru_type == IVL_VT_REAL || fal_type == IVL_VT_REAL) { expr_type_ = IVL_VT_REAL; - else if (tru_type == IVL_VT_LOGIC || fal_type == IVL_VT_LOGIC) + expr_width_ = 1; + } else if (tru_type == IVL_VT_LOGIC || fal_type == IVL_VT_LOGIC) { expr_type_ = IVL_VT_LOGIC; - else + expr_width_ = max(tru_wid,fal_wid); + } else { + ivl_assert(*this, tru_type == fal_type); expr_type_ = tru_type; + expr_width_ = max(tru_wid,fal_wid); + } - expr_width_ = max(tru_wid,fal_wid); + if (debug_elaborate) + cerr << get_fileline() << ": debug: " + << "Ternary expression type=" << expr_type_ + << ", width=" << expr_width_ + << ", unsized_flag=" << flag + << " (tru_type=" << tru_type + << ", fal_type=" << fal_type << ")" << endl; - expr_type__ = expr_type_; + use_expr_type = expr_type_; return expr_width_; } @@ -2982,8 +3000,8 @@ NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope, << " of expression: " << *this << endl; } ivl_assert(*this, use_wid > 0); - NetExpr*tru = elab_and_eval(des, scope, tru_, use_wid); - return pad_to_width(tru, use_wid, *this); + NetExpr*tmp = elab_and_eval_alternative_(des, scope, tru_, use_wid); + return pad_to_width(tmp, use_wid, *this); } // Condition is constant FALSE, so we only need the @@ -3000,21 +3018,21 @@ NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope, << " of expression: " << *this << endl; } ivl_assert(*this, use_wid > 0); - NetExpr*fal = elab_and_eval(des, scope, fal_, use_wid); - return pad_to_width(fal, use_wid, *this); + NetExpr*tmp = elab_and_eval_alternative_(des, scope, fal_, use_wid); + return pad_to_width(tmp, use_wid, *this); } // X and Z conditions need to blend both results, so we // can't short-circuit. } - NetExpr*tru = elab_and_eval(des, scope, tru_, use_wid); + NetExpr*tru = elab_and_eval_alternative_(des, scope, tru_, use_wid); if (tru == 0) { delete con; return 0; } - NetExpr*fal = elab_and_eval(des, scope, fal_, use_wid); + NetExpr*fal = elab_and_eval_alternative_(des, scope, fal_, use_wid); if (fal == 0) { delete con; delete tru; @@ -3042,6 +3060,22 @@ NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope, return res; } +/* + * When elaborating the true or false alternative expression of a + * ternary, take into account the overall expression type. If the type + * is not vectorable, then the alternative expression is evaluated as + * self-determined. + */ +NetExpr* PETernary::elab_and_eval_alternative_(Design*des, NetScope*scope, + PExpr*expr, int use_wid) const +{ + if (type_is_vectorable(expr->expr_type()) && !type_is_vectorable(expr_type_)) { + return elab_and_eval(des, scope, expr, -1); + } + + return elab_and_eval(des, scope, expr, use_wid); +} + unsigned PEUnary::test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type__, diff --git a/eval_tree.cc b/eval_tree.cc index c16bddb08..9a9843c13 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -1484,7 +1484,9 @@ NetExpr* NetETernary::eval_tree(int prune_to_width) << "constant condition value: "; print_ternary_cond(cond_); cerr << get_fileline() << ": : Blending real cases " - << "to get " << val << endl; + << "true=" << tv.as_double() + << ", false=" << fv.as_double() + << ", to get " << val << endl; } NetECReal*rc = new NetECReal(val); diff --git a/expr_synth.cc b/expr_synth.cc index bf1c44879..0691d9188 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -1184,12 +1184,21 @@ NetNet* NetETernary::synthesize(Design *des, NetScope*scope, NetExpr*root) osig->data_type(expr_type()); osig->local_flag(true); - /* Make sure both value operands are the right width. */ - tsig = crop_to_width(des, pad_to_width(des, tsig, width, *this), width); - fsig = crop_to_width(des, pad_to_width(des, fsig, width, *this), width); + /* Make sure the types match. */ + if (expr_type() == IVL_VT_REAL) { + tsig = cast_to_real(des, scope, tsig); + fsig = cast_to_real(des, scope, fsig); + + } + + /* Make sure both value operands are the right width. */ + if (type_is_vectorable(expr_type())) { + tsig = crop_to_width(des, pad_to_width(des, tsig, width, *this), width); + fsig = crop_to_width(des, pad_to_width(des, fsig, width, *this), width); + ivl_assert(*this, width == tsig->vector_width()); + ivl_assert(*this, width == fsig->vector_width()); + } - assert(width == tsig->vector_width()); - assert(width == fsig->vector_width()); perm_string oname = csig->scope()->local_symbol(); NetMux *mux = new NetMux(csig->scope(), oname, width, diff --git a/netlist.cc b/netlist.cc index a8e588d19..6886b4a76 100644 --- a/netlist.cc +++ b/netlist.cc @@ -2270,11 +2270,16 @@ ivl_variable_type_t NetESignal::expr_type() const NetETernary::NetETernary(NetExpr*c, NetExpr*t, NetExpr*f) : cond_(c), true_val_(t), false_val_(f) { - // use widest result - if (true_val_->expr_width() > false_val_->expr_width()) - expr_width(true_val_->expr_width()); - else - expr_width(false_val_->expr_width()); + if (type_is_vectorable(expr_type())) { + // use widest result + if (true_val_->expr_width() > false_val_->expr_width()) + expr_width(true_val_->expr_width()); + else + expr_width(false_val_->expr_width()); + } else { + expr_width(1); + } + cast_signed(c->has_sign() && t->has_sign() && f->has_sign()); }