diff --git a/design_dump.cc b/design_dump.cc index 166ae70ab..af1483e65 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -229,7 +229,10 @@ ostream&operator<<(ostream&out, const vector&rlist) void NetNet::dump_net(ostream&o, unsigned ind) const { o << setw(ind) << "" << type() << ": " << name() - << unpacked_dims_ << " unpacked dims=" << unpacked_dimensions() << " count=" << pin_count(); + << unpacked_dims_ << " unpacked dims=" << unpacked_dimensions(); + if (!packed_dims_.empty()) + o << " packed dims=" << packed_dims_; + o << " pin_count=" << pin_count(); if (local_flag_) o << " (local)"; o << " " << data_type_; @@ -264,6 +267,9 @@ void NetNet::dump_net(ostream&o, unsigned ind) const if (! packed_dims_.empty()) o << " packed dims: " << packed_dims_; + if (net_type_) + o << " net_type_=" << typeid(*net_type_).name(); + o << " (eref=" << peek_eref() << ", lref=" << peek_lref() << ")"; if (scope()) o << " scope=" << scope_path(scope()); diff --git a/elab_lval.cc b/elab_lval.cc index ec7af12df..7d0546ba9 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -1,5 +1,6 @@ /* * Copyright (c) 2000-2012 Stephen Williams (steve@icarus.com) + * Copyright CERN 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 @@ -682,6 +683,11 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope, netstruct_t*struct_type = reg->struct_type(); ivl_assert(*this, struct_type); + if (debug_elaborate) { + cerr << get_fileline() << ": debug: elaborate lval packed member: " + << "path_=" << path_ << endl; + } + if (! struct_type->packed()) { cerr << get_fileline() << ": sorry: Only packed structures " << "are supported in l-value." << endl; @@ -689,6 +695,38 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope, return false; } + // Shouldn't be seeing unpacked arrays of packed structs... + ivl_assert(*this, reg->unpacked_dimensions() == 0); + + // This is a packed member, so the name is of the form + // "a.b[...].c[...]" which means that the path_ must have at + // least 2 components. We are processing "c[...]" at that + // point (otherwise known as member_name) so we'll save a + // reference to it in name_tail. We are also processing "b[]" + // so save that as name_base. + + ivl_assert(*this, path_.size() >= 2); + + pform_name_t::const_reverse_iterator name_idx = path_.rbegin(); + ivl_assert(*this, name_idx->name == member_name); + const name_component_t&name_tail = *name_idx; + ++ name_idx; + const name_component_t&name_base = *name_idx; + + // The dimenions in the expression must match the packed + // dimensions that are declared for the variable. For example, + // if foo is a packed array of struct, then this expression + // must be "b[n][m]" with the right number of dimensions to + // match the declaration of "b". + ivl_assert(*this, name_base.index.size() == reg->packed_dimensions()); + + // Generate an expression that takes the input array of + // expressions and generates a canonical offset into the + // packed array. + NetExpr*packed_base = 0; + if (reg->packed_dimensions() > 0) + packed_base = collapse_array_indices(des, scope, reg, name_base.index); + unsigned long off; const netstruct_t::member_t* member = struct_type->packed_member(member_name, off); @@ -701,12 +739,6 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope, unsigned long use_width = member->width(); - // We are processing the tail of a string of names. For - // example, the verilog may be "a.b.c", so we are processing - // "c" at this point. Of course, "c" is the name of the member - // we are working on and "a.b" is the name of reg. - const name_component_t&name_tail = path_.back(); - if (name_tail.index.size() > member->packed_dims.size()) { cerr << get_fileline() << ": error: Too make index expressions for member." << endl; des->errors += 1; @@ -749,8 +781,20 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope, use_width = lwid; } - lv->set_part(new NetEConst(verinum(off)), use_width); - return true; + long tmp; + if (eval_as_long(tmp, packed_base)) { + off += tmp * struct_type->packed_width(); + delete packed_base; + packed_base = 0; + } + + if (packed_base == 0) { + lv->set_part(new NetEConst(verinum(off)), use_width); + return true; + } + + ivl_assert(*this, 0); + return false; } NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*, bool) const diff --git a/elab_sig.cc b/elab_sig.cc index 59e01b3f6..fd7277e94 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -1,5 +1,6 @@ /* * Copyright (c) 2000-2012 Stephen Williams (steve@icarus.com) + * Copyright CERN 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 @@ -19,6 +20,7 @@ # include "config.h" +# include # include # include @@ -35,9 +37,12 @@ # include "netenum.h" # include "netstruct.h" # include "netdarray.h" +# include "netparray.h" # include "util.h" # include "ivl_assert.h" +using namespace std; + static bool get_const_argument(NetExpr*exp, verinum&res) { switch (exp->expr_type()) { @@ -892,20 +897,35 @@ static netstruct_t* elaborate_struct_type(Design*des, NetScope*scope, return res; } -static netdarray_t* elaborate_parray_type(Design*des, NetScope*scope, - parray_type_t*data_type) +static netparray_t* elaborate_parray_type(Design*des, NetScope*scope, + parray_type_t*data_type) { listpacked_dimensions; bool bad_range = evaluate_ranges(des, scope, packed_dimensions, * data_type->packed_dims); - ivl_assert(*data_type, bad_range); + ivl_assert(*data_type, !bad_range); - netdarray_t*res = new netdarray_t(packed_dimensions, IVL_VT_NO_TYPE, 0); + netparray_t*res = new netparray_t(packed_dimensions); //res->set_line(*data_type); return res; } +static nettype_base_t*elaborate_type(Design*des, NetScope*scope, + data_type_t*pform_type) +{ + if (struct_type_t*struct_type = dynamic_cast(pform_type)) { + netstruct_t*use_type = elaborate_struct_type(des, scope, struct_type); + return use_type; + } + + cerr << pform_type->get_fileline() << ": sorry: I don't know how to elaborate " + << typeid(*pform_type).name() << " here." << endl; + des->errors += 1; + + return 0; +} + bool test_ranges_eeq(const list&lef, const list&rig) { if (lef.size() != rig.size()) @@ -1212,13 +1232,33 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const sig = new NetNet(scope, name_, wtype, netarray); } else if (parray_type_t*parray_type = dynamic_cast(set_data_type_)) { + // The pform gives us a parray_type_t for packed arrays + // that show up in type definitions. This can be handled + // a lot like packed dimensions from other means. - netdarray_t*use_type = elaborate_parray_type(des, scope, parray_type); - sig = new NetNet(scope, name_, wtype, use_type); + // The trick here is that the parray type has an + // arbitrary sub-type, and not just a scalar bit... + netparray_t*use_type = elaborate_parray_type(des, scope, parray_type); + // Should not be getting packed dimensions other then + // through the parray type declaration. + ivl_assert(*this, packed_dimensions.empty()); + + if (debug_elaborate) { + cerr << get_fileline() << ": debug: Create signal " << wtype + << " parray=" << use_type->packed_dimensions() + << " " << name_ << unpacked_dimensions + << " in scope " << scope_path(scope) << endl; + } + + nettype_base_t*base_type = elaborate_type(des, scope, parray_type->base_type); #if 0 - cerr << get_fileline() << ": sorry: Packed arrays not supported here." << endl; + cerr << get_fileline() << ": sorry: Packed array of " + << typeid(*parray_type->base_type).name() + << " not supported." << endl; des->errors += 1; #endif + sig = new NetNet(scope, name_, wtype, use_type->packed_dimensions(), unpacked_dimensions, base_type); + } else { if (debug_elaborate) { diff --git a/netlist.cc b/netlist.cc index ec867f7be..a86e9d881 100644 --- a/netlist.cc +++ b/netlist.cc @@ -820,6 +820,17 @@ netdarray_t* NetNet::darray_type(void) const return dynamic_cast (net_type_); } +unsigned long NetNet::vector_width() const +{ + unsigned long wid = netrange_width(packed_dims_); + if (net_type_) { + long tmp = net_type_->packed_width(); + if (tmp > 0) wid *= tmp; + } + + return wid; +} + ivl_discipline_t NetNet::get_discipline() const { return discipline_; diff --git a/netlist.h b/netlist.h index a79971a76..d07f58f0e 100644 --- a/netlist.h +++ b/netlist.h @@ -77,6 +77,7 @@ class NetEvWait; class PExpr; class PFunction; class netdarray_t; +class netparray_t; class netenum_t; class netstruct_t; @@ -614,6 +615,7 @@ class NetNet : public NetObj, public PortType { // This form builds a NetNet from its record/enum definition. explicit NetNet(NetScope*s, perm_string n, Type t, netstruct_t*type); explicit NetNet(NetScope*s, perm_string n, Type t, netdarray_t*type); + //explicit NetNet(NetScope*s, perm_string n, Type t, netparray_t*type); virtual ~NetNet(); @@ -662,7 +664,7 @@ class NetNet : public NetObj, public PortType { /* The vector_width returns the bit width of the packed array, vector or scaler that is this NetNet object. */ - unsigned long vector_width() const { return netrange_width(packed_dims_); } + unsigned long vector_width() const; /* Given a prefix of indices, figure out how wide the resulting slice would be. This is a generalization of the @@ -694,6 +696,10 @@ class NetNet : public NetObj, public PortType { indices. (Currently only one array index is supported.) */ inline unsigned unpacked_dimensions() const { return unpacked_dims_.size(); } + /* This methor returns 0 for scalars, but vectors and other + PACKED arrays have packed dimensions. */ + inline size_t packed_dimensions() const { return packed_dims_.size(); } + // This is the number of array elements. unsigned unpacked_count() const; diff --git a/netmisc.cc b/netmisc.cc index 814a3f783..aeb6479cb 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -1127,3 +1127,25 @@ bool evaluate_index_prefix(Design*des, NetScope*scope, return true; } + +/* + * Given a list of indices, treat them as packed indices and convert + * them to an expression that normalizes the list to a single index + * expression over a canonical equivilent 1-dimensional array. + */ +NetExpr*collapse_array_indices(Design*des, NetScope*scope, NetNet*net, + const list&indices) +{ + listprefix_indices; + bool rc = evaluate_index_prefix(des, scope, prefix_indices, indices); + assert(rc); + + const index_component_t&back_index = indices.back(); + assert(back_index.sel == index_component_t::SEL_BIT); + assert(back_index.msb && !back_index.lsb); + + NetExpr*base = elab_and_eval(des, scope, back_index.msb, -1, true); + + NetExpr*res = normalize_variable_bit_base(prefix_indices, base, net); + return res; +} diff --git a/netmisc.h b/netmisc.h index 452e0f17c..1972e652b 100644 --- a/netmisc.h +++ b/netmisc.h @@ -310,4 +310,8 @@ extern void collapse_partselect_pv_to_concat(Design*des, NetNet*sig); extern bool evaluate_index_prefix(Design*des, NetScope*scope, list&prefix_indices, const list&indices); + +extern NetExpr*collapse_array_indices(Design*des, NetScope*scope, NetNet*net, + const std::list&indices); + #endif diff --git a/netparray.h b/netparray.h new file mode 100644 index 000000000..70be869ec --- /dev/null +++ b/netparray.h @@ -0,0 +1,53 @@ +#ifndef __netarray_H +#define __netarray_H +/* + * Copyright (c) 2012 Stephen Williams (steve@icarus.com) + * Copyright CERN 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 + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "LineInfo.h" +# include "nettypes.h" +# include + +/* + * Packed arrays. + */ +class netparray_t : public nettype_base_t, public LineInfo { + + public: + explicit netparray_t(const std::list&packed); + ~netparray_t(); + + inline const std::list& packed_dimensions() const + { return packed_dims_; } + + private: + std::list packed_dims_; + +}; + +inline netparray_t::netparray_t(const std::list&packed) +: packed_dims_(packed) +{ +} + +inline netparray_t::~netparray_t() +{ +} + +#endif diff --git a/nettypes.cc b/nettypes.cc index 12dba0e20..9d31c81c2 100644 --- a/nettypes.cc +++ b/nettypes.cc @@ -26,6 +26,11 @@ nettype_base_t::~nettype_base_t() { } +long nettype_base_t::packed_width(void) const +{ + return 0; +} + unsigned long netrange_width(const list&packed) { unsigned wid = 1; diff --git a/nettypes.h b/nettypes.h index 4f771be35..3292ffc8c 100644 --- a/nettypes.h +++ b/nettypes.h @@ -30,6 +30,7 @@ class nettype_base_t { public: virtual ~nettype_base_t() =0; + virtual long packed_width(void) const; }; class netrange_t { diff --git a/pform_dump.cc b/pform_dump.cc index e8036ca67..0ce59a91a 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -146,6 +146,13 @@ void data_type_t::pform_dump(ostream&out, unsigned indent) const out << setw(indent) << "" << typeid(*this).name() << endl; } +void parray_type_t::pform_dump(ostream&out, unsigned indent) const +{ + out << setw(indent) << "" << "Packed array " << "[...]" + << " of:" << endl; + base_type->pform_dump(out, indent+4); +} + static void dump_attributes_map(ostream&out, const map&attributes, int ind) diff --git a/pform_types.h b/pform_types.h index 80c912fcf..a47b671fa 100644 --- a/pform_types.h +++ b/pform_types.h @@ -154,6 +154,7 @@ struct parray_type_t : public data_type_t { inline explicit parray_type_t(data_type_t*btype, std::list*pd) : base_type(btype), packed_dims(pd) { } virtual ivl_variable_type_t figure_packed_base_type(void)const; + virtual void pform_dump(std::ostream&out, unsigned indent) const; data_type_t*base_type; std::auto_ptr< list > packed_dims;