Merge branch 'work12'
This commit is contained in:
commit
6137566385
2
PExpr.cc
2
PExpr.cc
|
|
@ -363,7 +363,7 @@ bool PEIdent::has_aa_term(Design*des, NetScope*scope) const
|
|||
|
||||
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)
|
||||
return scope->is_auto();
|
||||
|
|
|
|||
16
PWire.cc
16
PWire.cc
|
|
@ -29,7 +29,7 @@ PWire::PWire(perm_string n,
|
|||
: name_(n), type_(t), port_type_(pt), data_type_(dt),
|
||||
signed_(false), isint_(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)
|
||||
{
|
||||
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(struct_type_ == 0);
|
||||
enum_type_ = enum_type;
|
||||
}
|
||||
|
||||
void PWire::set_struct_type(struct_type_t*type)
|
||||
{
|
||||
assert(enum_type_ == 0);
|
||||
assert(struct_type_ == 0);
|
||||
struct_type_ = type;
|
||||
assert(set_data_type_ == 0);
|
||||
set_data_type_ = type;
|
||||
}
|
||||
|
||||
void PWire::set_discipline(ivl_discipline_t d)
|
||||
|
|
|
|||
6
PWire.h
6
PWire.h
|
|
@ -81,8 +81,7 @@ class PWire : public LineInfo {
|
|||
|
||||
void set_unpacked_idx(const std::list<pform_range_t>&ranges);
|
||||
|
||||
void set_enumeration(enum_type_t*enum_type);
|
||||
void set_struct_type(struct_type_t*type);
|
||||
void set_packed_type(data_type_t*type);
|
||||
|
||||
void set_discipline(ivl_discipline_t);
|
||||
ivl_discipline_t get_discipline(void) const;
|
||||
|
|
@ -119,8 +118,7 @@ class PWire : public LineInfo {
|
|||
// me the size and address ranges of the memory.
|
||||
std::list<pform_range_t>unpacked_;
|
||||
|
||||
enum_type_t*enum_type_;
|
||||
struct_type_t*struct_type_;
|
||||
data_type_t*set_data_type_;
|
||||
|
||||
ivl_discipline_t discipline_;
|
||||
|
||||
|
|
|
|||
|
|
@ -229,7 +229,10 @@ ostream&operator<<(ostream&out, const vector<netrange_t>&rlist)
|
|||
void NetNet::dump_net(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << type() << ": " << name()
|
||||
<< unpacked_dims_ << " unpacked dims=" << unpacked_dimensions() << " count=" << pin_count();
|
||||
<< unpacked_dims_ << " unpacked dims=" << unpacked_dimensions();
|
||||
if (!packed_dims_.empty())
|
||||
o << " packed dims=" << packed_dims_;
|
||||
o << " pin_count=" << pin_count();
|
||||
if (local_flag_)
|
||||
o << " (local)";
|
||||
o << " " << data_type_;
|
||||
|
|
@ -264,6 +267,9 @@ void NetNet::dump_net(ostream&o, unsigned ind) const
|
|||
if (! packed_dims_.empty())
|
||||
o << " packed dims: " << packed_dims_;
|
||||
|
||||
if (net_type_)
|
||||
o << " net_type_=" << typeid(*net_type_).name();
|
||||
|
||||
o << " (eref=" << peek_eref() << ", lref=" << peek_lref() << ")";
|
||||
if (scope())
|
||||
o << " scope=" << scope_path(scope());
|
||||
|
|
|
|||
77
elab_expr.cc
77
elab_expr.cc
|
|
@ -1553,7 +1553,9 @@ bool calculate_part(const LineInfo*li, Design*des, NetScope*scope,
|
|||
*/
|
||||
static NetExpr* check_for_struct_members(const LineInfo*li,
|
||||
Design*des, NetScope*scope,
|
||||
NetNet*net, const name_component_t&comp)
|
||||
NetNet*net,
|
||||
const list<index_component_t>&base_index,
|
||||
const name_component_t&comp)
|
||||
{
|
||||
unsigned long off;
|
||||
const netstruct_t::member_t*mem = get_struct_member(li, des, 0, net,
|
||||
|
|
@ -1563,12 +1565,14 @@ static NetExpr* check_for_struct_members(const LineInfo*li,
|
|||
unsigned use_width = mem->width();
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << li->get_fileline() << ": check_for_struct_members: "
|
||||
cerr << li->get_fileline() << ": debug: check_for_struct_members: "
|
||||
<< "Found struct member " << mem->name
|
||||
<< " At offset " << off
|
||||
<< ", member width = " << use_width << endl;
|
||||
}
|
||||
|
||||
// The struct member may be a packed array. Process index
|
||||
// expression that address the member element.
|
||||
if ( ! comp.index.empty() ) {
|
||||
// Evaluate all but the last index expression, into prefix_indices.
|
||||
list<long>prefix_indices;
|
||||
|
|
@ -1597,7 +1601,7 @@ static NetExpr* check_for_struct_members(const LineInfo*li,
|
|||
prefix_to_slice(mem->packed_dims, prefix_indices, poff, loff, lwid);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << li->get_fileline() << ": check_for_struct_members: "
|
||||
cerr << li->get_fileline() << ": debug: check_for_struct_members: "
|
||||
<< "Evaluate prefix gives slice loff=" << loff
|
||||
<< ", lwid=" << lwid << ", part select pwid=" << pwid << endl;
|
||||
}
|
||||
|
|
@ -1609,8 +1613,44 @@ static NetExpr* check_for_struct_members(const LineInfo*li,
|
|||
use_width = lwid;
|
||||
}
|
||||
|
||||
// If the base symbol has dimensions, then this is a packed
|
||||
// array of structures. Convert an array of indices to a
|
||||
// single part select. For example, "net" is a packed array
|
||||
// of struct, and "mem" is the struct member. In Verilog it
|
||||
// looks something like "net[idx].mem". We've already
|
||||
// converted "mem" to an offset into the packed struct, so now
|
||||
// we just canonicalize "[idx]" and add the ".mem" offset to
|
||||
// get a collapsed index.
|
||||
NetExpr*packed_base = 0;
|
||||
if(net->packed_dimensions() > 1) {
|
||||
list<index_component_t>tmp_index = base_index;
|
||||
index_component_t member_select;
|
||||
member_select.sel = index_component_t::SEL_BIT;
|
||||
member_select.msb = new PENumber(new verinum(off));
|
||||
tmp_index.push_back(member_select);
|
||||
packed_base = collapse_array_exprs(des, scope, li, net, tmp_index);
|
||||
ivl_assert(*li, packed_base);
|
||||
if (debug_elaborate) {
|
||||
cerr << li->get_fileline() << ": debug: check_for_struct_members: "
|
||||
<< "Got collapsed array expr: " << *packed_base << endl;
|
||||
}
|
||||
}
|
||||
|
||||
long tmp;
|
||||
if (packed_base && eval_as_long(tmp, packed_base)) {
|
||||
off = tmp;
|
||||
delete packed_base;
|
||||
packed_base = 0;
|
||||
}
|
||||
|
||||
NetESignal*sig = new NetESignal(net);
|
||||
NetEConst*base = make_const_val(off);
|
||||
NetExpr *base = packed_base? packed_base : make_const_val(off);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << li->get_fileline() << ": debug: check_for_struct_members: "
|
||||
<< "Convert packed indices/member select into part select: " << *base << endl;
|
||||
}
|
||||
|
||||
NetESelect*sel = new NetESelect(sig, base, use_width);
|
||||
return sel;
|
||||
}
|
||||
|
|
@ -2263,7 +2303,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
|||
|
||||
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);
|
||||
|
||||
// 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);
|
||||
|
||||
expr_type_ = use_enum->base_type();
|
||||
expr_width_ = use_enum->base_width();
|
||||
expr_width_ = use_enum->packed_width();
|
||||
min_width_ = expr_width_;
|
||||
signed_flag_ = par_enum->has_sign();
|
||||
|
||||
|
|
@ -2400,9 +2440,17 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
|||
// Check to see if we have a net and if so is it a structure?
|
||||
if (net != 0) {
|
||||
// If this net is a struct, the method name may be
|
||||
// a struct member.
|
||||
// a struct member. If it is, then we know the
|
||||
// width of this identifier my knowing the width
|
||||
// of the member. We don't even need to know
|
||||
// anything about positions in containing arrays.
|
||||
if (net->struct_type() != 0) {
|
||||
ivl_assert(*this, use_path.back().index.empty());
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: PEIdent::test_width: "
|
||||
<< "Net " << use_path << " is a struct, "
|
||||
<< "checking width of member " << method_name << endl;
|
||||
}
|
||||
|
||||
const netstruct_t::member_t*mem;
|
||||
unsigned long unused;
|
||||
|
|
@ -2603,10 +2651,19 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
// If this net is a struct, the method name may be
|
||||
// a struct member.
|
||||
if (net->struct_type() != 0) {
|
||||
ivl_assert(*this, use_path.back().index.empty());
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "PEIdent::elaborate_expr: "
|
||||
<< "Ident " << use_path
|
||||
<< " is a struct."
|
||||
<< " Expecting " << net->packed_dims().size()
|
||||
<< "-1 dimensions, "
|
||||
<< "got " << use_path.back().index.size() << "." << endl;
|
||||
}
|
||||
|
||||
return check_for_struct_members(this, des, scope,
|
||||
net, member_comp);
|
||||
net, use_path.back().index,
|
||||
member_comp);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
73
elab_lval.cc
73
elab_lval.cc
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2012 Stephen Williams (steve@icarus.com)
|
||||
* Copyright CERN 2012 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -682,6 +683,11 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope,
|
|||
netstruct_t*struct_type = reg->struct_type();
|
||||
ivl_assert(*this, struct_type);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: elaborate lval packed member: "
|
||||
<< "path_=" << path_ << endl;
|
||||
}
|
||||
|
||||
if (! struct_type->packed()) {
|
||||
cerr << get_fileline() << ": sorry: Only packed structures "
|
||||
<< "are supported in l-value." << endl;
|
||||
|
|
@ -689,6 +695,27 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope,
|
|||
return false;
|
||||
}
|
||||
|
||||
// Shouldn't be seeing unpacked arrays of packed structs...
|
||||
ivl_assert(*this, reg->unpacked_dimensions() == 0);
|
||||
|
||||
// This is a packed member, so the name is of the form
|
||||
// "a.b[...].c[...]" which means that the path_ must have at
|
||||
// least 2 components. We are processing "c[...]" at that
|
||||
// point (otherwise known as member_name) so we'll save a
|
||||
// reference to it in name_tail. We are also processing "b[]"
|
||||
// so save that as name_base.
|
||||
|
||||
ivl_assert(*this, path_.size() >= 2);
|
||||
|
||||
pform_name_t::const_reverse_iterator name_idx = path_.rbegin();
|
||||
ivl_assert(*this, name_idx->name == member_name);
|
||||
const name_component_t&name_tail = *name_idx;
|
||||
++ name_idx;
|
||||
const name_component_t&name_base = *name_idx;
|
||||
|
||||
// Calculate the offset within the packed structure of the
|
||||
// member, and any indices. We will add in the offset of the
|
||||
// struct into the packed array later.
|
||||
unsigned long off;
|
||||
const netstruct_t::member_t* member = struct_type->packed_member(member_name, off);
|
||||
|
||||
|
|
@ -701,14 +728,8 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope,
|
|||
|
||||
unsigned long use_width = member->width();
|
||||
|
||||
// We are processing the tail of a string of names. For
|
||||
// example, the verilog may be "a.b.c", so we are processing
|
||||
// "c" at this point. Of course, "c" is the name of the member
|
||||
// we are working on and "a.b" is the name of reg.
|
||||
const name_component_t&name_tail = path_.back();
|
||||
|
||||
if (name_tail.index.size() > member->packed_dims.size()) {
|
||||
cerr << get_fileline() << ": error: Too make index expressions for member." << endl;
|
||||
cerr << get_fileline() << ": error: Too many index expressions for member." << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -749,10 +770,48 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope,
|
|||
use_width = lwid;
|
||||
}
|
||||
|
||||
// The dimenions in the expression must match the packed
|
||||
// dimensions that are declared for the variable. For example,
|
||||
// if foo is a packed array of struct, then this expression
|
||||
// must be "b[n][m]" with the right number of dimensions to
|
||||
// match the declaration of "b".
|
||||
// Note that one of the packed dimensions is the packed struct
|
||||
// itself.
|
||||
ivl_assert(*this, name_base.index.size()+1 == reg->packed_dimensions());
|
||||
|
||||
// Generate an expression that takes the input array of
|
||||
// expressions and generates a canonical offset into the
|
||||
// packed array.
|
||||
NetExpr*packed_base = 0;
|
||||
if (reg->packed_dimensions() > 1) {
|
||||
list<index_component_t>tmp_index = name_base.index;
|
||||
index_component_t member_select;
|
||||
member_select.sel = index_component_t::SEL_BIT;
|
||||
member_select.msb = new PENumber(new verinum(off));
|
||||
tmp_index.push_back(member_select);
|
||||
packed_base = collapse_array_indices(des, scope, reg, tmp_index);
|
||||
}
|
||||
|
||||
long tmp;
|
||||
if (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);
|
||||
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
|
||||
{
|
||||
cerr << get_fileline() << ": error: Constant values not allowed "
|
||||
|
|
|
|||
67
elab_net.cc
67
elab_net.cc
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* 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
|
||||
* 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;
|
||||
}
|
||||
|
||||
// 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
|
||||
member of a struct. Take the name of the form "a.b.member",
|
||||
remove the member and store it into method_name, and retry
|
||||
the search with "a.b". */
|
||||
if (sig == 0 && path_.size() >= 2) {
|
||||
pform_name_t use_path = path_;
|
||||
method_name = peek_tail_name(use_path);
|
||||
use_path.pop_back();
|
||||
symbol_search(this, des, scope, use_path, sig, par, eve);
|
||||
method_name = path_tail.name;
|
||||
symbol_search(this, des, scope, path_prefix, sig, par, eve);
|
||||
|
||||
// Whoops, not a struct signal, so give up on this avenue.
|
||||
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.
|
||||
long widx = 0;
|
||||
|
||||
const name_component_t&name_tail = path_.back();
|
||||
list<long> unpacked_indices_const;
|
||||
|
||||
netstruct_t*struct_type = 0;
|
||||
if ((struct_type = sig->struct_type()) && !method_name.nil()) {
|
||||
|
||||
// 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)
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Signal " << sig->name() << " is a structure, "
|
||||
|
|
@ -489,13 +497,50 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
|||
lidx = member_off;
|
||||
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) {
|
||||
|
||||
// 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()
|
||||
<< " needs " << sig->unpacked_dimensions() << " indices,"
|
||||
<< " but got only " << name_tail.index.size() << "." << endl;
|
||||
<< " but got only " << path_tail.index.size() << "." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -504,7 +549,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
|||
// "unpacked_indices" array.
|
||||
list<NetExpr*>unpacked_indices;
|
||||
bool flag = indices_to_expressions(des, scope, this,
|
||||
name_tail.index, sig->unpacked_dimensions(),
|
||||
path_tail.index, sig->unpacked_dimensions(),
|
||||
true,
|
||||
unpacked_indices,
|
||||
unpacked_indices_const);
|
||||
|
|
@ -539,7 +584,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
|||
<< " to index l-value array." << endl;
|
||||
|
||||
/* 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()) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "can not select part of ";
|
||||
|
|
@ -566,7 +611,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
|||
lidx = lidx_tmp;
|
||||
}
|
||||
|
||||
} else if (!name_tail.index.empty()) {
|
||||
} else if (!path_tail.index.empty()) {
|
||||
if (sig->get_scalar()) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "can not select part of ";
|
||||
|
|
|
|||
|
|
@ -181,12 +181,12 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
|||
verinum max_value (0);
|
||||
if (enum_type->signed_flag) {
|
||||
min_value = v_not((pow(verinum(2),
|
||||
verinum(use_enum->base_width()-1)))) +
|
||||
verinum(use_enum->packed_width()-1)))) +
|
||||
one_value;
|
||||
max_value = pow(verinum(2), verinum(use_enum->base_width()-1)) -
|
||||
max_value = pow(verinum(2), verinum(use_enum->packed_width()-1)) -
|
||||
one_value;
|
||||
} else {
|
||||
max_value = pow(verinum(2), verinum(use_enum->base_width())) -
|
||||
max_value = pow(verinum(2), verinum(use_enum->packed_width())) -
|
||||
one_value;
|
||||
}
|
||||
min_value.has_sign(true);
|
||||
|
|
@ -249,15 +249,15 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
|||
// The values are explicitly sized to the width of the
|
||||
// base type of the enumeration.
|
||||
verinum tmp_val (0);
|
||||
if (cur_value.len() < use_enum->base_width()) {
|
||||
if (cur_value.len() < use_enum->packed_width()) {
|
||||
// Pad the current value if it is narrower than the final
|
||||
// width of the enum.
|
||||
tmp_val = pad_to_width (cur_value, use_enum->base_width());
|
||||
tmp_val = pad_to_width (cur_value, use_enum->packed_width());
|
||||
tmp_val.has_len(true);
|
||||
} else {
|
||||
// Truncate an oversized value. We report out of bound
|
||||
// values above. This may create duplicates.
|
||||
tmp_val = verinum(cur_value, use_enum->base_width());
|
||||
tmp_val = verinum(cur_value, use_enum->packed_width());
|
||||
}
|
||||
tmp_val.has_sign(enum_type->signed_flag);
|
||||
|
||||
|
|
|
|||
80
elab_sig.cc
80
elab_sig.cc
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2012 Stephen Williams (steve@icarus.com)
|
||||
* Copyright CERN 2012 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -19,6 +20,7 @@
|
|||
|
||||
# include "config.h"
|
||||
|
||||
# include <typeinfo>
|
||||
# include <cstdlib>
|
||||
# include <iostream>
|
||||
|
||||
|
|
@ -35,9 +37,12 @@
|
|||
# include "netenum.h"
|
||||
# include "netstruct.h"
|
||||
# include "netdarray.h"
|
||||
# include "netparray.h"
|
||||
# include "util.h"
|
||||
# include "ivl_assert.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static bool get_const_argument(NetExpr*exp, verinum&res)
|
||||
{
|
||||
switch (exp->expr_type()) {
|
||||
|
|
@ -892,6 +897,35 @@ static netstruct_t* elaborate_struct_type(Design*des, NetScope*scope,
|
|||
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)
|
||||
{
|
||||
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
|
||||
// struct type.
|
||||
if (struct_type_) {
|
||||
netstruct_t*use_type = elaborate_struct_type(des, scope, 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);
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Create signal " << wtype;
|
||||
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);
|
||||
|
||||
} else if (enum_type_) {
|
||||
ivl_assert(*this, struct_type_ == 0);
|
||||
ivl_assert(*this, ! enum_type_->names->empty());
|
||||
list<named_pexpr_t>::const_iterator sample_name = enum_type_->names->begin();
|
||||
} else if (enum_type_t*enum_type = dynamic_cast<enum_type_t*>(set_data_type_)) {
|
||||
list<named_pexpr_t>::const_iterator sample_name = enum_type->names->begin();
|
||||
netenum_t*use_enum = scope->enumeration_for_name(sample_name->name);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Create signal " << wtype
|
||||
<< " enumeration "
|
||||
<< name_ << " in scope " << scope_path(scope) << endl;
|
||||
<< name_ << " in scope " << scope_path(scope)
|
||||
<< " with packed_dimensions=" << packed_dimensions
|
||||
<< " and packed_width=" << use_enum->packed_width() << endl;
|
||||
}
|
||||
|
||||
sig = new NetNet(scope, name_, wtype, packed_dimensions, unpacked_dimensions, use_enum);
|
||||
|
||||
|
||||
} else if (netarray) {
|
||||
ivl_assert(*this, struct_type_==0);
|
||||
ivl_assert(*this, enum_type_==0);
|
||||
|
||||
if (debug_elaborate) {
|
||||
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());
|
||||
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 {
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Create signal " << wtype;
|
||||
|
|
|
|||
|
|
@ -163,6 +163,26 @@ NetScope* Design::find_scope(const std::list<hname_t>&path) const
|
|||
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
|
||||
* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* statements that were collected during the elaborate_scope pass and
|
||||
|
|
|
|||
|
|
@ -334,7 +334,7 @@ NetESFunc::NetESFunc(const char*n, netenum_t*enum_type, unsigned np)
|
|||
: name_(0), type_(enum_type->base_type()), enum_type_(enum_type), parms_(np)
|
||||
{
|
||||
name_ = lex_strings.add(n);
|
||||
expr_width(enum_type->base_width());
|
||||
expr_width(enum_type->packed_width());
|
||||
}
|
||||
|
||||
NetESFunc::~NetESFunc()
|
||||
|
|
|
|||
|
|
@ -32,6 +32,14 @@ netenum_t::~netenum_t()
|
|||
{
|
||||
}
|
||||
|
||||
long netenum_t::packed_width() const
|
||||
{
|
||||
if (msb_ >= lsb_)
|
||||
return msb_ - lsb_ + 1;
|
||||
else
|
||||
return lsb_ - msb_ + 1;
|
||||
}
|
||||
|
||||
bool netenum_t::insert_name(size_t name_idx, perm_string name, const verinum&val)
|
||||
{
|
||||
std::pair<std::map<perm_string,verinum>::iterator, bool> res;
|
||||
|
|
|
|||
10
netenum.h
10
netenum.h
|
|
@ -37,7 +37,7 @@ class netenum_t : public LineInfo, public nettype_base_t {
|
|||
~netenum_t();
|
||||
|
||||
ivl_variable_type_t base_type() const;
|
||||
unsigned base_width() const;
|
||||
long packed_width() const;
|
||||
bool has_sign() const;
|
||||
|
||||
// The size() is the number of enumeration literals.
|
||||
|
|
@ -73,14 +73,6 @@ class netenum_t : public LineInfo, public nettype_base_t {
|
|||
inline ivl_variable_type_t netenum_t::base_type() const
|
||||
{ return base_type_; }
|
||||
|
||||
inline unsigned netenum_t::base_width() const
|
||||
{
|
||||
if (msb_ >= lsb_)
|
||||
return msb_ - lsb_ + 1;
|
||||
else
|
||||
return lsb_ - msb_ + 1;
|
||||
}
|
||||
|
||||
inline size_t netenum_t::size() const { return names_.size(); }
|
||||
|
||||
inline bool netenum_t::has_sign() const { return signed_flag_; }
|
||||
|
|
|
|||
60
netlist.cc
60
netlist.cc
|
|
@ -476,6 +476,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins)
|
|||
|
||||
// Synthesize a single range to describe this canonical vector.
|
||||
packed_dims_.push_back(netrange_t(npins-1, 0));
|
||||
calculate_slice_widths_from_packed_dims_();
|
||||
|
||||
Link::DIR dir = Link::PASSIVE;
|
||||
|
||||
|
|
@ -521,6 +522,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
|
|||
eref_count_(0), lref_count_(0)
|
||||
{
|
||||
packed_dims_ = packed;
|
||||
calculate_slice_widths_from_packed_dims_();
|
||||
assert(s);
|
||||
|
||||
Link::DIR dir = Link::PASSIVE;
|
||||
|
|
@ -564,6 +566,32 @@ static unsigned calculate_count(const list<netrange_t>&unpacked)
|
|||
return sum;
|
||||
}
|
||||
|
||||
template <class T> static unsigned calculate_count(T*type)
|
||||
{
|
||||
long wid = type->packed_width();
|
||||
if (wid >= 0)
|
||||
return wid;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
void NetNet::calculate_slice_widths_from_packed_dims_(void)
|
||||
{
|
||||
if (packed_dims_.empty()) {
|
||||
slice_wids_.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
slice_wids_.resize(packed_dims_.size());
|
||||
|
||||
slice_wids_[0] = netrange_width(packed_dims_);
|
||||
list<netrange_t>::const_iterator cur = packed_dims_.begin();
|
||||
for (size_t idx = 1 ; idx < slice_wids_.size() ; idx += 1) {
|
||||
slice_wids_[idx] = slice_wids_[idx-1] / cur->width();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NetNet::NetNet(NetScope*s, perm_string n, Type t,
|
||||
const list<netrange_t>&packed,
|
||||
const list<netrange_t>&unpacked,
|
||||
|
|
@ -576,6 +604,9 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
|
|||
eref_count_(0), lref_count_(0)
|
||||
{
|
||||
packed_dims_ = packed;
|
||||
if (net_type)
|
||||
packed_dims_.push_back(netrange_t(calculate_count(net_type)-1, 0));
|
||||
calculate_slice_widths_from_packed_dims_();
|
||||
size_t idx = 0;
|
||||
for (list<netrange_t>::const_iterator cur = unpacked.begin()
|
||||
; cur != unpacked.end() ; ++cur, idx += 1) {
|
||||
|
|
@ -611,15 +642,6 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
|
|||
s->add_signal(this);
|
||||
}
|
||||
|
||||
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
|
||||
* vector with the msb_/lsb_ chosen to name enough bits for the entire
|
||||
|
|
@ -634,6 +656,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, netstruct_t*ty)
|
|||
eref_count_(0), lref_count_(0)
|
||||
{
|
||||
packed_dims_.push_back(netrange_t(calculate_count(ty)-1, 0));
|
||||
calculate_slice_widths_from_packed_dims_();
|
||||
Link::DIR dir = Link::PASSIVE;
|
||||
|
||||
switch (t) {
|
||||
|
|
@ -820,6 +843,25 @@ netdarray_t* NetNet::darray_type(void) const
|
|||
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
|
||||
{
|
||||
return discipline_;
|
||||
|
|
|
|||
22
netlist.h
22
netlist.h
|
|
@ -77,6 +77,7 @@ class NetEvWait;
|
|||
class PExpr;
|
||||
class PFunction;
|
||||
class netdarray_t;
|
||||
class netparray_t;
|
||||
class netenum_t;
|
||||
class netstruct_t;
|
||||
|
||||
|
|
@ -614,6 +615,7 @@ class NetNet : public NetObj, public PortType {
|
|||
// This form builds a NetNet from its record/enum definition.
|
||||
explicit NetNet(NetScope*s, perm_string n, Type t, netstruct_t*type);
|
||||
explicit NetNet(NetScope*s, perm_string n, Type t, netdarray_t*type);
|
||||
//explicit NetNet(NetScope*s, perm_string n, Type t, netparray_t*type);
|
||||
|
||||
virtual ~NetNet();
|
||||
|
||||
|
|
@ -662,7 +664,7 @@ class NetNet : public NetObj, public PortType {
|
|||
|
||||
/* The vector_width returns the bit width of the packed array,
|
||||
vector or scaler that is this NetNet object. */
|
||||
unsigned long vector_width() const { return netrange_width(packed_dims_); }
|
||||
inline unsigned long vector_width() const { return slice_width(0); }
|
||||
|
||||
/* Given a prefix of indices, figure out how wide the
|
||||
resulting slice would be. This is a generalization of the
|
||||
|
|
@ -694,6 +696,10 @@ class NetNet : public NetObj, public PortType {
|
|||
indices. (Currently only one array index is supported.) */
|
||||
inline unsigned unpacked_dimensions() const { return unpacked_dims_.size(); }
|
||||
|
||||
/* This methor returns 0 for scalars, but vectors and other
|
||||
PACKED arrays have packed dimensions. */
|
||||
inline size_t packed_dimensions() const { return packed_dims_.size(); }
|
||||
|
||||
// This is the number of array elements.
|
||||
unsigned unpacked_count() const;
|
||||
|
||||
|
|
@ -738,6 +744,14 @@ class NetNet : public NetObj, public PortType {
|
|||
std::list<netrange_t> packed_dims_;
|
||||
std::vector<netrange_t> unpacked_dims_;
|
||||
|
||||
// These are the widths of the various slice depths. There is
|
||||
// one entry in this vector for each packed dimension. The
|
||||
// value at N is the slice width if N indices are provided.
|
||||
//
|
||||
// For example: slice_wids_[0] is vector_width().
|
||||
void calculate_slice_widths_from_packed_dims_(void);
|
||||
std::vector<unsigned long> slice_wids_;
|
||||
|
||||
unsigned eref_count_;
|
||||
unsigned lref_count_;
|
||||
|
||||
|
|
@ -4161,6 +4175,12 @@ class Design {
|
|||
path is taken as an absolute scope name. Otherwise, the
|
||||
scope is located starting at the passed scope and working
|
||||
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(NetScope*, const std::list<hname_t>&path,
|
||||
NetScope::TYPE type = NetScope::MODULE) const;
|
||||
|
|
|
|||
116
netmisc.cc
116
netmisc.cc
|
|
@ -180,6 +180,21 @@ static NetExpr* make_add_expr(NetExpr*expr, long val)
|
|||
return res;
|
||||
}
|
||||
|
||||
static NetExpr* make_add_expr(const LineInfo*loc, NetExpr*expr1, NetExpr*expr2)
|
||||
{
|
||||
bool use_signed = expr1->has_sign() && expr2->has_sign();
|
||||
unsigned use_wid = expr1->expr_width();
|
||||
|
||||
if (expr2->expr_width() > use_wid)
|
||||
use_wid = expr2->expr_width();
|
||||
|
||||
expr1 = pad_to_width(expr1, use_wid, *loc);
|
||||
expr2 = pad_to_width(expr2, use_wid, *loc);
|
||||
|
||||
NetEBAdd*tmp = new NetEBAdd('+', expr1, expr2, use_wid, use_signed);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Subtract an existing expression from a signed constant.
|
||||
*/
|
||||
|
|
@ -254,6 +269,8 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb,
|
|||
if (is_up) offset -= wid - 1;
|
||||
/* Calculate the space needed for the offset. */
|
||||
unsigned min_wid = num_bits(offset);
|
||||
if (num_bits(soff) > min_wid)
|
||||
min_wid = num_bits(soff);
|
||||
/* We need enough space for the larger of the offset or the
|
||||
* base expression. */
|
||||
if (min_wid < base->expr_width()) min_wid = base->expr_width();
|
||||
|
|
@ -287,6 +304,8 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb,
|
|||
if ((soff-offset) == 0) return base;
|
||||
/* Calculate the space needed for the offset. */
|
||||
unsigned min_wid = num_bits(-offset);
|
||||
if (num_bits(soff) > min_wid)
|
||||
min_wid = num_bits(soff);
|
||||
/* We need enough space for the larger of the offset or the
|
||||
* base expression. */
|
||||
if (min_wid < base->expr_width()) min_wid = base->expr_width();
|
||||
|
|
@ -835,7 +854,8 @@ bool eval_as_double(double&value, NetExpr*expr)
|
|||
* expression if it is present.
|
||||
*/
|
||||
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
|
||||
// name, for example "foo".
|
||||
|
|
@ -873,6 +893,7 @@ hname_t eval_path_component(Design*des, NetScope*scope,
|
|||
return res;
|
||||
}
|
||||
|
||||
#if 1
|
||||
// Darn, the expression doesn't evaluate to a constant. That's
|
||||
// an error to be reported. And make up a fake index value to
|
||||
// return to the caller.
|
||||
|
|
@ -880,6 +901,8 @@ hname_t eval_path_component(Design*des, NetScope*scope,
|
|||
<< "Scope index expression is not constant: "
|
||||
<< *index.msb << endl;
|
||||
des->errors += 1;
|
||||
#endif
|
||||
error_flag = true;
|
||||
|
||||
delete tmp;
|
||||
return hname_t (comp.name, 0);
|
||||
|
|
@ -888,15 +911,20 @@ hname_t eval_path_component(Design*des, NetScope*scope,
|
|||
std::list<hname_t> eval_scope_path(Design*des, NetScope*scope,
|
||||
const pform_name_t&path)
|
||||
{
|
||||
bool path_error_flag = false;
|
||||
list<hname_t> res;
|
||||
|
||||
typedef pform_name_t::const_iterator pform_path_it;
|
||||
|
||||
for (pform_path_it cur = path.begin() ; cur != path.end(); ++ cur ) {
|
||||
const name_component_t&comp = *cur;
|
||||
res.push_back( eval_path_component(des,scope,comp) );
|
||||
res.push_back( eval_path_component(des,scope,comp,path_error_flag) );
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (path_error_flag) {
|
||||
cerr << "XXXXX: Errors evaluating path " << path << endl;
|
||||
}
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -1127,3 +1155,85 @@ bool evaluate_index_prefix(Design*des, NetScope*scope,
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluate the indices. The chain of indices are applied to the
|
||||
* packed indices of a NetNet to generate a canonical expression to
|
||||
* replace the exprs.
|
||||
*/
|
||||
NetExpr*collapse_array_exprs(Design*des, NetScope*scope,
|
||||
const LineInfo*loc, NetNet*net,
|
||||
const list<index_component_t>&indices)
|
||||
{
|
||||
// First elaborate all the expressions as far as possible.
|
||||
list<NetExpr*> exprs;
|
||||
list<long> exprs_const;
|
||||
bool flag = indices_to_expressions(des, scope, loc, indices,
|
||||
net->packed_dimensions(),
|
||||
false, exprs, exprs_const);
|
||||
ivl_assert(*loc, exprs.size() == net->packed_dimensions());
|
||||
|
||||
// Special Case: there is only 1 packed dimension, so the
|
||||
// single expression should already be naturally canonical.
|
||||
if (net->slice_width(1) == 1) {
|
||||
return *exprs.begin();
|
||||
}
|
||||
|
||||
const std::list<netrange_t>&pdims = net->packed_dims();
|
||||
std::list<netrange_t>::const_iterator pcur = pdims.begin();
|
||||
|
||||
list<NetExpr*>::iterator ecur = exprs.begin();
|
||||
NetExpr* base = 0;
|
||||
for (size_t idx = 0 ; idx < net->packed_dimensions() ; idx += 1, ++pcur, ++ecur) {
|
||||
unsigned cur_slice_width = net->slice_width(idx+1);
|
||||
// This normalizes the expression of this index based on
|
||||
// the msb/lsb values.
|
||||
NetExpr*tmp = normalize_variable_base(*ecur, pcur->get_msb(),
|
||||
pcur->get_lsb(),
|
||||
cur_slice_width, true);
|
||||
|
||||
// If this slice has width, then scale it.
|
||||
if (net->slice_width(idx+1) != 1) {
|
||||
unsigned min_wid = tmp->expr_width();
|
||||
if (num_bits(cur_slice_width) >= min_wid) {
|
||||
min_wid = num_bits(cur_slice_width)+1;
|
||||
tmp = pad_to_width(tmp, min_wid, *loc);
|
||||
}
|
||||
|
||||
tmp = make_mult_expr(tmp, cur_slice_width);
|
||||
}
|
||||
|
||||
// Now add it to the position we've accumulated so far.
|
||||
if (base) {
|
||||
base = make_add_expr(loc, base, tmp);
|
||||
} else {
|
||||
base = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a list of indices, treat them as packed indices and convert
|
||||
* them to an expression that normalizes the list to a single index
|
||||
* 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;
|
||||
}
|
||||
|
|
|
|||
18
netmisc.h
18
netmisc.h
|
|
@ -256,18 +256,14 @@ void eval_expr(NetExpr*&expr, int context_width =-1);
|
|||
bool eval_as_long(long&value, NetExpr*expr);
|
||||
bool eval_as_double(double&value, NetExpr*expr);
|
||||
|
||||
/*
|
||||
* Evaluate the component of a scope path to get an hname_t value. Do
|
||||
* the evaluation in the context of the given scope.
|
||||
*/
|
||||
extern hname_t eval_path_component(Design*des, NetScope*scope,
|
||||
const name_component_t&comp);
|
||||
|
||||
/*
|
||||
* Evaluate an entire scope path in the context of the given scope.
|
||||
*/
|
||||
extern std::list<hname_t> eval_scope_path(Design*des, NetScope*scope,
|
||||
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
|
||||
|
|
@ -310,4 +306,12 @@ extern void collapse_partselect_pv_to_concat(Design*des, NetNet*sig);
|
|||
extern bool evaluate_index_prefix(Design*des, NetScope*scope,
|
||||
list<long>&prefix_indices,
|
||||
const list<index_component_t>&indices);
|
||||
|
||||
extern NetExpr*collapse_array_indices(Design*des, NetScope*scope, NetNet*net,
|
||||
const std::list<index_component_t>&indices);
|
||||
|
||||
extern NetExpr*collapse_array_exprs(Design*des, NetScope*scope,
|
||||
const LineInfo*loc, NetNet*net,
|
||||
const list<index_component_t>&indices);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -17,31 +17,36 @@
|
|||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 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 "nettypes.h"
|
||||
# include <vector>
|
||||
|
||||
class netarray_t : public LineInfo {
|
||||
/*
|
||||
* Packed arrays.
|
||||
*/
|
||||
class netparray_t : public nettype_base_t, public LineInfo {
|
||||
|
||||
public:
|
||||
explicit netarray_t(const std::list<netrange_t>&packed);
|
||||
~netarray_t();
|
||||
explicit netparray_t(const std::list<netrange_t>&packed);
|
||||
~netparray_t();
|
||||
|
||||
unsigned packed_width() const;
|
||||
inline const std::list<netrange_t>& packed_dimensions() const
|
||||
{ return packed_dims_; }
|
||||
|
||||
private:
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
netarray_t::~netarray_t()
|
||||
inline netparray_t::~netparray_t()
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -26,6 +26,11 @@ nettype_base_t::~nettype_base_t()
|
|||
{
|
||||
}
|
||||
|
||||
long nettype_base_t::packed_width(void) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long netrange_width(const list<netrange_t>&packed)
|
||||
{
|
||||
unsigned wid = 1;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
class nettype_base_t {
|
||||
public:
|
||||
virtual ~nettype_base_t() =0;
|
||||
virtual long packed_width(void) const;
|
||||
};
|
||||
|
||||
class netrange_t {
|
||||
|
|
|
|||
111
parse.y
111
parse.y
|
|
@ -2,6 +2,7 @@
|
|||
%{
|
||||
/*
|
||||
* 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
|
||||
* 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 <gatetype> gatetype switchtype
|
||||
%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 <parmvalue> parameter_value_opt
|
||||
|
||||
|
|
@ -894,7 +895,7 @@ data_type /* IEEE1800-2005: A.2.2.1 */
|
|||
$$ = tmp;
|
||||
}
|
||||
| TYPE_IDENTIFIER range_opt
|
||||
{ if ($2) $$ = new array_type_t($1, $2);
|
||||
{ if ($2) $$ = new parray_type_t($1, $2);
|
||||
else $$ = $1;
|
||||
}
|
||||
| K_string
|
||||
|
|
@ -1842,11 +1843,11 @@ block_item_decl
|
|||
recovering from an error. */
|
||||
|
||||
| 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 ';'
|
||||
{ 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 ';'
|
||||
|
|
@ -3891,31 +3892,24 @@ module_item
|
|||
/* Modules can contain further sub-module definitions. */
|
||||
: module
|
||||
|
||||
/* This rule detects net declarations that possibly include a
|
||||
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_or_implicit delay3_opt net_variable_list ';'
|
||||
|
||||
| attribute_list_opt net_type
|
||||
primitive_type_opt unsigned_signed_opt range_opt
|
||||
delay3_opt
|
||||
net_variable_list ';'
|
||||
|
||||
{ ivl_variable_type_t dtype = $3;
|
||||
if (dtype == IVL_VT_NO_TYPE)
|
||||
dtype = IVL_VT_LOGIC;
|
||||
pform_makewire(@2, $5, $4, $7, $2, NetNet::NOT_A_PORT, dtype, $1);
|
||||
if ($6 != 0) {
|
||||
yyerror(@6, "sorry: net delays not supported.");
|
||||
delete $6;
|
||||
{ data_type_t*data_type = $3;
|
||||
if (data_type == 0) {
|
||||
data_type = new vector_type_t(IVL_VT_LOGIC, false, 0);
|
||||
FILE_NAME(data_type, @2);
|
||||
}
|
||||
pform_set_data_type(@2, data_type, $5, $2, $1);
|
||||
if ($4 != 0) {
|
||||
yyerror(@2, "sorry: net delays not supported.");
|
||||
delete $4;
|
||||
}
|
||||
delete $1;
|
||||
}
|
||||
|
||||
| attribute_list_opt K_wreal delay3 net_variable_list ';'
|
||||
{ pform_makewire(@2, 0, true, $4, NetNet::WIRE,
|
||||
NetNet::NOT_A_PORT, IVL_VT_REAL, $1);
|
||||
{ real_type_t*tmpt = new real_type_t(real_type_t::REAL);
|
||||
pform_set_data_type(@2, tmpt, $4, NetNet::WIRE, $1);
|
||||
if ($3 != 0) {
|
||||
yyerror(@3, "sorry: net delays not supported.");
|
||||
delete $3;
|
||||
|
|
@ -3924,8 +3918,8 @@ module_item
|
|||
}
|
||||
|
||||
| attribute_list_opt K_wreal net_variable_list ';'
|
||||
{ pform_makewire(@2, 0, true, $3, NetNet::WIRE,
|
||||
NetNet::NOT_A_PORT, IVL_VT_REAL, $1);
|
||||
{ real_type_t*tmpt = new real_type_t(real_type_t::REAL);
|
||||
pform_set_data_type(@2, tmpt, $3, NetNet::WIRE, $1);
|
||||
delete $1;
|
||||
}
|
||||
|
||||
|
|
@ -3933,15 +3927,13 @@ module_item
|
|||
net_decl_assigns, which are <name> = <expr> assignment
|
||||
declarations. */
|
||||
|
||||
| attribute_list_opt net_type
|
||||
primitive_type_opt unsigned_signed_opt range_opt
|
||||
delay3_opt net_decl_assigns ';'
|
||||
|
||||
{ ivl_variable_type_t dtype = $3;
|
||||
if (dtype == IVL_VT_NO_TYPE)
|
||||
dtype = IVL_VT_LOGIC;
|
||||
pform_makewire(@2, $5, $4, $6,
|
||||
str_strength, $7, $2, dtype);
|
||||
| attribute_list_opt net_type data_type_or_implicit delay3_opt net_decl_assigns ';'
|
||||
{ data_type_t*data_type = $3;
|
||||
if (data_type == 0) {
|
||||
data_type = new vector_type_t(IVL_VT_LOGIC, false, 0);
|
||||
FILE_NAME(data_type, @2);
|
||||
}
|
||||
pform_makewire(@2, $4, str_strength, $5, $2, data_type);
|
||||
if ($1) {
|
||||
yyerror(@2, "sorry: Attributes not supported "
|
||||
"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
|
||||
gives strength to the assignment drivers. */
|
||||
|
||||
| attribute_list_opt net_type
|
||||
primitive_type_opt unsigned_signed_opt
|
||||
drive_strength net_decl_assigns ';'
|
||||
|
||||
{ ivl_variable_type_t dtype = $3;
|
||||
if (dtype == IVL_VT_NO_TYPE)
|
||||
dtype = IVL_VT_LOGIC;
|
||||
pform_makewire(@2, 0, $4, 0, $5, $6, $2, dtype);
|
||||
| attribute_list_opt net_type data_type_or_implicit drive_strength net_decl_assigns ';'
|
||||
{ data_type_t*data_type = $3;
|
||||
if (data_type == 0) {
|
||||
data_type = new vector_type_t(IVL_VT_LOGIC, false, 0);
|
||||
FILE_NAME(data_type, @2);
|
||||
}
|
||||
pform_makewire(@2, 0, $4, $5, $2, data_type);
|
||||
if ($1) {
|
||||
yyerror(@2, "sorry: Attributes not supported "
|
||||
"on net declaration assignments.");
|
||||
delete $1;
|
||||
}
|
||||
}
|
||||
|
||||
| attribute_list_opt K_wreal net_decl_assigns ';'
|
||||
{ pform_makewire(@2, 0, true, 0, str_strength, $3,
|
||||
NetNet::WIRE, IVL_VT_REAL);
|
||||
{ real_type_t*data_type = new real_type_t(real_type_t::REAL);
|
||||
pform_makewire(@2, 0, str_strength, $3, NetNet::WIRE, data_type);
|
||||
if ($1) {
|
||||
yyerror(@2, "sorry: Attributes not supported "
|
||||
"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
|
||||
: K_logic { $$ = IVL_VT_LOGIC; }
|
||||
| K_bit { $$ = IVL_VT_BOOL; /* IEEE1800 / IEEE1364-2009 */}
|
||||
;
|
||||
|
||||
primitive_type_opt : primitive_type { $$ = $1; } | { $$ = IVL_VT_NO_TYPE; } ;
|
||||
|
||||
net_type
|
||||
: K_wire { $$ = NetNet::WIRE; }
|
||||
| K_tri { $$ = NetNet::TRI; }
|
||||
|
|
@ -4890,10 +4857,10 @@ function_range_or_type_opt
|
|||
so that bit ranges can be assigned. */
|
||||
register_variable
|
||||
: IDENTIFIER dimensions_opt
|
||||
{ perm_string ident_name = lex_strings.make($1);
|
||||
pform_makewire(@1, ident_name, NetNet::REG,
|
||||
{ perm_string name = lex_strings.make($1);
|
||||
pform_makewire(@1, name, NetNet::REG,
|
||||
NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0);
|
||||
pform_set_reg_idx(ident_name, $2);
|
||||
pform_set_reg_idx(name, $2);
|
||||
$$ = $1;
|
||||
}
|
||||
| IDENTIFIER '=' expression
|
||||
|
|
|
|||
190
pform.cc
190
pform.cc
|
|
@ -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.
|
||||
*/
|
||||
static void pform_set_net_range(perm_string name,
|
||||
NetNet::Type net_type,
|
||||
const list<pform_range_t>*range,
|
||||
bool signed_flag,
|
||||
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.");
|
||||
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) {
|
||||
/* 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);
|
||||
}
|
||||
|
||||
void pform_set_net_range(list<perm_string>*names,
|
||||
static void pform_set_net_range(list<perm_string>*names,
|
||||
list<pform_range_t>*range,
|
||||
bool signed_flag,
|
||||
ivl_variable_type_t dt,
|
||||
NetNet::Type net_type,
|
||||
std::list<named_pexpr_t>*attr)
|
||||
{
|
||||
for (list<perm_string>::iterator cur = names->begin()
|
||||
; cur != names->end() ; ++ 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;
|
||||
|
|
@ -1997,7 +2012,7 @@ void pform_module_define_port(const struct vlltype&li,
|
|||
}
|
||||
|
||||
} 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;
|
||||
range = 0;
|
||||
|
||||
|
|
@ -2017,7 +2032,7 @@ void pform_module_define_port(const struct vlltype&li,
|
|||
cur->set_signed(signed_flag);
|
||||
|
||||
if (struct_type) {
|
||||
cur->set_struct_type(struct_type);
|
||||
cur->set_packed_type(struct_type);
|
||||
|
||||
} else if (range == 0) {
|
||||
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);
|
||||
/* This has already been done for real variables. */
|
||||
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.
|
||||
*/
|
||||
void pform_makewire(const vlltype&li,
|
||||
list<pform_range_t>*range,
|
||||
bool signed_flag,
|
||||
list<PExpr*>*delay,
|
||||
str_pair_t str,
|
||||
net_decl_assign_t*decls,
|
||||
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;
|
||||
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) {
|
||||
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);
|
||||
if (cur != 0) {
|
||||
PEIdent*lval = new PEIdent(first->name);
|
||||
|
|
@ -2705,7 +2724,7 @@ void pform_set_port_type(const struct vlltype&li,
|
|||
; cur != names->end() ; ++ cur ) {
|
||||
perm_string txt = *cur;
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -2764,9 +2783,9 @@ void pform_set_reg_time(list<perm_string>*names, list<named_pexpr_t>*attr)
|
|||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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()
|
||||
; cur != names->end() ; ++ 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
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)
|
||||
{
|
||||
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, attr);
|
||||
return;
|
||||
ivl_variable_type_t base_type = data_type->figure_packed_base_type();
|
||||
if (base_type == IVL_VT_NO_TYPE) {
|
||||
VLerror(li, "Compound type is not PACKED in this context.");
|
||||
}
|
||||
|
||||
if (struct_type_t*struct_type = dynamic_cast<struct_type_t*> (data_type)) {
|
||||
pform_set_struct_type(struct_type, names, attr);
|
||||
return;
|
||||
PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, base_type);
|
||||
net->set_packed_type(data_type);
|
||||
pform_bind_attributes(net->attributes, attr, true);
|
||||
}
|
||||
|
||||
if (enum_type_t*enum_type = dynamic_cast<enum_type_t*> (data_type)) {
|
||||
pform_set_enum(li, enum_type, names, attr);
|
||||
return;
|
||||
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)
|
||||
{
|
||||
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,
|
||||
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.
|
||||
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);
|
||||
|
||||
cur->set_signed(enum_type->signed_flag);
|
||||
|
||||
assert(enum_type->range.get() != 0);
|
||||
assert(enum_type->range->size() == 1);
|
||||
cur->set_range(*enum_type->range, SR_NET);
|
||||
cur->set_enumeration(enum_type);
|
||||
//XXXXcur->set_range(*enum_type->range, SR_NET);
|
||||
cur->set_packed_type(enum_type);
|
||||
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
|
||||
// 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()
|
||||
; cur != names->end() ; ++ 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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*>*out = new svector<PWire*>(names->size());
|
||||
|
|
|
|||
19
pform.h
19
pform.h
|
|
@ -265,13 +265,11 @@ extern void pform_makewire(const struct vlltype&li,
|
|||
|
||||
/* This form handles assignment declarations. */
|
||||
extern void pform_makewire(const struct vlltype&li,
|
||||
list<pform_range_t>*range,
|
||||
bool signed_flag,
|
||||
list<PExpr*>*delay,
|
||||
str_pair_t str,
|
||||
net_decl_assign_t*assign_list,
|
||||
NetNet::Type type,
|
||||
ivl_variable_type_t);
|
||||
data_type_t*data_type);
|
||||
|
||||
/* This form handles nets declared as structures. (See pform_struct_type.cc) */
|
||||
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,
|
||||
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,
|
||||
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_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_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);
|
||||
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);
|
||||
|
||||
/* pform_set_attrib and pform_set_type_attrib exist to support the
|
||||
$attribute syntax, which can only set string values to
|
||||
|
|
|
|||
|
|
@ -146,6 +146,13 @@ void data_type_t::pform_dump(ostream&out, unsigned indent) const
|
|||
out << setw(indent) << "" << typeid(*this).name() << endl;
|
||||
}
|
||||
|
||||
void parray_type_t::pform_dump(ostream&out, unsigned indent) const
|
||||
{
|
||||
out << setw(indent) << "" << "Packed array " << "[...]"
|
||||
<< " of:" << endl;
|
||||
base_type->pform_dump(out, indent+4);
|
||||
}
|
||||
|
||||
static void dump_attributes_map(ostream&out,
|
||||
const map<perm_string,PExpr*>&attributes,
|
||||
int ind)
|
||||
|
|
@ -391,6 +398,10 @@ void PWire::dump(ostream&out, unsigned ind) const
|
|||
}
|
||||
|
||||
out << ";" << endl;
|
||||
if (set_data_type_) {
|
||||
set_data_type_->pform_dump(out, 8);
|
||||
}
|
||||
|
||||
dump_attributes_map(out, attributes, 8);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,17 +21,17 @@
|
|||
# include "parse_misc.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);
|
||||
}
|
||||
|
||||
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()
|
||||
; cur != names->end() ; ++ cur) {
|
||||
pform_set_string_type(string_type, *cur, attr);
|
||||
pform_set_string_type(string_type, *cur, net_type, attr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,12 +21,15 @@
|
|||
# include "parse_misc.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;
|
||||
|
||||
for (list<struct_member_t*>::iterator cur = struct_type->members->begin()
|
||||
; cur != struct_type->members->end() ; ++ cur) {
|
||||
for (list<struct_member_t*>::iterator cur = members->begin()
|
||||
; cur != members->end() ; ++ 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,
|
||||
* 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);
|
||||
net->set_struct_type(struct_type);
|
||||
PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, base_type);
|
||||
net->set_packed_type(struct_type);
|
||||
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) {
|
||||
pform_set_packed_struct(struct_type, name, attr);
|
||||
pform_set_packed_struct(struct_type, name, net_type, attr);
|
||||
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);
|
||||
}
|
||||
|
||||
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()
|
||||
; 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,
|
||||
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);
|
||||
FILE_NAME(cur, li);
|
||||
cur->set_struct_type(struct_type);
|
||||
cur->set_packed_type(struct_type);
|
||||
}
|
||||
|
||||
void pform_makewire(const struct vlltype&li,
|
||||
|
|
|
|||
|
|
@ -27,3 +27,18 @@ data_type_t::~data_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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,9 +69,12 @@ struct decl_assignment_t {
|
|||
* "data_type" rule in the parse rule. We make the type virtual so
|
||||
* that dynamic types will work.
|
||||
*/
|
||||
struct data_type_t : public LineInfo {
|
||||
class data_type_t : public LineInfo {
|
||||
public:
|
||||
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.
|
||||
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 {
|
||||
virtual ivl_variable_type_t figure_packed_base_type(void)const;
|
||||
bool packed_flag;
|
||||
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 {
|
||||
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,
|
||||
std::list<pform_range_t>*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;
|
||||
bool signed_flag;
|
||||
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 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 {
|
||||
inline explicit array_type_t(data_type_t*btype, std::list<pform_range_t>*pd)
|
||||
struct parray_type_t : public data_type_t {
|
||||
inline explicit parray_type_t(data_type_t*btype, std::list<pform_range_t>*pd)
|
||||
: base_type(btype), packed_dims(pd) { }
|
||||
virtual ivl_variable_type_t figure_packed_base_type(void)const;
|
||||
virtual void pform_dump(std::ostream&out, unsigned indent) const;
|
||||
|
||||
data_type_t*base_type;
|
||||
std::auto_ptr< list<pform_range_t> > packed_dims;
|
||||
};
|
||||
|
|
|
|||
203
symbol_search.cc
203
symbol_search.cc
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* 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
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -19,12 +20,145 @@
|
|||
|
||||
# include "netlist.h"
|
||||
# include "netmisc.h"
|
||||
# include <cassert>
|
||||
# include "ivl_assert.h"
|
||||
|
||||
|
||||
/*
|
||||
* 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,
|
||||
pform_name_t path,
|
||||
NetNet*&net,
|
||||
|
|
@ -32,58 +166,19 @@ NetScope*symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
|||
NetEvent*&eve,
|
||||
const NetExpr*&ex1, const NetExpr*&ex2)
|
||||
{
|
||||
assert(scope);
|
||||
bool hier_path = false;
|
||||
|
||||
/* 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();
|
||||
}
|
||||
|
||||
symbol_search_results recurse;
|
||||
bool flag = symbol_search(li, des, scope, path, &recurse);
|
||||
if (! flag) {
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ extern "C" ivl_variable_type_t ivl_enum_type(ivl_enumtype_t net)
|
|||
extern "C" unsigned ivl_enum_width(ivl_enumtype_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->base_width();
|
||||
return net->packed_width();
|
||||
}
|
||||
|
||||
extern "C" int ivl_enum_signed(ivl_enumtype_t net)
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
# include "parse_types.h"
|
||||
// Need this for parse_errors?
|
||||
# include "parse_api.h"
|
||||
# include <cassert>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
|
@ -38,6 +39,54 @@ Architecture::~Architecture()
|
|||
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()
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ class ComponentBase;
|
|||
class Entity;
|
||||
class Expression;
|
||||
class ExpName;
|
||||
class GenerateStatement;
|
||||
class SequentialStmt;
|
||||
class Signal;
|
||||
class named_expr_t;
|
||||
|
|
@ -71,6 +72,18 @@ class Architecture : public Scope, public LineInfo {
|
|||
// Elaborate this architecture in the context of the given 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
|
||||
// of the specified entity. This method is used by the
|
||||
// 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
|
||||
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
|
||||
};
|
||||
|
||||
|
|
@ -98,9 +123,9 @@ class GenerateStatement : public Architecture::Statement {
|
|||
GenerateStatement(perm_string gname, std::list<Architecture::Statement*>&s);
|
||||
~GenerateStatement();
|
||||
|
||||
protected:
|
||||
inline perm_string get_name() { return name_; }
|
||||
inline perm_string get_name() const { return name_; }
|
||||
|
||||
protected:
|
||||
int elaborate_statements(Entity*ent, Architecture*arc);
|
||||
int emit_statements(ostream&out, Entity*ent, Architecture*arc);
|
||||
void dump_statements(ostream&out, int indent) const;
|
||||
|
|
|
|||
|
|
@ -133,7 +133,9 @@ int GenerateStatement::elaborate_statements(Entity*ent, Architecture*arc)
|
|||
int ForGenerate::elaborate(Entity*ent, Architecture*arc)
|
||||
{
|
||||
int errors = 0;
|
||||
arc->push_genvar_type(genvar_, lsb_->probe_type(ent, arc));
|
||||
errors += elaborate_statements(ent, arc);
|
||||
arc->pop_genvar_type();
|
||||
return errors;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -183,16 +183,19 @@ int GenerateStatement::emit_statements(ostream&out, Entity*ent, Architecture*arc
|
|||
int ForGenerate::emit(ostream&out, Entity*ent, Architecture*arc)
|
||||
{
|
||||
int errors = 0;
|
||||
out << "genvar \\" << genvar_ << " ;" << endl;
|
||||
out << "for (\\" << genvar_ << " = ";
|
||||
out << "genvar \\" << get_name() << ":" << genvar_ << " ;" << endl;
|
||||
out << "for (\\" << get_name() << ":" << genvar_ << " = ";
|
||||
errors += lsb_->emit(out, ent, arc);
|
||||
out << "; \\" << genvar_ << " <= ";
|
||||
out << "; \\" << get_name() << ":" << genvar_ << " <= ";
|
||||
errors += msb_->emit(out, ent, arc);
|
||||
out << "; \\" << genvar_ << " = \\" << genvar_ << " + 1)"
|
||||
out << "; \\" << get_name() << ":" << genvar_ << " = \\" << get_name() << ":" << genvar_ << " + 1)"
|
||||
<< " begin : \\" << get_name() << endl;
|
||||
|
||||
arc->push_genvar_emit(genvar_, this);
|
||||
|
||||
errors += emit_statements(out, ent, arc);
|
||||
|
||||
arc->pop_genvar_emit();
|
||||
out << "end" << endl;
|
||||
|
||||
return errors;
|
||||
|
|
|
|||
|
|
@ -20,12 +20,16 @@
|
|||
*/
|
||||
|
||||
# include "StringHeap.h"
|
||||
# include <fstream>
|
||||
|
||||
const int GN_KEYWORD_2008 = 0x0001;
|
||||
|
||||
// TRUE if processing is supposed to dump progress to stderr.
|
||||
extern bool verbose_flag;
|
||||
|
||||
extern bool debug_elaboration;
|
||||
extern std::ofstream debug_log_file;
|
||||
|
||||
extern StringHeapLex lex_strings;
|
||||
|
||||
extern StringHeapLex filename_strings;
|
||||
|
|
|
|||
|
|
@ -424,3 +424,15 @@ void prange_t::dump(ostream&out, int indent) const
|
|||
out << setw(indent) << "" << (direction_ ? "downto" : "to");
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,28 +50,6 @@ bool Expression::symbolic_compare(const Expression*) const
|
|||
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)
|
||||
: base_(bas), name_(nam)
|
||||
{
|
||||
|
|
@ -366,6 +344,36 @@ const char* ExpName::name() const
|
|||
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)
|
||||
: ExpBinary(op1, op2), fun_(ty)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ class Expression : public LineInfo {
|
|||
|
||||
// Debug dump of the expression.
|
||||
virtual void dump(ostream&out, int indent = 0) const =0;
|
||||
virtual ostream& dump_inline(ostream&out) const;
|
||||
|
||||
protected:
|
||||
// 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);
|
||||
}
|
||||
|
||||
static inline ostream& operator <<(ostream&out, const Expression&exp)
|
||||
{
|
||||
return exp.dump_inline(out);
|
||||
}
|
||||
|
||||
class ExpUnary : public Expression {
|
||||
|
||||
public:
|
||||
|
|
@ -473,6 +479,7 @@ class ExpInteger : public Expression {
|
|||
bool is_primary(void) const;
|
||||
bool evaluate(ScopeBase*scope, int64_t&val) const;
|
||||
void dump(ostream&out, int indent = 0) const;
|
||||
virtual ostream& dump_inline(ostream&out) const;
|
||||
|
||||
private:
|
||||
int64_t value_;
|
||||
|
|
@ -528,6 +535,8 @@ class ExpName : public Expression {
|
|||
void dump(ostream&out, int indent = 0) const;
|
||||
const char* name() const;
|
||||
|
||||
void set_range(Expression*msb, Expression*lsb);
|
||||
|
||||
private:
|
||||
const VType* elaborate_adjust_type_with_range_(Entity*ent, Architecture*arc, const VType*type);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* 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
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -25,6 +26,7 @@
|
|||
# include <iostream>
|
||||
# include <typeinfo>
|
||||
# include "parse_types.h"
|
||||
# include "compiler.h"
|
||||
# include "ivl_assert.h"
|
||||
|
||||
using namespace std;
|
||||
|
|
@ -87,6 +89,17 @@ int ExpName::elaborate_lval_(Entity*ent, Architecture*arc, bool is_sequ, ExpName
|
|||
{
|
||||
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()) {
|
||||
cerr << get_fileline() << ": sorry: I don't know how to elaborate "
|
||||
<< "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();
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// 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;
|
||||
|
||||
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);
|
||||
|
||||
suffix_type = element_type;
|
||||
|
||||
}
|
||||
|
||||
if (suffix_type == 0) {
|
||||
|
|
@ -654,6 +700,10 @@ const VType* ExpName::probe_prefixed_type_(Entity*ent, Architecture*arc) const
|
|||
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
|
||||
// the name of a member.
|
||||
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))
|
||||
return ctype;
|
||||
|
||||
if (const VType*gtype = arc->probe_genvar_type(name_)) {
|
||||
return gtype;
|
||||
}
|
||||
|
||||
cerr << get_fileline() << ": error: Signal/variable " << name_
|
||||
<< " not found in this context." << endl;
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -610,7 +610,12 @@ int ExpName::emit_as_prefix_(ostream&out, Entity*ent, Architecture*arc)
|
|||
}
|
||||
|
||||
out << "\\" << name_ << " ";
|
||||
ivl_assert(*this, index_ == 0);
|
||||
if (index_) {
|
||||
out << "[";
|
||||
errors += index_->emit(out, ent, arc);
|
||||
out << "]";
|
||||
ivl_assert(*this, lsb_ == 0);
|
||||
}
|
||||
out << ".";
|
||||
return errors;
|
||||
}
|
||||
|
|
@ -623,7 +628,12 @@ int ExpName::emit(ostream&out, Entity*ent, Architecture*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_ << " ";
|
||||
|
||||
if (index_) {
|
||||
out << "[";
|
||||
errors += index_->emit(out, ent, arc);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
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
|
||||
* 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
|
||||
* information to the file named <path>.
|
||||
*
|
||||
* elaboration=<path>
|
||||
* Enable debugging of elaboratin by dumping elaboration
|
||||
* process information to the file named <path>.
|
||||
*
|
||||
* entities=<path>
|
||||
* Enable debugging of elaborated entities by writing the
|
||||
* elaboration results to the file named <path>.
|
||||
|
|
@ -94,7 +99,10 @@ bool verbose_flag = false;
|
|||
// Where to dump design entities
|
||||
const char*dump_design_entities_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 parser_cleanup();
|
||||
|
|
@ -109,6 +117,10 @@ static void process_debug_token(const char*word)
|
|||
dump_design_entities_path = strdup(word+9);
|
||||
} else if (strncmp(word, "libraries=", 10) == 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (debug_log_path) {
|
||||
debug_log_file.open(debug_log_path);
|
||||
}
|
||||
|
||||
if ( (rc = mkdir(work_path, 0777)) < 0 ) {
|
||||
if (errno != EEXIST) {
|
||||
fprintf(stderr, "Icarus Verilog VHDL unable to create work directory %s, errno=%d\n", work_path, errno);
|
||||
|
|
|
|||
130
vhdlpp/parse.y
130
vhdlpp/parse.y
|
|
@ -7,6 +7,7 @@
|
|||
%{
|
||||
/*
|
||||
* 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
|
||||
* 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();
|
||||
}
|
||||
|
||||
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,
|
||||
const VType*type)
|
||||
{
|
||||
|
|
@ -220,8 +190,6 @@ static list<VTypeRecord::element_t*>* record_elements(list<perm_string>*names,
|
|||
char*text;
|
||||
|
||||
std::list<perm_string>* name_list;
|
||||
std::vector<perm_string>* compound_name;
|
||||
std::list<std::vector<perm_string>* >* compound_name_list;
|
||||
|
||||
bool flag;
|
||||
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_logical expression_logical_and expression_logical_or
|
||||
%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> simple_expression term waveform_element
|
||||
%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> name_list expression_list
|
||||
%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_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 <name_list> logical_name_list identifier_list
|
||||
%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> sequential_statement if_statement signal_assignment_statement
|
||||
|
|
@ -1497,8 +1464,8 @@ mode
|
|||
|
||||
mode_opt : mode {$$ = $1;} | {$$ = PORT_NONE;} ;
|
||||
|
||||
name
|
||||
: IDENTIFIER
|
||||
name /* IEEE 1076-2008 P8.1 */
|
||||
: IDENTIFIER /* simple_name (IEEE 1076-2008 P8.2) */
|
||||
{ ExpName*tmp = new ExpName(lex_strings.make($1));
|
||||
FILE_NAME(tmp, @1);
|
||||
delete[]$1;
|
||||
|
|
@ -1506,10 +1473,7 @@ name
|
|||
}
|
||||
|
||||
| selected_name
|
||||
{ ExpName*tmp = make_name_from_prefix(@1, $1);
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
{ $$ = $1; }
|
||||
|
||||
/* Note that this rule can match array element selects and various
|
||||
function calls. The only way we can tell the difference is from
|
||||
|
|
@ -1534,8 +1498,8 @@ name
|
|||
$$ = tmp;
|
||||
}
|
||||
| selected_name '(' range ')'
|
||||
{ ExpName*tmp = make_name_from_prefix(@1, $1, $3->msb(), $3->lsb());
|
||||
delete $1;
|
||||
{ ExpName*tmp = dynamic_cast<ExpName*> ($1);
|
||||
tmp->set_range($3->msb(), $3->lsb());
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
|
@ -1667,20 +1631,9 @@ port_map_aspect_opt
|
|||
| { $$ = 0; }
|
||||
;
|
||||
|
||||
prefix
|
||||
: IDENTIFIER
|
||||
{ std::vector<perm_string>* tmp = new std::vector<perm_string>();
|
||||
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
|
||||
|
||||
prefix /* IEEE 1076-2008 P8.1 */
|
||||
: name
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
|
|
@ -1926,34 +1879,42 @@ secondary_unit
|
|||
| package_body
|
||||
;
|
||||
|
||||
selected_name
|
||||
selected_name /* IEEE 1076-2008 P8.3 */
|
||||
: prefix '.' suffix
|
||||
{ std::vector<perm_string>* tmp = $1;
|
||||
tmp->push_back(lex_strings.make($3));
|
||||
{ Expression*pfx = $1;
|
||||
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;
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
selected_names
|
||||
: selected_names ',' selected_name
|
||||
{
|
||||
std::list<std::vector<perm_string>* >* tmp = $1;
|
||||
{ std::list<Expression*>* tmp = $1;
|
||||
tmp->push_back($3);
|
||||
$$ = tmp;
|
||||
}
|
||||
| selected_name
|
||||
{
|
||||
std::list<std::vector<perm_string>* >* tmp = new std::list<std::vector<perm_string>* >();
|
||||
{ std::list<Expression*>* tmp = new std::list<Expression*>();
|
||||
tmp->push_back($1);
|
||||
$$ = 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
|
||||
rules, but is a convenient place to attach use_clause actions. */
|
||||
selected_name_use
|
||||
selected_name_lib
|
||||
: IDENTIFIER '.' K_all
|
||||
{ library_use(@1, active_scope, 0, $1, 0);
|
||||
delete[]$1;
|
||||
|
|
@ -1971,9 +1932,9 @@ selected_name_use
|
|||
}
|
||||
;
|
||||
|
||||
selected_names_use
|
||||
: selected_names_use ',' selected_name_use
|
||||
| selected_name_use
|
||||
selected_names_lib
|
||||
: selected_names_lib ',' selected_name_lib
|
||||
| selected_name_lib
|
||||
;
|
||||
|
||||
|
||||
|
|
@ -2102,16 +2063,11 @@ subtype_indication
|
|||
|
||||
suffix
|
||||
: IDENTIFIER
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
{ $$ = $1; }
|
||||
| CHARACTER_LITERAL
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
{ $$ = $1; }
|
||||
| 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");
|
||||
}
|
||||
;
|
||||
|
|
@ -2191,30 +2147,28 @@ type_definition
|
|||
|
||||
use_clause
|
||||
: K_use selected_names ';'
|
||||
{
|
||||
$$ = $2;
|
||||
}
|
||||
{ $$ = $2; }
|
||||
| K_use error ';'
|
||||
{ errormsg(@1, "Syntax error in use clause.\n"); yyerrok; }
|
||||
;
|
||||
|
||||
use_clause_lib
|
||||
: K_use selected_names_use ';'
|
||||
: K_use selected_names_lib ';'
|
||||
| K_use error ';'
|
||||
{ errormsg(@1, "Syntax error in use clause.\n"); yyerrok; }
|
||||
;
|
||||
|
||||
use_clauses
|
||||
: use_clauses use_clause
|
||||
| use_clause
|
||||
use_clauses_lib
|
||||
: use_clauses_lib use_clause_lib
|
||||
| use_clause_lib
|
||||
;
|
||||
|
||||
use_clauses_opt
|
||||
: use_clauses
|
||||
: use_clauses_lib
|
||||
|
|
||||
;
|
||||
|
||||
variable_assignment_statement
|
||||
variable_assignment_statement /* IEEE 1076-2008 P10.6.1 */
|
||||
: name VASSIGN expression ';'
|
||||
{ VariableSeqAssignment*tmp = new VariableSeqAssignment($1, $3);
|
||||
FILE_NAME(tmp, @1);
|
||||
|
|
|
|||
|
|
@ -246,6 +246,8 @@ class VTypeDef : public VType {
|
|||
explicit VTypeDef(perm_string name, const VType*is);
|
||||
~VTypeDef();
|
||||
|
||||
inline perm_string peek_name() const { return name_; }
|
||||
|
||||
// If the type is not given a definition in the constructor,
|
||||
// then this must be used to set the definition later.
|
||||
void set_definition(const VType*is);
|
||||
|
|
|
|||
Loading…
Reference in New Issue