diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 12064f09d..832bbbece 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -38,7 +38,7 @@ Chuxuan Wang Chykon Congcong Cai Conor McCullough -Dan Petrisko +Dan Ruelas-Petrisko Daniel Bates Danny Oler Dave Sargeant diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 36913ebd4..bc5b9f661 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -821,16 +821,20 @@ class AstConfig final : public AstNode { // Parents: NETLIST // @astgen op1 := designp : List[AstConfigCell] // @astgen op2 := itemsp : List[AstNode] - std::string m_name; // Config block name + std::string m_libname; // Config library, or "" + std::string m_configname; // Config name within library public: - AstConfig(FileLine* fl, const std::string& name, AstNode* itemsp) + AstConfig(FileLine* fl, const std::string& libname, const std::string& cellname) : ASTGEN_SUPER_Config(fl) - , m_name{name} { - addItemsp(itemsp); - } + , m_libname{libname} + , m_configname{cellname} {} ASTGEN_MEMBERS_AstConfig; - std::string name() const override VL_MT_STABLE { return m_name; } + std::string name() const override VL_MT_STABLE { return m_libname + "." + m_configname; } + std::string libname() const VL_MT_STABLE { return m_libname; } + std::string configname() const VL_MT_STABLE { return m_configname; } + void dump(std::ostream& str) const override; + void dumpJson(std::ostream& str) const override; }; class AstConfigCell final : public AstNode { // Parents: CONFIGRULE diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index d7ed985dc..f18be3c40 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1858,6 +1858,16 @@ void AstClocking::dumpJson(std::ostream& str) const { dumpJsonBoolFunc(str, isGlobal); dumpJsonGen(str); } +void AstConfig::dump(std::ostream& str) const { + this->AstNode::dump(str); + str << " configname=" << configname(); + if (libname() != "work") str << " libname=" << libname(); +} +void AstConfig::dumpJson(std::ostream& str) const { + dumpJsonStrFunc(str, configname); + if (libname() != "work") dumpJsonStr(str, "libname=", libname()); + dumpJsonGen(str); +} void AstConfigRule::dump(std::ostream& str) const { this->AstNode::dump(str); if (isCell()) str << " [CELL]"; diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp index d2d1fa200..5cb1bf001 100644 --- a/src/V3LinkCells.cpp +++ b/src/V3LinkCells.cpp @@ -91,6 +91,59 @@ void LinkCellsGraph::loopsMessageCb(V3GraphVertex* vertexp, V3EdgeFuncP edgeFunc //###################################################################### // Link state, as a visitor of each AstNode +// State to pass between config parsing and cell linking visitors. +struct LinkCellsState final { + // Set of possible top module names from command line and configs + std::unordered_set m_topModuleNames; +}; + +class LinkConfigsVisitor final : public VNVisitor { + // STATE + LinkCellsState& m_state; // Context for linking cells + + // VISITORS + void visit(AstConfig* nodep) override { + const string fullTopName = v3Global.opt.work() + '.' + v3Global.opt.topModule(); + const bool topMatch = (fullTopName == nodep->name()); + if (topMatch) { + m_state.m_topModuleNames.erase(fullTopName); + for (AstConfigCell* cellp = nodep->designp(); cellp; + cellp = VN_AS(cellp->nextp(), ConfigCell)) { + m_state.m_topModuleNames.insert(cellp->name()); + } + } + // We don't do iterateChildren here because we want to skip designp + iterateAndNextNull(nodep->itemsp()); + } + + void visit(AstConfigCell* nodep) override { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: config cell"); + iterateChildren(nodep); + } + void visit(AstConfigRule* nodep) override { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: config rule"); + iterateChildren(nodep); + } + void visit(AstConfigUse* nodep) override { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: config use"); + iterateChildren(nodep); + } + + void visit(AstNode* nodep) override { iterateChildren(nodep); } + +public: + // CONSTRUCTORS + LinkConfigsVisitor(AstNetlist* nodep, LinkCellsState& state) + : m_state{state} { + // Initialize top module from command line option + if (!m_state.m_topModuleNames.size() && !v3Global.opt.topModule().empty()) { + const string fullTopName = v3Global.opt.work() + '.' + v3Global.opt.topModule(); + m_state.m_topModuleNames.insert(fullTopName); + } + iterate(nodep); + } +}; + class LinkCellsVisitor final : public VNVisitor { // NODE STATE // Entire netlist: @@ -105,6 +158,7 @@ class LinkCellsVisitor final : public VNVisitor { // STATE VInFilter* const m_filterp; // Parser filter + LinkCellsState& m_state; // State for linking cells // Below state needs to be preserved between each module call. AstNodeModule* m_modp = nullptr; // Current module @@ -245,7 +299,8 @@ class LinkCellsVisitor final : public VNVisitor { if (VN_IS(nodep, Iface) || VN_IS(nodep, Package)) { nodep->inLibrary(true); // Interfaces can't be at top, unless asked } - const bool topMatch = (v3Global.opt.topModule() == nodep->prettyName()); + const string fullName = nodep->libname() + "." + nodep->name(); + const bool topMatch = (m_state.m_topModuleNames.count(fullName) > 0); if (topMatch) { m_topVertexp = vertex(nodep); UINFO(2, "Link --top-module: " << nodep); @@ -603,23 +658,6 @@ class LinkCellsVisitor final : public VNVisitor { iterateAndNextNull(nodep->attrsp()); } - void visit(AstConfig* nodep) override { - nodep->v3warn(E_UNSUPPORTED, "Unsupported: config"); - iterateChildren(nodep); - } - void visit(AstConfigCell* nodep) override { - nodep->v3warn(E_UNSUPPORTED, "Unsupported: config cell"); - iterateChildren(nodep); - } - void visit(AstConfigRule* nodep) override { - nodep->v3warn(E_UNSUPPORTED, "Unsupported: config rule"); - iterateChildren(nodep); - } - void visit(AstConfigUse* nodep) override { - nodep->v3warn(E_UNSUPPORTED, "Unsupported: config use"); - iterateChildren(nodep); - } - void visit(AstNode* nodep) override { iterateChildren(nodep); } // METHODS @@ -676,8 +714,9 @@ class LinkCellsVisitor final : public VNVisitor { public: // CONSTRUCTORS - LinkCellsVisitor(AstNetlist* nodep, VInFilter* filterp) + LinkCellsVisitor(AstNetlist* nodep, VInFilter* filterp, LinkCellsState& state) : m_filterp{filterp} + , m_state{state} , m_mods{nodep} { if (v3Global.opt.hierChild()) { const V3HierBlockOptSet& hierBlocks = v3Global.opt.hierBlocks(); @@ -704,5 +743,8 @@ public: void V3LinkCells::link(AstNetlist* nodep, VInFilter* filterp) { UINFO(4, __FUNCTION__ << ": "); - { LinkCellsVisitor{nodep, filterp}; } + // Configs must be parsed first because they determine the library search order for linking + LinkCellsState state; + { LinkConfigsVisitor{nodep, state}; } + { LinkCellsVisitor{nodep, filterp, state}; } } diff --git a/src/verilog.y b/src/verilog.y index a94a9046f..264bb3403 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -7783,8 +7783,9 @@ config_declaration: // == IEEE: config_declaration yCONFIG idAny/*config_identifier*/ ';' /*cont*/ configParameterListE design_statement config_rule_statementListE /*cont*/ yENDCONFIG endLabelE - { AstConfig* const newp = new AstConfig{$1, *$2, $4}; - newp->addItemsp($5); + { AstConfig* const newp = new AstConfig{$1, PARSEP->libname(), *$2}; + newp->addDesignp($5); + newp->addItemsp($4); newp->addItemsp($6); GRAMMARP->endLabel($7, *$2, $8); PARSEP->rootp()->addMiscsp(newp); } @@ -7805,7 +7806,7 @@ configParameter: // IEEE: part of config_declaration { $$ = nullptr; BBUNSUP($1, "Unsupported: config localparam declaration"); DEL($1); } ; -design_statement: // == IEEE: design_statement +design_statement: // == IEEE: design_statement yDESIGN configCellList ';' { $$ = $2; } ; @@ -7816,7 +7817,7 @@ configCellList: // IEEE: part of design_statement configCell: // IEEE: part of design_statement, part of cell_clause idAny/*cell_identifier*/ - { $$ = new AstConfigCell{$1, "", *$1}; } + { $$ = new AstConfigCell{$1, PARSEP->libname(), *$1}; } | idAny/*library_identifier*/ '.' idAny/*cell_identifier*/ { $$ = new AstConfigCell{$1, *$1, *$3}; } ; diff --git a/test_regress/t/t_config_hier.out b/test_regress/t/t_config_hier.out index 4596408ce..b91782953 100644 --- a/test_regress/t/t_config_hier.out +++ b/test_regress/t/t_config_hier.out @@ -1,34 +1,16 @@ -%Error-UNSUPPORTED: t/t_config_hier.v:34:1: Unsupported: config - 34 | config cfg21; - | ^~~~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_config_hier.v:35:10: Unsupported: config cell - 35 | design t; - | ^ %Error-UNSUPPORTED: t/t_config_hier.v:36:3: Unsupported: config rule 36 | instance t.u_1 use work.cfg2 :config; | ^~~~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error-UNSUPPORTED: t/t_config_hier.v:36:18: Unsupported: config use 36 | instance t.u_1 use work.cfg2 :config; | ^~~ -%Error-UNSUPPORTED: t/t_config_hier.v:39:1: Unsupported: config - 39 | config cfg22; - | ^~~~~~ -%Error-UNSUPPORTED: t/t_config_hier.v:40:10: Unsupported: config cell - 40 | design t; - | ^ %Error-UNSUPPORTED: t/t_config_hier.v:41:3: Unsupported: config rule 41 | instance t.u_1 use cfg2 :config; | ^~~~~~~~ %Error-UNSUPPORTED: t/t_config_hier.v:41:18: Unsupported: config use 41 | instance t.u_1 use cfg2 :config; | ^~~ -%Error-UNSUPPORTED: t/t_config_hier.v:44:1: Unsupported: config - 44 | config cfg31; - | ^~~~~~ -%Error-UNSUPPORTED: t/t_config_hier.v:45:10: Unsupported: config cell - 45 | design t; - | ^ %Error-UNSUPPORTED: t/t_config_hier.v:46:3: Unsupported: config rule 46 | cell work.m1 use work.cfg2 :config; | ^~~~ @@ -38,12 +20,6 @@ %Error-UNSUPPORTED: t/t_config_hier.v:46:16: Unsupported: config use 46 | cell work.m1 use work.cfg2 :config; | ^~~ -%Error-UNSUPPORTED: t/t_config_hier.v:49:1: Unsupported: config - 49 | config cfg32; - | ^~~~~~ -%Error-UNSUPPORTED: t/t_config_hier.v:50:10: Unsupported: config cell - 50 | design t; - | ^ %Error-UNSUPPORTED: t/t_config_hier.v:51:3: Unsupported: config rule 51 | cell m1 use cfg2 :config; | ^~~~ @@ -53,12 +29,6 @@ %Error-UNSUPPORTED: t/t_config_hier.v:51:11: Unsupported: config use 51 | cell m1 use cfg2 :config; | ^~~ -%Error-UNSUPPORTED: t/t_config_hier.v:54:1: Unsupported: config - 54 | config cfg41; - | ^~~~~~ -%Error-UNSUPPORTED: t/t_config_hier.v:55:10: Unsupported: config cell - 55 | design t; - | ^ %Error-UNSUPPORTED: t/t_config_hier.v:56:3: Unsupported: config rule 56 | cell work.m1 use work.cfg2; | ^~~~ @@ -68,18 +38,10 @@ %Error-UNSUPPORTED: t/t_config_hier.v:56:16: Unsupported: config use 56 | cell work.m1 use work.cfg2; | ^~~ -%Error-UNSUPPORTED: t/t_config_hier.v:60:1: Unsupported: config - 60 | config cfg2; - | ^~~~~~ -%Error-UNSUPPORTED: t/t_config_hier.v:61:10: Unsupported: config cell - 61 | design c2_b; - | ^~~~ %Error-UNSUPPORTED: t/t_config_hier.v:62:3: Unsupported: config rule 62 | instance u_bb use work.c2_bb; | ^~~~~~~~ %Error-UNSUPPORTED: t/t_config_hier.v:62:17: Unsupported: config use 62 | instance u_bb use work.c2_bb; | ^~~ -%Error: Specified --top-module 'cfg21' was not found in design. - ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. %Error: Exiting due to diff --git a/test_regress/t/t_config_multitop.py b/test_regress/t/t_config_multitop.py new file mode 100755 index 000000000..55c7eceab --- /dev/null +++ b/test_regress/t/t_config_multitop.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2025 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile(verilator_flags2=['--binary', '--top cfg1']) + +test.execute() + +test.file_grep(test.run_log_filename, r"In 'm1'") +test.file_grep(test.run_log_filename, r"In 'm2'") + +test.passes() diff --git a/test_regress/t/t_config_multitop.v b/test_regress/t/t_config_multitop.v new file mode 100644 index 000000000..0fce4b478 --- /dev/null +++ b/test_regress/t/t_config_multitop.v @@ -0,0 +1,19 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// verilator lint_off MULTITOP +module m1; + initial $display("In '%m'"); +endmodule + +module m2; + initial $display("In '%m'"); +endmodule + +config cfg1; + design m1 m2; +endconfig : cfg1 // Test end label +// verilator lint_on MULTITOP diff --git a/test_regress/t/t_config_rules.out b/test_regress/t/t_config_rules.out index ca089b184..82bb2c748 100644 --- a/test_regress/t/t_config_rules.out +++ b/test_regress/t/t_config_rules.out @@ -1,13 +1,7 @@ -%Error-UNSUPPORTED: t/t_config_rules.v:24:1: Unsupported: config - 24 | config cfg; - | ^~~~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_config_rules.v:25:10: Unsupported: config cell - 25 | design t; - | ^ %Error-UNSUPPORTED: t/t_config_rules.v:28:3: Unsupported: config rule 28 | default liblist; | ^~~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error-UNSUPPORTED: t/t_config_rules.v:29:3: Unsupported: config rule 29 | default liblist liba libb; | ^~~~~~~ @@ -74,6 +68,4 @@ %Error-UNSUPPORTED: t/t_config_rules.v:48:17: Unsupported: config use 48 | cell work.m43 use work.m43alt; | ^~~ -%Error: Specified --top-module 'cfg' was not found in design. - ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. %Error: Exiting due to diff --git a/test_regress/t/t_config_top.out b/test_regress/t/t_config_top.out deleted file mode 100644 index 0692b6a52..000000000 --- a/test_regress/t/t_config_top.out +++ /dev/null @@ -1,22 +0,0 @@ -%Error-UNSUPPORTED: t/t_config_top.v:20:1: Unsupported: config - 20 | config cfg1; - | ^~~~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_config_top.v:21:10: Unsupported: config cell - 21 | design m1; - | ^~ -%Error-UNSUPPORTED: t/t_config_top.v:25:1: Unsupported: config - 25 | config cfg2; - | ^~~~~~ -%Error-UNSUPPORTED: t/t_config_top.v:26:10: Unsupported: config cell - 26 | design m2; - | ^~ -%Error-UNSUPPORTED: t/t_config_top.v:29:1: Unsupported: config - 29 | config cfg3; - | ^~~~~~ -%Error-UNSUPPORTED: t/t_config_top.v:30:10: Unsupported: config cell - 30 | design work.m3; - | ^~~~ -%Error: Specified --top-module 'cfg2' was not found in design. - ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. -%Error: Exiting due to diff --git a/test_regress/t/t_config_top.py b/test_regress/t/t_config_top.py index f3b5677d5..ca0397f58 100755 --- a/test_regress/t/t_config_top.py +++ b/test_regress/t/t_config_top.py @@ -11,6 +11,8 @@ import vltest_bootstrap test.scenarios('simulator') -test.lint(verilator_flags2=["--top cfg2"], fails=True, expect_filename=test.golden_filename) +test.compile(verilator_flags2=['--binary', '--top cfg2']) + +test.execute() test.passes() diff --git a/test_regress/t/t_config_top2.out b/test_regress/t/t_config_top2.out deleted file mode 100644 index 7ae2334aa..000000000 --- a/test_regress/t/t_config_top2.out +++ /dev/null @@ -1,13 +0,0 @@ -%Error-UNSUPPORTED: t/t_config_top2.v:21:1: Unsupported: config - 21 | config cfg12; - | ^~~~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_config_top2.v:22:10: Unsupported: config cell - 22 | design work.m1 m2; - | ^~~~ -%Error-UNSUPPORTED: t/t_config_top2.v:22:18: Unsupported: config cell - 22 | design work.m1 m2; - | ^~ -%Error: Specified --top-module 'cfg2' was not found in design. - ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. -%Error: Exiting due to diff --git a/test_regress/t/t_config_top2.py b/test_regress/t/t_config_top2.py index f3b5677d5..55622426b 100755 --- a/test_regress/t/t_config_top2.py +++ b/test_regress/t/t_config_top2.py @@ -11,6 +11,8 @@ import vltest_bootstrap test.scenarios('simulator') -test.lint(verilator_flags2=["--top cfg2"], fails=True, expect_filename=test.golden_filename) +test.compile(verilator_flags2=['--binary', '--top cfg12']) + +test.execute() test.passes() diff --git a/test_regress/t/t_config_top2.v b/test_regress/t/t_config_top2.v index 68add5751..e85336130 100644 --- a/test_regress/t/t_config_top2.v +++ b/test_regress/t/t_config_top2.v @@ -4,6 +4,7 @@ // any use, without warranty, 2025 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 +// verilator lint_off MULTITOP module m1; initial begin m2.fin; @@ -21,3 +22,4 @@ endmodule config cfg12; design work.m1 m2; // Test both modules listed, library.cell, and cell w/o library endconfig +// verilator lint_on MULTITOP diff --git a/test_regress/t/t_config_unsup.out b/test_regress/t/t_config_unsup.out index c119aafea..633e80773 100644 --- a/test_regress/t/t_config_unsup.out +++ b/test_regress/t/t_config_unsup.out @@ -1,13 +1,7 @@ -%Error-UNSUPPORTED: t/t_config_unsup.v:24:1: Unsupported: config - 24 | config cfg; - | ^~~~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_config_unsup.v:25:10: Unsupported: config cell - 25 | design t; - | ^ %Error-UNSUPPORTED: t/t_config_unsup.v:28:3: Unsupported: config rule 28 | default liblist; | ^~~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error-UNSUPPORTED: t/t_config_unsup.v:29:3: Unsupported: config rule 29 | default liblist liba libb; | ^~~~~~~