Get unpacked arrays working.
This commit is contained in:
parent
f7ba954ef7
commit
6e8aef8262
9
PWire.cc
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
7
PWire.h
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_;
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
115
elab_expr.cc
115
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;
|
||||
}
|
||||
|
||||
} 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);
|
||||
|
||||
// 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);
|
||||
|
||||
|
|
|
|||
79
elab_lval.cc
79
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);
|
||||
// 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
|
||||
// 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);
|
||||
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;
|
||||
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. */
|
||||
|
||||
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 << "+:";
|
||||
|
|
|
|||
81
elab_net.cc
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) {
|
||||
} else if (sig->unpacked_dimensions() > 0) {
|
||||
|
||||
if (name_tail.index.empty()) {
|
||||
cerr << get_fileline() << ": error: array " << sig->name()
|
||||
<< " must be used with an index." << 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;
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
45
elab_sig.cc
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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
85
netlist.cc
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
|
||||
unsigned NetNet::unpacked_count() 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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
|||
21
netlist.h
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.
|
||||
|
|
|
|||
231
netmisc.cc
231
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine generates the normalization expression needed for a variable
|
||||
* array word select.
|
||||
*/
|
||||
NetExpr *normalize_variable_array_base(NetExpr *base, long offset,
|
||||
unsigned count)
|
||||
ostream& operator << (ostream&o, __IndicesManip<long> val)
|
||||
{
|
||||
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;
|
||||
for (list<long>::const_iterator cur = val.val.begin()
|
||||
; cur != val.val.end() ; ++cur) {
|
||||
o << "[" << *cur << "]";
|
||||
}
|
||||
/* Normalize the expression. */
|
||||
base = make_add_expr(base, -offset);
|
||||
return o;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
|
|
|
|||
33
netmisc.h
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
|
||||
|
|
|
|||
22
parse.y
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;
|
||||
}
|
||||
;
|
||||
|
|
|
|||
5
pform.cc
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,
|
||||
|
|
|
|||
3
pform.h
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 << "]";
|
||||
}
|
||||
|
||||
|
|
|
|||
23
t-dll.cc
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: "
|
||||
|
|
|
|||
4
t-dll.h
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
|
||||
|
|
|
|||
Loading…
Reference in New Issue