From 892622bf64c0fe516e680d044cfbe254921c7d7a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 19 Feb 2022 12:28:05 +0100 Subject: [PATCH 1/5] Add helper function to get parameter line info The NetScope class has a method called find_parameter() that looks up the parameter and returns a iterator to it. This is only ever used to get the line information of the parameter. Refactor the function so that it only returns the line info. This will allow to call this function on a const NetScope object. Signed-off-by: Lars-Peter Clausen --- elab_expr.cc | 12 ++++-------- net_scope.cc | 8 ++++---- netlist.h | 2 +- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index 0a5e31536..3ba58ef03 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -5091,8 +5091,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); @@ -5298,8 +5297,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); @@ -5380,8 +5378,7 @@ 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); @@ -5500,8 +5497,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; diff --git a/net_scope.cc b/net_scope.cc index 61ca017d4..2e6a60366 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -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::iterator idx; + map::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 diff --git a/netlist.h b/netlist.h index 66268b93e..68514c3e6 100644 --- a/netlist.h +++ b/netlist.h @@ -1239,7 +1239,7 @@ class NetScope : public Definitions, public Attrib { typedef std::map::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. */ From ad23b08a1073115ecd0fdbcc01384fac957bcc8c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 19 Feb 2022 12:08:57 +0100 Subject: [PATCH 2/5] Constify scope reference in NetEConstParam and NetECRealParam Parameter expressions need to remember the scope they have been declared in so that the code generator backends can insert the right parameter reference, rather than a constant value. Currently the scope is stored as a non-const reference. But that is not needed. Mark the scope reference as const so NetEConstParam and NetECRealParam can be created when only a const scope reference is available. Signed-off-by: Lars-Peter Clausen --- net_expr.cc | 2 +- netlist.cc | 2 +- netlist.h | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/net_expr.cc b/net_expr.cc index 4a0ee3008..5cd29e013 100644 --- a/net_expr.cc +++ b/net_expr.cc @@ -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) { } diff --git a/netlist.cc b/netlist.cc index a83b5f5e3..21a44faea 100644 --- a/netlist.cc +++ b/netlist.cc @@ -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()); diff --git a/netlist.h b/netlist.h index 68514c3e6..dd6b9dbb7 100644 --- a/netlist.h +++ b/netlist.h @@ -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_; }; From 427091d3d3e62bb342f9771297d848984f837461 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 19 Feb 2022 12:58:27 +0100 Subject: [PATCH 3/5] Support access to class constants on objects It is allowed to access a constant declared in a class scope, such as a enum value or parameter, on an object of that class type. This is described in section 8.5 ("Object properties and object parameter data") of the LRM (1800-2017). E.g. ``` class C enum { A } e; endclass C c = new; c.e = c.A; ``` Support this by in addition of searching for class properties on the object also search for constants in the class scope. A bit of refactoring is needed around the parameter elaboration functions since they expect a non-const NetScope, but for classes we only have a const scope available. The non-const scope is needed to be able to mark specparams as non-annotatable. Since classes can't have specparams this part is factored out into a separate function the NetScope parameter for the shared functions is made const. Signed-off-by: Lars-Peter Clausen --- PExpr.h | 24 ++++-- elab_expr.cc | 145 ++++++++++++++++++++------------ ivtest/ivltests/enum_in_class.v | 2 +- netclass.cc | 6 ++ netclass.h | 4 + 5 files changed, 120 insertions(+), 61 deletions(-) diff --git a/PExpr.h b/PExpr.h index 70af29613..6ee7001f5 100644 --- a/PExpr.h +++ b/PExpr.h @@ -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, diff --git a/elab_expr.cc b/elab_expr.cc index 3ba58ef03..9f993f0f9 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -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 (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 (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 { @@ -5100,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 { @@ -5226,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 { @@ -5306,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 { @@ -5385,6 +5405,31 @@ NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope, 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 @@ -5393,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 { @@ -5410,16 +5455,6 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des, << "par_type: " << 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()) diff --git a/ivtest/ivltests/enum_in_class.v b/ivtest/ivltests/enum_in_class.v index df5749f57..0513d1dac 100644 --- a/ivtest/ivltests/enum_in_class.v +++ b/ivtest/ivltests/enum_in_class.v @@ -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 diff --git a/netclass.cc b/netclass.cc index 7e69a604d..93c02d5e8 100644 --- a/netclass.cc +++ b/netclass.cc @@ -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); +} diff --git a/netclass.h b/netclass.h index c97180c4d..af50efd10 100644 --- a/netclass.h +++ b/netclass.h @@ -27,6 +27,7 @@ # include 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 From d104e28dbf1aad5c65c7d532bb8d275238782566 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 5 Feb 2022 11:29:27 +0100 Subject: [PATCH 4/5] Support non-overridable parameters in classes SystemVerilog allows `parameter` and `localparam` to declare constants within a class scope. E.g. ```SystemVerilog class C; localparam A = 10; endclass ``` In this context both declare a local parameter that can not be overwritten. Supporting this can be achieved for the most part by adding a parser sub-rule in class declaration rule. In addition some extra support code is needed to mark the parameter as non-overridable. Signed-off-by: Lars-Peter Clausen --- elab_scope.cc | 2 ++ parse.y | 9 +++++++-- pform.cc | 3 +++ pform.h | 1 + pform_pclass.cc | 5 +++++ 5 files changed, 18 insertions(+), 2 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index 36125fffd..23a9a8ef4 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -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. diff --git a/parse.y b/parse.y index 4ddf96132..5cd9cea38 100644 --- a/parse.y +++ b/parse.y @@ -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 diff --git a/pform.cc b/pform.cc index f9f7a3237..0d3f97c4f 100644 --- a/pform.cc +++ b/pform.cc @@ -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); diff --git a/pform.h b/pform.h index 687dee9bd..69e5e9c1e 100644 --- a/pform.h +++ b/pform.h @@ -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*parms, std::vector*decl, std::list*table, diff --git a/pform_pclass.cc b/pform_pclass.cc index e9facc013..fdef299dc 100644 --- a/pform_pclass.cc +++ b/pform_pclass.cc @@ -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; +} From 2e845821a88641486fa997ecdbcb08b4f40d5406 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 16 Feb 2022 10:52:58 +0100 Subject: [PATCH 5/5] Add regression test for localparams in classes Check that localparams and non-overridable parameters can be declared in a class. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/sv_class_localparam.v | 28 +++++++++++++++++++++++++++ ivtest/regress-sv.list | 1 + ivtest/regress-vlog95.list | 1 + 3 files changed, 30 insertions(+) create mode 100644 ivtest/ivltests/sv_class_localparam.v diff --git a/ivtest/ivltests/sv_class_localparam.v b/ivtest/ivltests/sv_class_localparam.v new file mode 100644 index 000000000..b92923d81 --- /dev/null +++ b/ivtest/ivltests/sv_class_localparam.v @@ -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 diff --git a/ivtest/regress-sv.list b/ivtest/regress-sv.list index c4b8b163c..887715467 100644 --- a/ivtest/regress-sv.list +++ b/ivtest/regress-sv.list @@ -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 diff --git a/ivtest/regress-vlog95.list b/ivtest/regress-vlog95.list index 1c66d40f6..4196cb366 100644 --- a/ivtest/regress-vlog95.list +++ b/ivtest/regress-vlog95.list @@ -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