Skip to content

Commit

Permalink
Handle ternary expressions with mixed argument types.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
steveicarus committed Jan 6, 2009
1 parent 8eb7e4b commit 707a3eb
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 28 deletions.
4 changes: 4 additions & 0 deletions PExpr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_;
Expand Down
70 changes: 52 additions & 18 deletions elab_expr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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
Expand All @@ -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_;
}

Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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__,
Expand Down
4 changes: 3 additions & 1 deletion eval_tree.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
17 changes: 13 additions & 4 deletions expr_synth.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1184,12 +1184,21 @@ NetNet* NetETernary::synthesize(Design *des, NetScope*scope, NetExpr*root)
osig->data_type(expr_type());
osig->local_flag(true);

/* 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. */
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);
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,
Expand Down
15 changes: 10 additions & 5 deletions netlist.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}

Expand Down

0 comments on commit 707a3eb

Please sign in to comment.