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:
parent
241b6723e5
commit
0199ad129d
|
|
@ -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*,
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
elaborate.cc
12
elaborate.cc
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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_;
|
||||||
|
|
|
||||||
20
netmisc.cc
20
netmisc.cc
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue