Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Get unpacked arrays working.

  • Loading branch information...
commit 6e8aef82626d174aba7e53666652cb5087e780b2 1 parent f7ba954
@steveicarus authored
View
9 PWire.cc
@@ -29,7 +29,7 @@ PWire::PWire(perm_string n,
: name_(n), type_(t), port_type_(pt), data_type_(dt),
signed_(false), isint_(false),
port_set_(false), net_set_(false), is_scalar_(false),
- error_cnt_(0), lidx_(0), ridx_(0), enum_type_(0), struct_type_(0),
+ error_cnt_(0), enum_type_(0), struct_type_(0),
discipline_(0)
{
if (t == NetNet::INTEGER) {
@@ -242,15 +242,14 @@ void PWire::set_range(const list<pform_range_t>&rlist, PWSRType type)
}
}
-void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx)
+void PWire::set_unpacked_idx(const list<pform_range_t>&ranges)
{
- if (lidx_ != 0 || ridx_ != 0) {
+ if (! unpacked_.empty()) {
cerr << get_fileline() << ": error: Array ``" << name_
<< "'' has already been declared." << endl;
error_cnt_ += 1;
} else {
- lidx_ = ldx;
- ridx_ = rdx;
+ unpacked_ = ranges;
}
}
View
7 PWire.h
@@ -78,7 +78,7 @@ class PWire : public LineInfo {
void set_range_scalar(PWSRType type);
void set_range(const std::list<pform_range_t>&ranges, PWSRType type);
- void set_memory_idx(PExpr*ldx, PExpr*rdx);
+ void set_unpacked_idx(const std::list<pform_range_t>&ranges);
void set_enumeration(enum_type_t*enum_type);
void set_struct_type(struct_type_t*type);
@@ -115,9 +115,8 @@ class PWire : public LineInfo {
unsigned error_cnt_;
// If this wire is actually a memory, these indices will give
- // me the size and address range of the memory.
- PExpr*lidx_;
- PExpr*ridx_;
+ // me the size and address ranges of the memory.
+ std::list<pform_range_t>unpacked_;
enum_type_t*enum_type_;
struct_type_t*struct_type_;
View
11 design_dump.cc
@@ -196,11 +196,20 @@ ostream&operator<<(ostream&out, const list<NetNet::range_t>&rlist)
return out;
}
+ostream&operator<<(ostream&out, const vector<NetNet::range_t>&rlist)
+{
+ for (vector<NetNet::range_t>::const_iterator cur = rlist.begin()
+ ; cur != rlist.end() ; ++cur) {
+ out << "[" << cur->msb << ":" << cur->lsb << "]";
+ }
+ return out;
+}
+
/* Dump a net. This can be a wire or register. */
void NetNet::dump_net(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << type() << ": " << name()
- << "[" << s0_ << ":" << e0_ << " count=" << pin_count() << "]";
+ << unpacked_dims_ << " unpacked dims=" << unpacked_dimensions() << " count=" << pin_count();
if (local_flag_)
o << " (local)";
o << " " << data_type_;
View
107 elab_expr.cc
@@ -1873,7 +1873,7 @@ bool PEIdent::calculate_packed_indices_(Design*des, NetScope*scope, NetNet*net,
{
list<index_component_t> index;
index = path_.back().index;
- for (size_t idx = 0 ; idx < net->array_dimensions() ; idx += 1)
+ for (size_t idx = 0 ; idx < net->unpacked_dimensions() ; idx += 1)
index.pop_front();
return evaluate_index_prefix(des, scope, prefix_indices, index);
@@ -2073,7 +2073,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
if (!name_tail.index.empty()) {
const index_component_t&index_tail = name_tail.index.back();
// Skip full array word net selects.
- if (!net || (name_tail.index.size() > net->array_dimensions())) {
+ if (!net || (name_tail.index.size() > net->unpacked_dimensions())) {
use_sel = index_tail.sel;
}
}
@@ -3037,78 +3037,69 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
const name_component_t&name_tail = path_.back();
- if (name_tail.index.empty() && !(SYS_TASK_ARG & flags)) {
+ // Special case: This is the entire array, and we are a direct
+ // argument of a system task.
+ if (name_tail.index.empty() && (SYS_TASK_ARG & flags)) {
+ NetESignal*res = new NetESignal(net, 0);
+ res->set_line(*this);
+ return res;
+ }
+
+ if (name_tail.index.empty()) {
cerr << get_fileline() << ": error: Array " << path()
<< " Needs an array index here." << endl;
des->errors += 1;
return 0;
}
- index_component_t index_front;
- if (! name_tail.index.empty()) {
- index_front = name_tail.index.front();
- ivl_assert(*this, index_front.sel != index_component_t::SEL_NONE);
- if (index_front.sel != index_component_t::SEL_BIT) {
- cerr << get_fileline() << ": error: Array " << path_
- << " cannot be indexed by a range." << endl;
- des->errors += 1;
- return 0;
- }
- ivl_assert(*this, index_front.msb);
- ivl_assert(*this, !index_front.lsb);
- }
-
- NetExpr*word_index = 0;
- if (index_front.sel != index_component_t::SEL_NONE)
- word_index = elab_and_eval(des, scope, index_front.msb, -1,
- need_const);
-
- if (word_index == 0 && !(SYS_TASK_ARG & flags))
+ // Make sure there are enough indices to address an array element.
+ if (name_tail.index.size() < net->unpacked_dimensions()) {
+ cerr << get_fileline() << ": error: Array " << path()
+ << " needs " << net->unpacked_dimensions() << " indices,"
+ << " but got only " << name_tail.index.size() << "." << endl;
+ des->errors += 1;
return 0;
+ }
- if (NetEConst*word_addr = dynamic_cast<NetEConst*>(word_index)) {
- long addr = word_addr->value().as_long();
-
- // Special case: The index is out of range, so the value
- // of this expression is a 'bx vector the width of a word.
- if (!net->array_index_is_valid(addr)) {
- cerr << get_fileline() << ": warning: returning 'bx for out "
- "of bounds array access " << net->name()
- << "[" << addr << "]." << endl;
- NetEConst*resx = make_const_x(net->vector_width());
- resx->set_line(*this);
- delete word_index;
- return resx;
- }
-
- // Recalculate the constant address with the adjusted base.
- unsigned use_addr = net->array_index_to_address(addr);
- if (addr < 0 || use_addr != (unsigned long)addr) {
- verinum val ( (uint64_t)use_addr, 8*sizeof(use_addr));
- NetEConst*tmp = new NetEConst(val);
- tmp->set_line(*this);
- delete word_index;
- word_index = tmp;
+ // Evaluate all the index expressions into an
+ // "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);
+
+ NetExpr*canon_index = 0;
+ if (flag) {
+ 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;
}
- } else if (word_index) {
- // If there is a non-zero base to the memory, then build an
- // expression to calculate the canonical address.
- if (long base = net->array_first()) {
+ } else {
+ ivl_assert(*this, unpacked_indices.size() == net->unpacked_dimensions());
+ canon_index = normalize_variable_unpacked(net, unpacked_indices);
+ }
- word_index = normalize_variable_array_base(
- word_index, base, net->array_count());
- eval_expr(word_index);
- }
+ if (canon_index == 0) {
+ NetEConst*xxx = make_const_x(net->vector_width());
+ xxx->set_line(*this);
+ return xxx;
}
- NetESignal*res = new NetESignal(net, word_index);
+ NetESignal*res = new NetESignal(net, canon_index);
res->set_line(*this);
// Detect that the word has a bit/part select as well.
index_component_t::ctype_t word_sel = index_component_t::SEL_NONE;
- if (name_tail.index.size() > 1)
+ if (name_tail.index.size() > net->unpacked_dimensions())
word_sel = name_tail.index.back().sel;
if (net->get_scalar() &&
@@ -3117,7 +3108,7 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
if (res->expr_type() == IVL_VT_REAL) cerr << "real";
else cerr << "scalar";
cerr << " array word: " << net->name()
- <<"[" << *word_index << "]" << endl;
+ << as_indices(unpacked_indices) << endl;
des->errors += 1;
delete res;
return 0;
@@ -3599,7 +3590,7 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope,
unsigned expr_wid,
unsigned flags) const
{
- if (net->array_dimensions() > 0)
+ if (net->unpacked_dimensions() > 0)
return elaborate_expr_net_word_(des, scope, net, found_in,
expr_wid, flags);
View
83 elab_lval.cc
@@ -202,7 +202,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
// slice. This is, in fact, an error in l-values. Detect the
// situation by noting if the index count is less than the
// array dimensions (unpacked).
- if (reg->array_dimensions() > name_tail.index.size()) {
+ if (reg->unpacked_dimensions() > name_tail.index.size()) {
cerr << get_fileline() << ": error: Cannot assign to array "
<< path_ << ". Did you forget a word index?" << endl;
des->errors += 1;
@@ -228,7 +228,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
return lv;
}
- if (reg->array_dimensions() > 0)
+ if (reg->unpacked_dimensions() > 0)
return elaborate_lval_net_word_(des, scope, reg);
// This must be after the array word elaboration above!
@@ -278,6 +278,15 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
const name_component_t&name_tail = path_.back();
ivl_assert(*this, !name_tail.index.empty());
+ if (name_tail.index.size() < reg->unpacked_dimensions()) {
+ cerr << get_fileline() << ": error: Array " << reg->name()
+ << " needs " << reg->unpacked_dimensions() << " indices,"
+ << " but got only " << name_tail.index.size() << "." << endl;
+ des->errors += 1;
+ return 0;
+ }
+
+ // Make sure there are enough indices to address an array element.
const index_component_t&index_head = name_tail.index.front();
if (index_head.sel == index_component_t::SEL_PART) {
cerr << get_fileline() << ": error: cannot perform a part "
@@ -286,47 +295,47 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
return 0;
}
- ivl_assert(*this, index_head.sel == index_component_t::SEL_BIT);
- ivl_assert(*this, index_head.msb != 0);
- ivl_assert(*this, index_head.lsb == 0);
- NetExpr*word = elab_and_eval(des, scope, index_head.msb, -1);
-
- // If there is a non-zero base to the memory, then build an
- // expression to calculate the canonical address.
- if (long base = reg->array_first()) {
-
- word = normalize_variable_array_base(word, base,
- reg->array_count());
- eval_expr(word);
+ // Evaluate all the index expressions into an
+ // "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);
+
+ 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;
+ }
+ } else {
+ ivl_assert(*this, unpacked_indices.size() == reg->unpacked_dimensions());
+ canon_index = normalize_variable_unpacked(reg, unpacked_indices);
}
+
NetAssign_*lv = new NetAssign_(reg);
- lv->set_word(word);
+ lv->set_word(canon_index);
if (debug_elaborate)
- cerr << get_fileline() << ": debug: Set array word=" << *word << endl;
-
- // Test for the case that the index is a constant, and is out
- // of bounds. The "word" expression is the word index already
- // converted to canonical address, so this just needs to check
- // that the address is not too big.
- if (NetEConst*word_const = dynamic_cast<NetEConst*>(word)) {
- verinum word_val = word_const->value();
- long index = word_val.as_long();
-
- if (index < 0 || index >= (long) reg->array_count()) {
- cerr << get_fileline() << ": warning: Constant array index "
- << (index + reg->array_first())
- << " is out of range for array "
- << reg->name() << "." << endl;
- }
- }
+ cerr << get_fileline() << ": debug: Set array word=" << *canon_index << endl;
+
/* An array word may also have part selects applied to them. */
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
- if (name_tail.index.size() > 1)
+ if (name_tail.index.size() > reg->unpacked_dimensions())
use_sel = name_tail.index.back().sel;
if (reg->get_scalar() &&
@@ -335,7 +344,7 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
if (reg->data_type() == IVL_VT_REAL) cerr << "real";
else cerr << "scalar";
cerr << " array word: " << reg->name()
- << "[" << *word << "]" << endl;
+ << "[" << *canon_index << "]" << endl;
des->errors += 1;
return 0;
}
@@ -563,7 +572,7 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
if (warn_ob_select) {
if (rel_base < 0) {
cerr << get_fileline() << ": warning: " << reg->name();
- if (reg->array_dimensions() > 0) cerr << "[]";
+ if (reg->unpacked_dimensions() > 0) cerr << "[]";
cerr << "[" << lsv;
if (use_sel == index_component_t::SEL_IDX_UP) {
cerr << "+:";
@@ -574,7 +583,7 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
}
if (rel_base + wid > reg->vector_width()) {
cerr << get_fileline() << ": warning: " << reg->name();
- if (reg->array_dimensions() > 0) cerr << "[]";
+ if (reg->unpacked_dimensions() > 0) cerr << "[]";
cerr << "[" << lsv;
if (use_sel == index_component_t::SEL_IDX_UP) {
cerr << "+:";
@@ -587,7 +596,7 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
} else {
if (warn_ob_select) {
cerr << get_fileline() << ": warning: " << reg->name();
- if (reg->array_dimensions() > 0) cerr << "[]";
+ if (reg->unpacked_dimensions() > 0) cerr << "[]";
cerr << "['bx";
if (use_sel == index_component_t::SEL_IDX_UP) {
cerr << "+:";
View
81 elab_net.cc
@@ -208,7 +208,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
// Only treat as part/bit selects any index that is beyond the
// word selects for an array. This is not an array, then
// dimensions==0 and any index is treated as a select.
- if (name_tail.index.size() <= sig->array_dimensions()) {
+ if (name_tail.index.size() <= sig->unpacked_dimensions()) {
midx = sig->vector_width()-1;
lidx = 0;
return true;
@@ -247,7 +247,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
if (warn_ob_select) {
cerr << get_fileline() << ": warning: "
<< sig->name();
- if (sig->array_dimensions() > 0) cerr << "[]";
+ if (sig->unpacked_dimensions() > 0) cerr << "[]";
cerr << "['bx";
if (index_tail.sel ==
index_component_t::SEL_IDX_UP) {
@@ -279,7 +279,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
/* Warn about an indexed part select that is out of range. */
if (warn_ob_select && (lidx < 0)) {
cerr << get_fileline() << ": warning: " << sig->name();
- if (sig->array_dimensions() > 0) cerr << "[]";
+ if (sig->unpacked_dimensions() > 0) cerr << "[]";
cerr << "[" << midx_val;
if (index_tail.sel == index_component_t::SEL_IDX_UP) {
cerr << "+:";
@@ -290,7 +290,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
}
if (warn_ob_select && (midx >= (long)sig->vector_width())) {
cerr << get_fileline() << ": warning: " << sig->name();
- if (sig->array_dimensions() > 0) {
+ if (sig->unpacked_dimensions() > 0) {
cerr << "[]";
}
cerr << "[" << midx_val;
@@ -337,16 +337,11 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
if (midx_tmp >= (long)sig->vector_width() || lidx_tmp < 0) {
cerr << get_fileline() << ": warning: Part select "
<< sig->name();
- if (sig->array_dimensions() > 0) {
+ if (sig->unpacked_dimensions() > 0) {
cerr << "[]";
}
cerr << "[" << msb << ":" << lsb
<< "] is out of range." << endl;
-#if 0
- midx_tmp = sig->vector_width() - 1;
- lidx_tmp = 0;
- des->errors += 1;
-#endif
}
/* This is completely out side the signal so just skip it. */
if (lidx_tmp >= (long)sig->vector_width() || midx_tmp < 0) {
@@ -359,7 +354,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
}
case index_component_t::SEL_BIT:
- if (name_tail.index.size() > sig->array_dimensions()) {
+ if (name_tail.index.size() > sig->unpacked_dimensions()) {
long msb;
bool bit_defined_flag;
/* bool flag = */ calculate_bits_(des, scope, msb, bit_defined_flag);
@@ -460,11 +455,9 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
unsigned midx = sig->vector_width()-1, lidx = 0;
// The default word select is the first.
long widx = 0;
- // The widx_val is the word select as entered in the source
- // code. It's used for error messages.
- long widx_val = 0;
const name_component_t&name_tail = path_.back();
+ list<long> unpacked_indices_const;
netstruct_t*struct_type = 0;
if ((struct_type = sig->struct_type()) && !method_name.nil()) {
@@ -485,53 +478,64 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
lidx = member_off;
midx = lidx + member->width() - 1;
- } else if (sig->array_dimensions() > 0) {
-
- if (name_tail.index.empty()) {
- cerr << get_fileline() << ": error: array " << sig->name()
- << " must be used with an index." << endl;
- des->errors += 1;
- return 0;
- }
+ } else if (sig->unpacked_dimensions() > 0) {
- const index_component_t&index_head = name_tail.index.front();
- if (index_head.sel == index_component_t::SEL_PART) {
- cerr << get_fileline() << ": error: cannot perform a part "
- << "select on array " << sig->name() << "." << endl;
+ // Make sure there are enough indices to address an array element.
+ if (name_tail.index.size() < sig->unpacked_dimensions()) {
+ cerr << get_fileline() << ": error: Array " << path()
+ << " needs " << sig->unpacked_dimensions() << " indices,"
+ << " but got only " << name_tail.index.size() << "." << endl;
des->errors += 1;
return 0;
}
- ivl_assert(*this, index_head.sel == index_component_t::SEL_BIT);
- NetExpr*tmp_ex = elab_and_eval(des, scope, index_head.msb, -1, true);
- NetEConst*tmp = dynamic_cast<NetEConst*>(tmp_ex);
- if (!tmp) {
+ // Evaluate all the index expressions into an
+ // "unpacked_indices" array.
+ list<NetExpr*>unpacked_indices;
+ bool flag = indices_to_expressions(des, scope, this,
+ name_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;
des->errors += 1;
return 0;
}
- widx_val = tmp->value().as_long();
- if (sig->array_index_is_valid(widx_val))
- widx = sig->array_index_to_address(widx_val);
- else
+ 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.
widx = -1;
- delete tmp_ex;
+
+ } 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)
cerr << get_fileline() << ": debug: Use [" << widx << "]"
<< " to index l-value array." << endl;
/* The array has a part/bit select at the end. */
- if (name_tail.index.size() > sig->array_dimensions()) {
+ if (name_tail.index.size() > sig->unpacked_dimensions()) {
if (sig->get_scalar()) {
cerr << get_fileline() << ": error: "
<< "can not select part of ";
if (sig->data_type() == IVL_VT_REAL) cerr << "real";
else cerr << "scalar";
cerr << " array word: " << sig->name()
- << "[" << widx_val << "]" << endl;
+ << as_indices(unpacked_indices_const) << endl;
des->errors += 1;
return 0;
}
@@ -550,6 +554,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
midx = midx_tmp;
lidx = lidx_tmp;
}
+
} else if (!name_tail.index.empty()) {
if (sig->get_scalar()) {
cerr << get_fileline() << ": error: "
@@ -590,7 +595,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
if (widx < 0 || widx >= (long) sig->pin_count()) {
cerr << get_fileline() << ": warning: ignoring out of "
"bounds l-value array access "
- << sig->name() << "[" << widx_val << "]." << endl;
+ << sig->name() << as_indices(unpacked_indices_const) << "." << endl;
return 0;
}
View
45 elab_sig.cc
@@ -1057,19 +1057,17 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
attrib_list_t*attrib_list = evaluate_attributes(attributes, nattrib,
des, scope);
- long array_s0 = 0;
- long array_e0 = 0;
- unsigned array_dimensions = 0;
- /* If the ident has idx expressions, then this is a
- memory. It can only have the idx registers after the msb
- and lsb expressions are filled. And, if it has one index,
- it has both. */
- if (lidx_ || ridx_) {
- assert(lidx_ && ridx_);
+ list<NetNet::range_t>unpacked_dimensions;
- NetExpr*lexp = elab_and_eval(des, scope, lidx_, -1, true);
- NetExpr*rexp = elab_and_eval(des, scope, ridx_, -1, true);
+ for (list<pform_range_t>::const_iterator cur = unpacked_.begin()
+ ; cur != unpacked_.end() ; ++cur) {
+ PExpr*use_lidx = cur->first;
+ PExpr*use_ridx = cur->second;
+ assert(use_lidx && use_ridx);
+
+ NetExpr*lexp = elab_and_eval(des, scope, use_lidx, -1, true);
+ NetExpr*rexp = elab_and_eval(des, scope, use_ridx, -1, true);
if ((lexp == 0) || (rexp == 0)) {
cerr << get_fileline() << ": internal error: There is "
@@ -1086,19 +1084,21 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
delete rexp;
delete lexp;
- if (!const_flag) {
+ long index_l, index_r;
+ if (! const_flag) {
cerr << get_fileline() << ": error: The indices "
<< "are not constant for array ``"
<< name_ << "''." << endl;
des->errors += 1;
/* Attempt to recover from error, */
- array_s0 = 0;
- array_e0 = 0;
+ index_l = 0;
+ index_r = 0;
} else {
- array_s0 = lval.as_long();
- array_e0 = rval.as_long();
- }
- array_dimensions = 1;
+ index_l = lval.as_long();
+ index_r = rval.as_long();
+ }
+
+ unpacked_dimensions.push_back(NetNet::range_t(index_l, index_r));
}
if (data_type_ == IVL_VT_REAL && !packed_dimensions.empty()) {
@@ -1173,16 +1173,11 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
if (!get_scalar()) {
cerr << " " << packed_dimensions;
}
- cerr << " " << name_;
- if (array_dimensions > 0) {
- cerr << " [" << array_s0 << ":" << array_e0 << "]" << endl;
- }
+ cerr << " " << name_ << unpacked_dimensions;
cerr << " in scope " << scope_path(scope) << endl;
}
- sig = array_dimensions > 0
- ? new NetNet(scope, name_, wtype, packed_dimensions, array_s0, array_e0)
- : new NetNet(scope, name_, wtype, packed_dimensions);
+ sig = new NetNet(scope, name_, wtype, packed_dimensions, unpacked_dimensions);
}
// If this is an enumeration, then set the enumeration set for
View
2  net_nex_input.cc
@@ -159,7 +159,7 @@ NexusSet* NetESignal::nex_input(bool rem_out)
delete tmp;
if (warn_sens_entire_arr) {
cerr << get_fileline() << ": warning: @* is sensitive to all "
- << net_->array_count() << " words in array '"
+ << net_->unpacked_count() << " words in array '"
<< name() << "'." << endl;
}
}
View
85 netlist.cc
@@ -452,7 +452,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins)
type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE),
signed_(false), isint_(false), is_scalar_(false), local_flag_(false),
enumeration_(0), struct_type_(0), discipline_(0),
- dimensions_(0), s0_(0), e0_(0), eref_count_(0), lref_count_(0)
+ eref_count_(0), lref_count_(0)
{
assert(s);
assert(npins>0);
@@ -501,7 +501,6 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false),
isint_(false), is_scalar_(false), local_flag_(false),
enumeration_(0), struct_type_(0), discipline_(0),
- dimensions_(0), s0_(0), e0_(0),
eref_count_(0), lref_count_(0)
{
packed_dims_ = packed;
@@ -529,34 +528,41 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
s->add_signal(this);
}
-static unsigned calculate_count(long s, long e)
+static unsigned calculate_count(const list<NetNet::range_t>&unpacked)
{
- unsigned long r;
- if (s >= e) {
- r = s - e;
- } else {
- r = e - s;
+ unsigned long sum = 1;
+ for (list<NetNet::range_t>::const_iterator cur = unpacked.begin()
+ ; cur != unpacked.end() ; ++cur) {
+ sum *= cur->width();
}
- if (r >= UINT_MAX) {
+
+ if (sum >= UINT_MAX)
return 0;
- }
- return r + 1;
+
+ return sum;
}
NetNet::NetNet(NetScope*s, perm_string n, Type t,
- const list<NetNet::range_t>&packed, long array_s, long array_e)
-: NetObj(s, n, calculate_count(array_s, array_e)),
+ const list<NetNet::range_t>&packed,
+ const list<NetNet::range_t>&unpacked)
+: NetObj(s, n, calculate_count(unpacked)),
type_(t), port_type_(NOT_A_PORT),
data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false),
is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(0),
- discipline_(0),
- dimensions_(1), s0_(array_s), e0_(array_e),
+ discipline_(0), unpacked_dims_(unpacked.size()),
eref_count_(0), lref_count_(0)
{
packed_dims_ = packed;
+ size_t idx = 0;
+ for (list<NetNet::range_t>::const_iterator cur = unpacked.begin()
+ ; cur != unpacked.end() ; ++cur, idx += 1) {
+ unpacked_dims_[idx] = *cur;
+ }
+ assert(idx == unpacked_dims_.size());
+
ivl_assert(*this, s);
if (pin_count() == 0) {
- cerr << "Array too big [" << array_s << ":" << array_e << "]" << endl;
+ cerr << "Array too big " << unpacked << endl;
ivl_assert(*this, 0);
}
@@ -602,7 +608,6 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, netstruct_t*ty)
data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false),
is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(ty),
discipline_(0),
- dimensions_(0), s0_(0), e0_(0),
eref_count_(0), lref_count_(0)
{
packed_dims_.push_back(range_t(calculate_count(ty)-1, 0));
@@ -878,52 +883,16 @@ bool NetNet::sb_to_slice(const list<long>&indices, long sb, long&loff, unsigned
return true;
}
-
-unsigned NetNet::array_dimensions() const
-{
- return dimensions_;
-}
-
-long NetNet::array_first() const
-{
- if (s0_ <= e0_)
- return s0_;
- else
- return e0_;
-}
-
-bool NetNet::array_addr_swapped() const
+unsigned NetNet::unpacked_count() const
{
- if (s0_ <= e0_)
- return false;
- else
- return true;
-}
+ unsigned c = 1;
+ for (size_t idx = 0 ; idx < unpacked_dims_.size() ; idx += 1) {
+ c *= unpacked_dims_[idx].width();
+ }
-unsigned NetNet::array_count() const
-{
- unsigned c = calculate_count(s0_, e0_);
- ivl_assert(*this, c > 0);
return c;
}
-bool NetNet::array_index_is_valid(long sb) const
-{
- if (sb < s0_ && sb < e0_)
- return false;
- if (sb > e0_ && sb > s0_)
- return false;
- return true;
-}
-
-unsigned NetNet::array_index_to_address(long sb) const
-{
- if (s0_ <= e0_)
- return sb - s0_;
- else
- return sb - e0_;
-}
-
void NetNet::incr_eref()
{
eref_count_ += 1;
View
21 netlist.h
@@ -591,7 +591,8 @@ class NetNet : public NetObj {
explicit NetNet(NetScope*s, perm_string n, Type t,
const std::list<range_t>&packed);
explicit NetNet(NetScope*s, perm_string n, Type t,
- const std::list<range_t>&packed, long s0, long e0);
+ const std::list<range_t>&packed,
+ const std::list<range_t>&unpacked);
// This form builds a NetNet from its record definition.
explicit NetNet(NetScope*s, perm_string n, Type t, netstruct_t*type);
@@ -635,6 +636,8 @@ class NetNet : public NetObj {
the verilog declaration. */
const std::list<range_t>& packed_dims() const { return packed_dims_; }
+ const std::vector<range_t>& unpacked_dims() const { return unpacked_dims_; }
+
/* The vector_width returns the bit width of the packed array,
vector or scaler that is this NetNet object. The static
method is also a convenient way to convert a range list to
@@ -670,18 +673,10 @@ class NetNet : public NetObj {
/* This method returns 0 for scalars and vectors, and greater
for arrays. The value is the number of array
indices. (Currently only one array index is supported.) */
- unsigned array_dimensions() const;
- long array_first() const;
- bool array_addr_swapped() const;
+ inline unsigned unpacked_dimensions() const { return unpacked_dims_.size(); }
// This is the number of array elements.
- unsigned array_count() const;
-
- // This method returns a 0 based address of an array entry as
- // indexed by idx. The Verilog source may give index ranges
- // that are not zero based.
- bool array_index_is_valid(long idx) const;
- unsigned array_index_to_address(long idx) const;
+ unsigned unpacked_count() const;
bool local_flag() const { return local_flag_; }
void local_flag(bool f) { local_flag_ = f; }
@@ -723,11 +718,11 @@ class NetNet : public NetObj {
ivl_discipline_t discipline_;
std::list<range_t> packed_dims_;
- const unsigned dimensions_;
- long s0_, e0_;
+ std::vector<range_t> unpacked_dims_;
unsigned eref_count_;
unsigned lref_count_;
+
// When the signal is an unresolved wire, we need more detail
// which bits are assigned. This mask is true for each bit
// that is known to be driven.
View
233 netmisc.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)
+ * Copyright (c) 2001-2012 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -384,51 +384,202 @@ NetExpr *normalize_variable_slice_base(const list<long>&indices, NetExpr*base,
return base;
}
+ostream& operator << (ostream&o, __IndicesManip<long> val)
+{
+ for (list<long>::const_iterator cur = val.val.begin()
+ ; cur != val.val.end() ; ++cur) {
+ o << "[" << *cur << "]";
+ }
+ return o;
+}
+
+ostream& operator << (ostream&o, __IndicesManip<NetExpr*> val)
+{
+ for (list<NetExpr*>::const_iterator cur = val.val.begin()
+ ; cur != val.val.end() ; ++cur) {
+ o << "[" << *(*cur) << "]";
+ }
+ return o;
+}
+
/*
- * This routine generates the normalization expression needed for a variable
- * array word select.
+ * 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.
*/
-NetExpr *normalize_variable_array_base(NetExpr *base, long offset,
- unsigned count)
-{
- assert(offset != 0);
- /* Calculate the space needed for the offset. */
- unsigned min_wid = num_bits(-offset);
- /* We need enough space for the larger of the offset or the base
- * expression. */
- if (min_wid < base->expr_width()) min_wid = base->expr_width();
- /* Now that we have the minimum needed width increase it by one
- * to make room for the normalization calculation. */
- min_wid += 1;
- /* Pad the base expression to the correct width. */
- base = pad_to_width(base, min_wid, *base);
- /* If the offset is greater than zero then we need to do signed
- * math to get the location value correct. */
- if (offset > 0 && ! base->has_sign()) {
- /* We need this extra select to hide the signed property
- * from the padding above. It will be removed automatically
- * during code generation. */
- NetESelect *tmp = new NetESelect(base, 0 , min_wid);
- tmp->set_line(*base);
- tmp->cast_signed(true);
- base = tmp;
- }
- /* Normalize the expression. */
- base = make_add_expr(base, -offset);
-
- /* We should not need to do this, but .array/port does not
- * handle a small signed index correctly and it is a major
- * effort to fix it. For now we will just pad the expression
- * enough so that any negative value when converted to
- * unsigned is larger than the maximum array word. */
- if (base->has_sign()) {
- unsigned range_wid = num_bits(count-1) + 1;
- if (min_wid < range_wid) {
- base = pad_to_width(base, range_wid, *base);
+bool indices_to_expressions(Design*des, NetScope*scope,
+ // loc is for error messages.
+ const LineInfo*loc,
+ // src is the index list, and count is
+ // the number of items in the list to use.
+ const list<index_component_t>&src, unsigned count,
+ // True if the expression MUST be constant.
+ bool need_const,
+ // These are the outputs.
+ list<NetExpr*>&indices, list<long>&indices_const)
+{
+ ivl_assert(*loc, count <= src.size());
+
+ bool flag = true;
+ for (list<index_component_t>::const_iterator cur = src.begin()
+ ; count > 0 ; ++cur, --count) {
+ ivl_assert(*loc, cur->sel != index_component_t::SEL_NONE);
+
+ if (cur->sel != index_component_t::SEL_BIT) {
+ cerr << loc->get_fileline() << ": error: "
+ << "Array cannot be indexed by a range." << endl;
+ des->errors += 1;
+ }
+ ivl_assert(*loc, cur->msb);
+
+ 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;
+
+ // 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;
}
+
+ indices.push_back(word_index);
}
- return base;
+ return flag;
+}
+
+static void make_strides(const vector<NetNet::range_t>&dims,
+ vector<long>&stride)
+{
+ stride[dims.size()-1] = 1;
+ for (size_t idx = stride.size()-1 ; idx > 0 ; --idx) {
+ long tmp = dims[idx].width();
+ if (idx < stride.size())
+ tmp *= stride[idx];
+ stride[idx-1] = tmp;
+ }
+}
+
+/*
+ * Take in a vector of constant indices and convert them to a single
+ * number that is the canonical address (zero based, 1-d) of the
+ * word. If any of the indices are out of bounds, return nil instead
+ * of an expression.
+ */
+NetExpr* normalize_variable_unpacked(const NetNet*net, list<long>&indices)
+{
+ const vector<NetNet::range_t>&dims = net->unpacked_dims();
+
+ // Make strides for each index. The stride is the distance (in
+ // words) to the next element in the canonical array.
+ vector<long> stride (dims.size());
+ make_strides(dims, stride);
+
+ int64_t canonical_addr = 0;
+
+ int idx = 0;
+ for (list<long>::const_iterator cur = indices.begin()
+ ; cur != indices.end() ; ++cur, ++idx) {
+ long tmp = *cur;
+
+ if (dims[idx].lsb <= dims[idx].msb)
+ tmp -= dims[idx].lsb;
+ else
+ tmp -= dims[idx].msb;
+
+ // Notice of this index is out of range.
+ if (tmp < 0 || tmp >= dims[idx].width()) {
+ return 0;
+ }
+
+ canonical_addr += tmp * stride[idx];
+ }
+
+ NetEConst*canonical_expr = new NetEConst(verinum(canonical_addr));
+ return canonical_expr;
+}
+
+NetExpr* normalize_variable_unpacked(const NetNet*net, list<NetExpr*>&indices)
+{
+ const vector<NetNet::range_t>&dims = net->unpacked_dims();
+
+ // Make strides for each index. The stride is the distance (in
+ // words) to the next element in the canonical array.
+ vector<long> stride (dims.size());
+ make_strides(dims, stride);
+
+ NetExpr*canonical_expr = 0;
+
+ int idx = 0;
+ for (list<NetExpr*>::const_iterator cur = indices.begin()
+ ; cur != indices.end() ; ++cur, ++idx) {
+ NetExpr*tmp = *cur;
+ // If the expression elaboration generated errors, then
+ // give up. Presumably, the error during expression
+ // elaboration already generated the error message.
+ if (tmp == 0)
+ return 0;
+
+ int64_t use_base;
+ if (dims[idx].lsb <= dims[idx].msb)
+ use_base = dims[idx].lsb;
+ else
+ use_base = dims[idx].msb;
+
+ int64_t use_stride = stride[idx];
+
+ // Account for that we are doing arithmatic and should
+ // have a proper width to make sure there ar no
+ // losses. So calculate a min_wid width.
+ unsigned tmp_wid;
+ unsigned min_wid = tmp->expr_width();
+ if (use_stride != 1 && ((tmp_wid = num_bits(use_stride)) >= min_wid))
+ min_wid = tmp_wid + 1;
+ if (use_base != 0 && ((tmp_wid = num_bits(use_base)) >= min_wid))
+ min_wid = tmp_wid + 1;
+ if ((tmp_wid = num_bits(dims[idx].width()+1)) >= min_wid)
+ min_wid = tmp_wid + 1;
+
+ tmp = pad_to_width(tmp, min_wid, *net);
+
+ // Now generate the math to calculate the canonical address.
+ NetExpr*tmp_scaled = 0;
+ if (NetEConst*tmp_const = dynamic_cast<NetEConst*> (tmp)) {
+ // Special case: the index is constant, so this
+ // iteration can be replaced with a constant
+ // expression.
+ int64_t val = tmp_const->value().as_long();
+ val -= use_base;
+ val *= use_stride;
+ tmp_scaled = new NetEConst(verinum(val));
+
+ } else {
+ tmp_scaled = tmp;
+ if (use_base != 0)
+ tmp_scaled = make_add_expr(tmp_scaled, -use_base);
+ if (use_stride != 1)
+ tmp_scaled = make_mult_expr(tmp_scaled, use_stride);
+ }
+
+ if (canonical_expr == 0) {
+ canonical_expr = tmp_scaled;
+ } else {
+ canonical_expr = new NetEBAdd('+', canonical_expr, tmp_scaled,
+ canonical_expr->expr_width()+1, false);
+ }
+ }
+
+ return canonical_expr;
}
NetEConst* make_const_x(unsigned long wid)
View
33 netmisc.h
@@ -142,8 +142,37 @@ extern NetExpr *normalize_variable_part_base(const list<long>&indices, NetExpr*b
extern NetExpr*normalize_variable_slice_base(const list<long>&indices, NetExpr *base,
const NetNet*reg, unsigned long&lwid);
-extern NetExpr*normalize_variable_array_base(NetExpr *base, long offset,
- unsigned count);
+/*
+ * The as_indices() manipulator is a convenient way to emit a list of
+ * index values in the form [<>][<>]....
+ */
+template <class TYPE> struct __IndicesManip {
+ inline __IndicesManip(const std::list<TYPE>&v) : val(v) { }
+ const std::list<TYPE>&val;
+};
+template <class TYPE> inline __IndicesManip<TYPE> as_indices(const std::list<TYPE>&indices)
+{ return __IndicesManip<TYPE>(indices); }
+
+extern ostream& operator << (ostream&o, __IndicesManip<long>);
+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,
+ // loc is for error messages.
+ const LineInfo*loc,
+ // src is the index list, and count is
+ // the number of items in the list to use.
+ const list<index_component_t>&src, unsigned count,
+ // True if the expression MUST be constant.
+ bool need_const,
+ // These are the outputs.
+ 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);
/*
* This function takes as input a NetNet signal and adds a constant
View
22 parse.y
@@ -4947,16 +4947,7 @@ register_variable
{ perm_string ident_name = lex_strings.make($1);
pform_makewire(@1, ident_name, NetNet::REG,
NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0);
- if ($2 != 0) {
- pform_range_t index;
- if ($2->size() > 1) {
- yyerror(@2, "sorry: only 1 dimensional arrays "
- "are currently supported.");
- }
- index = $2->front();
- pform_set_reg_idx(ident_name, index.first, index.second);
- delete $2;
- }
+ pform_set_reg_idx(ident_name, $2);
$$ = $1;
}
| IDENTIFIER '=' expression
@@ -4988,16 +4979,7 @@ net_variable
{ perm_string name = lex_strings.make($1);
pform_makewire(@1, name, NetNet::IMPLICIT,
NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0);
- if ($2 != 0) {
- pform_range_t index;
- if ($2->size() > 1) {
- yyerror(@2, "sorry: only 1 dimensional arrays "
- "are currently supported.");
- }
- index = $2->front();
- pform_set_reg_idx(name, index.first, index.second);
- delete $2;
- }
+ pform_set_reg_idx(name, $2);
$$ = $1;
}
;
View
5 pform.cc
@@ -2273,7 +2273,7 @@ void pform_set_type_attrib(perm_string name, const string&key,
* This function attaches a memory index range to an existing
* register. (The named wire must be a register.
*/
-void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r)
+void pform_set_reg_idx(perm_string name, list<pform_range_t>*indices)
{
PWire*cur = lexical_scope->wires_find(name);
if (cur == 0) {
@@ -2281,7 +2281,8 @@ void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r)
return;
}
- cur->set_memory_idx(l, r);
+ if (indices && !indices->empty())
+ cur->set_unpacked_idx(*indices);
}
LexicalScope::range_t* pform_parameter_value_range(bool exclude_flag,
View
3  pform.h
@@ -294,7 +294,8 @@ extern void pform_set_net_range(list<perm_string>*names,
bool signed_flag,
ivl_variable_type_t,
std::list<named_pexpr_t>*attr);
-extern void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r);
+extern void pform_set_reg_idx(perm_string name,
+ std::list<pform_range_t>*indices);
extern void pform_set_reg_integer(list<perm_string>*names, list<named_pexpr_t>*attr);
extern void pform_set_reg_time(list<perm_string>*names, list<named_pexpr_t>*attr);
View
9 pform_dump.cc
@@ -376,11 +376,12 @@ void PWire::dump(ostream&out, unsigned ind) const
out << " " << name_;
- // If the wire has indices, dump them.
- if (lidx_ || ridx_) {
+ // If the wire has unpacked indices, dump them.
+ for (list<pform_range_t>::const_iterator cur = unpacked_.begin()
+ ; cur != unpacked_.end() ; ++cur) {
out << "[";
- if (lidx_) out << *lidx_;
- if (ridx_) out << ":" << *ridx_;
+ if (cur->first) out << *cur->first;
+ if (cur->second) out << ":" << *cur->second;
out << "]";
}
View
23 t-dll.cc
@@ -2403,7 +2403,8 @@ void dll_target::signal(const NetNet*net)
(net->peek_lref() > 0) ? 1 : 0;
obj->discipline = net->get_discipline();
- obj->array_dimensions_ = net->array_dimensions();
+ obj->array_dimensions_ = net->unpacked_dimensions();
+ assert(obj->array_dimensions_ == net->unpacked_dimensions());
switch (net->port_type()) {
@@ -2493,9 +2494,23 @@ void dll_target::signal(const NetNet*net)
t_cookie of the Nexus object so that I find it again when I
next encounter the nexus. */
- obj->array_base = net->array_first();
- obj->array_words = net->array_count();
- obj->array_addr_swapped = net->array_addr_swapped() ? 1 : 0;
+ if (obj->array_dimensions_ == 1) {
+ const vector<NetNet::range_t>& dims = net->unpacked_dims();
+ if (dims[0].msb < dims[0].lsb) {
+ obj->array_base = dims[0].msb;
+ obj->array_addr_swapped = false;
+ } else {
+ obj->array_base = dims[0].lsb;
+ obj->array_addr_swapped = true;
+ }
+ obj->array_words = net->unpacked_count();
+ } else {
+ // The back-end API doesn't yet support multi-dimension
+ // unpacked arrays, so just report the canonical dimensions.
+ obj->array_base = 0;
+ obj->array_words = net->unpacked_count();
+ obj->array_addr_swapped = 0;
+ }
ivl_assert(*net, obj->array_words == net->pin_count());
if (debug_optimizer && obj->array_words > 1000) cerr << "debug: "
View
4 t-dll.h
@@ -1,7 +1,7 @@
#ifndef __t_dll_H
#define __t_dll_H
/*
- * Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com)
+ * Copyright (c) 2000-2012 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -685,7 +685,7 @@ struct ivl_signal_s {
unsigned forced_net_ : 1;
/* For now, support only 0 or 1 array dimensions. */
- unsigned array_dimensions_ : 1;
+ unsigned array_dimensions_ : 8;
unsigned array_addr_swapped : 1;
/* These encode the declared packed dimensions for the
Please sign in to comment.
Something went wrong with that request. Please try again.