diff --git a/Statement.h b/Statement.h index e2e95040e..9f49a0b8d 100644 --- a/Statement.h +++ b/Statement.h @@ -108,7 +108,8 @@ class PAssign_ : public Statement { NetAssign_* elaborate_lval(Design*, NetScope*scope) const; NetExpr* elaborate_rval_(Design*, NetScope*, ivl_type_t lv_net_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_obj_(Design*, NetScope*, diff --git a/elab_expr.cc b/elab_expr.cc index d4394c1cc..6d8c1236d 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -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, 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) { 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, - false, lv_type); + false, lv_type, force_unsigned); } /* diff --git a/elab_lval.cc b/elab_lval.cc index ab277685f..718d80e76 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -138,6 +138,9 @@ NetAssign_* PEConcat::elaborate_lval(Design*des, continue; } + /* A concatenation is always unsigned. */ + tmp->set_signed(false); + /* Link the new l-value to the previous one. */ NetAssign_*last = tmp; while (last->more) @@ -399,6 +402,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, /* No select expressions. */ NetAssign_*lv = new NetAssign_(reg); + lv->set_signed(reg->get_signed()); return lv; } diff --git a/elaborate.cc b/elaborate.cc index 49fee42dc..62f55cd1a 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -2307,7 +2307,8 @@ NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope, NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope, ivl_type_t lv_net_type, ivl_variable_type_t lv_type, - unsigned lv_width) const + unsigned lv_width, + bool force_unsigned) const { 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 // 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, - rval(), is_constant_); + rval(), is_constant_, force_unsigned); 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); 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; NetAssign*cur = new NetAssign(lv, op_, rv); diff --git a/net_assign.cc b/net_assign.cc index c46a8aa2a..29005f885 100644 --- a/net_assign.cc +++ b/net_assign.cc @@ -44,6 +44,7 @@ NetAssign_::NetAssign_(NetAssign_*n) { lwid_ = 0; more = 0; + signed_ = false; turn_sig_to_wire_on_release_ = false; } @@ -53,6 +54,7 @@ NetAssign_::NetAssign_(NetNet*s) lwid_ = sig_->vector_width(); sig_->incr_lref(); more = 0; + signed_ = false; turn_sig_to_wire_on_release_ = false; } diff --git a/netlist.h b/netlist.h index 2b731f54b..285a5533f 100644 --- a/netlist.h +++ b/netlist.h @@ -2764,6 +2764,12 @@ class NetAssign_ { void set_property(const perm_string&name); 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 // method accounts for the presence of the mux, so it is not // necessarily the same as the pin_count(). @@ -2814,6 +2820,7 @@ class NetAssign_ { // member/property if signal is a class. perm_string member_; + bool signed_; bool turn_sig_to_wire_on_release_; // indexed part select base NetExpr*base_; diff --git a/netmisc.cc b/netmisc.cc index 50a48a2c3..2ced04acb 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -802,9 +802,10 @@ NetExpr* condition_reduce(NetExpr*expr) } static NetExpr* do_elab_and_eval(Design*des, NetScope*scope, PExpr*pe, - int context_width, bool need_const, bool annotatable, - bool force_expand, - ivl_variable_type_t cast_type) + int context_width, bool need_const, + bool annotatable, bool force_expand, + ivl_variable_type_t cast_type, + bool force_unsigned) { PExpr::width_mode_t mode = PExpr::SIZED; 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)) 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) { cerr << pe->get_fileline() << ": elab_and_eval: test_width of " << *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, 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, - 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) { 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, diff --git a/netmisc.h b/netmisc.h index 9accf6f20..2da355359 100644 --- a/netmisc.h +++ b/netmisc.h @@ -258,7 +258,8 @@ extern NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, int context_width, bool need_const =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, 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_variable_type_t lv_type, 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, std::vector&llist,