Handle packed arrays of packed struct in l-value expressions.
This commit is contained in:
parent
3d9ed1f0f8
commit
b4cc9d14a5
|
|
@ -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());
|
||||
|
|
|
|||
60
elab_lval.cc
60
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
|
||||
|
|
|
|||
54
elab_sig.cc
54
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 <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) {
|
||||
|
|
|
|||
11
netlist.cc
11
netlist.cc
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
22
netmisc.cc
22
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<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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
class nettype_base_t {
|
||||
public:
|
||||
virtual ~nettype_base_t() =0;
|
||||
virtual long packed_width(void) const;
|
||||
};
|
||||
|
||||
class netrange_t {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue