Handle packed arrays of packed struct in l-value expressions.

This commit is contained in:
Stephen Williams 2012-08-05 16:28:40 -07:00
parent 3d9ed1f0f8
commit b4cc9d14a5
12 changed files with 217 additions and 17 deletions

View File

@ -229,7 +229,10 @@ ostream&operator<<(ostream&out, const vector<netrange_t>&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());

View File

@ -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

View File

@ -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 <typeinfo>
# include <cstdlib>
# include <iostream>
@ -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)
{
list<netrange_t>packed_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<struct_type_t*>(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<netrange_t>&lef, const list<netrange_t>&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<parray_type_t*>(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) {

View File

@ -820,6 +820,17 @@ netdarray_t* NetNet::darray_type(void) const
return dynamic_cast<netdarray_t*> (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_;

View File

@ -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;

View File

@ -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<index_component_t>&indices)
{
list<long>prefix_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;
}

View File

@ -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<long>&prefix_indices,
const list<index_component_t>&indices);
extern NetExpr*collapse_array_indices(Design*des, NetScope*scope, NetNet*net,
const std::list<index_component_t>&indices);
#endif

53
netparray.h Normal file
View File

@ -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 <vector>
/*
* Packed arrays.
*/
class netparray_t : public nettype_base_t, public LineInfo {
public:
explicit netparray_t(const std::list<netrange_t>&packed);
~netparray_t();
inline const std::list<netrange_t>& packed_dimensions() const
{ return packed_dims_; }
private:
std::list<netrange_t> packed_dims_;
};
inline netparray_t::netparray_t(const std::list<netrange_t>&packed)
: packed_dims_(packed)
{
}
inline netparray_t::~netparray_t()
{
}
#endif

View File

@ -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<netrange_t>&packed)
{
unsigned wid = 1;

View File

@ -30,6 +30,7 @@
class nettype_base_t {
public:
virtual ~nettype_base_t() =0;
virtual long packed_width(void) const;
};
class netrange_t {

View File

@ -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<perm_string,PExpr*>&attributes,
int ind)

View File

@ -154,6 +154,7 @@ struct parray_type_t : public data_type_t {
inline explicit parray_type_t(data_type_t*btype, std::list<pform_range_t>*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<pform_range_t> > packed_dims;