Add `--work` library-selection option (#5891 partial).

This commit is contained in:
Wilson Snyder 2025-06-29 20:17:27 -04:00
parent c3d86626ee
commit 916a89761e
32 changed files with 350 additions and 139 deletions

View File

@ -26,6 +26,7 @@ Verilator 5.037 devel
* Add BADVLTPRAGMA on unknown Verilator pragmas (#5945). [Shou-Li Hsu] * Add BADVLTPRAGMA on unknown Verilator pragmas (#5945). [Shou-Li Hsu]
* Add ternary operator into branch coverage (#5880). [Ryszard Rozak, Antmicro Ltd.] * Add ternary operator into branch coverage (#5880). [Ryszard Rozak, Antmicro Ltd.]
* Add aggregate type error checks (#5570) (#5950). [Shou-Li Hsu] * Add aggregate type error checks (#5570) (#5950). [Shou-Li Hsu]
* Add `--work` library-selection option (#5891 partial).
* Add `--filter-type` to verilator_coverage (#6030). [Ryszard Rozak, Antmicro Ltd.] * Add `--filter-type` to verilator_coverage (#6030). [Ryszard Rozak, Antmicro Ltd.]
* Add `--hierarchical-threads` (#6037). [Bartłomiej Chmiel] * Add `--hierarchical-threads` (#6037). [Bartłomiej Chmiel]
* Add `MODMISSING` error, in place of unnamed error (#6054). [Paul Swirhun] * Add `MODMISSING` error, in place of unnamed error (#6054). [Paul Swirhun]

View File

@ -513,6 +513,7 @@ detailed descriptions of these arguments.
-Wno-fatal Disable fatal exit on warnings -Wno-fatal Disable fatal exit on warnings
-Wno-lint Disable all lint warnings -Wno-lint Disable all lint warnings
-Wno-style Disable all style warnings -Wno-style Disable all style warnings
-work <libname> Set config library for following files
-Wpedantic Warn on compliance-test issues -Wpedantic Warn on compliance-test issues
-Wwarn-<message> Enable specified warning message -Wwarn-<message> Enable specified warning message
-Wwarn-lint Enable lint warning message -Wwarn-lint Enable lint warning message

View File

@ -1596,8 +1596,8 @@ Summary:
When the input Verilog contains more than one top-level module, When the input Verilog contains more than one top-level module,
it specifies the name of the module to become the top-level module, it specifies the name of the module to become the top-level module,
and sets the default for :vlopt:`--prefix` if not explicitly specified. and sets the default for :vlopt:`--prefix` if not explicitly specified.
This is not needed with standard designs with only one top. See also This is not needed with standard designs with only one top.
:option:`MULTITOP` warning. See :ref:`Finding and Binding Modules`.
.. option:: --trace .. option:: --trace
@ -1881,6 +1881,19 @@ Summary:
``-Wno-UNUSEDGENVAR`` ``-Wno-UNUSEDPARAM`` ``-Wno-UNUSEDSIGNAL`` ``-Wno-UNUSEDGENVAR`` ``-Wno-UNUSEDPARAM`` ``-Wno-UNUSEDSIGNAL``
``-Wno-VARHIDDEN``. ``-Wno-VARHIDDEN``.
.. option:: -work <libname>
Use the specified Verilog config library name for all cells read after
this argument. May be specified multiple times, it will apply to cells
read between the given arguments. E.g. `-work liba a.v -work libb b.v`
will use `liba` for modules inside `a.v` or in cells resolved
hierarchically under those modules, and will use `libb` for modules
inside `b.v` or hierarchically under.
Defaults to "work" (IEEE 1800-2023 3.3.1).
See :ref:`Finding and Binding Modules`.
.. option:: -Wpedantic .. option:: -Wpedantic
Warn on any construct demanded by IEEE, and disable all Verilator Warn on any construct demanded by IEEE, and disable all Verilator

View File

@ -478,7 +478,8 @@ shortreal
other simulators either do not support float, or convert likewise. other simulators either do not support float, or convert likewise.
specify specparam specify specparam
All specify blocks and timing checks are ignored. All timing checks and specify blocks (except specparam, which is
supported) are ignored.
uwire uwire
Verilator does not perform warning checking on uwires; it treats the Verilator does not perform warning checking on uwires; it treats the

View File

@ -66,6 +66,40 @@ Once a model is built, the next step is typically for the user to run it,
see :ref:`Simulating`. see :ref:`Simulating`.
.. _Finding and Binding Modules:
Finding and Binding Modules
===========================
Verilator provides several mechanisms to find the source code containing a
module, primitive, interface, or program ("module" in this section) and
bind them to an instantiation. These capabilities are similar to the
"Precompiling in a single-pass" use model described in IEEE 1800-2023
33.5.1, although `config` is not yet supported.
Verilator first reads all files provided on the command line and
:vlopt:`-f` files, and parses all modules within. Each module is assigned
to the most recent library specified with :vlopt:`-work`, thus `-work liba
a.v -work libb b.v` will assign modules in `a.v` to `liba` and modules in
`b.v` to `libb`.
If a module is not defined from a file on the command-line, Verilator
attempts to find a filename constructed from the module name using
:vlopt:`-y` and `+libext`.
Binding begins with the :vlopt:`--top` module, if provided. If not provided
Verilator attempts to figure out the top module itself, and if multiple
tops result a :option:`MULTITOP` warning is issued which may be suppressed
(see details in :option:`MULTITOP`).
Verilator will attempt to bind lower unresolved instances first in the same
library name as the parent's instantiation library, and if not found search
globally across all libraries in the order modules were declared. This
allows otherwise conflicting duplicate module names between libraries to
coexist uniquely within each library name. When IEEE `config use` is
supported, more complicated selections will be able to be specified.
.. _Hierarchical Verilation: .. _Hierarchical Verilation:
Hierarchical Verilation Hierarchical Verilation

View File

@ -332,6 +332,7 @@ Prabhat
Prabhu Prabhu
Prateek Prateek
Pre Pre
Precompiling
Preprocess Preprocess
Pretet Pretet
Pretl Pretl

View File

@ -193,6 +193,11 @@ string AstNode::prettyName(const string& namein) VL_PURE {
pos += 7; pos += 7;
continue; continue;
} }
if (0 == std::strncmp(pos, "__LIB__", 7)) {
pretty = ""; // Trim library name before module name
pos += 7;
continue;
}
if (0 == std::strncmp(pos, "__PVT__", 7)) { if (0 == std::strncmp(pos, "__PVT__", 7)) {
pretty += ""; pretty += "";
pos += 7; pos += 7;

View File

@ -226,6 +226,7 @@ class AstNodeModule VL_NOT_FINAL : public AstNode {
const string m_origName; // Name of the module, ignoring name() changes, for dot lookup const string m_origName; // Name of the module, ignoring name() changes, for dot lookup
string m_someInstanceName; // Hierarchical name of some arbitrary instance of this module. string m_someInstanceName; // Hierarchical name of some arbitrary instance of this module.
// Used for user messages only. // Used for user messages only.
string m_libname; // Work library
int m_level = 0; // 1=top module, 2=cell off top module, ... int m_level = 0; // 1=top module, 2=cell off top module, ...
VLifetime m_lifetime; // Lifetime VLifetime m_lifetime; // Lifetime
VTimescale m_timeunit; // Global time unit VTimescale m_timeunit; // Global time unit
@ -243,10 +244,11 @@ class AstNodeModule VL_NOT_FINAL : public AstNode {
bool m_recursive : 1; // Recursive module bool m_recursive : 1; // Recursive module
bool m_recursiveClone : 1; // If recursive, what module it clones, otherwise nullptr bool m_recursiveClone : 1; // If recursive, what module it clones, otherwise nullptr
protected: protected:
AstNodeModule(VNType t, FileLine* fl, const string& name) AstNodeModule(VNType t, FileLine* fl, const string& name, const string& libname)
: AstNode{t, fl} : AstNode{t, fl}
, m_name{name} , m_name{name}
, m_origName{name} , m_origName{name}
, m_libname{libname}
, m_modPublic{false} , m_modPublic{false}
, m_modTrace{false} , m_modTrace{false}
, m_inLibrary{false} , m_inLibrary{false}
@ -275,6 +277,8 @@ public:
void inLibrary(bool flag) { m_inLibrary = flag; } void inLibrary(bool flag) { m_inLibrary = flag; }
void level(int level) { m_level = level; } void level(int level) { m_level = level; }
int level() const VL_MT_SAFE { return m_level; } int level() const VL_MT_SAFE { return m_level; }
string libname() const { return m_libname; }
string prettyLibnameQ() const { return "'" + prettyName(libname()) + "'"; }
bool isTop() const VL_MT_SAFE { return level() == 1; } bool isTop() const VL_MT_SAFE { return level() == 1; }
bool modPublic() const { return m_modPublic; } bool modPublic() const { return m_modPublic; }
void modPublic(bool flag) { m_modPublic = flag; } void modPublic(bool flag) { m_modPublic = flag; }
@ -2507,8 +2511,8 @@ class AstClass final : public AstNodeModule {
bool m_virtual = false; // Virtual class bool m_virtual = false; // Virtual class
public: public:
AstClass(FileLine* fl, const string& name) AstClass(FileLine* fl, const string& name, const string& libname)
: ASTGEN_SUPER_Class(fl, name) {} : ASTGEN_SUPER_Class(fl, name, libname) {}
ASTGEN_MEMBERS_AstClass; ASTGEN_MEMBERS_AstClass;
string verilogKwd() const override { return "class"; } string verilogKwd() const override { return "class"; }
bool maybePointedTo() const override VL_MT_SAFE { return true; } bool maybePointedTo() const override VL_MT_SAFE { return true; }
@ -2581,8 +2585,8 @@ class AstClassPackage final : public AstNodeModule {
// @astgen ptr := m_classp : Optional[AstClass] // Class package this is under // @astgen ptr := m_classp : Optional[AstClass] // Class package this is under
// // (weak pointer, hard link is other way) // // (weak pointer, hard link is other way)
public: public:
AstClassPackage(FileLine* fl, const string& name) AstClassPackage(FileLine* fl, const string& name, const string& libname)
: ASTGEN_SUPER_ClassPackage(fl, name) {} : ASTGEN_SUPER_ClassPackage(fl, name, libname) {}
ASTGEN_MEMBERS_AstClassPackage; ASTGEN_MEMBERS_AstClassPackage;
string verilogKwd() const override { return "classpackage"; } string verilogKwd() const override { return "classpackage"; }
bool timescaleMatters() const override { return false; } bool timescaleMatters() const override { return false; }
@ -2592,8 +2596,8 @@ public:
class AstIface final : public AstNodeModule { class AstIface final : public AstNodeModule {
// A module declaration // A module declaration
public: public:
AstIface(FileLine* fl, const string& name) AstIface(FileLine* fl, const string& name, const string& libname)
: ASTGEN_SUPER_Iface(fl, name) {} : ASTGEN_SUPER_Iface(fl, name, libname) {}
ASTGEN_MEMBERS_AstIface; ASTGEN_MEMBERS_AstIface;
// Interfaces have `timescale applicability but lots of code seems to // Interfaces have `timescale applicability but lots of code seems to
// get false warnings if we enable this // get false warnings if we enable this
@ -2607,13 +2611,13 @@ class AstModule final : public AstNodeModule {
public: public:
class Checker {}; // for constructor type-overload selection class Checker {}; // for constructor type-overload selection
class Program {}; // for constructor type-overload selection class Program {}; // for constructor type-overload selection
AstModule(FileLine* fl, const string& name) AstModule(FileLine* fl, const string& name, const string& libname)
: ASTGEN_SUPER_Module(fl, name) {} : ASTGEN_SUPER_Module(fl, name, libname) {}
AstModule(FileLine* fl, const string& name, Checker) AstModule(FileLine* fl, const string& name, const string& libname, Checker)
: ASTGEN_SUPER_Module(fl, name) : ASTGEN_SUPER_Module(fl, name, libname)
, m_isChecker{true} {} , m_isChecker{true} {}
AstModule(FileLine* fl, const string& name, Program) AstModule(FileLine* fl, const string& name, const string& libname, Program)
: ASTGEN_SUPER_Module(fl, name) : ASTGEN_SUPER_Module(fl, name, libname)
, m_isProgram{true} {} , m_isProgram{true} {}
ASTGEN_MEMBERS_AstModule; ASTGEN_MEMBERS_AstModule;
string verilogKwd() const override { string verilogKwd() const override {
@ -2628,8 +2632,8 @@ public:
class AstNotFoundModule final : public AstNodeModule { class AstNotFoundModule final : public AstNodeModule {
// A missing module declaration // A missing module declaration
public: public:
AstNotFoundModule(FileLine* fl, const string& name) AstNotFoundModule(FileLine* fl, const string& name, const string& libname)
: ASTGEN_SUPER_NotFoundModule(fl, name) {} : ASTGEN_SUPER_NotFoundModule(fl, name, libname) {}
ASTGEN_MEMBERS_AstNotFoundModule; ASTGEN_MEMBERS_AstNotFoundModule;
string verilogKwd() const override { return "/*not-found-*/ module"; } string verilogKwd() const override { return "/*not-found-*/ module"; }
bool timescaleMatters() const override { return false; } bool timescaleMatters() const override { return false; }
@ -2637,8 +2641,8 @@ public:
class AstPackage final : public AstNodeModule { class AstPackage final : public AstNodeModule {
// A package declaration // A package declaration
public: public:
AstPackage(FileLine* fl, const string& name) AstPackage(FileLine* fl, const string& name, const string& libname)
: ASTGEN_SUPER_Package(fl, name) {} : ASTGEN_SUPER_Package(fl, name, libname) {}
ASTGEN_MEMBERS_AstPackage; ASTGEN_MEMBERS_AstPackage;
string verilogKwd() const override { return "package"; } string verilogKwd() const override { return "package"; }
bool timescaleMatters() const override { return !isDollarUnit(); } bool timescaleMatters() const override { return !isDollarUnit(); }
@ -2648,8 +2652,8 @@ public:
class AstPrimitive final : public AstNodeModule { class AstPrimitive final : public AstNodeModule {
// A primitive declaration // A primitive declaration
public: public:
AstPrimitive(FileLine* fl, const string& name) AstPrimitive(FileLine* fl, const string& name, const string& libname)
: ASTGEN_SUPER_Primitive(fl, name) {} : ASTGEN_SUPER_Primitive(fl, name, libname) {}
ASTGEN_MEMBERS_AstPrimitive; ASTGEN_MEMBERS_AstPrimitive;
string verilogKwd() const override { return "primitive"; } string verilogKwd() const override { return "primitive"; }
bool timescaleMatters() const override { return false; } bool timescaleMatters() const override { return false; }

View File

@ -1353,7 +1353,7 @@ AstBasicDType* AstTypeTable::findInsertSameDType(AstBasicDType* nodep) {
AstConstPool::AstConstPool(FileLine* fl) AstConstPool::AstConstPool(FileLine* fl)
: ASTGEN_SUPER_ConstPool(fl) : ASTGEN_SUPER_ConstPool(fl)
, m_modp{new AstModule{fl, "@CONST-POOL@"}} , m_modp{new AstModule{fl, "@CONST-POOL@", "work"}}
, m_scopep{new AstScope{fl, m_modp, "@CONST-POOL@", nullptr, nullptr}} { , m_scopep{new AstScope{fl, m_modp, "@CONST-POOL@", nullptr, nullptr}} {
this->modulep(m_modp); this->modulep(m_modp);
m_modp->addStmtsp(m_scopep); m_modp->addStmtsp(m_scopep);
@ -2298,7 +2298,7 @@ void AstNetlist::dumpJson(std::ostream& str) const {
} }
AstPackage* AstNetlist::dollarUnitPkgAddp() { AstPackage* AstNetlist::dollarUnitPkgAddp() {
if (!m_dollarUnitPkgp) { if (!m_dollarUnitPkgp) {
m_dollarUnitPkgp = new AstPackage{fileline(), AstPackage::dollarUnitName()}; m_dollarUnitPkgp = new AstPackage{fileline(), AstPackage::dollarUnitName(), "work"};
// packages are always libraries; don't want to make them a "top" // packages are always libraries; don't want to make them a "top"
m_dollarUnitPkgp->inLibrary(true); m_dollarUnitPkgp->inLibrary(true);
m_dollarUnitPkgp->modTrace(false); // may reconsider later m_dollarUnitPkgp->modTrace(false); // may reconsider later
@ -2325,6 +2325,7 @@ void AstNodeModule::dump(std::ostream& str) const {
str << " [RECURSIVE]"; str << " [RECURSIVE]";
} }
str << " [" << timeunit() << "]"; str << " [" << timeunit() << "]";
if (libname() != "work") str << " libname=" << libname();
} }
void AstNodeModule::dumpJson(std::ostream& str) const { void AstNodeModule::dumpJson(std::ostream& str) const {
dumpJsonStrFunc(str, origName); dumpJsonStrFunc(str, origName);
@ -2335,6 +2336,7 @@ void AstNodeModule::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, recursiveClone); dumpJsonBoolFunc(str, recursiveClone);
dumpJsonBoolFunc(str, recursive); dumpJsonBoolFunc(str, recursive);
dumpJsonStr(str, "timeunit", timeunit().ascii()); dumpJsonStr(str, "timeunit", timeunit().ascii());
if (libname() != "work") dumpJsonStr(str, "libname=", libname());
dumpJsonGen(str); dumpJsonGen(str);
} }
void AstPackageExport::dump(std::ostream& str) const { void AstPackageExport::dump(std::ostream& str) const {

View File

@ -93,7 +93,7 @@ class ClassVisitor final : public VNVisitor {
// Make containing package // Make containing package
// Note origName is the same as the class origName so errors look correct // Note origName is the same as the class origName so errors look correct
AstClassPackage* const packagep AstClassPackage* const packagep
= new AstClassPackage{nodep->fileline(), nodep->origName()}; = new AstClassPackage{nodep->fileline(), nodep->origName(), nodep->libname()};
packagep->name(nodep->name() + "__Vclpkg"); packagep->name(nodep->name() + "__Vclpkg");
nodep->editCountInc(); nodep->editCountInc();
nodep->classOrPackagep(packagep); nodep->classOrPackagep(packagep);
@ -138,6 +138,7 @@ class ClassVisitor final : public VNVisitor {
} }
void visit(AstNodeModule* nodep) override { void visit(AstNodeModule* nodep) override {
// Visit for NodeModules that are not AstClass (AstClass is-a AstNodeModule) // Visit for NodeModules that are not AstClass (AstClass is-a AstNodeModule)
// Classes are always under a Package (perhaps $unit) or a module
VL_RESTORER(m_prefix); VL_RESTORER(m_prefix);
VL_RESTORER(m_modp); VL_RESTORER(m_modp);
m_modp = nodep; m_modp = nodep;

View File

@ -39,11 +39,21 @@ class CMakeEmitter final {
template <typename T_List> template <typename T_List>
static string cmake_list(const T_List& strs) { static string cmake_list(const T_List& strs) {
string s; string s;
for (auto it = strs.begin(); it != strs.end(); ++it) { for (auto& itr : strs) {
if (!s.empty()) s += ' ';
s += '"'; s += '"';
s += V3OutFormatter::quoteNameControls(*it); s += V3OutFormatter::quoteNameControls(itr);
s += '"';
}
return s;
}
static string cmake_list(const VFileLibList& strs) {
string s;
for (auto& itr : strs) {
if (!s.empty()) s += ' ';
s += '"';
s += V3OutFormatter::quoteNameControls(itr.filename());
s += '"'; s += '"';
if (it != strs.end()) s += ' ';
} }
return s; return s;
} }
@ -193,8 +203,8 @@ class CMakeEmitter final {
*of << " "; *of << " ";
const string vFile = hblockp->vFileIfNecessary(); const string vFile = hblockp->vFileIfNecessary();
if (!vFile.empty()) *of << vFile << " "; if (!vFile.empty()) *of << vFile << " ";
const V3StringList& vFiles = v3Global.opt.vFiles(); for (const auto& i : v3Global.opt.vFiles())
for (const string& i : vFiles) *of << V3Os::filenameRealPath(i) << " "; *of << V3Os::filenameRealPath(i.filename()) << " ";
*of << " VERILATOR_ARGS "; *of << " VERILATOR_ARGS ";
*of << "-f " << hblockp->commandArgsFilename(true) *of << "-f " << hblockp->commandArgsFilename(true)
<< " -CFLAGS -fPIC" // hierarchical block will be static, but may be linked << " -CFLAGS -fPIC" // hierarchical block will be static, but may be linked

View File

@ -814,13 +814,12 @@ class EmitMkHierVerilation final {
const string verilator_wrapper = V3Os::filenameDir(fullpath_bin) + "/verilator"; const string verilator_wrapper = V3Os::filenameDir(fullpath_bin) + "/verilator";
of.puts("VM_HIER_VERILATOR := " + verilator_wrapper + "\n"); of.puts("VM_HIER_VERILATOR := " + verilator_wrapper + "\n");
of.puts("VM_HIER_INPUT_FILES := \\\n"); of.puts("VM_HIER_INPUT_FILES := \\\n");
const V3StringList& vFiles = v3Global.opt.vFiles(); for (const auto& i : v3Global.opt.vFiles())
for (const string& i : vFiles) of.puts(" " + V3Os::filenameRealPath(i) + " \\\n"); of.puts(" " + V3Os::filenameRealPath(i.filename()) + " \\\n");
of.puts("\n"); of.puts("\n");
const V3StringSet& libraryFiles = v3Global.opt.libraryFiles();
of.puts("VM_HIER_VERILOG_LIBS := \\\n"); of.puts("VM_HIER_VERILOG_LIBS := \\\n");
for (const string& i : libraryFiles) { for (const auto& i : v3Global.opt.libraryFiles()) {
of.puts(" " + V3Os::filenameRealPath(i) + " \\\n"); of.puts(" " + V3Os::filenameRealPath(i.filename()) + " \\\n");
} }
of.puts("\n"); of.puts("\n");
} }

View File

@ -133,9 +133,9 @@ class V3EmitMkJsonEmitter final {
const string vFile = hblockp->vFileIfNecessary(); const string vFile = hblockp->vFileIfNecessary();
if (!vFile.empty()) sources.emplace_back(vFile); if (!vFile.empty()) sources.emplace_back(vFile);
const V3StringList& vFiles = v3Global.opt.vFiles(); for (const auto& i : v3Global.opt.vFiles())
for (const string& i : vFiles) sources.emplace_back(
sources.emplace_back(V3Os::filenameSlashPath(V3Os::filenameRealPath(i))); V3Os::filenameSlashPath(V3Os::filenameRealPath(i.filename())));
std::vector<std::string> cflags; std::vector<std::string> cflags;
cflags.emplace_back("-fPIC"); cflags.emplace_back("-fPIC");
@ -156,9 +156,9 @@ class V3EmitMkJsonEmitter final {
for (const auto& itr : *planp) for (const auto& itr : *planp)
sources.emplace_back(makeDir + "/" + itr.second->hierWrapperFilename(true)); sources.emplace_back(makeDir + "/" + itr.second->hierWrapperFilename(true));
const V3StringList& vFiles = v3Global.opt.vFiles(); for (const auto& itr : v3Global.opt.vFiles())
for (const string& i : vFiles) sources.emplace_back(
sources.emplace_back(V3Os::filenameSlashPath(V3Os::filenameRealPath(i))); V3Os::filenameSlashPath(V3Os::filenameRealPath(itr.filename())));
of.begin() of.begin()
.put("prefix", v3Global.opt.prefix()) .put("prefix", v3Global.opt.prefix())

View File

@ -81,7 +81,8 @@ public:
ForkDynScopeInstance& createInstancePrototype() { ForkDynScopeInstance& createInstancePrototype() {
UASSERT_OBJ(!m_instance.initialized(), m_procp, "Dynamic scope already instantiated."); UASSERT_OBJ(!m_instance.initialized(), m_procp, "Dynamic scope already instantiated.");
m_instance.m_classp = new AstClass{m_procp->fileline(), generateDynScopeClassName()}; m_instance.m_classp
= new AstClass{m_procp->fileline(), generateDynScopeClassName(), m_modp->libname()};
UINFO(9, "new dynscope class " << m_instance.m_classp); UINFO(9, "new dynscope class " << m_instance.m_classp);
m_instance.m_refDTypep m_instance.m_refDTypep
= new AstClassRefDType{m_procp->fileline(), m_instance.m_classp, nullptr}; = new AstClassRefDType{m_procp->fileline(), m_instance.m_classp, nullptr};

View File

@ -60,42 +60,39 @@ void V3Global::readFiles() {
if (v3Global.opt.stdWaiver()) { if (v3Global.opt.stdWaiver()) {
parser.parseFile( parser.parseFile(
new FileLine{V3Options::getStdWaiverPath()}, V3Options::getStdWaiverPath(), false, new FileLine{V3Options::getStdWaiverPath()}, V3Options::getStdWaiverPath(), false,
"Cannot find verilated_std_waiver.vlt containing built-in lint waivers: "); "work", "Cannot find verilated_std_waiver.vlt containing built-in lint waivers: ");
} }
// Read .vlt files // Read .vlt files
const V3StringSet& vltFiles = v3Global.opt.vltFiles(); for (auto& filelib : v3Global.opt.vltFiles()) {
for (const string& filename : vltFiles) { parser.parseFile(new FileLine{FileLine::commandLineFilename()}, filelib.filename(), false,
parser.parseFile(new FileLine{FileLine::commandLineFilename()}, filename, false, filelib.libname(), "Cannot find file containing .vlt file: ");
"Cannot find file containing .vlt file: ");
} }
// Parse the std package // Parse the std package
if (v3Global.opt.stdPackage()) { if (v3Global.opt.stdPackage()) {
parser.parseFile(new FileLine{V3Options::getStdPackagePath()}, parser.parseFile(new FileLine{V3Options::getStdPackagePath()},
V3Options::getStdPackagePath(), false, V3Options::getStdPackagePath(), false, "work",
"Cannot find verilated_std.sv containing built-in std:: definitions: "); "Cannot find verilated_std.sv containing built-in std:: definitions: ");
} }
// Read top module // Read top module
const V3StringList& vFiles = v3Global.opt.vFiles(); for (const auto& filelib : v3Global.opt.vFiles()) {
for (const string& filename : vFiles) { parser.parseFile(new FileLine{FileLine::commandLineFilename()}, filelib.filename(), false,
parser.parseFile(new FileLine{FileLine::commandLineFilename()}, filename, false, filelib.libname(), "Cannot find file containing module: ");
"Cannot find file containing module: ");
} }
// Read libraries // Read libraries
// To be compatible with other simulators, // To be compatible with other simulators,
// this needs to be done after the top file is read // this needs to be done after the top file is read
const V3StringSet& libraryFiles = v3Global.opt.libraryFiles(); for (const auto& filelib : v3Global.opt.libraryFiles()) {
for (const string& filename : libraryFiles) { parser.parseFile(new FileLine{FileLine::commandLineFilename()}, filelib.filename(), true,
parser.parseFile(new FileLine{FileLine::commandLineFilename()}, filename, true, filelib.libname(), "Cannot find file containing library module: ");
"Cannot find file containing library module: ");
} }
// Read hierarchical type parameter file // Read hierarchical type parameter file
const string filename = v3Global.opt.hierParamFile(); for (const auto& filelib : v3Global.opt.hierParamFile()) {
if (!filename.empty()) { parser.parseFile(new FileLine{FileLine::commandLineFilename()}, filelib.filename(), false,
parser.parseFile(new FileLine{FileLine::commandLineFilename()}, filename, false, filelib.libname(),
"Cannot open file containing hierarchical parameter declarations: "); "Cannot open file containing hierarchical parameter declarations: ");
} }

View File

@ -116,12 +116,11 @@ static void V3HierWriteCommonInputs(const V3HierBlock* hblockp, std::ostream* of
if (hblockp) topModuleFile = hblockp->vFileIfNecessary(); if (hblockp) topModuleFile = hblockp->vFileIfNecessary();
if (!forCMake) { if (!forCMake) {
if (!topModuleFile.empty()) *of << topModuleFile << "\n"; if (!topModuleFile.empty()) *of << topModuleFile << "\n";
const V3StringList& vFiles = v3Global.opt.vFiles(); for (const auto& i : v3Global.opt.vFiles()) *of << i.filename() << "\n";
for (const string& i : vFiles) *of << i << "\n";
} }
const V3StringSet& libraryFiles = v3Global.opt.libraryFiles(); for (const auto& i : v3Global.opt.libraryFiles()) {
for (const string& i : libraryFiles) { if (V3Os::filenameRealPath(i.filename()) != topModuleFile)
if (V3Os::filenameRealPath(i) != topModuleFile) *of << "-v " << i << "\n"; *of << "-v " << i.filename() << "\n";
} }
} }
@ -251,9 +250,9 @@ string V3HierBlock::hierGeneratedFilenames(bool withDir) const {
string V3HierBlock::vFileIfNecessary() const { string V3HierBlock::vFileIfNecessary() const {
string filename = V3Os::filenameRealPath(m_modp->fileline()->filename()); string filename = V3Os::filenameRealPath(m_modp->fileline()->filename());
for (const string& v : v3Global.opt.vFiles()) { for (const auto& v : v3Global.opt.vFiles()) {
// Already listed in vFiles, so no need to add the file. // Already listed in vFiles, so no need to add the file.
if (filename == V3Os::filenameRealPath(v)) return ""; if (filename == V3Os::filenameRealPath(v.filename())) return "";
} }
return filename; return filename;
} }

View File

@ -127,14 +127,34 @@ class LinkCellsVisitor final : public VNVisitor {
const V3GraphEdge* const edgep = new V3GraphEdge{&m_graph, fromp, top, weight, cuttable}; const V3GraphEdge* const edgep = new V3GraphEdge{&m_graph, fromp, top, weight, cuttable};
UINFO(9, " newEdge " << edgep << " " << fromp->name() << " -> " << top->name()); UINFO(9, " newEdge " << edgep << " " << fromp->name() << " -> " << top->name());
} }
void insertModInLib(const string& name, const string& libname, AstNodeModule* nodep) {
AstNodeModule* findModuleSym(const string& modName) { // Be able to find the module under it's library using the name it was given
const VSymEnt* const foundp = m_mods.rootp()->findIdFallback(modName); VSymEnt* libSymp = m_mods.rootp()->findIdFlat(libname);
return foundp ? VN_AS(foundp->nodep(), NodeModule) : nullptr; if (!libSymp)
libSymp = m_mods.rootp()->insert(libname, new VSymEnt{&m_mods, v3Global.rootp()});
libSymp->insert(name, new VSymEnt{&m_mods, nodep});
} }
AstNodeModule* resolveModule(AstNode* nodep, const string& modName) { AstNodeModule* findModuleLibSym(const string& modName, const string& libname) {
AstNodeModule* modp = findModuleSym(modName); // Given module name and library name, find within that exact library
const VSymEnt* const libSymp = m_mods.rootp()->findIdFallback(libname);
if (!libSymp) return nullptr;
const VSymEnt* const foundp = libSymp->findIdFallback(modName);
return foundp ? VN_AS(foundp->nodep(), NodeModule) : nullptr;
}
AstNodeModule* findModuleSym(const string& modName, const string& libname) {
// Given module and library to start search in, resolve using config library choices
// TODO support IEEE config library search order
// First search local library
AstNodeModule* foundp = findModuleLibSym(modName, libname);
if (foundp) return foundp;
// THen search global
foundp = findModuleLibSym(modName, "__GLOBAL");
return foundp;
}
AstNodeModule* resolveModule(AstNode* nodep, const string& modName, const string& libname) {
AstNodeModule* modp = findModuleSym(modName, libname);
if (!modp) { if (!modp) {
// Read-subfile // Read-subfile
// If file not found, make AstNotFoundModule, rather than error out. // If file not found, make AstNotFoundModule, rather than error out.
@ -142,12 +162,12 @@ class LinkCellsVisitor final : public VNVisitor {
const string prettyName = AstNode::prettyName(modName); const string prettyName = AstNode::prettyName(modName);
V3Parse parser{v3Global.rootp(), m_filterp}; V3Parse parser{v3Global.rootp(), m_filterp};
// true below -> other simulators treat modules in link-found files as library cells // true below -> other simulators treat modules in link-found files as library cells
parser.parseFile(nodep->fileline(), prettyName, true, ""); parser.parseFile(nodep->fileline(), prettyName, true, m_modp->libname(), "");
V3Error::abortIfErrors(); V3Error::abortIfErrors();
// We've read new modules, grab new pointers to their names // We've read new modules, grab new pointers to their names
readModNames(); readModNames();
// Check again // Check again
modp = findModuleSym(modName); modp = findModuleSym(modName, libname);
if (!modp) { if (!modp) {
// This shouldn't throw a message as parseFile will create // This shouldn't throw a message as parseFile will create
// a AstNotFoundModule for us // a AstNotFoundModule for us
@ -188,7 +208,7 @@ class LinkCellsVisitor final : public VNVisitor {
m_modp = nodep; m_modp = nodep;
UINFO(4, "Link Module: " << nodep); UINFO(4, "Link Module: " << nodep);
if (nodep->fileline()->filebasenameNoExt() != nodep->prettyName() if (nodep->fileline()->filebasenameNoExt() != nodep->prettyName()
&& !v3Global.opt.isLibraryFile(nodep->fileline()->filename()) && !v3Global.opt.isLibraryFile(nodep->fileline()->filename(), nodep->libname())
&& !VN_IS(nodep, NotFoundModule) && !nodep->recursiveClone() && !VN_IS(nodep, NotFoundModule) && !nodep->recursiveClone()
&& !nodep->internal()) { && !nodep->internal()) {
// We only complain once per file, otherwise library-like files // We only complain once per file, otherwise library-like files
@ -228,7 +248,7 @@ class LinkCellsVisitor final : public VNVisitor {
UINFO(4, "Link IfaceRef: " << nodep); UINFO(4, "Link IfaceRef: " << nodep);
// Use findIdUpward instead of findIdFlat; it doesn't matter for now // Use findIdUpward instead of findIdFlat; it doesn't matter for now
// but we might support modules-under-modules someday. // but we might support modules-under-modules someday.
AstNodeModule* const modp = resolveModule(nodep, nodep->ifaceName()); AstNodeModule* const modp = resolveModule(nodep, nodep->ifaceName(), m_modp->libname());
if (modp) { if (modp) {
if (VN_IS(modp, Iface)) { if (VN_IS(modp, Iface)) {
// Track module depths, so can sort list from parent down to children // Track module depths, so can sort list from parent down to children
@ -259,7 +279,7 @@ class LinkCellsVisitor final : public VNVisitor {
// Package Import: We need to do the package before the use of a package // Package Import: We need to do the package before the use of a package
iterateChildren(nodep); iterateChildren(nodep);
if (!nodep->packagep()) { if (!nodep->packagep()) {
AstNodeModule* const modp = resolveModule(nodep, nodep->pkgName()); AstNodeModule* const modp = resolveModule(nodep, nodep->pkgName(), m_modp->libname());
if (AstPackage* const pkgp = VN_CAST(modp, Package)) nodep->packagep(pkgp); if (AstPackage* const pkgp = VN_CAST(modp, Package)) nodep->packagep(pkgp);
if (!nodep->packagep()) { if (!nodep->packagep()) {
nodep->v3error("Export package not found: " << nodep->prettyPkgNameQ()); nodep->v3error("Export package not found: " << nodep->prettyPkgNameQ());
@ -271,7 +291,7 @@ class LinkCellsVisitor final : public VNVisitor {
// Package Import: We need to do the package before the use of a package // Package Import: We need to do the package before the use of a package
iterateChildren(nodep); iterateChildren(nodep);
if (!nodep->packagep()) { if (!nodep->packagep()) {
AstNodeModule* const modp = resolveModule(nodep, nodep->pkgName()); AstNodeModule* const modp = resolveModule(nodep, nodep->pkgName(), m_modp->libname());
if (AstPackage* const pkgp = VN_CAST(modp, Package)) nodep->packagep(pkgp); if (AstPackage* const pkgp = VN_CAST(modp, Package)) nodep->packagep(pkgp);
// If not found, V3LinkDot will report errors // If not found, V3LinkDot will report errors
if (!nodep->packagep()) { if (!nodep->packagep()) {
@ -289,7 +309,7 @@ class LinkCellsVisitor final : public VNVisitor {
// this move to post param, which would mean we do not auto-read modules // this move to post param, which would mean we do not auto-read modules
// and means we cannot compute module levels until later. // and means we cannot compute module levels until later.
UINFO(4, "Link Bind: " << nodep); UINFO(4, "Link Bind: " << nodep);
AstNodeModule* const modp = resolveModule(nodep, nodep->name()); AstNodeModule* const modp = resolveModule(nodep, nodep->name(), m_modp->libname());
if (modp) { if (modp) {
AstNode* const cellsp = nodep->cellsp()->unlinkFrBackWithNext(); AstNode* const cellsp = nodep->cellsp()->unlinkFrBackWithNext();
// Module may have already linked, so need to pick up these new cells // Module may have already linked, so need to pick up these new cells
@ -325,7 +345,7 @@ class LinkCellsVisitor final : public VNVisitor {
UINFO(4, "Link Cell: " << nodep); UINFO(4, "Link Cell: " << nodep);
// Use findIdFallback instead of findIdFlat; it doesn't matter for now // Use findIdFallback instead of findIdFlat; it doesn't matter for now
// but we might support modules-under-modules someday. // but we might support modules-under-modules someday.
AstNodeModule* cellmodp = resolveModule(nodep, nodep->modName()); AstNodeModule* cellmodp = resolveModule(nodep, nodep->modName(), m_modp->libname());
if (cellmodp) { if (cellmodp) {
if (cellmodp == m_modp || cellmodp->user2p() == m_modp) { if (cellmodp == m_modp || cellmodp->user2p() == m_modp) {
UINFO(1, "Self-recursive module " << cellmodp); UINFO(1, "Self-recursive module " << cellmodp);
@ -529,7 +549,7 @@ class LinkCellsVisitor final : public VNVisitor {
if (pinp->name() == "") pinp->name("__paramNumber" + cvtToStr(pinp->pinNum())); if (pinp->name() == "") pinp->name("__paramNumber" + cvtToStr(pinp->pinNum()));
} }
if (m_varp) { // Parser didn't know what was interface, resolve now if (m_varp) { // Parser didn't know what was interface, resolve now
AstNodeModule* const varModp = findModuleSym(nodep->name()); AstNodeModule* const varModp = findModuleSym(nodep->name(), m_modp->libname());
if (AstIface* const ifacep = VN_CAST(varModp, Iface)) { if (AstIface* const ifacep = VN_CAST(varModp, Iface)) {
// Might be an interface, but might also not really be due to interface being // Might be an interface, but might also not really be due to interface being
// hidden by another declaration. Assume it is relevant and order as-if. // hidden by another declaration. Assume it is relevant and order as-if.
@ -591,21 +611,26 @@ class LinkCellsVisitor final : public VNVisitor {
// Look at all modules, and store pointers to all module names // Look at all modules, and store pointers to all module names
for (AstNodeModule *nextp, *nodep = v3Global.rootp()->modulesp(); nodep; nodep = nextp) { for (AstNodeModule *nextp, *nodep = v3Global.rootp()->modulesp(); nodep; nodep = nextp) {
nextp = VN_AS(nodep->nextp(), NodeModule); nextp = VN_AS(nodep->nextp(), NodeModule);
if (v3Global.opt.hierChild() && nodep->name() == hierIt->second.origName()) { if (v3Global.opt.hierChild() && nodep->origName() == hierIt->second.origName()) {
nodep->name(hierIt->first); // Change name of this module to be mangled name nodep->name(hierIt->first); // Change name of this module to be mangled name
// considering parameter // considering parameter
} }
const AstNodeModule* const foundp = findModuleSym(nodep->name()); const AstNodeModule* const libFoundp = findModuleLibSym(nodep->origName(), nodep->libname());
if (foundp && foundp != nodep) { const AstNodeModule* const globalFoundp = findModuleLibSym(nodep->name(), "__GLOBAL");
if (!(foundp->fileline()->warnIsOff(V3ErrorCode::MODDUP) if (libFoundp && libFoundp == nodep) {
// Ok
} else if (libFoundp && !globalFoundp) {
nodep->v3fatalSrc("Module should be found globally if inserted in lib");
} else if (libFoundp) {
if (!(libFoundp->fileline()->warnIsOff(V3ErrorCode::MODDUP)
|| nodep->fileline()->warnIsOff(V3ErrorCode::MODDUP) || nodep->fileline()->warnIsOff(V3ErrorCode::MODDUP)
|| hierBlocks.find(nodep->name()) != hierBlocks.end())) { || hierBlocks.find(nodep->name()) != hierBlocks.end())) {
nodep->v3warn(MODDUP, "Duplicate declaration of module: " nodep->v3warn(MODDUP, "Duplicate declaration of module: "
<< nodep->prettyNameQ() << '\n' << nodep->prettyNameQ() << '\n'
<< nodep->warnContextPrimary() << '\n' << nodep->warnContextPrimary() << '\n'
<< foundp->warnOther() << libFoundp->warnOther()
<< "... Location of original declaration\n" << "... Location of original declaration\n"
<< foundp->warnContextSecondary()); << libFoundp->warnContextSecondary());
} }
if (VN_IS(nodep, Package)) { if (VN_IS(nodep, Package)) {
// Packages may be imported, we instead rename to be unique // Packages may be imported, we instead rename to be unique
@ -614,8 +639,16 @@ class LinkCellsVisitor final : public VNVisitor {
nodep->unlinkFrBack(); nodep->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(nodep), nodep); VL_DO_DANGLING(pushDeletep(nodep), nodep);
} }
} else if (!foundp) { } else if (!libFoundp && globalFoundp && globalFoundp != nodep) {
m_mods.rootp()->insert(nodep->name(), new VSymEnt{&m_mods, nodep}); // ...__LIB__ stripped by prettyName
const string newName = nodep->libname() + "__LIB__" + nodep->origName();
UINFO(9, "Module rename as in multiple libraries " << newName << " <- " << nodep);
insertModInLib(nodep->origName(), nodep->libname(), nodep); // Original name
nodep->name(newName);
insertModInLib(nodep->name(), "__GLOBAL", nodep);
} else if (!libFoundp) {
insertModInLib(nodep->origName(), nodep->libname(), nodep);
insertModInLib(nodep->name(), "__GLOBAL", nodep);
} }
} }
// if (debug() >= 9) m_mods.dump(cout, "-syms: "); // if (debug() >= 9) m_mods.dump(cout, "-syms: ");
@ -641,7 +674,9 @@ public:
iterate(nodep); iterate(nodep);
} }
~LinkCellsVisitor() override { ~LinkCellsVisitor() override {
if (debug() >= 5 || dumpGraphLevel() >= 5) { m_mods.dumpFilePrefixed("linkcells"); } if (debug() >= 5 || dumpGraphLevel() >= 5) {
m_mods.dumpFilePrefixed("linkcells");
}
} }
}; };

View File

@ -164,7 +164,7 @@ void V3LinkLevel::wrapTop(AstNetlist* rootp) {
return; return;
} }
AstNodeModule* const newmodp = new AstModule{oldmodp->fileline(), "$root"}; AstNodeModule* const newmodp = new AstModule{oldmodp->fileline(), "$root", oldmodp->libname()};
newmodp->name(AstNode::encodeName(newmodp->name())); // so origName is nice newmodp->name(AstNode::encodeName(newmodp->name())); // so origName is nice
// Make the new module first in the list // Make the new module first in the list
oldmodp->unlinkFrBackWithNext(); oldmodp->unlinkFrBackWithNext();

View File

@ -313,7 +313,8 @@ class LinkResolveVisitor final : public VNVisitor {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: %l in $fscanf"); nodep->v3warn(E_UNSUPPORTED, "Unsupported: %l in $fscanf");
fmt = ""; fmt = "";
} }
if (m_modp) fmt = VString::quotePercent(m_modp->prettyName()); if (m_modp)
fmt = AstNode::prettyName(m_modp->libname()) + "." + m_modp->prettyName();
break; break;
default: // Most operators, just move to next argument default: // Most operators, just move to next argument
if (!V3Number::displayedFmtLegal(ch, isScan)) { if (!V3Number::displayedFmtLegal(ch, isScan)) {

View File

@ -380,10 +380,12 @@ bool V3Options::isFuture0(const string& flag) const {
bool V3Options::isFuture1(const string& flag) const { bool V3Options::isFuture1(const string& flag) const {
return m_future1s.find(flag) != m_future1s.end(); return m_future1s.find(flag) != m_future1s.end();
} }
bool V3Options::isLibraryFile(const string& filename) const { bool V3Options::isLibraryFile(const string& filename, const string& libname) const {
return m_libraryFiles.find(filename) != m_libraryFiles.end(); return m_libraryFiles.find({filename, libname}) != m_libraryFiles.end();
}
void V3Options::addLibraryFile(const string& filename, const string& libname) {
m_libraryFiles.insert({filename, libname});
} }
void V3Options::addLibraryFile(const string& filename) { m_libraryFiles.insert(filename); }
bool V3Options::isClocker(const string& signame) const { bool V3Options::isClocker(const string& signame) const {
return m_clockers.find(signame) != m_clockers.end(); return m_clockers.find(signame) != m_clockers.end();
} }
@ -392,12 +394,14 @@ bool V3Options::isNoClocker(const string& signame) const {
return m_noClockers.find(signame) != m_noClockers.end(); return m_noClockers.find(signame) != m_noClockers.end();
} }
void V3Options::addNoClocker(const string& signame) { m_noClockers.insert(signame); } void V3Options::addNoClocker(const string& signame) { m_noClockers.insert(signame); }
void V3Options::addVFile(const string& filename) { void V3Options::addVFile(const string& filename, const string& libname) {
// We use a list for v files, because it's legal to have includes // We use a list for v files, because it's legal to have includes
// in a specific order and multiple of them. // in a specific order and multiple of them.
m_vFiles.push_back(filename); m_vFiles.push_back({filename, libname});
}
void V3Options::addVltFile(const string& filename, const string& libname) {
m_vltFiles.insert({filename, libname});
} }
void V3Options::addVltFile(const string& filename) { m_vltFiles.insert(filename); }
void V3Options::addForceInc(const string& filename) { m_forceIncs.push_back(filename); } void V3Options::addForceInc(const string& filename) { m_forceIncs.push_back(filename); }
void V3Options::addLineArg(const string& arg) { m_impp->m_lineArgs.push_back(arg); } void V3Options::addLineArg(const string& arg) { m_impp->m_lineArgs.push_back(arg); }
@ -416,7 +420,7 @@ string V3Options::allArgsString() const VL_MT_SAFE {
// Delete some options for Verilation of the hierarchical blocks. // Delete some options for Verilation of the hierarchical blocks.
string V3Options::allArgsStringForHierBlock(bool forTop) const { string V3Options::allArgsStringForHierBlock(bool forTop) const {
std::set<string> vFiles; std::set<string> vFiles;
for (const auto& vFile : m_vFiles) vFiles.insert(vFile); for (const auto& vFile : m_vFiles) vFiles.insert(vFile.filename());
string out; string out;
bool stripArg = false; bool stripArg = false;
bool stripArgIfNum = false; bool stripArgIfNum = false;
@ -1058,16 +1062,16 @@ void V3Options::parseOpts(FileLine* fl, int argc, char** argv) VL_MT_DISABLED {
// Default certain options and error check // Default certain options and error check
// Detailed error, since this is what we often get when run with minimal arguments // Detailed error, since this is what we often get when run with minimal arguments
const V3StringList& vFilesList = vFiles(); if (vFiles().empty()) {
if (vFilesList.empty()) {
v3fatal("verilator: No Input Verilog file specified on command line, " v3fatal("verilator: No Input Verilog file specified on command line, "
"see verilator --help for more information\n"); "see verilator --help for more information\n");
} }
// Default prefix to the filename // Default prefix to the filename
if (prefix() == "" && topModule() != "") m_prefix = "V"s + AstNode::encodeName(topModule()); if (prefix() == "" && topModule() != "") m_prefix = "V"s + AstNode::encodeName(topModule());
if (prefix() == "" && vFilesList.size() >= 1) if (prefix() == "" && vFiles().size() >= 1)
m_prefix = "V"s + AstNode::encodeName(V3Os::filenameNonDirExt(*(vFilesList.begin()))); m_prefix
= "V"s + AstNode::encodeName(V3Os::filenameNonDirExt(vFiles().begin()->filename()));
if (modPrefix() == "") m_modPrefix = prefix(); if (modPrefix() == "") m_modPrefix = prefix();
// Find files in makedir // Find files in makedir
@ -1386,8 +1390,9 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
m_hierBlocks.emplace(opt.mangledName(), opt); m_hierBlocks.emplace(opt.mangledName(), opt);
}); });
DECL_OPTION("-hierarchical-child", Set, &m_hierChild); DECL_OPTION("-hierarchical-child", Set, &m_hierChild);
DECL_OPTION("-hierarchical-params-file", CbVal, DECL_OPTION("-hierarchical-params-file", CbVal, [this](const char* optp) {
[this](const char* optp) { m_hierParamsFile = optp; }); m_hierParamsFile.push_back({optp, work()});
});
DECL_OPTION("-I", CbPartialMatch, DECL_OPTION("-I", CbPartialMatch,
[this, &optdir](const char* optp) { addIncDirUser(parseFileArg(optdir, optp)); }); [this, &optdir](const char* optp) { addIncDirUser(parseFileArg(optdir, optp)); });
@ -1699,7 +1704,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
std::exit(0); std::exit(0);
}); });
DECL_OPTION("-v", CbVal, [this, &optdir](const char* valp) { DECL_OPTION("-v", CbVal, [this, &optdir](const char* valp) {
V3Options::addLibraryFile(parseFileArg(optdir, valp)); V3Options::addLibraryFile(parseFileArg(optdir, valp), work());
}); });
DECL_OPTION("-valgrind", CbCall, []() {}); // Processed only in bin/verilator shell DECL_OPTION("-valgrind", CbCall, []() {}); // Processed only in bin/verilator shell
DECL_OPTION("-verilate", OnOff, &m_verilate); DECL_OPTION("-verilate", OnOff, &m_verilate);
@ -1762,6 +1767,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
DECL_OPTION("-Wno-style", CbCall, []() { FileLine::globalWarnStyleOff(true); }); DECL_OPTION("-Wno-style", CbCall, []() { FileLine::globalWarnStyleOff(true); });
DECL_OPTION("-Wno-UNUSED", CbCall, []() { FileLine::globalWarnUnusedOff(true); }); DECL_OPTION("-Wno-UNUSED", CbCall, []() { FileLine::globalWarnUnusedOff(true); });
DECL_OPTION("-Wno-WIDTH", CbCall, []() { FileLine::globalWarnOff(V3ErrorCode::WIDTH, true); }); DECL_OPTION("-Wno-WIDTH", CbCall, []() { FileLine::globalWarnOff(V3ErrorCode::WIDTH, true); });
DECL_OPTION("-work", Set, &m_work);
DECL_OPTION("-Wpedantic", CbCall, [this]() { DECL_OPTION("-Wpedantic", CbCall, [this]() {
m_pedantic = true; m_pedantic = true;
V3Error::pretendError(V3ErrorCode::ASSIGNIN, false); V3Error::pretendError(V3ErrorCode::ASSIGNIN, false);
@ -1888,9 +1894,9 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|| suffixed(filename, ".so")) { || suffixed(filename, ".so")) {
V3Options::addLdLibs(filename); V3Options::addLdLibs(filename);
} else if (suffixed(filename, ".vlt")) { } else if (suffixed(filename, ".vlt")) {
V3Options::addVltFile(filename); V3Options::addVltFile(filename, work());
} else { } else {
V3Options::addVFile(filename); V3Options::addVFile(filename, work());
} }
++i; ++i;
} }

View File

@ -59,6 +59,34 @@ constexpr bool operator==(const VOptionBool& lhs, const VOptionBool& rhs) {
constexpr bool operator==(const VOptionBool& lhs, VOptionBool::en rhs) { return lhs.m_e == rhs; } constexpr bool operator==(const VOptionBool& lhs, VOptionBool::en rhs) { return lhs.m_e == rhs; }
constexpr bool operator==(VOptionBool::en lhs, const VOptionBool& rhs) { return lhs == rhs.m_e; } constexpr bool operator==(VOptionBool::en lhs, const VOptionBool& rhs) { return lhs == rhs.m_e; }
//######################################################################
class VFileLibName final {
// Filename and libname pair
const string m_filename; // Filename
const string m_libname; // Libname
public:
VFileLibName(const string& filename, const string& libname)
: m_filename{filename}
, m_libname{libname} {}
VFileLibName(const VFileLibName& rhs)
: m_filename{rhs.m_filename}
, m_libname{rhs.m_libname} {}
string filename() const { return m_filename; }
string libname() const { return m_libname; }
bool operator==(const VFileLibName& rhs) const {
return m_filename == rhs.m_filename && m_libname == rhs.m_libname;
}
bool operator<(const VFileLibName& rhs) const {
if (m_filename < rhs.m_filename) return true;
if (m_filename > rhs.m_filename) return false;
return m_libname < rhs.m_libname;
}
};
using VFileLibList = std::vector<VFileLibName>;
using VFileLibSet = std::set<VFileLibName>;
// ###################################################################### // ######################################################################
class VTimescale final { class VTimescale final {
@ -207,11 +235,11 @@ private:
V3StringSet m_futures; // argument: -Wfuture- list V3StringSet m_futures; // argument: -Wfuture- list
V3StringSet m_future0s; // argument: -future list V3StringSet m_future0s; // argument: -future list
V3StringSet m_future1s; // argument: -future1 list V3StringSet m_future1s; // argument: -future1 list
V3StringSet m_libraryFiles; // argument: Verilog -v files VFileLibSet m_libraryFiles; // argument: Verilog -v files
V3StringSet m_clockers; // argument: Verilog -clk signals V3StringSet m_clockers; // argument: Verilog -clk signals
V3StringSet m_noClockers; // argument: Verilog -noclk signals V3StringSet m_noClockers; // argument: Verilog -noclk signals
V3StringList m_vFiles; // argument: Verilog files to read VFileLibList m_vFiles; // argument: Verilog files to read
V3StringSet m_vltFiles; // argument: Verilator config files to read VFileLibSet m_vltFiles; // argument: Verilator config files to read
V3StringList m_forceIncs; // argument: -FI V3StringList m_forceIncs; // argument: -FI
DebugLevelMap m_debugLevel; // argument: --debugi-<srcfile/tag> <level> DebugLevelMap m_debugLevel; // argument: --debugi-<srcfile/tag> <level>
DebugLevelMap m_dumpLevel; // argument: --dumpi-<srcfile/tag> <level> DebugLevelMap m_dumpLevel; // argument: --dumpi-<srcfile/tag> <level>
@ -359,7 +387,7 @@ private:
string m_diagnosticsSarifOutput; // main switch: --diagnostics-sarif-output string m_diagnosticsSarifOutput; // main switch: --diagnostics-sarif-output
string m_exeName; // main switch: -o {name} string m_exeName; // main switch: -o {name}
string m_flags; // main switch: -f {name} string m_flags; // main switch: -f {name}
string m_hierParamsFile; // main switch: --hierarchical-params-file VFileLibList m_hierParamsFile; // main switch: --hierarchical-params-file
string m_jsonOnlyOutput; // main switch: --json-only-output string m_jsonOnlyOutput; // main switch: --json-only-output
string m_jsonOnlyMetaOutput; // main switch: --json-only-meta-output string m_jsonOnlyMetaOutput; // main switch: --json-only-meta-output
string m_l2Name; // main switch: --l2name; "" for top-module's name string m_l2Name; // main switch: --l2name; "" for top-module's name
@ -373,6 +401,7 @@ private:
string m_topModule; // main switch: --top-module string m_topModule; // main switch: --top-module
string m_unusedRegexp; // main switch: --unused-regexp string m_unusedRegexp; // main switch: --unused-regexp
string m_waiverOutput; // main switch: --waiver-output {filename} string m_waiverOutput; // main switch: --waiver-output {filename}
string m_work = "work"; // main switch: --work {libname}
string m_xAssign; // main switch: --x-assign string m_xAssign; // main switch: --x-assign
string m_xInitial; // main switch: --x-initial string m_xInitial; // main switch: --x-initial
string m_xmlOutput; // main switch: --xml-output string m_xmlOutput; // main switch: --xml-output
@ -463,11 +492,11 @@ public:
void addCompilerIncludes(const string& filename); void addCompilerIncludes(const string& filename);
void addLdLibs(const string& filename); void addLdLibs(const string& filename);
void addMakeFlags(const string& filename); void addMakeFlags(const string& filename);
void addLibraryFile(const string& filename); void addLibraryFile(const string& filename, const string& libname);
void addClocker(const string& signame); void addClocker(const string& signame);
void addNoClocker(const string& signame); void addNoClocker(const string& signame);
void addVFile(const string& filename); void addVFile(const string& filename, const string& libname);
void addVltFile(const string& filename); void addVltFile(const string& filename, const string& libname);
void addForceInc(const string& filename); void addForceInc(const string& filename);
bool available() const VL_MT_SAFE { return m_available; } bool available() const VL_MT_SAFE { return m_available; }
void ccSet(); void ccSet();
@ -642,7 +671,7 @@ public:
: m_diagnosticsSarifOutput; : m_diagnosticsSarifOutput;
} }
string exeName() const { return m_exeName != "" ? m_exeName : prefix(); } string exeName() const { return m_exeName != "" ? m_exeName : prefix(); }
string hierParamFile() const { return m_hierParamsFile; } VFileLibList hierParamFile() const { return m_hierParamsFile; }
string jsonOnlyOutput() const { return m_jsonOnlyOutput; } string jsonOnlyOutput() const { return m_jsonOnlyOutput; }
string jsonOnlyMetaOutput() const { return m_jsonOnlyMetaOutput; } string jsonOnlyMetaOutput() const { return m_jsonOnlyMetaOutput; }
string l2Name() const { return m_l2Name; } string l2Name() const { return m_l2Name; }
@ -668,6 +697,7 @@ public:
bool noTraceTop() const { return m_noTraceTop; } bool noTraceTop() const { return m_noTraceTop; }
string unusedRegexp() const { return m_unusedRegexp; } string unusedRegexp() const { return m_unusedRegexp; }
string waiverOutput() const { return m_waiverOutput; } string waiverOutput() const { return m_waiverOutput; }
string work() const { return m_work; }
bool isWaiverOutput() const { return !m_waiverOutput.empty(); } bool isWaiverOutput() const { return !m_waiverOutput.empty(); }
string xAssign() const { return m_xAssign; } string xAssign() const { return m_xAssign; }
string xInitial() const { return m_xInitial; } string xInitial() const { return m_xInitial; }
@ -678,9 +708,9 @@ public:
const V3StringSet& compilerIncludes() const { return m_compilerIncludes; } const V3StringSet& compilerIncludes() const { return m_compilerIncludes; }
const V3StringList& ldLibs() const { return m_ldLibs; } const V3StringList& ldLibs() const { return m_ldLibs; }
const V3StringList& makeFlags() const { return m_makeFlags; } const V3StringList& makeFlags() const { return m_makeFlags; }
const V3StringSet& libraryFiles() const { return m_libraryFiles; } const VFileLibSet& libraryFiles() const { return m_libraryFiles; }
const V3StringList& vFiles() const { return m_vFiles; } const VFileLibList& vFiles() const { return m_vFiles; }
const V3StringSet& vltFiles() const { return m_vltFiles; } const VFileLibSet& vltFiles() const { return m_vltFiles; }
const V3StringList& forceIncs() const { return m_forceIncs; } const V3StringList& forceIncs() const { return m_forceIncs; }
bool hasParameter(const string& name); bool hasParameter(const string& name);
@ -690,7 +720,7 @@ public:
bool isFuture(const string& flag) const; bool isFuture(const string& flag) const;
bool isFuture0(const string& flag) const; bool isFuture0(const string& flag) const;
bool isFuture1(const string& flag) const; bool isFuture1(const string& flag) const;
bool isLibraryFile(const string& filename) const; bool isLibraryFile(const string& filename, const string& libname) const;
bool isClocker(const string& signame) const; bool isClocker(const string& signame) const;
bool isNoClocker(const string& signame) const; bool isNoClocker(const string& signame) const;

View File

@ -43,7 +43,7 @@ public:
// METHODS // METHODS
// Preprocess and read the Verilog file specified into the netlist database // Preprocess and read the Verilog file specified into the netlist database
void parseFile(FileLine* fileline, const string& modname, bool inLibrary, void parseFile(FileLine* fileline, const string& modname, bool inLibrary,
const string& errmsg) VL_MT_DISABLED; const string& libname, const string& errmsg) VL_MT_DISABLED;
// Push preprocessed text to the lexer // Push preprocessed text to the lexer
static void ppPushText(V3ParseImp* impp, const string& text) VL_MT_DISABLED; static void ppPushText(V3ParseImp* impp, const string& text) VL_MT_DISABLED;

View File

@ -294,6 +294,7 @@ void V3ParseImp::preprocDumps(std::ostream& os, bool forInputs) {
} }
void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool inLibrary, void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool inLibrary,
const string& libname,
const string& errmsg) { // "" for no error, make fake node const string& errmsg) { // "" for no error, make fake node
const string nondirname = V3Os::filenameNonDir(modfilename); const string nondirname = V3Os::filenameNonDir(modfilename);
const string modname = V3Os::filenameNonDirExt(modfilename); const string modname = V3Os::filenameNonDirExt(modfilename);
@ -303,13 +304,14 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i
m_lexFileline->newContent(); m_lexFileline->newContent();
m_bisonLastFileline = m_lexFileline; m_bisonLastFileline = m_lexFileline;
m_inLibrary = inLibrary; m_inLibrary = inLibrary;
m_libname = libname;
// Preprocess into m_ppBuffer // Preprocess into m_ppBuffer
const bool ok = V3PreShell::preproc(fileline, modfilename, m_filterp, this, errmsg); const bool ok = V3PreShell::preproc(fileline, modfilename, m_filterp, this, errmsg);
if (!ok) { if (!ok) {
if (errmsg != "") return; // Threw error already if (errmsg != "") return; // Threw error already
// Create fake node for later error reporting // Create fake node for later error reporting
AstNodeModule* const nodep = new AstNotFoundModule{fileline, modname}; AstNodeModule* const nodep = new AstNotFoundModule{fileline, modname, libname};
v3Global.rootp()->addModulesp(nodep); v3Global.rootp()->addModulesp(nodep);
return; return;
} }
@ -745,8 +747,8 @@ V3Parse::~V3Parse() { //
VL_DO_CLEAR(delete m_impp, m_impp = nullptr); VL_DO_CLEAR(delete m_impp, m_impp = nullptr);
} }
void V3Parse::parseFile(FileLine* fileline, const string& modname, bool inLibrary, void V3Parse::parseFile(FileLine* fileline, const string& modname, bool inLibrary,
const string& errmsg) { const string& libname, const string& errmsg) {
m_impp->parseFile(fileline, modname, inLibrary, errmsg); m_impp->parseFile(fileline, modname, inLibrary, libname, errmsg);
} }
void V3Parse::ppPushText(V3ParseImp* impp, const string& text) { void V3Parse::ppPushText(V3ParseImp* impp, const string& text) {
if (text != "") impp->ppPushText(text); if (text != "") impp->ppPushText(text);

View File

@ -150,6 +150,7 @@ class V3ParseImp final {
FileLine* m_bisonLastFileline = nullptr; // Filename/linenumber of last token FileLine* m_bisonLastFileline = nullptr; // Filename/linenumber of last token
bool m_inLibrary = false; // Currently reading a library vs. regular file bool m_inLibrary = false; // Currently reading a library vs. regular file
string m_libname; // Config library name (or --work)
int m_lexKwdDepth = 0; // Inside a `begin_keywords int m_lexKwdDepth = 0; // Inside a `begin_keywords
int m_lexKwdLast; // Last LEX state in `begin_keywords int m_lexKwdLast; // Last LEX state in `begin_keywords
VOptionBool m_unconnectedDrive; // Last unconnected drive VOptionBool m_unconnectedDrive; // Last unconnected drive
@ -254,6 +255,7 @@ public:
// Return next token, for bison, since bison isn't class based, use a global THIS // Return next token, for bison, since bison isn't class based, use a global THIS
AstNetlist* rootp() const { return m_rootp; } AstNetlist* rootp() const { return m_rootp; }
bool inLibrary() const { return m_inLibrary; } bool inLibrary() const { return m_inLibrary; }
string libname() const { return m_libname; }
VOptionBool unconnectedDrive() const { return m_unconnectedDrive; } VOptionBool unconnectedDrive() const { return m_unconnectedDrive; }
void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; } void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; }
@ -287,7 +289,7 @@ public:
int tokenToBison() VL_MT_DISABLED; // Pass token to bison int tokenToBison() VL_MT_DISABLED; // Pass token to bison
void parseFile(FileLine* fileline, const string& modfilename, bool inLibrary, void parseFile(FileLine* fileline, const string& modfilename, bool inLibrary,
const string& errmsg) VL_MT_DISABLED; const string& libname, const string& errmsg) VL_MT_DISABLED;
void dumpInputsFile() VL_MT_DISABLED; void dumpInputsFile() VL_MT_DISABLED;
static void candidatePli(VSpellCheck* spellerp) VL_MT_DISABLED; static void candidatePli(VSpellCheck* spellerp) VL_MT_DISABLED;

View File

@ -1250,7 +1250,7 @@ package_declaration: // ==IEEE: package_declaration
packageFront<nodeModulep>: packageFront<nodeModulep>:
yPACKAGE lifetimeE idAny ';' yPACKAGE lifetimeE idAny ';'
{ $$ = new AstPackage{$<fl>3, *$3}; { $$ = new AstPackage{$<fl>3, *$3, PARSEP->libname()};
if ($$->name() == "std") { if ($$->name() == "std") {
if ($$->fileline()->filename() != V3Options::getStdPackagePath()) { if ($$->fileline()->filename() != V3Options::getStdPackagePath()) {
$$->v3error("Redeclaring the 'std' package is not allowed"); $$->v3error("Redeclaring the 'std' package is not allowed");
@ -1394,7 +1394,7 @@ modFront<nodeModulep>:
// // General note: all *Front functions must call symPushNew before // // General note: all *Front functions must call symPushNew before
// // any formal arguments, as the arguments must land in the new scope. // // any formal arguments, as the arguments must land in the new scope.
yMODULE lifetimeE idAny yMODULE lifetimeE idAny
{ $$ = new AstModule{$<fl>3, *$3}; { $$ = new AstModule{$<fl>3, *$3, PARSEP->libname()};
$$->lifetime($2); $$->lifetime($2);
$$->inLibrary(PARSEP->inLibrary() || $$->fileline()->celldefineOn()); $$->inLibrary(PARSEP->inLibrary() || $$->fileline()->celldefineOn());
$$->modTrace(GRAMMARP->allTracingOn($$->fileline())); $$->modTrace(GRAMMARP->allTracingOn($$->fileline()));
@ -1415,7 +1415,7 @@ importsAndParametersE<nodep>: // IEEE: common part of module_declaration, inte
udpFront<nodeModulep>: udpFront<nodeModulep>:
yPRIMITIVE lifetimeE idAny yPRIMITIVE lifetimeE idAny
{ $$ = new AstPrimitive{$<fl>3, *$3}; { $$ = new AstPrimitive{$<fl>3, *$3, PARSEP->libname()};
$$->inLibrary(true); $$->inLibrary(true);
$$->lifetime($2); $$->lifetime($2);
$$->modTrace(false); $$->modTrace(false);
@ -1685,7 +1685,7 @@ interface_declaration: // IEEE: interface_declaration + interface_nonan
intFront<nodeModulep>: intFront<nodeModulep>:
yINTERFACE lifetimeE idAny/*new_interface*/ yINTERFACE lifetimeE idAny/*new_interface*/
{ $$ = new AstIface{$<fl>3, *$3}; { $$ = new AstIface{$<fl>3, *$3, PARSEP->libname()};
$$->inLibrary(true); $$->inLibrary(true);
$$->lifetime($2); $$->lifetime($2);
PARSEP->rootp()->addModulesp($$); } PARSEP->rootp()->addModulesp($$); }
@ -1772,7 +1772,7 @@ program_declaration: // IEEE: program_declaration + program_nonansi_h
pgmFront<nodeModulep>: pgmFront<nodeModulep>:
yPROGRAM lifetimeE idAny/*new_program*/ yPROGRAM lifetimeE idAny/*new_program*/
{ $$ = new AstModule{$<fl>3, *$3, AstModule::Program{}}; { $$ = new AstModule{$<fl>3, *$3, PARSEP->libname(), AstModule::Program{}};
$$->lifetime($2); $$->lifetime($2);
$$->inLibrary(PARSEP->inLibrary() || $$->fileline()->celldefineOn()); $$->inLibrary(PARSEP->inLibrary() || $$->fileline()->celldefineOn());
$$->modTrace(GRAMMARP->allTracingOn($$->fileline())); $$->modTrace(GRAMMARP->allTracingOn($$->fileline()));
@ -6792,7 +6792,7 @@ covergroup_declaration<nodep>: // ==IEEE: covergroup_declaration
covergroup_declarationFront<classp>: // IEEE: part of covergroup_declaration covergroup_declarationFront<classp>: // IEEE: part of covergroup_declaration
yCOVERGROUP idAny yCOVERGROUP idAny
{ $$ = new AstClass{$<fl>2, *$2}; { $$ = new AstClass{$<fl>2, *$2, PARSEP->libname()};
BBCOVERIGN($<fl>1, "Ignoring unsupported: covergroup"); } BBCOVERIGN($<fl>1, "Ignoring unsupported: covergroup"); }
; ;
@ -7196,7 +7196,7 @@ checker_declaration<nodeModulep>: // ==IEEE: part of checker_declaration
checkerFront<nodeModulep>: // IEEE: part of checker_declaration checkerFront<nodeModulep>: // IEEE: part of checker_declaration
yCHECKER idAny/*checker_identifier*/ yCHECKER idAny/*checker_identifier*/
{ $$ = new AstModule{$<fl>2, *$2, AstModule::Checker{}}; { $$ = new AstModule{$<fl>2, *$2, PARSEP->libname(), AstModule::Checker{}};
$$->modTrace(GRAMMARP->allTracingOn($$->fileline())); $$->modTrace(GRAMMARP->allTracingOn($$->fileline()));
$$->timeunit(PARSEP->timeLastUnit()); $$->timeunit(PARSEP->timeLastUnit());
$$->unconnectedDrive(PARSEP->unconnectedDrive()); } $$->unconnectedDrive(PARSEP->unconnectedDrive()); }
@ -7327,14 +7327,14 @@ class_declaration<nodep>: // ==IEEE: part of class_declaration
classFront<classp>: // IEEE: part of class_declaration classFront<classp>: // IEEE: part of class_declaration
// // IEEE 1800-2023: lifetimeE replaced with final_specifierE // // IEEE 1800-2023: lifetimeE replaced with final_specifierE
classVirtualE yCLASS final_specifierE lifetimeE idAny/*class_identifier*/ classVirtualE yCLASS final_specifierE lifetimeE idAny/*class_identifier*/
{ $$ = new AstClass{$2, *$5}; { $$ = new AstClass{$2, *$5, PARSEP->libname()};
$$->baseOverride($3); $$->baseOverride($3);
$$->isVirtual($1); $$->isVirtual($1);
v3Global.setHasClasses(); } v3Global.setHasClasses(); }
// // IEEE: part of interface_class_declaration // // IEEE: part of interface_class_declaration
// // IEEE 1800-2023: lifetimeE removed // // IEEE 1800-2023: lifetimeE removed
| yINTERFACE yCLASS idAny/*class_identifier*/ | yINTERFACE yCLASS idAny/*class_identifier*/
{ $$ = new AstClass{$2, *$3}; { $$ = new AstClass{$2, *$3, PARSEP->libname()};
$$->isInterfaceClass(true); $$->isInterfaceClass(true);
v3Global.setHasClasses(); } v3Global.setHasClasses(); }
; ;

View File

@ -0,0 +1,5 @@
*-* All Finished *-*
liba:m1 %m=t.u_1 %l=liba.m1
liba:m3 %m=t.u_1.u_13 %l=liba.m3
libb:m2 %m=t.u_2 %l=libb.m2
libb:m3 %m=t.u_2.u_23 %l=libb.m3

22
test_regress/t/t_config_work.py Executable file
View File

@ -0,0 +1,22 @@
#!/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', '--work liba', 't/t_config_work__liba.v', '--work libb', 't/t_config_work__libb.v'])
test.execute()
# Sort so that 'initial' scheduling order is not relevant
test.files_identical_sorted(test.run_log_filename, test.golden_filename, is_logfile=True)
test.passes()

View File

@ -0,0 +1,11 @@
// 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
module t;
m1 u_1();
m2 u_2();
final $write("*-* All Finished *-*\n");
endmodule

View File

@ -0,0 +1,14 @@
// 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
module m1;
m3 u_13();
initial $display("liba:m1 %%m=%m %%l=%l");
endmodule
module m3; // Module name duplicated between libraries
initial $display("liba:m3 %%m=%m %%l=%l");
endmodule

View File

@ -0,0 +1,14 @@
// 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
module m2;
m3 u_23();
initial $display("libb:m2 %%m=%m %%l=%l");
endmodule
module m3; // Module name duplicated between libraries
initial $display("libb:m3 %%m=%m %%l=%l");
endmodule

View File

@ -1,8 +1,8 @@
[0] In top.t: Hi [0] In top.t: Hi
[0] In top.t.sub.write_m (sub) [0] In top.t.sub.write_m (work.sub)
[0] In top.t.sub.write_m.subblock (sub) [0] In top.t.sub.write_m.subblock (work.sub)
[0] In top.t.sub2.write_m (sub2) [0] In top.t.sub2.write_m (work.sub2)
[0] In top.t.sub2.write_m.subblock2 (sub2) [0] In top.t.sub2.write_m.subblock2 (work.sub2)
a: -0.4=> 0.4 0 0 0 a: -0.4=> 0.4 0 0 0
[0] Back \ Quote " [0] Back \ Quote "
[0] %b=000001100 %0b=1100 %b=00000101010111011101110111100110011001100 %0b=101010111011101110111100110011001100 %b=000001010101111000001001000110100010101100111100000010010001101000101011001111000 %0b=1010101111000001001000110100010101100111100000010010001101000101011001111000 [0] %b=000001100 %0b=1100 %b=00000101010111011101110111100110011001100 %0b=101010111011101110111100110011001100 %b=000001010101111000001001000110100010101100111100000010010001101000101011001111000 %0b=1010101111000001001000110100010101100111100000010010001101000101011001111000

View File

@ -58,7 +58,7 @@ module t;
$swrite(str2, "lib=%l"); $swrite(str2, "lib=%l");
`ifdef TEST_VERBOSE $display("chkl %0s",str2); `endif `ifdef TEST_VERBOSE $display("chkl %0s",str2); `endif
if (str2 !== "lib=t") $stop; if (str2 !== "lib=work.t") $stop;
str3 = $sformatf("u=%u", {"a","b","c","d"}); // Value selected so is printable str3 = $sformatf("u=%u", {"a","b","c","d"}); // Value selected so is printable
`ifdef TEST_VERBOSE $display("chku %s", str3); `endif `ifdef TEST_VERBOSE $display("chku %s", str3); `endif