Merge branch 'work12'

This commit is contained in:
Stephen Williams 2012-09-14 17:28:50 -07:00
commit 6137566385
43 changed files with 1238 additions and 489 deletions

View File

@ -363,7 +363,7 @@ bool PEIdent::has_aa_term(Design*des, NetScope*scope) const
const NetExpr*ex1, *ex2; const NetExpr*ex1, *ex2;
scope = symbol_search(0, des, scope, path_, net, par, eve, ex1, ex2); scope = symbol_search(this, des, scope, path_, net, par, eve, ex1, ex2);
if (scope) if (scope)
return scope->is_auto(); return scope->is_auto();

View File

@ -29,7 +29,7 @@ PWire::PWire(perm_string n,
: name_(n), type_(t), port_type_(pt), data_type_(dt), : name_(n), type_(t), port_type_(pt), data_type_(dt),
signed_(false), isint_(false), signed_(false), isint_(false),
port_set_(false), net_set_(false), is_scalar_(false), port_set_(false), net_set_(false), is_scalar_(false),
error_cnt_(0), enum_type_(0), struct_type_(0), error_cnt_(0), set_data_type_(0),
discipline_(0) discipline_(0)
{ {
if (t == NetNet::INTEGER) { if (t == NetNet::INTEGER) {
@ -253,18 +253,10 @@ void PWire::set_unpacked_idx(const list<pform_range_t>&ranges)
} }
} }
void PWire::set_enumeration(enum_type_t*enum_type) void PWire::set_packed_type(data_type_t*type)
{ {
assert(enum_type_ == 0); assert(set_data_type_ == 0);
assert(struct_type_ == 0); set_data_type_ = type;
enum_type_ = enum_type;
}
void PWire::set_struct_type(struct_type_t*type)
{
assert(enum_type_ == 0);
assert(struct_type_ == 0);
struct_type_ = type;
} }
void PWire::set_discipline(ivl_discipline_t d) void PWire::set_discipline(ivl_discipline_t d)

View File

@ -81,8 +81,7 @@ class PWire : public LineInfo {
void set_unpacked_idx(const std::list<pform_range_t>&ranges); void set_unpacked_idx(const std::list<pform_range_t>&ranges);
void set_enumeration(enum_type_t*enum_type); void set_packed_type(data_type_t*type);
void set_struct_type(struct_type_t*type);
void set_discipline(ivl_discipline_t); void set_discipline(ivl_discipline_t);
ivl_discipline_t get_discipline(void) const; ivl_discipline_t get_discipline(void) const;
@ -119,8 +118,7 @@ class PWire : public LineInfo {
// me the size and address ranges of the memory. // me the size and address ranges of the memory.
std::list<pform_range_t>unpacked_; std::list<pform_range_t>unpacked_;
enum_type_t*enum_type_; data_type_t*set_data_type_;
struct_type_t*struct_type_;
ivl_discipline_t discipline_; ivl_discipline_t discipline_;

View File

@ -229,7 +229,10 @@ ostream&operator<<(ostream&out, const vector<netrange_t>&rlist)
void NetNet::dump_net(ostream&o, unsigned ind) const void NetNet::dump_net(ostream&o, unsigned ind) const
{ {
o << setw(ind) << "" << type() << ": " << name() 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_) if (local_flag_)
o << " (local)"; o << " (local)";
o << " " << data_type_; o << " " << data_type_;
@ -264,6 +267,9 @@ void NetNet::dump_net(ostream&o, unsigned ind) const
if (! packed_dims_.empty()) if (! packed_dims_.empty())
o << " packed dims: " << packed_dims_; o << " packed dims: " << packed_dims_;
if (net_type_)
o << " net_type_=" << typeid(*net_type_).name();
o << " (eref=" << peek_eref() << ", lref=" << peek_lref() << ")"; o << " (eref=" << peek_eref() << ", lref=" << peek_lref() << ")";
if (scope()) if (scope())
o << " scope=" << scope_path(scope()); o << " scope=" << scope_path(scope());

View File

@ -1553,7 +1553,9 @@ bool calculate_part(const LineInfo*li, Design*des, NetScope*scope,
*/ */
static NetExpr* check_for_struct_members(const LineInfo*li, static NetExpr* check_for_struct_members(const LineInfo*li,
Design*des, NetScope*scope, 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; unsigned long off;
const netstruct_t::member_t*mem = get_struct_member(li, des, 0, net, 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(); unsigned use_width = mem->width();
if (debug_elaborate) { 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 << "Found struct member " << mem->name
<< " At offset " << off << " At offset " << off
<< ", member width = " << use_width << endl; << ", 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() ) { if ( ! comp.index.empty() ) {
// Evaluate all but the last index expression, into prefix_indices. // Evaluate all but the last index expression, into prefix_indices.
list<long>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); prefix_to_slice(mem->packed_dims, prefix_indices, poff, loff, lwid);
if (debug_elaborate) { 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 << "Evaluate prefix gives slice loff=" << loff
<< ", lwid=" << lwid << ", part select pwid=" << pwid << endl; << ", lwid=" << lwid << ", part select pwid=" << pwid << endl;
} }
@ -1609,8 +1613,44 @@ static NetExpr* check_for_struct_members(const LineInfo*li,
use_width = lwid; 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); 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); NetESelect*sel = new NetESelect(sig, base, use_width);
return sel; return sel;
} }
@ -2263,7 +2303,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
const NetExpr*ex1, *ex2; const NetExpr*ex1, *ex2;
NetScope*found_in = symbol_search(0, des, scope, path_, net, par, eve, NetScope*found_in = symbol_search(this, des, scope, path_, net, par, eve,
ex1, ex2); ex1, ex2);
// If there is a part/bit select expression, then process it // If there is a part/bit select expression, then process it
@ -2352,7 +2392,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
ivl_assert(*this, use_enum != 0); ivl_assert(*this, use_enum != 0);
expr_type_ = use_enum->base_type(); expr_type_ = use_enum->base_type();
expr_width_ = use_enum->base_width(); expr_width_ = use_enum->packed_width();
min_width_ = expr_width_; min_width_ = expr_width_;
signed_flag_ = par_enum->has_sign(); 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? // Check to see if we have a net and if so is it a structure?
if (net != 0) { if (net != 0) {
// If this net is a struct, the method name may be // 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) { 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; const netstruct_t::member_t*mem;
unsigned long unused; 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 // If this net is a struct, the method name may be
// a struct member. // a struct member.
if (net->struct_type() != 0) { 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, return check_for_struct_members(this, des, scope,
net, member_comp); net, use_path.back().index,
member_comp);
} }
} }

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2000-2012 Stephen Williams (steve@icarus.com) * 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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * 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(); netstruct_t*struct_type = reg->struct_type();
ivl_assert(*this, 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()) { if (! struct_type->packed()) {
cerr << get_fileline() << ": sorry: Only packed structures " cerr << get_fileline() << ": sorry: Only packed structures "
<< "are supported in l-value." << endl; << "are supported in l-value." << endl;
@ -689,6 +695,27 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope,
return false; 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;
// 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; unsigned long off;
const netstruct_t::member_t* member = struct_type->packed_member(member_name, off); const netstruct_t::member_t* member = struct_type->packed_member(member_name, off);
@ -701,14 +728,8 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope,
unsigned long use_width = member->width(); 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()) { if (name_tail.index.size() > member->packed_dims.size()) {
cerr << get_fileline() << ": error: Too make index expressions for member." << endl; cerr << get_fileline() << ": error: Too many index expressions for member." << endl;
des->errors += 1; des->errors += 1;
return false; return false;
} }
@ -749,10 +770,48 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope,
use_width = lwid; 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 (packed_base && eval_as_long(tmp, packed_base)) {
off = tmp;
delete packed_base;
packed_base = 0;
}
if (packed_base == 0) {
lv->set_part(new NetEConst(verinum(off)), use_width); lv->set_part(new NetEConst(verinum(off)), use_width);
return true; 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;
}
NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*, bool) const NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*, bool) const
{ {
cerr << get_fileline() << ": error: Constant values not allowed " cerr << get_fileline() << ": error: Constant values not allowed "

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 1999-2012 Stephen Williams (steve@icarus.com) * Copyright (c) 1999-2012 Stephen Williams (steve@icarus.com)
* Copyright CERN 2012 / Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -418,15 +419,20 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
return 0; return 0;
} }
// Break the path_ into the tail name and the prefix. For
// example, a name "a.b.c" is broken into name_tail="c" and
// path_prefix="a.b".
const name_component_t&path_tail = path_.back();
pform_name_t path_prefix = path_;
path_prefix.pop_back();
/* If the signal is not found, check to see if this is a /* If the signal is not found, check to see if this is a
member of a struct. Take the name of the form "a.b.member", member of a struct. Take the name of the form "a.b.member",
remove the member and store it into method_name, and retry remove the member and store it into method_name, and retry
the search with "a.b". */ the search with "a.b". */
if (sig == 0 && path_.size() >= 2) { if (sig == 0 && path_.size() >= 2) {
pform_name_t use_path = path_; method_name = path_tail.name;
method_name = peek_tail_name(use_path); symbol_search(this, des, scope, path_prefix, sig, par, eve);
use_path.pop_back();
symbol_search(this, des, scope, use_path, sig, par, eve);
// Whoops, not a struct signal, so give up on this avenue. // Whoops, not a struct signal, so give up on this avenue.
if (sig && sig->struct_type() == 0) { if (sig && sig->struct_type() == 0) {
@ -467,14 +473,16 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
// The default word select is the first. // The default word select is the first.
long widx = 0; long widx = 0;
const name_component_t&name_tail = path_.back();
list<long> unpacked_indices_const; list<long> unpacked_indices_const;
netstruct_t*struct_type = 0; netstruct_t*struct_type = 0;
if ((struct_type = sig->struct_type()) && !method_name.nil()) { if ((struct_type = sig->struct_type()) && !method_name.nil()) {
// Detect the variable is a structure and there was a // Detect the variable is a structure and there was a
// method name detected. // method name detected. We've already found that
// the path_ is <>.sig.method_name and signal
// (NetNet). We also know that sig is struct_type(), so
// look for a method named method_name.
if (debug_elaborate) if (debug_elaborate)
cerr << get_fileline() << ": debug: " cerr << get_fileline() << ": debug: "
<< "Signal " << sig->name() << " is a structure, " << "Signal " << sig->name() << " is a structure, "
@ -489,13 +497,50 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
lidx = member_off; lidx = member_off;
midx = lidx + member->width() - 1; midx = lidx + member->width() - 1;
// The dimensions of the tail of the prefix must match
// the dimensions of the signal at this point. (The sig
// has a packed dimension for the packed struct size.)
// For example, if the path_=a[<m>][<n>].member, then
// sig must have 3 packed dimenions: one for the struct
// members and two actual packed dimensions.
ivl_assert(*this, path_prefix.back().index.size()+1 == sig->packed_dimensions());
// Elaborate an expression from the packed indices and
// the member offset (into the structure) to get a
// canonical expression into the packed signal vector.
NetExpr*packed_base = 0;
if (sig->packed_dimensions() > 1) {
list<index_component_t>tmp_index = path_prefix.back().index;
index_component_t member_select;
member_select.sel = index_component_t::SEL_BIT;
member_select.msb = new PENumber(new verinum(member_off));
tmp_index.push_back(member_select);
packed_base = collapse_array_indices(des, scope, sig, tmp_index);
if (debug_elaborate) {
cerr << get_fileline() << ": debug: "
<< "packed_base expression = " << *packed_base << endl;
}
}
long tmp;
if (packed_base && eval_as_long(tmp, packed_base)) {
lidx = tmp;
midx = lidx + member->width() - 1;
delete packed_base;
packed_base = 0;
}
// Currently, only support const dimensions here.
ivl_assert(*this, packed_base == 0);
} else if (sig->unpacked_dimensions() > 0) { } else if (sig->unpacked_dimensions() > 0) {
// Make sure there are enough indices to address an array element. // Make sure there are enough indices to address an array element.
if (name_tail.index.size() < sig->unpacked_dimensions()) { if (path_tail.index.size() < sig->unpacked_dimensions()) {
cerr << get_fileline() << ": error: Array " << path() cerr << get_fileline() << ": error: Array " << path()
<< " needs " << sig->unpacked_dimensions() << " indices," << " needs " << sig->unpacked_dimensions() << " indices,"
<< " but got only " << name_tail.index.size() << "." << endl; << " but got only " << path_tail.index.size() << "." << endl;
des->errors += 1; des->errors += 1;
return 0; return 0;
} }
@ -504,7 +549,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
// "unpacked_indices" array. // "unpacked_indices" array.
list<NetExpr*>unpacked_indices; list<NetExpr*>unpacked_indices;
bool flag = indices_to_expressions(des, scope, this, bool flag = indices_to_expressions(des, scope, this,
name_tail.index, sig->unpacked_dimensions(), path_tail.index, sig->unpacked_dimensions(),
true, true,
unpacked_indices, unpacked_indices,
unpacked_indices_const); unpacked_indices_const);
@ -539,7 +584,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
<< " to index l-value array." << endl; << " to index l-value array." << endl;
/* The array has a part/bit select at the end. */ /* The array has a part/bit select at the end. */
if (name_tail.index.size() > sig->unpacked_dimensions()) { if (path_tail.index.size() > sig->unpacked_dimensions()) {
if (sig->get_scalar()) { if (sig->get_scalar()) {
cerr << get_fileline() << ": error: " cerr << get_fileline() << ": error: "
<< "can not select part of "; << "can not select part of ";
@ -566,7 +611,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
lidx = lidx_tmp; lidx = lidx_tmp;
} }
} else if (!name_tail.index.empty()) { } else if (!path_tail.index.empty()) {
if (sig->get_scalar()) { if (sig->get_scalar()) {
cerr << get_fileline() << ": error: " cerr << get_fileline() << ": error: "
<< "can not select part of "; << "can not select part of ";

View File

@ -181,12 +181,12 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
verinum max_value (0); verinum max_value (0);
if (enum_type->signed_flag) { if (enum_type->signed_flag) {
min_value = v_not((pow(verinum(2), min_value = v_not((pow(verinum(2),
verinum(use_enum->base_width()-1)))) + verinum(use_enum->packed_width()-1)))) +
one_value; 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; one_value;
} else { } else {
max_value = pow(verinum(2), verinum(use_enum->base_width())) - max_value = pow(verinum(2), verinum(use_enum->packed_width())) -
one_value; one_value;
} }
min_value.has_sign(true); 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 // The values are explicitly sized to the width of the
// base type of the enumeration. // base type of the enumeration.
verinum tmp_val (0); 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 // Pad the current value if it is narrower than the final
// width of the enum. // 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); tmp_val.has_len(true);
} else { } else {
// Truncate an oversized value. We report out of bound // Truncate an oversized value. We report out of bound
// values above. This may create duplicates. // 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); tmp_val.has_sign(enum_type->signed_flag);

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2000-2012 Stephen Williams (steve@icarus.com) * 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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -19,6 +20,7 @@
# include "config.h" # include "config.h"
# include <typeinfo>
# include <cstdlib> # include <cstdlib>
# include <iostream> # include <iostream>
@ -35,9 +37,12 @@
# include "netenum.h" # include "netenum.h"
# include "netstruct.h" # include "netstruct.h"
# include "netdarray.h" # include "netdarray.h"
# include "netparray.h"
# include "util.h" # include "util.h"
# include "ivl_assert.h" # include "ivl_assert.h"
using namespace std;
static bool get_const_argument(NetExpr*exp, verinum&res) static bool get_const_argument(NetExpr*exp, verinum&res)
{ {
switch (exp->expr_type()) { switch (exp->expr_type()) {
@ -892,6 +897,35 @@ static netstruct_t* elaborate_struct_type(Design*des, NetScope*scope,
return res; return res;
} }
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);
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) bool test_ranges_eeq(const list<netrange_t>&lef, const list<netrange_t>&rig)
{ {
if (lef.size() != rig.size()) if (lef.size() != rig.size())
@ -1158,8 +1192,8 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
// If this is a struct type, then build the net with the // If this is a struct type, then build the net with the
// struct type. // struct type.
if (struct_type_) { if (struct_type_t*struct_type = dynamic_cast<struct_type_t*>(set_data_type_)) {
netstruct_t*use_type = elaborate_struct_type(des, scope, struct_type_); netstruct_t*use_type = elaborate_struct_type(des, scope, struct_type);
if (debug_elaborate) { if (debug_elaborate) {
cerr << get_fileline() << ": debug: Create signal " << wtype; cerr << get_fileline() << ": debug: Create signal " << wtype;
if (use_type->packed()) if (use_type->packed())
@ -1172,23 +1206,22 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
sig = new NetNet(scope, name_, wtype, use_type); sig = new NetNet(scope, name_, wtype, use_type);
} else if (enum_type_) { } else if (enum_type_t*enum_type = dynamic_cast<enum_type_t*>(set_data_type_)) {
ivl_assert(*this, struct_type_ == 0); list<named_pexpr_t>::const_iterator sample_name = enum_type->names->begin();
ivl_assert(*this, ! enum_type_->names->empty());
list<named_pexpr_t>::const_iterator sample_name = enum_type_->names->begin();
netenum_t*use_enum = scope->enumeration_for_name(sample_name->name); netenum_t*use_enum = scope->enumeration_for_name(sample_name->name);
if (debug_elaborate) { if (debug_elaborate) {
cerr << get_fileline() << ": debug: Create signal " << wtype cerr << get_fileline() << ": debug: Create signal " << wtype
<< " enumeration " << " 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); sig = new NetNet(scope, name_, wtype, packed_dimensions, unpacked_dimensions, use_enum);
} else if (netarray) { } else if (netarray) {
ivl_assert(*this, struct_type_==0);
ivl_assert(*this, enum_type_==0);
if (debug_elaborate) { if (debug_elaborate) {
cerr << get_fileline() << ": debug: Create signal " << wtype cerr << get_fileline() << ": debug: Create signal " << wtype
@ -1200,6 +1233,35 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
ivl_assert(*this, unpacked_dimensions.empty()); ivl_assert(*this, unpacked_dimensions.empty());
sig = new NetNet(scope, name_, wtype, netarray); 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.
// 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 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 { } else {
if (debug_elaborate) { if (debug_elaborate) {
cerr << get_fileline() << ": debug: Create signal " << wtype; cerr << get_fileline() << ": debug: Create signal " << wtype;

View File

@ -163,6 +163,26 @@ NetScope* Design::find_scope(const std::list<hname_t>&path) const
return 0; return 0;
} }
/*
* This method locates a scope in the design, given its rooted
* hierarchical name. Each component of the key is used to scan one
* more step down the tree until the name runs out or the search
* fails.
*/
NetScope* Design::find_scope(const hname_t&path) const
{
for (list<NetScope*>::const_iterator scope = root_scopes_.begin()
; scope != root_scopes_.end(); ++ scope ) {
NetScope*cur = *scope;
if (path.peek_name() == cur->basename())
return cur;
}
return 0;
}
/* /*
* This is a relative lookup of a scope by name. The starting point is * This is a relative lookup of a scope by name. The starting point is
* the scope parameter within which I start looking for the scope. If * the scope parameter within which I start looking for the scope. If
@ -206,6 +226,43 @@ NetScope* Design::find_scope(NetScope*scope, const std::list<hname_t>&path,
return find_scope(path); return find_scope(path);
} }
/*
* This is a relative lookup of a scope by name. The starting point is
* the scope parameter within which I start looking for the scope. If
* I do not find the scope within the passed scope, start looking in
* parent scopes until I find it, or I run out of parent scopes.
*/
NetScope* Design::find_scope(NetScope*scope, const hname_t&path,
NetScope::TYPE type) const
{
assert(scope);
for ( ; scope ; scope = scope->parent()) {
NetScope*cur = scope;
/* If we are looking for a module or we are not
* looking at the last path component check for
* a name match (second line). */
if (cur->type() == NetScope::MODULE
&& (type == NetScope::MODULE)
&& cur->module_name()==path.peek_name()) {
/* Up references may match module name */
} else {
cur = cur->child( path );
}
if (cur) return cur;
}
// Last chance. Look for the name starting at the root.
list<hname_t>path_list;
path_list.push_back(path);
return find_scope(path_list);
}
/* /*
* This method runs through the scope, noticing the defparam * This method runs through the scope, noticing the defparam
* statements that were collected during the elaborate_scope pass and * statements that were collected during the elaborate_scope pass and

View File

@ -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_(0), type_(enum_type->base_type()), enum_type_(enum_type), parms_(np)
{ {
name_ = lex_strings.add(n); name_ = lex_strings.add(n);
expr_width(enum_type->base_width()); expr_width(enum_type->packed_width());
} }
NetESFunc::~NetESFunc() NetESFunc::~NetESFunc()

View File

@ -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) 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; std::pair<std::map<perm_string,verinum>::iterator, bool> res;

View File

@ -37,7 +37,7 @@ class netenum_t : public LineInfo, public nettype_base_t {
~netenum_t(); ~netenum_t();
ivl_variable_type_t base_type() const; ivl_variable_type_t base_type() const;
unsigned base_width() const; long packed_width() const;
bool has_sign() const; bool has_sign() const;
// The size() is the number of enumeration literals. // 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 inline ivl_variable_type_t netenum_t::base_type() const
{ return base_type_; } { 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 size_t netenum_t::size() const { return names_.size(); }
inline bool netenum_t::has_sign() const { return signed_flag_; } inline bool netenum_t::has_sign() const { return signed_flag_; }

View File

@ -476,6 +476,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins)
// Synthesize a single range to describe this canonical vector. // Synthesize a single range to describe this canonical vector.
packed_dims_.push_back(netrange_t(npins-1, 0)); packed_dims_.push_back(netrange_t(npins-1, 0));
calculate_slice_widths_from_packed_dims_();
Link::DIR dir = Link::PASSIVE; Link::DIR dir = Link::PASSIVE;
@ -521,6 +522,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
eref_count_(0), lref_count_(0) eref_count_(0), lref_count_(0)
{ {
packed_dims_ = packed; packed_dims_ = packed;
calculate_slice_widths_from_packed_dims_();
assert(s); assert(s);
Link::DIR dir = Link::PASSIVE; Link::DIR dir = Link::PASSIVE;
@ -564,6 +566,32 @@ static unsigned calculate_count(const list<netrange_t>&unpacked)
return sum; 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, NetNet::NetNet(NetScope*s, perm_string n, Type t,
const list<netrange_t>&packed, const list<netrange_t>&packed,
const list<netrange_t>&unpacked, const list<netrange_t>&unpacked,
@ -576,6 +604,9 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
eref_count_(0), lref_count_(0) eref_count_(0), lref_count_(0)
{ {
packed_dims_ = packed; 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; size_t idx = 0;
for (list<netrange_t>::const_iterator cur = unpacked.begin() for (list<netrange_t>::const_iterator cur = unpacked.begin()
; cur != unpacked.end() ; ++cur, idx += 1) { ; cur != unpacked.end() ; ++cur, idx += 1) {
@ -611,15 +642,6 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
s->add_signal(this); s->add_signal(this);
} }
static unsigned calculate_count(netstruct_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 * 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 * 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) eref_count_(0), lref_count_(0)
{ {
packed_dims_.push_back(netrange_t(calculate_count(ty)-1, 0)); packed_dims_.push_back(netrange_t(calculate_count(ty)-1, 0));
calculate_slice_widths_from_packed_dims_();
Link::DIR dir = Link::PASSIVE; Link::DIR dir = Link::PASSIVE;
switch (t) { switch (t) {
@ -820,6 +843,25 @@ netdarray_t* NetNet::darray_type(void) const
return dynamic_cast<netdarray_t*> (net_type_); return dynamic_cast<netdarray_t*> (net_type_);
} }
/*
* "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
{
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 ivl_discipline_t NetNet::get_discipline() const
{ {
return discipline_; return discipline_;

View File

@ -77,6 +77,7 @@ class NetEvWait;
class PExpr; class PExpr;
class PFunction; class PFunction;
class netdarray_t; class netdarray_t;
class netparray_t;
class netenum_t; class netenum_t;
class netstruct_t; class netstruct_t;
@ -614,6 +615,7 @@ class NetNet : public NetObj, public PortType {
// This form builds a NetNet from its record/enum definition. // 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, netstruct_t*type);
explicit NetNet(NetScope*s, perm_string n, Type t, netdarray_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(); virtual ~NetNet();
@ -662,7 +664,7 @@ class NetNet : public NetObj, public PortType {
/* The vector_width returns the bit width of the packed array, /* The vector_width returns the bit width of the packed array,
vector or scaler that is this NetNet object. */ vector or scaler that is this NetNet object. */
unsigned long vector_width() const { return netrange_width(packed_dims_); } inline unsigned long vector_width() const { return slice_width(0); }
/* Given a prefix of indices, figure out how wide the /* Given a prefix of indices, figure out how wide the
resulting slice would be. This is a generalization of 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.) */ indices. (Currently only one array index is supported.) */
inline unsigned unpacked_dimensions() const { return unpacked_dims_.size(); } 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. // This is the number of array elements.
unsigned unpacked_count() const; unsigned unpacked_count() const;
@ -738,6 +744,14 @@ class NetNet : public NetObj, public PortType {
std::list<netrange_t> packed_dims_; std::list<netrange_t> packed_dims_;
std::vector<netrange_t> unpacked_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 eref_count_;
unsigned lref_count_; unsigned lref_count_;
@ -4161,6 +4175,12 @@ class Design {
path is taken as an absolute scope name. Otherwise, the path is taken as an absolute scope name. Otherwise, the
scope is located starting at the passed scope and working scope is located starting at the passed scope and working
up if needed. */ up if needed. */
NetScope* find_scope(const hname_t&path) const;
NetScope* find_scope(NetScope*, const hname_t&name,
NetScope::TYPE type = NetScope::MODULE) const;
// Note: Try to remove these versions of find_scope. Avoid
// using these in new code, use the above forms (or
// symbol_search) instead.
NetScope* find_scope(const std::list<hname_t>&path) const; NetScope* find_scope(const std::list<hname_t>&path) const;
NetScope* find_scope(NetScope*, const std::list<hname_t>&path, NetScope* find_scope(NetScope*, const std::list<hname_t>&path,
NetScope::TYPE type = NetScope::MODULE) const; NetScope::TYPE type = NetScope::MODULE) const;

View File

@ -180,6 +180,21 @@ static NetExpr* make_add_expr(NetExpr*expr, long val)
return res; 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. * 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; if (is_up) offset -= wid - 1;
/* Calculate the space needed for the offset. */ /* Calculate the space needed for the offset. */
unsigned min_wid = num_bits(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 /* We need enough space for the larger of the offset or the
* base expression. */ * base expression. */
if (min_wid < base->expr_width()) min_wid = base->expr_width(); 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; if ((soff-offset) == 0) return base;
/* Calculate the space needed for the offset. */ /* Calculate the space needed for the offset. */
unsigned min_wid = num_bits(-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 /* We need enough space for the larger of the offset or the
* base expression. */ * base expression. */
if (min_wid < base->expr_width()) min_wid = base->expr_width(); if (min_wid < base->expr_width()) min_wid = base->expr_width();
@ -835,7 +854,8 @@ bool eval_as_double(double&value, NetExpr*expr)
* expression if it is present. * expression if it is present.
*/ */
hname_t eval_path_component(Design*des, NetScope*scope, hname_t eval_path_component(Design*des, NetScope*scope,
const name_component_t&comp) const name_component_t&comp,
bool&error_flag)
{ {
// No index expression, so the path component is an undecorated // No index expression, so the path component is an undecorated
// name, for example "foo". // name, for example "foo".
@ -873,6 +893,7 @@ hname_t eval_path_component(Design*des, NetScope*scope,
return res; return res;
} }
#if 1
// Darn, the expression doesn't evaluate to a constant. That's // Darn, the expression doesn't evaluate to a constant. That's
// an error to be reported. And make up a fake index value to // an error to be reported. And make up a fake index value to
// return to the caller. // return to the caller.
@ -880,6 +901,8 @@ hname_t eval_path_component(Design*des, NetScope*scope,
<< "Scope index expression is not constant: " << "Scope index expression is not constant: "
<< *index.msb << endl; << *index.msb << endl;
des->errors += 1; des->errors += 1;
#endif
error_flag = true;
delete tmp; delete tmp;
return hname_t (comp.name, 0); 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, std::list<hname_t> eval_scope_path(Design*des, NetScope*scope,
const pform_name_t&path) const pform_name_t&path)
{ {
bool path_error_flag = false;
list<hname_t> res; list<hname_t> res;
typedef pform_name_t::const_iterator pform_path_it; typedef pform_name_t::const_iterator pform_path_it;
for (pform_path_it cur = path.begin() ; cur != path.end(); ++ cur ) { for (pform_path_it cur = path.begin() ; cur != path.end(); ++ cur ) {
const name_component_t&comp = *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; return res;
} }
@ -1127,3 +1155,85 @@ bool evaluate_index_prefix(Design*des, NetScope*scope,
return true; 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
* 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);
eval_expr(res, -1);
return res;
}

View File

@ -256,18 +256,14 @@ void eval_expr(NetExpr*&expr, int context_width =-1);
bool eval_as_long(long&value, NetExpr*expr); bool eval_as_long(long&value, NetExpr*expr);
bool eval_as_double(double&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. * Evaluate an entire scope path in the context of the given scope.
*/ */
extern std::list<hname_t> eval_scope_path(Design*des, NetScope*scope, extern std::list<hname_t> eval_scope_path(Design*des, NetScope*scope,
const pform_name_t&path); const pform_name_t&path);
extern hname_t eval_path_component(Design*des, NetScope*scope,
const name_component_t&comp,
bool&error_flag);
/* /*
* Return true if the data type is a type that is normally available * Return true if the data type is a type that is normally available
@ -310,4 +306,12 @@ extern void collapse_partselect_pv_to_concat(Design*des, NetNet*sig);
extern bool evaluate_index_prefix(Design*des, NetScope*scope, extern bool evaluate_index_prefix(Design*des, NetScope*scope,
list<long>&prefix_indices, list<long>&prefix_indices,
const list<index_component_t>&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);
extern NetExpr*collapse_array_exprs(Design*des, NetScope*scope,
const LineInfo*loc, NetNet*net,
const list<index_component_t>&indices);
#endif #endif

View File

@ -17,31 +17,36 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/ */
# include "LineInfo.h" # include "LineInfo.h"
# include "nettypes.h"
# include <vector> # include <vector>
class netarray_t : public LineInfo { /*
* Packed arrays.
*/
class netparray_t : public nettype_base_t, public LineInfo {
public: public:
explicit netarray_t(const std::list<netrange_t>&packed); explicit netparray_t(const std::list<netrange_t>&packed);
~netarray_t(); ~netparray_t();
unsigned packed_width() const; inline const std::list<netrange_t>& packed_dimensions() const
{ return packed_dims_; }
private: private:
std::list<netrange_t> packed_dims_; std::list<netrange_t> packed_dims_;
}; };
inline netarray_t::netarray_t(const std::list<netrange_t>&packed) inline netparray_t::netparray_t(const std::list<netrange_t>&packed)
: packed_dims_(packed) : packed_dims_(packed)
{ {
} }
netarray_t::~netarray_t() inline netparray_t::~netparray_t()
{ {
} }

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 long netrange_width(const list<netrange_t>&packed)
{ {
unsigned wid = 1; unsigned wid = 1;

View File

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

111
parse.y
View File

@ -2,6 +2,7 @@
%{ %{
/* /*
* Copyright (c) 1998-2012 Stephen Williams (steve@icarus.com) * Copyright (c) 1998-2012 Stephen Williams (steve@icarus.com)
* Copyright CERN 2012 / Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -566,7 +567,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
%type <nettype> net_type var_type net_type_opt %type <nettype> net_type var_type net_type_opt
%type <gatetype> gatetype switchtype %type <gatetype> gatetype switchtype
%type <porttype> port_direction port_direction_opt %type <porttype> port_direction port_direction_opt
%type <vartype> primitive_type primitive_type_opt bit_logic %type <vartype> bit_logic
%type <vartype> integer_vector_type %type <vartype> integer_vector_type
%type <parmvalue> parameter_value_opt %type <parmvalue> parameter_value_opt
@ -894,7 +895,7 @@ data_type /* IEEE1800-2005: A.2.2.1 */
$$ = tmp; $$ = tmp;
} }
| TYPE_IDENTIFIER range_opt | TYPE_IDENTIFIER range_opt
{ if ($2) $$ = new array_type_t($1, $2); { if ($2) $$ = new parray_type_t($1, $2);
else $$ = $1; else $$ = $1;
} }
| K_string | K_string
@ -1842,11 +1843,11 @@ block_item_decl
recovering from an error. */ recovering from an error. */
| data_type register_variable_list ';' | data_type register_variable_list ';'
{ if ($1) pform_set_data_type(@1, $1, $2, attributes_in_context); { if ($1) pform_set_data_type(@1, $1, $2, NetNet::REG, attributes_in_context);
} }
| K_reg data_type register_variable_list ';' | K_reg data_type register_variable_list ';'
{ if ($2) pform_set_data_type(@2, $2, $3, attributes_in_context); { if ($2) pform_set_data_type(@2, $2, $3, NetNet::REG, attributes_in_context);
} }
| K_event list_of_identifiers ';' | K_event list_of_identifiers ';'
@ -3891,31 +3892,24 @@ module_item
/* Modules can contain further sub-module definitions. */ /* Modules can contain further sub-module definitions. */
: module : module
/* This rule detects net declarations that possibly include a | attribute_list_opt net_type data_type_or_implicit delay3_opt net_variable_list ';'
primitive type, an optional vector range and signed flag. This
also includes an optional delay set. The values are then applied
to a list of names. If the primitive type is not specified, then
resort to the default type LOGIC. */
| attribute_list_opt net_type { data_type_t*data_type = $3;
primitive_type_opt unsigned_signed_opt range_opt if (data_type == 0) {
delay3_opt data_type = new vector_type_t(IVL_VT_LOGIC, false, 0);
net_variable_list ';' FILE_NAME(data_type, @2);
}
{ ivl_variable_type_t dtype = $3; pform_set_data_type(@2, data_type, $5, $2, $1);
if (dtype == IVL_VT_NO_TYPE) if ($4 != 0) {
dtype = IVL_VT_LOGIC; yyerror(@2, "sorry: net delays not supported.");
pform_makewire(@2, $5, $4, $7, $2, NetNet::NOT_A_PORT, dtype, $1); delete $4;
if ($6 != 0) {
yyerror(@6, "sorry: net delays not supported.");
delete $6;
} }
delete $1; delete $1;
} }
| attribute_list_opt K_wreal delay3 net_variable_list ';' | attribute_list_opt K_wreal delay3 net_variable_list ';'
{ pform_makewire(@2, 0, true, $4, NetNet::WIRE, { real_type_t*tmpt = new real_type_t(real_type_t::REAL);
NetNet::NOT_A_PORT, IVL_VT_REAL, $1); pform_set_data_type(@2, tmpt, $4, NetNet::WIRE, $1);
if ($3 != 0) { if ($3 != 0) {
yyerror(@3, "sorry: net delays not supported."); yyerror(@3, "sorry: net delays not supported.");
delete $3; delete $3;
@ -3924,8 +3918,8 @@ module_item
} }
| attribute_list_opt K_wreal net_variable_list ';' | attribute_list_opt K_wreal net_variable_list ';'
{ pform_makewire(@2, 0, true, $3, NetNet::WIRE, { real_type_t*tmpt = new real_type_t(real_type_t::REAL);
NetNet::NOT_A_PORT, IVL_VT_REAL, $1); pform_set_data_type(@2, tmpt, $3, NetNet::WIRE, $1);
delete $1; delete $1;
} }
@ -3933,15 +3927,13 @@ module_item
net_decl_assigns, which are <name> = <expr> assignment net_decl_assigns, which are <name> = <expr> assignment
declarations. */ declarations. */
| attribute_list_opt net_type | attribute_list_opt net_type data_type_or_implicit delay3_opt net_decl_assigns ';'
primitive_type_opt unsigned_signed_opt range_opt { data_type_t*data_type = $3;
delay3_opt net_decl_assigns ';' if (data_type == 0) {
data_type = new vector_type_t(IVL_VT_LOGIC, false, 0);
{ ivl_variable_type_t dtype = $3; FILE_NAME(data_type, @2);
if (dtype == IVL_VT_NO_TYPE) }
dtype = IVL_VT_LOGIC; pform_makewire(@2, $4, str_strength, $5, $2, data_type);
pform_makewire(@2, $5, $4, $6,
str_strength, $7, $2, dtype);
if ($1) { if ($1) {
yyerror(@2, "sorry: Attributes not supported " yyerror(@2, "sorry: Attributes not supported "
"on net declaration assignments."); "on net declaration assignments.");
@ -3949,42 +3941,26 @@ module_item
} }
} }
/* Allow struct nets. */
| attribute_list_opt net_type struct_data_type net_variable_list ';'
{ pform_makewire(@2, $3, NetNet::NOT_A_PORT, $4, $1);
delete $1;
}
| attribute_list_opt net_type struct_data_type error ';'
{ yyerror(@5, "error: Errors in net variable list.");
}
| attribute_list_opt net_type TYPE_IDENTIFIER net_variable_list ';'
{ yyerror(@2, "sorry: Nets of named types not supported."); }
/* This form doesn't have the range, but does have strengths. This /* This form doesn't have the range, but does have strengths. This
gives strength to the assignment drivers. */ gives strength to the assignment drivers. */
| attribute_list_opt net_type | attribute_list_opt net_type data_type_or_implicit drive_strength net_decl_assigns ';'
primitive_type_opt unsigned_signed_opt { data_type_t*data_type = $3;
drive_strength net_decl_assigns ';' if (data_type == 0) {
data_type = new vector_type_t(IVL_VT_LOGIC, false, 0);
{ ivl_variable_type_t dtype = $3; FILE_NAME(data_type, @2);
if (dtype == IVL_VT_NO_TYPE) }
dtype = IVL_VT_LOGIC; pform_makewire(@2, 0, $4, $5, $2, data_type);
pform_makewire(@2, 0, $4, 0, $5, $6, $2, dtype);
if ($1) { if ($1) {
yyerror(@2, "sorry: Attributes not supported " yyerror(@2, "sorry: Attributes not supported "
"on net declaration assignments."); "on net declaration assignments.");
delete $1; delete $1;
} }
} }
| attribute_list_opt K_wreal net_decl_assigns ';' | attribute_list_opt K_wreal net_decl_assigns ';'
{ pform_makewire(@2, 0, true, 0, str_strength, $3, { real_type_t*data_type = new real_type_t(real_type_t::REAL);
NetNet::WIRE, IVL_VT_REAL); pform_makewire(@2, 0, str_strength, $3, NetNet::WIRE, data_type);
if ($1) { if ($1) {
yyerror(@2, "sorry: Attributes not supported " yyerror(@2, "sorry: Attributes not supported "
"on net declaration assignments."); "on net declaration assignments.");
@ -4369,20 +4345,11 @@ net_decl_assigns
} }
; ;
primitive_type
: K_logic { $$ = IVL_VT_LOGIC; }
| K_bool { $$ = IVL_VT_BOOL; /* Icarus Verilog xtypes */}
| K_bit { $$ = IVL_VT_BOOL; /* IEEE1800 / IEEE1364-2009 */}
| K_real { $$ = IVL_VT_REAL; }
;
bit_logic bit_logic
: K_logic { $$ = IVL_VT_LOGIC; } : K_logic { $$ = IVL_VT_LOGIC; }
| K_bit { $$ = IVL_VT_BOOL; /* IEEE1800 / IEEE1364-2009 */} | K_bit { $$ = IVL_VT_BOOL; /* IEEE1800 / IEEE1364-2009 */}
; ;
primitive_type_opt : primitive_type { $$ = $1; } | { $$ = IVL_VT_NO_TYPE; } ;
net_type net_type
: K_wire { $$ = NetNet::WIRE; } : K_wire { $$ = NetNet::WIRE; }
| K_tri { $$ = NetNet::TRI; } | K_tri { $$ = NetNet::TRI; }
@ -4890,10 +4857,10 @@ function_range_or_type_opt
so that bit ranges can be assigned. */ so that bit ranges can be assigned. */
register_variable register_variable
: IDENTIFIER dimensions_opt : IDENTIFIER dimensions_opt
{ perm_string ident_name = lex_strings.make($1); { perm_string name = lex_strings.make($1);
pform_makewire(@1, ident_name, NetNet::REG, pform_makewire(@1, name, NetNet::REG,
NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0); NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0);
pform_set_reg_idx(ident_name, $2); pform_set_reg_idx(name, $2);
$$ = $1; $$ = $1;
} }
| IDENTIFIER '=' expression | IDENTIFIER '=' expression

190
pform.cc
View File

@ -1563,6 +1563,7 @@ void pform_make_udp(perm_string name, bool synchronous_flag,
* and the name that I receive only has the tail component. * and the name that I receive only has the tail component.
*/ */
static void pform_set_net_range(perm_string name, static void pform_set_net_range(perm_string name,
NetNet::Type net_type,
const list<pform_range_t>*range, const list<pform_range_t>*range,
bool signed_flag, bool signed_flag,
ivl_variable_type_t dt, ivl_variable_type_t dt,
@ -1574,6 +1575,19 @@ static void pform_set_net_range(perm_string name,
VLerror("error: name is not a valid net."); VLerror("error: name is not a valid net.");
return; return;
} }
// If this is not implicit ("implicit" meaning we don't
// know what the type is yet) then set the type now.
if (net_type != NetNet::IMPLICIT && net_type != NetNet::NONE) {
bool rc = cur->set_wire_type(net_type);
if (rc == false) {
ostringstream msg;
msg << name << " " << net_type
<< " definition conflicts with " << cur->get_wire_type()
<< " definition at " << cur->get_fileline()
<< ".";
VLerror(msg.str().c_str());
}
}
if (range == 0) { if (range == 0) {
/* This is the special case that we really mean a /* This is the special case that we really mean a
@ -1591,16 +1605,17 @@ static void pform_set_net_range(perm_string name,
pform_bind_attributes(cur->attributes, attr, true); pform_bind_attributes(cur->attributes, attr, true);
} }
void pform_set_net_range(list<perm_string>*names, static void pform_set_net_range(list<perm_string>*names,
list<pform_range_t>*range, list<pform_range_t>*range,
bool signed_flag, bool signed_flag,
ivl_variable_type_t dt, ivl_variable_type_t dt,
NetNet::Type net_type,
std::list<named_pexpr_t>*attr) std::list<named_pexpr_t>*attr)
{ {
for (list<perm_string>::iterator cur = names->begin() for (list<perm_string>::iterator cur = names->begin()
; cur != names->end() ; ++ cur ) { ; cur != names->end() ; ++ cur ) {
perm_string txt = *cur; perm_string txt = *cur;
pform_set_net_range(txt, range, signed_flag, dt, SR_NET, attr); pform_set_net_range(txt, net_type, range, signed_flag, dt, SR_NET, attr);
} }
delete names; delete names;
@ -1997,7 +2012,7 @@ void pform_module_define_port(const struct vlltype&li,
} }
} else if ((struct_type = dynamic_cast<struct_type_t*>(vtype))) { } else if ((struct_type = dynamic_cast<struct_type_t*>(vtype))) {
data_type = figure_struct_base_type(struct_type); data_type = struct_type->figure_packed_base_type();
signed_flag = false; signed_flag = false;
range = 0; range = 0;
@ -2017,7 +2032,7 @@ void pform_module_define_port(const struct vlltype&li,
cur->set_signed(signed_flag); cur->set_signed(signed_flag);
if (struct_type) { if (struct_type) {
cur->set_struct_type(struct_type); cur->set_packed_type(struct_type);
} else if (range == 0) { } else if (range == 0) {
cur->set_range_scalar((type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH); cur->set_range_scalar((type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH);
@ -2144,7 +2159,7 @@ void pform_makewire(const vlltype&li,
pform_makewire(li, txt, type, pt, dt, attr); pform_makewire(li, txt, type, pt, dt, attr);
/* This has already been done for real variables. */ /* This has already been done for real variables. */
if (dt != IVL_VT_REAL) { if (dt != IVL_VT_REAL) {
pform_set_net_range(txt, range, signed_flag, dt, rt, 0); pform_set_net_range(txt, type, range, signed_flag, dt, rt, 0);
} }
} }
@ -2156,27 +2171,31 @@ void pform_makewire(const vlltype&li,
* This form makes nets with delays and continuous assignments. * This form makes nets with delays and continuous assignments.
*/ */
void pform_makewire(const vlltype&li, void pform_makewire(const vlltype&li,
list<pform_range_t>*range,
bool signed_flag,
list<PExpr*>*delay, list<PExpr*>*delay,
str_pair_t str, str_pair_t str,
net_decl_assign_t*decls, net_decl_assign_t*decls,
NetNet::Type type, NetNet::Type type,
ivl_variable_type_t dt) data_type_t*data_type)
{ {
// The decls pointer is a circularly linked list.
net_decl_assign_t*first = decls->next; net_decl_assign_t*first = decls->next;
decls->next = 0;
list<perm_string>*names = new list<perm_string>;
// Go through the circularly linked list non-destructively.
do {
pform_makewire(li, first->name, type, NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0);
names->push_back(first->name);
first = first->next;
} while (first != decls->next);
pform_set_data_type(li, data_type, names, type, 0);
// This time, go through the list, deleting cells as I'm done.
first = decls->next;
decls->next = 0;
while (first) { while (first) {
net_decl_assign_t*next = first->next; net_decl_assign_t*next = first->next;
pform_makewire(li, first->name, type, NetNet::NOT_A_PORT, dt, 0);
/* This has already been done for real variables. */
if (dt != IVL_VT_REAL) {
pform_set_net_range(first->name, range, signed_flag, dt,
SR_NET, 0);
}
PWire*cur = pform_get_wire_in_scope(first->name); PWire*cur = pform_get_wire_in_scope(first->name);
if (cur != 0) { if (cur != 0) {
PEIdent*lval = new PEIdent(first->name); PEIdent*lval = new PEIdent(first->name);
@ -2705,7 +2724,7 @@ void pform_set_port_type(const struct vlltype&li,
; cur != names->end() ; ++ cur ) { ; cur != names->end() ; ++ cur ) {
perm_string txt = *cur; perm_string txt = *cur;
pform_set_port_type(txt, pt, li.text, li.first_line); pform_set_port_type(txt, pt, li.text, li.first_line);
pform_set_net_range(txt, range, signed_flag, IVL_VT_NO_TYPE, pform_set_net_range(txt, NetNet::NONE, range, signed_flag, IVL_VT_NO_TYPE,
SR_PORT, 0); SR_PORT, 0);
} }
@ -2764,9 +2783,9 @@ void pform_set_reg_time(list<perm_string>*names, list<named_pexpr_t>*attr)
delete names; delete names;
} }
static void pform_set_integer_2atom(uint64_t width, bool signed_flag, perm_string name, list<named_pexpr_t>*attr) static void pform_set_integer_2atom(uint64_t width, bool signed_flag, perm_string name, NetNet::Type net_type, list<named_pexpr_t>*attr)
{ {
PWire*cur = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_BOOL); PWire*cur = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, IVL_VT_BOOL);
assert(cur); assert(cur);
cur->set_signed(signed_flag); cur->set_signed(signed_flag);
@ -2780,84 +2799,56 @@ static void pform_set_integer_2atom(uint64_t width, bool signed_flag, perm_strin
pform_bind_attributes(cur->attributes, attr, true); pform_bind_attributes(cur->attributes, attr, true);
} }
static void pform_set_integer_2atom(uint64_t width, bool signed_flag, list<perm_string>*names, list<named_pexpr_t>*attr) static void pform_set_integer_2atom(uint64_t width, bool signed_flag, list<perm_string>*names, NetNet::Type net_type, list<named_pexpr_t>*attr)
{ {
for (list<perm_string>::iterator cur = names->begin() for (list<perm_string>::iterator cur = names->begin()
; cur != names->end() ; ++ cur ) { ; cur != names->end() ; ++ cur ) {
perm_string txt = *cur; perm_string txt = *cur;
pform_set_integer_2atom(width, signed_flag, txt, attr); pform_set_integer_2atom(width, signed_flag, txt, net_type, attr);
} }
delete names; delete names;
} }
/* template <class T> static void pform_set2_data_type(const struct vlltype&li, T*data_type, perm_string name, NetNet::Type net_type, list<named_pexpr_t>*attr)
* This function detects the derived class for the given type and
* dispatches the type to the proper subtype function.
*/
void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list<perm_string>*names, list<named_pexpr_t>*attr)
{ {
if (atom2_type_t*atom2_type = dynamic_cast<atom2_type_t*> (data_type)) { ivl_variable_type_t base_type = data_type->figure_packed_base_type();
pform_set_integer_2atom(atom2_type->type_code, atom2_type->signed_flag, names, attr); if (base_type == IVL_VT_NO_TYPE) {
return; VLerror(li, "Compound type is not PACKED in this context.");
} }
if (struct_type_t*struct_type = dynamic_cast<struct_type_t*> (data_type)) { PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, base_type);
pform_set_struct_type(struct_type, names, attr); net->set_packed_type(data_type);
return; pform_bind_attributes(net->attributes, attr, true);
} }
if (enum_type_t*enum_type = dynamic_cast<enum_type_t*> (data_type)) { template <class T> static void pform_set2_data_type(const struct vlltype&li, T*data_type, list<perm_string>*names, NetNet::Type net_type, list<named_pexpr_t>*attr)
pform_set_enum(li, enum_type, names, attr); {
return; for (list<perm_string>::iterator cur = names->begin()
; cur != names->end() ; ++ cur) {
pform_set2_data_type(li, data_type, *cur, net_type, attr);
} }
if (vector_type_t*vec_type = dynamic_cast<vector_type_t*> (data_type)) {
pform_set_net_range(names, vec_type->pdims.get(),
vec_type->signed_flag,
vec_type->base_type, attr);
return;
}
if (/*real_type_t*real_type =*/ dynamic_cast<real_type_t*> (data_type)) {
pform_set_net_range(names, 0, true, IVL_VT_REAL, attr);
return;
}
if (/*class_type_t*class_type =*/ dynamic_cast<class_type_t*> (data_type)) {
VLerror(li, "sorry: Class types not supported.");
return;
}
if (/*array_type_t*array_type = */ dynamic_cast<array_type_t*> (data_type)) {
VLerror(li, "sorry: General array types not supported.");
return;
}
if (string_type_t*string_type = dynamic_cast<string_type_t*> (data_type)) {
pform_set_string_type(string_type, names, attr);
return;
}
assert(0);
} }
static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type,
perm_string name, std::list<named_pexpr_t>*attr) perm_string name, NetNet::Type net_type,
std::list<named_pexpr_t>*attr)
{ {
(void) li; // The line information is not currently needed. (void) li; // The line information is not currently needed.
PWire*cur = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, enum_type->base_type); PWire*cur = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, enum_type->base_type);
assert(cur); assert(cur);
cur->set_signed(enum_type->signed_flag); cur->set_signed(enum_type->signed_flag);
assert(enum_type->range.get() != 0); assert(enum_type->range.get() != 0);
assert(enum_type->range->size() == 1); assert(enum_type->range->size() == 1);
cur->set_range(*enum_type->range, SR_NET); //XXXXcur->set_range(*enum_type->range, SR_NET);
cur->set_enumeration(enum_type); cur->set_packed_type(enum_type);
pform_bind_attributes(cur->attributes, attr, true); pform_bind_attributes(cur->attributes, attr, true);
} }
void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, list<perm_string>*names, std::list<named_pexpr_t>*attr) static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type,
list<perm_string>*names, NetNet::Type net_type,
std::list<named_pexpr_t>*attr)
{ {
// By definition, the base type can only be IVL_VT_LOGIC or // By definition, the base type can only be IVL_VT_LOGIC or
// IVL_VT_BOOL. // IVL_VT_BOOL.
@ -2877,12 +2868,69 @@ void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, list<perm_st
for (list<perm_string>::iterator cur = names->begin() for (list<perm_string>::iterator cur = names->begin()
; cur != names->end() ; ++ cur) { ; cur != names->end() ; ++ cur) {
perm_string txt = *cur; perm_string txt = *cur;
pform_set_enum(li, enum_type, txt, attr); pform_set_enum(li, enum_type, txt, net_type, attr);
} }
delete names; delete names;
} }
/*
* This function detects the derived class for the given type and
* dispatches the type to the proper subtype function.
*/
void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list<perm_string>*names, NetNet::Type net_type, list<named_pexpr_t>*attr)
{
if (data_type == 0) {
VLerror(li, "internal error: data_type==0.");
assert(0);
}
if (atom2_type_t*atom2_type = dynamic_cast<atom2_type_t*> (data_type)) {
pform_set_integer_2atom(atom2_type->type_code, atom2_type->signed_flag, names, net_type, attr);
return;
}
if (struct_type_t*struct_type = dynamic_cast<struct_type_t*> (data_type)) {
pform_set_struct_type(struct_type, names, net_type, attr);
return;
}
if (enum_type_t*enum_type = dynamic_cast<enum_type_t*> (data_type)) {
pform_set_enum(li, enum_type, names, net_type, attr);
return;
}
if (vector_type_t*vec_type = dynamic_cast<vector_type_t*> (data_type)) {
pform_set_net_range(names, vec_type->pdims.get(),
vec_type->signed_flag,
vec_type->base_type, net_type, attr);
return;
}
if (/*real_type_t*real_type =*/ dynamic_cast<real_type_t*> (data_type)) {
pform_set_net_range(names, 0, true, IVL_VT_REAL, net_type, attr);
return;
}
if (/*class_type_t*class_type =*/ dynamic_cast<class_type_t*> (data_type)) {
VLerror(li, "sorry: Class types not supported.");
return;
}
if (parray_type_t*array_type = dynamic_cast<parray_type_t*> (data_type)) {
pform_set2_data_type(li, array_type, names, net_type, attr);
return;
}
if (string_type_t*string_type = dynamic_cast<string_type_t*> (data_type)) {
pform_set_string_type(string_type, names, net_type, attr);
return;
}
VLerror(li, "internal error: Unexpected data_type.");
assert(0);
}
svector<PWire*>* pform_make_udp_input_ports(list<perm_string>*names) svector<PWire*>* pform_make_udp_input_ports(list<perm_string>*names)
{ {
svector<PWire*>*out = new svector<PWire*>(names->size()); svector<PWire*>*out = new svector<PWire*>(names->size());

19
pform.h
View File

@ -265,13 +265,11 @@ extern void pform_makewire(const struct vlltype&li,
/* This form handles assignment declarations. */ /* This form handles assignment declarations. */
extern void pform_makewire(const struct vlltype&li, extern void pform_makewire(const struct vlltype&li,
list<pform_range_t>*range,
bool signed_flag,
list<PExpr*>*delay, list<PExpr*>*delay,
str_pair_t str, str_pair_t str,
net_decl_assign_t*assign_list, net_decl_assign_t*assign_list,
NetNet::Type type, NetNet::Type type,
ivl_variable_type_t); data_type_t*data_type);
/* This form handles nets declared as structures. (See pform_struct_type.cc) */ /* This form handles nets declared as structures. (See pform_struct_type.cc) */
extern void pform_makewire(const struct vlltype&li, extern void pform_makewire(const struct vlltype&li,
@ -292,25 +290,16 @@ extern void pform_set_port_type(const struct vlltype&li,
bool signed_flag, bool signed_flag,
NetNet::PortType); NetNet::PortType);
extern void pform_set_net_range(list<perm_string>*names,
list<pform_range_t>*,
bool signed_flag,
ivl_variable_type_t,
std::list<named_pexpr_t>*attr);
extern void pform_set_reg_idx(perm_string name, extern void pform_set_reg_idx(perm_string name,
std::list<pform_range_t>*indices); std::list<pform_range_t>*indices);
extern void pform_set_reg_integer(list<perm_string>*names, list<named_pexpr_t>*attr); extern void pform_set_reg_integer(list<perm_string>*names, list<named_pexpr_t>*attr);
extern void pform_set_reg_time(list<perm_string>*names, list<named_pexpr_t>*attr); extern void pform_set_reg_time(list<perm_string>*names, list<named_pexpr_t>*attr);
//XXXXextern void pform_set_integer_2atom(uint64_t width, bool signed_flag, list<perm_string>*names); extern void pform_set_data_type(const struct vlltype&li, data_type_t*, list<perm_string>*names, NetNet::Type net_type, list<named_pexpr_t>*attr);
extern void pform_set_data_type(const struct vlltype&li, data_type_t*, list<perm_string>*names, list<named_pexpr_t>*attr); extern void pform_set_struct_type(struct_type_t*struct_type, std::list<perm_string>*names, NetNet::Type net_type, std::list<named_pexpr_t>*attr);
extern void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, list<perm_string>*names, std::list<named_pexpr_t>*attr); extern void pform_set_string_type(string_type_t*string_type, std::list<perm_string>*names, NetNet::Type net_type, std::list<named_pexpr_t>*attr);
extern void pform_set_struct_type(struct_type_t*struct_type, std::list<perm_string>*names, std::list<named_pexpr_t>*attr);
extern void pform_set_string_type(string_type_t*string_type, std::list<perm_string>*names, std::list<named_pexpr_t>*attr);
/* pform_set_attrib and pform_set_type_attrib exist to support the /* pform_set_attrib and pform_set_type_attrib exist to support the
$attribute syntax, which can only set string values to $attribute syntax, which can only set string values to

View File

@ -146,6 +146,13 @@ void data_type_t::pform_dump(ostream&out, unsigned indent) const
out << setw(indent) << "" << typeid(*this).name() << endl; 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, static void dump_attributes_map(ostream&out,
const map<perm_string,PExpr*>&attributes, const map<perm_string,PExpr*>&attributes,
int ind) int ind)
@ -391,6 +398,10 @@ void PWire::dump(ostream&out, unsigned ind) const
} }
out << ";" << endl; out << ";" << endl;
if (set_data_type_) {
set_data_type_->pform_dump(out, 8);
}
dump_attributes_map(out, attributes, 8); dump_attributes_map(out, attributes, 8);
} }

View File

@ -21,17 +21,17 @@
# include "parse_misc.h" # include "parse_misc.h"
# include "ivl_assert.h" # include "ivl_assert.h"
static void pform_set_string_type(string_type_t*string_type, perm_string name, list<named_pexpr_t>*attr) static void pform_set_string_type(string_type_t*string_type, perm_string name, NetNet::Type net_type, list<named_pexpr_t>*attr)
{ {
PWire*net = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_STRING); PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, IVL_VT_STRING);
pform_bind_attributes(net->attributes, attr, true); pform_bind_attributes(net->attributes, attr, true);
} }
void pform_set_string_type(string_type_t*string_type, list<perm_string>*names, list<named_pexpr_t>*attr) void pform_set_string_type(string_type_t*string_type, list<perm_string>*names, NetNet::Type net_type, list<named_pexpr_t>*attr)
{ {
for (list<perm_string>::iterator cur = names->begin() for (list<perm_string>::iterator cur = names->begin()
; cur != names->end() ; ++ cur) { ; cur != names->end() ; ++ cur) {
pform_set_string_type(string_type, *cur, attr); pform_set_string_type(string_type, *cur, net_type, attr);
} }
} }

View File

@ -21,12 +21,15 @@
# include "parse_misc.h" # include "parse_misc.h"
# include "ivl_assert.h" # include "ivl_assert.h"
ivl_variable_type_t figure_struct_base_type(struct_type_t*struct_type) ivl_variable_type_t struct_type_t::figure_packed_base_type(void) const
{ {
if (! packed_flag)
return IVL_VT_NO_TYPE;
ivl_variable_type_t base_type = IVL_VT_BOOL; ivl_variable_type_t base_type = IVL_VT_BOOL;
for (list<struct_member_t*>::iterator cur = struct_type->members->begin() for (list<struct_member_t*>::iterator cur = members->begin()
; cur != struct_type->members->end() ; ++ cur) { ; cur != members->end() ; ++ cur) {
struct_member_t*tmp = *cur; struct_member_t*tmp = *cur;
@ -48,19 +51,19 @@ ivl_variable_type_t figure_struct_base_type(struct_type_t*struct_type)
* out the base type of the packed variable. Elaboration, later on, * out the base type of the packed variable. Elaboration, later on,
* well figure out the rest. * well figure out the rest.
*/ */
static void pform_set_packed_struct(struct_type_t*struct_type, perm_string name, list<named_pexpr_t>*attr) static void pform_set_packed_struct(struct_type_t*struct_type, perm_string name, NetNet::Type net_type, list<named_pexpr_t>*attr)
{ {
ivl_variable_type_t base_type = figure_struct_base_type(struct_type); ivl_variable_type_t base_type = struct_type->figure_packed_base_type();
PWire*net = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, base_type); PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, base_type);
net->set_struct_type(struct_type); net->set_packed_type(struct_type);
pform_bind_attributes(net->attributes, attr, true); pform_bind_attributes(net->attributes, attr, true);
} }
static void pform_set_struct_type(struct_type_t*struct_type, perm_string name, list<named_pexpr_t>*attr) static void pform_set_struct_type(struct_type_t*struct_type, perm_string name, NetNet::Type net_type, list<named_pexpr_t>*attr)
{ {
if (struct_type->packed_flag) { if (struct_type->packed_flag) {
pform_set_packed_struct(struct_type, name, attr); pform_set_packed_struct(struct_type, name, net_type, attr);
return; return;
} }
@ -68,11 +71,11 @@ static void pform_set_struct_type(struct_type_t*struct_type, perm_string name, l
ivl_assert(*struct_type, 0); ivl_assert(*struct_type, 0);
} }
void pform_set_struct_type(struct_type_t*struct_type, list<perm_string>*names, list<named_pexpr_t>*attr) void pform_set_struct_type(struct_type_t*struct_type, list<perm_string>*names, NetNet::Type net_type, list<named_pexpr_t>*attr)
{ {
for (list<perm_string>::iterator cur = names->begin() for (list<perm_string>::iterator cur = names->begin()
; cur != names->end() ; ++ cur) { ; cur != names->end() ; ++ cur) {
pform_set_struct_type(struct_type, *cur, attr); pform_set_struct_type(struct_type, *cur, net_type, attr);
} }
} }
@ -82,11 +85,11 @@ static void pform_makewire(const struct vlltype&li,
perm_string name, perm_string name,
list<named_pexpr_t>*) list<named_pexpr_t>*)
{ {
ivl_variable_type_t base_type = figure_struct_base_type(struct_type); ivl_variable_type_t base_type = struct_type->figure_packed_base_type();
PWire*cur = pform_get_make_wire_in_scope(name, NetNet::WIRE, ptype, base_type); PWire*cur = pform_get_make_wire_in_scope(name, NetNet::WIRE, ptype, base_type);
FILE_NAME(cur, li); FILE_NAME(cur, li);
cur->set_struct_type(struct_type); cur->set_packed_type(struct_type);
} }
void pform_makewire(const struct vlltype&li, void pform_makewire(const struct vlltype&li,

View File

@ -27,3 +27,18 @@ data_type_t::~data_type_t()
string_type_t::~string_type_t() string_type_t::~string_type_t()
{ {
} }
ivl_variable_type_t data_type_t::figure_packed_base_type(void) const
{
return IVL_VT_NO_TYPE;
}
ivl_variable_type_t parray_type_t::figure_packed_base_type(void) const
{
return base_type->figure_packed_base_type();
}
ivl_variable_type_t vector_type_t::figure_packed_base_type(void) const
{
return base_type;
}

View File

@ -69,9 +69,12 @@ struct decl_assignment_t {
* "data_type" rule in the parse rule. We make the type virtual so * "data_type" rule in the parse rule. We make the type virtual so
* that dynamic types will work. * that dynamic types will work.
*/ */
struct data_type_t : public LineInfo { class data_type_t : public LineInfo {
public:
virtual ~data_type_t() = 0; virtual ~data_type_t() = 0;
// This method is used to figure out the base type of a packed
// compound object. Return IVL_VT_NO_TYPE if the type is not packed.
virtual ivl_variable_type_t figure_packed_base_type(void)const;
// This method is used by the pform dumper to diagnostic dump. // This method is used by the pform dumper to diagnostic dump.
virtual void pform_dump(std::ostream&out, unsigned indent) const; virtual void pform_dump(std::ostream&out, unsigned indent) const;
}; };
@ -97,10 +100,10 @@ struct struct_member_t : public LineInfo {
}; };
struct struct_type_t : public data_type_t { struct struct_type_t : public data_type_t {
virtual ivl_variable_type_t figure_packed_base_type(void)const;
bool packed_flag; bool packed_flag;
std::auto_ptr< list<struct_member_t*> > members; std::auto_ptr< list<struct_member_t*> > members;
}; };
extern ivl_variable_type_t figure_struct_base_type(struct_type_t*struct_type);
struct atom2_type_t : public data_type_t { struct atom2_type_t : public data_type_t {
inline explicit atom2_type_t(int tc, bool flag) inline explicit atom2_type_t(int tc, bool flag)
@ -132,6 +135,8 @@ struct vector_type_t : public data_type_t {
inline explicit vector_type_t(ivl_variable_type_t bt, bool sf, inline explicit vector_type_t(ivl_variable_type_t bt, bool sf,
std::list<pform_range_t>*pd) std::list<pform_range_t>*pd)
: base_type(bt), signed_flag(sf), reg_flag(false), implicit_flag(false), pdims(pd) { } : base_type(bt), signed_flag(sf), reg_flag(false), implicit_flag(false), pdims(pd) { }
virtual ivl_variable_type_t figure_packed_base_type(void)const;
ivl_variable_type_t base_type; ivl_variable_type_t base_type;
bool signed_flag; bool signed_flag;
bool reg_flag; // True if "reg" was used bool reg_flag; // True if "reg" was used
@ -141,11 +146,16 @@ struct vector_type_t : public data_type_t {
/* /*
* The array_type_t is a generalization of the vector_type_t in that * The array_type_t is a generalization of the vector_type_t in that
* the base type is another general data type. * the base type is another general data type. Ultimately, the subtype
* must also be packed (as this is a packed array) but that may be
* worked out during elaboration.
*/ */
struct array_type_t : public data_type_t { struct parray_type_t : public data_type_t {
inline explicit array_type_t(data_type_t*btype, std::list<pform_range_t>*pd) inline explicit parray_type_t(data_type_t*btype, std::list<pform_range_t>*pd)
: base_type(btype), packed_dims(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; data_type_t*base_type;
std::auto_ptr< list<pform_range_t> > packed_dims; std::auto_ptr< list<pform_range_t> > packed_dims;
}; };

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2003-2010 Stephen Williams (steve@icarus.com) * Copyright (c) 2003-2010 Stephen Williams (steve@icarus.com)
* Copyright CERN 2012 / Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -19,12 +20,145 @@
# include "netlist.h" # include "netlist.h"
# include "netmisc.h" # include "netmisc.h"
# include <cassert> # include "ivl_assert.h"
/* /*
* Search for the hierarchical name. * Search for the hierarchical name.
*/ */
struct symbol_search_results {
inline symbol_search_results() {
scope = 0;
net = 0;
par_val = 0;
par_msb = 0;
par_lsb = 0;
eve = 0;
}
inline bool is_scope() const {
if (net) return false;
if (eve) return false;
if (par_val) return false;
if (scope) return true;
return false;
}
// Scope where symbol was located. This is set in all cases,
// assuming the search succeeded.
NetScope*scope;
// If this was a net, the signal itself.
NetNet*net;
// If this was a parameter, the value expression and the
// optional value dimensions.
const NetExpr*par_val;
const NetExpr*par_msb;
const NetExpr*par_lsb;
// If this is a named event, ...
NetEvent*eve;
};
bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
pform_name_t path, struct symbol_search_results*res,
NetScope*start_scope = 0)
{
assert(scope);
bool prefix_scope = false;
bool recurse_flag = false;
name_component_t path_tail = path.back();
path.pop_back();
// If this is a recursive call, then we need to know that so
// that we can enable the search for scopes. Set the
// recurse_flag to true if this is a recurse.
if (start_scope==0)
start_scope = scope;
else
recurse_flag = true;
// If there are components ahead of the tail, symbol_search
// recursively. Ideally, the result is a scope that we search
// for the tail key, but there are other special cases as well.
if (path.size() > 0) {
symbol_search_results recurse;
bool flag = symbol_search(li, des, scope, path, &recurse, start_scope);
if (! flag)
return false;
// The prefix is found to be a scope, so switch to that
// scoke, set the hier_path to turn of upwards searches,
// and continue our search for the tail.
if (recurse.is_scope()) {
scope = recurse.scope;
prefix_scope = true;
if (scope->is_auto() && li) {
cerr << li->get_fileline() << ": error: Hierarchical "
"reference to automatically allocated item "
"`" << path_tail.name << "' in path `" << path << "'" << endl;
des->errors += 1;
}
}
}
while (scope) {
if (NetNet*net = scope->find_signal(path_tail.name)) {
res->scope = scope;
res->net = net;
return true;
}
if (NetEvent*eve = scope->find_event(path_tail.name)) {
res->scope = scope;
res->eve = eve;
return true;
}
if (const NetExpr*par = scope->get_parameter(des, path_tail.name, res->par_msb, res->par_lsb)) {
res->scope = scope;
res->par_val = par;
return true;
}
if (recurse_flag) {
bool flag = false;
hname_t path_item = eval_path_component(des, start_scope, path_tail, flag);
if (flag) {
cerr << li->get_fileline() << ": XXXXX: Errors evaluating scope index" << endl;
} else if (NetScope*chld = des->find_scope(scope, path_item)) {
res->scope = chld;
return true;
}
}
// Don't scan up past a module boundary.
if (scope->type()==NetScope::MODULE && !scope->nested_module())
break;
// Don't scan up if we are searching within a prefixed scope.
if (prefix_scope)
break;
scope = scope->parent();
}
// Last chance: this is a single name, so it might be the name
// of a root scope. Ask the design if this is a root
// scope. This is only possible if there is no prefix.
if (prefix_scope==false) {
hname_t path_item (path_tail.name);
scope = des->find_scope(path_item);
if (scope) {
res->scope = scope;
return true;
}
}
return false;
}
/*
* Compatibility version. Remove me!
*/
NetScope*symbol_search(const LineInfo*li, Design*des, NetScope*scope, NetScope*symbol_search(const LineInfo*li, Design*des, NetScope*scope,
pform_name_t path, pform_name_t path,
NetNet*&net, NetNet*&net,
@ -32,58 +166,19 @@ NetScope*symbol_search(const LineInfo*li, Design*des, NetScope*scope,
NetEvent*&eve, NetEvent*&eve,
const NetExpr*&ex1, const NetExpr*&ex2) const NetExpr*&ex1, const NetExpr*&ex2)
{ {
assert(scope); symbol_search_results recurse;
bool hier_path = false; bool flag = symbol_search(li, des, scope, path, &recurse);
if (! flag) {
/* Get the tail name of the object we are looking for. */
perm_string key = peek_tail_name(path);
path.pop_back();
/* Initialize output argument to cleared. */
net = 0;
par = 0;
eve = 0;
/* If the path has a scope part, then search for the specified
scope that we are supposed to search. */
if (! path.empty()) {
list<hname_t> path_list = eval_scope_path(des, scope, path);
assert(path_list.size() <= path.size());
// If eval_scope_path returns a short list, then some
// part of the scope was not found. Abort.
if (path_list.size() < path.size())
return 0;
scope = des->find_scope(scope, path_list);
if (scope && scope->is_auto() && li) {
cerr << li->get_fileline() << ": error: Hierarchical "
"reference to automatically allocated item "
"`" << key << "' in path `" << path << "'" << endl;
des->errors += 1;
}
hier_path = true;
}
while (scope) {
if ( (net = scope->find_signal(key)) )
return scope;
if ( (eve = scope->find_event(key)) )
return scope;
if ( (par = scope->get_parameter(des, key, ex1, ex2)) )
return scope;
/* We can't look up if we are at the enclosing module scope
* or if a hierarchical path was given. */
if ((scope->type()==NetScope::MODULE && !scope->nested_module()) || hier_path)
scope = 0;
else
scope = scope->parent();
}
return 0; return 0;
} }
if (recurse.is_scope())
return recurse.scope;
net = recurse.net;
par = recurse.par_val;
ex1 = recurse.par_msb;
ex2 = recurse.par_lsb;
eve = recurse.eve;
return recurse.scope;
}

View File

@ -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) extern "C" unsigned ivl_enum_width(ivl_enumtype_t net)
{ {
assert(net); assert(net);
return net->base_width(); return net->packed_width();
} }
extern "C" int ivl_enum_signed(ivl_enumtype_t net) extern "C" int ivl_enum_signed(ivl_enumtype_t net)

View File

@ -22,6 +22,7 @@
# include "parse_types.h" # include "parse_types.h"
// Need this for parse_errors? // Need this for parse_errors?
# include "parse_api.h" # include "parse_api.h"
# include <cassert>
using namespace std; using namespace std;
@ -38,6 +39,54 @@ Architecture::~Architecture()
ScopeBase::cleanup(); ScopeBase::cleanup();
} }
void Architecture::push_genvar_type(perm_string gname, const VType*gtype)
{
genvar_type_t tmp;
tmp.name = gname;
tmp.vtype = gtype;
genvar_type_stack_.push_back(tmp);
}
void Architecture::pop_genvar_type(void)
{
assert(! genvar_type_stack_.empty());
genvar_type_stack_.pop_back();
}
const VType* Architecture::probe_genvar_type(perm_string gname)
{
for (std::list<genvar_type_t>::reverse_iterator cur = genvar_type_stack_.rbegin()
; cur != genvar_type_stack_.rend() ; ++cur) {
if (cur->name == gname)
return cur->vtype;
}
return 0;
}
void Architecture::push_genvar_emit(perm_string gname, const GenerateStatement*gen)
{
genvar_emit_t tmp;
tmp.name = gname;
tmp.gen = gen;
genvar_emit_stack_.push_back(tmp);
}
void Architecture::pop_genvar_emit(void)
{
assert(! genvar_emit_stack_.empty());
genvar_emit_stack_.pop_back();
}
const GenerateStatement* Architecture::probe_genvar_emit(perm_string gname)
{
for (std::list<genvar_emit_t>::reverse_iterator cur = genvar_emit_stack_.rbegin()
; cur != genvar_emit_stack_.rend() ; ++cur) {
if (cur->name == gname)
return cur->gen;
}
return 0;
}
Architecture::Statement::Statement() Architecture::Statement::Statement()
{ {
} }

View File

@ -29,6 +29,7 @@ class ComponentBase;
class Entity; class Entity;
class Expression; class Expression;
class ExpName; class ExpName;
class GenerateStatement;
class SequentialStmt; class SequentialStmt;
class Signal; class Signal;
class named_expr_t; class named_expr_t;
@ -71,6 +72,18 @@ class Architecture : public Scope, public LineInfo {
// Elaborate this architecture in the context of the given entity. // Elaborate this architecture in the context of the given entity.
int elaborate(Entity*entity); int elaborate(Entity*entity);
// These methods are used while in the scope of a generate
// block to mark that a name is a genvar at this point.
const VType* probe_genvar_type(perm_string);
void push_genvar_type(perm_string gname, const VType*gtype);
void pop_genvar_type(void);
// These methods are used during EMIT to check for names that
// are genvar names.
const GenerateStatement* probe_genvar_emit(perm_string);
void push_genvar_emit(perm_string gname, const GenerateStatement*);
void pop_genvar_emit(void);
// Emit this architecture to the given out file in the context // Emit this architecture to the given out file in the context
// of the specified entity. This method is used by the // of the specified entity. This method is used by the
// elaborate code to display generated code to the specified // elaborate code to display generated code to the specified
@ -85,6 +98,18 @@ class Architecture : public Scope, public LineInfo {
// Concurrent statements local to this architecture // Concurrent statements local to this architecture
std::list<Architecture::Statement*> statements_; std::list<Architecture::Statement*> statements_;
struct genvar_type_t {
perm_string name;
const VType*vtype;
};
std::list<genvar_type_t> genvar_type_stack_;
struct genvar_emit_t {
perm_string name;
const GenerateStatement*gen;
};
std::list<genvar_emit_t> genvar_emit_stack_;
private: // Not implemented private: // Not implemented
}; };
@ -98,9 +123,9 @@ class GenerateStatement : public Architecture::Statement {
GenerateStatement(perm_string gname, std::list<Architecture::Statement*>&s); GenerateStatement(perm_string gname, std::list<Architecture::Statement*>&s);
~GenerateStatement(); ~GenerateStatement();
protected: inline perm_string get_name() const { return name_; }
inline perm_string get_name() { return name_; }
protected:
int elaborate_statements(Entity*ent, Architecture*arc); int elaborate_statements(Entity*ent, Architecture*arc);
int emit_statements(ostream&out, Entity*ent, Architecture*arc); int emit_statements(ostream&out, Entity*ent, Architecture*arc);
void dump_statements(ostream&out, int indent) const; void dump_statements(ostream&out, int indent) const;

View File

@ -133,7 +133,9 @@ int GenerateStatement::elaborate_statements(Entity*ent, Architecture*arc)
int ForGenerate::elaborate(Entity*ent, Architecture*arc) int ForGenerate::elaborate(Entity*ent, Architecture*arc)
{ {
int errors = 0; int errors = 0;
arc->push_genvar_type(genvar_, lsb_->probe_type(ent, arc));
errors += elaborate_statements(ent, arc); errors += elaborate_statements(ent, arc);
arc->pop_genvar_type();
return errors; return errors;
} }

View File

@ -183,16 +183,19 @@ int GenerateStatement::emit_statements(ostream&out, Entity*ent, Architecture*arc
int ForGenerate::emit(ostream&out, Entity*ent, Architecture*arc) int ForGenerate::emit(ostream&out, Entity*ent, Architecture*arc)
{ {
int errors = 0; int errors = 0;
out << "genvar \\" << genvar_ << " ;" << endl; out << "genvar \\" << get_name() << ":" << genvar_ << " ;" << endl;
out << "for (\\" << genvar_ << " = "; out << "for (\\" << get_name() << ":" << genvar_ << " = ";
errors += lsb_->emit(out, ent, arc); errors += lsb_->emit(out, ent, arc);
out << "; \\" << genvar_ << " <= "; out << "; \\" << get_name() << ":" << genvar_ << " <= ";
errors += msb_->emit(out, ent, arc); errors += msb_->emit(out, ent, arc);
out << "; \\" << genvar_ << " = \\" << genvar_ << " + 1)" out << "; \\" << get_name() << ":" << genvar_ << " = \\" << get_name() << ":" << genvar_ << " + 1)"
<< " begin : \\" << get_name() << endl; << " begin : \\" << get_name() << endl;
arc->push_genvar_emit(genvar_, this);
errors += emit_statements(out, ent, arc); errors += emit_statements(out, ent, arc);
arc->pop_genvar_emit();
out << "end" << endl; out << "end" << endl;
return errors; return errors;

View File

@ -20,12 +20,16 @@
*/ */
# include "StringHeap.h" # include "StringHeap.h"
# include <fstream>
const int GN_KEYWORD_2008 = 0x0001; const int GN_KEYWORD_2008 = 0x0001;
// TRUE if processing is supposed to dump progress to stderr. // TRUE if processing is supposed to dump progress to stderr.
extern bool verbose_flag; extern bool verbose_flag;
extern bool debug_elaboration;
extern std::ofstream debug_log_file;
extern StringHeapLex lex_strings; extern StringHeapLex lex_strings;
extern StringHeapLex filename_strings; extern StringHeapLex filename_strings;

View File

@ -424,3 +424,15 @@ void prange_t::dump(ostream&out, int indent) const
out << setw(indent) << "" << (direction_ ? "downto" : "to"); out << setw(indent) << "" << (direction_ ? "downto" : "to");
right_->dump(out, indent); right_->dump(out, indent);
} }
ostream& Expression::dump_inline(ostream&out) const
{
out << typeid(*this).name();
return out;
}
ostream& ExpInteger::dump_inline(ostream&out) const
{
out << value_;
return out;
}

View File

@ -50,28 +50,6 @@ bool Expression::symbolic_compare(const Expression*) const
return false; return false;
} }
bool ExpName::symbolic_compare(const Expression*that) const
{
const ExpName*that_name = dynamic_cast<const ExpName*> (that);
if (that_name == 0)
return false;
if (name_ != that_name->name_)
return false;
if (that_name->index_ && !index_)
return false;
if (index_ && !that_name->index_)
return false;
if (index_) {
assert(that_name->index_);
return index_->symbolic_compare(that_name->index_);
}
return true;
}
ExpAttribute::ExpAttribute(ExpName*bas, perm_string nam) ExpAttribute::ExpAttribute(ExpName*bas, perm_string nam)
: base_(bas), name_(nam) : base_(bas), name_(nam)
{ {
@ -366,6 +344,36 @@ const char* ExpName::name() const
return name_; return name_;
} }
bool ExpName::symbolic_compare(const Expression*that) const
{
const ExpName*that_name = dynamic_cast<const ExpName*> (that);
if (that_name == 0)
return false;
if (name_ != that_name->name_)
return false;
if (that_name->index_ && !index_)
return false;
if (index_ && !that_name->index_)
return false;
if (index_) {
assert(that_name->index_);
return index_->symbolic_compare(that_name->index_);
}
return true;
}
void ExpName::set_range(Expression*msb, Expression*lsb)
{
assert(index_==0);
index_ = msb;
assert(lsb_==0);
lsb_ = lsb;
}
ExpRelation::ExpRelation(ExpRelation::fun_t ty, Expression*op1, Expression*op2) ExpRelation::ExpRelation(ExpRelation::fun_t ty, Expression*op1, Expression*op2)
: ExpBinary(op1, op2), fun_(ty) : ExpBinary(op1, op2), fun_(ty)
{ {

View File

@ -111,6 +111,7 @@ class Expression : public LineInfo {
// Debug dump of the expression. // Debug dump of the expression.
virtual void dump(ostream&out, int indent = 0) const =0; virtual void dump(ostream&out, int indent = 0) const =0;
virtual ostream& dump_inline(ostream&out) const;
protected: protected:
// This function is called by the derived class during // This function is called by the derived class during
@ -131,6 +132,11 @@ static inline void FILE_NAME(Expression*tgt, const LineInfo*src)
tgt->set_line(*src); tgt->set_line(*src);
} }
static inline ostream& operator <<(ostream&out, const Expression&exp)
{
return exp.dump_inline(out);
}
class ExpUnary : public Expression { class ExpUnary : public Expression {
public: public:
@ -473,6 +479,7 @@ class ExpInteger : public Expression {
bool is_primary(void) const; bool is_primary(void) const;
bool evaluate(ScopeBase*scope, int64_t&val) const; bool evaluate(ScopeBase*scope, int64_t&val) const;
void dump(ostream&out, int indent = 0) const; void dump(ostream&out, int indent = 0) const;
virtual ostream& dump_inline(ostream&out) const;
private: private:
int64_t value_; int64_t value_;
@ -528,6 +535,8 @@ class ExpName : public Expression {
void dump(ostream&out, int indent = 0) const; void dump(ostream&out, int indent = 0) const;
const char* name() const; const char* name() const;
void set_range(Expression*msb, Expression*lsb);
private: private:
const VType* elaborate_adjust_type_with_range_(Entity*ent, Architecture*arc, const VType*type); const VType* elaborate_adjust_type_with_range_(Entity*ent, Architecture*arc, const VType*type);

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com)
* Copyright CERN 2012 / Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -25,6 +26,7 @@
# include <iostream> # include <iostream>
# include <typeinfo> # include <typeinfo>
# include "parse_types.h" # include "parse_types.h"
# include "compiler.h"
# include "ivl_assert.h" # include "ivl_assert.h"
using namespace std; using namespace std;
@ -87,6 +89,17 @@ int ExpName::elaborate_lval_(Entity*ent, Architecture*arc, bool is_sequ, ExpName
{ {
int errors = 0; int errors = 0;
if (debug_elaboration) {
debug_log_file << get_fileline() << ": ExpName::elaborate_lval_: "
<< "name_=" << name_
<< ", suffix->name()=" << suffix->name();
if (index_)
debug_log_file << ", index_=" << *index_;
if (lsb_)
debug_log_file << ", lsb_=" << *lsb_;
debug_log_file << endl;
}
if (prefix_.get()) { if (prefix_.get()) {
cerr << get_fileline() << ": sorry: I don't know how to elaborate " cerr << get_fileline() << ": sorry: I don't know how to elaborate "
<< "ExpName prefix of " << name_ << "ExpName prefix of " << name_
@ -128,8 +141,40 @@ int ExpName::elaborate_lval_(Entity*ent, Architecture*arc, bool is_sequ, ExpName
found_type = var->peek_type(); found_type = var->peek_type();
} }
// Resolve type definition to get an actual type.
while (const VTypeDef*tdef = dynamic_cast<const VTypeDef*> (found_type)) {
found_type = tdef->peek_definition();
if (debug_elaboration) {
debug_log_file << get_fileline() << ": ExpName::elaborate_lval_: "
<< "Resolve typedef " << tdef->peek_name()
<< " to defined type=" << typeid(*found_type).name()
<< endl;
}
}
ivl_assert(*this, found_type); ivl_assert(*this, found_type);
// If the prefix type is an array, then we may actually have a
// case of an array of structs. For example:
// foo(n).bar
// where foo is an array, (n) is an array index and foo(n) is
// something that takes a suffix. For the purpose of our
// expression type calculations, we need the element type.
if (const VTypeArray*array = dynamic_cast<const VTypeArray*> (found_type)) {
found_type = array->element_type();
while (const VTypeDef*tdef = dynamic_cast<const VTypeDef*> (found_type)) {
found_type = tdef->peek_definition();
}
if (debug_elaboration) {
debug_log_file << get_fileline() << ": ExpName::elaborate_lval_: "
<< "Extract array element type=" << typeid(*found_type).name()
<< endl;
}
}
const VType*suffix_type = 0; const VType*suffix_type = 0;
if (const VTypeRecord*record = dynamic_cast<const VTypeRecord*> (found_type)) { if (const VTypeRecord*record = dynamic_cast<const VTypeRecord*> (found_type)) {
@ -140,6 +185,7 @@ int ExpName::elaborate_lval_(Entity*ent, Architecture*arc, bool is_sequ, ExpName
ivl_assert(*this, element_type); ivl_assert(*this, element_type);
suffix_type = element_type; suffix_type = element_type;
} }
if (suffix_type == 0) { if (suffix_type == 0) {
@ -654,6 +700,10 @@ const VType* ExpName::probe_prefixed_type_(Entity*ent, Architecture*arc) const
return 0; return 0;
} }
while (const VTypeDef*def = dynamic_cast<const VTypeDef*> (prefix_type)) {
prefix_type = def->peek_definition();
}
// If the prefix type is a record, then the current name is // If the prefix type is a record, then the current name is
// the name of a member. // the name of a member.
if (const VTypeRecord*pref_record = dynamic_cast<const VTypeRecord*> (prefix_type)) { if (const VTypeRecord*pref_record = dynamic_cast<const VTypeRecord*> (prefix_type)) {
@ -699,6 +749,10 @@ const VType* ExpName::probe_type(Entity*ent, Architecture*arc) const
if (arc->find_constant(name_, ctype, cval)) if (arc->find_constant(name_, ctype, cval))
return ctype; return ctype;
if (const VType*gtype = arc->probe_genvar_type(name_)) {
return gtype;
}
cerr << get_fileline() << ": error: Signal/variable " << name_ cerr << get_fileline() << ": error: Signal/variable " << name_
<< " not found in this context." << endl; << " not found in this context." << endl;
return 0; return 0;

View File

@ -610,7 +610,12 @@ int ExpName::emit_as_prefix_(ostream&out, Entity*ent, Architecture*arc)
} }
out << "\\" << name_ << " "; out << "\\" << name_ << " ";
ivl_assert(*this, index_ == 0); if (index_) {
out << "[";
errors += index_->emit(out, ent, arc);
out << "]";
ivl_assert(*this, lsb_ == 0);
}
out << "."; out << ".";
return errors; return errors;
} }
@ -623,7 +628,12 @@ int ExpName::emit(ostream&out, Entity*ent, Architecture*arc)
errors += prefix_->emit_as_prefix_(out, ent, arc); errors += prefix_->emit_as_prefix_(out, ent, arc);
} }
const GenerateStatement*gs = 0;
if (arc && (gs = arc->probe_genvar_emit(name_)))
out << "\\" << gs->get_name() << ":" << name_ << " ";
else
out << "\\" << name_ << " "; out << "\\" << name_ << " ";
if (index_) { if (index_) {
out << "["; out << "[";
errors += index_->emit(out, ent, arc); errors += index_->emit(out, ent, arc);

View File

@ -1,6 +1,7 @@
const char COPYRIGHT[] = const char COPYRIGHT[] =
"Copyright (c) 2011 Stephen Williams (steve@icarus.com)"; "Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com)\n"
"Copyright CERN 2012 / Stephen Williams (steve@icarus.com)";
/* /*
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -36,6 +37,10 @@ const char COPYRIGHT[] =
* Enable debugging of library support by dumping library * Enable debugging of library support by dumping library
* information to the file named <path>. * information to the file named <path>.
* *
* elaboration=<path>
* Enable debugging of elaboratin by dumping elaboration
* process information to the file named <path>.
*
* entities=<path> * entities=<path>
* Enable debugging of elaborated entities by writing the * Enable debugging of elaborated entities by writing the
* elaboration results to the file named <path>. * elaboration results to the file named <path>.
@ -94,7 +99,10 @@ bool verbose_flag = false;
// Where to dump design entities // Where to dump design entities
const char*dump_design_entities_path = 0; const char*dump_design_entities_path = 0;
const char*dump_libraries_path = 0; const char*dump_libraries_path = 0;
const char*debug_log_path = 0;
bool debug_elaboration = false;
ofstream debug_log_file;
extern void dump_libraries(ostream&file); extern void dump_libraries(ostream&file);
extern void parser_cleanup(); extern void parser_cleanup();
@ -109,6 +117,10 @@ static void process_debug_token(const char*word)
dump_design_entities_path = strdup(word+9); dump_design_entities_path = strdup(word+9);
} else if (strncmp(word, "libraries=", 10) == 0) { } else if (strncmp(word, "libraries=", 10) == 0) {
dump_libraries_path = strdup(word+10); dump_libraries_path = strdup(word+10);
} else if (strncmp(word, "log=", 4) == 0) {
debug_log_path = strdup(word+4);
} else if (strcmp(word, "elaboration") == 0) {
debug_elaboration = true;
} }
} }
@ -148,6 +160,10 @@ int main(int argc, char*argv[])
break; break;
} }
if (debug_log_path) {
debug_log_file.open(debug_log_path);
}
if ( (rc = mkdir(work_path, 0777)) < 0 ) { if ( (rc = mkdir(work_path, 0777)) < 0 ) {
if (errno != EEXIST) { if (errno != EEXIST) {
fprintf(stderr, "Icarus Verilog VHDL unable to create work directory %s, errno=%d\n", work_path, errno); fprintf(stderr, "Icarus Verilog VHDL unable to create work directory %s, errno=%d\n", work_path, errno);

View File

@ -7,6 +7,7 @@
%{ %{
/* /*
* Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com)
* Copyright CERN 2012 / Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -167,37 +168,6 @@ static Expression*aggregate_or_primary(const YYLTYPE&loc, std::list<ExpAggregate
return el1->extract_expression(); return el1->extract_expression();
} }
static ExpName*make_name_from_prefix(const YYLTYPE&loc, const vector<perm_string>*names)
{
ExpName*cur = new ExpName(names->at(0));
FILE_NAME(cur, loc);
for (size_t idx = 1 ; idx < names->size() ; idx += 1) {
ExpName*tmp = new ExpName(cur, names->at(idx));
FILE_NAME(tmp, loc);
cur = tmp;
}
return cur;
}
static ExpName*make_name_from_prefix(const YYLTYPE&loc, const vector<perm_string>*names, Expression*msb, Expression*lsb)
{
ExpName*cur = new ExpName(names->at(0));
FILE_NAME(cur, loc);
for (size_t idx = 1 ; idx < (names->size()-1) ; idx += 1) {
ExpName*tmp = new ExpName(cur, names->at(idx));
FILE_NAME(tmp, loc);
cur = tmp;
}
ExpName*result = new ExpName(cur, names->back(), msb, lsb);
FILE_NAME(result, loc);
return result;
}
static list<VTypeRecord::element_t*>* record_elements(list<perm_string>*names, static list<VTypeRecord::element_t*>* record_elements(list<perm_string>*names,
const VType*type) const VType*type)
{ {
@ -220,8 +190,6 @@ static list<VTypeRecord::element_t*>* record_elements(list<perm_string>*names,
char*text; char*text;
std::list<perm_string>* name_list; std::list<perm_string>* name_list;
std::vector<perm_string>* compound_name;
std::list<std::vector<perm_string>* >* compound_name_list;
bool flag; bool flag;
int64_t uni_integer; int64_t uni_integer;
@ -331,7 +299,7 @@ static list<VTypeRecord::element_t*>* record_elements(list<perm_string>*names,
%type <expr> expression factor primary relation %type <expr> expression factor primary relation
%type <expr> expression_logical expression_logical_and expression_logical_or %type <expr> expression_logical expression_logical_and expression_logical_or
%type <expr> expression_logical_xnor expression_logical_xor %type <expr> expression_logical_xnor expression_logical_xor
%type <expr> name %type <expr> name prefix selected_name
%type <expr> shift_expression signal_declaration_assign_opt %type <expr> shift_expression signal_declaration_assign_opt
%type <expr> simple_expression term waveform_element %type <expr> simple_expression term waveform_element
%type <expr> interface_element_expression %type <expr> interface_element_expression
@ -339,6 +307,7 @@ static list<VTypeRecord::element_t*>* record_elements(list<perm_string>*names,
%type <expr_list> waveform waveform_elements %type <expr_list> waveform waveform_elements
%type <expr_list> name_list expression_list %type <expr_list> name_list expression_list
%type <expr_list> process_sensitivity_list process_sensitivity_list_opt %type <expr_list> process_sensitivity_list process_sensitivity_list_opt
%type <expr_list> selected_names use_clause
%type <named_expr> association_element %type <named_expr> association_element
%type <named_expr_list> association_list port_map_aspect port_map_aspect_opt %type <named_expr_list> association_list port_map_aspect port_map_aspect_opt
@ -353,8 +322,6 @@ static list<VTypeRecord::element_t*>* record_elements(list<perm_string>*names,
%type <text> identifier_opt identifier_colon_opt logical_name suffix %type <text> identifier_opt identifier_colon_opt logical_name suffix
%type <name_list> logical_name_list identifier_list %type <name_list> logical_name_list identifier_list
%type <name_list> enumeration_literal_list enumeration_literal %type <name_list> enumeration_literal_list enumeration_literal
%type <compound_name> prefix selected_name
%type <compound_name_list> selected_names use_clause
%type <sequ_list> sequence_of_statements if_statement_else %type <sequ_list> sequence_of_statements if_statement_else
%type <sequ> sequential_statement if_statement signal_assignment_statement %type <sequ> sequential_statement if_statement signal_assignment_statement
@ -1497,8 +1464,8 @@ mode
mode_opt : mode {$$ = $1;} | {$$ = PORT_NONE;} ; mode_opt : mode {$$ = $1;} | {$$ = PORT_NONE;} ;
name name /* IEEE 1076-2008 P8.1 */
: IDENTIFIER : IDENTIFIER /* simple_name (IEEE 1076-2008 P8.2) */
{ ExpName*tmp = new ExpName(lex_strings.make($1)); { ExpName*tmp = new ExpName(lex_strings.make($1));
FILE_NAME(tmp, @1); FILE_NAME(tmp, @1);
delete[]$1; delete[]$1;
@ -1506,10 +1473,7 @@ name
} }
| selected_name | selected_name
{ ExpName*tmp = make_name_from_prefix(@1, $1); { $$ = $1; }
delete $1;
$$ = tmp;
}
/* Note that this rule can match array element selects and various /* Note that this rule can match array element selects and various
function calls. The only way we can tell the difference is from function calls. The only way we can tell the difference is from
@ -1534,8 +1498,8 @@ name
$$ = tmp; $$ = tmp;
} }
| selected_name '(' range ')' | selected_name '(' range ')'
{ ExpName*tmp = make_name_from_prefix(@1, $1, $3->msb(), $3->lsb()); { ExpName*tmp = dynamic_cast<ExpName*> ($1);
delete $1; tmp->set_range($3->msb(), $3->lsb());
$$ = tmp; $$ = tmp;
} }
; ;
@ -1667,20 +1631,9 @@ port_map_aspect_opt
| { $$ = 0; } | { $$ = 0; }
; ;
prefix
: IDENTIFIER prefix /* IEEE 1076-2008 P8.1 */
{ std::vector<perm_string>* tmp = new std::vector<perm_string>(); : name
tmp->push_back(lex_strings.make($1));
delete[] $1;
$$ = tmp;
}
| STRING_LITERAL
{ std::vector<perm_string>* tmp = new std::vector<perm_string>();
tmp->push_back(lex_strings.make($1));
delete[] $1;
$$ = tmp;
}
| selected_name
{ $$ = $1; } { $$ = $1; }
; ;
@ -1926,34 +1879,42 @@ secondary_unit
| package_body | package_body
; ;
selected_name selected_name /* IEEE 1076-2008 P8.3 */
: prefix '.' suffix : prefix '.' suffix
{ std::vector<perm_string>* tmp = $1; { Expression*pfx = $1;
tmp->push_back(lex_strings.make($3)); ExpName*pfx1 = dynamic_cast<ExpName*>(pfx);
assert(pfx1);
perm_string tmp = lex_strings.make($3);
$$ = new ExpName(pfx1, tmp);
FILE_NAME($$, @3);
delete[]$3;
}
| error '.' suffix
{ errormsg(@1, "Syntax error in prefix in front of \"%s\".\n", $3);
yyerrok;
$$ = new ExpName(lex_strings.make($3));
FILE_NAME($$, @3);
delete[]$3; delete[]$3;
$$ = tmp;
} }
; ;
selected_names selected_names
: selected_names ',' selected_name : selected_names ',' selected_name
{ { std::list<Expression*>* tmp = $1;
std::list<std::vector<perm_string>* >* tmp = $1;
tmp->push_back($3); tmp->push_back($3);
$$ = tmp; $$ = tmp;
} }
| selected_name | selected_name
{ { std::list<Expression*>* tmp = new std::list<Expression*>();
std::list<std::vector<perm_string>* >* tmp = new std::list<std::vector<perm_string>* >();
tmp->push_back($1); tmp->push_back($1);
$$ = tmp; $$ = tmp;
} }
; ;
/* The *_use variant of selected_name is used by the "use" /* The *_lib variant of selected_name is used by the "use"
clause. It is syntactically identical to other selected_name clause. It is syntactically identical to other selected_name
rules, but is a convenient place to attach use_clause actions. */ rules, but is a convenient place to attach use_clause actions. */
selected_name_use selected_name_lib
: IDENTIFIER '.' K_all : IDENTIFIER '.' K_all
{ library_use(@1, active_scope, 0, $1, 0); { library_use(@1, active_scope, 0, $1, 0);
delete[]$1; delete[]$1;
@ -1971,9 +1932,9 @@ selected_name_use
} }
; ;
selected_names_use selected_names_lib
: selected_names_use ',' selected_name_use : selected_names_lib ',' selected_name_lib
| selected_name_use | selected_name_lib
; ;
@ -2102,16 +2063,11 @@ subtype_indication
suffix suffix
: IDENTIFIER : IDENTIFIER
{ { $$ = $1; }
$$ = $1;
}
| CHARACTER_LITERAL | CHARACTER_LITERAL
{ { $$ = $1; }
$$ = $1;
}
| K_all | K_all
{ { //do not have now better idea than using char constant
//do not have now better idea than using char constant
$$ = strcpy(new char[strlen("all"+1)], "all"); $$ = strcpy(new char[strlen("all"+1)], "all");
} }
; ;
@ -2191,30 +2147,28 @@ type_definition
use_clause use_clause
: K_use selected_names ';' : K_use selected_names ';'
{ { $$ = $2; }
$$ = $2;
}
| K_use error ';' | K_use error ';'
{ errormsg(@1, "Syntax error in use clause.\n"); yyerrok; } { errormsg(@1, "Syntax error in use clause.\n"); yyerrok; }
; ;
use_clause_lib use_clause_lib
: K_use selected_names_use ';' : K_use selected_names_lib ';'
| K_use error ';' | K_use error ';'
{ errormsg(@1, "Syntax error in use clause.\n"); yyerrok; } { errormsg(@1, "Syntax error in use clause.\n"); yyerrok; }
; ;
use_clauses use_clauses_lib
: use_clauses use_clause : use_clauses_lib use_clause_lib
| use_clause | use_clause_lib
; ;
use_clauses_opt use_clauses_opt
: use_clauses : use_clauses_lib
| |
; ;
variable_assignment_statement variable_assignment_statement /* IEEE 1076-2008 P10.6.1 */
: name VASSIGN expression ';' : name VASSIGN expression ';'
{ VariableSeqAssignment*tmp = new VariableSeqAssignment($1, $3); { VariableSeqAssignment*tmp = new VariableSeqAssignment($1, $3);
FILE_NAME(tmp, @1); FILE_NAME(tmp, @1);

View File

@ -246,6 +246,8 @@ class VTypeDef : public VType {
explicit VTypeDef(perm_string name, const VType*is); explicit VTypeDef(perm_string name, const VType*is);
~VTypeDef(); ~VTypeDef();
inline perm_string peek_name() const { return name_; }
// If the type is not given a definition in the constructor, // If the type is not given a definition in the constructor,
// then this must be used to set the definition later. // then this must be used to set the definition later.
void set_definition(const VType*is); void set_definition(const VType*is);