Merge pull request #620 from larsclausen/class-localparams

Support non-overridable parameters in classes
This commit is contained in:
Stephen Williams 2022-02-26 09:09:00 -08:00 committed by GitHub
commit 83f1ea60b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 183 additions and 82 deletions

24
PExpr.h
View File

@ -430,35 +430,42 @@ class PEIdent : public PExpr {
NetAssign_*) const;
private:
NetExpr*elaborate_expr_param_or_specparam_(Design*des,
NetScope*scope,
const NetExpr*par,
NetScope*found_in,
ivl_type_t par_type,
unsigned expr_wid,
unsigned flags) const;
NetExpr*elaborate_expr_param_(Design*des,
NetScope*scope,
const NetExpr*par,
NetScope*found_in,
const NetScope*found_in,
ivl_type_t par_type,
unsigned expr_wid,
unsigned flags) const;
NetExpr*elaborate_expr_param_bit_(Design*des,
NetScope*scope,
const NetExpr*par,
NetScope*found_in,
const NetScope*found_in,
ivl_type_t par_type,
bool need_const) const;
NetExpr*elaborate_expr_param_part_(Design*des,
NetScope*scope,
const NetExpr*par,
NetScope*found_in,
const NetScope*found_in,
ivl_type_t par_type,
unsigned expr_wid) const;
NetExpr*elaborate_expr_param_idx_up_(Design*des,
NetScope*scope,
const NetExpr*par,
NetScope*found_in,
const NetScope*found_in,
ivl_type_t par_type,
bool need_const) const;
NetExpr*elaborate_expr_param_idx_do_(Design*des,
NetScope*scope,
const NetExpr*par,
NetScope*found_in,
const NetScope*found_in,
ivl_type_t par_type,
bool need_const) const;
NetExpr*elaborate_expr_net(Design*des,
@ -504,8 +511,15 @@ class PEIdent : public PExpr {
unsigned expr_wid,
unsigned flags) const;
NetExpr *elaborate_expr_class_field_(Design*des, NetScope*scope,
NetNet*net,
const name_component_t&comp,
unsigned expr_wid,
unsigned flags) const;
unsigned test_width_method_(Design*des, NetScope*scope, width_mode_t&mode);
unsigned test_width_parameter_(const NetExpr *par, width_mode_t&mode);
private:
NetNet* elaborate_lnet_common_(Design*des, NetScope*scope,

View File

@ -2516,15 +2516,24 @@ static NetExpr* class_static_property_expression(const LineInfo*li,
return expr;
}
static NetExpr* check_for_class_property(const LineInfo*li,
Design*des, NetScope*scope,
NetNet*net,
const name_component_t&comp)
NetExpr* PEIdent::elaborate_expr_class_field_(Design*des, NetScope*scope,
NetNet*net,
const name_component_t&comp,
unsigned expr_wid,
unsigned flags) const
{
const netclass_t*class_type = net->class_type();
ivl_type_t par_type;
const NetExpr *par_val = class_type->get_parameter(des, comp.name, par_type);
if (par_val)
return elaborate_expr_param_(des, scope, par_val,
class_type->class_scope(), par_type,
expr_wid, flags);
int pidx = class_type->property_idx_from_name(comp.name);
if (pidx < 0) {
cerr << li->get_fileline() << ": error: "
cerr << get_fileline() << ": error: "
<< "Class " << class_type->get_name()
<< " has no property " << comp.name << "." << endl;
des->errors += 1;
@ -2532,7 +2541,7 @@ static NetExpr* check_for_class_property(const LineInfo*li,
}
if (debug_elaborate) {
cerr << li->get_fileline() << ": check_for_class_property: "
cerr << get_fileline() << ": check_for_class_property: "
<< "Property " << comp.name
<< " of net " << net->name()
<< ", context scope=" << scope_path(scope)
@ -2541,7 +2550,7 @@ static NetExpr* check_for_class_property(const LineInfo*li,
property_qualifier_t qual = class_type->get_prop_qual(pidx);
if (qual.test_local() && ! class_type->test_scope_is_method(scope)) {
cerr << li->get_fileline() << ": error: "
cerr << get_fileline() << ": error: "
<< "Local property " << class_type->get_prop_name(pidx)
<< " is not accessible in this context."
<< " (scope=" << scope_path(scope) << ")" << endl;
@ -2550,12 +2559,12 @@ static NetExpr* check_for_class_property(const LineInfo*li,
if (qual.test_static()) {
perm_string prop_name = lex_strings.make(class_type->get_prop_name(pidx));
return class_static_property_expression(li, class_type,
return class_static_property_expression(this, class_type,
prop_name);
}
NetEProperty*tmp = new NetEProperty(net, comp.name);
tmp->set_line(*li);
tmp->set_line(*this);
return tmp;
}
@ -3977,6 +3986,33 @@ unsigned PEIdent::test_width_method_(Design*des, NetScope*scope, width_mode_t&)
return 0;
}
unsigned PEIdent::test_width_parameter_(const NetExpr *par, 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)) {
const netenum_t*use_enum = par_enum->enumeration();
ivl_assert(*this, use_enum != 0);
expr_type_ = use_enum->base_type();
expr_width_ = use_enum->packed_width();
min_width_ = expr_width_;
signed_flag_ = par_enum->has_sign();
return expr_width_;
}
expr_type_ = par->expr_type();
expr_width_ = par->expr_width();
min_width_ = expr_width_;
signed_flag_ = par->has_sign();
if (!par->has_width() && (mode < LOSSLESS))
mode = LOSSLESS;
return expr_width_;
}
unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
{
NetScope*use_scope = scope;
@ -4128,6 +4164,11 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
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);
ivl_type_t par_type;
const NetExpr *par = class_type->get_parameter(des, pname, par_type);
if (par)
return test_width_parameter_(par, mode);
int pidx = class_type->property_idx_from_name(pname);
if (pidx >= 0) {
ivl_type_t ptype = class_type->get_prop_type(pidx);
@ -4172,33 +4213,10 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
return expr_width_;
}
// The width of an enumeration literal is the width of the
// enumeration base.
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);
expr_type_ = use_enum->base_type();
expr_width_ = use_enum->packed_width();
min_width_ = expr_width_;
signed_flag_ = par_enum->has_sign();
return expr_width_;
}
// The width of a parameter is the width of the parameter value
// (as evaluated earlier).
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_ = sr.par_val->has_sign();
if (!sr.par_val->has_width() && (mode < LOSSLESS))
mode = LOSSLESS;
return expr_width_;
}
if (sr.par_val != 0)
return test_width_parameter_(sr.par_val, mode);
if (path_.size() == 1
&& scope->genvar_tmp.str()
@ -4283,8 +4301,8 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
<< " look for property " << member_comp << endl;
}
return check_for_class_property(this, des, scope,
net, member_comp);
return elaborate_expr_class_field_(des, scope, net,
member_comp, 0, flags);
}
}
@ -4578,8 +4596,9 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
des->errors += 1;
}
NetExpr*tmp = elaborate_expr_param_(des, scope, sr.par_val, sr.scope,
sr.par_type, expr_wid, flags);
NetExpr*tmp = elaborate_expr_param_or_specparam_(des, scope, sr.par_val,
sr.scope, sr.par_type,
expr_wid, flags);
if (!tmp) return 0;
@ -4808,8 +4827,9 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
ivl_assert(*this, sr.path_tail.size() == 1);
const name_component_t member_comp = sr.path_tail.front();
return check_for_class_property(this, des, use_scope,
sr.net, member_comp);
return elaborate_expr_class_field_(des, use_scope,
sr.net, member_comp,
expr_wid, flags);
}
if (sr.net->enumeration() && !sr.path_tail.empty()) {
@ -5007,7 +5027,7 @@ static verinum param_part_select_bits(const verinum&par_val, long wid,
NetExpr* PEIdent::elaborate_expr_param_bit_(Design*des, NetScope*scope,
const NetExpr*par,
NetScope*found_in,
const NetScope*found_in,
ivl_type_t par_type,
bool need_const) const
{
@ -5091,8 +5111,7 @@ NetExpr* PEIdent::elaborate_expr_param_bit_(Design*des, NetScope*scope,
/* Create a parameter reference for the variable select. */
NetEConstParam*ptmp = new NetEConstParam(found_in, name, par_ex->value());
NetScope::param_ref_t pref = found_in->find_parameter(name);
ptmp->set_line((*pref).second);
ptmp->set_line(found_in->get_parameter_line_info(name));
NetExpr*tmp = new NetESelect(ptmp, sel, 1);
tmp->set_line(*this);
@ -5101,7 +5120,7 @@ NetExpr* PEIdent::elaborate_expr_param_bit_(Design*des, NetScope*scope,
NetExpr* PEIdent::elaborate_expr_param_part_(Design*des, NetScope*scope,
const NetExpr*par,
NetScope*,
const NetScope*,
ivl_type_t par_type,
unsigned expr_wid) const
{
@ -5227,7 +5246,7 @@ static void warn_param_ob(long par_msv, long par_lsv, bool defined,
NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope,
const NetExpr*par,
NetScope*found_in,
const NetScope*found_in,
ivl_type_t par_type,
bool need_const) const
{
@ -5298,8 +5317,7 @@ NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope,
/* Create a parameter reference for the variable select. */
NetEConstParam*ptmp = new NetEConstParam(found_in, name, par_ex->value());
NetScope::param_ref_t pref = found_in->find_parameter(name);
ptmp->set_line((*pref).second);
ptmp->set_line(found_in->get_parameter_line_info(name));
NetExpr*tmp = new NetESelect(ptmp, base, wid, IVL_SEL_IDX_UP);
tmp->set_line(*this);
@ -5308,7 +5326,7 @@ NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope,
NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope,
const NetExpr*par,
NetScope*found_in,
const NetScope*found_in,
ivl_type_t par_type,
bool need_const) const
{
@ -5380,14 +5398,38 @@ NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope,
/* Create a parameter reference for the variable select. */
NetEConstParam*ptmp = new NetEConstParam(found_in, name, par_ex->value());
NetScope::param_ref_t pref = found_in->find_parameter(name);
ptmp->set_line((*pref).second);
ptmp->set_line(found_in->get_parameter_line_info(name));
NetExpr*tmp = new NetESelect(ptmp, base, wid, IVL_SEL_IDX_DOWN);
tmp->set_line(*this);
return tmp;
}
NetExpr* PEIdent::elaborate_expr_param_or_specparam_(Design*des,
NetScope*scope,
const NetExpr*par,
NetScope*found_in,
ivl_type_t par_type,
unsigned expr_wid,
unsigned flags) const
{
bool need_const = NEED_CONST & flags;
if (need_const && !(ANNOTATABLE & flags)) {
perm_string name = peek_tail_name(path_);
if (found_in->make_parameter_unannotatable(name)) {
cerr << get_fileline() << ": warning: specparam '" << name
<< "' is being used in a constant expression." << endl;
cerr << get_fileline() << ": : This will prevent it "
"being annotated at run time." << endl;
}
}
return elaborate_expr_param_(des, scope, par, found_in, par_type,
expr_wid, flags);
}
/*
* Handle the case that the identifier is a parameter reference. The
* parameter expression has already been located for us (as the par
@ -5396,7 +5438,7 @@ NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope,
NetExpr* PEIdent::elaborate_expr_param_(Design*des,
NetScope*scope,
const NetExpr*par,
NetScope*found_in,
const NetScope*found_in,
ivl_type_t par_type,
unsigned expr_wid, unsigned flags) const
{
@ -5413,16 +5455,6 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des,
<< "par_type: <nil>" << endl;
}
if (need_const && !(ANNOTATABLE & flags)) {
perm_string name = peek_tail_name(path_);
if (found_in->make_parameter_unannotatable(name)) {
cerr << get_fileline() << ": warning: specparam '" << name
<< "' is being used in a constant expression." << endl;
cerr << get_fileline() << ": : This will prevent it "
"being annotated at run time." << endl;
}
}
const name_component_t&name_tail = path_.back();
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
if (!name_tail.index.empty())
@ -5500,8 +5532,7 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des,
/* The numeric parameter value needs to have the file and line
* information for the actual parameter not the expression. */
assert(tmp);
NetScope::param_ref_t pref = found_in->find_parameter(name);
tmp->set_line((*pref).second);
tmp->set_line(found_in->get_parameter_line_info(name));
}
return tmp;

View File

@ -524,6 +524,8 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass)
class_scope->add_typedefs(&pclass->typedefs);
collect_scope_parameters(des, class_scope, pclass->parameters);
// Elaborate enum types declared in the class. We need these
// now because enumeration constants can be used during scope
// elaboration.

View File

@ -38,7 +38,7 @@ initial begin
// Not yet supported
// c.e2 = C::A;
// c.e2 = c.A;
c.e2 = c.A;
// Check that they have the numerical value from the right scope
if (c.e1 == 1 && c.e2 == 10) begin

View File

@ -0,0 +1,28 @@
// Check that it is possible to declare parameters and localparams inside a
// class. Both declared parameters that can not be overridden.
module test;
class C;
// `parameter` is also declaring a local parameter inside a class
parameter A = 1;
localparam B = 2;
function bit test();
return A == 1 && B == 2;
endfunction
endclass
initial begin
C c;
c = new;
if (c.test() && c.A == 1 && c.B == 2) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -436,6 +436,7 @@ sv_class22 normal,-g2009 ivltests
sv_class23 normal,-g2009 ivltests
sv_class24 normal,-g2009 ivltests
sv_class_extends_scoped normal,-g2009 ivltests
sv_class_localparam normal,-g2009 ivltests
sv_class_new_init normal,-g2009 ivltests
sv_darray1 normal,-g2009 ivltests
sv_darray2 normal,-g2009 ivltests

View File

@ -364,6 +364,7 @@ sv_class22 CE,-g2009 ivltests
sv_class23 CE,-g2009 ivltests
sv_class24 CE,-g2009 ivltests
sv_class_extends_scoped CE,-g2009 ivltests
sv_class_localparam CE,-g2009 ivltests
sv_class_new_init CE,-g2009 ivltests
sv_end_label CE,-g2009 ivltests # Also generate
sv_foreach2 CE,-g2009,-pallowsigned=1 ivltests

View File

@ -304,7 +304,7 @@ ivl_variable_type_t NetECReal::expr_type() const
return IVL_VT_REAL;
}
NetECRealParam::NetECRealParam(NetScope*s, perm_string n, const verireal&v)
NetECRealParam::NetECRealParam(const NetScope*s, perm_string n, const verireal&v)
: NetECReal(v), scope_(s), name_(n)
{
}

View File

@ -460,18 +460,18 @@ const NetExpr* NetScope::get_parameter(Design*des, perm_string key,
return tmp;
}
NetScope::param_ref_t NetScope::find_parameter(perm_string key)
LineInfo NetScope::get_parameter_line_info(perm_string key) const
{
map<perm_string,param_expr_t>::iterator idx;
map<perm_string,param_expr_t>::const_iterator idx;
idx = parameters.find(key);
if (idx != parameters.end()) return idx;
if (idx != parameters.end()) return idx->second;
// To get here the parameter must already exist, so we should
// never get here.
assert(0);
// But return something to avoid a compiler warning.
return idx;
return LineInfo();
}
void NetScope::print_type(ostream&stream) const

View File

@ -188,3 +188,9 @@ bool netclass_t::test_scope_is_method(const NetScope*scope) const
else
return true;
}
const NetExpr* netclass_t::get_parameter(Design *des, perm_string name,
ivl_type_t &par_type) const
{
return class_scope_->get_parameter(des, name, par_type);
}

View File

@ -27,6 +27,7 @@
# include <map>
class Design;
class NetExpr;
class NetNet;
class NetScope;
class PClass;
@ -112,6 +113,9 @@ class netclass_t : public ivl_type_s {
std::ostream& debug_dump(std::ostream&fd) const;
void dump_scope(std::ostream&fd) const;
const NetExpr* get_parameter(Design *des, perm_string name,
ivl_type_t &par_type) const;
private:
perm_string name_;
// If this is derived from another base class, point to it

View File

@ -2391,7 +2391,7 @@ void NetEConst::trim()
expr_width(value_.len());
}
NetEConstParam::NetEConstParam(NetScope*s, perm_string n, const verinum&v)
NetEConstParam::NetEConstParam(const NetScope*s, perm_string n, const verinum&v)
: NetEConst(v), scope_(s), name_(n)
{
cast_signed_base_(v.has_sign());

View File

@ -1239,7 +1239,7 @@ class NetScope : public Definitions, public Attrib {
typedef std::map<perm_string,param_expr_t>::iterator param_ref_t;
param_ref_t find_parameter(perm_string name);
LineInfo get_parameter_line_info(perm_string name) const;
/* Module instance arrays are collected here for access during
the multiple elaboration passes. */
@ -2175,7 +2175,7 @@ class NetEConstEnum : public NetEConst {
class NetEConstParam : public NetEConst {
public:
explicit NetEConstParam(NetScope*scope, perm_string name,
explicit NetEConstParam(const NetScope*scope, perm_string name,
const verinum&val);
~NetEConstParam();
@ -2188,7 +2188,7 @@ class NetEConstParam : public NetEConst {
virtual NetEConstParam* dup_expr() const;
private:
NetScope*scope_;
const NetScope*scope_;
perm_string name_;
};
@ -2236,7 +2236,7 @@ class NetECString : public NetEConst {
class NetECRealParam : public NetECReal {
public:
explicit NetECRealParam(NetScope*scope, perm_string name,
explicit NetECRealParam(const NetScope*scope, perm_string name,
const verireal&val);
~NetECRealParam();
@ -2249,7 +2249,7 @@ class NetECRealParam : public NetECReal {
virtual NetECRealParam* dup_expr() const;
private:
NetScope*scope_;
const NetScope*scope_;
perm_string name_;
};

View File

@ -978,6 +978,8 @@ class_item /* IEEE1800-2005: A.1.8 */
yyerrok;
}
| parameter_declaration
| error ';'
{ yyerror(@2, "error: invalid class item.");
yyerrok;
@ -2016,7 +2018,7 @@ package_import_item_list
package_item /* IEEE1800-2005 A.1.10 */
: timeunits_declaration
| parameter_or_localparam param_type parameter_assign_list ';'
| parameter_declaration
| type_declaration
| function_declaration
| task_declaration
@ -2697,7 +2699,7 @@ block_item_decl
{ if ($2) pform_make_events($2, @1.text, @1.first_line);
}
| parameter_or_localparam param_type parameter_assign_list ';'
| parameter_declaration
/* Blocks can have type declarations. */
@ -5570,6 +5572,9 @@ param_type : data_type_or_implicit { param_data_type = $1; }
parameter : K_parameter { param_is_local = false; };
localparam : K_localparam { param_is_local = true; };
parameter_declaration
: parameter_or_localparam param_type parameter_assign_list ';'
parameter_or_localparam
: parameter
| localparam

View File

@ -3213,6 +3213,9 @@ void pform_set_parameter(const struct vlltype&loc,
scope->has_parameter_port_list)
overridable = false;
if (pform_in_class())
overridable = false;
Module::param_expr_t*parm = new Module::param_expr_t();
FILE_NAME(parm, loc);

View File

@ -202,6 +202,7 @@ extern void pform_set_this_class(const struct vlltype&loc, PTaskFunc*net);
extern void pform_set_constructor_return(PFunction*net);
extern void pform_end_class_declaration(const struct vlltype&loc);
extern bool pform_in_class();
extern void pform_make_udp(perm_string name, std::list<perm_string>*parms,
std::vector<PWire*>*decl, std::list<std::string>*table,

View File

@ -164,3 +164,8 @@ void pform_end_class_declaration(const struct vlltype&loc)
pform_cur_class = 0;
pform_pop_scope();
}
bool pform_in_class()
{
return pform_cur_class != 0;
}