From eed38bd14a0a970e82c3af32d4e6b3328f209bf5 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 19 Mar 2022 21:15:53 +0100 Subject: [PATCH] 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); } /*