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 0a5e31536..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 { @@ -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: " << 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; 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/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/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 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/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/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 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 66268b93e..dd6b9dbb7 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. */ @@ -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_; }; 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; +}