From 6f8eede371f3e4df61d436c7b8da3044e9c500c6 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 21 May 2013 21:44:31 +0100 Subject: [PATCH] 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. --- PExpr.h | 9 ++++---- elab_lval.cc | 48 ++++++++++++++++++++++++------------------- elab_net.cc | 29 +++++++++++++++++++++++--- tgt-vvp/vvp_process.c | 7 ++++--- 4 files changed, 62 insertions(+), 31 deletions(-) diff --git a/PExpr.h b/PExpr.h index 6331ddd3a..7612cbe6a 100644 --- a/PExpr.h +++ b/PExpr.h @@ -380,12 +380,13 @@ class PEIdent : public PExpr { private: NetAssign_*elaborate_lval_method_class_member_(Design*, NetScope*) const; NetAssign_*elaborate_lval_net_word_(Design*, NetScope*, NetNet*, - bool is_cassign, - bool is_force) const; - bool elaborate_lval_net_bit_(Design*, NetScope*, NetAssign_*) const; + bool need_const_idx) const; + bool elaborate_lval_net_bit_(Design*, NetScope*, NetAssign_*, + bool need_const_idx) const; bool elaborate_lval_net_part_(Design*, NetScope*, NetAssign_*) const; 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*, NetAssign_*, const perm_string&) const; diff --git a/elab_lval.cc b/elab_lval.cc index 084f1fa87..0b4e23683 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -265,9 +265,10 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, // where the name is a member/method of a struct/class. ivl_assert(*this, method_name.nil()); + bool need_const_idx = is_cassign || is_force; + if (reg->unpacked_dimensions() > 0) - return elaborate_lval_net_word_(des, scope, reg, - is_cassign, is_force); + return elaborate_lval_net_word_(des, scope, reg, need_const_idx); // This must be after the array word elaboration above! if (reg->get_scalar() && @@ -289,7 +290,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, if (use_sel == index_component_t::SEL_IDX_UP || use_sel == index_component_t::SEL_IDX_DO) { 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; } @@ -301,7 +302,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, return lv; } else { NetAssign_*lv = new NetAssign_(reg); - elaborate_lval_net_bit_(des, scope, lv); + elaborate_lval_net_bit_(des, scope, lv, need_const_idx); return lv; } } @@ -351,8 +352,7 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*, NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des, NetScope*scope, NetNet*reg, - bool is_cassign, - bool is_force) const + bool need_const_idx) const { const name_component_t&name_tail = path_.back(); ivl_assert(*this, !name_tail.index.empty()); @@ -398,7 +398,7 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des, << "." << endl; } else if (flags.variable) { - if (is_cassign || is_force) { + if (need_const_idx) { cerr << get_fileline() << ": error: array '" << reg->name() << "' index must be a constant in this context." << endl; des->errors += 1; @@ -448,21 +448,22 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des, } 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) elaborate_lval_net_part_(des, scope, lv); if (use_sel == index_component_t::SEL_IDX_UP || 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; } bool PEIdent::elaborate_lval_net_bit_(Design*des, NetScope*scope, - NetAssign_*lv) const + NetAssign_*lv, + bool need_const_idx) const { listprefix_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 // of the vector, then set the l-value part select // 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); 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, NetScope*scope, NetAssign_*lv, - index_component_t::ctype_t use_sel) const + index_component_t::ctype_t use_sel, + bool need_const_idx) const { listprefix_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(); 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; 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; } } 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()); /* Correct the mux for the range of the vector. */ if (use_sel == index_component_t::SEL_IDX_UP) { diff --git a/elab_net.cc b/elab_net.cc index db4adc788..84d411160 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -255,7 +255,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig, } else { cerr << "-:"; } - cerr << wid << "] is always outside vector." + cerr << wid << "] is always outside the vector." << endl; } return false; @@ -315,7 +315,18 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig, long msb, lsb; bool 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 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; bool 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()) { long tmp_loff; diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index b4d4aa799..6d57a3910 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -197,8 +197,8 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit, if (part_off_ex == 0) { part_off = 0; - } else if (number_is_immediate(part_off_ex, IMM_WID, 0)) { - assert(! number_is_unknown(part_off_ex)); + } else if (number_is_immediate(part_off_ex, IMM_WID, 0) && + !number_is_unknown(part_off_ex)) { part_off = get_number_immediate(part_off_ex); part_off_ex = 0; } @@ -1183,7 +1183,8 @@ static int show_stmt_deassign(ivl_statement_t net) part_off = 0; if (part_off_ex != 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); }