Merge branch 'master' into develop-v5

This commit is contained in:
Wilson Snyder 2022-10-01 11:24:55 -04:00
commit 880cac2fdd
43 changed files with 1049 additions and 40 deletions

View File

@ -24,10 +24,10 @@ jobs:
Build:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
env:
CI_BUILD_STAGE_NAME: build
CI_RUNS_ON: ubuntu-20.04
CI_RUNS_ON: ubuntu-22.04
steps:
- name: Checkout
@ -73,11 +73,11 @@ jobs:
- 9
include:
- { test: dist, num: '' }
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
name: test-${{ matrix.test }}${{ matrix.num }}
env:
CI_BUILD_STAGE_NAME: test
CI_RUNS_ON: ubuntu-20.04
CI_RUNS_ON: ubuntu-22.04
steps:
- name: Download tar archive

11
Changes
View File

@ -13,7 +13,7 @@ Verilator 5.001 devel
**Major:**
* This is a major new release, currently only in alpha testing.
* This is a major new release.
* Fully support the Active and NBA scheduling regions as defined by the
SystemVerilog standard (IEEE 1800-2017 chapter 4). This means all generated
clocks are now simulated correctly (#3278, #3384). [Geza Lore, Shunyao CAD]
@ -22,7 +22,7 @@ Verilator 5.001 devel
* Add --binary option as alias of --main --exe --build --timing (#3625).
Verilator 4.227 devel
Verilator 4.228 2022-10-01
==========================
**Announcement:**
@ -33,14 +33,18 @@ Verilator 4.227 devel
**Minor:**
* Support IEEE constant signal strengths (#3601). [Ryszard Rozak/Antmicro]
* Support some IEEE signal strengths (#3601) (#3629). [Ryszard Rozak/Antmicro]
* Add --main to generate main() C++ (previously was experimental only).
* Add --build-jobs, and rework arguments for -j (#3623). [Kamil Rakoczy]
* Rename --bin to --build-dep-bin.
* Rename debug flags --dumpi-tree, --dumpi-graph, etc. [Geza Lore]
* Fix thread saftey in SystemC VL_ASSIGN_SBW/WSB (#3494) (#3513). [Mladen Slijepcevic]
* Fix crash in gate optimization of circular logic (#3543). [Bill Flynn]
* Fix arguments in non-static method call (#3547) (#3582). [Gustav Svensk]
* Fix default --mod-prefix when --prefix is repeated (#3603). [Geza Lore]
* Fix calling trace() after open() segfault (#3610) (#3627). [Yu-Sheng Lin]
* Fix typedef'ed class conversion to boolean (#3616). [Aleksander Kiryk]
* Fix Verilation speed when disabled warnings (#3632). [Kamil Rakoczy/Antmicro]
Verilator 4.226 2022-08-31
@ -55,6 +59,7 @@ Verilator 4.226 2022-08-31
* Support $test$plusargs(expr) (#3489).
* Rename trace rolloverSize() (#3570).
* Improve Verilation speed with --threads on large designs. [Geza Lore]
* Improve Verilation memory by reducing V3Number (#3521). [Mariusz Glebocki/Antmicro]
* Fix struct pattern assignment (#2328) (#3517). [Mostafa Gamal]
* Fix public combo propagation issues (#2905). [Todd Strader]
* Fix incorrect tristate logic (#3399) [shareefj, Vighnesh Iyer]

View File

@ -71,6 +71,7 @@ Ludwig Rogiers
Lukasz Dalek
Maarten De Braekeleer
Maciej Sobkowski
Marcel Chang
Marco Widmer
Mariusz Glebocki
Markus Krause

View File

@ -382,6 +382,12 @@ Summary:
<--dump-tree>` may be useful if the dump files are large and not
desired.
.. option:: --dump-tree-dot
Rarely needed. Enable dumping Ast .tree.dot debug files in Graphviz
Dot format. This option implies :vlopt:`--dump-tree`, unless
:vlopt:`--dumpi-tree` was passed explicitly.
.. option:: --dump-tree-addrids
Rarely needed - for developer use. Replace AST node addresses with

View File

@ -1677,6 +1677,16 @@ Similarly the ``NETLIST`` has a list of modules referred to by its
``op1p()`` pointer.
.tree.dot Output
----------------
``*.tree.dot`` files are dumps of the AST Tree in `Graphviz
<https://www.graphviz.org>`__ dot format. This can be used to
visualize the AST Tree. The vertices correspond to ``AstNode``
instances, and the edges represent the pointers (``op1p``,
``op2p``, etc) between the nodes.
Debugging with GDB
------------------

View File

@ -82,7 +82,7 @@ int sc_main(int argc, char* argv[]) {
// You must do one evaluation before enabling waves, in order to allow
// SystemC to interconnect everything for testing.
sc_start(1, SC_NS);
sc_start(SC_ZERO_TIME);
#if VM_TRACE
// If verilator was invoked with --trace argument,

View File

@ -551,15 +551,15 @@ template <>
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::runOffloadedCallbacks(
const std::vector<CallbackRecord>& cbVec) {
// Fall back on sequential execution
for (const CallbackRecord& cbr : cbVec) {
#ifdef VL_THREADED
for (const CallbackRecord& cbr : cbVec) {
Buffer* traceBufferp = getTraceBuffer();
cbr.m_dumpOffloadCb(cbr.m_userp, static_cast<OffloadBuffer*>(traceBufferp));
commitTraceBuffer(traceBufferp);
#else
VL_FATAL_MT(__FILE__, __LINE__, "", "Unreachable");
#endif
}
#else
if (!cbVec.empty()) VL_FATAL_MT(__FILE__, __LINE__, "", "Unreachable");
#endif
}
template <>
@ -586,7 +586,9 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::dump(uint64_t timeui) VL_MT_SAFE_EXCLUD
if (!preChangeDump()) return;
}
#ifdef VL_THREADED
uint32_t* bufferp = nullptr;
#endif
if (offload()) {
#ifdef VL_THREADED
// Currently only incremental dumps run on the worker thread

View File

@ -1141,6 +1141,49 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump, boo
}
}
static void drawChildren(std::ostream& os, const AstNode* thisp, const AstNode* childp,
const std::string& childName) {
if (childp) {
os << "\tn" << cvtToHex(thisp) << " -> n" << cvtToHex(childp) << " ["
<< "label=\"" << childName << "\" color=red];\n";
for (const AstNode* nodep = childp; nodep; nodep = nodep->nextp()) {
nodep->dumpTreeDot(os);
if (nodep->nextp()) {
os << "\tn" << cvtToHex(nodep) << " -> n" << cvtToHex(nodep->nextp()) << " ["
<< "label=\"next\" color=red];\n";
os << "\t{rank=same; n" << cvtToHex(nodep) << ", n" << cvtToHex(nodep->nextp())
<< "}\n";
}
}
}
}
void AstNode::dumpTreeDot(std::ostream& os) const {
os << "\tn" << cvtToHex(this) << "\t["
<< "label=\"" << typeName() << "\\n"
<< name() << "\"];\n";
drawChildren(os, this, m_op1p, "op1");
drawChildren(os, this, m_op2p, "op2");
drawChildren(os, this, m_op3p, "op3");
drawChildren(os, this, m_op4p, "op4");
}
void AstNode::dumpTreeDotFile(const string& filename, bool append, bool doDump) {
if (doDump) {
UINFO(2, "Dumping " << filename << endl);
const std::unique_ptr<std::ofstream> treedotp{V3File::new_ofstream(filename, append)};
if (treedotp->fail()) v3fatal("Can't write " << filename);
*treedotp << "digraph vTree{\n";
*treedotp << "\tgraph\t[label=\"" << filename + ".dot"
<< "\",\n";
*treedotp << "\t\t labelloc=t, labeljust=l,\n";
*treedotp << "\t\t //size=\"7.5,10\",\n"
<< "];\n";
dumpTreeDot(*treedotp);
*treedotp << "}\n";
}
}
void AstNode::v3errorEndFatal(std::ostringstream& str) const {
v3errorEnd(str);
assert(0); // LCOV_EXCL_LINE

View File

@ -1916,6 +1916,8 @@ public:
void dumpTreeFile(const string& filename, bool append = false, bool doDump = true,
bool doCheck = true);
static void dumpTreeFileGdb(const AstNode* nodep, const char* filenamep = nullptr);
void dumpTreeDot(std::ostream& os = std::cout) const;
void dumpTreeDotFile(const string& filename, bool append = false, bool doDump = true);
// METHODS - queries
// Changes control flow, disable some optimizations

View File

@ -424,10 +424,46 @@ private:
}
}
void preserveTopIfaces(AstNetlist* rootp) {
for (AstNodeModule* modp = rootp->modulesp(); modp && modp->level() <= 2;
modp = VN_AS(modp->nextp(), NodeModule)) {
for (AstNode* subnodep = modp->stmtsp(); subnodep; subnodep = subnodep->nextp()) {
if (AstVar* const varp = VN_CAST(subnodep, Var)) {
if (varp->isIfaceRef()) {
const AstNodeDType* const subtypep = varp->subDTypep();
const AstIfaceRefDType* ifacerefp = nullptr;
if (VN_IS(subtypep, IfaceRefDType)) {
ifacerefp = VN_AS(varp->subDTypep(), IfaceRefDType);
} else if (VN_IS(subtypep, BracketArrayDType)) {
const AstBracketArrayDType* const arrp
= VN_AS(subtypep, BracketArrayDType);
const AstNodeDType* const arrsubtypep = arrp->subDTypep();
if (VN_IS(arrsubtypep, IfaceRefDType)) {
ifacerefp = VN_AS(arrsubtypep, IfaceRefDType);
}
} else if (VN_IS(subtypep, UnpackArrayDType)) {
const AstUnpackArrayDType* const arrp
= VN_AS(subtypep, UnpackArrayDType);
const AstNodeDType* const arrsubtypep = arrp->subDTypep();
if (VN_IS(arrsubtypep, IfaceRefDType)) {
ifacerefp = VN_AS(arrsubtypep, IfaceRefDType);
}
}
if (ifacerefp && !ifacerefp->cellp()
&& (ifacerefp->ifacep()->user1() == 0)) {
ifacerefp->ifacep()->user1(1);
}
}
}
}
}
}
public:
// CONSTRUCTORS
DeadVisitor(AstNetlist* nodep, bool elimUserVars, bool elimDTypes, bool elimScopes,
bool elimCells)
bool elimCells, bool elimTopIfaces)
: m_elimUserVars{elimUserVars}
, m_elimDTypes{elimDTypes}
, m_elimCells{elimCells} {
@ -448,6 +484,7 @@ public:
if (elimCells) deadCheckCells();
deadCheckClasses();
// Modules after vars, because might be vars we delete inside a mod we delete
if (!elimTopIfaces) preserveTopIfaces(nodep);
deadCheckMod();
// We may have removed some datatypes, cleanup
@ -461,30 +498,32 @@ public:
void V3Dead::deadifyModules(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor{nodep, false, false, false, false}; } // Destruct before checking
{
DeadVisitor{nodep, false, false, false, false, !v3Global.opt.topIfacesSupported()};
} // Destruct before checking
V3Global::dumpCheckGlobalTree("deadModules", 0, dumpTree() >= 6);
}
void V3Dead::deadifyDTypes(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor{nodep, false, true, false, false}; } // Destruct before checking
{ DeadVisitor{nodep, false, true, false, false, false}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadDtypes", 0, dumpTree() >= 3);
}
void V3Dead::deadifyDTypesScoped(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor{nodep, false, true, true, false}; } // Destruct before checking
{ DeadVisitor{nodep, false, true, true, false, false}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0, dumpTree() >= 3);
}
void V3Dead::deadifyAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor{nodep, true, true, false, true}; } // Destruct before checking
{ DeadVisitor{nodep, true, true, false, true, false}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadAll", 0, dumpTree() >= 3);
}
void V3Dead::deadifyAllScoped(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor{nodep, true, true, true, true}; } // Destruct before checking
{ DeadVisitor{nodep, true, true, true, true, false}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadAllScoped", 0, dumpTree() >= 3);
}

View File

@ -93,8 +93,11 @@ string V3Global::digitsFilename(int number) {
}
void V3Global::dumpCheckGlobalTree(const string& stagename, int newNumber, bool doDump) {
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename(stagename + ".tree", newNumber), false,
doDump);
const string treeFilename = v3Global.debugFilename(stagename + ".tree", newNumber);
v3Global.rootp()->dumpTreeFile(treeFilename, false, doDump);
if (v3Global.opt.dumpTreeDot()) {
v3Global.rootp()->dumpTreeDotFile(treeFilename + ".dot", false, doDump);
}
if (v3Global.opt.stats()) V3Stats::statsStage(stagename);
}

View File

@ -178,7 +178,10 @@ private:
std::vector<V3GraphVertex*> m_callTrace; // List of everything we hit processing so far
void main() {
// Use Tarjan's algorithm to find the strongly connected subgraphs.
// Use Pearce's algorithm to color the strongly connected components. For reference see
// "An Improved Algorithm for Finding the Strongly Connected Components of a Directed
// Graph", David J.Pearce, 2005
//
// Node State:
// Vertex::user // DFS number indicating possible root of subtree, 0=not iterated
// Vertex::color // Output subtree number (fully processed)

View File

@ -308,6 +308,19 @@ public:
if (forScopeCreation()) m_nameScopeSymMap.emplace(scopename, symp);
return symp;
}
VSymEnt* insertTopIface(AstCell* nodep, const string& scopename) {
VSymEnt* const symp = new VSymEnt{&m_syms, nodep};
UINFO(9, " INSERTtopiface se" << cvtToHex(symp) << " " << scopename << " " << nodep
<< endl);
symp->parentp(rootEntp()); // Needed so backward search can find name of top module
symp->fallbackp(dunitEntp()); // Needed so can find $unit stuff
nodep->user1p(symp);
if (nodep->modp()) nodep->modp()->user1p(symp);
checkDuplicate(rootEntp(), nodep, nodep->origName());
rootEntp()->insert(nodep->origName(), symp);
if (forScopeCreation()) m_nameScopeSymMap.emplace(scopename, symp);
return symp;
}
VSymEnt* insertCell(VSymEnt* abovep, VSymEnt* modSymp, AstCell* nodep,
const string& scopename) {
UASSERT_OBJ(abovep, nodep, "Null symbol table inserting node");
@ -764,8 +777,55 @@ class LinkDotFindVisitor final : public VNVisitor {
modp = VN_AS(modp->nextp(), NodeModule)) {
UINFO(8, "Top Module: " << modp << endl);
m_scope = "TOP";
if (m_statep->forPrearray() && v3Global.opt.topIfacesSupported()) {
for (AstNode* subnodep = modp->stmtsp(); subnodep; subnodep = subnodep->nextp()) {
if (AstVar* const varp = VN_CAST(subnodep, Var)) {
if (varp->isIfaceRef()) {
const AstNodeDType* const subtypep = varp->subDTypep();
const AstIfaceRefDType* ifacerefp = nullptr;
if (VN_IS(subtypep, IfaceRefDType)) {
ifacerefp = VN_AS(varp->subDTypep(), IfaceRefDType);
} else if (VN_IS(subtypep, BracketArrayDType)) {
const AstBracketArrayDType* const arrp
= VN_AS(subtypep, BracketArrayDType);
const AstNodeDType* const arrsubtypep = arrp->subDTypep();
if (VN_IS(arrsubtypep, IfaceRefDType)) {
ifacerefp = VN_AS(arrsubtypep, IfaceRefDType);
}
} else if (VN_IS(subtypep, UnpackArrayDType)) {
const AstUnpackArrayDType* const arrp
= VN_AS(subtypep, UnpackArrayDType);
const AstNodeDType* const arrsubtypep = arrp->subDTypep();
if (VN_IS(arrsubtypep, IfaceRefDType)) {
ifacerefp = VN_AS(arrsubtypep, IfaceRefDType);
}
}
if (ifacerefp && !ifacerefp->cellp()) {
// A dummy cell to keep the top level interface alive and correctly
// optimized for default parameter values
AstCell* ifacecellp
= new AstCell{nodep->fileline(),
nodep->fileline(),
modp->name() + "__02E" + varp->name(),
ifacerefp->ifaceName(),
nullptr,
nullptr,
nullptr};
ifacecellp->modp(ifacerefp->ifacep());
m_curSymp = m_modSymp
= m_statep->insertTopIface(ifacecellp, m_scope);
{ iterate(ifacecellp); }
}
}
}
}
}
m_curSymp = m_modSymp = m_statep->insertTopCell(modp, m_scope);
{ iterate(modp); }
m_scope = "";
m_curSymp = m_modSymp = nullptr;
}

View File

@ -199,6 +199,36 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
} else {
ioNames.insert(oldvarp->name());
}
} else if (v3Global.opt.topIfacesSupported() && oldvarp->isIfaceRef()) {
const AstNodeDType* const subtypep = oldvarp->subDTypep();
if (VN_IS(subtypep, IfaceRefDType)) {
const AstIfaceRefDType* const ifacerefp = VN_AS(subtypep, IfaceRefDType);
if (!ifacerefp->cellp()) {
if (ioNames.find(oldvarp->name()) != ioNames.end()) {
// UINFO(8, "Multitop dup interface found: " << oldvarp << endl);
dupNames.insert(oldvarp->name());
} else {
ioNames.insert(oldvarp->name());
}
}
}
if (VN_IS(subtypep, UnpackArrayDType)) {
const AstUnpackArrayDType* const arrp = VN_AS(subtypep, UnpackArrayDType);
const AstNodeDType* const arrsubtypep = arrp->subDTypep();
if (VN_IS(arrsubtypep, IfaceRefDType)) {
const AstIfaceRefDType* const ifacerefp
= VN_AS(arrsubtypep, IfaceRefDType);
if (!ifacerefp->cellp()) {
if (ioNames.find(oldvarp->name()) != ioNames.end()) {
// UINFO(8, "Multitop dup interface array found: " << oldvarp
// << endl);
dupNames.insert(oldvarp->name());
} else {
ioNames.insert(oldvarp->name());
}
}
}
}
}
}
}
@ -256,6 +286,104 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
// Skip length and width comp; we know it's a direct assignment
pinp->modVarp(oldvarp);
cellp->addPinsp(pinp);
} else if (v3Global.opt.topIfacesSupported() && oldvarp->isIfaceRef()) {
// for each interface port on oldmodp instantiate a corresponding interface
// cell in $root
const AstNodeDType* const subtypep = oldvarp->subDTypep();
if (VN_IS(subtypep, IfaceRefDType)) {
const AstIfaceRefDType* const ifacerefp = VN_AS(subtypep, IfaceRefDType);
if (!ifacerefp->cellp()) {
string name = oldvarp->name();
if (dupNames.find(name) != dupNames.end()) {
// __02E=. while __DOT__ looks nicer but will break V3LinkDot
name = oldmodp->name() + "__02E" + name;
}
AstCell* ifacecellp = new AstCell{newmodp->fileline(),
newmodp->fileline(),
name,
ifacerefp->ifaceName(),
nullptr,
nullptr,
nullptr};
ifacecellp->modp(ifacerefp->ifacep());
newmodp->addStmtsp(ifacecellp);
AstIfaceRefDType* const idtypep = new AstIfaceRefDType{
newmodp->fileline(), name, ifacerefp->ifaceName()};
idtypep->ifacep(nullptr);
idtypep->dtypep(idtypep);
idtypep->cellp(ifacecellp);
rootp->typeTablep()->addTypesp(idtypep);
AstVar* varp = new AstVar{newmodp->fileline(), VVarType::IFACEREF,
name + "__Viftop", idtypep};
varp->isIfaceParent(true);
ifacecellp->addNextHere(varp);
ifacecellp->hasIfaceVar(true);
AstPin* const pinp
= new AstPin{oldvarp->fileline(), 0, varp->name(),
new AstVarRef{varp->fileline(), varp,
oldvarp->isWritable() ? VAccess::WRITE
: VAccess::READ}};
pinp->modVarp(oldvarp);
cellp->addPinsp(pinp);
}
} else if (VN_IS(subtypep, UnpackArrayDType)) {
const AstUnpackArrayDType* const oldarrp
= VN_AS(subtypep, UnpackArrayDType);
const AstNodeDType* const arrsubtypep = oldarrp->subDTypep();
if (VN_IS(arrsubtypep, IfaceRefDType)) {
const AstIfaceRefDType* const ifacerefp
= VN_AS(arrsubtypep, IfaceRefDType);
if (!ifacerefp->cellp()) {
string name = oldvarp->name();
if (dupNames.find(name) != dupNames.end()) {
// __02E=. while __DOT__ looks nicer but will break V3LinkDot
name = oldmodp->name() + "__02E" + name;
}
AstUnpackArrayDType* arraydtypep
= VN_AS(oldvarp->dtypep(), UnpackArrayDType);
AstCell* ifacearraycellp
= new AstCell{newmodp->fileline(),
newmodp->fileline(),
name,
ifacerefp->ifaceName(),
nullptr,
nullptr,
arraydtypep->rangep()->cloneTree(true)};
ifacearraycellp->modp(ifacerefp->ifacep());
newmodp->addStmtsp(ifacearraycellp);
AstIfaceRefDType* const idtypep = new AstIfaceRefDType{
newmodp->fileline(), name, ifacerefp->ifaceName()};
idtypep->ifacep(nullptr);
idtypep->dtypep(idtypep);
idtypep->cellp(ifacearraycellp);
rootp->typeTablep()->addTypesp(idtypep);
AstNodeArrayDType* const arrp = new AstUnpackArrayDType{
newmodp->fileline(), idtypep,
arraydtypep->rangep()->cloneTree(true)};
AstVar* varp = new AstVar{newmodp->fileline(), VVarType::IFACEREF,
name + "__Viftop", arrp};
varp->isIfaceParent(true);
ifacearraycellp->addNextHere(varp);
ifacearraycellp->hasIfaceVar(true);
rootp->typeTablep()->addTypesp(arrp);
AstPin* const pinp = new AstPin{
oldvarp->fileline(), 0, varp->name(),
new AstVarRef{varp->fileline(), varp,
oldvarp->isWritable() ? VAccess::WRITE
: VAccess::READ}};
pinp->modVarp(oldvarp);
cellp->addPinsp(pinp);
}
}
}
}
}
}

View File

@ -281,7 +281,7 @@ private:
nodep->valuep()->unlinkFrBack()));
}
}
if (nodep->isIfaceRef() && !nodep->isIfaceParent()) {
if (nodep->isIfaceRef() && !nodep->isIfaceParent() && !v3Global.opt.topIfacesSupported()) {
// Only AstIfaceRefDType's at this point correspond to ports;
// haven't made additional ones for interconnect yet, so assert is simple
// What breaks later is we don't have a Scope/Cell representing

View File

@ -828,6 +828,11 @@ void V3Options::notify() {
// Mark options as available
m_available = true;
// --dump-tree-dot will turn on tree dumping.
if (!m_dumpLevel.count("tree") && m_dumpLevel.count("tree-dot")) {
m_dumpLevel["tree"] = m_dumpLevel["tree-dot"];
}
}
//######################################################################

View File

@ -458,6 +458,9 @@ public:
bool decoration() const { return m_decoration; }
bool dpiHdrOnly() const { return m_dpiHdrOnly; }
bool dumpDefines() const { return m_dumpLevel.count("defines") && m_dumpLevel.at("defines"); }
bool dumpTreeDot() const {
return m_dumpLevel.count("tree-dot") && m_dumpLevel.at("tree-dot");
}
bool exe() const { return m_exe; }
bool flatten() const { return m_flatten; }
bool gmake() const { return m_gmake; }
@ -494,6 +497,7 @@ public:
bool vpi() const { return m_vpi; }
bool xInitialEdge() const { return m_xInitialEdge; }
bool xmlOnly() const { return m_xmlOnly; }
bool topIfacesSupported() const { return lintOnly() && !hierarchical(); }
int buildJobs() const { return m_buildJobs; }
int convergeLimit() const { return m_convergeLimit; }

View File

@ -493,6 +493,47 @@ class TristateVisitor final : public TristateBaseVisitor {
}
return VN_AS(invarp->user1p(), Var);
}
AstConst* getNonZConstp(AstConst* const constp) {
FileLine* const fl = constp->fileline();
V3Number numz{constp, constp->width()};
numz.opBitsZ(constp->num()); // Z->1, else 0
V3Number numz0{constp, constp->width()};
numz0.opNot(numz); // Z->0, else 1
return new AstConst{fl, numz0};
}
AstNode* getEnExprBasedOnOriginalp(AstNode* const nodep) {
if (AstVarRef* const varrefp = VN_CAST(nodep, VarRef)) {
return new AstVarRef{varrefp->fileline(), getCreateEnVarp(varrefp->varp()),
VAccess::READ};
} else if (AstConst* const constp = VN_CAST(nodep, Const)) {
return getNonZConstp(constp);
} else if (AstExtend* const extendp = VN_CAST(nodep, Extend)) {
// Extend inserts 0 at the beginning. 0 in __en variable means that this bit equals z,
// so in order to preserve the value of the original AstExtend node we should insert 1
// instead of 0. To extend __en expression we have to negate its lhsp() and then negate
// whole extend.
// Unlink lhsp before copying to save unnecessary copy of lhsp
AstNode* const lhsp = extendp->lhsp()->unlinkFrBack();
AstExtend* const enExtendp = extendp->cloneTree(false);
extendp->lhsp(lhsp);
AstNode* const enLhsp = getEnExprBasedOnOriginalp(lhsp);
enExtendp->lhsp(new AstNot{enLhsp->fileline(), enLhsp});
return new AstNot{enExtendp->fileline(), enExtendp};
} else if (AstSel* const selp = VN_CAST(nodep, Sel)) {
AstNode* const fromp = selp->fromp()->unlinkFrBack();
AstSel* const enSelp = selp->cloneTree(false);
selp->fromp(fromp);
AstNode* const enFromp = getEnExprBasedOnOriginalp(fromp);
enSelp->fromp(enFromp);
return enSelp;
} else {
nodep->v3warn(E_UNSUPPORTED,
"Unsupported tristate construct: " << nodep->prettyTypeName()
<< " in function " << __func__);
return nullptr;
}
}
AstVar* getCreateOutVarp(AstVar* invarp) {
// Return the master __out for the specified input variable
if (!invarp->user4p()) {
@ -959,14 +1000,10 @@ class TristateVisitor final : public TristateBaseVisitor {
} else if (m_tgraph.isTristate(nodep)) {
m_tgraph.didProcess(nodep);
FileLine* const fl = nodep->fileline();
V3Number numz(nodep, nodep->width());
numz.opBitsZ(nodep->num()); // Z->1, else 0
V3Number numz0(nodep, nodep->width());
numz0.opNot(numz); // Z->0, else 1
V3Number num1(nodep, nodep->width());
num1.opAnd(nodep->num(), numz0); // 01X->01X, Z->0
AstConst* const newconstp = new AstConst(fl, num1);
AstConst* const enp = new AstConst(fl, numz0);
AstConst* const enp = getNonZConstp(nodep);
V3Number num1{nodep, nodep->width()};
num1.opAnd(nodep->num(), enp->num()); // 01X->01X, Z->0
AstConst* const newconstp = new AstConst{fl, num1};
nodep->replaceWith(newconstp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
newconstp->user1p(enp); // Propagate up constant with non-Z bits as 1
@ -1263,23 +1300,27 @@ class TristateVisitor final : public TristateBaseVisitor {
UINFO(9, dbgState() << nodep << endl);
// Constification always moves const to LHS
AstConst* const constp = VN_CAST(nodep->lhsp(), Const);
AstVarRef* const varrefp = VN_CAST(nodep->rhsp(), VarRef); // Input variable
if (constp && constp->user1p() && varrefp) {
if (constp && constp->user1p()) {
// 3'b1z0 -> ((3'b101 == in__en) && (3'b100 == in))
varrefp->unlinkFrBack();
AstNode* const rhsp = nodep->rhsp();
rhsp->unlinkFrBack();
FileLine* const fl = nodep->fileline();
AstNode* enRhsp;
if (rhsp->user1p()) {
enRhsp = rhsp->user1p();
rhsp->user1p(nullptr);
} else {
enRhsp = getEnExprBasedOnOriginalp(rhsp);
}
const V3Number oneIfEn
= VN_AS(constp->user1p(), Const)
->num(); // visit(AstConst) already split into en/ones
const V3Number& oneIfEnOne = constp->num();
AstVar* const envarp = getCreateEnVarp(varrefp->varp());
AstNode* newp
= new AstLogAnd(fl,
new AstEq(fl, new AstConst(fl, oneIfEn),
new AstVarRef(fl, envarp, VAccess::READ)),
= new AstLogAnd{fl, new AstEq{fl, new AstConst{fl, oneIfEn}, enRhsp},
// Keep the caseeq if there are X's present
new AstEqCase(fl, new AstConst(fl, oneIfEnOne), varrefp));
if (neq) newp = new AstLogNot(fl, newp);
new AstEqCase{fl, new AstConst{fl, oneIfEnOne}, rhsp}};
if (neq) newp = new AstLogNot{fl, newp};
UINFO(9, " newceq " << newp << endl);
if (debug() >= 9) nodep->dumpTree(cout, "-caseeq-old: ");
if (debug() >= 9) newp->dumpTree(cout, "-caseeq-new: ");

View File

@ -0,0 +1,20 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 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
scenarios(vlt => 1);
top_filename("t/t_EXAMPLE.v");
lint(
v_flags => ["--lint-only --dump-tree-dot"],
);
ok(1);
1;

View File

@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
scenarios(vlt => 1);
lint(
compile(
fails => 1,
expect_filename => $Self->{golden_filename},
);

View File

@ -0,0 +1,16 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2008 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
scenarios(linter => 1);
lint();
ok(1);
1;

View File

@ -0,0 +1,48 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2017 by Josh Redford.
// SPDX-License-Identifier: CC0-1.0
interface my_if;
logic valid;
logic [7:0] data ;
modport slave_mp (
input valid,
input data
);
modport master_mp (
output valid,
output data
);
endinterface
module t
(
input wire clk,
my_if.slave_mp in_if [2],
my_if.master_mp out_if [2]
);
my_if my_i [2] ();
always @(posedge clk)
begin
my_i[0].valid <= in_if[0].valid;
my_i[0].data <= in_if[0].data;
my_i[1].valid <= in_if[1].valid;
my_i[1].data <= in_if[1].data;
end
assign out_if[0].valid = my_i[0].valid;
assign out_if[0].data = my_i[0].data;
assign out_if[1].valid = my_i[1].valid;
assign out_if[1].data = my_i[1].data;
endmodule

View File

@ -0,0 +1,16 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2008 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
scenarios(linter => 1);
lint();
ok(1);
1;

View File

@ -0,0 +1,39 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2017 by Josh Redford.
// SPDX-License-Identifier: CC0-1.0
interface my_if #(
parameter DW = 8
) ();
logic valid;
logic [DW-1:0] data ;
modport slave_mp (
input valid,
input data
);
modport master_mp (
output valid,
output data
);
endinterface
module t
(
input wire clk,
my_if.slave_mp in_if [2],
my_if.master_mp out_if [2]
);
assign out_if[0].valid = in_if[0].valid;
assign out_if[0].data = in_if[0].data;
assign out_if[1].valid = in_if[1].valid;
assign out_if[1].data = in_if[1].data;
endmodule

View File

@ -0,0 +1,16 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2008 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
scenarios(linter => 1);
lint();
ok(1);
1;

View File

@ -0,0 +1,77 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2017 by Josh Redford.
// SPDX-License-Identifier: CC0-1.0
interface my_if #( parameter integer DW = 8 ) (input clk);
localparam DW_LOCAL = DW;
logic valid;
logic [DW-1:0] data;
modport slave_mp (
input valid,
input data
);
modport master_mp (
output valid,
output data
);
function automatic integer width();
return $bits(data);
endfunction
generate
if (DW < 4)
begin: dw_lt_4_G
function automatic integer min_width();
return 4;
endfunction
end
else
begin: dw_ge_4_G
function automatic integer min_width();
return 8;
endfunction
end
endgenerate
endinterface
module t
(
input wire clk,
my_if in_if [2],
my_if out_if [2]
);
assign out_if[0].valid = in_if[0].valid;
assign out_if[0].data = in_if[0].data;
assign out_if[1].valid = in_if[1].valid;
assign out_if[1].data = in_if[1].data;
my_if my_i (.clk(clk));
initial
begin
$display(in_if[0].DW_LOCAL);
$display(in_if[0].width());
$display(in_if[0].dw_ge_4_G.min_width());
$display(out_if[0].DW_LOCAL);
$display(out_if[0].width());
$display(out_if[0].dw_ge_4_G.min_width());
$display(in_if[1].DW_LOCAL);
$display(in_if[1].width());
$display(in_if[1].dw_ge_4_G.min_width());
$display(out_if[1].DW_LOCAL);
$display(out_if[1].width());
$display(out_if[1].dw_ge_4_G.min_width());
end
endmodule

View File

@ -0,0 +1,5 @@
%Error: t/t_lint_iface_array_topmodule_bad.v:8:24: Parameter without initial value is never given value (IEEE 1800-2017 6.20.1): 'DW'
: ... In instance t
8 | parameter integer DW
| ^~
%Error: Exiting due to

View File

@ -0,0 +1,19 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2008 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
scenarios(linter => 1);
lint(
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,50 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2017 by Josh Redford.
// SPDX-License-Identifier: CC0-1.0
interface my_if #(
parameter integer DW
) ();
logic valid;
logic [7:0] data ;
modport slave_mp (
input valid,
input data
);
modport master_mp (
output valid,
output data
);
endinterface
module t
(
input wire clk,
my_if.slave_mp in_if [2],
my_if.master_mp out_if [2]
);
my_if my_i [2] ();
always @(posedge clk)
begin
my_i[0].valid <= in_if[0].valid;
my_i[0].data <= in_if[0].data;
my_i[1].valid <= in_if[1].valid;
my_i[1].data <= in_if[1].data;
end
assign out_if[0].valid = my_i[0].valid;
assign out_if[0].data = my_i[0].data;
assign out_if[1].valid = my_i[1].valid;
assign out_if[1].data = my_i[1].data;
endmodule

View File

@ -0,0 +1,16 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2008 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
scenarios(linter => 1);
lint();
ok(1);
1;

View File

@ -0,0 +1,42 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2017 by Josh Redford.
// SPDX-License-Identifier: CC0-1.0
interface my_if;
logic valid;
logic [7:0] data ;
modport slave_mp (
input valid,
input data
);
modport master_mp (
output valid,
output data
);
endinterface
module t
(
input wire clk,
my_if.slave_mp in_if,
my_if.master_mp out_if
);
my_if my_i ();
always @(posedge clk)
begin
my_i.valid <= in_if.valid;
my_i.data <= in_if.data;
end
assign out_if.valid = my_i.valid;
assign out_if.data = my_i.data;
endmodule

View File

@ -0,0 +1,16 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2008 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
scenarios(linter => 1);
lint();
ok(1);
1;

View File

@ -0,0 +1,35 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2017 by Josh Redford.
// SPDX-License-Identifier: CC0-1.0
interface my_if #(
parameter integer DW = 8
) ();
logic valid;
logic [DW-1:0] data;
modport slave_mp (
input valid,
input data
);
modport master_mp (
output valid,
output data
);
endinterface
module t
(
input wire clk,
my_if.slave_mp in_if,
my_if.master_mp out_if
);
assign out_if.valid = in_if.valid;
assign out_if.data = in_if.data;
endmodule

View File

@ -0,0 +1,16 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2008 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
scenarios(linter => 1);
lint();
ok(1);
1;

View File

@ -0,0 +1,67 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2017 by Josh Redford.
// SPDX-License-Identifier: CC0-1.0
interface my_if #( parameter integer DW = 8 ) (input clk);
localparam DW_LOCAL = DW;
logic valid;
logic [DW-1:0] data;
modport slave_mp (
input valid,
input data
);
modport master_mp (
output valid,
output data
);
function automatic integer width();
return $bits(data);
endfunction
generate
if (DW < 4)
begin: dw_lt_4_G
function automatic integer min_width();
return 4;
endfunction
end
else
begin: dw_ge_4_G
function automatic integer min_width();
return 8;
endfunction
end
endgenerate
endinterface
module t
(
input wire clk,
my_if in_if,
my_if out_if
);
assign out_if.valid = in_if.valid;
assign out_if.data = in_if.data;
my_if my_i (.clk(clk));
initial
begin
$display(in_if.DW_LOCAL);
$display(in_if.width());
$display(in_if.dw_ge_4_G.min_width());
$display(out_if.DW_LOCAL);
$display(out_if.width());
$display(out_if.dw_ge_4_G.min_width());
end
endmodule

View File

@ -0,0 +1,5 @@
%Error: t/t_lint_iface_topmodule_bad.v:8:23: Parameter without initial value is never given value (IEEE 1800-2017 6.20.1): 'DW'
: ... In instance t
8 | parameter integer DW
| ^~
%Error: Exiting due to

View File

@ -0,0 +1,19 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2008 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
scenarios(linter => 1);
lint(
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,44 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2017 by Josh Redford.
// SPDX-License-Identifier: CC0-1.0
interface my_if #(
parameter integer DW
) ();
logic valid;
logic [DW-1:0] data ;
modport slave_mp (
input valid,
input data
);
modport master_mp (
output valid,
output data
);
endinterface
module t
(
input wire clk,
my_if.slave_mp in_if,
my_if.master_mp out_if
);
my_if my_i ();
always @(posedge clk)
begin
my_i.valid <= in_if.valid;
my_i.data <= in_if.data;
end
assign out_if.valid = my_i.valid;
assign out_if.data = my_i.data;
endmodule

View File

@ -0,0 +1,8 @@
%Error-UNSUPPORTED: t/t_tri_and_eqcase.v:9:28: Unsupported tristate construct: AND in function getEnExprBasedOnOriginalp
9 | logic b = 1'z === (clk1 & clk2);
| ^
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: Internal Error: t/t_tri_and_eqcase.v:9:18: ../V3Ast.cpp:#: Null item passed to setOp2p
9 | logic b = 1'z === (clk1 & clk2);
| ^~~
... See the manual at https://verilator.org/verilator_doc.html for more assistance.

View File

@ -0,0 +1,19 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 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
scenarios(vlt => 1);
lint(
fails => $Self->{vlt_all},
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,17 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2022 by Antmicro Ltd.
// SPDX-License-Identifier: CC0-1.0
module t (clk1, clk2);
input wire clk1, clk2;
logic b = 1'z === (clk1 & clk2);
always begin
if (!b) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule

View File

@ -0,0 +1,21 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2022 by Antmicro Ltd. 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
scenarios(simulator => 1);
compile(
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -0,0 +1,26 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2022 by Antmicro Ltd.
// SPDX-License-Identifier: CC0-1.0
module t (/*AUTOARG*/);
wire [3:0] a = 4'b11z1;
logic b = 1'bz === a[1];
logic c = 1'bz === a[2];
logic d = 2'bzz === 2'(a[1]);
logic e = 2'b0z === 2'(a[1]);
always begin
if (b && !c && !d && e) begin
$write("*-* All Finished *-*\n");
$finish;
end
else begin
$write("Error: b = %b, c = %b, d = %b, e = %b ", b, c, d, e);
$write("expected: b = 1, c = 0, d = 0, e = 1\n");
$stop;
end
end
endmodule