From 583a7ddc352a8520f8b2e8939b22c266076ca3a6 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 17 Mar 2022 12:25:28 +0100 Subject: [PATCH 1/3] netclass: Make pointer to base class const The base class type is not owned by a class and is shared. For this reason it must not be modified. To ensure this mark the base class pointer as const. Signed-off-by: Lars-Peter Clausen --- netclass.cc | 4 ++-- netclass.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/netclass.cc b/netclass.cc index 82be2c55e..3365a8949 100644 --- a/netclass.cc +++ b/netclass.cc @@ -23,8 +23,8 @@ using namespace std; -netclass_t::netclass_t(perm_string name, netclass_t*sup) -: name_(name), super_(sup), class_scope_(0), definition_scope_(0) +netclass_t::netclass_t(perm_string name, const netclass_t*super) +: name_(name), super_(super), class_scope_(0), definition_scope_(0) { } diff --git a/netclass.h b/netclass.h index 7274bd5f7..af473ba71 100644 --- a/netclass.h +++ b/netclass.h @@ -35,7 +35,7 @@ class PExpr; class netclass_t : public ivl_type_s { public: - netclass_t(perm_string class_name, netclass_t*par); + netclass_t(perm_string class_name, const netclass_t*super); ~netclass_t(); // Set the property of the class during elaboration. Set the @@ -120,7 +120,7 @@ class netclass_t : public ivl_type_s { perm_string name_; // If this is derived from another base class, point to it // here. - netclass_t*super_; + const netclass_t*super_; // Map property names to property table index. std::map properties_; // Vector of properties. From eed38bd14a0a970e82c3af32d4e6b3328f209bf5 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 19 Mar 2022 21:15:53 +0100 Subject: [PATCH 2/3] Handle multiple instances of modules with class definitions For classes declared inside a module each module instance creates a new unique class type. These types are not compatible to each other. This is necessary since module parameters can change the class implementation. This is defined in section 6.22 ("Type compatibility") of the LRM (1800-2017). In the current implementation when a class is elaborated the elaborated type is stored in the class_type_t so it is possible to look up the elaborated class type. But this class_type_t is shared among elaborated class types. As a result when creating multiple instances of a module with a class definition an internal assert is triggered. To support multiple module instances with class definitions instead of storing the elaborated type in the type definition look up the type in the scope in which the type definition is references. This is similar to how the same problem is solved for enum types. For packages we still need to remember the elaborated type otherwise scoped class type references wont work. Since there is only one instance of a package this doesn't have the same problem as classes in modules. Signed-off-by: Lars-Peter Clausen --- elab_scope.cc | 31 ++++++++++++++++--------------- elab_type.cc | 7 ++++--- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index fe39506e9..9d156ba52 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -489,29 +489,30 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) << endl; } - class_type_t*base_class = dynamic_cast (use_type->base_type); - if (use_type->base_type && !base_class) { - cerr << pclass->get_fileline() << ": error: " - << "Base type of " << use_type->name - << " is not a class." << endl; - des->errors += 1; - } - netclass_t*use_base_class = 0; - if (base_class) { - use_base_class = base_class->save_elaborated_type; - if (use_base_class == 0) { + const netclass_t*use_base_class = 0; + if (use_type->base_type) { + ivl_type_t base_type = use_type->base_type->elaborate_type(des, scope); + use_base_class = dynamic_cast(base_type); + if (!use_base_class) { cerr << pclass->get_fileline() << ": error: " - << "Base class " << base_class->name - << " not found." << endl; + << "Base type of " << use_type->name + << " is not a class." << endl; des->errors += 1; } } netclass_t*use_class = new netclass_t(use_type->name, use_base_class); - ivl_assert(*pclass, use_type->save_elaborated_type == 0); - use_type->save_elaborated_type = use_class; + // If this is a package we need to remember the elaborated type so that + // scoped type references work. Since there is only one instance for each + // package this works. For classes defined in modules there might be + // multiple instances though. Each module instance will have its own class + // type instance, so the same does not work there. + if (scope->type() == NetScope::PACKAGE) { + ivl_assert(*pclass, use_type->save_elaborated_type == 0); + use_type->save_elaborated_type = use_class; + } NetScope*class_scope = new NetScope(scope, hname_t(pclass->pscope_name()), NetScope::CLASS, scope->unit()); diff --git a/elab_type.cc b/elab_type.cc index 948836856..ecd81e098 100644 --- a/elab_type.cc +++ b/elab_type.cc @@ -101,10 +101,11 @@ ivl_type_t atom2_type_t::elaborate_type_raw(Design*des, NetScope*) const } } -ivl_type_t class_type_t::elaborate_type_raw(Design*, NetScope*) const +ivl_type_t class_type_t::elaborate_type_raw(Design*des, NetScope*scope) const { - ivl_assert(*this, save_elaborated_type); - return save_elaborated_type; + if (save_elaborated_type) + return save_elaborated_type; + return scope->find_class(des, name); } /* From abe5e692ceea29733c8e4a97e35c1134e060555a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 22 Mar 2022 11:10:47 +0100 Subject: [PATCH 3/3] Add regression test for classes defined in modules Check that it is possible to have multiple instances of a module that declares a class and that the class in each module instance is a unique type that can have dependencies on module parameters. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/sv_class_in_module_decl.v | 32 +++++++++++++++++++++++ ivtest/regress-sv.list | 1 + ivtest/regress-vlog95.list | 1 + 3 files changed, 34 insertions(+) create mode 100644 ivtest/ivltests/sv_class_in_module_decl.v diff --git a/ivtest/ivltests/sv_class_in_module_decl.v b/ivtest/ivltests/sv_class_in_module_decl.v new file mode 100644 index 000000000..267bed7b9 --- /dev/null +++ b/ivtest/ivltests/sv_class_in_module_decl.v @@ -0,0 +1,32 @@ +// Check that it is possible to have multiple instances of a module that defines +// a class and that the actual class types can have different implementations +// based on module parameters. + +module M #( + parameter X = 0 +); + + class C; + function int f; + return X; + endfunction + endclass + + C c = new; + +endmodule + +module test; + + M #(10) m1(); + M #(20) m2(); + + initial begin + if (m1.c.f() == 10 && m2.c.f() == 20) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/regress-sv.list b/ivtest/regress-sv.list index 70e7b90c5..26c1e2ff8 100644 --- a/ivtest/regress-sv.list +++ b/ivtest/regress-sv.list @@ -458,6 +458,7 @@ sv_class_empty_item normal,-g2009 ivltests sv_class_extends_scoped normal,-g2009 ivltests sv_class_localparam normal,-g2009 ivltests sv_class_new_init normal,-g2009 ivltests +sv_class_in_module_decl normal,-g2009 ivltests sv_darray1 normal,-g2009 ivltests sv_darray2 normal,-g2009 ivltests sv_darray3 normal,-g2009 ivltests diff --git a/ivtest/regress-vlog95.list b/ivtest/regress-vlog95.list index 89af38b69..576b6354b 100644 --- a/ivtest/regress-vlog95.list +++ b/ivtest/regress-vlog95.list @@ -372,6 +372,7 @@ sv_class_empty_item CE,-g2009 ivltests sv_class_extends_scoped CE,-g2009 ivltests sv_class_localparam CE,-g2009 ivltests sv_class_new_init CE,-g2009 ivltests +sv_class_in_module_decl CE,-g2009 ivltests sv_end_label CE,-g2009 ivltests # Also generate sv_foreach2 CE,-g2009,-pallowsigned=1 ivltests sv_foreach3 CE,-g2009 ivltests