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:
parent
ea938b7907
commit
b45834f074
14
PExpr.h
14
PExpr.h
|
|
@ -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,
|
||||||
|
|
|
||||||
68
elab_expr.cc
68
elab_expr.cc
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue