diff --git a/elab_expr.cc b/elab_expr.cc index 8cb1b164f..39360ab30 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -2526,16 +2526,26 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, // well. In this case it can be converted to a conventional // part select. if (NetEConst*base_c = dynamic_cast (base)) { - long lsv = base_c->value().as_long(); + NetExpr*ex; + if (base_c->value().is_defined()) { + long lsv = base_c->value().as_long(); - // If the part select covers exactly the entire - // vector, then do not bother with it. Return the - // signal itself. - if (net->sig()->sb_to_idx(lsv) == 0 && wid == net->vector_width()) - return net; + // If the part select covers exactly the entire + // vector, then do not bother with it. Return the + // signal itself. + if (net->sig()->sb_to_idx(lsv) == 0 && + wid == net->vector_width()) { + delete base; + return net; + } - // Otherwise, make a part select that covers the right range. - NetExpr*ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv))); + // Otherwise, make a part select that covers the right + // range. + ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv))); + } else { + // Return 'bx for an undefined base. + ex = new NetEConst(verinum(verinum::Vx, 1, false)); + } NetESelect*ss = new NetESelect(net, ex, wid); ss->set_line(*this); @@ -2569,14 +2579,7 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope, NetESignal*net, NetScope*found_in)const { - const name_component_t&name_tail = path_.back(); - ivl_assert(*this, ! name_tail.index.empty()); - - const index_component_t&index_tail = name_tail.index.back(); - ivl_assert(*this, index_tail.lsb != 0); - ivl_assert(*this, index_tail.msb != 0); - - NetExpr*base = elab_and_eval(des, scope, index_tail.msb, -1); + NetExpr*base = calculate_up_do_base_(des, scope); unsigned long wid = 0; calculate_up_do_width_(des, scope, wid); @@ -2585,17 +2588,26 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope, // well. In this case it can be converted to a conventional // part select. if (NetEConst*base_c = dynamic_cast (base)) { - long lsv = base_c->value().as_long(); + NetExpr*ex; + if (base_c->value().is_defined()) { + long lsv = base_c->value().as_long(); - // If the part select covers exactly the entire - // vector, then do not bother with it. Return the - // signal itself. - if (net->sig()->sb_to_idx(lsv) == (signed) (wid-1) && - wid == net->vector_width()) - return net; + // If the part select covers exactly the entire + // vector, then do not bother with it. Return the + // signal itself. + if (net->sig()->sb_to_idx(lsv) == (signed) (wid-1) && + wid == net->vector_width()) { + delete base; + return net; + } - // Otherwise, make a part select that covers the right range. - NetExpr*ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv)-wid+1)); + // Otherwise, make a part select that covers the right + // range. + ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv)-wid+1)); + } else { + // Return 'bx for an undefined base. + ex = new NetEConst(verinum(verinum::Vx, 1, false)); + } NetESelect*ss = new NetESelect(net, ex, wid); ss->set_line(*this); diff --git a/expr_synth.cc b/expr_synth.cc index 89fd2d2b8..3ac8ce9f0 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -974,31 +974,49 @@ NetNet* NetESelect::synthesize(Design *des, NetScope*scope) // it is constant. In this case we can generate fixed part selects. if (NetEConst*base_const = dynamic_cast(base_)) { verinum base_tmp = base_const->value(); - ivl_assert(*this, base_tmp.is_defined()); + unsigned select_width = expr_width(); + + // Return 'bx for a constant undefined selections. + if (!base_tmp.is_defined()) { + NetNet*result = make_const_x(des, scope, select_width); + result->set_line(*this); + return result; + } long base_val = base_tmp.as_long(); - unsigned select_width = expr_width(); // Any below X bits? NetNet*below = 0; if (base_val < 0) { unsigned below_width = abs(base_val); base_val = 0; - ivl_assert(*this, below_width < select_width); - select_width -= below_width; + if (below_width > select_width) { + below_width = select_width; + select_width = 0; + } else { + select_width -= below_width; + } below = make_const_x(des, scope, below_width); below->set_line(*this); + // All the selected bits are below the signal. + if (select_width == 0) return below; } // Any above bits? NetNet*above = 0; if ((unsigned)base_val+select_width > sub->vector_width()) { - select_width = sub->vector_width() - base_val; + if (base_val > (long)sub->vector_width()) { + select_width = 0; + } else { + select_width = sub->vector_width() - base_val; + } unsigned above_width = expr_width() - select_width; above = make_const_x(des, scope, above_width); above->set_line(*this); + // All the selected bits are above the signal. + if (select_width == 0) return above; } // Make the make part select. diff --git a/verinum.cc b/verinum.cc index 67a57e81b..f85509381 100644 --- a/verinum.cc +++ b/verinum.cc @@ -315,9 +315,10 @@ verinum::verinum(int64_t that) { int64_t tmp; - tmp = that/2; + if (that < 0) tmp = (that+1)/2; + else tmp = that/2; nbits_ = 1; - while ((tmp != 0) && (tmp != -1)) { + while (tmp != 0) { nbits_ += 1; tmp /= 2; }