Handle part selects with bad (xz) bits.

Part selects need to be fully defined. If not, then the resulting
expression is 'bx no matter what. The same for bit selects, when
the bit select expression is constant.
This commit is contained in:
Stephen Williams 2009-01-01 16:20:41 -08:00
parent ea938b7907
commit b45834f074
4 changed files with 82 additions and 9 deletions

14
PExpr.h
View File

@ -293,8 +293,18 @@ class PEIdent : public PExpr {
pform_name_t path_; pform_name_t path_;
private: private:
// Common functions to calculate parts of part/bit selects. // Common functions to calculate parts of part/bit
bool calculate_parts_(Design*, NetScope*, long&msb, long&lsb) const; // selects. These methods return true if the expressions
// elaborate/calculate, or false if there is some sort of
// source error.
// The calculate_parts_ method calculates the range
// expressions of a part select for the current object. The
// part select expressions are elaborated and evaluated, and
// the values written to the msb/lsb arguments. If there are
// invalid bits (xz) in either expression, then the defined
// flag is set to *false*.
bool calculate_parts_(Design*, NetScope*, long&msb, long&lsb, bool&defined) const;
NetExpr* calculate_up_do_base_(Design*, NetScope*) const; NetExpr* calculate_up_do_base_(Design*, NetScope*) const;
bool calculate_param_range_(Design*, NetScope*, bool calculate_param_range_(Design*, NetScope*,
const NetExpr*msb_ex, long&msb, const NetExpr*msb_ex, long&msb,

View File

@ -1636,8 +1636,9 @@ NetExpr* PEFNumber::elaborate_expr(Design*des, NetScope*scope, int, bool) const
* convert the values to canonical form. * convert the values to canonical form.
*/ */
bool PEIdent::calculate_parts_(Design*des, NetScope*scope, bool PEIdent::calculate_parts_(Design*des, NetScope*scope,
long&msb, long&lsb) const long&msb, long&lsb, bool&defined) const
{ {
defined = true;
const name_component_t&name_tail = path_.back(); const name_component_t&name_tail = path_.back();
ivl_assert(*this, !name_tail.index.empty()); ivl_assert(*this, !name_tail.index.empty());
@ -1670,6 +1671,8 @@ bool PEIdent::calculate_parts_(Design*des, NetScope*scope,
/* Attempt to recover from error. */ /* Attempt to recover from error. */
lsb = 0; lsb = 0;
} else { } else {
if (! lsb_c->value().is_defined())
defined = false;
lsb = lsb_c->value().as_long(); lsb = lsb_c->value().as_long();
} }
@ -1686,6 +1689,8 @@ bool PEIdent::calculate_parts_(Design*des, NetScope*scope,
/* Attempt to recover from error. */ /* Attempt to recover from error. */
msb = lsb; msb = lsb;
} else { } else {
if (! msb_c->value().is_defined())
defined = false;
msb = msb_c->value().as_long(); msb = msb_c->value().as_long();
} }
@ -1801,8 +1806,12 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope,
break; break;
case index_component_t::SEL_PART: case index_component_t::SEL_PART:
{ long msb, lsb; { long msb, lsb;
calculate_parts_(des, scope, msb, lsb); bool parts_defined;
use_width = 1 + ((msb>lsb)? (msb-lsb) : (lsb-msb)); calculate_parts_(des, scope, msb, lsb, parts_defined);
if (parts_defined)
use_width = 1 + ((msb>lsb)? (msb-lsb) : (lsb-msb));
else
use_width = UINT_MAX;
break; break;
} }
case index_component_t::SEL_IDX_UP: case index_component_t::SEL_IDX_UP:
@ -2093,7 +2102,8 @@ NetExpr* PEIdent::elaborate_expr_param_part_(Design*des, NetScope*scope,
const NetExpr*par_lsb) const const NetExpr*par_lsb) const
{ {
long msv, lsv; long msv, lsv;
bool flag = calculate_parts_(des, scope, msv, lsv); bool parts_defined_flag;
bool flag = calculate_parts_(des, scope, msv, lsv, parts_defined_flag);
if (!flag) if (!flag)
return 0; return 0;
@ -2102,6 +2112,17 @@ NetExpr* PEIdent::elaborate_expr_param_part_(Design*des, NetScope*scope,
if (!flag) if (!flag)
return 0; return 0;
if (! parts_defined_flag) {
if (debug_elaborate)
cerr << get_fileline() << ": debug: Part select of paramter "
<< "has x/z bits, so resorting to 'bx result." << endl;
long wid = 1 + labs(par_msv-par_lsv);
NetEConst*tmp = make_const_x(wid);
tmp->set_line(*this);
return tmp;
}
// Notice that the par_msv is not used in this function other // Notice that the par_msv is not used in this function other
// than for this test. It is used to tell the direction that // than for this test. It is used to tell the direction that
// the bits are numbers, so that we can make sure the // the bits are numbers, so that we can make sure the
@ -2282,6 +2303,20 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des,
NetEConst*re = dynamic_cast<NetEConst*>(mtmp); NetEConst*re = dynamic_cast<NetEConst*>(mtmp);
if (le && re) { if (le && re) {
// Special case: If the bit select is constant and
// not fully defined, then we know that the result
// must be 1'bx.
if (! re->value().is_defined()) {
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "Constant bit select of parameter is "
<< "not defined. Return constant X value."
<< endl;
NetEConst*res = make_const_x(1);
res->set_line(*this);
return res;
}
/* Argument and bit select are constant. Calculate /* Argument and bit select are constant. Calculate
the final result. */ the final result. */
verinum lv = le->value(); verinum lv = le->value();
@ -2467,7 +2502,8 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
NetESignal*net, NetScope*found_in) const NetESignal*net, NetScope*found_in) const
{ {
long msv, lsv; long msv, lsv;
bool flag = calculate_parts_(des, scope, msv, lsv); bool parts_defined_flag;
bool flag = calculate_parts_(des, scope, msv, lsv, parts_defined_flag);
if (!flag) if (!flag)
return 0; return 0;
@ -2476,6 +2512,18 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
unsigned. Remember that any order is possible, unsigned. Remember that any order is possible,
i.e., [1:0], [-4:6], etc. */ i.e., [1:0], [-4:6], etc. */
unsigned long wid = 1 + labs(msv-lsv); unsigned long wid = 1 + labs(msv-lsv);
/* But wait... if the part select expressions are not fully
defined, then fall back on the tested width. */
if (!parts_defined_flag) {
if (debug_elaborate)
cerr << get_fileline() << ": debug: Part select is not fully "
<< "defined. Falling back on width of " << expr_width_
<< " and generating constant 'bx vector." << endl;
NetEConst*tmp = make_const_x(expr_width_);
tmp->set_line(*this);
return tmp;
}
if (net->sig()->sb_to_idx(msv) < net->sig()->sb_to_idx(lsv)) { if (net->sig()->sb_to_idx(msv) < net->sig()->sb_to_idx(lsv)) {
cerr << get_fileline() << ": error: part select [" cerr << get_fileline() << ": error: part select ["
@ -2648,6 +2696,16 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
// to the part select, so that I save the effort of // to the part select, so that I save the effort of
// making a mux part in the netlist. // making a mux part in the netlist.
if (NetEConst*msc = dynamic_cast<NetEConst*> (ex)) { if (NetEConst*msc = dynamic_cast<NetEConst*> (ex)) {
// Special case: The bit select expresion is constant
// x/z. The result of the expression is 1'bx.
if (! msc->value().is_defined()) {
NetEConst*tmp = make_const_x(1);
tmp->set_line(*this);
delete ex;
return tmp;
}
long msv = msc->value().as_long(); long msv = msc->value().as_long();
unsigned idx = net->sig()->sb_to_idx(msv); unsigned idx = net->sig()->sb_to_idx(msv);

View File

@ -353,10 +353,13 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
// constant. The calculate_parts_ function calculates the // constant. The calculate_parts_ function calculates the
// values into msb and lsb. // values into msb and lsb.
long msb, lsb; long msb, lsb;
bool flag = calculate_parts_(des, scope, msb, lsb); bool parts_defined_flag;
bool flag = calculate_parts_(des, scope, msb, lsb, parts_defined_flag);
if (!flag) if (!flag)
return false; return false;
ivl_assert(*this, parts_defined_flag);
NetNet*reg = lv->sig(); NetNet*reg = lv->sig();
assert(reg); assert(reg);

View File

@ -278,7 +278,9 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
case index_component_t::SEL_PART: { case index_component_t::SEL_PART: {
long msb, lsb; long msb, lsb;
/* bool flag = */ calculate_parts_(des, scope, msb, lsb); bool part_defined_flag;
/* bool flag = */ calculate_parts_(des, scope, msb, lsb, part_defined_flag);
ivl_assert(*this, part_defined_flag);
long lidx_tmp = sig->sb_to_idx(lsb); long lidx_tmp = sig->sb_to_idx(lsb);
long midx_tmp = sig->sb_to_idx(msb); long midx_tmp = sig->sb_to_idx(msb);