diff --git a/Changes b/Changes index d2038fcde..700bc035d 100644 --- a/Changes +++ b/Changes @@ -6,6 +6,8 @@ The contributors that suggested a given feature are shown in []. Thanks! *** Support or/and/xor array intrinsic methods, bug1210. [Mike Popoloski] +*** Support package export, bug1217. [Usuario Eda] + *** Fix ordering of arrayed cell wide connections, bug1202 partial. [Mike Popoloski] **** Support module port parameters without defaults, bug 1213. [Mike Popoloski] diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 8eb69c210..6dee14db8 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -891,6 +891,10 @@ void AstNodeModule::dump(ostream& str) { if (inLibrary()) str<<" [LIB]"; if (dead()) str<<" [DEAD]"; } +void AstPackageExport::dump(ostream& str) { + this->AstNode::dump(str); + str<<" -> "<AstNode::dump(str); str<<" -> "<brokeExists()); return NULL; } + virtual void cloneRelink() { if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep(); } + virtual void dump(ostream& str); + virtual string name() const { return m_name; } + AstPackage* packagep() const { return m_packagep; } + void packagep(AstPackage* nodep) { m_packagep=nodep; } +}; + class AstPackageImport : public AstNode { private: // A package import declaration diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 5345b0a8c..74db17d6f 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1017,6 +1017,24 @@ class LinkDotFindVisitor : public AstNVisitor { UINFO(9," Link Done: "<getNodeSym(nodep->packagep()); + if (nodep->name()!="*") { + VSymEnt* impp = srcp->findIdFlat(nodep->name()); + if (!impp) { + nodep->v3error("Export object not found: "<packagep()->prettyName()<<"::"<prettyName()); + } + } + m_curSymp->exportFromPackage(m_statep->symsp(), srcp, nodep->name()); + UINFO(9," Link Done: "<exportStarStar(m_statep->symsp()); + // No longer needed, but can't delete until any multi-instantiated modules are expanded + } virtual void visit(AstNode* nodep) { // Default: Just iterate @@ -2216,6 +2234,16 @@ private: checkNoDot(nodep); nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep); } + virtual void visit(AstPackageExport* nodep) { + // No longer needed + checkNoDot(nodep); + nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep); + } + virtual void visit(AstPackageExportStarStar* nodep) { + // No longer needed + checkNoDot(nodep); + nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep); + } virtual void visit(AstCellRef* nodep) { UINFO(5," AstCellRef: "<iterateChildren(*this); diff --git a/src/V3ParseSym.h b/src/V3ParseSym.h index eb86f7ab7..f98accaf3 100644 --- a/src/V3ParseSym.h +++ b/src/V3ParseSym.h @@ -122,7 +122,7 @@ public: if (foundp) return foundp->nodep(); else return NULL; } - void import(AstNode* packagep, const string& id_or_star) { + void importItem(AstNode* packagep, const string& id_or_star) { // Import from package::id_or_star to this VSymEnt* symp = getTable(packagep); if (!symp) { // Internal problem, because we earlier found pkg to label it an ID__aPACKAGE @@ -133,6 +133,19 @@ public: // We let V3LinkDot report the error instead of us symCurrentp()->importFromPackage(&m_syms, symp, id_or_star); } + void exportItem(AstNode* packagep, const string& id_or_star) { + // Export from this the remote package::id_or_star + VSymEnt* symp = getTable(packagep); + if (!symp) { // Internal problem, because we earlier found pkg to label it an ID__aPACKAGE + packagep->v3fatalSrc("Export package not found"); + return; + } + symCurrentp()->exportFromPackage(&m_syms, symp, id_or_star); + } + void exportStarStar(AstNode* packagep) { + // Export *::* from remote packages + symCurrentp()->exportStarStar(&m_syms); + } public: // CREATORS explicit V3ParseSym(AstNetlist* rootp) diff --git a/src/V3SymTable.h b/src/V3SymTable.h index 55c233ce4..c04000e3e 100644 --- a/src/V3SymTable.h +++ b/src/V3SymTable.h @@ -41,6 +41,7 @@ class VSymEnt; // Symbol table typedef set VSymMap; +typedef set VSymConstMap; class VSymEnt { // Symbol table that can have a "superior" table for resolving upper references @@ -65,7 +66,7 @@ private: static inline int debug() { return 0; } // NOT runtime, too hot of a function #endif public: - void dumpIterate(ostream& os, VSymMap& doneSymsr, const string& indent, int numLevels, const string& searchName) { + void dumpIterate(ostream& os, VSymConstMap& doneSymsr, const string& indent, int numLevels, const string& searchName) const { os<exported() && !findIdFlat(name)) { // Don't insert over existing entry VSymEnt* symp = new VSymEnt(graphp, srcp); symp->exported(false); // Can't reimport an import without an export symp->imported(true); reinsert(name, symp); - return true; - } else { - return false; + } + } + void exportOneSymbol(VSymGraph* graphp, const string& name, const VSymEnt* srcp) { + if (srcp->exported()) { + if (VSymEnt* symp = findIdFlat(name)) { // Should already exist in current table + if (!symp->exported()) symp->exported(true); + } } } public: - bool importFromPackage(VSymGraph* graphp, const VSymEnt* srcp, const string& id_or_star) { + void importFromPackage(VSymGraph* graphp, const VSymEnt* srcp, const string& id_or_star) { // Import tokens from source symbol table into this symbol table - // Returns true if successful - bool any = false; if (id_or_star != "*") { IdNameMap::const_iterator it = srcp->m_idNameMap.find(id_or_star); - if (it != m_idNameMap.end()) { + if (it != srcp->m_idNameMap.end()) { importOneSymbol(graphp, it->first, it->second); } - any = true; // Legal, though perhaps lint questionable to import nothing } else { for (IdNameMap::const_iterator it=srcp->m_idNameMap.begin(); it!=srcp->m_idNameMap.end(); ++it) { - if (importOneSymbol(graphp, it->first, it->second)) any = true; + importOneSymbol(graphp, it->first, it->second); } } - return any; + } + void exportFromPackage(VSymGraph* graphp, const VSymEnt* srcp, const string& id_or_star) { + // Export tokens from source symbol table into this symbol table + if (id_or_star != "*") { + IdNameMap::const_iterator it = srcp->m_idNameMap.find(id_or_star); + if (it != srcp->m_idNameMap.end()) { + exportOneSymbol(graphp, it->first, it->second); + } + } else { + for (IdNameMap::const_iterator it=srcp->m_idNameMap.begin(); it!=srcp->m_idNameMap.end(); ++it) { + exportOneSymbol(graphp, it->first, it->second); + } + } + } + void exportStarStar(VSymGraph* graphp) { + // Export *:*: Export all tokens from imported packages + for (IdNameMap::const_iterator it=m_idNameMap.begin(); it!=m_idNameMap.end(); ++it) { + VSymEnt* symp = it->second; + if (!symp->exported()) symp->exported(true); + } } void importFromIface(VSymGraph* graphp, const VSymEnt* srcp, bool onlyUnmodportable = false) { // Import interface tokens from source symbol table into this symbol table, recursively @@ -239,7 +260,7 @@ public: VSymEnt* rootp() const { return m_symRootp; } // Debug void dump(ostream& os, const string& indent="") { - VSymMap doneSyms; + VSymConstMap doneSyms; os<<"SymEnt Dump:\n"; m_symRootp->dumpIterate(os, doneSyms, indent, 9999, "$root"); bool first = true; diff --git a/src/verilog.y b/src/verilog.y index b339796f2..672525bbf 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -707,7 +707,7 @@ package_itemList: // IEEE: { package_item } package_item: // ==IEEE: package_item package_or_generate_item_declaration { $$ = $1; } //UNSUP anonymous_program { $$ = $1; } - //UNSUP package_export_declaration { $$ = $1; } + | package_export_declaration { $$ = $1; } | timeunits_declaration { $$ = $1; } ; @@ -746,7 +746,7 @@ package_import_itemList: package_import_item: // ==IEEE: package_import_item yaID__aPACKAGE yP_COLONCOLON package_import_itemObj { $$ = new AstPackageImport($1, $1->castPackage(), *$3); - SYMP->import($1,*$3); } + SYMP->importItem($1,*$3); } ; package_import_itemObj: // IEEE: part of package_import_item @@ -754,6 +754,22 @@ package_import_itemObj: // IEEE: part of package_import_item | '*' { $$=$1; static string star="*"; $$=☆ } ; +package_export_declaration: // IEEE: package_export_declaration + yEXPORT '*' yP_COLONCOLON '*' ';' { $$ = new AstPackageExportStarStar($1); SYMP->exportStarStar($1); } + | yEXPORT package_export_itemList ';' { $$ = $2; } + ; + +package_export_itemList: + package_export_item { $$ = $1; } + | package_export_itemList ',' package_export_item { $$ = $1->addNextNull($3); } + ; + +package_export_item: // ==IEEE: package_export_item + yaID__aPACKAGE yP_COLONCOLON package_import_itemObj + { $$ = new AstPackageExport($1, $1->castPackage(), *$3); + SYMP->exportItem($1,*$3); } + ; + //********************************************************************** // Module headers diff --git a/test_regress/t/t_package_export.pl b/test_regress/t/t_package_export.pl index 9cd16f86a..27a0ad8e8 100755 --- a/test_regress/t/t_package_export.pl +++ b/test_regress/t/t_package_export.pl @@ -7,7 +7,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Lesser General Public License Version 3 or the Perl Artistic License # Version 2.0. -$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug592"); $Self->{vcs} and $Self->unsupported("VCS unsupported"); compile ( diff --git a/test_regress/t/t_package_export.v b/test_regress/t/t_package_export.v index b864a14ca..e8dbece18 100644 --- a/test_regress/t/t_package_export.v +++ b/test_regress/t/t_package_export.v @@ -5,17 +5,46 @@ // see bug 591 -package pkg2; - parameter PARAM2 = 16; -endpackage // pkg2 - package pkg1; - import pkg2::*; + parameter PARAM2 = 16; + parameter PARAM3 = 16; +endpackage : pkg1 + + +package pkg10; + import pkg1::*; + import pkg1::*; // Ignore if already `ifdef T_PACKAGE_EXPORT - export pkg2::*; // Not supported on all simulators + export *::*; // Not supported on all simulators `endif parameter PARAM1 = 8; -endpackage // pkg1 +endpackage +package pkg11; + import pkg10::*; +endpackage + +package pkg20; + import pkg1::*; +`ifdef T_PACKAGE_EXPORT + export pkg1::*; +`endif + parameter PARAM1 = 8; +endpackage +package pkg21; + import pkg20::*; +endpackage + +package pkg30; + import pkg1::*; +`ifdef T_PACKAGE_EXPORT + export pkg1::PARAM2; + export pkg1::PARAM3; +`endif + parameter PARAM1 = 8; +endpackage +package pkg31; + import pkg30::*; +endpackage module t (/*AUTOARG*/ // Inputs @@ -23,10 +52,17 @@ module t (/*AUTOARG*/ ); input clk; - import pkg1::*; + reg [pkg11::PARAM1 : 0] bus11; + reg [pkg11::PARAM2 : 0] bus12; + reg [pkg11::PARAM3 : 0] bus13; - reg [PARAM1:0] bus1; - reg [PARAM2:0] bus2; + reg [pkg21::PARAM1 : 0] bus21; + reg [pkg21::PARAM2 : 0] bus22; + reg [pkg21::PARAM3 : 0] bus23; + + reg [pkg31::PARAM1 : 0] bus31; + reg [pkg31::PARAM2 : 0] bus32; + reg [pkg31::PARAM3 : 0] bus33; initial begin $write("*-* All Finished *-*\n"); diff --git a/test_regress/t/t_package_export_bad.pl b/test_regress/t/t_package_export_bad.pl index a1c77460a..96f501b7e 100755 --- a/test_regress/t/t_package_export_bad.pl +++ b/test_regress/t/t_package_export_bad.pl @@ -16,7 +16,12 @@ compile ( make_top_shell => 0, make_main => 0, expect=> -'%Error: t/t_package_export.v:\d+: Can\'t find definition of variable: PARAM2 +'%Error: t/t_package_export.v:\d+: Can\'t find definition of scope/variable: PARAM2 +%Error: t/t_package_export.v:\d+: Can\'t find definition of scope/variable: PARAM3 +%Error: t/t_package_export.v:\d+: Can\'t find definition of scope/variable: PARAM2 +%Error: t/t_package_export.v:\d+: Can\'t find definition of scope/variable: PARAM3 +%Error: t/t_package_export.v:\d+: Can\'t find definition of scope/variable: PARAM2 +%Error: t/t_package_export.v:\d+: Can\'t find definition of scope/variable: PARAM3 %Error: Exiting due to.*', );