Consolidate unpacked array type elaboration
There are currently two implementations for elaborating unpacked array types. One that is used when elaborating a signal with an unpacked array type and one that is used everywhere else using the elaborate_type() infrastructure. The elaborate_type() implementation is less complete and for example does not support bounded queue types. Consolidate both into a single implementation to reduce duplicated code and get consistent behavior. This for example makes sure that the maximum queue size is respected when used as a function return type. Nested data structures of arrays, dynamic arrays or queues are not yet supported. In the current implementation when encountering such a type an assert will be triggered and the application crashes. In the new implementation an error message will be printed without crashing the application. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
parent
66a5cfe660
commit
724d7d4282
152
elab_sig.cc
152
elab_sig.cc
|
|
@ -965,28 +965,6 @@ ivl_type_t PWire::elaborate_type(Design*des, NetScope*scope,
|
|||
return vec;
|
||||
}
|
||||
|
||||
ivl_type_t PWire::elaborate_darray_type(Design*des, NetScope*scope,
|
||||
const char *darray_type,
|
||||
const std::vector<netrange_t>&packed_dimensions)
|
||||
const
|
||||
{
|
||||
ivl_type_t type = elaborate_type(des, scope, packed_dimensions);
|
||||
|
||||
if (dynamic_cast<const netvector_t*>(type) ||
|
||||
dynamic_cast<const netparray_t*>(type) ||
|
||||
dynamic_cast<const netreal_t*>(type) ||
|
||||
dynamic_cast<const netstring_t*>(type))
|
||||
return type;
|
||||
|
||||
cerr << get_fileline() << ": Sorry: "
|
||||
<< darray_type << " of type `" << *type
|
||||
<< "` is not yet supported." << endl;
|
||||
des->errors++;
|
||||
|
||||
// Return something to recover
|
||||
return new netvector_t(IVL_VT_LOGIC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Elaborate a source wire. The "wire" is the declaration of wires,
|
||||
* registers, ports and memories. The parser has already merged the
|
||||
|
|
@ -1136,86 +1114,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
attrib_list_t*attrib_list = evaluate_attributes(attributes, nattrib,
|
||||
des, scope);
|
||||
|
||||
|
||||
list<netrange_t>unpacked_dimensions;
|
||||
netdarray_t*netdarray = 0;
|
||||
|
||||
for (list<pform_range_t>::const_iterator cur = unpacked_.begin()
|
||||
; cur != unpacked_.end() ; ++cur) {
|
||||
PExpr*use_lidx = cur->first;
|
||||
PExpr*use_ridx = cur->second;
|
||||
|
||||
// Special case: If we encounter an undefined
|
||||
// dimensions, then turn this into a dynamic array and
|
||||
// put all the packed dimensions there.
|
||||
if (use_lidx==0 && use_ridx==0) {
|
||||
ivl_type_t base_type = elaborate_darray_type(des,
|
||||
array_type_scope,
|
||||
"Dynamic array",
|
||||
packed_dimensions);
|
||||
packed_dimensions.clear();
|
||||
ivl_assert(*this, netdarray==0);
|
||||
netdarray = new netdarray_t(base_type);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Special case: Detect the mark for a QUEUE
|
||||
// declaration, which is the dimensions [null:max_idx].
|
||||
if (dynamic_cast<PENull*>(use_lidx)) {
|
||||
ivl_type_t base_type = elaborate_darray_type(des,
|
||||
array_type_scope,
|
||||
"Queue",
|
||||
packed_dimensions);
|
||||
packed_dimensions.clear();
|
||||
ivl_assert(*this, netdarray==0);
|
||||
long max_idx;
|
||||
if (use_ridx) {
|
||||
NetExpr*tmp = elab_and_eval(des, array_type_scope, use_ridx,
|
||||
-1, true);
|
||||
NetEConst*cv = dynamic_cast<NetEConst*>(tmp);
|
||||
if (cv == 0) {
|
||||
cerr << get_fileline() << ": error: queue '" << name_
|
||||
<< "' bound must be a constant!" << endl;
|
||||
des->errors += 1;
|
||||
max_idx = -1;
|
||||
} else {
|
||||
verinum res = cv->value();
|
||||
if (res.is_defined()) {
|
||||
max_idx = res.as_long();
|
||||
if (max_idx < 0) {
|
||||
cerr << get_fileline() << ": error: queue '"
|
||||
<< name_ << "' bound must be positive ("
|
||||
<< max_idx << ")!" << endl;
|
||||
des->errors += 1;
|
||||
max_idx = -1;
|
||||
}
|
||||
} else {
|
||||
cerr << get_fileline() << ": error: queue '" << name_
|
||||
<< "' bound is undefined!" << endl;
|
||||
des->errors += 1;
|
||||
max_idx = -1;
|
||||
}
|
||||
}
|
||||
} else max_idx = -1;
|
||||
netdarray = new netqueue_t(base_type, max_idx);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Cannot handle dynamic arrays/queues of arrays yet.
|
||||
ivl_assert(*this, netdarray==0);
|
||||
|
||||
long index_l, index_r;
|
||||
evaluate_range(des, array_type_scope, this, *cur, index_l, index_r);
|
||||
|
||||
if (abs(index_r - index_l) > warn_dimension_size) {
|
||||
cerr << get_fileline() << ": warning: Array dimension "
|
||||
"is greater than " << warn_dimension_size
|
||||
<< "." << endl;
|
||||
}
|
||||
|
||||
unpacked_dimensions.push_back(netrange_t(index_l, index_r));
|
||||
}
|
||||
|
||||
if (data_type_ == IVL_VT_REAL && !packed_dimensions.empty()) {
|
||||
cerr << get_fileline() << ": error: real ";
|
||||
if (wtype == NetNet::REG) cerr << "variable";
|
||||
|
|
@ -1263,37 +1161,31 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
wtype = NetNet::WIRE;
|
||||
}
|
||||
|
||||
ivl_type_t type = elaborate_type(des, array_type_scope, packed_dimensions);
|
||||
// Create the type for the unpacked dimensions. If the
|
||||
// unpacked_dimensions are empty this will just return the base type.
|
||||
type = elaborate_array_type(des, array_type_scope, *this, type, unpacked_);
|
||||
|
||||
NetNet*sig = 0;
|
||||
|
||||
if (netdarray) {
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PWire::elaborate_sig: "
|
||||
<< "Create signal wtype=" << wtype
|
||||
<< " name=" << name_
|
||||
<< " netdarray=" << *netdarray
|
||||
<< " in scope " << scope_path(scope) << endl;
|
||||
}
|
||||
|
||||
ivl_assert(*this, packed_dimensions.empty());
|
||||
ivl_assert(*this, unpacked_dimensions.empty());
|
||||
sig = new NetNet(scope, name_, wtype, netdarray);
|
||||
|
||||
} else {
|
||||
ivl_type_t use_type = elaborate_type(des, array_type_scope,
|
||||
packed_dimensions);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Create signal "
|
||||
<< wtype << " " << *set_data_type_
|
||||
<< " " << name_ << unpacked_dimensions
|
||||
<< " in scope " << scope_path(scope) << endl;
|
||||
}
|
||||
|
||||
sig = new NetNet(scope, name_, wtype, unpacked_dimensions, use_type);
|
||||
list<netrange_t> unpacked_dimensions;
|
||||
// If this is an unpacked array extract the base type and unpacked
|
||||
// dimensions as these are separate properties of the NetNet.
|
||||
if (const netuarray_t *atype = dynamic_cast<const netuarray_t*>(type)) {
|
||||
unpacked_dimensions.insert(unpacked_dimensions.begin(),
|
||||
atype->static_dimensions().begin(),
|
||||
atype->static_dimensions().end());
|
||||
type = atype->element_type();
|
||||
}
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Create signal " << wtype;
|
||||
if (set_data_type_)
|
||||
cout << " " << *set_data_type_;
|
||||
cout << name_ << unpacked_dimensions << " in scope "
|
||||
<< scope_path(scope) << endl;
|
||||
}
|
||||
|
||||
NetNet*sig = new NetNet(scope, name_, wtype, unpacked_dimensions, type);
|
||||
|
||||
if (wtype == NetNet::WIRE) sig->devirtualize_pins();
|
||||
sig->set_line(*this);
|
||||
sig->port_type(port_type_);
|
||||
|
|
|
|||
168
elab_type.cc
168
elab_type.cc
|
|
@ -222,39 +222,145 @@ ivl_type_t struct_type_t::elaborate_type_raw(Design*des, NetScope*scope) const
|
|||
return res;
|
||||
}
|
||||
|
||||
static ivl_type_t elaborate_darray_check_type(Design *des, const LineInfo &li,
|
||||
ivl_type_t type,
|
||||
const char *darray_type)
|
||||
{
|
||||
if (dynamic_cast<const netvector_t*>(type) ||
|
||||
dynamic_cast<const netparray_t*>(type) ||
|
||||
dynamic_cast<const netreal_t*>(type) ||
|
||||
dynamic_cast<const netstring_t*>(type))
|
||||
return type;
|
||||
|
||||
cerr << li.get_fileline() << ": Sorry: "
|
||||
<< darray_type << " of type `" << *type
|
||||
<< "` is not yet supported." << endl;
|
||||
des->errors++;
|
||||
|
||||
// Return something to recover
|
||||
return new netvector_t(IVL_VT_LOGIC);
|
||||
}
|
||||
|
||||
static ivl_type_t elaborate_queue_type(Design *des, NetScope *scope,
|
||||
const LineInfo &li, ivl_type_t base_type,
|
||||
PExpr *ridx)
|
||||
{
|
||||
base_type = elaborate_darray_check_type(des, li, base_type, "Queue");
|
||||
|
||||
long max_idx = -1;
|
||||
if (ridx) {
|
||||
NetExpr*tmp = elab_and_eval(des, scope, ridx, -1, true);
|
||||
NetEConst*cv = dynamic_cast<NetEConst*>(tmp);
|
||||
if (cv == 0) {
|
||||
cerr << li.get_fileline() << ": error: "
|
||||
<< "queue bound must be constant."
|
||||
<< endl;
|
||||
des->errors++;
|
||||
} else {
|
||||
verinum res = cv->value();
|
||||
if (res.is_defined()) {
|
||||
max_idx = res.as_long();
|
||||
if (max_idx < 0) {
|
||||
cerr << li.get_fileline() << ": error: "
|
||||
<< "queue bound must be positive ("
|
||||
<< max_idx << ")." << endl;
|
||||
des->errors++;
|
||||
max_idx = -1;
|
||||
}
|
||||
} else {
|
||||
cerr << li.get_fileline() << ": error: "
|
||||
<< "queue bound must be defined."
|
||||
<< endl;
|
||||
des->errors++;
|
||||
}
|
||||
}
|
||||
delete cv;
|
||||
}
|
||||
|
||||
return new netqueue_t(base_type, max_idx);
|
||||
}
|
||||
|
||||
// If dims is not empty create a unpacked array type and clear dims, otherwise
|
||||
// return the base type. Also check that we actually support the base type.
|
||||
static ivl_type_t elaborate_static_array_type(Design *des, const LineInfo &li,
|
||||
ivl_type_t base_type,
|
||||
std::vector<netrange_t> &dims)
|
||||
{
|
||||
if (dims.empty())
|
||||
return base_type;
|
||||
|
||||
if (dynamic_cast<const netqueue_t*>(base_type)) {
|
||||
cerr << li.get_fileline() << ": sorry: "
|
||||
<< "array of queue type is not yet supported."
|
||||
<< endl;
|
||||
des->errors++;
|
||||
// Recover
|
||||
base_type = new netvector_t(IVL_VT_LOGIC);
|
||||
} else if (dynamic_cast<const netdarray_t*>(base_type)) {
|
||||
cerr << li.get_fileline() << ": sorry: "
|
||||
<< "array of dynamic array type is not yet supported."
|
||||
<< endl;
|
||||
des->errors++;
|
||||
// Recover
|
||||
base_type = new netvector_t(IVL_VT_LOGIC);
|
||||
}
|
||||
|
||||
ivl_type_t type = new netuarray_t(dims, base_type);
|
||||
dims.clear();
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
ivl_type_t elaborate_array_type(Design *des, NetScope *scope,
|
||||
const LineInfo &li, ivl_type_t base_type,
|
||||
const list<pform_range_t> &dims)
|
||||
{
|
||||
const long warn_dimension_size = 1 << 30;
|
||||
std::vector<netrange_t> dimensions;
|
||||
dimensions.reserve(dims.size());
|
||||
|
||||
ivl_type_t type = base_type;
|
||||
|
||||
for (list<pform_range_t>::const_iterator cur = dims.begin();
|
||||
cur != dims.end() ; ++cur) {
|
||||
PExpr *lidx = cur->first;
|
||||
PExpr *ridx = cur->second;
|
||||
|
||||
if (lidx == 0 && ridx == 0) {
|
||||
// Special case: If we encounter an undefined dimensions,
|
||||
// then turn this into a dynamic array and put all the
|
||||
// packed dimensions there.
|
||||
type = elaborate_static_array_type(des, li, type, dimensions);
|
||||
type = elaborate_darray_check_type(des, li, type, "Dynamic array");
|
||||
type = new netdarray_t(type);
|
||||
continue;
|
||||
} else if (dynamic_cast<PENull*>(lidx)) {
|
||||
// Special case: Detect the mark for a QUEUE declaration,
|
||||
// which is the dimensions [null:max_idx].
|
||||
type = elaborate_static_array_type(des, li, type, dimensions);
|
||||
type = elaborate_queue_type(des, scope, li, type, ridx);
|
||||
continue;
|
||||
}
|
||||
|
||||
long index_l, index_r;
|
||||
evaluate_range(des, scope, &li, *cur, index_l, index_r);
|
||||
|
||||
if (abs(index_r - index_l) > warn_dimension_size) {
|
||||
cerr << li.get_fileline() << ": warning: "
|
||||
<< "Array dimension is greater than "
|
||||
<< warn_dimension_size << "."
|
||||
<< endl;
|
||||
}
|
||||
|
||||
dimensions.push_back(netrange_t(index_l, index_r));
|
||||
}
|
||||
|
||||
return elaborate_static_array_type(des, li, type, dimensions);
|
||||
}
|
||||
|
||||
ivl_type_t uarray_type_t::elaborate_type_raw(Design*des, NetScope*scope) const
|
||||
{
|
||||
|
||||
ivl_type_t btype = base_type->elaborate_type(des, scope);
|
||||
|
||||
assert(dims->size() >= 1);
|
||||
list<pform_range_t>::const_iterator cur = dims->begin();
|
||||
|
||||
// Special case: if the dimension is nil:nil, this is a
|
||||
// dynamic array. Note that we only know how to handle dynamic
|
||||
// arrays with 1 dimension at a time.
|
||||
if (cur->first==0 && cur->second==0) {
|
||||
assert(dims->size()==1);
|
||||
ivl_type_s*res = new netdarray_t(btype);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Special case: if the dimension is null:nil. this is a queue.
|
||||
if (dynamic_cast<PENull*>(cur->first)) {
|
||||
// FIXME: Need to set the max size if cur->second is defined
|
||||
ivl_type_s*res = new netqueue_t(btype, -1);
|
||||
return res;
|
||||
}
|
||||
|
||||
vector<netrange_t> dimensions;
|
||||
bool dimensions_ok = evaluate_ranges(des, scope, this, dimensions, *dims);
|
||||
|
||||
if (!dimensions_ok) {
|
||||
cerr << get_fileline() << " : warning: "
|
||||
<< "Bad dimensions for type here." << endl;
|
||||
}
|
||||
|
||||
ivl_assert(*this, btype);
|
||||
ivl_type_s*res = new netuarray_t(dimensions, btype);
|
||||
return res;
|
||||
return elaborate_array_type(des, scope, *this, btype, *dims.get());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
./ivltests/sv_queue_parray_fail.v:7: error: queue 'q_vec1' bound must be positive (-1)!
|
||||
./ivltests/sv_queue_parray_fail.v:8: error: queue 'q_vec2' bound is undefined!
|
||||
./ivltests/sv_queue_parray_fail.v:7: error: queue bound must be positive (-1).
|
||||
./ivltests/sv_queue_parray_fail.v:8: error: queue bound must be defined.
|
||||
./ivltests/sv_queue_parray_fail.v:9: error: A reference to a wire or reg (`bound') is not allowed in a constant expression.
|
||||
./ivltests/sv_queue_parray_fail.v:9: error: queue 'q_vec3' bound must be a constant!
|
||||
./ivltests/sv_queue_parray_fail.v:9: error: queue bound must be constant.
|
||||
./ivltests/sv_queue_parray_fail.v:12: error: size() method takes no arguments
|
||||
./ivltests/sv_queue_parray_fail.v:13: error: pop_front() method takes no arguments
|
||||
./ivltests/sv_queue_parray_fail.v:14: error: pop_back() method takes no arguments
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
./ivltests/sv_queue_real_fail.v:4: error: queue 'q_real1' bound must be positive (-1)!
|
||||
./ivltests/sv_queue_real_fail.v:5: error: queue 'q_real2' bound is undefined!
|
||||
./ivltests/sv_queue_real_fail.v:4: error: queue bound must be positive (-1).
|
||||
./ivltests/sv_queue_real_fail.v:5: error: queue bound must be defined.
|
||||
./ivltests/sv_queue_real_fail.v:6: error: A reference to a wire or reg (`bound') is not allowed in a constant expression.
|
||||
./ivltests/sv_queue_real_fail.v:6: error: queue 'q_real3' bound must be a constant!
|
||||
./ivltests/sv_queue_real_fail.v:6: error: queue bound must be constant.
|
||||
./ivltests/sv_queue_real_fail.v:9: error: size() method takes no arguments
|
||||
./ivltests/sv_queue_real_fail.v:10: error: pop_front() method takes no arguments
|
||||
./ivltests/sv_queue_real_fail.v:11: error: pop_back() method takes no arguments
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
./ivltests/sv_queue_string_fail.v:4: error: queue 'q_str1' bound must be positive (-1)!
|
||||
./ivltests/sv_queue_string_fail.v:5: error: queue 'q_str2' bound is undefined!
|
||||
./ivltests/sv_queue_string_fail.v:4: error: queue bound must be positive (-1).
|
||||
./ivltests/sv_queue_string_fail.v:5: error: queue bound must be defined.
|
||||
./ivltests/sv_queue_string_fail.v:6: error: A reference to a wire or reg (`bound') is not allowed in a constant expression.
|
||||
./ivltests/sv_queue_string_fail.v:6: error: queue 'q_str3' bound must be a constant!
|
||||
./ivltests/sv_queue_string_fail.v:6: error: queue bound must be constant.
|
||||
./ivltests/sv_queue_string_fail.v:9: error: size() method takes no arguments
|
||||
./ivltests/sv_queue_string_fail.v:10: error: pop_front() method takes no arguments
|
||||
./ivltests/sv_queue_string_fail.v:11: error: pop_back() method takes no arguments
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
./ivltests/sv_queue_vec_fail.v:4: error: queue 'q_vec1' bound must be positive (-1)!
|
||||
./ivltests/sv_queue_vec_fail.v:5: error: queue 'q_vec2' bound is undefined!
|
||||
./ivltests/sv_queue_vec_fail.v:4: error: queue bound must be positive (-1).
|
||||
./ivltests/sv_queue_vec_fail.v:5: error: queue bound must be defined.
|
||||
./ivltests/sv_queue_vec_fail.v:6: error: A reference to a wire or reg (`bound') is not allowed in a constant expression.
|
||||
./ivltests/sv_queue_vec_fail.v:6: error: queue 'q_vec3' bound must be a constant!
|
||||
./ivltests/sv_queue_vec_fail.v:6: error: queue bound must be constant.
|
||||
./ivltests/sv_queue_vec_fail.v:9: error: size() method takes no arguments
|
||||
./ivltests/sv_queue_vec_fail.v:10: error: pop_front() method takes no arguments
|
||||
./ivltests/sv_queue_vec_fail.v:11: error: pop_back() method takes no arguments
|
||||
|
|
|
|||
|
|
@ -364,6 +364,10 @@ struct class_type_t : public data_type_t {
|
|||
virtual SymbolType symbol_type() const;
|
||||
};
|
||||
|
||||
ivl_type_t elaborate_array_type(Design *des, NetScope *scope,
|
||||
const LineInfo &li, ivl_type_t base_type,
|
||||
const std::list<pform_range_t> &dims);
|
||||
|
||||
/*
|
||||
* The pform_name_t is the general form for a hierarchical
|
||||
* identifier. It is an ordered list of name components. Each name
|
||||
|
|
|
|||
Loading…
Reference in New Issue