Handle out-of range and undefined LHS bit/part selects in assignments.
For constant bit/part selects, issue a warning if the select is out of range or an undefined value. In any case, the RHS value should be discarded, and the actual assignment should be skipped.
This commit is contained in:
parent
c693930595
commit
6f8eede371
9
PExpr.h
9
PExpr.h
|
|
@ -380,12 +380,13 @@ class PEIdent : public PExpr {
|
||||||
private:
|
private:
|
||||||
NetAssign_*elaborate_lval_method_class_member_(Design*, NetScope*) const;
|
NetAssign_*elaborate_lval_method_class_member_(Design*, NetScope*) const;
|
||||||
NetAssign_*elaborate_lval_net_word_(Design*, NetScope*, NetNet*,
|
NetAssign_*elaborate_lval_net_word_(Design*, NetScope*, NetNet*,
|
||||||
bool is_cassign,
|
bool need_const_idx) const;
|
||||||
bool is_force) const;
|
bool elaborate_lval_net_bit_(Design*, NetScope*, NetAssign_*,
|
||||||
bool elaborate_lval_net_bit_(Design*, NetScope*, NetAssign_*) const;
|
bool need_const_idx) const;
|
||||||
bool elaborate_lval_net_part_(Design*, NetScope*, NetAssign_*) const;
|
bool elaborate_lval_net_part_(Design*, NetScope*, NetAssign_*) const;
|
||||||
bool elaborate_lval_net_idx_(Design*, NetScope*, NetAssign_*,
|
bool elaborate_lval_net_idx_(Design*, NetScope*, NetAssign_*,
|
||||||
index_component_t::ctype_t) const;
|
index_component_t::ctype_t,
|
||||||
|
bool need_const_idx) const;
|
||||||
bool elaborate_lval_net_class_member_(Design*, NetScope*,
|
bool elaborate_lval_net_class_member_(Design*, NetScope*,
|
||||||
NetAssign_*,
|
NetAssign_*,
|
||||||
const perm_string&) const;
|
const perm_string&) const;
|
||||||
|
|
|
||||||
48
elab_lval.cc
48
elab_lval.cc
|
|
@ -265,9 +265,10 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
||||||
// where the name is a member/method of a struct/class.
|
// where the name is a member/method of a struct/class.
|
||||||
ivl_assert(*this, method_name.nil());
|
ivl_assert(*this, method_name.nil());
|
||||||
|
|
||||||
|
bool need_const_idx = is_cassign || is_force;
|
||||||
|
|
||||||
if (reg->unpacked_dimensions() > 0)
|
if (reg->unpacked_dimensions() > 0)
|
||||||
return elaborate_lval_net_word_(des, scope, reg,
|
return elaborate_lval_net_word_(des, scope, reg, need_const_idx);
|
||||||
is_cassign, is_force);
|
|
||||||
|
|
||||||
// This must be after the array word elaboration above!
|
// This must be after the array word elaboration above!
|
||||||
if (reg->get_scalar() &&
|
if (reg->get_scalar() &&
|
||||||
|
|
@ -289,7 +290,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
||||||
if (use_sel == index_component_t::SEL_IDX_UP ||
|
if (use_sel == index_component_t::SEL_IDX_UP ||
|
||||||
use_sel == index_component_t::SEL_IDX_DO) {
|
use_sel == index_component_t::SEL_IDX_DO) {
|
||||||
NetAssign_*lv = new NetAssign_(reg);
|
NetAssign_*lv = new NetAssign_(reg);
|
||||||
elaborate_lval_net_idx_(des, scope, lv, use_sel);
|
elaborate_lval_net_idx_(des, scope, lv, use_sel, need_const_idx);
|
||||||
return lv;
|
return lv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -301,7 +302,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
||||||
return lv;
|
return lv;
|
||||||
} else {
|
} else {
|
||||||
NetAssign_*lv = new NetAssign_(reg);
|
NetAssign_*lv = new NetAssign_(reg);
|
||||||
elaborate_lval_net_bit_(des, scope, lv);
|
elaborate_lval_net_bit_(des, scope, lv, need_const_idx);
|
||||||
return lv;
|
return lv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -351,8 +352,7 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*,
|
||||||
NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
||||||
NetScope*scope,
|
NetScope*scope,
|
||||||
NetNet*reg,
|
NetNet*reg,
|
||||||
bool is_cassign,
|
bool need_const_idx) const
|
||||||
bool is_force) const
|
|
||||||
{
|
{
|
||||||
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());
|
||||||
|
|
@ -398,7 +398,7 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
||||||
<< "." << endl;
|
<< "." << endl;
|
||||||
|
|
||||||
} else if (flags.variable) {
|
} else if (flags.variable) {
|
||||||
if (is_cassign || is_force) {
|
if (need_const_idx) {
|
||||||
cerr << get_fileline() << ": error: array '" << reg->name()
|
cerr << get_fileline() << ": error: array '" << reg->name()
|
||||||
<< "' index must be a constant in this context." << endl;
|
<< "' index must be a constant in this context." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
|
|
@ -448,21 +448,22 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_sel == index_component_t::SEL_BIT)
|
if (use_sel == index_component_t::SEL_BIT)
|
||||||
elaborate_lval_net_bit_(des, scope, lv);
|
elaborate_lval_net_bit_(des, scope, lv, need_const_idx);
|
||||||
|
|
||||||
if (use_sel == index_component_t::SEL_PART)
|
if (use_sel == index_component_t::SEL_PART)
|
||||||
elaborate_lval_net_part_(des, scope, lv);
|
elaborate_lval_net_part_(des, scope, lv);
|
||||||
|
|
||||||
if (use_sel == index_component_t::SEL_IDX_UP ||
|
if (use_sel == index_component_t::SEL_IDX_UP ||
|
||||||
use_sel == index_component_t::SEL_IDX_DO)
|
use_sel == index_component_t::SEL_IDX_DO)
|
||||||
elaborate_lval_net_idx_(des, scope, lv, use_sel);
|
elaborate_lval_net_idx_(des, scope, lv, use_sel, need_const_idx);
|
||||||
|
|
||||||
return lv;
|
return lv;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PEIdent::elaborate_lval_net_bit_(Design*des,
|
bool PEIdent::elaborate_lval_net_bit_(Design*des,
|
||||||
NetScope*scope,
|
NetScope*scope,
|
||||||
NetAssign_*lv) const
|
NetAssign_*lv,
|
||||||
|
bool need_const_idx) const
|
||||||
{
|
{
|
||||||
list<long>prefix_indices;
|
list<long>prefix_indices;
|
||||||
bool rc = calculate_packed_indices_(des, scope, lv->sig(), prefix_indices);
|
bool rc = calculate_packed_indices_(des, scope, lv->sig(), prefix_indices);
|
||||||
|
|
@ -556,6 +557,13 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
|
||||||
// Non-constant bit mux. Correct the mux for the range
|
// Non-constant bit mux. Correct the mux for the range
|
||||||
// of the vector, then set the l-value part select
|
// of the vector, then set the l-value part select
|
||||||
// expression.
|
// expression.
|
||||||
|
if (need_const_idx) {
|
||||||
|
cerr << get_fileline() << ": error: '" << reg->name()
|
||||||
|
<< "' bit select must be a constant in this context."
|
||||||
|
<< endl;
|
||||||
|
des->errors += 1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
mux = normalize_variable_bit_base(prefix_indices, mux, reg);
|
mux = normalize_variable_bit_base(prefix_indices, mux, reg);
|
||||||
lv->set_part(mux, 1);
|
lv->set_part(mux, 1);
|
||||||
|
|
||||||
|
|
@ -694,7 +702,8 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
|
||||||
bool PEIdent::elaborate_lval_net_idx_(Design*des,
|
bool PEIdent::elaborate_lval_net_idx_(Design*des,
|
||||||
NetScope*scope,
|
NetScope*scope,
|
||||||
NetAssign_*lv,
|
NetAssign_*lv,
|
||||||
index_component_t::ctype_t use_sel) const
|
index_component_t::ctype_t use_sel,
|
||||||
|
bool need_const_idx) const
|
||||||
{
|
{
|
||||||
list<long>prefix_indices;
|
list<long>prefix_indices;
|
||||||
bool rc = calculate_packed_indices_(des, scope, lv->sig(), prefix_indices);
|
bool rc = calculate_packed_indices_(des, scope, lv->sig(), prefix_indices);
|
||||||
|
|
@ -710,16 +719,6 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
|
||||||
NetNet*reg = lv->sig();
|
NetNet*reg = lv->sig();
|
||||||
assert(reg);
|
assert(reg);
|
||||||
|
|
||||||
if (reg->type() != NetNet::REG) {
|
|
||||||
cerr << get_fileline() << ": error: " << path_ <<
|
|
||||||
" is not a reg/integer/time in " << scope_path(scope) <<
|
|
||||||
"." << endl;
|
|
||||||
cerr << reg->get_fileline() << ": : " << path_ <<
|
|
||||||
" is declared here as " << reg->type() << "." << endl;
|
|
||||||
des->errors += 1;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long wid;
|
unsigned long wid;
|
||||||
calculate_up_do_width_(des, scope, wid);
|
calculate_up_do_width_(des, scope, wid);
|
||||||
|
|
||||||
|
|
@ -782,6 +781,13 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
|
||||||
cerr << " has an undefined base." << endl;
|
cerr << " has an undefined base." << endl;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (need_const_idx) {
|
||||||
|
cerr << get_fileline() << ": error: '" << reg->name()
|
||||||
|
<< "' base index must be a constant in this context."
|
||||||
|
<< endl;
|
||||||
|
des->errors += 1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
ivl_assert(*this, prefix_indices.size()+1 == reg->packed_dims().size());
|
ivl_assert(*this, prefix_indices.size()+1 == reg->packed_dims().size());
|
||||||
/* Correct the mux for the range of the vector. */
|
/* Correct the mux for the range of the vector. */
|
||||||
if (use_sel == index_component_t::SEL_IDX_UP) {
|
if (use_sel == index_component_t::SEL_IDX_UP) {
|
||||||
|
|
|
||||||
29
elab_net.cc
29
elab_net.cc
|
|
@ -255,7 +255,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
|
||||||
} else {
|
} else {
|
||||||
cerr << "-:";
|
cerr << "-:";
|
||||||
}
|
}
|
||||||
cerr << wid << "] is always outside vector."
|
cerr << wid << "] is always outside the vector."
|
||||||
<< endl;
|
<< endl;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -315,7 +315,18 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
|
||||||
long msb, lsb;
|
long msb, lsb;
|
||||||
bool part_defined_flag;
|
bool part_defined_flag;
|
||||||
/* bool flag = */ calculate_parts_(des, scope, msb, lsb, part_defined_flag);
|
/* bool flag = */ calculate_parts_(des, scope, msb, lsb, part_defined_flag);
|
||||||
ivl_assert(*this, part_defined_flag);
|
|
||||||
|
/* We have an undefined index and that is out of range. */
|
||||||
|
if (!part_defined_flag) {
|
||||||
|
if (warn_ob_select) {
|
||||||
|
cerr << get_fileline() << ": warning: "
|
||||||
|
<< sig->name();
|
||||||
|
if (sig->unpacked_dimensions() > 0) cerr << "[]";
|
||||||
|
cerr << "['bx] is always outside the vector."
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
long lidx_tmp = sig->sb_to_idx(prefix_indices, lsb);
|
long lidx_tmp = sig->sb_to_idx(prefix_indices, lsb);
|
||||||
long midx_tmp = sig->sb_to_idx(prefix_indices, msb);
|
long midx_tmp = sig->sb_to_idx(prefix_indices, msb);
|
||||||
|
|
@ -358,7 +369,19 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
|
||||||
long msb;
|
long msb;
|
||||||
bool bit_defined_flag;
|
bool bit_defined_flag;
|
||||||
/* bool flag = */ calculate_bits_(des, scope, msb, bit_defined_flag);
|
/* bool flag = */ calculate_bits_(des, scope, msb, bit_defined_flag);
|
||||||
ivl_assert(*this, bit_defined_flag);
|
|
||||||
|
/* We have an undefined index and that is out of range. */
|
||||||
|
if (!bit_defined_flag) {
|
||||||
|
if (warn_ob_select) {
|
||||||
|
cerr << get_fileline() << ": warning: "
|
||||||
|
<< sig->name();
|
||||||
|
if (sig->unpacked_dimensions() > 0) cerr << "[]";
|
||||||
|
cerr << "['bx] is always outside the vector."
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (prefix_indices.size()+2 <= sig->packed_dims().size()) {
|
if (prefix_indices.size()+2 <= sig->packed_dims().size()) {
|
||||||
long tmp_loff;
|
long tmp_loff;
|
||||||
|
|
|
||||||
|
|
@ -197,8 +197,8 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
|
||||||
|
|
||||||
if (part_off_ex == 0) {
|
if (part_off_ex == 0) {
|
||||||
part_off = 0;
|
part_off = 0;
|
||||||
} else if (number_is_immediate(part_off_ex, IMM_WID, 0)) {
|
} else if (number_is_immediate(part_off_ex, IMM_WID, 0) &&
|
||||||
assert(! number_is_unknown(part_off_ex));
|
!number_is_unknown(part_off_ex)) {
|
||||||
part_off = get_number_immediate(part_off_ex);
|
part_off = get_number_immediate(part_off_ex);
|
||||||
part_off_ex = 0;
|
part_off_ex = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1183,7 +1183,8 @@ static int show_stmt_deassign(ivl_statement_t net)
|
||||||
part_off = 0;
|
part_off = 0;
|
||||||
if (part_off_ex != 0) {
|
if (part_off_ex != 0) {
|
||||||
assert(number_is_immediate(part_off_ex, 64, 0));
|
assert(number_is_immediate(part_off_ex, 64, 0));
|
||||||
assert(! number_is_unknown(part_off_ex));
|
if (number_is_unknown(part_off_ex))
|
||||||
|
return 0;
|
||||||
part_off = get_number_immediate(part_off_ex);
|
part_off = get_number_immediate(part_off_ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue