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.)
This commit is contained in:
Cary R 2008-12-01 19:21:47 -08:00 committed by Stephen Williams
parent a84682e07d
commit 0abefc61fb
3 changed files with 63 additions and 32 deletions

View File

@ -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 // well. In this case it can be converted to a conventional
// part select. // part select.
if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) { if (NetEConst*base_c = dynamic_cast<NetEConst*> (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 // If the part select covers exactly the entire
// vector, then do not bother with it. Return the // vector, then do not bother with it. Return the
// signal itself. // signal itself.
if (net->sig()->sb_to_idx(lsv) == 0 && wid == net->vector_width()) if (net->sig()->sb_to_idx(lsv) == 0 &&
return net; wid == net->vector_width()) {
delete base;
return net;
}
// Otherwise, make a part select that covers the right range. // Otherwise, make a part select that covers the right
NetExpr*ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv))); // 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); NetESelect*ss = new NetESelect(net, ex, wid);
ss->set_line(*this); 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, NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
NetESignal*net, NetScope*found_in)const NetESignal*net, NetScope*found_in)const
{ {
const name_component_t&name_tail = path_.back(); NetExpr*base = calculate_up_do_base_(des, scope);
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);
unsigned long wid = 0; unsigned long wid = 0;
calculate_up_do_width_(des, scope, wid); 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 // well. In this case it can be converted to a conventional
// part select. // part select.
if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) { if (NetEConst*base_c = dynamic_cast<NetEConst*> (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 // If the part select covers exactly the entire
// vector, then do not bother with it. Return the // vector, then do not bother with it. Return the
// signal itself. // signal itself.
if (net->sig()->sb_to_idx(lsv) == (signed) (wid-1) && if (net->sig()->sb_to_idx(lsv) == (signed) (wid-1) &&
wid == net->vector_width()) wid == net->vector_width()) {
return net; delete base;
return net;
}
// Otherwise, make a part select that covers the right range. // Otherwise, make a part select that covers the right
NetExpr*ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv)-wid+1)); // 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); NetESelect*ss = new NetESelect(net, ex, wid);
ss->set_line(*this); ss->set_line(*this);

View File

@ -974,31 +974,49 @@ NetNet* NetESelect::synthesize(Design *des, NetScope*scope)
// it is constant. In this case we can generate fixed part selects. // it is constant. In this case we can generate fixed part selects.
if (NetEConst*base_const = dynamic_cast<NetEConst*>(base_)) { if (NetEConst*base_const = dynamic_cast<NetEConst*>(base_)) {
verinum base_tmp = base_const->value(); 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(); long base_val = base_tmp.as_long();
unsigned select_width = expr_width();
// Any below X bits? // Any below X bits?
NetNet*below = 0; NetNet*below = 0;
if (base_val < 0) { if (base_val < 0) {
unsigned below_width = abs(base_val); unsigned below_width = abs(base_val);
base_val = 0; base_val = 0;
ivl_assert(*this, below_width < select_width); if (below_width > select_width) {
select_width -= below_width; below_width = select_width;
select_width = 0;
} else {
select_width -= below_width;
}
below = make_const_x(des, scope, below_width); below = make_const_x(des, scope, below_width);
below->set_line(*this); below->set_line(*this);
// All the selected bits are below the signal.
if (select_width == 0) return below;
} }
// Any above bits? // Any above bits?
NetNet*above = 0; NetNet*above = 0;
if ((unsigned)base_val+select_width > sub->vector_width()) { 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; unsigned above_width = expr_width() - select_width;
above = make_const_x(des, scope, above_width); above = make_const_x(des, scope, above_width);
above->set_line(*this); above->set_line(*this);
// All the selected bits are above the signal.
if (select_width == 0) return above;
} }
// Make the make part select. // Make the make part select.

View File

@ -315,9 +315,10 @@ verinum::verinum(int64_t that)
{ {
int64_t tmp; int64_t tmp;
tmp = that/2; if (that < 0) tmp = (that+1)/2;
else tmp = that/2;
nbits_ = 1; nbits_ = 1;
while ((tmp != 0) && (tmp != -1)) { while (tmp != 0) {
nbits_ += 1; nbits_ += 1;
tmp /= 2; tmp /= 2;
} }