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),
|
: 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
7
PWire.h
7
PWire.h
|
|
@ -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_;
|
||||||
|
|
|
||||||
|
|
@ -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_;
|
||||||
|
|
|
||||||
103
elab_expr.cc
103
elab_expr.cc
|
|
@ -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_
|
|
||||||
<< " cannot be indexed by a range." << endl;
|
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ivl_assert(*this, index_front.msb);
|
|
||||||
ivl_assert(*this, !index_front.lsb);
|
// 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetExpr*word_index = 0;
|
} else {
|
||||||
if (index_front.sel != index_component_t::SEL_NONE)
|
ivl_assert(*this, unpacked_indices.size() == net->unpacked_dimensions());
|
||||||
word_index = elab_and_eval(des, scope, index_front.msb, -1,
|
canon_index = normalize_variable_unpacked(net, unpacked_indices);
|
||||||
need_const);
|
|
||||||
|
|
||||||
if (word_index == 0 && !(SYS_TASK_ARG & flags))
|
|
||||||
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.
|
if (canon_index == 0) {
|
||||||
unsigned use_addr = net->array_index_to_address(addr);
|
NetEConst*xxx = make_const_x(net->vector_width());
|
||||||
if (addr < 0 || use_addr != (unsigned long)addr) {
|
xxx->set_line(*this);
|
||||||
verinum val ( (uint64_t)use_addr, 8*sizeof(use_addr));
|
return xxx;
|
||||||
NetEConst*tmp = new NetEConst(val);
|
|
||||||
tmp->set_line(*this);
|
|
||||||
delete word_index;
|
|
||||||
word_index = tmp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (word_index) {
|
NetESignal*res = new NetESignal(net, canon_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);
|
|
||||||
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);
|
||||||
|
|
||||||
|
|
|
||||||
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
|
// 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 << "+:";
|
||||||
|
|
|
||||||
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
|
// 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
43
elab_sig.cc
43
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,
|
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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
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),
|
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;
|
||||||
|
|
|
||||||
21
netlist.h
21
netlist.h
|
|
@ -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.
|
||||||
|
|
|
||||||
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
|
* 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)
|
||||||
|
|
|
||||||
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,
|
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
22
parse.y
|
|
@ -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;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
|
||||||
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
|
* 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,
|
||||||
|
|
|
||||||
3
pform.h
3
pform.h
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 << "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
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;
|
(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: "
|
||||||
|
|
|
||||||
4
t-dll.h
4
t-dll.h
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue