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_;
private:
// Common functions to calculate parts of part/bit selects.
bool calculate_parts_(Design*, NetScope*, long&msb, long&lsb) const;
// Common functions to calculate parts of part/bit
// 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;
bool calculate_param_range_(Design*, NetScope*,
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.
*/
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();
ivl_assert(*this, !name_tail.index.empty());
@ -1670,6 +1671,8 @@ bool PEIdent::calculate_parts_(Design*des, NetScope*scope,
/* Attempt to recover from error. */
lsb = 0;
} else {
if (! lsb_c->value().is_defined())
defined = false;
lsb = lsb_c->value().as_long();
}
@ -1686,6 +1689,8 @@ bool PEIdent::calculate_parts_(Design*des, NetScope*scope,
/* Attempt to recover from error. */
msb = lsb;
} else {
if (! msb_c->value().is_defined())
defined = false;
msb = msb_c->value().as_long();
}
@ -1801,8 +1806,12 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope,
break;
case index_component_t::SEL_PART:
{ long msb, lsb;
calculate_parts_(des, scope, msb, lsb);
use_width = 1 + ((msb>lsb)? (msb-lsb) : (lsb-msb));
bool parts_defined;
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;
}
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
{
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)
return 0;
@ -2102,6 +2112,17 @@ NetExpr* PEIdent::elaborate_expr_param_part_(Design*des, NetScope*scope,
if (!flag)
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
// than for this test. It is used to tell the direction that
// 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);
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
the final result. */
verinum lv = le->value();
@ -2467,7 +2502,8 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
NetESignal*net, NetScope*found_in) const
{
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)
return 0;
@ -2476,6 +2512,18 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
unsigned. Remember that any order is possible,
i.e., [1:0], [-4:6], etc. */
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)) {
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
// making a mux part in the netlist.
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();
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
// values into msb and 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)
return false;
ivl_assert(*this, parts_defined_flag);
NetNet*reg = lv->sig();
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: {
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 midx_tmp = sig->sb_to_idx(msb);