Handle out-of range and undefined LHS word indices in assignments.
For constant word indices, issue a warning if the index 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
0aca19356c
commit
26dc6d68cd
14
PExpr.h
14
PExpr.h
|
|
@ -154,11 +154,12 @@ class PExpr : public LineInfo {
|
|||
|
||||
// Expressions that can be in the l-value of procedural
|
||||
// assignments can be elaborated with this method. If the
|
||||
// is_force flag is true, then the set of valid l-value types
|
||||
// is slightly modified to accommodate the Verilog force
|
||||
// statement
|
||||
// is_cassign or is_force flags are true, then the set of
|
||||
// valid l-value types is slightly modified to accommodate
|
||||
// the Verilog procedural continuous assignment statements.
|
||||
virtual NetAssign_* elaborate_lval(Design*des,
|
||||
NetScope*scope,
|
||||
bool is_cassign,
|
||||
bool is_force) const;
|
||||
|
||||
// This attempts to evaluate a constant expression, and return
|
||||
|
|
@ -216,6 +217,7 @@ class PEConcat : public PExpr {
|
|||
unsigned flags) const;
|
||||
virtual NetAssign_* elaborate_lval(Design*des,
|
||||
NetScope*scope,
|
||||
bool is_cassign,
|
||||
bool is_force) const;
|
||||
virtual bool is_collapsible_net(Design*des, NetScope*scope) const;
|
||||
private:
|
||||
|
|
@ -316,6 +318,7 @@ class PEIdent : public PExpr {
|
|||
// Identifiers are also allowed as procedural assignment l-values.
|
||||
virtual NetAssign_* elaborate_lval(Design*des,
|
||||
NetScope*scope,
|
||||
bool is_cassign,
|
||||
bool is_force) const;
|
||||
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
|
||||
|
|
@ -376,7 +379,9 @@ class PEIdent : public PExpr {
|
|||
|
||||
private:
|
||||
NetAssign_*elaborate_lval_method_class_member_(Design*, NetScope*) const;
|
||||
NetAssign_*elaborate_lval_net_word_(Design*, NetScope*, NetNet*) 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 elaborate_lval_net_part_(Design*, NetScope*, NetAssign_*) const;
|
||||
bool elaborate_lval_net_idx_(Design*, NetScope*, NetAssign_*,
|
||||
|
|
@ -563,6 +568,7 @@ class PENumber : public PExpr {
|
|||
unsigned expr_wid, unsigned) const;
|
||||
virtual NetAssign_* elaborate_lval(Design*des,
|
||||
NetScope*scope,
|
||||
bool is_cassign,
|
||||
bool is_force) const;
|
||||
|
||||
virtual verinum* eval_const(Design*des, NetScope*sc) const;
|
||||
|
|
|
|||
34
elab_expr.cc
34
elab_expr.cc
|
|
@ -3759,26 +3759,38 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
|
|||
// "unpacked_indices" array.
|
||||
list<NetExpr*>unpacked_indices;
|
||||
list<long> unpacked_indices_const;
|
||||
bool flag = indices_to_expressions(des, scope, this,
|
||||
name_tail.index, net->unpacked_dimensions(),
|
||||
need_const,
|
||||
unpacked_indices,
|
||||
unpacked_indices_const);
|
||||
indices_flags idx_flags;
|
||||
indices_to_expressions(des, scope, this,
|
||||
name_tail.index, net->unpacked_dimensions(),
|
||||
need_const,
|
||||
idx_flags,
|
||||
unpacked_indices,
|
||||
unpacked_indices_const);
|
||||
|
||||
NetExpr*canon_index = 0;
|
||||
if (flag) {
|
||||
if (idx_flags.invalid) {
|
||||
// Nothing to do.
|
||||
|
||||
} else if (idx_flags.undefined) {
|
||||
cerr << get_fileline() << ": warning: "
|
||||
<< "returning 'bx for undefined array access "
|
||||
<< net->name() << as_indices(unpacked_indices)
|
||||
<< "." << endl;
|
||||
|
||||
} else if (idx_flags.variable) {
|
||||
ivl_assert(*this, unpacked_indices.size() == net->unpacked_dimensions());
|
||||
canon_index = normalize_variable_unpacked(net, unpacked_indices);
|
||||
|
||||
} else {
|
||||
ivl_assert(*this, unpacked_indices_const.size() == net->unpacked_dimensions());
|
||||
canon_index = normalize_variable_unpacked(net, unpacked_indices_const);
|
||||
|
||||
if (canon_index == 0) {
|
||||
cerr << get_fileline() << ": warning: "
|
||||
<< "returning 'bx for out of bounds array access "
|
||||
<< net->name() << as_indices(unpacked_indices_const) << "." << endl;
|
||||
<< net->name() << as_indices(unpacked_indices_const)
|
||||
<< "." << endl;
|
||||
}
|
||||
|
||||
} else {
|
||||
ivl_assert(*this, unpacked_indices.size() == net->unpacked_dimensions());
|
||||
canon_index = normalize_variable_unpacked(net, unpacked_indices);
|
||||
}
|
||||
|
||||
if (canon_index == 0) {
|
||||
|
|
|
|||
69
elab_lval.cc
69
elab_lval.cc
|
|
@ -71,7 +71,7 @@
|
|||
* is to try to make a net elaboration, and see if the result is
|
||||
* suitable for assignment.
|
||||
*/
|
||||
NetAssign_* PExpr::elaborate_lval(Design*, NetScope*, bool) const
|
||||
NetAssign_* PExpr::elaborate_lval(Design*, NetScope*, bool, bool) const
|
||||
{
|
||||
NetNet*ll = 0;
|
||||
if (ll == 0) {
|
||||
|
|
@ -99,6 +99,7 @@ NetAssign_* PExpr::elaborate_lval(Design*, NetScope*, bool) const
|
|||
*/
|
||||
NetAssign_* PEConcat::elaborate_lval(Design*des,
|
||||
NetScope*scope,
|
||||
bool is_cassign,
|
||||
bool is_force) const
|
||||
{
|
||||
if (repeat_) {
|
||||
|
|
@ -119,7 +120,8 @@ NetAssign_* PEConcat::elaborate_lval(Design*des,
|
|||
continue;
|
||||
}
|
||||
|
||||
NetAssign_*tmp = parms_[idx]->elaborate_lval(des, scope, is_force);
|
||||
NetAssign_*tmp = parms_[idx]->elaborate_lval(des, scope,
|
||||
is_cassign, is_force);
|
||||
|
||||
/* If the l-value doesn't elaborate, the error was
|
||||
already detected and printed. We just skip it and let
|
||||
|
|
@ -152,6 +154,7 @@ NetAssign_* PEConcat::elaborate_lval(Design*des,
|
|||
*/
|
||||
NetAssign_* PEIdent::elaborate_lval(Design*des,
|
||||
NetScope*scope,
|
||||
bool is_cassign,
|
||||
bool is_force) const
|
||||
{
|
||||
NetNet* reg = 0;
|
||||
|
|
@ -263,7 +266,8 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
|||
ivl_assert(*this, method_name.nil());
|
||||
|
||||
if (reg->unpacked_dimensions() > 0)
|
||||
return elaborate_lval_net_word_(des, scope, reg);
|
||||
return elaborate_lval_net_word_(des, scope, reg,
|
||||
is_cassign, is_force);
|
||||
|
||||
// This must be after the array word elaboration above!
|
||||
if (reg->get_scalar() &&
|
||||
|
|
@ -346,7 +350,9 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*,
|
|||
|
||||
NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
||||
NetScope*scope,
|
||||
NetNet*reg) const
|
||||
NetNet*reg,
|
||||
bool is_cassign,
|
||||
bool is_force) const
|
||||
{
|
||||
const name_component_t&name_tail = path_.back();
|
||||
ivl_assert(*this, !name_tail.index.empty());
|
||||
|
|
@ -373,30 +379,49 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
|||
// "unpacked_indices" array.
|
||||
list<NetExpr*>unpacked_indices;
|
||||
list<long> unpacked_indices_const;
|
||||
bool flag = indices_to_expressions(des, scope, this,
|
||||
name_tail.index, reg->unpacked_dimensions(),
|
||||
false,
|
||||
unpacked_indices,
|
||||
unpacked_indices_const);
|
||||
indices_flags flags;
|
||||
indices_to_expressions(des, scope, this,
|
||||
name_tail.index, reg->unpacked_dimensions(),
|
||||
false,
|
||||
flags,
|
||||
unpacked_indices,
|
||||
unpacked_indices_const);
|
||||
|
||||
NetExpr*canon_index = 0;
|
||||
if (flag) {
|
||||
ivl_assert(*this, unpacked_indices_const.size() == reg->unpacked_dimensions());
|
||||
canon_index = normalize_variable_unpacked(reg, unpacked_indices_const);
|
||||
if (canon_index == 0) {
|
||||
cerr << get_fileline() << ": warning: "
|
||||
<< "ignoring out of bounds l-value array access " << reg->name();
|
||||
for (list<long>::const_iterator cur = unpacked_indices_const.begin()
|
||||
; cur != unpacked_indices_const.end() ; ++cur) {
|
||||
cerr << "[" << *cur << "]";
|
||||
}
|
||||
cerr << "." << endl;
|
||||
if (flags.invalid) {
|
||||
// Nothing to do.
|
||||
|
||||
} else if (flags.undefined) {
|
||||
cerr << get_fileline() << ": warning: "
|
||||
<< "ignoring undefined l-value array access "
|
||||
<< reg->name() << as_indices(unpacked_indices)
|
||||
<< "." << endl;
|
||||
|
||||
} else if (flags.variable) {
|
||||
if (is_cassign || is_force) {
|
||||
cerr << get_fileline() << ": error: array '" << reg->name()
|
||||
<< "' index must be a constant in this context." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
ivl_assert(*this, unpacked_indices.size() == reg->unpacked_dimensions());
|
||||
canon_index = normalize_variable_unpacked(reg, unpacked_indices);
|
||||
|
||||
} else {
|
||||
ivl_assert(*this, unpacked_indices_const.size() == reg->unpacked_dimensions());
|
||||
canon_index = normalize_variable_unpacked(reg, unpacked_indices_const);
|
||||
|
||||
if (canon_index == 0) {
|
||||
cerr << get_fileline() << ": warning: "
|
||||
<< "ignoring out of bounds l-value array access "
|
||||
<< reg->name() << as_indices(unpacked_indices_const)
|
||||
<< "." << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure invalid array accesses are ignored.
|
||||
if (canon_index == 0)
|
||||
canon_index = new NetEConst(verinum(verinum::Vx));
|
||||
|
||||
NetAssign_*lv = new NetAssign_(reg);
|
||||
lv->set_word(canon_index);
|
||||
|
|
@ -959,7 +984,7 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope,
|
|||
return false;
|
||||
}
|
||||
|
||||
NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*, bool) const
|
||||
NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*, bool, bool) const
|
||||
{
|
||||
cerr << get_fileline() << ": error: Constant values not allowed "
|
||||
<< "in l-value expressions." << endl;
|
||||
|
|
|
|||
64
elab_net.cc
64
elab_net.cc
|
|
@ -581,35 +581,49 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
|||
// Evaluate all the index expressions into an
|
||||
// "unpacked_indices" array.
|
||||
list<NetExpr*>unpacked_indices;
|
||||
bool flag = indices_to_expressions(des, scope, this,
|
||||
path_tail.index, sig->unpacked_dimensions(),
|
||||
true,
|
||||
unpacked_indices,
|
||||
unpacked_indices_const);
|
||||
// Note that !flag includes that there were any other
|
||||
// elaboration errors generating the unpacked_indices list.
|
||||
if (!flag) {
|
||||
cerr << get_fileline() << ": error: array " << sig->name()
|
||||
<< " index must be a constant in this context." << endl;
|
||||
indices_flags flags;
|
||||
indices_to_expressions(des, scope, this,
|
||||
path_tail.index, sig->unpacked_dimensions(),
|
||||
true,
|
||||
flags,
|
||||
unpacked_indices,
|
||||
unpacked_indices_const);
|
||||
|
||||
if (flags.invalid) {
|
||||
return 0;
|
||||
|
||||
} else if (flags.variable) {
|
||||
cerr << get_fileline() << ": error: array '" << sig->name()
|
||||
<< "' index must be a constant in this context." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetExpr*canon_index = 0;
|
||||
ivl_assert(*this, unpacked_indices_const.size() == sig->unpacked_dimensions());
|
||||
canon_index = normalize_variable_unpacked(sig, unpacked_indices_const);
|
||||
if (canon_index == 0) {
|
||||
// Normalize detected an out-of-bounds
|
||||
// index. Indicate that by setting the generated
|
||||
// widx to -1.
|
||||
} else if (flags.undefined) {
|
||||
cerr << get_fileline() << ": warning: "
|
||||
<< "ignoring undefined l-value array access "
|
||||
<< sig->name() << as_indices(unpacked_indices)
|
||||
<< "." << endl;
|
||||
widx = -1;
|
||||
|
||||
} else {
|
||||
NetEConst*canon_const = dynamic_cast<NetEConst*>(canon_index);
|
||||
ivl_assert(*this, canon_const);
|
||||
NetExpr*canon_index = 0;
|
||||
ivl_assert(*this, unpacked_indices_const.size() == sig->unpacked_dimensions());
|
||||
canon_index = normalize_variable_unpacked(sig, unpacked_indices_const);
|
||||
|
||||
widx = canon_const->value().as_long();
|
||||
delete canon_index;
|
||||
if (canon_index == 0) {
|
||||
cerr << get_fileline() << ": warning: "
|
||||
<< "ignoring out of bounds l-value array access "
|
||||
<< sig->name() << as_indices(unpacked_indices_const)
|
||||
<< "." << endl;
|
||||
widx = -1;
|
||||
|
||||
} else {
|
||||
NetEConst*canon_const = dynamic_cast<NetEConst*>(canon_index);
|
||||
ivl_assert(*this, canon_const);
|
||||
|
||||
widx = canon_const->value().as_long();
|
||||
delete canon_index;
|
||||
}
|
||||
}
|
||||
|
||||
if (debug_elaborate)
|
||||
|
|
@ -681,12 +695,8 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
|||
}
|
||||
|
||||
if (sig->pin_count() > 1) {
|
||||
if (widx < 0 || widx >= (long) sig->pin_count()) {
|
||||
cerr << get_fileline() << ": warning: ignoring out of "
|
||||
"bounds l-value array access "
|
||||
<< sig->name() << as_indices(unpacked_indices_const) << "." << endl;
|
||||
if (widx < 0 || widx >= (long) sig->pin_count())
|
||||
return 0;
|
||||
}
|
||||
|
||||
netvector_t*tmp2_vec = new netvector_t(sig->data_type(),
|
||||
sig->vector_width()-1,0);
|
||||
|
|
|
|||
12
elaborate.cc
12
elaborate.cc
|
|
@ -2213,7 +2213,7 @@ NetProc* Statement::elaborate(Design*des, NetScope*) const
|
|||
NetAssign_* PAssign_::elaborate_lval(Design*des, NetScope*scope) const
|
||||
{
|
||||
assert(lval_);
|
||||
return lval_->elaborate_lval(des, scope, false);
|
||||
return lval_->elaborate_lval(des, scope, false, false);
|
||||
}
|
||||
|
||||
NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,
|
||||
|
|
@ -3483,7 +3483,7 @@ NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope,
|
|||
detailed message. */
|
||||
NetAssign_*lv;
|
||||
if (parms_[idx]) {
|
||||
lv = parms_[idx]->elaborate_lval(des, scope, false);
|
||||
lv = parms_[idx]->elaborate_lval(des, scope, false, false);
|
||||
if (lv == 0) {
|
||||
cerr << parms_[idx]->get_fileline() << ": error: "
|
||||
<< "I give up on task port " << (idx+1)
|
||||
|
|
@ -3564,7 +3564,7 @@ NetCAssign* PCAssign::elaborate(Design*des, NetScope*scope) const
|
|||
return 0;
|
||||
}
|
||||
|
||||
NetAssign_*lval = lval_->elaborate_lval(des, scope, false);
|
||||
NetAssign_*lval = lval_->elaborate_lval(des, scope, true, false);
|
||||
if (lval == 0)
|
||||
return 0;
|
||||
|
||||
|
|
@ -3601,7 +3601,7 @@ NetDeassign* PDeassign::elaborate(Design*des, NetScope*scope) const
|
|||
return 0;
|
||||
}
|
||||
|
||||
NetAssign_*lval = lval_->elaborate_lval(des, scope, false);
|
||||
NetAssign_*lval = lval_->elaborate_lval(des, scope, true, false);
|
||||
if (lval == 0)
|
||||
return 0;
|
||||
|
||||
|
|
@ -4212,7 +4212,7 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const
|
|||
return 0;
|
||||
}
|
||||
|
||||
NetAssign_*lval = lval_->elaborate_lval(des, scope, true);
|
||||
NetAssign_*lval = lval_->elaborate_lval(des, scope, false, true);
|
||||
if (lval == 0)
|
||||
return 0;
|
||||
|
||||
|
|
@ -4400,7 +4400,7 @@ NetProc* PRelease::elaborate(Design*des, NetScope*scope) const
|
|||
return 0;
|
||||
}
|
||||
|
||||
NetAssign_*lval = lval_->elaborate_lval(des, scope, true);
|
||||
NetAssign_*lval = lval_->elaborate_lval(des, scope, false, true);
|
||||
if (lval == 0)
|
||||
return 0;
|
||||
|
||||
|
|
|
|||
34
netmisc.cc
34
netmisc.cc
|
|
@ -458,11 +458,9 @@ ostream& operator << (ostream&o, __IndicesManip<NetExpr*> val)
|
|||
* The src is the input index expression list from the expression, and
|
||||
* the count is the number that are to be elaborated into the indices
|
||||
* list. At the same time, create a indices_const list that contains
|
||||
* the evaluated values for the expression, if they can be
|
||||
* evaluated. This function will return "true" if all the constants
|
||||
* can be evaluated.
|
||||
* the evaluated values for the expression, if they can be evaluated.
|
||||
*/
|
||||
bool indices_to_expressions(Design*des, NetScope*scope,
|
||||
void indices_to_expressions(Design*des, NetScope*scope,
|
||||
// loc is for error messages.
|
||||
const LineInfo*loc,
|
||||
// src is the index list, and count is
|
||||
|
|
@ -471,11 +469,14 @@ bool indices_to_expressions(Design*des, NetScope*scope,
|
|||
// True if the expression MUST be constant.
|
||||
bool need_const,
|
||||
// These are the outputs.
|
||||
indices_flags&flags,
|
||||
list<NetExpr*>&indices, list<long>&indices_const)
|
||||
{
|
||||
ivl_assert(*loc, count <= src.size());
|
||||
|
||||
bool flag = true;
|
||||
flags.invalid = false;
|
||||
flags.variable = false;
|
||||
flags.undefined = false;
|
||||
for (list<index_component_t>::const_iterator cur = src.begin()
|
||||
; count > 0 ; ++cur, --count) {
|
||||
ivl_assert(*loc, cur->sel != index_component_t::SEL_NONE);
|
||||
|
|
@ -489,25 +490,21 @@ bool indices_to_expressions(Design*des, NetScope*scope,
|
|||
|
||||
NetExpr*word_index = elab_and_eval(des, scope, cur->msb, -1, need_const);
|
||||
|
||||
// If the elaboration failed, then it is most certainly
|
||||
// not constant, either.
|
||||
if (word_index == 0)
|
||||
flag = false;
|
||||
flags.invalid = true;
|
||||
|
||||
// Track if we detect any non-constant expressions
|
||||
// here. This may allow for a special case.
|
||||
if (flag) {
|
||||
NetEConst*word_const = dynamic_cast<NetEConst*> (word_index);
|
||||
if (word_const)
|
||||
indices_const.push_back(word_const->value().as_long());
|
||||
else
|
||||
flag = false;
|
||||
}
|
||||
NetEConst*word_const = dynamic_cast<NetEConst*> (word_index);
|
||||
if (word_const == 0)
|
||||
flags.variable = true;
|
||||
else if (!word_const->value().is_defined())
|
||||
flags.undefined = true;
|
||||
else if (!flags.variable && !flags.undefined)
|
||||
indices_const.push_back(word_const->value().as_long());
|
||||
|
||||
indices.push_back(word_index);
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
static void make_strides(const vector<netrange_t>&dims,
|
||||
|
|
@ -1237,9 +1234,10 @@ NetExpr*collapse_array_exprs(Design*des, NetScope*scope,
|
|||
// First elaborate all the expressions as far as possible.
|
||||
list<NetExpr*> exprs;
|
||||
list<long> exprs_const;
|
||||
indices_flags flags;
|
||||
indices_to_expressions(des, scope, loc, indices,
|
||||
net->packed_dimensions(),
|
||||
false, exprs, exprs_const);
|
||||
false, flags, exprs, exprs_const);
|
||||
ivl_assert(*loc, exprs.size() == net->packed_dimensions());
|
||||
|
||||
// Special Case: there is only 1 packed dimension, so the
|
||||
|
|
|
|||
10
netmisc.h
10
netmisc.h
|
|
@ -166,7 +166,12 @@ extern ostream& operator << (ostream&o, __IndicesManip<NetExpr*>);
|
|||
* Given a list of index expressions, generate elaborated expressions
|
||||
* and constant values, if possible.
|
||||
*/
|
||||
extern bool indices_to_expressions(Design*des, NetScope*scope,
|
||||
struct indices_flags {
|
||||
bool invalid; // at least one index failed elaboration
|
||||
bool variable; // at least one index is a dynamic value
|
||||
bool undefined; // at least one index is an undefined value
|
||||
};
|
||||
extern void indices_to_expressions(Design*des, NetScope*scope,
|
||||
// loc is for error messages.
|
||||
const LineInfo*loc,
|
||||
// src is the index list, and count is
|
||||
|
|
@ -175,7 +180,8 @@ extern bool indices_to_expressions(Design*des, NetScope*scope,
|
|||
// True if the expression MUST be constant.
|
||||
bool need_const,
|
||||
// These are the outputs.
|
||||
list<NetExpr*>&indices, list<long>&indices_const);
|
||||
indices_flags&flags,
|
||||
list<NetExpr*>&indices,list<long>&indices_const);
|
||||
|
||||
extern NetExpr*normalize_variable_unpacked(const NetNet*net, list<long>&indices);
|
||||
extern NetExpr*normalize_variable_unpacked(const NetNet*net, list<NetExpr*>&indices);
|
||||
|
|
|
|||
|
|
@ -343,10 +343,13 @@ static void set_vec_to_lval_slice(ivl_lval_t lval, unsigned bit, unsigned wid)
|
|||
|
||||
/* If the word index is a constant expression, then evaluate
|
||||
it to select the word, and pay no further heed to the
|
||||
expression itself. */
|
||||
if (word_ix && number_is_immediate(word_ix, IMM_WID, 0)) {
|
||||
assert(! number_is_unknown(word_ix));
|
||||
expression itself. Out-of-bounds and undefined indices are
|
||||
converted to a canonical index of 'bx during elaboration,
|
||||
and we don't try to optimise that case. */
|
||||
if (word_ix && number_is_immediate(word_ix, IMM_WID, 0) &&
|
||||
!number_is_unknown(word_ix)) {
|
||||
use_word = get_number_immediate(word_ix);
|
||||
assert(use_word < ivl_signal_array_count(sig));
|
||||
word_ix = 0;
|
||||
}
|
||||
|
||||
|
|
@ -437,16 +440,10 @@ static void set_vec_to_lval_slice(ivl_lval_t lval, unsigned bit, unsigned wid)
|
|||
/* If the word index is a constant, then we can write
|
||||
directly to the word and save the index calculation. */
|
||||
if (word_ix == 0) {
|
||||
if (use_word < ivl_signal_array_count(sig)) {
|
||||
fprintf(vvp_out, " %%ix/load 1, 0, 0;\n");
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n",
|
||||
use_word);
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
sig, bit, wid);
|
||||
} else {
|
||||
fprintf(vvp_out, " ; %%set/v v%p_%lu, %u, %u "
|
||||
"OUT OF BOUNDS\n", sig, use_word, bit, wid);
|
||||
}
|
||||
fprintf(vvp_out, " %%ix/load 1, 0, 0;\n");
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word);
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
sig, bit, wid);
|
||||
|
||||
} else {
|
||||
unsigned skip_set = transient_id++;
|
||||
|
|
@ -711,12 +708,34 @@ static int show_stmt_assign_sig_real(ivl_statement_t net)
|
|||
// For now, only support 1-dimensional arrays.
|
||||
assert(ivl_signal_dimensions(var) == 1);
|
||||
|
||||
// Calculate the word index into an index register
|
||||
ivl_expr_t word_ex = ivl_lval_idx(lval);
|
||||
int word_ix = allocate_word();
|
||||
draw_eval_expr_into_integer(word_ex, word_ix);
|
||||
// Generate an assignment to write to the array.
|
||||
fprintf(vvp_out, " %%store/reala v%p, %d;\n", var, word_ix);
|
||||
|
||||
/* If the word index is a constant, then we can write
|
||||
directly to the word and save the index calculation.
|
||||
Out-of-bounds and undefined indices are converted to
|
||||
a canonical index of 'bx during elaboration, and we
|
||||
don't try to optimise that case. */
|
||||
if (word_ex && number_is_immediate(word_ex, IMM_WID, 0) &&
|
||||
!number_is_unknown(word_ex)) {
|
||||
unsigned long use_word = get_number_immediate(word_ex);
|
||||
assert(use_word < ivl_signal_array_count(var));
|
||||
fprintf(vvp_out, " %%ix/load %u, %lu, 0;\n",
|
||||
word_ix, use_word);
|
||||
fprintf(vvp_out, " %%store/reala v%p, %d;\n",
|
||||
var, word_ix);
|
||||
|
||||
} else {
|
||||
unsigned do_store = transient_id++;
|
||||
unsigned end_store = transient_id++;
|
||||
draw_eval_expr_into_integer(word_ex, word_ix);
|
||||
fprintf(vvp_out, " %%jmp/0 t_%u, 4;\n", do_store);
|
||||
fprintf(vvp_out, " %%pop/real 1;\n");
|
||||
fprintf(vvp_out, " %%jmp t_%u;\n", end_store);
|
||||
fprintf(vvp_out, "t_%u ;\n", do_store);
|
||||
fprintf(vvp_out, " %%store/reala v%p, %d;\n", var, word_ix);
|
||||
fprintf(vvp_out, "t_%u ;\n", end_store);
|
||||
}
|
||||
|
||||
clr_word(word_ix);
|
||||
|
||||
|
|
|
|||
|
|
@ -45,18 +45,22 @@ static void assign_to_array_r_word(ivl_signal_t lsig, ivl_expr_t word_ix,
|
|||
uint64_t delay,
|
||||
ivl_expr_t dexp, unsigned nevents)
|
||||
{
|
||||
unsigned skip_assign = transient_id++;
|
||||
unsigned end_assign = transient_id++;
|
||||
|
||||
/* This code is common to all the different types of array delays. */
|
||||
if (number_is_immediate(word_ix, IMM_WID, 0)) {
|
||||
assert(! number_is_unknown(word_ix));
|
||||
if (number_is_immediate(word_ix, IMM_WID, 0) &&
|
||||
!number_is_unknown(word_ix)) {
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu, 0; address\n",
|
||||
get_number_immediate(word_ix));
|
||||
} else {
|
||||
/* Calculate array word index into index register 3 */
|
||||
draw_eval_expr_into_integer(word_ix, 3);
|
||||
/* Skip assignment if word expression is not defined. */
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
|
||||
unsigned do_assign = transient_id++;
|
||||
fprintf(vvp_out, " %%jmp/0 t_%u, 4;\n", do_assign);
|
||||
fprintf(vvp_out, " %%pop/real 1;\n");
|
||||
fprintf(vvp_out, " %%jmp t_%u;\n", end_assign);
|
||||
fprintf(vvp_out, "t_%u ;\n", do_assign);
|
||||
}
|
||||
|
||||
if (dexp != 0) {
|
||||
|
|
@ -91,7 +95,7 @@ static void assign_to_array_r_word(ivl_signal_t lsig, ivl_expr_t word_ix,
|
|||
}
|
||||
}
|
||||
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_assign);
|
||||
fprintf(vvp_out, "t_%u ;\n", end_assign);
|
||||
if (nevents != 0) fprintf(vvp_out, " %%evctl/c;\n");
|
||||
|
||||
clear_expression_lookaside();
|
||||
|
|
@ -107,15 +111,15 @@ static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix,
|
|||
unsigned long part_off = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
/* This code is common to all the different types of array delays. */
|
||||
if (number_is_immediate(word_ix, IMM_WID, 0)) {
|
||||
assert(! number_is_unknown(word_ix));
|
||||
if (number_is_immediate(word_ix, IMM_WID, 0) &&
|
||||
!number_is_unknown(word_ix)) {
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu, 0; address\n",
|
||||
get_number_immediate(word_ix));
|
||||
} else {
|
||||
|
|
@ -840,12 +844,36 @@ static void force_real_to_lval(ivl_statement_t net)
|
|||
|
||||
assert(ivl_lval_width(lval) == 1);
|
||||
assert(ivl_lval_part_off(lval) == 0);
|
||||
assert(ivl_lval_idx(lval) == 0);
|
||||
|
||||
ivl_expr_t word_idx = ivl_lval_idx(lval);
|
||||
unsigned long use_word = 0;
|
||||
if (word_idx != 0) {
|
||||
assert(number_is_immediate(word_idx, IMM_WID, 0));
|
||||
/* An out-of-range or undefined index will have been
|
||||
converted to a canonical offset of 1'bx. Skip the
|
||||
assignment in this case. */
|
||||
if (number_is_unknown(word_idx)) {
|
||||
fprintf(vvp_out, " %%pop/real 1;\n");
|
||||
return;
|
||||
}
|
||||
use_word = get_number_immediate(word_idx);
|
||||
|
||||
/* We do not currently support using a word from a variable
|
||||
array as the L-value (SystemVerilog / Icarus extension). */
|
||||
if (ivl_signal_type(lsig) == IVL_SIT_REG) {
|
||||
fprintf(stderr, "%s:%u: tgt-vvp sorry: cannot %s to the "
|
||||
"word of a variable array (%s[%ld]).\n",
|
||||
ivl_stmt_file(net), ivl_stmt_lineno(net),
|
||||
command_name, ivl_signal_basename(lsig),
|
||||
ivl_signal_array_base(lsig) + (long)use_word);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* L-Value must be a signal: reg or wire */
|
||||
assert(lsig != 0);
|
||||
|
||||
fprintf(vvp_out, " %s v%p_0;\n", command_name, lsig);
|
||||
|
||||
fprintf(vvp_out, " %s v%p_%lu;\n", command_name, lsig, use_word);
|
||||
}
|
||||
|
||||
static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec)
|
||||
|
|
@ -886,14 +914,33 @@ static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec)
|
|||
part_off = 0;
|
||||
} else {
|
||||
assert(number_is_immediate(part_off_ex, IMM_WID, 0));
|
||||
assert(! number_is_unknown(part_off_ex));
|
||||
/* An out-of-range or undefined offset will have been
|
||||
converted to a canonical offset of 1'bx. Skip the
|
||||
assignment in this case. */
|
||||
if (number_is_unknown(part_off_ex))
|
||||
return;
|
||||
part_off = get_number_immediate(part_off_ex);
|
||||
}
|
||||
|
||||
if (word_idx != 0) {
|
||||
assert(number_is_immediate(word_idx, IMM_WID, 0));
|
||||
assert(! number_is_unknown(word_idx));
|
||||
/* An out-of-range or undefined index will have been
|
||||
converted to a canonical offset of 1'bx. Skip the
|
||||
assignment in this case. */
|
||||
if (number_is_unknown(word_idx))
|
||||
return;
|
||||
use_word = get_number_immediate(word_idx);
|
||||
|
||||
/* We do not currently support using a word from a variable
|
||||
array as the L-value (SystemVerilog / Icarus extension). */
|
||||
if (ivl_signal_type(lsig) == IVL_SIT_REG) {
|
||||
fprintf(stderr, "%s:%u: tgt-vvp sorry: cannot %s to the "
|
||||
"word of a variable array (%s[%ld]).\n",
|
||||
ivl_stmt_file(net), ivl_stmt_lineno(net),
|
||||
command_name, ivl_signal_basename(lsig),
|
||||
ivl_signal_array_base(lsig) + (long)use_word);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* L-Value must be a signal: reg or wire */
|
||||
|
|
@ -1000,10 +1047,14 @@ static void force_link_rval(ivl_statement_t net, ivl_expr_t rval)
|
|||
/* At least for now, only handle force to fixed words of an array. */
|
||||
if ((lword_idx = ivl_lval_idx(lval)) != 0) {
|
||||
assert(number_is_immediate(lword_idx, IMM_WID, 0));
|
||||
assert(! number_is_unknown(lword_idx));
|
||||
/* An out-of-range or undefined index will have been
|
||||
converted to a canonical offset of 1'bx. Skip the
|
||||
assignment in this case. */
|
||||
if (number_is_unknown(lword_idx))
|
||||
return;
|
||||
use_lword = get_number_immediate(lword_idx);
|
||||
/* We do not currently support using a word from a variable
|
||||
* array as the L-value (Icarus extension). */
|
||||
* array as the L-value (SystemVerilog / Icarus extension). */
|
||||
if (ivl_signal_type(lsig) == IVL_SIT_REG) {
|
||||
/* Normalize the array access. */
|
||||
long real_word = use_lword;
|
||||
|
|
@ -1019,7 +1070,11 @@ static void force_link_rval(ivl_statement_t net, ivl_expr_t rval)
|
|||
if ((rword_idx = ivl_expr_oper1(rval)) != 0) {
|
||||
assert(ivl_signal_dimensions(rsig) != 0);
|
||||
assert(number_is_immediate(rword_idx, IMM_WID, 0));
|
||||
assert(! number_is_unknown(rword_idx));
|
||||
/* An out-of-range or undefined index will have been
|
||||
converted to a canonical offset of 1'bx. Skip the
|
||||
assignment in this case. */
|
||||
if (number_is_unknown(rword_idx))
|
||||
return;
|
||||
use_rword = get_number_immediate(rword_idx);
|
||||
/* We do not currently support using a word from a variable
|
||||
* array as the R-value. */
|
||||
|
|
@ -1093,9 +1148,20 @@ static int show_stmt_deassign(ivl_statement_t net)
|
|||
lval = ivl_stmt_lval(net, 0);
|
||||
assert(ivl_lval_width(lval) == 1);
|
||||
assert(ivl_lval_part_off(lval) == 0);
|
||||
assert(ivl_lval_idx(lval) == 0);
|
||||
|
||||
fprintf(vvp_out, " %%deassign/wr v%p_0;\n", sig);
|
||||
ivl_expr_t word_idx = ivl_lval_idx(lval);
|
||||
unsigned long use_word = 0;
|
||||
if (word_idx != 0) {
|
||||
assert(number_is_immediate(word_idx, IMM_WID, 0));
|
||||
/* An out-of-range or undefined index will have been
|
||||
converted to a canonical offset of 1'bx. Skip the
|
||||
deassignment in this case. */
|
||||
if (number_is_unknown(word_idx))
|
||||
return 0;
|
||||
use_word = get_number_immediate(word_idx);
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%deassign/wr v%p_%lu;\n", sig, use_word);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1123,7 +1189,11 @@ static int show_stmt_deassign(ivl_statement_t net)
|
|||
|
||||
if (word_idx != 0) {
|
||||
assert(number_is_immediate(word_idx, IMM_WID, 0));
|
||||
assert(! number_is_unknown(word_idx));
|
||||
/* An out-of-range or undefined index will have been
|
||||
converted to a canonical offset of 1'bx. Skip the
|
||||
deassignment in this case. */
|
||||
if (number_is_unknown(word_idx))
|
||||
return 0;
|
||||
use_word = get_number_immediate(word_idx);
|
||||
}
|
||||
|
||||
|
|
@ -1432,11 +1502,23 @@ static int show_stmt_release(ivl_statement_t net)
|
|||
lval = ivl_stmt_lval(net, 0);
|
||||
assert(ivl_lval_width(lval) == 1);
|
||||
assert(ivl_lval_part_off(lval) == 0);
|
||||
assert(ivl_lval_idx(lval) == 0);
|
||||
|
||||
ivl_expr_t word_idx = ivl_lval_idx(lval);
|
||||
unsigned long use_word = 0;
|
||||
if (word_idx != 0) {
|
||||
assert(number_is_immediate(word_idx, IMM_WID, 0));
|
||||
/* An out-of-range or undefined index will have been
|
||||
converted to a canonical offset of 1'bx. Skip the
|
||||
deassignment in this case. */
|
||||
if (number_is_unknown(word_idx))
|
||||
return 0;
|
||||
use_word = get_number_immediate(word_idx);
|
||||
}
|
||||
|
||||
if (ivl_signal_type(sig) == IVL_SIT_REG) type = 1;
|
||||
|
||||
fprintf(vvp_out, " %%release/wr v%p_0, %u;\n", sig, type);
|
||||
fprintf(vvp_out, " %%release/wr v%p_%lu, %u;\n",
|
||||
sig, use_word, type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1459,7 +1541,11 @@ static int show_stmt_release(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));
|
||||
/* An out-of-range or undefined offset will have been
|
||||
converted to a canonical offset of 1'bx. Skip the
|
||||
assignment in this case. */
|
||||
if (number_is_unknown(part_off_ex))
|
||||
return 0;
|
||||
part_off = get_number_immediate(part_off_ex);
|
||||
}
|
||||
|
||||
|
|
@ -1474,7 +1560,11 @@ static int show_stmt_release(ivl_statement_t net)
|
|||
|
||||
if (word_idx != 0) {
|
||||
assert(number_is_immediate(word_idx, IMM_WID, 0));
|
||||
assert(! number_is_unknown(word_idx));
|
||||
/* An out-of-range or undefined index will have been
|
||||
converted to a canonical offset of 1'bx. Skip the
|
||||
assignment in this case. */
|
||||
if (number_is_unknown(word_idx))
|
||||
return 0;
|
||||
use_word = get_number_immediate(word_idx);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue