Rework packed dimensions handling
Make packed structs more obviously parts of a vector. Handle arrays of structs in certain cases.
This commit is contained in:
parent
b4cc9d14a5
commit
0bdabab4fb
75
elab_expr.cc
75
elab_expr.cc
|
|
@ -1553,7 +1553,9 @@ bool calculate_part(const LineInfo*li, Design*des, NetScope*scope,
|
|||
*/
|
||||
static NetExpr* check_for_struct_members(const LineInfo*li,
|
||||
Design*des, NetScope*scope,
|
||||
NetNet*net, const name_component_t&comp)
|
||||
NetNet*net,
|
||||
const list<index_component_t>&base_index,
|
||||
const name_component_t&comp)
|
||||
{
|
||||
unsigned long off;
|
||||
const netstruct_t::member_t*mem = get_struct_member(li, des, 0, net,
|
||||
|
|
@ -1563,12 +1565,14 @@ static NetExpr* check_for_struct_members(const LineInfo*li,
|
|||
unsigned use_width = mem->width();
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << li->get_fileline() << ": check_for_struct_members: "
|
||||
cerr << li->get_fileline() << ": debug: check_for_struct_members: "
|
||||
<< "Found struct member " << mem->name
|
||||
<< " At offset " << off
|
||||
<< ", member width = " << use_width << endl;
|
||||
}
|
||||
|
||||
// The struct member may be a packed array. Process index
|
||||
// expression that address the member element.
|
||||
if ( ! comp.index.empty() ) {
|
||||
// Evaluate all but the last index expression, into prefix_indices.
|
||||
list<long>prefix_indices;
|
||||
|
|
@ -1597,7 +1601,7 @@ static NetExpr* check_for_struct_members(const LineInfo*li,
|
|||
prefix_to_slice(mem->packed_dims, prefix_indices, poff, loff, lwid);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << li->get_fileline() << ": check_for_struct_members: "
|
||||
cerr << li->get_fileline() << ": debug: check_for_struct_members: "
|
||||
<< "Evaluate prefix gives slice loff=" << loff
|
||||
<< ", lwid=" << lwid << ", part select pwid=" << pwid << endl;
|
||||
}
|
||||
|
|
@ -1609,8 +1613,44 @@ static NetExpr* check_for_struct_members(const LineInfo*li,
|
|||
use_width = lwid;
|
||||
}
|
||||
|
||||
// If the base symbol has dimensions, then this is a packed
|
||||
// array of structures. Convert an array of indices to a
|
||||
// single part select. For example, "net" is a packed array
|
||||
// of struct, and "mem" is the struct member. In Verilog it
|
||||
// looks something like "net[idx].mem". We've already
|
||||
// converted "mem" to an offset into the packed struct, so now
|
||||
// we just canonicalize "[idx]" and add the ".mem" offset to
|
||||
// get a collapsed index.
|
||||
NetExpr*packed_base = 0;
|
||||
if(net->packed_dimensions() > 1) {
|
||||
list<index_component_t>tmp_index = base_index;
|
||||
index_component_t member_select;
|
||||
member_select.sel = index_component_t::SEL_BIT;
|
||||
member_select.msb = new PENumber(new verinum(off));
|
||||
tmp_index.push_back(member_select);
|
||||
packed_base = collapse_array_exprs(des, scope, li, net, tmp_index);
|
||||
ivl_assert(*li, packed_base);
|
||||
if (debug_elaborate) {
|
||||
cerr << li->get_fileline() << ": debug: check_for_struct_members: "
|
||||
<< "Got collapsed array expr: " << *packed_base << endl;
|
||||
}
|
||||
}
|
||||
|
||||
long tmp;
|
||||
if (packed_base && eval_as_long(tmp, packed_base)) {
|
||||
off = tmp;
|
||||
delete packed_base;
|
||||
packed_base = 0;
|
||||
}
|
||||
|
||||
NetESignal*sig = new NetESignal(net);
|
||||
NetEConst*base = make_const_val(off);
|
||||
NetExpr *base = packed_base? packed_base : make_const_val(off);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << li->get_fileline() << ": debug: check_for_struct_members: "
|
||||
<< "Convert packed indices/member select into part select: " << *base << endl;
|
||||
}
|
||||
|
||||
NetESelect*sel = new NetESelect(sig, base, use_width);
|
||||
return sel;
|
||||
}
|
||||
|
|
@ -2352,7 +2392,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
|||
ivl_assert(*this, use_enum != 0);
|
||||
|
||||
expr_type_ = use_enum->base_type();
|
||||
expr_width_ = use_enum->base_width();
|
||||
expr_width_ = use_enum->packed_width();
|
||||
min_width_ = expr_width_;
|
||||
signed_flag_ = par_enum->has_sign();
|
||||
|
||||
|
|
@ -2400,9 +2440,17 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
|||
// Check to see if we have a net and if so is it a structure?
|
||||
if (net != 0) {
|
||||
// If this net is a struct, the method name may be
|
||||
// a struct member.
|
||||
// a struct member. If it is, then we know the
|
||||
// width of this identifier my knowing the width
|
||||
// of the member. We don't even need to know
|
||||
// anything about positions in containing arrays.
|
||||
if (net->struct_type() != 0) {
|
||||
ivl_assert(*this, use_path.back().index.empty());
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: PEIdent::test_width: "
|
||||
<< "Net " << use_path << " is a struct, "
|
||||
<< "checking width of member " << method_name << endl;
|
||||
}
|
||||
|
||||
const netstruct_t::member_t*mem;
|
||||
unsigned long unused;
|
||||
|
|
@ -2603,10 +2651,19 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
// If this net is a struct, the method name may be
|
||||
// a struct member.
|
||||
if (net->struct_type() != 0) {
|
||||
ivl_assert(*this, use_path.back().index.empty());
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "PEIdent::elaborate_expr: "
|
||||
<< "Ident " << use_path
|
||||
<< " is a struct."
|
||||
<< " Expecting " << net->packed_dims().size()
|
||||
<< "-1 dimensions, "
|
||||
<< "got " << use_path.back().index.size() << "." << endl;
|
||||
}
|
||||
|
||||
return check_for_struct_members(this, des, scope,
|
||||
net, member_comp);
|
||||
net, use_path.back().index,
|
||||
member_comp);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
47
elab_lval.cc
47
elab_lval.cc
|
|
@ -713,20 +713,9 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope,
|
|||
++ 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);
|
||||
|
||||
// Calculate the offset within the packed structure of the
|
||||
// member, and any indices. We will add in the offset of the
|
||||
// struct into the packed array later.
|
||||
unsigned long off;
|
||||
const netstruct_t::member_t* member = struct_type->packed_member(member_name, off);
|
||||
|
||||
|
|
@ -781,9 +770,31 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope,
|
|||
use_width = lwid;
|
||||
}
|
||||
|
||||
// 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".
|
||||
// Note that one of the packed dimensions is the packed struct
|
||||
// itself.
|
||||
ivl_assert(*this, name_base.index.size()+1 == 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() > 1) {
|
||||
list<index_component_t>tmp_index = name_base.index;
|
||||
index_component_t member_select;
|
||||
member_select.sel = index_component_t::SEL_BIT;
|
||||
member_select.msb = new PENumber(new verinum(off));
|
||||
tmp_index.push_back(member_select);
|
||||
packed_base = collapse_array_indices(des, scope, reg, tmp_index);
|
||||
}
|
||||
|
||||
long tmp;
|
||||
if (eval_as_long(tmp, packed_base)) {
|
||||
off += tmp * struct_type->packed_width();
|
||||
if (packed_base && eval_as_long(tmp, packed_base)) {
|
||||
off = tmp;
|
||||
delete packed_base;
|
||||
packed_base = 0;
|
||||
}
|
||||
|
|
@ -793,6 +804,10 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope,
|
|||
return true;
|
||||
}
|
||||
|
||||
// Oops, packed_base is not fully evaluated, so I don't know
|
||||
// yet what to do with it.
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "I don't know how to handle this index expression? " << *packed_base << endl;
|
||||
ivl_assert(*this, 0);
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -181,12 +181,12 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
|||
verinum max_value (0);
|
||||
if (enum_type->signed_flag) {
|
||||
min_value = v_not((pow(verinum(2),
|
||||
verinum(use_enum->base_width()-1)))) +
|
||||
verinum(use_enum->packed_width()-1)))) +
|
||||
one_value;
|
||||
max_value = pow(verinum(2), verinum(use_enum->base_width()-1)) -
|
||||
max_value = pow(verinum(2), verinum(use_enum->packed_width()-1)) -
|
||||
one_value;
|
||||
} else {
|
||||
max_value = pow(verinum(2), verinum(use_enum->base_width())) -
|
||||
max_value = pow(verinum(2), verinum(use_enum->packed_width())) -
|
||||
one_value;
|
||||
}
|
||||
min_value.has_sign(true);
|
||||
|
|
@ -249,15 +249,15 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
|||
// The values are explicitly sized to the width of the
|
||||
// base type of the enumeration.
|
||||
verinum tmp_val (0);
|
||||
if (cur_value.len() < use_enum->base_width()) {
|
||||
if (cur_value.len() < use_enum->packed_width()) {
|
||||
// Pad the current value if it is narrower than the final
|
||||
// width of the enum.
|
||||
tmp_val = pad_to_width (cur_value, use_enum->base_width());
|
||||
tmp_val = pad_to_width (cur_value, use_enum->packed_width());
|
||||
tmp_val.has_len(true);
|
||||
} else {
|
||||
// Truncate an oversized value. We report out of bound
|
||||
// values above. This may create duplicates.
|
||||
tmp_val = verinum(cur_value, use_enum->base_width());
|
||||
tmp_val = verinum(cur_value, use_enum->packed_width());
|
||||
}
|
||||
tmp_val.has_sign(enum_type->signed_flag);
|
||||
|
||||
|
|
|
|||
|
|
@ -1213,7 +1213,9 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Create signal " << wtype
|
||||
<< " enumeration "
|
||||
<< name_ << " in scope " << scope_path(scope) << endl;
|
||||
<< name_ << " in scope " << scope_path(scope)
|
||||
<< " with packed_dimensions=" << packed_dimensions
|
||||
<< " and packed_width=" << use_enum->packed_width() << endl;
|
||||
}
|
||||
|
||||
sig = new NetNet(scope, name_, wtype, packed_dimensions, unpacked_dimensions, use_enum);
|
||||
|
|
|
|||
|
|
@ -334,7 +334,7 @@ NetESFunc::NetESFunc(const char*n, netenum_t*enum_type, unsigned np)
|
|||
: name_(0), type_(enum_type->base_type()), enum_type_(enum_type), parms_(np)
|
||||
{
|
||||
name_ = lex_strings.add(n);
|
||||
expr_width(enum_type->base_width());
|
||||
expr_width(enum_type->packed_width());
|
||||
}
|
||||
|
||||
NetESFunc::~NetESFunc()
|
||||
|
|
|
|||
|
|
@ -32,6 +32,14 @@ netenum_t::~netenum_t()
|
|||
{
|
||||
}
|
||||
|
||||
long netenum_t::packed_width() const
|
||||
{
|
||||
if (msb_ >= lsb_)
|
||||
return msb_ - lsb_ + 1;
|
||||
else
|
||||
return lsb_ - msb_ + 1;
|
||||
}
|
||||
|
||||
bool netenum_t::insert_name(size_t name_idx, perm_string name, const verinum&val)
|
||||
{
|
||||
std::pair<std::map<perm_string,verinum>::iterator, bool> res;
|
||||
|
|
|
|||
10
netenum.h
10
netenum.h
|
|
@ -37,7 +37,7 @@ class netenum_t : public LineInfo, public nettype_base_t {
|
|||
~netenum_t();
|
||||
|
||||
ivl_variable_type_t base_type() const;
|
||||
unsigned base_width() const;
|
||||
long packed_width() const;
|
||||
bool has_sign() const;
|
||||
|
||||
// The size() is the number of enumeration literals.
|
||||
|
|
@ -73,14 +73,6 @@ class netenum_t : public LineInfo, public nettype_base_t {
|
|||
inline ivl_variable_type_t netenum_t::base_type() const
|
||||
{ return base_type_; }
|
||||
|
||||
inline unsigned netenum_t::base_width() const
|
||||
{
|
||||
if (msb_ >= lsb_)
|
||||
return msb_ - lsb_ + 1;
|
||||
else
|
||||
return lsb_ - msb_ + 1;
|
||||
}
|
||||
|
||||
inline size_t netenum_t::size() const { return names_.size(); }
|
||||
|
||||
inline bool netenum_t::has_sign() const { return signed_flag_; }
|
||||
|
|
|
|||
65
netlist.cc
65
netlist.cc
|
|
@ -476,6 +476,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins)
|
|||
|
||||
// Synthesize a single range to describe this canonical vector.
|
||||
packed_dims_.push_back(netrange_t(npins-1, 0));
|
||||
calculate_slice_widths_from_packed_dims_();
|
||||
|
||||
Link::DIR dir = Link::PASSIVE;
|
||||
|
||||
|
|
@ -521,6 +522,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
|
|||
eref_count_(0), lref_count_(0)
|
||||
{
|
||||
packed_dims_ = packed;
|
||||
calculate_slice_widths_from_packed_dims_();
|
||||
assert(s);
|
||||
|
||||
Link::DIR dir = Link::PASSIVE;
|
||||
|
|
@ -564,6 +566,32 @@ static unsigned calculate_count(const list<netrange_t>&unpacked)
|
|||
return sum;
|
||||
}
|
||||
|
||||
template <class T> static unsigned calculate_count(T*type)
|
||||
{
|
||||
long wid = type->packed_width();
|
||||
if (wid >= 0)
|
||||
return wid;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
void NetNet::calculate_slice_widths_from_packed_dims_(void)
|
||||
{
|
||||
if (packed_dims_.empty()) {
|
||||
slice_wids_.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
slice_wids_.resize(packed_dims_.size());
|
||||
|
||||
slice_wids_[0] = netrange_width(packed_dims_);
|
||||
list<netrange_t>::const_iterator cur = packed_dims_.begin();
|
||||
for (size_t idx = 1 ; idx < slice_wids_.size() ; idx += 1) {
|
||||
slice_wids_[idx] = slice_wids_[idx-1] / cur->width();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NetNet::NetNet(NetScope*s, perm_string n, Type t,
|
||||
const list<netrange_t>&packed,
|
||||
const list<netrange_t>&unpacked,
|
||||
|
|
@ -576,6 +604,9 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
|
|||
eref_count_(0), lref_count_(0)
|
||||
{
|
||||
packed_dims_ = packed;
|
||||
if (net_type)
|
||||
packed_dims_.push_back(netrange_t(calculate_count(net_type)-1, 0));
|
||||
calculate_slice_widths_from_packed_dims_();
|
||||
size_t idx = 0;
|
||||
for (list<netrange_t>::const_iterator cur = unpacked.begin()
|
||||
; cur != unpacked.end() ; ++cur, idx += 1) {
|
||||
|
|
@ -611,15 +642,6 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
|
|||
s->add_signal(this);
|
||||
}
|
||||
|
||||
template <class T> static unsigned calculate_count(T*type)
|
||||
{
|
||||
long wid = type->packed_width();
|
||||
if (wid >= 0)
|
||||
return wid;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* When we create a netnet for a packed struct, create a single
|
||||
* vector with the msb_/lsb_ chosen to name enough bits for the entire
|
||||
|
|
@ -634,6 +656,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, netstruct_t*ty)
|
|||
eref_count_(0), lref_count_(0)
|
||||
{
|
||||
packed_dims_.push_back(netrange_t(calculate_count(ty)-1, 0));
|
||||
calculate_slice_widths_from_packed_dims_();
|
||||
Link::DIR dir = Link::PASSIVE;
|
||||
|
||||
switch (t) {
|
||||
|
|
@ -820,15 +843,23 @@ netdarray_t* NetNet::darray_type(void) const
|
|||
return dynamic_cast<netdarray_t*> (net_type_);
|
||||
}
|
||||
|
||||
unsigned long NetNet::vector_width() const
|
||||
/*
|
||||
* "depth" is the number of index expressions that the user is using
|
||||
* to index this identifer. So consider if Net was declared like so:
|
||||
*
|
||||
* reg [5:0][3:0] foo;
|
||||
*
|
||||
* In this case, slice_width(2) == 1 (slice_width(N) where N is the
|
||||
* number of dimensions will always be 1.) and represents
|
||||
* $bits(foo[a][b]). Then, slice_width(1)==4 ($bits(foo[a]) and slice_width(0)==24.
|
||||
*/
|
||||
unsigned long NetNet::slice_width(size_t depth) const
|
||||
{
|
||||
unsigned long wid = netrange_width(packed_dims_);
|
||||
if (net_type_) {
|
||||
long tmp = net_type_->packed_width();
|
||||
if (tmp > 0) wid *= tmp;
|
||||
}
|
||||
|
||||
return wid;
|
||||
if (depth > slice_wids_.size())
|
||||
return 0;
|
||||
if (depth == slice_wids_.size())
|
||||
return 1;
|
||||
return slice_wids_[depth];
|
||||
}
|
||||
|
||||
ivl_discipline_t NetNet::get_discipline() const
|
||||
|
|
|
|||
10
netlist.h
10
netlist.h
|
|
@ -664,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;
|
||||
inline unsigned long vector_width() const { return slice_width(0); }
|
||||
|
||||
/* Given a prefix of indices, figure out how wide the
|
||||
resulting slice would be. This is a generalization of the
|
||||
|
|
@ -744,6 +744,14 @@ class NetNet : public NetObj, public PortType {
|
|||
std::list<netrange_t> packed_dims_;
|
||||
std::vector<netrange_t> unpacked_dims_;
|
||||
|
||||
// These are the widths of the various slice depths. There is
|
||||
// one entry in this vector for each packed dimension. The
|
||||
// value at N is the slice width if N indices are provided.
|
||||
//
|
||||
// For example: slice_wids_[0] is vector_width().
|
||||
void calculate_slice_widths_from_packed_dims_(void);
|
||||
std::vector<unsigned long> slice_wids_;
|
||||
|
||||
unsigned eref_count_;
|
||||
unsigned lref_count_;
|
||||
|
||||
|
|
|
|||
96
netmisc.cc
96
netmisc.cc
|
|
@ -180,6 +180,21 @@ static NetExpr* make_add_expr(NetExpr*expr, long val)
|
|||
return res;
|
||||
}
|
||||
|
||||
static NetExpr* make_add_expr(const LineInfo*loc, NetExpr*expr1, NetExpr*expr2)
|
||||
{
|
||||
bool use_signed = expr1->has_sign() && expr2->has_sign();
|
||||
unsigned use_wid = expr1->expr_width();
|
||||
|
||||
if (expr2->expr_width() > use_wid)
|
||||
use_wid = expr2->expr_width();
|
||||
|
||||
expr1 = pad_to_width(expr1, use_wid, *loc);
|
||||
expr2 = pad_to_width(expr2, use_wid, *loc);
|
||||
|
||||
NetEBAdd*tmp = new NetEBAdd('+', expr1, expr2, use_wid, use_signed);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Subtract an existing expression from a signed constant.
|
||||
*/
|
||||
|
|
@ -254,6 +269,8 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb,
|
|||
if (is_up) offset -= wid - 1;
|
||||
/* Calculate the space needed for the offset. */
|
||||
unsigned min_wid = num_bits(offset);
|
||||
if (num_bits(soff) > min_wid)
|
||||
min_wid = num_bits(soff);
|
||||
/* 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();
|
||||
|
|
@ -287,6 +304,8 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb,
|
|||
if ((soff-offset) == 0) return base;
|
||||
/* Calculate the space needed for the offset. */
|
||||
unsigned min_wid = num_bits(-offset);
|
||||
if (num_bits(soff) > min_wid)
|
||||
min_wid = num_bits(soff);
|
||||
/* 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();
|
||||
|
|
@ -834,8 +853,9 @@ bool eval_as_double(double&value, NetExpr*expr)
|
|||
* returns the path component name. It will evaluate the index
|
||||
* expression if it is present.
|
||||
*/
|
||||
hname_t eval_path_component(Design*des, NetScope*scope,
|
||||
const name_component_t&comp)
|
||||
static hname_t eval_path_component(Design*des, NetScope*scope,
|
||||
const name_component_t&comp,
|
||||
bool&error_flag)
|
||||
{
|
||||
// No index expression, so the path component is an undecorated
|
||||
// name, for example "foo".
|
||||
|
|
@ -873,6 +893,7 @@ hname_t eval_path_component(Design*des, NetScope*scope,
|
|||
return res;
|
||||
}
|
||||
|
||||
#if 1
|
||||
// Darn, the expression doesn't evaluate to a constant. That's
|
||||
// an error to be reported. And make up a fake index value to
|
||||
// return to the caller.
|
||||
|
|
@ -880,6 +901,8 @@ hname_t eval_path_component(Design*des, NetScope*scope,
|
|||
<< "Scope index expression is not constant: "
|
||||
<< *index.msb << endl;
|
||||
des->errors += 1;
|
||||
#endif
|
||||
error_flag = true;
|
||||
|
||||
delete tmp;
|
||||
return hname_t (comp.name, 0);
|
||||
|
|
@ -888,15 +911,20 @@ hname_t eval_path_component(Design*des, NetScope*scope,
|
|||
std::list<hname_t> eval_scope_path(Design*des, NetScope*scope,
|
||||
const pform_name_t&path)
|
||||
{
|
||||
bool path_error_flag = false;
|
||||
list<hname_t> res;
|
||||
|
||||
typedef pform_name_t::const_iterator pform_path_it;
|
||||
|
||||
for (pform_path_it cur = path.begin() ; cur != path.end(); ++ cur ) {
|
||||
const name_component_t&comp = *cur;
|
||||
res.push_back( eval_path_component(des,scope,comp) );
|
||||
res.push_back( eval_path_component(des,scope,comp,path_error_flag) );
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (path_error_flag) {
|
||||
cerr << "XXXXX: Errors evaluating path " << path << endl;
|
||||
}
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -1128,6 +1156,64 @@ bool evaluate_index_prefix(Design*des, NetScope*scope,
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluate the indices. The chain of indices are applied to the
|
||||
* packed indices of a NetNet to generate a canonical expression to
|
||||
* replace the exprs.
|
||||
*/
|
||||
NetExpr*collapse_array_exprs(Design*des, NetScope*scope,
|
||||
const LineInfo*loc, NetNet*net,
|
||||
const list<index_component_t>&indices)
|
||||
{
|
||||
// First elaborate all the expressions as far as possible.
|
||||
list<NetExpr*> exprs;
|
||||
list<long> exprs_const;
|
||||
bool flag = indices_to_expressions(des, scope, loc, indices,
|
||||
net->packed_dimensions(),
|
||||
false, exprs, exprs_const);
|
||||
ivl_assert(*loc, exprs.size() == net->packed_dimensions());
|
||||
|
||||
// Special Case: there is only 1 packed dimension, so the
|
||||
// single expression should already be naturally canonical.
|
||||
if (net->slice_width(1) == 1) {
|
||||
return *exprs.begin();
|
||||
}
|
||||
|
||||
const std::list<netrange_t>&pdims = net->packed_dims();
|
||||
std::list<netrange_t>::const_iterator pcur = pdims.begin();
|
||||
|
||||
list<NetExpr*>::iterator ecur = exprs.begin();
|
||||
NetExpr* base = 0;
|
||||
for (size_t idx = 0 ; idx < net->packed_dimensions() ; idx += 1, ++pcur, ++ecur) {
|
||||
unsigned cur_slice_width = net->slice_width(idx+1);
|
||||
// This normalizes the expression of this index based on
|
||||
// the msb/lsb values.
|
||||
NetExpr*tmp = normalize_variable_base(*ecur, pcur->get_msb(),
|
||||
pcur->get_lsb(),
|
||||
cur_slice_width, true);
|
||||
|
||||
// If this slice has width, then scale it.
|
||||
if (net->slice_width(idx+1) != 1) {
|
||||
unsigned min_wid = tmp->expr_width();
|
||||
if (num_bits(cur_slice_width) >= min_wid) {
|
||||
min_wid = num_bits(cur_slice_width)+1;
|
||||
tmp = pad_to_width(tmp, min_wid, *loc);
|
||||
}
|
||||
|
||||
tmp = make_mult_expr(tmp, cur_slice_width);
|
||||
}
|
||||
|
||||
// Now add it to the position we've accumulated so far.
|
||||
if (base) {
|
||||
base = make_add_expr(loc, base, tmp);
|
||||
} else {
|
||||
base = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a list of indices, treat them as packed indices and convert
|
||||
* them to an expression that normalizes the list to a single index
|
||||
|
|
@ -1147,5 +1233,7 @@ NetExpr*collapse_array_indices(Design*des, NetScope*scope, NetNet*net,
|
|||
NetExpr*base = elab_and_eval(des, scope, back_index.msb, -1, true);
|
||||
|
||||
NetExpr*res = normalize_variable_bit_base(prefix_indices, base, net);
|
||||
|
||||
eval_expr(res, -1);
|
||||
return res;
|
||||
}
|
||||
|
|
|
|||
11
netmisc.h
11
netmisc.h
|
|
@ -256,13 +256,6 @@ void eval_expr(NetExpr*&expr, int context_width =-1);
|
|||
bool eval_as_long(long&value, NetExpr*expr);
|
||||
bool eval_as_double(double&value, NetExpr*expr);
|
||||
|
||||
/*
|
||||
* Evaluate the component of a scope path to get an hname_t value. Do
|
||||
* the evaluation in the context of the given scope.
|
||||
*/
|
||||
extern hname_t eval_path_component(Design*des, NetScope*scope,
|
||||
const name_component_t&comp);
|
||||
|
||||
/*
|
||||
* Evaluate an entire scope path in the context of the given scope.
|
||||
*/
|
||||
|
|
@ -314,4 +307,8 @@ extern bool evaluate_index_prefix(Design*des, NetScope*scope,
|
|||
extern NetExpr*collapse_array_indices(Design*des, NetScope*scope, NetNet*net,
|
||||
const std::list<index_component_t>&indices);
|
||||
|
||||
extern NetExpr*collapse_array_exprs(Design*des, NetScope*scope,
|
||||
const LineInfo*loc, NetNet*net,
|
||||
const list<index_component_t>&indices);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
2
pform.cc
2
pform.cc
|
|
@ -2872,7 +2872,7 @@ static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type,
|
|||
|
||||
assert(enum_type->range.get() != 0);
|
||||
assert(enum_type->range->size() == 1);
|
||||
cur->set_range(*enum_type->range, SR_NET);
|
||||
//XXXXcur->set_range(*enum_type->range, SR_NET);
|
||||
cur->set_packed_type(enum_type);
|
||||
pform_bind_attributes(cur->attributes, attr, true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ extern "C" ivl_variable_type_t ivl_enum_type(ivl_enumtype_t net)
|
|||
extern "C" unsigned ivl_enum_width(ivl_enumtype_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->base_width();
|
||||
return net->packed_width();
|
||||
}
|
||||
|
||||
extern "C" int ivl_enum_signed(ivl_enumtype_t net)
|
||||
|
|
|
|||
Loading…
Reference in New Issue