diff --git a/PExpr.cc b/PExpr.cc index 2928e4bc5..8454ad930 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -238,8 +238,8 @@ static pform_name_t pn_from_ps(perm_string n) return tmp; } -PECallFunction::PECallFunction(PPackage*pkg, perm_string n, const list &parms) -: package_(pkg), path_(pn_from_ps(n)), parms_(parms.size()), is_overridden_(false) +PECallFunction::PECallFunction(PPackage*pkg, const pform_name_t&n, const list &parms) +: package_(pkg), path_(n), parms_(parms.size()), is_overridden_(false) { int tmp_idx = 0; assert(parms_.size() == parms.size()); diff --git a/PExpr.h b/PExpr.h index 75db22d5f..86550a303 100644 --- a/PExpr.h +++ b/PExpr.h @@ -521,7 +521,8 @@ class PEIdent : public PExpr { unsigned expr_wid, unsigned flags) const; - unsigned test_width_method_(Design*des, NetScope*scope, width_mode_t&mode); + unsigned test_width_method_(const symbol_search_results &sr); + unsigned test_width_parameter_(const NetExpr *par, width_mode_t&mode); @@ -886,8 +887,7 @@ class PECallFunction : public PExpr { public: explicit PECallFunction(const pform_name_t&n, const std::vector &parms); // Call function defined in package. - explicit PECallFunction(PPackage*pkg, perm_string n, const std::vector &parms); - explicit PECallFunction(PPackage*pkg, perm_string n, const std::list &parms); + explicit PECallFunction(PPackage*pkg, const pform_name_t&n, const std::list &parms); // Used to convert a user function called as a task explicit PECallFunction(PPackage*pkg, const pform_name_t&n, const std::vector &parms); diff --git a/elab_expr.cc b/elab_expr.cc index 0dc874ac0..7db1f21ef 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -3981,7 +3981,7 @@ NetExpr* PEIdent::calculate_up_do_base_(Design*des, NetScope*scope, return tmp; } -unsigned PEIdent::test_width_method_(Design*des, NetScope*scope, width_mode_t&) +unsigned PEIdent::test_width_method_(const symbol_search_results &sr) { if (!gn_system_verilog()) return 0; @@ -3998,12 +3998,7 @@ unsigned PEIdent::test_width_method_(Design*des, NetScope*scope, width_mode_t&) << " of signal " << use_path << endl; } - NetNet*net = 0; - ivl_type_t cls_val = 0; - const NetExpr*par = 0; - ivl_type_t par_type = 0; - NetEvent*eve = 0; - symbol_search(this, des, scope, use_path, net, par, eve, par_type, cls_val); + NetNet *net = sr.net; if (net == 0) { if (debug_elaborate) cerr << get_fileline() << ": PEIdent::test_width_method_: " @@ -4088,13 +4083,13 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) ivl_assert(*this, use_scope); } - if (unsigned tmp = test_width_method_(des, scope, mode)) { - return tmp; - } - symbol_search_results sr; symbol_search(this, des, use_scope, path_, &sr); + if (unsigned tmp = test_width_method_(sr)) { + return tmp; + } + // If there is a part/bit select expression, then process it // here. This constrains the results no matter what kind the // name is. diff --git a/ivtest/ivltests/sv_ps_method1.v b/ivtest/ivltests/sv_ps_method1.v new file mode 100644 index 000000000..496925705 --- /dev/null +++ b/ivtest/ivltests/sv_ps_method1.v @@ -0,0 +1,39 @@ +// Check that it is possible to perform method call on a package scoped +// identifier of an enum. + +package P; + enum integer { + A, B + } e = A; +endpackage + +module test; + + bit failed = 1'b0; + + `define check(expr, val) \ + if (val !== expr) begin \ + $display("FAILED(%0d). `%s` got %b, expected %b.", `__LINE__, `"expr`", expr, val); \ + failed = 1'b1; \ + end + + initial begin + // Calling without a parameter. Both variants are allowed + `check(P::e.first, P::A) + `check(P::e.first(), P::A) + + // Is the width reported correctly for both variants? + `check($bits(P::e.first), $bits(integer)) + `check($bits(P::e.first()), $bits(integer)) + + // Calling with a parameter + `check(P::e.next(1), P::B) + + `check($bits(P::e.next(1)), $bits(integer)) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_ps_method2.v b/ivtest/ivltests/sv_ps_method2.v new file mode 100644 index 000000000..73a859263 --- /dev/null +++ b/ivtest/ivltests/sv_ps_method2.v @@ -0,0 +1,40 @@ +// Check that it is possible to perform method call on a package scoped +// identifier of a class object. + +package P; + class C; + function int f1(int x); + return x + 1; + endfunction + + function int f2(); + return 10; + endfunction + endclass + + C c = new; +endpackage + +module test; + + bit failed = 1'b0; + + `define check(expr, val) \ + if (val !== expr) begin \ + $display("FAILED(%0d). `%s` got %b, expected %b.", `__LINE__, `"expr`", expr, val); \ + failed = 1'b1; \ + end + + initial begin + `check(P::c.f1(10), 11) + `check(P::c.f2(), 10) + + `check($bits(P::c.f1(10)), $bits(int)) + `check($bits(P::c.f2()), $bits(int)) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_ps_method3.v b/ivtest/ivltests/sv_ps_method3.v new file mode 100644 index 000000000..3cef4bec2 --- /dev/null +++ b/ivtest/ivltests/sv_ps_method3.v @@ -0,0 +1,22 @@ +// Check that the parameter to a method on a package scoped identifier is +// evaluated in the scope where the method is called, not where the identifier +// is declared. + +package P; + localparam N = 1; + enum { + A, B, C + } e = A; +endpackage + +module test; + localparam N = 2; + + initial begin + if (P::e.next(N) === P::C) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end +endmodule diff --git a/ivtest/ivltests/sv_ps_method4.v b/ivtest/ivltests/sv_ps_method4.v new file mode 100644 index 000000000..464529109 --- /dev/null +++ b/ivtest/ivltests/sv_ps_method4.v @@ -0,0 +1,27 @@ +// Check that the parameter to a class method on a package scoped identifier is +// evaluated in the scope where the method is called, not where the identifier +// is declared. + +package P; + localparam N = 1; + + class C; + function int f(int x); + return x; + endfunction + endclass + + C c = new; +endpackage + +module test; + localparam N = 2; + + initial begin + if (P::c.f(N) === 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 df5cb1a6c..3ef2a144b 100644 --- a/ivtest/regress-sv.list +++ b/ivtest/regress-sv.list @@ -700,6 +700,10 @@ sv_ps_function_fail3 CE,-g2009 ivltests sv_ps_member_sel1 normal,-g2009 ivltests sv_ps_member_sel2 normal,-g2009 ivltests sv_ps_member_sel3 normal,-g2009 ivltests +sv_ps_method1 normal,-g2009 ivltests +sv_ps_method2 normal,-g2009 ivltests +sv_ps_method3 normal,-g2009 ivltests +sv_ps_method4 normal,-g2009 ivltests sv_ps_type1 normal,-g2009 ivltests sv_ps_type_cast1 normal,-g2009 ivltests sv_ps_type_cast2 normal,-g2009 ivltests diff --git a/ivtest/regress-vlog95.list b/ivtest/regress-vlog95.list index 3f5db26eb..ed8119e51 100644 --- a/ivtest/regress-vlog95.list +++ b/ivtest/regress-vlog95.list @@ -463,6 +463,8 @@ sv_port_default7 CE,-g2009,-pallowsigned=1 ivltests sv_port_default8 CE,-g2009,-pallowsigned=1 ivltests sv_port_default9 CE,-g2009 ivltests sv_ps_member_sel3 CE,-g2009 ivltests +sv_ps_method2 CE,-g2009 ivltests +sv_ps_method4 CE,-g2009 ivltests sv_ps_type_class1 CE,-g2009 ivltests sv_ps_type_class_prop CE,-g2009 ivltests sv_root_class CE,-g2009 ivltests @@ -521,6 +523,8 @@ pr3390385b CE,-g2009 ivltests # ++ pr3390385c CE,-g2009 ivltests # ++ pr3390385d CE,-g2009 ivltests # ++ pr3462145 CE,-g2009 ivltests # ++ +sv_ps_method1 CE,-g2009 ivltests # enum +sv_ps_method3 CE,-g2009 ivltests # enum sv_queue_assign1 CE,-g2009 ivltests # queue sv_queue_assign2 CE,-g2009 ivltests # queue sv_queue_copy_empty1 CE,-g2009 ivltests # queue diff --git a/parse.y b/parse.y index 081851b2f..07ed144e8 100644 --- a/parse.y +++ b/parse.y @@ -3776,11 +3776,10 @@ expr_primary delete $3; $$ = tmp; } - | package_scope IDENTIFIER { lex_in_package_scope(0); } '(' expression_list_with_nuls ')' - { perm_string use_name = lex_strings.make($2); - PECallFunction*tmp = new PECallFunction($1, use_name, *$5); + | package_scope hierarchy_identifier { lex_in_package_scope(0); } '(' expression_list_with_nuls ')' + { PECallFunction*tmp = new PECallFunction($1, *$2, *$5); FILE_NAME(tmp, @2); - delete[]$2; + delete $2; delete $5; $$ = tmp; }