From 0abefc61fbdb08a3f07ca78bf58be4a63a3bc7d0 Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 1 Dec 2008 19:21:47 -0800 Subject: [PATCH] Fix out of range indexed part selects and negative verinum width calc. This patch fixes fully out of range constant indexed part selects to just return 'bx. It also adds support for constant undefined base values which also just return 'bx. A bug in the bit width calculation when building an unsized, signed negative integer value was also fixed (-3 needs 3 bits not 2, etc.) --- elab_expr.cc | 62 ++++++++++++++++++++++++++++++--------------------- expr_synth.cc | 28 ++++++++++++++++++----- verinum.cc | 5 +++-- 3 files changed, 63 insertions(+), 32 deletions(-) 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; }