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:
Martin Whitaker 2013-05-18 19:21:37 +01:00
parent 0aca19356c
commit 26dc6d68cd
9 changed files with 297 additions and 131 deletions

14
PExpr.h
View File

@ -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;

View File

@ -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) {

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);
}