Fix expression type for compressed assignment statements.

A compressed assignment statement should give exactly the same
result as the equivalent uncompressed statement. This means
that the type (signed/unsigned) of the LHS affects the type of
the RHS expression (unlike in normal assignments). We need to
take care that bit/part selects and concatenations are correctly
identified as unsigned values, even in the cases where they
reduce to a single whole signal.
This commit is contained in:
Martin Whitaker 2016-02-23 16:53:01 +00:00
parent 241b6723e5
commit 0199ad129d
8 changed files with 44 additions and 14 deletions

View File

@ -108,7 +108,8 @@ class PAssign_ : public Statement {
NetAssign_* elaborate_lval(Design*, NetScope*scope) const; NetAssign_* elaborate_lval(Design*, NetScope*scope) const;
NetExpr* elaborate_rval_(Design*, NetScope*, ivl_type_t lv_net_type, NetExpr* elaborate_rval_(Design*, NetScope*, ivl_type_t lv_net_type,
ivl_variable_type_t lv_type, ivl_variable_type_t lv_type,
unsigned lv_width) const; unsigned lv_width,
bool force_unsigned =false) const;
NetExpr* elaborate_rval_(Design*, NetScope*, ivl_type_t ntype) const; NetExpr* elaborate_rval_(Design*, NetScope*, ivl_type_t ntype) const;
NetExpr* elaborate_rval_obj_(Design*, NetScope*, NetExpr* elaborate_rval_obj_(Design*, NetScope*,

View File

@ -90,7 +90,7 @@ static NetBranch* find_existing_implicit_branch(NetNet*sig, NetNet*gnd)
NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_type_t lv_net_type, NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_type_t lv_net_type,
ivl_variable_type_t lv_type, unsigned lv_width, ivl_variable_type_t lv_type, unsigned lv_width,
PExpr*expr, bool need_const) PExpr*expr, bool need_const, bool force_unsigned)
{ {
if (debug_elaborate) { if (debug_elaborate) {
cerr << expr->get_fileline() << ": elaborate_rval_expr: " cerr << expr->get_fileline() << ": elaborate_rval_expr: "
@ -135,7 +135,7 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_type_t lv_net_type,
} }
return elab_and_eval(des, scope, expr, context_wid, need_const, return elab_and_eval(des, scope, expr, context_wid, need_const,
false, lv_type); false, lv_type, force_unsigned);
} }
/* /*

View File

@ -138,6 +138,9 @@ NetAssign_* PEConcat::elaborate_lval(Design*des,
continue; continue;
} }
/* A concatenation is always unsigned. */
tmp->set_signed(false);
/* Link the new l-value to the previous one. */ /* Link the new l-value to the previous one. */
NetAssign_*last = tmp; NetAssign_*last = tmp;
while (last->more) while (last->more)
@ -399,6 +402,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
/* No select expressions. */ /* No select expressions. */
NetAssign_*lv = new NetAssign_(reg); NetAssign_*lv = new NetAssign_(reg);
lv->set_signed(reg->get_signed());
return lv; return lv;
} }

View File

@ -2307,7 +2307,8 @@ NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,
NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope, NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,
ivl_type_t lv_net_type, ivl_type_t lv_net_type,
ivl_variable_type_t lv_type, ivl_variable_type_t lv_type,
unsigned lv_width) const unsigned lv_width,
bool force_unsigned) const
{ {
ivl_assert(*this, rval_); ivl_assert(*this, rval_);
@ -2316,7 +2317,7 @@ NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,
// should look into fixing calls to this method to pass a // should look into fixing calls to this method to pass a
// net_type instead of the separate lv_width/lv_type values. // net_type instead of the separate lv_width/lv_type values.
NetExpr*rv = elaborate_rval_expr(des, scope, lv_net_type, lv_type, lv_width, NetExpr*rv = elaborate_rval_expr(des, scope, lv_net_type, lv_type, lv_width,
rval(), is_constant_); rval(), is_constant_, force_unsigned);
if (!is_constant_ || !rv) return rv; if (!is_constant_ || !rv) return rv;
@ -2434,7 +2435,12 @@ NetProc* PAssign::elaborate_compressed_(Design*des, NetScope*scope) const
NetAssign_*lv = elaborate_lval(des, scope); NetAssign_*lv = elaborate_lval(des, scope);
if (lv == 0) return 0; if (lv == 0) return 0;
NetExpr*rv = elaborate_rval_(des, scope, 0, lv->expr_type(), count_lval_width(lv)); // Compressed assignments should behave identically to the
// equivalent uncompressed assignments. This means we need
// to take the type of the LHS into account when determining
// the type of the RHS expression.
NetExpr*rv = elaborate_rval_(des, scope, 0, lv->expr_type(),
count_lval_width(lv), !lv->get_signed());
if (rv == 0) return 0; if (rv == 0) return 0;
NetAssign*cur = new NetAssign(lv, op_, rv); NetAssign*cur = new NetAssign(lv, op_, rv);

View File

@ -44,6 +44,7 @@ NetAssign_::NetAssign_(NetAssign_*n)
{ {
lwid_ = 0; lwid_ = 0;
more = 0; more = 0;
signed_ = false;
turn_sig_to_wire_on_release_ = false; turn_sig_to_wire_on_release_ = false;
} }
@ -53,6 +54,7 @@ NetAssign_::NetAssign_(NetNet*s)
lwid_ = sig_->vector_width(); lwid_ = sig_->vector_width();
sig_->incr_lref(); sig_->incr_lref();
more = 0; more = 0;
signed_ = false;
turn_sig_to_wire_on_release_ = false; turn_sig_to_wire_on_release_ = false;
} }

View File

@ -2764,6 +2764,12 @@ class NetAssign_ {
void set_property(const perm_string&name); void set_property(const perm_string&name);
inline perm_string get_property(void) const { return member_; } inline perm_string get_property(void) const { return member_; }
// Determine if the assigned object is signed or unsigned.
// This is used when determining the expression type for
// a compressed assignment statement.
bool get_signed() const { return signed_; }
void set_signed(bool flag) { signed_ = flag; }
// Get the width of the r-value that this node expects. This // Get the width of the r-value that this node expects. This
// method accounts for the presence of the mux, so it is not // method accounts for the presence of the mux, so it is not
// necessarily the same as the pin_count(). // necessarily the same as the pin_count().
@ -2814,6 +2820,7 @@ class NetAssign_ {
// member/property if signal is a class. // member/property if signal is a class.
perm_string member_; perm_string member_;
bool signed_;
bool turn_sig_to_wire_on_release_; bool turn_sig_to_wire_on_release_;
// indexed part select base // indexed part select base
NetExpr*base_; NetExpr*base_;

View File

@ -802,9 +802,10 @@ NetExpr* condition_reduce(NetExpr*expr)
} }
static NetExpr* do_elab_and_eval(Design*des, NetScope*scope, PExpr*pe, static NetExpr* do_elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
int context_width, bool need_const, bool annotatable, int context_width, bool need_const,
bool force_expand, bool annotatable, bool force_expand,
ivl_variable_type_t cast_type) ivl_variable_type_t cast_type,
bool force_unsigned)
{ {
PExpr::width_mode_t mode = PExpr::SIZED; PExpr::width_mode_t mode = PExpr::SIZED;
if ((context_width == -2) && !gn_strict_expr_width_flag) if ((context_width == -2) && !gn_strict_expr_width_flag)
@ -824,6 +825,11 @@ static NetExpr* do_elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
if ((pe->expr_type() != IVL_VT_REAL) && (expr_width < pos_context_width)) if ((pe->expr_type() != IVL_VT_REAL) && (expr_width < pos_context_width))
expr_width = pos_context_width; expr_width = pos_context_width;
// If this is the RHS of a compressed assignment, the LHS also
// affects the expression type (signed/unsigned).
if (force_unsigned)
pe->cast_signed(false);
if (debug_elaborate) { if (debug_elaborate) {
cerr << pe->get_fileline() << ": elab_and_eval: test_width of " cerr << pe->get_fileline() << ": elab_and_eval: test_width of "
<< *pe << endl; << *pe << endl;
@ -910,10 +916,11 @@ static NetExpr* do_elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
int context_width, bool need_const, bool annotatable, int context_width, bool need_const, bool annotatable,
ivl_variable_type_t cast_type) ivl_variable_type_t cast_type, bool force_unsigned)
{ {
return do_elab_and_eval(des, scope, pe, context_width, return do_elab_and_eval(des, scope, pe, context_width,
need_const, annotatable, false, cast_type); need_const, annotatable, false,
cast_type, force_unsigned);
} }
/* /*
@ -926,7 +933,8 @@ NetExpr* elab_and_eval_lossless(Design*des, NetScope*scope, PExpr*pe,
ivl_variable_type_t cast_type) ivl_variable_type_t cast_type)
{ {
return do_elab_and_eval(des, scope, pe, context_width, return do_elab_and_eval(des, scope, pe, context_width,
need_const, annotatable, true, cast_type); need_const, annotatable, true,
cast_type, false);
} }
NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,

View File

@ -258,7 +258,8 @@ extern NetExpr* elab_and_eval(Design*des, NetScope*scope,
PExpr*pe, int context_width, PExpr*pe, int context_width,
bool need_const =false, bool need_const =false,
bool annotatable =false, bool annotatable =false,
ivl_variable_type_t cast_type =IVL_VT_NO_TYPE); ivl_variable_type_t cast_type =IVL_VT_NO_TYPE,
bool force_unsigned =false);
extern NetExpr* elab_and_eval_lossless(Design*des, NetScope*scope, extern NetExpr* elab_and_eval_lossless(Design*des, NetScope*scope,
PExpr*pe, int context_width, PExpr*pe, int context_width,
@ -297,7 +298,8 @@ extern NetExpr* elaborate_rval_expr(Design*des, NetScope*scope,
ivl_type_t lv_net_type, ivl_type_t lv_net_type,
ivl_variable_type_t lv_type, ivl_variable_type_t lv_type,
unsigned lv_width, PExpr*expr, unsigned lv_width, PExpr*expr,
bool need_const =false); bool need_const =false,
bool force_unsigned =false);
extern bool evaluate_ranges(Design*des, NetScope*scope, extern bool evaluate_ranges(Design*des, NetScope*scope,
std::vector<netrange_t>&llist, std::vector<netrange_t>&llist,