Rework PEIdent::test_width() to use new-style symbol_search().

This fixes issue #527.
This commit is contained in:
Martin Whitaker 2021-07-31 14:18:52 +01:00
parent e547a8355d
commit 83d9b5deda
1 changed files with 74 additions and 89 deletions

View File

@ -3966,12 +3966,6 @@ unsigned PEIdent::test_width_method_(Design*des, NetScope*scope, width_mode_t&)
unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
{
NetNet* net = 0;
ivl_type_t cls_val = 0;
const NetExpr*par = 0;
ivl_type_t par_type = 0;
NetEvent* eve = 0;
NetScope*use_scope = scope;
if (package_) {
use_scope = des->find_package(package_->pscope_name());
@ -3982,8 +3976,8 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
return tmp;
}
NetScope*found_in = symbol_search(this, des, use_scope, path_,
net, par, eve, par_type, cls_val);
symbol_search_results sr;
symbol_search(this, des, use_scope, path_, &sr);
// If there is a part/bit select expression, then process it
// here. This constrains the results no matter what kind the
@ -3994,7 +3988,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
if (!name_tail.index.empty()) {
const index_component_t&index_tail = name_tail.index.back();
// Skip full array word net selects.
if (!net || (name_tail.index.size() > net->unpacked_dimensions())) {
if (!sr.net || (name_tail.index.size() > sr.net->unpacked_dimensions())) {
use_sel = index_tail.sel;
}
}
@ -4029,7 +4023,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
// slice width will be. If not, then assume it will be a
// simple bit select. If the net only has a single dimension
// then this is still a simple bit select.
if ((net == 0) || (net->packed_dimensions() <= 1))
if ((sr.net == 0) || (sr.net->packed_dimensions() <= 1))
use_width = 1;
break;
case index_component_t::SEL_BIT_LAST:
@ -4042,31 +4036,31 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
ivl_assert(*this, 0);
}
if (const netdarray_t*darray = net ? net->darray_type() : 0) {
if (const netdarray_t*darray = sr.net ? sr.net->darray_type() : 0) {
switch (use_sel) {
case index_component_t::SEL_BIT:
case index_component_t::SEL_BIT_LAST:
expr_type_ = darray->element_base_type();
expr_width_ = darray->element_width();
min_width_ = expr_width_;
signed_flag_ = net->get_signed();
signed_flag_ = sr.net->get_signed();
break;
default:
expr_type_ = net->data_type();
expr_width_ = net->vector_width();
expr_type_ = sr.net->data_type();
expr_width_ = sr.net->vector_width();
min_width_ = expr_width_;
signed_flag_ = net->get_signed();
signed_flag_ = sr.net->get_signed();
break;
}
return expr_width_;
}
// Look for a class property.
if (gn_system_verilog() && cls_val) {
expr_type_ = cls_val->base_type();
expr_width_ = cls_val->packed_width();
if (gn_system_verilog() && sr.cls_val) {
expr_type_ = sr.cls_val->base_type();
expr_width_ = sr.cls_val->packed_width();
min_width_ = expr_width_;
signed_flag_ = cls_val->get_signed();
signed_flag_ = sr.cls_val->get_signed();
return expr_width_;
}
@ -4074,10 +4068,10 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
// We have a bit/part select. Account for any remaining dimensions
// beyond the indexed dimension.
size_t use_depth = name_tail.index.size();
if (net) {
if (use_depth >= net->unpacked_dimensions())
use_depth -= net->unpacked_dimensions();
use_width *= net->slice_width(use_depth);
if (sr.net) {
if (use_depth >= sr.net->unpacked_dimensions())
use_depth -= sr.net->unpacked_dimensions();
use_width *= sr.net->slice_width(use_depth);
}
expr_type_ = IVL_VT_LOGIC; // Assume bit/parts selects are logic
@ -4089,14 +4083,56 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
}
// The width of a signal expression is the width of the signal.
if (net != 0) {
if (sr.net != 0) {
// If this net is a struct, the path tail may be
// a struct member. If it is, then we know the
// width of this identifier by knowing the width
// of the member. We don't even need to know
// anything about positions in containing arrays.
if (sr.net->struct_type() != 0 && !sr.path_tail.empty()) {
if (debug_elaborate) {
cerr << get_fileline() << ": debug: PEIdent::test_width: "
<< "Net " << sr.path_head << " is a struct, "
<< "checking width of member " << sr.path_tail << endl;
}
const netstruct_t::member_t*mem;
unsigned long unused;
mem = get_struct_member(this, des, scope, sr.net,
peek_tail_name(sr.path_tail), unused);
if (mem) {
expr_type_ = mem->data_type();
expr_width_ = mem->net_type->packed_width();
min_width_ = expr_width_;
signed_flag_ = mem->get_signed();
return expr_width_;
}
}
// Similarly, if this net is an object, the path tail may
// be a class property.
if (sr.net->class_type() != 0 && !sr.path_tail.empty()) {
const netclass_t*class_type = sr.net->class_type();
perm_string pname = peek_tail_name(sr.path_tail);
int pidx = class_type->property_idx_from_name(pname);
if (pidx >= 0) {
ivl_type_t ptype = class_type->get_prop_type(pidx);
expr_type_ = ptype->base_type();
expr_width_ = ptype->packed_width();
min_width_ = expr_width_;
signed_flag_ = ptype->get_signed();
return expr_width_;
}
}
size_t use_depth = name_tail.index.size();
// Account for unpacked dimensions by assuming that the
// unpacked dimensions are consumed first, so subtract
// the unpacked dimensions from the dimension depth
// useable for making the slice.
if (use_depth >= net->unpacked_dimensions()) {
use_depth -= net->unpacked_dimensions();
if (use_depth >= sr.net->unpacked_dimensions()) {
use_depth -= sr.net->unpacked_dimensions();
} else {
// In this case, we have a slice of an unpacked
@ -4105,19 +4141,19 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
use_depth = 0;
}
expr_type_ = net->data_type();
expr_width_ = net->slice_width(use_depth);
expr_type_ = sr.net->data_type();
expr_width_ = sr.net->slice_width(use_depth);
min_width_ = expr_width_;
signed_flag_ = net->get_signed();
signed_flag_ = sr.net->get_signed();
if (debug_elaborate) {
cerr << get_fileline() << ": PEIdent::test_width: "
<< net->name() << " is a net, "
<< sr.net->name() << " is a net, "
<< "type=" << expr_type_
<< ", width=" << expr_width_
<< ", signed_=" << (signed_flag_ ? "true" : "false")
<< ", use_depth=" << use_depth
<< ", packed_dimensions=" << net->packed_dimensions()
<< ", unpacked_dimensions=" << net->unpacked_dimensions()
<< ", packed_dimensions=" << sr.net->packed_dimensions()
<< ", unpacked_dimensions=" << sr.net->unpacked_dimensions()
<< endl;
}
return expr_width_;
@ -4125,7 +4161,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
// The width of an enumeration literal is the width of the
// enumeration base.
if (const NetEConstEnum*par_enum = dynamic_cast<const NetEConstEnum*> (par)) {
if (const NetEConstEnum*par_enum = dynamic_cast<const NetEConstEnum*> (sr.par_val)) {
const netenum_t*use_enum = par_enum->enumeration();
ivl_assert(*this, use_enum != 0);
@ -4139,13 +4175,13 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
// The width of a parameter is the width of the parameter value
// (as evaluated earlier).
if (par != 0) {
expr_type_ = par->expr_type();
expr_width_ = par->expr_width();
if (sr.par_val != 0) {
expr_type_ = sr.par_val->expr_type();
expr_width_ = sr.par_val->expr_width();
min_width_ = expr_width_;
signed_flag_ = par->has_sign();
signed_flag_ = sr.par_val->has_sign();
if (!par->has_width() && (mode < LOSSLESS))
if (!sr.par_val->has_width() && (mode < LOSSLESS))
mode = LOSSLESS;
return expr_width_;
@ -4170,57 +4206,6 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
return expr_width_;
}
// If this is SystemVerilog then maybe this is a structure element.
if (gn_system_verilog() && found_in==0 && path_.size() >= 2) {
pform_name_t use_path = path_;
perm_string method_name = peek_tail_name(use_path);
use_path.pop_back();
ivl_assert(*this, net == 0);
symbol_search(this, des, scope, use_path, net, par, eve, par_type, cls_val);
// 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. If it is, then we know the
// width of this identifier my knowing the width
// of the member. We don't even need to know
// anything about positions in containing arrays.
if (net->struct_type() != 0) {
if (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;
mem = get_struct_member(this, des, scope, net,
method_name, unused);
if (mem) {
expr_type_ = mem->data_type();
expr_width_ = mem->net_type->packed_width();
min_width_ = expr_width_;
signed_flag_ = mem->get_signed();
return expr_width_;
}
}
if (const netclass_t*class_type = net->class_type()) {
int pidx = class_type->property_idx_from_name(method_name);
if (pidx >= 0) {
ivl_type_t ptype = class_type->get_prop_type(pidx);
expr_type_ = ptype->base_type();
expr_width_ = ptype->packed_width();
min_width_ = expr_width_;
signed_flag_ = ptype->get_signed();
return expr_width_;
}
}
}
}
// Not a net, and not a parameter? Give up on the type, but
// set the width to 0.
expr_type_ = IVL_VT_NO_TYPE;