Get unpacked arrays working.

This commit is contained in:
Stephen Williams 2012-05-25 15:58:29 -07:00
parent f7ba954ef7
commit 6e8aef8262
18 changed files with 468 additions and 317 deletions

View File

@ -29,7 +29,7 @@ PWire::PWire(perm_string n,
: name_(n), type_(t), port_type_(pt), data_type_(dt), : name_(n), type_(t), port_type_(pt), data_type_(dt),
signed_(false), isint_(false), signed_(false), isint_(false),
port_set_(false), net_set_(false), is_scalar_(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) discipline_(0)
{ {
if (t == NetNet::INTEGER) { 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_ cerr << get_fileline() << ": error: Array ``" << name_
<< "'' has already been declared." << endl; << "'' has already been declared." << endl;
error_cnt_ += 1; error_cnt_ += 1;
} else { } else {
lidx_ = ldx; unpacked_ = ranges;
ridx_ = rdx;
} }
} }

View File

@ -78,7 +78,7 @@ class PWire : public LineInfo {
void set_range_scalar(PWSRType type); void set_range_scalar(PWSRType type);
void set_range(const std::list<pform_range_t>&ranges, 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_enumeration(enum_type_t*enum_type);
void set_struct_type(struct_type_t*type); void set_struct_type(struct_type_t*type);
@ -115,9 +115,8 @@ class PWire : public LineInfo {
unsigned error_cnt_; unsigned error_cnt_;
// If this wire is actually a memory, these indices will give // If this wire is actually a memory, these indices will give
// me the size and address range of the memory. // me the size and address ranges of the memory.
PExpr*lidx_; std::list<pform_range_t>unpacked_;
PExpr*ridx_;
enum_type_t*enum_type_; enum_type_t*enum_type_;
struct_type_t*struct_type_; struct_type_t*struct_type_;

View File

@ -196,11 +196,20 @@ ostream&operator<<(ostream&out, const list<NetNet::range_t>&rlist)
return out; 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. */ /* Dump a net. This can be a wire or register. */
void NetNet::dump_net(ostream&o, unsigned ind) const void NetNet::dump_net(ostream&o, unsigned ind) const
{ {
o << setw(ind) << "" << type() << ": " << name() o << setw(ind) << "" << type() << ": " << name()
<< "[" << s0_ << ":" << e0_ << " count=" << pin_count() << "]"; << unpacked_dims_ << " unpacked dims=" << unpacked_dimensions() << " count=" << pin_count();
if (local_flag_) if (local_flag_)
o << " (local)"; o << " (local)";
o << " " << data_type_; o << " " << data_type_;

View File

@ -1873,7 +1873,7 @@ bool PEIdent::calculate_packed_indices_(Design*des, NetScope*scope, NetNet*net,
{ {
list<index_component_t> index; list<index_component_t> index;
index = path_.back().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(); index.pop_front();
return evaluate_index_prefix(des, scope, prefix_indices, index); 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()) { if (!name_tail.index.empty()) {
const index_component_t&index_tail = name_tail.index.back(); const index_component_t&index_tail = name_tail.index.back();
// Skip full array word net selects. // 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; 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(); 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() cerr << get_fileline() << ": error: Array " << path()
<< " Needs an array index here." << endl; << " Needs an array index here." << endl;
des->errors += 1; des->errors += 1;
return 0; return 0;
} }
index_component_t index_front; // Make sure there are enough indices to address an array element.
if (! name_tail.index.empty()) { if (name_tail.index.size() < net->unpacked_dimensions()) {
index_front = name_tail.index.front(); cerr << get_fileline() << ": error: Array " << path()
ivl_assert(*this, index_front.sel != index_component_t::SEL_NONE); << " needs " << net->unpacked_dimensions() << " indices,"
if (index_front.sel != index_component_t::SEL_BIT) { << " but got only " << name_tail.index.size() << "." << endl;
cerr << get_fileline() << ": error: Array " << path_ des->errors += 1;
<< " 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))
return 0; 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;
}
} 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()) {
word_index = normalize_variable_array_base(
word_index, base, net->array_count());
eval_expr(word_index);
}
} }
NetESignal*res = new NetESignal(net, word_index); // 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 {
ivl_assert(*this, unpacked_indices.size() == net->unpacked_dimensions());
canon_index = normalize_variable_unpacked(net, unpacked_indices);
}
if (canon_index == 0) {
NetEConst*xxx = make_const_x(net->vector_width());
xxx->set_line(*this);
return xxx;
}
NetESignal*res = new NetESignal(net, canon_index);
res->set_line(*this); res->set_line(*this);
// Detect that the word has a bit/part select as well. // Detect that the word has a bit/part select as well.
index_component_t::ctype_t word_sel = index_component_t::SEL_NONE; 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; word_sel = name_tail.index.back().sel;
if (net->get_scalar() && 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"; if (res->expr_type() == IVL_VT_REAL) cerr << "real";
else cerr << "scalar"; else cerr << "scalar";
cerr << " array word: " << net->name() cerr << " array word: " << net->name()
<<"[" << *word_index << "]" << endl; << as_indices(unpacked_indices) << endl;
des->errors += 1; des->errors += 1;
delete res; delete res;
return 0; return 0;
@ -3599,7 +3590,7 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope,
unsigned expr_wid, unsigned expr_wid,
unsigned flags) const unsigned flags) const
{ {
if (net->array_dimensions() > 0) if (net->unpacked_dimensions() > 0)
return elaborate_expr_net_word_(des, scope, net, found_in, return elaborate_expr_net_word_(des, scope, net, found_in,
expr_wid, flags); expr_wid, flags);

View File

@ -202,7 +202,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
// slice. This is, in fact, an error in l-values. Detect the // slice. This is, in fact, an error in l-values. Detect the
// situation by noting if the index count is less than the // situation by noting if the index count is less than the
// array dimensions (unpacked). // 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 " cerr << get_fileline() << ": error: Cannot assign to array "
<< path_ << ". Did you forget a word index?" << endl; << path_ << ". Did you forget a word index?" << endl;
des->errors += 1; des->errors += 1;
@ -228,7 +228,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
return lv; return lv;
} }
if (reg->array_dimensions() > 0) if (reg->unpacked_dimensions() > 0)
return elaborate_lval_net_word_(des, scope, reg); return elaborate_lval_net_word_(des, scope, reg);
// This must be after the array word elaboration above! // 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(); const name_component_t&name_tail = path_.back();
ivl_assert(*this, !name_tail.index.empty()); 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(); const index_component_t&index_head = name_tail.index.front();
if (index_head.sel == index_component_t::SEL_PART) { if (index_head.sel == index_component_t::SEL_PART) {
cerr << get_fileline() << ": error: cannot perform a part " cerr << get_fileline() << ": error: cannot perform a part "
@ -286,47 +295,47 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
return 0; 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); // 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);
// If there is a non-zero base to the memory, then build an NetExpr*canon_index = 0;
// expression to calculate the canonical address. if (flag) {
if (long base = reg->array_first()) { ivl_assert(*this, unpacked_indices_const.size() == reg->unpacked_dimensions());
canon_index = normalize_variable_unpacked(reg, unpacked_indices_const);
word = normalize_variable_array_base(word, base, if (canon_index == 0) {
reg->array_count()); cerr << get_fileline() << ": warning: "
eval_expr(word); << "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); NetAssign_*lv = new NetAssign_(reg);
lv->set_word(word); lv->set_word(canon_index);
if (debug_elaborate) if (debug_elaborate)
cerr << get_fileline() << ": debug: Set array word=" << *word << endl; cerr << get_fileline() << ": debug: Set array word=" << *canon_index << 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;
}
}
/* An array word may also have part selects applied to them. */ /* An array word may also have part selects applied to them. */
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE; 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; use_sel = name_tail.index.back().sel;
if (reg->get_scalar() && 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"; if (reg->data_type() == IVL_VT_REAL) cerr << "real";
else cerr << "scalar"; else cerr << "scalar";
cerr << " array word: " << reg->name() cerr << " array word: " << reg->name()
<< "[" << *word << "]" << endl; << "[" << *canon_index << "]" << endl;
des->errors += 1; des->errors += 1;
return 0; return 0;
} }
@ -563,7 +572,7 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
if (warn_ob_select) { if (warn_ob_select) {
if (rel_base < 0) { if (rel_base < 0) {
cerr << get_fileline() << ": warning: " << reg->name(); cerr << get_fileline() << ": warning: " << reg->name();
if (reg->array_dimensions() > 0) cerr << "[]"; if (reg->unpacked_dimensions() > 0) cerr << "[]";
cerr << "[" << lsv; cerr << "[" << lsv;
if (use_sel == index_component_t::SEL_IDX_UP) { if (use_sel == index_component_t::SEL_IDX_UP) {
cerr << "+:"; cerr << "+:";
@ -574,7 +583,7 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
} }
if (rel_base + wid > reg->vector_width()) { if (rel_base + wid > reg->vector_width()) {
cerr << get_fileline() << ": warning: " << reg->name(); cerr << get_fileline() << ": warning: " << reg->name();
if (reg->array_dimensions() > 0) cerr << "[]"; if (reg->unpacked_dimensions() > 0) cerr << "[]";
cerr << "[" << lsv; cerr << "[" << lsv;
if (use_sel == index_component_t::SEL_IDX_UP) { if (use_sel == index_component_t::SEL_IDX_UP) {
cerr << "+:"; cerr << "+:";
@ -587,7 +596,7 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
} else { } else {
if (warn_ob_select) { if (warn_ob_select) {
cerr << get_fileline() << ": warning: " << reg->name(); cerr << get_fileline() << ": warning: " << reg->name();
if (reg->array_dimensions() > 0) cerr << "[]"; if (reg->unpacked_dimensions() > 0) cerr << "[]";
cerr << "['bx"; cerr << "['bx";
if (use_sel == index_component_t::SEL_IDX_UP) { if (use_sel == index_component_t::SEL_IDX_UP) {
cerr << "+:"; cerr << "+:";

View File

@ -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 // Only treat as part/bit selects any index that is beyond the
// word selects for an array. This is not an array, then // word selects for an array. This is not an array, then
// dimensions==0 and any index is treated as a select. // 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; midx = sig->vector_width()-1;
lidx = 0; lidx = 0;
return true; return true;
@ -247,7 +247,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
if (warn_ob_select) { if (warn_ob_select) {
cerr << get_fileline() << ": warning: " cerr << get_fileline() << ": warning: "
<< sig->name(); << sig->name();
if (sig->array_dimensions() > 0) cerr << "[]"; if (sig->unpacked_dimensions() > 0) cerr << "[]";
cerr << "['bx"; cerr << "['bx";
if (index_tail.sel == if (index_tail.sel ==
index_component_t::SEL_IDX_UP) { 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. */ /* Warn about an indexed part select that is out of range. */
if (warn_ob_select && (lidx < 0)) { if (warn_ob_select && (lidx < 0)) {
cerr << get_fileline() << ": warning: " << sig->name(); cerr << get_fileline() << ": warning: " << sig->name();
if (sig->array_dimensions() > 0) cerr << "[]"; if (sig->unpacked_dimensions() > 0) cerr << "[]";
cerr << "[" << midx_val; cerr << "[" << midx_val;
if (index_tail.sel == index_component_t::SEL_IDX_UP) { if (index_tail.sel == index_component_t::SEL_IDX_UP) {
cerr << "+:"; 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())) { if (warn_ob_select && (midx >= (long)sig->vector_width())) {
cerr << get_fileline() << ": warning: " << sig->name(); cerr << get_fileline() << ": warning: " << sig->name();
if (sig->array_dimensions() > 0) { if (sig->unpacked_dimensions() > 0) {
cerr << "[]"; cerr << "[]";
} }
cerr << "[" << midx_val; 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) { if (midx_tmp >= (long)sig->vector_width() || lidx_tmp < 0) {
cerr << get_fileline() << ": warning: Part select " cerr << get_fileline() << ": warning: Part select "
<< sig->name(); << sig->name();
if (sig->array_dimensions() > 0) { if (sig->unpacked_dimensions() > 0) {
cerr << "[]"; cerr << "[]";
} }
cerr << "[" << msb << ":" << lsb cerr << "[" << msb << ":" << lsb
<< "] is out of range." << endl; << "] 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. */ /* This is completely out side the signal so just skip it. */
if (lidx_tmp >= (long)sig->vector_width() || midx_tmp < 0) { 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: case index_component_t::SEL_BIT:
if (name_tail.index.size() > sig->array_dimensions()) { if (name_tail.index.size() > sig->unpacked_dimensions()) {
long msb; long msb;
bool bit_defined_flag; bool bit_defined_flag;
/* bool flag = */ calculate_bits_(des, scope, msb, bit_defined_flag); /* bool flag = */ calculate_bits_(des, scope, msb, bit_defined_flag);
@ -460,11 +455,9 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
unsigned midx = sig->vector_width()-1, lidx = 0; unsigned midx = sig->vector_width()-1, lidx = 0;
// The default word select is the first. // The default word select is the first.
long widx = 0; 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(); const name_component_t&name_tail = path_.back();
list<long> unpacked_indices_const;
netstruct_t*struct_type = 0; netstruct_t*struct_type = 0;
if ((struct_type = sig->struct_type()) && !method_name.nil()) { 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; lidx = member_off;
midx = lidx + member->width() - 1; midx = lidx + member->width() - 1;
} else if (sig->array_dimensions() > 0) { } else if (sig->unpacked_dimensions() > 0) {
if (name_tail.index.empty()) { // Make sure there are enough indices to address an array element.
cerr << get_fileline() << ": error: array " << sig->name() if (name_tail.index.size() < sig->unpacked_dimensions()) {
<< " must be used with an index." << endl; cerr << get_fileline() << ": error: Array " << path()
<< " needs " << sig->unpacked_dimensions() << " indices,"
<< " but got only " << name_tail.index.size() << "." << endl;
des->errors += 1; des->errors += 1;
return 0; return 0;
} }
const index_component_t&index_head = name_tail.index.front(); // Evaluate all the index expressions into an
if (index_head.sel == index_component_t::SEL_PART) { // "unpacked_indices" array.
cerr << get_fileline() << ": error: cannot perform a part " list<NetExpr*>unpacked_indices;
<< "select on array " << sig->name() << "." << endl; bool flag = indices_to_expressions(des, scope, this,
des->errors += 1; name_tail.index, sig->unpacked_dimensions(),
return 0; true,
} unpacked_indices,
ivl_assert(*this, index_head.sel == index_component_t::SEL_BIT); unpacked_indices_const);
// Note that !flag includes that there were any other
NetExpr*tmp_ex = elab_and_eval(des, scope, index_head.msb, -1, true); // elaboration errors generating the unpacked_indices list.
NetEConst*tmp = dynamic_cast<NetEConst*>(tmp_ex); if (!flag) {
if (!tmp) {
cerr << get_fileline() << ": error: array " << sig->name() cerr << get_fileline() << ": error: array " << sig->name()
<< " index must be a constant in this context." << endl; << " index must be a constant in this context." << endl;
des->errors += 1; des->errors += 1;
return 0; return 0;
} }
widx_val = tmp->value().as_long(); NetExpr*canon_index = 0;
if (sig->array_index_is_valid(widx_val)) ivl_assert(*this, unpacked_indices_const.size() == sig->unpacked_dimensions());
widx = sig->array_index_to_address(widx_val); canon_index = normalize_variable_unpacked(sig, unpacked_indices_const);
else if (canon_index == 0) {
// Normalize detected an out-of-bounds
// index. Indicate that by setting the generated
// widx to -1.
widx = -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) if (debug_elaborate)
cerr << get_fileline() << ": debug: Use [" << widx << "]" cerr << get_fileline() << ": debug: Use [" << widx << "]"
<< " to index l-value array." << endl; << " to index l-value array." << endl;
/* The array has a part/bit select at the end. */ /* 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()) { if (sig->get_scalar()) {
cerr << get_fileline() << ": error: " cerr << get_fileline() << ": error: "
<< "can not select part of "; << "can not select part of ";
if (sig->data_type() == IVL_VT_REAL) cerr << "real"; if (sig->data_type() == IVL_VT_REAL) cerr << "real";
else cerr << "scalar"; else cerr << "scalar";
cerr << " array word: " << sig->name() cerr << " array word: " << sig->name()
<< "[" << widx_val << "]" << endl; << as_indices(unpacked_indices_const) << endl;
des->errors += 1; des->errors += 1;
return 0; return 0;
} }
@ -550,6 +554,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
midx = midx_tmp; midx = midx_tmp;
lidx = lidx_tmp; lidx = lidx_tmp;
} }
} else if (!name_tail.index.empty()) { } else if (!name_tail.index.empty()) {
if (sig->get_scalar()) { if (sig->get_scalar()) {
cerr << get_fileline() << ": error: " 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()) { if (widx < 0 || widx >= (long) sig->pin_count()) {
cerr << get_fileline() << ": warning: ignoring out of " cerr << get_fileline() << ": warning: ignoring out of "
"bounds l-value array access " "bounds l-value array access "
<< sig->name() << "[" << widx_val << "]." << endl; << sig->name() << as_indices(unpacked_indices_const) << "." << endl;
return 0; return 0;
} }

View File

@ -1057,19 +1057,17 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
attrib_list_t*attrib_list = evaluate_attributes(attributes, nattrib, attrib_list_t*attrib_list = evaluate_attributes(attributes, nattrib,
des, scope); des, scope);
long array_s0 = 0;
long array_e0 = 0;
unsigned array_dimensions = 0;
/* If the ident has idx expressions, then this is a list<NetNet::range_t>unpacked_dimensions;
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_);
NetExpr*lexp = elab_and_eval(des, scope, lidx_, -1, true); for (list<pform_range_t>::const_iterator cur = unpacked_.begin()
NetExpr*rexp = elab_and_eval(des, scope, ridx_, -1, true); ; 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)) { if ((lexp == 0) || (rexp == 0)) {
cerr << get_fileline() << ": internal error: There is " cerr << get_fileline() << ": internal error: There is "
@ -1086,19 +1084,21 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
delete rexp; delete rexp;
delete lexp; delete lexp;
if (!const_flag) { long index_l, index_r;
if (! const_flag) {
cerr << get_fileline() << ": error: The indices " cerr << get_fileline() << ": error: The indices "
<< "are not constant for array ``" << "are not constant for array ``"
<< name_ << "''." << endl; << name_ << "''." << endl;
des->errors += 1; des->errors += 1;
/* Attempt to recover from error, */ /* Attempt to recover from error, */
array_s0 = 0; index_l = 0;
array_e0 = 0; index_r = 0;
} else { } else {
array_s0 = lval.as_long(); index_l = lval.as_long();
array_e0 = rval.as_long(); index_r = rval.as_long();
} }
array_dimensions = 1;
unpacked_dimensions.push_back(NetNet::range_t(index_l, index_r));
} }
if (data_type_ == IVL_VT_REAL && !packed_dimensions.empty()) { 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()) { if (!get_scalar()) {
cerr << " " << packed_dimensions; cerr << " " << packed_dimensions;
} }
cerr << " " << name_; cerr << " " << name_ << unpacked_dimensions;
if (array_dimensions > 0) {
cerr << " [" << array_s0 << ":" << array_e0 << "]" << endl;
}
cerr << " in scope " << scope_path(scope) << endl; cerr << " in scope " << scope_path(scope) << endl;
} }
sig = array_dimensions > 0 sig = new NetNet(scope, name_, wtype, packed_dimensions, unpacked_dimensions);
? new NetNet(scope, name_, wtype, packed_dimensions, array_s0, array_e0)
: new NetNet(scope, name_, wtype, packed_dimensions);
} }
// If this is an enumeration, then set the enumeration set for // If this is an enumeration, then set the enumeration set for

View File

@ -159,7 +159,7 @@ NexusSet* NetESignal::nex_input(bool rem_out)
delete tmp; delete tmp;
if (warn_sens_entire_arr) { if (warn_sens_entire_arr) {
cerr << get_fileline() << ": warning: @* is sensitive to all " cerr << get_fileline() << ": warning: @* is sensitive to all "
<< net_->array_count() << " words in array '" << net_->unpacked_count() << " words in array '"
<< name() << "'." << endl; << name() << "'." << endl;
} }
} }

View File

@ -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), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE),
signed_(false), isint_(false), is_scalar_(false), local_flag_(false), signed_(false), isint_(false), is_scalar_(false), local_flag_(false),
enumeration_(0), struct_type_(0), discipline_(0), 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(s);
assert(npins>0); 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), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false),
isint_(false), is_scalar_(false), local_flag_(false), isint_(false), is_scalar_(false), local_flag_(false),
enumeration_(0), struct_type_(0), discipline_(0), 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)
{ {
packed_dims_ = packed; packed_dims_ = packed;
@ -529,34 +528,41 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
s->add_signal(this); 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; unsigned long sum = 1;
if (s >= e) { for (list<NetNet::range_t>::const_iterator cur = unpacked.begin()
r = s - e; ; cur != unpacked.end() ; ++cur) {
} else { sum *= cur->width();
r = e - s;
} }
if (r >= UINT_MAX) {
if (sum >= UINT_MAX)
return 0; return 0;
}
return r + 1; return sum;
} }
NetNet::NetNet(NetScope*s, perm_string n, Type t, NetNet::NetNet(NetScope*s, perm_string n, Type t,
const list<NetNet::range_t>&packed, long array_s, long array_e) const list<NetNet::range_t>&packed,
: NetObj(s, n, calculate_count(array_s, array_e)), const list<NetNet::range_t>&unpacked)
: NetObj(s, n, calculate_count(unpacked)),
type_(t), port_type_(NOT_A_PORT), type_(t), port_type_(NOT_A_PORT),
data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false),
is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(0), is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(0),
discipline_(0), discipline_(0), unpacked_dims_(unpacked.size()),
dimensions_(1), s0_(array_s), e0_(array_e),
eref_count_(0), lref_count_(0) eref_count_(0), lref_count_(0)
{ {
packed_dims_ = packed; 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); ivl_assert(*this, s);
if (pin_count() == 0) { if (pin_count() == 0) {
cerr << "Array too big [" << array_s << ":" << array_e << "]" << endl; cerr << "Array too big " << unpacked << endl;
ivl_assert(*this, 0); 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), data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false),
is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(ty), is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(ty),
discipline_(0), discipline_(0),
dimensions_(0), s0_(0), e0_(0),
eref_count_(0), lref_count_(0) eref_count_(0), lref_count_(0)
{ {
packed_dims_.push_back(range_t(calculate_count(ty)-1, 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; return true;
} }
unsigned NetNet::unpacked_count() const
unsigned NetNet::array_dimensions() const
{ {
return dimensions_; unsigned c = 1;
} for (size_t idx = 0 ; idx < unpacked_dims_.size() ; idx += 1) {
c *= unpacked_dims_[idx].width();
}
long NetNet::array_first() const
{
if (s0_ <= e0_)
return s0_;
else
return e0_;
}
bool NetNet::array_addr_swapped() const
{
if (s0_ <= e0_)
return false;
else
return true;
}
unsigned NetNet::array_count() const
{
unsigned c = calculate_count(s0_, e0_);
ivl_assert(*this, c > 0);
return c; 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() void NetNet::incr_eref()
{ {
eref_count_ += 1; eref_count_ += 1;

View File

@ -591,7 +591,8 @@ class NetNet : public NetObj {
explicit NetNet(NetScope*s, perm_string n, Type t, explicit NetNet(NetScope*s, perm_string n, Type t,
const std::list<range_t>&packed); const std::list<range_t>&packed);
explicit NetNet(NetScope*s, perm_string n, Type t, 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. // This form builds a NetNet from its record definition.
explicit NetNet(NetScope*s, perm_string n, Type t, netstruct_t*type); explicit NetNet(NetScope*s, perm_string n, Type t, netstruct_t*type);
@ -635,6 +636,8 @@ class NetNet : public NetObj {
the verilog declaration. */ the verilog declaration. */
const std::list<range_t>& packed_dims() const { return packed_dims_; } 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, /* The vector_width returns the bit width of the packed array,
vector or scaler that is this NetNet object. The static vector or scaler that is this NetNet object. The static
method is also a convenient way to convert a range list to 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 /* This method returns 0 for scalars and vectors, and greater
for arrays. The value is the number of array for arrays. The value is the number of array
indices. (Currently only one array index is supported.) */ indices. (Currently only one array index is supported.) */
unsigned array_dimensions() const; inline unsigned unpacked_dimensions() const { return unpacked_dims_.size(); }
long array_first() const;
bool array_addr_swapped() const;
// This is the number of array elements. // This is the number of array elements.
unsigned array_count() const; unsigned unpacked_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;
bool local_flag() const { return local_flag_; } bool local_flag() const { return local_flag_; }
void local_flag(bool f) { local_flag_ = f; } void local_flag(bool f) { local_flag_ = f; }
@ -723,11 +718,11 @@ class NetNet : public NetObj {
ivl_discipline_t discipline_; ivl_discipline_t discipline_;
std::list<range_t> packed_dims_; std::list<range_t> packed_dims_;
const unsigned dimensions_; std::vector<range_t> unpacked_dims_;
long s0_, e0_;
unsigned eref_count_; unsigned eref_count_;
unsigned lref_count_; unsigned lref_count_;
// When the signal is an unresolved wire, we need more detail // When the signal is an unresolved wire, we need more detail
// which bits are assigned. This mask is true for each bit // which bits are assigned. This mask is true for each bit
// that is known to be driven. // that is known to be driven.

View File

@ -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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * 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; return base;
} }
/* ostream& operator << (ostream&o, __IndicesManip<long> val)
* This routine generates the normalization expression needed for a variable
* array word select.
*/
NetExpr *normalize_variable_array_base(NetExpr *base, long offset,
unsigned count)
{ {
assert(offset != 0); for (list<long>::const_iterator cur = val.val.begin()
/* Calculate the space needed for the offset. */ ; cur != val.val.end() ; ++cur) {
unsigned min_wid = num_bits(-offset); o << "[" << *cur << "]";
/* 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. */ return o;
base = make_add_expr(base, -offset); }
/* We should not need to do this, but .array/port does not ostream& operator << (ostream&o, __IndicesManip<NetExpr*> val)
* handle a small signed index correctly and it is a major {
* effort to fix it. For now we will just pad the expression for (list<NetExpr*>::const_iterator cur = val.val.begin()
* enough so that any negative value when converted to ; cur != val.val.end() ; ++cur) {
* unsigned is larger than the maximum array word. */ o << "[" << *(*cur) << "]";
if (base->has_sign()) { }
unsigned range_wid = num_bits(count-1) + 1; return o;
if (min_wid < range_wid) { }
base = pad_to_width(base, range_wid, *base);
/*
* 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.
*/
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 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 base; return canonical_expr;
} }
NetEConst* make_const_x(unsigned long wid) NetEConst* make_const_x(unsigned long wid)

View File

@ -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, extern NetExpr*normalize_variable_slice_base(const list<long>&indices, NetExpr *base,
const NetNet*reg, unsigned long&lwid); 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 * This function takes as input a NetNet signal and adds a constant

22
parse.y
View File

@ -4947,16 +4947,7 @@ register_variable
{ perm_string ident_name = lex_strings.make($1); { perm_string ident_name = lex_strings.make($1);
pform_makewire(@1, ident_name, NetNet::REG, pform_makewire(@1, ident_name, NetNet::REG,
NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0); NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0);
if ($2 != 0) { pform_set_reg_idx(ident_name, $2);
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;
}
$$ = $1; $$ = $1;
} }
| IDENTIFIER '=' expression | IDENTIFIER '=' expression
@ -4988,16 +4979,7 @@ net_variable
{ perm_string name = lex_strings.make($1); { perm_string name = lex_strings.make($1);
pform_makewire(@1, name, NetNet::IMPLICIT, pform_makewire(@1, name, NetNet::IMPLICIT,
NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0); NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0);
if ($2 != 0) { pform_set_reg_idx(name, $2);
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;
}
$$ = $1; $$ = $1;
} }
; ;

View File

@ -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 * This function attaches a memory index range to an existing
* register. (The named wire must be a register. * 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); PWire*cur = lexical_scope->wires_find(name);
if (cur == 0) { if (cur == 0) {
@ -2281,7 +2281,8 @@ void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r)
return; 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, LexicalScope::range_t* pform_parameter_value_range(bool exclude_flag,

View File

@ -294,7 +294,8 @@ extern void pform_set_net_range(list<perm_string>*names,
bool signed_flag, bool signed_flag,
ivl_variable_type_t, ivl_variable_type_t,
std::list<named_pexpr_t>*attr); 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_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); extern void pform_set_reg_time(list<perm_string>*names, list<named_pexpr_t>*attr);

View File

@ -376,11 +376,12 @@ void PWire::dump(ostream&out, unsigned ind) const
out << " " << name_; out << " " << name_;
// If the wire has indices, dump them. // If the wire has unpacked indices, dump them.
if (lidx_ || ridx_) { for (list<pform_range_t>::const_iterator cur = unpacked_.begin()
; cur != unpacked_.end() ; ++cur) {
out << "["; out << "[";
if (lidx_) out << *lidx_; if (cur->first) out << *cur->first;
if (ridx_) out << ":" << *ridx_; if (cur->second) out << ":" << *cur->second;
out << "]"; out << "]";
} }

View File

@ -2403,7 +2403,8 @@ void dll_target::signal(const NetNet*net)
(net->peek_lref() > 0) ? 1 : 0; (net->peek_lref() > 0) ? 1 : 0;
obj->discipline = net->get_discipline(); 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()) { 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 t_cookie of the Nexus object so that I find it again when I
next encounter the nexus. */ next encounter the nexus. */
obj->array_base = net->array_first(); if (obj->array_dimensions_ == 1) {
obj->array_words = net->array_count(); const vector<NetNet::range_t>& dims = net->unpacked_dims();
obj->array_addr_swapped = net->array_addr_swapped() ? 1 : 0; 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()); ivl_assert(*net, obj->array_words == net->pin_count());
if (debug_optimizer && obj->array_words > 1000) cerr << "debug: " if (debug_optimizer && obj->array_words > 1000) cerr << "debug: "

View File

@ -1,7 +1,7 @@
#ifndef __t_dll_H #ifndef __t_dll_H
#define __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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * 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; unsigned forced_net_ : 1;
/* For now, support only 0 or 1 array dimensions. */ /* For now, support only 0 or 1 array dimensions. */
unsigned array_dimensions_ : 1; unsigned array_dimensions_ : 8;
unsigned array_addr_swapped : 1; unsigned array_addr_swapped : 1;
/* These encode the declared packed dimensions for the /* These encode the declared packed dimensions for the