Add `--work` library-selection option (#5891 partial).
This commit is contained in:
parent
c3d86626ee
commit
916a89761e
1
Changes
1
Changes
|
@ -26,6 +26,7 @@ Verilator 5.037 devel
|
|||
* Add BADVLTPRAGMA on unknown Verilator pragmas (#5945). [Shou-Li Hsu]
|
||||
* Add ternary operator into branch coverage (#5880). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* 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 `--hierarchical-threads` (#6037). [Bartłomiej Chmiel]
|
||||
* Add `MODMISSING` error, in place of unnamed error (#6054). [Paul Swirhun]
|
||||
|
|
|
@ -513,6 +513,7 @@ detailed descriptions of these arguments.
|
|||
-Wno-fatal Disable fatal exit on warnings
|
||||
-Wno-lint Disable all lint warnings
|
||||
-Wno-style Disable all style warnings
|
||||
-work <libname> Set config library for following files
|
||||
-Wpedantic Warn on compliance-test issues
|
||||
-Wwarn-<message> Enable specified warning message
|
||||
-Wwarn-lint Enable lint warning message
|
||||
|
|
|
@ -1596,8 +1596,8 @@ Summary:
|
|||
When the input Verilog contains more than one 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.
|
||||
This is not needed with standard designs with only one top. See also
|
||||
:option:`MULTITOP` warning.
|
||||
This is not needed with standard designs with only one top.
|
||||
See :ref:`Finding and Binding Modules`.
|
||||
|
||||
.. option:: --trace
|
||||
|
||||
|
@ -1881,6 +1881,19 @@ Summary:
|
|||
``-Wno-UNUSEDGENVAR`` ``-Wno-UNUSEDPARAM`` ``-Wno-UNUSEDSIGNAL``
|
||||
``-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
|
||||
|
||||
Warn on any construct demanded by IEEE, and disable all Verilator
|
||||
|
|
|
@ -478,7 +478,8 @@ shortreal
|
|||
other simulators either do not support float, or convert likewise.
|
||||
|
||||
specify specparam
|
||||
All specify blocks and timing checks are ignored.
|
||||
All timing checks and specify blocks (except specparam, which is
|
||||
supported) are ignored.
|
||||
|
||||
uwire
|
||||
Verilator does not perform warning checking on uwires; it treats the
|
||||
|
|
|
@ -66,6 +66,40 @@ Once a model is built, the next step is typically for the user to run it,
|
|||
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
|
||||
|
|
|
@ -332,6 +332,7 @@ Prabhat
|
|||
Prabhu
|
||||
Prateek
|
||||
Pre
|
||||
Precompiling
|
||||
Preprocess
|
||||
Pretet
|
||||
Pretl
|
||||
|
|
|
@ -193,6 +193,11 @@ string AstNode::prettyName(const string& namein) VL_PURE {
|
|||
pos += 7;
|
||||
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)) {
|
||||
pretty += "";
|
||||
pos += 7;
|
||||
|
|
|
@ -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
|
||||
string m_someInstanceName; // Hierarchical name of some arbitrary instance of this module.
|
||||
// Used for user messages only.
|
||||
string m_libname; // Work library
|
||||
int m_level = 0; // 1=top module, 2=cell off top module, ...
|
||||
VLifetime m_lifetime; // Lifetime
|
||||
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_recursiveClone : 1; // If recursive, what module it clones, otherwise nullptr
|
||||
protected:
|
||||
AstNodeModule(VNType t, FileLine* fl, const string& name)
|
||||
AstNodeModule(VNType t, FileLine* fl, const string& name, const string& libname)
|
||||
: AstNode{t, fl}
|
||||
, m_name{name}
|
||||
, m_origName{name}
|
||||
, m_libname{libname}
|
||||
, m_modPublic{false}
|
||||
, m_modTrace{false}
|
||||
, m_inLibrary{false}
|
||||
|
@ -275,6 +277,8 @@ public:
|
|||
void inLibrary(bool flag) { m_inLibrary = flag; }
|
||||
void level(int level) { m_level = 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 modPublic() const { return m_modPublic; }
|
||||
void modPublic(bool flag) { m_modPublic = flag; }
|
||||
|
@ -2507,8 +2511,8 @@ class AstClass final : public AstNodeModule {
|
|||
bool m_virtual = false; // Virtual class
|
||||
|
||||
public:
|
||||
AstClass(FileLine* fl, const string& name)
|
||||
: ASTGEN_SUPER_Class(fl, name) {}
|
||||
AstClass(FileLine* fl, const string& name, const string& libname)
|
||||
: ASTGEN_SUPER_Class(fl, name, libname) {}
|
||||
ASTGEN_MEMBERS_AstClass;
|
||||
string verilogKwd() const override { return "class"; }
|
||||
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
|
||||
// // (weak pointer, hard link is other way)
|
||||
public:
|
||||
AstClassPackage(FileLine* fl, const string& name)
|
||||
: ASTGEN_SUPER_ClassPackage(fl, name) {}
|
||||
AstClassPackage(FileLine* fl, const string& name, const string& libname)
|
||||
: ASTGEN_SUPER_ClassPackage(fl, name, libname) {}
|
||||
ASTGEN_MEMBERS_AstClassPackage;
|
||||
string verilogKwd() const override { return "classpackage"; }
|
||||
bool timescaleMatters() const override { return false; }
|
||||
|
@ -2592,8 +2596,8 @@ public:
|
|||
class AstIface final : public AstNodeModule {
|
||||
// A module declaration
|
||||
public:
|
||||
AstIface(FileLine* fl, const string& name)
|
||||
: ASTGEN_SUPER_Iface(fl, name) {}
|
||||
AstIface(FileLine* fl, const string& name, const string& libname)
|
||||
: ASTGEN_SUPER_Iface(fl, name, libname) {}
|
||||
ASTGEN_MEMBERS_AstIface;
|
||||
// Interfaces have `timescale applicability but lots of code seems to
|
||||
// get false warnings if we enable this
|
||||
|
@ -2607,13 +2611,13 @@ class AstModule final : public AstNodeModule {
|
|||
public:
|
||||
class Checker {}; // for constructor type-overload selection
|
||||
class Program {}; // for constructor type-overload selection
|
||||
AstModule(FileLine* fl, const string& name)
|
||||
: ASTGEN_SUPER_Module(fl, name) {}
|
||||
AstModule(FileLine* fl, const string& name, Checker)
|
||||
: ASTGEN_SUPER_Module(fl, name)
|
||||
AstModule(FileLine* fl, const string& name, const string& libname)
|
||||
: ASTGEN_SUPER_Module(fl, name, libname) {}
|
||||
AstModule(FileLine* fl, const string& name, const string& libname, Checker)
|
||||
: ASTGEN_SUPER_Module(fl, name, libname)
|
||||
, m_isChecker{true} {}
|
||||
AstModule(FileLine* fl, const string& name, Program)
|
||||
: ASTGEN_SUPER_Module(fl, name)
|
||||
AstModule(FileLine* fl, const string& name, const string& libname, Program)
|
||||
: ASTGEN_SUPER_Module(fl, name, libname)
|
||||
, m_isProgram{true} {}
|
||||
ASTGEN_MEMBERS_AstModule;
|
||||
string verilogKwd() const override {
|
||||
|
@ -2628,8 +2632,8 @@ public:
|
|||
class AstNotFoundModule final : public AstNodeModule {
|
||||
// A missing module declaration
|
||||
public:
|
||||
AstNotFoundModule(FileLine* fl, const string& name)
|
||||
: ASTGEN_SUPER_NotFoundModule(fl, name) {}
|
||||
AstNotFoundModule(FileLine* fl, const string& name, const string& libname)
|
||||
: ASTGEN_SUPER_NotFoundModule(fl, name, libname) {}
|
||||
ASTGEN_MEMBERS_AstNotFoundModule;
|
||||
string verilogKwd() const override { return "/*not-found-*/ module"; }
|
||||
bool timescaleMatters() const override { return false; }
|
||||
|
@ -2637,8 +2641,8 @@ public:
|
|||
class AstPackage final : public AstNodeModule {
|
||||
// A package declaration
|
||||
public:
|
||||
AstPackage(FileLine* fl, const string& name)
|
||||
: ASTGEN_SUPER_Package(fl, name) {}
|
||||
AstPackage(FileLine* fl, const string& name, const string& libname)
|
||||
: ASTGEN_SUPER_Package(fl, name, libname) {}
|
||||
ASTGEN_MEMBERS_AstPackage;
|
||||
string verilogKwd() const override { return "package"; }
|
||||
bool timescaleMatters() const override { return !isDollarUnit(); }
|
||||
|
@ -2648,8 +2652,8 @@ public:
|
|||
class AstPrimitive final : public AstNodeModule {
|
||||
// A primitive declaration
|
||||
public:
|
||||
AstPrimitive(FileLine* fl, const string& name)
|
||||
: ASTGEN_SUPER_Primitive(fl, name) {}
|
||||
AstPrimitive(FileLine* fl, const string& name, const string& libname)
|
||||
: ASTGEN_SUPER_Primitive(fl, name, libname) {}
|
||||
ASTGEN_MEMBERS_AstPrimitive;
|
||||
string verilogKwd() const override { return "primitive"; }
|
||||
bool timescaleMatters() const override { return false; }
|
||||
|
|
|
@ -1353,7 +1353,7 @@ AstBasicDType* AstTypeTable::findInsertSameDType(AstBasicDType* nodep) {
|
|||
|
||||
AstConstPool::AstConstPool(FileLine* 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}} {
|
||||
this->modulep(m_modp);
|
||||
m_modp->addStmtsp(m_scopep);
|
||||
|
@ -2298,7 +2298,7 @@ void AstNetlist::dumpJson(std::ostream& str) const {
|
|||
}
|
||||
AstPackage* AstNetlist::dollarUnitPkgAddp() {
|
||||
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"
|
||||
m_dollarUnitPkgp->inLibrary(true);
|
||||
m_dollarUnitPkgp->modTrace(false); // may reconsider later
|
||||
|
@ -2325,6 +2325,7 @@ void AstNodeModule::dump(std::ostream& str) const {
|
|||
str << " [RECURSIVE]";
|
||||
}
|
||||
str << " [" << timeunit() << "]";
|
||||
if (libname() != "work") str << " libname=" << libname();
|
||||
}
|
||||
void AstNodeModule::dumpJson(std::ostream& str) const {
|
||||
dumpJsonStrFunc(str, origName);
|
||||
|
@ -2335,6 +2336,7 @@ void AstNodeModule::dumpJson(std::ostream& str) const {
|
|||
dumpJsonBoolFunc(str, recursiveClone);
|
||||
dumpJsonBoolFunc(str, recursive);
|
||||
dumpJsonStr(str, "timeunit", timeunit().ascii());
|
||||
if (libname() != "work") dumpJsonStr(str, "libname=", libname());
|
||||
dumpJsonGen(str);
|
||||
}
|
||||
void AstPackageExport::dump(std::ostream& str) const {
|
||||
|
|
|
@ -93,7 +93,7 @@ class ClassVisitor final : public VNVisitor {
|
|||
// Make containing package
|
||||
// Note origName is the same as the class origName so errors look correct
|
||||
AstClassPackage* const packagep
|
||||
= new AstClassPackage{nodep->fileline(), nodep->origName()};
|
||||
= new AstClassPackage{nodep->fileline(), nodep->origName(), nodep->libname()};
|
||||
packagep->name(nodep->name() + "__Vclpkg");
|
||||
nodep->editCountInc();
|
||||
nodep->classOrPackagep(packagep);
|
||||
|
@ -138,6 +138,7 @@ class ClassVisitor final : public VNVisitor {
|
|||
}
|
||||
void visit(AstNodeModule* nodep) override {
|
||||
// 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_modp);
|
||||
m_modp = nodep;
|
||||
|
|
|
@ -39,11 +39,21 @@ class CMakeEmitter final {
|
|||
template <typename T_List>
|
||||
static string cmake_list(const T_List& strs) {
|
||||
string s;
|
||||
for (auto it = strs.begin(); it != strs.end(); ++it) {
|
||||
for (auto& itr : strs) {
|
||||
if (!s.empty()) 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 += '"';
|
||||
if (it != strs.end()) s += ' ';
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
@ -193,8 +203,8 @@ class CMakeEmitter final {
|
|||
*of << " ";
|
||||
const string vFile = hblockp->vFileIfNecessary();
|
||||
if (!vFile.empty()) *of << vFile << " ";
|
||||
const V3StringList& vFiles = v3Global.opt.vFiles();
|
||||
for (const string& i : vFiles) *of << V3Os::filenameRealPath(i) << " ";
|
||||
for (const auto& i : v3Global.opt.vFiles())
|
||||
*of << V3Os::filenameRealPath(i.filename()) << " ";
|
||||
*of << " VERILATOR_ARGS ";
|
||||
*of << "-f " << hblockp->commandArgsFilename(true)
|
||||
<< " -CFLAGS -fPIC" // hierarchical block will be static, but may be linked
|
||||
|
|
|
@ -814,13 +814,12 @@ class EmitMkHierVerilation final {
|
|||
const string verilator_wrapper = V3Os::filenameDir(fullpath_bin) + "/verilator";
|
||||
of.puts("VM_HIER_VERILATOR := " + verilator_wrapper + "\n");
|
||||
of.puts("VM_HIER_INPUT_FILES := \\\n");
|
||||
const V3StringList& vFiles = v3Global.opt.vFiles();
|
||||
for (const string& i : vFiles) of.puts(" " + V3Os::filenameRealPath(i) + " \\\n");
|
||||
for (const auto& i : v3Global.opt.vFiles())
|
||||
of.puts(" " + V3Os::filenameRealPath(i.filename()) + " \\\n");
|
||||
of.puts("\n");
|
||||
const V3StringSet& libraryFiles = v3Global.opt.libraryFiles();
|
||||
of.puts("VM_HIER_VERILOG_LIBS := \\\n");
|
||||
for (const string& i : libraryFiles) {
|
||||
of.puts(" " + V3Os::filenameRealPath(i) + " \\\n");
|
||||
for (const auto& i : v3Global.opt.libraryFiles()) {
|
||||
of.puts(" " + V3Os::filenameRealPath(i.filename()) + " \\\n");
|
||||
}
|
||||
of.puts("\n");
|
||||
}
|
||||
|
|
|
@ -133,9 +133,9 @@ class V3EmitMkJsonEmitter final {
|
|||
const string vFile = hblockp->vFileIfNecessary();
|
||||
if (!vFile.empty()) sources.emplace_back(vFile);
|
||||
|
||||
const V3StringList& vFiles = v3Global.opt.vFiles();
|
||||
for (const string& i : vFiles)
|
||||
sources.emplace_back(V3Os::filenameSlashPath(V3Os::filenameRealPath(i)));
|
||||
for (const auto& i : v3Global.opt.vFiles())
|
||||
sources.emplace_back(
|
||||
V3Os::filenameSlashPath(V3Os::filenameRealPath(i.filename())));
|
||||
|
||||
std::vector<std::string> cflags;
|
||||
cflags.emplace_back("-fPIC");
|
||||
|
@ -156,9 +156,9 @@ class V3EmitMkJsonEmitter final {
|
|||
for (const auto& itr : *planp)
|
||||
sources.emplace_back(makeDir + "/" + itr.second->hierWrapperFilename(true));
|
||||
|
||||
const V3StringList& vFiles = v3Global.opt.vFiles();
|
||||
for (const string& i : vFiles)
|
||||
sources.emplace_back(V3Os::filenameSlashPath(V3Os::filenameRealPath(i)));
|
||||
for (const auto& itr : v3Global.opt.vFiles())
|
||||
sources.emplace_back(
|
||||
V3Os::filenameSlashPath(V3Os::filenameRealPath(itr.filename())));
|
||||
|
||||
of.begin()
|
||||
.put("prefix", v3Global.opt.prefix())
|
||||
|
|
|
@ -81,7 +81,8 @@ public:
|
|||
ForkDynScopeInstance& createInstancePrototype() {
|
||||
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);
|
||||
m_instance.m_refDTypep
|
||||
= new AstClassRefDType{m_procp->fileline(), m_instance.m_classp, nullptr};
|
||||
|
|
|
@ -60,42 +60,39 @@ void V3Global::readFiles() {
|
|||
if (v3Global.opt.stdWaiver()) {
|
||||
parser.parseFile(
|
||||
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
|
||||
const V3StringSet& vltFiles = v3Global.opt.vltFiles();
|
||||
for (const string& filename : vltFiles) {
|
||||
parser.parseFile(new FileLine{FileLine::commandLineFilename()}, filename, false,
|
||||
"Cannot find file containing .vlt file: ");
|
||||
for (auto& filelib : v3Global.opt.vltFiles()) {
|
||||
parser.parseFile(new FileLine{FileLine::commandLineFilename()}, filelib.filename(), false,
|
||||
filelib.libname(), "Cannot find file containing .vlt file: ");
|
||||
}
|
||||
|
||||
// Parse the std package
|
||||
if (v3Global.opt.stdPackage()) {
|
||||
parser.parseFile(new FileLine{V3Options::getStdPackagePath()},
|
||||
V3Options::getStdPackagePath(), false,
|
||||
V3Options::getStdPackagePath(), false, "work",
|
||||
"Cannot find verilated_std.sv containing built-in std:: definitions: ");
|
||||
}
|
||||
|
||||
// Read top module
|
||||
const V3StringList& vFiles = v3Global.opt.vFiles();
|
||||
for (const string& filename : vFiles) {
|
||||
parser.parseFile(new FileLine{FileLine::commandLineFilename()}, filename, false,
|
||||
"Cannot find file containing module: ");
|
||||
for (const auto& filelib : v3Global.opt.vFiles()) {
|
||||
parser.parseFile(new FileLine{FileLine::commandLineFilename()}, filelib.filename(), false,
|
||||
filelib.libname(), "Cannot find file containing module: ");
|
||||
}
|
||||
|
||||
// Read libraries
|
||||
// To be compatible with other simulators,
|
||||
// this needs to be done after the top file is read
|
||||
const V3StringSet& libraryFiles = v3Global.opt.libraryFiles();
|
||||
for (const string& filename : libraryFiles) {
|
||||
parser.parseFile(new FileLine{FileLine::commandLineFilename()}, filename, true,
|
||||
"Cannot find file containing library module: ");
|
||||
for (const auto& filelib : v3Global.opt.libraryFiles()) {
|
||||
parser.parseFile(new FileLine{FileLine::commandLineFilename()}, filelib.filename(), true,
|
||||
filelib.libname(), "Cannot find file containing library module: ");
|
||||
}
|
||||
|
||||
// Read hierarchical type parameter file
|
||||
const string filename = v3Global.opt.hierParamFile();
|
||||
if (!filename.empty()) {
|
||||
parser.parseFile(new FileLine{FileLine::commandLineFilename()}, filename, false,
|
||||
for (const auto& filelib : v3Global.opt.hierParamFile()) {
|
||||
parser.parseFile(new FileLine{FileLine::commandLineFilename()}, filelib.filename(), false,
|
||||
filelib.libname(),
|
||||
"Cannot open file containing hierarchical parameter declarations: ");
|
||||
}
|
||||
|
||||
|
|
|
@ -116,12 +116,11 @@ static void V3HierWriteCommonInputs(const V3HierBlock* hblockp, std::ostream* of
|
|||
if (hblockp) topModuleFile = hblockp->vFileIfNecessary();
|
||||
if (!forCMake) {
|
||||
if (!topModuleFile.empty()) *of << topModuleFile << "\n";
|
||||
const V3StringList& vFiles = v3Global.opt.vFiles();
|
||||
for (const string& i : vFiles) *of << i << "\n";
|
||||
for (const auto& i : v3Global.opt.vFiles()) *of << i.filename() << "\n";
|
||||
}
|
||||
const V3StringSet& libraryFiles = v3Global.opt.libraryFiles();
|
||||
for (const string& i : libraryFiles) {
|
||||
if (V3Os::filenameRealPath(i) != topModuleFile) *of << "-v " << i << "\n";
|
||||
for (const auto& i : v3Global.opt.libraryFiles()) {
|
||||
if (V3Os::filenameRealPath(i.filename()) != topModuleFile)
|
||||
*of << "-v " << i.filename() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -251,9 +250,9 @@ string V3HierBlock::hierGeneratedFilenames(bool withDir) const {
|
|||
|
||||
string V3HierBlock::vFileIfNecessary() const {
|
||||
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.
|
||||
if (filename == V3Os::filenameRealPath(v)) return "";
|
||||
if (filename == V3Os::filenameRealPath(v.filename())) return "";
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
|
|
@ -127,14 +127,34 @@ class LinkCellsVisitor final : public VNVisitor {
|
|||
const V3GraphEdge* const edgep = new V3GraphEdge{&m_graph, fromp, top, weight, cuttable};
|
||||
UINFO(9, " newEdge " << edgep << " " << fromp->name() << " -> " << top->name());
|
||||
}
|
||||
|
||||
AstNodeModule* findModuleSym(const string& modName) {
|
||||
const VSymEnt* const foundp = m_mods.rootp()->findIdFallback(modName);
|
||||
return foundp ? VN_AS(foundp->nodep(), NodeModule) : nullptr;
|
||||
void insertModInLib(const string& name, const string& libname, AstNodeModule* nodep) {
|
||||
// Be able to find the module under it's library using the name it was given
|
||||
VSymEnt* libSymp = m_mods.rootp()->findIdFlat(libname);
|
||||
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* modp = findModuleSym(modName);
|
||||
AstNodeModule* findModuleLibSym(const string& modName, const string& libname) {
|
||||
// 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) {
|
||||
// Read-subfile
|
||||
// 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);
|
||||
V3Parse parser{v3Global.rootp(), m_filterp};
|
||||
// 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();
|
||||
// We've read new modules, grab new pointers to their names
|
||||
readModNames();
|
||||
// Check again
|
||||
modp = findModuleSym(modName);
|
||||
modp = findModuleSym(modName, libname);
|
||||
if (!modp) {
|
||||
// This shouldn't throw a message as parseFile will create
|
||||
// a AstNotFoundModule for us
|
||||
|
@ -188,7 +208,7 @@ class LinkCellsVisitor final : public VNVisitor {
|
|||
m_modp = nodep;
|
||||
UINFO(4, "Link Module: " << nodep);
|
||||
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()
|
||||
&& !nodep->internal()) {
|
||||
// We only complain once per file, otherwise library-like files
|
||||
|
@ -228,7 +248,7 @@ class LinkCellsVisitor final : public VNVisitor {
|
|||
UINFO(4, "Link IfaceRef: " << nodep);
|
||||
// Use findIdUpward instead of findIdFlat; it doesn't matter for now
|
||||
// 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 (VN_IS(modp, Iface)) {
|
||||
// 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
|
||||
iterateChildren(nodep);
|
||||
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 (!nodep->packagep()) {
|
||||
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
|
||||
iterateChildren(nodep);
|
||||
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 not found, V3LinkDot will report errors
|
||||
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
|
||||
// and means we cannot compute module levels until later.
|
||||
UINFO(4, "Link Bind: " << nodep);
|
||||
AstNodeModule* const modp = resolveModule(nodep, nodep->name());
|
||||
AstNodeModule* const modp = resolveModule(nodep, nodep->name(), m_modp->libname());
|
||||
if (modp) {
|
||||
AstNode* const cellsp = nodep->cellsp()->unlinkFrBackWithNext();
|
||||
// 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);
|
||||
// Use findIdFallback instead of findIdFlat; it doesn't matter for now
|
||||
// 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 == m_modp || cellmodp->user2p() == m_modp) {
|
||||
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 (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)) {
|
||||
// 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.
|
||||
|
@ -591,21 +611,26 @@ class LinkCellsVisitor final : public VNVisitor {
|
|||
// Look at all modules, and store pointers to all module names
|
||||
for (AstNodeModule *nextp, *nodep = v3Global.rootp()->modulesp(); nodep; nodep = nextp) {
|
||||
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
|
||||
// considering parameter
|
||||
}
|
||||
const AstNodeModule* const foundp = findModuleSym(nodep->name());
|
||||
if (foundp && foundp != nodep) {
|
||||
if (!(foundp->fileline()->warnIsOff(V3ErrorCode::MODDUP)
|
||||
const AstNodeModule* const libFoundp = findModuleLibSym(nodep->origName(), nodep->libname());
|
||||
const AstNodeModule* const globalFoundp = findModuleLibSym(nodep->name(), "__GLOBAL");
|
||||
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)
|
||||
|| hierBlocks.find(nodep->name()) != hierBlocks.end())) {
|
||||
nodep->v3warn(MODDUP, "Duplicate declaration of module: "
|
||||
<< nodep->prettyNameQ() << '\n'
|
||||
<< nodep->warnContextPrimary() << '\n'
|
||||
<< foundp->warnOther()
|
||||
<< libFoundp->warnOther()
|
||||
<< "... Location of original declaration\n"
|
||||
<< foundp->warnContextSecondary());
|
||||
<< libFoundp->warnContextSecondary());
|
||||
}
|
||||
if (VN_IS(nodep, Package)) {
|
||||
// Packages may be imported, we instead rename to be unique
|
||||
|
@ -614,8 +639,16 @@ class LinkCellsVisitor final : public VNVisitor {
|
|||
nodep->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
} else if (!foundp) {
|
||||
m_mods.rootp()->insert(nodep->name(), new VSymEnt{&m_mods, nodep});
|
||||
} else if (!libFoundp && globalFoundp && globalFoundp != 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: ");
|
||||
|
@ -641,7 +674,9 @@ public:
|
|||
iterate(nodep);
|
||||
}
|
||||
~LinkCellsVisitor() override {
|
||||
if (debug() >= 5 || dumpGraphLevel() >= 5) { m_mods.dumpFilePrefixed("linkcells"); }
|
||||
if (debug() >= 5 || dumpGraphLevel() >= 5) {
|
||||
m_mods.dumpFilePrefixed("linkcells");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -164,7 +164,7 @@ void V3LinkLevel::wrapTop(AstNetlist* rootp) {
|
|||
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
|
||||
// Make the new module first in the list
|
||||
oldmodp->unlinkFrBackWithNext();
|
||||
|
|
|
@ -313,7 +313,8 @@ class LinkResolveVisitor final : public VNVisitor {
|
|||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: %l in $fscanf");
|
||||
fmt = "";
|
||||
}
|
||||
if (m_modp) fmt = VString::quotePercent(m_modp->prettyName());
|
||||
if (m_modp)
|
||||
fmt = AstNode::prettyName(m_modp->libname()) + "." + m_modp->prettyName();
|
||||
break;
|
||||
default: // Most operators, just move to next argument
|
||||
if (!V3Number::displayedFmtLegal(ch, isScan)) {
|
||||
|
|
|
@ -380,10 +380,12 @@ bool V3Options::isFuture0(const string& flag) const {
|
|||
bool V3Options::isFuture1(const string& flag) const {
|
||||
return m_future1s.find(flag) != m_future1s.end();
|
||||
}
|
||||
bool V3Options::isLibraryFile(const string& filename) const {
|
||||
return m_libraryFiles.find(filename) != m_libraryFiles.end();
|
||||
bool V3Options::isLibraryFile(const string& filename, const string& libname) const {
|
||||
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 {
|
||||
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();
|
||||
}
|
||||
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
|
||||
// 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::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.
|
||||
string V3Options::allArgsStringForHierBlock(bool forTop) const {
|
||||
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;
|
||||
bool stripArg = 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
|
||||
// Detailed error, since this is what we often get when run with minimal arguments
|
||||
const V3StringList& vFilesList = vFiles();
|
||||
if (vFilesList.empty()) {
|
||||
if (vFiles().empty()) {
|
||||
v3fatal("verilator: No Input Verilog file specified on command line, "
|
||||
"see verilator --help for more information\n");
|
||||
}
|
||||
|
||||
// Default prefix to the filename
|
||||
if (prefix() == "" && topModule() != "") m_prefix = "V"s + AstNode::encodeName(topModule());
|
||||
if (prefix() == "" && vFilesList.size() >= 1)
|
||||
m_prefix = "V"s + AstNode::encodeName(V3Os::filenameNonDirExt(*(vFilesList.begin())));
|
||||
if (prefix() == "" && vFiles().size() >= 1)
|
||||
m_prefix
|
||||
= "V"s + AstNode::encodeName(V3Os::filenameNonDirExt(vFiles().begin()->filename()));
|
||||
if (modPrefix() == "") m_modPrefix = prefix();
|
||||
|
||||
// Find files in makedir
|
||||
|
@ -1386,8 +1390,9 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||
m_hierBlocks.emplace(opt.mangledName(), opt);
|
||||
});
|
||||
DECL_OPTION("-hierarchical-child", Set, &m_hierChild);
|
||||
DECL_OPTION("-hierarchical-params-file", CbVal,
|
||||
[this](const char* optp) { m_hierParamsFile = optp; });
|
||||
DECL_OPTION("-hierarchical-params-file", CbVal, [this](const char* optp) {
|
||||
m_hierParamsFile.push_back({optp, work()});
|
||||
});
|
||||
|
||||
DECL_OPTION("-I", CbPartialMatch,
|
||||
[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);
|
||||
});
|
||||
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("-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-UNUSED", CbCall, []() { FileLine::globalWarnUnusedOff(true); });
|
||||
DECL_OPTION("-Wno-WIDTH", CbCall, []() { FileLine::globalWarnOff(V3ErrorCode::WIDTH, true); });
|
||||
DECL_OPTION("-work", Set, &m_work);
|
||||
DECL_OPTION("-Wpedantic", CbCall, [this]() {
|
||||
m_pedantic = true;
|
||||
V3Error::pretendError(V3ErrorCode::ASSIGNIN, false);
|
||||
|
@ -1888,9 +1894,9 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||
|| suffixed(filename, ".so")) {
|
||||
V3Options::addLdLibs(filename);
|
||||
} else if (suffixed(filename, ".vlt")) {
|
||||
V3Options::addVltFile(filename);
|
||||
V3Options::addVltFile(filename, work());
|
||||
} else {
|
||||
V3Options::addVFile(filename);
|
||||
V3Options::addVFile(filename, work());
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
|
|
@ -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==(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 {
|
||||
|
@ -207,11 +235,11 @@ private:
|
|||
V3StringSet m_futures; // argument: -Wfuture- list
|
||||
V3StringSet m_future0s; // argument: -future 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_noClockers; // argument: Verilog -noclk signals
|
||||
V3StringList m_vFiles; // argument: Verilog files to read
|
||||
V3StringSet m_vltFiles; // argument: Verilator config files to read
|
||||
VFileLibList m_vFiles; // argument: Verilog files to read
|
||||
VFileLibSet m_vltFiles; // argument: Verilator config files to read
|
||||
V3StringList m_forceIncs; // argument: -FI
|
||||
DebugLevelMap m_debugLevel; // argument: --debugi-<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_exeName; // main switch: -o {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_jsonOnlyMetaOutput; // main switch: --json-only-meta-output
|
||||
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_unusedRegexp; // main switch: --unused-regexp
|
||||
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_xInitial; // main switch: --x-initial
|
||||
string m_xmlOutput; // main switch: --xml-output
|
||||
|
@ -463,11 +492,11 @@ public:
|
|||
void addCompilerIncludes(const string& filename);
|
||||
void addLdLibs(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 addNoClocker(const string& signame);
|
||||
void addVFile(const string& filename);
|
||||
void addVltFile(const string& filename);
|
||||
void addVFile(const string& filename, const string& libname);
|
||||
void addVltFile(const string& filename, const string& libname);
|
||||
void addForceInc(const string& filename);
|
||||
bool available() const VL_MT_SAFE { return m_available; }
|
||||
void ccSet();
|
||||
|
@ -642,7 +671,7 @@ public:
|
|||
: m_diagnosticsSarifOutput;
|
||||
}
|
||||
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 jsonOnlyMetaOutput() const { return m_jsonOnlyMetaOutput; }
|
||||
string l2Name() const { return m_l2Name; }
|
||||
|
@ -668,6 +697,7 @@ public:
|
|||
bool noTraceTop() const { return m_noTraceTop; }
|
||||
string unusedRegexp() const { return m_unusedRegexp; }
|
||||
string waiverOutput() const { return m_waiverOutput; }
|
||||
string work() const { return m_work; }
|
||||
bool isWaiverOutput() const { return !m_waiverOutput.empty(); }
|
||||
string xAssign() const { return m_xAssign; }
|
||||
string xInitial() const { return m_xInitial; }
|
||||
|
@ -678,9 +708,9 @@ public:
|
|||
const V3StringSet& compilerIncludes() const { return m_compilerIncludes; }
|
||||
const V3StringList& ldLibs() const { return m_ldLibs; }
|
||||
const V3StringList& makeFlags() const { return m_makeFlags; }
|
||||
const V3StringSet& libraryFiles() const { return m_libraryFiles; }
|
||||
const V3StringList& vFiles() const { return m_vFiles; }
|
||||
const V3StringSet& vltFiles() const { return m_vltFiles; }
|
||||
const VFileLibSet& libraryFiles() const { return m_libraryFiles; }
|
||||
const VFileLibList& vFiles() const { return m_vFiles; }
|
||||
const VFileLibSet& vltFiles() const { return m_vltFiles; }
|
||||
const V3StringList& forceIncs() const { return m_forceIncs; }
|
||||
|
||||
bool hasParameter(const string& name);
|
||||
|
@ -690,7 +720,7 @@ public:
|
|||
bool isFuture(const string& flag) const;
|
||||
bool isFuture0(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 isNoClocker(const string& signame) const;
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ public:
|
|||
// METHODS
|
||||
// Preprocess and read the Verilog file specified into the netlist database
|
||||
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
|
||||
static void ppPushText(V3ParseImp* impp, const string& text) VL_MT_DISABLED;
|
||||
|
|
|
@ -294,6 +294,7 @@ void V3ParseImp::preprocDumps(std::ostream& os, bool forInputs) {
|
|||
}
|
||||
|
||||
void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool inLibrary,
|
||||
const string& libname,
|
||||
const string& errmsg) { // "" for no error, make fake node
|
||||
const string nondirname = V3Os::filenameNonDir(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_bisonLastFileline = m_lexFileline;
|
||||
m_inLibrary = inLibrary;
|
||||
m_libname = libname;
|
||||
|
||||
// Preprocess into m_ppBuffer
|
||||
const bool ok = V3PreShell::preproc(fileline, modfilename, m_filterp, this, errmsg);
|
||||
if (!ok) {
|
||||
if (errmsg != "") return; // Threw error already
|
||||
// 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);
|
||||
return;
|
||||
}
|
||||
|
@ -745,8 +747,8 @@ V3Parse::~V3Parse() { //
|
|||
VL_DO_CLEAR(delete m_impp, m_impp = nullptr);
|
||||
}
|
||||
void V3Parse::parseFile(FileLine* fileline, const string& modname, bool inLibrary,
|
||||
const string& errmsg) {
|
||||
m_impp->parseFile(fileline, modname, inLibrary, errmsg);
|
||||
const string& libname, const string& errmsg) {
|
||||
m_impp->parseFile(fileline, modname, inLibrary, libname, errmsg);
|
||||
}
|
||||
void V3Parse::ppPushText(V3ParseImp* impp, const string& text) {
|
||||
if (text != "") impp->ppPushText(text);
|
||||
|
|
|
@ -150,6 +150,7 @@ class V3ParseImp final {
|
|||
FileLine* m_bisonLastFileline = nullptr; // Filename/linenumber of last token
|
||||
|
||||
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_lexKwdLast; // Last LEX state in `begin_keywords
|
||||
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
|
||||
AstNetlist* rootp() const { return m_rootp; }
|
||||
bool inLibrary() const { return m_inLibrary; }
|
||||
string libname() const { return m_libname; }
|
||||
VOptionBool unconnectedDrive() const { return m_unconnectedDrive; }
|
||||
void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; }
|
||||
|
||||
|
@ -287,7 +289,7 @@ public:
|
|||
int tokenToBison() VL_MT_DISABLED; // Pass token to bison
|
||||
|
||||
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;
|
||||
static void candidatePli(VSpellCheck* spellerp) VL_MT_DISABLED;
|
||||
|
||||
|
|
|
@ -1250,7 +1250,7 @@ package_declaration: // ==IEEE: package_declaration
|
|||
|
||||
packageFront<nodeModulep>:
|
||||
yPACKAGE lifetimeE idAny ';'
|
||||
{ $$ = new AstPackage{$<fl>3, *$3};
|
||||
{ $$ = new AstPackage{$<fl>3, *$3, PARSEP->libname()};
|
||||
if ($$->name() == "std") {
|
||||
if ($$->fileline()->filename() != V3Options::getStdPackagePath()) {
|
||||
$$->v3error("Redeclaring the 'std' package is not allowed");
|
||||
|
@ -1394,7 +1394,7 @@ modFront<nodeModulep>:
|
|||
// // General note: all *Front functions must call symPushNew before
|
||||
// // any formal arguments, as the arguments must land in the new scope.
|
||||
yMODULE lifetimeE idAny
|
||||
{ $$ = new AstModule{$<fl>3, *$3};
|
||||
{ $$ = new AstModule{$<fl>3, *$3, PARSEP->libname()};
|
||||
$$->lifetime($2);
|
||||
$$->inLibrary(PARSEP->inLibrary() || $$->fileline()->celldefineOn());
|
||||
$$->modTrace(GRAMMARP->allTracingOn($$->fileline()));
|
||||
|
@ -1415,7 +1415,7 @@ importsAndParametersE<nodep>: // IEEE: common part of module_declaration, inte
|
|||
|
||||
udpFront<nodeModulep>:
|
||||
yPRIMITIVE lifetimeE idAny
|
||||
{ $$ = new AstPrimitive{$<fl>3, *$3};
|
||||
{ $$ = new AstPrimitive{$<fl>3, *$3, PARSEP->libname()};
|
||||
$$->inLibrary(true);
|
||||
$$->lifetime($2);
|
||||
$$->modTrace(false);
|
||||
|
@ -1685,7 +1685,7 @@ interface_declaration: // IEEE: interface_declaration + interface_nonan
|
|||
|
||||
intFront<nodeModulep>:
|
||||
yINTERFACE lifetimeE idAny/*new_interface*/
|
||||
{ $$ = new AstIface{$<fl>3, *$3};
|
||||
{ $$ = new AstIface{$<fl>3, *$3, PARSEP->libname()};
|
||||
$$->inLibrary(true);
|
||||
$$->lifetime($2);
|
||||
PARSEP->rootp()->addModulesp($$); }
|
||||
|
@ -1772,7 +1772,7 @@ program_declaration: // IEEE: program_declaration + program_nonansi_h
|
|||
|
||||
pgmFront<nodeModulep>:
|
||||
yPROGRAM lifetimeE idAny/*new_program*/
|
||||
{ $$ = new AstModule{$<fl>3, *$3, AstModule::Program{}};
|
||||
{ $$ = new AstModule{$<fl>3, *$3, PARSEP->libname(), AstModule::Program{}};
|
||||
$$->lifetime($2);
|
||||
$$->inLibrary(PARSEP->inLibrary() || $$->fileline()->celldefineOn());
|
||||
$$->modTrace(GRAMMARP->allTracingOn($$->fileline()));
|
||||
|
@ -6792,7 +6792,7 @@ covergroup_declaration<nodep>: // ==IEEE: covergroup_declaration
|
|||
|
||||
covergroup_declarationFront<classp>: // IEEE: part of covergroup_declaration
|
||||
yCOVERGROUP idAny
|
||||
{ $$ = new AstClass{$<fl>2, *$2};
|
||||
{ $$ = new AstClass{$<fl>2, *$2, PARSEP->libname()};
|
||||
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
|
||||
yCHECKER idAny/*checker_identifier*/
|
||||
{ $$ = new AstModule{$<fl>2, *$2, AstModule::Checker{}};
|
||||
{ $$ = new AstModule{$<fl>2, *$2, PARSEP->libname(), AstModule::Checker{}};
|
||||
$$->modTrace(GRAMMARP->allTracingOn($$->fileline()));
|
||||
$$->timeunit(PARSEP->timeLastUnit());
|
||||
$$->unconnectedDrive(PARSEP->unconnectedDrive()); }
|
||||
|
@ -7327,14 +7327,14 @@ class_declaration<nodep>: // ==IEEE: part of class_declaration
|
|||
classFront<classp>: // IEEE: part of class_declaration
|
||||
// // IEEE 1800-2023: lifetimeE replaced with final_specifierE
|
||||
classVirtualE yCLASS final_specifierE lifetimeE idAny/*class_identifier*/
|
||||
{ $$ = new AstClass{$2, *$5};
|
||||
{ $$ = new AstClass{$2, *$5, PARSEP->libname()};
|
||||
$$->baseOverride($3);
|
||||
$$->isVirtual($1);
|
||||
v3Global.setHasClasses(); }
|
||||
// // IEEE: part of interface_class_declaration
|
||||
// // IEEE 1800-2023: lifetimeE removed
|
||||
| yINTERFACE yCLASS idAny/*class_identifier*/
|
||||
{ $$ = new AstClass{$2, *$3};
|
||||
{ $$ = new AstClass{$2, *$3, PARSEP->libname()};
|
||||
$$->isInterfaceClass(true);
|
||||
v3Global.setHasClasses(); }
|
||||
;
|
||||
|
|
|
@ -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
|
|
@ -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()
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -1,8 +1,8 @@
|
|||
[0] In top.t: Hi
|
||||
[0] In top.t.sub.write_m (sub)
|
||||
[0] In top.t.sub.write_m.subblock (sub)
|
||||
[0] In top.t.sub2.write_m (sub2)
|
||||
[0] In top.t.sub2.write_m.subblock2 (sub2)
|
||||
[0] In top.t.sub.write_m (work.sub)
|
||||
[0] In top.t.sub.write_m.subblock (work.sub)
|
||||
[0] In top.t.sub2.write_m (work.sub2)
|
||||
[0] In top.t.sub2.write_m.subblock2 (work.sub2)
|
||||
a: -0.4=> 0.4 0 0 0
|
||||
[0] Back \ Quote "
|
||||
[0] %b=000001100 %0b=1100 %b=00000101010111011101110111100110011001100 %0b=101010111011101110111100110011001100 %b=000001010101111000001001000110100010101100111100000010010001101000101011001111000 %0b=1010101111000001001000110100010101100111100000010010001101000101011001111000
|
||||
|
|
|
@ -58,7 +58,7 @@ module t;
|
|||
|
||||
$swrite(str2, "lib=%l");
|
||||
`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
|
||||
`ifdef TEST_VERBOSE $display("chku %s", str3); `endif
|
||||
|
|
Loading…
Reference in New Issue