From ba25b55f53c7923ef9e726a27bd7cf7329c2a6b8 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 3 Jan 2021 18:45:08 +0000 Subject: [PATCH] Elaborate package scopes in textual order (fix for issue #461) When elaborating a subclass, the base class scope needs to be elaborated before the subclass scope. If the base class and subclass are defined in different packages, this requires the package scopes to be elaborated in the correct order. SystemVerilog reqires packages to be defined before they are used, so that is the order we should elaborate them in. --- elaborate.cc | 43 ++++++++++++++++++++++--------------------- main.cc | 6 +++--- parse_api.h | 4 ++-- pform_package.cc | 20 +++++++++++++------- 4 files changed, 40 insertions(+), 33 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index 940d00365..21b131762 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -6766,18 +6766,18 @@ static void check_timescales() if (some_explicit && some_implicit) break; } - map::iterator pkg; + vector::iterator pkg; if (gn_system_verilog() && !(some_explicit && some_implicit)) { for (pkg = pform_packages.begin(); pkg != pform_packages.end(); ++pkg) { - const PPackage*pp = (*pkg).second; + const PPackage*pp = *pkg; check_timescales(some_explicit, some_implicit, pp); if (some_explicit && some_implicit) break; } } if (gn_system_verilog() && !(some_explicit && some_implicit)) { - for (unsigned idx = 0; idx < pform_units.size(); idx += 1) { - const PPackage*pp = pform_units[idx]; + for (pkg = pform_units.begin(); pkg != pform_units.end(); ++pkg) { + const PPackage*pp = *pkg; // We don't need a timescale if the compilation unit // contains no items outside a design element. if (pp->parameters.empty() && @@ -6828,15 +6828,15 @@ static void check_timescales() return; for (pkg = pform_packages.begin(); pkg != pform_packages.end(); ++pkg) { - PPackage*pp = (*pkg).second; + PPackage*pp = *pkg; if (pp->has_explicit_timescale()) continue; - cerr << " : -- package " << (*pkg).first + cerr << " : -- package " << pp->pscope_name() << " declared here: " << pp->get_fileline() << endl; } - for (unsigned idx = 0; idx < pform_units.size(); idx += 1) { - PPackage*pp = pform_units[idx]; + for (pkg = pform_units.begin(); pkg != pform_units.end(); ++pkg) { + PPackage*pp = *pkg; if (pp->has_explicit_timescale()) continue; @@ -6892,8 +6892,9 @@ Design* elaborate(listroots) // Elaborate the compilation unit scopes. From here on, these are // treated as an additional set of packages. if (gn_system_verilog()) { - for (i = 0; i < pform_units.size(); i += 1) { - PPackage*unit = pform_units[i]; + for (vector::iterator pkg = pform_units.begin() + ; pkg != pform_units.end() ; ++pkg) { + PPackage*unit = *pkg; NetScope*scope = des->make_package_scope(unit->pscope_name(), 0, true); scope->set_line(unit); scope->add_imports(&unit->explicit_imports); @@ -6904,6 +6905,7 @@ Design* elaborate(listroots) pack_elems[i].pack = unit; pack_elems[i].scope = scope; + i += 1; unit_scopes[unit] = scope; } @@ -6914,20 +6916,19 @@ Design* elaborate(listroots) // in SystemVerilog, packages are not allowed to refer to // the compilation unit scope, but the VHDL preprocessor // assumes they can. - for (map::iterator pac = pform_packages.begin() - ; pac != pform_packages.end() ; ++ pac) { + for (vector::iterator pkg = pform_packages.begin() + ; pkg != pform_packages.end() ; ++pkg) { + PPackage*pack = *pkg; + NetScope*unit_scope = unit_scopes[pack->parent_scope()]; + NetScope*scope = des->make_package_scope(pack->pscope_name(), unit_scope, false); + scope->set_line(pack); + scope->add_imports(&pack->explicit_imports); + set_scope_timescale(des, scope, pack); - ivl_assert(*pac->second, pac->first == pac->second->pscope_name()); - NetScope*unit_scope = unit_scopes[pac->second->parent_scope()]; - NetScope*scope = des->make_package_scope(pac->first, unit_scope, false); - scope->set_line(pac->second); - scope->add_imports(&pac->second->explicit_imports); - set_scope_timescale(des, scope, pac->second); - - elaborator_work_item_t*es = new elaborate_package_t(des, scope, pac->second); + elaborator_work_item_t*es = new elaborate_package_t(des, scope, pack); des->elaboration_work_list.push_back(es); - pack_elems[i].pack = pac->second; + pack_elems[i].pack = pack; pack_elems[i].scope = scope; i += 1; } diff --git a/main.cc b/main.cc index 45b626f77..7da46989a 100644 --- a/main.cc +++ b/main.cc @@ -1,5 +1,5 @@ const char COPYRIGHT[] = - "Copyright (c) 1998-2020 Stephen Williams (steve@icarus.com)"; + "Copyright (c) 1998-2021 Stephen Williams (steve@icarus.com)"; /* * This source code is free software; you can redistribute it @@ -1142,9 +1142,9 @@ int main(int argc, char*argv[]) pform_dump(out, *pac); } out << "PFORM DUMP PACKAGES:" << endl; - for (map::iterator pac = pform_packages.begin() + for (vector::iterator pac = pform_packages.begin() ; pac != pform_packages.end() ; ++ pac) { - pform_dump(out, pac->second); + pform_dump(out, *pac); } out << "PFORM DUMP MODULES:" << endl; for (map::iterator mod = pform_modules.begin() diff --git a/parse_api.h b/parse_api.h index 1b76b767b..0ed284b3c 100644 --- a/parse_api.h +++ b/parse_api.h @@ -1,7 +1,7 @@ #ifndef IVL_parse_api_H #define IVL_parse_api_H /* - * Copyright (c) 2001-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2021 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -43,7 +43,7 @@ struct enum_type_t; extern std::map pform_modules; extern std::map pform_primitives; extern std::vector pform_units; -extern std::map pform_packages; +extern std::vector pform_packages; extern void pform_dump(std::ostream&out, const PClass*pac); extern void pform_dump(std::ostream&out, const PPackage*pac); diff --git a/pform_package.cc b/pform_package.cc index 375523f41..100ae6b42 100644 --- a/pform_package.cc +++ b/pform_package.cc @@ -29,9 +29,14 @@ using namespace std; /* - * This is a map of packages that have been defined. + * This is a list of packages in the order that they were defined. */ -map pform_packages; +vector pform_packages; + +/* + * This allows us to easily check for name collisions. + */ +static map packages_by_name; static PPackage*pform_cur_package = 0; @@ -51,8 +56,8 @@ void pform_end_package_declaration(const struct vlltype&loc) ivl_assert(loc, pform_cur_package); perm_string use_name = pform_cur_package->pscope_name(); - map::const_iterator test = pform_packages.find(use_name); - if (test != pform_packages.end()) { + map::const_iterator test = packages_by_name.find(use_name); + if (test != packages_by_name.end()) { ostringstream msg; msg << "Package " << use_name << " was already declared here: " << test->second->get_fileline() << ends; @@ -60,7 +65,8 @@ void pform_end_package_declaration(const struct vlltype&loc) } - pform_packages[use_name] = pform_cur_package; + packages_by_name[use_name] = pform_cur_package; + pform_packages.push_back(pform_cur_package); pform_cur_package = 0; pform_pop_scope(); } @@ -152,8 +158,8 @@ data_type_t* pform_test_type_identifier(PPackage*pkg, const char*txt) PPackage* pform_test_package_identifier(const char*pkg_name) { perm_string use_name = lex_strings.make(pkg_name); - map::const_iterator pcur = pform_packages.find(use_name); - if (pcur == pform_packages.end()) + map::const_iterator pcur = packages_by_name.find(use_name); + if (pcur == packages_by_name.end()) return 0; assert(pcur->second);