diff --git a/PExpr.h b/PExpr.h index d8c7a030f..75db22d5f 100644 --- a/PExpr.h +++ b/PExpr.h @@ -407,6 +407,11 @@ class PEIdent : public PExpr { std::list&prefix_indices) const; private: + + NetAssign_ *elaborate_lval_var_(Design *des, NetScope *scope, + bool is_force, bool is_cassign, + NetNet *reg, ivl_type_t data_type, + pform_name_t tail_path) const; NetAssign_*elaborate_lval_method_class_member_(Design*, NetScope*) const; NetAssign_*elaborate_lval_net_word_(Design*, NetScope*, NetNet*, bool need_const_idx) const; diff --git a/elab_lval.cc b/elab_lval.cc index f38abbfa9..2a613f34d 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -227,6 +227,15 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, << endl; } + return elaborate_lval_var_(des, scope, is_force, is_cassign, reg, + sr.type, member_path); +} + +NetAssign_*PEIdent::elaborate_lval_var_(Design *des, NetScope *scope, + bool is_force, bool is_cassign, + NetNet *reg, ivl_type_t data_type, + pform_name_t tail_path) const +{ // We are processing the tail of a string of names. For // example, the Verilog may be "a.b.c", so we are processing // "c" at this point. @@ -266,7 +275,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, && (reg->type() != NetNet::UNRESOLVED_WIRE) && !is_force) { cerr << get_fileline() << ": error: " << path_ << - " is not a valid l-value in " << scope_path(use_scope) << + " is not a valid l-value in " << scope_path(scope) << "." << endl; cerr << reg->get_fileline() << ": : " << path_ << " is declared here as " << reg->type() << "." << endl; @@ -277,25 +286,23 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, // If we find that the matched variable is a packed struct, // then we can handled it with the net_packed_member_ method. - if (reg->struct_type() && !member_path.empty()) { + if (reg->struct_type() && !tail_path.empty()) { NetAssign_*lv = new NetAssign_(reg); - elaborate_lval_net_packed_member_(des, scope, lv, member_path); + elaborate_lval_net_packed_member_(des, scope, lv, tail_path); return lv; } // If the variable is a class object, then handle it with the // net_class_member_ method. - const netclass_t *class_type = dynamic_cast(sr.type); - if (class_type && !member_path.empty() && gn_system_verilog()) { - NetAssign_*lv = elaborate_lval_net_class_member_(des, scope, class_type, reg, member_path); - return lv; - } + const netclass_t *class_type = dynamic_cast(data_type); + if (class_type && !tail_path.empty() && gn_system_verilog()) + return elaborate_lval_net_class_member_(des, scope, class_type, reg, tail_path); // Past this point, we should have taken care of the cases // where the name is a member/method of a struct/class. // XXXX ivl_assert(*this, method_name.nil()); - ivl_assert(*this, member_path.empty()); + ivl_assert(*this, tail_path.empty()); bool need_const_idx = is_cassign || is_force || (reg->type()==NetNet::UNRESOLVED_WIRE); @@ -380,10 +387,11 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des, property_qualifier_t qual = class_type->get_prop_qual(pidx); - // Static properties are handled as normal signals. Regular symbol - // search will find it. - if (qual.test_static()) - return 0; + if (qual.test_static()) { + NetNet *sig = class_type->find_static_property(member_name); + return elaborate_lval_var_(des, scope, false, false, sig, + class_type, {}); + } NetScope*scope_method = find_method_containing_scope(*this, scope); ivl_assert(*this, scope_method); diff --git a/ivtest/ivltests/sv_class_static_prop4.v b/ivtest/ivltests/sv_class_static_prop4.v new file mode 100644 index 000000000..553770eeb --- /dev/null +++ b/ivtest/ivltests/sv_class_static_prop4.v @@ -0,0 +1,45 @@ +// Check that it is possible to access static properties of a base class + +class B; + static int x = 0; + static int y = 0; +endclass + +class C extends B; + + task t(int a, int b); + x = a; + this.y = b; + endtask + + function int f; + return x + this.y; + endfunction + +endclass + +module test; + bit failed = 1'b0; + + `define check(expr, val) \ + if (expr !== val) begin \ + $display("FAILED: `%s`, expected %b, got %b", `"expr`", val, expr); \ + failed = 1'b1; \ + end + + C c = new; + + initial begin + // Check access inside the class + c.t(10, 20); + `check(c.f(), 30) + + // Check access outside of the class + c.x = 40; + `check(c.x, 40) + + if (!failed) begin + $display("PASSED"); + end + end +endmodule diff --git a/ivtest/regress-sv.list b/ivtest/regress-sv.list index f5439f7b3..9cf41bbfc 100644 --- a/ivtest/regress-sv.list +++ b/ivtest/regress-sv.list @@ -590,6 +590,7 @@ sv_class_return normal,-g2009 ivltests sv_class_static_prop1 normal,-g2009 ivltests sv_class_static_prop2 normal,-g2009 ivltests sv_class_static_prop3 normal,-g2009 ivltests +sv_class_static_prop4 normal,-g2009 ivltests sv_class_super1 normal,-g2009 ivltests sv_class_super2 normal,-g2009 ivltests sv_class_super3 normal,-g2009 ivltests diff --git a/ivtest/regress-vlog95.list b/ivtest/regress-vlog95.list index 76d299369..ad008941a 100644 --- a/ivtest/regress-vlog95.list +++ b/ivtest/regress-vlog95.list @@ -437,6 +437,7 @@ sv_class_return CE,-g2009 ivltests sv_class_static_prop1 CE,-g2009 ivltests sv_class_static_prop2 CE,-g2009 ivltests sv_class_static_prop3 CE,-g2009 ivltests +sv_class_static_prop4 CE,-g2009 ivltests sv_class_super1 CE,-g2009 ivltests sv_class_super2 CE,-g2009 ivltests sv_class_super3 CE,-g2009 ivltests diff --git a/netclass.cc b/netclass.cc index e9b5e7480..172cf9965 100644 --- a/netclass.cc +++ b/netclass.cc @@ -174,8 +174,14 @@ NetScope*netclass_t::method_from_name(perm_string name) const NetNet* netclass_t::find_static_property(perm_string name) const { - NetNet*tmp = class_scope_->find_signal(name); - return tmp; + NetNet *net = class_scope_->find_signal(name); + if (net) + return net; + + if (super_) + return super_->find_static_property(name); + + return nullptr; } bool netclass_t::test_scope_is_method(const NetScope*scope) const