From cd1fe64e6c3296d4724b17c20d70296e93ab13fd Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 16 Sep 2023 21:46:01 -0400 Subject: [PATCH 001/157] devel release --- CMakeLists.txt | 2 +- Changes | 7 +++++++ configure.ac | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c600a850..87a695c0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ cmake_minimum_required(VERSION 3.15) cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime project(Verilator - VERSION 5.016 + VERSION 5.017 HOMEPAGE_URL https://verilator.org LANGUAGES CXX ) diff --git a/Changes b/Changes index 2a6f93e02..9c86598cf 100644 --- a/Changes +++ b/Changes @@ -8,6 +8,13 @@ The changes in each Verilator version are described below. The contributors that suggested a given feature are shown in []. Thanks! +Verilator 5.017 devel +========================== + +**Minor:** + + + Verilator 5.016 2023-09-16 ========================== diff --git a/configure.ac b/configure.ac index c10eadcd1..c530489f3 100644 --- a/configure.ac +++ b/configure.ac @@ -10,7 +10,7 @@ # Then 'make maintainer-dist' #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[5.016 2023-09-16], +AC_INIT([Verilator],[5.017 devel], [https://verilator.org], [verilator],[https://verilator.org]) From 761adf1cf01eaa1a2fa927f63719b67ed17e48b4 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 16 Sep 2023 22:50:54 -0400 Subject: [PATCH 002/157] Internals: Add cloneTreePure to prepare for side effect check. Use cloneTreePure when what is being cloned must be side-effect free. Use cloneTree when safe to contain side effects (e.g. cloning module). --- src/V3Assert.cpp | 16 +++---- src/V3AssertPre.cpp | 16 +++---- src/V3Ast.h | 3 +- src/V3AstNodeExpr.h | 6 +-- src/V3AstNodes.cpp | 4 +- src/V3Case.cpp | 12 ++--- src/V3Const.cpp | 26 +++++------ src/V3Delayed.cpp | 2 +- src/V3DfgDfgToAst.cpp | 4 +- src/V3Expand.cpp | 54 ++++++++++----------- src/V3Force.cpp | 8 ++-- src/V3Gate.cpp | 11 +++-- src/V3LinkInc.cpp | 6 +-- src/V3MergeCond.cpp | 4 +- src/V3Premit.cpp | 12 ++--- src/V3Randomize.cpp | 2 +- src/V3Slice.cpp | 9 ++-- src/V3Split.cpp | 2 + src/V3SplitAs.cpp | 3 ++ src/V3Subst.cpp | 2 +- src/V3Tristate.cpp | 26 +++++------ src/V3Unknown.cpp | 10 ++-- src/V3Width.cpp | 26 ++++++----- src/astgen | 3 ++ src/verilog.y | 106 +++++++++++++++++++++--------------------- 25 files changed, 193 insertions(+), 180 deletions(-) diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 59fd8ede5..e010215d9 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -243,7 +243,7 @@ private: } // Build a bitmask of the true predicates - AstNodeExpr* const predp = ifp->condp()->cloneTree(false); + AstNodeExpr* const predp = ifp->condp()->cloneTreePure(false); if (propp) { propp = new AstConcat{nodep->fileline(), predp, propp}; } else { @@ -312,17 +312,17 @@ private: icondp = VN_AS(icondp->nextp(), NodeExpr)) { AstNodeExpr* onep; if (AstInsideRange* const rcondp = VN_CAST(icondp, InsideRange)) { - onep = rcondp->newAndFromInside(nodep->exprp(), - rcondp->lhsp()->cloneTree(true), - rcondp->rhsp()->cloneTree(true)); + onep = rcondp->newAndFromInside( + nodep->exprp(), rcondp->lhsp()->cloneTreePure(true), + rcondp->rhsp()->cloneTreePure(true)); } else if (nodep->casex() || nodep->casez() || nodep->caseInside()) { onep = AstEqWild::newTyped(itemp->fileline(), - nodep->exprp()->cloneTree(false), - icondp->cloneTree(false)); + nodep->exprp()->cloneTreePure(false), + icondp->cloneTreePure(false)); } else { onep = AstEq::newTyped(icondp->fileline(), - nodep->exprp()->cloneTree(false), - icondp->cloneTree(false)); + nodep->exprp()->cloneTreePure(false), + icondp->cloneTreePure(false)); } if (propp) { propp = new AstConcat{icondp->fileline(), onep, propp}; diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp index 341204593..766d454d1 100644 --- a/src/V3AssertPre.cpp +++ b/src/V3AssertPre.cpp @@ -177,7 +177,7 @@ private: if (nodep->direction() == VDirection::OUTPUT) { AstVarRef* const skewedRefp = new AstVarRef{flp, varp, VAccess::READ}; skewedRefp->user1(true); - AstAssign* const assignp = new AstAssign{flp, exprp->cloneTree(false), skewedRefp}; + AstAssign* const assignp = new AstAssign{flp, exprp->cloneTreePure(false), skewedRefp}; if (skewp->isZero()) { // Drive the var in Re-NBA (IEEE 1800-2017 14.16) m_clockingp->addNextHere(new AstAlwaysReactive{ @@ -208,12 +208,12 @@ private: refp->user1(true); if (skewp->num().is1Step()) { // Assign the sampled expression to the clockvar (IEEE 1800-2017 14.13) - AstSampled* const sampledp = new AstSampled{flp, exprp->cloneTree(false)}; + AstSampled* const sampledp = new AstSampled{flp, exprp->cloneTreePure(false)}; sampledp->dtypeFrom(exprp); m_clockingp->addNextHere(new AstAssignW{flp, refp, sampledp}); } else if (skewp->isZero()) { // #0 means the var has to be sampled in Observed (IEEE 1800-2017 14.13) - AstAssign* const assignp = new AstAssign{flp, refp, exprp->cloneTree(false)}; + AstAssign* const assignp = new AstAssign{flp, refp, exprp->cloneTreePure(false)}; m_clockingp->addNextHere(new AstAlwaysObserved{ flp, new AstSenTree{flp, m_clockingp->sensesp()->cloneTree(false)}, assignp}); } else { @@ -230,7 +230,7 @@ private: AstCMethodHard* const pushp = new AstCMethodHard{ flp, new AstVarRef{flp, queueVarp, VAccess::WRITE}, "push", new AstTime{nodep->fileline(), m_modp->timeunit()}}; - pushp->addPinsp(exprp->cloneTree(false)); + pushp->addPinsp(exprp->cloneTreePure(false)); pushp->dtypeSetVoid(); m_clockingp->addNextHere( new AstAlways{flp, VAlwaysKwd::ALWAYS, nullptr, pushp->makeStmt()}); @@ -372,7 +372,7 @@ private: if (sentreep) sentreep->unlinkFrBack(); AstNodeExpr* const past = new AstPast{fl, exprp, nullptr}; past->dtypeFrom(exprp); - exprp = new AstAnd{fl, past, new AstNot{fl, exprp->cloneTree(false)}}; + exprp = new AstAnd{fl, past, new AstNot{fl, exprp->cloneTreePure(false)}}; exprp->dtypeSetBit(); nodep->replaceWith(exprp); nodep->sentreep(newSenTree(nodep, sentreep)); @@ -393,7 +393,7 @@ private: if (sentreep) sentreep->unlinkFrBack(); AstNodeExpr* const past = new AstPast{fl, exprp, nullptr}; past->dtypeFrom(exprp); - exprp = new AstAnd{fl, new AstNot{fl, past}, exprp->cloneTree(false)}; + exprp = new AstAnd{fl, new AstNot{fl, past}, exprp->cloneTreePure(false)}; exprp->dtypeSetBit(); nodep->replaceWith(exprp); nodep->sentreep(newSenTree(nodep, sentreep)); @@ -408,7 +408,7 @@ private: if (sentreep) sentreep->unlinkFrBack(); AstNodeExpr* const past = new AstPast{fl, exprp, nullptr}; past->dtypeFrom(exprp); - exprp = new AstEq{fl, past, exprp->cloneTree(false)}; + exprp = new AstEq{fl, past, exprp->cloneTreePure(false)}; exprp->dtypeSetBit(); nodep->replaceWith(exprp); nodep->sentreep(newSenTree(nodep, sentreep)); @@ -442,7 +442,7 @@ private: // Block is the new expression to evaluate AstNodeExpr* blockp = VN_AS(nodep->propp()->unlinkFrBack(), NodeExpr); if (AstNodeExpr* const disablep = nodep->disablep()) { - m_disablep = disablep->cloneTree(false); + m_disablep = disablep->cloneTreePure(false); if (VN_IS(nodep->backp(), Cover)) { blockp = new AstAnd{disablep->fileline(), new AstNot{disablep->fileline(), disablep->unlinkFrBack()}, diff --git a/src/V3Ast.h b/src/V3Ast.h index b925d7f26..5de6ab906 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1998,7 +1998,8 @@ public: AstNode* belowp); // When calling, "this" is second argument // METHODS - Iterate on a tree - AstNode* cloneTree(bool cloneNextLink); // Not const, as sets clonep() on original nodep + AstNode* cloneTree(bool cloneNextLink); // Not const, as sets clonep() on original nodep // + AstNode* cloneTreePure(bool cloneNextLink) { return cloneTree(cloneNextLink); } bool gateTree() { return gateTreeIter(); } // Is tree isGateOptimizable? inline bool sameTree(const AstNode* node2p) const; // Does tree of this == node2p? // Does tree of this == node2p?, not allowing non-isGateOptimizable diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 4c4250b96..e5e44c785 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -4187,10 +4187,10 @@ class AstCountBits final : public AstNodeQuadop { // Number of bits set in vector public: AstCountBits(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* ctrl1p) - : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl1p->cloneTree(false), - ctrl1p->cloneTree(false)) {} + : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl1p->cloneTreePure(false), + ctrl1p->cloneTreePure(false)) {} AstCountBits(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* ctrl1p, AstNodeExpr* ctrl2p) - : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl2p->cloneTree(false)) {} + : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl2p->cloneTreePure(false)) {} AstCountBits(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* ctrl1p, AstNodeExpr* ctrl2p, AstNodeExpr* ctrl3p) : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl3p) {} diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index b08d56f9e..9a35b190b 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -279,8 +279,8 @@ AstExecGraph::~AstExecGraph() { VL_DO_DANGLING(delete m_depGraphp, m_depGraphp); AstNodeExpr* AstInsideRange::newAndFromInside(AstNodeExpr* exprp, AstNodeExpr* lhsp, AstNodeExpr* rhsp) { - AstNodeExpr* const ap = new AstGte{fileline(), exprp->cloneTree(true), lhsp}; - AstNodeExpr* const bp = new AstLte{fileline(), exprp->cloneTree(true), rhsp}; + AstNodeExpr* const ap = new AstGte{fileline(), exprp->cloneTreePure(true), lhsp}; + AstNodeExpr* const bp = new AstLte{fileline(), exprp->cloneTreePure(true), rhsp}; ap->fileline()->modifyWarnOff(V3ErrorCode::UNSIGNED, true); bp->fileline()->modifyWarnOff(V3ErrorCode::CMPCONST, true); return new AstAnd{fileline(), ap, bp}; diff --git a/src/V3Case.cpp b/src/V3Case.cpp index 8297c1b69..9110d9b93 100644 --- a/src/V3Case.cpp +++ b/src/V3Case.cpp @@ -362,10 +362,10 @@ private: // Alternate scheme if we ever do multiple bits at a time: // V3Number nummask (cexprp, cexprp->width(), (1UL<fileline(), cexprp->cloneTree(false), + // AstNode* and1p = new AstAnd(cexprp->fileline(), cexprp->cloneTreePure(false), // new AstConst(cexprp->fileline(), nummask)); AstNodeExpr* const and1p - = new AstSel{cexprp->fileline(), cexprp->cloneTree(false), msb, 1}; + = new AstSel{cexprp->fileline(), cexprp->cloneTreePure(false), msb, 1}; AstNodeExpr* const eqp = new AstNeq{cexprp->fileline(), new AstConst{cexprp->fileline(), 0}, and1p}; AstIf* const ifp = new AstIf{cexprp->fileline(), eqp, tree1p, tree0p}; @@ -450,7 +450,7 @@ private: V3Number numval{itemp, iconstp->width()}; numval.opBitsOne(iconstp->num()); AstNodeExpr* const and1p - = new AstAnd{itemp->fileline(), cexprp->cloneTree(false), + = new AstAnd{itemp->fileline(), cexprp->cloneTreePure(false), new AstConst{itemp->fileline(), nummask}}; AstNodeExpr* const and2p = new AstAnd{ itemp->fileline(), new AstConst{itemp->fileline(), numval}, @@ -460,7 +460,7 @@ private: condp = AstEq::newTyped(itemp->fileline(), and1p, and2p); } else { // Not a caseX mask, we can build CASEEQ(cexpr icond) - AstNodeExpr* const and1p = cexprp->cloneTree(false); + AstNodeExpr* const and1p = cexprp->cloneTreePure(false); AstNodeExpr* const and2p = icondp; condp = AstEq::newTyped(itemp->fileline(), and1p, and2p); } @@ -502,7 +502,7 @@ private: if (++depth > CASE_ENCODER_GROUP_DEPTH) depth = 1; if (depth == 1) { // First group or starting new group itemnextp = nullptr; - AstIf* const newp = new AstIf{itemp->fileline(), ifexprp->cloneTree(true)}; + AstIf* const newp = new AstIf{itemp->fileline(), ifexprp->cloneTreePure(true)}; if (groupnextp) { groupnextp->addElsesp(newp); } else { @@ -512,7 +512,7 @@ private: } else { // Continue group, modify if condition to OR in this new condition AstNodeExpr* const condp = groupnextp->condp()->unlinkFrBack(); groupnextp->condp( - new AstOr{ifexprp->fileline(), condp, ifexprp->cloneTree(true)}); + new AstOr{ifexprp->fileline(), condp, ifexprp->cloneTreePure(true)}); } } { // Make the new lower IF and attach in the tree diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 696fceb5e..888bd7780 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1494,13 +1494,13 @@ private: const AstSel* rselp = VN_CAST(rhsp, Sel); // a[i:0] a if (lselp && !rselp && rhsp->sameGateTree(lselp->fromp())) - rselp = new AstSel{rhsp->fileline(), rhsp->cloneTree(false), 0, rhsp->width()}; + rselp = new AstSel{rhsp->fileline(), rhsp->cloneTreePure(false), 0, rhsp->width()}; // a[i:j] {a[j-1:k], b} if (lselp && !rselp && VN_IS(rhsp, Concat)) return ifMergeAdjacent(lhsp, VN_CAST(rhsp, Concat)->lhsp()); // a a[msb:j] if (rselp && !lselp && lhsp->sameGateTree(rselp->fromp())) - lselp = new AstSel{lhsp->fileline(), lhsp->cloneTree(false), 0, lhsp->width()}; + lselp = new AstSel{lhsp->fileline(), lhsp->cloneTreePure(false), 0, lhsp->width()}; // {b, a[j:k]} a[k-1:i] if (rselp && !lselp && VN_IS(lhsp, Concat)) return ifMergeAdjacent(VN_CAST(lhsp, Concat)->rhsp(), rhsp); @@ -1812,10 +1812,10 @@ private: // {llp OP lrp, rlp OP rrp} => {llp, rlp} OP {lrp, rrp}, where OP = AND/OR/XOR AstNodeBiop* const lp = VN_AS(nodep->lhsp(), NodeBiop); AstNodeBiop* const rp = VN_AS(nodep->rhsp(), NodeBiop); - AstNodeExpr* const llp = lp->lhsp()->cloneTree(false); - AstNodeExpr* const lrp = lp->rhsp()->cloneTree(false); - AstNodeExpr* const rlp = rp->lhsp()->cloneTree(false); - AstNodeExpr* const rrp = rp->rhsp()->cloneTree(false); + AstNodeExpr* const llp = lp->lhsp()->cloneTreePure(false); + AstNodeExpr* const lrp = lp->rhsp()->cloneTreePure(false); + AstNodeExpr* const rlp = rp->lhsp()->cloneTreePure(false); + AstNodeExpr* const rrp = rp->rhsp()->cloneTreePure(false); if (concatMergeable(lp, rp, 0)) { AstConcat* const newlp = new AstConcat{rlp->fileline(), llp, rlp}; AstConcat* const newrp = new AstConcat{rrp->fileline(), lrp, rrp}; @@ -1897,9 +1897,9 @@ private: AstNodeExpr* const ap = lhsp->lhsp()->unlinkFrBack(); AstNodeExpr* const bp = lhsp->rhsp()->unlinkFrBack(); AstNodeBiop* const shift1p = nodep; - AstNodeBiop* const shift2p = nodep->cloneTree(true); + AstNodeBiop* const shift2p = nodep->cloneTreePure(true); shift1p->lhsp(ap); - shift1p->rhsp(shiftp->cloneTree(true)); + shift1p->rhsp(shiftp->cloneTreePure(true)); shift2p->lhsp(bp); shift2p->rhsp(shiftp); AstNodeBiop* const newp = lhsp; @@ -2085,7 +2085,7 @@ private: AstNodeExpr* const lc2p = VN_AS(nodep->lhsp(), Concat)->rhsp()->unlinkFrBack(); AstNodeExpr* const conp = VN_AS(nodep->lhsp(), Concat)->unlinkFrBack(); AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack(); - AstNodeExpr* const rhs2p = rhsp->cloneTree(false); + AstNodeExpr* const rhs2p = rhsp->cloneTreePure(false); // Calc widths const int lsb2 = 0; const int msb2 = lsb2 + lc2p->width() - 1; @@ -2430,8 +2430,8 @@ private: nodep->fileline(), new AstLogOr{nodep->fileline(), new AstLogNot{nodep->fileline(), lhsp}, rhsp}, new AstLogOr{nodep->fileline(), - new AstLogNot{nodep->fileline(), rhsp->cloneTree(false)}, - lhsp->cloneTree(false)}}; + new AstLogNot{nodep->fileline(), rhsp->cloneTreePure(false)}, + lhsp->cloneTreePure(false)}}; newp->dtypeFrom(nodep); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); @@ -2588,8 +2588,8 @@ private: AstNodeExpr* const bilhsp = fromp->lhsp()->unlinkFrBack(); AstNodeExpr* const birhsp = fromp->rhsp()->unlinkFrBack(); // - fromp->lhsp( - new AstSel{nodep->fileline(), bilhsp, lsbp->cloneTree(true), widthp->cloneTree(true)}); + fromp->lhsp(new AstSel{nodep->fileline(), bilhsp, lsbp->cloneTreePure(true), + widthp->cloneTreePure(true)}); fromp->rhsp(new AstSel{nodep->fileline(), birhsp, lsbp, widthp}); fromp->dtypeFrom(nodep); nodep->replaceWith(fromp); diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index 226185e89..d8d9185ff 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -353,7 +353,7 @@ private: } if (bitselp) { selectsp = new AstSel{nodep->fileline(), selectsp, bitreadp, - bitselp->widthp()->cloneTree(false)}; + bitselp->widthp()->cloneTreePure(false)}; // Always pure } // Build "IF (changeit) ... UINFO(9, " For " << setvscp << endl); diff --git a/src/V3DfgDfgToAst.cpp b/src/V3DfgDfgToAst.cpp index 6667ee35f..089e551b4 100644 --- a/src/V3DfgDfgToAst.cpp +++ b/src/V3DfgDfgToAst.cpp @@ -282,8 +282,8 @@ class DfgToAstVisitor final : DfgVisitor { FileLine* const flp = dfgVarp->driverFileLine(idx); AstConst* const lsbp = new AstConst{flp, dfgVarp->driverLsb(idx)}; AstConst* const widthp = new AstConst{flp, edge.sourcep()->width()}; - AstSel* const rhsp = new AstSel{flp, rRef(), lsbp, widthp->cloneTree(false)}; - AstSel* const lhsp = new AstSel{flp, wRef(), lsbp->cloneTree(false), widthp}; + AstSel* const rhsp = new AstSel{flp, rRef(), lsbp, widthp->cloneTreePure(false)}; + AstSel* const lhsp = new AstSel{flp, wRef(), lsbp->cloneTreePure(false), widthp}; // Add assignment of the value to the selected bits addResultEquation(flp, lhsp, rhsp); }); diff --git a/src/V3Expand.cpp b/src/V3Expand.cpp index 54cb31068..7af734fe8 100644 --- a/src/V3Expand.cpp +++ b/src/V3Expand.cpp @@ -137,7 +137,7 @@ private: AstNodeExpr* rhsp) { FileLine* const fl = placep->fileline(); return new AstAssign{fl, - new AstWordSel{fl, lhsp->cloneTree(true), + new AstWordSel{fl, lhsp->cloneTreePure(true), new AstConst{fl, static_cast(word)}}, rhsp}; } @@ -166,20 +166,20 @@ private: // Concat may pass negative word numbers, that means it wants a zero FileLine* const fl = nodep->fileline(); if (nodep->isWide() && word >= 0 && word < nodep->widthWords()) { - return new AstWordSel{fl, nodep->cloneTree(true), + return new AstWordSel{fl, nodep->cloneTreePure(true), new AstConst{fl, static_cast(word)}}; } else if (nodep->isQuad() && word == 0) { - AstNodeExpr* const quadfromp = nodep->cloneTree(true); + AstNodeExpr* const quadfromp = nodep->cloneTreePure(true); quadfromp->dtypeSetBitUnsized(VL_QUADSIZE, quadfromp->widthMin(), VSigning::UNSIGNED); return new AstCCast{fl, quadfromp, VL_EDATASIZE}; } else if (nodep->isQuad() && word == 1) { - AstNodeExpr* const quadfromp = nodep->cloneTree(true); + AstNodeExpr* const quadfromp = nodep->cloneTreePure(true); quadfromp->dtypeSetBitUnsized(VL_QUADSIZE, quadfromp->widthMin(), VSigning::UNSIGNED); return new AstCCast{ fl, new AstShiftR{fl, quadfromp, new AstConst{fl, VL_EDATASIZE}, VL_EDATASIZE}, VL_EDATASIZE}; } else if (!nodep->isWide() && !nodep->isQuad() && word == 0) { - return nodep->cloneTree(true); + return nodep->cloneTreePure(true); } else { // Out of bounds return new AstConst{fl, 0}; } @@ -231,7 +231,7 @@ private: if (VN_IS(lsbp, Const)) { wordp = new AstConst{lfl, wordOffset + VL_BITWORD_E(VN_AS(lsbp, Const)->toUInt())}; } else { - wordp = new AstShiftR{lfl, lsbp->cloneTree(true), + wordp = new AstShiftR{lfl, lsbp->cloneTreePure(true), new AstConst{lfl, VL_EDATASIZE_LOG2}, VL_EDATASIZE}; if (wordOffset != 0) { // This is indexing a arraysel, so a 32 bit constant is fine @@ -260,7 +260,7 @@ private: return new AstConst{fl, VL_BITBIT_E(VN_AS(lsbp, Const)->toUInt())}; } else { return new AstAnd{fl, new AstConst{fl, VL_EDATASIZE - 1}, - dropCondBound(lsbp)->cloneTree(true)}; + dropCondBound(lsbp)->cloneTreePure(true)}; } } @@ -351,7 +351,7 @@ private: FileLine* const fl = nodep->fileline(); for (int w = 0; w < nodep->widthWords(); ++w) { addWordAssign(nodep, w, - new AstCond{fl, rhsp->condp()->cloneTree(true), + new AstCond{fl, rhsp->condp()->cloneTreePure(true), newAstWordSelClone(rhsp->thenp(), w), newAstWordSelClone(rhsp->elsep(), w)}); } @@ -419,7 +419,7 @@ private: FileLine* const lfl = nodep->lsbp()->fileline(); FileLine* const ffl = nodep->fromp()->fileline(); AstNodeExpr* lowwordp - = newWordSel(ffl, nodep->fromp()->cloneTree(true), nodep->lsbp()); + = newWordSel(ffl, nodep->fromp()->cloneTreePure(true), nodep->lsbp()); if (nodep->isQuad() && !lowwordp->isQuad()) { lowwordp = new AstCCast{nfl, lowwordp, nodep}; } @@ -431,9 +431,9 @@ private: const uint32_t midMsbOffset = std::min(nodep->widthConst(), VL_EDATASIZE) - 1; AstNodeExpr* const midMsbp = new AstAdd{lfl, new AstConst{lfl, midMsbOffset}, - nodep->lsbp()->cloneTree(true)}; + nodep->lsbp()->cloneTreePure(true)}; AstNodeExpr* midwordp = // SEL(from,[midwordnum]) - newWordSel(ffl, nodep->fromp()->cloneTree(true), midMsbp, 0); + newWordSel(ffl, nodep->fromp()->cloneTreePure(true), midMsbp, 0); // newWordSel clones the index, so delete it VL_DO_DANGLING(midMsbp->deleteTree(), midMsbp); if (nodep->isQuad() && !midwordp->isQuad()) { @@ -459,9 +459,9 @@ private: if (nodep->widthConst() > VL_EDATASIZE) { const uint32_t hiMsbOffset = nodep->widthConst() - 1; AstNodeExpr* const hiMsbp = new AstAdd{lfl, new AstConst{lfl, hiMsbOffset}, - nodep->lsbp()->cloneTree(true)}; + nodep->lsbp()->cloneTreePure(true)}; AstNodeExpr* hiwordp = // SEL(from,[hiwordnum]) - newWordSel(ffl, nodep->fromp()->cloneTree(true), hiMsbp); + newWordSel(ffl, nodep->fromp()->cloneTreePure(true), hiMsbp); // newWordSel clones the index, so delete it VL_DO_DANGLING(hiMsbp->deleteTree(), hiMsbp); if (nodep->isQuad() && !hiwordp->isQuad()) { @@ -518,13 +518,13 @@ private: for (int w = 0; w < nodep->widthWords(); ++w) { // Grab lowest bits AstNodeExpr* const lowwordp - = newWordSel(rfl, rhsp->fromp()->cloneTree(true), rhsp->lsbp(), w); + = newWordSel(rfl, rhsp->fromp()->cloneTreePure(true), rhsp->lsbp(), w); AstNodeExpr* const lowp = new AstShiftR{rfl, lowwordp, newSelBitBit(rhsp->lsbp()), VL_EDATASIZE}; // Upper bits const V3Number zero{nodep, VL_EDATASIZE, 0}; AstNodeExpr* const midwordp = // SEL(from,[1+wordnum]) - newWordSel(ffl, rhsp->fromp()->cloneTree(true), rhsp->lsbp(), w + 1); + newWordSel(ffl, rhsp->fromp()->cloneTreePure(true), rhsp->lsbp(), w + 1); AstNodeExpr* const midshiftp = new AstSub{lfl, new AstConst{lfl, VL_EDATASIZE}, newSelBitBit(rhsp->lsbp())}; AstNodeExpr* const midmayp = new AstShiftL{rfl, midwordp, midshiftp, VL_EDATASIZE}; @@ -596,9 +596,9 @@ private: } else { UINFO(8, " ASSIGNSEL(const,narrow) " << nodep << endl); if (destp->isQuad() && !rhsp->isQuad()) { rhsp = new AstCCast{nfl, rhsp, nodep}; } - AstNodeExpr* oldvalp = destp->cloneTree(true); + AstNodeExpr* oldvalp = destp->cloneTreePure(true); fixCloneLvalue(oldvalp); - if (!ones) { oldvalp = new AstAnd{lfl, new AstConst{lfl, maskold}, oldvalp}; } + if (!ones) oldvalp = new AstAnd{lfl, new AstConst{lfl, maskold}, oldvalp}; // The bit-select can refer to bits outside the width of nodep // which we aren't allowed to assign to. This is a mask of the @@ -619,7 +619,7 @@ private: UINFO(8, " ASSIGNSEL(varlsb,wide,1bit) " << nodep << endl); AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack(); AstNodeExpr* const destp = lhsp->fromp()->unlinkFrBack(); - AstNodeExpr* oldvalp = newWordSel(lfl, destp->cloneTree(true), lhsp->lsbp()); + AstNodeExpr* oldvalp = newWordSel(lfl, destp->cloneTreePure(true), lhsp->lsbp()); fixCloneLvalue(oldvalp); if (!ones) { oldvalp = new AstAnd{ @@ -633,7 +633,7 @@ private: oldvalp}; } // Restrict the shift amount to 0-31, see bug804. - AstNodeExpr* const shiftp = new AstAnd{nfl, lhsp->lsbp()->cloneTree(true), + AstNodeExpr* const shiftp = new AstAnd{nfl, lhsp->lsbp()->cloneTreePure(true), new AstConst{nfl, VL_EDATASIZE - 1}}; AstNode* const newp = new AstAssign{ nfl, newWordSel(nfl, destp, lhsp->lsbp()), @@ -657,7 +657,7 @@ private: // nodep->dumpTree("- old: "); AstNodeExpr* rhsp = nodep->rhsp()->unlinkFrBack(); AstNodeExpr* const destp = lhsp->fromp()->unlinkFrBack(); - AstNodeExpr* oldvalp = destp->cloneTree(true); + AstNodeExpr* oldvalp = destp->cloneTreePure(true); fixCloneLvalue(oldvalp); V3Number maskwidth{nodep, destp->widthMin()}; @@ -667,13 +667,13 @@ private: if (!ones) { oldvalp = new AstAnd{ lfl, - new AstNot{lfl, - new AstShiftL{lfl, new AstConst{nfl, maskwidth}, - lhsp->lsbp()->cloneTree(true), destp->width()}}, + new AstNot{lfl, new AstShiftL{lfl, new AstConst{nfl, maskwidth}, + lhsp->lsbp()->cloneTreePure(true), + destp->width()}}, oldvalp}; } AstNodeExpr* newp - = new AstShiftL{lfl, rhsp, lhsp->lsbp()->cloneTree(true), destp->width()}; + = new AstShiftL{lfl, rhsp, lhsp->lsbp()->cloneTreePure(true), destp->width()}; // Apply cleaning to the new value being inserted. Mask is // slightly wider than necessary to avoid an AND with all ones // being optimized out. No need to clean if destp is @@ -749,12 +749,12 @@ private: "Replication value isn't a constant. Checked earlier!"); const uint32_t times = constp->toUInt(); if (nodep->isQuad() && !lhsp->isQuad()) { lhsp = new AstCCast{fl, lhsp, nodep}; } - newp = lhsp->cloneTree(true); + newp = lhsp->cloneTreePure(true); for (unsigned repnum = 1; repnum < times; repnum++) { const int rhsshift = repnum * lhswidth; newp = new AstOr{ fl, - new AstShiftL{fl, lhsp->cloneTree(true), + new AstShiftL{fl, lhsp->cloneTreePure(true), new AstConst{fl, static_cast(rhsshift)}, nodep->width()}, newp}; @@ -778,7 +778,7 @@ private: for (int w = 0; w < rhsp->widthWords(); ++w) { AstNodeExpr* newp; if (lhswidth == 1) { - newp = new AstNegate{fl, lhsp->cloneTree(true)}; + newp = new AstNegate{fl, lhsp->cloneTreePure(true)}; // Replicate always unsigned newp->dtypeSetLogicSized(VL_EDATASIZE, VSigning::UNSIGNED); } else { diff --git a/src/V3Force.cpp b/src/V3Force.cpp index 6eab5f0d4..464ea6237 100644 --- a/src/V3Force.cpp +++ b/src/V3Force.cpp @@ -188,13 +188,13 @@ class ForceConvertVisitor final : public VNVisitor { V3Number ones{lhsp, isRangedDType(lhsp) ? lhsp->width() : 1}; ones.setAllBits1(); AstAssign* const setEnp - = new AstAssign{flp, lhsp->cloneTree(false), new AstConst{rhsp->fileline(), ones}}; + = new AstAssign{flp, lhsp->cloneTreePure(false), new AstConst{rhsp->fileline(), ones}}; transformWritenVarScopes(setEnp->lhsp(), [this](AstVarScope* vscp) { return getForceComponents(vscp).m_enVscp; }); // Set corresponding value signals to the forced value AstAssign* const setValp - = new AstAssign{flp, lhsp->cloneTree(false), rhsp->cloneTree(false)}; + = new AstAssign{flp, lhsp->cloneTreePure(false), rhsp->cloneTreePure(false)}; transformWritenVarScopes(setValp->lhsp(), [this](AstVarScope* vscp) { return getForceComponents(vscp).m_valVscp; }); @@ -223,7 +223,7 @@ class ForceConvertVisitor final : public VNVisitor { V3Number zero{lhsp, isRangedDType(lhsp) ? lhsp->width() : 1}; zero.setAllBits0(); AstAssign* const resetEnp - = new AstAssign{flp, lhsp->cloneTree(false), new AstConst{lhsp->fileline(), zero}}; + = new AstAssign{flp, lhsp->cloneTreePure(false), new AstConst{lhsp->fileline(), zero}}; transformWritenVarScopes(resetEnp->lhsp(), [this](AstVarScope* vscp) { return getForceComponents(vscp).m_enVscp; }); @@ -235,7 +235,7 @@ class ForceConvertVisitor final : public VNVisitor { FileLine* const fl_nowarn = new FileLine{flp}; fl_nowarn->warnOff(V3ErrorCode::BLKANDNBLK, true); AstAssign* const resetRdp - = new AstAssign{fl_nowarn, lhsp->cloneTree(false), lhsp->unlinkFrBack()}; + = new AstAssign{fl_nowarn, lhsp->cloneTreePure(false), lhsp->unlinkFrBack()}; // Replace write refs on the LHS resetRdp->lhsp()->foreach([this](AstNodeVarRef* refp) { if (refp->access() != VAccess::WRITE) return; diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index e99c1561f..b3811bce8 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -395,7 +395,7 @@ private: void optimizeElimVar(AstVarScope* varscp, AstNode* substp, AstNode* consumerp) { if (debug() >= 5) consumerp->dumpTree("- elimUsePre: "); if (!m_substitutions.tryGet(consumerp)) m_optimized.push_back(consumerp); - m_substitutions(consumerp).emplace(varscp, substp->cloneTree(false)); + m_substitutions(consumerp).emplace(varscp, substp->cloneTreePure(false)); } void commitElimVar(AstNode* logicp) { @@ -1008,7 +1008,7 @@ static void eliminate(AstNode* logicp, // Prevent an infinite loop... substp, "Replacing node with itself; perhaps circular logic?"); // The replacement - AstNode* const newp = substp->cloneTree(false); + AstNode* const newp = substp->cloneTreePure(false); // Which fileline() to use? If replacing with logic, an error/warning is likely to want // to point to the logic IE what we're replacing with. However, a VARREF should point // to the original as it's otherwise confusing to throw warnings that point to a PIN @@ -1219,9 +1219,10 @@ private: preselp->replaceWith(newselp); VL_DO_DANGLING(preselp->deleteTree(), preselp); // create new rhs for pre assignment - AstNode* const newrhsp = new AstConcat{ - m_assignp->rhsp()->fileline(), m_assignp->rhsp()->cloneTree(false), - assignp->rhsp()->cloneTree(false)}; + AstNode* const newrhsp + = new AstConcat{m_assignp->rhsp()->fileline(), + m_assignp->rhsp()->cloneTreePure(false), + assignp->rhsp()->cloneTreePure(false)}; AstNode* const oldrhsp = m_assignp->rhsp(); oldrhsp->replaceWith(newrhsp); VL_DO_DANGLING(oldrhsp->deleteTree(), oldrhsp); diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp index 3a6eb7eaf..6c0834182 100644 --- a/src/V3LinkInc.cpp +++ b/src/V3LinkInc.cpp @@ -283,9 +283,9 @@ private: // Define what operation will we be doing AstNodeExpr* operp; if (VN_IS(nodep, PostSub) || VN_IS(nodep, PreSub)) { - operp = new AstSub{fl, readp->cloneTree(true), newconstp}; + operp = new AstSub{fl, readp->cloneTreePure(true), newconstp}; } else { - operp = new AstAdd{fl, readp->cloneTree(true), newconstp}; + operp = new AstAdd{fl, readp->cloneTreePure(true), newconstp}; } if (VN_IS(nodep, PreAdd) || VN_IS(nodep, PreSub)) { @@ -301,7 +301,7 @@ private: // PostAdd/PostSub operations // Assign the original variable to the temporary one AstAssign* const assignp = new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, - readp->cloneTree(true)}; + readp->cloneTreePure(true)}; insertNextToStmt(nodep, assignp); // Increment the original variable by one assignp->addNextHere(new AstAssign{fl, writep, operp}); diff --git a/src/V3MergeCond.cpp b/src/V3MergeCond.cpp index 8a237c8ba..52c6a4dfa 100644 --- a/src/V3MergeCond.cpp +++ b/src/V3MergeCond.cpp @@ -601,7 +601,7 @@ private: if (condp == rhsp) return resp; if (const AstAnd* const andp = VN_CAST(rhsp, And)) { UASSERT_OBJ(andp->rhsp() == condp, rhsp, "Should not try to fold this"); - return new AstAnd{andp->fileline(), andp->lhsp()->cloneTree(false), resp}; + return new AstAnd{andp->fileline(), andp->lhsp()->cloneTreePure(false), resp}; } } else if (const AstAnd* const andp = VN_CAST(rhsp, And)) { if (andp->lhsp()->sameTree(m_mgCondp)) { @@ -655,7 +655,7 @@ private: // We need a copy of the condition in the new equivalent 'if' statement, // and we also need to keep track of it for comparisons later. - m_mgCondp = m_mgCondp->cloneTree(false); + m_mgCondp = m_mgCondp->cloneTreePure(false); // Create equivalent 'if' statement and insert it before the first node AstIf* const resultp = new AstIf{m_mgCondp->fileline(), m_mgCondp}; m_mgFirstp->addHereThisAsNext(resultp); diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 2d1d3cfdb..9b58dc8b4 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -257,7 +257,7 @@ private: // Create equivalent of VL_SIGNONES_(node_width) constzerop = new AstNegate{ nodep->fileline(), - new AstShiftR{nodep->fileline(), nodep->lhsp()->cloneTree(false), + new AstShiftR{nodep->fileline(), nodep->lhsp()->cloneTreePure(false), new AstConst(nodep->fileline(), m1value), nodep->width()}}; } else { constzerop = new AstConst{nodep->fileline(), AstConst::WidthedValue{}, @@ -269,10 +269,10 @@ private: = new AstConst(nodep->fileline(), AstConst::WidthedValue{}, nodep->rhsp()->widthMin(), m1value); constwidthp->dtypeFrom(nodep->rhsp()); // unsigned - AstCond* const newp = new AstCond{ - nodep->fileline(), - new AstGte{nodep->fileline(), constwidthp, nodep->rhsp()->cloneTree(false)}, - nodep, constzerop}; + AstCond* const newp = new AstCond{nodep->fileline(), + new AstGte{nodep->fileline(), constwidthp, + nodep->rhsp()->cloneTreePure(false)}, + nodep, constzerop}; replaceHandle.relink(newp); } } @@ -370,7 +370,7 @@ private: UINFO(4, "Autoflush " << nodep << endl); nodep->addNextHere( new AstFFlush{nodep->fileline(), - nodep->filep() ? nodep->filep()->cloneTree(true) : nullptr}); + nodep->filep() ? nodep->filep()->cloneTreePure(true) : nullptr}); } } } diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 7d6aad6f9..95c4ce2e9 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -338,7 +338,7 @@ private: = new AstIf{itemp->fileline(), new AstLte{condp->fileline(), new AstVarRef{condp->fileline(), randVarp, VAccess::READ}, - sump->cloneTree(true)}, + sump->cloneTreePure(true)}, stmtsp, nullptr}; ifsp->addElsesp(newifp); ifsp = newifp; diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp index e4aa7407f..968a16571 100644 --- a/src/V3Slice.cpp +++ b/src/V3Slice.cpp @@ -98,10 +98,10 @@ class SliceVisitor final : public VNVisitor { nodep->v3error("Array initialization has too few elements, need element " << offset); } - newp = itemp ? itemp->cloneTree(false) : new AstConst{nodep->fileline(), 0}; + newp = itemp ? itemp->cloneTreePure(false) : new AstConst{nodep->fileline(), 0}; } else if (AstNodeCond* const snodep = VN_CAST(nodep, NodeCond)) { UINFO(9, " cloneCond(" << elements << "," << offset << ") " << nodep << endl); - return snodep->cloneType(snodep->condp()->cloneTree(false), + return snodep->cloneType(snodep->condp()->cloneTreePure(false), cloneAndSel(snodep->thenp(), elements, offset), cloneAndSel(snodep->elsep(), elements, offset)); } else if (const AstSliceSel* const snodep = VN_CAST(nodep, SliceSel)) { @@ -110,7 +110,8 @@ class SliceVisitor final : public VNVisitor { + (!snodep->declRange().ascending() ? snodep->declRange().elements() - 1 - offset : offset)); - newp = new AstArraySel{nodep->fileline(), snodep->fromp()->cloneTree(false), leOffset}; + newp = new AstArraySel{nodep->fileline(), snodep->fromp()->cloneTreePure(false), + leOffset}; } else if (VN_IS(nodep, ArraySel) || VN_IS(nodep, NodeVarRef) || VN_IS(nodep, NodeSel) || VN_IS(nodep, CMethodHard) || VN_IS(nodep, MemberSel) || VN_IS(nodep, ExprStmt)) { @@ -118,7 +119,7 @@ class SliceVisitor final : public VNVisitor { const int leOffset = !arrayp->rangep()->ascending() ? arrayp->rangep()->elementsConst() - 1 - offset : offset; - newp = new AstArraySel{nodep->fileline(), VN_AS(nodep, NodeExpr)->cloneTree(false), + newp = new AstArraySel{nodep->fileline(), VN_AS(nodep, NodeExpr)->cloneTreePure(false), leOffset}; } else { if (!m_assignError) { diff --git a/src/V3Split.cpp b/src/V3Split.cpp index 5ff887b59..1e6b82801 100644 --- a/src/V3Split.cpp +++ b/src/V3Split.cpp @@ -767,6 +767,8 @@ protected: // Clone this if into its set of split blocks AstSplitPlaceholder* const if_placeholderp = makePlaceholderp(); AstSplitPlaceholder* const else_placeholderp = makePlaceholderp(); + // We check for condition isPure earlier, but may still clone a + // non-pure to separate from other pure statements. AstIf* const clonep = new AstIf{nodep->fileline(), nodep->condp()->cloneTree(true), if_placeholderp, else_placeholderp}; const AstIf* const origp = VN_CAST(nodep, If); diff --git a/src/V3SplitAs.cpp b/src/V3SplitAs.cpp index 24bf6f831..f67263dd7 100644 --- a/src/V3SplitAs.cpp +++ b/src/V3SplitAs.cpp @@ -142,6 +142,9 @@ private: void splitAlways(AstAlways* nodep, AstVarScope* splitVscp) { if (debug() >= 9) nodep->dumpTree("- in: "); // Duplicate it and link in + // Below cloneTree should perhaps be cloneTreePure, but given + // isolate_assignments is required to hit this code, we presume the user + // knows what they are asking for AstAlways* const newp = nodep->cloneTree(false); newp->user1(true); // So we don't clone it again nodep->addNextHere(newp); diff --git a/src/V3Subst.cpp b/src/V3Subst.cpp index 38ebafb6a..79aa116a6 100644 --- a/src/V3Subst.cpp +++ b/src/V3Subst.cpp @@ -292,7 +292,7 @@ private: } void replaceSubstEtc(AstNode* nodep, AstNodeExpr* substp) { if (debug() > 5) nodep->dumpTree("- substw_old: "); - AstNodeExpr* newp = substp->cloneTree(true); + AstNodeExpr* newp = substp->cloneTreePure(true); if (!nodep->isQuad() && newp->isQuad()) { newp = new AstCCast{newp->fileline(), newp, nodep}; } diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index 99ff0f328..ded800d65 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -516,14 +516,14 @@ class TristateVisitor final : public TristateBaseVisitor { // Unlink lhsp before copying to save unnecessary copy of lhsp AstNodeExpr* const lhsp = extendp->lhsp()->unlinkFrBack(); - AstExtend* const enExtendp = extendp->cloneTree(false); + AstExtend* const enExtendp = extendp->cloneTreePure(false); extendp->lhsp(lhsp); AstNodeExpr* 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)) { AstNodeExpr* const fromp = selp->fromp()->unlinkFrBack(); - AstSel* const enSelp = selp->cloneTree(false); + AstSel* const enSelp = selp->cloneTreePure(false); selp->fromp(fromp); AstNodeExpr* const enFromp = getEnExprBasedOnOriginalp(fromp); enSelp->fromp(enFromp); @@ -572,7 +572,7 @@ class TristateVisitor final : public TristateBaseVisitor { // Would be nicer if we made this a new AST type AstNodeExpr* const newp = new AstShiftL{ selp->fileline(), new AstExtend{selp->fileline(), enp, selp->fromp()->width()}, - selp->lsbp()->cloneTree(false), selp->fromp()->width()}; + selp->lsbp()->cloneTreePure(false), selp->fromp()->width()}; return newp; } @@ -779,7 +779,7 @@ class TristateVisitor final : public TristateBaseVisitor { // If weaker driver should be overwritten by a stronger, replace its value with z exprCurrentStrengthp = new AstAnd{fl, new AstVarRef{fl, varStrengthp, VAccess::READ}, - new AstNot{fl, enp->cloneTree(false)}}; + new AstNot{fl, enp->cloneTreePure(false)}}; } else { exprCurrentStrengthp = new AstVarRef{fl, varStrengthp, VAccess::READ}; } @@ -1086,7 +1086,7 @@ class TristateVisitor final : public TristateBaseVisitor { if (nodep->fromp()->user1p()) { // SEL(VARREF, lsb) AstNodeExpr* const en1p = getEnp(nodep->fromp()); AstNodeExpr* const enp - = new AstSel{nodep->fileline(), en1p, nodep->lsbp()->cloneTree(true), + = new AstSel{nodep->fileline(), en1p, nodep->lsbp()->cloneTreePure(true), nodep->widthp()->cloneTree(true)}; UINFO(9, " newsel " << enp << endl); nodep->user1p(enp); // propagate up SEL(fromp->enable, value) @@ -1113,7 +1113,7 @@ class TristateVisitor final : public TristateBaseVisitor { // Each half of the concat gets a select of the enable expression AstNodeExpr* const enp = VN_AS(nodep->user1p(), NodeExpr); nodep->user1p(nullptr); - nodep->lhsp()->user1p(new AstSel{nodep->fileline(), enp->cloneTree(true), + nodep->lhsp()->user1p(new AstSel{nodep->fileline(), enp->cloneTreePure(true), nodep->rhsp()->width(), nodep->lhsp()->width()}); nodep->rhsp()->user1p( @@ -1208,8 +1208,8 @@ class TristateVisitor final : public TristateBaseVisitor { m_tgraph.didProcess(nodep); AstNodeExpr* const en1p = getEnp(expr1p); AstNodeExpr* const en2p = getEnp(expr2p); - AstNodeExpr* subexpr1p = expr1p->cloneTree(false); - AstNodeExpr* subexpr2p = expr2p->cloneTree(false); + AstNodeExpr* subexpr1p = expr1p->cloneTreePure(false); + AstNodeExpr* subexpr2p = expr2p->cloneTreePure(false); if (isAnd) { subexpr1p = new AstNot{nodep->fileline(), subexpr1p}; subexpr2p = new AstNot{nodep->fileline(), subexpr2p}; @@ -1407,15 +1407,15 @@ class TristateVisitor final : public TristateBaseVisitor { if (nonXp) { // Need to still count '0 or '1 or 'x's if (dropop[0]) { nodep->rhsp()->unlinkFrBack()->deleteTree(); - nodep->rhsp(nonXp->cloneTree(true)); + nodep->rhsp(nonXp->cloneTreePure(true)); } if (dropop[1]) { nodep->thsp()->unlinkFrBack()->deleteTree(); - nodep->thsp(nonXp->cloneTree(true)); + nodep->thsp(nonXp->cloneTreePure(true)); } if (dropop[2]) { nodep->fhsp()->unlinkFrBack()->deleteTree(); - nodep->fhsp(nonXp->cloneTree(true)); + nodep->fhsp(nonXp->cloneTreePure(true)); } newp = new AstAdd{nodep->fileline(), nodep, newp}; } @@ -1582,8 +1582,8 @@ class TristateVisitor final : public TristateBaseVisitor { << nodep->prettyNameQ()); } } else { - AstNodeExpr* const outexprp - = VN_AS(nodep->exprp(), NodeExpr)->cloneTree(false); // Note has lvalue() set + AstNodeExpr* const outexprp = VN_AS(nodep->exprp(), NodeExpr) + ->cloneTreePure(false); // Note has lvalue() set outpinp = new AstPin{nodep->fileline(), nodep->pinNum(), outModVarp->name(), // should be {var}"__out" outexprp}; diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp index bf597e4e3..66a6c78c4 100644 --- a/src/V3Unknown.cpp +++ b/src/V3Unknown.cpp @@ -306,15 +306,15 @@ private: } if (dropop[0]) { nodep->rhsp()->unlinkFrBack()->deleteTree(); - nodep->rhsp(nonXp->cloneTree(true)); + nodep->rhsp(nonXp->cloneTreePure(true)); } if (dropop[1]) { nodep->thsp()->unlinkFrBack()->deleteTree(); - nodep->thsp(nonXp->cloneTree(true)); + nodep->thsp(nonXp->cloneTreePure(true)); } if (dropop[2]) { nodep->fhsp()->unlinkFrBack()->deleteTree(); - nodep->fhsp(nonXp->cloneTree(true)); + nodep->fhsp(nonXp->cloneTreePure(true)); } iterateChildren(nodep); } @@ -398,7 +398,7 @@ private: = new AstGte{nodep->fileline(), new AstConst(nodep->fileline(), AstConst::WidthedValue{}, nodep->lsbp()->width(), maxmsb), - nodep->lsbp()->cloneTree(false)}; + nodep->lsbp()->cloneTreePure(false)}; // See if the condition is constant true (e.g. always in bound due to constant select) // Note below has null backp(); the Edit function knows how to deal with that. condp = V3Const::constifyEdit(condp); @@ -457,7 +457,7 @@ private: = new AstGte{nodep->fileline(), new AstConst(nodep->fileline(), AstConst::WidthedValue{}, nodep->bitp()->width(), declElements - 1), - nodep->bitp()->cloneTree(false)}; + nodep->bitp()->cloneTreePure(false)}; // Note below has null backp(); the Edit function knows how to deal with that. condp = V3Const::constifyEdit(condp); if (condp->isOne()) { diff --git a/src/V3Width.cpp b/src/V3Width.cpp index e1c0edff1..c00628e92 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1858,7 +1858,7 @@ private: if (assoc) { AstVar* const varp = enumVarp(enumDtp, VAttrType::ENUM_VALID, true, 0); testp = new AstAssocSel{fl_novalue, newVarRefDollarUnit(varp), - nodep->fromp()->cloneTree(false)}; + nodep->fromp()->cloneTreePure(false)}; } else { const int selwidth = V3Number::log2b(maxval) + 1; // Width to address a bit AstVar* const varp @@ -1867,12 +1867,12 @@ private: fl_nowidth->warnOff(V3ErrorCode::WIDTH, true); testp = new AstCond{ fl, - new AstGt{fl_nowidth, nodep->fromp()->cloneTree(false), + new AstGt{fl_nowidth, nodep->fromp()->cloneTreePure(false), new AstConst{fl_nowidth, AstConst::Unsized64{}, maxval}}, new AstConst{fl, AstConst::BitFalse{}}, - new AstArraySel{ - fl, newVarRefDollarUnit(varp), - new AstSel{fl_novalue, nodep->fromp()->cloneTree(false), 0, selwidth}}}; + new AstArraySel{fl, newVarRefDollarUnit(varp), + new AstSel{fl_novalue, nodep->fromp()->cloneTreePure(false), 0, + selwidth}}}; } newp = new AstCond{ fl, testp, @@ -2550,7 +2550,7 @@ private: "Inside operator not legal on non-unpacked arrays (IEEE 1800-2017 11.4.13)"); continue; } else { - inewp = AstEqWild::newTyped(itemp->fileline(), nodep->exprp()->cloneTree(true), + inewp = AstEqWild::newTyped(itemp->fileline(), nodep->exprp()->cloneTreePure(true), itemp->unlinkFrBack()); } if (newp) { @@ -3625,7 +3625,7 @@ private: FileLine* const fl = nodep->fileline(); AstNodeExpr* newp = nullptr; for (int i = 0; i < adtypep->elementsConst(); ++i) { - AstNodeExpr* const arrayRef = nodep->fromp()->cloneTree(false); + AstNodeExpr* const arrayRef = nodep->fromp()->cloneTreePure(false); AstNodeExpr* const selector = new AstArraySel{fl, arrayRef, i}; if (!newp) { newp = selector; @@ -4552,8 +4552,9 @@ private: if (adtypep->isString()) { if (varp) { AstConst* const leftp = new AstConst{fl, AstConst::Signed32{}, 0}; - AstLt* const condp = new AstLt{fl, new AstVarRef{fl, varp, VAccess::READ}, - new AstLenN{fl, fromp->cloneTree(false)}}; + AstLt* const condp + = new AstLt{fl, new AstVarRef{fl, varp, VAccess::READ}, + new AstLenN{fl, fromp->cloneTreePure(false)}}; AstAdd* const incp = new AstAdd{fl, new AstConst{fl, AstConst::Signed32{}, 1}, new AstVarRef{fl, varp, VAccess::READ}}; @@ -4576,7 +4577,8 @@ private: } else if (VN_IS(fromDtp, DynArrayDType) || VN_IS(fromDtp, QueueDType)) { if (varp) { auto* const leftp = new AstConst{fl, AstConst::Signed32{}, 0}; - auto* const sizep = new AstCMethodHard{fl, fromp->cloneTree(false), "size"}; + auto* const sizep + = new AstCMethodHard{fl, fromp->cloneTreePure(false), "size"}; sizep->dtypeSetSigned32(); sizep->didWidth(true); sizep->protect(false); @@ -4601,10 +4603,10 @@ private: fl, VVarType::BLOCKTEMP, varp->name() + "__Vfirst", VFlagBitPacked{}, 1}; first_varp->usedLoopIdx(true); AstNodeExpr* const firstp = new AstMethodCall{ - fl, fromp->cloneTree(false), "first", + fl, fromp->cloneTreePure(false), "first", new AstArg{fl, "", new AstVarRef{fl, varp, VAccess::READWRITE}}}; AstNodeExpr* const nextp = new AstMethodCall{ - fl, fromp->cloneTree(false), "next", + fl, fromp->cloneTreePure(false), "next", new AstArg{fl, "", new AstVarRef{fl, varp, VAccess::READWRITE}}}; AstNode* const first_clearp = new AstAssign{fl, new AstVarRef{fl, first_varp, VAccess::WRITE}, diff --git a/src/astgen b/src/astgen index 048077e3d..761313ee5 100755 --- a/src/astgen +++ b/src/astgen @@ -961,6 +961,9 @@ def write_ast_macros(filename): Ast{t}* cloneTree(bool cloneNext) {{ return static_cast(AstNode::cloneTree(cloneNext)); }} + Ast{t}* cloneTreePure(bool cloneNext) {{ + return static_cast(AstNode::cloneTreePure(cloneNext)); + }} Ast{t}* clonep() const {{ return static_cast(AstNode::clonep()); }} Ast{t}* addNext(Ast{t}* nodep) {{ return static_cast(AstNode::addNext(this, nodep)); }} ''', diff --git a/src/verilog.y b/src/verilog.y index 65d92bc6b..794a4cf61 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -2885,40 +2885,40 @@ genvar_iteration: // ==IEEE: genvar_iteration varRefBase '=' expr { $$ = new AstAssign{$2, $1, $3}; } | varRefBase yP_PLUSEQ expr - { $$ = new AstAssign{$2, $1, new AstAdd{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstAdd{$2, $1->cloneTreePure(true), $3}}; } | varRefBase yP_MINUSEQ expr - { $$ = new AstAssign{$2, $1, new AstSub{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstSub{$2, $1->cloneTreePure(true), $3}}; } | varRefBase yP_TIMESEQ expr - { $$ = new AstAssign{$2, $1, new AstMul{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstMul{$2, $1->cloneTreePure(true), $3}}; } | varRefBase yP_DIVEQ expr - { $$ = new AstAssign{$2, $1, new AstDiv{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstDiv{$2, $1->cloneTreePure(true), $3}}; } | varRefBase yP_MODEQ expr - { $$ = new AstAssign{$2, $1, new AstModDiv{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstModDiv{$2, $1->cloneTreePure(true), $3}}; } | varRefBase yP_ANDEQ expr - { $$ = new AstAssign{$2, $1, new AstAnd{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstAnd{$2, $1->cloneTreePure(true), $3}}; } | varRefBase yP_OREQ expr - { $$ = new AstAssign{$2, $1, new AstOr{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstOr{$2, $1->cloneTreePure(true), $3}}; } | varRefBase yP_XOREQ expr - { $$ = new AstAssign{$2, $1, new AstXor{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstXor{$2, $1->cloneTreePure(true), $3}}; } | varRefBase yP_SLEFTEQ expr - { $$ = new AstAssign{$2, $1, new AstShiftL{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstShiftL{$2, $1->cloneTreePure(true), $3}}; } | varRefBase yP_SRIGHTEQ expr - { $$ = new AstAssign{$2, $1, new AstShiftR{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstShiftR{$2, $1->cloneTreePure(true), $3}}; } | varRefBase yP_SSRIGHTEQ expr - { $$ = new AstAssign{$2, $1, new AstShiftRS{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstShiftRS{$2, $1->cloneTreePure(true), $3}}; } // // inc_or_dec_operator // When support ++ as a real AST type, maybe AstWhile::precondsp() becomes generic AstNodeExprStmt? | yP_PLUSPLUS varRefBase - { $$ = new AstAssign{$1, $2, new AstAdd{$1, $2->cloneTree(true), + { $$ = new AstAssign{$1, $2, new AstAdd{$1, $2->cloneTreePure(true), new AstConst{$1, AstConst::StringToParse{}, "'b1"}}}; } | yP_MINUSMINUS varRefBase - { $$ = new AstAssign{$1, $2, new AstSub{$1, $2->cloneTree(true), + { $$ = new AstAssign{$1, $2, new AstSub{$1, $2->cloneTreePure(true), new AstConst{$1, AstConst::StringToParse{}, "'b1"}}}; } | varRefBase yP_PLUSPLUS - { $$ = new AstAssign{$2, $1, new AstAdd{$2, $1->cloneTree(true), + { $$ = new AstAssign{$2, $1, new AstAdd{$2, $1->cloneTreePure(true), new AstConst{$2, AstConst::StringToParse{}, "'b1"}}}; } | varRefBase yP_MINUSMINUS - { $$ = new AstAssign{$2, $1, new AstSub{$2, $1->cloneTree(true), + { $$ = new AstAssign{$2, $1, new AstSub{$2, $1->cloneTreePure(true), new AstConst{$2, AstConst::StringToParse{}, "'b1"}}}; } ; @@ -3681,44 +3681,44 @@ foperator_assignment: // IEEE: operator_assignment (for first part of fexprLvalue '=' delay_or_event_controlE expr { $$ = new AstAssign{$2, $1, $4, $3}; } // | fexprLvalue yP_PLUSEQ expr - { $$ = new AstAssign{$2, $1, new AstAdd{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstAdd{$2, $1->cloneTreePure(true), $3}}; } | fexprLvalue yP_MINUSEQ expr - { $$ = new AstAssign{$2, $1, new AstSub{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstSub{$2, $1->cloneTreePure(true), $3}}; } | fexprLvalue yP_TIMESEQ expr - { $$ = new AstAssign{$2, $1, new AstMul{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstMul{$2, $1->cloneTreePure(true), $3}}; } | fexprLvalue yP_DIVEQ expr - { $$ = new AstAssign{$2, $1, new AstDiv{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstDiv{$2, $1->cloneTreePure(true), $3}}; } | fexprLvalue yP_MODEQ expr - { $$ = new AstAssign{$2, $1, new AstModDiv{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstModDiv{$2, $1->cloneTreePure(true), $3}}; } | fexprLvalue yP_ANDEQ expr - { $$ = new AstAssign{$2, $1, new AstAnd{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstAnd{$2, $1->cloneTreePure(true), $3}}; } | fexprLvalue yP_OREQ expr - { $$ = new AstAssign{$2, $1, new AstOr{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstOr{$2, $1->cloneTreePure(true), $3}}; } | fexprLvalue yP_XOREQ expr - { $$ = new AstAssign{$2, $1, new AstXor{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstXor{$2, $1->cloneTreePure(true), $3}}; } | fexprLvalue yP_SLEFTEQ expr - { $$ = new AstAssign{$2, $1, new AstShiftL{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstShiftL{$2, $1->cloneTreePure(true), $3}}; } | fexprLvalue yP_SRIGHTEQ expr - { $$ = new AstAssign{$2, $1, new AstShiftR{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstShiftR{$2, $1->cloneTreePure(true), $3}}; } | fexprLvalue yP_SSRIGHTEQ expr - { $$ = new AstAssign{$2, $1, new AstShiftRS{$2, $1->cloneTree(true), $3}}; } + { $$ = new AstAssign{$2, $1, new AstShiftRS{$2, $1->cloneTreePure(true), $3}}; } ; inc_or_dec_expression: // ==IEEE: inc_or_dec_expression // // Need fexprScope instead of variable_lvalue to prevent conflict ~l~exprScope yP_PLUSPLUS { $$ = $1; $$ = new AstPostAdd{$2, new AstConst{$2, AstConst::StringToParse{}, "'b1"}, - $1, $1->cloneTree(true)}; } + $1, $1->cloneTreePure(true)}; } | ~l~exprScope yP_MINUSMINUS { $$ = $1; $$ = new AstPostSub{$2, new AstConst{$2, AstConst::StringToParse{}, "'b1"}, - $1, $1->cloneTree(true)}; } + $1, $1->cloneTreePure(true)}; } // // Need expr instead of variable_lvalue to prevent conflict | yP_PLUSPLUS expr { $$ = $1; $$ = new AstPreAdd{$1, new AstConst{$1, AstConst::StringToParse{}, "'b1"}, - $2, $2->cloneTree(true)}; } + $2, $2->cloneTreePure(true)}; } | yP_MINUSMINUS expr { $$ = $1; $$ = new AstPreSub{$1, new AstConst{$1, AstConst::StringToParse{}, "'b1"}, - $2, $2->cloneTree(true)}; } + $2, $2->cloneTreePure(true)}; } ; finc_or_dec_expression: // ==IEEE: inc_or_dec_expression @@ -4734,40 +4734,40 @@ expr: // IEEE: part of expression/constant_expression/ // // Need exprScope of variable_lvalue to prevent conflict | '(' ~p~exprScope '=' expr ')' { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, $4}, - $2->cloneTree(true)}; } + $2->cloneTreePure(true)}; } | '(' ~p~exprScope yP_PLUSEQ expr ')' - { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstAdd{$3, $2->cloneTree(true), $4}}, - $2->cloneTree(true)}; } + { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstAdd{$3, $2->cloneTreePure(true), $4}}, + $2->cloneTreePure(true)}; } | '(' ~p~exprScope yP_MINUSEQ expr ')' - { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstSub{$3, $2->cloneTree(true), $4}}, - $2->cloneTree(true)}; } + { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstSub{$3, $2->cloneTreePure(true), $4}}, + $2->cloneTreePure(true)}; } | '(' ~p~exprScope yP_TIMESEQ expr ')' - { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstMul{$3, $2->cloneTree(true), $4}}, - $2->cloneTree(true)}; } + { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstMul{$3, $2->cloneTreePure(true), $4}}, + $2->cloneTreePure(true)}; } | '(' ~p~exprScope yP_DIVEQ expr ')' - { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstDiv{$3, $2->cloneTree(true), $4}}, - $2->cloneTree(true)}; } + { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstDiv{$3, $2->cloneTreePure(true), $4}}, + $2->cloneTreePure(true)}; } | '(' ~p~exprScope yP_MODEQ expr ')' - { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstModDiv{$3, $2->cloneTree(true), $4}}, - $2->cloneTree(true)}; } + { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstModDiv{$3, $2->cloneTreePure(true), $4}}, + $2->cloneTreePure(true)}; } | '(' ~p~exprScope yP_ANDEQ expr ')' - { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstAnd{$3, $2->cloneTree(true), $4}}, - $2->cloneTree(true)}; } + { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstAnd{$3, $2->cloneTreePure(true), $4}}, + $2->cloneTreePure(true)}; } | '(' ~p~exprScope yP_OREQ expr ')' - { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstOr{$3, $2->cloneTree(true), $4}}, - $2->cloneTree(true)}; } + { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstOr{$3, $2->cloneTreePure(true), $4}}, + $2->cloneTreePure(true)}; } | '(' ~p~exprScope yP_XOREQ expr ')' - { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstXor{$3, $2->cloneTree(true), $4}}, - $2->cloneTree(true)}; } + { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstXor{$3, $2->cloneTreePure(true), $4}}, + $2->cloneTreePure(true)}; } | '(' ~p~exprScope yP_SLEFTEQ expr ')' - { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstShiftL{$3, $2->cloneTree(true), $4}}, - $2->cloneTree(true)}; } + { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstShiftL{$3, $2->cloneTreePure(true), $4}}, + $2->cloneTreePure(true)}; } | '(' ~p~exprScope yP_SRIGHTEQ expr ')' - { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstShiftR{$3, $2->cloneTree(true), $4}}, - $2->cloneTree(true)}; } + { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstShiftR{$3, $2->cloneTreePure(true), $4}}, + $2->cloneTreePure(true)}; } | '(' ~p~exprScope yP_SSRIGHTEQ expr ')' - { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstShiftRS{$3, $2->cloneTree(true), $4}}, - $2->cloneTree(true)}; } + { $$ = new AstExprStmt{$1, new AstAssign{$3, $2, new AstShiftRS{$3, $2->cloneTreePure(true), $4}}, + $2->cloneTreePure(true)}; } // // // IEEE: expression binary_operator expression | ~l~expr '+' ~r~expr { $$ = new AstAdd{$2, $1, $3}; } From f507ee56b04bd299f7675cb559109d3f69feb090 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 17 Sep 2023 08:01:54 -0400 Subject: [PATCH 003/157] Fix warning in configure sc_main compile. (#4499) --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index c530489f3..6ad04c29c 100644 --- a/configure.ac +++ b/configure.ac @@ -573,7 +573,7 @@ ACO_SAVE_LIBS="$LIBS" LIBS="$LIBS -lsystemc" AC_LINK_IFELSE( [AC_LANG_PROGRAM([[#include - extern "C" int sc_main(int argc, char* argv[]) {} + extern "C" int sc_main(int argc, char* argv[]) { return 0; } ]],[[sc_version()]])], [_my_result=yes AC_DEFINE([HAVE_SYSTEMC],[1],[Defined if have SystemC library])], From ab13548018e3db957920bdcdc593358602ca87d9 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 17 Sep 2023 18:23:44 -0400 Subject: [PATCH 004/157] Support resizing function call inout arguments (#4467). --- Changes | 1 + src/V3AstNodeExpr.h | 15 +++ src/V3Task.cpp | 105 +++++++++++---- src/V3Width.cpp | 18 +-- test_regress/t/t_func_bad.out | 7 +- test_regress/t/t_func_tasknsvar_bad.out | 8 -- test_regress/t/t_func_tasknsvar_bad.v | 19 --- ...nc_tasknsvar_bad.pl => t_func_wide_out.pl} | 12 +- test_regress/t/t_func_wide_out.v | 125 ++++++++++++++++++ test_regress/t/t_func_wide_out_bad.out | 87 +++++++++++- test_regress/t/t_func_wide_out_bad.pl | 4 +- test_regress/t/t_func_wide_out_bad.v | 30 ----- test_regress/t/t_func_wide_out_c.cpp | 46 +++++++ test_regress/t/t_func_wide_out_noinl.pl | 25 ++++ test_regress/t/t_uvm_pkg_todo.vh | 40 ++---- 15 files changed, 408 insertions(+), 134 deletions(-) delete mode 100644 test_regress/t/t_func_tasknsvar_bad.out delete mode 100644 test_regress/t/t_func_tasknsvar_bad.v rename test_regress/t/{t_func_tasknsvar_bad.pl => t_func_wide_out.pl} (71%) create mode 100644 test_regress/t/t_func_wide_out.v delete mode 100644 test_regress/t/t_func_wide_out_bad.v create mode 100644 test_regress/t/t_func_wide_out_c.cpp create mode 100755 test_regress/t/t_func_wide_out_noinl.pl diff --git a/Changes b/Changes index 9c86598cf..6a13b022b 100644 --- a/Changes +++ b/Changes @@ -13,6 +13,7 @@ Verilator 5.017 devel **Minor:** +* Support resizing function call inout arguments (#4467). Verilator 5.016 2023-09-16 diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index e5e44c785..ec2f06693 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -5083,6 +5083,21 @@ public: bool sizeMattersLhs() const override { return false; } int instrCount() const override { return 1 + V3Number::log2b(width()); } }; +class AstResizeLValue final : public AstNodeUniop { + // Resize a LValue into a wider/narrower entity at function argument boundry + // Width and signness is implied from nodep->width() +public: + AstResizeLValue(FileLine* fl, AstNodeExpr* lhsp) + : ASTGEN_SUPER_ResizeLValue(fl, lhsp) {} + ASTGEN_MEMBERS_AstResizeLValue; + void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } + string emitVerilog() override { return "%l"; } + string emitC() final override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + int instrCount() const override { return 0; } +}; class AstSigned final : public AstNodeUniop { // $signed(lhs) public: diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 6dff27044..1170f3326 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -412,6 +412,53 @@ private: }); } + AstAssign* connectPortMakeInAssign(AstNodeExpr* pinp, AstVarScope* newvscp, bool pureCheck) { + // Create input assignment to go in FRONT of function call + AstNodeExpr* inPinp = pinp; + if (AstResizeLValue* sinPinp = VN_CAST(inPinp, ResizeLValue)) inPinp = sinPinp->lhsp(); + AstNodeExpr* const inPinClonep + = pureCheck ? inPinp->cloneTreePure(true) : inPinp->cloneTree(true); + AstAssign* const assp = new AstAssign{ + pinp->fileline(), new AstVarRef{newvscp->fileline(), newvscp, VAccess::WRITE}, + inPinClonep}; + assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); // Ok if in <= block + return assp; + } + AstAssign* connectPortMakeOutAssign(AstVar* portp, AstNodeExpr* pinp, AstVarScope* newvscp, + bool pureCheck) { + // If needed, remap size of function to caller's output size + AstNodeExpr* outPinp = pinp; + AstNodeExpr* postRhsp = new AstVarRef{newvscp->fileline(), newvscp, VAccess::READ}; + if (AstResizeLValue* soutPinp = VN_CAST(outPinp, ResizeLValue)) { + outPinp = soutPinp->lhsp(); + if (AstNodeUniop* soutPinp = VN_CAST(outPinp, Extend)) { + outPinp = soutPinp->lhsp(); + } else if (AstNodeUniop* soutPinp = VN_CAST(outPinp, ExtendS)) { + outPinp = soutPinp->lhsp(); + } else if (AstSel* soutPinp = VN_CAST(outPinp, Sel)) { + outPinp = soutPinp->fromp(); + } else { + outPinp->v3fatalSrc("Inout pin resizing should have had extend or select"); + } + if (outPinp->width() < portp->width()) { + postRhsp = new AstSel{pinp->fileline(), postRhsp, 0, pinp->width()}; + } else { // pin width > port width + if (pinp->isSigned() && postRhsp->isSigned()) { + postRhsp = new AstExtendS{pinp->fileline(), postRhsp}; + } else { + postRhsp = new AstExtend{pinp->fileline(), postRhsp}; + } + } + postRhsp->dtypeFrom(outPinp); + } + // Put output assignment AFTER function call + AstNodeExpr* const outPinClonep + = pureCheck ? outPinp->cloneTreePure(true) : outPinp->cloneTree(true); + AstAssign* const assp = new AstAssign{pinp->fileline(), outPinClonep, postRhsp}; + assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); // Ok if in <= block + return assp; + } + void connectPort(AstVar* portp, AstArg* argp, const string& namePrefix, AstNode* beginp, bool inlineTask) { AstNodeExpr* const pinp = argp->exprp(); @@ -432,23 +479,31 @@ private: pinp->v3error("Function/task " + portp->direction().prettyName() // e.g. "output" + " connected to constant instead of variable: " + portp->prettyNameQ()); - } else if (portp->isInoutish()) { - // Correct lvalue; see comments below + } + // else if (portp->direction() == VDirection::REF) { + // TODO References need to instead pass a real reference var, see issue #3385 + else if (portp->isInoutish()) { + // if (debug() >= 9) pinp->dumpTree("-pinrsize- "); V3LinkLValue::linkLValueSet(pinp); - if (AstVarRef* const varrefp = VN_CAST(pinp, VarRef)) { - // Connect to this exact variable - if (inlineTask) { - AstVarScope* const localVscp = varrefp->varScopep(); - UASSERT_OBJ(localVscp, varrefp, "Null var scope"); - portp->user2p(localVscp); - pushDeletep(pinp); - } - } else { - pinp->v3warn( - E_TASKNSVAR, - "Unsupported: Function/task input argument is not simple variable"); + AstVarScope* const newvscp + = createVarScope(portp, namePrefix + "__" + portp->shortName()); + portp->user2p(newvscp); + if (!inlineTask) + pinp->replaceWith( + new AstVarRef{newvscp->fileline(), newvscp, VAccess::READWRITE}); + + // Put input assignment in FRONT of all other statements + AstAssign* const preassp = connectPortMakeInAssign(pinp, newvscp, true); + if (AstNode* const afterp = beginp->nextp()) { + afterp->unlinkFrBackWithNext(); + AstNode::addNext(preassp, afterp); } + beginp->addNext(preassp); + + AstAssign* const postassp = connectPortMakeOutAssign(portp, pinp, newvscp, true); + beginp->addNext(postassp); + // if (debug() >= 9) beginp->dumpTreeAndNext(cout, "-pinrsize-out- "); } else if (portp->isWritable()) { // Make output variables // Correct lvalue; we didn't know when we linked @@ -463,29 +518,21 @@ private: portp->user2p(newvscp); if (!inlineTask) pinp->replaceWith(new AstVarRef{newvscp->fileline(), newvscp, VAccess::WRITE}); - AstAssign* const assp - = new AstAssign{pinp->fileline(), pinp, - new AstVarRef{newvscp->fileline(), newvscp, VAccess::READ}}; - assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, - true); // Ok if in <= block + AstAssign* const postassp = connectPortMakeOutAssign(portp, pinp, newvscp, false); // Put assignment BEHIND of all other statements - beginp->addNext(assp); + beginp->addNext(postassp); } else if (inlineTask && portp->isNonOutput()) { // Make input variable - AstVarScope* const inVscp + AstVarScope* const newvscp = createVarScope(portp, namePrefix + "__" + portp->shortName()); - portp->user2p(inVscp); - AstAssign* const assp = new AstAssign{ - pinp->fileline(), new AstVarRef{inVscp->fileline(), inVscp, VAccess::WRITE}, - pinp}; - assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, - true); // Ok if in <= block + portp->user2p(newvscp); + AstAssign* const preassp = connectPortMakeInAssign(pinp, newvscp, false); // Put assignment in FRONT of all other statements if (AstNode* const afterp = beginp->nextp()) { afterp->unlinkFrBackWithNext(); - AstNode::addNext(assp, afterp); + AstNode::addNext(preassp, afterp); } - beginp->addNext(assp); + beginp->addNext(preassp); } } } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index c00628e92..756cf3dc9 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -5577,7 +5577,7 @@ private: for (const auto& tconnect : tconnects) { const AstVar* const portp = tconnect.first; const AstArg* const argp = tconnect.second; - AstNode* const pinp = argp->exprp(); + AstNodeExpr* const pinp = argp->exprp(); if (!pinp) continue; // Argument error we'll find later AstNodeDType* const portDTypep = portp->dtypep()->skipRefToEnump(); const AstNodeDType* const pinDTypep = pinp->dtypep()->skipRefToEnump(); @@ -5588,13 +5588,15 @@ private: << portDTypep->prettyDTypeName() << " but connection is " << pinDTypep->prettyDTypeName() << "."); } else if (portp->isWritable() && pinp->width() != portp->width()) { - pinp->v3warn(E_UNSUPPORTED, "Unsupported: Function output argument " - << portp->prettyNameQ() << " requires " - << portp->width() << " bits, but connection's " - << pinp->prettyTypeName() << " generates " - << pinp->width() << " bits."); - // otherwise would need some mess to force both sides to proper size - // (get an ASSIGN with EXTEND on the lhs instead of rhs) + pinp->v3widthWarn(portp->width(), pinp->width(), + "Function output argument " + << portp->prettyNameQ() << " requires " << portp->width() + << " bits, but connection's " << pinp->prettyTypeName() + << " generates " << pinp->width() << " bits."); + VNRelinker relinkHandle; + pinp->unlinkFrBack(&relinkHandle); + AstNodeExpr* const newp = new AstResizeLValue{pinp->fileline(), pinp}; + relinkHandle.relink(newp); } if (!portp->basicp() || portp->basicp()->isOpaque()) { checkClassAssign(nodep, "Function Argument", pinp, portDTypep); diff --git a/test_regress/t/t_func_bad.out b/test_regress/t/t_func_bad.out index cac076c15..d5d2b8dc2 100644 --- a/test_regress/t/t_func_bad.out +++ b/test_regress/t/t_func_bad.out @@ -10,11 +10,12 @@ : ... In instance t 11 | x; | ^ -%Error-UNSUPPORTED: t/t_func_bad.v:11:7: Unsupported: Function output argument 'y' requires 1 bits, but connection's CONST '?32?h0' generates 32 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_func_bad.v:11:7: Function output argument 'y' requires 1 bits, but connection's CONST '?32?h0' generates 32 bits. + : ... In instance t 11 | x; | ^ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest + ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest + ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. %Error: t/t_func_bad.v:14:17: No such argument 'no_such' in function call to FUNC 'f' : ... In instance t 14 | f(.j(1), .no_such(2)); diff --git a/test_regress/t/t_func_tasknsvar_bad.out b/test_regress/t/t_func_tasknsvar_bad.out deleted file mode 100644 index 9fd20faba..000000000 --- a/test_regress/t/t_func_tasknsvar_bad.out +++ /dev/null @@ -1,8 +0,0 @@ -%Error-TASKNSVAR: t/t_func_tasknsvar_bad.v:16:29: Unsupported: Function/task input argument is not simple variable - 16 | foo(bus_we_select_from[2]); - | ^ - ... For error description see https://verilator.org/warn/TASKNSVAR?v=latest -%Error: Internal Error: t/t_func_tasknsvar_bad.v:10:7: ../V3Broken.cpp:#: Broken link in node (or something without maybePointedTo): 'm_varp && !m_varp->brokeExists()' @ ../V3AstNodes.cpp:# - 10 | sig = '1; - | ^~~ - ... See the manual at https://verilator.org/verilator_doc.html for more assistance. diff --git a/test_regress/t/t_func_tasknsvar_bad.v b/test_regress/t/t_func_tasknsvar_bad.v deleted file mode 100644 index 7f4a62308..000000000 --- a/test_regress/t/t_func_tasknsvar_bad.v +++ /dev/null @@ -1,19 +0,0 @@ -// DESCRIPTION: Verilator: Test of select from constant -// -// This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2020 by Wilson Snyder. -// SPDX-License-Identifier: CC0-1.0 - -module t (/*AUTOARG*/); - - task foo(inout sig); - sig = '1; - endtask - - reg [3:0] bus_we_select_from; - - initial begin - foo(bus_we_select_from[2]); // Will get TASKNSVAR error - end - -endmodule diff --git a/test_regress/t/t_func_tasknsvar_bad.pl b/test_regress/t/t_func_wide_out.pl similarity index 71% rename from test_regress/t/t_func_tasknsvar_bad.pl rename to test_regress/t/t_func_wide_out.pl index a5846c699..bdc7b0a29 100755 --- a/test_regress/t/t_func_tasknsvar_bad.pl +++ b/test_regress/t/t_func_wide_out.pl @@ -8,11 +8,15 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(vlt => 1); +scenarios(simulator => 1); -lint( - fails => 1, - expect_filename => $Self->{golden_filename}, +compile( + verilator_flags2 => ["-Wno-WIDTHTRUNC"], + v_flags2 => ["+define+T_FUNC_WIDE_OUT t/t_func_wide_out_c.cpp"], + ); + +execute( + check_finished => 1, ); ok(1); diff --git a/test_regress/t/t_func_wide_out.v b/test_regress/t/t_func_wide_out.v new file mode 100644 index 000000000..6a7c9fb1c --- /dev/null +++ b/test_regress/t/t_func_wide_out.v @@ -0,0 +1,125 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); + +typedef bit signed [11:0] s12_t; +typedef bit unsigned [11:0] u12_t; +typedef bit signed [69:0] s70_t; +typedef bit unsigned [69:0] u70_t; + +import "DPI-C" context function void dpii_inv_s12(input s12_t in, output s12_t out); +import "DPI-C" context function void dpii_inv_u12(input u12_t in, output u12_t out); +import "DPI-C" context function void dpii_inv_s70(input s70_t in, output s70_t out); +import "DPI-C" context function void dpii_inv_u70(input s70_t in, output u70_t out); + +class Cls #(type T = bit); + static function void get(inout T value); +`ifdef TEST_NOINLINE + // verilator no_inline_task +`endif + value = ~value; + endfunction +endclass + +module t; + + parameter MSG_PORT_WIDTH = 4350; + localparam PAYLOAD_MAX_BITS = 4352; + + reg [MSG_PORT_WIDTH-1:0] msg; + + function void func (output bit [PAYLOAD_MAX_BITS-1:0] data); +`ifdef TEST_NOINLINE + // verilator no_inline_task +`endif + data = {PAYLOAD_MAX_BITS{1'b1}}; + endfunction + + s12_t ds12; + u12_t du12; + s70_t ds70; + u70_t du70; + s12_t qs12; + u12_t qu12; + s70_t qs70; + u70_t qu70; + + initial begin + // Operator TASKREF 'func' expects 4352 bits on the Function Argument, but Function Argument's VARREF 'msg' generates 4350 bits. + // verilator lint_off WIDTHEXPAND + func(msg); + if (msg !== {MSG_PORT_WIDTH{1'b1}}) $stop; + + begin + // narrow connect to wide + ds12 = 12'h234; + Cls#(s70_t)::get(ds12); + `checkh(ds12, 12'hdcb); + ds12 = 12'he34; // negative if signed + Cls#(s70_t)::get(ds12); + `checkh(ds12, 12'h1cb); + + du12 = 12'h244; + Cls#(u70_t)::get(du12); + `checkh(du12, 12'hdbb); + du12 = 12'he34; // negative if signed + Cls#(u70_t)::get(du12); + `checkh(du12, 12'h1cb); + + // wie connect to narrow + ds70 = 12'h254; + Cls#(s12_t)::get(ds70); + `checkh(ds70, 70'h3ffffffffffffffdab); + ds70 = 12'he34; // negative if signed + Cls#(s12_t)::get(ds70); + `checkh(ds70, 70'h0000000000000001cb); + + du70 = 12'h264; + Cls#(u12_t)::get(du70); + `checkh(du70, 70'h000000000000000d9b); + du70 = 12'he34; // negative if signed + Cls#(u12_t)::get(du70); + `checkh(du70, 70'h0000000000000001cb); + end + + begin + // narrow connect to wide + ds12 = 12'h234; + dpii_inv_s70(ds12, qs12); + `checkh(qs12, 12'hdcb); + ds12 = 12'he34; // negative if signed + dpii_inv_s70(ds12, qs12); + `checkh(qs12, 12'h1cb); + + du12 = 12'h244; + dpii_inv_u70(du12, qu12); + `checkh(qu12, 12'hdbb); + du12 = 12'he34; // negative if signed + dpii_inv_u70(ds12, qs12); + `checkh(qs12, 12'h1cb); + + // wie connect to narrow + ds70 = 12'h254; + dpii_inv_s12(ds70, qs70); + `checkh(qs70, 70'h3ffffffffffffffdab); + ds70 = 12'he34; // negative if signed + dpii_inv_s12(ds70, qs70); + `checkh(qs70, 70'h0000000000000001cb); + + du70 = 12'h264; + dpii_inv_u12(du70, qu70); + `checkh(qu70, 70'h000000000000000d9b); + du70 = 12'he34; // negative if signed + dpii_inv_u12(du70, qu70); + `checkh(qu70, 70'h0000000000000001cb); + end + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_func_wide_out_bad.out b/test_regress/t/t_func_wide_out_bad.out index e10df9ce9..b2648177a 100644 --- a/test_regress/t/t_func_wide_out_bad.out +++ b/test_regress/t/t_func_wide_out_bad.out @@ -1,6 +1,83 @@ -%Error-UNSUPPORTED: t/t_func_wide_out_bad.v:17:12: Unsupported: Function output argument 'data' requires 4352 bits, but connection's VARREF 'msg' generates 4350 bits. - : ... In instance t - 17 | func(msg); - | ^~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Warning-WIDTHTRUNC: t/t_func_wide_out.v:76:27: Function output argument 'value' requires 12 bits, but connection's VARREF 'ds70' generates 70 bits. + : ... In instance t + 76 | Cls#(s12_t)::get(ds70); + | ^~~~ + ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest + ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. +%Warning-WIDTHTRUNC: t/t_func_wide_out.v:76:23: Operator TASKREF 'get' expects 12 bits on the Function Argument, but Function Argument's VARREF 'ds70' generates 70 bits. + : ... In instance t + 76 | Cls#(s12_t)::get(ds70); + | ^~~ +%Warning-WIDTHTRUNC: t/t_func_wide_out.v:79:27: Function output argument 'value' requires 12 bits, but connection's VARREF 'ds70' generates 70 bits. + : ... In instance t + 79 | Cls#(s12_t)::get(ds70); + | ^~~~ +%Warning-WIDTHTRUNC: t/t_func_wide_out.v:79:23: Operator TASKREF 'get' expects 12 bits on the Function Argument, but Function Argument's VARREF 'ds70' generates 70 bits. + : ... In instance t + 79 | Cls#(s12_t)::get(ds70); + | ^~~ +%Warning-WIDTHTRUNC: t/t_func_wide_out.v:83:27: Function output argument 'value' requires 12 bits, but connection's VARREF 'du70' generates 70 bits. + : ... In instance t + 83 | Cls#(u12_t)::get(du70); + | ^~~~ +%Warning-WIDTHTRUNC: t/t_func_wide_out.v:83:23: Operator TASKREF 'get' expects 12 bits on the Function Argument, but Function Argument's VARREF 'du70' generates 70 bits. + : ... In instance t + 83 | Cls#(u12_t)::get(du70); + | ^~~ +%Warning-WIDTHTRUNC: t/t_func_wide_out.v:86:27: Function output argument 'value' requires 12 bits, but connection's VARREF 'du70' generates 70 bits. + : ... In instance t + 86 | Cls#(u12_t)::get(du70); + | ^~~~ +%Warning-WIDTHTRUNC: t/t_func_wide_out.v:86:23: Operator TASKREF 'get' expects 12 bits on the Function Argument, but Function Argument's VARREF 'du70' generates 70 bits. + : ... In instance t + 86 | Cls#(u12_t)::get(du70); + | ^~~ +%Warning-WIDTHTRUNC: t/t_func_wide_out.v:108:10: Operator TASKREF 'dpii_inv_s12' expects 12 bits on the Function Argument, but Function Argument's VARREF 'ds70' generates 70 bits. + : ... In instance t + 108 | dpii_inv_s12(ds70, qs70); + | ^~~~~~~~~~~~ +%Warning-WIDTHTRUNC: t/t_func_wide_out.v:108:29: Function output argument 'out' requires 12 bits, but connection's VARREF 'qs70' generates 70 bits. + : ... In instance t + 108 | dpii_inv_s12(ds70, qs70); + | ^~~~ +%Warning-WIDTHTRUNC: t/t_func_wide_out.v:108:10: Operator TASKREF 'dpii_inv_s12' expects 12 bits on the Function Argument, but Function Argument's VARREF 'qs70' generates 70 bits. + : ... In instance t + 108 | dpii_inv_s12(ds70, qs70); + | ^~~~~~~~~~~~ +%Warning-WIDTHTRUNC: t/t_func_wide_out.v:111:10: Operator TASKREF 'dpii_inv_s12' expects 12 bits on the Function Argument, but Function Argument's VARREF 'ds70' generates 70 bits. + : ... In instance t + 111 | dpii_inv_s12(ds70, qs70); + | ^~~~~~~~~~~~ +%Warning-WIDTHTRUNC: t/t_func_wide_out.v:111:29: Function output argument 'out' requires 12 bits, but connection's VARREF 'qs70' generates 70 bits. + : ... In instance t + 111 | dpii_inv_s12(ds70, qs70); + | ^~~~ +%Warning-WIDTHTRUNC: t/t_func_wide_out.v:111:10: Operator TASKREF 'dpii_inv_s12' expects 12 bits on the Function Argument, but Function Argument's VARREF 'qs70' generates 70 bits. + : ... In instance t + 111 | dpii_inv_s12(ds70, qs70); + | ^~~~~~~~~~~~ +%Warning-WIDTHTRUNC: t/t_func_wide_out.v:115:10: Operator TASKREF 'dpii_inv_u12' expects 12 bits on the Function Argument, but Function Argument's VARREF 'du70' generates 70 bits. + : ... In instance t + 115 | dpii_inv_u12(du70, qu70); + | ^~~~~~~~~~~~ +%Warning-WIDTHTRUNC: t/t_func_wide_out.v:115:29: Function output argument 'out' requires 12 bits, but connection's VARREF 'qu70' generates 70 bits. + : ... In instance t + 115 | dpii_inv_u12(du70, qu70); + | ^~~~ +%Warning-WIDTHTRUNC: t/t_func_wide_out.v:115:10: Operator TASKREF 'dpii_inv_u12' expects 12 bits on the Function Argument, but Function Argument's VARREF 'qu70' generates 70 bits. + : ... In instance t + 115 | dpii_inv_u12(du70, qu70); + | ^~~~~~~~~~~~ +%Warning-WIDTHTRUNC: t/t_func_wide_out.v:118:10: Operator TASKREF 'dpii_inv_u12' expects 12 bits on the Function Argument, but Function Argument's VARREF 'du70' generates 70 bits. + : ... In instance t + 118 | dpii_inv_u12(du70, qu70); + | ^~~~~~~~~~~~ +%Warning-WIDTHTRUNC: t/t_func_wide_out.v:118:29: Function output argument 'out' requires 12 bits, but connection's VARREF 'qu70' generates 70 bits. + : ... In instance t + 118 | dpii_inv_u12(du70, qu70); + | ^~~~ +%Warning-WIDTHTRUNC: t/t_func_wide_out.v:118:10: Operator TASKREF 'dpii_inv_u12' expects 12 bits on the Function Argument, but Function Argument's VARREF 'qu70' generates 70 bits. + : ... In instance t + 118 | dpii_inv_u12(du70, qu70); + | ^~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_func_wide_out_bad.pl b/test_regress/t/t_func_wide_out_bad.pl index a60503a1f..15b164f6a 100755 --- a/test_regress/t/t_func_wide_out_bad.pl +++ b/test_regress/t/t_func_wide_out_bad.pl @@ -8,7 +8,9 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(linter => 1); +scenarios(vlt => 1); + +top_filename("t/t_func_wide_out.v"); lint( fails => 1, diff --git a/test_regress/t/t_func_wide_out_bad.v b/test_regress/t/t_func_wide_out_bad.v deleted file mode 100644 index e7fd53a4b..000000000 --- a/test_regress/t/t_func_wide_out_bad.v +++ /dev/null @@ -1,30 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2003 by Wilson Snyder. -// SPDX-License-Identifier: CC0-1.0 - -module t (); - - parameter MSG_PORT_WIDTH = 4350; - localparam PAYLOAD_MAX_BITS = 4352; - - reg [MSG_PORT_WIDTH-1:0] msg; - - initial begin - // Operator TASKREF 'func' expects 4352 bits on the Function Argument, but Function Argument's VARREF 'msg' generates 4350 bits. - // verilator lint_off WIDTH - func(msg); - // verilator lint_on WIDTH - if (msg !== {MSG_PORT_WIDTH{1'b1}}) $stop; - $write("*-* All Finished *-*\n"); - $finish; - end - - function integer func (output bit [PAYLOAD_MAX_BITS-1:0] data); - /*verilator no_inline_task*/ - data = {PAYLOAD_MAX_BITS{1'b1}}; - return 1; - endfunction - -endmodule diff --git a/test_regress/t/t_func_wide_out_c.cpp b/test_regress/t/t_func_wide_out_c.cpp new file mode 100644 index 000000000..7518d510b --- /dev/null +++ b/test_regress/t/t_func_wide_out_c.cpp @@ -0,0 +1,46 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2009-2009 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 +// +//************************************************************************* + +#include "svdpi.h" + +#include +#include + +//====================================================================== + +// clang-format off +#if defined(VERILATOR) +# ifdef T_FUNC_WIDE_OUT +# include "Vt_func_wide_out__Dpi.h" +# elif defined(T_FUNC_WIDE_OUT_NOINL) +# include "Vt_func_wide_out_noinl__Dpi.h" +# else +# error "Unknown test" +# endif +#elif defined(VCS) +# include "../vc_hdrs.h" +#else +# error "Unknown simulator for DPI test" +#endif +// clang-format on + +//====================================================================== + +void dpii_inv_s12(const svBitVecVal* in, svBitVecVal* out) { out[0] = ~in[0]; } +void dpii_inv_u12(const svBitVecVal* in, svBitVecVal* out) { out[0] = ~in[0]; } +void dpii_inv_s70(const svBitVecVal* in, svBitVecVal* out) { + out[0] = ~in[0]; + out[1] = ~in[1] & 0xf; +} +void dpii_inv_u70(const svBitVecVal* in, svBitVecVal* out) { + out[0] = ~in[0]; + out[1] = ~in[1] & 0xf; +} diff --git a/test_regress/t/t_func_wide_out_noinl.pl b/test_regress/t/t_func_wide_out_noinl.pl new file mode 100755 index 000000000..cfdf588bf --- /dev/null +++ b/test_regress/t/t_func_wide_out_noinl.pl @@ -0,0 +1,25 @@ +#!/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(simulator => 1); + +top_filename("t_func_wide_out.v"); + +compile( + verilator_flags2 => ["-Wno-WIDTHTRUNC"], + v_flags2 => ["+define+T_FUNC_WIDE_OUT_NOINL +define+TEST_NOINLINE t/t_func_wide_out_c.cpp"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_uvm_pkg_todo.vh b/test_regress/t/t_uvm_pkg_todo.vh index dceffefad..35f108a3d 100644 --- a/test_regress/t/t_uvm_pkg_todo.vh +++ b/test_regress/t/t_uvm_pkg_todo.vh @@ -13464,10 +13464,8 @@ function uvm_component::new (string name, uvm_component parent); event_pool = new("event_pool"); m_domain = parent.m_domain; reseed(); -//TODO issue #4467 - Fix UVM function output width reassignment -//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:13463:76: Unsupported: Function output argument 'value' requires 4096 bits, but connection's VARREF 'recording_detail' generates 32 bits. -//TODO if (!uvm_config_db #(uvm_bitstream_t)::get(this, "", "recording_detail", recording_detail)) -//TODO void'(uvm_config_db #(int)::get(this, "", "recording_detail", recording_detail)); + if (!uvm_config_db #(uvm_bitstream_t)::get(this, "", "recording_detail", recording_detail)) + void'(uvm_config_db #(int)::get(this, "", "recording_detail", recording_detail)); m_rh.set_name(get_full_name()); set_report_verbosity_level(parent.get_report_verbosity_level()); m_set_cl_msg_args(); @@ -15876,10 +15874,8 @@ virtual class uvm_port_base #(type IF=uvm_void) extends IF; m_min_size = min_size; m_max_size = max_size; m_comp = new(name, parent, this); -//TODO issue #4467 - Fix UVM function output width reassignment -//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:15875:75: Unsupported: Function output argument 'value' requires 4096 bits, but connection's VARREF 'tmp' generates 32 bits. -//TODO if (!uvm_config_int::get(m_comp, "", "check_connection_relationships",tmp)) -//TODO m_comp.set_report_id_action(s_connection_warning_id, UVM_NO_ACTION); + if (!uvm_config_int::get(m_comp, "", "check_connection_relationships",tmp)) + m_comp.set_report_id_action(s_connection_warning_id, UVM_NO_ACTION); endfunction function string get_name(); return m_comp.get_name(); @@ -26304,17 +26300,13 @@ function uvm_status_e uvm_reg::backdoor_read_func(uvm_reg_item rw); uvm_report_info ("RegMem", $sformatf("backdoor_read from %s ", hdl_concat.slices[j].path), UVM_DEBUG, "t/uvm/src/reg/uvm_reg.svh", 2192, "", 1); end if (hdl_concat.slices[j].offset < 0) begin -//TODO issue #4467 - Fix UVM function output width reassignment -//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:26297:57: Unsupported: Function output argument 'value' requires 1024 bits, but connection's VARREF 'val' generates 64 bits. -//TODO ok &= uvm_hdl_read(hdl_concat.slices[j].path,val); + ok &= uvm_hdl_read(hdl_concat.slices[j].path,val); continue; end begin uvm_reg_data_t slice; int k = hdl_concat.slices[j].offset; -//TODO issue #4467 - Fix UVM function output width reassignment -//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:26303:58: Unsupported: Function output argument 'value' requires 1024 bits, but connection's VARREF 'slice' generates 64 bits. -//TODO ok &= uvm_hdl_read(hdl_concat.slices[j].path, slice); + ok &= uvm_hdl_read(hdl_concat.slices[j].path, slice); repeat (hdl_concat.slices[j].size) begin val[k++] = slice[0]; slice >>= 1; @@ -29572,17 +29564,13 @@ function uvm_status_e uvm_mem::backdoor_read_func(uvm_reg_item rw); uvm_report_info ("RegModel", {"backdoor_read from ",hdl_path}, UVM_DEBUG, "t/uvm/src/reg/uvm_mem.svh", 1691, "", 1); end if (hdl_concat.slices[j].offset < 0) begin -//TODO issue #4467 - Fix UVM function output width reassignment -//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:29567:44: Unsupported: Function output argument 'value' requires 1024 bits, but connection's VARREF 'slice' generates 64 bits. -//TODO ok &= uvm_hdl_read(hdl_path, val); + ok &= uvm_hdl_read(hdl_path, val); continue; end begin uvm_reg_data_t slice; int k = hdl_concat.slices[j].offset; -//TODO issue #4467 - Fix UVM function output width reassignment -//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:34181:38: Unsupported: Function output argument 'value' requires 1024 bits, but connection's VARREF 'd' generates 64 bits. -//TODO ok &= uvm_hdl_read(hdl_path, slice); + ok &= uvm_hdl_read(hdl_path, slice); repeat (hdl_concat.slices[j].size) begin val[k++] = slice[0]; slice >>= 1; @@ -34196,13 +34184,11 @@ endfunction : __m_uvm_execute_field_op foreach (path.slices[j]) begin string p_ = path.slices[j].path; uvm_reg_data_t d; -//TODO issue #4467 - Fix UVM function output width reassignment -//TODO %Error: t/t_uvm_pkg_todo.vh:19861:21: Function Argument expects a CLASSREFDTYPE 'uvm_sequencer__Tz97_TBz97', got CLASSREFDTYPE 'uvm_sequencer__Tz97' -//TODO if (!uvm_hdl_read(p_,d)) -//TODO begin -//TODO if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"uvm_reg_mem_hdl_paths_seq")) -//TODO uvm_report_error ("uvm_reg_mem_hdl_paths_seq", $sformatf("HDL path \"%s\" for register \"%s\" is not readable", p_, r.get_full_name()), UVM_NONE, "t/uvm/src/reg/sequences/uvm_reg_mem_hdl_paths_seq.svh", 145, "", 1); -//TODO end + if (!uvm_hdl_read(p_,d)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"uvm_reg_mem_hdl_paths_seq")) + uvm_report_error ("uvm_reg_mem_hdl_paths_seq", $sformatf("HDL path \"%s\" for register \"%s\" is not readable", p_, r.get_full_name()), UVM_NONE, "t/uvm/src/reg/sequences/uvm_reg_mem_hdl_paths_seq.svh", 145, "", 1); + end if (!uvm_hdl_check_path(p_)) begin if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"uvm_reg_mem_hdl_paths_seq")) From b68f101e8152773d8a0823db9011abf296030d7a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 17 Sep 2023 19:49:38 -0400 Subject: [PATCH 005/157] Support preprocessing __LINE__ --- docs/guide/extensions.rst | 13 ++++++++++--- src/V3FileLine.cpp | 5 ++++- test_regress/t/t_preproc.out | 17 +++++++++++------ test_regress/t/t_preproc_comments.out | 17 +++++++++++------ test_regress/t/t_preproc_inc3.vh | 6 +++++- 5 files changed, 41 insertions(+), 17 deletions(-) diff --git a/docs/guide/extensions.rst b/docs/guide/extensions.rst index 5994fb770..26e1bc425 100644 --- a/docs/guide/extensions.rst +++ b/docs/guide/extensions.rst @@ -17,14 +17,21 @@ or "`ifdef`"'s may break other tools. .. option:: `__LINE__ - The :option:`\`__LINE__` define expands to the current filename as a - string, like C++'s __LINE__. This Verilator feature added in 2006 was - incorporated into IEEE 1800-2009. + The :option:`\`__LINE__` define expands to the current line number like + C++'s __LINE__. This Verilator feature added in 2006 was incorporated + into IEEE 1800-2009. .. option:: `error [string] This will report an error when encountered, like C++'s #error. +.. option:: `line + + As a special case `\`line \`__LINE__ "filename"` allows setting the + filename, without changing the line number. This is used for some + internal tests, so that debugging can leave the line numbers correctly + referring to the test file's line numbers. + .. option:: """ [string] """ A triple-quoted block specifies a string that may include newlines and diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index f3a0fb6de..87b7115a5 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -221,7 +221,10 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) { bool fail = false; const char* const ln = textp; while (*textp && !std::isspace(*textp)) ++textp; - if (std::isdigit(*ln)) { + if (0 == strncmp(ln, "`__LINE__", strlen("`__LINE__"))) { + // Special case - see docs - don't change other than accounting for `line itself + lineno(lineno() + 1); + } if (std::isdigit(*ln)) { lineno(std::atoi(ln)); } else { fail = true; diff --git a/test_regress/t/t_preproc.out b/test_regress/t/t_preproc.out index 1aa204271..6e09e8fcd 100644 --- a/test_regress/t/t_preproc.out +++ b/test_regress/t/t_preproc.out @@ -23,29 +23,34 @@ At file "t/t_preproc_inc2.vh" line 5 `line 7 "t/t_preproc_inc2.vh" 0 `line 1 "t/t_preproc_inc3.vh" 1 -`line 2 "inc3_a_filename_from_line_directive" 0 +`line 2 "t/t_preproc_inc3.vh" 0 -`line 7 "inc3_a_filename_from_line_directive" 0 +`line 6 "t/t_preproc_inc3.vh" 0 - At file "inc3_a_filename_from_line_directive" line 11 + At file "t/t_preproc_inc3.vh" line 10 +`line 12 "inc3_a_filename_from_line_directive_with_LINE" 0 + At file "inc3_a_filename_from_line_directive_with_LINE" line 12 +`line 100 "inc3_a_filename_from_line_directive" 0 + At file "inc3_a_filename_from_line_directive" line 100 -`line 13 "inc3_a_filename_from_line_directive" 0 + +`line 103 "inc3_a_filename_from_line_directive" 0 -`line 16 "inc3_a_filename_from_line_directive" 0 +`line 106 "inc3_a_filename_from_line_directive" 0 -`line 20 "inc3_a_filename_from_line_directive" 2 +`line 110 "inc3_a_filename_from_line_directive" 2 `line 7 "t/t_preproc_inc2.vh" 0 diff --git a/test_regress/t/t_preproc_comments.out b/test_regress/t/t_preproc_comments.out index 4c6a565ab..ba69fa2c0 100644 --- a/test_regress/t/t_preproc_comments.out +++ b/test_regress/t/t_preproc_comments.out @@ -23,29 +23,34 @@ At file "t/t_preproc_inc2.vh" line 5 `line 7 "t/t_preproc_inc2.vh" 0 `line 1 "t/t_preproc_inc3.vh" 1 -`line 2 "inc3_a_filename_from_line_directive" 0 // DESCRIPTION: Verilog::Preproc: Example source code +`line 2 "t/t_preproc_inc3.vh" 0 // This file ONLY is placed under the Creative Commons Public Domain, for // any use, without warranty, 2000-2007 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 -`line 7 "inc3_a_filename_from_line_directive" 0 +`line 6 "t/t_preproc_inc3.vh" 0 // FOO - At file "inc3_a_filename_from_line_directive" line 11 + At file "t/t_preproc_inc3.vh" line 10 +`line 12 "inc3_a_filename_from_line_directive_with_LINE" 0 + At file "inc3_a_filename_from_line_directive_with_LINE" line 12 +`line 100 "inc3_a_filename_from_line_directive" 0 + At file "inc3_a_filename_from_line_directive" line 100 -`line 13 "inc3_a_filename_from_line_directive" 0 + +`line 103 "inc3_a_filename_from_line_directive" 0 // guard -`line 16 "inc3_a_filename_from_line_directive" 0 +`line 106 "inc3_a_filename_from_line_directive" 0 -`line 20 "inc3_a_filename_from_line_directive" 2 +`line 110 "inc3_a_filename_from_line_directive" 2 `line 7 "t/t_preproc_inc2.vh" 0 diff --git a/test_regress/t/t_preproc_inc3.vh b/test_regress/t/t_preproc_inc3.vh index 0abaf0e7a..9d3d91ac4 100644 --- a/test_regress/t/t_preproc_inc3.vh +++ b/test_regress/t/t_preproc_inc3.vh @@ -1,4 +1,3 @@ -`line 2 "inc3_a_filename_from_line_directive" 0 // DESCRIPTION: Verilog::Preproc: Example source code // This file ONLY is placed under the Creative Commons Public Domain, for // any use, without warranty, 2000-2007 by Wilson Snyder. @@ -9,6 +8,11 @@ `define _EMPTY // FOO At file `__FILE__ line `__LINE__ +`line `__LINE__ "inc3_a_filename_from_line_directive_with_LINE" 0 + At file `__FILE__ line `__LINE__ +`line 100 "inc3_a_filename_from_line_directive" 0 + At file `__FILE__ line `__LINE__ + `else `error "INC2 File already included once" `endif // guard From 016278a75975dc49bd6100a516bfddde9280a6f8 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 17 Sep 2023 21:43:00 -0400 Subject: [PATCH 006/157] Commentary --- src/V3Ast.cpp | 4 ++-- src/V3Config.cpp | 4 ++-- src/V3Config.h | 2 +- src/V3FileLine.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 67dba756d..8f50841ae 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -372,8 +372,8 @@ AstNode* AstNode::addNext(AstNode* nodep, AstNode* newp) { void AstNode::addNextHere(AstNode* newp) { // Add to m_nextp on exact node passed, not at the end. - // This could be at head, tail, or both (single) - // New could be head of single node, or list + // 'this' could be at head, tail, or both (single) + // 'newp' could be head of single node, or list UASSERT(newp, "Null item passed to addNext"); UASSERT_OBJ(!newp->backp(), newp, "New node (back) already assigned?"); debugTreeChange(this, "-addHereThs: ", __LINE__, false); diff --git a/src/V3Config.cpp b/src/V3Config.cpp index 7bcb4b72c..de968acab 100644 --- a/src/V3Config.cpp +++ b/src/V3Config.cpp @@ -590,8 +590,8 @@ void V3Config::addVarAttr(FileLine* fl, const string& module, const string& ftas } } -void V3Config::addWaiver(V3ErrorCode code, const string& filename, const string& message) { - V3ConfigResolver::s().files().at(filename).addWaiver(code, message); +void V3Config::addWaiver(V3ErrorCode code, const string& filename, const string& match) { + V3ConfigResolver::s().files().at(filename).addWaiver(code, match); } void V3Config::applyCase(AstCase* nodep) { diff --git a/src/V3Config.h b/src/V3Config.h index 2ae32ef0d..bee0ea59e 100644 --- a/src/V3Config.h +++ b/src/V3Config.h @@ -41,7 +41,7 @@ public: static void addScopeTraceOn(bool on, const string& scope, int levels); static void addVarAttr(FileLine* fl, const string& module, const string& ftask, const string& signal, VAttrType type, AstSenTree* nodep); - static void addWaiver(V3ErrorCode code, const string& filename, const string& message); + static void addWaiver(V3ErrorCode code, const string& filename, const string& match); static void applyCase(AstCase* nodep); static void applyCoverageBlock(AstNodeModule* modulep, AstBegin* nodep); diff --git a/src/V3FileLine.h b/src/V3FileLine.h index 514299173..15541f418 100644 --- a/src/V3FileLine.h +++ b/src/V3FileLine.h @@ -121,7 +121,7 @@ std::ostream& operator<<(std::ostream& os, VFileContent* contentp); // File and line number of an object, mostly for error reporting -// This class is instantiated for every source code line (potentially millions), and instances +// This class is instantiated for every source code line (potentially millions), and instances // created at any point usually persist until the end of the program. To save space, per-file // information (e.g. filename, source language) is held in tables in the FileLineSingleton class. // Similarly, message enablement flags are interned in FileLineSingleton. From cd201f8eb88db35afd1cea824e3b1631f62d97d7 Mon Sep 17 00:00:00 2001 From: github action Date: Mon, 18 Sep 2023 01:44:43 +0000 Subject: [PATCH 007/157] Apply 'make format' --- src/V3FileLine.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index 87b7115a5..91ee773f2 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -224,7 +224,8 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) { if (0 == strncmp(ln, "`__LINE__", strlen("`__LINE__"))) { // Special case - see docs - don't change other than accounting for `line itself lineno(lineno() + 1); - } if (std::isdigit(*ln)) { + } + if (std::isdigit(*ln)) { lineno(std::atoi(ln)); } else { fail = true; From 47b3f464a9b15913ce3228132edb279954f03841 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Mon, 18 Sep 2023 15:21:30 +0200 Subject: [PATCH 008/157] Disable conversion of impure logical expressions to bitwise expressions (#487 partial) (#4437) --- configure.ac | 1 + src/V3Ast.cpp | 10 -- src/V3Ast.h | 22 +++- src/V3AstNodeExpr.h | 131 +++++++++++++------- src/V3AstNodeOther.h | 100 ++++++++------- src/V3AstNodes.cpp | 126 +++++++++++++++++-- src/V3Const.cpp | 32 ++--- src/V3Inline.cpp | 5 +- src/V3LinkInc.cpp | 4 +- src/V3Premit.cpp | 1 + src/V3Scope.cpp | 1 + src/V3Task.cpp | 3 + src/V3Width.cpp | 1 - test_regress/t/t_class_method_str_literal.v | 20 +++ test_regress/t/t_const_opt_shortcut.pl | 5 +- test_regress/t/t_dpi_shortcircuit.out | 20 --- test_regress/t/t_dpi_shortcircuit.pl | 5 +- 17 files changed, 318 insertions(+), 169 deletions(-) delete mode 100644 test_regress/t/t_dpi_shortcircuit.out diff --git a/configure.ac b/configure.ac index 6ad04c29c..c508bcfb9 100644 --- a/configure.ac +++ b/configure.ac @@ -442,6 +442,7 @@ m4_foreach([cflag],[ [-mno-cet], [-Qunused-arguments], [-Wno-bool-operation], + [-Wno-constant-logical-operand], [-Wno-tautological-bitwise-compare], [-Wno-parentheses-equality], [-Wno-sign-compare], diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 8f50841ae..ddde27f08 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -1343,16 +1343,6 @@ void AstNode::dumpTreeDotFile(const string& filename, bool append, bool doDump) } } -bool AstNode::isTreePureRecurse() const { - // Should memoize this if call commonly - if (!this->isPure()) return false; - if (this->op1p() && !this->op1p()->isTreePureRecurse()) return false; - if (this->op2p() && !this->op2p()->isTreePureRecurse()) return false; - if (this->op3p() && !this->op3p()->isTreePureRecurse()) return false; - if (this->op4p() && !this->op4p()->isTreePureRecurse()) return false; - return true; -} - string AstNode::instanceStr() const { // Max iterations before giving up on location search, // in case we have some circular reference bug. diff --git a/src/V3Ast.h b/src/V3Ast.h index 5de6ab906..8c42e41ba 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -167,6 +167,21 @@ inline std::ostream& operator<<(std::ostream& os, const VLifetime& rhs) { // ###################################################################### +class VPurity final { + // Used in some nodes to cache the result of isPure method +public: + enum en : uint8_t { NOT_CACHED, PURE, IMPURE }; + enum en m_e; + VPurity() + : m_e{NOT_CACHED} {} + bool isCached() const { return m_e != NOT_CACHED; } + bool isPure() const { return m_e == PURE; } + void setPurity(bool pure) { m_e = pure ? PURE : IMPURE; } + void clearCache() { m_e = NOT_CACHED; } +}; + +// ###################################################################### + class VAccess final { public: enum en : uint8_t { @@ -690,6 +705,7 @@ public: } bool isReadOnly() const VL_MT_SAFE { return m_e == INPUT || m_e == CONSTREF; } bool isWritable() const VL_MT_SAFE { return m_e == OUTPUT || m_e == INOUT || m_e == REF; } + bool isRef() const VL_MT_SAFE { return m_e == REF; } bool isRefOrConstRef() const VL_MT_SAFE { return m_e == REF || m_e == CONSTREF; } }; constexpr bool operator==(const VDirection& lhs, const VDirection& rhs) { @@ -2024,8 +2040,6 @@ public: void dumpTreeDot(std::ostream& os = std::cout) const; void dumpTreeDotFile(const string& filename, bool append = false, bool doDump = true); - bool isTreePureRecurse() const; - // METHODS - queries // Changes control flow, disable some optimizations virtual bool isBrancher() const { return false; } @@ -2034,11 +2048,11 @@ public: // GateDedupable is a slightly larger superset of GateOptimzable (eg, AstNodeIf) virtual bool isGateDedupable() const { return isGateOptimizable(); } // Else creates output or exits, etc, not unconsumed - virtual bool isOutputter() const { return false; } + virtual bool isOutputter() { return false; } // Else a AstTime etc which output can't be predicted from input virtual bool isPredictOptimizable() const { return !isTimingControl(); } // Else a $display, etc, that must be ordered with other displays - virtual bool isPure() const { return true; } + virtual bool isPure() { return true; } // Else a AstTime etc that can't be substituted out virtual bool isSubstOptimizable() const { return true; } // An event control, delay, wait, etc. diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index ec2f06693..823c26a05 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -64,11 +64,14 @@ public: // Wrap This expression into an AstStmtExpr to denote it occurs in statement position inline AstStmtExpr* makeStmt(); + virtual void clearCachedPurity(){}; // Most nodes don't cache their purity }; class AstNodeBiop VL_NOT_FINAL : public AstNodeExpr { // Binary expression // @astgen op1 := lhsp : AstNodeExpr // @astgen op2 := rhsp : AstNodeExpr + VPurity m_purity; // Pure state + protected: AstNodeBiop(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp) : AstNodeExpr{t, fl} { @@ -93,6 +96,12 @@ public: virtual bool stringFlavor() const { return false; } // N flavor of nodes with both flavors? int instrCount() const override { return widthInstrs(); } bool same(const AstNode*) const override { return true; } + bool isPure() override; + const char* broken() const override; + void clearCachedPurity() override; + +private: + bool getPurity() const { return lhsp()->isPure() && rhsp()->isPure(); } }; class AstNodeBiCom VL_NOT_FINAL : public AstNodeBiop { // Binary expr with commutative properties @@ -196,8 +205,8 @@ public: } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override; - bool isOutputter() const override { return !isPure(); } + bool isPure() override; + bool isOutputter() override { return !isPure(); } AstCFunc* funcp() const { return m_funcp; } void funcp(AstCFunc* funcp) { m_funcp = funcp; } void argTypes(const string& str) { m_argTypes = str; } @@ -219,6 +228,8 @@ class AstNodeFTaskRef VL_NOT_FINAL : public AstNodeExpr { string m_dotted; // Dotted part of scope the name()ed task/func is under or "" string m_inlinedDots; // Dotted hierarchy flattened out bool m_pli = false; // Pli system call ($name) + VPurity m_purity; // Pure state + protected: AstNodeFTaskRef(VNType t, FileLine* fl, AstNode* namep, AstNodeExpr* pinsp) : AstNodeExpr{t, fl} { @@ -249,11 +260,15 @@ public: void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } bool pli() const { return m_pli; } void pli(bool flag) { m_pli = flag; } - bool isPure() const override; + bool isPure() override; string emitVerilog() final override { V3ERROR_NA_RETURN(""); } string emitC() final override { V3ERROR_NA_RETURN(""); } bool cleanOut() const final override { V3ERROR_NA_RETURN(true); } + void clearCachedPurity() override; + +private: + bool getPurity() const; }; class AstNodePreSel VL_NOT_FINAL : public AstNodeExpr { // Something that becomes an AstSel @@ -261,6 +276,8 @@ class AstNodePreSel VL_NOT_FINAL : public AstNodeExpr { // @astgen op2 := rhsp : AstNodeExpr // @astgen op3 := thsp : Optional[AstNodeExpr] // @astgen op4 := attrp : Optional[AstAttrOf] + VPurity m_purity; // Pure state + protected: AstNodePreSel(VNType t, FileLine* fl, AstNodeExpr* fromp, AstNodeExpr* rhsp, AstNodeExpr* thsp) : AstNodeExpr{t, fl} { @@ -277,6 +294,14 @@ public: string emitVerilog() final override { V3ERROR_NA_RETURN(""); } string emitC() final override { V3ERROR_NA_RETURN(""); } bool cleanOut() const final override { V3ERROR_NA_RETURN(true); } + bool isPure() override; + const char* broken() const override; + void clearCachedPurity() override; + +private: + bool getPurity() const { + return fromp()->isPure() && rhsp()->isPure() && (!thsp() || thsp()->isPure()); + } }; class AstNodeQuadop VL_NOT_FINAL : public AstNodeExpr { // 4-ary expression @@ -284,6 +309,8 @@ class AstNodeQuadop VL_NOT_FINAL : public AstNodeExpr { // @astgen op2 := rhsp : AstNodeExpr // @astgen op3 := thsp : AstNodeExpr // @astgen op4 := fhsp : AstNodeExpr + VPurity m_purity; // Pure state + protected: AstNodeQuadop(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, AstNodeExpr* thsp, AstNodeExpr* fhsp) @@ -311,6 +338,14 @@ public: virtual bool sizeMattersFhs() const = 0; // True if output result depends on ths size int instrCount() const override { return widthInstrs(); } bool same(const AstNode*) const override { return true; } + bool isPure() override; + const char* broken() const override; + void clearCachedPurity() override; + +private: + bool getPurity() const { + return lhsp()->isPure() && rhsp()->isPure() && thsp()->isPure() && fhsp()->isPure(); + } }; class AstNodeTermop VL_NOT_FINAL : public AstNodeExpr { // Terminal operator -- an operator with no "inputs" @@ -330,6 +365,8 @@ class AstNodeTriop VL_NOT_FINAL : public AstNodeExpr { // @astgen op1 := lhsp : AstNodeExpr // @astgen op2 := rhsp : AstNodeExpr // @astgen op3 := thsp : AstNodeExpr + VPurity m_purity; // Pure state + protected: AstNodeTriop(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, AstNodeExpr* thsp) : AstNodeExpr{t, fl} { @@ -354,6 +391,12 @@ public: virtual bool sizeMattersThs() const = 0; // True if output result depends on ths size int instrCount() const override { return widthInstrs(); } bool same(const AstNode*) const override { return true; } + bool isPure() override; + const char* broken() const override; + void clearCachedPurity() override; + +private: + bool getPurity() const { return lhsp()->isPure() && rhsp()->isPure() && thsp()->isPure(); } }; class AstNodeCond VL_NOT_FINAL : public AstNodeTriop { // @astgen alias op1 := condp @@ -403,6 +446,8 @@ public: class AstNodeUniop VL_NOT_FINAL : public AstNodeExpr { // Unary expression // @astgen op1 := lhsp : AstNodeExpr + VPurity m_purity; // Pure state + protected: AstNodeUniop(VNType t, FileLine* fl, AstNodeExpr* lhsp) : AstNodeExpr{t, fl} { @@ -424,6 +469,9 @@ public: virtual bool stringFlavor() const { return false; } // N flavor of nodes with both flavors? int instrCount() const override { return widthInstrs(); } bool same(const AstNode*) const override { return true; } + bool isPure() override; + const char* broken() const override; + void clearCachedPurity() override; }; class AstNodeSystemUniopD VL_NOT_FINAL : public AstNodeUniop { public: @@ -600,7 +648,7 @@ public: const AstCMethodHard* asamep = static_cast(samep); return (m_name == asamep->m_name); } - bool isPure() const override { return m_pure; } + bool isPure() override { return m_pure; } int instrCount() const override; string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } @@ -1121,7 +1169,7 @@ public: string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return true; } - bool isPure() const override { return false; } + bool isPure() override { return false; } bool same(const AstNode*) const override { return true; } }; class AstFError final : public AstNodeExpr { @@ -1139,7 +1187,7 @@ public: bool cleanOut() const override { return true; } int instrCount() const override { return widthInstrs() * 64; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering + bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering bool same(const AstNode* /*samep*/) const override { return true; } }; class AstFOpen final : public AstNodeExpr { @@ -1158,8 +1206,8 @@ public: string verilogKwd() const override { return "$fopen"; } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } - bool isOutputter() const override { return true; } + bool isPure() override { return false; } + bool isOutputter() override { return true; } bool isUnlikely() const override { return true; } bool same(const AstNode* /*samep*/) const override { return true; } }; @@ -1177,8 +1225,8 @@ public: string verilogKwd() const override { return "$fopen"; } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } - bool isOutputter() const override { return true; } + bool isPure() override { return false; } + bool isOutputter() override { return true; } bool isUnlikely() const override { return true; } bool same(const AstNode* /*samep*/) const override { return true; } }; @@ -1201,8 +1249,8 @@ public: string emitC() override { V3ERROR_NA_RETURN(""); } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering - bool isOutputter() const override { return true; } // SPECIAL: makes output + bool isPure() override { return false; } // SPECIAL: has 'visual' ordering + bool isOutputter() override { return true; } // SPECIAL: makes output bool cleanOut() const override { return false; } bool same(const AstNode* /*samep*/) const override { return true; } }; @@ -1219,8 +1267,8 @@ public: string emitC() override { V3ERROR_NA_RETURN(""); } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } - bool isOutputter() const override { return true; } + bool isPure() override { return false; } + bool isOutputter() override { return true; } bool isUnlikely() const override { return true; } bool cleanOut() const override { return false; } bool same(const AstNode* /*samep*/) const override { return true; } @@ -1244,8 +1292,8 @@ public: string emitC() override { V3ERROR_NA_RETURN(""); } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering - bool isOutputter() const override { return true; } // SPECIAL: makes output + bool isPure() override { return false; } // SPECIAL: has 'visual' ordering + bool isOutputter() override { return true; } // SPECIAL: makes output bool cleanOut() const override { return false; } bool same(const AstNode* samep) const override { return text() == static_cast(samep)->text(); @@ -1270,8 +1318,8 @@ public: string emitC() override { V3ERROR_NA_RETURN(""); } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering - bool isOutputter() const override { return true; } // SPECIAL: makes output + bool isPure() override { return false; } // SPECIAL: has 'visual' ordering + bool isOutputter() override { return true; } // SPECIAL: makes output bool cleanOut() const override { return false; } bool same(const AstNode* /*samep*/) const override { return true; } }; @@ -1288,8 +1336,8 @@ public: string emitC() override { V3ERROR_NA_RETURN(""); } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } - bool isOutputter() const override { return true; } + bool isPure() override { return false; } + bool isOutputter() override { return true; } bool isUnlikely() const override { return true; } bool cleanOut() const override { return false; } bool same(const AstNode* /*samep*/) const override { return true; } @@ -1766,8 +1814,8 @@ public: string emitC() override { V3ERROR_NA_RETURN(""); } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering - bool isOutputter() const override { return true; } // SPECIAL: makes output + bool isPure() override { return false; } // SPECIAL: has 'visual' ordering + bool isOutputter() override { return true; } // SPECIAL: makes output bool cleanOut() const override { return false; } bool same(const AstNode* samep) const override { return text() == static_cast(samep)->text(); @@ -1924,8 +1972,8 @@ public: string emitC() override { return "VL_STACKTRACE_N()"; } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } - bool isOutputter() const override { return true; } + bool isPure() override { return false; } + bool isOutputter() override { return true; } bool isUnlikely() const override { return true; } bool cleanOut() const override { return true; } bool same(const AstNode* /*samep*/) const override { return true; } @@ -1970,8 +2018,8 @@ public: string verilogKwd() const override { return "$ignored"; } bool isGateOptimizable() const override { return false; } // Though deleted before opt bool isPredictOptimizable() const override { return false; } // Though deleted before opt - bool isPure() const override { return false; } // Though deleted before opt - bool isOutputter() const override { return true; } // Though deleted before opt + bool isPure() override { return false; } // Though deleted before opt + bool isOutputter() override { return true; } // Though deleted before opt int instrCount() const override { return INSTR_COUNT_PLI; } string emitVerilog() override { V3ERROR_NA_RETURN(""); } @@ -1992,8 +2040,8 @@ public: string emitC() override { return "VL_SYSTEM_%nq(%lw, %P)"; } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } - bool isOutputter() const override { return true; } + bool isPure() override { return false; } + bool isOutputter() override { return true; } bool isUnlikely() const override { return true; } bool cleanOut() const override { return true; } bool same(const AstNode* /*samep*/) const override { return true; } @@ -2076,8 +2124,8 @@ public: bool cleanOut() const override { return false; } string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } - bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs - bool isOutputter() const override { return true; } + bool isPure() override { return false; } // SPECIAL: User may order w/other sigs + bool isOutputter() override { return true; } bool isGateOptimizable() const override { return false; } bool isSubstOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } @@ -2132,7 +2180,7 @@ public: string emitC() override { V3ERROR_NA_RETURN(""); } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return !outp(); } + bool isPure() override { return !outp(); } bool cleanOut() const override { return true; } bool same(const AstNode* /*samep*/) const override { return true; } }; @@ -2239,7 +2287,7 @@ public: bool sizeMattersLhs() const override { return false; } bool sizeMattersRhs() const override { return false; } int instrCount() const override { return widthInstrs() * 20; } - bool isPure() const override { return true; } + bool isPure() override { return true; } }; class AstCompareNN final : public AstNodeBiop { // Verilog str.compare() and str.icompare() @@ -2463,7 +2511,7 @@ public: bool sizeMattersRhs() const override { return false; } int instrCount() const override { return widthInstrs() * 64; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering + bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering AstNode* filep() const { return lhsp(); } AstNode* charp() const { return rhsp(); } }; @@ -2748,11 +2796,6 @@ public: int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } }; class AstLogOr final : public AstNodeBiop { - // LOGOR with optional side effects - // Side effects currently used in some V3Width code - // TBD if this concept is generally adopted for side-effect tracking - // versus V3Const tracking it itself - bool m_sideEffect = false; // Has side effect, relies on short-circuiting public: AstLogOr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp) : ASTGEN_SUPER_LogOr(fl, lhsp, rhsp) { @@ -2765,11 +2808,6 @@ public: void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { out.opLogOr(lhs, rhs); } - bool same(const AstNode* samep) const override { - const AstLogOr* const sp = static_cast(samep); - return m_sideEffect == sp->m_sideEffect; - } - void dump(std::ostream& str = std::cout) const override; string emitVerilog() override { return "%k(%l %f|| %r)"; } string emitC() override { return "VL_LOGOR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } string emitSimpleOperator() override { return "||"; } @@ -2779,9 +2817,6 @@ public: bool sizeMattersLhs() const override { return false; } bool sizeMattersRhs() const override { return false; } int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } - bool isPure() const override { return !m_sideEffect; } - void sideEffect(bool flag) { m_sideEffect = flag; } - bool sideEffect() const { return m_sideEffect; } }; class AstLt final : public AstNodeBiop { public: @@ -4760,7 +4795,7 @@ public: bool sizeMattersLhs() const override { return false; } int instrCount() const override { return widthInstrs() * 16; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering + bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering AstNode* filep() const { return lhsp(); } }; class AstFGetC final : public AstNodeUniop { @@ -4777,7 +4812,7 @@ public: bool sizeMattersLhs() const override { return false; } int instrCount() const override { return widthInstrs() * 64; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering + bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering AstNode* filep() const { return lhsp(); } }; class AstISToRD final : public AstNodeUniop { diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index ffb7ef422..23e1b0891 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -88,6 +88,8 @@ private: bool m_virtual : 1; // Virtual method in class bool m_needProcess : 1; // Implements part of a process that allocates std::process VLifetime m_lifetime; // Lifetime + VPurity m_purity; // Pure state + protected: AstNodeFTask(VNType t, FileLine* fl, const string& name, AstNode* stmtsp) : AstNode{t, fl} @@ -180,6 +182,8 @@ public: void lifetime(const VLifetime& flag) { m_lifetime = flag; } VLifetime lifetime() const { return m_lifetime; } bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); } + bool isPure() override; + const char* broken() const override; void propagateAttrFrom(const AstNodeFTask* fromp) { // Creating a wrapper with e.g. cloneType(); preserve some attributes classMethod(fromp->classMethod()); @@ -189,6 +193,9 @@ public: lifetime(fromp->lifetime()); underGenerate(fromp->underGenerate()); } + +private: + bool getPurity() const; }; class AstNodeFile VL_NOT_FINAL : public AstNode { // Emitted Output file @@ -469,8 +476,8 @@ public: ASTGEN_MEMBERS_AstNodeReadWriteMem; bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } - bool isOutputter() const override { return true; } + bool isPure() override { return false; } + bool isOutputter() override { return true; } bool isUnlikely() const override { return true; } bool same(const AstNode* samep) const override { return isHex() == static_cast(samep)->isHex(); @@ -994,8 +1001,8 @@ public: string verilogKwd() const override { return string{"$"} + string{displayType().ascii()}; } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering - bool isOutputter() const override { return true; } // SPECIAL: $display makes output + bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering + bool isOutputter() override { return true; } // SPECIAL: $display makes output bool isUnlikely() const override { return true; } bool same(const AstNode* samep) const override { return displayType() == static_cast(samep)->displayType(); @@ -1915,6 +1922,7 @@ public: bool isInoutish() const { return m_direction.isInoutish(); } bool isNonOutput() const { return m_direction.isNonOutput(); } bool isReadOnly() const VL_MT_SAFE { return m_direction.isReadOnly(); } + bool isRef() const VL_MT_SAFE { return m_direction.isRef(); } bool isWritable() const VL_MT_SAFE { return m_direction.isWritable(); } bool isTristate() const { return m_tristate; } bool isPrimaryIO() const { return m_primaryIO; } @@ -2616,7 +2624,7 @@ public: } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isOutputter() const override { return true; } + bool isOutputter() override { return true; } // but isPure() true AstCoverDecl* declp() const { return m_declp; } // Where defined }; @@ -2638,7 +2646,7 @@ public: bool same(const AstNode* /*samep*/) const override { return true; } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return true; } - bool isOutputter() const override { + bool isOutputter() override { return false; // Though the AstCoverInc under this is an outputter } // but isPure() true @@ -2715,8 +2723,8 @@ public: } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering - bool isOutputter() const override { return true; } // SPECIAL: $display makes output + bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering + bool isOutputter() override { return true; } // SPECIAL: $display makes output bool isUnlikely() const override { return true; } bool same(const AstNode* samep) const override { return displayType() == static_cast(samep)->displayType(); @@ -2758,7 +2766,7 @@ public: string verilogKwd() const override { return ctlType().ascii(); } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isOutputter() const override { return true; } + bool isOutputter() override { return true; } virtual bool cleanOut() const { return true; } bool same(const AstNode* /*samep*/) const override { return true; } VDumpCtlType ctlType() const { return m_ctlType; } @@ -2790,8 +2798,8 @@ public: string verilogKwd() const override { return "$fclose"; } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } - bool isOutputter() const override { return true; } + bool isPure() override { return false; } + bool isOutputter() override { return true; } bool isUnlikely() const override { return true; } bool same(const AstNode* /*samep*/) const override { return true; } }; @@ -2807,8 +2815,8 @@ public: string verilogKwd() const override { return "$fflush"; } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } - bool isOutputter() const override { return true; } + bool isPure() override { return false; } + bool isOutputter() override { return true; } bool isUnlikely() const override { return true; } bool same(const AstNode* /*samep*/) const override { return true; } }; @@ -2819,8 +2827,8 @@ public: ASTGEN_MEMBERS_AstFinish; bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering - bool isOutputter() const override { return true; } // SPECIAL: $display makes output + bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering + bool isOutputter() override { return true; } // SPECIAL: $display makes output bool isUnlikely() const override { return true; } int instrCount() const override { return 0; } // Rarely executes bool same(const AstNode* samep) const override { return fileline() == samep->fileline(); } @@ -2942,8 +2950,8 @@ public: string verilogKwd() const override { return m_off ? "$monitoroff" : "$monitoron"; } bool isGateOptimizable() const override { return false; } // Though deleted before opt bool isPredictOptimizable() const override { return false; } // Though deleted before opt - bool isPure() const override { return false; } // Though deleted before opt - bool isOutputter() const override { return true; } // Though deleted before opt + bool isPure() override { return false; } // Though deleted before opt + bool isOutputter() override { return true; } // Though deleted before opt int instrCount() const override { return INSTR_COUNT_PLI; } bool same(const AstNode* samep) const override { return m_off == static_cast(samep)->m_off; @@ -2964,8 +2972,8 @@ public: string verilogKwd() const override { return "$printtimescale"; } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } - bool isOutputter() const override { return true; } + bool isPure() override { return false; } + bool isOutputter() override { return true; } int instrCount() const override { return INSTR_COUNT_PLI; } void timeunit(const VTimescale& flag) { m_timeunit = flag; } VTimescale timeunit() const { return m_timeunit; } @@ -3042,8 +3050,8 @@ public: string verilogKwd() const override { return "$sformat"; } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return true; } - bool isPure() const override { return true; } - bool isOutputter() const override { return false; } + bool isPure() override { return true; } + bool isOutputter() override { return false; } virtual bool cleanOut() const { return false; } int instrCount() const override { return INSTR_COUNT_PLI; } bool same(const AstNode* /*samep*/) const override { return true; } @@ -3057,8 +3065,8 @@ public: string verilogKwd() const override { return "$stacktrace"; } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } - bool isOutputter() const override { return true; } + bool isPure() override { return false; } + bool isOutputter() override { return true; } bool isUnlikely() const override { return true; } bool same(const AstNode* /*samep*/) const override { return true; } }; @@ -3079,8 +3087,8 @@ public: ASTGEN_MEMBERS_AstStop; bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering - bool isOutputter() const override { return true; } // SPECIAL: $display makes output + bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering + bool isOutputter() override { return true; } // SPECIAL: $display makes output bool isUnlikely() const override { return true; } int instrCount() const override { return 0; } // Rarely executes bool same(const AstNode* samep) const override { return fileline() == samep->fileline(); } @@ -3098,8 +3106,8 @@ public: string verilogKwd() const override { return ""; } bool isGateOptimizable() const override { return true; } bool isPredictOptimizable() const override { return true; } - bool isPure() const override { return true; } - bool isOutputter() const override { return false; } + bool isPure() override { return true; } + bool isOutputter() override { return false; } int instrCount() const override { return 0; } bool same(const AstNode* /*samep*/) const override { return true; } }; @@ -3115,8 +3123,8 @@ public: string verilogKwd() const override { return "$system"; } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } - bool isOutputter() const override { return true; } + bool isPure() override { return false; } + bool isOutputter() override { return true; } bool isUnlikely() const override { return true; } bool same(const AstNode* /*samep*/) const override { return true; } }; @@ -3139,8 +3147,8 @@ public: string verilogKwd() const override { return "$timeformat"; } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } - bool isOutputter() const override { return true; } + bool isPure() override { return false; } + bool isOutputter() override { return true; } int instrCount() const override { return INSTR_COUNT_PLI; } }; class AstTraceDecl final : public AstNodeStmt { @@ -3229,7 +3237,7 @@ public: } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isOutputter() const override { return true; } + bool isOutputter() override { return true; } // but isPure() true AstTraceDecl* declp() const { return m_declp; } bool full() const { return m_full; } @@ -3266,8 +3274,8 @@ public: ASTGEN_MEMBERS_AstUCStmt; bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } - bool isOutputter() const override { return true; } + bool isPure() override { return false; } + bool isOutputter() override { return true; } bool same(const AstNode* /*samep*/) const override { return true; } }; class AstWait final : public AstNodeStmt { @@ -3557,48 +3565,48 @@ public: AstScCtor(FileLine* fl, const string& textp) : ASTGEN_SUPER_ScCtor(fl, textp) {} ASTGEN_MEMBERS_AstScCtor; - bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs - bool isOutputter() const override { return true; } + bool isPure() override { return false; } // SPECIAL: User may order w/other sigs + bool isOutputter() override { return true; } }; class AstScDtor final : public AstNodeText { public: AstScDtor(FileLine* fl, const string& textp) : ASTGEN_SUPER_ScDtor(fl, textp) {} ASTGEN_MEMBERS_AstScDtor; - bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs - bool isOutputter() const override { return true; } + bool isPure() override { return false; } // SPECIAL: User may order w/other sigs + bool isOutputter() override { return true; } }; class AstScHdr final : public AstNodeText { public: AstScHdr(FileLine* fl, const string& textp) : ASTGEN_SUPER_ScHdr(fl, textp) {} ASTGEN_MEMBERS_AstScHdr; - bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs - bool isOutputter() const override { return true; } + bool isPure() override { return false; } // SPECIAL: User may order w/other sigs + bool isOutputter() override { return true; } }; class AstScImp final : public AstNodeText { public: AstScImp(FileLine* fl, const string& textp) : ASTGEN_SUPER_ScImp(fl, textp) {} ASTGEN_MEMBERS_AstScImp; - bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs - bool isOutputter() const override { return true; } + bool isPure() override { return false; } // SPECIAL: User may order w/other sigs + bool isOutputter() override { return true; } }; class AstScImpHdr final : public AstNodeText { public: AstScImpHdr(FileLine* fl, const string& textp) : ASTGEN_SUPER_ScImpHdr(fl, textp) {} ASTGEN_MEMBERS_AstScImpHdr; - bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs - bool isOutputter() const override { return true; } + bool isPure() override { return false; } // SPECIAL: User may order w/other sigs + bool isOutputter() override { return true; } }; class AstScInt final : public AstNodeText { public: AstScInt(FileLine* fl, const string& textp) : ASTGEN_SUPER_ScInt(fl, textp) {} ASTGEN_MEMBERS_AstScInt; - bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs - bool isOutputter() const override { return true; } + bool isPure() override { return false; } // SPECIAL: User may order w/other sigs + bool isOutputter() override { return true; } }; // === AstNodeSimpleText === diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 9a35b190b..29fbf3902 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -51,6 +51,7 @@ AstIface* AstIfaceRefDType::ifaceViaCellp() const { const char* AstNodeFTaskRef::broken() const { BROKEN_RTN(m_taskp && !m_taskp->brokeExists()); BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); + BROKEN_RTN(m_purity.isCached() && m_purity.isPure() != getPurity()); return nullptr; } @@ -61,12 +62,34 @@ void AstNodeFTaskRef::cloneRelink() { } } -bool AstNodeFTaskRef::isPure() const { - // TODO: For non-DPI functions we could traverse the AST of function's body to determine - // pureness. - return this->taskp() && this->taskp()->dpiImport() && this->taskp()->dpiPure(); +bool AstNodeFTaskRef::isPure() { + if (!this->taskp()) { + // The task isn't linked yet, so it's assumed that it is impure, but the value shouldn't be + // cached. + return false; + } else { + if (!m_purity.isCached()) m_purity.setPurity(this->getPurity()); + return m_purity.isPure(); + } } +void AstNodeFTaskRef::clearCachedPurity() { + m_purity.clearCache(); + if (AstNodeExpr* const exprp = VN_CAST(backp(), NodeExpr)) exprp->clearCachedPurity(); +} + +bool AstNodeFTaskRef::getPurity() const { + AstNodeFTask* const taskp = this->taskp(); + // Unlinked yet, so treat as impure + if (!taskp) return false; + + // First compute the purity of arguments + for (AstNode* pinp = this->pinsp(); pinp; pinp = pinp->nextp()) { + if (!pinp->isPure()) return false; + } + + return taskp->isPure(); +} bool AstNodeFTaskRef::isGateOptimizable() const { return m_taskp && m_taskp->isGateOptimizable(); } const char* AstNodeVarRef::broken() const { @@ -121,7 +144,71 @@ const char* AstNodeCCall::broken() const { BROKEN_RTN(m_funcp && !m_funcp->brokeExists()); return nullptr; } -bool AstNodeCCall::isPure() const { return funcp()->dpiPure(); } +bool AstNodeCCall::isPure() { return funcp()->dpiPure(); } +bool AstNodeUniop::isPure() { + if (!m_purity.isCached()) m_purity.setPurity(lhsp()->isPure()); + return m_purity.isPure(); +} +const char* AstNodeUniop::broken() const { + BROKEN_RTN(m_purity.isCached() && m_purity.isPure() != lhsp()->isPure()); + return nullptr; +} +void AstNodeUniop::clearCachedPurity() { + m_purity.clearCache(); + if (AstNodeExpr* const exprp = VN_CAST(backp(), NodeExpr)) exprp->clearCachedPurity(); +} + +bool AstNodeBiop::isPure() { + if (!m_purity.isCached()) m_purity.setPurity(getPurity()); + return m_purity.isPure(); +} +const char* AstNodeBiop::broken() const { + BROKEN_RTN(m_purity.isCached() && m_purity.isPure() != getPurity()); + return nullptr; +} +void AstNodeBiop::clearCachedPurity() { + m_purity.clearCache(); + if (AstNodeExpr* const exprp = VN_CAST(backp(), NodeExpr)) exprp->clearCachedPurity(); +} + +bool AstNodeTriop::isPure() { + if (!m_purity.isCached()) m_purity.setPurity(getPurity()); + return m_purity.isPure(); +} +const char* AstNodeTriop::broken() const { + BROKEN_RTN(m_purity.isCached() && m_purity.isPure() != getPurity()); + return nullptr; +} +void AstNodeTriop::clearCachedPurity() { + m_purity.clearCache(); + if (AstNodeExpr* const exprp = VN_CAST(backp(), NodeExpr)) exprp->clearCachedPurity(); +} + +bool AstNodePreSel::isPure() { + if (!m_purity.isCached()) m_purity.setPurity(getPurity()); + return m_purity.isPure(); +} +const char* AstNodePreSel::broken() const { + BROKEN_RTN(m_purity.isCached() && m_purity.isPure() != getPurity()); + return nullptr; +} +void AstNodePreSel::clearCachedPurity() { + m_purity.clearCache(); + if (AstNodeExpr* const exprp = VN_CAST(backp(), NodeExpr)) exprp->clearCachedPurity(); +} + +bool AstNodeQuadop::isPure() { + if (!m_purity.isCached()) m_purity.setPurity(getPurity()); + return m_purity.isPure(); +} +const char* AstNodeQuadop::broken() const { + BROKEN_RTN(m_purity.isCached() && m_purity.isPure() != getPurity()); + return nullptr; +} +void AstNodeQuadop::clearCachedPurity() { + m_purity.clearCache(); + if (AstNodeExpr* const exprp = VN_CAST(backp(), NodeExpr)) exprp->clearCachedPurity(); +} AstNodeCond::AstNodeCond(VNType t, FileLine* fl, AstNodeExpr* condp, AstNodeExpr* thenp, AstNodeExpr* elsep) @@ -1622,10 +1709,6 @@ void AstJumpLabel::dump(std::ostream& str) const { str << "%Error:UNLINKED"; } } -void AstLogOr::dump(std::ostream& str) const { - this->AstNodeExpr::dump(str); - if (sideEffect()) str << " [SIDE]"; -} void AstMemberDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); @@ -2218,6 +2301,31 @@ void AstNodeFTask::dump(std::ostream& str) const { if (taskPublic()) str << " [PUBLIC]"; if ((dpiImport() || dpiExport()) && cname() != name()) str << " [c=" << cname() << "]"; } +bool AstNodeFTask::isPure() { + if (!m_purity.isCached()) m_purity.setPurity(getPurity()); + return m_purity.isPure(); +} +const char* AstNodeFTask::broken() const { + BROKEN_RTN(m_purity.isCached() && m_purity.isPure() != getPurity()); + return nullptr; +} +bool AstNodeFTask::getPurity() const { + if (this->dpiImport()) return this->dpiPure(); + // Check the list of statements if it contains any impure statement + // or any write reference to a variable that isn't an automatic function local. + for (AstNode* stmtp = this->stmtsp(); stmtp; stmtp = stmtp->nextp()) { + if (const AstVar* const varp = VN_CAST(stmtp, Var)) { + if (varp->isInoutish() || varp->isRef()) return false; + } + if (!stmtp->isPure()) return false; + if (stmtp->exists([](const AstNodeVarRef* const varrefp) { + return (!varrefp->varp()->isFuncLocal() || varrefp->varp()->lifetime().isStatic()) + && varrefp->access().isWriteOrRW(); + })) + return false; + } + return true; +} void AstNodeBlock::dump(std::ostream& str) const { this->AstNode::dump(str); if (unnamed()) str << " [UNNAMED]"; diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 888bd7780..b96b2fee8 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1217,13 +1217,13 @@ private: bool operandHugeShiftL(const AstNodeBiop* nodep) { return (VN_IS(nodep->rhsp(), Const) && !VN_AS(nodep->rhsp(), Const)->num().isFourState() && (VN_AS(nodep->rhsp(), Const)->toUInt() >= static_cast(nodep->width())) - && isTPure(nodep->lhsp())); + && nodep->lhsp()->isPure()); } bool operandHugeShiftR(const AstNodeBiop* nodep) { return (VN_IS(nodep->rhsp(), Const) && !VN_AS(nodep->rhsp(), Const)->num().isFourState() && (VN_AS(nodep->rhsp(), Const)->toUInt() >= static_cast(nodep->lhsp()->width())) - && isTPure(nodep->lhsp())); + && nodep->lhsp()->isPure()); } bool operandIsTwo(const AstNode* nodep) { return (VN_IS(nodep, Const) && !VN_AS(nodep, Const)->num().isFourState() @@ -1377,14 +1377,6 @@ private: return nodep; } - bool isTPure(AstNode* nodep) { - // Pure checks - if this node and all nodes under it are free of - // side effects can do this optimization - // Eventually we'll recurse through tree when unknown, memoizing results so far, - // but for now can disable en masse until V3Purify takes effect. - return m_doShort || VN_IS(nodep, VarRef) || VN_IS(nodep, Const); - } - // Extraction checks bool warnSelect(AstSel* nodep) { if (m_doGenerate) { @@ -1587,7 +1579,7 @@ private: // For example, "0 * n" -> 0 if n has no side effects // Else strength reduce it to 0 & n. // If ever change the operation note AstAnd rule specially ignores this created pattern - if (isTPure(checkp)) { + if (checkp->isPure()) { VL_DO_DANGLING(replaceNum(nodep, 0), nodep); } else { AstNode* const newp = new AstAnd{nodep->fileline(), new AstConst{nodep->fileline(), 0}, @@ -2053,7 +2045,7 @@ private: VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); return true; } - } else if (m_doV && VN_IS(nodep->lhsp(), Concat) && nodep->isTreePureRecurse()) { + } else if (m_doV && VN_IS(nodep->lhsp(), Concat) && nodep->isPure()) { bool need_temp = false; if (m_warn && !VN_IS(nodep, AssignDly)) { // Is same var on LHS and RHS? // Note only do this (need user4) when m_warn, which is @@ -3014,7 +3006,7 @@ private: } VL_DO_DANGLING(nodep->deleteTree(), nodep); } else if (!afterComment(nodep->thensp()) && !afterComment(nodep->elsesp())) { - if (!nodep->condp()->isTreePureRecurse()) { + if (!nodep->condp()->isPure()) { // Condition has side effect - leave - perhaps in // future simplify to remove all but side effect terms } else { @@ -3374,7 +3366,7 @@ private: TREEOPA("AstNodeQuadop{$lhsp.castConst, $rhsp.castConst, $thsp.castConst, $fhsp.castConst}", "replaceConst(nodep)"); // Zero on one side or the other TREEOP ("AstAdd {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)"); - TREEOP ("AstAnd {$lhsp.isZero, $rhsp, isTPure($rhsp)}", "replaceZero(nodep)"); // Can't use replaceZeroChkPure as we make this pattern in ChkPure + TREEOP ("AstAnd {$lhsp.isZero, $rhsp, $rhsp.isPure}", "replaceZero(nodep)"); // Can't use replaceZeroChkPure as we make this pattern in ChkPure // This visit function here must allow for short-circuiting. TREEOPS("AstLogAnd {$lhsp.isZero}", "replaceZero(nodep)"); TREEOP ("AstLogAnd{$lhsp.isZero, $rhsp}", "replaceZero(nodep)"); @@ -3414,12 +3406,12 @@ private: // Non-zero on one side or the other TREEOP ("AstAnd {$lhsp.isAllOnes, $rhsp}", "replaceWRhs(nodep)"); TREEOP ("AstLogAnd{$lhsp.isNeqZero, $rhsp}", "replaceWRhsBool(nodep)"); - TREEOP ("AstOr {$lhsp.isAllOnes, $rhsp, isTPure($rhsp)}", "replaceWLhs(nodep)"); // ->allOnes + TREEOP ("AstOr {$lhsp.isAllOnes, $rhsp, $rhsp.isPure}", "replaceWLhs(nodep)"); // ->allOnes TREEOP ("AstLogOr {$lhsp.isNeqZero, $rhsp}", "replaceNum(nodep,1)"); TREEOP ("AstAnd {$lhsp, $rhsp.isAllOnes}", "replaceWLhs(nodep)"); TREEOP ("AstLogAnd{$lhsp, $rhsp.isNeqZero}", "replaceWLhsBool(nodep)"); - TREEOP ("AstOr {$lhsp, $rhsp.isAllOnes, isTPure($lhsp)}", "replaceWRhs(nodep)"); // ->allOnes - TREEOP ("AstLogOr {$lhsp, $rhsp.isNeqZero, isTPure($lhsp), nodep->isPure()}", "replaceNum(nodep,1)"); + TREEOP ("AstOr {$lhsp, $rhsp.isAllOnes, $lhsp.isPure}", "replaceWRhs(nodep)"); // ->allOnes + TREEOP ("AstLogOr {$lhsp, $rhsp.isNeqZero, $lhsp.isPure, nodep->isPure()}", "replaceNum(nodep,1)"); TREEOP ("AstXor {$lhsp.isAllOnes, $rhsp}", "AstNot{$rhsp}"); TREEOP ("AstMul {$lhsp.isOne, $rhsp}", "replaceWRhs(nodep)"); TREEOP ("AstMulS {$lhsp.isOne, $rhsp}", "replaceWRhs(nodep)"); @@ -3591,9 +3583,9 @@ private: TREEOPV("AstOneHot{$lhsp.width1}", "replaceWLhs(nodep)"); TREEOPV("AstOneHot0{$lhsp.width1}", "replaceNum(nodep,1)"); // Binary AND/OR is faster than logical and/or (usually) - TREEOPV("AstLogAnd{$lhsp.width1, $rhsp.width1, isTPure($lhsp), isTPure($rhsp)}", "AstAnd{$lhsp,$rhsp}"); - TREEOPV("AstLogOr {$lhsp.width1, $rhsp.width1, nodep->isPure(), isTPure($lhsp), isTPure($rhsp)}", "AstOr{$lhsp,$rhsp}"); - TREEOPV("AstLogNot{$lhsp.width1, isTPure($lhsp)}", "AstNot{$lhsp}"); + TREEOPV("AstLogAnd{$lhsp.width1, $rhsp.width1, nodep->isPure()}", "AstAnd{$lhsp,$rhsp}"); + TREEOPV("AstLogOr {$lhsp.width1, $rhsp.width1, nodep->isPure()}", "AstOr{$lhsp,$rhsp}"); + TREEOPV("AstLogNot{$lhsp.width1}", "AstNot{$lhsp}"); // CONCAT(CONCAT({a},{b}),{c}) -> CONCAT({a},CONCAT({b},{c})) // CONCAT({const},CONCAT({const},{c})) -> CONCAT((constifiedCONC{const|const},{c})) TREEOPV("AstConcat{matchConcatRand(nodep)}", "DONE"); diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index e97ce6ec6..09e486a12 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -170,7 +170,10 @@ private: void visit(AstNodeFTaskRef* nodep) override { // Remove link. V3LinkDot will reestablish it after inlining. // MethodCalls not currently supported by inliner, so keep linked - if (!nodep->classOrPackagep() && !VN_IS(nodep, MethodCall)) nodep->taskp(nullptr); + if (!nodep->classOrPackagep() && !VN_IS(nodep, MethodCall)) { + nodep->taskp(nullptr); + nodep->clearCachedPurity(); + } iterateChildren(nodep); } void visit(AstAlways* nodep) override { diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp index 6c0834182..164f005c2 100644 --- a/src/V3LinkInc.cpp +++ b/src/V3LinkInc.cpp @@ -222,7 +222,7 @@ private: // Currently we can't reference the target, so we just copy the AST both for read and // write, but doing so would double any side-effects, so as a safety measure all // statements which could have side-effects are banned at the moment. - if (!nodep->rhsp()->isTreePureRecurse()) { + if (!nodep->rhsp()->isPure()) { nodep->rhsp()->v3warn(E_UNSUPPORTED, "Unsupported: Inc/Dec of expression with side-effects"); return; @@ -252,7 +252,7 @@ private: // Currently we can't reference the target, so we just copy the AST both for read and // write, but doing so would double any side-effects, so as a safety measure all // statements which could have side-effects are banned at the moment. - if (!nodep->rhsp()->isTreePureRecurse()) { + if (!nodep->rhsp()->isPure()) { nodep->rhsp()->v3warn(E_UNSUPPORTED, "Unsupported: Inc/Dec of expression with side-effects"); return; diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 9b58dc8b4..39dbdb9ad 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -346,6 +346,7 @@ private: // We're going to need the expression several times in the expanded code, // so might as well make it a common expression createDeepTemp(nodep->condp(), false); + nodep->clearCachedPurity(); } checkNode(nodep); } diff --git a/src/V3Scope.cpp b/src/V3Scope.cpp index b5a31ea51..8156ec1e3 100644 --- a/src/V3Scope.cpp +++ b/src/V3Scope.cpp @@ -394,6 +394,7 @@ private: UINFO(9, " New pkg-taskref " << nodep << endl); } else if (!VN_IS(nodep, MethodCall)) { nodep->taskp(nullptr); + nodep->clearCachedPurity(); UINFO(9, " New pkg-taskref " << nodep << endl); } iterateChildren(nodep); diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 1170f3326..246748d59 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -1437,6 +1437,9 @@ private: "funcref-like expression to non-function"); AstVarRef* const outrefp = new AstVarRef{nodep->fileline(), outvscp, VAccess::READ}; beginp = new AstExprStmt{nodep->fileline(), beginp, outrefp}; + // AstExprStmt is currently treated as impure, so clear the cached purity of its + // parents + nodep->clearCachedPurity(); nodep->replaceWith(beginp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } else { diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 756cf3dc9..1e2be1013 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -4613,7 +4613,6 @@ private: new AstConst{fl, AstConst::BitFalse{}}}; auto* const orp = new AstLogOr{fl, new AstVarRef{fl, first_varp, VAccess::READ}, new AstNeq{fl, new AstConst{fl, 0}, nextp}}; - orp->sideEffect(true); AstNode* const whilep = new AstWhile{fl, orp, first_clearp}; first_clearp->addNext(bodyPointp); AstNode* const ifbodyp diff --git a/test_regress/t/t_class_method_str_literal.v b/test_regress/t/t_class_method_str_literal.v index 5f6309c02..54dec5ca5 100644 --- a/test_regress/t/t_class_method_str_literal.v +++ b/test_regress/t/t_class_method_str_literal.v @@ -6,6 +6,24 @@ module t; +class uvm_reg; + function int get_1; + return 1; + endfunction + + function bit get_true; + return 1; + endfunction + + function string get_string; + if (get_1() == 1) begin + return get_true() ? "user backdoor" : "DPI backdoor"; + end else begin + return ""; + end + endfunction +endclass + class T; function automatic string return_str(input string a_string); return a_string; @@ -19,6 +37,8 @@ endclass initial begin T t_c = new; + uvm_reg u_r = new; + if (u_r.get_string() != "user backdoor") $stop; if (t_c.return_str("A") != "A") $stop; if (t_c.static_return_str("B") != "B") $stop; if (T::static_return_str("C") != "C") $stop; diff --git a/test_regress/t/t_const_opt_shortcut.pl b/test_regress/t/t_const_opt_shortcut.pl index 8955f94f0..beae879d6 100755 --- a/test_regress/t/t_const_opt_shortcut.pl +++ b/test_regress/t/t_const_opt_shortcut.pl @@ -16,10 +16,7 @@ compile( ); execute( - # Shortcut is not properly implemented yet as in https://github.com/verilator/verilator/issues/487 - # When the issue is fixed, change the following two lines. - check_finished => 0, - fails => $Self->{vlt_all}, + check_finished => 1, ); ok(1); diff --git a/test_regress/t/t_dpi_shortcircuit.out b/test_regress/t/t_dpi_shortcircuit.out deleted file mode 100644 index 2cc554bcf..000000000 --- a/test_regress/t/t_dpi_shortcircuit.out +++ /dev/null @@ -1,20 +0,0 @@ -%Error: Line 62: Bad result, got=1 expect=0 -%Error: Line 66: Bad result, got=1 expect=0 -%Error: Line 69: Bad result, got=0 expect=1 -%Error: Line 81: Bad result, got=0 expect=1 -%Error: Line 91: Bad result, got=0 expect=1 -%Error: Line 108: Bad result, got=1 expect=0 -%Error: Line 112: Bad result, got=1 expect=0 -%Error: Line 114: Bad result, got=0 expect=1 -%Error: Line 126: Bad result, got=0 expect=1 -%Error: Line 136: Bad result, got=0 expect=1 -%Error: Line 148: Bad result, got=1 expect=0 -%Error: Line 152: Bad result, got=1 expect=0 -%Error: Line 179: Bad result, got=0 expect=1 -%Error: Line 219: Bad result, got=64 expect=32 -%Error: Line 220: Bad result, got=64 expect=16 -%Error: Line 221: Bad result, got=64 expect=16 -%Error: Line 222: Bad result, got=64 expect=36 -%Error: Line 223: Bad result, got=64 expect=46 -%Error: t/t_dpi_shortcircuit.v:225: Verilog $stop -Aborting... diff --git a/test_regress/t/t_dpi_shortcircuit.pl b/test_regress/t/t_dpi_shortcircuit.pl index ee25e9d79..b109f6b46 100755 --- a/test_regress/t/t_dpi_shortcircuit.pl +++ b/test_regress/t/t_dpi_shortcircuit.pl @@ -16,10 +16,7 @@ compile( ); execute( - # Should pass, Verilator unsupported, bug413 short circuit"); - fails => $Self->{vlt}, - check_finished => !$Self->{vlt}, - expect_filename => $Self->{golden_filename}, + check_finished => 1, ); ok(1); From 24ff3155ae07e731759d1e4bbd0c89c9e3a50539 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 18 Sep 2023 21:17:21 -0400 Subject: [PATCH 009/157] Support randc (#4349). --- Changes | 1 + docs/guide/warnings.rst | 5 +- include/verilated_types.h | 64 +++++++++++++++++++++- src/V3AstNodeDType.h | 35 +++++++++++++ src/V3AstNodeOther.h | 11 ++++ src/V3AstNodes.cpp | 8 +++ src/V3Common.cpp | 2 +- src/V3EmitCFunc.cpp | 2 + src/V3Hasher.cpp | 5 ++ src/V3ParseImp.h | 5 +- src/V3Randomize.cpp | 70 ++++++++++++++++++++++--- src/V3Unknown.cpp | 12 +++++ test_regress/t/t_randc.out | 12 ----- test_regress/t/t_randc.pl | 10 ++-- test_regress/t/t_randc_ignore_unsup.pl | 24 --------- test_regress/t/t_randc_oversize_bad.out | 7 ++- test_regress/t/t_randc_oversize_bad.v | 7 ++- test_regress/t/t_uvm_todo.pl | 1 - 18 files changed, 220 insertions(+), 61 deletions(-) delete mode 100644 test_regress/t/t_randc.out delete mode 100755 test_regress/t/t_randc_ignore_unsup.pl diff --git a/Changes b/Changes index 6a13b022b..a23881b92 100644 --- a/Changes +++ b/Changes @@ -13,6 +13,7 @@ Verilator 5.017 devel **Minor:** +* Support randc (#4349). * Support resizing function call inout arguments (#4467). diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst index 7f0898b5d..b7cf29a81 100644 --- a/docs/guide/warnings.rst +++ b/docs/guide/warnings.rst @@ -1360,7 +1360,10 @@ List Of Warnings .. option:: RANDC - Warns that the :code:`randc` keyword is unsupported and being converted + Historical, never issued since version 5.018, when :code:`randc` became + fully supported. + + Warned that the :code:`randc` keyword was unsupported and was converted to :code:`rand`. diff --git a/include/verilated_types.h b/include/verilated_types.h index bce36f258..00ffbedb1 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -74,8 +74,18 @@ extern std::string VL_TO_STRING_W(int words, const WDataInP obj); #define VL_OUTW(name, msb, lsb, words) VlWide name ///< Declare output signal, 65+ bits //=================================================================== -// VlProcess stores metadata of running processes +// Functions needed here +constexpr IData VL_CLOG2_CE_Q(QData lhs) VL_PURE { + if (VL_UNLIKELY(!lhs)) return 0; + --lhs; + int shifts = 0; + for (; lhs != 0; ++shifts) lhs = lhs >> 1ULL; + return shifts; +} + +//=================================================================== +// VlProcess stores metadata of running processes class VlProcess final { // MEMBERS int m_state; // Current state of the process @@ -210,6 +220,58 @@ public: size_t operator()() { return VL_MASK_I(31) & vl_rand64(); } }; +template +class VlRandC final { + T_Value m_remaining = 0; // Number of values to pull before re-randomize + T_Value m_lfsr = 1; // LFSR state + // Polynomials are first listed at https://users.ece.cmu.edu/~koopman/lfsr/ + static constexpr uint64_t s_polynomials[] = { + 0x0ULL, // 0 never used (constant, no randomization) + 0x0ULL, // 1 + 0x3ULL, 0x5ULL, 0x9ULL, 0x12ULL, 0x21ULL, + 0x41ULL, 0x8eULL, 0x108ULL, 0x204ULL, 0x402ULL, + 0x829ULL, 0x100dULL, 0x2015ULL, 0x4001ULL, + 0x8016ULL, // 16 + 0x10004ULL, 0x20040ULL, 0x40013ULL, 0x80004ULL, 0x100002ULL, + 0x200001ULL, 0x400010ULL, 0x80000dULL, 0x1000004ULL, 0x2000023ULL, + 0x4000013ULL, 0x8000004ULL, 0x10000002ULL, 0x20000029ULL, 0x40000004ULL, + 0x80000057ULL, // 32 + 0x100000029ULL // 33 + }; + +public: + // CONSTRUCTORS + VlRandC() { + static_assert(T_numValues >= 1, ""); + static_assert(sizeof(T_Value) == 8 || (T_numValues < (1ULL << (8 * sizeof(T_Value)))), ""); + } + // METHODS + T_Value randomize(VlRNG& rngr) { + if (VL_UNLIKELY(!m_remaining)) reseed(rngr); + constexpr uint32_t clogWidth = VL_CLOG2_CE_Q(T_numValues) + 1; + constexpr uint32_t lfsrWidth = (clogWidth < 2) ? 2 : clogWidth; + constexpr T_Value polynomial = static_cast(s_polynomials[lfsrWidth]); + // printf(" numV=%ld w=%d poly=%x\n", T_numValues, lfsrWidth, polynomial); + // Loop until get reasonable value. Because we picked a LFSR of at most one + // extra bit in width, this will only require at most on average 1.5 loops + do { + m_lfsr = (m_lfsr & 1ULL) ? ((m_lfsr >> 1ULL) ^ polynomial) : (m_lfsr >> 1ULL); + } while (m_lfsr > T_numValues); // Note if == then output value 0 + --m_remaining; + T_Value result = (m_lfsr == T_numValues) ? 0 : m_lfsr; + // printf(" result=%x (numv=%ld, rem=%d)\n", result, T_numValues, m_remaining); + return result; + } + void reseed(VlRNG& rngr) { + constexpr uint32_t lfsrWidth = VL_CLOG2_CE_Q(T_numValues) + 1; + m_remaining = T_numValues; + do { + m_lfsr = rngr.rand64() & VL_MASK_Q(lfsrWidth); + // printf(" lfsr.reseed=%x\n", m_lfsr); + } while (!m_lfsr); // 0 not a legal seed + } +}; + // These require the class object to have the thread safety lock inline IData VL_RANDOM_RNG_I(VlRNG& rngr) VL_MT_UNSAFE { return rngr.rand64(); } inline QData VL_RANDOM_RNG_Q(VlRNG& rngr) VL_MT_UNSAFE { return rngr.rand64(); } diff --git a/src/V3AstNodeDType.h b/src/V3AstNodeDType.h index 180d14cca..b8ee2c72e 100644 --- a/src/V3AstNodeDType.h +++ b/src/V3AstNodeDType.h @@ -494,6 +494,41 @@ public: int widthTotalBytes() const override { V3ERROR_NA_RETURN(0); } bool isCompound() const override { return true; } }; +class AstCDType final : public AstNodeDType { + // Raw "C" data type passed directly to output + string m_name; // Name of data type, printed when do V3EmitC +public: + AstCDType(FileLine* fl, const string& name) + : ASTGEN_SUPER_CDType(fl) + , m_name{name} { + this->dtypep(this); + } + +public: + ASTGEN_MEMBERS_AstCDType; + bool same(const AstNode* samep) const override { + const AstCDType* const asamep = static_cast(samep); + return m_name == asamep->m_name; + } + bool similarDType(const AstNodeDType* samep) const override { return same(samep); } + string name() const override VL_MT_STABLE { return m_name; } + string prettyDTypeName() const override { return m_name; } + const char* broken() const override { return nullptr; } + // METHODS + AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; } + AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; } + AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + int widthAlignBytes() const override { return 8; } // Assume + int widthTotalBytes() const override { return 8; } // Assume + bool isCompound() const override { return true; } + static string typeToHold(uint64_t maxItem) { + return (maxItem < (1ULL << 8)) ? "CData" + : (maxItem < (1ULL << 16)) ? "SData" + : (maxItem < (1ULL << 32)) ? "IData" + : "QData"; + } +}; class AstClassRefDType final : public AstNodeDType { // Reference to a class // @astgen op1 := paramsp: List[AstPin] diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 23e1b0891..8d4622164 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -1684,6 +1684,7 @@ class AstVar final : public AstNode { bool m_attrSplitVar : 1; // declared with split_var metacomment bool m_fileDescr : 1; // File descriptor bool m_isRand : 1; // Random variable + bool m_isRandC : 1; // Random cyclic variable (isRand also set) bool m_isConst : 1; // Table contains constant data bool m_isContinuously : 1; // Ever assigned continuously (for force/release) bool m_hasStrengthAssignment : 1; // Is on LHS of assignment with strength specifier @@ -1691,6 +1692,7 @@ class AstVar final : public AstNode { bool m_isPulldown : 1; // Tri0 bool m_isPullup : 1; // Tri1 bool m_isIfaceParent : 1; // dtype is reference to interface present in this module + bool m_isInternal : 1; // Internal state, don't add to method pinter bool m_isDpiOpenArray : 1; // DPI import open array bool m_isHideLocal : 1; // Verilog local bool m_isHideProtected : 1; // Verilog protected @@ -1728,6 +1730,7 @@ class AstVar final : public AstNode { m_attrSplitVar = false; m_fileDescr = false; m_isRand = false; + m_isRandC = false; m_isConst = false; m_isContinuously = false; m_hasStrengthAssignment = false; @@ -1735,6 +1738,7 @@ class AstVar final : public AstNode { m_isPulldown = false; m_isPullup = false; m_isIfaceParent = false; + m_isInternal = false; m_isDpiOpenArray = false; m_isHideLocal = false; m_isHideProtected = false; @@ -1880,10 +1884,15 @@ public: void scSensitive(bool flag) { m_scSensitive = flag; } void primaryIO(bool flag) { m_primaryIO = flag; } void isRand(bool flag) { m_isRand = flag; } + void isRandC(bool flag) { + m_isRandC = flag; + if (flag) isRand(true); + } void isConst(bool flag) { m_isConst = flag; } void isContinuously(bool flag) { m_isContinuously = flag; } void isStatic(bool flag) { m_isStatic = flag; } void isIfaceParent(bool flag) { m_isIfaceParent = flag; } + void isInternal(bool flag) { m_isInternal = flag; } void funcLocal(bool flag) { m_funcLocal = flag; if (flag) m_funcLocalSticky = true; @@ -1929,6 +1938,7 @@ public: bool isPrimaryInish() const { return isPrimaryIO() && isNonOutput(); } bool isIfaceRef() const { return (varType() == VVarType::IFACEREF); } bool isIfaceParent() const { return m_isIfaceParent; } + bool isInternal() const { return m_isInternal; } bool isSignal() const { return varType().isSignal(); } bool isNet() const { return varType().isNet(); } bool isTemp() const { return varType().isTemp(); } @@ -1964,6 +1974,7 @@ public: bool isSigUserRWPublic() const { return m_sigUserRWPublic; } bool isTrace() const { return m_trace; } bool isRand() const { return m_isRand; } + bool isRandC() const { return m_isRandC; } bool isConst() const VL_MT_SAFE { return m_isConst; } bool isStatic() const VL_MT_SAFE { return m_isStatic; } bool isLatched() const { return m_isLatched; } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 29fbf3902..d28692165 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -799,6 +799,8 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const { const CTypeRecursed key = adtypep->keyDTypep()->cTypeRecurse(true); const CTypeRecursed val = adtypep->subDTypep()->cTypeRecurse(true); info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">"; + } else if (const auto* const adtypep = VN_CAST(dtypep, CDType)) { + info.m_type = adtypep->name(); } else if (const auto* const adtypep = VN_CAST(dtypep, WildcardArrayDType)) { const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true); info.m_type = "VlAssocArray"; @@ -2187,8 +2189,14 @@ void AstVar::dump(std::ostream& str) const { if (isPulldown()) str << " [PULLDOWN]"; if (isUsedClock()) str << " [CLK]"; if (isSigPublic()) str << " [P]"; + if (isInternal()) str << " [INTERNAL]"; if (isLatched()) str << " [LATCHED]"; if (isUsedLoopIdx()) str << " [LOOP]"; + if (isRandC()) { + str << " [RANDC]"; + } else if (isRand()) { + str << " [RAND]"; + } if (noReset()) str << " [!RST]"; if (attrIsolateAssign()) str << " [aISO]"; if (attrFileDescr()) str << " [aFD]"; diff --git a/src/V3Common.cpp b/src/V3Common.cpp index 4dc587a10..e4cddae9d 100644 --- a/src/V3Common.cpp +++ b/src/V3Common.cpp @@ -116,7 +116,7 @@ static void makeToStringMiddle(AstClass* nodep) { std::string comma; for (AstNode* itemp = nodep->membersp(); itemp; itemp = itemp->nextp()) { if (const auto* const varp = VN_CAST(itemp, Var)) { - if (!varp->isParam()) { + if (!varp->isParam() && !varp->isInternal()) { string stmt = "out += \""; stmt += comma; comma = ", "; diff --git a/src/V3EmitCFunc.cpp b/src/V3EmitCFunc.cpp index 644aa9b78..0264059a3 100644 --- a/src/V3EmitCFunc.cpp +++ b/src/V3EmitCFunc.cpp @@ -667,6 +667,8 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, const string& varNameP const string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : ""); return emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), depth + 1, suffix + ".atDefault()" + cvtarray); + } else if (VN_IS(dtypep, CDType)) { + return ""; // Constructor does it } else if (VN_IS(dtypep, ClassRefDType)) { return ""; // Constructor does it } else if (VN_IS(dtypep, IfaceRefDType)) { diff --git a/src/V3Hasher.cpp b/src/V3Hasher.cpp index 9169d06bd..f0a4d2bfa 100644 --- a/src/V3Hasher.cpp +++ b/src/V3Hasher.cpp @@ -147,6 +147,11 @@ private: m_hash += nodep->nrange().right(); }); } + void visit(AstCDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->name(); + }); + } void visit(AstConstDType* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // iterateConstNull(nodep->virtRefDTypep()); diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index bba341102..9017c0ae6 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -83,11 +83,8 @@ struct VMemberQualifiers { } void applyToNodes(AstVar* nodesp) const { for (AstVar* nodep = nodesp; nodep; nodep = VN_AS(nodep->nextp(), Var)) { - if (m_randc) { - nodep->v3warn(RANDC, "Unsupported: Converting 'randc' to 'rand'"); - nodep->isRand(true); - } if (m_rand) nodep->isRand(true); + if (m_randc) nodep->isRandC(true); if (m_local) nodep->isHideLocal(true); if (m_protected) nodep->isHideProtected(true); if (m_automatic) nodep->lifetime(VLifetime::AUTOMATIC); diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 95c4ce2e9..983ecf98a 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -144,6 +144,7 @@ private: const AstNodeFTask* m_ftaskp = nullptr; // Current function/task size_t m_enumValueTabCount = 0; // Number of tables with enum values created int m_randCaseNum = 0; // Randcase number within a module for var naming + std::map m_randcDtypes; // RandC data type deduplication // METHODS AstVar* enumValueTabp(AstEnumDType* nodep) { @@ -172,8 +173,49 @@ private: nodep->user2p(varp); return varp; } - AstNodeStmt* newRandStmtsp(FileLine* fl, AstNodeVarRef* varrefp, int offset = 0, - AstMemberDType* memberp = nullptr) { + + AstCDType* findVlRandCDType(FileLine* fl, uint64_t items) { + // For 8 items we need to have a 9 item LFSR so items is max count + const std::string type = AstCDType::typeToHold(items); + const std::string name = "VlRandC<" + type + ", " + cvtToStr(items) + "ULL>"; + // Create or reuse (to avoid duplicates) randomization object dtype + auto it = m_randcDtypes.find(name); + if (it != m_randcDtypes.end()) return it->second; + AstCDType* newp = new AstCDType{fl, name}; + v3Global.rootp()->typeTablep()->addTypesp(newp); + m_randcDtypes.emplace(std::make_pair(name, newp)); + return newp; + } + + AstVar* newRandcVarsp(AstVar* varp) { + // If a randc, make a VlRandC object to hold the state + if (!varp->isRandC()) return nullptr; + uint64_t items = 0; + + if (AstEnumDType* const enumDtp = VN_CAST(varp->dtypep()->skipRefToEnump(), EnumDType)) { + items = static_cast(enumDtp->itemCount()); + } else { + AstBasicDType* const basicp = varp->dtypep()->skipRefp()->basicp(); + UASSERT_OBJ(basicp, varp, "Unexpected randc variable dtype"); + if (basicp->width() > 32) { + varp->v3error("Maxiumum implemented width for randc is 32 bits, " + << varp->prettyNameQ() << " is " << basicp->width() << " bits"); + varp->isRandC(false); + varp->isRand(true); + return nullptr; + } + items = 1ULL << basicp->width(); + } + AstCDType* newdtp = findVlRandCDType(varp->fileline(), items); + AstVar* newp + = new AstVar{varp->fileline(), VVarType::MEMBER, varp->name() + "__Vrandc", newdtp}; + newp->isInternal(true); + varp->addNextHere(newp); + UINFO(9, "created " << varp << endl); + return newp; + } + AstNodeStmt* newRandStmtsp(FileLine* fl, AstNodeVarRef* varrefp, AstVar* randcVarp, + int offset = 0, AstMemberDType* memberp = nullptr) { if (const auto* const structDtp = VN_CAST(memberp ? memberp->subDTypep()->skipRefp() : varrefp->dtypep()->skipRefp(), StructDType)) { @@ -182,7 +224,7 @@ private: for (AstMemberDType* smemberp = structDtp->membersp(); smemberp; smemberp = VN_AS(smemberp->nextp(), MemberDType)) { AstNodeStmt* const randp = newRandStmtsp( - fl, stmtsp ? varrefp->cloneTree(false) : varrefp, offset, smemberp); + fl, stmtsp ? varrefp->cloneTree(false) : varrefp, nullptr, offset, smemberp); if (stmtsp) { stmtsp->addNext(randp); } else { @@ -198,15 +240,15 @@ private: AstVarRef* const tabRefp = new AstVarRef{fl, enumValueTabp(enumDtp), VAccess::READ}; tabRefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp()); - AstRandRNG* const randp - = new AstRandRNG{fl, varrefp->findBasicDType(VBasicDTypeKwd::UINT32)}; + AstNodeExpr* const randp + = newRandValue(fl, randcVarp, varrefp->findBasicDType(VBasicDTypeKwd::UINT32)); AstNodeExpr* const moddivp = new AstModDiv{ fl, randp, new AstConst{fl, static_cast(enumDtp->itemCount())}}; moddivp->dtypep(enumDtp); valp = new AstArraySel{fl, tabRefp, moddivp}; } else { - valp = new AstRandRNG{fl, - (memberp ? memberp->dtypep() : varrefp->varp()->dtypep())}; + valp = newRandValue(fl, randcVarp, + (memberp ? memberp->dtypep() : varrefp->varp()->dtypep())); } return new AstAssign{fl, new AstSel{fl, varrefp, offset + (memberp ? memberp->lsb() : 0), @@ -214,6 +256,17 @@ private: valp}; } } + AstNodeExpr* newRandValue(FileLine* fl, AstVar* randcVarp, AstNodeDType* dtypep) { + if (randcVarp) { + AstNode* argsp = new AstVarRef{fl, randcVarp, VAccess::READWRITE}; + argsp->addNext(new AstText{fl, ".randomize(__Vm_rng)"}); + AstCExpr* newp = new AstCExpr{fl, argsp}; + newp->dtypep(dtypep); + return newp; + } else { + return new AstRandRNG{fl, dtypep}; + } + } void addPrePostCall(AstClass* classp, AstFunc* funcp, const string& name) { if (AstTask* userFuncp = VN_CAST(m_memberMap.findMember(classp, name), Task)) { AstTaskRef* const callp @@ -271,8 +324,9 @@ private: if (!memberVarp || !memberVarp->isRand()) continue; const AstNodeDType* const dtypep = memberp->dtypep()->skipRefp(); if (VN_IS(dtypep, BasicDType) || VN_IS(dtypep, StructDType)) { + AstVar* const randcVarp = newRandcVarsp(memberVarp); AstVarRef* const refp = new AstVarRef{fl, memberVarp, VAccess::WRITE}; - AstNodeStmt* const stmtp = newRandStmtsp(fl, refp); + AstNodeStmt* const stmtp = newRandStmtsp(fl, refp, randcVarp); funcp->addStmtsp(stmtp); } else if (const auto* const classRefp = VN_CAST(dtypep, ClassRefDType)) { if (classRefp->classp() == nodep) { diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp index 66a6c78c4..5a5c6d969 100644 --- a/src/V3Unknown.cpp +++ b/src/V3Unknown.cpp @@ -452,6 +452,18 @@ private: } if (debug() >= 9) nodep->dumpTree("- arraysel_old: "); + // If value MODDIV constant, where constant <= declElements, known ok + // V3Random makes these to intentionally prevent exceeding enum array bounds. + if (const AstModDiv* const moddivp = VN_CAST(nodep->bitp(), ModDiv)) { + if (const AstConst* const modconstp = VN_CAST(moddivp->rhsp(), Const)) { + if (modconstp->width() <= 32 + && modconstp->toUInt() <= static_cast(declElements)) { + UINFO(9, "arraysel mod const " << declElements + << " >= " << modconstp->toUInt() << endl); + return; + } + } + } // See if the condition is constant true AstNodeExpr* condp = new AstGte{nodep->fileline(), diff --git a/test_regress/t/t_randc.out b/test_regress/t/t_randc.out deleted file mode 100644 index f83777149..000000000 --- a/test_regress/t/t_randc.out +++ /dev/null @@ -1,12 +0,0 @@ -%Warning-RANDC: t/t_randc.v:8:26: Unsupported: Converting 'randc' to 'rand' - 8 | randc bit [WIDTH-1:0] m_var; - | ^~~~~ - ... For warning description see https://verilator.org/warn/RANDC?v=latest - ... Use "/* verilator lint_off RANDC */" and lint_on around source to disable this message. -%Warning-RANDC: t/t_randc.v:46:26: Unsupported: Converting 'randc' to 'rand' - 46 | randc bit [WIDTH-1:0] m_var; - | ^~~~~ -%Warning-RANDC: t/t_randc.v:76:17: Unsupported: Converting 'randc' to 'rand' - 76 | randc enum_t m_var; - | ^~~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_randc.pl b/test_regress/t/t_randc.pl index 66fa61649..aabcde63e 100755 --- a/test_regress/t/t_randc.pl +++ b/test_regress/t/t_randc.pl @@ -8,11 +8,13 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(linter => 1); +scenarios(simulator => 1); -lint( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, +compile( + ); + +execute( + check_finished => 1, ); ok(1); diff --git a/test_regress/t/t_randc_ignore_unsup.pl b/test_regress/t/t_randc_ignore_unsup.pl deleted file mode 100755 index af711b6c9..000000000 --- a/test_regress/t/t_randc_ignore_unsup.pl +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env perl -if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } -# DESCRIPTION: Verilator: Verilog Test driver/expect definition -# -# Copyright 2020 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_randc.v"); - -compile( - verilator_flags2 => ['-Wno-RANDC -DTEST_IGNORE_RANDC'], - ); - -execute( - check_finished => 1, - ); - -ok(1); -1; diff --git a/test_regress/t/t_randc_oversize_bad.out b/test_regress/t/t_randc_oversize_bad.out index 293258c1f..61f0030e3 100644 --- a/test_regress/t/t_randc_oversize_bad.out +++ b/test_regress/t/t_randc_oversize_bad.out @@ -1,6 +1,5 @@ -%Warning-RANDC: t/t_randc_oversize_bad.v:8:21: Unsupported: Converting 'randc' to 'rand' - 8 | randc bit [33:0] i; +%Error: t/t_randc_oversize_bad.v:8:21: Maxiumum implemented width for randc is 32 bits, 'i' is 38 bits + : ... In instance t + 8 | randc bit [37:0] i; | ^ - ... For warning description see https://verilator.org/warn/RANDC?v=latest - ... Use "/* verilator lint_off RANDC */" and lint_on around source to disable this message. %Error: Exiting due to diff --git a/test_regress/t/t_randc_oversize_bad.v b/test_regress/t/t_randc_oversize_bad.v index 852f4743c..c687f61df 100644 --- a/test_regress/t/t_randc_oversize_bad.v +++ b/test_regress/t/t_randc_oversize_bad.v @@ -5,8 +5,13 @@ // SPDX-License-Identifier: CC0-1.0 class Cls; - randc bit [33:0] i; + randc bit [37:0] i; endclass module t (/*AUTOARG*/); + Cls c; + initial begin + c = new; + c.randomize; + end endmodule diff --git a/test_regress/t/t_uvm_todo.pl b/test_regress/t/t_uvm_todo.pl index b71e06d09..9fb3de36f 100755 --- a/test_regress/t/t_uvm_todo.pl +++ b/test_regress/t/t_uvm_todo.pl @@ -15,7 +15,6 @@ compile( "-Wno-PKGNODECL -Wno-IMPLICITSTATIC -Wno-CONSTRAINTIGN -Wno-MISINDENT", "-Wno-CASEINCOMPLETE -Wno-CASTCONST -Wno-SYMRSVDWORD -Wno-WIDTHEXPAND -Wno-WIDTHTRUNC", "-Wno-REALCVT", # TODO note mostly related to $realtime - could suppress or fix upstream - "-Wno-RANDC", # TODO issue #4349, add support "-Wno-ZERODLY", # TODO issue #4494, add support ], verilator_make_gmake => 0, From 470f480bc1cad7d8f9066b2fa783cba7ccbaaec6 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 19 Sep 2023 07:23:35 -0400 Subject: [PATCH 010/157] Fix -m32 compile issue --- include/verilated_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/verilated_types.h b/include/verilated_types.h index 00ffbedb1..4fac347f1 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -220,7 +220,7 @@ public: size_t operator()() { return VL_MASK_I(31) & vl_rand64(); } }; -template +template class VlRandC final { T_Value m_remaining = 0; // Number of values to pull before re-randomize T_Value m_lfsr = 1; // LFSR state From b9ea249f8135e80d3eaf610232039c4c7785831f Mon Sep 17 00:00:00 2001 From: Michal Czyz <120088471+mczyz-antmicro@users.noreply.github.com> Date: Tue, 19 Sep 2023 15:08:17 +0200 Subject: [PATCH 011/157] Rewrite usage of annotation options (#4486) (#4504) --- docs/CONTRIBUTORS | 1 + docs/guide/exe_verilator_coverage.rst | 49 +++++++++++++++++++++------ 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index f066d9bef..b80f0bfc3 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -114,6 +114,7 @@ Martin Stadler Matthew Ballance Michael Killough Michaël Lefebvre +Michal Czyz Mike Popoloski Miodrag Milanović Mladen Slijepcevic diff --git a/docs/guide/exe_verilator_coverage.rst b/docs/guide/exe_verilator_coverage.rst index 2c78cf7de..a9ae9a044 100644 --- a/docs/guide/exe_verilator_coverage.rst +++ b/docs/guide/exe_verilator_coverage.rst @@ -64,30 +64,59 @@ if there are multiple coverage points on a single line they will merge. The minimum coverage across all merged points will be used to report coverage of the line. -The first character of the line shows a summary of the coverage; this -allows use of grep to filter the report. `%` indicates at least one point -on the line was below the coverage limit. `+` indicates an -:option:`--annotate-points` point was at or above the limit, and `-` that -the point was below the limit. +Coverage data is annotated at the beginning of the line and is formatted +as a special character followed by the number of coverage hits. The special +characters " ,%,+,-" indicate summary of the coverage, and allow use of grep +to filter the report. + +* " " (whitespace) indicates that all points on the line are above the coverage limit. +* "%" indicates at least one point on the line was below the coverage limit. +* "+" coverage point was at or above the limit. Only used with :option:`--annotate-points`. +* "-" coverage point was below the limit. Only used with :option:`--annotate-points`. + +.. code-block:: + + 100000 input logic a; // Begins with whitespace, because + // number of hits (100000) is above the limit. + +100000 point: comment=a // Begins with +, because + // number of hits (100000) is above the limit. + %000000 input logic b; // Begins with %, because + // number of hits (0) is below the limit. + -000000 point: comment=b // Begins with -, because + // number of hits (0) is below the limit. .. option:: --annotate-all Specifies all files should be shown. By default, only those source files with low coverage are written to the output directory. +This option should be used together with :option:`--annotate`. + .. option:: --annotate-min -Specifies if the coverage point does not include the count number of -coverage hits, then the coverage point will be considered above the -threshold, and the coverage report will put a "%" to indicate the coverage -is insufficient. Defaults to 10. +Specifies the threshold () below which coverage point is considered +sufficient. If the threshold is not exceeded, then the annotation will begin +with a "%" symbol to indicate the coverage is insufficient. + +The threshold defaults to 10. + +This option should be used together with :option:`--annotate`. + .. option:: --annotate-points Specifies all coverage points should be shown after each line of text. By default, only source lines are shown. -with low coverage are written to the output directory. +.. code-block:: + + 100000 input logic a, b, c; + +100000 point: comment=a // These lines are only shown + +200000 point: comment=b // with option --annotate-points + +300000 point: comment=c // enabled. + + +This option should be used together with :option:`--annotate`. .. option:: --help From a16ea94836f44a5db877a9069f3d663bdfa4be72 Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Tue, 19 Sep 2023 23:32:42 +0200 Subject: [PATCH 012/157] Fix detecting local vars in nested forks (#4493) (#4506) --- src/V3Fork.cpp | 10 ++++++---- test_regress/t/t_fork_none_var.pl | 8 +++----- test_regress/t/t_fork_none_var.v | 2 +- test_regress/t/t_uvm_pkg_todo.vh | 4 +--- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/V3Fork.cpp b/src/V3Fork.cpp index 0cfc7dd00..db64eda77 100644 --- a/src/V3Fork.cpp +++ b/src/V3Fork.cpp @@ -516,9 +516,11 @@ private: VL_RESTORER(m_capturedVarsp); VL_RESTORER(m_capturedVarRefsp); VL_RESTORER(m_newProcess); + VL_RESTORER(m_forkLocalsp); m_capturedVarsp = nullptr; m_capturedVarRefsp = nullptr; m_newProcess = false; + m_forkLocalsp.clear(); iterateChildren(nodep); @@ -566,7 +568,6 @@ private: if (!nodep->joinType().join()) { ++m_forkDepth; m_newProcess = true; - m_forkLocalsp.clear(); // Nested forks get moved into separate tasks if (nested) { visitTaskifiable(nodep); @@ -604,9 +605,10 @@ private: UASSERT_OBJ( !nodep->varp()->lifetime().isNone(), nodep, "Variable's lifetime is unknown. Can't determine if a capture is necessary."); - - AstVar* const varp = captureRef(nodep); - nodep->varp(varp); + if (m_forkLocalsp.count(nodep->varp()) == 0) { + AstVar* const varp = captureRef(nodep); + nodep->varp(varp); + } } } void visit(AstAssign* nodep) override { diff --git a/test_regress/t/t_fork_none_var.pl b/test_regress/t/t_fork_none_var.pl index 3407291f9..b8493bd06 100755 --- a/test_regress/t/t_fork_none_var.pl +++ b/test_regress/t/t_fork_none_var.pl @@ -13,13 +13,11 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], make_main => 0, - fails => $Self->{vlt_all}, # issue #4493 ); -# issue #4493 -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_fork_none_var.v b/test_regress/t/t_fork_none_var.v index 3b568b085..1dc892b53 100644 --- a/test_regress/t/t_fork_none_var.v +++ b/test_regress/t/t_fork_none_var.v @@ -22,7 +22,7 @@ module t(/*AUTOARG*/); fork automatic int k = i; begin - // issue #4493 + // see issue #4493 $display("[%0t] start %0d", $time, k); // UVM's arb_sequence_q[is_relevant_entries[k]].wait_for_relevant(); m_mask[k] = 1; diff --git a/test_regress/t/t_uvm_pkg_todo.vh b/test_regress/t/t_uvm_pkg_todo.vh index 35f108a3d..d80314618 100644 --- a/test_regress/t/t_uvm_pkg_todo.vh +++ b/test_regress/t/t_uvm_pkg_todo.vh @@ -19192,9 +19192,7 @@ task uvm_sequencer_base::m_wait_for_available_sequence(); fork automatic int k = i; begin -//TODO issue #4493 - Fix UVM fork..join_none local variable can't locate varref scope -//TODO %Error: Internal Error: t/t_uvm_pkg_todo.vh:19203:56: ../V3Scope.cpp:80: Can't locate varref scope -//TODO arb_sequence_q[is_relevant_entries[k]].sequence_ptr.wait_for_relevant(); + arb_sequence_q[is_relevant_entries[k]].sequence_ptr.wait_for_relevant(); if ($realtime != m_last_wait_relevant_time) begin m_last_wait_relevant_time = $realtime ; m_wait_relevant_count = 0 ; From 4b2bf556d8579a64d5886477556b8ca499c12942 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 20 Sep 2023 07:32:21 -0400 Subject: [PATCH 013/157] Tests: Revert UVM upstream (chipsalliance/uvm-verilator#7) --- test_regress/t/t_uvm_pkg_all.vh | 6 +++--- test_regress/t/t_uvm_pkg_todo.vh | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test_regress/t/t_uvm_pkg_all.vh b/test_regress/t/t_uvm_pkg_all.vh index 9e4b85028..a2fd611b6 100644 --- a/test_regress/t/t_uvm_pkg_all.vh +++ b/test_regress/t/t_uvm_pkg_all.vh @@ -517,7 +517,7 @@ virtual class uvm_coreservice_t; pure virtual function uvm_resource_pool get_resource_pool(); pure virtual function void set_resource_pool_default_precedence(int unsigned precedence); pure virtual function int unsigned get_resource_pool_default_precedence(); - static uvm_coreservice_t inst; + local static uvm_coreservice_t inst; static function uvm_coreservice_t get(); if(inst==null) uvm_init(null); @@ -830,11 +830,11 @@ function void uvm_init(uvm_coreservice_t cs=null); end else begin uvm_coreservice_t actual; - actual = uvm_coreservice_t::inst; + actual = uvm_coreservice_t::get(); if ((cs != actual) && (cs != null)) begin if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/INIT/MULTI")) - uvm_report_warning ("UVM/INIT/MULTI", "uvm_init() called after library has already completed initialization, subsequent calls are ignored!", UVM_NONE, "t/uvm/src/base/uvm_globals.svh", 349, "", 1); + uvm_report_warning ("UVM/INIT/MULTI", "uvm_init() called after library has already completed initialization, subsequent calls are ignored!", UVM_NONE, "t/uvm/src/base/uvm_globals.svh", 344, "", 1); end end return; diff --git a/test_regress/t/t_uvm_pkg_todo.vh b/test_regress/t/t_uvm_pkg_todo.vh index d80314618..f3f21fa0d 100644 --- a/test_regress/t/t_uvm_pkg_todo.vh +++ b/test_regress/t/t_uvm_pkg_todo.vh @@ -517,7 +517,7 @@ virtual class uvm_coreservice_t; pure virtual function uvm_resource_pool get_resource_pool(); pure virtual function void set_resource_pool_default_precedence(int unsigned precedence); pure virtual function int unsigned get_resource_pool_default_precedence(); - static uvm_coreservice_t inst; + local static uvm_coreservice_t inst; static function uvm_coreservice_t get(); if(inst==null) uvm_init(null); @@ -830,11 +830,11 @@ function void uvm_init(uvm_coreservice_t cs=null); end else begin uvm_coreservice_t actual; - actual = uvm_coreservice_t::inst; + actual = uvm_coreservice_t::get(); if ((cs != actual) && (cs != null)) begin if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/INIT/MULTI")) - uvm_report_warning ("UVM/INIT/MULTI", "uvm_init() called after library has already completed initialization, subsequent calls are ignored!", UVM_NONE, "t/uvm/src/base/uvm_globals.svh", 349, "", 1); + uvm_report_warning ("UVM/INIT/MULTI", "uvm_init() called after library has already completed initialization, subsequent calls are ignored!", UVM_NONE, "t/uvm/src/base/uvm_globals.svh", 344, "", 1); end end return; From 4636e9cffb709de7d953389b708854a6077f5149 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Wed, 20 Sep 2023 13:33:11 +0200 Subject: [PATCH 014/157] Fix passing arguments by reference (#3385 partial) (#4489) --- src/V3Ast.h | 2 +- src/V3AstNodeOther.h | 1 + src/V3AstNodes.cpp | 5 +- src/V3LinkLevel.cpp | 2 +- src/V3Task.cpp | 36 +++++++++-- test_regress/t/t_func_inout_bit_sel.pl | 21 +++++++ test_regress/t/t_func_inout_bit_sel.v | 31 ++++++++++ test_regress/t/t_func_ref_arg.pl | 21 +++++++ test_regress/t/t_func_ref_arg.v | 60 +++++++++++++++++++ test_regress/t/t_func_ref_bad.out | 4 ++ test_regress/t/t_func_ref_bad.pl | 19 ++++++ test_regress/t/t_func_ref_bad.v | 22 +++++++ test_regress/t/t_func_ref_unsup.out | 8 +++ test_regress/t/t_func_ref_unsup.pl | 19 ++++++ test_regress/t/t_func_ref_unsup.v | 41 +++++++++++++ .../t/t_queue_persistence_inl_unsup.out | 5 ++ ...ce.pl => t_queue_persistence_inl_unsup.pl} | 7 +-- test_regress/t/t_queue_persistence_noinl.pl | 3 +- 18 files changed, 292 insertions(+), 15 deletions(-) create mode 100755 test_regress/t/t_func_inout_bit_sel.pl create mode 100644 test_regress/t/t_func_inout_bit_sel.v create mode 100755 test_regress/t/t_func_ref_arg.pl create mode 100644 test_regress/t/t_func_ref_arg.v create mode 100644 test_regress/t/t_func_ref_bad.out create mode 100755 test_regress/t/t_func_ref_bad.pl create mode 100644 test_regress/t/t_func_ref_bad.v create mode 100644 test_regress/t/t_func_ref_unsup.out create mode 100755 test_regress/t/t_func_ref_unsup.pl create mode 100644 test_regress/t/t_func_ref_unsup.v create mode 100644 test_regress/t/t_queue_persistence_inl_unsup.out rename test_regress/t/{t_queue_persistence.pl => t_queue_persistence_inl_unsup.pl} (84%) diff --git a/src/V3Ast.h b/src/V3Ast.h index 8c42e41ba..22e4fd846 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -706,7 +706,7 @@ public: bool isReadOnly() const VL_MT_SAFE { return m_e == INPUT || m_e == CONSTREF; } bool isWritable() const VL_MT_SAFE { return m_e == OUTPUT || m_e == INOUT || m_e == REF; } bool isRef() const VL_MT_SAFE { return m_e == REF; } - bool isRefOrConstRef() const VL_MT_SAFE { return m_e == REF || m_e == CONSTREF; } + bool isConstRef() const VL_MT_SAFE { return m_e == CONSTREF; } }; constexpr bool operator==(const VDirection& lhs, const VDirection& rhs) { return lhs.m_e == rhs.m_e; diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 8d4622164..12b7ce9f2 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -1931,6 +1931,7 @@ public: bool isInoutish() const { return m_direction.isInoutish(); } bool isNonOutput() const { return m_direction.isNonOutput(); } bool isReadOnly() const VL_MT_SAFE { return m_direction.isReadOnly(); } + bool isConstRef() const VL_MT_SAFE { return m_direction.isConstRef(); } bool isRef() const VL_MT_SAFE { return m_direction.isRef(); } bool isWritable() const VL_MT_SAFE { return m_direction.isWritable(); } bool isTristate() const { return m_tristate; } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index d28692165..81dfdbaf4 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -475,7 +475,8 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& if (isStatic() && namespc.empty()) ostatic = "static "; const bool isRef = isDpiOpenArray() - || (forFunc && (isWritable() || direction().isRefOrConstRef())) || asRef; + || (forFunc && (isWritable() || this->isRef() || this->isConstRef())) + || asRef; if (forFunc && isReadOnly() && isRef) ostatic = ostatic + "const "; @@ -589,7 +590,7 @@ string AstVar::cPubArgType(bool named, bool forReturn) const { if (forReturn) named = false; string arg; if (isWide() && isReadOnly()) arg += "const "; - const bool isRef = !forReturn && (isWritable() || direction().isRefOrConstRef()); + const bool isRef = !forReturn && (isWritable() || this->isRef() || this->isConstRef()); if (VN_IS(dtypeSkipRefp(), BasicDType) && !dtypeSkipRefp()->isDouble() && !dtypeSkipRefp()->isString()) { // Backward compatible type declaration diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index 1b0dc54cf..03ba5bf96 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -277,7 +277,7 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) { varp->sigPublic(true); // User needs to be able to get to it... oldvarp->primaryIO(false); varp->primaryIO(true); - if (varp->direction().isRefOrConstRef()) { + if (varp->isRef() || varp->isConstRef()) { varp->v3warn(E_UNSUPPORTED, "Unsupported: ref/const ref as primary input/output: " << varp->prettyNameQ()); diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 246748d59..7586795a0 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -479,10 +479,38 @@ private: pinp->v3error("Function/task " + portp->direction().prettyName() // e.g. "output" + " connected to constant instead of variable: " + portp->prettyNameQ()); - } - // else if (portp->direction() == VDirection::REF) { - // TODO References need to instead pass a real reference var, see issue #3385 - else if (portp->isInoutish()) { + } else if (portp->isRef() || portp->isConstRef()) { + bool refArgOk = false; + if (VN_IS(pinp, VarRef) || VN_IS(pinp, MemberSel) || VN_IS(pinp, StructSel) + || VN_IS(pinp, ArraySel)) { + refArgOk = true; + } else if (const AstCMethodHard* const cMethodp = VN_CAST(pinp, CMethodHard)) { + refArgOk = cMethodp->name() == "at"; + } + if (refArgOk) { + if (AstVarRef* const varrefp = VN_CAST(pinp, VarRef)) { + varrefp->access(VAccess::READWRITE); + } + } else { + pinp->v3error("Function/task ref argument is not of allowed type"); + } + if (inlineTask) { + if (AstVarRef* const varrefp = VN_CAST(pinp, VarRef)) { + // Connect to this exact variable + AstVarScope* const localVscp = varrefp->varScopep(); + UASSERT_OBJ(localVscp, varrefp, "Null var scope"); + portp->user2p(localVscp); + pushDeletep(pinp); + } else { + pinp->v3warn(E_TASKNSVAR, "Unsupported: ref argument of inlined " + "function/task is not a simple variable"); + // Providing a var to avoid an internal error. + AstVarScope* const newvscp + = createVarScope(portp, namePrefix + "__" + portp->shortName()); + portp->user2p(newvscp); + } + } + } else if (portp->isInoutish()) { // if (debug() >= 9) pinp->dumpTree("-pinrsize- "); V3LinkLValue::linkLValueSet(pinp); diff --git a/test_regress/t/t_func_inout_bit_sel.pl b/test_regress/t/t_func_inout_bit_sel.pl new file mode 100755 index 000000000..beaa2ca59 --- /dev/null +++ b/test_regress/t/t_func_inout_bit_sel.pl @@ -0,0 +1,21 @@ +#!/usr/bin/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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_func_inout_bit_sel.v b/test_regress/t/t_func_inout_bit_sel.v new file mode 100644 index 000000000..3af758d75 --- /dev/null +++ b/test_regress/t/t_func_inout_bit_sel.v @@ -0,0 +1,31 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); + +class Cls; + function bit get_x_set_1(inout bit x); + bit a = x; + x = 1; + return a; + endfunction +endclass + +module t (/*AUTOARG*/); + int a; + bit b; + Cls cls; + initial begin + cls = new; + b = cls.get_x_set_1(a[1]); + `checkh(b, 0); + `checkh(a[1], 1); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_func_ref_arg.pl b/test_regress/t/t_func_ref_arg.pl new file mode 100755 index 000000000..aabcde63e --- /dev/null +++ b/test_regress/t/t_func_ref_arg.pl @@ -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 2020 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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_func_ref_arg.v b/test_regress/t/t_func_ref_arg.v new file mode 100644 index 000000000..b552a2b24 --- /dev/null +++ b/test_regress/t/t_func_ref_arg.v @@ -0,0 +1,60 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); + +class MyInt; + int x; + function new(int a); + x = a; + endfunction +endclass + +function int get_val_set_5(ref int x); + automatic int y = x; + x = 5; + return y; +endfunction + +class Cls; + function int get_val_set_2(ref int x); + automatic int y = x; + x = 2; + return y; + endfunction +endclass + +module t (/*AUTOARG*/); + int a, b; + int arr[1]; + Cls cls; + MyInt mi; + initial begin + a = 10; + b = get_val_set_5(a); + `checkh(a, 5); + `checkh(b, 10); + + cls = new; + b = cls.get_val_set_2(a); + `checkh(a, 2); + `checkh(b, 5); + + mi = new(1); + b = cls.get_val_set_2(mi.x); + `checkh(mi.x, 2); + `checkh(b, 1); + + arr[0] = 10; + b = cls.get_val_set_2(arr[0]); + `checkh(arr[0], 2); + `checkh(b, 10); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_func_ref_bad.out b/test_regress/t/t_func_ref_bad.out new file mode 100644 index 000000000..aa39be63e --- /dev/null +++ b/test_regress/t/t_func_ref_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_func_ref_bad.v:19:22: Function/task ref argument is not of allowed type + 19 | b = cls.get_x(a[1]); + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_func_ref_bad.pl b/test_regress/t/t_func_ref_bad.pl new file mode 100755 index 000000000..23eda8f99 --- /dev/null +++ b/test_regress/t/t_func_ref_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/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 => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_func_ref_bad.v b/test_regress/t/t_func_ref_bad.v new file mode 100644 index 000000000..22154bb05 --- /dev/null +++ b/test_regress/t/t_func_ref_bad.v @@ -0,0 +1,22 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Cls; + function logic get_x(ref logic x); + return x; + endfunction +endclass + +module t (/*AUTOARG*/); + logic [10:0] a; + logic b; + Cls cls; + initial begin + cls = new; + b = cls.get_x(a[1]); + $stop; + end +endmodule diff --git a/test_regress/t/t_func_ref_unsup.out b/test_regress/t/t_func_ref_unsup.out new file mode 100644 index 000000000..1888aea08 --- /dev/null +++ b/test_regress/t/t_func_ref_unsup.out @@ -0,0 +1,8 @@ +%Error-TASKNSVAR: t/t_func_ref_unsup.v:29:28: Unsupported: ref argument of inlined function/task is not a simple variable + 29 | b = get_val_set_5(mi.x); + | ^ + ... For error description see https://verilator.org/warn/TASKNSVAR?v=latest +%Error-TASKNSVAR: t/t_func_ref_unsup.v:34:28: Unsupported: ref argument of inlined function/task is not a simple variable + 34 | b = get_val_set_5(arr[0]); + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_func_ref_unsup.pl b/test_regress/t/t_func_ref_unsup.pl new file mode 100755 index 000000000..23eda8f99 --- /dev/null +++ b/test_regress/t/t_func_ref_unsup.pl @@ -0,0 +1,19 @@ +#!/usr/bin/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 => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_func_ref_unsup.v b/test_regress/t/t_func_ref_unsup.v new file mode 100644 index 000000000..6fa1e9d87 --- /dev/null +++ b/test_regress/t/t_func_ref_unsup.v @@ -0,0 +1,41 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); + +class MyInt; + int x; + function new(int a); + x = a; + endfunction +endclass + +function int get_val_set_5(ref int x); + automatic int y = x; + x = 5; + return y; +endfunction + +module t (/*AUTOARG*/); + int b; + int arr[1]; + MyInt mi; + initial begin + mi = new(1); + b = get_val_set_5(mi.x); + `checkh(mi.x, 5); + `checkh(b, 1); + + arr[0] = 10; + b = get_val_set_5(arr[0]); + `checkh(arr[0], 5); + `checkh(b, 10); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_queue_persistence_inl_unsup.out b/test_regress/t/t_queue_persistence_inl_unsup.out new file mode 100644 index 000000000..d9e34ab83 --- /dev/null +++ b/test_regress/t/t_queue_persistence_inl_unsup.out @@ -0,0 +1,5 @@ +%Error-TASKNSVAR: t/t_queue_persistence.v:30:13: Unsupported: ref argument of inlined function/task is not a simple variable + 30 | func(q[1]); + | ^ + ... For error description see https://verilator.org/warn/TASKNSVAR?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_queue_persistence.pl b/test_regress/t/t_queue_persistence_inl_unsup.pl similarity index 84% rename from test_regress/t/t_queue_persistence.pl rename to test_regress/t/t_queue_persistence_inl_unsup.pl index c9515ce9b..8cf7fc5b6 100755 --- a/test_regress/t/t_queue_persistence.pl +++ b/test_regress/t/t_queue_persistence_inl_unsup.pl @@ -19,11 +19,8 @@ else { compile( timing_loop => 1, verilator_flags2 => ["--timing"], - ); - - execute( - fails => $Self->{vlt_all}, # bug3385 need to fix "ref" - check_finished => !$Self->{vlt_all}, + fails => 1, # bug3385 need to fix "ref" + expect_filename => $Self->{golden_filename}, ); } diff --git a/test_regress/t/t_queue_persistence_noinl.pl b/test_regress/t/t_queue_persistence_noinl.pl index afaa948eb..187562462 100755 --- a/test_regress/t/t_queue_persistence_noinl.pl +++ b/test_regress/t/t_queue_persistence_noinl.pl @@ -22,8 +22,7 @@ else { ); execute( - fails => $Self->{vlt_all}, # bug3385 need to fix "ref" - check_finished => !$Self->{vlt_all}, + check_finished => 1, ); } From 9f75068059c7c263d7fd1c53b8297056b7b3dc29 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 23 Sep 2023 08:52:50 -0400 Subject: [PATCH 015/157] Cleanup some error messages to properly quote --- src/V3Ast.cpp | 8 +-- src/V3FileLine.cpp | 4 +- src/V3LinkDot.cpp | 2 +- src/V3LinkParse.cpp | 2 +- src/V3PreLex.l | 2 +- src/V3Simulate.h | 4 +- src/verilog.l | 6 +- src/verilog.y | 4 +- test_regress/t/t_array_backw_index_bad.out | 14 ++-- test_regress/t/t_array_list_bad.out | 4 +- test_regress/t/t_array_method_bad.out | 2 +- test_regress/t/t_array_method_unsup.out | 10 +-- test_regress/t/t_array_pattern_bad.out | 2 +- test_regress/t/t_array_pattern_bad2.out | 2 +- test_regress/t/t_array_pattern_bad3.out | 6 +- test_regress/t/t_assert_comp_bad.out | 16 ++--- test_regress/t/t_assert_disable_bad.out | 2 +- test_regress/t/t_assert_procedural_clk.out | 4 +- .../t/t_assert_recursive_property_unsup.out | 2 +- test_regress/t/t_assoc_method_bad.out | 28 ++++---- test_regress/t/t_assoc_wildcard_bad.out | 38 +++++----- test_regress/t/t_bigmem_bad.out | 2 +- test_regress/t/t_bitsel_const_bad.out | 2 +- test_regress/t/t_bitsel_wire_array_bad.out | 2 +- test_regress/t/t_case_genx_bad.out | 2 +- test_regress/t/t_cast_class_incompat_bad.out | 4 +- test_regress/t/t_cast_size_bad.out | 4 +- test_regress/t/t_castdyn_castconst_bad.out | 6 +- test_regress/t/t_castdyn_unsup_bad.out | 2 +- test_regress/t/t_class_assign_bad.out | 18 ++--- test_regress/t/t_class_assign_cond_bad.out | 10 +-- test_regress/t/t_class_builtin_bad.out | 4 +- test_regress/t/t_class_copy_bad.out | 2 +- .../t/t_class_extends_aliased_real_bad.out | 2 +- .../t/t_class_extends_int_param_bad.out | 2 +- test_regress/t/t_class_extern_bad.out | 4 +- test_regress/t/t_class_local_bad.out | 30 ++++---- test_regress/t/t_class_member_bad.out | 4 +- test_regress/t/t_class_method_bad.out | 2 +- test_regress/t/t_class_new_bad.out | 10 +-- test_regress/t/t_class_param_bad2.out | 2 +- test_regress/t/t_class_param_circ_bad.out | 2 +- test_regress/t/t_class_param_enum_bad.out | 4 +- test_regress/t/t_class_param_nconst_bad.out | 4 +- test_regress/t/t_class_param_nested_bad.out | 4 +- test_regress/t/t_class_param_noinit_bad.out | 2 +- test_regress/t/t_class_virtual_bad.out | 2 +- test_regress/t/t_clocking_bad1.out | 2 +- test_regress/t/t_clocking_bad4.out | 22 +++--- test_regress/t/t_clocking_notiming.out | 2 +- test_regress/t/t_clocking_unsup2.out | 2 +- test_regress/t/t_concat_large_bad.out | 2 +- test_regress/t/t_const_bad.out | 6 +- test_regress/t/t_constraint_mode_warn_bad.out | 24 +++---- test_regress/t/t_cover_unused_bad.out | 2 +- test_regress/t/t_delay_stmtdly_bad.out | 16 ++--- test_regress/t/t_dfg_multidriver_dfg_bad.out | 8 +-- test_regress/t/t_dpi_2exparg_bad.out | 4 +- test_regress/t/t_dpi_unpack_bad.out | 14 ++-- test_regress/t/t_dynarray_bad.out | 2 +- test_regress/t/t_enum_bad_circdecl.out | 2 +- test_regress/t/t_enum_bad_value.out | 2 +- test_regress/t/t_enum_bad_wrap.out | 2 +- test_regress/t/t_enum_huge_methods_bad.out | 2 +- test_regress/t/t_enum_overlap_bad.out | 2 +- test_regress/t/t_enum_type_bad.out | 6 +- test_regress/t/t_enum_type_methods_bad.out | 2 +- test_regress/t/t_enum_type_nomethod_bad.out | 2 +- test_regress/t/t_enum_x_bad.out | 4 +- test_regress/t/t_event_control.out | 4 +- test_regress/t/t_event_control_expr_unsup.out | 2 +- test_regress/t/t_event_copy.out | 4 +- test_regress/t/t_flag_context_bad.out | 4 +- test_regress/t/t_flag_structs_packed_bad.out | 2 +- test_regress/t/t_flag_werror_bad1.out | 2 +- test_regress/t/t_flag_werror_bad2.out | 2 +- test_regress/t/t_flag_wfatal.out | 2 +- test_regress/t/t_force_tri.out | 2 +- test_regress/t/t_fork.out | 2 +- test_regress/t/t_fork_disable.out | 4 +- test_regress/t/t_fork_func2_bad.out | 2 +- test_regress/t/t_func_bad.out | 14 ++-- test_regress/t/t_func_bad_width.out | 4 +- test_regress/t/t_func_const2_bad.out | 6 +- test_regress/t/t_func_const3_bad.out | 2 +- test_regress/t/t_func_const_bad.out | 22 +++--- .../t/t_func_const_packed_array_bad.out | 6 +- .../t/t_func_const_packed_struct_bad.out | 6 +- .../t/t_func_const_packed_struct_bad2.out | 6 +- test_regress/t/t_func_const_struct_bad.out | 6 +- test_regress/t/t_func_recurse_param.out | 4 +- test_regress/t/t_func_recurse_param_bad.out | 2 +- test_regress/t/t_func_refio_bad.out | 2 +- test_regress/t/t_func_wide_out_bad.out | 40 +++++------ test_regress/t/t_fuzz_triand_bad.out | 4 +- test_regress/t/t_gen_cond_bitrange_bad.out | 8 +-- test_regress/t/t_gen_missing_bad2.out | 8 +-- test_regress/t/t_gen_var_bad.out | 2 +- test_regress/t/t_generate_fatal_bad.out | 48 ++++++------- test_regress/t/t_hier_block0_bad.out | 4 +- test_regress/t/t_hier_block1_bad.out | 6 +- test_regress/t/t_implements_new_bad.out | 2 +- test_regress/t/t_inside_queue_bad.out | 6 +- test_regress/t/t_inside_unpacked.out | 4 +- test_regress/t/t_inst_array_bad.out | 2 +- test_regress/t/t_inst_misarray2_bad.out | 2 +- test_regress/t/t_inst_misarray_bad.out | 2 +- test_regress/t/t_inst_overwide_bad.out | 8 +-- test_regress/t/t_inst_pin_realnreal.out | 2 +- test_regress/t/t_inst_recurse2_bad.out | 2 +- test_regress/t/t_interface_ar3.out | 4 +- test_regress/t/t_interface_array_bad.out | 4 +- .../t/t_interface_array_nocolon_bad.out | 8 +-- test_regress/t/t_interface_asvar_bad.out | 4 +- .../t/t_interface_modport_dir_bad.out | 2 +- test_regress/t/t_interface_param_acc_bits.out | 2 +- .../t/t_interface_param_another_bad.out | 2 +- test_regress/t/t_interface_size_bad.out | 4 +- test_regress/t/t_interface_virtual_bad.out | 16 ++--- test_regress/t/t_interface_wrong_bad.out | 2 +- test_regress/t/t_lint_always_comb_bad.out | 8 +-- .../t/t_lint_always_comb_multidriven.out | 20 +++--- test_regress/t/t_lint_cmpconst_bad.out | 2 +- test_regress/t/t_lint_const_func_dpi_bad.out | 6 +- test_regress/t/t_lint_const_func_gen_bad.out | 6 +- test_regress/t/t_lint_contassreg_bad.out | 2 +- test_regress/t/t_lint_edge_real_bad.out | 4 +- test_regress/t/t_lint_genunnamed_bad.out | 18 +++-- .../t/t_lint_iface_array_topmodule_bad.out | 2 +- test_regress/t/t_lint_iface_topmodule_bad.out | 2 +- test_regress/t/t_lint_ifdepth_bad.out | 2 +- test_regress/t/t_lint_in_inc_bad.out | 4 +- test_regress/t/t_lint_infinite_bad.out | 4 +- test_regress/t/t_lint_modport_dir_bad.out | 2 +- test_regress/t/t_lint_once_bad.out | 4 +- .../t/t_lint_pragma_protected_bad.out | 4 +- test_regress/t/t_lint_repeat_bad.out | 2 +- test_regress/t/t_lint_restore_bad.out | 2 +- test_regress/t/t_lint_setout_bad.out | 2 +- test_regress/t/t_lint_setout_bad_noinl.out | 2 +- test_regress/t/t_lint_stmtdly_bad.out | 2 +- test_regress/t/t_lint_subout_bad.out | 6 +- test_regress/t/t_lint_unsigned_bad.out | 2 +- test_regress/t/t_lint_unused_bad.out | 30 ++++---- test_regress/t/t_lint_unused_iface_bad.out | 4 +- test_regress/t/t_lint_vcmarker_bad.out | 6 +- test_regress/t/t_lint_width_bad.out | 22 +++--- test_regress/t/t_lint_width_genfor_bad.out | 10 +-- .../t/t_lint_widthexpand_docs_bad.out | 2 +- test_regress/t/t_mailbox_bad.out | 2 +- test_regress/t/t_math_eq_bad.out | 2 +- test_regress/t/t_math_repl2_bad.out | 2 +- test_regress/t/t_math_repl_bad.out | 8 +-- test_regress/t/t_math_shift_over_bad.out | 2 +- test_regress/t/t_mem_multi_ref_bad.out | 18 ++--- test_regress/t/t_mem_slice_bad.out | 12 ++-- test_regress/t/t_metacmt_onoff.out | 4 +- test_regress/t/t_net_delay.out | 6 +- test_regress/t/t_notiming.out | 22 +++--- test_regress/t/t_notiming_off.out | 12 ++-- test_regress/t/t_packed_concat_bad.out | 6 +- test_regress/t/t_param_circ_bad.out | 2 +- test_regress/t/t_param_concat_bad.out | 6 +- test_regress/t/t_param_default_bad.out | 2 +- test_regress/t/t_param_default_presv_bad.out | 2 +- test_regress/t/t_param_noval_bad.out | 14 ++-- test_regress/t/t_param_sel_range_bad.out | 2 +- test_regress/t/t_param_type_bad2.out | 4 +- test_regress/t/t_param_width_loc_bad.out | 2 +- test_regress/t/t_past_bad.out | 8 +-- test_regress/t/t_pp_line_bad.out | 2 +- test_regress/t/t_preproc_inc_bad.out | 2 +- test_regress/t/t_process_bad.out | 4 +- test_regress/t/t_process_notiming.out | 26 +++---- test_regress/t/t_queue_empty_bad.out | 4 +- test_regress/t/t_queue_method3_bad.out | 4 +- test_regress/t/t_queue_method_bad.out | 18 ++--- test_regress/t/t_randc_oversize_bad.out | 2 +- .../t/t_randomize_method_types_unsup.out | 10 +-- test_regress/t/t_randstate_obj.out | 4 +- test_regress/t/t_sampled_expr_unsup.out | 2 +- test_regress/t/t_select_bad_msb.out | 4 +- test_regress/t/t_select_bad_range.out | 4 +- test_regress/t/t_select_bad_range2.out | 2 +- test_regress/t/t_select_bad_range3.out | 2 +- test_regress/t/t_select_bad_range4.out | 38 +++++----- test_regress/t/t_select_bad_range5.out | 8 +-- test_regress/t/t_select_bad_tri.out | 2 +- test_regress/t/t_semaphore_bad.out | 2 +- test_regress/t/t_split_var_1_bad.out | 30 ++++---- test_regress/t/t_stream_bad.out | 6 +- .../t/t_stream_dynamic_wide_unsup.out | 4 +- .../t/t_stream_integer_type_unsup.out | 72 +++++++++---------- test_regress/t/t_strength_2_uneq_assign.out | 4 +- test_regress/t/t_string_type_methods_bad.out | 8 +-- test_regress/t/t_struct_contents_bad.out | 20 +++--- test_regress/t/t_struct_init_bad.out | 2 +- test_regress/t/t_struct_notfound_bad.out | 2 +- test_regress/t/t_struct_packed_init_bad.out | 2 +- test_regress/t/t_struct_unpacked_init.out | 2 +- .../t/t_structu_dataType_assignment_bad.out | 2 +- test_regress/t/t_sys_readmem_assoc_bad.out | 4 +- test_regress/t/t_timing_func_bad.out | 12 ++-- test_regress/t/t_timing_localevent_unsup.out | 2 +- test_regress/t/t_timing_unset1.out | 24 +++---- test_regress/t/t_timing_unset2.out | 12 ++-- test_regress/t/t_timing_unset3.out | 2 +- test_regress/t/t_tri_array.out | 8 +-- test_regress/t/t_tri_compass_bad.out | 2 +- test_regress/t/t_tri_pull2_bad.out | 2 +- test_regress/t/t_tri_pull_bad.out | 2 +- test_regress/t/t_tri_pullvec_bad.out | 4 +- test_regress/t/t_type_compare_bad.out | 2 +- test_regress/t/t_unbounded_bad.out | 4 +- test_regress/t/t_unpacked_concat_bad.out | 4 +- test_regress/t/t_var_const_bad.out | 2 +- test_regress/t/t_var_ref_bad1.out | 2 +- test_regress/t/t_var_ref_bad2.out | 4 +- test_regress/t/t_var_rsvd_bad.out | 2 +- test_regress/t/t_var_types_bad.out | 14 ++-- test_regress/t/t_vlt_warn_bad.out | 2 +- test_regress/t/t_vlt_warn_ecode_bad.out | 4 +- test_regress/t/t_wait.out | 18 ++--- test_regress/t/t_wire_beh1364_bad.out | 10 +-- test_regress/t/t_wire_beh1800_bad.out | 10 +-- test_regress/t/t_wire_behp1364_bad.out | 6 +- test_regress/t/t_wire_behp1800_bad.out | 6 +- 227 files changed, 757 insertions(+), 755 deletions(-) diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index ddde27f08..35f6606f9 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -1348,23 +1348,19 @@ string AstNode::instanceStr() const { // in case we have some circular reference bug. constexpr unsigned maxIterations = 10000; unsigned iterCount = 0; - for (const AstNode* backp = this; backp; backp = backp->backp(), ++iterCount) { if (VL_UNCOVERABLE(iterCount >= maxIterations)) return ""; // LCOV_EXCL_LINE - // Prefer the enclosing scope, if there is one. This is always under the enclosing module, // so just pick it up when encountered if (const AstScope* const scopep = VN_CAST(backp, Scope)) { - return scopep->isTop() ? "" : "... In instance " + scopep->prettyName(); + return scopep->isTop() ? "" : "... note: In instance " + scopep->prettyNameQ(); } - // If scopes don't exist, report an example instance of the enclosing module if (const AstModule* const modp = VN_CAST(backp, Module)) { const string instanceName = modp->someInstanceName(); - return instanceName.empty() ? "" : "... In instance " + instanceName; + return instanceName.empty() ? "" : "... note: In instance '" + instanceName + "'"; } } - return ""; } void AstNode::v3errorEnd(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex) { diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index 91ee773f2..e97db97b2 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -476,8 +476,8 @@ string FileLine::warnContextParent() const VL_REQUIRES(V3Error::s().m_mutex) { string result; for (FileLine* parentFl = parent(); parentFl; parentFl = parentFl->parent()) { if (parentFl->filenameIsGlobal()) break; - result += parentFl->warnOther() + "... note: In file included from " - + parentFl->filebasename() + "\n"; + result += parentFl->warnOther() + "... note: In file included from '" + + parentFl->filebasename() + "'\n"; } return result; } diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index ceb1f2284..d9751b87a 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -3348,7 +3348,7 @@ private: } if (nodep->isExternProto()) { if (!m_curSymp->findIdFallback(nodep->name())) { - nodep->v3error("definition not found for extern " + nodep->prettyNameQ()); + nodep->v3error("Definition not found for extern " + nodep->prettyNameQ()); } } VSymEnt* const oldCurSymp = m_curSymp; diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index e61ff5f59..00b9ea3aa 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -674,7 +674,7 @@ private: if (nodep->stmtsp()) { nodep->v3warn(GENUNNAMED, "Unnamed generate block " - << nodep->prettyNameQ() << " (IEEE 1800-2017 27.6)" + << nodep->prettyNameQ() << " (IEEE 1800-2017 27.6)\n" << nodep->warnMore() << "... Suggest assign a label with 'begin : gen_'"); } diff --git a/src/V3PreLex.l b/src/V3PreLex.l index 1daee9a31..9c84b9ed5 100644 --- a/src/V3PreLex.l +++ b/src/V3PreLex.l @@ -125,7 +125,7 @@ bom [\357\273\277] int res; char enctype[16]; // long enough to hold "quote-printable" if (LEXP->m_protBytes > 0) { - LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "multiple `pragma protected encoding sections"); + LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "Multiple `pragma protected encoding sections"); } res = sscanf(yytext + std::strlen("encoding"), " = (enctype = \"%15[A-Za-z0-9]\", line_length = %d, bytes = %d)", &enctype[0], &LEXP->m_protLength, &LEXP->m_protBytes); if (res == 0) diff --git a/src/V3Simulate.h b/src/V3Simulate.h index a3f1be13a..bc36bf0d7 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -185,8 +185,8 @@ public: std::ostringstream stack; for (const auto& callstack : vlstd::reverse_view(m_callStack)) { AstFuncRef* const funcp = callstack->m_funcp; - stack << "\n " << funcp->fileline() << "... Called from " - << funcp->prettyName() << "() with parameters:"; + stack << "\n " << funcp->fileline() << "... Called from '" + << funcp->prettyName() << "()' with parameters:"; V3TaskConnects* tconnects = callstack->m_tconnects; for (V3TaskConnects::iterator conIt = tconnects->begin(); conIt != tconnects->end(); ++conIt) { diff --git a/src/verilog.l b/src/verilog.l index eec6be4ed..3ac7873b3 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -1084,9 +1084,9 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "`verilog" { FL_FWD; BEGIN PARSEP->lexKwdLastState(); FL_BRK; } /* Errors */ - "<<<<<<<"[^\n\r]* { FL; yylval.fl->v3error("version control conflict marker in file"); FL_BRK; } - "======="[^\n\r]* { FL; yylval.fl->v3error("version control conflict marker in file"); FL_BRK; } - ">>>>>>>"[^\n\r]* { FL; yylval.fl->v3error("version control conflict marker in file"); FL_BRK; } + "<<<<<<<"[^\n\r]* { FL; yylval.fl->v3error("Version control conflict marker in file"); FL_BRK; } + "======="[^\n\r]* { FL; yylval.fl->v3error("Version control conflict marker in file"); FL_BRK; } + ">>>>>>>"[^\n\r]* { FL; yylval.fl->v3error("Version control conflict marker in file"); FL_BRK; } /* If add to this list also add to V3LanguageWords.h */ } diff --git a/src/verilog.y b/src/verilog.y index 794a4cf61..c850947d2 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -7289,7 +7289,7 @@ vltOffFront: { const char *codemsg = (*$3).c_str(); if (V3ErrorCode::unusedMsg(codemsg)) {$$ = V3ErrorCode::I_UNUSED; } else {$$ = V3ErrorCode{codemsg}; } - if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown error code: " << *$3); } } + if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown error code: '" << *$3 << "'"); } } ; vltOnFront: @@ -7301,7 +7301,7 @@ vltOnFront: { const char *codemsg = (*$3).c_str(); if (V3ErrorCode::unusedMsg(codemsg)) {$$ = V3ErrorCode::I_UNUSED; } else {$$ = V3ErrorCode{codemsg}; } - if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown error code: " << *$3); } } + if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown error code: '" << *$3 << "'"); } } ; vltDModuleE: diff --git a/test_regress/t/t_array_backw_index_bad.out b/test_regress/t/t_array_backw_index_bad.out index f49d74019..babc5358e 100644 --- a/test_regress/t/t_array_backw_index_bad.out +++ b/test_regress/t/t_array_backw_index_bad.out @@ -1,29 +1,29 @@ %Error: t/t_array_backw_index_bad.v:17:19: Slice selection '[1:3]' has reversed range order versus data type's '[3:0]' - : ... In instance t + : ... note: In instance 't' 17 | array_assign[1:3] = '{32'd4, 32'd3, 32'd2}; | ^ %Error: t/t_array_backw_index_bad.v:18:20: Slice selection '[3:1]' has reversed range order versus data type's '[0:3]' - : ... In instance t + : ... note: In instance 't' 18 | larray_assign[3:1] = '{32'd4, 32'd3, 32'd2}; | ^ %Error: t/t_array_backw_index_bad.v:19:20: Slice selection '[4:6]' has reversed range order versus data type's '[6:3]' - : ... In instance t + : ... note: In instance 't' 19 | array_assign2[4:6] = '{32'd4, 32'd3, 32'd2}; | ^ %Error: t/t_array_backw_index_bad.v:20:21: Slice selection '[6:4]' has reversed range order versus data type's '[3:6]' - : ... In instance t + : ... note: In instance 't' 20 | larray_assign2[6:4] = '{32'd4, 32'd3, 32'd2}; | ^ %Error: t/t_array_backw_index_bad.v:22:19: Slice selection index '[4:3]' outside data type's '[3:0]' - : ... In instance t + : ... note: In instance 't' 22 | array_assign[4:3] = '{32'd4, 32'd3}; | ^ %Error: t/t_array_backw_index_bad.v:23:19: Slice selection index '[1:-1]' outside data type's '[3:0]' - : ... In instance t + : ... note: In instance 't' 23 | array_assign[1:-1] = '{32'd4, 32'd3}; | ^ %Error: t/t_array_backw_index_bad.v:23:28: Assignment pattern missed initializing elements: -1 - : ... In instance t + : ... note: In instance 't' 23 | array_assign[1:-1] = '{32'd4, 32'd3}; | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_array_list_bad.out b/test_regress/t/t_array_list_bad.out index c1b3a1b46..96a70f1d3 100644 --- a/test_regress/t/t_array_list_bad.out +++ b/test_regress/t/t_array_list_bad.out @@ -1,9 +1,9 @@ %Error: t/t_array_list_bad.v:38:25: Assignment pattern missed initializing elements: 'logic' 't3' - : ... In instance t + : ... note: In instance 't' 38 | test_out <= '{'0, '0}; | ^~ %Warning-WIDTHEXPAND: t/t_array_list_bad.v:38:22: Operator ASSIGNDLY expects 3 bits on the Assign RHS, but Assign RHS's CONCAT generates 2 bits. - : ... In instance t + : ... note: In instance 't' 38 | test_out <= '{'0, '0}; | ^~ ... For warning description see https://verilator.org/warn/WIDTHEXPAND?v=latest diff --git a/test_regress/t/t_array_method_bad.out b/test_regress/t/t_array_method_bad.out index 34f1fcb09..ce2d8a52d 100644 --- a/test_regress/t/t_array_method_bad.out +++ b/test_regress/t/t_array_method_bad.out @@ -1,5 +1,5 @@ %Error: t/t_array_method_bad.v:11:9: Unknown built-in array method 'mex' - : ... In instance t + : ... note: In instance 't' 11 | q.mex; | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_array_method_unsup.out b/test_regress/t/t_array_method_unsup.out index 792927193..9e3cd5e02 100644 --- a/test_regress/t/t_array_method_unsup.out +++ b/test_regress/t/t_array_method_unsup.out @@ -1,21 +1,21 @@ %Error: t/t_array_method_unsup.v:24:17: 'with' not legal on this method - : ... In instance t + : ... note: In instance 't' 24 | i = q.sum with (item + 1); do if ((i) !== (32'h11)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method_unsup.v",24, (i), (32'h11)); $stop; end while(0);; | ^~~~ %Error: t/t_array_method_unsup.v:25:21: 'with' not legal on this method - : ... In instance t + : ... note: In instance 't' 25 | i = q.product with (item + 1); do if ((i) !== (32'h168)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method_unsup.v",25, (i), (32'h168)); $stop; end while(0);; | ^~~~ %Error: t/t_array_method_unsup.v:28:17: 'with' not legal on this method - : ... In instance t + : ... note: In instance 't' 28 | i = q.and with (item + 1); do if ((i) !== (32'b1001)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method_unsup.v",28, (i), (32'b1001)); $stop; end while(0);; | ^~~~ %Error: t/t_array_method_unsup.v:29:16: 'with' not legal on this method - : ... In instance t + : ... note: In instance 't' 29 | i = q.or with (item + 1); do if ((i) !== (32'b1111)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method_unsup.v",29, (i), (32'b1111)); $stop; end while(0);; | ^~~~ %Error: t/t_array_method_unsup.v:30:17: 'with' not legal on this method - : ... In instance t + : ... note: In instance 't' 30 | i = q.xor with (item + 1); do if ((i) !== (32'hb)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method_unsup.v",30, (i), (32'hb)); $stop; end while(0);; | ^~~~ %Error: Exiting due to diff --git a/test_regress/t/t_array_pattern_bad.out b/test_regress/t/t_array_pattern_bad.out index 957b1715e..2a451e965 100644 --- a/test_regress/t/t_array_pattern_bad.out +++ b/test_regress/t/t_array_pattern_bad.out @@ -1,5 +1,5 @@ %Error: t/t_array_pattern_bad.v:24:18: Assignment pattern key 'valids' not found as member - : ... In instance t + : ... note: In instance 't' 24 | valids: '1}; | ^~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_array_pattern_bad2.out b/test_regress/t/t_array_pattern_bad2.out index bc5533253..ca000e327 100644 --- a/test_regress/t/t_array_pattern_bad2.out +++ b/test_regress/t/t_array_pattern_bad2.out @@ -1,5 +1,5 @@ %Error: t/t_array_pattern_bad2.v:22:16: Multiple '{ default: } clauses - : ... In instance t + : ... note: In instance 't' 22 | myinfo = '{default: '0, | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_array_pattern_bad3.out b/test_regress/t/t_array_pattern_bad3.out index dd393b336..ccc680c93 100644 --- a/test_regress/t/t_array_pattern_bad3.out +++ b/test_regress/t/t_array_pattern_bad3.out @@ -1,13 +1,13 @@ %Error: t/t_array_pattern_bad3.v:20:15: Assignment pattern key used multiple times: 1 - : ... In instance t + : ... note: In instance 't' 20 | 1: '1}; | ^ %Error: t/t_array_pattern_bad3.v:21:13: Assignment pattern with too many elements - : ... In instance t + : ... note: In instance 't' 21 | arr = '{'0, '1, '0, '1}; | ^~ %Error: t/t_array_pattern_bad3.v:22:13: Assignment pattern missed initializing elements: 2 - : ... In instance t + : ... note: In instance 't' 22 | arr = '{'0, '1}; | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_assert_comp_bad.out b/test_regress/t/t_assert_comp_bad.out index 759fcf96a..90ed6293e 100644 --- a/test_regress/t/t_assert_comp_bad.out +++ b/test_regress/t/t_assert_comp_bad.out @@ -1,35 +1,35 @@ -Info: t/t_assert_comp_bad.v:10:7: Elaboration system task message (IEEE 1800-2017 20.11) - : ... In instance t + : ... note: In instance 't' 10 | $info; | ^~~~~ -Info: t/t_assert_comp_bad.v:11:7: User elaboration-time info - : ... In instance t + : ... note: In instance 't' 11 | $info("User elaboration-time info"); | ^~~~~ %Warning-USERWARN: t/t_assert_comp_bad.v:12:7: Elaboration system task message (IEEE 1800-2017 20.11) - : ... In instance t + : ... note: In instance 't' 12 | $warning; | ^~~~~~~~ ... For warning description see https://verilator.org/warn/USERWARN?v=latest ... Use "/* verilator lint_off USERWARN */" and lint_on around source to disable this message. %Warning-USERWARN: t/t_assert_comp_bad.v:13:7: User elaboration-time warning - : ... In instance t + : ... note: In instance 't' 13 | $warning("User elaboration-time warning"); | ^~~~~~~~ %Warning-USERWARN: t/t_assert_comp_bad.v:14:7: 1 - : ... In instance t + : ... note: In instance 't' 14 | $warning(1); | ^~~~~~~~ %Warning-USERERROR: t/t_assert_comp_bad.v:15:7: Elaboration system task message (IEEE 1800-2017 20.11) - : ... In instance t + : ... note: In instance 't' 15 | $error; | ^~~~~~ %Warning-USERERROR: t/t_assert_comp_bad.v:16:7: User elaboration-time error - : ... In instance t + : ... note: In instance 't' 16 | $error("User elaboration-time error"); | ^~~~~~ %Warning-USERFATAL: t/t_assert_comp_bad.v:17:7: User elaboration-time fatal - : ... In instance t + : ... note: In instance 't' 17 | $fatal(0, "User elaboration-time fatal"); | ^~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_assert_disable_bad.out b/test_regress/t/t_assert_disable_bad.out index a53fbe9d1..8fc8cf9ef 100644 --- a/test_regress/t/t_assert_disable_bad.out +++ b/test_regress/t/t_assert_disable_bad.out @@ -1,5 +1,5 @@ %Error: t/t_assert_disable_bad.v:27:38: disable iff expression before property call and in its body is not legal - : ... In instance t + : ... note: In instance 't' 27 | assert property (disable iff (val == 0) check(1, 1)); | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_assert_procedural_clk.out b/test_regress/t/t_assert_procedural_clk.out index 0cd9304b0..98cbce1d6 100644 --- a/test_regress/t/t_assert_procedural_clk.out +++ b/test_regress/t/t_assert_procedural_clk.out @@ -1,9 +1,9 @@ %Error: t/t_assert_procedural_clk.v:21:13: Unsupported: Procedural concurrent assertion with clocking event inside always (IEEE 1800-2917 16.14.6) - : ... In instance t + : ... note: In instance 't' 21 | assume property (@(posedge clk) cyc == 9); | ^~~~~~ %Error: t/t_assert_procedural_clk.v:22:13: Unsupported: Procedural concurrent assertion with clocking event inside always (IEEE 1800-2917 16.14.6) - : ... In instance t + : ... note: In instance 't' 22 | assume property (@(negedge clk) cyc == 9); | ^~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_assert_recursive_property_unsup.out b/test_regress/t/t_assert_recursive_property_unsup.out index 7a2e9e68b..6176205df 100644 --- a/test_regress/t/t_assert_recursive_property_unsup.out +++ b/test_regress/t/t_assert_recursive_property_unsup.out @@ -1,5 +1,5 @@ %Error-UNSUPPORTED: t/t_assert_recursive_property_unsup.v:20:13: Unsupported: Recursive property call: 'check' - : ... In instance t + : ... note: In instance 't' 20 | property check(int n); | ^~~~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest diff --git a/test_regress/t/t_assoc_method_bad.out b/test_regress/t/t_assoc_method_bad.out index 76c49e771..794685136 100644 --- a/test_regress/t/t_assoc_method_bad.out +++ b/test_regress/t/t_assoc_method_bad.out @@ -1,57 +1,57 @@ %Error: t/t_assoc_method_bad.v:14:13: The 1 arguments passed to .num method does not match its requiring 0 arguments - : ... In instance t + : ... note: In instance 't' 14 | v = a.num("badarg"); | ^~~ %Error: t/t_assoc_method_bad.v:15:13: The 1 arguments passed to .size method does not match its requiring 0 arguments - : ... In instance t + : ... note: In instance 't' 15 | v = a.size("badarg"); | ^~~~ %Error: t/t_assoc_method_bad.v:16:13: The 0 arguments passed to .exists method does not match its requiring 1 arguments - : ... In instance t + : ... note: In instance 't' 16 | v = a.exists(); | ^~~~~~ %Error: t/t_assoc_method_bad.v:17:13: The 2 arguments passed to .exists method does not match its requiring 1 arguments - : ... In instance t + : ... note: In instance 't' 17 | v = a.exists(k, "bad2"); | ^~~~~~ %Error: t/t_assoc_method_bad.v:18:13: The 0 arguments passed to .first method does not match its requiring 1 arguments - : ... In instance t + : ... note: In instance 't' 18 | v = a.first(); | ^~~~~ %Error: t/t_assoc_method_bad.v:19:13: The 2 arguments passed to .next method does not match its requiring 1 arguments - : ... In instance t + : ... note: In instance 't' 19 | v = a.next(k, "bad2"); | ^~~~ %Error: t/t_assoc_method_bad.v:20:13: The 0 arguments passed to .last method does not match its requiring 1 arguments - : ... In instance t + : ... note: In instance 't' 20 | v = a.last(); | ^~~~ %Error: t/t_assoc_method_bad.v:21:13: The 2 arguments passed to .prev method does not match its requiring 1 arguments - : ... In instance t + : ... note: In instance 't' 21 | v = a.prev(k, "bad2"); | ^~~~ %Error: t/t_assoc_method_bad.v:22:9: The 2 arguments passed to .delete method does not match its requiring 0 to 1 arguments - : ... In instance t + : ... note: In instance 't' 22 | a.delete(k, "bad2"); | ^~~~~~ %Error: t/t_assoc_method_bad.v:24:9: Array method 'sort' not legal on associative arrays - : ... In instance t + : ... note: In instance 't' 24 | a.sort; | ^~~~ %Error: t/t_assoc_method_bad.v:25:9: Array method 'rsort' not legal on associative arrays - : ... In instance t + : ... note: In instance 't' 25 | a.rsort; | ^~~~~ %Error: t/t_assoc_method_bad.v:26:9: Array method 'reverse' not legal on associative arrays - : ... In instance t + : ... note: In instance 't' 26 | a.reverse; | ^~~~~~~ %Error: t/t_assoc_method_bad.v:27:9: Array method 'shuffle' not legal on associative arrays - : ... In instance t + : ... note: In instance 't' 27 | a.shuffle; | ^~~~~~~ %Error: t/t_assoc_method_bad.v:29:9: Unknown built-in associative array method 'bad_not_defined' - : ... In instance t + : ... note: In instance 't' 29 | a.bad_not_defined(); | ^~~~~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_assoc_wildcard_bad.out b/test_regress/t/t_assoc_wildcard_bad.out index 650f4b90c..348dfb271 100644 --- a/test_regress/t/t_assoc_wildcard_bad.out +++ b/test_regress/t/t_assoc_wildcard_bad.out @@ -1,77 +1,77 @@ %Error: t/t_assoc_wildcard_bad.v:23:13: The 1 arguments passed to .num method does not match its requiring 0 arguments - : ... In instance t + : ... note: In instance 't' 23 | v = a.num("badarg"); | ^~~ %Error: t/t_assoc_wildcard_bad.v:24:13: The 1 arguments passed to .size method does not match its requiring 0 arguments - : ... In instance t + : ... note: In instance 't' 24 | v = a.size("badarg"); | ^~~~ %Error: t/t_assoc_wildcard_bad.v:25:13: The 0 arguments passed to .exists method does not match its requiring 1 arguments - : ... In instance t + : ... note: In instance 't' 25 | v = a.exists(); | ^~~~~~ %Error: t/t_assoc_wildcard_bad.v:26:13: The 2 arguments passed to .exists method does not match its requiring 1 arguments - : ... In instance t + : ... note: In instance 't' 26 | v = a.exists(k, "bad2"); | ^~~~~~ %Error: t/t_assoc_wildcard_bad.v:27:9: The 2 arguments passed to .delete method does not match its requiring 0 to 1 arguments - : ... In instance t + : ... note: In instance 't' 27 | a.delete(k, "bad2"); | ^~~~~~ %Error: t/t_assoc_wildcard_bad.v:29:9: Array method 'sort' not legal on associative arrays - : ... In instance t + : ... note: In instance 't' 29 | a.sort; | ^~~~ %Error: t/t_assoc_wildcard_bad.v:30:9: Array method 'rsort' not legal on associative arrays - : ... In instance t + : ... note: In instance 't' 30 | a.rsort; | ^~~~~ %Error: t/t_assoc_wildcard_bad.v:31:9: Array method 'reverse' not legal on associative arrays - : ... In instance t + : ... note: In instance 't' 31 | a.reverse; | ^~~~~~~ %Error: t/t_assoc_wildcard_bad.v:32:9: Array method 'shuffle' not legal on associative arrays - : ... In instance t + : ... note: In instance 't' 32 | a.shuffle; | ^~~~~~~ %Error: t/t_assoc_wildcard_bad.v:34:9: Array method 'first' not legal on wildcard associative arrays - : ... In instance t + : ... note: In instance 't' 34 | a.first; | ^~~~~ %Error: t/t_assoc_wildcard_bad.v:35:9: Array method 'last' not legal on wildcard associative arrays - : ... In instance t + : ... note: In instance 't' 35 | a.last; | ^~~~ %Error: t/t_assoc_wildcard_bad.v:36:9: Array method 'next' not legal on wildcard associative arrays - : ... In instance t + : ... note: In instance 't' 36 | a.next; | ^~~~ %Error: t/t_assoc_wildcard_bad.v:37:9: Array method 'prev' not legal on wildcard associative arrays - : ... In instance t + : ... note: In instance 't' 37 | a.prev; | ^~~~ %Error: t/t_assoc_wildcard_bad.v:38:9: Array method 'unique_index' not legal on wildcard associative arrays - : ... In instance t + : ... note: In instance 't' 38 | a.unique_index; | ^~~~~~~~~~~~ %Error: t/t_assoc_wildcard_bad.v:39:9: Array method 'find_index' not legal on wildcard associative arrays - : ... In instance t + : ... note: In instance 't' 39 | a.find_index; | ^~~~~~~~~~ %Error: t/t_assoc_wildcard_bad.v:40:9: Array method 'find_first_index' not legal on wildcard associative arrays - : ... In instance t + : ... note: In instance 't' 40 | a.find_first_index; | ^~~~~~~~~~~~~~~~ %Error: t/t_assoc_wildcard_bad.v:41:9: Array method 'find_last_index' not legal on wildcard associative arrays - : ... In instance t + : ... note: In instance 't' 41 | a.find_last_index; | ^~~~~~~~~~~~~~~ %Error: t/t_assoc_wildcard_bad.v:43:8: Wildcard index must be integral (IEEE 1800-2017 7.8.1) - : ... In instance t + : ... note: In instance 't' 43 | a[x] = "bad"; | ^ %Error: t/t_assoc_wildcard_bad.v:45:9: Unknown wildcard associative array method 'bad_not_defined' - : ... In instance t + : ... note: In instance 't' 45 | a.bad_not_defined(); | ^~~~~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_bigmem_bad.out b/test_regress/t/t_bigmem_bad.out index ec7bfe78a..fc31e3e90 100644 --- a/test_regress/t/t_bigmem_bad.out +++ b/test_regress/t/t_bigmem_bad.out @@ -1,5 +1,5 @@ %Warning-SELRANGE: t/t_bigmem_bad.v:14:19: Selection index out of range: (nodep->declElWidth() == 0) -1:0 outside 268435455:0 - : ... In instance t_bigmem + : ... note: In instance 't_bigmem' 14 | if (wen) mem[addr] <= data; | ^ ... For warning description see https://verilator.org/warn/SELRANGE?v=latest diff --git a/test_regress/t/t_bitsel_const_bad.out b/test_regress/t/t_bitsel_const_bad.out index 767882eeb..549399517 100644 --- a/test_regress/t/t_bitsel_const_bad.out +++ b/test_regress/t/t_bitsel_const_bad.out @@ -1,5 +1,5 @@ %Error: t/t_bitsel_const_bad.v:21:16: Illegal bit or array select; type does not have a bit range, or bad dimension: data type is 'logic' - : ... In instance t + : ... note: In instance 't' 21 | assign a = b[0]; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_bitsel_wire_array_bad.out b/test_regress/t/t_bitsel_wire_array_bad.out index d256eef7d..43ba6671a 100644 --- a/test_regress/t/t_bitsel_wire_array_bad.out +++ b/test_regress/t/t_bitsel_wire_array_bad.out @@ -1,5 +1,5 @@ %Error: t/t_bitsel_wire_array_bad.v:21:16: Illegal assignment of constant to unpacked array - : ... In instance t + : ... note: In instance 't' 21 | assign b = a[0]; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_case_genx_bad.out b/test_regress/t/t_case_genx_bad.out index abdb81e62..c70d5a572 100644 --- a/test_regress/t/t_case_genx_bad.out +++ b/test_regress/t/t_case_genx_bad.out @@ -1,5 +1,5 @@ %Error: t/t_case_genx_bad.v:14:9: Use of x/? constant in generate case statement, (no such thing as 'generate casez') - : ... In instance t + : ... note: In instance 't' 14 | 32'b1xxx: initial begin end | ^~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_cast_class_incompat_bad.out b/test_regress/t/t_cast_class_incompat_bad.out index 2f214826d..8fe092ad8 100644 --- a/test_regress/t/t_cast_class_incompat_bad.out +++ b/test_regress/t/t_cast_class_incompat_bad.out @@ -1,10 +1,10 @@ %Error: t/t_cast_class_incompat_bad.v:26:16: Dynamic, not static cast, required to cast 'CLASSREFDTYPE 'BaseExtended'' from 'CLASSREFDTYPE 'Base'' - : ... In instance t + : ... note: In instance 't' : ... Suggest dynamic $cast 26 | cls_ab = BaseExtended'(cls_a); | ^~~~~~~~~~~~ %Error: t/t_cast_class_incompat_bad.v:27:15: Incompatible types to static cast to 'CLASSREFDTYPE 'Other'' from 'CLASSREFDTYPE 'BaseExtended'' - : ... In instance t + : ... note: In instance 't' 27 | other = Other'(cls_ab); | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_cast_size_bad.out b/test_regress/t/t_cast_size_bad.out index 498099b69..e8243cae6 100644 --- a/test_regress/t/t_cast_size_bad.out +++ b/test_regress/t/t_cast_size_bad.out @@ -1,9 +1,9 @@ %Error: t/t_cast_size_bad.v:14:15: Size-changing cast to zero or negative size - : ... In instance t + : ... note: In instance 't' 14 | b = (-1)'(a); | ^ %Warning-WIDTHEXPAND: t/t_cast_size_bad.v:14:9: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's SEL generates 1 bits. - : ... In instance t + : ... note: In instance 't' 14 | b = (-1)'(a); | ^ ... For warning description see https://verilator.org/warn/WIDTHEXPAND?v=latest diff --git a/test_regress/t/t_castdyn_castconst_bad.out b/test_regress/t/t_castdyn_castconst_bad.out index 0251dc59e..adb79a262 100644 --- a/test_regress/t/t_castdyn_castconst_bad.out +++ b/test_regress/t/t_castdyn_castconst_bad.out @@ -1,17 +1,17 @@ %Warning-CASTCONST: t/t_castdyn_castconst_bad.v:20:11: $cast will always return one as 'int' is always castable from 'logic[31:0]' - : ... In instance t + : ... note: In instance 't' : ... Suggest static cast 20 | i = $cast(v, 1); | ^~~~~ ... For warning description see https://verilator.org/warn/CASTCONST?v=latest ... Use "/* verilator lint_off CASTCONST */" and lint_on around source to disable this message. %Warning-CASTCONST: t/t_castdyn_castconst_bad.v:21:11: $cast will always return one as 'CLASSREFDTYPE 'Base'' is always castable from 'CLASSREFDTYPE 'Base'' - : ... In instance t + : ... note: In instance 't' : ... Suggest static cast 21 | i = $cast(b, b); | ^~~~~ %Warning-CASTCONST: t/t_castdyn_castconst_bad.v:22:11: $cast will always return zero as 'CLASSREFDTYPE 'Base'' is not castable from 'CLASSREFDTYPE 'Other'' - : ... In instance t + : ... note: In instance 't' 22 | i = $cast(b, o); | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_castdyn_unsup_bad.out b/test_regress/t/t_castdyn_unsup_bad.out index 328f9b91b..e73b1eecd 100644 --- a/test_regress/t/t_castdyn_unsup_bad.out +++ b/test_regress/t/t_castdyn_unsup_bad.out @@ -1,5 +1,5 @@ %Error-UNSUPPORTED: t/t_castdyn_unsup_bad.v:13:7: Unsupported: $cast to 'string[$]' from 'int[string]' - : ... In instance t + : ... note: In instance 't' : ... Suggest try static cast 13 | $cast(q, aarray); | ^~~~~ diff --git a/test_regress/t/t_class_assign_bad.out b/test_regress/t/t_class_assign_bad.out index 151bc48a8..4ae5b5cad 100644 --- a/test_regress/t/t_class_assign_bad.out +++ b/test_regress/t/t_class_assign_bad.out @@ -1,37 +1,37 @@ %Error: t/t_class_assign_bad.v:28:9: Assign RHS expects a CLASSREFDTYPE 'Cls', got BASICDTYPE 'logic' - : ... In instance t + : ... note: In instance 't' 28 | c = 0; | ^ %Error: t/t_class_assign_bad.v:29:9: Assign RHS expects a CLASSREFDTYPE 'Cls', got BASICDTYPE 'logic' - : ... In instance t + : ... note: In instance 't' 29 | c = 1; | ^ %Error: t/t_class_assign_bad.v:30:9: Assign RHS expects a CLASSREFDTYPE 'Cls', got CLASSREFDTYPE 'Cls2' - : ... In instance t + : ... note: In instance 't' 30 | c = c2; | ^ %Error: t/t_class_assign_bad.v:31:13: Assign RHS expects a CLASSREFDTYPE 'ClsExt', got CLASSREFDTYPE 'Cls' - : ... In instance t + : ... note: In instance 't' 31 | c_ext = c; | ^ %Error: t/t_class_assign_bad.v:32:11: Assign RHS expects a CLASSREFDTYPE 'Cls2', got CLASSREFDTYPE 'Cls' - : ... In instance t + : ... note: In instance 't' 32 | ct2 = c; | ^ %Error: t/t_class_assign_bad.v:34:7: Function Argument expects a CLASSREFDTYPE 'Cls', got BASICDTYPE 'logic' - : ... In instance t + : ... note: In instance 't' 34 | t(0); | ^ %Error: t/t_class_assign_bad.v:35:7: Function Argument expects a CLASSREFDTYPE 'Cls', got BASICDTYPE 'logic' - : ... In instance t + : ... note: In instance 't' 35 | t(1); | ^ %Error: t/t_class_assign_bad.v:36:7: Function Argument expects a CLASSREFDTYPE 'Cls', got CLASSREFDTYPE 'Cls2' - : ... In instance t + : ... note: In instance 't' 36 | t(c2); | ^ %Error: t/t_class_assign_bad.v:37:7: Function Argument expects a CLASSREFDTYPE 'ClsExt', got CLASSREFDTYPE 'Cls' - : ... In instance t + : ... note: In instance 't' 37 | f(c); | ^ %Error: Exiting due to diff --git a/test_regress/t/t_class_assign_cond_bad.out b/test_regress/t/t_class_assign_cond_bad.out index d0d347f17..6705aafef 100644 --- a/test_regress/t/t_class_assign_cond_bad.out +++ b/test_regress/t/t_class_assign_cond_bad.out @@ -1,21 +1,21 @@ %Error: t/t_class_assign_cond_bad.v:22:25: Incompatible types of operands of condition operator: CLASSREFDTYPE 'Cls1' and CLASSREFDTYPE 'Cls2' - : ... In instance t + : ... note: In instance 't' 22 | c1 = (c1 != null) ? c1 : c2; | ^ %Error: t/t_class_assign_cond_bad.v:23:10: Assign RHS expects a CLASSREFDTYPE 'Cls1', got CLASSREFDTYPE 'Cls2' - : ... In instance t + : ... note: In instance 't' 23 | c1 = (c1 != null) ? c2 : c2; | ^ %Error: t/t_class_assign_cond_bad.v:24:25: Incompatible types of operands of condition operator: BASICDTYPE 'logic' and CLASSREFDTYPE 'Cls2' - : ... In instance t + : ... note: In instance 't' 24 | c2 = (c1 == null) ? 1'b1 : c2; | ^ %Error: t/t_class_assign_cond_bad.v:24:10: Assign RHS expects a CLASSREFDTYPE 'Cls2', got BASICDTYPE 'logic' - : ... In instance t + : ... note: In instance 't' 24 | c2 = (c1 == null) ? 1'b1 : c2; | ^ %Error: t/t_class_assign_cond_bad.v:25:29: Incompatible types of operands of condition operator: CLASSREFDTYPE 'ExtCls1' and CLASSREFDTYPE 'Cls1' - : ... In instance t + : ... note: In instance 't' 25 | ext_c1 = (c1 == null) ? ext_c1 : c1; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_class_builtin_bad.out b/test_regress/t/t_class_builtin_bad.out index 525420077..5b5c21072 100644 --- a/test_regress/t/t_class_builtin_bad.out +++ b/test_regress/t/t_class_builtin_bad.out @@ -1,9 +1,9 @@ %Error: t/t_class_builtin_bad.v:8:17: The 'rand_mode' method is built-in and cannot be overridden (IEEE 1800-2017 18.8) - : ... In instance t + : ... note: In instance 't' 8 | function int rand_mode(bit onoff); | ^~~~~~~~~ %Error: t/t_class_builtin_bad.v:11:17: The 'constraint_mode' method is built-in and cannot be overridden (IEEE 1800-2017 18.9) - : ... In instance t + : ... note: In instance 't' 11 | function int constraint_mode(bit onoff); | ^~~~~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_copy_bad.out b/test_regress/t/t_class_copy_bad.out index 5b1c726b6..de65e77eb 100644 --- a/test_regress/t/t_class_copy_bad.out +++ b/test_regress/t/t_class_copy_bad.out @@ -1,5 +1,5 @@ %Error: t/t_class_copy_bad.v:19:16: New-as-copier passed different data type 'CLASSREFDTYPE 'Cls'' then expected 'CLASSREFDTYPE 'Other'' - : ... In instance t + : ... note: In instance 't' 19 | c1 = new co; | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_class_extends_aliased_real_bad.out b/test_regress/t/t_class_extends_aliased_real_bad.out index ce714742d..0aca6d8e4 100644 --- a/test_regress/t/t_class_extends_aliased_real_bad.out +++ b/test_regress/t/t_class_extends_aliased_real_bad.out @@ -1,5 +1,5 @@ %Error: t/t_class_extends_aliased_real_bad.v:14:10: Attempting to extend using non-class - : ... In instance t + : ... note: In instance 't' 14 | bar #(real_t) bar_real_t; | ^~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_extends_int_param_bad.out b/test_regress/t/t_class_extends_int_param_bad.out index e16b75da5..d6d473552 100644 --- a/test_regress/t/t_class_extends_int_param_bad.out +++ b/test_regress/t/t_class_extends_int_param_bad.out @@ -1,5 +1,5 @@ %Error: t/t_class_extends_int_param_bad.v:9:23: Attempting to extend using non-class - : ... In instance t + : ... note: In instance 't' 9 | class Bar #(type T=int) extends T; | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_extern_bad.out b/test_regress/t/t_class_extern_bad.out index 96a3e2bb1..6fda0c135 100644 --- a/test_regress/t/t_class_extern_bad.out +++ b/test_regress/t/t_class_extern_bad.out @@ -4,10 +4,10 @@ t/t_class_extern_bad.v:8:16: ... Location of original declaration 8 | extern task nodef(); | ^~~~~ -%Error: t/t_class_extern_bad.v:8:16: definition not found for extern 'nodef' +%Error: t/t_class_extern_bad.v:8:16: Definition not found for extern 'nodef' 8 | extern task nodef(); | ^~~~~ -%Error: t/t_class_extern_bad.v:9:16: definition not found for extern 'nodef' +%Error: t/t_class_extern_bad.v:9:16: Definition not found for extern 'nodef' 9 | extern task nodef(); | ^~~~~ %Error: t/t_class_extern_bad.v:12:6: extern not found that declares 'noproto' diff --git a/test_regress/t/t_class_local_bad.out b/test_regress/t/t_class_local_bad.out index 994f36a69..872e4f1e3 100644 --- a/test_regress/t/t_class_local_bad.out +++ b/test_regress/t/t_class_local_bad.out @@ -1,5 +1,5 @@ %Error-ENCAPSULATED: t/t_class_local_bad.v:71:20: 'm_loc' is hidden as 'local' within this context (IEEE 1800-2017 8.18) - : ... In instance t + : ... note: In instance 't' 71 | bad(); if (c.m_loc != 2) $stop; | ^~~~~ t/t_class_local_bad.v:71:20: ... Location of definition @@ -7,98 +7,98 @@ | ^~~~~ ... For error description see https://verilator.org/warn/ENCAPSULATED?v=latest %Error-ENCAPSULATED: t/t_class_local_bad.v:72:20: 'm_prot' is hidden as 'protected' within this context (IEEE 1800-2017 8.18) - : ... In instance t + : ... note: In instance 't' 72 | bad(); if (c.m_prot != 20) $stop; | ^~~~~~ t/t_class_local_bad.v:72:20: ... Location of definition 16 | protected int m_prot = 3; | ^~~~~~ %Error-ENCAPSULATED: t/t_class_local_bad.v:74:20: 'm_loc' is hidden as 'local' within this context (IEEE 1800-2017 8.18) - : ... In instance t + : ... note: In instance 't' 74 | bad(); if (e.m_loc != 2) $stop; | ^~~~~ t/t_class_local_bad.v:74:20: ... Location of definition 15 | local int m_loc = 2; | ^~~~~ %Error-ENCAPSULATED: t/t_class_local_bad.v:75:20: 'm_prot' is hidden as 'protected' within this context (IEEE 1800-2017 8.18) - : ... In instance t + : ... note: In instance 't' 75 | bad(); if (e.m_prot != 20) $stop; | ^~~~~~ t/t_class_local_bad.v:75:20: ... Location of definition 16 | protected int m_prot = 3; | ^~~~~~ %Error-ENCAPSULATED: t/t_class_local_bad.v:77:16: 'f_loc' is hidden as 'local' within this context (IEEE 1800-2017 8.18) - : ... In instance t + : ... note: In instance 't' 77 | bad(); c.f_loc(); | ^~~~~ t/t_class_local_bad.v:77:16: ... Location of definition 18 | local task f_loc; endtask | ^~~~~ %Error-ENCAPSULATED: t/t_class_local_bad.v:78:16: 'f_prot' is hidden as 'protected' within this context (IEEE 1800-2017 8.18) - : ... In instance t + : ... note: In instance 't' 78 | bad(); c.f_prot(); | ^~~~~~ t/t_class_local_bad.v:78:16: ... Location of definition 19 | protected task f_prot; endtask | ^~~~~~ %Error-ENCAPSULATED: t/t_class_local_bad.v:80:16: 's_loc' is hidden as 'local' within this context (IEEE 1800-2017 8.18) - : ... In instance t + : ... note: In instance 't' 80 | bad(); c.s_loc(); | ^~~~~ t/t_class_local_bad.v:80:16: ... Location of definition 21 | static local task s_loc; endtask | ^~~~~ %Error-ENCAPSULATED: t/t_class_local_bad.v:81:16: 's_prot' is hidden as 'protected' within this context (IEEE 1800-2017 8.18) - : ... In instance t + : ... note: In instance 't' 81 | bad(); c.s_prot(); | ^~~~~~ t/t_class_local_bad.v:81:16: ... Location of definition 22 | static protected task s_prot; endtask | ^~~~~~ %Error-ENCAPSULATED: t/t_class_local_bad.v:83:19: 's_loc' is hidden as 'local' within this context (IEEE 1800-2017 8.18) - : ... In instance t + : ... note: In instance 't' 83 | bad(); Cls::s_loc(); | ^~~~~ t/t_class_local_bad.v:83:19: ... Location of definition 21 | static local task s_loc; endtask | ^~~~~ %Error-ENCAPSULATED: t/t_class_local_bad.v:84:19: 's_prot' is hidden as 'protected' within this context (IEEE 1800-2017 8.18) - : ... In instance t + : ... note: In instance 't' 84 | bad(); Cls::s_prot(); | ^~~~~~ t/t_class_local_bad.v:84:19: ... Location of definition 22 | static protected task s_prot; endtask | ^~~~~~ %Error-ENCAPSULATED: t/t_class_local_bad.v:47:18: 'm_loc' is hidden as 'local' within this context (IEEE 1800-2017 8.18) - : ... In instance t + : ... note: In instance 't' 47 | bad(); if (m_loc != 10) $stop; | ^~~~~ t/t_class_local_bad.v:47:18: ... Location of definition 15 | local int m_loc = 2; | ^~~~~ %Error-ENCAPSULATED: t/t_class_local_bad.v:50:14: 'f_loc' is hidden as 'local' within this context (IEEE 1800-2017 8.18) - : ... In instance t + : ... note: In instance 't' 50 | bad(); f_loc(); | ^~~~~ t/t_class_local_bad.v:50:14: ... Location of definition 18 | local task f_loc; endtask | ^~~~~ %Error-ENCAPSULATED: t/t_class_local_bad.v:53:16: 'f_loc' is hidden as 'local' within this context (IEEE 1800-2017 8.18) - : ... In instance t + : ... note: In instance 't' 53 | bad(); o.f_loc(); | ^~~~~ t/t_class_local_bad.v:53:16: ... Location of definition 18 | local task f_loc; endtask | ^~~~~ %Error-ENCAPSULATED: t/t_class_local_bad.v:56:14: 's_loc' is hidden as 'local' within this context (IEEE 1800-2017 8.18) - : ... In instance t + : ... note: In instance 't' 56 | bad(); s_loc(); | ^~~~~ t/t_class_local_bad.v:56:14: ... Location of definition 21 | static local task s_loc; endtask | ^~~~~ %Error-ENCAPSULATED: t/t_class_local_bad.v:59:19: 's_loc' is hidden as 'local' within this context (IEEE 1800-2017 8.18) - : ... In instance t + : ... note: In instance 't' 59 | bad(); Cls::s_loc(); | ^~~~~ t/t_class_local_bad.v:59:19: ... Location of definition diff --git a/test_regress/t/t_class_member_bad.out b/test_regress/t/t_class_member_bad.out index 49570f53f..a7b0dbb3e 100644 --- a/test_regress/t/t_class_member_bad.out +++ b/test_regress/t/t_class_member_bad.out @@ -1,10 +1,10 @@ %Error: t/t_class_member_bad.v:18:9: Member 'memb3' not found in class 'Cls2' - : ... In instance t + : ... note: In instance 't' : ... Suggested alternative: 'memb2' 18 | c.memb3 = 3; | ^~~~~ %Warning-WIDTHTRUNC: t/t_class_member_bad.v:18:15: Operator ASSIGN expects 1 bits on the Assign RHS, but Assign RHS's CONST '?32?sh3' generates 32 or 2 bits. - : ... In instance t + : ... note: In instance 't' 18 | c.memb3 = 3; | ^ ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest diff --git a/test_regress/t/t_class_method_bad.out b/test_regress/t/t_class_method_bad.out index 5a2cbc931..754de927c 100644 --- a/test_regress/t/t_class_method_bad.out +++ b/test_regress/t/t_class_method_bad.out @@ -1,5 +1,5 @@ %Error: t/t_class_method_bad.v:18:9: Class method 'meth3' not found in class 'Cls2' - : ... In instance t + : ... note: In instance 't' : ... Suggested alternative: 'meth2' 18 | c.meth3(); | ^~~~~ diff --git a/test_regress/t/t_class_new_bad.out b/test_regress/t/t_class_new_bad.out index 454eae5d6..19ea9d1cf 100644 --- a/test_regress/t/t_class_new_bad.out +++ b/test_regress/t/t_class_new_bad.out @@ -1,20 +1,20 @@ %Error: t/t_class_new_bad.v:31:16: Too many arguments in function call to FUNC 'new' - : ... In instance t + : ... note: In instance 't' 31 | c1 = new(3); | ^ %Error: t/t_class_new_bad.v:32:16: Too many arguments in function call to FUNC 'new' - : ... In instance t + : ... note: In instance 't' 32 | c2 = new(3); | ^ %Error: t/t_class_new_bad.v:33:12: Missing argument on non-defaulted argument 'i' in function call to FUNC 'new' - : ... In instance t + : ... note: In instance 't' 33 | c3 = new(); | ^~~ %Error: t/t_class_new_bad.v:34:12: dynamic new() not expected in this context (data type must be dynamic array) - : ... In instance t + : ... note: In instance 't' 34 | c1 = new[2]; | ^~~ %Error: Internal Error: t/t_class_new_bad.v:34:12: ../V3Width.cpp:#: Node has no type - : ... In instance t + : ... note: In instance 't' 34 | c1 = new[2]; | ^~~ diff --git a/test_regress/t/t_class_param_bad2.out b/test_regress/t/t_class_param_bad2.out index 35b901184..1eadc4902 100644 --- a/test_regress/t/t_class_param_bad2.out +++ b/test_regress/t/t_class_param_bad2.out @@ -1,5 +1,5 @@ %Error: t/t_class_param_bad2.v:12:4: Missing type parameter: 'PARAMB' - : ... In instance t + : ... note: In instance 't' 12 | Cls c; | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_param_circ_bad.out b/test_regress/t/t_class_param_circ_bad.out index 35b6ce09a..48506b492 100644 --- a/test_regress/t/t_class_param_circ_bad.out +++ b/test_regress/t/t_class_param_circ_bad.out @@ -1,5 +1,5 @@ %Error: t/t_class_param_circ_bad.v:14:4: Exceeded maximum --module-recursion-depth of 100 - : ... In instance t + : ... note: In instance 't' 14 | ClsA #(PARAM+1) a; | ^~~~ %Error: Internal Error: ../V3Param.cpp:#: should find just-made module diff --git a/test_regress/t/t_class_param_enum_bad.out b/test_regress/t/t_class_param_enum_bad.out index 4f5f727f9..95e80621a 100644 --- a/test_regress/t/t_class_param_enum_bad.out +++ b/test_regress/t/t_class_param_enum_bad.out @@ -1,9 +1,9 @@ %Error: t/t_class_param_enum_bad.v:20:31: Assign RHS expects a CLASSREFDTYPE 'Converter__Tz2', got CLASSREFDTYPE 'Converter__Tz1' - : ... In instance t + : ... note: In instance 't' 20 | Converter#(bit) conv2 = conv1; | ^~~~~ %Error-ENUMVALUE: t/t_class_param_enum_bad.v:21:19: Implicit conversion to enum 'ENUMDTYPE '$unit::enum_t'' from 'logic[31:0]' (IEEE 1800-2017 6.19.3) - : ... In instance t + : ... note: In instance 't' : ... Suggest use enum's mnemonic, or static cast 21 | conv1.toInt(0); | ^ diff --git a/test_regress/t/t_class_param_nconst_bad.out b/test_regress/t/t_class_param_nconst_bad.out index 812399530..28382723a 100644 --- a/test_regress/t/t_class_param_nconst_bad.out +++ b/test_regress/t/t_class_param_nconst_bad.out @@ -1,9 +1,9 @@ %Error: t/t_class_param_nconst_bad.v:12:17: Expecting expression to be constant, but can't convert a RAND to constant. - : ... In instance t + : ... note: In instance 't' 12 | Cls #(.PARAM($random)) c; | ^~~~~~~ %Error: t/t_class_param_nconst_bad.v:12:11: Can't convert defparam value to constant: Param 'PARAM' of 'Cls' - : ... In instance t + : ... note: In instance 't' 12 | Cls #(.PARAM($random)) c; | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_param_nested_bad.out b/test_regress/t/t_class_param_nested_bad.out index ce4a30bc0..9e7f90c07 100644 --- a/test_regress/t/t_class_param_nested_bad.out +++ b/test_regress/t/t_class_param_nested_bad.out @@ -1,10 +1,10 @@ %Error-UNSUPPORTED: t/t_class_param_nested_bad.v:51:23: dotted expressions in parameters - : ... In instance t + : ... note: In instance 't' : ... Suggest use a typedef 51 | Wrap2 #(Wrap#(19)::PBASE * 2) w38; | ^~~~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error: Internal Error: t/t_class_param_nested_bad.v:51:29: ../V3Width.cpp:#: Node has no type - : ... In instance t + : ... note: In instance 't' 51 | Wrap2 #(Wrap#(19)::PBASE * 2) w38; | ^ diff --git a/test_regress/t/t_class_param_noinit_bad.out b/test_regress/t/t_class_param_noinit_bad.out index 7e021c7b9..2e8cd6dc1 100644 --- a/test_regress/t/t_class_param_noinit_bad.out +++ b/test_regress/t/t_class_param_noinit_bad.out @@ -1,5 +1,5 @@ %Error: t/t_class_param_noinit_bad.v:13:7: Class parameter without initial value is never given value (IEEE 1800-2017 6.20.1): 'B' - : ... In instance t + : ... note: In instance 't' 13 | Cls #(1) c; | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_virtual_bad.out b/test_regress/t/t_class_virtual_bad.out index 4b1e2878b..946c04299 100644 --- a/test_regress/t/t_class_virtual_bad.out +++ b/test_regress/t/t_class_virtual_bad.out @@ -1,5 +1,5 @@ %Error: t/t_class_virtual_bad.v:12:17: Illegal to call 'new' using an abstract virtual class (IEEE 1800-2017 8.21) - : ... In instance t + : ... note: In instance 't' 12 | VBase b = new; | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_clocking_bad1.out b/test_regress/t/t_clocking_bad1.out index 214ae7a0d..c134cd91d 100644 --- a/test_regress/t/t_clocking_bad1.out +++ b/test_regress/t/t_clocking_bad1.out @@ -1,5 +1,5 @@ %Error: t/t_clocking_bad1.v:16:12: Only one default clocking block allowed per module (IEEE 1800-2017 14.12) - : ... In instance t + : ... note: In instance 't' 16 | default clocking @(posedge clk); | ^~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_clocking_bad4.out b/test_regress/t/t_clocking_bad4.out index b5702e561..04df674f1 100644 --- a/test_regress/t/t_clocking_bad4.out +++ b/test_regress/t/t_clocking_bad4.out @@ -1,45 +1,45 @@ %Error: t/t_clocking_bad4.v:23:15: Skew must be constant (IEEE 1800-2017 14.4) - : ... In instance t + : ... note: In instance 't' 23 | input #cyc in; | ^~~ %Error: t/t_clocking_bad4.v:24:16: Skew cannot be negative - : ... In instance t + : ... note: In instance 't' 24 | input #(-1) out; | ^ %Error: t/t_clocking_bad4.v:31:11: Usage of cycle delays requires default clocking (IEEE 1800-2017 14.11) - : ... In instance t + : ... note: In instance 't' 31 | always ##1; | ^~ %Error: t/t_clocking_bad4.v:32:15: Only non-blocking assignments can write to clockvars (IEEE 1800-2017 14.16) - : ... In instance t + : ... note: In instance 't' 32 | always cb1.out = clk; | ^~~ %Error: t/t_clocking_bad4.v:33:15: Only non-blocking assignments can write to clockvars (IEEE 1800-2017 14.16) - : ... In instance t + : ... note: In instance 't' 33 | assign cb1.out = clk; | ^~~ %Error: t/t_clocking_bad4.v:34:21: Only non-blocking assignments can write to clockvars (IEEE 1800-2017 14.16) - : ... In instance t + : ... note: In instance 't' 34 | always write(cb1.out); | ^~~ %Error: t/t_clocking_bad4.v:35:22: Event controls cannot be used in synchronous drives (IEEE 1800-2017 14.16) - : ... In instance t + : ... note: In instance 't' 35 | always cb1.out <= @(posedge clk) 1; | ^ %Error: t/t_clocking_bad4.v:36:22: Only cycle delays can be used in synchronous drives (IEEE 1800-2017 14.16) - : ... In instance t + : ... note: In instance 't' 36 | always cb1.out <= #1 1; | ^ %Error: t/t_clocking_bad4.v:37:18: Cycle delays not allowed as intra-assignment delays (IEEE 1800-2017 14.11) - : ... In instance t + : ... note: In instance 't' 37 | always out <= ##1 1; | ^~ %Error: t/t_clocking_bad4.v:40:12: Cannot write to input clockvar (IEEE 1800-2017 14.3) - : ... In instance t + : ... note: In instance 't' 40 | cb1.in = 1; | ^~ %Error: t/t_clocking_bad4.v:41:21: Cannot read from output clockvar (IEEE 1800-2017 14.3) - : ... In instance t + : ... note: In instance 't' 41 | $display(cb1.out); | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_clocking_notiming.out b/test_regress/t/t_clocking_notiming.out index 4a304c9d9..7b7fe7943 100644 --- a/test_regress/t/t_clocking_notiming.out +++ b/test_regress/t/t_clocking_notiming.out @@ -1,5 +1,5 @@ %Error-NOTIMING: t/t_clocking_notiming.v:11:8: Clocking output skew greater than #0 requires --timing - : ... In instance t + : ... note: In instance 't' 11 | output #1 out; | ^~~~~~ ... For error description see https://verilator.org/warn/NOTIMING?v=latest diff --git a/test_regress/t/t_clocking_unsup2.out b/test_regress/t/t_clocking_unsup2.out index 644d2e206..9d4b7df46 100644 --- a/test_regress/t/t_clocking_unsup2.out +++ b/test_regress/t/t_clocking_unsup2.out @@ -1,5 +1,5 @@ %Error-UNSUPPORTED: t/t_clocking_unsup2.v:16:11: Unsupported: ##0 delays - : ... In instance t + : ... note: In instance 't' 16 | always ##0; | ^~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest diff --git a/test_regress/t/t_concat_large_bad.out b/test_regress/t/t_concat_large_bad.out index 1874895ef..9ae1fcc8c 100644 --- a/test_regress/t/t_concat_large_bad.out +++ b/test_regress/t/t_concat_large_bad.out @@ -1,5 +1,5 @@ %Warning-WIDTHCONCAT: t/t_concat_large_bad.v:9:29: More than a 8k bit replication is probably wrong: 32768 - : ... In instance t + : ... note: In instance 't' 9 | wire [32767:0] a = {32768{1'b1}}; | ^ ... For warning description see https://verilator.org/warn/WIDTHCONCAT?v=latest diff --git a/test_regress/t/t_const_bad.out b/test_regress/t/t_const_bad.out index 65358eb59..5ef1e1fd6 100644 --- a/test_regress/t/t_const_bad.out +++ b/test_regress/t/t_const_bad.out @@ -1,15 +1,15 @@ %Warning-WIDTHXZEXPAND: t/t_const_bad.v:13:39: Unsized constant being X/Z extended to 68 bits: ?32?bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - : ... In instance t + : ... note: In instance 't' 13 | if (68'hx_xxxxxxxx_xxxxxxxx !== 'dX) $stop; | ^~~ ... For warning description see https://verilator.org/warn/WIDTHXZEXPAND?v=latest ... Use "/* verilator lint_off WIDTHXZEXPAND */" and lint_on around source to disable this message. %Warning-WIDTHXZEXPAND: t/t_const_bad.v:14:39: Unsized constant being X/Z extended to 68 bits: ?32?bzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz - : ... In instance t + : ... note: In instance 't' 14 | if (68'hz_zzzzzzzz_zzzzzzzz !== 'dZ) $stop; | ^~~ %Warning-WIDTHXZEXPAND: t/t_const_bad.v:15:39: Unsized constant being X/Z extended to 68 bits: ?32?bzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz - : ... In instance t + : ... note: In instance 't' 15 | if (68'h?_????????_???????? !== 'd?) $stop; | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_constraint_mode_warn_bad.out b/test_regress/t/t_constraint_mode_warn_bad.out index 478853c43..7bcae1c14 100644 --- a/test_regress/t/t_constraint_mode_warn_bad.out +++ b/test_regress/t/t_constraint_mode_warn_bad.out @@ -4,51 +4,51 @@ ... For warning description see https://verilator.org/warn/CONSTRAINTIGN?v=latest ... Use "/* verilator lint_off CONSTRAINTIGN */" and lint_on around source to disable this message. %Warning-CONSTRAINTIGN: t/t_constraint_mode.v:14:11: rand_mode ignored (unsupported) - : ... In instance t + : ... note: In instance 't' 14 | one.rand_mode(0); | ^~~~~~~~~ %Warning-CONSTRAINTIGN: t/t_constraint_mode.v:15:11: rand_mode ignored (unsupported) - : ... In instance t + : ... note: In instance 't' 15 | one.rand_mode(1); | ^~~~~~~~~ %Warning-CONSTRAINTIGN: t/t_constraint_mode.v:16:15: rand_mode ignored (unsupported) - : ... In instance t + : ... note: In instance 't' 16 | if (one.rand_mode() != 1) $stop; | ^~~~~~~~~ %Warning-CONSTRAINTIGN: t/t_constraint_mode.v:19:9: constraint_mode ignored (unsupported) - : ... In instance t + : ... note: In instance 't' 19 | a.constraint_mode(1); | ^~~~~~~~~~~~~~~ %Warning-CONSTRAINTIGN: t/t_constraint_mode.v:20:9: constraint_mode ignored (unsupported) - : ... In instance t + : ... note: In instance 't' 20 | a.constraint_mode(0); | ^~~~~~~~~~~~~~~ %Warning-CONSTRAINTIGN: t/t_constraint_mode.v:21:13: constraint_mode ignored (unsupported) - : ... In instance t + : ... note: In instance 't' 21 | if (a.constraint_mode() != 0) $stop; | ^~~~~~~~~~~~~~~ %Warning-CONSTRAINTIGN: t/t_constraint_mode.v:41:13: rand_mode ignored (unsupported) - : ... In instance t + : ... note: In instance 't' 41 | p.one.rand_mode(0); | ^~~~~~~~~ %Warning-CONSTRAINTIGN: t/t_constraint_mode.v:42:13: rand_mode ignored (unsupported) - : ... In instance t + : ... note: In instance 't' 42 | p.one.rand_mode(1); | ^~~~~~~~~ %Warning-CONSTRAINTIGN: t/t_constraint_mode.v:43:17: rand_mode ignored (unsupported) - : ... In instance t + : ... note: In instance 't' 43 | if (p.one.rand_mode() != 1) $stop; | ^~~~~~~~~ %Warning-CONSTRAINTIGN: t/t_constraint_mode.v:46:11: constraint_mode ignored (unsupported) - : ... In instance t + : ... note: In instance 't' 46 | p.a.constraint_mode(1); | ^~~~~~~~~~~~~~~ %Warning-CONSTRAINTIGN: t/t_constraint_mode.v:47:11: constraint_mode ignored (unsupported) - : ... In instance t + : ... note: In instance 't' 47 | p.a.constraint_mode(0); | ^~~~~~~~~~~~~~~ %Warning-CONSTRAINTIGN: t/t_constraint_mode.v:48:15: constraint_mode ignored (unsupported) - : ... In instance t + : ... note: In instance 't' 48 | if (p.a.constraint_mode() != 0) $stop; | ^~~~~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_cover_unused_bad.out b/test_regress/t/t_cover_unused_bad.out index 023d50917..32656657e 100644 --- a/test_regress/t/t_cover_unused_bad.out +++ b/test_regress/t/t_cover_unused_bad.out @@ -1,5 +1,5 @@ %Warning-UNUSEDSIGNAL: t/t_cover_unused_bad.v:14:10: Signal is not used: 'unu3' - : ... In instance t + : ... note: In instance 't' 14 | logic unu3 = 0; | ^~~~ ... For warning description see https://verilator.org/warn/UNUSEDSIGNAL?v=latest diff --git a/test_regress/t/t_delay_stmtdly_bad.out b/test_regress/t/t_delay_stmtdly_bad.out index ed8235f57..40b0b31a3 100644 --- a/test_regress/t/t_delay_stmtdly_bad.out +++ b/test_regress/t/t_delay_stmtdly_bad.out @@ -1,35 +1,35 @@ %Warning-ASSIGNDLY: t/t_delay.v:25:11: Ignoring timing control on this assignment/primitive due to --no-timing - : ... In instance t + : ... note: In instance 't' 25 | assign #(1.2000000000000000) dly1 = dly0 + 32'h1; | ^ ... For warning description see https://verilator.org/warn/ASSIGNDLY?v=latest ... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message. %Warning-ASSIGNDLY: t/t_delay.v:26:11: Ignoring timing control on this assignment/primitive due to --no-timing - : ... In instance t + : ... note: In instance 't' 26 | assign #(sub.delay) dly3 = dly1 + 1; | ^ %Warning-ASSIGNDLY: t/t_delay.v:33:18: Ignoring timing control on this assignment/primitive due to --no-timing - : ... In instance t + : ... note: In instance 't' 33 | dly0 <= #0 32'h11; | ^ %Warning-ASSIGNDLY: t/t_delay.v:36:18: Ignoring timing control on this assignment/primitive due to --no-timing - : ... In instance t + : ... note: In instance 't' 36 | dly0 <= #0.12 dly0 + 32'h12; | ^ %Warning-ASSIGNDLY: t/t_delay.v:44:18: Ignoring timing control on this assignment/primitive due to --no-timing - : ... In instance t + : ... note: In instance 't' 44 | dly0 <= #(dly_s.dly) 32'h55; | ^ %Warning-STMTDLY: t/t_delay.v:50:10: Ignoring delay on this statement due to --no-timing - : ... In instance t + : ... note: In instance 't' 50 | #100 $finish; | ^ %Warning-UNUSEDSIGNAL: t/t_delay.v:23:12: Signal is not used: 'dly_s' - : ... In instance t + : ... note: In instance 't' 23 | dly_s_t dly_s; | ^~~~~ %Warning-UNUSEDSIGNAL: t/t_delay.v:57:13: Signal is not used: 'delay' - : ... In instance t.sub + : ... note: In instance 't.sub' 57 | realtime delay = 2.3; | ^~~~~ %Warning-BLKSEQ: t/t_delay.v:43:20: Blocking assignment '=' in sequential logic process diff --git a/test_regress/t/t_dfg_multidriver_dfg_bad.out b/test_regress/t/t_dfg_multidriver_dfg_bad.out index ce36240b8..62fea591c 100644 --- a/test_regress/t/t_dfg_multidriver_dfg_bad.out +++ b/test_regress/t/t_dfg_multidriver_dfg_bad.out @@ -1,5 +1,5 @@ %Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:13:18: Bits [3:1] of signal 'a' have multiple combinational drivers - : ... In instance t + : ... note: In instance 't' t/t_dfg_multidriver_dfg_bad.v:14:19: ... Location of first driver 14 | assign a[3:0] = i[3:0]; | ^ @@ -10,7 +10,7 @@ ... For warning description see https://verilator.org/warn/MULTIDRIVEN?v=latest ... Use "/* verilator lint_off MULTIDRIVEN */" and lint_on around source to disable this message. %Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:13:18: Bits [3:3] of signal 'a' have multiple combinational drivers - : ... In instance t + : ... note: In instance 't' t/t_dfg_multidriver_dfg_bad.v:14:19: ... Location of first driver 14 | assign a[3:0] = i[3:0]; | ^ @@ -19,7 +19,7 @@ | ^ t/t_dfg_multidriver_dfg_bad.v:13:18: ... Only the first driver will be respected %Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:13:18: Bits [7:6] of signal 'a' have multiple combinational drivers - : ... In instance t + : ... note: In instance 't' t/t_dfg_multidriver_dfg_bad.v:17:19: ... Location of first driver 17 | assign a[8:5] = i[8:5]; | ^ @@ -28,7 +28,7 @@ | ^ t/t_dfg_multidriver_dfg_bad.v:13:18: ... Only the first driver will be respected %Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:13:18: Bits [9:9] of signal 'a' have multiple combinational drivers - : ... In instance t + : ... note: In instance 't' t/t_dfg_multidriver_dfg_bad.v:19:17: ... Location of first driver 19 | assign a[9] = i[9]; | ^ diff --git a/test_regress/t/t_dpi_2exparg_bad.out b/test_regress/t/t_dpi_2exparg_bad.out index 47496c569..cb7fe065d 100644 --- a/test_regress/t/t_dpi_2exparg_bad.out +++ b/test_regress/t/t_dpi_2exparg_bad.out @@ -1,11 +1,11 @@ %Warning-WIDTHEXPAND: t/t_dpi_2exparg_bad.v:19:56: Operator NOT expects 64 bits on the LHS, but LHS's VARREF 'i' generates 32 bits. - : ... In instance t.b + : ... note: In instance 't.b' 19 | task dpix_twice(input int i, output [63:0] o); o = ~i; endtask | ^ ... For warning description see https://verilator.org/warn/WIDTHEXPAND?v=latest ... Use "/* verilator lint_off WIDTHEXPAND */" and lint_on around source to disable this message. %Warning-WIDTHTRUNC: t/t_dpi_2exparg_bad.v:12:53: Operator ASSIGN expects 3 bits on the Assign RHS, but Assign RHS's NOT generates 32 bits. - : ... In instance t.a + : ... note: In instance 't.a' 12 | task dpix_twice(input int i, output [2:0] o); o = ~i; endtask | ^ %Error: t/t_dpi_2exparg_bad.v:19:9: Duplicate declaration of DPI function with different signature: 'dpix_twice' diff --git a/test_regress/t/t_dpi_unpack_bad.out b/test_regress/t/t_dpi_unpack_bad.out index aaaeef547..3e03f665e 100644 --- a/test_regress/t/t_dpi_unpack_bad.out +++ b/test_regress/t/t_dpi_unpack_bad.out @@ -1,31 +1,31 @@ %Error-UNSUPPORTED: t/t_dpi_unpack_bad.v:21:20: Shape of the argument does not match the shape of the parameter ('logic[2:0]' v.s. 'logic[3:0]') - : ... In instance t + : ... note: In instance 't' 21 | import_func0(sig0); | ^~~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Warning-WIDTHEXPAND: t/t_dpi_unpack_bad.v:21:7: Operator TASKREF 'import_func0' expects 4 bits on the Function Argument, but Function Argument's VARREF 'sig0' generates 3 bits. - : ... In instance t + : ... note: In instance 't' 21 | import_func0(sig0); | ^~~~~~~~~~~~ ... Use "/* verilator lint_off WIDTHEXPAND */" and lint_on around source to disable this message. %Error-UNSUPPORTED: t/t_dpi_unpack_bad.v:23:20: Shape of the argument does not match the shape of the parameter ('logic[2:0]$[0:2][0:1]' v.s. 'logic[2:0]$[0:2]') - : ... In instance t + : ... note: In instance 't' 23 | import_func1(sig1); | ^~~~ %Error-UNSUPPORTED: t/t_dpi_unpack_bad.v:25:20: Shape of the argument does not match the shape of the parameter ('logic[2:0]$[0:2][0:1]' v.s. 'logic[2:0]$[0:2][0:2]') - : ... In instance t + : ... note: In instance 't' 25 | import_func2(sig1); | ^~~~ %Error-UNSUPPORTED: t/t_dpi_unpack_bad.v:27:20: Shape of the argument does not match the shape of the parameter ('bit[2:0]' v.s. 'logic[2:0]') - : ... In instance t + : ... note: In instance 't' 27 | import_func2(sig2); | ^~~~ %Error-UNSUPPORTED: t/t_dpi_unpack_bad.v:29:24: Argument is not an unpacked array while parameter 'in' is - : ... In instance t + : ... note: In instance 't' 29 | import_func0(sig0[1]); | ^ %Warning-WIDTHEXPAND: t/t_dpi_unpack_bad.v:29:7: Operator TASKREF 'import_func0' expects 4 bits on the Function Argument, but Function Argument's ARRAYSEL generates 3 bits. - : ... In instance t + : ... note: In instance 't' 29 | import_func0(sig0[1]); | ^~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_dynarray_bad.out b/test_regress/t/t_dynarray_bad.out index a579f8fc8..fe1e71b45 100644 --- a/test_regress/t/t_dynarray_bad.out +++ b/test_regress/t/t_dynarray_bad.out @@ -1,5 +1,5 @@ %Warning-WIDTHTRUNC: t/t_dynarray_bad.v:15:11: Operator NEWDYNAMIC expects 32 bits on the new() size, but new() size's VARREF 's' generates 64 bits. - : ... In instance t + : ... note: In instance 't' 15 | a = new [s]; | ^~~ ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest diff --git a/test_regress/t/t_enum_bad_circdecl.out b/test_regress/t/t_enum_bad_circdecl.out index 3c30cd2c2..abeff1184 100644 --- a/test_regress/t/t_enum_bad_circdecl.out +++ b/test_regress/t/t_enum_bad_circdecl.out @@ -1,5 +1,5 @@ %Error: t/t_enum_bad_circdecl.v:11:6: Typedef has self-reference: 'bad_redecl' - : ... In instance t + : ... note: In instance 't' 11 | } bad_redecl; | ^~~~~~~~~~ t/t_enum_bad_circdecl.v:9:17: ... Location of reference diff --git a/test_regress/t/t_enum_bad_value.out b/test_regress/t/t_enum_bad_value.out index 052f16ac8..03af7f4b0 100644 --- a/test_regress/t/t_enum_bad_value.out +++ b/test_regress/t/t_enum_bad_value.out @@ -1,5 +1,5 @@ %Error: t/t_enum_bad_value.v:10:19: Enum value exceeds width of enum type (IEEE 1800-2017 6.19) - : ... In instance t + : ... note: In instance 't' 10 | VALUE_BAD = 8 | ^ %Error: Exiting due to diff --git a/test_regress/t/t_enum_bad_wrap.out b/test_regress/t/t_enum_bad_wrap.out index 72c9403fc..2dab9a311 100644 --- a/test_regress/t/t_enum_bad_wrap.out +++ b/test_regress/t/t_enum_bad_wrap.out @@ -1,5 +1,5 @@ %Error: t/t_enum_bad_wrap.v:11:19: Enum value illegally wrapped around (IEEE 1800-2017 6.19) - : ... In instance t + : ... note: In instance 't' 11 | WRAPPED | ^~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_enum_huge_methods_bad.out b/test_regress/t/t_enum_huge_methods_bad.out index b5d5e6853..6671d5dc9 100644 --- a/test_regress/t/t_enum_huge_methods_bad.out +++ b/test_regress/t/t_enum_huge_methods_bad.out @@ -2,7 +2,7 @@ 15 | ELARGE = 160'h1234_4567_abcd_1234_4567_abcd | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ %Error-UNSUPPORTED: t/t_enum_huge_methods_bad.v:30:21: Unsupported: enum next/prev/name method on enum with > 64 bits - : ... In instance t + : ... note: In instance 't' 30 | $display(e.name); | ^~~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest diff --git a/test_regress/t/t_enum_overlap_bad.out b/test_regress/t/t_enum_overlap_bad.out index 6e745c509..16f3d51a3 100644 --- a/test_regress/t/t_enum_overlap_bad.out +++ b/test_regress/t/t_enum_overlap_bad.out @@ -1,5 +1,5 @@ %Error: t/t_enum_overlap_bad.v:12:11: Overlapping enumeration value: 'e1b' - : ... In instance t + : ... note: In instance 't' 12 | e1b=1 | ^~~ t/t_enum_overlap_bad.v:10:11: ... Location of original declaration diff --git a/test_regress/t/t_enum_type_bad.out b/test_regress/t/t_enum_type_bad.out index 59d5cb988..a6f749c3b 100644 --- a/test_regress/t/t_enum_type_bad.out +++ b/test_regress/t/t_enum_type_bad.out @@ -1,16 +1,16 @@ %Error-ENUMVALUE: t/t_enum_type_bad.v:28:11: Implicit conversion to enum 't.e_t' from 'logic[31:0]' (IEEE 1800-2017 6.19.3) - : ... In instance t + : ... note: In instance 't' : ... Suggest use enum's mnemonic, or static cast 28 | e = 1; | ^ ... For error description see https://verilator.org/warn/ENUMVALUE?v=latest %Error-ENUMVALUE: t/t_enum_type_bad.v:29:11: Implicit conversion to enum 't.o_t' from 't.e_t' (IEEE 1800-2017 6.19.3) - : ... In instance t + : ... note: In instance 't' : ... Suggest use enum's mnemonic, or static cast 29 | o = e; | ^ %Error-ENUMVALUE: t/t_enum_type_bad.v:35:15: Implicit conversion to enum 't.o_t' from 'ENUMDTYPE 't.e_t'' (IEEE 1800-2017 6.19.3) - : ... In instance t + : ... note: In instance 't' : ... Suggest use enum's mnemonic, or static cast 35 | o = str.m_e; | ^~~ diff --git a/test_regress/t/t_enum_type_methods_bad.out b/test_regress/t/t_enum_type_methods_bad.out index 41c5834a1..233d51a6b 100644 --- a/test_regress/t/t_enum_type_methods_bad.out +++ b/test_regress/t/t_enum_type_methods_bad.out @@ -1,5 +1,5 @@ %Error: Internal Error: t/t_enum_type_methods_bad.v:24:14: ../V3Width.cpp:#: Unsupported: enum next/prev with non-const argument - : ... In instance t + : ... note: In instance 't' 24 | e.next(increment); | ^~~~~~~~~ ... See the manual at https://verilator.org/verilator_doc.html for more assistance. diff --git a/test_regress/t/t_enum_type_nomethod_bad.out b/test_regress/t/t_enum_type_nomethod_bad.out index bc6d41978..f2085bb77 100644 --- a/test_regress/t/t_enum_type_nomethod_bad.out +++ b/test_regress/t/t_enum_type_nomethod_bad.out @@ -1,5 +1,5 @@ %Error: t/t_enum_type_nomethod_bad.v:15:9: Unknown built-in enum method 'bad_no_such_method' - : ... In instance t + : ... note: In instance 't' 15 | e.bad_no_such_method(); | ^~~~~~~~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_enum_x_bad.out b/test_regress/t/t_enum_x_bad.out index 360ee2f57..c9441d947 100644 --- a/test_regress/t/t_enum_x_bad.out +++ b/test_regress/t/t_enum_x_bad.out @@ -1,9 +1,9 @@ %Error: t/t_enum_x_bad.v:9:21: Enum value with X/Zs cannot be assigned to non-fourstate type (IEEE 1800-2017 6.19) - : ... In instance t + : ... note: In instance 't' 9 | enum bit [1:0] { BADX = 2'b1x } BAD1; | ^~~~ %Error: t/t_enum_x_bad.v:12:23: Enum value that is unassigned cannot follow value with X/Zs (IEEE 1800-2017 6.19) - : ... In instance t + : ... note: In instance 't' 12 | e1 | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_event_control.out b/test_regress/t/t_event_control.out index f04260a95..2debb40b8 100644 --- a/test_regress/t/t_event_control.out +++ b/test_regress/t/t_event_control.out @@ -1,11 +1,11 @@ %Error-NOTIMING: t/t_event_control.v:14:7: Event control statement in this location requires --timing - : ... In instance t + : ... note: In instance 't' : ... With --no-timing, suggest have one event control statement per procedure, at the top of the procedure 14 | @(clk); | ^ ... For error description see https://verilator.org/warn/NOTIMING?v=latest %Error-NOTIMING: t/t_event_control.v:16:7: Event control statement in this location requires --timing - : ... In instance t + : ... note: In instance 't' : ... With --no-timing, suggest have one event control statement per procedure, at the top of the procedure 16 | @(clk); | ^ diff --git a/test_regress/t/t_event_control_expr_unsup.out b/test_regress/t/t_event_control_expr_unsup.out index 8f8e2cb64..8b6cc69ae 100644 --- a/test_regress/t/t_event_control_expr_unsup.out +++ b/test_regress/t/t_event_control_expr_unsup.out @@ -3,7 +3,7 @@ | ^~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error-UNSUPPORTED: t/t_event_control_expr.v:82:17: Unsupported: function calls in sensitivity lists - : ... In instance t.u_method + : ... note: In instance 't.u_method' 82 | always @(obj.get_k()) begin | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_event_copy.out b/test_regress/t/t_event_copy.out index 9965cd23e..6be6494fe 100644 --- a/test_regress/t/t_event_copy.out +++ b/test_regress/t/t_event_copy.out @@ -1,10 +1,10 @@ %Error-UNSUPPORTED: t/t_event_copy.v:100:13: Unsupported: assignment of event data type - : ... In instance t + : ... note: In instance 't' 100 | e4 = e3; | ^ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error-UNSUPPORTED: t/t_event_copy.v:101:13: Unsupported: assignment of event data type - : ... In instance t + : ... note: In instance 't' 101 | e3 = e2; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_flag_context_bad.out b/test_regress/t/t_flag_context_bad.out index 5cd7f81be..cbab432e9 100644 --- a/test_regress/t/t_flag_context_bad.out +++ b/test_regress/t/t_flag_context_bad.out @@ -1,7 +1,7 @@ %Warning-WIDTHTRUNC: t/t_flag_context_bad.v:9:19: Operator ASSIGNW expects 3 bits on the Assign RHS, but Assign RHS's CONST '5'h1f' generates 5 bits. - : ... In instance t + : ... note: In instance 't' ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. %Warning-UNUSEDSIGNAL: t/t_flag_context_bad.v:9:15: Signal is not used: 'foo' - : ... In instance t + : ... note: In instance 't' %Error: Exiting due to diff --git a/test_regress/t/t_flag_structs_packed_bad.out b/test_regress/t/t_flag_structs_packed_bad.out index 43068e836..d8a2f8fa3 100644 --- a/test_regress/t/t_flag_structs_packed_bad.out +++ b/test_regress/t/t_flag_structs_packed_bad.out @@ -1,5 +1,5 @@ %Error: t/t_flag_structs_packed.v:14:19: Unpacked data type 'STRUCTDTYPE 'x.notpacked_t'' in packed struct/union (IEEE 1800-2017 7.2.1) - : ... In instance x + : ... note: In instance 'x' 14 | notpacked_t b; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_flag_werror_bad1.out b/test_regress/t/t_flag_werror_bad1.out index 5e0131123..904df576d 100644 --- a/test_regress/t/t_flag_werror_bad1.out +++ b/test_regress/t/t_flag_werror_bad1.out @@ -1,5 +1,5 @@ %Warning-WIDTHTRUNC: t/t_flag_werror.v:10:19: Operator ASSIGNW expects 4 bits on the Assign RHS, but Assign RHS's CONST '6'h2e' generates 6 bits. - : ... In instance t + : ... note: In instance 't' 10 | wire [3:0] foo = 6'h2e; | ^ ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest diff --git a/test_regress/t/t_flag_werror_bad2.out b/test_regress/t/t_flag_werror_bad2.out index 2f1001fbd..55ffa6d25 100644 --- a/test_regress/t/t_flag_werror_bad2.out +++ b/test_regress/t/t_flag_werror_bad2.out @@ -1,5 +1,5 @@ %Error-WIDTHTRUNC: t/t_flag_werror.v:10:19: Operator ASSIGNW expects 4 bits on the Assign RHS, but Assign RHS's CONST '6'h2e' generates 6 bits. - : ... In instance t + : ... note: In instance 't' 10 | wire [3:0] foo = 6'h2e; | ^ ... For error description see https://verilator.org/warn/WIDTHTRUNC?v=latest diff --git a/test_regress/t/t_flag_wfatal.out b/test_regress/t/t_flag_wfatal.out index 8489b1824..16a2669fd 100644 --- a/test_regress/t/t_flag_wfatal.out +++ b/test_regress/t/t_flag_wfatal.out @@ -1,5 +1,5 @@ %Warning-WIDTHTRUNC: t/t_flag_wfatal.v:10:19: Operator ASSIGNW expects 4 bits on the Assign RHS, but Assign RHS's CONST '6'h2e' generates 6 bits. - : ... In instance t + : ... note: In instance 't' 10 | wire [3:0] foo = 6'h2e; | ^ ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest diff --git a/test_regress/t/t_force_tri.out b/test_regress/t/t_force_tri.out index 97b0dd018..9a80c51c3 100644 --- a/test_regress/t/t_force_tri.out +++ b/test_regress/t/t_force_tri.out @@ -1,5 +1,5 @@ %Error-UNSUPPORTED: t/t_force_tri.v:27:10: Unsupported tristate construct: ASSIGNFORCE - : ... In instance t + : ... note: In instance 't' 27 | force bus = 4'bzz10; | ^~~~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest diff --git a/test_regress/t/t_fork.out b/test_regress/t/t_fork.out index 6070aeb85..5f067c56a 100644 --- a/test_regress/t/t_fork.out +++ b/test_regress/t/t_fork.out @@ -1,5 +1,5 @@ %Error-NOTIMING: t/t_fork.v:10:14: Fork statements require --timing - : ... In instance t + : ... note: In instance 't' 10 | fork : fblk | ^~~~ ... For error description see https://verilator.org/warn/NOTIMING?v=latest diff --git a/test_regress/t/t_fork_disable.out b/test_regress/t/t_fork_disable.out index 62ba6a34f..4a245ec4d 100644 --- a/test_regress/t/t_fork_disable.out +++ b/test_regress/t/t_fork_disable.out @@ -1,10 +1,10 @@ %Error-UNSUPPORTED: t/t_fork_disable.v:16:7: Unsupported: disable fork statements - : ... In instance t + : ... note: In instance 't' 16 | disable fork; | ^~~~~~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error-UNSUPPORTED: t/t_fork_disable.v:17:7: Unsupported: wait fork statements - : ... In instance t + : ... note: In instance 't' 17 | wait fork; | ^~~~ %Error: Exiting due to diff --git a/test_regress/t/t_fork_func2_bad.out b/test_regress/t/t_fork_func2_bad.out index 16cdd6242..e9a3650d3 100644 --- a/test_regress/t/t_fork_func2_bad.out +++ b/test_regress/t/t_fork_func2_bad.out @@ -1,5 +1,5 @@ %Error: t/t_fork_func2_bad.v:10:7: Only fork .. join_none is legal in functions. (IEEE 1800-2017 13.4.4) - : ... In instance t + : ... note: In instance 't' 10 | fork | ^~~~ %Error: Exiting due to diff --git a/test_regress/t/t_func_bad.out b/test_regress/t/t_func_bad.out index d5d2b8dc2..0b52f146a 100644 --- a/test_regress/t/t_func_bad.out +++ b/test_regress/t/t_func_bad.out @@ -1,31 +1,31 @@ %Error: t/t_func_bad.v:9:11: Missing argument on non-defaulted argument 'from2' in function call to FUNC 'add' - : ... In instance t + : ... note: In instance 't' 9 | if (add(3'd1) != 0) $stop; | ^~~ %Error: t/t_func_bad.v:10:27: Too many arguments in function call to FUNC 'add' - : ... In instance t + : ... note: In instance 't' 10 | if (add(3'd1, 3'd2, 3'd3) != 0) $stop; | ^~~~ %Error: t/t_func_bad.v:11:7: Missing argument on non-defaulted argument 'y' in function call to TASK 'x' - : ... In instance t + : ... note: In instance 't' 11 | x; | ^ %Warning-WIDTHTRUNC: t/t_func_bad.v:11:7: Function output argument 'y' requires 1 bits, but connection's CONST '?32?h0' generates 32 bits. - : ... In instance t + : ... note: In instance 't' 11 | x; | ^ ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. %Error: t/t_func_bad.v:14:17: No such argument 'no_such' in function call to FUNC 'f' - : ... In instance t + : ... note: In instance 't' 14 | f(.j(1), .no_such(2)); | ^~~~~~~ %Error: t/t_func_bad.v:15:19: Duplicate argument 'dup' in function call to FUNC 'f' - : ... In instance t + : ... note: In instance 't' 15 | f(.dup(1), .dup(3)); | ^~~ %Error: t/t_func_bad.v:16:13: Too many arguments in function call to FUNC 'f' - : ... In instance t + : ... note: In instance 't' 16 | f(1,2,3); | ^ %Error: Exiting due to diff --git a/test_regress/t/t_func_bad_width.out b/test_regress/t/t_func_bad_width.out index af48783fa..c274b565a 100644 --- a/test_regress/t/t_func_bad_width.out +++ b/test_regress/t/t_func_bad_width.out @@ -1,11 +1,11 @@ %Warning-WIDTHEXPAND: t/t_func_bad_width.v:13:13: Operator FUNCREF 'MUX' expects 40 bits on the Function Argument, but Function Argument's VARREF 'in' generates 39 bits. - : ... In instance t + : ... note: In instance 't' 13 | out = MUX (in); | ^~~ ... For warning description see https://verilator.org/warn/WIDTHEXPAND?v=latest ... Use "/* verilator lint_off WIDTHEXPAND */" and lint_on around source to disable this message. %Warning-WIDTHTRUNC: t/t_func_bad_width.v:13:11: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's FUNCREF 'MUX' generates 32 bits. - : ... In instance t + : ... note: In instance 't' 13 | out = MUX (in); | ^ %Error: Exiting due to diff --git a/test_regress/t/t_func_const2_bad.out b/test_regress/t/t_func_const2_bad.out index 05647a61d..2a12b83a7 100644 --- a/test_regress/t/t_func_const2_bad.out +++ b/test_regress/t/t_func_const2_bad.out @@ -2,12 +2,12 @@ ... For warning description see https://verilator.org/warn/USERFATAL?v=latest ... Use "/* verilator lint_off USERFATAL */" and lint_on around source to disable this message. %Error: t/t_func_const2_bad.v:22:23: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_add2' - : ... In instance t.b8_a7.c9 + : ... note: In instance 't.b8_a7.c9' t/t_func_const2_bad.v:10:6: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing - t/t_func_const2_bad.v:15:13: ... Called from f_add() with parameters: + t/t_func_const2_bad.v:15:13: ... Called from 'f_add()' with parameters: a = 32'h7 b = 32'h8 - t/t_func_const2_bad.v:22:23: ... Called from f_add2() with parameters: + t/t_func_const2_bad.v:22:23: ... Called from 'f_add2()' with parameters: a = ?32?h7 b = ?32?h8 c = ?32?h9 diff --git a/test_regress/t/t_func_const3_bad.out b/test_regress/t/t_func_const3_bad.out index 5390514c9..6172af3b0 100644 --- a/test_regress/t/t_func_const3_bad.out +++ b/test_regress/t/t_func_const3_bad.out @@ -1,5 +1,5 @@ %Warning-WIDTHCONCAT: t/t_func_const3_bad.v:12:28: More than a 8k bit replication is probably wrong: 9000 - : ... In instance t.b9k.c9 + : ... note: In instance 't.b9k.c9' 12 | localparam SOMEP = {BITS{1'b0}}; | ^ ... For warning description see https://verilator.org/warn/WIDTHCONCAT?v=latest diff --git a/test_regress/t/t_func_const_bad.out b/test_regress/t/t_func_const_bad.out index 22ecf6b39..f8802f4db 100644 --- a/test_regress/t/t_func_const_bad.out +++ b/test_regress/t/t_func_const_bad.out @@ -1,33 +1,33 @@ %Error: t/t_func_const_bad.v:12:20: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_output' - : ... In instance t + : ... note: In instance 't' t/t_func_const_bad.v:13:64: ... Location of non-constant VAR 'o': Language violation: Outputs/refs not allowed in constant functions 12 | localparam B1 = f_bad_output(1,2); | ^~~~~~~~~~~~ %Error: t/t_func_const_bad.v:21:20: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_dotted' - : ... In instance t + : ... note: In instance 't' t/t_func_const_bad.v:23:24: ... Location of non-constant VARXREF 'EIGHT': Language violation: Dotted hierarchical references not allowed in constant functions - t/t_func_const_bad.v:21:20: ... Called from f_bad_dotted() with parameters: + t/t_func_const_bad.v:21:20: ... Called from 'f_bad_dotted()' with parameters: a = ?32?h2 21 | localparam B2 = f_bad_dotted(2); | ^~~~~~~~~~~~ %Error: t/t_func_const_bad.v:28:20: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_nonparam' - : ... In instance t + : ... note: In instance 't' t/t_func_const_bad.v:30:24: ... Location of non-constant VARREF 'modvar': Language violation: reference to non-function-local variable - t/t_func_const_bad.v:28:20: ... Called from f_bad_nonparam() with parameters: + t/t_func_const_bad.v:28:20: ... Called from 'f_bad_nonparam()' with parameters: a = ?32?h3 28 | localparam B3 = f_bad_nonparam(3); | ^~~~~~~~~~~~~~ %Error: t/t_func_const_bad.v:36:20: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_infinite' - : ... In instance t + : ... note: In instance 't' t/t_func_const_bad.v:38:7: ... Location of non-constant WHILE: Loop unrolling took too long; probably this is an infinite loop, or set --unroll-count above 1024 - t/t_func_const_bad.v:36:20: ... Called from f_bad_infinite() with parameters: + t/t_func_const_bad.v:36:20: ... Called from 'f_bad_infinite()' with parameters: a = ?32?h3 36 | localparam B4 = f_bad_infinite(3); | ^~~~~~~~~~~~~~ %Error: t/t_func_const_bad.v:44:23: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_stop' - : ... In instance t + : ... note: In instance 't' t/t_func_const_bad.v:46:7: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing - t/t_func_const_bad.v:44:23: ... Called from f_bad_stop() with parameters: + t/t_func_const_bad.v:44:23: ... Called from 'f_bad_stop()' with parameters: a = ?32?h3 44 | localparam BSTOP = f_bad_stop(3); | ^~~~~~~~~~ @@ -38,9 +38,9 @@ ... For warning description see https://verilator.org/warn/USERFATAL?v=latest ... Use "/* verilator lint_off USERFATAL */" and lint_on around source to disable this message. %Error: t/t_func_const_bad.v:50:24: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_fatal' - : ... In instance t + : ... note: In instance 't' t/t_func_const_bad.v:55:7: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing - t/t_func_const_bad.v:50:24: ... Called from f_bad_fatal() with parameters: + t/t_func_const_bad.v:50:24: ... Called from 'f_bad_fatal()' with parameters: a = ?32?h3 50 | localparam BFATAL = f_bad_fatal(3); | ^~~~~~~~~~~ diff --git a/test_regress/t/t_func_const_packed_array_bad.out b/test_regress/t/t_func_const_packed_array_bad.out index 19284f0eb..6b55415c0 100644 --- a/test_regress/t/t_func_const_packed_array_bad.out +++ b/test_regress/t/t_func_const_packed_array_bad.out @@ -2,11 +2,11 @@ ... For warning description see https://verilator.org/warn/USERFATAL?v=latest ... Use "/* verilator lint_off USERFATAL */" and lint_on around source to disable this message. %Error: t/t_func_const_packed_array_bad.v:12:21: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_add2' - : ... In instance t + : ... note: In instance 't' t/t_func_const_packed_array_bad.v:23:9: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing - t/t_func_const_packed_array_bad.v:31:16: ... Called from f_add() with parameters: + t/t_func_const_packed_array_bad.v:31:16: ... Called from 'f_add()' with parameters: params = [0 = 32'h7, 1 = 32'h8] - t/t_func_const_packed_array_bad.v:12:21: ... Called from f_add2() with parameters: + t/t_func_const_packed_array_bad.v:12:21: ... Called from 'f_add2()' with parameters: a = ?32?h7 b = ?32?h8 c = ?32?h9 diff --git a/test_regress/t/t_func_const_packed_struct_bad.out b/test_regress/t/t_func_const_packed_struct_bad.out index 6cc4a4d8e..3dd459670 100644 --- a/test_regress/t/t_func_const_packed_struct_bad.out +++ b/test_regress/t/t_func_const_packed_struct_bad.out @@ -2,11 +2,11 @@ ... For warning description see https://verilator.org/warn/USERFATAL?v=latest ... Use "/* verilator lint_off USERFATAL */" and lint_on around source to disable this message. %Error: t/t_func_const_packed_struct_bad.v:14:21: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_add2' - : ... In instance t + : ... note: In instance 't' t/t_func_const_packed_struct_bad.v:25:9: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing - t/t_func_const_packed_struct_bad.v:33:16: ... Called from f_add() with parameters: + t/t_func_const_packed_struct_bad.v:33:16: ... Called from 'f_add()' with parameters: params = [0 = '{a: 32'h7, b: 32'h22b}, 1 = '{a: 32'h3039, b: 32'h8}] - t/t_func_const_packed_struct_bad.v:14:21: ... Called from f_add2() with parameters: + t/t_func_const_packed_struct_bad.v:14:21: ... Called from 'f_add2()' with parameters: a = ?32?h7 b = ?32?h8 c = ?32?h9 diff --git a/test_regress/t/t_func_const_packed_struct_bad2.out b/test_regress/t/t_func_const_packed_struct_bad2.out index 5090203c3..23643b079 100644 --- a/test_regress/t/t_func_const_packed_struct_bad2.out +++ b/test_regress/t/t_func_const_packed_struct_bad2.out @@ -2,11 +2,11 @@ ... For warning description see https://verilator.org/warn/USERFATAL?v=latest ... Use "/* verilator lint_off USERFATAL */" and lint_on around source to disable this message. %Error: t/t_func_const_packed_struct_bad2.v:20:21: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_add2' - : ... In instance t + : ... note: In instance 't' t/t_func_const_packed_struct_bad2.v:31:9: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing - t/t_func_const_packed_struct_bad2.v:43:16: ... Called from f_add() with parameters: + t/t_func_const_packed_struct_bad2.v:43:16: ... Called from 'f_add()' with parameters: params = [0 = '{a: 32'h7, foo: 6'hb, sub_params: '{b: 32'h37, bar: 8'h6f}}, 1 = '{a: 32'h3039, foo: 6'hc, sub_params: '{b: 32'h8, bar: 8'h70}}] - t/t_func_const_packed_struct_bad2.v:20:21: ... Called from f_add2() with parameters: + t/t_func_const_packed_struct_bad2.v:20:21: ... Called from 'f_add2()' with parameters: a = ?32?h7 b = ?32?h8 c = ?32?h9 diff --git a/test_regress/t/t_func_const_struct_bad.out b/test_regress/t/t_func_const_struct_bad.out index a8fd8baf8..4b0bb70ae 100644 --- a/test_regress/t/t_func_const_struct_bad.out +++ b/test_regress/t/t_func_const_struct_bad.out @@ -2,11 +2,11 @@ ... For warning description see https://verilator.org/warn/USERFATAL?v=latest ... Use "/* verilator lint_off USERFATAL */" and lint_on around source to disable this message. %Error: t/t_func_const_struct_bad.v:17:21: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_add2' - : ... In instance t + : ... note: In instance 't' t/t_func_const_struct_bad.v:28:9: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing - t/t_func_const_struct_bad.v:38:16: ... Called from f_add() with parameters: + t/t_func_const_struct_bad.v:38:16: ... Called from 'f_add()' with parameters: params = '{a: 32'h7, b: 32'h8} - t/t_func_const_struct_bad.v:17:21: ... Called from f_add2() with parameters: + t/t_func_const_struct_bad.v:17:21: ... Called from 'f_add2()' with parameters: a = ?32?h7 b = ?32?h8 c = ?32?h9 diff --git a/test_regress/t/t_func_recurse_param.out b/test_regress/t/t_func_recurse_param.out index ba95348dc..1d578c015 100644 --- a/test_regress/t/t_func_recurse_param.out +++ b/test_regress/t/t_func_recurse_param.out @@ -1,10 +1,10 @@ %Error: t/t_func_recurse_param.v:15:26: Expecting expression to be constant, but can't determine constant for FUNCREF 'recurse_self' - : ... In instance t + : ... note: In instance 't' t/t_func_recurse_param.v:9:27: ... Location of non-constant FUNC 'recurse_self': Unsupported: Recursive constant functions 15 | localparam int ZERO = recurse_self(0); | ^~~~~~~~~~~~ %Error: t/t_func_recurse_param.v:16:28: Expecting expression to be constant, but can't determine constant for FUNCREF 'recurse_self' - : ... In instance t + : ... note: In instance 't' t/t_func_recurse_param.v:9:27: ... Location of non-constant FUNC 'recurse_self': Unsupported: Recursive constant functions 16 | localparam int ELEVEN = recurse_self(3); | ^~~~~~~~~~~~ diff --git a/test_regress/t/t_func_recurse_param_bad.out b/test_regress/t/t_func_recurse_param_bad.out index 7ec686842..fd61bb496 100644 --- a/test_regress/t/t_func_recurse_param_bad.out +++ b/test_regress/t/t_func_recurse_param_bad.out @@ -1,5 +1,5 @@ %Error: t/t_func_recurse_param_bad.v:15:26: Expecting expression to be constant, but can't determine constant for FUNCREF 'recurse_self' - : ... In instance t + : ... note: In instance 't' t/t_func_recurse_param_bad.v:9:27: ... Location of non-constant FUNC 'recurse_self': Unsupported: Recursive constant functions 15 | localparam int HUGE = recurse_self(10000); | ^~~~~~~~~~~~ diff --git a/test_regress/t/t_func_refio_bad.out b/test_regress/t/t_func_refio_bad.out index b92a72d8d..279b12315 100644 --- a/test_regress/t/t_func_refio_bad.out +++ b/test_regress/t/t_func_refio_bad.out @@ -1,5 +1,5 @@ %Error: t/t_func_refio_bad.v:16:17: Ref argument requires matching types; port 'q' requires integer[$] but connection is logic[31:0]. - : ... In instance t + : ... note: In instance 't' 16 | queue_set(42); | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_func_wide_out_bad.out b/test_regress/t/t_func_wide_out_bad.out index b2648177a..3d66ef69f 100644 --- a/test_regress/t/t_func_wide_out_bad.out +++ b/test_regress/t/t_func_wide_out_bad.out @@ -1,83 +1,83 @@ %Warning-WIDTHTRUNC: t/t_func_wide_out.v:76:27: Function output argument 'value' requires 12 bits, but connection's VARREF 'ds70' generates 70 bits. - : ... In instance t + : ... note: In instance 't' 76 | Cls#(s12_t)::get(ds70); | ^~~~ ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. %Warning-WIDTHTRUNC: t/t_func_wide_out.v:76:23: Operator TASKREF 'get' expects 12 bits on the Function Argument, but Function Argument's VARREF 'ds70' generates 70 bits. - : ... In instance t + : ... note: In instance 't' 76 | Cls#(s12_t)::get(ds70); | ^~~ %Warning-WIDTHTRUNC: t/t_func_wide_out.v:79:27: Function output argument 'value' requires 12 bits, but connection's VARREF 'ds70' generates 70 bits. - : ... In instance t + : ... note: In instance 't' 79 | Cls#(s12_t)::get(ds70); | ^~~~ %Warning-WIDTHTRUNC: t/t_func_wide_out.v:79:23: Operator TASKREF 'get' expects 12 bits on the Function Argument, but Function Argument's VARREF 'ds70' generates 70 bits. - : ... In instance t + : ... note: In instance 't' 79 | Cls#(s12_t)::get(ds70); | ^~~ %Warning-WIDTHTRUNC: t/t_func_wide_out.v:83:27: Function output argument 'value' requires 12 bits, but connection's VARREF 'du70' generates 70 bits. - : ... In instance t + : ... note: In instance 't' 83 | Cls#(u12_t)::get(du70); | ^~~~ %Warning-WIDTHTRUNC: t/t_func_wide_out.v:83:23: Operator TASKREF 'get' expects 12 bits on the Function Argument, but Function Argument's VARREF 'du70' generates 70 bits. - : ... In instance t + : ... note: In instance 't' 83 | Cls#(u12_t)::get(du70); | ^~~ %Warning-WIDTHTRUNC: t/t_func_wide_out.v:86:27: Function output argument 'value' requires 12 bits, but connection's VARREF 'du70' generates 70 bits. - : ... In instance t + : ... note: In instance 't' 86 | Cls#(u12_t)::get(du70); | ^~~~ %Warning-WIDTHTRUNC: t/t_func_wide_out.v:86:23: Operator TASKREF 'get' expects 12 bits on the Function Argument, but Function Argument's VARREF 'du70' generates 70 bits. - : ... In instance t + : ... note: In instance 't' 86 | Cls#(u12_t)::get(du70); | ^~~ %Warning-WIDTHTRUNC: t/t_func_wide_out.v:108:10: Operator TASKREF 'dpii_inv_s12' expects 12 bits on the Function Argument, but Function Argument's VARREF 'ds70' generates 70 bits. - : ... In instance t + : ... note: In instance 't' 108 | dpii_inv_s12(ds70, qs70); | ^~~~~~~~~~~~ %Warning-WIDTHTRUNC: t/t_func_wide_out.v:108:29: Function output argument 'out' requires 12 bits, but connection's VARREF 'qs70' generates 70 bits. - : ... In instance t + : ... note: In instance 't' 108 | dpii_inv_s12(ds70, qs70); | ^~~~ %Warning-WIDTHTRUNC: t/t_func_wide_out.v:108:10: Operator TASKREF 'dpii_inv_s12' expects 12 bits on the Function Argument, but Function Argument's VARREF 'qs70' generates 70 bits. - : ... In instance t + : ... note: In instance 't' 108 | dpii_inv_s12(ds70, qs70); | ^~~~~~~~~~~~ %Warning-WIDTHTRUNC: t/t_func_wide_out.v:111:10: Operator TASKREF 'dpii_inv_s12' expects 12 bits on the Function Argument, but Function Argument's VARREF 'ds70' generates 70 bits. - : ... In instance t + : ... note: In instance 't' 111 | dpii_inv_s12(ds70, qs70); | ^~~~~~~~~~~~ %Warning-WIDTHTRUNC: t/t_func_wide_out.v:111:29: Function output argument 'out' requires 12 bits, but connection's VARREF 'qs70' generates 70 bits. - : ... In instance t + : ... note: In instance 't' 111 | dpii_inv_s12(ds70, qs70); | ^~~~ %Warning-WIDTHTRUNC: t/t_func_wide_out.v:111:10: Operator TASKREF 'dpii_inv_s12' expects 12 bits on the Function Argument, but Function Argument's VARREF 'qs70' generates 70 bits. - : ... In instance t + : ... note: In instance 't' 111 | dpii_inv_s12(ds70, qs70); | ^~~~~~~~~~~~ %Warning-WIDTHTRUNC: t/t_func_wide_out.v:115:10: Operator TASKREF 'dpii_inv_u12' expects 12 bits on the Function Argument, but Function Argument's VARREF 'du70' generates 70 bits. - : ... In instance t + : ... note: In instance 't' 115 | dpii_inv_u12(du70, qu70); | ^~~~~~~~~~~~ %Warning-WIDTHTRUNC: t/t_func_wide_out.v:115:29: Function output argument 'out' requires 12 bits, but connection's VARREF 'qu70' generates 70 bits. - : ... In instance t + : ... note: In instance 't' 115 | dpii_inv_u12(du70, qu70); | ^~~~ %Warning-WIDTHTRUNC: t/t_func_wide_out.v:115:10: Operator TASKREF 'dpii_inv_u12' expects 12 bits on the Function Argument, but Function Argument's VARREF 'qu70' generates 70 bits. - : ... In instance t + : ... note: In instance 't' 115 | dpii_inv_u12(du70, qu70); | ^~~~~~~~~~~~ %Warning-WIDTHTRUNC: t/t_func_wide_out.v:118:10: Operator TASKREF 'dpii_inv_u12' expects 12 bits on the Function Argument, but Function Argument's VARREF 'du70' generates 70 bits. - : ... In instance t + : ... note: In instance 't' 118 | dpii_inv_u12(du70, qu70); | ^~~~~~~~~~~~ %Warning-WIDTHTRUNC: t/t_func_wide_out.v:118:29: Function output argument 'out' requires 12 bits, but connection's VARREF 'qu70' generates 70 bits. - : ... In instance t + : ... note: In instance 't' 118 | dpii_inv_u12(du70, qu70); | ^~~~ %Warning-WIDTHTRUNC: t/t_func_wide_out.v:118:10: Operator TASKREF 'dpii_inv_u12' expects 12 bits on the Function Argument, but Function Argument's VARREF 'qu70' generates 70 bits. - : ... In instance t + : ... note: In instance 't' 118 | dpii_inv_u12(du70, qu70); | ^~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_fuzz_triand_bad.out b/test_regress/t/t_fuzz_triand_bad.out index d2186a59e..4ed8efd50 100644 --- a/test_regress/t/t_fuzz_triand_bad.out +++ b/test_regress/t/t_fuzz_triand_bad.out @@ -1,10 +1,10 @@ %Error-UNSUPPORTED: t/t_fuzz_triand_bad.v:8:12: Unsupported: Member call on object 'VARREF 'g'' which is a 'BASICDTYPE 'logic'' - : ... In instance t + : ... note: In instance 't' 8 | tri g=g.and.g; | ^~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error: Internal Error: t/t_fuzz_triand_bad.v:8:12: ../V3Width.cpp:#: Unlinked data type - : ... In instance t + : ... note: In instance 't' 8 | tri g=g.and.g; | ^~~ ... See the manual at https://verilator.org/verilator_doc.html for more assistance. diff --git a/test_regress/t/t_gen_cond_bitrange_bad.out b/test_regress/t/t_gen_cond_bitrange_bad.out index 98d3aad6b..47a9d3a71 100644 --- a/test_regress/t/t_gen_cond_bitrange_bad.out +++ b/test_regress/t/t_gen_cond_bitrange_bad.out @@ -1,19 +1,19 @@ %Warning-SELRANGE: t/t_gen_cond_bitrange_bad.v:58:38: Selection index out of range: 2:2 outside 1:0 - : ... In instance t.i_test_gen + : ... note: In instance 't.i_test_gen' 58 | if ((g < (SIZE + 1)) && MASK[g]) begin | ^ ... For warning description see https://verilator.org/warn/SELRANGE?v=latest ... Use "/* verilator lint_off SELRANGE */" and lint_on around source to disable this message. %Warning-SELRANGE: t/t_gen_cond_bitrange_bad.v:70:32: Selection index out of range: 2:2 outside 1:0 - : ... In instance t.i_test_gen + : ... note: In instance 't.i_test_gen' 70 | if ((g < SIZE) && MASK[g + 1]) begin | ^ %Warning-SELRANGE: t/t_gen_cond_bitrange_bad.v:83:33: Selection index out of range: 2:2 outside 1:0 - : ... In instance t.i_test_gen + : ... note: In instance 't.i_test_gen' 83 | if ((g < (SIZE)) & MASK[g]) begin | ^ %Warning-SELRANGE: t/t_gen_cond_bitrange_bad.v:96:35: Selection index out of range: 2:2 outside 1:0 - : ... In instance t.i_test_gen + : ... note: In instance 't.i_test_gen' 96 | if (!((g >= SIZE) | ~MASK[g])) begin | ^ %Error: Exiting due to diff --git a/test_regress/t/t_gen_missing_bad2.out b/test_regress/t/t_gen_missing_bad2.out index d7c378472..4236c9693 100644 --- a/test_regress/t/t_gen_missing_bad2.out +++ b/test_regress/t/t_gen_missing_bad2.out @@ -1,17 +1,17 @@ %Error: t/t_gen_missing_bad2.v:8:8: Expecting expression to be constant, but can't convert a TESTPLUSARGS to constant. - : ... In instance t + : ... note: In instance 't' 8 | if ($test$plusargs("BAD-non-constant")) begin | ^~~~~~~~~~~~~~ %Error: t/t_gen_missing_bad2.v:8:8: Generate If condition must evaluate to constant - : ... In instance t + : ... note: In instance 't' 8 | if ($test$plusargs("BAD-non-constant")) begin | ^~~~~~~~~~~~~~ %Error: t/t_gen_missing_bad2.v:12:7: Expecting expression to be constant, but can't convert a TESTPLUSARGS to constant. - : ... In instance t + : ... note: In instance 't' 12 | $test$plusargs("BAD-non-constant"): initial $stop; | ^~~~~~~~~~~~~~ %Error: t/t_gen_missing_bad2.v:12:41: Generate Case item does not evaluate to constant - : ... In instance t + : ... note: In instance 't' 12 | $test$plusargs("BAD-non-constant"): initial $stop; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_gen_var_bad.out b/test_regress/t/t_gen_var_bad.out index e488e77d0..bedab7f34 100644 --- a/test_regress/t/t_gen_var_bad.out +++ b/test_regress/t/t_gen_var_bad.out @@ -1,5 +1,5 @@ %Error: t/t_gen_var_bad.v:10:7: Non-genvar used in generate for: 'i' - : ... In instance t + : ... note: In instance 't' 10 | for (i=0; i<3; i=i+1) begin | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_generate_fatal_bad.out b/test_regress/t/t_generate_fatal_bad.out index 5eb417f9d..f2569883c 100644 --- a/test_regress/t/t_generate_fatal_bad.out +++ b/test_regress/t/t_generate_fatal_bad.out @@ -2,86 +2,86 @@ ... For warning description see https://verilator.org/warn/USERFATAL?v=latest ... Use "/* verilator lint_off USERFATAL */" and lint_on around source to disable this message. %Error: t/t_generate_fatal_bad.v:13:29: Expecting expression to be constant, but can't determine constant for FUNCREF 'get_baz' - : ... In instance t.nested_loop[10].foo2_inst.foo2_loop[1].foo_in_foo2_inst + : ... note: In instance 't.nested_loop[10].foo2_inst.foo2_loop[1].foo_in_foo2_inst' t/t_generate_fatal_bad.v:9:4: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing - t/t_generate_fatal_bad.v:13:29: ... Called from get_baz() with parameters: + t/t_generate_fatal_bad.v:13:29: ... Called from 'get_baz()' with parameters: bar = ?32?h0 13 | localparam integer BAZ = get_baz(BAR); | ^~~~~~~ %Error: t/t_generate_fatal_bad.v:13:29: Expecting expression to be constant, but can't determine constant for FUNCREF 'get_baz' - : ... In instance t.genloop[1].foo_inst + : ... note: In instance 't.genloop[1].foo_inst' t/t_generate_fatal_bad.v:9:4: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing - t/t_generate_fatal_bad.v:13:29: ... Called from get_baz() with parameters: + t/t_generate_fatal_bad.v:13:29: ... Called from 'get_baz()' with parameters: bar = ?32?h1 13 | localparam integer BAZ = get_baz(BAR); | ^~~~~~~ %Error: t/t_generate_fatal_bad.v:13:29: Expecting expression to be constant, but can't determine constant for FUNCREF 'get_baz' - : ... In instance t.gen_l1[2].gen_l2[0].foo_inst2 + : ... note: In instance 't.gen_l1[2].gen_l2[0].foo_inst2' t/t_generate_fatal_bad.v:9:4: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing - t/t_generate_fatal_bad.v:13:29: ... Called from get_baz() with parameters: + t/t_generate_fatal_bad.v:13:29: ... Called from 'get_baz()' with parameters: bar = 32'h2 13 | localparam integer BAZ = get_baz(BAR); | ^~~~~~~ %Error: t/t_generate_fatal_bad.v:13:29: Expecting expression to be constant, but can't determine constant for FUNCREF 'get_baz' - : ... In instance t.gen_l1[2].gen_l2[1].foo_inst2 + : ... note: In instance 't.gen_l1[2].gen_l2[1].foo_inst2' t/t_generate_fatal_bad.v:9:4: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing - t/t_generate_fatal_bad.v:13:29: ... Called from get_baz() with parameters: + t/t_generate_fatal_bad.v:13:29: ... Called from 'get_baz()' with parameters: bar = 32'h4 13 | localparam integer BAZ = get_baz(BAR); | ^~~~~~~ %Error: t/t_generate_fatal_bad.v:13:29: Expecting expression to be constant, but can't determine constant for FUNCREF 'get_baz' - : ... In instance t.gen_l1[3].gen_l2[0].foo_inst2 + : ... note: In instance 't.gen_l1[3].gen_l2[0].foo_inst2' t/t_generate_fatal_bad.v:9:4: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing - t/t_generate_fatal_bad.v:13:29: ... Called from get_baz() with parameters: + t/t_generate_fatal_bad.v:13:29: ... Called from 'get_baz()' with parameters: bar = 32'h3 13 | localparam integer BAZ = get_baz(BAR); | ^~~~~~~ %Error: t/t_generate_fatal_bad.v:13:29: Expecting expression to be constant, but can't determine constant for FUNCREF 'get_baz' - : ... In instance t.gen_l1[3].gen_l2[1].foo_inst2 + : ... note: In instance 't.gen_l1[3].gen_l2[1].foo_inst2' t/t_generate_fatal_bad.v:9:4: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing - t/t_generate_fatal_bad.v:13:29: ... Called from get_baz() with parameters: + t/t_generate_fatal_bad.v:13:29: ... Called from 'get_baz()' with parameters: bar = 32'h5 13 | localparam integer BAZ = get_baz(BAR); | ^~~~~~~ %Error: t/t_generate_fatal_bad.v:13:29: Expecting expression to be constant, but can't determine constant for FUNCREF 'get_baz' - : ... In instance t.cond_true.foo_inst3 + : ... note: In instance 't.cond_true.foo_inst3' t/t_generate_fatal_bad.v:9:4: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing - t/t_generate_fatal_bad.v:13:29: ... Called from get_baz() with parameters: + t/t_generate_fatal_bad.v:13:29: ... Called from 'get_baz()' with parameters: bar = ?32?h6 13 | localparam integer BAZ = get_baz(BAR); | ^~~~~~~ %Error: t/t_generate_fatal_bad.v:13:29: Expecting expression to be constant, but can't determine constant for FUNCREF 'get_baz' - : ... In instance t.genblk4.foo_inst4 + : ... note: In instance 't.genblk4.foo_inst4' t/t_generate_fatal_bad.v:9:4: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing - t/t_generate_fatal_bad.v:13:29: ... Called from get_baz() with parameters: + t/t_generate_fatal_bad.v:13:29: ... Called from 'get_baz()' with parameters: bar = ?32?h7 13 | localparam integer BAZ = get_baz(BAR); | ^~~~~~~ %Error: t/t_generate_fatal_bad.v:13:29: Expecting expression to be constant, but can't determine constant for FUNCREF 'get_baz' - : ... In instance t.nested_loop[8].foo2_inst.foo2_loop[0].foo_in_foo2_inst + : ... note: In instance 't.nested_loop[8].foo2_inst.foo2_loop[0].foo_in_foo2_inst' t/t_generate_fatal_bad.v:9:4: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing - t/t_generate_fatal_bad.v:13:29: ... Called from get_baz() with parameters: + t/t_generate_fatal_bad.v:13:29: ... Called from 'get_baz()' with parameters: bar = 32'h8 13 | localparam integer BAZ = get_baz(BAR); | ^~~~~~~ %Error: t/t_generate_fatal_bad.v:13:29: Expecting expression to be constant, but can't determine constant for FUNCREF 'get_baz' - : ... In instance t.nested_loop[8].foo2_inst.foo2_loop[1].foo_in_foo2_inst + : ... note: In instance 't.nested_loop[8].foo2_inst.foo2_loop[1].foo_in_foo2_inst' t/t_generate_fatal_bad.v:9:4: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing - t/t_generate_fatal_bad.v:13:29: ... Called from get_baz() with parameters: + t/t_generate_fatal_bad.v:13:29: ... Called from 'get_baz()' with parameters: bar = 32'h9 13 | localparam integer BAZ = get_baz(BAR); | ^~~~~~~ %Error: t/t_generate_fatal_bad.v:13:29: Expecting expression to be constant, but can't determine constant for FUNCREF 'get_baz' - : ... In instance t.nested_loop[10].foo2_inst.foo2_loop[0].foo_in_foo2_inst + : ... note: In instance 't.nested_loop[10].foo2_inst.foo2_loop[0].foo_in_foo2_inst' t/t_generate_fatal_bad.v:9:4: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing - t/t_generate_fatal_bad.v:13:29: ... Called from get_baz() with parameters: + t/t_generate_fatal_bad.v:13:29: ... Called from 'get_baz()' with parameters: bar = 32'ha 13 | localparam integer BAZ = get_baz(BAR); | ^~~~~~~ %Error: t/t_generate_fatal_bad.v:13:29: Expecting expression to be constant, but can't determine constant for FUNCREF 'get_baz' - : ... In instance t.nested_loop[10].foo2_inst.foo2_loop[1].foo_in_foo2_inst + : ... note: In instance 't.nested_loop[10].foo2_inst.foo2_loop[1].foo_in_foo2_inst' t/t_generate_fatal_bad.v:9:4: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing - t/t_generate_fatal_bad.v:13:29: ... Called from get_baz() with parameters: + t/t_generate_fatal_bad.v:13:29: ... Called from 'get_baz()' with parameters: bar = 32'hb 13 | localparam integer BAZ = get_baz(BAR); | ^~~~~~~ diff --git a/test_regress/t/t_hier_block0_bad.out b/test_regress/t/t_hier_block0_bad.out index c3a778047..57d1bde09 100644 --- a/test_regress/t/t_hier_block0_bad.out +++ b/test_regress/t/t_hier_block0_bad.out @@ -1,9 +1,9 @@ %Error: t/t_hier_block0_bad.v:21:11: 'sub0' has hier_block metacomment, hierarchical Verilation supports only integer/floating point/string parameters - : ... In instance t + : ... note: In instance 't' 21 | sub0 #(UNPACKED) i_sub0(.clk(clk), .in(8'(count)), .out(out0)); | ^~~~~~~~ %Error: t/t_hier_block0_bad.v:23:12: 'sub1' has hier_block metacomment, but 'parameter type' is not supported - : ... In instance t + : ... note: In instance 't' 23 | sub1 #(.T(logic[7:0])) i_sub1(.in(out0), .out(out1)); | ^ %Error: t/t_hier_block0_bad.v:27:42: Cannot access inside hierarchical block diff --git a/test_regress/t/t_hier_block1_bad.out b/test_regress/t/t_hier_block1_bad.out index 4e7234c0f..8284bfa27 100644 --- a/test_regress/t/t_hier_block1_bad.out +++ b/test_regress/t/t_hier_block1_bad.out @@ -1,16 +1,16 @@ %Warning-HIERBLOCK: t/t_hier_block1_bad.v:16:8: Top module illegally marked hierarchical block, ignoring marking - : ... In instance t + : ... note: In instance 't' : ... Suggest remove verilator hier_block on this module 16 | module t ( | ^ ... For warning description see https://verilator.org/warn/HIERBLOCK?v=latest ... Use "/* verilator lint_off HIERBLOCK */" and lint_on around source to disable this message. %Error: t/t_hier_block1_bad.v:45:32: Modport cannot be used at the hierarchical block boundary - : ... In instance t.i_sub1 + : ... note: In instance 't.i_sub1' 45 | module sub1 (byte_ifs.receiver in, byte_ifs.sender out); /*verilator hier_block*/ | ^~ %Error: t/t_hier_block1_bad.v:45:52: Modport cannot be used at the hierarchical block boundary - : ... In instance t.i_sub1 + : ... note: In instance 't.i_sub1' 45 | module sub1 (byte_ifs.receiver in, byte_ifs.sender out); /*verilator hier_block*/ | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_implements_new_bad.out b/test_regress/t/t_implements_new_bad.out index e86450d3a..3201ecfaf 100644 --- a/test_regress/t/t_implements_new_bad.out +++ b/test_regress/t/t_implements_new_bad.out @@ -1,5 +1,5 @@ %Error: t/t_implements_new_bad.v:13:11: Illegal to call 'new' using an abstract virtual class (IEEE 1800-2017 8.21) - : ... In instance t + : ... note: In instance 't' 13 | c = new; | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_inside_queue_bad.out b/test_regress/t/t_inside_queue_bad.out index ad0b436c9..37b7be1ad 100644 --- a/test_regress/t/t_inside_queue_bad.out +++ b/test_regress/t/t_inside_queue_bad.out @@ -1,13 +1,13 @@ %Error: t/t_inside_queue_bad.v:15:15: Inside operator not legal on non-unpacked arrays (IEEE 1800-2017 11.4.13) - : ... In instance t + : ... note: In instance 't' 15 | m = (10 inside {q}); | ^~~~~~ %Error: t/t_inside_queue_bad.v:16:15: Inside operator not legal on non-unpacked arrays (IEEE 1800-2017 11.4.13) - : ... In instance t + : ... note: In instance 't' 16 | m = (10 inside {assoc}); | ^~~~~~ %Error: t/t_inside_queue_bad.v:17:15: Inside operator not legal on non-unpacked arrays (IEEE 1800-2017 11.4.13) - : ... In instance t + : ... note: In instance 't' 17 | m = (10 inside {dyn}); | ^~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_inside_unpacked.out b/test_regress/t/t_inside_unpacked.out index 608d0f49b..d46038344 100644 --- a/test_regress/t/t_inside_unpacked.out +++ b/test_regress/t/t_inside_unpacked.out @@ -1,9 +1,9 @@ %Error: t/t_inside_unpacked.v:17:35: Unsupported: inside (set membership operator) on unpacked array - : ... In instance t + : ... note: In instance 't' 17 | localparam HIT_INSIDE = HIT_LP inside {CHECKLIST_P}; | ^~~~~~ %Error: t/t_inside_unpacked.v:18:37: Unsupported: inside (set membership operator) on unpacked array - : ... In instance t + : ... note: In instance 't' 18 | localparam MISS_INSIDE = MISS_LP inside {CHECKLIST_P}; | ^~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_inst_array_bad.out b/test_regress/t/t_inst_array_bad.out index b438a2a0d..cb47790f3 100644 --- a/test_regress/t/t_inst_array_bad.out +++ b/test_regress/t/t_inst_array_bad.out @@ -1,5 +1,5 @@ %Error: t/t_inst_array_bad.v:19:28: Input port connection 'onebit' as part of a module instance array requires 1 or 8 bits, but connection's VARREF 'onebitbad' generates 9 bits. (IEEE 1800-2017 23.3.3) - : ... In instance t + : ... note: In instance 't' 19 | sub sub [7:0] (allbits, onebitbad, bitout); | ^~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_inst_misarray2_bad.out b/test_regress/t/t_inst_misarray2_bad.out index 889bfcc7c..032c520ec 100644 --- a/test_regress/t/t_inst_misarray2_bad.out +++ b/test_regress/t/t_inst_misarray2_bad.out @@ -1,5 +1,5 @@ %Error: t/t_inst_misarray2_bad.v:10:17: Illegal input port connection 'i_data', mismatch between port which is not an array, and expression which is an array. (IEEE 1800-2017 7.6) - : ... In instance t + : ... note: In instance 't' 10 | .i_data(fft_oQ[6:0]) | ^~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_inst_misarray_bad.out b/test_regress/t/t_inst_misarray_bad.out index 56dd2368a..bfbffa997 100644 --- a/test_regress/t/t_inst_misarray_bad.out +++ b/test_regress/t/t_inst_misarray_bad.out @@ -1,5 +1,5 @@ %Error: t/t_inst_misarray_bad.v:17:23: Illegal input port connection 'foo', mismatch between port which is an array, and expression which is not an array. (IEEE 1800-2017 7.6) - : ... In instance t + : ... note: In instance 't' 17 | .foo(foo)); | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_inst_overwide_bad.out b/test_regress/t/t_inst_overwide_bad.out index 6bf85b1c5..3a43fefa6 100644 --- a/test_regress/t/t_inst_overwide_bad.out +++ b/test_regress/t/t_inst_overwide_bad.out @@ -1,19 +1,19 @@ %Warning-WIDTHEXPAND: t/t_inst_overwide.v:23:14: Output port connection 'outy_w92' expects 92 bits on the pin connection, but pin connection's VARREF 'outc_w30' generates 30 bits. - : ... In instance t + : ... note: In instance 't' 23 | .outy_w92 (outc_w30), | ^~~~~~~~ ... For warning description see https://verilator.org/warn/WIDTHEXPAND?v=latest ... Use "/* verilator lint_off WIDTHEXPAND */" and lint_on around source to disable this message. %Warning-WIDTHTRUNC: t/t_inst_overwide.v:24:14: Output port connection 'outz_w22' expects 22 bits on the pin connection, but pin connection's VARREF 'outd_w73' generates 73 bits. - : ... In instance t + : ... note: In instance 't' 24 | .outz_w22 (outd_w73), | ^~~~~~~~ %Warning-WIDTHEXPAND: t/t_inst_overwide.v:27:14: Input port connection 'inw_w31' expects 31 bits on the pin connection, but pin connection's VARREF 'ina_w1' generates 1 bits. - : ... In instance t + : ... note: In instance 't' 27 | .inw_w31 (ina_w1), | ^~~~~~~ %Warning-WIDTHTRUNC: t/t_inst_overwide.v:28:14: Input port connection 'inx_w11' expects 11 bits on the pin connection, but pin connection's VARREF 'inb_w61' generates 61 bits. - : ... In instance t + : ... note: In instance 't' 28 | .inx_w11 (inb_w61) | ^~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_inst_pin_realnreal.out b/test_regress/t/t_inst_pin_realnreal.out index d78ce9a1e..486d7613c 100644 --- a/test_regress/t/t_inst_pin_realnreal.out +++ b/test_regress/t/t_inst_pin_realnreal.out @@ -1,5 +1,5 @@ %Error-UNSUPPORTED: t/t_inst_pin_realnreal.v:51:32: Unsupported: Output port connection 'out' connects real to non-real - : ... In instance t.netlist + : ... note: In instance 't.netlist' 51 | pga_model pga0(.in, .gain, .out(pga_out)); | ^~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest diff --git a/test_regress/t/t_inst_recurse2_bad.out b/test_regress/t/t_inst_recurse2_bad.out index 312a2bf48..024193f31 100644 --- a/test_regress/t/t_inst_recurse2_bad.out +++ b/test_regress/t/t_inst_recurse2_bad.out @@ -1,5 +1,5 @@ %Error-UNSUPPORTED: t/t_inst_recurse2_bad.v:18:8: Unsupported: Identically recursive module (module instantiates itself, without changing parameters): 'looped' - : ... In instance t.looped.looped + : ... note: In instance 't.looped.looped' 18 | module looped ( ); | ^~~~~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest diff --git a/test_regress/t/t_interface_ar3.out b/test_regress/t/t_interface_ar3.out index 49bc89443..97dead9a0 100644 --- a/test_regress/t/t_interface_ar3.out +++ b/test_regress/t/t_interface_ar3.out @@ -1,9 +1,9 @@ %Error: t/t_interface_ar3.v:16:36: Unsupported: interface slices - : ... In instance t + : ... note: In instance 't' 16 | sub sub01 [2] (.clk, .infc(iinst[0:1])); | ^ %Error: Internal Error: t/t_interface_ar3.v:16:36: ../V3Inst.cpp:#: No interface varref under array - : ... In instance t + : ... note: In instance 't' 16 | sub sub01 [2] (.clk, .infc(iinst[0:1])); | ^ ... See the manual at https://verilator.org/verilator_doc.html for more assistance. diff --git a/test_regress/t/t_interface_array_bad.out b/test_regress/t/t_interface_array_bad.out index 0caac3af4..a5c9dddac 100644 --- a/test_regress/t/t_interface_array_bad.out +++ b/test_regress/t/t_interface_array_bad.out @@ -1,9 +1,9 @@ %Error: t/t_interface_array_bad.v:23:16: Expecting expression to be constant, but variable isn't const: 'bar' - : ... In instance t + : ... note: In instance 't' 23 | assign foos[bar].a = 1'b1; | ^~~ %Error: t/t_interface_array_bad.v:23:15: Could not expand constant selection inside dotted reference: 'bar' - : ... In instance t + : ... note: In instance 't' 23 | assign foos[bar].a = 1'b1; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_interface_array_nocolon_bad.out b/test_regress/t/t_interface_array_nocolon_bad.out index 744b81d20..efeba5432 100644 --- a/test_regress/t/t_interface_array_nocolon_bad.out +++ b/test_regress/t/t_interface_array_nocolon_bad.out @@ -1,19 +1,19 @@ %Warning-ASCRANGE: t/t_interface_array_nocolon_bad.v:26:26: Ascending instance range connecting to vector: left < right of instance range: [0:2] - : ... In instance t + : ... note: In instance 't' 26 | foo_intf foos [N] (.x(X)); | ^ ... For warning description see https://verilator.org/warn/ASCRANGE?v=latest ... Use "/* verilator lint_off ASCRANGE */" and lint_on around source to disable this message. %Warning-ASCRANGE: t/t_interface_array_nocolon_bad.v:27:28: Ascending instance range connecting to vector: left < right of instance range: [1:3] - : ... In instance t + : ... note: In instance 't' 27 | foo_intf fool [1:3] (.x(X)); | ^ %Warning-ASCRANGE: t/t_interface_array_nocolon_bad.v:30:26: Ascending instance range connecting to vector: left < right of instance range: [0:2] - : ... In instance t + : ... note: In instance 't' 30 | foo_subm subs [N] (.x(X)); | ^ %Warning-ASCRANGE: t/t_interface_array_nocolon_bad.v:31:28: Ascending instance range connecting to vector: left < right of instance range: [1:3] - : ... In instance t + : ... note: In instance 't' 31 | foo_subm subl [1:3] (.x(X)); | ^ %Error: Exiting due to diff --git a/test_regress/t/t_interface_asvar_bad.out b/test_regress/t/t_interface_asvar_bad.out index ffcdb86d7..84efcaf96 100644 --- a/test_regress/t/t_interface_asvar_bad.out +++ b/test_regress/t/t_interface_asvar_bad.out @@ -1,9 +1,9 @@ %Error: t/t_interface_asvar_bad.v:29:16: Operator ASSIGN expected non-interface on Assign RHS but 'itf' is an interface. - : ... In instance t.source + : ... note: In instance 't.source' 29 | getter = itf; | ^~~ %Error: t/t_interface_asvar_bad.v:30:23: Operator ADD expected non-interface on RHS but 'itf' is an interface. - : ... In instance t.source + : ... note: In instance 't.source' 30 | getter = 4'd3 + itf; | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_interface_modport_dir_bad.out b/test_regress/t/t_interface_modport_dir_bad.out index d7783d86d..aaec5dd1c 100644 --- a/test_regress/t/t_interface_modport_dir_bad.out +++ b/test_regress/t/t_interface_modport_dir_bad.out @@ -1,5 +1,5 @@ %Error: t/t_interface_modport_dir_bad.v:52:25: Port connection 'ctrl' expected 'source' interface modport on pin connection but got 'sink' modport. - : ... In instance t.source_i + : ... note: In instance 't.source_i' 52 | sourceMod source_i (.ctrl); | ^~~~ %Error: Exiting due to diff --git a/test_regress/t/t_interface_param_acc_bits.out b/test_regress/t/t_interface_param_acc_bits.out index 69419ae25..51998432b 100644 --- a/test_regress/t/t_interface_param_acc_bits.out +++ b/test_regress/t/t_interface_param_acc_bits.out @@ -1,5 +1,5 @@ %Error: t/t_interface_param_acc_bits.v:15:42: Parameter-resolved constants must not use dotted references: 'dummy' - : ... In instance t + : ... note: In instance 't' 15 | simple_bus #(.PARAMETER($bits(sb_intf.dummy))) simple(); | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_interface_param_another_bad.out b/test_regress/t/t_interface_param_another_bad.out index c77f8eae3..f63612458 100644 --- a/test_regress/t/t_interface_param_another_bad.out +++ b/test_regress/t/t_interface_param_another_bad.out @@ -1,5 +1,5 @@ %Error: t/t_interface_param_another_bad.v:9:42: Parameter-resolved constants must not use dotted references: 'dummy' - : ... In instance t + : ... note: In instance 't' 9 | simple_bus #(.PARAMETER($bits(sb_intf.dummy))) simple(); | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_interface_size_bad.out b/test_regress/t/t_interface_size_bad.out index b5ccb6def..80351f39a 100644 --- a/test_regress/t/t_interface_size_bad.out +++ b/test_regress/t/t_interface_size_bad.out @@ -1,9 +1,9 @@ %Error: t/t_interface_size_bad.v:16:20: Illegal port connection 'foo', mismatch between port which is an interface array of size 5, and expression which is an interface array of size 4. - : ... In instance t + : ... note: In instance 't' 16 | baz baz4_inst (.foo(foo4)); | ^~~ %Error: t/t_interface_size_bad.v:17:20: Illegal port connection 'foo', mismatch between port which is an interface array of size 5, and expression which is an interface array of size 6. - : ... In instance t + : ... note: In instance 't' 17 | baz baz6_inst (.foo(foo6)); | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_interface_virtual_bad.out b/test_regress/t/t_interface_virtual_bad.out index 6afbdc125..7149f62ba 100644 --- a/test_regress/t/t_interface_virtual_bad.out +++ b/test_regress/t/t_interface_virtual_bad.out @@ -1,33 +1,33 @@ %Error: t/t_interface_virtual_bad.v:31:12: Operator ASSIGN expected 'PBus' interface on Assign RHS but 'q8__Viftop' is a different interface ('QBus'). - : ... In instance t + : ... note: In instance 't' 31 | v8 = q8; | ^~ %Error: t/t_interface_virtual_bad.v:35:12: Operator ASSIGN expected no interface modport on Assign RHS but got 'phy' modport. - : ... In instance t + : ... note: In instance 't' 35 | v8 = v8_phy; | ^~~~~~ %Error: t/t_interface_virtual_bad.v:37:17: Operator ASSIGN expected non-interface on Assign RHS but 'p8__Viftop' is an interface. - : ... In instance t + : ... note: In instance 't' 37 | data = p8.phy; | ^~~ %Error: t/t_interface_virtual_bad.v:38:14: Operator ASSIGN expected non-interface on Assign RHS but 'v8_phy' is an interface. - : ... In instance t + : ... note: In instance 't' 38 | data = v8_phy; | ^~~~~~ %Error: t/t_interface_virtual_bad.v:39:14: Operator ASSIGN expected non-interface on Assign RHS but 'v8' is an interface. - : ... In instance t + : ... note: In instance 't' 39 | data = v8; | ^~ %Error: t/t_interface_virtual_bad.v:40:14: Operator ASSIGN expected non-interface on Assign RHS but 'p8__Viftop' is an interface. - : ... In instance t + : ... note: In instance 't' 40 | data = p8; | ^~ %Error: t/t_interface_virtual_bad.v:41:12: Operator ASSIGN expected 'PBus' interface on Assign RHS but 'data' is not an interface. - : ... In instance t + : ... note: In instance 't' 41 | v8 = data; | ^~~~ %Error: t/t_interface_virtual_bad.v:44:79: Member 'gran' not found in interface 'PBus' - : ... In instance t + : ... note: In instance 't' : ... Suggested alternative: 'grant' 44 | $display("q8.grant=", p8.grant, " v8.grant=", v8.grant, v8_phy.addr, v8.gran); | ^~~~ diff --git a/test_regress/t/t_interface_wrong_bad.out b/test_regress/t/t_interface_wrong_bad.out index d4694955a..ce767fc66 100644 --- a/test_regress/t/t_interface_wrong_bad.out +++ b/test_regress/t/t_interface_wrong_bad.out @@ -1,5 +1,5 @@ %Error: t/t_interface_wrong_bad.v:32:8: Port 'foo_port' expects 'foo_intf' interface but pin connects 'bar_intf' interface - : ... In instance t + : ... note: In instance 't' 32 | .foo_port (bar) | ^~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_always_comb_bad.out b/test_regress/t/t_lint_always_comb_bad.out index 10d0e1dfb..33157d657 100644 --- a/test_regress/t/t_lint_always_comb_bad.out +++ b/test_regress/t/t_lint_always_comb_bad.out @@ -1,19 +1,19 @@ %Error-PROCASSWIRE: t/t_lint_always_comb_bad.v:29:9: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'temp1' - : ... In instance t + : ... note: In instance 't' 29 | temp1 = 'h0; | ^~~~~ ... For error description see https://verilator.org/warn/PROCASSWIRE?v=latest %Error-PROCASSWIRE: t/t_lint_always_comb_bad.v:31:9: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'temp1' - : ... In instance t + : ... note: In instance 't' 31 | temp1 = (temp1_d1r - 'h1); | ^~~~~ %Warning-ALWCOMBORDER: t/t_lint_always_comb_bad.v:32:7: Always_comb variable driven after use: 'mid' - : ... In instance t + : ... note: In instance 't' 32 | mid = (temp1_d1r == 'h0); | ^~~ ... Use "/* verilator lint_off ALWCOMBORDER */" and lint_on around source to disable this message. %Error-PROCASSWIRE: t/t_lint_always_comb_bad.v:46:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'temp1_d1r' - : ... In instance t + : ... note: In instance 't' 46 | temp1_d1r <= temp1; | ^~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_always_comb_multidriven.out b/test_regress/t/t_lint_always_comb_multidriven.out index e57a462a5..a9708f7f6 100644 --- a/test_regress/t/t_lint_always_comb_multidriven.out +++ b/test_regress/t/t_lint_always_comb_multidriven.out @@ -1,5 +1,5 @@ %Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven.v:26:16: Variable written to in always_comb also written by other process (IEEE 1800-2017 9.2.2.2): 'out1' - : ... In instance t + : ... note: In instance 't' t/t_lint_always_comb_multidriven.v:26:16: 26 | always_comb out1 = d; | ^~~~ @@ -9,7 +9,7 @@ ... For warning description see https://verilator.org/warn/MULTIDRIVEN?v=latest ... Use "/* verilator lint_off MULTIDRIVEN */" and lint_on around source to disable this message. %Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven.v:29:16: Variable written to in always_comb also written by other process (IEEE 1800-2017 9.2.2.2): 'out2' - : ... In instance t + : ... note: In instance 't' t/t_lint_always_comb_multidriven.v:29:16: 29 | always_comb out2 = 1'b0; | ^~~~ @@ -17,7 +17,7 @@ 28 | assign out2 = d; | ^~~~ %Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven.v:32:11: Variable also written to in always_comb (IEEE 1800-2017 9.2.2.2): 'out3' - : ... In instance t + : ... note: In instance 't' t/t_lint_always_comb_multidriven.v:32:11: 32 | assign out3 = 1'b0; | ^~~~ @@ -25,7 +25,7 @@ 31 | always_comb out3 = d; | ^~~~ %Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven.v:35:11: Variable also written to in always_comb (IEEE 1800-2017 9.2.2.2): 'out4' - : ... In instance t + : ... note: In instance 't' t/t_lint_always_comb_multidriven.v:35:11: 35 | assign out4 = d; | ^~~~ @@ -33,7 +33,7 @@ 34 | always_comb out4 = 1'b0; | ^~~~ %Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven.v:38:16: Variable written to in always_comb also written by other process (IEEE 1800-2017 9.2.2.2): 'out5' - : ... In instance t + : ... note: In instance 't' t/t_lint_always_comb_multidriven.v:38:16: 38 | always_comb out5 = d; | ^~~~ @@ -41,7 +41,7 @@ 37 | always_comb out5 = 1'b0; | ^~~~ %Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven.v:41:16: Variable written to in always_comb also written by other process (IEEE 1800-2017 9.2.2.2): 'out6' - : ... In instance t + : ... note: In instance 't' t/t_lint_always_comb_multidriven.v:41:16: 41 | always_comb out6 = 1'b0; | ^~~~ @@ -49,7 +49,7 @@ 40 | always_comb out6 = d; | ^~~~ %Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven.v:17:15: Bits [0:0] of signal 'out2' have multiple combinational drivers - : ... In instance t + : ... note: In instance 't' t/t_lint_always_comb_multidriven.v:28:16: ... Location of first driver 28 | assign out2 = d; | ^ @@ -58,7 +58,7 @@ | ^ t/t_lint_always_comb_multidriven.v:17:15: ... Only the first driver will be respected %Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven.v:19:15: Bits [0:0] of signal 'out4' have multiple combinational drivers - : ... In instance t + : ... note: In instance 't' t/t_lint_always_comb_multidriven.v:34:21: ... Location of first driver 34 | always_comb out4 = 1'b0; | ^ @@ -67,7 +67,7 @@ | ^ t/t_lint_always_comb_multidriven.v:19:15: ... Only the first driver will be respected %Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven.v:20:15: Bits [0:0] of signal 'out5' have multiple combinational drivers - : ... In instance t + : ... note: In instance 't' t/t_lint_always_comb_multidriven.v:37:21: ... Location of first driver 37 | always_comb out5 = 1'b0; | ^ @@ -76,7 +76,7 @@ | ^ t/t_lint_always_comb_multidriven.v:20:15: ... Only the first driver will be respected %Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven.v:21:15: Bits [0:0] of signal 'out6' have multiple combinational drivers - : ... In instance t + : ... note: In instance 't' t/t_lint_always_comb_multidriven.v:40:21: ... Location of first driver 40 | always_comb out6 = d; | ^ diff --git a/test_regress/t/t_lint_cmpconst_bad.out b/test_regress/t/t_lint_cmpconst_bad.out index 39cb5e47c..cb994fb50 100644 --- a/test_regress/t/t_lint_cmpconst_bad.out +++ b/test_regress/t/t_lint_cmpconst_bad.out @@ -1,5 +1,5 @@ %Warning-CMPCONST: t/t_lint_cmpconst_bad.v:13:15: Comparison is constant due to limited range - : ... In instance t + : ... note: In instance 't' 13 | if (uns > 3'b111) $stop; | ^ ... For warning description see https://verilator.org/warn/CMPCONST?v=latest diff --git a/test_regress/t/t_lint_const_func_dpi_bad.out b/test_regress/t/t_lint_const_func_dpi_bad.out index 6ac7d0ab6..329c5eeea 100644 --- a/test_regress/t/t_lint_const_func_dpi_bad.out +++ b/test_regress/t/t_lint_const_func_dpi_bad.out @@ -1,11 +1,11 @@ %Error: t/t_lint_const_func_dpi_bad.v:8:32: Constant function may not be DPI import (IEEE 1800-2017 13.4.3) - : ... In instance t + : ... note: In instance 't' 8 | import "DPI-C" function int dpiFunc(); | ^~~~~~~ %Error: t/t_lint_const_func_dpi_bad.v:9:23: Expecting expression to be constant, but can't determine constant for FUNCREF 'dpiFunc' - : ... In instance t + : ... note: In instance 't' t/t_lint_const_func_dpi_bad.v:8:32: ... Location of non-constant FUNC 'dpiFunc': DPI import functions aren't simulatable - t/t_lint_const_func_dpi_bad.v:9:23: ... Called from dpiFunc() with parameters: + t/t_lint_const_func_dpi_bad.v:9:23: ... Called from 'dpiFunc()' with parameters: 9 | localparam PARAM = dpiFunc(); | ^~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_const_func_gen_bad.out b/test_regress/t/t_lint_const_func_gen_bad.out index 61bd870a8..0ff833ba1 100644 --- a/test_regress/t/t_lint_const_func_gen_bad.out +++ b/test_regress/t/t_lint_const_func_gen_bad.out @@ -1,11 +1,11 @@ %Error: t/t_lint_const_func_gen_bad.v:11:30: Constant function may not be declared under generate (IEEE 1800-2017 13.4.3) - : ... In instance t + : ... note: In instance 't' 11 | function automatic bit constFunc(); | ^~~~~~~~~ %Error: t/t_lint_const_func_gen_bad.v:15:26: Expecting expression to be constant, but can't determine constant for FUNCREF 'constFunc' - : ... In instance t + : ... note: In instance 't' t/t_lint_const_func_gen_bad.v:11:30: ... Location of non-constant FUNC 'constFunc': Constant function called under generate - t/t_lint_const_func_gen_bad.v:15:26: ... Called from constFunc() with parameters: + t/t_lint_const_func_gen_bad.v:15:26: ... Called from 'constFunc()' with parameters: 15 | localparam PARAM = constFunc(); | ^~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_contassreg_bad.out b/test_regress/t/t_lint_contassreg_bad.out index 4921a2787..21f3b5ec4 100644 --- a/test_regress/t/t_lint_contassreg_bad.out +++ b/test_regress/t/t_lint_contassreg_bad.out @@ -1,5 +1,5 @@ %Error-CONTASSREG: t/t_lint_contassreg_bad.v:14:11: Continuous assignment to reg, perhaps intended wire (IEEE 1364-2005 6.1; Verilog only, legal in SV): 'r' - : ... In instance t + : ... note: In instance 't' 14 | assign r = 1'b0; | ^ ... For error description see https://verilator.org/warn/CONTASSREG?v=latest diff --git a/test_regress/t/t_lint_edge_real_bad.out b/test_regress/t/t_lint_edge_real_bad.out index 6932b75ea..b9012194b 100644 --- a/test_regress/t/t_lint_edge_real_bad.out +++ b/test_regress/t/t_lint_edge_real_bad.out @@ -1,9 +1,9 @@ %Error: t/t_lint_edge_real_bad.v:19:22: Edge event control not legal on real type (IEEE 1800-2017 6.12.1) - : ... In instance t + : ... note: In instance 't' 19 | always @ (posedge rbad) $stop; | ^~~~ %Error: t/t_lint_edge_real_bad.v:20:22: Edge event control not legal on non-integral type (IEEE 1800-2017 9.4.2) - : ... In instance t + : ... note: In instance 't' 20 | always @ (posedge ebad) $stop; | ^~~~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_genunnamed_bad.out b/test_regress/t/t_lint_genunnamed_bad.out index 2989ed1aa..09d2fe43b 100644 --- a/test_regress/t/t_lint_genunnamed_bad.out +++ b/test_regress/t/t_lint_genunnamed_bad.out @@ -1,21 +1,27 @@ -%Warning-GENUNNAMED: t/t_lint_genunnamed_bad.v:14:6: Unnamed generate block 'genblk2' (IEEE 1800-2017 27.6) : ... Suggest assign a label with 'begin : gen_' +%Warning-GENUNNAMED: t/t_lint_genunnamed_bad.v:14:6: Unnamed generate block 'genblk2' (IEEE 1800-2017 27.6) + : ... Suggest assign a label with 'begin : gen_' 14 | begin | ^~~~~ ... For warning description see https://verilator.org/warn/GENUNNAMED?v=latest ... Use "/* verilator lint_off GENUNNAMED */" and lint_on around source to disable this message. -%Warning-GENUNNAMED: t/t_lint_genunnamed_bad.v:18:6: Unnamed generate block 'genblk2' (IEEE 1800-2017 27.6) : ... Suggest assign a label with 'begin : gen_' +%Warning-GENUNNAMED: t/t_lint_genunnamed_bad.v:18:6: Unnamed generate block 'genblk2' (IEEE 1800-2017 27.6) + : ... Suggest assign a label with 'begin : gen_' 18 | begin | ^~~~~ -%Warning-GENUNNAMED: t/t_lint_genunnamed_bad.v:22:4: Unnamed generate block 'genblk3' (IEEE 1800-2017 27.6) : ... Suggest assign a label with 'begin : gen_' +%Warning-GENUNNAMED: t/t_lint_genunnamed_bad.v:22:4: Unnamed generate block 'genblk3' (IEEE 1800-2017 27.6) + : ... Suggest assign a label with 'begin : gen_' 22 | for (genvar v = 0; v < P; ++v) ; | ^~~ -%Warning-GENUNNAMED: t/t_lint_genunnamed_bad.v:24:4: Unnamed generate block 'genblk4' (IEEE 1800-2017 27.6) : ... Suggest assign a label with 'begin : gen_' +%Warning-GENUNNAMED: t/t_lint_genunnamed_bad.v:24:4: Unnamed generate block 'genblk4' (IEEE 1800-2017 27.6) + : ... Suggest assign a label with 'begin : gen_' 24 | for (genvar v = 0; v < P; ++v) | ^~~ -%Warning-GENUNNAMED: t/t_lint_genunnamed_bad.v:30:9: Unnamed generate block 'genblk5' (IEEE 1800-2017 27.6) : ... Suggest assign a label with 'begin : gen_' +%Warning-GENUNNAMED: t/t_lint_genunnamed_bad.v:30:9: Unnamed generate block 'genblk5' (IEEE 1800-2017 27.6) + : ... Suggest assign a label with 'begin : gen_' 30 | 1: initial begin end | ^~~~~~~ -%Warning-GENUNNAMED: t/t_lint_genunnamed_bad.v:31:9: Unnamed generate block 'genblk5' (IEEE 1800-2017 27.6) : ... Suggest assign a label with 'begin : gen_' +%Warning-GENUNNAMED: t/t_lint_genunnamed_bad.v:31:9: Unnamed generate block 'genblk5' (IEEE 1800-2017 27.6) + : ... Suggest assign a label with 'begin : gen_' 31 | 2: begin | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_iface_array_topmodule_bad.out b/test_regress/t/t_lint_iface_array_topmodule_bad.out index 6c0980c74..c71e24a5c 100644 --- a/test_regress/t/t_lint_iface_array_topmodule_bad.out +++ b/test_regress/t/t_lint_iface_array_topmodule_bad.out @@ -1,5 +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 + : ... note: In instance 't' 8 | parameter integer DW | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_iface_topmodule_bad.out b/test_regress/t/t_lint_iface_topmodule_bad.out index b5263bb79..49cd039e9 100644 --- a/test_regress/t/t_lint_iface_topmodule_bad.out +++ b/test_regress/t/t_lint_iface_topmodule_bad.out @@ -1,5 +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 + : ... note: In instance 't' 8 | parameter integer DW | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_ifdepth_bad.out b/test_regress/t/t_lint_ifdepth_bad.out index 01c910555..43e2eca53 100644 --- a/test_regress/t/t_lint_ifdepth_bad.out +++ b/test_regress/t/t_lint_ifdepth_bad.out @@ -1,5 +1,5 @@ %Warning-IFDEPTH: t/t_lint_ifdepth_bad.v:22:12: Deep 'if' statement; suggest unique/priority to avoid slow logic - : ... In instance t + : ... note: In instance 't' 22 | else if (value==11) begin end | ^~ ... For warning description see https://verilator.org/warn/IFDEPTH?v=latest diff --git a/test_regress/t/t_lint_in_inc_bad.out b/test_regress/t/t_lint_in_inc_bad.out index b643c6ad8..b151b87be 100644 --- a/test_regress/t/t_lint_in_inc_bad.out +++ b/test_regress/t/t_lint_in_inc_bad.out @@ -1,6 +1,6 @@ %Error: t/t_lint_in_inc_bad_2.vh:9:7: syntax error, unexpected if, expecting '(' 9 | if if if; | ^~ - t/t_lint_in_inc_bad_1.vh:8:1: ... note: In file included from t_lint_in_inc_bad_1.vh - t/t_lint_in_inc_bad.v:8:1: ... note: In file included from t_lint_in_inc_bad.v + t/t_lint_in_inc_bad_1.vh:8:1: ... note: In file included from 't_lint_in_inc_bad_1.vh' + t/t_lint_in_inc_bad.v:8:1: ... note: In file included from 't_lint_in_inc_bad.v' %Error: Exiting due to diff --git a/test_regress/t/t_lint_infinite_bad.out b/test_regress/t/t_lint_infinite_bad.out index 4599a677f..3a324846d 100644 --- a/test_regress/t/t_lint_infinite_bad.out +++ b/test_regress/t/t_lint_infinite_bad.out @@ -1,11 +1,11 @@ %Warning-INFINITELOOP: t/t_lint_infinite_bad.v:10:7: Infinite loop (condition always true) - : ... In instance t + : ... note: In instance 't' 10 | forever begin end | ^~~~~~~ ... For warning description see https://verilator.org/warn/INFINITELOOP?v=latest ... Use "/* verilator lint_off INFINITELOOP */" and lint_on around source to disable this message. %Warning-INFINITELOOP: t/t_lint_infinite_bad.v:12:7: Infinite loop (condition always true) - : ... In instance t + : ... note: In instance 't' 12 | for (reg [31:0] i=0; i>=0; i=i+1) begin end | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_modport_dir_bad.out b/test_regress/t/t_lint_modport_dir_bad.out index 976bcd3b1..4931bac79 100644 --- a/test_regress/t/t_lint_modport_dir_bad.out +++ b/test_regress/t/t_lint_modport_dir_bad.out @@ -1,5 +1,5 @@ %Error: t/t_lint_modport_dir_bad.v:26:20: Attempt to drive input-only modport: 'signal' - : ... In instance t.sub + : ... note: In instance 't.sub' 26 | assign dummy_in.signal = signal_i; | ^~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_once_bad.out b/test_regress/t/t_lint_once_bad.out index 2f4ffa38d..d6993b0f7 100644 --- a/test_regress/t/t_lint_once_bad.out +++ b/test_regress/t/t_lint_once_bad.out @@ -1,11 +1,11 @@ %Warning-UNUSEDSIGNAL: t/t_lint_once_bad.v:19:14: Signal is not driven, nor used: 'unus1' - : ... In instance t.sub1 + : ... note: In instance 't.sub1' 19 | reg [A:0] unus1; reg [A:0] unus2; | ^~~~~ ... For warning description see https://verilator.org/warn/UNUSEDSIGNAL?v=latest ... Use "/* verilator lint_off UNUSEDSIGNAL */" and lint_on around source to disable this message. %Warning-UNUSEDSIGNAL: t/t_lint_once_bad.v:19:34: Signal is not driven, nor used: 'unus2' - : ... In instance t.sub1 + : ... note: In instance 't.sub1' 19 | reg [A:0] unus1; reg [A:0] unus2; | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_pragma_protected_bad.out b/test_regress/t/t_lint_pragma_protected_bad.out index a19cc9826..dac9a4676 100644 --- a/test_regress/t/t_lint_pragma_protected_bad.out +++ b/test_regress/t/t_lint_pragma_protected_bad.out @@ -6,7 +6,7 @@ 16 | `pragma protect encrypt_agent_info | ^~~~~~~~~~~~~~~~~~ %Error-BADSTDPRAGMA: t/t_lint_pragma_protected_bad.v:29:1: BASE64 encoding length mismatch in `pragma protect key_bloock/data_block -%Error-BADSTDPRAGMA: t/t_lint_pragma_protected_bad.v:33:17: multiple `pragma protected encoding sections +%Error-BADSTDPRAGMA: t/t_lint_pragma_protected_bad.v:33:17: Multiple `pragma protected encoding sections 33 | `pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 128) | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ %Warning-PROTECTED: t/t_lint_pragma_protected_bad.v:50:17: A '`pragma protected data_block' encrypted section was detected and will be skipped. @@ -38,7 +38,7 @@ %Warning-PROTECTED: t/t_lint_pragma_protected_bad.v:69:17: A '`pragma protected data_block' encrypted section was detected and will be skipped. %Error-BADSTDPRAGMA: t/t_lint_pragma_protected_bad.v:70:1: BASE64 line too long in `pragma protect key_bloock/data_block %Error-BADSTDPRAGMA: t/t_lint_pragma_protected_bad.v:70:1: BASE64 encoding length mismatch in `pragma protect key_bloock/data_block -%Error-BADSTDPRAGMA: t/t_lint_pragma_protected_bad.v:72:17: multiple `pragma protected encoding sections +%Error-BADSTDPRAGMA: t/t_lint_pragma_protected_bad.v:72:17: Multiple `pragma protected encoding sections 72 | `pragma protect encoding = (enctype = "BASE64", line_length = 1, bytes = 4) | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ %Error-BADSTDPRAGMA: t/t_lint_pragma_protected_bad.v:72:17: line_length must be multiple of 4 for BASE64 diff --git a/test_regress/t/t_lint_repeat_bad.out b/test_regress/t/t_lint_repeat_bad.out index de1fa2a99..225cce27b 100644 --- a/test_regress/t/t_lint_repeat_bad.out +++ b/test_regress/t/t_lint_repeat_bad.out @@ -1,5 +1,5 @@ %Warning-WIDTHTRUNC: t/t_lint_repeat_bad.v:18:17: Operator ASSIGNW expects 1 bits on the Assign RHS, but Assign RHS's VARREF 'a' generates 2 bits. - : ... In instance t.sub3 + : ... note: In instance 't.sub3' 18 | wire [0:0] b = a; | ^ ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest diff --git a/test_regress/t/t_lint_restore_bad.out b/test_regress/t/t_lint_restore_bad.out index 3f219f8e6..242414e49 100644 --- a/test_regress/t/t_lint_restore_bad.out +++ b/test_regress/t/t_lint_restore_bad.out @@ -1,5 +1,5 @@ %Warning-WIDTHTRUNC: t/t_lint_restore_bad.v:19:17: Operator ASSIGN expects 5 bits on the Assign RHS, but Assign RHS's CONST '64'h1' generates 64 bits. - : ... In instance t + : ... note: In instance 't' 19 | initial five = 64'h1; | ^ ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest diff --git a/test_regress/t/t_lint_setout_bad.out b/test_regress/t/t_lint_setout_bad.out index 19e21e7d3..143058185 100644 --- a/test_regress/t/t_lint_setout_bad.out +++ b/test_regress/t/t_lint_setout_bad.out @@ -1,5 +1,5 @@ %Error-PORTSHORT: t/t_lint_setout_bad.v:17:8: Output port is connected to a constant pin, electrical short - : ... In instance t + : ... note: In instance 't' 17 | .cpu_if_timeout(1'b0) | ^~~~~~~~~~~~~~ ... For error description see https://verilator.org/warn/PORTSHORT?v=latest diff --git a/test_regress/t/t_lint_setout_bad_noinl.out b/test_regress/t/t_lint_setout_bad_noinl.out index 19e21e7d3..143058185 100644 --- a/test_regress/t/t_lint_setout_bad_noinl.out +++ b/test_regress/t/t_lint_setout_bad_noinl.out @@ -1,5 +1,5 @@ %Error-PORTSHORT: t/t_lint_setout_bad.v:17:8: Output port is connected to a constant pin, electrical short - : ... In instance t + : ... note: In instance 't' 17 | .cpu_if_timeout(1'b0) | ^~~~~~~~~~~~~~ ... For error description see https://verilator.org/warn/PORTSHORT?v=latest diff --git a/test_regress/t/t_lint_stmtdly_bad.out b/test_regress/t/t_lint_stmtdly_bad.out index c91e37476..a028e83e0 100644 --- a/test_regress/t/t_lint_stmtdly_bad.out +++ b/test_regress/t/t_lint_stmtdly_bad.out @@ -1,5 +1,5 @@ %Warning-STMTDLY: t/t_lint_stmtdly_bad.v:10:7: Ignoring delay on this statement due to --no-timing - : ... In instance t + : ... note: In instance 't' 10 | #100 $finish; | ^ ... For warning description see https://verilator.org/warn/STMTDLY?v=latest diff --git a/test_regress/t/t_lint_subout_bad.out b/test_regress/t/t_lint_subout_bad.out index 846d5de89..fe1a91a4d 100644 --- a/test_regress/t/t_lint_subout_bad.out +++ b/test_regress/t/t_lint_subout_bad.out @@ -1,14 +1,14 @@ %Error-PORTSHORT: t/t_lint_subout_bad.v:12:14: Output port is connected to a constant pin, electrical short - : ... In instance t + : ... note: In instance 't' 12 | sub sub1(.out({32'b0, sig})); | ^~~ ... For error description see https://verilator.org/warn/PORTSHORT?v=latest %Error-PORTSHORT: t/t_lint_subout_bad.v:13:14: Output port is connected to a constant pin, electrical short - : ... In instance t + : ... note: In instance 't' 13 | sub sub2(.out({32'b1, sig})); | ^~~ %Error-PORTSHORT: t/t_lint_subout_bad.v:11:14: Output port is connected to a constant pin, electrical short - : ... In instance t + : ... note: In instance 't' 11 | sub sub0(.out(33'b0)); | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_unsigned_bad.out b/test_regress/t/t_lint_unsigned_bad.out index 8f9d385b1..853b31f4f 100644 --- a/test_regress/t/t_lint_unsigned_bad.out +++ b/test_regress/t/t_lint_unsigned_bad.out @@ -1,5 +1,5 @@ %Warning-UNSIGNED: t/t_lint_unsigned_bad.v:13:15: Comparison is constant due to unsigned arithmetic - : ... In instance t + : ... note: In instance 't' 13 | if (uns < 0) $stop; | ^ ... For warning description see https://verilator.org/warn/UNSIGNED?v=latest diff --git a/test_regress/t/t_lint_unused_bad.out b/test_regress/t/t_lint_unused_bad.out index 4c2025413..2632b7a97 100644 --- a/test_regress/t/t_lint_unused_bad.out +++ b/test_regress/t/t_lint_unused_bad.out @@ -1,63 +1,63 @@ %Warning-UNUSEDSIGNAL: t/t_lint_unused_bad.v:17:15: Bits of signal are not used: 'assunu1'[5:1] - : ... In instance t.sub + : ... note: In instance 't.sub' 17 | wire [5:0] assunu1 = 0; | ^~~~~~~ ... For warning description see https://verilator.org/warn/UNUSEDSIGNAL?v=latest ... Use "/* verilator lint_off UNUSEDSIGNAL */" and lint_on around source to disable this message. %Warning-UNDRIVEN: t/t_lint_unused_bad.v:21:17: Bits of signal are not driven: 'udrb2'[14:13,11] - : ... In instance t.sub + : ... note: In instance 't.sub' 21 | wire [15:10] udrb2; | ^~~~~ %Warning-UNUSEDSIGNAL: t/t_lint_unused_bad.v:26:15: Signal is not driven, nor used: 'unu3' - : ... In instance t.sub + : ... note: In instance 't.sub' 26 | wire unu3; | ^~~~ %Warning-UNUSEDSIGNAL: t/t_lint_unused_bad.v:28:15: Bits of signal are not driven, nor used: 'mixed'[3] - : ... In instance t.sub + : ... note: In instance 't.sub' 28 | wire [3:0] mixed; | ^~~~~ %Warning-UNUSEDSIGNAL: t/t_lint_unused_bad.v:28:15: Bits of signal are not used: 'mixed'[2] - : ... In instance t.sub + : ... note: In instance 't.sub' 28 | wire [3:0] mixed; | ^~~~~ %Warning-UNDRIVEN: t/t_lint_unused_bad.v:28:15: Bits of signal are not driven: 'mixed'[1] - : ... In instance t.sub + : ... note: In instance 't.sub' 28 | wire [3:0] mixed; | ^~~~~ %Warning-UNUSEDPARAM: t/t_lint_unused_bad.v:37:14: Parameter is not used: 'UNUSED_P' - : ... In instance t.sub + : ... note: In instance 't.sub' 37 | parameter UNUSED_P = 1; | ^~~~~~~~ %Warning-UNUSEDPARAM: t/t_lint_unused_bad.v:38:15: Parameter is not used: 'UNUSED_LP' - : ... In instance t.sub + : ... note: In instance 't.sub' 38 | localparam UNUSED_LP = 2; | ^~~~~~~~~ %Warning-UNUSEDGENVAR: t/t_lint_unused_bad.v:40:15: Genvar is not used: 'unused_gv' - : ... In instance t.sub + : ... note: In instance 't.sub' 40 | genvar unused_gv; | ^~~~~~~~~ %Warning-UNUSEDPARAM: t/t_lint_unused_bad.v:45:15: Parameter is not used: 'linter_param1' - : ... In instance t.sub + : ... note: In instance 't.sub' 45 | localparam linter_param1 = 1; | ^~~~~~~~~~~~~ %Warning-UNUSEDGENVAR: t/t_lint_unused_bad.v:46:11: Genvar is not used: 'linter_genvar1' - : ... In instance t.sub + : ... note: In instance 't.sub' 46 | genvar linter_genvar1; | ^~~~~~~~~~~~~~ %Warning-UNUSEDSIGNAL: t/t_lint_unused_bad.v:50:9: Signal is not driven, nor used: 'linter_sig2' - : ... In instance t.sub + : ... note: In instance 't.sub' 50 | wire linter_sig2; | ^~~~~~~~~~~ %Warning-UNUSEDGENVAR: t/t_lint_unused_bad.v:52:11: Genvar is not used: 'linter_genvar2' - : ... In instance t.sub + : ... note: In instance 't.sub' 52 | genvar linter_genvar2; | ^~~~~~~~~~~~~~ %Warning-UNUSEDSIGNAL: t/t_lint_unused_bad.v:56:9: Signal is not driven, nor used: 'linter_sig3' - : ... In instance t.sub + : ... note: In instance 't.sub' 56 | wire linter_sig3; | ^~~~~~~~~~~ %Warning-UNUSEDPARAM: t/t_lint_unused_bad.v:57:15: Parameter is not used: 'linter_param3' - : ... In instance t.sub + : ... note: In instance 't.sub' 57 | localparam linter_param3 = 3; | ^~~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_unused_iface_bad.out b/test_regress/t/t_lint_unused_iface_bad.out index ba0a9294e..2f073331d 100644 --- a/test_regress/t/t_lint_unused_iface_bad.out +++ b/test_regress/t/t_lint_unused_iface_bad.out @@ -1,11 +1,11 @@ %Warning-UNDRIVEN: t/t_lint_unused_iface_bad.v:8:10: Signal is not driven: 'sig_udrv' - : ... In instance t.sub + : ... note: In instance 't.sub' 8 | logic sig_udrv; | ^~~~~~~~ ... For warning description see https://verilator.org/warn/UNDRIVEN?v=latest ... Use "/* verilator lint_off UNDRIVEN */" and lint_on around source to disable this message. %Warning-UNUSEDSIGNAL: t/t_lint_unused_iface_bad.v:9:10: Signal is not used: 'sig_uusd' - : ... In instance t.sub + : ... note: In instance 't.sub' 9 | logic sig_uusd; | ^~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_vcmarker_bad.out b/test_regress/t/t_lint_vcmarker_bad.out index 944368358..c086394e3 100644 --- a/test_regress/t/t_lint_vcmarker_bad.out +++ b/test_regress/t/t_lint_vcmarker_bad.out @@ -1,10 +1,10 @@ -%Error: t/t_lint_vcmarker_bad.v:9:1: version control conflict marker in file +%Error: t/t_lint_vcmarker_bad.v:9:1: Version control conflict marker in file 9 | <<<<<<< HEAD | ^~~~~~~~~~~~~~~ -%Error: t/t_lint_vcmarker_bad.v:11:1: version control conflict marker in file +%Error: t/t_lint_vcmarker_bad.v:11:1: Version control conflict marker in file 11 | ======= | ^~~~~~~~~~~ -%Error: t/t_lint_vcmarker_bad.v:13:1: version control conflict marker in file +%Error: t/t_lint_vcmarker_bad.v:13:1: Version control conflict marker in file 13 | >>>>>>> MERGE | ^~~~~~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_width_bad.out b/test_regress/t/t_lint_width_bad.out index dc841f05d..1237949e3 100644 --- a/test_regress/t/t_lint_width_bad.out +++ b/test_regress/t/t_lint_width_bad.out @@ -1,47 +1,47 @@ %Warning-WIDTHTRUNC: t/t_lint_width_bad.v:17:25: Operator VAR 'XS' expects 4 bits on the Initial value, but Initial value's CONST '?32?bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' generates 32 bits. - : ... In instance t + : ... note: In instance 't' 17 | localparam [3:0] XS = 'hx; | ^~ ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. %Warning-WIDTHEXPAND: t/t_lint_width_bad.v:47:19: Operator ASSIGNW expects 5 bits on the Assign RHS, but Assign RHS's VARREF 'in' generates 4 bits. - : ... In instance t.p4 + : ... note: In instance 't.p4' 47 | wire [4:0] out = in; | ^ %Warning-WIDTHEXPAND: t/t_lint_width_bad.v:21:25: Operator SHIFTL expects 5 bits on the LHS, but LHS's CONST '1'h1' generates 1 bits. - : ... In instance t + : ... note: In instance 't' 21 | wire [4:0] d = (1'b1 << 2) + 5'b1; | ^~ %Warning-WIDTHTRUNC: t/t_lint_width_bad.v:27:32: Operator ASSIGNW expects 6 bits on the Assign RHS, but Assign RHS's SHIFTL generates 7 bits. - : ... In instance t + : ... note: In instance 't' 27 | wire [WIDTH-1:0] masked = (({{(WIDTH){1'b0}}, one_bit}) << shifter); | ^ %Warning-WIDTHEXPAND: t/t_lint_width_bad.v:32:37: Operator ADD expects 3 bits on the LHS, but LHS's VARREF 'one' generates 1 bits. - : ... In instance t + : ... note: In instance 't' 32 | wire [2:0] cnt = (one + one + one + one); | ^ %Warning-WIDTHEXPAND: t/t_lint_width_bad.v:32:37: Operator ADD expects 3 bits on the RHS, but RHS's VARREF 'one' generates 1 bits. - : ... In instance t + : ... note: In instance 't' 32 | wire [2:0] cnt = (one + one + one + one); | ^ %Warning-WIDTHEXPAND: t/t_lint_width_bad.v:32:43: Operator ADD expects 3 bits on the RHS, but RHS's VARREF 'one' generates 1 bits. - : ... In instance t + : ... note: In instance 't' 32 | wire [2:0] cnt = (one + one + one + one); | ^ %Warning-WIDTHEXPAND: t/t_lint_width_bad.v:32:49: Operator ADD expects 3 bits on the RHS, but RHS's VARREF 'one' generates 1 bits. - : ... In instance t + : ... note: In instance 't' 32 | wire [2:0] cnt = (one + one + one + one); | ^ %Warning-WIDTHEXPAND: t/t_lint_width_bad.v:37:26: Operator GT expects 41 bits on the LHS, but LHS's VARREF 'a' generates 32 bits. - : ... In instance t + : ... note: In instance 't' 37 | initial for (a = 0; a > THREE; ++a) $display(a); | ^ %Warning-WIDTHEXPAND: t/t_lint_width_bad.v:38:26: Operator GTE expects 41 bits on the LHS, but LHS's VARREF 'a' generates 32 bits. - : ... In instance t + : ... note: In instance 't' 38 | initial for (a = 0; a >= THREE; ++a) $display(a); | ^~ %Warning-WIDTHTRUNC: t/t_lint_width_bad.v:40:12: Logical operator IF expects 1 bit on the If, but If's VARREF 'THREE' generates 41 bits. - : ... In instance t + : ... note: In instance 't' 40 | initial if (THREE) $stop; | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_width_genfor_bad.out b/test_regress/t/t_lint_width_genfor_bad.out index 4e672b104..f3eee67d3 100644 --- a/test_regress/t/t_lint_width_genfor_bad.out +++ b/test_regress/t/t_lint_width_genfor_bad.out @@ -1,23 +1,23 @@ %Warning-WIDTHTRUNC: t/t_lint_width_genfor_bad.v:25:13: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's CONST '?32?sh10' generates 32 or 5 bits. - : ... In instance t + : ... note: In instance 't' 25 | rg = g; | ^ ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. %Warning-WIDTHTRUNC: t/t_lint_width_genfor_bad.v:26:13: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's VARREF 'P' generates 32 or 5 bits. - : ... In instance t + : ... note: In instance 't' 26 | rp = P; | ^ %Warning-WIDTHTRUNC: t/t_lint_width_genfor_bad.v:27:13: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's VARREF 'w' generates 5 bits. - : ... In instance t + : ... note: In instance 't' 27 | rw = w; | ^ %Warning-WIDTHTRUNC: t/t_lint_width_genfor_bad.v:28:13: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's CONST '64'h1' generates 64 bits. - : ... In instance t + : ... note: In instance 't' 28 | rc = 64'h1; | ^ %Warning-WIDTHTRUNC: t/t_lint_width_genfor_bad.v:33:13: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's VARREF 'i' generates 32 bits. - : ... In instance t + : ... note: In instance 't' 33 | ri = i; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_lint_widthexpand_docs_bad.out b/test_regress/t/t_lint_widthexpand_docs_bad.out index 241fa51ce..8af03b587 100644 --- a/test_regress/t/t_lint_widthexpand_docs_bad.out +++ b/test_regress/t/t_lint_widthexpand_docs_bad.out @@ -1,5 +1,5 @@ %Warning-WIDTHEXPAND: t/t_lint_widthexpand_docs_bad.v:10:29: Bit extraction of array[4:0] requires 3 bit index, not 2 bits. - : ... In instance t + : ... note: In instance 't' 10 | wire int rd_value = array[rd_addr]; | ^ ... For warning description see https://verilator.org/warn/WIDTHEXPAND?v=latest diff --git a/test_regress/t/t_mailbox_bad.out b/test_regress/t/t_mailbox_bad.out index 3ef286864..bf7e85b52 100644 --- a/test_regress/t/t_mailbox_bad.out +++ b/test_regress/t/t_mailbox_bad.out @@ -1,5 +1,5 @@ %Error: t/t_mailbox_bad.v:12:13: Class method 'bad_method' not found in class 'mailbox__Tz1' - : ... In instance t + : ... note: In instance 't' 12 | if (m.bad_method() != 0) $stop; | ^~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_math_eq_bad.out b/test_regress/t/t_math_eq_bad.out index d428d8f50..1eaf134bc 100644 --- a/test_regress/t/t_math_eq_bad.out +++ b/test_regress/t/t_math_eq_bad.out @@ -1,5 +1,5 @@ %Error: t/t_math_eq_bad.v:13:13: Real is illegal operand to ?== operator - : ... In instance t + : ... note: In instance 't' 13 | if (a ==? 1.0) $stop; | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_math_repl2_bad.out b/test_regress/t/t_math_repl2_bad.out index 5d3ff0d0d..5e4e76690 100644 --- a/test_regress/t/t_math_repl2_bad.out +++ b/test_regress/t/t_math_repl2_bad.out @@ -1,5 +1,5 @@ %Error: t/t_math_repl2_bad.v:28:30: More than a 16 Mbit replication, perhaps the replication factor was two's-complement negative: 4294967291 - : ... In instance t + : ... note: In instance 't' 28 | out <= {{(P24 - P29){1'b0}}, in}; | ^ %Error: Internal Error: ../V3Number.h:#: `num` member accessed when data type is UNINITIALIZED diff --git a/test_regress/t/t_math_repl_bad.out b/test_regress/t/t_math_repl_bad.out index 34fc9e4f8..d39d2f109 100644 --- a/test_regress/t/t_math_repl_bad.out +++ b/test_regress/t/t_math_repl_bad.out @@ -1,19 +1,19 @@ %Error: t/t_math_repl_bad.v:12:14: Replication value of 0 is only legal under a concatenation (IEEE 1800-2017 11.4.12.1) - : ... In instance t + : ... note: In instance 't' 12 | o = {0 {1'b1}}; | ^ %Warning-WIDTHEXPAND: t/t_math_repl_bad.v:12:9: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's REPLICATE generates 1 bits. - : ... In instance t + : ... note: In instance 't' 12 | o = {0 {1'b1}}; | ^ ... For warning description see https://verilator.org/warn/WIDTHEXPAND?v=latest ... Use "/* verilator lint_off WIDTHEXPAND */" and lint_on around source to disable this message. %Error: t/t_math_repl_bad.v:13:43: Replication value isn't a constant. - : ... In instance t + : ... note: In instance 't' 13 | o = {$test$plusargs("NON-CONSTANT") {1'b1}}; | ^ %Warning-WIDTHEXPAND: t/t_math_repl_bad.v:13:9: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's REPLICATE generates 1 bits. - : ... In instance t + : ... note: In instance 't' 13 | o = {$test$plusargs("NON-CONSTANT") {1'b1}}; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_math_shift_over_bad.out b/test_regress/t/t_math_shift_over_bad.out index b731354e6..09004172d 100644 --- a/test_regress/t/t_math_shift_over_bad.out +++ b/test_regress/t/t_math_shift_over_bad.out @@ -1,5 +1,5 @@ %Error: t/t_math_shift_over_bad.v:19:20: Value too wide for 32-bits expected in this context 64'h123456789abcdef - : ... In instance t + : ... note: In instance 't' 19 | assign o = i << 64'h01234567_89abcdef; | ^~~~~~~~~~~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_mem_multi_ref_bad.out b/test_regress/t/t_mem_multi_ref_bad.out index 8a43b779e..83bce0b5f 100644 --- a/test_regress/t/t_mem_multi_ref_bad.out +++ b/test_regress/t/t_mem_multi_ref_bad.out @@ -1,39 +1,39 @@ %Error: t/t_mem_multi_ref_bad.v:15:11: Illegal bit or array select; type does not have a bit range, or bad dimension: data type is 'logic' - : ... In instance t + : ... note: In instance 't' 15 | dimn[1:0] = 0; | ^ %Warning-SELRANGE: t/t_mem_multi_ref_bad.v:15:11: Extracting 2 bits from only 1 bit number - : ... In instance t + : ... note: In instance 't' 15 | dimn[1:0] = 0; | ^ ... For warning description see https://verilator.org/warn/SELRANGE?v=latest ... Use "/* verilator lint_off SELRANGE */" and lint_on around source to disable this message. %Error: t/t_mem_multi_ref_bad.v:16:14: Illegal bit or array select; type does not have a bit range, or bad dimension: data type is 'logic' - : ... In instance t + : ... note: In instance 't' 16 | dim0[1][1] = 0; | ^ %Warning-SELRANGE: t/t_mem_multi_ref_bad.v:16:14: Selection index out of range: 1:1 outside 0:0 - : ... In instance t + : ... note: In instance 't' 16 | dim0[1][1] = 0; | ^ %Error: t/t_mem_multi_ref_bad.v:17:17: Illegal bit or array select; type does not have a bit range, or bad dimension: data type is 'logic' - : ... In instance t + : ... note: In instance 't' 17 | dim1[1][1][1] = 0; | ^ %Warning-SELRANGE: t/t_mem_multi_ref_bad.v:17:17: Selection index out of range: 1:1 outside 0:0 - : ... In instance t + : ... note: In instance 't' 17 | dim1[1][1][1] = 0; | ^ %Warning-SELRANGE: t/t_mem_multi_ref_bad.v:19:19: Selection index out of range: 1 outside 0:0 - : ... In instance t + : ... note: In instance 't' 19 | dim2[0 +: 1][1] = 0; | ^ %Error: t/t_mem_multi_ref_bad.v:23:16: Illegal bit or array select; type does not have a bit range, or bad dimension: data type is 'logic' - : ... In instance t + : ... note: In instance 't' 23 | dim0nv[1][1] = 0; | ^ %Warning-SELRANGE: t/t_mem_multi_ref_bad.v:23:16: Selection index out of range: 1:1 outside 0:0 - : ... In instance t + : ... note: In instance 't' 23 | dim0nv[1][1] = 0; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_mem_slice_bad.out b/test_regress/t/t_mem_slice_bad.out index 35f165b59..b8ee9429c 100644 --- a/test_regress/t/t_mem_slice_bad.out +++ b/test_regress/t/t_mem_slice_bad.out @@ -1,25 +1,25 @@ %Error: t/t_mem_slice_bad.v:39:31: Slice selection index '[2:0]' outside data type's '[1:0]' - : ... In instance t + : ... note: In instance 't' 39 | assign active_command3[1:0][2:0][3:0] = (use_AnB) ? command_A3[1:0][2:0][3:0] : command_B3[1:0][1:0][3:0]; | ^ %Error: t/t_mem_slice_bad.v:39:36: Slice selection index '[3:0]' outside data type's '[2:0]' - : ... In instance t + : ... note: In instance 't' 39 | assign active_command3[1:0][2:0][3:0] = (use_AnB) ? command_A3[1:0][2:0][3:0] : command_B3[1:0][1:0][3:0]; | ^ %Error: t/t_mem_slice_bad.v:39:72: Slice selection index '[2:0]' outside data type's '[1:0]' - : ... In instance t + : ... note: In instance 't' 39 | assign active_command3[1:0][2:0][3:0] = (use_AnB) ? command_A3[1:0][2:0][3:0] : command_B3[1:0][1:0][3:0]; | ^ %Error: t/t_mem_slice_bad.v:39:77: Slice selection index '[3:0]' outside data type's '[2:0]' - : ... In instance t + : ... note: In instance 't' 39 | assign active_command3[1:0][2:0][3:0] = (use_AnB) ? command_A3[1:0][2:0][3:0] : command_B3[1:0][1:0][3:0]; | ^ %Error: t/t_mem_slice_bad.v:39:105: Slice selection index '[3:0]' outside data type's '[1:0]' - : ... In instance t + : ... note: In instance 't' 39 | assign active_command3[1:0][2:0][3:0] = (use_AnB) ? command_A3[1:0][2:0][3:0] : command_B3[1:0][1:0][3:0]; | ^ %Error: t/t_mem_slice_bad.v:51:41: Slice selection index '[8:0]' outside data type's '[7:0]' - : ... In instance t + : ... note: In instance 't' 51 | active_command4[7:0] <= command_A4[8:0]; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_metacmt_onoff.out b/test_regress/t/t_metacmt_onoff.out index 7b912780c..1c8f60b7c 100644 --- a/test_regress/t/t_metacmt_onoff.out +++ b/test_regress/t/t_metacmt_onoff.out @@ -1,11 +1,11 @@ %Warning-ASCRANGE: t/t_metacmt_onoff.v:8:8: Ascending bit range vector: left < right of bit range: [0:1] - : ... In instance t + : ... note: In instance 't' 8 | reg [0:1] show1; /*verilator lint_off ASCRANGE*/ reg [0:2] ign2; /*verilator lint_on ASCRANGE*/ reg [0:3] show3; | ^ ... For warning description see https://verilator.org/warn/ASCRANGE?v=latest ... Use "/* verilator lint_off ASCRANGE */" and lint_on around source to disable this message. %Warning-ASCRANGE: t/t_metacmt_onoff.v:8:107: Ascending bit range vector: left < right of bit range: [0:3] - : ... In instance t + : ... note: In instance 't' 8 | reg [0:1] show1; /*verilator lint_off ASCRANGE*/ reg [0:2] ign2; /*verilator lint_on ASCRANGE*/ reg [0:3] show3; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_net_delay.out b/test_regress/t/t_net_delay.out index d812684ed..be7a665b1 100644 --- a/test_regress/t/t_net_delay.out +++ b/test_regress/t/t_net_delay.out @@ -1,15 +1,15 @@ %Warning-STMTDLY: t/t_net_delay.v:15:14: Ignoring delay on this statement due to --no-timing - : ... In instance t + : ... note: In instance 't' 15 | wire[3:0] #4 val1 = half_cyc; | ^ ... For warning description see https://verilator.org/warn/STMTDLY?v=latest ... Use "/* verilator lint_off STMTDLY */" and lint_on around source to disable this message. %Warning-STMTDLY: t/t_net_delay.v:16:14: Ignoring delay on this statement due to --no-timing - : ... In instance t + : ... note: In instance 't' 16 | wire[3:0] #4 val2; | ^ %Warning-ASSIGNDLY: t/t_net_delay.v:19:11: Ignoring timing control on this assignment/primitive due to --no-timing - : ... In instance t + : ... note: In instance 't' 19 | assign #4 val2 = half_cyc; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_notiming.out b/test_regress/t/t_notiming.out index e12212acd..3819b82b6 100644 --- a/test_regress/t/t_notiming.out +++ b/test_regress/t/t_notiming.out @@ -1,49 +1,49 @@ %Warning-STMTDLY: t/t_notiming.v:12:8: Ignoring delay on this statement due to --no-timing - : ... In instance t + : ... note: In instance 't' 12 | #1 | ^ ... For warning description see https://verilator.org/warn/STMTDLY?v=latest ... Use "/* verilator lint_off STMTDLY */" and lint_on around source to disable this message. %Error-NOTIMING: t/t_notiming.v:13:8: Fork statements require --timing - : ... In instance t + : ... note: In instance 't' 13 | fork @e; @e; join; | ^~~~ %Error-NOTIMING: t/t_notiming.v:14:8: Event control statement in this location requires --timing - : ... In instance t + : ... note: In instance 't' : ... With --no-timing, suggest have one event control statement per procedure, at the top of the procedure 14 | @e | ^ %Error-NOTIMING: t/t_notiming.v:15:8: Wait statements require --timing - : ... In instance t + : ... note: In instance 't' 15 | wait(x == 4) | ^~~~ %Error-NOTIMING: t/t_notiming.v:19:8: Event control statement in this location requires --timing - : ... In instance t + : ... note: In instance 't' : ... With --no-timing, suggest have one event control statement per procedure, at the top of the procedure 19 | @e | ^ %Warning-STMTDLY: t/t_notiming.v:26:12: Ignoring delay on this statement due to --no-timing - : ... In instance t + : ... note: In instance 't' 26 | initial #1 ->e; | ^ %Warning-STMTDLY: t/t_notiming.v:27:12: Ignoring delay on this statement due to --no-timing - : ... In instance t + : ... note: In instance 't' 27 | initial #2 $stop; | ^ %Error-NOTIMING: t/t_notiming.v:33:10: mailbox::put() requires --timing - : ... In instance t + : ... note: In instance 't' 33 | m.put(i); | ^~~ %Error-NOTIMING: t/t_notiming.v:34:10: mailbox::get() requires --timing - : ... In instance t + : ... note: In instance 't' 34 | m.get(i); | ^~~ %Error-NOTIMING: t/t_notiming.v:35:10: mailbox::peek() requires --timing - : ... In instance t + : ... note: In instance 't' 35 | m.peek(i); | ^~~~ %Error-NOTIMING: t/t_notiming.v:36:10: semaphore::get() requires --timing - : ... In instance t + : ... note: In instance 't' 36 | s.get(); | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_notiming_off.out b/test_regress/t/t_notiming_off.out index 72c86fd65..78ba91da6 100644 --- a/test_regress/t/t_notiming_off.out +++ b/test_regress/t/t_notiming_off.out @@ -1,29 +1,29 @@ %Error-NOTIMING: t/t_timing_off.v:25:8: Event control statement in this location requires --timing - : ... In instance t + : ... note: In instance 't' : ... With --no-timing, suggest have one event control statement per procedure, at the top of the procedure 25 | @e1; | ^ ... For error description see https://verilator.org/warn/NOTIMING?v=latest %Warning-STMTDLY: t/t_timing_off.v:33:12: Ignoring delay on this statement due to --no-timing - : ... In instance t + : ... note: In instance 't' 33 | initial #2 ->e1; | ^ ... Use "/* verilator lint_off STMTDLY */" and lint_on around source to disable this message. %Warning-STMTDLY: t/t_timing_off.v:37:12: Ignoring delay on this statement due to --no-timing - : ... In instance t + : ... note: In instance 't' 37 | initial #3 $stop; | ^ %Warning-STMTDLY: t/t_timing_off.v:38:12: Ignoring delay on this statement due to --no-timing - : ... In instance t + : ... note: In instance 't' 38 | initial #1 @(e1, e2) #1 $stop; | ^ %Error-NOTIMING: t/t_timing_off.v:38:15: Event control statement in this location requires --timing - : ... In instance t + : ... note: In instance 't' : ... With --no-timing, suggest have one event control statement per procedure, at the top of the procedure 38 | initial #1 @(e1, e2) #1 $stop; | ^ %Warning-STMTDLY: t/t_timing_off.v:38:25: Ignoring delay on this statement due to --no-timing - : ... In instance t + : ... note: In instance 't' 38 | initial #1 @(e1, e2) #1 $stop; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_packed_concat_bad.out b/test_regress/t/t_packed_concat_bad.out index 559a8c1ca..c508f1635 100644 --- a/test_regress/t/t_packed_concat_bad.out +++ b/test_regress/t/t_packed_concat_bad.out @@ -1,15 +1,15 @@ %Warning-WIDTHCONCAT: t/t_packed_concat_bad.v:17:47: Unsized numbers/parameters not allowed in replications. - : ... In instance t + : ... note: In instance 't' 17 | localparam bit_int_t [1:0] count_bits = {2{$bits(count_t)}}; | ^~~~~ ... For warning description see https://verilator.org/warn/WIDTHCONCAT?v=latest ... Use "/* verilator lint_off WIDTHCONCAT */" and lint_on around source to disable this message. %Warning-WIDTHCONCAT: t/t_packed_concat_bad.v:18:46: Unsized numbers/parameters not allowed in concatenations. - : ... In instance t + : ... note: In instance 't' 18 | localparam bit_int_t [1:0] count_bitsc = {$bits(count_t), $bits(count_t)}; | ^~~~~ %Warning-WIDTHCONCAT: t/t_packed_concat_bad.v:18:60: Unsized numbers/parameters not allowed in replications. - : ... In instance t + : ... note: In instance 't' 18 | localparam bit_int_t [1:0] count_bitsc = {$bits(count_t), $bits(count_t)}; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_param_circ_bad.out b/test_regress/t/t_param_circ_bad.out index ce70ca9d9..bc052c47e 100644 --- a/test_regress/t/t_param_circ_bad.out +++ b/test_regress/t/t_param_circ_bad.out @@ -1,5 +1,5 @@ %Error: t/t_param_circ_bad.v:11:43: Variable's initial value is circular: 'X' - : ... In instance t.sub + : ... note: In instance 't.sub' 11 | module sub #(parameter WIDTH=X, parameter X=WIDTH) | ^ %Error: Exiting due to diff --git a/test_regress/t/t_param_concat_bad.out b/test_regress/t/t_param_concat_bad.out index 008022682..87b78c550 100644 --- a/test_regress/t/t_param_concat_bad.out +++ b/test_regress/t/t_param_concat_bad.out @@ -1,15 +1,15 @@ %Warning-WIDTHCONCAT: t/t_param_concat.v:19:15: Unsized numbers/parameters not allowed in concatenations. - : ... In instance t + : ... note: In instance 't' 19 | if ({UNSIZED,UNSIZED+1} != {32'd10, 32'd11}) $stop; | ^~~~~~~ ... For warning description see https://verilator.org/warn/WIDTHCONCAT?v=latest ... Use "/* verilator lint_off WIDTHCONCAT */" and lint_on around source to disable this message. %Warning-WIDTHCONCAT: t/t_param_concat.v:19:22: Unsized numbers/parameters not allowed in replications. - : ... In instance t + : ... note: In instance 't' 19 | if ({UNSIZED,UNSIZED+1} != {32'd10, 32'd11}) $stop; | ^ %Warning-WIDTHCONCAT: t/t_param_concat.v:20:17: Unsized numbers/parameters not allowed in replications. - : ... In instance t + : ... note: In instance 't' 20 | if ({2{UNSIZED}} != {32'd10, 32'd10}) $stop; | ^~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_param_default_bad.out b/test_regress/t/t_param_default_bad.out index 630da39db..a31068bf2 100644 --- a/test_regress/t/t_param_default_bad.out +++ b/test_regress/t/t_param_default_bad.out @@ -1,5 +1,5 @@ %Error: t/t_param_default_bad.v:7:26: Parameter without initial value is never given value (IEEE 1800-2017 6.20.1): 'Foo' - : ... In instance t.foo + : ... note: In instance 't.foo' 7 | module m #(parameter int Foo); | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_param_default_presv_bad.out b/test_regress/t/t_param_default_presv_bad.out index 1e86bff74..eba93507a 100644 --- a/test_regress/t/t_param_default_presv_bad.out +++ b/test_regress/t/t_param_default_presv_bad.out @@ -4,7 +4,7 @@ ... For warning description see https://verilator.org/warn/NEWERSTD?v=latest ... Use "/* verilator lint_off NEWERSTD */" and lint_on around source to disable this message. %Error: t/t_param_default_bad.v:7:26: Parameter without initial value is never given value (IEEE 1800-2017 6.20.1): 'Foo' - : ... In instance t.foo + : ... note: In instance 't.foo' 7 | module m #(parameter int Foo); | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_param_noval_bad.out b/test_regress/t/t_param_noval_bad.out index ff5b9a48f..31ce3ad64 100644 --- a/test_regress/t/t_param_noval_bad.out +++ b/test_regress/t/t_param_noval_bad.out @@ -1,30 +1,30 @@ %Error: t/t_param_noval_bad.v:7:22: Parameter without initial value is never given value (IEEE 1800-2017 6.20.1): 'P' - : ... In instance t + : ... note: In instance 't' 7 | module t #(parameter P); | ^ %Warning-WIDTHTRUNC: t/t_param_noval_bad.v:10:7: Logical operator GENFOR expects 1 bit on the For Test Condition, but For Test Condition's VARREF 'P' generates 32 bits. - : ... In instance t + : ... note: In instance 't' 10 | for (j=0; P; j++) | ^~~ ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. %Error: t/t_param_noval_bad.v:10:7: Non-genvar used in generate for: 'j' - : ... In instance t + : ... note: In instance 't' 10 | for (j=0; P; j++) | ^~~ %Error: t/t_param_noval_bad.v:10:7: Loop unrolling failed. - : ... In instance t + : ... note: In instance 't' 10 | for (j=0; P; j++) | ^~~ %Error-UNSUPPORTED: t/t_param_noval_bad.v:10:7: Unsupported: Can't unroll generate for; Unable to unroll loop - : ... In instance t + : ... note: In instance 't' 10 | for (j=0; P; j++) | ^~~ %Error: t/t_param_noval_bad.v:10:7: For loop doesn't have genvar index, or is malformed - : ... In instance t + : ... note: In instance 't' 10 | for (j=0; P; j++) | ^~~ %Error: Internal Error: t/t_param_noval_bad.v:10:7: ../V3Param.cpp:#: GENFOR should have been wrapped in BEGIN - : ... In instance t + : ... note: In instance 't' 10 | for (j=0; P; j++) | ^~~ diff --git a/test_regress/t/t_param_sel_range_bad.out b/test_regress/t/t_param_sel_range_bad.out index 9316728ba..64fa2b82f 100644 --- a/test_regress/t/t_param_sel_range_bad.out +++ b/test_regress/t/t_param_sel_range_bad.out @@ -1,5 +1,5 @@ %Warning-SELRANGE: t/t_param_sel_range.v:43:35: Selection index out of range: 7:7 outside 4:0 - : ... In instance t.u2 + : ... note: In instance 't.u2' 43 | r_rst[i] <= r_rst[i-1]; | ^ ... For warning description see https://verilator.org/warn/SELRANGE?v=latest diff --git a/test_regress/t/t_param_type_bad2.out b/test_regress/t/t_param_type_bad2.out index 9d199c249..b1b6448c7 100644 --- a/test_regress/t/t_param_type_bad2.out +++ b/test_regress/t/t_param_type_bad2.out @@ -1,9 +1,9 @@ %Error: t/t_param_type_bad2.v:8:19: Operator VAR 't' expected non-datatype Initial value but 'logic' is a datatype. - : ... In instance t + : ... note: In instance 't' 8 | localparam t = logic; | ^~~~~ %Error: t/t_param_type_bad2.v:9:20: Operator VAR 't2' expected non-datatype Initial value but 'real' is a datatype. - : ... In instance t + : ... note: In instance 't' 9 | localparam t2 = realtime; | ^~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_param_width_loc_bad.out b/test_regress/t/t_param_width_loc_bad.out index 3905343e9..985c3ddca 100644 --- a/test_regress/t/t_param_width_loc_bad.out +++ b/test_regress/t/t_param_width_loc_bad.out @@ -1,5 +1,5 @@ %Warning-WIDTHTRUNC: t/t_param_width_loc_bad.v:25:21: Operator VAR 'param' expects 1 bits on the Initial value, but Initial value's CONST '32'h0' generates 32 bits. - : ... In instance t.test_i + : ... note: In instance 't.test_i' 25 | parameter logic param = 1'b0 | ^~~~~ ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest diff --git a/test_regress/t/t_past_bad.out b/test_regress/t/t_past_bad.out index f1e1ea1b8..69a981f05 100644 --- a/test_regress/t/t_past_bad.out +++ b/test_regress/t/t_past_bad.out @@ -1,17 +1,17 @@ %Error: t/t_past_bad.v:16:20: Expecting expression to be constant, but variable isn't const: 'num' - : ... In instance t + : ... note: In instance 't' 16 | if ($past(d, num)) $stop; | ^~~ %Error: t/t_past_bad.v:16:11: $past tick value must be constant (IEEE 1800-2017 16.9.3) - : ... In instance t + : ... note: In instance 't' 16 | if ($past(d, num)) $stop; | ^~~~~ %Error: t/t_past_bad.v:17:20: $past tick value must be >= 1 (IEEE 1800-2017 16.9.3) - : ... In instance t + : ... note: In instance 't' 17 | if ($past(d, 0)) $stop; | ^ %Warning-TICKCOUNT: t/t_past_bad.v:18:20: $past tick value of 10000 may have a large performance cost - : ... In instance t + : ... note: In instance 't' 18 | if ($past(d, 10000)) $stop; | ^~~~~ ... For warning description see https://verilator.org/warn/TICKCOUNT?v=latest diff --git a/test_regress/t/t_pp_line_bad.out b/test_regress/t/t_pp_line_bad.out index 15958d5ff..062cbf6af 100644 --- a/test_regress/t/t_pp_line_bad.out +++ b/test_regress/t/t_pp_line_bad.out @@ -9,5 +9,5 @@ 7 | `line | ^~~~~ %Error: somefile:100:1: `line was not properly formed with '`line number "filename" level' - t/t_pp_line_bad.v:101:1: ... note: In file included from t_pp_line_bad.v + t/t_pp_line_bad.v:101:1: ... note: In file included from 't_pp_line_bad.v' %Error: Exiting due to diff --git a/test_regress/t/t_preproc_inc_bad.out b/test_regress/t/t_preproc_inc_bad.out index b03e7f868..006f0ec09 100644 --- a/test_regress/t/t_preproc_inc_bad.out +++ b/test_regress/t/t_preproc_inc_bad.out @@ -1,5 +1,5 @@ %Error: t/t_preproc_inc_inc_bad.vh:11:1: syntax error, unexpected endmodule, expecting IDENTIFIER or randomize 11 | endmodule | ^~~~~~~~~ - t/t_preproc_inc_bad.v:10:1: ... note: In file included from t_preproc_inc_bad.v + t/t_preproc_inc_bad.v:10:1: ... note: In file included from 't_preproc_inc_bad.v' %Error: Exiting due to diff --git a/test_regress/t/t_process_bad.out b/test_regress/t/t_process_bad.out index 0c696d1d4..0665a79e0 100644 --- a/test_regress/t/t_process_bad.out +++ b/test_regress/t/t_process_bad.out @@ -1,9 +1,9 @@ %Error: t/t_process_bad.v:13:13: Class method 'bad_method' not found in class 'process' - : ... In instance t + : ... note: In instance 't' 13 | if (p.bad_method() != 0) $stop; | ^~~~~~~~~~ %Error: t/t_process_bad.v:15:9: Class method 'bad_method_2' not found in class 'process' - : ... In instance t + : ... note: In instance 't' 15 | p.bad_method_2(); | ^~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_process_notiming.out b/test_regress/t/t_process_notiming.out index 833040f13..b3934ae0b 100644 --- a/test_regress/t/t_process_notiming.out +++ b/test_regress/t/t_process_notiming.out @@ -1,54 +1,54 @@ %Error-NOTIMING: t/t_process.v:26:20: process::self() requires --timing - : ... In instance t + : ... note: In instance 't' 26 | p = process::self(); | ^~~~ ... For error description see https://verilator.org/warn/NOTIMING?v=latest %Error-NOTIMING: t/t_process.v:27:13: process::status() requires --timing - : ... In instance t + : ... note: In instance 't' 27 | if (p.status() != process::RUNNING) $stop; | ^~~~~~ %Error-NOTIMING: t/t_process.v:28:13: process::status() requires --timing - : ... In instance t + : ... note: In instance 't' 28 | if (p.status() == process::WAITING) $stop; | ^~~~~~ %Error-NOTIMING: t/t_process.v:29:13: process::status() requires --timing - : ... In instance t + : ... note: In instance 't' 29 | if (p.status() == process::SUSPENDED) $stop; | ^~~~~~ %Error-NOTIMING: t/t_process.v:30:13: process::status() requires --timing - : ... In instance t + : ... note: In instance 't' 30 | if (p.status() == process::KILLED) $stop; | ^~~~~~ %Error-NOTIMING: t/t_process.v:31:13: process::status() requires --timing - : ... In instance t + : ... note: In instance 't' 31 | if (p.status() == process::FINISHED) $stop; | ^~~~~~ %Error-NOTIMING: t/t_process.v:33:16: process::kill() requires --timing - : ... In instance t + : ... note: In instance 't' 33 | if (0) p.kill(); | ^~~~ %Error-NOTIMING: t/t_process.v:34:16: process::await() requires --timing - : ... In instance t + : ... note: In instance 't' 34 | if (0) p.await(); | ^~~~~ %Error-NOTIMING: t/t_process.v:35:16: process::suspend() requires --timing - : ... In instance t + : ... note: In instance 't' 35 | if (0) p.suspend(); | ^~~~~~~ %Error-NOTIMING: t/t_process.v:36:16: process::resume() requires --timing - : ... In instance t + : ... note: In instance 't' 36 | if (0) p.resume(); | ^~~~~~ %Error-NOTIMING: t/t_process.v:38:9: process::srandom() requires --timing - : ... In instance t + : ... note: In instance 't' 38 | p.srandom(0); | ^~~~~~~ %Error-NOTIMING: t/t_process.v:39:25: process::get_randstate() requires --timing - : ... In instance t + : ... note: In instance 't' 39 | p.set_randstate(p.get_randstate()); | ^~~~~~~~~~~~~ %Error-NOTIMING: t/t_process.v:39:9: process::set_randstate() requires --timing - : ... In instance t + : ... note: In instance 't' 39 | p.set_randstate(p.get_randstate()); | ^~~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_queue_empty_bad.out b/test_regress/t/t_queue_empty_bad.out index a9762673b..c8fe1528e 100644 --- a/test_regress/t/t_queue_empty_bad.out +++ b/test_regress/t/t_queue_empty_bad.out @@ -1,10 +1,10 @@ %Error-UNSUPPORTED: t/t_queue_empty_bad.v:11:11: Unsupported/Illegal: empty queue ('{}') in this context - : ... In instance t + : ... note: In instance 't' 11 | i = {} + 1; | ^ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error-UNSUPPORTED: t/t_queue_empty_bad.v:13:9: Unsupported/Illegal: empty queue ('{}') in this assign context - : ... In instance t + : ... note: In instance 't' 13 | i = {}; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_queue_method3_bad.out b/test_regress/t/t_queue_method3_bad.out index 4beb3e580..ca32b617d 100644 --- a/test_regress/t/t_queue_method3_bad.out +++ b/test_regress/t/t_queue_method3_bad.out @@ -1,10 +1,10 @@ %Error-UNSUPPORTED: t/t_queue_method3_bad.v:16:52: Unsupported: Member call on object 'SEL' which is a 'BASICDTYPE 'int'' - : ... In instance t + : ... note: In instance 't' 16 | points_qv = points_q.find_first(a) with (a.x.index == 0); | ^~~~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error: Internal Error: t/t_queue_method3_bad.v:16:58: ../V3Width.cpp:#: Node has no type - : ... In instance t + : ... note: In instance 't' 16 | points_qv = points_q.find_first(a) with (a.x.index == 0); | ^~ ... See the manual at https://verilator.org/verilator_doc.html for more assistance. diff --git a/test_regress/t/t_queue_method_bad.out b/test_regress/t/t_queue_method_bad.out index 64de372f9..db03af9f0 100644 --- a/test_regress/t/t_queue_method_bad.out +++ b/test_regress/t/t_queue_method_bad.out @@ -1,37 +1,37 @@ %Error: t/t_queue_method_bad.v:15:9: The 1 arguments passed to .reverse method does not match its requiring 0 arguments - : ... In instance t + : ... note: In instance 't' 15 | q.reverse(1); | ^~~~~~~ %Error: t/t_queue_method_bad.v:16:9: The 1 arguments passed to .shuffle method does not match its requiring 0 arguments - : ... In instance t + : ... note: In instance 't' 16 | q.shuffle(1); | ^~~~~~~ %Error: t/t_queue_method_bad.v:17:14: 'with' statement is required for .find method - : ... In instance t + : ... note: In instance 't' 17 | qv = q.find; | ^~~~ %Error: t/t_queue_method_bad.v:18:14: 'with' statement is required for .find_first method - : ... In instance t + : ... note: In instance 't' 18 | qv = q.find_first; | ^~~~~~~~~~ %Error: t/t_queue_method_bad.v:19:14: 'with' statement is required for .find_last method - : ... In instance t + : ... note: In instance 't' 19 | qv = q.find_last; | ^~~~~~~~~ %Error: t/t_queue_method_bad.v:20:14: 'with' statement is required for .find_index method - : ... In instance t + : ... note: In instance 't' 20 | qi = q.find_index; | ^~~~~~~~~~ %Error: t/t_queue_method_bad.v:21:14: 'with' statement is required for .find_first_index method - : ... In instance t + : ... note: In instance 't' 21 | qi = q.find_first_index; | ^~~~~~~~~~~~~~~~ %Error: t/t_queue_method_bad.v:22:14: 'with' statement is required for .find_last_index method - : ... In instance t + : ... note: In instance 't' 22 | qi = q.find_last_index; | ^~~~~~~~~~~~~~~ %Error: t/t_queue_method_bad.v:24:19: 'with' not legal on this method - : ... In instance t + : ... note: In instance 't' 24 | qi = q.size with (1); | ^~~~ %Error: Exiting due to diff --git a/test_regress/t/t_randc_oversize_bad.out b/test_regress/t/t_randc_oversize_bad.out index 61f0030e3..6eaf0eefe 100644 --- a/test_regress/t/t_randc_oversize_bad.out +++ b/test_regress/t/t_randc_oversize_bad.out @@ -1,5 +1,5 @@ %Error: t/t_randc_oversize_bad.v:8:21: Maxiumum implemented width for randc is 32 bits, 'i' is 38 bits - : ... In instance t + : ... note: In instance 't' 8 | randc bit [37:0] i; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_randomize_method_types_unsup.out b/test_regress/t/t_randomize_method_types_unsup.out index 331acdcd8..d75313662 100644 --- a/test_regress/t/t_randomize_method_types_unsup.out +++ b/test_regress/t/t_randomize_method_types_unsup.out @@ -1,22 +1,22 @@ %Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:12:13: Unsupported: random member variable with type 'int[string]' - : ... In instance t + : ... note: In instance 't' 12 | rand int assocarr[string]; | ^~~~~~~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:13:13: Unsupported: random member variable with type 'int[]' - : ... In instance t + : ... note: In instance 't' 13 | rand int dynarr[]; | ^~~~~~ %Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:14:13: Unsupported: random member variable with type 'int$[0:4]' - : ... In instance t + : ... note: In instance 't' 14 | rand int unpackarr[5]; | ^~~~~~~~~ %Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:15:15: Unsupported: random member variable with type '$unit::Union' - : ... In instance t + : ... note: In instance 't' 15 | rand Union uni; | ^~~ %Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:16:13: Unsupported: random member variable with type of a current class - : ... In instance t + : ... note: In instance 't' 16 | rand Cls cls; | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_randstate_obj.out b/test_regress/t/t_randstate_obj.out index 74f858877..62595c9e5 100644 --- a/test_regress/t/t_randstate_obj.out +++ b/test_regress/t/t_randstate_obj.out @@ -1,10 +1,10 @@ %Error-UNSUPPORTED: t/t_randstate_obj.v:20:13: Unsupported: 'get_randstate'/'set_randstate' called on object. Suggest call from inside class. - : ... In instance t + : ... note: In instance 't' 20 | s = c.get_randstate(); | ^~~~~~~~~~~~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error-UNSUPPORTED: t/t_randstate_obj.v:26:9: Unsupported: 'get_randstate'/'set_randstate' called on object. Suggest call from inside class. - : ... In instance t + : ... note: In instance 't' 26 | c.set_randstate(s); | ^~~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_sampled_expr_unsup.out b/test_regress/t/t_sampled_expr_unsup.out index 8a8a1634d..f6b05c074 100644 --- a/test_regress/t/t_sampled_expr_unsup.out +++ b/test_regress/t/t_sampled_expr_unsup.out @@ -1,5 +1,5 @@ %Error-UNSUPPORTED: t/t_sampled_expr_unsup.v:20:38: Unsupported: Write to variable in sampled expression - : ... In instance t + : ... note: In instance 't' 20 | assert property (@(posedge clk) f(a) >= 0); | ^ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest diff --git a/test_regress/t/t_select_bad_msb.out b/test_regress/t/t_select_bad_msb.out index 84e30c325..aa46cf502 100644 --- a/test_regress/t/t_select_bad_msb.out +++ b/test_regress/t/t_select_bad_msb.out @@ -1,11 +1,11 @@ %Warning-ASCRANGE: t/t_select_bad_msb.v:12:8: Ascending bit range vector: left < right of bit range: [0:22] - : ... In instance t + : ... note: In instance 't' 12 | reg [0:22] backwd; | ^ ... For warning description see https://verilator.org/warn/ASCRANGE?v=latest ... Use "/* verilator lint_off ASCRANGE */" and lint_on around source to disable this message. %Warning-SELRANGE: t/t_select_bad_msb.v:16:16: [1:4] Slice range has ascending bit ordering, perhaps you wanted [4:1] - : ... In instance t + : ... note: In instance 't' 16 | sel2 = mi[1:4]; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_select_bad_range.out b/test_regress/t/t_select_bad_range.out index c0b031982..19205ca10 100644 --- a/test_regress/t/t_select_bad_range.out +++ b/test_regress/t/t_select_bad_range.out @@ -1,11 +1,11 @@ %Warning-SELRANGE: t/t_select_bad_range.v:16:15: Selection index out of range: 44:44 outside 43:0 - : ... In instance t + : ... note: In instance 't' 16 | sel = mi[44]; | ^ ... For warning description see https://verilator.org/warn/SELRANGE?v=latest ... Use "/* verilator lint_off SELRANGE */" and lint_on around source to disable this message. %Warning-SELRANGE: t/t_select_bad_range.v:17:16: Selection index out of range: 44:41 outside 43:0 - : ... In instance t + : ... note: In instance 't' 17 | sel2 = mi[44:41]; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_select_bad_range2.out b/test_regress/t/t_select_bad_range2.out index f648d7c2b..428fc9aed 100644 --- a/test_regress/t/t_select_bad_range2.out +++ b/test_regress/t/t_select_bad_range2.out @@ -1,5 +1,5 @@ %Warning-SELRANGE: t/t_select_bad_range2.v:51:21: Selection index out of range: 3:2 outside 1:0 - : ... In instance t.test + : ... note: In instance 't.test' 51 | assign out32 = in[3:2]; | ^ ... For warning description see https://verilator.org/warn/SELRANGE?v=latest diff --git a/test_regress/t/t_select_bad_range3.out b/test_regress/t/t_select_bad_range3.out index fa19b0512..612b981a8 100644 --- a/test_regress/t/t_select_bad_range3.out +++ b/test_regress/t/t_select_bad_range3.out @@ -1,5 +1,5 @@ %Warning-SELRANGE: t/t_select_bad_range3.v:19:33: Selection index out of range: 13 outside 12:10 - : ... In instance t + : ... note: In instance 't' 19 | assign outwires[12] = inwires[13]; | ^ ... For warning description see https://verilator.org/warn/SELRANGE?v=latest diff --git a/test_regress/t/t_select_bad_range4.out b/test_regress/t/t_select_bad_range4.out index 6646fc383..395b1bee4 100644 --- a/test_regress/t/t_select_bad_range4.out +++ b/test_regress/t/t_select_bad_range4.out @@ -1,79 +1,79 @@ %Error: t/t_select_bad_range4.v:17:8: Width of bit range is huge; vector of over 1 billion bits: 0x20000001 - : ... In instance t + : ... note: In instance 't' 17 | reg [1<<29 : 0] hugerange; | ^ %Error: t/t_select_bad_range4.v:20:16: Width of :+ or :- is < 0: 32'hffffffff - : ... In instance t + : ... note: In instance 't' 20 | sel2 = mi[44 +: -1]; | ^ %Error-UNSUPPORTED: t/t_select_bad_range4.v:20:16: Unsupported: left < right of bit extract: 2<4 - : ... In instance t + : ... note: In instance 't' 20 | sel2 = mi[44 +: -1]; | ^ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Warning-WIDTHEXPAND: t/t_select_bad_range4.v:20:12: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's SEL generates 3 bits. - : ... In instance t + : ... note: In instance 't' 20 | sel2 = mi[44 +: -1]; | ^ ... Use "/* verilator lint_off WIDTHEXPAND */" and lint_on around source to disable this message. %Error: t/t_select_bad_range4.v:21:16: Width of :+ or :- is huge; vector of over 1 billion bits: 32'h20000000 - : ... In instance t + : ... note: In instance 't' 21 | sel2 = mi[44 +: 1<<29]; | ^ %Warning-SELRANGE: t/t_select_bad_range4.v:21:16: Extracting 20000000 bits from only 6 bit number - : ... In instance t + : ... note: In instance 't' 21 | sel2 = mi[44 +: 1<<29]; | ^ %Warning-SELRANGE: t/t_select_bad_range4.v:21:16: Selection index out of range: 20000003:4 outside 2d:28 - : ... In instance t + : ... note: In instance 't' 21 | sel2 = mi[44 +: 1<<29]; | ^ %Warning-WIDTHTRUNC: t/t_select_bad_range4.v:21:12: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's SEL generates 20000000 bits. - : ... In instance t + : ... note: In instance 't' 21 | sel2 = mi[44 +: 1<<29]; | ^ %Error: t/t_select_bad_range4.v:22:23: Expecting expression to be constant, but variable isn't const: 'nonconst' - : ... In instance t + : ... note: In instance 't' 22 | sel2 = mi[44 +: nonconst]; | ^~~~~~~~ %Error: t/t_select_bad_range4.v:22:23: Width of :+ or :- bit slice range isn't a constant - : ... In instance t + : ... note: In instance 't' 22 | sel2 = mi[44 +: nonconst]; | ^~~~~~~~ %Warning-WIDTHEXPAND: t/t_select_bad_range4.v:22:12: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's SEL generates 1 bits. - : ... In instance t + : ... note: In instance 't' 22 | sel2 = mi[44 +: nonconst]; | ^ %Warning-WIDTHEXPAND: t/t_select_bad_range4.v:23:17: Operator SUB expects 20 or 6 bits on the LHS, but LHS's VARREF 'nonconst' generates 1 bits. - : ... In instance t + : ... note: In instance 't' 23 | sel2 = mi[nonconst]; | ^~~~~~~~ %Warning-WIDTHEXPAND: t/t_select_bad_range4.v:23:12: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's SEL generates 1 bits. - : ... In instance t + : ... note: In instance 't' 23 | sel2 = mi[nonconst]; | ^ %Error: t/t_select_bad_range4.v:24:17: First value of [a:b] isn't a constant, maybe you want +: or -: - : ... In instance t + : ... note: In instance 't' 24 | sel2 = mi[nonconst : nonconst]; | ^~~~~~~~ %Error: t/t_select_bad_range4.v:24:28: Second value of [a:b] isn't a constant, maybe you want +: or -: - : ... In instance t + : ... note: In instance 't' 24 | sel2 = mi[nonconst : nonconst]; | ^~~~~~~~ %Warning-WIDTHEXPAND: t/t_select_bad_range4.v:24:12: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's SEL generates 1 bits. - : ... In instance t + : ... note: In instance 't' 24 | sel2 = mi[nonconst : nonconst]; | ^ %Warning-SELRANGE: t/t_select_bad_range4.v:25:16: Extracting 20000001 bits from only 6 bit number - : ... In instance t + : ... note: In instance 't' 25 | sel2 = mi[1<<29 : 0]; | ^ %Warning-SELRANGE: t/t_select_bad_range4.v:25:16: Selection index out of range: 1fffffd8:ffffffd8 outside 2d:28 - : ... In instance t + : ... note: In instance 't' 25 | sel2 = mi[1<<29 : 0]; | ^ %Warning-WIDTHTRUNC: t/t_select_bad_range4.v:25:12: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's SEL generates 20000001 bits. - : ... In instance t + : ... note: In instance 't' 25 | sel2 = mi[1<<29 : 0]; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_select_bad_range5.out b/test_regress/t/t_select_bad_range5.out index 0c84ef079..c1dd3fa1e 100644 --- a/test_regress/t/t_select_bad_range5.out +++ b/test_regress/t/t_select_bad_range5.out @@ -1,19 +1,19 @@ %Error: t/t_select_bad_range5.v:16:19: Illegal bit or array select; type does not have a bit range, or bad dimension: data type is 'logic' - : ... In instance t + : ... note: In instance 't' 16 | assign mi = unk[3:2]; | ^ %Warning-SELRANGE: t/t_select_bad_range5.v:16:19: Extracting 2 bits from only 1 bit number - : ... In instance t + : ... note: In instance 't' 16 | assign mi = unk[3:2]; | ^ ... For warning description see https://verilator.org/warn/SELRANGE?v=latest ... Use "/* verilator lint_off SELRANGE */" and lint_on around source to disable this message. %Warning-SELRANGE: t/t_select_bad_range5.v:16:19: Selection index out of range: 3:2 outside 1:0 - : ... In instance t + : ... note: In instance 't' 16 | assign mi = unk[3:2]; | ^ %Warning-WIDTHTRUNC: t/t_select_bad_range5.v:16:14: Operator ASSIGNW expects 1 bits on the Assign RHS, but Assign RHS's SEL generates 2 bits. - : ... In instance t + : ... note: In instance 't' 16 | assign mi = unk[3:2]; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_select_bad_tri.out b/test_regress/t/t_select_bad_tri.out index 2fd802546..6b0b07934 100644 --- a/test_regress/t/t_select_bad_tri.out +++ b/test_regress/t/t_select_bad_tri.out @@ -2,6 +2,6 @@ 11 | if (in[( (1'h0 / 1'b0) )+:71] != 71'h0) $stop; | ^ %Error: Internal Error: t/t_select_bad_tri.v:11:24: ../V3Number.cpp:#: toUInt with 4-state 1'bx - : ... In instance t + : ... note: In instance 't' 11 | if (in[( (1'h0 / 1'b0) )+:71] != 71'h0) $stop; | ^ diff --git a/test_regress/t/t_semaphore_bad.out b/test_regress/t/t_semaphore_bad.out index 2fc1c33cb..41eab7032 100644 --- a/test_regress/t/t_semaphore_bad.out +++ b/test_regress/t/t_semaphore_bad.out @@ -1,5 +1,5 @@ %Error: t/t_semaphore_bad.v:12:13: Class method 'bad_method' not found in class 'semaphore' - : ... In instance t + : ... note: In instance 't' 12 | if (s.bad_method() != 0) $stop; | ^~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_split_var_1_bad.out b/test_regress/t/t_split_var_1_bad.out index 0b8fbf11a..6337a8271 100644 --- a/test_regress/t/t_split_var_1_bad.out +++ b/test_regress/t/t_split_var_1_bad.out @@ -16,63 +16,63 @@ 40 | i_sub0.cannot_split1[0] = 0; | ^~~~~~~~~~~~~ %Warning-SELRANGE: t/t_split_var_1_bad.v:90:33: Selection index out of range: 13 outside 12:10 - : ... In instance t.i_sub3 + : ... note: In instance 't.i_sub3' 90 | assign outwires[12] = inwires[13]; | ^ %Warning-WIDTHTRUNC: t/t_split_var_1_bad.v:41:31: Operator ASSIGN expects 8 bits on the Assign RHS, but Assign RHS's FUNCREF 'bad_func' generates 32 bits. - : ... In instance t + : ... note: In instance 't' 41 | i_sub0.cannot_split1[1] = bad_func(addr, rd_data0); | ^ %Error: t/t_split_var_1_bad.v:79:16: Illegal assignment of constant to unpacked array - : ... In instance t.i_sub2 + : ... note: In instance 't.i_sub2' 79 | assign b = a[0]; | ^ %Warning-SPLITVAR: t/t_split_var_1_bad.v:56:31: 'cannot_split0' has split_var metacomment but will not be split because index cannot be determined statically. - : ... In instance t.i_sub0 + : ... note: In instance 't.i_sub0' 56 | rd_data = cannot_split0[addr]; | ^~~~ %Warning-SPLITVAR: t/t_split_var_1_bad.v:90:34: 'inwires' has split_var metacomment but will not be split because index is out of range. - : ... In instance t.i_sub3 + : ... note: In instance 't.i_sub3' 90 | assign outwires[12] = inwires[13]; | ^~ %Warning-SPLITVAR: t/t_split_var_1_bad.v:17:9: 'should_show_warning0' has split_var metacomment but will not be split because it is not an aggregate type of bit nor logic. - : ... In instance t + : ... note: In instance 't' 17 | real should_show_warning0 /*verilator split_var*/ ; | ^~~~~~~~~~~~~~~~~~~~ %Warning-SPLITVAR: t/t_split_var_1_bad.v:18:11: 'should_show_warning1' has split_var metacomment but will not be split because it is not an aggregate type of bit nor logic. - : ... In instance t + : ... note: In instance 't' 18 | string should_show_warning1 /*verilator split_var*/ ; | ^~~~~~~~~~~~~~~~~~~~ %Warning-SPLITVAR: t/t_split_var_1_bad.v:19:11: 'should_show_warning2' has split_var metacomment but will not be split because its bitwidth is 1. - : ... In instance t + : ... note: In instance 't' 19 | wire should_show_warning2 /*verilator split_var*/ ; | ^~~~~~~~~~~~~~~~~~~~ %Warning-SPLITVAR: t/t_split_var_1_bad.v:23:16: 'public_signal' has split_var metacomment but will not be split because it is public. - : ... In instance t + : ... note: In instance 't' 23 | logic [1:0] public_signal /*verilator public*/ /*verilator split_var*/ ; | ^~~~~~~~~~~~~ %Warning-SPLITVAR: t/t_split_var_1_bad.v:31:44: 'inout_port' has split_var metacomment but will not be split because it is an inout port. - : ... In instance t + : ... note: In instance 't' 31 | function int bad_func(inout logic [3:0] inout_port /*verilator split_var*/ , | ^~~~~~~~~~ %Warning-SPLITVAR: t/t_split_var_1_bad.v:32:42: 'ref_port' has split_var metacomment but will not be split because it is a ref argument. - : ... In instance t + : ... note: In instance 't' 32 | ref logic [7:0] ref_port /*verilator split_var*/ ); | ^~~~~~~~ %Warning-SPLITVAR: t/t_split_var_1_bad.v:37:19: 'loop_idx' has split_var metacomment but will not be split because it is used as a loop variable. - : ... In instance t + : ... note: In instance 't' 37 | logic [7:0] loop_idx /*verilator split_var*/ ; | ^~~~~~~~ %Warning-SPLITVAR: t/t_split_var_1_bad.v:62:11: 'cannot_split_genvar' has split_var metacomment but will not be split because it is not an aggregate type of bit nor logic. - : ... In instance t.i_sub1 + : ... note: In instance 't.i_sub1' 62 | genvar cannot_split_genvar /*verilator split_var*/ ; | ^~~~~~~~~~~~~~~~~~~ %Warning-SPLITVAR: t/t_split_var_1_bad.v:65:65: 'cannot_split' has split_var metacomment but will not be split because its bit range cannot be determined statically. - : ... In instance t.i_sub1 + : ... note: In instance 't.i_sub1' 65 | logic [8:0] rd_tmp /*verilator split_var*/ = cannot_split[addr]; | ^ %Warning-SPLITVAR: t/t_split_var_1_bad.v:66:23: 'rd_tmp' has split_var metacomment but will not be split because its bit range cannot be determined statically. - : ... In instance t.i_sub1 + : ... note: In instance 't.i_sub1' 66 | rd_data = rd_tmp[{3'b0, addr[0]}+:8]; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_stream_bad.out b/test_regress/t/t_stream_bad.out index 966297307..34284f067 100644 --- a/test_regress/t/t_stream_bad.out +++ b/test_regress/t/t_stream_bad.out @@ -1,13 +1,13 @@ %Error: t/t_stream_bad.v:12:32: Expecting expression to be constant, but can't convert a RAND to constant. - : ... In instance t + : ... note: In instance 't' 12 | initial packed_data_32 = {<<$random{byte_in}}; | ^~~~~~~ %Error: t/t_stream_bad.v:12:30: Slice size isn't a constant or basic data type. - : ... In instance t + : ... note: In instance 't' 12 | initial packed_data_32 = {<<$random{byte_in}}; | ^~ %Error-UNSUPPORTED: t/t_stream_bad.v:12:30: Unsupported: Stream operation on a variable of a type 'byte$[0:3]' - : ... In instance t + : ... note: In instance 't' 12 | initial packed_data_32 = {<<$random{byte_in}}; | ^~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest diff --git a/test_regress/t/t_stream_dynamic_wide_unsup.out b/test_regress/t/t_stream_dynamic_wide_unsup.out index 6ddca3aaf..1edcffc16 100644 --- a/test_regress/t/t_stream_dynamic_wide_unsup.out +++ b/test_regress/t/t_stream_dynamic_wide_unsup.out @@ -1,10 +1,10 @@ %Error-UNSUPPORTED: t/t_stream_dynamic_wide_unsup.v:15:14: Unsupported: Assignment of stream of dynamic array to a variable of size greater than 64 - : ... In instance t + : ... note: In instance 't' 15 | bit100 = { >> bit {arr} }; | ^ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error-UNSUPPORTED: t/t_stream_dynamic_wide_unsup.v:17:14: Unsupported: Assignment of stream of dynamic array to a variable of size greater than 64 - : ... In instance t + : ... note: In instance 't' 17 | bit100 = { << bit {arr} }; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_stream_integer_type_unsup.out b/test_regress/t/t_stream_integer_type_unsup.out index e688d40f8..83e8c92a9 100644 --- a/test_regress/t/t_stream_integer_type_unsup.out +++ b/test_regress/t/t_stream_integer_type_unsup.out @@ -1,146 +1,146 @@ %Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:118:31: Unsupported: Stream operation on a variable of a type 'byte$[0:3]' - : ... In instance t + : ... note: In instance 't' 118 | packed_data_32 = {<<8{byte_in}}; | ^~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:119:31: Unsupported: Stream operation on a variable of a type 'shortint$[0:3]' - : ... In instance t + : ... note: In instance 't' 119 | packed_data_64 = {<<16{shortint_in}}; | ^~ %Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:120:31: Unsupported: Stream operation on a variable of a type 'int$[0:3]' - : ... In instance t + : ... note: In instance 't' 120 | packed_data_128 = {<<32{int_in}}; | ^~ %Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:121:31: Unsupported: Stream operation on a variable of a type 'integer$[0:3]' - : ... In instance t + : ... note: In instance 't' 121 | packed_data_128_i = {<<32{integer_in}}; | ^~ %Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:122:31: Unsupported: Stream operation on a variable of a type 'longint$[0:3]' - : ... In instance t + : ... note: In instance 't' 122 | packed_data_256 = {<<64{longint_in}}; | ^~ %Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:123:31: Unsupported: Stream operation on a variable of a type 'time$[0:3]' - : ... In instance t + : ... note: In instance 't' 123 | packed_time_256 = {<<64{time_in}}; | ^~ %Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:124:31: Unsupported: Stream operation on a variable of a type 'bit[7:0]$[0:3]' - : ... In instance t + : ... note: In instance 't' 124 | v_packed_data_32 = {<<8{bit_in}}; | ^~ %Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:125:31: Unsupported: Stream operation on a variable of a type 'bit[15:0]$[0:3]' - : ... In instance t + : ... note: In instance 't' 125 | v_packed_data_64 = {<<16{logic_in}}; | ^~ %Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:126:31: Unsupported: Stream operation on a variable of a type 'bit[31:0]$[0:3]' - : ... In instance t + : ... note: In instance 't' 126 | v_packed_data_128 = {<<32{reg_in}}; | ^~ %Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:128:11: Unsupported: Stream operation on a variable of a type 'byte$[0:3]' - : ... In instance t + : ... note: In instance 't' 128 | {<<8{byte_out}} = packed_data_32; | ^~ %Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:129:11: Unsupported: Stream operation on a variable of a type 'shortint$[0:3]' - : ... In instance t + : ... note: In instance 't' 129 | {<<16{shortint_out}} = packed_data_64; | ^~ %Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:130:11: Unsupported: Stream operation on a variable of a type 'int$[0:3]' - : ... In instance t + : ... note: In instance 't' 130 | {<<32{int_out}} = packed_data_128; | ^~ %Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:131:11: Unsupported: Stream operation on a variable of a type 'integer$[0:3]' - : ... In instance t + : ... note: In instance 't' 131 | {<<32{integer_out}} = packed_data_128_i; | ^~ %Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:132:11: Unsupported: Stream operation on a variable of a type 'longint$[0:3]' - : ... In instance t + : ... note: In instance 't' 132 | {<<64{longint_out}} = packed_data_256; | ^~ %Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:133:11: Unsupported: Stream operation on a variable of a type 'time$[0:3]' - : ... In instance t + : ... note: In instance 't' 133 | {<<64{time_out}} = packed_time_256; | ^~ %Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:134:11: Unsupported: Stream operation on a variable of a type 'bit[7:0]$[0:3]' - : ... In instance t + : ... note: In instance 't' 134 | {<<8{bit_out}} = v_packed_data_32; | ^~ %Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:135:11: Unsupported: Stream operation on a variable of a type 'bit[15:0]$[0:3]' - : ... In instance t + : ... note: In instance 't' 135 | {<<16{logic_out}} = v_packed_data_64; | ^~ %Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:136:11: Unsupported: Stream operation on a variable of a type 'bit[31:0]$[0:3]' - : ... In instance t + : ... note: In instance 't' 136 | {<<32{reg_out}} = v_packed_data_128; | ^~ %Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:150:31: Unsupported: Stream operation on a variable of a type 'byte$[0:3]' - : ... In instance t + : ... note: In instance 't' 150 | packed_data_32 = {<e; | ^ %Error-NEEDTIMINGOPT: t/t_notiming.v:27:12: Use --timing or --no-timing to specify how delays should be handled - : ... In instance t + : ... note: In instance 't' 27 | initial #2 $stop; | ^ %Error-NEEDTIMINGOPT: t/t_notiming.v:33:10: Use --timing or --no-timing to specify how mailbox::put() should be handled - : ... In instance t + : ... note: In instance 't' 33 | m.put(i); | ^~~ %Error-NEEDTIMINGOPT: t/t_notiming.v:34:10: Use --timing or --no-timing to specify how mailbox::get() should be handled - : ... In instance t + : ... note: In instance 't' 34 | m.get(i); | ^~~ %Error-NEEDTIMINGOPT: t/t_notiming.v:35:10: Use --timing or --no-timing to specify how mailbox::peek() should be handled - : ... In instance t + : ... note: In instance 't' 35 | m.peek(i); | ^~~~ %Error-NEEDTIMINGOPT: t/t_notiming.v:36:10: Use --timing or --no-timing to specify how semaphore::get() should be handled - : ... In instance t + : ... note: In instance 't' 36 | s.get(); | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_timing_unset2.out b/test_regress/t/t_timing_unset2.out index 0d340a8f2..cccbcc862 100644 --- a/test_regress/t/t_timing_unset2.out +++ b/test_regress/t/t_timing_unset2.out @@ -1,26 +1,26 @@ %Error-NEEDTIMINGOPT: t/t_timing_off.v:25:8: Use --timing or --no-timing to specify how event controls should be handled - : ... In instance t + : ... note: In instance 't' 25 | @e1; | ^ ... For error description see https://verilator.org/warn/NEEDTIMINGOPT?v=latest %Error-NEEDTIMINGOPT: t/t_timing_off.v:33:12: Use --timing or --no-timing to specify how delays should be handled - : ... In instance t + : ... note: In instance 't' 33 | initial #2 ->e1; | ^ %Error-NEEDTIMINGOPT: t/t_timing_off.v:37:12: Use --timing or --no-timing to specify how delays should be handled - : ... In instance t + : ... note: In instance 't' 37 | initial #3 $stop; | ^ %Error-NEEDTIMINGOPT: t/t_timing_off.v:38:12: Use --timing or --no-timing to specify how delays should be handled - : ... In instance t + : ... note: In instance 't' 38 | initial #1 @(e1, e2) #1 $stop; | ^ %Error-NEEDTIMINGOPT: t/t_timing_off.v:38:15: Use --timing or --no-timing to specify how event controls should be handled - : ... In instance t + : ... note: In instance 't' 38 | initial #1 @(e1, e2) #1 $stop; | ^ %Error-NEEDTIMINGOPT: t/t_timing_off.v:38:25: Use --timing or --no-timing to specify how delays should be handled - : ... In instance t + : ... note: In instance 't' 38 | initial #1 @(e1, e2) #1 $stop; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_timing_unset3.out b/test_regress/t/t_timing_unset3.out index 3d91db2b4..8401328f3 100644 --- a/test_regress/t/t_timing_unset3.out +++ b/test_regress/t/t_timing_unset3.out @@ -1,5 +1,5 @@ %Error-NEEDTIMINGOPT: t/t_clocking_notiming.v:11:8: Use --timing or --no-timing to specify how clocking output skew greater than #0 should be handled - : ... In instance t + : ... note: In instance 't' 11 | output #1 out; | ^~~~~~ ... For error description see https://verilator.org/warn/NEEDTIMINGOPT?v=latest diff --git a/test_regress/t/t_tri_array.out b/test_regress/t/t_tri_array.out index 4ca9228ce..228308ed4 100644 --- a/test_regress/t/t_tri_array.out +++ b/test_regress/t/t_tri_array.out @@ -1,18 +1,18 @@ %Error-UNSUPPORTED: t/t_tri_array.v:25:25: Unsupported LHS tristate construct: ARRAYSEL - : ... In instance t + : ... note: In instance 't' 25 | Pad pad1 (.pad(pad[g]), | ^ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error-UNSUPPORTED: t/t_tri_array.v:28:25: Unsupported LHS tristate construct: ARRAYSEL - : ... In instance t + : ... note: In instance 't' 28 | Pad pad0 (.pad(pad[g]), | ^ %Error: t/t_tri_array.v:25:25: Select from non-array BASICDTYPE 'bit' - : ... In instance t + : ... note: In instance 't' 25 | Pad pad1 (.pad(pad[g]), | ^ %Error: t/t_tri_array.v:28:25: Select from non-array BASICDTYPE 'bit' - : ... In instance t + : ... note: In instance 't' 28 | Pad pad0 (.pad(pad[g]), | ^ %Error: Internal Error: t/t_tri_array.v:25:22: ../V3Dfg.h:#: DfgVertex is not of expected type, but instead has type 'VARPACKED' diff --git a/test_regress/t/t_tri_compass_bad.out b/test_regress/t/t_tri_compass_bad.out index d9c240860..0bd522480 100644 --- a/test_regress/t/t_tri_compass_bad.out +++ b/test_regress/t/t_tri_compass_bad.out @@ -1,5 +1,5 @@ %Error-UNSUPPORTED: t/t_tri_compass_bad.v:16:12: Unsupported: tristate in top-level IO: '__pinNumber1' - : ... In instance t + : ... note: In instance 't' 16 | sub sub(i, o); | ^ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest diff --git a/test_regress/t/t_tri_pull2_bad.out b/test_regress/t/t_tri_pull2_bad.out index ea60ddfd2..cd8ed3185 100644 --- a/test_regress/t/t_tri_pull2_bad.out +++ b/test_regress/t/t_tri_pull2_bad.out @@ -1,5 +1,5 @@ %Error-UNSUPPORTED: t/t_tri_pull2_bad.v:12:11: Unsupported: Conflicting pull directions. - : ... In instance t + : ... note: In instance 't' 12 | pullup p1(A); | ^~ t/t_tri_pull2_bad.v:22:13: ... Location of conflicting pull. diff --git a/test_regress/t/t_tri_pull_bad.out b/test_regress/t/t_tri_pull_bad.out index 6d7960c19..fb22a6d89 100644 --- a/test_regress/t/t_tri_pull_bad.out +++ b/test_regress/t/t_tri_pull_bad.out @@ -1,5 +1,5 @@ %Error-UNSUPPORTED: t/t_tri_pull_bad.v:13:13: Unsupported: Conflicting pull directions. - : ... In instance t + : ... note: In instance 't' 13 | pulldown p2(A); | ^~ t/t_tri_pull_bad.v:12:11: ... Location of conflicting pull. diff --git a/test_regress/t/t_tri_pullvec_bad.out b/test_regress/t/t_tri_pullvec_bad.out index ae95a7c27..297186924 100644 --- a/test_regress/t/t_tri_pullvec_bad.out +++ b/test_regress/t/t_tri_pullvec_bad.out @@ -1,5 +1,5 @@ %Error-UNSUPPORTED: t/t_tri_pullvec_bad.v:13:13: Unsupported: Conflicting pull directions. - : ... In instance t + : ... note: In instance 't' 13 | pulldown p1 (w[1]); | ^~ t/t_tri_pullvec_bad.v:12:11: ... Location of conflicting pull. @@ -7,7 +7,7 @@ | ^~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error-UNSUPPORTED: t/t_tri_pullvec_bad.v:14:13: Unsupported: Conflicting pull directions. - : ... In instance t + : ... note: In instance 't' 14 | pulldown p2 (w[2]); | ^~ t/t_tri_pullvec_bad.v:12:11: ... Location of conflicting pull. diff --git a/test_regress/t/t_type_compare_bad.out b/test_regress/t/t_type_compare_bad.out index e3827de74..ea2fbaba2 100644 --- a/test_regress/t/t_type_compare_bad.out +++ b/test_regress/t/t_type_compare_bad.out @@ -1,5 +1,5 @@ %Error: t/t_type_compare_bad.v:12:9: Case(type) statement requires items that have type() items - : ... In instance t + : ... note: In instance 't' 12 | 1: $stop; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_unbounded_bad.out b/test_regress/t/t_unbounded_bad.out index c21431950..2e4bdca79 100644 --- a/test_regress/t/t_unbounded_bad.out +++ b/test_regress/t/t_unbounded_bad.out @@ -1,10 +1,10 @@ %Error-UNSUPPORTED: t/t_unbounded_bad.v:9:11: Unsupported/illegal unbounded ('$') in this context. - : ... In instance t + : ... note: In instance 't' 9 | if ($) $stop; | ^ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Warning-WIDTHTRUNC: t/t_unbounded_bad.v:9:7: Logical operator IF expects 1 bit on the If, but If's UNBOUNDED generates 32 bits. - : ... In instance t + : ... note: In instance 't' 9 | if ($) $stop; | ^~ ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. diff --git a/test_regress/t/t_unpacked_concat_bad.out b/test_regress/t/t_unpacked_concat_bad.out index 0f7ec60dd..4f2954473 100644 --- a/test_regress/t/t_unpacked_concat_bad.out +++ b/test_regress/t/t_unpacked_concat_bad.out @@ -1,10 +1,10 @@ %Error-UNSUPPORTED: t/t_unpacked_concat_bad.v:17:46: Unsupported: Non-1 replication to form 'bit[31:0]$[1:0]' data type - : ... In instance t + : ... note: In instance 't' 17 | localparam bit_int_t count_bits [1:0] = {2{$bits(count_t)}}; | ^ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error: t/t_unpacked_concat_bad.v:17:46: Assignment pattern missed initializing elements: 0 - : ... In instance t + : ... note: In instance 't' 17 | localparam bit_int_t count_bits [1:0] = {2{$bits(count_t)}}; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_var_const_bad.out b/test_regress/t/t_var_const_bad.out index f29ef0b8a..a29bdef45 100644 --- a/test_regress/t/t_var_const_bad.out +++ b/test_regress/t/t_var_const_bad.out @@ -1,5 +1,5 @@ %Error: t/t_var_const_bad.v:17:7: Assigning to const variable: 'five' - : ... In instance t + : ... note: In instance 't' 17 | five = 3'd4; | ^~~~ %Error: Exiting due to diff --git a/test_regress/t/t_var_ref_bad1.out b/test_regress/t/t_var_ref_bad1.out index fad8332f9..9351d8750 100644 --- a/test_regress/t/t_var_ref_bad1.out +++ b/test_regress/t/t_var_ref_bad1.out @@ -1,5 +1,5 @@ %Error: t/t_var_ref_bad1.v:14:8: Ref connection 'bad_sub_ref' requires matching types; ref requires 'real' data type but connection is 'bit' data type. - : ... In instance t + : ... note: In instance 't' 14 | (.bad_sub_ref(bad_parent)); | ^~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_var_ref_bad2.out b/test_regress/t/t_var_ref_bad2.out index 7a14ae05e..fa46d14c5 100644 --- a/test_regress/t/t_var_ref_bad2.out +++ b/test_regress/t/t_var_ref_bad2.out @@ -1,9 +1,9 @@ %Error: t/t_var_ref_bad2.v:13:7: Assigning to const ref variable: 'bad_const_set' - : ... In instance t + : ... note: In instance 't' 13 | bad_const_set = 32'h4567; | ^~~~~~~~~~~~~ %Error: t/t_var_ref_bad2.v:23:17: Ref argument requires matching types; port 'int_ref' requires int but connection is byte. - : ... In instance t + : ... note: In instance 't' 23 | checkset2(bad_non_int); | ^~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_var_rsvd_bad.out b/test_regress/t/t_var_rsvd_bad.out index ef3f32fc0..93b831450 100644 --- a/test_regress/t/t_var_rsvd_bad.out +++ b/test_regress/t/t_var_rsvd_bad.out @@ -4,7 +4,7 @@ ... For warning description see https://verilator.org/warn/SYMRSVDWORD?v=latest ... Use "/* verilator lint_off SYMRSVDWORD */" and lint_on around source to disable this message. %Warning-SYMRSVDWORD: t/t_var_rsvd_port.v:15:9: Symbol matches C++ keyword: 'switch' - : ... In instance t + : ... note: In instance 't' 15 | reg switch /*verilator public*/ ; | ^~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_var_types_bad.out b/test_regress/t/t_var_types_bad.out index 47c3d490b..199f4423d 100644 --- a/test_regress/t/t_var_types_bad.out +++ b/test_regress/t/t_var_types_bad.out @@ -1,21 +1,21 @@ %Error: t/t_var_types_bad.v:39:13: Illegal bit or array select; type does not have a bit range, or bad dimension: data type is 'bit' - : ... In instance t + : ... note: In instance 't' 39 | d_bitz[0] = 1'b1; | ^ %Error: t/t_var_types_bad.v:40:15: Illegal bit or array select; type does not have a bit range, or bad dimension: data type is 'logic' - : ... In instance t + : ... note: In instance 't' 40 | d_logicz[0] = 1'b1; | ^ %Error: t/t_var_types_bad.v:41:13: Illegal bit or array select; type does not have a bit range, or bad dimension: data type is 'logic' - : ... In instance t + : ... note: In instance 't' 41 | d_regz[0] = 1'b1; | ^ %Error: t/t_var_types_bad.v:46:13: Illegal bit or array select; type does not have a bit range, or bad dimension: data type is 'real' - : ... In instance t + : ... note: In instance 't' 46 | d_real[0] = 1'b1; | ^ %Error: t/t_var_types_bad.v:46:7: Expected integral (non-real) input to SEL - : ... In instance t + : ... note: In instance 't' 46 | d_real[0] = 1'b1; | ^~~~~~ %Warning-REALCVT: t/t_var_types_bad.v:46:7: Implicit conversion of real to integer @@ -24,11 +24,11 @@ ... For warning description see https://verilator.org/warn/REALCVT?v=latest ... Use "/* verilator lint_off REALCVT */" and lint_on around source to disable this message. %Error: t/t_var_types_bad.v:47:17: Illegal bit or array select; type does not have a bit range, or bad dimension: data type is 'real' - : ... In instance t + : ... note: In instance 't' 47 | d_realtime[0] = 1'b1; | ^ %Error: t/t_var_types_bad.v:47:7: Expected integral (non-real) input to SEL - : ... In instance t + : ... note: In instance 't' 47 | d_realtime[0] = 1'b1; | ^~~~~~~~~~ %Warning-REALCVT: t/t_var_types_bad.v:47:7: Implicit conversion of real to integer diff --git a/test_regress/t/t_vlt_warn_bad.out b/test_regress/t/t_vlt_warn_bad.out index e4520566e..4f49d7621 100644 --- a/test_regress/t/t_vlt_warn_bad.out +++ b/test_regress/t/t_vlt_warn_bad.out @@ -1,5 +1,5 @@ %Warning-WIDTHTRUNC: t/t_vlt_warn.v:21:33: Operator ASSIGN expects 1 bits on the Assign RHS, but Assign RHS's CONST '2'h3' generates 2 bits. - : ... In instance t + : ... note: In instance 't' 21 | reg width_warn3_var_line20 = 2'b11; | ^~~~~ ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest diff --git a/test_regress/t/t_vlt_warn_ecode_bad.out b/test_regress/t/t_vlt_warn_ecode_bad.out index ec0e047bf..4b28e5c34 100644 --- a/test_regress/t/t_vlt_warn_ecode_bad.out +++ b/test_regress/t/t_vlt_warn_ecode_bad.out @@ -1,7 +1,7 @@ -%Error: t/t_vlt_warn_ecode_bad.vlt:9:1: Unknown error code: BADRULENAME +%Error: t/t_vlt_warn_ecode_bad.vlt:9:1: Unknown error code: 'BADRULENAME' 9 | lint_off -rule BADRULENAME -file "t/t_vlt_warn.v" | ^~~~~~~~ -%Error: t/t_vlt_warn_ecode_bad.vlt:10:1: Unknown error code: BADRULENAME +%Error: t/t_vlt_warn_ecode_bad.vlt:10:1: Unknown error code: 'BADRULENAME' 10 | lint_on -rule BADRULENAME -file "t/t_vlt_warn.v" | ^~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_wait.out b/test_regress/t/t_wait.out index 2de31cc23..5e07cbc26 100644 --- a/test_regress/t/t_wait.out +++ b/test_regress/t/t_wait.out @@ -1,39 +1,39 @@ %Error-NOTIMING: t/t_wait.v:12:7: Wait statements require --timing - : ... In instance t + : ... note: In instance 't' 12 | wait (value == 1); | ^~~~ ... For error description see https://verilator.org/warn/NOTIMING?v=latest %Error-NOTIMING: t/t_wait.v:14:7: Wait statements require --timing - : ... In instance t + : ... note: In instance 't' 14 | wait (0); | ^~~~ %Error-NOTIMING: t/t_wait.v:17:7: Wait statements require --timing - : ... In instance t + : ... note: In instance 't' 17 | wait (value == 2); | ^~~~ %Error-NOTIMING: t/t_wait.v:20:7: Wait statements require --timing - : ... In instance t + : ... note: In instance 't' 20 | wait (value == 3) if (value != 3) $stop; | ^~~~ %Warning-STMTDLY: t/t_wait.v:25:7: Ignoring delay on this statement due to --no-timing - : ... In instance t + : ... note: In instance 't' 25 | #10; | ^ ... Use "/* verilator lint_off STMTDLY */" and lint_on around source to disable this message. %Warning-STMTDLY: t/t_wait.v:27:7: Ignoring delay on this statement due to --no-timing - : ... In instance t + : ... note: In instance 't' 27 | #10; | ^ %Warning-STMTDLY: t/t_wait.v:29:7: Ignoring delay on this statement due to --no-timing - : ... In instance t + : ... note: In instance 't' 29 | #10; | ^ %Warning-STMTDLY: t/t_wait.v:31:7: Ignoring delay on this statement due to --no-timing - : ... In instance t + : ... note: In instance 't' 31 | #10; | ^ %Warning-STMTDLY: t/t_wait.v:33:7: Ignoring delay on this statement due to --no-timing - : ... In instance t + : ... note: In instance 't' 33 | #10; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_wire_beh1364_bad.out b/test_regress/t/t_wire_beh1364_bad.out index 4667a07f9..46ef1ad3c 100644 --- a/test_regress/t/t_wire_beh1364_bad.out +++ b/test_regress/t/t_wire_beh1364_bad.out @@ -1,22 +1,22 @@ %Error-PROCASSWIRE: t/t_wire_beh1364_bad.v:26:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'w' - : ... In instance t + : ... note: In instance 't' 26 | w = 0; | ^ ... For error description see https://verilator.org/warn/PROCASSWIRE?v=latest %Error-PROCASSWIRE: t/t_wire_beh1364_bad.v:27:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'o' - : ... In instance t + : ... note: In instance 't' 27 | o = 0; | ^ %Error-PROCASSWIRE: t/t_wire_beh1364_bad.v:28:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'oa' - : ... In instance t + : ... note: In instance 't' 28 | oa = 0; | ^~ %Error-PROCASSWIRE: t/t_wire_beh1364_bad.v:29:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'wo' - : ... In instance t + : ... note: In instance 't' 29 | wo = 0; | ^~ %Error-PROCASSWIRE: t/t_wire_beh1364_bad.v:30:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'woa' - : ... In instance t + : ... note: In instance 't' 30 | woa = 0; | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_wire_beh1800_bad.out b/test_regress/t/t_wire_beh1800_bad.out index 7f6881e18..534097220 100644 --- a/test_regress/t/t_wire_beh1800_bad.out +++ b/test_regress/t/t_wire_beh1800_bad.out @@ -1,22 +1,22 @@ %Error-PROCASSWIRE: t/t_wire_beh1800_bad.v:25:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'w' - : ... In instance t + : ... note: In instance 't' 25 | w = '0; | ^ ... For error description see https://verilator.org/warn/PROCASSWIRE?v=latest %Error-PROCASSWIRE: t/t_wire_beh1800_bad.v:26:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'o' - : ... In instance t + : ... note: In instance 't' 26 | o = '0; | ^ %Error-PROCASSWIRE: t/t_wire_beh1800_bad.v:27:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'oa' - : ... In instance t + : ... note: In instance 't' 27 | oa = '0; | ^~ %Error-PROCASSWIRE: t/t_wire_beh1800_bad.v:28:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'wo' - : ... In instance t + : ... note: In instance 't' 28 | wo = '0; | ^~ %Error-PROCASSWIRE: t/t_wire_beh1800_bad.v:29:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'woa' - : ... In instance t + : ... note: In instance 't' 29 | woa = '0; | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_wire_behp1364_bad.out b/test_regress/t/t_wire_behp1364_bad.out index 9fbbf0f6c..8f874080e 100644 --- a/test_regress/t/t_wire_behp1364_bad.out +++ b/test_regress/t/t_wire_behp1364_bad.out @@ -1,14 +1,14 @@ %Error-PROCASSWIRE: t/t_wire_behp1364_bad.v:24:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'w' - : ... In instance t + : ... note: In instance 't' 24 | w = 0; | ^ ... For error description see https://verilator.org/warn/PROCASSWIRE?v=latest %Error-PROCASSWIRE: t/t_wire_behp1364_bad.v:25:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'o' - : ... In instance t + : ... note: In instance 't' 25 | o = 0; | ^ %Error-PROCASSWIRE: t/t_wire_behp1364_bad.v:26:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'oa' - : ... In instance t + : ... note: In instance 't' 26 | oa = 0; | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_wire_behp1800_bad.out b/test_regress/t/t_wire_behp1800_bad.out index 658c081e0..e2e3e2645 100644 --- a/test_regress/t/t_wire_behp1800_bad.out +++ b/test_regress/t/t_wire_behp1800_bad.out @@ -1,14 +1,14 @@ %Error-PROCASSWIRE: t/t_wire_behp1800_bad.v:23:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'w' - : ... In instance t + : ... note: In instance 't' 23 | w = '0; | ^ ... For error description see https://verilator.org/warn/PROCASSWIRE?v=latest %Error-PROCASSWIRE: t/t_wire_behp1800_bad.v:24:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'o' - : ... In instance t + : ... note: In instance 't' 24 | o = '0; | ^ %Error-PROCASSWIRE: t/t_wire_behp1800_bad.v:25:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'oa' - : ... In instance t + : ... note: In instance 't' 25 | oa = '0; | ^~ %Error: Exiting due to From 429cb1f7f726ccad3b933e899ac255b806948d92 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 23 Sep 2023 09:04:35 -0400 Subject: [PATCH 016/157] Commentary (#4517) --- docs/guide/environment.rst | 21 +++++++++++++++++++++ docs/internals.rst | 4 ++-- docs/spelling.txt | 1 + 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/docs/guide/environment.rst b/docs/guide/environment.rst index a8e4b4439..4cfe4c535 100644 --- a/docs/guide/environment.rst +++ b/docs/guide/environment.rst @@ -7,6 +7,21 @@ Environment This section describes the environment variables used by Verilator and associated programs. +.. option:: AR + + Optionally overrides the default :command:`ar` (archive) binary used by + the Verilated makefiles. If AR is not set, the version found at + configure time is used. + +.. option:: CXX + + Optionally overrides the default compiler binary used by the Verilated + makefiles. If CXX is not set, the version found at configure time is + used. Note the default flags passed to the compiler are determined at + configuration time, so changing the CXX compiler version using this + variable, as opposed to passing it at configuration time, may not give + desired results. + .. option:: LD_LIBRARY_PATH A generic Linux/OS variable specifying what directories have shared @@ -35,6 +50,12 @@ associated programs. those programs. If OBJCACHE is not set, and at configure time ccache was present, ccache will be used as a default. +.. option:: PYTHON3 + + Optionally overrides the default :command:`python3` binary used by the + Verilated makefiles. If PYTHON3 is not set, the version found at + configure time is used. + .. option:: SYSTEMC Deprecated. Used only if :option:`SYSTEMC_INCLUDE` or diff --git a/docs/internals.rst b/docs/internals.rst index 136c90265..d03eebd17 100644 --- a/docs/internals.rst +++ b/docs/internals.rst @@ -1400,7 +1400,7 @@ Controlling the Test Driver --------------------------- The test driver script `driver.pl` runs tests; see the `Test Driver` -section. The individual test drivers are written in PERL; see `Test +section. The individual test drivers are written in Perl; see `Test Language`. @@ -1432,7 +1432,7 @@ Developers will also want to call ./configure with two extra flags: disabled by default, as SystemC installation problems would otherwise falsely indicate a Verilator problem. -When enabling the long tests, some additional PERL modules are needed, +When enabling the long tests, some additional Perl modules are needed, which you can install using cpan. :: diff --git a/docs/spelling.txt b/docs/spelling.txt index cddf6a1b2..d55530c50 100644 --- a/docs/spelling.txt +++ b/docs/spelling.txt @@ -486,6 +486,7 @@ countbits countones cout cpp +cppstyle cpu ctor ctrace From d64c023099fb5018501a08e42be9f096e32710b3 Mon Sep 17 00:00:00 2001 From: Anthony Donlon <4056887+donlon@users.noreply.github.com> Date: Sat, 23 Sep 2023 23:50:05 +0800 Subject: [PATCH 017/157] CI: Cancel previous runs for pull requests automatically (#4512) --- .github/workflows/build.yml | 4 ++++ .github/workflows/msbuild.yml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 704917c53..46752f44c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,6 +23,10 @@ defaults: shell: bash working-directory: repo +concurrency: + group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || github.run_id }} + cancel-in-progress: true + jobs: build: diff --git a/.github/workflows/msbuild.yml b/.github/workflows/msbuild.yml index dd25c2669..fe148ad6e 100644 --- a/.github/workflows/msbuild.yml +++ b/.github/workflows/msbuild.yml @@ -22,6 +22,10 @@ defaults: run: working-directory: repo +concurrency: + group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || github.run_id }} + cancel-in-progress: true + jobs: windows: From 28bd7e5b198b1380dcf193d14c1c170db7371c6b Mon Sep 17 00:00:00 2001 From: Mariusz Glebocki Date: Mon, 25 Sep 2023 04:12:23 +0200 Subject: [PATCH 018/157] Rework multithreading handling to separate by code units that use/never use it. (#4228) --- src/Makefile_obj.in | 2 +- src/V3Active.cpp | 2 + src/V3Active.h | 4 +- src/V3ActiveTop.cpp | 2 + src/V3ActiveTop.h | 4 +- src/V3Assert.cpp | 2 + src/V3Assert.h | 3 +- src/V3AssertPre.cpp | 2 + src/V3AssertPre.h | 4 +- src/V3AstNodeOther.h | 2 +- src/V3AstNodes.cpp | 8 +- src/V3Begin.cpp | 2 + src/V3Begin.h | 4 +- src/V3Branch.cpp | 2 + src/V3Branch.h | 4 +- src/V3CCtors.cpp | 2 + src/V3CCtors.h | 6 +- src/V3CUse.cpp | 2 + src/V3CUse.h | 4 +- src/V3Case.cpp | 2 + src/V3Case.h | 6 +- src/V3Cast.cpp | 2 + src/V3Cast.h | 4 +- src/V3Class.cpp | 2 + src/V3Class.h | 4 +- src/V3Clean.cpp | 2 + src/V3Clean.h | 4 +- src/V3Clock.cpp | 2 + src/V3Clock.h | 4 +- src/V3Combine.cpp | 2 + src/V3Combine.h | 4 +- src/V3Common.cpp | 2 + src/V3Common.h | 4 +- src/V3Const.cpp | 2 + src/V3Const.h | 29 +- src/V3Coverage.cpp | 2 + src/V3Coverage.h | 4 +- src/V3CoverageJoin.cpp | 2 + src/V3CoverageJoin.h | 4 +- src/V3Dead.cpp | 2 + src/V3Dead.h | 12 +- src/V3Delayed.cpp | 2 + src/V3Delayed.h | 4 +- src/V3Depth.cpp | 2 + src/V3Depth.h | 4 +- src/V3DepthBlock.cpp | 2 + src/V3DepthBlock.h | 4 +- src/V3Descope.cpp | 2 + src/V3Descope.h | 4 +- src/V3Dfg.cpp | 2 + src/V3Dfg.h | 75 +-- src/V3DfgAstToDfg.cpp | 2 + src/V3DfgDecomposition.cpp | 2 + src/V3DfgDfgToAst.cpp | 2 + src/V3DfgOptimizer.cpp | 2 + src/V3DfgOptimizer.h | 5 +- src/V3DfgPasses.cpp | 2 + src/V3DfgPasses.h | 25 +- src/V3DfgPeephole.cpp | 2 + src/V3DfgPeephole.h | 6 +- src/V3DfgVertices.h | 12 +- src/V3DupFinder.cpp | 2 + src/V3DupFinder.h | 9 +- src/V3EmitC.h | 14 +- src/V3EmitCBase.h | 2 +- src/V3EmitCFunc.h | 1 + src/V3EmitCMain.cpp | 2 + src/V3EmitCMain.h | 4 +- src/V3EmitCMake.cpp | 2 + src/V3EmitCMake.h | 4 +- src/V3EmitCModel.cpp | 2 + src/V3EmitCSyms.cpp | 2 + src/V3EmitMk.cpp | 2 + src/V3EmitMk.h | 6 +- src/V3EmitV.h | 2 + src/V3EmitXml.cpp | 2 + src/V3EmitXml.h | 4 +- src/V3Error.cpp | 23 +- src/V3Error.h | 35 +- src/V3Expand.cpp | 2 + src/V3Expand.h | 4 +- src/V3Force.cpp | 2 + src/V3Force.h | 4 +- src/V3Fork.cpp | 2 + src/V3Fork.h | 6 +- src/V3Gate.cpp | 2 + src/V3Gate.h | 4 +- src/V3Global.h | 7 +- src/V3Graph.cpp | 2 + src/V3Graph.h | 109 +++-- src/V3GraphAcyc.cpp | 2 + src/V3GraphAlg.cpp | 2 + src/V3GraphPathChecker.cpp | 2 + src/V3GraphPathChecker.h | 14 +- src/V3GraphTest.cpp | 2 + src/V3HierBlock.cpp | 2 + src/V3HierBlock.h | 41 +- src/V3Inline.cpp | 2 + src/V3Inline.h | 4 +- src/V3Inst.cpp | 2 + src/V3Inst.h | 10 +- src/V3InstrCount.cpp | 2 + src/V3InstrCount.h | 5 +- src/V3Life.cpp | 2 + src/V3Life.h | 4 +- src/V3LifePost.cpp | 2 + src/V3LifePost.h | 4 +- src/V3LinkCells.cpp | 2 + src/V3LinkCells.h | 4 +- src/V3LinkDot.cpp | 2 + src/V3LinkDot.h | 11 +- src/V3LinkInc.cpp | 2 + src/V3LinkInc.h | 4 +- src/V3LinkJump.cpp | 2 + src/V3LinkJump.h | 4 +- src/V3LinkLValue.cpp | 2 + src/V3LinkLValue.h | 6 +- src/V3LinkLevel.cpp | 2 + src/V3LinkLevel.h | 11 +- src/V3LinkParse.cpp | 2 + src/V3LinkParse.h | 4 +- src/V3LinkResolve.cpp | 2 + src/V3LinkResolve.h | 4 +- src/V3Localize.cpp | 2 + src/V3Localize.h | 4 +- src/V3MergeCond.cpp | 2 + src/V3MergeCond.h | 4 +- src/V3Name.cpp | 2 + src/V3Name.h | 4 +- src/V3Number_test.cpp | 1 + src/V3OptionParser.cpp | 2 + src/V3OptionParser.h | 56 ++- src/V3Options.cpp | 25 +- src/V3Options.h | 11 +- src/V3Order.cpp | 2 + src/V3Order.h | 4 +- src/V3OrderGraph.h | 59 ++- src/V3OrderMoveGraph.h | 24 +- src/V3Param.cpp | 2 + src/V3Param.h | 4 +- src/V3Parse.h | 9 +- src/V3ParseGrammar.cpp | 2 + src/V3ParseImp.cpp | 2 + src/V3ParseImp.h | 68 +-- src/V3ParseLex.cpp | 2 + src/V3Partition.cpp | 2 + src/V3Partition.h | 15 +- src/V3PartitionGraph.h | 14 +- src/V3PreProc.cpp | 2 + src/V3PreProc.h | 5 +- src/V3PreShell.cpp | 2 + src/V3PreShell.h | 17 +- src/V3Premit.cpp | 2 + src/V3Premit.h | 4 +- src/V3ProtectLib.cpp | 2 + src/V3ProtectLib.h | 4 +- src/V3Randomize.cpp | 2 + src/V3Randomize.h | 8 +- src/V3Reloop.cpp | 2 + src/V3Reloop.h | 4 +- src/V3Sched.cpp | 2 + src/V3Sched.h | 22 +- src/V3SchedAcyclic.cpp | 2 + src/V3SchedPartition.cpp | 2 + src/V3SchedReplicate.cpp | 2 + src/V3SchedTiming.cpp | 2 + src/V3Scope.cpp | 2 + src/V3Scope.h | 4 +- src/V3Scoreboard.cpp | 2 + src/V3Scoreboard.h | 3 +- src/V3Slice.cpp | 2 + src/V3Slice.h | 4 +- src/V3Split.cpp | 2 + src/V3Split.h | 6 +- src/V3SplitAs.cpp | 2 + src/V3SplitAs.h | 4 +- src/V3SplitVar.cpp | 2 + src/V3SplitVar.h | 6 +- src/V3Subst.cpp | 2 + src/V3Subst.h | 4 +- src/V3TSP.cpp | 2 + src/V3TSP.h | 5 +- src/V3Table.cpp | 2 + src/V3Table.h | 4 +- src/V3Task.cpp | 2 + src/V3Task.h | 14 +- src/V3Timing.cpp | 2 + src/V3Timing.h | 3 +- src/V3Trace.cpp | 2 + src/V3Trace.h | 4 +- src/V3TraceDecl.cpp | 2 + src/V3TraceDecl.h | 4 +- src/V3Tristate.cpp | 2 + src/V3Tristate.h | 4 +- src/V3Undriven.cpp | 2 + src/V3Undriven.h | 4 +- src/V3Unknown.cpp | 2 + src/V3Unknown.h | 4 +- src/V3Unroll.cpp | 2 + src/V3Unroll.h | 11 +- src/V3VariableOrder.cpp | 2 + src/V3VariableOrder.h | 4 +- src/V3Width.cpp | 5 +- src/V3Width.h | 14 +- src/V3WidthSel.cpp | 2 + src/Verilator.cpp | 943 +++++++++++++++++++------------------ src/VlcMain.cpp | 2 + src/VlcOptions.h | 10 +- src/VlcTop.cpp | 2 + src/verilog.y | 13 +- 210 files changed, 1365 insertions(+), 913 deletions(-) diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 471af2c79..162da5d85 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -389,7 +389,7 @@ HEADER_CC_H := $(filter-out $(NON_STANDALONE_HEADERS), $(notdir $(wildcard $(src header_cc: $(addsuffix __header_cc.o, $(basename $(HEADER_CC_H))) %__header_cc.cpp: %.h - $(PYTHON3) $(srcdir)/../bin/verilator_includer $^ > $@ + $(PYTHON3) $(srcdir)/../bin/verilator_includer -DVL_MT_DISABLED_CODE_UNIT=1 $^ > $@ .SUFFIXES: diff --git a/src/V3Active.cpp b/src/V3Active.cpp index 54b110d00..857c34045 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -26,6 +26,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Active.h b/src/V3Active.h index 81684c6f1..090d7b019 100644 --- a/src/V3Active.h +++ b/src/V3Active.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Active final { public: - static void activeAll(AstNetlist* nodep); + static void activeAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3ActiveTop.cpp b/src/V3ActiveTop.cpp index 16cfe6e95..4dc193116 100644 --- a/src/V3ActiveTop.cpp +++ b/src/V3ActiveTop.cpp @@ -23,6 +23,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3ActiveTop.h b/src/V3ActiveTop.h index ac9361c7d..ae3821112 100644 --- a/src/V3ActiveTop.h +++ b/src/V3ActiveTop.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3ActiveTop final { public: - static void activeTopAll(AstNetlist* nodep); + static void activeTopAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index e010215d9..b13fae8c0 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Assert.h b/src/V3Assert.h index dcf26756a..f345c2e27 100644 --- a/src/V3Assert.h +++ b/src/V3Assert.h @@ -21,12 +21,13 @@ #include "verilatedos.h" #include "V3Ast.h" +#include "V3ThreadSafety.h" //============================================================================ class V3Assert final { public: - static void assertAll(AstNetlist* nodep); + static void assertAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp index 766d454d1..bf416c276 100644 --- a/src/V3AssertPre.cpp +++ b/src/V3AssertPre.cpp @@ -19,6 +19,8 @@ // Transform clocking blocks into imperative logic //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3AssertPre.h b/src/V3AssertPre.h index 9cc61528d..dc58f6054 100644 --- a/src/V3AssertPre.h +++ b/src/V3AssertPre.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3AssertPre final { public: - static void assertPreAll(AstNetlist* nodep); + static void assertPreAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 12b7ce9f2..a6b8aa63f 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -1034,7 +1034,7 @@ class AstExecGraph final : public AstNode { const string m_name; // Name of this AstExecGraph (for uniqueness at code generation) public: - explicit AstExecGraph(FileLine* fl, const string& name); + explicit AstExecGraph(FileLine* fl, const string& name) VL_MT_DISABLED; ASTGEN_MEMBERS_AstExecGraph; ~AstExecGraph() override; const char* broken() const override { diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 81dfdbaf4..3ba281286 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -357,10 +357,10 @@ AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* r } } -AstExecGraph::AstExecGraph(FileLine* fileline, const string& name) - : ASTGEN_SUPER_ExecGraph(fileline) - , m_depGraphp{new V3Graph} - , m_name{name} {} +AstExecGraph::AstExecGraph(FileLine* fileline, const string& name) VL_MT_DISABLED + : ASTGEN_SUPER_ExecGraph(fileline), + m_depGraphp{new V3Graph}, + m_name{name} {} AstExecGraph::~AstExecGraph() { VL_DO_DANGLING(delete m_depGraphp, m_depGraphp); } diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index abe27a1dc..1ff68713b 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -26,6 +26,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Begin.h b/src/V3Begin.h index b62f6ce34..b2cd44a01 100644 --- a/src/V3Begin.h +++ b/src/V3Begin.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Begin final { public: - static void debeginAll(AstNetlist* nodep); + static void debeginAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Branch.cpp b/src/V3Branch.cpp index e84e041b5..f24307808 100644 --- a/src/V3Branch.cpp +++ b/src/V3Branch.cpp @@ -23,6 +23,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Branch.h b/src/V3Branch.h index a86d9fae1..79f793307 100644 --- a/src/V3Branch.h +++ b/src/V3Branch.h @@ -20,6 +20,8 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ @@ -27,7 +29,7 @@ class AstNetlist; class V3Branch final { public: // CONSTRUCTORS - static void branchAll(AstNetlist* nodep); + static void branchAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3CCtors.cpp b/src/V3CCtors.cpp index 0cec01ab1..1727126ed 100644 --- a/src/V3CCtors.cpp +++ b/src/V3CCtors.cpp @@ -24,6 +24,8 @@ // This transformation honors outputSplitCFuncs. //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3CCtors.h b/src/V3CCtors.h index 4a244dca2..c719d65d1 100644 --- a/src/V3CCtors.h +++ b/src/V3CCtors.h @@ -20,14 +20,16 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + //============================================================================ class V3CCtors final { public: - static void cctorsAll(); + static void cctorsAll() VL_MT_DISABLED; private: - static void evalAsserts(); + static void evalAsserts() VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3CUse.cpp b/src/V3CUse.cpp index 1fae654db..05215f5bc 100644 --- a/src/V3CUse.cpp +++ b/src/V3CUse.cpp @@ -22,6 +22,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3CUse.h b/src/V3CUse.h index 1ab67c8f0..4e475f3b8 100644 --- a/src/V3CUse.h +++ b/src/V3CUse.h @@ -20,11 +20,13 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + //============================================================================ class V3CUse final { public: - static void cUseAll(); + static void cUseAll() VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Case.cpp b/src/V3Case.cpp index 9110d9b93..53cc524ce 100644 --- a/src/V3Case.cpp +++ b/src/V3Case.cpp @@ -34,6 +34,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Case.h b/src/V3Case.h index 0fa9fb11f..d78984d16 100644 --- a/src/V3Case.h +++ b/src/V3Case.h @@ -20,6 +20,8 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; class AstNodeCase; @@ -27,8 +29,8 @@ class AstNodeCase; class V3Case final { public: - static void caseAll(AstNetlist* nodep); - static void caseLint(AstNodeCase* nodep); + static void caseAll(AstNetlist* nodep) VL_MT_DISABLED; + static void caseLint(AstNodeCase* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Cast.cpp b/src/V3Cast.cpp index eaecd7320..7362f9c71 100644 --- a/src/V3Cast.cpp +++ b/src/V3Cast.cpp @@ -37,6 +37,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Cast.h b/src/V3Cast.h index 1f359dc9c..23177ced6 100644 --- a/src/V3Cast.h +++ b/src/V3Cast.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Cast final { public: - static void castAll(AstNetlist* nodep); + static void castAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Class.cpp b/src/V3Class.cpp index ab62db18c..e71de0dab 100644 --- a/src/V3Class.cpp +++ b/src/V3Class.cpp @@ -20,6 +20,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Class.h b/src/V3Class.h index bde611ead..8401a9504 100644 --- a/src/V3Class.h +++ b/src/V3Class.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Class final { public: - static void classAll(AstNetlist* nodep); + static void classAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Clean.cpp b/src/V3Clean.cpp index 026ebe039..9023fadd7 100644 --- a/src/V3Clean.cpp +++ b/src/V3Clean.cpp @@ -23,6 +23,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Clean.h b/src/V3Clean.h index 451004d00..be37e2420 100644 --- a/src/V3Clean.h +++ b/src/V3Clean.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Clean final { public: - static void cleanAll(AstNetlist* nodep); + static void cleanAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Clock.cpp b/src/V3Clock.cpp index c72730ffb..6a66f45e5 100644 --- a/src/V3Clock.cpp +++ b/src/V3Clock.cpp @@ -27,6 +27,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Clock.h b/src/V3Clock.h index c809b9113..da009685b 100644 --- a/src/V3Clock.h +++ b/src/V3Clock.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Clock final { public: - static void clockAll(AstNetlist* nodep); + static void clockAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Combine.cpp b/src/V3Combine.cpp index a4d425229..f6fcd3260 100644 --- a/src/V3Combine.cpp +++ b/src/V3Combine.cpp @@ -19,6 +19,8 @@ // Also drop empty CFuncs //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Combine.h b/src/V3Combine.h index 2ea3ef581..466cb850c 100644 --- a/src/V3Combine.h +++ b/src/V3Combine.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Combine final { public: - static void combineAll(AstNetlist* nodep); + static void combineAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Common.cpp b/src/V3Common.cpp index e4cddae9d..d6e08d083 100644 --- a/src/V3Common.cpp +++ b/src/V3Common.cpp @@ -20,6 +20,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Common.h b/src/V3Common.h index f71e7ba2e..854077e07 100644 --- a/src/V3Common.h +++ b/src/V3Common.h @@ -20,11 +20,13 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + //============================================================================ class V3Common final { public: - static void commonAll(); + static void commonAll() VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Const.cpp b/src/V3Const.cpp index b96b2fee8..ea0e4bea6 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -20,6 +20,8 @@ // If operands are constant, replace this node with constant. //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Const.h b/src/V3Const.h index a0c0cf797..e992faca8 100644 --- a/src/V3Const.h +++ b/src/V3Const.h @@ -21,43 +21,44 @@ #include "verilatedos.h" #include "V3Ast.h" +#include "V3ThreadSafety.h" //============================================================================ class V3Const final { public: - static AstNode* constifyParamsEdit(AstNode* nodep); - static AstNodeExpr* constifyParamsEdit(AstNodeExpr* exprp) { + static AstNode* constifyParamsEdit(AstNode* nodep) VL_MT_DISABLED; + static AstNodeExpr* constifyParamsEdit(AstNodeExpr* exprp) VL_MT_DISABLED { return VN_AS(constifyParamsEdit(static_cast(exprp)), NodeExpr); } - static AstNode* constifyParamsNoWarnEdit(AstNode* nodep); - static AstNodeExpr* constifyParamsNoWarnEdit(AstNodeExpr* exprp) { + static AstNode* constifyParamsNoWarnEdit(AstNode* nodep) VL_MT_DISABLED; + static AstNodeExpr* constifyParamsNoWarnEdit(AstNodeExpr* exprp) VL_MT_DISABLED { return VN_AS(constifyParamsNoWarnEdit(static_cast(exprp)), NodeExpr); } - static AstNode* constifyGenerateParamsEdit(AstNode* nodep); + static AstNode* constifyGenerateParamsEdit(AstNode* nodep) VL_MT_DISABLED; // Only do constant pushing, without removing dead logic - static void constifyAllLive(AstNetlist* nodep); + static void constifyAllLive(AstNetlist* nodep) VL_MT_DISABLED; // Everything that's possible - static void constifyAll(AstNetlist* nodep); + static void constifyAll(AstNetlist* nodep) VL_MT_DISABLED; // Also, warn - static void constifyAllLint(AstNetlist* nodep); + static void constifyAllLint(AstNetlist* nodep) VL_MT_DISABLED; // C++ datatypes - static void constifyCpp(AstNetlist* nodep); + static void constifyCpp(AstNetlist* nodep) VL_MT_DISABLED; // Only the current node and lower // Return new node that may have replaced nodep - static AstNode* constifyEditCpp(AstNode* nodep); - static AstNodeExpr* constifyEditCpp(AstNodeExpr* exprp) { + static AstNode* constifyEditCpp(AstNode* nodep) VL_MT_DISABLED; + static AstNodeExpr* constifyEditCpp(AstNodeExpr* exprp) VL_MT_DISABLED { return VN_AS(constifyEditCpp(static_cast(exprp)), NodeExpr); } // Only the current node and lower // Return new node that may have replaced nodep - static AstNode* constifyEdit(AstNode* nodep); - static AstNodeExpr* constifyEdit(AstNodeExpr* exprp) { + static AstNode* constifyEdit(AstNode* nodep) VL_MT_DISABLED; + static AstNodeExpr* constifyEdit(AstNodeExpr* exprp) VL_MT_DISABLED { return VN_AS(constifyEdit(static_cast(exprp)), NodeExpr); } // Only the current node and lower, with special SenTree optimization // Return new node that may have replaced nodep - static AstNode* constifyExpensiveEdit(AstNode* nodep); + static AstNode* constifyExpensiveEdit(AstNode* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Coverage.cpp b/src/V3Coverage.cpp index 280e652cc..85c9af732 100644 --- a/src/V3Coverage.cpp +++ b/src/V3Coverage.cpp @@ -24,6 +24,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Coverage.h b/src/V3Coverage.h index 3a29fd7cb..b3a48739b 100644 --- a/src/V3Coverage.h +++ b/src/V3Coverage.h @@ -20,6 +20,8 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ @@ -27,7 +29,7 @@ class AstNetlist; class V3Coverage final { public: // CONSTRUCTORS - static void coverage(AstNetlist* rootp); + static void coverage(AstNetlist* rootp) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3CoverageJoin.cpp b/src/V3CoverageJoin.cpp index dbfc26862..58176cd69 100644 --- a/src/V3CoverageJoin.cpp +++ b/src/V3CoverageJoin.cpp @@ -17,6 +17,8 @@ // If two COVERTOGGLEs have same VARSCOPE, combine them //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3CoverageJoin.h b/src/V3CoverageJoin.h index 3f1a88345..9441b3742 100644 --- a/src/V3CoverageJoin.h +++ b/src/V3CoverageJoin.h @@ -20,6 +20,8 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ @@ -27,7 +29,7 @@ class AstNetlist; class V3CoverageJoin final { public: // CONSTRUCTORS - static void coverageJoin(AstNetlist* rootp); + static void coverageJoin(AstNetlist* rootp) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index dd91a542d..6a0f8ae7a 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -33,6 +33,8 @@ // here after scoping to allow more dead node removal. //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Dead.h b/src/V3Dead.h index c94508137..614bc7270 100644 --- a/src/V3Dead.h +++ b/src/V3Dead.h @@ -20,6 +20,8 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ @@ -27,13 +29,13 @@ class AstNetlist; class V3Dead final { public: // Modules, no vars/dtypes - static void deadifyModules(AstNetlist* nodep); + static void deadifyModules(AstNetlist* nodep) VL_MT_DISABLED; // Modules, Data types - static void deadifyDTypes(AstNetlist* nodep); - static void deadifyDTypesScoped(AstNetlist* nodep); + static void deadifyDTypes(AstNetlist* nodep) VL_MT_DISABLED; + static void deadifyDTypesScoped(AstNetlist* nodep) VL_MT_DISABLED; // Everything that's possible - static void deadifyAll(AstNetlist* nodep); - static void deadifyAllScoped(AstNetlist* nodep); + static void deadifyAll(AstNetlist* nodep) VL_MT_DISABLED; + static void deadifyAllScoped(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index d8d9185ff..eba736d48 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -48,6 +48,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Delayed.h b/src/V3Delayed.h index dd36bda69..c8147cb0d 100644 --- a/src/V3Delayed.h +++ b/src/V3Delayed.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Delayed final { public: - static void delayedAll(AstNetlist* nodep); + static void delayedAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Depth.cpp b/src/V3Depth.cpp index 32797e069..7f1012f50 100644 --- a/src/V3Depth.cpp +++ b/src/V3Depth.cpp @@ -23,6 +23,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Depth.h b/src/V3Depth.h index a35aaf56a..b844330cf 100644 --- a/src/V3Depth.h +++ b/src/V3Depth.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Depth final { public: - static void depthAll(AstNetlist* nodep); + static void depthAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3DepthBlock.cpp b/src/V3DepthBlock.cpp index 4adebda13..b0e65d136 100644 --- a/src/V3DepthBlock.cpp +++ b/src/V3DepthBlock.cpp @@ -20,6 +20,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3DepthBlock.h b/src/V3DepthBlock.h index 0282d0487..9f29b0ce9 100644 --- a/src/V3DepthBlock.h +++ b/src/V3DepthBlock.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3DepthBlock final { public: - static void depthBlockAll(AstNetlist* nodep); + static void depthBlockAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Descope.cpp b/src/V3Descope.cpp index fe5fe15f9..8b68ca011 100644 --- a/src/V3Descope.cpp +++ b/src/V3Descope.cpp @@ -22,6 +22,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Descope.h b/src/V3Descope.h index b8f77b8db..ff1e0a9ff 100644 --- a/src/V3Descope.h +++ b/src/V3Descope.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Descope final { public: - static void descopeAll(AstNetlist* nodep); + static void descopeAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Dfg.cpp b/src/V3Dfg.cpp index c3caf86c8..4e70c94ac 100644 --- a/src/V3Dfg.cpp +++ b/src/V3Dfg.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Dfg.h b/src/V3Dfg.h index e0d72335b..3be33cf06 100644 --- a/src/V3Dfg.h +++ b/src/V3Dfg.h @@ -35,8 +35,10 @@ #include "V3Ast.h" #include "V3Error.h" +#include "V3Global.h" #include "V3Hash.h" #include "V3List.h" +#include "V3ThreadSafety.h" #include "V3Dfg__gen_forward_class_decls.h" // From ./astgen @@ -140,8 +142,8 @@ class DfgGraph final { public: // CONSTRUCTOR - explicit DfgGraph(AstModule& module, const string& name = ""); - ~DfgGraph(); + explicit DfgGraph(AstModule& module, const string& name = "") VL_MT_DISABLED; + ~DfgGraph() VL_MT_DISABLED; VL_UNCOPYABLE(DfgGraph); // METHODS @@ -183,12 +185,12 @@ public: inline void forEachVertex(std::function f) const; // Add contents of other graph to this graph. Leaves other graph empty. - void addGraph(DfgGraph& other); + void addGraph(DfgGraph& other) VL_MT_DISABLED; // Split this graph into individual components (unique sub-graphs with no edges between them). // Also removes any vertices that are not weakly connected to any variable. // Leaves 'this' graph empty. - std::vector> splitIntoComponents(std::string label); + std::vector> splitIntoComponents(std::string label) VL_MT_DISABLED; // Extract cyclic sub-graphs from 'this' graph. Cyclic sub-graphs are those that contain at // least one strongly connected component (SCC) plus any other vertices that feed or sink from @@ -198,26 +200,27 @@ public: // of a cycle) are left in 'this' graph. This means that at the end 'this' graph is guaranteed // to be a DAG (acyclic). 'this' will not necessarily be a connected graph at the end, even if // it was originally connected. - std::vector> extractCyclicComponents(std::string label); + std::vector> + extractCyclicComponents(std::string label) VL_MT_DISABLED; // Dump graph in Graphviz format into the given stream 'os'. 'label' is added to the name of // the graph which is included in the output. - void dumpDot(std::ostream& os, const string& label = "") const; + void dumpDot(std::ostream& os, const string& label = "") const VL_MT_DISABLED; // Dump graph in Graphviz format into a new file with the given 'fileName'. 'label' is added to // the name of the graph which is included in the output. - void dumpDotFile(const string& fileName, const string& label = "") const; + void dumpDotFile(const string& fileName, const string& label = "") const VL_MT_DISABLED; // Dump graph in Graphviz format into a new automatically numbered debug file. 'label' is // added to the name of the graph, which is included in the file name and the output. - void dumpDotFilePrefixed(const string& label = "") const; + void dumpDotFilePrefixed(const string& label = "") const VL_MT_DISABLED; // Dump upstream (source) logic cone starting from given vertex into a file with the given // 'fileName'. 'name' is the name of the graph, which is included in the output. void dumpDotUpstreamCone(const string& fileName, const DfgVertex& vtx, - const string& name = "") const; + const string& name = "") const VL_MT_DISABLED; // Dump all individual logic cones driving external variables in Graphviz format into separate // new automatically numbered debug files. 'label' is added to the name of the graph, which is // included in the file names and the output. This is useful for very large graphs that are // otherwise difficult to browse visually due to their size. - void dumpDotAllVarConesPrefixed(const string& label = "") const; + void dumpDotAllVarConesPrefixed(const string& label = "") const VL_MT_DISABLED; }; //------------------------------------------------------------------------------ @@ -243,9 +246,9 @@ public: // The sink (consumer) of this edge DfgVertex* sinkp() const { return m_sinkp; } // Remove driver of this edge - void unlinkSource(); + void unlinkSource() VL_MT_DISABLED; // Relink this edge to be driven from the given new source vertex - void relinkSource(DfgVertex* newSourcep); + void relinkSource(DfgVertex* newSourcep) VL_MT_DISABLED; }; //------------------------------------------------------------------------------ @@ -272,10 +275,10 @@ protected: UserDataStorage m_userDataStorage; // User data storage // CONSTRUCTOR - DfgVertex(DfgGraph& dfg, VDfgType type, FileLine* flp, AstNodeDType* dtypep); + DfgVertex(DfgGraph& dfg, VDfgType type, FileLine* flp, AstNodeDType* dtypep) VL_MT_DISABLED; public: - virtual ~DfgVertex(); + virtual ~DfgVertex() VL_MT_DISABLED; // METHODS private: @@ -283,10 +286,10 @@ private: virtual void accept(DfgVisitor& v) = 0; // Part of Vertex equality only dependent on this vertex - virtual bool selfEquals(const DfgVertex& that) const; + virtual bool selfEquals(const DfgVertex& that) const VL_MT_DISABLED; // Part of Vertex hash only dependent on this vertex - virtual V3Hash selfHash() const; + virtual V3Hash selfHash() const VL_MT_DISABLED; public: // Supported packed types @@ -409,7 +412,7 @@ public: // semantics of the logic. The 'cache' argument is used to store results to avoid repeat // evaluations, but it requires that the upstream sources of the compared vertices do not // change between invocations. - bool equals(const DfgVertex& that, EqualsCache& cache) const; + bool equals(const DfgVertex& that, EqualsCache& cache) const VL_MT_DISABLED; // Uncached version of 'equals' bool equals(const DfgVertex& that) const { @@ -419,7 +422,7 @@ public: // Hash of vertex (depends on this vertex and all upstream vertices feeding into this vertex). // Uses user data for caching hashes - V3Hash hash(); + V3Hash hash() VL_MT_DISABLED; // Source edges of this vertex virtual std::pair sourceEdges() = 0; @@ -437,13 +440,13 @@ public: bool hasMultipleSinks() const { return m_sinksp && m_sinksp->m_nextp; } // Fanout (number of sinks) of this vertex (expensive to compute) - uint32_t fanout() const; + uint32_t fanout() const VL_MT_DISABLED; // Unlink from container (graph or builder), then delete this vertex - void unlinkDelete(DfgGraph& dfg); + void unlinkDelete(DfgGraph& dfg) VL_MT_DISABLED; // Relink all sinks to be driven from the given new source - void replaceWith(DfgVertex* newSourcep); + void replaceWith(DfgVertex* newSourcep) VL_MT_DISABLED; // Access to vertex list for faster iteration in important contexts DfgVertex* verticesNext() const { return m_verticesEnt.nextp(); } @@ -451,56 +454,58 @@ public: // Calls given function 'f' for each source vertex of this vertex // Unconnected source edges are not iterated. - inline void forEachSource(std::function f); + inline void forEachSource(std::function f) VL_MT_DISABLED; // Calls given function 'f' for each source vertex of this vertex // Unconnected source edges are not iterated. - inline void forEachSource(std::function f) const; + inline void forEachSource(std::function f) const VL_MT_DISABLED; // Calls given function 'f' for each source edge of this vertex. Also passes source index. - inline void forEachSourceEdge(std::function f); + inline void forEachSourceEdge(std::function f) VL_MT_DISABLED; // Calls given function 'f' for each source edge of this vertex. Also passes source index. - inline void forEachSourceEdge(std::function f) const; + inline void + forEachSourceEdge(std::function f) const VL_MT_DISABLED; // Calls given function 'f' for each sink vertex of this vertex // Unlinking/deleting the given sink during iteration is safe, but not other sinks of this // vertex. - inline void forEachSink(std::function f); + inline void forEachSink(std::function f) VL_MT_DISABLED; // Calls given function 'f' for each sink vertex of this vertex - inline void forEachSink(std::function f) const; + inline void forEachSink(std::function f) const VL_MT_DISABLED; // Calls given function 'f' for each sink edge of this vertex. // Unlinking/deleting the given sink during iteration is safe, but not other sinks of this // vertex. - inline void forEachSinkEdge(std::function f); + inline void forEachSinkEdge(std::function f) VL_MT_DISABLED; // Calls given function 'f' for each sink edge of this vertex. - inline void forEachSinkEdge(std::function f) const; + inline void forEachSinkEdge(std::function f) const VL_MT_DISABLED; // Returns first source edge which satisfies the given predicate 'p', or nullptr if no such // sink vertex exists - inline const DfgEdge* findSourceEdge(std::function p) const; + inline const DfgEdge* + findSourceEdge(std::function p) const VL_MT_DISABLED; // Returns first sink vertex of type 'Vertex' which satisfies the given predicate 'p', // or nullptr if no such sink vertex exists template - inline Vertex* findSink(std::function p) const; + inline Vertex* findSink(std::function p) const VL_MT_DISABLED; // Returns first sink vertex of type 'Vertex', or nullptr if no such sink vertex exists. // This is a special case of 'findSink' above with the predicate always true. template - inline Vertex* findSink() const; + inline Vertex* findSink() const VL_MT_DISABLED; // Is this a DfgConst that is all zeroes - inline bool isZero() const; + inline bool isZero() const VL_MT_DISABLED; // Is this a DfgConst that is all ones - inline bool isOnes() const; + inline bool isOnes() const VL_MT_DISABLED; // Should this vertex be inlined when rendering to Ast, or be stored to a temporary - inline bool inlined() const; + inline bool inlined() const VL_MT_DISABLED; // Methods that allow DfgVertex to participate in error reporting/messaging void v3errorEnd(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex) { diff --git a/src/V3DfgAstToDfg.cpp b/src/V3DfgAstToDfg.cpp index da265a1ff..c4aa2d1be 100644 --- a/src/V3DfgAstToDfg.cpp +++ b/src/V3DfgAstToDfg.cpp @@ -26,6 +26,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3DfgDecomposition.cpp b/src/V3DfgDecomposition.cpp index 9dc61a07d..31bb001ce 100644 --- a/src/V3DfgDecomposition.cpp +++ b/src/V3DfgDecomposition.cpp @@ -18,6 +18,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3DfgDfgToAst.cpp b/src/V3DfgDfgToAst.cpp index 089e551b4..43728cef9 100644 --- a/src/V3DfgDfgToAst.cpp +++ b/src/V3DfgDfgToAst.cpp @@ -26,6 +26,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3DfgOptimizer.cpp b/src/V3DfgOptimizer.cpp index a299cae0e..0a514723b 100644 --- a/src/V3DfgOptimizer.cpp +++ b/src/V3DfgOptimizer.cpp @@ -18,6 +18,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3DfgOptimizer.h b/src/V3DfgOptimizer.h index 16b4b34cb..8ec1ede6c 100644 --- a/src/V3DfgOptimizer.h +++ b/src/V3DfgOptimizer.h @@ -21,15 +21,16 @@ #include "verilatedos.h" #include "V3Ast.h" +#include "V3ThreadSafety.h" //============================================================================ namespace V3DfgOptimizer { // Extract further logic blocks from the design for additional optimization opportunities -void extract(AstNetlist*); +void extract(AstNetlist*) VL_MT_DISABLED; // Optimize the design -void optimize(AstNetlist*, const string& label); +void optimize(AstNetlist*, const string& label) VL_MT_DISABLED; } // namespace V3DfgOptimizer #endif // Guard diff --git a/src/V3DfgPasses.cpp b/src/V3DfgPasses.cpp index 3edfe5a88..44026320e 100644 --- a/src/V3DfgPasses.cpp +++ b/src/V3DfgPasses.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "V3DfgPasses.h" diff --git a/src/V3DfgPasses.h b/src/V3DfgPasses.h index fabe4f92d..6b6689503 100644 --- a/src/V3DfgPasses.h +++ b/src/V3DfgPasses.h @@ -20,6 +20,7 @@ #include "config_build.h" #include "V3DfgPeephole.h" +#include "V3ThreadSafety.h" class AstModule; class DfgGraph; @@ -35,7 +36,7 @@ public: VDouble0 m_eliminated; // Number of common sub-expressions eliminated explicit V3DfgCseContext(const std::string& label) : m_label{label} {} - ~V3DfgCseContext(); + ~V3DfgCseContext() VL_MT_DISABLED; }; class DfgRemoveVarsContext final { @@ -45,7 +46,7 @@ public: VDouble0 m_removed; // Number of redundant variables removed explicit DfgRemoveVarsContext(const std::string& label) : m_label{label} {} - ~DfgRemoveVarsContext(); + ~DfgRemoveVarsContext() VL_MT_DISABLED; }; class V3DfgOptimizationContext final { @@ -73,8 +74,8 @@ public: V3DfgCseContext m_cseContext1{m_label + " 2nd"}; V3DfgPeepholeContext m_peepholeContext{m_label}; DfgRemoveVarsContext m_removeVarsContext{m_label}; - explicit V3DfgOptimizationContext(const std::string& label); - ~V3DfgOptimizationContext(); + explicit V3DfgOptimizationContext(const std::string& label) VL_MT_DISABLED; + ~V3DfgOptimizationContext() VL_MT_DISABLED; const std::string& prefix() const { return m_prefix; } }; @@ -87,29 +88,29 @@ namespace V3DfgPasses { // Construct a DfGGraph representing the combinational logic in the given AstModule. The logic // that is represented by the graph is removed from the given AstModule. Returns the // constructed DfgGraph. -DfgGraph* astToDfg(AstModule&, V3DfgOptimizationContext&); +DfgGraph* astToDfg(AstModule&, V3DfgOptimizationContext&) VL_MT_DISABLED; // Optimize the given DfgGraph -void optimize(DfgGraph&, V3DfgOptimizationContext&); +void optimize(DfgGraph&, V3DfgOptimizationContext&) VL_MT_DISABLED; // Convert DfgGraph back into Ast, and insert converted graph back into its parent module. // Returns the parent module. -AstModule* dfgToAst(DfgGraph&, V3DfgOptimizationContext&); +AstModule* dfgToAst(DfgGraph&, V3DfgOptimizationContext&) VL_MT_DISABLED; //=========================================================================== // Intermediate/internal operations //=========================================================================== // Common subexpression elimination -void cse(DfgGraph&, V3DfgCseContext&); +void cse(DfgGraph&, V3DfgCseContext&) VL_MT_DISABLED; // Inline fully driven variables -void inlineVars(const DfgGraph&); +void inlineVars(const DfgGraph&) VL_MT_DISABLED; // Peephole optimizations -void peephole(DfgGraph&, V3DfgPeepholeContext&); +void peephole(DfgGraph&, V3DfgPeepholeContext&) VL_MT_DISABLED; // Remove redundant variables -void removeVars(DfgGraph&, DfgRemoveVarsContext&); +void removeVars(DfgGraph&, DfgRemoveVarsContext&) VL_MT_DISABLED; // Remove unused nodes -void removeUnused(DfgGraph&); +void removeUnused(DfgGraph&) VL_MT_DISABLED; } // namespace V3DfgPasses #endif diff --git a/src/V3DfgPeephole.cpp b/src/V3DfgPeephole.cpp index 72d1f19b0..c3d969a8e 100644 --- a/src/V3DfgPeephole.cpp +++ b/src/V3DfgPeephole.cpp @@ -21,6 +21,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "V3DfgPeephole.h" diff --git a/src/V3DfgPeephole.h b/src/V3DfgPeephole.h index 70cf8e044..c2d83042e 100644 --- a/src/V3DfgPeephole.h +++ b/src/V3DfgPeephole.h @@ -19,6 +19,8 @@ #include "config_build.h" +#include "V3ThreadSafety.h" + #include #define _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, arg) macro(arg, #arg) @@ -127,8 +129,8 @@ struct V3DfgPeepholeContext final { // Count of applications for each optimization (for statistics) std::array m_count; - explicit V3DfgPeepholeContext(const std::string& label); - ~V3DfgPeepholeContext(); + explicit V3DfgPeepholeContext(const std::string& label) VL_MT_DISABLED; + ~V3DfgPeepholeContext() VL_MT_DISABLED; }; #endif diff --git a/src/V3DfgVertices.h b/src/V3DfgVertices.h index a576d5767..bbcd9bdca 100644 --- a/src/V3DfgVertices.h +++ b/src/V3DfgVertices.h @@ -43,8 +43,8 @@ class DfgVertexVar VL_NOT_FINAL : public DfgVertexVariadic { bool m_hasModRefs = false; // This AstVar is referenced outside the DFG, but in the module bool m_hasExtRefs = false; // This AstVar is referenced from outside the module - bool selfEquals(const DfgVertex& that) const final; - V3Hash selfHash() const final; + bool selfEquals(const DfgVertex& that) const final VL_MT_DISABLED; + V3Hash selfHash() const final VL_MT_DISABLED; public: DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVar* varp, uint32_t initialCapacity) @@ -92,8 +92,8 @@ class DfgConst final : public DfgVertex { V3Number m_num; // Constant value - bool selfEquals(const DfgVertex& that) const override; - V3Hash selfHash() const override; + bool selfEquals(const DfgVertex& that) const override VL_MT_DISABLED; + V3Hash selfHash() const override VL_MT_DISABLED; public: DfgConst(DfgGraph& dfg, FileLine* flp, const V3Number& num) @@ -158,8 +158,8 @@ class DfgSel final : public DfgVertexUnary { // the constant 'lsbp', and as 'DfgMux` for the non-constant 'lsbp'. uint32_t m_lsb = 0; // The LSB index - bool selfEquals(const DfgVertex& that) const override; - V3Hash selfHash() const override; + bool selfEquals(const DfgVertex& that) const override VL_MT_DISABLED; + V3Hash selfHash() const override VL_MT_DISABLED; public: DfgSel(DfgGraph& dfg, FileLine* flp, AstNodeDType* dtypep) diff --git a/src/V3DupFinder.cpp b/src/V3DupFinder.cpp index f41d9b1df..f1e3ab956 100644 --- a/src/V3DupFinder.cpp +++ b/src/V3DupFinder.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3DupFinder.h b/src/V3DupFinder.h index 37118aebc..102ef6a43 100644 --- a/src/V3DupFinder.h +++ b/src/V3DupFinder.h @@ -26,6 +26,7 @@ #include "V3Ast.h" #include "V3Error.h" #include "V3Hasher.h" +#include "V3ThreadSafety.h" #include #include @@ -76,14 +77,14 @@ public: iterator insert(AstNode* nodep) { return emplace(m_hasher(nodep), nodep); } // Erase node from data structure - size_type erase(AstNode* nodep); + size_type erase(AstNode* nodep) VL_MT_DISABLED; // Return duplicate, if one was inserted, with optional user check for sameness - iterator findDuplicate(AstNode* nodep, V3DupFinderUserSame* checkp = nullptr); + iterator findDuplicate(AstNode* nodep, V3DupFinderUserSame* checkp = nullptr) VL_MT_DISABLED; // Dump for debug - void dumpFile(const string& filename, bool tree); - void dumpFilePrefixed(const string& nameComment, bool tree = false); + void dumpFile(const string& filename, bool tree) VL_MT_DISABLED; + void dumpFilePrefixed(const string& nameComment, bool tree = false) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3EmitC.h b/src/V3EmitC.h index 696eb3df6..4ee9460cf 100644 --- a/src/V3EmitC.h +++ b/src/V3EmitC.h @@ -20,17 +20,19 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + //============================================================================ class V3EmitC final { public: - static void emitcConstPool(); - static void emitcHeaders(); + static void emitcConstPool() VL_MT_DISABLED; + static void emitcHeaders() VL_MT_DISABLED; static void emitcImp(); - static void emitcInlines(); - static void emitcModel(); - static void emitcSyms(bool dpiHdrOnly = false); - static void emitcFiles(); + static void emitcInlines() VL_MT_DISABLED; + static void emitcModel() VL_MT_DISABLED; + static void emitcSyms(bool dpiHdrOnly = false) VL_MT_DISABLED; + static void emitcFiles() VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index d3d797e3a..5abf33271 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -22,7 +22,7 @@ #include "V3Ast.h" #include "V3File.h" -#include "V3Global.h" +#include "V3ThreadSafety.h" #include #include diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 6481ea2c4..8dbe3ca70 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -23,6 +23,7 @@ #include "V3EmitCConstInit.h" #include "V3Global.h" #include "V3MemberMap.h" +#include "V3ThreadSafety.h" #include #include diff --git a/src/V3EmitCMain.cpp b/src/V3EmitCMain.cpp index 3ea952903..873519d5d 100644 --- a/src/V3EmitCMain.cpp +++ b/src/V3EmitCMain.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3EmitCMain.h b/src/V3EmitCMain.h index cf4d04f9f..65877429b 100644 --- a/src/V3EmitCMain.h +++ b/src/V3EmitCMain.h @@ -20,11 +20,13 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + //============================================================================ class V3EmitCMain final { public: - static void emit(); + static void emit() VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp index 071808934..6598da9a8 100644 --- a/src/V3EmitCMake.cpp +++ b/src/V3EmitCMake.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3EmitCMake.h b/src/V3EmitCMake.h index 1f2a11246..ac611386c 100644 --- a/src/V3EmitCMake.h +++ b/src/V3EmitCMake.h @@ -20,11 +20,13 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + //============================================================================ class V3EmitCMake final { public: - static void emit(); + static void emit() VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp index 3f988ed32..8eff11e6f 100644 --- a/src/V3EmitCModel.cpp +++ b/src/V3EmitCModel.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 0ae5d82fd..4a041d784 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index 02696c342..3f38e5119 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3EmitMk.h b/src/V3EmitMk.h index 0ddfdba66..2c043890b 100644 --- a/src/V3EmitMk.h +++ b/src/V3EmitMk.h @@ -20,6 +20,8 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class V3HierBlockPlan; //============================================================================ @@ -29,8 +31,8 @@ public: // Number of source files after which to use parallel compiles static const size_t PARALLEL_FILE_CNT_THRESHOLD = 128; - static void emitmk(); - static void emitHierVerilation(const V3HierBlockPlan* planp); + static void emitmk() VL_MT_DISABLED; + static void emitHierVerilation(const V3HierBlockPlan* planp) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3EmitV.h b/src/V3EmitV.h index 8af3061df..80be5453a 100644 --- a/src/V3EmitV.h +++ b/src/V3EmitV.h @@ -20,6 +20,8 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNode; class AstSenTree; diff --git a/src/V3EmitXml.cpp b/src/V3EmitXml.cpp index 5466bf2f4..9065a24b7 100644 --- a/src/V3EmitXml.cpp +++ b/src/V3EmitXml.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3EmitXml.h b/src/V3EmitXml.h index 399f3f743..420795b0d 100644 --- a/src/V3EmitXml.h +++ b/src/V3EmitXml.h @@ -20,11 +20,13 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + //============================================================================ class V3EmitXml final { public: - static void emitxml(); + static void emitxml() VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Error.cpp b/src/V3Error.cpp index 48966be77..5d915f9c5 100644 --- a/src/V3Error.cpp +++ b/src/V3Error.cpp @@ -291,22 +291,27 @@ void V3Error::vlAbort() { VL_GCOV_DUMP(); std::abort(); } -void V3Error::v3errorAcquireLock() VL_ACQUIRE(s().m_mutex) { -#ifndef V3ERROR_NO_GLOBAL_ - V3Error::s().m_mutex.lockCheckStopRequest( - []() -> void { V3ThreadPool::s().waitIfStopRequested(); }); +void V3Error::v3errorAcquireLock(bool mtDisabledCodeUnit) VL_ACQUIRE(s().m_mutex) { +#if !defined(V3ERROR_NO_GLOBAL_) + if (!mtDisabledCodeUnit) { + V3Error::s().m_mutex.lockCheckStopRequest( + []() -> void { V3ThreadPool::s().waitIfStopRequested(); }); + } else { + V3Error::s().m_mutex.lock(); + } #else V3Error::s().m_mutex.lock(); #endif } -std::ostringstream& V3Error::v3errorPrep(V3ErrorCode code) VL_ACQUIRE(s().m_mutex) { - v3errorAcquireLock(); +std::ostringstream& V3Error::v3errorPrep(V3ErrorCode code, bool mtDisabledCodeUnit) + VL_ACQUIRE(s().m_mutex) { + v3errorAcquireLock(mtDisabledCodeUnit); s().v3errorPrep(code); return v3errorStr(); } -std::ostringstream& V3Error::v3errorPrepFileLine(V3ErrorCode code, const char* file, int line) - VL_ACQUIRE(s().m_mutex) { - v3errorPrep(code) << file << ":" << std::dec << line << ": "; +std::ostringstream& V3Error::v3errorPrepFileLine(V3ErrorCode code, const char* file, int line, + bool mtDisabledCodeUnit) VL_ACQUIRE(s().m_mutex) { + v3errorPrep(code, mtDisabledCodeUnit) << file << ":" << std::dec << line << ": "; return v3errorStr(); } std::ostringstream& V3Error::v3errorStr() VL_REQUIRES(s().m_mutex) { return s().v3errorStr(); } diff --git a/src/V3Error.h b/src/V3Error.h index b6c92e8af..87c6c0bad 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -24,7 +24,7 @@ // Limited V3 headers here - this is a base class for Vlc etc #include "V3String.h" -#ifndef V3ERROR_NO_GLOBAL_ +#ifndef VL_MT_DISABLED_CODE_UNIT #include "V3ThreadPool.h" #endif @@ -518,9 +518,11 @@ public: // Internals for v3error()/v3fatal() macros only // Error end takes the string stream to output, be careful to seek() as needed - static void v3errorAcquireLock() VL_ACQUIRE(s().m_mutex); - static std::ostringstream& v3errorPrep(V3ErrorCode code) VL_ACQUIRE(s().m_mutex); - static std::ostringstream& v3errorPrepFileLine(V3ErrorCode code, const char* file, int line) + static void v3errorAcquireLock(bool checkStopRequest) VL_ACQUIRE(s().m_mutex); + static std::ostringstream& v3errorPrep(V3ErrorCode code, bool mtDisabledCodeUnit) + VL_ACQUIRE(s().m_mutex); + static std::ostringstream& v3errorPrepFileLine(V3ErrorCode code, const char* file, int line, + bool mtDisabledCodeUnit) VL_ACQUIRE(s().m_mutex); static std::ostringstream& v3errorStr() VL_REQUIRES(s().m_mutex); // static, but often overridden in classes. @@ -530,8 +532,15 @@ public: }; // Global versions, so that if the class doesn't define an operator, we get the functions anyway. -void v3errorEnd(std::ostringstream& sstr) VL_RELEASE(V3Error::s().m_mutex); -void v3errorEndFatal(std::ostringstream& sstr) VL_RELEASE(V3Error::s().m_mutex) VL_ATTR_NORETURN; +void v3errorEnd(std::ostringstream& sstr) VL_RELEASE(V3Error::s().m_mutex) VL_MT_SAFE; +void v3errorEndFatal(std::ostringstream& sstr) + VL_RELEASE(V3Error::s().m_mutex) VL_MT_SAFE VL_ATTR_NORETURN; + +#ifdef VL_MT_DISABLED_CODE_UNIT +#define VL_MT_DISABLED_CODE_UNIT_DEFINED 1 +#else +#define VL_MT_DISABLED_CODE_UNIT_DEFINED 0 +#endif // Theses allow errors using << operators: v3error("foo"<<"bar"); // Careful, you can't put () around msg, as you would in most macro definitions. @@ -541,9 +550,12 @@ void v3errorEndFatal(std::ostringstream& sstr) VL_RELEASE(V3Error::s().m_mutex) // the comma operator (,) to guarantee the execution order here. #define v3errorBuildMessage(prep, msg) \ (prep, static_cast(V3Error::v3errorStr() << msg)) -#define v3warnCode(code, msg) v3errorEnd(v3errorBuildMessage(V3Error::v3errorPrep(code), msg)) +#define v3warnCode(code, msg) \ + v3errorEnd( \ + v3errorBuildMessage(V3Error::v3errorPrep(code, VL_MT_DISABLED_CODE_UNIT_DEFINED), msg)) #define v3warnCodeFatal(code, msg) \ - v3errorEndFatal(v3errorBuildMessage(V3Error::v3errorPrep(code), msg)) + v3errorEndFatal( \ + v3errorBuildMessage(V3Error::v3errorPrep(code, VL_MT_DISABLED_CODE_UNIT_DEFINED), msg)) #define v3warn(code, msg) v3warnCode(V3ErrorCode::code, msg) #define v3info(msg) v3warnCode(V3ErrorCode::EC_INFO, msg) #define v3error(msg) v3warnCode(V3ErrorCode::EC_ERROR, msg) @@ -553,10 +565,13 @@ void v3errorEndFatal(std::ostringstream& sstr) VL_RELEASE(V3Error::s().m_mutex) // Use this instead of fatal() to mention the source code line. #define v3fatalSrc(msg) \ v3errorEndFatal(v3errorBuildMessage( \ - V3Error::v3errorPrepFileLine(V3ErrorCode::EC_FATALSRC, __FILE__, __LINE__), msg)) + V3Error::v3errorPrepFileLine(V3ErrorCode::EC_FATALSRC, __FILE__, __LINE__, \ + VL_MT_DISABLED_CODE_UNIT_DEFINED), \ + msg)) // Use this when normal v3fatal is called in static method that overrides fileline. #define v3fatalStatic(msg) \ - ::v3errorEndFatal(v3errorBuildMessage(V3Error::v3errorPrep(V3ErrorCode::EC_FATAL), msg)) + ::v3errorEndFatal(v3errorBuildMessage( \ + V3Error::v3errorPrep(V3ErrorCode::EC_FATAL, VL_MT_DISABLED_CODE_UNIT_DEFINED), msg)) #define UINFO(level, stmsg) \ do { \ diff --git a/src/V3Expand.cpp b/src/V3Expand.cpp index 7af734fe8..2bfe49c5a 100644 --- a/src/V3Expand.cpp +++ b/src/V3Expand.cpp @@ -25,6 +25,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Expand.h b/src/V3Expand.h index 01938f7a9..e3f8fc630 100644 --- a/src/V3Expand.h +++ b/src/V3Expand.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Expand final { public: - static void expandAll(AstNetlist* nodep); + static void expandAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Force.cpp b/src/V3Force.cpp index 464ea6237..51437482b 100644 --- a/src/V3Force.cpp +++ b/src/V3Force.cpp @@ -37,6 +37,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Force.h b/src/V3Force.h index 0318f80e3..647d6c813 100644 --- a/src/V3Force.h +++ b/src/V3Force.h @@ -21,13 +21,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Force final { public: - static void forceAll(AstNetlist* nodep); + static void forceAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Fork.cpp b/src/V3Fork.cpp index db64eda77..bce03b9fa 100644 --- a/src/V3Fork.cpp +++ b/src/V3Fork.cpp @@ -38,6 +38,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Fork.h b/src/V3Fork.h index e36b530cb..53bd6c19d 100644 --- a/src/V3Fork.h +++ b/src/V3Fork.h @@ -21,6 +21,8 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ @@ -29,10 +31,10 @@ class V3Fork final { public: // Move/copy variables to "anonymous" objects if their lifetime might exceed the scope of a // procedure that declared them. Update the references apropriately. - static void makeDynamicScopes(AstNetlist* nodep); + static void makeDynamicScopes(AstNetlist* nodep) VL_MT_DISABLED; // Create tasks out of blocks/statments that can outlive processes in which they were forked. // Return value: number of tasks created - static void makeTasks(AstNetlist* nodep); + static void makeTasks(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index b3811bce8..a1594e185 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -21,6 +21,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Gate.h b/src/V3Gate.h index f4a03d3f0..f30c6f9a4 100644 --- a/src/V3Gate.h +++ b/src/V3Gate.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Gate final { public: - static void gateAll(AstNetlist* nodep); + static void gateAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Global.h b/src/V3Global.h index 90f8bc59b..a25a3f274 100644 --- a/src/V3Global.h +++ b/src/V3Global.h @@ -28,7 +28,9 @@ #include "V3Error.h" #include "V3FileLine.h" +#include "V3Mutex.h" #include "V3Options.h" +#include "V3ThreadSafety.h" #include #include @@ -127,6 +129,7 @@ public: V3Global() {} void boot(); void shutdown(); // Release allocated resources + // ACCESSORS (general) AstNetlist* rootp() const VL_MT_SAFE { return m_rootp; } VWidthMinUsage widthMinUsage() const { return m_widthMinUsage; } @@ -134,8 +137,8 @@ public: bool assertScoped() const { return m_assertScoped; } // METHODS - void readFiles(); - void removeStd(); + void readFiles() VL_MT_DISABLED; + void removeStd() VL_MT_DISABLED; void checkTree() const; static void dumpCheckGlobalTree(const string& stagename, int newNumber = 0, bool doDump = true); diff --git a/src/V3Graph.cpp b/src/V3Graph.cpp index 9eca82238..e8ab00441 100644 --- a/src/V3Graph.cpp +++ b/src/V3Graph.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Graph.h b/src/V3Graph.h index 84dd4f85f..c8a01acfa 100644 --- a/src/V3Graph.h +++ b/src/V3Graph.h @@ -23,6 +23,7 @@ #include "V3Error.h" #include "V3List.h" #include "V3Rtti.h" +#include "V3ThreadSafety.h" #include @@ -88,19 +89,20 @@ protected: friend class V3GraphEdge; friend class GraphAcyc; // METHODS - double orderDFSIterate(V3GraphVertex* vertexp); - void dumpEdge(std::ostream& os, const V3GraphVertex* vertexp, const V3GraphEdge* edgep); + double orderDFSIterate(V3GraphVertex* vertexp) VL_MT_DISABLED; + void dumpEdge(std::ostream& os, const V3GraphVertex* vertexp, + const V3GraphEdge* edgep) VL_MT_DISABLED; void verticesUnlink() { m_vertices.reset(); } // ACCESSORS public: - V3Graph(); - virtual ~V3Graph(); + V3Graph() VL_MT_DISABLED; + virtual ~V3Graph() VL_MT_DISABLED; virtual string dotRankDir() const { return "TB"; } // rankdir for dot plotting // METHODS - void clear(); // Empty it of all vertices/edges, as if making a new object - void clearColors(); + void clear() VL_MT_DISABLED; // Empty it of all vertices/edges, as if making a new object + void clearColors() VL_MT_DISABLED; bool empty() const { return m_vertices.empty(); } V3GraphVertex* verticesBeginp() const { return m_vertices.begin(); } @@ -109,66 +111,69 @@ public: /// Assign same color to all vertices in the same weakly connected component /// Thus different color if there's no edges between the two subgraphs - void weaklyConnected(V3EdgeFuncP edgeFuncp); + void weaklyConnected(V3EdgeFuncP edgeFuncp) VL_MT_DISABLED; /// Assign same color to all vertices that are strongly connected /// Thus different color if there's no directional circuit within the subgraphs. /// (I.E. all loops will occur within each color, not between them.) - void stronglyConnected(V3EdgeFuncP edgeFuncp); + void stronglyConnected(V3EdgeFuncP edgeFuncp) VL_MT_DISABLED; /// Assign an ordering number to all vertexes in a tree. /// All nodes with no inputs will get rank 1 - void rank(V3EdgeFuncP edgeFuncp); - void rank(); + void rank(V3EdgeFuncP edgeFuncp) VL_MT_DISABLED; + void rank() VL_MT_DISABLED; /// Sort all vertices and edges using the V3GraphVertex::sortCmp() function - void sortVertices(); + void sortVertices() VL_MT_DISABLED; /// Sort all edges and edges using the V3GraphEdge::sortCmp() function - void sortEdges(); + void sortEdges() VL_MT_DISABLED; /// Order all vertices by rank and fanout, lowest first /// Sort all vertices by rank and fanout, lowest first /// Sort all edges by weight, lowest first /// Side-effect: assigns ranks to every node. - void order(); + void order() VL_MT_DISABLED; // Similar to order() but does not assign ranks. Caller must // ensure that the graph has been ranked ahead of the call. - void orderPreRanked(); + void orderPreRanked() VL_MT_DISABLED; /// Make acyclical (into a tree) by breaking a minimal subset of cutable edges. - void acyclic(V3EdgeFuncP edgeFuncp); + void acyclic(V3EdgeFuncP edgeFuncp) VL_MT_DISABLED; /// Remove any redundant edges, weights become MAX of any other weight - void removeRedundantEdges(V3EdgeFuncP edgeFuncp); + void removeRedundantEdges(V3EdgeFuncP edgeFuncp) VL_MT_DISABLED; /// Remove any redundant edges, weights become SUM of any other weight - void removeRedundantEdgesSum(V3EdgeFuncP edgeFuncp); + void removeRedundantEdgesSum(V3EdgeFuncP edgeFuncp) VL_MT_DISABLED; /// Remove any transitive edges. E.g. if have edges A->B, B->C, and A->C /// then A->C is a "transitive" edge; it's implied by the first two /// (assuming the DAG is a dependency graph.) /// This algorithm can be expensive. - void removeTransitiveEdges(); + void removeTransitiveEdges() VL_MT_DISABLED; /// Call loopsVertexCb on any one loop starting where specified - void reportLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp); + void reportLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp) VL_MT_DISABLED; /// Build a subgraph of all loops starting where specified - void subtreeLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp, V3Graph* loopGraphp); + void subtreeLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp, + V3Graph* loopGraphp) VL_MT_DISABLED; /// Debugging - void dump(std::ostream& os = std::cout); - void dumpDotFile(const string& filename, bool colorAsSubgraph) const; - void dumpDotFilePrefixed(const string& nameComment, bool colorAsSubgraph = false) const; - void dumpDotFilePrefixedAlways(const string& nameComment, bool colorAsSubgraph = false) const; - void userClearVertices(); - void userClearEdges(); - static void selfTest(); + void dump(std::ostream& os = std::cout) VL_MT_DISABLED; + void dumpDotFile(const string& filename, bool colorAsSubgraph) const VL_MT_DISABLED; + void dumpDotFilePrefixed(const string& nameComment, + bool colorAsSubgraph = false) const VL_MT_DISABLED; + void dumpDotFilePrefixedAlways(const string& nameComment, + bool colorAsSubgraph = false) const VL_MT_DISABLED; + void userClearVertices() VL_MT_DISABLED; + void userClearEdges() VL_MT_DISABLED; + static void selfTest() VL_MT_DISABLED; // CALLBACKS - virtual void loopsMessageCb(V3GraphVertex* vertexp); - virtual void loopsVertexCb(V3GraphVertex* vertexp); + virtual void loopsMessageCb(V3GraphVertex* vertexp) VL_MT_DISABLED; + virtual void loopsVertexCb(V3GraphVertex* vertexp) VL_MT_DISABLED; }; //============================================================================ @@ -192,24 +197,24 @@ protected: uint32_t m_user; // Marker for some algorithms }; // METHODS - void verticesPushBack(V3Graph* graphp); + void verticesPushBack(V3Graph* graphp) VL_MT_DISABLED; // ACCESSORS void fanout(double fanout) { m_fanout = fanout; } void inUnlink() { m_ins.reset(); } // Low level; normally unlinkDelete is what you want void outUnlink() { m_outs.reset(); } // Low level; normally unlinkDelete is what you want protected: // CONSTRUCTORS - V3GraphVertex(V3Graph* graphp, const V3GraphVertex& old); + V3GraphVertex(V3Graph* graphp, const V3GraphVertex& old) VL_MT_DISABLED; public: - explicit V3GraphVertex(V3Graph* graphp); + explicit V3GraphVertex(V3Graph* graphp) VL_MT_DISABLED; //! Clone copy constructor. Doesn't copy edges or user/userp. - virtual V3GraphVertex* clone(V3Graph* graphp) const { + virtual V3GraphVertex* clone(V3Graph* graphp) const VL_MT_DISABLED { return new V3GraphVertex{graphp, *this}; } virtual ~V3GraphVertex() = default; - void unlinkEdges(V3Graph* graphp); - void unlinkDelete(V3Graph* graphp); + void unlinkEdges(V3Graph* graphp) VL_MT_DISABLED; + void unlinkDelete(V3Graph* graphp) VL_MT_DISABLED; // METHODS // Return true iff of type T @@ -275,23 +280,24 @@ public: V3GraphVertex* verticesNextp() const { return m_vertices.nextp(); } V3GraphEdge* inBeginp() const { return m_ins.begin(); } bool inEmpty() const { return inBeginp() == nullptr; } - bool inSize1() const; + bool inSize1() const VL_MT_DISABLED; V3GraphEdge* outBeginp() const { return m_outs.begin(); } bool outEmpty() const { return outBeginp() == nullptr; } - bool outSize1() const; + bool outSize1() const VL_MT_DISABLED; V3GraphEdge* beginp(GraphWay way) const { return way.forward() ? outBeginp() : inBeginp(); } // METHODS /// Error reporting - void v3errorEnd(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex); - void v3errorEndFatal(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex); + void v3errorEnd(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex) VL_MT_DISABLED; + void v3errorEndFatal(std::ostringstream& str) const + VL_RELEASE(V3Error::s().m_mutex) VL_MT_DISABLED; /// Edges are routed around this vertex to point from "from" directly to "to" - void rerouteEdges(V3Graph* graphp); + void rerouteEdges(V3Graph* graphp) VL_MT_DISABLED; /// Find the edge connecting ap and bp, where bp is wayward from ap. /// If edge is not found returns nullptr. O(edges) performance. - V3GraphEdge* findConnectingEdgep(GraphWay way, const V3GraphVertex* waywardp); + V3GraphEdge* findConnectingEdgep(GraphWay way, const V3GraphVertex* waywardp) VL_MT_DISABLED; }; -std::ostream& operator<<(std::ostream& os, V3GraphVertex* vertexp); +std::ostream& operator<<(std::ostream& os, V3GraphVertex* vertexp) VL_MT_DISABLED; //============================================================================ @@ -320,25 +326,26 @@ protected: }; // METHODS void init(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight, - bool cutable = false); + bool cutable = false) VL_MT_DISABLED; void cut() { m_weight = 0; } // 0 weight is same as disconnected - void outPushBack(); - void inPushBack(); + void outPushBack() VL_MT_DISABLED; + void inPushBack() VL_MT_DISABLED; // CONSTRUCTORS protected: V3GraphEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, - const V3GraphEdge& old) { + const V3GraphEdge& old) VL_MT_DISABLED { init(graphp, fromp, top, old.m_weight, old.m_cutable); } public: //! Add DAG from one node to the specified node V3GraphEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight, - bool cutable = false) { + bool cutable = false) VL_MT_DISABLED { init(graphp, fromp, top, weight, cutable); } //! Clone copy constructor. Doesn't copy existing vertices or user/userp. - virtual V3GraphEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const { + virtual V3GraphEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, + V3GraphVertex* top) const VL_MT_DISABLED { return new V3GraphEdge{graphp, fromp, top, *this}; } virtual ~V3GraphEdge() = default; @@ -384,9 +391,9 @@ public: if (!m_weight || !rhsp->m_weight) return 0; return top()->sortCmp(rhsp->top()); } - void unlinkDelete(); - V3GraphEdge* relinkFromp(V3GraphVertex* newFromp); - V3GraphEdge* relinkTop(V3GraphVertex* newTop); + void unlinkDelete() VL_MT_DISABLED; + V3GraphEdge* relinkFromp(V3GraphVertex* newFromp) VL_MT_DISABLED; + V3GraphEdge* relinkTop(V3GraphVertex* newTop) VL_MT_DISABLED; // ACCESSORS int weight() const { return m_weight; } void weight(int weight) { m_weight = weight; } diff --git a/src/V3GraphAcyc.cpp b/src/V3GraphAcyc.cpp index 4b15ca3dd..968efd38b 100644 --- a/src/V3GraphAcyc.cpp +++ b/src/V3GraphAcyc.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3GraphAlg.cpp b/src/V3GraphAlg.cpp index 67a2f12b0..99b65dbc5 100644 --- a/src/V3GraphAlg.cpp +++ b/src/V3GraphAlg.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3GraphPathChecker.cpp b/src/V3GraphPathChecker.cpp index f609652b0..21cd1493c 100644 --- a/src/V3GraphPathChecker.cpp +++ b/src/V3GraphPathChecker.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3GraphPathChecker.h b/src/V3GraphPathChecker.h index 620736ff1..c4326d129 100644 --- a/src/V3GraphPathChecker.h +++ b/src/V3GraphPathChecker.h @@ -20,6 +20,7 @@ #include "V3Error.h" #include "V3Graph.h" #include "V3GraphAlg.h" +#include "V3ThreadSafety.h" //###################################################################### @@ -39,21 +40,22 @@ class GraphPathChecker final : GraphAlg { public: // CONSTRUCTORS explicit GraphPathChecker(const V3Graph* graphp, - V3EdgeFuncP edgeFuncp = V3GraphEdge::followAlwaysTrue); - ~GraphPathChecker(); + V3EdgeFuncP edgeFuncp + = V3GraphEdge::followAlwaysTrue) VL_MT_DISABLED; + ~GraphPathChecker() VL_MT_DISABLED; // METHODS - bool pathExistsFrom(const V3GraphVertex* fromp, const V3GraphVertex* top); + bool pathExistsFrom(const V3GraphVertex* fromp, const V3GraphVertex* top) VL_MT_DISABLED; // If have edges A->B, B->C, and A->C then A->C is considered a // "transitive" edge (implied by A->B and B->C) and it could be safely // removed. Detect such an edge. - bool isTransitiveEdge(const V3GraphEdge* edgep); + bool isTransitiveEdge(const V3GraphEdge* edgep) VL_MT_DISABLED; private: bool pathExistsInternal(const V3GraphVertex* ap, const V3GraphVertex* bp, - unsigned* costp = nullptr); - void initHalfCriticalPaths(GraphWay way, bool checkOnly); + unsigned* costp = nullptr) VL_MT_DISABLED; + void initHalfCriticalPaths(GraphWay way, bool checkOnly) VL_MT_DISABLED; void incGeneration() { ++m_generation; } VL_UNCOPYABLE(GraphPathChecker); diff --git a/src/V3GraphTest.cpp b/src/V3GraphTest.cpp index 0550e73c1..1635bfc6a 100644 --- a/src/V3GraphTest.cpp +++ b/src/V3GraphTest.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3HierBlock.cpp b/src/V3HierBlock.cpp index 8c234cac2..331c8cbc9 100644 --- a/src/V3HierBlock.cpp +++ b/src/V3HierBlock.cpp @@ -72,6 +72,8 @@ // Used for b) and c). // This options is repeated for all instantiating hierarchical blocks. +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "V3HierBlock.h" #include "V3Ast.h" diff --git a/src/V3HierBlock.h b/src/V3HierBlock.h index 02842a62d..33310209f 100644 --- a/src/V3HierBlock.h +++ b/src/V3HierBlock.h @@ -19,7 +19,8 @@ #include "verilatedos.h" -#include "V3Global.h" +#include "V3Options.h" +#include "V3ThreadSafety.h" #include #include @@ -56,13 +57,13 @@ private: // METHODS VL_UNCOPYABLE(V3HierBlock); - static StrGParams stringifyParams(const GParams& gparams, bool forGOption); + static StrGParams stringifyParams(const GParams& gparams, bool forGOption) VL_MT_DISABLED; public: V3HierBlock(const AstNodeModule* modp, const GParams& gparams) : m_modp{modp} , m_gparams{gparams} {} - ~V3HierBlock(); + ~V3HierBlock() VL_MT_DISABLED; void addParent(V3HierBlock* parentp) { m_parents.insert(parentp); } void addChild(V3HierBlock* childp) { m_children.insert(childp); } @@ -73,19 +74,19 @@ public: const AstNodeModule* modp() const { return m_modp; } // For emitting Makefile and CMakeLists.txt - V3StringList commandArgs(bool forCMake) const; - V3StringList hierBlockArgs() const; - string hierPrefix() const; - string hierSomeFile(bool withDir, const char* prefix, const char* suffix) const; - string hierWrapper(bool withDir) const; - string hierMk(bool withDir) const; - string hierLib(bool withDir) const; - string hierGenerated(bool withDir) const; + V3StringList commandArgs(bool forCMake) const VL_MT_DISABLED; + V3StringList hierBlockArgs() const VL_MT_DISABLED; + string hierPrefix() const VL_MT_DISABLED; + string hierSomeFile(bool withDir, const char* prefix, const char* suffix) const VL_MT_DISABLED; + string hierWrapper(bool withDir) const VL_MT_DISABLED; + string hierMk(bool withDir) const VL_MT_DISABLED; + string hierLib(bool withDir) const VL_MT_DISABLED; + string hierGenerated(bool withDir) const VL_MT_DISABLED; // Returns the original HDL file if it is not included in v3Global.opt.vFiles(). - string vFileIfNecessary() const; + string vFileIfNecessary() const VL_MT_DISABLED; // Write command line arguments to .f file for this hierarchical block - void writeCommandArgsFile(bool forCMake) const; - string commandArgsFileName(bool forCMake) const; + void writeCommandArgsFile(bool forCMake) const VL_MT_DISABLED; + string commandArgsFileName(bool forCMake) const VL_MT_DISABLED; }; //###################################################################### @@ -103,8 +104,8 @@ public: using const_iterator = HierMap::const_iterator; using HierVector = std::vector; - void add(const AstNodeModule* modp, const std::vector& gparams); - void registerUsage(const AstNodeModule* parentp, const AstNodeModule* childp); + void add(const AstNodeModule* modp, const std::vector& gparams) VL_MT_DISABLED; + void registerUsage(const AstNodeModule* parentp, const AstNodeModule* childp) VL_MT_DISABLED; const_iterator begin() const { return m_blocks.begin(); } const_iterator end() const { return m_blocks.end(); } @@ -112,13 +113,13 @@ public: // Returns all hierarchical blocks that sorted in leaf-first order. // Latter block refers only already appeared hierarchical blocks. - HierVector hierBlocksSorted() const; + HierVector hierBlocksSorted() const VL_MT_DISABLED; // Write command line arguments to .f files for child Verilation run - void writeCommandArgsFiles(bool forCMake) const; - static string topCommandArgsFileName(bool forCMake); + void writeCommandArgsFiles(bool forCMake) const VL_MT_DISABLED; + static string topCommandArgsFileName(bool forCMake) VL_MT_DISABLED; - static void createPlan(AstNetlist* nodep); + static void createPlan(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // guard diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index 09e486a12..996e9d9bf 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -24,6 +24,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Inline.h b/src/V3Inline.h index dc5264ad1..1f347b139 100644 --- a/src/V3Inline.h +++ b/src/V3Inline.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Inline final { public: - static void inlineAll(AstNetlist* nodep); + static void inlineAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index 0b96463e5..5f0455714 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -21,6 +21,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Inst.h b/src/V3Inst.h index 6cfce8f77..8baccb465 100644 --- a/src/V3Inst.h +++ b/src/V3Inst.h @@ -20,6 +20,8 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstAssignW; class AstCell; class AstNetlist; @@ -29,11 +31,11 @@ class AstPin; class V3Inst final { public: - static void instAll(AstNetlist* nodep); - static void dearrayAll(AstNetlist* nodep); + static void instAll(AstNetlist* nodep) VL_MT_DISABLED; + static void dearrayAll(AstNetlist* nodep) VL_MT_DISABLED; static AstAssignW* pinReconnectSimple(AstPin* pinp, AstCell* cellp, bool forTristate, - bool alwaysCvt = false); - static void checkOutputShort(AstPin* nodep); + bool alwaysCvt = false) VL_MT_DISABLED; + static void checkOutputShort(AstPin* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3InstrCount.cpp b/src/V3InstrCount.cpp index c236da288..7e363ba17 100644 --- a/src/V3InstrCount.cpp +++ b/src/V3InstrCount.cpp @@ -15,6 +15,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3InstrCount.h b/src/V3InstrCount.h index 279885616..fc4978439 100644 --- a/src/V3InstrCount.h +++ b/src/V3InstrCount.h @@ -21,6 +21,8 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNode; class V3InstrCount final { @@ -38,7 +40,8 @@ public: // if we see the same node twice (across more than one call to count, // potentially) raises an error. // Optional osp is stream to dump critical path to. - static uint32_t count(AstNode* nodep, bool assertNoDups, std::ostream* osp = nullptr); + static uint32_t count(AstNode* nodep, bool assertNoDups, + std::ostream* osp = nullptr) VL_MT_DISABLED; }; #endif // guard diff --git a/src/V3Life.cpp b/src/V3Life.cpp index 0b5f83122..a20c17252 100644 --- a/src/V3Life.cpp +++ b/src/V3Life.cpp @@ -23,6 +23,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Life.h b/src/V3Life.h index fa4291519..024f4e7c8 100644 --- a/src/V3Life.h +++ b/src/V3Life.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Life final { public: - static void lifeAll(AstNetlist* nodep); + static void lifeAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3LifePost.cpp b/src/V3LifePost.cpp index f62882369..35728e5de 100644 --- a/src/V3LifePost.cpp +++ b/src/V3LifePost.cpp @@ -24,6 +24,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3LifePost.h b/src/V3LifePost.h index ddf92c555..01042ce38 100644 --- a/src/V3LifePost.h +++ b/src/V3LifePost.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3LifePost final { public: - static void lifepostAll(AstNetlist* nodep); + static void lifepostAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp index 6087999b3..d98a9158b 100644 --- a/src/V3LinkCells.cpp +++ b/src/V3LinkCells.cpp @@ -23,6 +23,8 @@ // Link to module that instantiates it //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3LinkCells.h b/src/V3LinkCells.h index eab1a73fe..dbaecd2be 100644 --- a/src/V3LinkCells.h +++ b/src/V3LinkCells.h @@ -20,6 +20,8 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; class VInFilter; class V3ParseSym; @@ -28,7 +30,7 @@ class V3ParseSym; class V3LinkCells final { public: - static void link(AstNetlist* nodep, VInFilter* filterp, V3ParseSym* parseSymp); + static void link(AstNetlist* nodep, VInFilter* filterp, V3ParseSym* parseSymp) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index d9751b87a..7ea95b46f 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -61,6 +61,8 @@ // b (VSymEnt->AstCell) //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3LinkDot.h b/src/V3LinkDot.h index 14af04e82..5e3667210 100644 --- a/src/V3LinkDot.h +++ b/src/V3LinkDot.h @@ -22,19 +22,20 @@ #include "V3Ast.h" #include "V3Error.h" +#include "V3ThreadSafety.h" //============================================================================ enum VLinkDotStep : uint8_t { LDS_PRIMARY, LDS_PARAMED, LDS_ARRAYED, LDS_SCOPED }; class V3LinkDot final { - static void linkDotGuts(AstNetlist* rootp, VLinkDotStep step); + static void linkDotGuts(AstNetlist* rootp, VLinkDotStep step) VL_MT_DISABLED; public: - static void linkDotPrimary(AstNetlist* nodep); - static void linkDotParamed(AstNetlist* nodep); - static void linkDotArrayed(AstNetlist* nodep); - static void linkDotScope(AstNetlist* nodep); + static void linkDotPrimary(AstNetlist* nodep) VL_MT_DISABLED; + static void linkDotParamed(AstNetlist* nodep) VL_MT_DISABLED; + static void linkDotArrayed(AstNetlist* nodep) VL_MT_DISABLED; + static void linkDotScope(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp index 164f005c2..49b775ab9 100644 --- a/src/V3LinkInc.cpp +++ b/src/V3LinkInc.cpp @@ -36,6 +36,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3LinkInc.h b/src/V3LinkInc.h index 1b5a6ff55..b41807437 100644 --- a/src/V3LinkInc.h +++ b/src/V3LinkInc.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3LinkInc final { public: - static void linkIncrements(AstNetlist* nodep); + static void linkIncrements(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp index b7785e975..68807a097 100644 --- a/src/V3LinkJump.cpp +++ b/src/V3LinkJump.cpp @@ -29,6 +29,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3LinkJump.h b/src/V3LinkJump.h index 598cd98bc..48b919f8a 100644 --- a/src/V3LinkJump.h +++ b/src/V3LinkJump.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3LinkJump final { public: - static void linkJump(AstNetlist* nodep); + static void linkJump(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp index 6ba79865f..9431731a3 100644 --- a/src/V3LinkLValue.cpp +++ b/src/V3LinkLValue.cpp @@ -18,6 +18,8 @@ // Set lvalue() attributes on appropriate VARREFs. //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3LinkLValue.h b/src/V3LinkLValue.h index 16656936d..26cbaa4e3 100644 --- a/src/V3LinkLValue.h +++ b/src/V3LinkLValue.h @@ -20,6 +20,8 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; class AstNode; @@ -27,8 +29,8 @@ class AstNode; class V3LinkLValue final { public: - static void linkLValue(AstNetlist* nodep); - static void linkLValueSet(AstNode* nodep); + static void linkLValue(AstNetlist* nodep) VL_MT_DISABLED; + static void linkLValueSet(AstNode* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index 03ba5bf96..dbb0631da 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -19,6 +19,8 @@ // Create new MODULE TOP with connections to below signals //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3LinkLevel.h b/src/V3LinkLevel.h index c1b1c6354..aa86a2b82 100644 --- a/src/V3LinkLevel.h +++ b/src/V3LinkLevel.h @@ -22,6 +22,7 @@ #include "V3Ast.h" #include "V3Error.h" +#include "V3ThreadSafety.h" #include @@ -31,13 +32,13 @@ class V3LinkLevel final { private: using ModVec = std::vector; - static void timescaling(const ModVec& mods); - static void wrapTopCell(AstNetlist* rootp); - static void wrapTopPackages(AstNetlist* rootp); + static void timescaling(const ModVec& mods) VL_MT_DISABLED; + static void wrapTopCell(AstNetlist* rootp) VL_MT_DISABLED; + static void wrapTopPackages(AstNetlist* rootp) VL_MT_DISABLED; public: - static void modSortByLevel(); - static void wrapTop(AstNetlist* rootp); + static void modSortByLevel() VL_MT_DISABLED; + static void wrapTop(AstNetlist* rootp) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 00b9ea3aa..48a5cf0e4 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -18,6 +18,8 @@ // Move some attributes around //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3LinkParse.h b/src/V3LinkParse.h index df57d97d2..5694c4396 100644 --- a/src/V3LinkParse.h +++ b/src/V3LinkParse.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3LinkParse final { public: - static void linkParse(AstNetlist* rootp); + static void linkParse(AstNetlist* rootp) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 187d84028..e3767407c 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -24,6 +24,8 @@ // SenItems: Convert pos/negedge of non-simple signals to temporaries //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3LinkResolve.h b/src/V3LinkResolve.h index 929c36452..0588f8e7a 100644 --- a/src/V3LinkResolve.h +++ b/src/V3LinkResolve.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3LinkResolve final { public: - static void linkResolve(AstNetlist* rootp); + static void linkResolve(AstNetlist* rootp) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Localize.cpp b/src/V3Localize.cpp index 586e8940e..16500e84d 100644 --- a/src/V3Localize.cpp +++ b/src/V3Localize.cpp @@ -22,6 +22,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Localize.h b/src/V3Localize.h index 65d369214..ee4e62e6d 100644 --- a/src/V3Localize.h +++ b/src/V3Localize.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Localize final { public: - static void localizeAll(AstNetlist* nodep); + static void localizeAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3MergeCond.cpp b/src/V3MergeCond.cpp index 52c6a4dfa..5598a5cdf 100644 --- a/src/V3MergeCond.cpp +++ b/src/V3MergeCond.cpp @@ -72,6 +72,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3MergeCond.h b/src/V3MergeCond.h index 07d41e538..4510e4572 100644 --- a/src/V3MergeCond.h +++ b/src/V3MergeCond.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3MergeCond final { public: - static void mergeAll(AstNetlist* nodep); + static void mergeAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Name.cpp b/src/V3Name.cpp index fc532f498..56896ef58 100644 --- a/src/V3Name.cpp +++ b/src/V3Name.cpp @@ -19,6 +19,8 @@ // Prepend __PVT__ to variable names //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Name.h b/src/V3Name.h index f51fdac0b..cb2781378 100644 --- a/src/V3Name.h +++ b/src/V3Name.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Name final { public: - static void nameAll(AstNetlist* nodep); + static void nameAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Number_test.cpp b/src/V3Number_test.cpp index fd0887d8b..1d7898013 100644 --- a/src/V3Number_test.cpp +++ b/src/V3Number_test.cpp @@ -17,6 +17,7 @@ // CHEAT! #define V3NUMBER_ASCII_BINARY #define V3ERROR_NO_GLOBAL_ +#define VL_MT_DISABLED_CODE_UNIT 1 #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3OptionParser.cpp b/src/V3OptionParser.cpp index 8d9f41b2c..ea245400e 100644 --- a/src/V3OptionParser.cpp +++ b/src/V3OptionParser.cpp @@ -15,6 +15,8 @@ //************************************************************************* #ifndef V3OPTION_PARSER_NO_VOPTION_BOOL +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "V3Global.h" #include "V3Options.h" #endif diff --git a/src/V3OptionParser.h b/src/V3OptionParser.h index cc22b8f0a..6975bd844 100644 --- a/src/V3OptionParser.h +++ b/src/V3OptionParser.h @@ -20,6 +20,8 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + #include #include #include @@ -64,25 +66,27 @@ private: const std::unique_ptr m_pimpl; // METHODS - ActionIfs* find(const char* optp); + ActionIfs* find(const char* optp) VL_MT_DISABLED; template - ActionIfs& add(const string& opt, ARG arg); - static bool hasPrefixFNo(const char* strp); // Returns true if strp starts with "-fno" - static bool hasPrefixNo(const char* strp); // Returns true if strp starts with "-no" + ActionIfs& add(const string& opt, ARG arg) VL_MT_DISABLED; + // Returns true if strp starts with "-fno" + static bool hasPrefixFNo(const char* strp) VL_MT_DISABLED; + // Returns true if strp starts with "-no" + static bool hasPrefixNo(const char* strp) VL_MT_DISABLED; public: // METHODS // Returns how many args are consumed. 0 means not match - int parse(int idx, int argc, char* argv[]); + int parse(int idx, int argc, char* argv[]) VL_MT_DISABLED; // Find the most similar option - string getSuggestion(const char* str) const; - void addSuggestionCandidate(const string& s); + string getSuggestion(const char* str) const VL_MT_DISABLED; + void addSuggestionCandidate(const string& s) VL_MT_DISABLED; // Call this function after all options are registered. - void finalize(); + void finalize() VL_MT_DISABLED; // CONSTRUCTORS - V3OptionParser(); - ~V3OptionParser(); + V3OptionParser() VL_MT_DISABLED; + ~V3OptionParser() VL_MT_DISABLED; }; class V3OptionParser::ActionIfs VL_NOT_FINAL { @@ -121,29 +125,33 @@ private: public: // METHODS - ActionIfs& operator()(const char* optp, Set, bool*) const; + ActionIfs& operator()(const char* optp, Set, bool*) const VL_MT_DISABLED; #ifndef V3OPTION_PARSER_NO_VOPTION_BOOL - ActionIfs& operator()(const char* optp, Set, VOptionBool*) const; + ActionIfs& operator()(const char* optp, Set, VOptionBool*) const VL_MT_DISABLED; #endif - ActionIfs& operator()(const char* optp, Set, int*) const; - ActionIfs& operator()(const char* optp, Set, string*) const; + ActionIfs& operator()(const char* optp, Set, int*) const VL_MT_DISABLED; + ActionIfs& operator()(const char* optp, Set, string*) const VL_MT_DISABLED; - ActionIfs& operator()(const char* optp, FOnOff, bool*) const; - ActionIfs& operator()(const char* optp, OnOff, bool*) const; + ActionIfs& operator()(const char* optp, FOnOff, bool*) const VL_MT_DISABLED; + ActionIfs& operator()(const char* optp, OnOff, bool*) const VL_MT_DISABLED; #ifndef V3OPTION_PARSER_NO_VOPTION_BOOL - ActionIfs& operator()(const char* optp, OnOff, VOptionBool*) const; + ActionIfs& operator()(const char* optp, OnOff, VOptionBool*) const VL_MT_DISABLED; #endif - ActionIfs& operator()(const char* optp, CbCall, std::function) const; - ActionIfs& operator()(const char* optp, CbFOnOff, std::function) const; - ActionIfs& operator()(const char* optp, CbOnOff, std::function) const; - ActionIfs& operator()(const char* optp, CbVal, std::function) const; - ActionIfs& operator()(const char* optp, CbVal, std::function) const; + ActionIfs& operator()(const char* optp, CbCall, + std::function) const VL_MT_DISABLED; + ActionIfs& operator()(const char* optp, CbFOnOff, + std::function) const VL_MT_DISABLED; + ActionIfs& operator()(const char* optp, CbOnOff, + std::function) const VL_MT_DISABLED; + ActionIfs& operator()(const char* optp, CbVal, std::function) const VL_MT_DISABLED; + ActionIfs& operator()(const char* optp, CbVal, + std::function) const VL_MT_DISABLED; ActionIfs& operator()(const char* optp, CbPartialMatch, - std::function) const; + std::function) const VL_MT_DISABLED; ActionIfs& operator()(const char* optp, CbPartialMatchVal, - std::function) const; + std::function) const VL_MT_DISABLED; // CONSTRUCTORS explicit AppendHelper(V3OptionParser& parser) diff --git a/src/V3Options.cpp b/src/V3Options.cpp index bc08b0256..42e33a040 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -292,7 +292,7 @@ void V3Options::addLangExt(const string& langext, const V3LangCode& lc) { m_impp->addLangExt(langext, lc); } void V3Options::addLibExtV(const string& libext) { m_impp->addLibExtV(libext); } -void V3Options::addDefine(const string& defline, bool allowPlus) { +void V3Options::addDefine(const string& defline, bool allowPlus) VL_MT_DISABLED { // Split +define+foo=value into the appropriate parts and parse // Optional + says to allow multiple defines on the line // + is not quotable, as other simulators do not allow that @@ -792,7 +792,7 @@ bool V3Options::coroutineSupport() { //###################################################################### // V3 Options notification methods -void V3Options::notify() { +void V3Options::notify() VL_MT_DISABLED { // Notify that all arguments have been passed and final modification can be made. FileLine* const cmdfl = new FileLine{FileLine::commandLineFilename()}; @@ -978,7 +978,7 @@ string V3Options::argString(int argc, char** argv) { //###################################################################### // V3 Options Parsing -void V3Options::parseOpts(FileLine* fl, int argc, char** argv) { +void V3Options::parseOpts(FileLine* fl, int argc, char** argv) VL_MT_DISABLED { // Parse all options // Initial entry point from Verilator.cpp parseOptsList(fl, ".", argc, argv); @@ -1009,7 +1009,8 @@ bool V3Options::suffixed(const string& sw, const char* arg) { return (0 == std::strcmp(sw.c_str() + sw.length() - std::strlen(arg), arg)); } -void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char** argv) { +void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, + char** argv) VL_MT_DISABLED { // Parse parameters // Note argc and argv DO NOT INCLUDE the filename in [0]!!! // May be called recursively when there are -f files. @@ -1057,7 +1058,8 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char // (If DECL_OPTION is a macro, then lambda would be collapsed into a single line). // Plus options - DECL_OPTION("+define+", CbPartialMatch, [this](const char* optp) { addDefine(optp, true); }); + DECL_OPTION("+define+", CbPartialMatch, + [this](const char* optp) VL_MT_DISABLED { addDefine(optp, true); }); DECL_OPTION("+incdir+", CbPartialMatch, [this, &optdir](const char* optp) { addIncDirUser(parseFileArg(optdir, optp)); }); DECL_OPTION("+libext+", CbPartialMatch, [this](const char* optp) { @@ -1159,7 +1161,8 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-coverage-underscore", OnOff, &m_coverageUnderscore); DECL_OPTION("-coverage-user", OnOff, &m_coverageUser); - DECL_OPTION("-D", CbPartialMatch, [this](const char* valp) { addDefine(valp, false); }); + DECL_OPTION("-D", CbPartialMatch, + [this](const char* valp) VL_MT_DISABLED { addDefine(valp, false); }); DECL_OPTION("-debug", CbCall, [this]() { setDebugMode(3); }); DECL_OPTION("-debugi", CbVal, [this](int v) { setDebugMode(v); }); DECL_OPTION("-debugi-", CbPartialMatchVal, [this](const char* optp, const char* valp) { @@ -1199,12 +1202,12 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-expand-limit", CbVal, [this](const char* valp) { m_expandLimit = std::atoi(valp); }); - DECL_OPTION("-F", CbVal, [this, fl, &optdir](const char* valp) { + DECL_OPTION("-F", CbVal, [this, fl, &optdir](const char* valp) VL_MT_DISABLED { parseOptsFile(fl, parseFileArg(optdir, valp), true); }); DECL_OPTION("-FI", CbVal, [this, &optdir](const char* valp) { addForceInc(parseFileArg(optdir, valp)); }); - DECL_OPTION("-f", CbVal, [this, fl, &optdir](const char* valp) { + DECL_OPTION("-f", CbVal, [this, fl, &optdir](const char* valp) VL_MT_DISABLED { parseOptsFile(fl, parseFileArg(optdir, valp), false); }); DECL_OPTION("-flatten", OnOff, &m_flatten); @@ -1604,7 +1607,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char // Note it may not be a future option, but one that is currently implemented. addFuture(optp); }); - DECL_OPTION("-Wno-", CbPartialMatch, [fl, &parser](const char* optp) { + DECL_OPTION("-Wno-", CbPartialMatch, [fl, &parser](const char* optp) VL_MT_DISABLED { if (!FileLine::globalWarnOff(optp, true)) { const string fullopt = std::string{"-Wno-"} + optp; fl->v3fatal("Unknown warning specified: " << fullopt @@ -1624,7 +1627,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char 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("-Wwarn-", CbPartialMatch, [this, fl, &parser](const char* optp) { + DECL_OPTION("-Wwarn-", CbPartialMatch, [this, fl, &parser](const char* optp) VL_MT_DISABLED { const V3ErrorCode code{optp}; if (code == V3ErrorCode::EC_ERROR) { if (!isFuture(optp)) { @@ -1741,7 +1744,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char //====================================================================== -void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) { +void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) VL_MT_DISABLED { // Read the specified -f filename and process as arguments UINFO(1, "Reading Options File " << filename << endl); diff --git a/src/V3Options.h b/src/V3Options.h index f9ee897bb..6378c8545 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -22,6 +22,7 @@ #include "V3Error.h" #include "V3LangCode.h" +#include "V3ThreadSafety.h" #include #include @@ -385,7 +386,7 @@ private: private: // METHODS void addArg(const string& arg); - void addDefine(const string& defline, bool allowPlus); + void addDefine(const string& defline, bool allowPlus) VL_MT_DISABLED; void addFuture(const string& flag); void addFuture0(const string& flag); void addFuture1(const string& flag); @@ -426,7 +427,7 @@ public: void addForceInc(const string& filename); bool available() const VL_MT_SAFE { return m_available; } void ccSet(); - void notify(); + void notify() VL_MT_DISABLED; // ACCESSORS (options) bool preprocOnly() const { return m_preprocOnly; } @@ -666,9 +667,9 @@ public: // Return options for child hierarchical blocks when forTop==false, otherwise returns args for // the top module. string allArgsStringForHierBlock(bool forTop) const; - void parseOpts(FileLine* fl, int argc, char** argv); - void parseOptsList(FileLine* fl, const string& optdir, int argc, char** argv); - void parseOptsFile(FileLine* fl, const string& filename, bool rel); + void parseOpts(FileLine* fl, int argc, char** argv) VL_MT_DISABLED; + void parseOptsList(FileLine* fl, const string& optdir, int argc, char** argv) VL_MT_DISABLED; + void parseOptsFile(FileLine* fl, const string& filename, bool rel) VL_MT_DISABLED; // METHODS (environment) // Most of these may be built into the executable with --enable-defenv, diff --git a/src/V3Order.cpp b/src/V3Order.cpp index 066d5d5b4..f0047b81e 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -71,6 +71,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Order.h b/src/V3Order.h index be2612371..3262e0ed8 100644 --- a/src/V3Order.h +++ b/src/V3Order.h @@ -20,6 +20,8 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + #include #include #include @@ -48,7 +50,7 @@ AstCFunc* order( bool parallel, // bool slow, // const ExternalDomainsProvider& externalDomains - = [](const AstVarScope*, std::vector&) {}); + = [](const AstVarScope*, std::vector&) {}) VL_MT_DISABLED; }; // namespace V3Order diff --git a/src/V3OrderGraph.h b/src/V3OrderGraph.h index af6788d6e..fef667f5b 100644 --- a/src/V3OrderGraph.h +++ b/src/V3OrderGraph.h @@ -92,10 +92,14 @@ public: // Methods to add edges representing constraints, utilizing the type system to help us ensure // the graph remains bipartite. - inline void addHardEdge(OrderLogicVertex* fromp, OrderVarVertex* top, int weight); - inline void addHardEdge(OrderVarVertex* fromp, OrderLogicVertex* top, int weight); - inline void addSoftEdge(OrderLogicVertex* fromp, OrderVarVertex* top, int weight); - inline void addSoftEdge(OrderVarVertex* fromp, OrderLogicVertex* top, int weight); + inline void addHardEdge(OrderLogicVertex* fromp, OrderVarVertex* top, + int weight) VL_MT_DISABLED; + inline void addHardEdge(OrderVarVertex* fromp, OrderLogicVertex* top, + int weight) VL_MT_DISABLED; + inline void addSoftEdge(OrderLogicVertex* fromp, OrderVarVertex* top, + int weight) VL_MT_DISABLED; + inline void addSoftEdge(OrderVarVertex* fromp, OrderLogicVertex* top, + int weight) VL_MT_DISABLED; }; //====================================================================== @@ -114,9 +118,9 @@ class OrderEitherVertex VL_NOT_FINAL : public V3GraphVertex { protected: // CONSTRUCTOR - OrderEitherVertex(OrderGraph* graphp, AstSenTree* domainp) - : V3GraphVertex{graphp} - , m_domainp{domainp} {} + OrderEitherVertex(OrderGraph* graphp, AstSenTree* domainp) VL_MT_DISABLED + : V3GraphVertex{graphp}, + m_domainp{domainp} {} ~OrderEitherVertex() override = default; public: @@ -125,7 +129,7 @@ public: // ACCESSORS AstSenTree* domainp() const VL_MT_STABLE { return m_domainp; } - void domainp(AstSenTree* domainp) { + void domainp(AstSenTree* domainp) VL_MT_DISABLED { #if VL_DEBUG UASSERT(!m_domainp, "Domain should only be set once"); #endif @@ -142,11 +146,11 @@ class OrderLogicVertex final : public OrderEitherVertex { public: // CONSTRUCTOR OrderLogicVertex(OrderGraph* graphp, AstScope* scopep, AstSenTree* domainp, - AstSenTree* hybridp, AstNode* nodep) - : OrderEitherVertex{graphp, domainp} - , m_nodep{nodep} - , m_scopep{scopep} - , m_hybridp{hybridp} { + AstSenTree* hybridp, AstNode* nodep) VL_MT_DISABLED + : OrderEitherVertex{graphp, domainp}, + m_nodep{nodep}, + m_scopep{scopep}, + m_hybridp{hybridp} { UASSERT_OBJ(scopep, nodep, "Must not be null"); UASSERT_OBJ(!(domainp && hybridp), nodep, "Cannot have bot domainp and hybridp set"); } @@ -174,9 +178,9 @@ class OrderVarVertex VL_NOT_FINAL : public OrderEitherVertex { public: // CONSTRUCTOR - OrderVarVertex(OrderGraph* graphp, AstVarScope* vscp) - : OrderEitherVertex{graphp, nullptr} - , m_vscp{vscp} {} + OrderVarVertex(OrderGraph* graphp, AstVarScope* vscp) VL_MT_DISABLED + : OrderEitherVertex{graphp, nullptr}, + m_vscp{vscp} {} ~OrderVarVertex() override = default; // ACCESSORS @@ -195,7 +199,7 @@ class OrderVarStdVertex final : public OrderVarVertex { VL_RTTI_IMPL(OrderVarStdVertex, OrderVarVertex) public: // CONSTRUCTOR - OrderVarStdVertex(OrderGraph* graphp, AstVarScope* vscp) + OrderVarStdVertex(OrderGraph* graphp, AstVarScope* vscp) VL_MT_DISABLED : OrderVarVertex{graphp, vscp} {} ~OrderVarStdVertex() override = default; @@ -212,7 +216,7 @@ class OrderVarPreVertex final : public OrderVarVertex { VL_RTTI_IMPL(OrderVarPreVertex, OrderVarVertex) public: // CONSTRUCTOR - OrderVarPreVertex(OrderGraph* graphp, AstVarScope* vscp) + OrderVarPreVertex(OrderGraph* graphp, AstVarScope* vscp) VL_MT_DISABLED : OrderVarVertex{graphp, vscp} {} ~OrderVarPreVertex() override = default; @@ -229,7 +233,7 @@ class OrderVarPostVertex final : public OrderVarVertex { VL_RTTI_IMPL(OrderVarPostVertex, OrderVarVertex) public: // CONSTRUCTOR - OrderVarPostVertex(OrderGraph* graphp, AstVarScope* vscp) + OrderVarPostVertex(OrderGraph* graphp, AstVarScope* vscp) VL_MT_DISABLED : OrderVarVertex{graphp, vscp} {} ~OrderVarPostVertex() override = default; @@ -246,7 +250,7 @@ class OrderVarPordVertex final : public OrderVarVertex { VL_RTTI_IMPL(OrderVarPordVertex, OrderVarVertex) public: // CONSTRUCTOR - OrderVarPordVertex(OrderGraph* graphp, AstVarScope* vscp) + OrderVarPordVertex(OrderGraph* graphp, AstVarScope* vscp) VL_MT_DISABLED : OrderVarVertex{graphp, vscp} {} ~OrderVarPordVertex() override = default; @@ -267,8 +271,7 @@ class OrderEdge final : public V3GraphEdge { friend class OrderGraph; // Only the OrderGraph can create these // CONSTRUCTOR OrderEdge(OrderGraph* graphp, OrderEitherVertex* fromp, OrderEitherVertex* top, int weight, - bool cutable) - : V3GraphEdge{graphp, fromp, top, weight, cutable} {} + bool cutable) VL_MT_DISABLED : V3GraphEdge{graphp, fromp, top, weight, cutable} {} ~OrderEdge() override = default; // LCOV_EXCL_START // Debug code @@ -279,16 +282,20 @@ class OrderEdge final : public V3GraphEdge { //====================================================================== // Inline methods -void OrderGraph::addHardEdge(OrderLogicVertex* fromp, OrderVarVertex* top, int weight) { +void OrderGraph::addHardEdge(OrderLogicVertex* fromp, OrderVarVertex* top, + int weight) VL_MT_DISABLED { new OrderEdge{this, fromp, top, weight, /* cutable: */ false}; } -void OrderGraph::addHardEdge(OrderVarVertex* fromp, OrderLogicVertex* top, int weight) { +void OrderGraph::addHardEdge(OrderVarVertex* fromp, OrderLogicVertex* top, + int weight) VL_MT_DISABLED { new OrderEdge{this, fromp, top, weight, /* cutable: */ false}; } -void OrderGraph::addSoftEdge(OrderLogicVertex* fromp, OrderVarVertex* top, int weight) { +void OrderGraph::addSoftEdge(OrderLogicVertex* fromp, OrderVarVertex* top, + int weight) VL_MT_DISABLED { new OrderEdge{this, fromp, top, weight, /* cutable: */ true}; } -void OrderGraph::addSoftEdge(OrderVarVertex* fromp, OrderLogicVertex* top, int weight) { +void OrderGraph::addSoftEdge(OrderVarVertex* fromp, OrderLogicVertex* top, + int weight) VL_MT_DISABLED { new OrderEdge{this, fromp, top, weight, /* cutable: */ true}; } diff --git a/src/V3OrderMoveGraph.h b/src/V3OrderMoveGraph.h index af5da4df0..2404e9730 100644 --- a/src/V3OrderMoveGraph.h +++ b/src/V3OrderMoveGraph.h @@ -27,6 +27,7 @@ #include "V3Ast.h" #include "V3Graph.h" #include "V3OrderGraph.h" +#include "V3ThreadSafety.h" #include @@ -49,11 +50,11 @@ protected: V3ListEnt m_readyVerticesE; // List of ready under domain/scope public: // CONSTRUCTORS - OrderMoveVertex(V3Graph* graphp, OrderLogicVertex* logicp) - : V3GraphVertex{graphp} - , m_logicp{logicp} - , m_state{POM_WAIT} - , m_domScopep{nullptr} {} + OrderMoveVertex(V3Graph* graphp, OrderLogicVertex* logicp) VL_MT_DISABLED + : V3GraphVertex{graphp}, + m_logicp{logicp}, + m_state{POM_WAIT}, + m_domScopep{nullptr} {} ~OrderMoveVertex() override = default; // METHODS @@ -78,11 +79,11 @@ public: } OrderLogicVertex* logicp() const VL_MT_STABLE { return m_logicp; } bool isWait() const { return m_state == POM_WAIT; } - void setReady() { + void setReady() VL_MT_DISABLED { UASSERT(m_state == POM_WAIT, "Wait->Ready on node not in proper state"); m_state = POM_READY; } - void setMoved() { + void setMoved() VL_MT_DISABLED { UASSERT(m_state == POM_READY, "Ready->Moved on node not in proper state"); m_state = POM_MOVED; } @@ -103,11 +104,10 @@ class MTaskMoveVertex final : public V3GraphVertex { public: MTaskMoveVertex(V3Graph* graphp, OrderLogicVertex* logicp, const OrderEitherVertex* varp, - const AstSenTree* domainp) - : V3GraphVertex{graphp} - , m_logicp{logicp} - , m_varp{varp} - , m_domainp{domainp} { + const AstSenTree* domainp) VL_MT_DISABLED : V3GraphVertex{graphp}, + m_logicp{logicp}, + m_varp{varp}, + m_domainp{domainp} { UASSERT(!(logicp && varp), "MTaskMoveVertex: logicp and varp may not both be set!\n"); } ~MTaskMoveVertex() override = default; diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 1539ce3c4..ce5ded6a8 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -44,6 +44,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Param.h b/src/V3Param.h index bf4fbe16d..d09a4314c 100644 --- a/src/V3Param.h +++ b/src/V3Param.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Param final { public: - static void param(AstNetlist* rootp); + static void param(AstNetlist* rootp) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Parse.h b/src/V3Parse.h index ed034d36b..70e7b4896 100644 --- a/src/V3Parse.h +++ b/src/V3Parse.h @@ -22,6 +22,7 @@ #include "V3Error.h" #include "V3Global.h" +#include "V3ThreadSafety.h" class AstNetlist; class VInFilter; @@ -39,16 +40,16 @@ private: public: // We must allow reading multiple files into one parser - V3Parse(AstNetlist* rootp, VInFilter* filterp, V3ParseSym* symp); - ~V3Parse(); + V3Parse(AstNetlist* rootp, VInFilter* filterp, V3ParseSym* symp) VL_MT_DISABLED; + ~V3Parse() VL_MT_DISABLED; // METHODS // Preprocess and read the Verilog file specified into the netlist database void parseFile(FileLine* fileline, const string& modname, bool inLibrary, - const string& errmsg); + const string& errmsg) VL_MT_DISABLED; // Push preprocessed text to the lexer - static void ppPushText(V3ParseImp* impp, const string& text); + static void ppPushText(V3ParseImp* impp, const string& text) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3ParseGrammar.cpp b/src/V3ParseGrammar.cpp index 74b729abc..10be43782 100644 --- a/src/V3ParseGrammar.cpp +++ b/src/V3ParseGrammar.cpp @@ -16,6 +16,8 @@ #define YYDEBUG 1 // Nicer errors +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "V3Ast.h" // This must be before V3ParseBison.cpp, as we don't want #defines to conflict VL_DEFINE_DEBUG_FUNCTIONS; diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index c7e2e62b4..1da582004 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -22,6 +22,8 @@ // V3Lexer.yy.cpp Flex output //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index 9017c0ae6..743b4ec14 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -25,6 +25,7 @@ #include "V3Global.h" #include "V3Parse.h" #include "V3ParseSym.h" +#include "V3ThreadSafety.h" #include #include @@ -123,7 +124,7 @@ struct V3ParseBisonYYSType { #include "V3Ast__gen_yystype.h" }; }; -std::ostream& operator<<(std::ostream& os, const V3ParseBisonYYSType& rhs); +std::ostream& operator<<(std::ostream& os, const V3ParseBisonYYSType& rhs) VL_MT_DISABLED; #define YYSTYPE V3ParseBisonYYSType @@ -170,21 +171,21 @@ public: void tagNodep(AstNode* nodep) { m_tagNodep = nodep; } AstNode* tagNodep() const { return m_tagNodep; } - void lexTimescaleParse(FileLine* fl, const char* textp); + void lexTimescaleParse(FileLine* fl, const char* textp) VL_MT_DISABLED; void timescaleMod(FileLine* fl, AstNodeModule* modp, bool unitSet, double unitVal, - bool precSet, double precVal); + bool precSet, double precVal) VL_MT_DISABLED; VTimescale timeLastUnit() const { return m_timeLastUnit; } FileLine* lexFileline() const { return m_lexFileline; } FileLine* lexCopyOrSameFileLine() { return lexFileline()->copyOrSameFileLine(); } - static void lexErrorPreprocDirective(FileLine* fl, const char* textp); - static string lexParseTag(const char* textp); - static double lexParseTimenum(const char* text); - void lexPpline(const char* textp); - void lexVerilatorCmtLint(FileLine* fl, const char* textp, bool warnOff); - void lexVerilatorCmtLintSave(const FileLine* fl); - void lexVerilatorCmtLintRestore(FileLine* fl); - static void lexVerilatorCmtBad(FileLine* fl, const char* textp); + static void lexErrorPreprocDirective(FileLine* fl, const char* textp) VL_MT_DISABLED; + static string lexParseTag(const char* textp) VL_MT_DISABLED; + static double lexParseTimenum(const char* text) VL_MT_DISABLED; + void lexPpline(const char* textp) VL_MT_DISABLED; + void lexVerilatorCmtLint(FileLine* fl, const char* textp, bool warnOff) VL_MT_DISABLED; + void lexVerilatorCmtLintSave(const FileLine* fl) VL_MT_DISABLED; + void lexVerilatorCmtLintRestore(FileLine* fl) VL_MT_DISABLED; + static void lexVerilatorCmtBad(FileLine* fl, const char* textp) VL_MT_DISABLED; void lexPushKeywords(int state) { ++m_lexKwdDepth; @@ -199,14 +200,14 @@ public: } } int lexKwdLastState() const { return m_lexKwdLast; } - static const char* tokenName(int tok); - static bool isStrengthToken(int tok); + static const char* tokenName(int tok) VL_MT_DISABLED; + static bool isStrengthToken(int tok) VL_MT_DISABLED; void ppPushText(const string& text) { m_ppBuffers.push_back(text); if (lexFileline()->contentp()) lexFileline()->contentp()->pushText(text); } - size_t ppInputToLex(char* buf, size_t max_size); + size_t ppInputToLex(char* buf, size_t max_size) VL_MT_DISABLED; static V3ParseImp* parsep() { return s_parsep; } @@ -248,12 +249,12 @@ public: void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; } // Interactions with parser - int bisonParse(); + int bisonParse() VL_MT_DISABLED; // Interactions with lexer - void lexNew(); - void lexDestroy(); - static int stateVerilogRecent(); // Parser -> lexer communication + void lexNew() VL_MT_DISABLED; + void lexDestroy() VL_MT_DISABLED; + static int stateVerilogRecent() VL_MT_DISABLED; // Parser -> lexer communication int lexPrevToken() const { return m_lexPrevToken; } // Parser -> lexer communication size_t flexPpInputToLex(char* buf, size_t max_size) { return ppInputToLex(buf, max_size); } @@ -282,28 +283,29 @@ public: m_lexKwdLast = stateVerilogRecent(); m_timeLastUnit = v3Global.opt.timeDefaultUnit(); } - ~V3ParseImp(); - void parserClear(); - void lexUnputString(const char* textp, size_t length); + ~V3ParseImp() VL_MT_DISABLED; + void parserClear() VL_MT_DISABLED; + void lexUnputString(const char* textp, size_t length) VL_MT_DISABLED; // METHODS // Preprocess and read the Verilog file specified into the netlist database - int tokenToBison(); // Pass token to bison + int tokenToBison() VL_MT_DISABLED; // Pass token to bison void parseFile(FileLine* fileline, const string& modfilename, bool inLibrary, - const string& errmsg); - void dumpInputsFile(); + const string& errmsg) VL_MT_DISABLED; + void dumpInputsFile() VL_MT_DISABLED; private: - void lexFile(const string& modname); - void yylexReadTok(); - void tokenPull(); - void tokenPipeline(); // Internal; called from tokenToBison - void tokenPipelineSym(); - size_t tokenPipeScanParam(size_t depth); - size_t tokenPipeScanType(size_t depth); - const V3ParseBisonYYSType* tokenPeekp(size_t depth); - void preprocDumps(std::ostream& os, bool forInputs); + void preprocDumps(std::ostream& os); + void lexFile(const string& modname) VL_MT_DISABLED; + void yylexReadTok() VL_MT_DISABLED; + void tokenPull() VL_MT_DISABLED; + void tokenPipeline() VL_MT_DISABLED; // Internal; called from tokenToBison + void tokenPipelineSym() VL_MT_DISABLED; + size_t tokenPipeScanParam(size_t depth) VL_MT_DISABLED; + size_t tokenPipeScanType(size_t depth) VL_MT_DISABLED; + const V3ParseBisonYYSType* tokenPeekp(size_t depth) VL_MT_DISABLED; + void preprocDumps(std::ostream& os, bool forInputs) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3ParseLex.cpp b/src/V3ParseLex.cpp index 43ae1fb53..bb39e3a59 100644 --- a/src/V3ParseLex.cpp +++ b/src/V3ParseLex.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index a67f92d7b..d2e27a85b 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Partition.h b/src/V3Partition.h index cfa68c515..caac97371 100644 --- a/src/V3Partition.h +++ b/src/V3Partition.h @@ -23,6 +23,7 @@ #include "V3Graph.h" #include "V3OrderGraph.h" #include "V3OrderMoveGraph.h" +#include "V3ThreadSafety.h" #include #include @@ -51,24 +52,24 @@ public: // Fill in the provided empty graph with AbstractLogicMTask's and their // interdependencies. - void go(V3Graph* mtasksp); + void go(V3Graph* mtasksp) VL_MT_DISABLED; - static void selfTest(); - static void selfTestNormalizeCosts(); + static void selfTest() VL_MT_DISABLED; + static void selfTestNormalizeCosts() VL_MT_DISABLED; // Print out a hash of the shape of graphp. Only needed to debug the // origin of some nondeterminism; otherwise this is pretty useless. - static void hashGraphDebug(const V3Graph* graphp, const char* debugName); + static void hashGraphDebug(const V3Graph* graphp, const char* debugName) VL_MT_DISABLED; // Print debug stats about graphp whose nodes must be AbstractMTask's. - static void debugMTaskGraphStats(const V3Graph* graphp, const string& stage); + static void debugMTaskGraphStats(const V3Graph* graphp, const string& stage) VL_MT_DISABLED; // Operate on the final ExecMTask graph, immediately prior to code // generation time. - static void finalize(AstNetlist* netlistp); + static void finalize(AstNetlist* netlistp) VL_MT_DISABLED; private: - uint32_t setupMTaskDeps(V3Graph* mtasksp); + uint32_t setupMTaskDeps(V3Graph* mtasksp) VL_MT_DISABLED; VL_UNCOPYABLE(V3Partition); }; diff --git a/src/V3PartitionGraph.h b/src/V3PartitionGraph.h index eb1455e2a..cdfab1be1 100644 --- a/src/V3PartitionGraph.h +++ b/src/V3PartitionGraph.h @@ -31,8 +31,7 @@ class AbstractMTask VL_NOT_FINAL : public V3GraphVertex { VL_RTTI_IMPL(AbstractMTask, V3GraphVertex) public: - explicit AbstractMTask(V3Graph* graphp) - : V3GraphVertex{graphp} {} + explicit AbstractMTask(V3Graph* graphp) VL_MT_DISABLED : V3GraphVertex{graphp} {} ~AbstractMTask() override = default; virtual uint32_t id() const = 0; virtual uint32_t cost() const = 0; @@ -44,8 +43,7 @@ public: // TYPES using VxList = std::list; // CONSTRUCTORS - explicit AbstractLogicMTask(V3Graph* graphp) - : AbstractMTask{graphp} {} + explicit AbstractLogicMTask(V3Graph* graphp) VL_MT_DISABLED : AbstractMTask{graphp} {} ~AbstractLogicMTask() override = default; // METHODS // Set of logic vertices in this mtask. Order is not significant. @@ -70,10 +68,10 @@ private: VL_UNCOPYABLE(ExecMTask); public: - ExecMTask(V3Graph* graphp, AstMTaskBody* bodyp, uint32_t id) - : AbstractMTask{graphp} - , m_bodyp{bodyp} - , m_id{id} {} + ExecMTask(V3Graph* graphp, AstMTaskBody* bodyp, uint32_t id) VL_MT_DISABLED + : AbstractMTask{graphp}, + m_bodyp{bodyp}, + m_id{id} {} AstMTaskBody* bodyp() const { return m_bodyp; } uint32_t id() const override VL_MT_SAFE { return m_id; } uint32_t priority() const { return m_priority; } diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index cea6db1f2..075d677d2 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3PreProc.h b/src/V3PreProc.h index f13ef98ed..13d4aefad 100644 --- a/src/V3PreProc.h +++ b/src/V3PreProc.h @@ -23,6 +23,7 @@ #include "V3Error.h" #include "V3FileLine.h" #include "V3Global.h" +#include "V3ThreadSafety.h" #include #include @@ -57,7 +58,7 @@ public: virtual bool isEof() const = 0; // Return true on EOF. virtual void insertUnreadback(const string& text) = 0; - FileLine* fileline(); ///< File/Line number for last getline call + FileLine* fileline() VL_MT_DISABLED; ///< File/Line number for last getline call // CONTROL METHODS // These options control how the parsing proceeds @@ -96,7 +97,7 @@ protected: void configure(FileLine* fl); public: - static V3PreProc* createPreProc(FileLine* fl); + static V3PreProc* createPreProc(FileLine* fl) VL_MT_DISABLED; virtual ~V3PreProc() = default; // LCOV_EXCL_LINE // Persistent }; diff --git a/src/V3PreShell.cpp b/src/V3PreShell.cpp index 087b25a75..fc48e1f62 100644 --- a/src/V3PreShell.cpp +++ b/src/V3PreShell.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3PreShell.h b/src/V3PreShell.h index eb6a426cd..6972d5a67 100644 --- a/src/V3PreShell.h +++ b/src/V3PreShell.h @@ -22,6 +22,7 @@ #include "V3Error.h" #include "V3FileLine.h" +#include "V3ThreadSafety.h" class V3ParseImp; class VInFilter; @@ -32,15 +33,15 @@ class VSpellCheck; class V3PreShell final { // Static class for calling preprocessor public: - static void boot(); - static void shutdown(); + static void boot() VL_MT_DISABLED; + static void shutdown() VL_MT_DISABLED; static bool preproc(FileLine* fl, const string& modname, VInFilter* filterp, - V3ParseImp* parsep, const string& errmsg); - static void preprocInclude(FileLine* fl, const string& modname); - static void defineCmdLine(const string& name, const string& value); - static void undef(const string& name); - static void dumpDefines(std::ostream& os); - static void candidateDefines(VSpellCheck* spellerp); + V3ParseImp* parsep, const string& errmsg) VL_MT_DISABLED; + static void preprocInclude(FileLine* fl, const string& modname) VL_MT_DISABLED; + static void defineCmdLine(const string& name, const string& value) VL_MT_DISABLED; + static void undef(const string& name) VL_MT_DISABLED; + static void dumpDefines(std::ostream& os) VL_MT_DISABLED; + static void candidateDefines(VSpellCheck* spellerp) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 39dbdb9ad..78a748543 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -24,6 +24,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Premit.h b/src/V3Premit.h index 59f09a188..e625392f0 100644 --- a/src/V3Premit.h +++ b/src/V3Premit.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Premit final { public: - static void premitAll(AstNetlist* nodep); + static void premitAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3ProtectLib.cpp b/src/V3ProtectLib.cpp index 3a993714a..08a415395 100644 --- a/src/V3ProtectLib.cpp +++ b/src/V3ProtectLib.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3ProtectLib.h b/src/V3ProtectLib.h index a3db9ea8c..7c1361573 100644 --- a/src/V3ProtectLib.h +++ b/src/V3ProtectLib.h @@ -20,11 +20,13 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + //============================================================================ class V3ProtectLib final { public: - static void protect(); + static void protect() VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 983ecf98a..b544690d1 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -24,6 +24,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Randomize.h b/src/V3Randomize.h index 223575203..5de300667 100644 --- a/src/V3Randomize.h +++ b/src/V3Randomize.h @@ -20,16 +20,18 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstClass; class AstFunc; class AstNetlist; class V3Randomize final { public: - static void randomizeNetlist(AstNetlist* nodep); + static void randomizeNetlist(AstNetlist* nodep) VL_MT_DISABLED; - static AstFunc* newRandomizeFunc(AstClass* nodep); - static AstFunc* newSRandomFunc(AstClass* nodep); + static AstFunc* newRandomizeFunc(AstClass* nodep) VL_MT_DISABLED; + static AstFunc* newSRandomFunc(AstClass* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Reloop.cpp b/src/V3Reloop.cpp index 284c0df36..b50f21b67 100644 --- a/src/V3Reloop.cpp +++ b/src/V3Reloop.cpp @@ -29,6 +29,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Reloop.h b/src/V3Reloop.h index da9228510..4408bcb8d 100644 --- a/src/V3Reloop.h +++ b/src/V3Reloop.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Reloop final { public: - static void reloopAll(AstNetlist* nodep); + static void reloopAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Sched.cpp b/src/V3Sched.cpp index 897cb6343..32386e38b 100644 --- a/src/V3Sched.cpp +++ b/src/V3Sched.cpp @@ -35,6 +35,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Sched.h b/src/V3Sched.h index 526525a37..fca742de4 100644 --- a/src/V3Sched.h +++ b/src/V3Sched.h @@ -21,6 +21,7 @@ #include "verilatedos.h" #include "V3Ast.h" +#include "V3ThreadSafety.h" #include #include @@ -130,12 +131,12 @@ public: AstNodeStmt* m_postUpdates = nullptr; // Post updates for the trigger eval function // Remaps external domains using the specified trigger map - std::map> - remapDomains(const std::unordered_map& trigMap) const; + std::map> remapDomains( + const std::unordered_map& trigMap) const VL_MT_DISABLED; // Creates a timing resume call (if needed, else returns null) - AstCCall* createResume(AstNetlist* const netlistp); + AstCCall* createResume(AstNetlist* const netlistp) VL_MT_DISABLED; // Creates a timing commit call (if needed, else returns null) - AstCCall* createCommit(AstNetlist* const netlistp); + AstCCall* createCommit(AstNetlist* const netlistp) VL_MT_DISABLED; TimingKit() = default; TimingKit(LogicByScope&& lbs, AstNodeStmt* postUpdates, @@ -149,19 +150,20 @@ public: }; // Creates the timing kit and marks variables written by suspendables -TimingKit prepareTiming(AstNetlist* const netlistp); +TimingKit prepareTiming(AstNetlist* const netlistp) VL_MT_DISABLED; // Transforms fork sub-statements into separate functions -void transformForks(AstNetlist* const netlistp); +void transformForks(AstNetlist* const netlistp) VL_MT_DISABLED; // Top level entry point to scheduling -void schedule(AstNetlist*); +void schedule(AstNetlist*) VL_MT_DISABLED; // Sub-steps -LogicByScope breakCycles(AstNetlist* netlistp, const LogicByScope& combinationalLogic); +LogicByScope breakCycles(AstNetlist* netlistp, + const LogicByScope& combinationalLogic) VL_MT_DISABLED; LogicRegions partition(LogicByScope& clockedLogic, LogicByScope& combinationalLogic, - LogicByScope& hybridLogic); -LogicReplicas replicateLogic(LogicRegions&); + LogicByScope& hybridLogic) VL_MT_DISABLED; +LogicReplicas replicateLogic(LogicRegions&) VL_MT_DISABLED; } // namespace V3Sched diff --git a/src/V3SchedAcyclic.cpp b/src/V3SchedAcyclic.cpp index 1416bc2e4..d6d9d73ce 100644 --- a/src/V3SchedAcyclic.cpp +++ b/src/V3SchedAcyclic.cpp @@ -33,6 +33,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3SchedPartition.cpp b/src/V3SchedPartition.cpp index 6299813b2..c7c3fb29b 100644 --- a/src/V3SchedPartition.cpp +++ b/src/V3SchedPartition.cpp @@ -34,6 +34,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3SchedReplicate.cpp b/src/V3SchedReplicate.cpp index e47e2fad8..037fd3593 100644 --- a/src/V3SchedReplicate.cpp +++ b/src/V3SchedReplicate.cpp @@ -34,6 +34,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp index ca7e45626..c3ffa9ef6 100644 --- a/src/V3SchedTiming.cpp +++ b/src/V3SchedTiming.cpp @@ -24,6 +24,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Scope.cpp b/src/V3Scope.cpp index 8156ec1e3..c68b14fe8 100644 --- a/src/V3Scope.cpp +++ b/src/V3Scope.cpp @@ -21,6 +21,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Scope.h b/src/V3Scope.h index 3a6e6b2c6..5e5760554 100644 --- a/src/V3Scope.h +++ b/src/V3Scope.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Scope final { public: - static void scopeAll(AstNetlist* nodep); + static void scopeAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Scoreboard.cpp b/src/V3Scoreboard.cpp index 761ba9f94..5d25cdf76 100644 --- a/src/V3Scoreboard.cpp +++ b/src/V3Scoreboard.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Scoreboard.h b/src/V3Scoreboard.h index 796183ef6..27573b8d2 100644 --- a/src/V3Scoreboard.h +++ b/src/V3Scoreboard.h @@ -22,6 +22,7 @@ #include "V3Error.h" #include "V3PairingHeap.h" +#include "V3ThreadSafety.h" //=============================================================================================== // V3Scoreboard is essentially a heap that can be hinted that some elements have changed keys, at @@ -139,7 +140,7 @@ public: // ###################################################################### namespace V3ScoreboardBase { -void selfTest(); +void selfTest() VL_MT_DISABLED; } // namespace V3ScoreboardBase #endif // Guard diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp index 968a16571..3282e9ef2 100644 --- a/src/V3Slice.cpp +++ b/src/V3Slice.cpp @@ -35,6 +35,8 @@ // simplified to look primarily for SLICESELs. //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Slice.h b/src/V3Slice.h index 002c31443..5eefd784c 100644 --- a/src/V3Slice.h +++ b/src/V3Slice.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Slice final { public: - static void sliceAll(AstNetlist* nodep); + static void sliceAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Split.cpp b/src/V3Split.cpp index 1e6b82801..aa0ac31f0 100644 --- a/src/V3Split.cpp +++ b/src/V3Split.cpp @@ -77,6 +77,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Split.h b/src/V3Split.h index e0978405d..e3eff188f 100644 --- a/src/V3Split.h +++ b/src/V3Split.h @@ -20,14 +20,16 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Split final { public: - static void splitReorderAll(AstNetlist* nodep); - static void splitAlwaysAll(AstNetlist* nodep); + static void splitReorderAll(AstNetlist* nodep) VL_MT_DISABLED; + static void splitAlwaysAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3SplitAs.cpp b/src/V3SplitAs.cpp index f67263dd7..80be47d77 100644 --- a/src/V3SplitAs.cpp +++ b/src/V3SplitAs.cpp @@ -21,6 +21,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3SplitAs.h b/src/V3SplitAs.h index 7d692813d..528695564 100644 --- a/src/V3SplitAs.h +++ b/src/V3SplitAs.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3SplitAs final { public: - static void splitAsAll(AstNetlist* nodep); + static void splitAsAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index dc62dc823..34779a573 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -110,6 +110,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3SplitVar.h b/src/V3SplitVar.h index 2d2c525a5..d3f47afb6 100644 --- a/src/V3SplitVar.h +++ b/src/V3SplitVar.h @@ -19,17 +19,19 @@ //============================================================================ +#include "V3ThreadSafety.h" + class AstNetlist; class AstVar; class V3SplitVar final { public: // Split variables marked with split_var metacomment. - static void splitVariable(AstNetlist* nodep); + static void splitVariable(AstNetlist* nodep) VL_MT_DISABLED; // Return true if the variable can be split. // This check is not perfect. - static bool canSplitVar(const AstVar* varp); + static bool canSplitVar(const AstVar* varp) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Subst.cpp b/src/V3Subst.cpp index 79aa116a6..b214a860f 100644 --- a/src/V3Subst.cpp +++ b/src/V3Subst.cpp @@ -22,6 +22,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Subst.h b/src/V3Subst.h index de7e09381..5320e4c3c 100644 --- a/src/V3Subst.h +++ b/src/V3Subst.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Subst final { public: - static void substituteAll(AstNetlist* nodep); + static void substituteAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3TSP.cpp b/src/V3TSP.cpp index 09774b8fc..cdc296c45 100644 --- a/src/V3TSP.cpp +++ b/src/V3TSP.cpp @@ -19,6 +19,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3TSP.h b/src/V3TSP.h index ea698c62a..91a31d7ed 100644 --- a/src/V3TSP.h +++ b/src/V3TSP.h @@ -22,6 +22,7 @@ #include "verilatedos.h" #include "V3Error.h" +#include "V3ThreadSafety.h" #include @@ -49,9 +50,9 @@ using StateVec = std::vector; // Given an unsorted set of TspState's, sort them to minimize // the transition cost for walking the sorted list. -void tspSort(const StateVec& states, StateVec* resultp); +void tspSort(const StateVec& states, StateVec* resultp) VL_MT_DISABLED; -void selfTest(); +void selfTest() VL_MT_DISABLED; } // namespace V3TSP #endif // Guard diff --git a/src/V3Table.cpp b/src/V3Table.cpp index 6e1c4d6db..ec9bb4167 100644 --- a/src/V3Table.cpp +++ b/src/V3Table.cpp @@ -21,6 +21,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Table.h b/src/V3Table.h index 08eaf62b7..40c43657b 100644 --- a/src/V3Table.h +++ b/src/V3Table.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Table final { public: - static void tableAll(AstNetlist* nodep); + static void tableAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 7586795a0..576342885 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -23,6 +23,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Task.h b/src/V3Task.h index 8dea5bee7..feea7e17e 100644 --- a/src/V3Task.h +++ b/src/V3Task.h @@ -22,6 +22,7 @@ #include "V3Ast.h" #include "V3Error.h" +#include "V3ThreadSafety.h" #include #include @@ -51,19 +52,20 @@ class V3Task final { static const char* const s_dpiTemporaryVarSuffix; public: - static void taskAll(AstNetlist* nodep); + static void taskAll(AstNetlist* nodep) VL_MT_DISABLED; /// Return vector of [port, pin-connects-to] (SLOW) static V3TaskConnects taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp, - V3TaskConnectState* statep = nullptr); + V3TaskConnectState* statep = nullptr) VL_MT_DISABLED; static void taskConnectWrap(AstNodeFTaskRef* nodep, const V3TaskConnects& tconnects, V3TaskConnectState* statep, - const std::set& argWrap); + const std::set& argWrap) VL_MT_DISABLED; static AstNodeFTask* taskConnectWrapNew(AstNodeFTask* taskp, const string& newname, const V3TaskConnects& tconnects, - const std::set& argWrap); + const std::set& argWrap) VL_MT_DISABLED; static string assignInternalToDpi(AstVar* portp, bool isPtr, const string& frSuffix, - const string& toSuffix, const string& frPrefix = ""); - static string assignDpiToInternal(const string& lhsName, AstVar* rhsp); + const string& toSuffix, + const string& frPrefix = "") VL_MT_DISABLED; + static string assignDpiToInternal(const string& lhsName, AstVar* rhsp) VL_MT_DISABLED; static const char* dpiTemporaryVarSuffix() VL_MT_SAFE { return s_dpiTemporaryVarSuffix; } }; diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index ba5fb36e1..6a10731b6 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -44,6 +44,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Timing.h b/src/V3Timing.h index 784b5cddf..271583793 100644 --- a/src/V3Timing.h +++ b/src/V3Timing.h @@ -21,12 +21,13 @@ #include "verilatedos.h" #include "V3Ast.h" +#include "V3ThreadSafety.h" //============================================================================ class V3Timing final { public: - static void timingAll(AstNetlist* nodep); + static void timingAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index abd9b5ffd..c698e1f99 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -35,6 +35,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Trace.h b/src/V3Trace.h index 4e89805e3..214f71a33 100644 --- a/src/V3Trace.h +++ b/src/V3Trace.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Trace final { public: - static void traceAll(AstNetlist* nodep); + static void traceAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index e06a7f02b..d7c69efc7 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -20,6 +20,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3TraceDecl.h b/src/V3TraceDecl.h index 0922e842f..91ca6cad7 100644 --- a/src/V3TraceDecl.h +++ b/src/V3TraceDecl.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3TraceDecl final { public: - static void traceDeclAll(AstNetlist* nodep); + static void traceDeclAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index ded800d65..f13c1dfa0 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -115,6 +115,8 @@ // unsupported. //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Tristate.h b/src/V3Tristate.h index 2b8a22c64..0fff67827 100644 --- a/src/V3Tristate.h +++ b/src/V3Tristate.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Tristate final { public: - static void tristateAll(AstNetlist* nodep); + static void tristateAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Undriven.cpp b/src/V3Undriven.cpp index 84e7aba35..ece583f21 100644 --- a/src/V3Undriven.cpp +++ b/src/V3Undriven.cpp @@ -23,6 +23,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Undriven.h b/src/V3Undriven.h index a93e7fc1a..30c107598 100644 --- a/src/V3Undriven.h +++ b/src/V3Undriven.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Undriven final { public: - static void undrivenAll(AstNetlist* nodep); + static void undrivenAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp index 5a5c6d969..4ad6c78b9 100644 --- a/src/V3Unknown.cpp +++ b/src/V3Unknown.cpp @@ -28,6 +28,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Unknown.h b/src/V3Unknown.h index 24af14faa..912152836 100644 --- a/src/V3Unknown.h +++ b/src/V3Unknown.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; //============================================================================ class V3Unknown final { public: - static void unknownAll(AstNetlist* nodep); + static void unknownAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Unroll.cpp b/src/V3Unroll.cpp index 6655001d1..59a6efa7b 100644 --- a/src/V3Unroll.cpp +++ b/src/V3Unroll.cpp @@ -24,6 +24,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3Unroll.h b/src/V3Unroll.h index 4abf47241..c13e99a58 100644 --- a/src/V3Unroll.h +++ b/src/V3Unroll.h @@ -22,6 +22,7 @@ #include "V3Ast.h" #include "V3Error.h" +#include "V3ThreadSafety.h" //============================================================================ /// Unroller with saved state, so caller can determine when pushDelete's are executed. @@ -35,18 +36,18 @@ class UnrollStateful final { public: // CONSTRUCTORS - UnrollStateful(); - ~UnrollStateful(); + UnrollStateful() VL_MT_DISABLED; + ~UnrollStateful() VL_MT_DISABLED; // METHODS - void unrollGen(AstNodeFor* nodep, const string& beginName); - void unrollAll(AstNetlist* nodep); + void unrollGen(AstNodeFor* nodep, const string& beginName) VL_MT_DISABLED; + void unrollAll(AstNetlist* nodep) VL_MT_DISABLED; }; //============================================================================ class V3Unroll final { public: - static void unrollAll(AstNetlist* nodep); + static void unrollAll(AstNetlist* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3VariableOrder.cpp b/src/V3VariableOrder.cpp index e108e1605..707a8d391 100644 --- a/src/V3VariableOrder.cpp +++ b/src/V3VariableOrder.cpp @@ -20,6 +20,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/V3VariableOrder.h b/src/V3VariableOrder.h index 5dc7b274e..33cc55cec 100644 --- a/src/V3VariableOrder.h +++ b/src/V3VariableOrder.h @@ -20,11 +20,13 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + //============================================================================ class V3VariableOrder final { public: - static void orderAll(); + static void orderAll() VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 1e2be1013..3cc703257 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -63,6 +63,8 @@ // iterateSubtreeReturnEdits. //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" @@ -124,7 +126,8 @@ std::ostream& operator<<(std::ostream& str, const Castable& rhs) { v3errorEnd( \ v3errorBuildMessage(V3Error::v3errorPrep((lhs) < (rhs) ? V3ErrorCode::WIDTHTRUNC \ : (lhs) > (rhs) ? V3ErrorCode::WIDTHEXPAND \ - : V3ErrorCode::WIDTH), \ + : V3ErrorCode::WIDTH, \ + VL_MT_DISABLED_CODE_UNIT), \ msg)) //###################################################################### diff --git a/src/V3Width.h b/src/V3Width.h index 497c0bd23..29021146f 100644 --- a/src/V3Width.h +++ b/src/V3Width.h @@ -20,6 +20,8 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + class AstNetlist; class AstNode; class AstNodeDType; @@ -28,18 +30,18 @@ class AstNodeDType; class V3Width final { public: - static void width(AstNetlist* nodep); - static AstNode* widthParamsEdit(AstNode* nodep); - static AstNode* widthGenerateParamsEdit(AstNode* nodep); + static void width(AstNetlist* nodep) VL_MT_DISABLED; + static AstNode* widthParamsEdit(AstNode* nodep) VL_MT_DISABLED; + static AstNode* widthGenerateParamsEdit(AstNode* nodep) VL_MT_DISABLED; // Final step... Mark all widths as equal - static void widthCommit(AstNetlist* nodep); + static void widthCommit(AstNetlist* nodep) VL_MT_DISABLED; - static AstNodeDType* getCommonClassTypep(AstNode* nodep1, AstNode* nodep2); + static AstNodeDType* getCommonClassTypep(AstNode* nodep1, AstNode* nodep2) VL_MT_DISABLED; // For use only in WidthVisitor // Replace AstSelBit, etc with AstSel/AstArraySel // Returns replacement node if nodep was deleted, or null if none. - static AstNode* widthSelNoIterEdit(AstNode* nodep); + static AstNode* widthSelNoIterEdit(AstNode* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp index 96c88a2d5..c15d64add 100644 --- a/src/V3WidthSel.cpp +++ b/src/V3WidthSel.cpp @@ -26,6 +26,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #include "verilatedos.h" diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 1e98874b8..10b0fb06d 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define VL_MT_CONTROL_CODE_UNIT 1 + #include "V3Active.h" #include "V3ActiveTop.h" #include "V3Assert.h" @@ -116,479 +118,490 @@ static void reportStatsIfEnabled() { } static void process() { - // Sort modules by level so later algorithms don't need to care - V3LinkLevel::modSortByLevel(); - V3Error::abortIfErrors(); - if (v3Global.opt.debugExitParse()) { - cout << "--debug-exit-parse: Exiting after parse\n"; - std::exit(0); - } - - // Convert parseref's to varrefs, and other directly post parsing fixups - V3LinkParse::linkParse(v3Global.rootp()); - // Cross-link signal names - // Cross-link dotted hierarchical references - V3LinkDot::linkDotPrimary(v3Global.rootp()); - v3Global.checkTree(); // Force a check, as link is most likely place for problems - // Check if all parameters have been found - v3Global.opt.checkParameters(); - // Correct state we couldn't know at parse time, repair SEL's - V3LinkResolve::linkResolve(v3Global.rootp()); - // Set Lvalue's in variable refs - V3LinkLValue::linkLValue(v3Global.rootp()); - // Convert return/continue/disable to jumps - V3LinkJump::linkJump(v3Global.rootp()); - // Convert --/++ to normal operations. Must be after LinkJump. - V3LinkInc::linkIncrements(v3Global.rootp()); - V3Error::abortIfErrors(); - - if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "Link"); - if (v3Global.opt.debugExitUvm23()) { + { + const V3MtDisabledLockGuard mtDisabler{v3MtDisabledLock()}; + // Sort modules by level so later algorithms don't need to care + V3LinkLevel::modSortByLevel(); V3Error::abortIfErrors(); - if (v3Global.opt.xmlOnly()) V3EmitXml::emitxml(); - cout << "--debug-exit-uvm23: Exiting after UVM-supported pass\n"; - std::exit(0); - } - - // Remove parameters by cloning modules to de-parameterized versions - // This requires some width calculations and constant propagation - V3Param::param(v3Global.rootp()); - V3LinkDot::linkDotParamed(v3Global.rootp()); // Cleanup as made new modules - V3LinkLValue::linkLValue(v3Global.rootp()); // Resolve new VarRefs - V3Error::abortIfErrors(); - - // Remove any modules that were parameterized and are no longer referenced. - V3Dead::deadifyModules(v3Global.rootp()); - v3Global.checkTree(); - - // Create a hierarchical Verilation plan - if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && v3Global.opt.hierarchical()) { - V3HierBlockPlan::createPlan(v3Global.rootp()); - // If a plan is created, further analysis is not necessary. - // The actual Verilation will be done based on this plan. - if (v3Global.hierPlanp()) { - reportStatsIfEnabled(); - return; + if (v3Global.opt.debugExitParse()) { + cout << "--debug-exit-parse: Exiting after parse\n"; + std::exit(0); } - } - if (v3Global.opt.debugExitUvm()) { + + // Convert parseref's to varrefs, and other directly post parsing fixups + V3LinkParse::linkParse(v3Global.rootp()); + // Cross-link signal names + // Cross-link dotted hierarchical references + V3LinkDot::linkDotPrimary(v3Global.rootp()); + v3Global.checkTree(); // Force a check, as link is most likely place for problems + // Check if all parameters have been found + v3Global.opt.checkParameters(); + // Correct state we couldn't know at parse time, repair SEL's + V3LinkResolve::linkResolve(v3Global.rootp()); + // Set Lvalue's in variable refs + V3LinkLValue::linkLValue(v3Global.rootp()); + // Convert return/continue/disable to jumps + V3LinkJump::linkJump(v3Global.rootp()); + // Convert --/++ to normal operations. Must be after LinkJump. + V3LinkInc::linkIncrements(v3Global.rootp()); V3Error::abortIfErrors(); - if (v3Global.opt.xmlOnly()) V3EmitXml::emitxml(); - cout << "--debug-exit-uvm: Exiting after UVM-supported pass\n"; - std::exit(0); - } - // Calculate and check widths, edit tree to TRUNC/EXTRACT any width mismatches - V3Width::width(v3Global.rootp()); - - V3Error::abortIfErrors(); - - // Commit to the widths we've chosen; Make widthMin==width - V3Width::widthCommit(v3Global.rootp()); - v3Global.assertDTypesResolved(true); - v3Global.widthMinUsage(VWidthMinUsage::MATCHES_WIDTH); - - // Coverage insertion - // Before we do dead code elimination and inlining, or we'll lose it. - if (v3Global.opt.coverage()) V3Coverage::coverage(v3Global.rootp()); - - // Add randomize() class methods if they are used by the design - if (v3Global.useRandomizeMethods()) V3Randomize::randomizeNetlist(v3Global.rootp()); - - // Push constants, but only true constants preserving liveness - // so V3Undriven sees variables to be eliminated, ie "if (0 && foo) ..." - if (v3Global.opt.fConstBeforeDfg()) V3Const::constifyAllLive(v3Global.rootp()); - - // Signal based lint checks, no change to structures - // Must be before first constification pass drops dead code - V3Undriven::undrivenAll(v3Global.rootp()); - - // Assertion insertion - // After we've added block coverage, but before other nasty transforms - V3AssertPre::assertPreAll(v3Global.rootp()); - // - V3Assert::assertAll(v3Global.rootp()); - - if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { - // Add top level wrapper with instance pointing to old top - // Move packages to under new top - // Must do this after we know parameters and dtypes (as don't clone dtype decls) - V3LinkLevel::wrapTop(v3Global.rootp()); - } - - // Propagate constants into expressions - if (v3Global.opt.fConstBeforeDfg()) V3Const::constifyAllLint(v3Global.rootp()); - - if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { - // Split packed variables into multiple pieces to resolve UNOPTFLAT. - // should be after constifyAllLint() which flattens to 1D bit vector - V3SplitVar::splitVariable(v3Global.rootp()); - - // Remove cell arrays (must be between V3Width and scoping) - V3Inst::dearrayAll(v3Global.rootp()); - V3LinkDot::linkDotArrayed(v3Global.rootp()); - - // Generate classes and tasks required to maintain proper lifetimes for references in forks - V3Fork::makeDynamicScopes(v3Global.rootp()); - V3Fork::makeTasks(v3Global.rootp()); - - // Task inlining & pushing BEGINs names to variables/cells - // Begin processing must be after Param, before module inlining - V3Begin::debeginAll(v3Global.rootp()); // Flatten cell names, before inliner - - // Expand inouts, stage 2 - // Also simplify pin connections to always be AssignWs in prep for V3Unknown - V3Tristate::tristateAll(v3Global.rootp()); - } - - if (!v3Global.opt.xmlOnly()) { - // Move assignments from X into MODULE temps. - // (Before flattening, so each new X variable is shared between all scopes of that module.) - V3Unknown::unknownAll(v3Global.rootp()); - v3Global.constRemoveXs(true); - } - - if (v3Global.opt.fDfgPreInline() || v3Global.opt.fDfgPostInline()) { - // If doing DFG optimization, extract some additional candidates - V3DfgOptimizer::extract(v3Global.rootp()); - } - - if (v3Global.opt.fDfgPreInline()) { - // Pre inline DFG optimization - V3DfgOptimizer::optimize(v3Global.rootp(), " pre inline"); - } - - if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { - // Module inlining - // Cannot remove dead variables after this, as alias information for final - // V3Scope's V3LinkDot is in the AstVar. - if (v3Global.opt.fInline()) { - V3Inline::inlineAll(v3Global.rootp()); - V3LinkDot::linkDotArrayed(v3Global.rootp()); // Cleanup as made new modules - } - } - - if (v3Global.opt.fDfgPostInline()) { - // Post inline DFG optimization - V3DfgOptimizer::optimize(v3Global.rootp(), "post inline"); - } - - // --PRE-FLAT OPTIMIZATIONS------------------ - - // Initial const/dead to reduce work for ordering code - V3Const::constifyAll(v3Global.rootp()); - v3Global.checkTree(); - - V3Dead::deadifyDTypes(v3Global.rootp()); - v3Global.checkTree(); - - V3Error::abortIfErrors(); - - // --FLATTENING--------------- - - if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { - // We're going to flatten the hierarchy, so as many optimizations that - // can be done as possible should be before this.... - - // Convert instantiations to wassigns and always blocks - V3Inst::instAll(v3Global.rootp()); - - // Inst may have made lots of concats; fix them - V3Const::constifyAll(v3Global.rootp()); - - // Flatten hierarchy, creating a SCOPE for each module's usage as a cell - V3Scope::scopeAll(v3Global.rootp()); - V3LinkDot::linkDotScope(v3Global.rootp()); - - // Relocate classes (after linkDot) - V3Class::classAll(v3Global.rootp()); - } - - // --SCOPE BASED OPTIMIZATIONS-------------- - - if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { - // Cleanup - V3Const::constifyAll(v3Global.rootp()); - V3Dead::deadifyDTypesScoped(v3Global.rootp()); - v3Global.checkTree(); - } - - if (!v3Global.opt.xmlOnly()) { - // Convert case statements to if() blocks. Must be after V3Unknown - // Must be before V3Task so don't need to deal with task in case value compares - V3Case::caseAll(v3Global.rootp()); - } - - if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { - // Inline all tasks - V3Task::taskAll(v3Global.rootp()); - } - - if (!v3Global.opt.xmlOnly()) { - // Add __PVT's - // After V3Task so task internal variables will get renamed - V3Name::nameAll(v3Global.rootp()); - - // Loop unrolling & convert FORs to WHILEs - V3Unroll::unrollAll(v3Global.rootp()); - - // Expand slices of arrays - V3Slice::sliceAll(v3Global.rootp()); - - // Push constants across variables and remove redundant assignments - V3Const::constifyAll(v3Global.rootp()); - - if (v3Global.opt.fLife()) V3Life::lifeAll(v3Global.rootp()); - - // Make large low-fanin logic blocks into lookup tables - // This should probably be done much later, once we have common logic elimination. - if (!v3Global.opt.lintOnly() && v3Global.opt.fTable()) { - V3Table::tableAll(v3Global.rootp()); + if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "Link"); + if (v3Global.opt.debugExitUvm23()) { + V3Error::abortIfErrors(); + if (v3Global.opt.xmlOnly()) V3EmitXml::emitxml(); + cout << "--debug-exit-uvm23: Exiting after UVM-supported pass\n"; + std::exit(0); } - // Cleanup - V3Const::constifyAll(v3Global.rootp()); - V3Dead::deadifyDTypesScoped(v3Global.rootp()); + // Remove parameters by cloning modules to de-parameterized versions + // This requires some width calculations and constant propagation + V3Param::param(v3Global.rootp()); + V3LinkDot::linkDotParamed(v3Global.rootp()); // Cleanup as made new modules + V3LinkLValue::linkLValue(v3Global.rootp()); // Resolve new VarRefs + V3Error::abortIfErrors(); + + // Remove any modules that were parameterized and are no longer referenced. + V3Dead::deadifyModules(v3Global.rootp()); v3Global.checkTree(); - // Move assignments/sensitives into a SBLOCK for each unique sensitivity list - // (May convert some ALWAYS to combo blocks, so should be before V3Gate step.) - V3Active::activeAll(v3Global.rootp()); - - // Split single ALWAYS blocks into multiple blocks for better ordering chances - if (v3Global.opt.fSplit()) V3Split::splitAlwaysAll(v3Global.rootp()); - V3SplitAs::splitAsAll(v3Global.rootp()); - - // Create tracing sample points, before we start eliminating signals - if (v3Global.opt.trace()) V3TraceDecl::traceDeclAll(v3Global.rootp()); - - // Convert forceable signals, process force/release statements. - // After V3TraceDecl so we don't trace additional signals inserted to implement forcing. - V3Force::forceAll(v3Global.rootp()); - - // Gate-based logic elimination; eliminate signals and push constant across cell boundaries - // Instant propagation makes lots-o-constant reduction possibilities. - if (v3Global.opt.fGate()) { - V3Gate::gateAll(v3Global.rootp()); - // V3Gate calls constant propagation itself. - } else { - v3info("Command Line disabled gate optimization with -fno-gate. " - "This may cause ordering problems."); + // Create a hierarchical Verilation plan + if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && v3Global.opt.hierarchical()) { + V3HierBlockPlan::createPlan(v3Global.rootp()); + // If a plan is created, further analysis is not necessary. + // The actual Verilation will be done based on this plan. + if (v3Global.hierPlanp()) { + reportStatsIfEnabled(); + return; + } + } + if (v3Global.opt.debugExitUvm()) { + V3Error::abortIfErrors(); + if (v3Global.opt.xmlOnly()) V3EmitXml::emitxml(); + cout << "--debug-exit-uvm: Exiting after UVM-supported pass\n"; + std::exit(0); } - // Combine COVERINCs with duplicate terms - if (v3Global.opt.coverage()) V3CoverageJoin::coverageJoin(v3Global.rootp()); + // Calculate and check widths, edit tree to TRUNC/EXTRACT any width mismatches + V3Width::width(v3Global.rootp()); - // Remove unused vars + V3Error::abortIfErrors(); + + // Commit to the widths we've chosen; Make widthMin==width + V3Width::widthCommit(v3Global.rootp()); + v3Global.assertDTypesResolved(true); + v3Global.widthMinUsage(VWidthMinUsage::MATCHES_WIDTH); + + // Coverage insertion + // Before we do dead code elimination and inlining, or we'll lose it. + if (v3Global.opt.coverage()) V3Coverage::coverage(v3Global.rootp()); + + // Add randomize() class methods if they are used by the design + if (v3Global.useRandomizeMethods()) V3Randomize::randomizeNetlist(v3Global.rootp()); + + // Push constants, but only true constants preserving liveness + // so V3Undriven sees variables to be eliminated, ie "if (0 && foo) ..." + if (v3Global.opt.fConstBeforeDfg()) V3Const::constifyAllLive(v3Global.rootp()); + + // Signal based lint checks, no change to structures + // Must be before first constification pass drops dead code + V3Undriven::undrivenAll(v3Global.rootp()); + + // Assertion insertion + // After we've added block coverage, but before other nasty transforms + V3AssertPre::assertPreAll(v3Global.rootp()); + // + V3Assert::assertAll(v3Global.rootp()); + + if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { + // Add top level wrapper with instance pointing to old top + // Move packages to under new top + // Must do this after we know parameters and dtypes (as don't clone dtype decls) + V3LinkLevel::wrapTop(v3Global.rootp()); + } + + // Propagate constants into expressions + if (v3Global.opt.fConstBeforeDfg()) V3Const::constifyAllLint(v3Global.rootp()); + + if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { + // Split packed variables into multiple pieces to resolve UNOPTFLAT. + // should be after constifyAllLint() which flattens to 1D bit vector + V3SplitVar::splitVariable(v3Global.rootp()); + + // Remove cell arrays (must be between V3Width and scoping) + V3Inst::dearrayAll(v3Global.rootp()); + V3LinkDot::linkDotArrayed(v3Global.rootp()); + + // Generate classes and tasks required to maintain proper lifetimes for references in + // forks + V3Fork::makeDynamicScopes(v3Global.rootp()); + V3Fork::makeTasks(v3Global.rootp()); + + // Task inlining & pushing BEGINs names to variables/cells + // Begin processing must be after Param, before module inlining + V3Begin::debeginAll(v3Global.rootp()); // Flatten cell names, before inliner + + // Expand inouts, stage 2 + // Also simplify pin connections to always be AssignWs in prep for V3Unknown + V3Tristate::tristateAll(v3Global.rootp()); + } + + if (!v3Global.opt.xmlOnly()) { + // Move assignments from X into MODULE temps. + // (Before flattening, so each new X variable is shared between all scopes of that + // module.) + V3Unknown::unknownAll(v3Global.rootp()); + v3Global.constRemoveXs(true); + } + + if (v3Global.opt.fDfgPreInline() || v3Global.opt.fDfgPostInline()) { + // If doing DFG optimization, extract some additional candidates + V3DfgOptimizer::extract(v3Global.rootp()); + } + + if (v3Global.opt.fDfgPreInline()) { + // Pre inline DFG optimization + V3DfgOptimizer::optimize(v3Global.rootp(), " pre inline"); + } + + if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { + // Module inlining + // Cannot remove dead variables after this, as alias information for final + // V3Scope's V3LinkDot is in the AstVar. + if (v3Global.opt.fInline()) { + V3Inline::inlineAll(v3Global.rootp()); + V3LinkDot::linkDotArrayed(v3Global.rootp()); // Cleanup as made new modules + } + } + + if (v3Global.opt.fDfgPostInline()) { + // Post inline DFG optimization + V3DfgOptimizer::optimize(v3Global.rootp(), "post inline"); + } + + // --PRE-FLAT OPTIMIZATIONS------------------ + + // Initial const/dead to reduce work for ordering code V3Const::constifyAll(v3Global.rootp()); - V3Dead::deadifyAllScoped(v3Global.rootp()); + v3Global.checkTree(); - // Reorder assignments in pipelined blocks - if (v3Global.opt.fReorder()) V3Split::splitReorderAll(v3Global.rootp()); + V3Dead::deadifyDTypes(v3Global.rootp()); + v3Global.checkTree(); - if (v3Global.opt.timing().isSetTrue()) { - // Convert AST for timing if requested - // Needs to be after V3Gate, as that step modifies sentrees - // Needs to be before V3Delayed, as delayed assignments are handled differently in - // suspendable processes - V3Timing::timingAll(v3Global.rootp()); - } + V3Error::abortIfErrors(); - // Create delayed assignments - // This creates lots of duplicate ACTIVES so ActiveTop needs to be after this step - V3Delayed::delayedAll(v3Global.rootp()); + // --FLATTENING--------------- - // Make Active's on the top level. - // Differs from V3Active, because identical clocks may be pushed - // down to a module and now be identical - V3ActiveTop::activeTopAll(v3Global.rootp()); + if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { + // We're going to flatten the hierarchy, so as many optimizations that + // can be done as possible should be before this.... - if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "PreOrder"); + // Convert instantiations to wassigns and always blocks + V3Inst::instAll(v3Global.rootp()); - // Schedule the logic - V3Sched::schedule(v3Global.rootp()); - - // Convert sense lists into IF statements. - V3Clock::clockAll(v3Global.rootp()); - - // Cleanup any dly vars or other temps that are simple assignments - // Life must be done before Subst, as it assumes each CFunc under - // _eval is called only once. - if (v3Global.opt.fLife()) { + // Inst may have made lots of concats; fix them V3Const::constifyAll(v3Global.rootp()); - V3Life::lifeAll(v3Global.rootp()); + + // Flatten hierarchy, creating a SCOPE for each module's usage as a cell + V3Scope::scopeAll(v3Global.rootp()); + V3LinkDot::linkDotScope(v3Global.rootp()); + + // Relocate classes (after linkDot) + V3Class::classAll(v3Global.rootp()); } - if (v3Global.opt.fLifePost()) V3LifePost::lifepostAll(v3Global.rootp()); + // --SCOPE BASED OPTIMIZATIONS-------------- - // Remove unused vars - V3Const::constifyAll(v3Global.rootp()); - V3Dead::deadifyAllScoped(v3Global.rootp()); - - // Create tracing logic, since we ripped out some signals the user might want to trace - // Note past this point, we presume traced variables won't move between CFuncs - // (It's OK if untraced temporaries move around, or vars - // "effectively" activate the same way.) - if (v3Global.opt.trace()) V3Trace::traceAll(v3Global.rootp()); - - if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "Scoped"); - } - - // --MODULE OPTIMIZATIONS-------------- - - if (!v3Global.opt.xmlOnly()) { - // Split deep blocks to appease MSVC++. Must be before Localize. - if (!v3Global.opt.lintOnly() && v3Global.opt.compLimitBlocks()) { - V3DepthBlock::depthBlockAll(v3Global.rootp()); + if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { + // Cleanup + V3Const::constifyAll(v3Global.rootp()); + V3Dead::deadifyDTypesScoped(v3Global.rootp()); + v3Global.checkTree(); } - // Up until this point, all references must be scoped - v3Global.assertScoped(false); - - // Move variables from modules to function local variables where possible - if (v3Global.opt.fLocalize()) V3Localize::localizeAll(v3Global.rootp()); - - // Remove remaining scopes; make varrefs/funccalls relative to current module - V3Descope::descopeAll(v3Global.rootp()); - - // Icache packing; combine common code in each module's functions into subroutines - if (v3Global.opt.fCombine()) V3Combine::combineAll(v3Global.rootp()); - } - - V3Error::abortIfErrors(); - - // --GENERATION------------------ - - if (!v3Global.opt.xmlOnly()) { - // Remove unused vars - V3Const::constifyAll(v3Global.rootp()); - V3Dead::deadifyAll(v3Global.rootp()); - - // Here down, widthMin() is the Verilog width, and width() is the C++ width - // Bits between widthMin() and width() are irrelevant, but may be non zero. - v3Global.widthMinUsage(VWidthMinUsage::VERILOG_WIDTH); - - // Make all expressions either 8, 16, 32 or 64 bits - V3Clean::cleanAll(v3Global.rootp()); - - // Move wide constants to BLOCK temps / ConstPool. - V3Premit::premitAll(v3Global.rootp()); - } - - // Expand macros and wide operators into C++ primitives - if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && v3Global.opt.fExpand()) { - V3Expand::expandAll(v3Global.rootp()); - } - - // Propagate constants across WORDSEL arrayed temporaries - if (!v3Global.opt.xmlOnly() && v3Global.opt.fSubst()) { - // Constant folding of expanded stuff - V3Const::constifyCpp(v3Global.rootp()); - V3Subst::substituteAll(v3Global.rootp()); - } - - if (!v3Global.opt.xmlOnly() && v3Global.opt.fSubstConst()) { - // Constant folding of substitutions - V3Const::constifyCpp(v3Global.rootp()); - V3Dead::deadifyAll(v3Global.rootp()); - } - - if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly()) { - if (v3Global.opt.fMergeCond()) { - // Merge conditionals - V3MergeCond::mergeAll(v3Global.rootp()); + if (!v3Global.opt.xmlOnly()) { + // Convert case statements to if() blocks. Must be after V3Unknown + // Must be before V3Task so don't need to deal with task in case value compares + V3Case::caseAll(v3Global.rootp()); } - if (v3Global.opt.fReloop()) { - // Reform loops to reduce code size - // Must be after all Sel/array index based optimizations - V3Reloop::reloopAll(v3Global.rootp()); + if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { + // Inline all tasks + V3Task::taskAll(v3Global.rootp()); } - // Fix very deep expressions - // Mark evaluation functions as member functions, if needed. - V3Depth::depthAll(v3Global.rootp()); + if (!v3Global.opt.xmlOnly()) { + // Add __PVT's + // After V3Task so task internal variables will get renamed + V3Name::nameAll(v3Global.rootp()); - // Branch prediction - V3Branch::branchAll(v3Global.rootp()); + // Loop unrolling & convert FORs to WHILEs + V3Unroll::unrollAll(v3Global.rootp()); - // Add C casts when longs need to become long-long and vice-versa - // Note depth may insert something needing a cast, so this must be last. - V3Cast::castAll(v3Global.rootp()); - } + // Expand slices of arrays + V3Slice::sliceAll(v3Global.rootp()); - V3Error::abortIfErrors(); - if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly()) { // - V3CCtors::cctorsAll(); - } + // Push constants across variables and remove redundant assignments + V3Const::constifyAll(v3Global.rootp()); - if (!v3Global.opt.xmlOnly() && v3Global.opt.mtasks()) { - // Finalize our MTask cost estimates and pack the mtasks into - // threads. Must happen pre-EmitC which relies on the packing - // order. Must happen post-V3LifePost which changes the relative - // costs of mtasks. - V3Partition::finalize(v3Global.rootp()); - } + if (v3Global.opt.fLife()) V3Life::lifeAll(v3Global.rootp()); - if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && !v3Global.opt.dpiHdrOnly()) { - // Add common methods/etc to modules - V3Common::commonAll(); + // Make large low-fanin logic blocks into lookup tables + // This should probably be done much later, once we have common logic elimination. + if (!v3Global.opt.lintOnly() && v3Global.opt.fTable()) { + V3Table::tableAll(v3Global.rootp()); + } - // Order variables - V3VariableOrder::orderAll(); + // Cleanup + V3Const::constifyAll(v3Global.rootp()); + V3Dead::deadifyDTypesScoped(v3Global.rootp()); + v3Global.checkTree(); - // Create AstCUse to determine what class forward declarations/#includes needed in C - V3CUse::cUseAll(); - } + // Move assignments/sensitives into a SBLOCK for each unique sensitivity list + // (May convert some ALWAYS to combo blocks, so should be before V3Gate step.) + V3Active::activeAll(v3Global.rootp()); - // Output the text - if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && !v3Global.opt.dpiHdrOnly()) { - // emitcInlines is first, as it may set needHInlines which other emitters read - V3EmitC::emitcInlines(); - V3EmitC::emitcSyms(); - V3EmitC::emitcConstPool(); - V3EmitC::emitcModel(); - V3EmitC::emitcHeaders(); - } else if (v3Global.opt.dpiHdrOnly()) { - V3EmitC::emitcSyms(true); + // Split single ALWAYS blocks into multiple blocks for better ordering chances + if (v3Global.opt.fSplit()) V3Split::splitAlwaysAll(v3Global.rootp()); + V3SplitAs::splitAsAll(v3Global.rootp()); + + // Create tracing sample points, before we start eliminating signals + if (v3Global.opt.trace()) V3TraceDecl::traceDeclAll(v3Global.rootp()); + + // Convert forceable signals, process force/release statements. + // After V3TraceDecl so we don't trace additional signals inserted to implement + // forcing. + V3Force::forceAll(v3Global.rootp()); + + // Gate-based logic elimination; eliminate signals and push constant across cell + // boundaries Instant propagation makes lots-o-constant reduction possibilities. + if (v3Global.opt.fGate()) { + V3Gate::gateAll(v3Global.rootp()); + // V3Gate calls constant propagation itself. + } else { + v3info("Command Line disabled gate optimization with -fno-gate. " + "This may cause ordering problems."); + } + + // Combine COVERINCs with duplicate terms + if (v3Global.opt.coverage()) V3CoverageJoin::coverageJoin(v3Global.rootp()); + + // Remove unused vars + V3Const::constifyAll(v3Global.rootp()); + V3Dead::deadifyAllScoped(v3Global.rootp()); + + // Reorder assignments in pipelined blocks + if (v3Global.opt.fReorder()) V3Split::splitReorderAll(v3Global.rootp()); + + if (v3Global.opt.timing().isSetTrue()) { + // Convert AST for timing if requested + // Needs to be after V3Gate, as that step modifies sentrees + // Needs to be before V3Delayed, as delayed assignments are handled differently in + // suspendable processes + V3Timing::timingAll(v3Global.rootp()); + } + + // Create delayed assignments + // This creates lots of duplicate ACTIVES so ActiveTop needs to be after this step + V3Delayed::delayedAll(v3Global.rootp()); + + // Make Active's on the top level. + // Differs from V3Active, because identical clocks may be pushed + // down to a module and now be identical + V3ActiveTop::activeTopAll(v3Global.rootp()); + + if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "PreOrder"); + + // Schedule the logic + V3Sched::schedule(v3Global.rootp()); + + // Convert sense lists into IF statements. + V3Clock::clockAll(v3Global.rootp()); + + // Cleanup any dly vars or other temps that are simple assignments + // Life must be done before Subst, as it assumes each CFunc under + // _eval is called only once. + if (v3Global.opt.fLife()) { + V3Const::constifyAll(v3Global.rootp()); + V3Life::lifeAll(v3Global.rootp()); + } + + if (v3Global.opt.fLifePost()) V3LifePost::lifepostAll(v3Global.rootp()); + + // Remove unused vars + V3Const::constifyAll(v3Global.rootp()); + V3Dead::deadifyAllScoped(v3Global.rootp()); + + // Create tracing logic, since we ripped out some signals the user might want to trace + // Note past this point, we presume traced variables won't move between CFuncs + // (It's OK if untraced temporaries move around, or vars + // "effectively" activate the same way.) + if (v3Global.opt.trace()) V3Trace::traceAll(v3Global.rootp()); + + if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "Scoped"); + } + + // --MODULE OPTIMIZATIONS-------------- + + if (!v3Global.opt.xmlOnly()) { + // Split deep blocks to appease MSVC++. Must be before Localize. + if (!v3Global.opt.lintOnly() && v3Global.opt.compLimitBlocks()) { + V3DepthBlock::depthBlockAll(v3Global.rootp()); + } + + // Up until this point, all references must be scoped + v3Global.assertScoped(false); + + // Move variables from modules to function local variables where possible + if (v3Global.opt.fLocalize()) V3Localize::localizeAll(v3Global.rootp()); + + // Remove remaining scopes; make varrefs/funccalls relative to current module + V3Descope::descopeAll(v3Global.rootp()); + + // Icache packing; combine common code in each module's functions into subroutines + if (v3Global.opt.fCombine()) V3Combine::combineAll(v3Global.rootp()); + } + + V3Error::abortIfErrors(); + + // --GENERATION------------------ + + if (!v3Global.opt.xmlOnly()) { + // Remove unused vars + V3Const::constifyAll(v3Global.rootp()); + V3Dead::deadifyAll(v3Global.rootp()); + + // Here down, widthMin() is the Verilog width, and width() is the C++ width + // Bits between widthMin() and width() are irrelevant, but may be non zero. + v3Global.widthMinUsage(VWidthMinUsage::VERILOG_WIDTH); + + // Make all expressions either 8, 16, 32 or 64 bits + V3Clean::cleanAll(v3Global.rootp()); + + // Move wide constants to BLOCK temps / ConstPool. + V3Premit::premitAll(v3Global.rootp()); + } + + // Expand macros and wide operators into C++ primitives + if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && v3Global.opt.fExpand()) { + V3Expand::expandAll(v3Global.rootp()); + } + + // Propagate constants across WORDSEL arrayed temporaries + if (!v3Global.opt.xmlOnly() && v3Global.opt.fSubst()) { + // Constant folding of expanded stuff + V3Const::constifyCpp(v3Global.rootp()); + V3Subst::substituteAll(v3Global.rootp()); + } + + if (!v3Global.opt.xmlOnly() && v3Global.opt.fSubstConst()) { + // Constant folding of substitutions + V3Const::constifyCpp(v3Global.rootp()); + V3Dead::deadifyAll(v3Global.rootp()); + } + + if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly()) { + if (v3Global.opt.fMergeCond()) { + // Merge conditionals + V3MergeCond::mergeAll(v3Global.rootp()); + } + + if (v3Global.opt.fReloop()) { + // Reform loops to reduce code size + // Must be after all Sel/array index based optimizations + V3Reloop::reloopAll(v3Global.rootp()); + } + + // Fix very deep expressions + // Mark evaluation functions as member functions, if needed. + V3Depth::depthAll(v3Global.rootp()); + + // Branch prediction + V3Branch::branchAll(v3Global.rootp()); + + // Add C casts when longs need to become long-long and vice-versa + // Note depth may insert something needing a cast, so this must be last. + V3Cast::castAll(v3Global.rootp()); + } + + V3Error::abortIfErrors(); + if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly()) { // + V3CCtors::cctorsAll(); + } + + if (!v3Global.opt.xmlOnly() && v3Global.opt.mtasks()) { + // Finalize our MTask cost estimates and pack the mtasks into + // threads. Must happen pre-EmitC which relies on the packing + // order. Must happen post-V3LifePost which changes the relative + // costs of mtasks. + V3Partition::finalize(v3Global.rootp()); + } + + if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && !v3Global.opt.dpiHdrOnly()) { + // Add common methods/etc to modules + V3Common::commonAll(); + + // Order variables + V3VariableOrder::orderAll(); + + // Create AstCUse to determine what class forward declarations/#includes needed in C + V3CUse::cUseAll(); + } + + // Output the text + if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && !v3Global.opt.dpiHdrOnly()) { + // emitcInlines is first, as it may set needHInlines which other emitters read + V3EmitC::emitcInlines(); + V3EmitC::emitcSyms(); + V3EmitC::emitcConstPool(); + V3EmitC::emitcModel(); + V3EmitC::emitcHeaders(); + } else if (v3Global.opt.dpiHdrOnly()) { + V3EmitC::emitcSyms(true); + } } if (!v3Global.opt.xmlOnly() && !v3Global.opt.dpiHdrOnly()) { // Unfortunately we have some lint checks in emitcImp. V3EmitC::emitcImp(); } - if (v3Global.opt.xmlOnly() - // Check XML when debugging to make sure no missing node types - || (v3Global.opt.debugCheck() && !v3Global.opt.lintOnly() && !v3Global.opt.dpiHdrOnly())) { - V3EmitXml::emitxml(); - } - - // Output DPI protected library files - if (!v3Global.opt.libCreate().empty()) { - if (v3Global.rootp()->delaySchedulerp()) { - v3warn(E_UNSUPPORTED, "Unsupported: --lib-create with --timing and delays"); + { + const V3MtDisabledLockGuard mtDisabler{v3MtDisabledLock()}; + if (v3Global.opt.xmlOnly() + // Check XML when debugging to make sure no missing node types + || (v3Global.opt.debugCheck() && !v3Global.opt.lintOnly() + && !v3Global.opt.dpiHdrOnly())) { + V3EmitXml::emitxml(); } - V3ProtectLib::protect(); - V3EmitV::emitvFiles(); - V3EmitC::emitcFiles(); - } - if (v3Global.opt.stats()) V3Stats::statsStage("emit"); - - // Statistics - reportStatsIfEnabled(); - - if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && !v3Global.opt.dpiHdrOnly()) { - size_t src_f_cnt = 0; - for (AstNode* nodep = v3Global.rootp()->filesp(); nodep; nodep = nodep->nextp()) { - if (const AstCFile* cfilep = VN_CAST(nodep, CFile)) - src_f_cnt += cfilep->source() ? 1 : 0; + // Output DPI protected library files + if (!v3Global.opt.libCreate().empty()) { + if (v3Global.rootp()->delaySchedulerp()) { + v3warn(E_UNSUPPORTED, "Unsupported: --lib-create with --timing and delays"); + } + V3ProtectLib::protect(); + V3EmitV::emitvFiles(); + V3EmitC::emitcFiles(); } - if (src_f_cnt >= V3EmitMk::PARALLEL_FILE_CNT_THRESHOLD) v3Global.useParallelBuild(true); - // Makefile must be after all other emitters - if (v3Global.opt.main()) V3EmitCMain::emit(); - if (v3Global.opt.cmake()) V3EmitCMake::emit(); - if (v3Global.opt.gmake()) V3EmitMk::emitmk(); + if (v3Global.opt.stats()) V3Stats::statsStage("emit"); + + // Statistics + reportStatsIfEnabled(); + + if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && !v3Global.opt.dpiHdrOnly()) { + size_t src_f_cnt = 0; + for (AstNode* nodep = v3Global.rootp()->filesp(); nodep; nodep = nodep->nextp()) { + if (const AstCFile* cfilep = VN_CAST(nodep, CFile)) + src_f_cnt += cfilep->source() ? 1 : 0; + } + if (src_f_cnt >= V3EmitMk::PARALLEL_FILE_CNT_THRESHOLD) + v3Global.useParallelBuild(true); + + // Makefile must be after all other emitters + if (v3Global.opt.main()) V3EmitCMain::emit(); + if (v3Global.opt.cmake()) V3EmitCMake::emit(); + if (v3Global.opt.gmake()) V3EmitMk::emitmk(); + } } } @@ -626,21 +639,29 @@ static void verilate(const string& argString) { // and after removing files as may make debug output) VBasicDTypeKwd::selfTest(); if (v3Global.opt.debugSelfTest()) { - VHashSha256::selfTest(); - VSpellCheck::selfTest(); - V3Graph::selfTest(); - V3TSP::selfTest(); - V3ScoreboardBase::selfTest(); - V3Partition::selfTest(); - V3Partition::selfTestNormalizeCosts(); - V3Broken::selfTest(); + { + const V3MtDisabledLockGuard mtDisabler{v3MtDisabledLock()}; + + VHashSha256::selfTest(); + VSpellCheck::selfTest(); + V3Graph::selfTest(); + V3TSP::selfTest(); + V3ScoreboardBase::selfTest(); + V3Partition::selfTest(); + V3Partition::selfTestNormalizeCosts(); + V3Broken::selfTest(); + } V3ThreadPool::selfTest(); UINFO(2, "selfTest done\n"); } - // Read first filename - v3Global.readFiles(); - v3Global.removeStd(); + { + const V3MtDisabledLockGuard mtDisabler{v3MtDisabledLock()}; + + // Read first filename + v3Global.readFiles(); + v3Global.removeStd(); + } // Link, etc, if needed if (!v3Global.opt.preprocOnly()) { // @@ -660,6 +681,8 @@ static void verilate(const string& argString) { V3Error::abortIfWarnings(); if (v3Global.hierPlanp()) { // This run is for just write a makefile + const V3MtDisabledLockGuard mtDisabler{v3MtDisabledLock()}; + UASSERT(v3Global.opt.hierarchical(), "hierarchical must be set"); UASSERT(!v3Global.opt.hierChild(), "This must not be a hierarhcical-child run"); UASSERT(v3Global.opt.hierBlocks().empty(), "hierarchical-block must not be set"); @@ -747,21 +770,25 @@ int main(int argc, char** argv) { time(&randseed); srand(static_cast(randseed)); - // Post-constructor initialization of netlists - v3Global.boot(); - - // Preprocessor - // Before command parsing so we can handle -Ds on command line. - V3PreShell::boot(); - - // Command option parsing - v3Global.opt.buildDepBin(VString::escapeStringForPath(argv[0])); const string argString = V3Options::argString(argc - 1, argv + 1); - v3Global.opt.parseOpts(new FileLine{FileLine::commandLineFilename()}, argc - 1, argv + 1); + { + const V3MtDisabledLockGuard mtDisabler{v3MtDisabledLock()}; - // Validate settings (aka Boost.Program_options) - v3Global.opt.notify(); - v3Global.rootp()->timeInit(); + // Post-constructor initialization of netlists + v3Global.boot(); + + // Preprocessor + // Before command parsing so we can handle -Ds on command line. + V3PreShell::boot(); + + // Command option parsing + v3Global.opt.buildDepBin(VString::escapeStringForPath(argv[0])); + v3Global.opt.parseOpts(new FileLine{FileLine::commandLineFilename()}, argc - 1, argv + 1); + + // Validate settings (aka Boost.Program_options) + v3Global.opt.notify(); + v3Global.rootp()->timeInit(); + } V3Error::abortIfErrors(); @@ -777,10 +804,14 @@ int main(int argc, char** argv) { execBuildJob(); } - // Explicitly release resources - V3PreShell::shutdown(); - v3Global.shutdown(); - FileLine::deleteAllRemaining(); + { + const V3MtDisabledLockGuard mtDisabler{v3MtDisabledLock()}; + + // Explicitly release resources + V3PreShell::shutdown(); + v3Global.shutdown(); + FileLine::deleteAllRemaining(); + } UINFO(1, "Done, Exiting...\n"); } diff --git a/src/VlcMain.cpp b/src/VlcMain.cpp index c0c75cdc7..34e314d6d 100644 --- a/src/VlcMain.cpp +++ b/src/VlcMain.cpp @@ -15,6 +15,8 @@ //************************************************************************* // clang-format off +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "config_build.h" #ifndef HAVE_CONFIG_PACKAGE # error "Something failed during ./configure as config_package.h is incomplete. Perhaps you used autoreconf, don't." diff --git a/src/VlcOptions.h b/src/VlcOptions.h index 5bfd183f5..a81737b4f 100644 --- a/src/VlcOptions.h +++ b/src/VlcOptions.h @@ -20,6 +20,8 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3ThreadSafety.h" + #include "config_rev.h" #include @@ -47,7 +49,7 @@ class VlcOptions final { private: // METHODS - static void showVersion(bool verbose); + static void showVersion(bool verbose) VL_MT_DISABLED; public: // CONSTRUCTORS @@ -55,8 +57,8 @@ public: ~VlcOptions() = default; // METHODS - void parseOptsList(int argc, char** argv); - void addReadFile(const string& filename); + void parseOptsList(int argc, char** argv) VL_MT_DISABLED; + void addReadFile(const string& filename) VL_MT_DISABLED; // ACCESSORS (options) const VlStringSet& readFiles() const { return m_readFiles; } @@ -70,7 +72,7 @@ public: string writeInfoFile() const { return m_writeInfoFile; } // METHODS (from main) - static string version(); + static string version() VL_MT_DISABLED; }; //###################################################################### diff --git a/src/VlcTop.cpp b/src/VlcTop.cpp index bf5038450..5ca8d968e 100644 --- a/src/VlcTop.cpp +++ b/src/VlcTop.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define VL_MT_DISABLED_CODE_UNIT 1 + #include "VlcTop.h" #include "V3Error.h" diff --git a/src/verilog.y b/src/verilog.y index c850947d2..cdc6682e9 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -120,15 +120,16 @@ public: } // METHODS - AstArg* argWrapList(AstNodeExpr* nodep); + AstArg* argWrapList(AstNodeExpr* nodep) VL_MT_DISABLED; bool allTracingOn(FileLine* fl) { return v3Global.opt.trace() && m_tracingParse && fl->tracingOn(); } - AstRange* scrubRange(AstNodeRange* rangep); - AstNodeDType* createArray(AstNodeDType* basep, AstNodeRange* rangep, bool isPacked); + AstRange* scrubRange(AstNodeRange* rangep) VL_MT_DISABLED; + AstNodeDType* createArray(AstNodeDType* basep, AstNodeRange* rangep, + bool isPacked) VL_MT_DISABLED; AstVar* createVariable(FileLine* fileline, const string& name, AstNodeRange* arrayp, - AstNode* attrsp); - AstNode* createSupplyExpr(FileLine* fileline, const string& name, int value); + AstNode* attrsp) VL_MT_DISABLED; + AstNode* createSupplyExpr(FileLine* fileline, const string& name, int value) VL_MT_DISABLED; AstText* createTextQuoted(FileLine* fileline, const string& text) { string newtext = deQuote(fileline, text); return new AstText{fileline, newtext}; @@ -254,7 +255,7 @@ public: return createArray(dtypep, rangearraysp, isPacked); } } - string deQuote(FileLine* fileline, string text); + string deQuote(FileLine* fileline, string text) VL_MT_DISABLED; void checkDpiVer(FileLine* fileline, const string& str) { if (str != "DPI-C" && !v3Global.opt.bboxSys()) { fileline->v3error("Unsupported DPI type '" << str << "': Use 'DPI-C'"); From 750b5be5d3f884e54f4a078b05b844a0e0b533de Mon Sep 17 00:00:00 2001 From: Anthony Donlon <4056887+donlon@users.noreply.github.com> Date: Mon, 25 Sep 2023 22:40:44 +0800 Subject: [PATCH 019/157] Remove support for parameterized UDPs (#4518) --- src/verilog.y | 7 +++---- test_regress/t/t_udp_param_bad.out | 7 +++++++ test_regress/t/t_udp_param_bad.pl | 19 +++++++++++++++++++ test_regress/t/t_udp_param_bad.v | 22 ++++++++++++++++++++++ 4 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 test_regress/t/t_udp_param_bad.out create mode 100755 test_regress/t/t_udp_param_bad.pl create mode 100644 test_regress/t/t_udp_param_bad.v diff --git a/src/verilog.y b/src/verilog.y index cdc6682e9..134494488 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -1346,16 +1346,15 @@ module_declaration: // ==IEEE: module_declaration GRAMMARP->m_modp = nullptr; SYMP->popScope($1); GRAMMARP->endLabel($7, $1, $7); } - | udpFront parameter_port_listE portsStarE ';' + | udpFront portsStarE ';' /*cont*/ module_itemListE yENDPRIMITIVE endLabelE { $1->modTrace(false); // Stash for implicit wires, etc if ($2) $1->addStmtsp($2); - if ($3) $1->addStmtsp($3); - if ($5) $1->addStmtsp($5); + if ($4) $1->addStmtsp($4); GRAMMARP->m_tracingParse = true; GRAMMARP->m_modp = nullptr; SYMP->popScope($1); - GRAMMARP->endLabel($7, $1, $7); } + GRAMMARP->endLabel($6, $1, $6); } // | yEXTERN modFront parameter_port_listE portsStarE ';' { BBUNSUP($1, "Unsupported: extern module"); } diff --git a/test_regress/t/t_udp_param_bad.out b/test_regress/t/t_udp_param_bad.out new file mode 100644 index 000000000..cd3152a08 --- /dev/null +++ b/test_regress/t/t_udp_param_bad.out @@ -0,0 +1,7 @@ +%Error: t/t_udp_param_bad.v:12:15: syntax error, unexpected '#', expecting ';' + 12 | primitive udp #( + | ^ +%Error: t/t_udp_param_bad.v:14:1: syntax error, unexpected ')', expecting ';' + 14 | ) (o, a); + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_udp_param_bad.pl b/test_regress/t/t_udp_param_bad.pl new file mode 100755 index 000000000..a60503a1f --- /dev/null +++ b/test_regress/t/t_udp_param_bad.pl @@ -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(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_udp_param_bad.v b/test_regress/t/t_udp_param_bad.v new file mode 100644 index 000000000..8ac68827e --- /dev/null +++ b/test_regress/t/t_udp_param_bad.v @@ -0,0 +1,22 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Anthony Donlon. +// SPDX-License-Identifier: CC0-1.0 + +module t; + wire a, b; + udp i_udp (a, b); +endmodule + +primitive udp #( + parameter A = 1 +) (o, a); + output o; + input a; + table + //o a + 0 : 1; + 1 : 0; + endtable +endprimitive From a9256d47584acf95ba4126f72b69d1f9017d82c5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 25 Sep 2023 11:28:44 -0400 Subject: [PATCH 020/157] CI: Disable m32 runs --- .github/workflows/build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 46752f44c..2ef21b11c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,7 +37,8 @@ jobs: compiler: - { cc: clang, cxx: clang++ } - { cc: gcc, cxx: g++ } - m32: [0, 1] + # m32 1 is deprecated, not here to speed up regressions + m32: [0] exclude: # Build pull requests only with ubuntu-22.04 and without m32 # - os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }} From 60e9827ffe7c68f2b786c8bed76d632c3931a1db Mon Sep 17 00:00:00 2001 From: Anthony Donlon <4056887+donlon@users.noreply.github.com> Date: Mon, 25 Sep 2023 23:39:04 +0800 Subject: [PATCH 021/157] Support converting parameters inside modules to localparams (#4511) --- src/V3AstNodeOther.h | 6 +- src/V3LinkParse.cpp | 15 ++++ src/V3ParseSym.h | 7 ++ src/V3SplitVar.cpp | 1 - src/verilog.y | 76 +++++++++---------- test_regress/t/t_param_implicit_local_bad.out | 23 ++++++ test_regress/t/t_param_implicit_local_bad.pl | 19 +++++ test_regress/t/t_param_implicit_local_bad.v | 55 ++++++++++++++ test_regress/t/t_param_named.v | 10 +-- 9 files changed, 160 insertions(+), 52 deletions(-) create mode 100644 test_regress/t/t_param_implicit_local_bad.out create mode 100755 test_regress/t/t_param_implicit_local_bad.pl create mode 100644 test_regress/t/t_param_implicit_local_bad.v diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index a6b8aa63f..2908bbe95 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -234,6 +234,7 @@ private: bool m_inLibrary : 1; // From a library, no error if not used, never top level bool m_dead : 1; // LinkDot believes is dead; will remove in Dead visitors bool m_hasGParam : 1; // Has global parameter (for link) + bool m_hasParameterList : 1; // Has #() for parameter declaration bool m_hierBlock : 1; // Hierarchical Block marked by HIER_BLOCK pragma bool m_internal : 1; // Internally created bool m_recursive : 1; // Recursive module @@ -248,6 +249,7 @@ protected: , m_inLibrary{false} , m_dead{false} , m_hasGParam{false} + , m_hasParameterList{false} , m_hierBlock{false} , m_internal{false} , m_recursive{false} @@ -277,6 +279,8 @@ public: bool dead() const { return m_dead; } void hasGParam(bool flag) { m_hasGParam = flag; } bool hasGParam() const { return m_hasGParam; } + void hasParameterList(bool flag) { m_hasParameterList = flag; } + bool hasParameterList() const { return m_hasParameterList; } void hierBlock(bool flag) { m_hierBlock = flag; } bool hierBlock() const { return m_hierBlock; } void internal(bool flag) { m_internal = flag; } @@ -1660,7 +1664,7 @@ class AstVar final : public AstNode { VVarAttrClocker m_attrClocker; MTaskIdSet m_mtaskIds; // MTaskID's that read or write this var int m_pinNum = 0; // For XML, if non-zero the connection pin number - bool m_ansi : 1; // ANSI port list variable (for dedup check) + bool m_ansi : 1; // Params or pins declared in the module header, rather than the body bool m_declTyped : 1; // Declared as type (for dedup check) bool m_tristate : 1; // Inout or triwire or trireg bool m_primaryIO : 1; // In/out to top level (or directly assigned from same) diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 48a5cf0e4..5b863df9c 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -66,6 +66,7 @@ private: AstNodeExpr* m_defaultOutSkewp = nullptr; // Current default output skew int m_genblkAbove = 0; // Begin block number of if/case/for above int m_genblkNum = 0; // Begin block number, 0=none seen + int m_beginDepth = 0; // How many begin blocks above current node within current AstNodeModule VLifetime m_lifetime = VLifetime::STATIC; // Propagating lifetime bool m_insideLoop = false; // True if the node is inside a loop @@ -312,7 +313,17 @@ private: if (nodep->lifetime().isNone() && nodep->varType() != VVarType::PORT) { nodep->lifetime(m_lifetime); } + + if (nodep->isGParam() && !nodep->isAnsi()) { // shadow some parameters into localparams + if (m_beginDepth > 0 + || (m_beginDepth == 0 + && (m_modp->hasParameterList() || VN_IS(m_modp, Class) + || VN_IS(m_modp, Package)))) { + nodep->varType(VVarType::LPARAM); + } + } if (nodep->isGParam() && m_modp) m_modp->hasGParam(true); + if (nodep->isParam() && !nodep->valuep() && nodep->fileline()->language() < V3LangCode::L1800_2009) { nodep->v3warn(NEWERSTD, @@ -619,6 +630,7 @@ private: VL_RESTORER(m_modp); VL_RESTORER(m_genblkAbove); VL_RESTORER(m_genblkNum); + VL_RESTORER(m_beginDepth); VL_RESTORER(m_lifetime); { // Module: Create sim table for entire module and iterate @@ -628,6 +640,7 @@ private: m_modp = nodep; m_genblkAbove = 0; m_genblkNum = 0; + m_beginDepth = 0; m_valueModp = nodep; m_lifetime = nodep->lifetime(); if (m_lifetime.isNone()) { @@ -658,6 +671,8 @@ private: void visit(AstBegin* nodep) override { V3Config::applyCoverageBlock(m_modp, nodep); cleanFileline(nodep); + VL_RESTORER(m_beginDepth); + m_beginDepth++; const AstNode* const backp = nodep->backp(); // IEEE says directly nested item is not a new block // The genblk name will get attached to the if true/false LOWER begin block(s) diff --git a/src/V3ParseSym.h b/src/V3ParseSym.h index c29db09d3..32b817e19 100644 --- a/src/V3ParseSym.h +++ b/src/V3ParseSym.h @@ -130,6 +130,13 @@ public: UASSERT_OBJ(!m_sympStack.empty(), nodep, "symbol stack underflow"); m_symCurrentp = m_sympStack.back(); } + AstNodeModule* findTopNodeModule(FileLine* fl, bool requireNoneNull = true) { + for (VSymEnt* const symp : vlstd::reverse_view(m_sympStack)) { + if (AstNodeModule* const modp = VN_CAST(symp->nodep(), NodeModule)) return modp; + } + if (requireNoneNull) fl->v3fatalSrc("fail to find current module"); + return nullptr; + } void showUpward() { // LCOV_EXCL_START UINFO(1, "ParseSym Stack:\n"); for (VSymEnt* const symp : vlstd::reverse_view(m_sympStack)) { diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index 34779a573..e940918b8 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -719,7 +719,6 @@ class SplitUnpackedVarVisitor final : public VNVisitor, public SplitVarImpl { adtypep = VN_AS(refp->dtypep()->skipRefp(), UnpackArrayDType); } else { AstSliceSel* const selp = VN_AS(ref.nodep(), SliceSel); - UASSERT_OBJ(selp, ref.nodep(), "Unexpected op is registered"); refp = VN_AS(selp->fromp(), VarRef); UASSERT_OBJ(refp, selp, "Unexpected op is registered"); adtypep = VN_AS(selp->dtypep()->skipRefp(), UnpackArrayDType); diff --git a/src/verilog.y b/src/verilog.y index 134494488..2b9120969 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -84,7 +84,6 @@ public: AstNodeDType* m_memDTypep = nullptr; // Pointer to data type for next member declaration AstDelay* m_netDelayp = nullptr; // Pointer to delay for next signal declaration AstStrengthSpec* m_netStrengthp = nullptr; // Pointer to strength for next net declaration - AstNodeModule* m_modp = nullptr; // Last module for timeunits FileLine* m_instModuleFl = nullptr; // Fileline of module referenced for instantiations AstPin* m_instParamp = nullptr; // Parameters for instantiations string m_instModule; // Name of module referenced for instantiations @@ -93,10 +92,9 @@ public: VLifetime m_varLifetime; // Static/Automatic for next signal bool m_impliedDecl = false; // Allow implied wire declarations bool m_varDeclTyped = false; // Var got reg/wire for dedup check - bool m_pinAnsi = false; // In ANSI port list + bool m_pinAnsi = false; // In ANSI parameter or port list bool m_tracingParse = true; // Tracing disable for parser bool m_inImplements = false; // Is inside class implements list - bool m_insideClass = false; // Is inside a class body bool m_insideProperty = false; // Is inside property declaration bool m_typedPropertyPort = false; // Typed property port occurred on port lists bool m_modportImpExpActive @@ -317,14 +315,12 @@ int V3ParseGrammar::s_modTypeImpNum = 0; #define VARRESET_LIST(decl) \ { \ GRAMMARP->m_pinNum = 1; \ - GRAMMARP->m_pinAnsi = false; \ VARRESET(); \ VARDECL(decl); \ } // Start of pinlist #define VARRESET_NONLIST(decl) \ { \ GRAMMARP->m_pinNum = 0; \ - GRAMMARP->m_pinAnsi = false; \ VARRESET(); \ VARDECL(decl); \ } // Not in a pinlist @@ -1209,11 +1205,14 @@ description: // ==IEEE: description timeunits_declaration: // ==IEEE: timeunits_declaration yTIMEUNIT yaTIMENUM ';' - { PARSEP->timescaleMod($2, GRAMMARP->m_modp, true, $2, false, 0); $$ = nullptr; } + { PARSEP->timescaleMod($2, SYMP->findTopNodeModule($1, false), true, $2, false, 0); + $$ = nullptr; } | yTIMEUNIT yaTIMENUM '/' yaTIMENUM ';' - { PARSEP->timescaleMod($2, GRAMMARP->m_modp, true, $2, true, $4); $$ = nullptr; } + { PARSEP->timescaleMod($2, SYMP->findTopNodeModule($1, false), true, $2, true, $4); + $$ = nullptr; } | yTIMEPRECISION yaTIMENUM ';' - { PARSEP->timescaleMod($2, GRAMMARP->m_modp, false, 0, true, $2); $$ = nullptr; } + { PARSEP->timescaleMod($2, SYMP->findTopNodeModule($1, false), false, 0, true, $2); + $$ = nullptr; } ; //********************************************************************** @@ -1223,7 +1222,6 @@ package_declaration: // ==IEEE: package_declaration packageFront package_itemListE yENDPACKAGE endLabelE { $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); // Stash for implicit wires, etc if ($2) $1->addStmtsp($2); - GRAMMARP->m_modp = nullptr; SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } ; @@ -1243,8 +1241,7 @@ packageFront: $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); $$->timeunit(PARSEP->timeLastUnit()); PARSEP->rootp()->addModulesp($$); - SYMP->pushNew($$); - GRAMMARP->m_modp = $$; } + SYMP->pushNew($$); } ; package_itemListE: // IEEE: [{ package_item }] @@ -1343,7 +1340,6 @@ module_declaration: // ==IEEE: module_declaration if ($2) $1->addStmtsp($2); if ($3) $1->addStmtsp($3); if ($5) $1->addStmtsp($5); - GRAMMARP->m_modp = nullptr; SYMP->popScope($1); GRAMMARP->endLabel($7, $1, $7); } | udpFront portsStarE ';' @@ -1352,7 +1348,6 @@ module_declaration: // ==IEEE: module_declaration if ($2) $1->addStmtsp($2); if ($4) $1->addStmtsp($4); GRAMMARP->m_tracingParse = true; - GRAMMARP->m_modp = nullptr; SYMP->popScope($1); GRAMMARP->endLabel($6, $1, $6); } // @@ -1371,8 +1366,7 @@ modFront: $$->timeunit(PARSEP->timeLastUnit()); $$->unconnectedDrive(PARSEP->unconnectedDrive()); PARSEP->rootp()->addModulesp($$); - SYMP->pushNew($$); - GRAMMARP->m_modp = $$; } + SYMP->pushNew($$); } | modFront sigAttrScope { $$ = $1; } ; @@ -1419,13 +1413,18 @@ parameter_value_assignmentClass: // IEEE: [ parameter_value_assignment ] parameter_port_listE: // IEEE: parameter_port_list + empty == parameter_value_assignment /* empty */ { $$ = nullptr; } - | '#' '(' ')' { $$ = nullptr; } + | '#' '(' ')' { $$ = nullptr; + SYMP->findTopNodeModule($1)->hasParameterList(true); } // // IEEE: '#' '(' list_of_param_assignments { ',' parameter_port_declaration } ')' // // IEEE: '#' '(' parameter_port_declaration { ',' parameter_port_declaration } ')' // // Can't just do that as "," conflicts with between vars and between stmts, so // // split into pre-comma and post-comma parts - | '#' '(' {VARRESET_LIST(GPARAM);} paramPortDeclOrArgList ')' - { $$ = $4; VARRESET_NONLIST(UNKNOWN); } + | '#' '(' { VARRESET_LIST(GPARAM); + SYMP->findTopNodeModule($1)->hasParameterList(true); + GRAMMARP->m_pinAnsi = true; } + /*cont*/ paramPortDeclOrArgList ')' { $$ = $4; + VARRESET_NONLIST(UNKNOWN); + GRAMMARP->m_pinAnsi = false; } // // Note legal to start with "a=b" with no parameter statement ; @@ -1451,7 +1450,10 @@ portsStarE: // IEEE: .* + list_of_ports + list_of_port_decla | '(' ')' { $$ = nullptr; } // // .* expanded from module_declaration //UNSUP '(' yP_DOTSTAR ')' { UNSUP } - | '(' {VARRESET_LIST(PORT);} list_of_ports ')' { $$ = $3; VARRESET_NONLIST(UNKNOWN); } + | '(' { VARRESET_LIST(PORT); + GRAMMARP->m_pinAnsi = true; } + /*cont*/ list_of_ports ')' { $$ = $3; VARRESET_NONLIST(UNKNOWN); + GRAMMARP->m_pinAnsi = false; } ; list_of_portsE: // IEEE: list_of_ports + list_of_port_declarations @@ -1596,7 +1598,7 @@ portDirNetE: // IEEE: part of port, optional net type and/or // // The higher level rule may override this VARDTYPE with one later in the parse. | port_direction { VARDECL(PORT); VARDTYPE_NDECL(nullptr); } | port_direction { VARDECL(PORT); } net_type { VARDTYPE_NDECL(nullptr); } // net_type calls VARDECL - | net_type { VARDTYPE_NDECL(nullptr); } // net_type calls VARDECL + | net_type { VARDTYPE_NDECL(nullptr); } // net_type calls VARDECL ; port_declNetE: // IEEE: part of port_declaration, optional net type @@ -1706,7 +1708,6 @@ program_declaration: // IEEE: program_declaration + program_nonansi_h if ($2) $1->addStmtsp($2); if ($3) $1->addStmtsp($3); if ($5) $1->addStmtsp($5); - GRAMMARP->m_modp = nullptr; SYMP->popScope($1); GRAMMARP->endLabel($7, $1, $7); } | yEXTERN pgmFront parameter_port_listE portsStarE ';' @@ -1722,8 +1723,7 @@ pgmFront: $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); $$->timeunit(PARSEP->timeLastUnit()); PARSEP->rootp()->addModulesp($$); - SYMP->pushNew($$); - GRAMMARP->m_modp = $$; } + SYMP->pushNew($$); } ; program_itemListE: // ==IEEE: [{ program_item }] @@ -1958,23 +1958,19 @@ net_type: // ==IEEE: net_type ; varParamReset: - yPARAMETER - { if (GRAMMARP->m_insideClass) { - VARRESET_NONLIST(LPARAM); - } else { - VARRESET_NONLIST(GPARAM); - } } + yPARAMETER { VARRESET_NONLIST(GPARAM); } | yLOCALPARAM { VARRESET_NONLIST(LPARAM); } + // Note that the type of these params could be modified later according to context (see V3LinkParse) ; port_direction: // ==IEEE: port_direction + tf_port_direction // // IEEE 19.8 just "input" FIRST forces type to wire - we'll ignore that here // // Only used for ANSI declarations - yINPUT { GRAMMARP->m_pinAnsi = true; VARIO(INPUT); } - | yOUTPUT { GRAMMARP->m_pinAnsi = true; VARIO(OUTPUT); } - | yINOUT { GRAMMARP->m_pinAnsi = true; VARIO(INOUT); } - | yREF { GRAMMARP->m_pinAnsi = true; VARIO(REF); } - | yCONST__REF yREF { GRAMMARP->m_pinAnsi = true; VARIO(CONSTREF); } + yINPUT { VARIO(INPUT); } + | yOUTPUT { VARIO(OUTPUT); } + | yINOUT { VARIO(INOUT); } + | yREF { VARIO(REF); } + | yCONST__REF yREF { VARIO(CONSTREF); } ; port_directionReset: // IEEE: port_direction that starts a port_declaraiton @@ -5960,12 +5956,12 @@ property_port_itemAssignment: // IEEE: part of property_port_item/sequen property_port_itemDirE: /* empty */ - { GRAMMARP->m_pinAnsi = true; VARIO(INPUT); } + { VARIO(INPUT); } | yLOCAL__ETC - { GRAMMARP->m_pinAnsi = true; VARIO(INPUT); + { VARIO(INPUT); BBUNSUP($1, "Unsupported: property port 'local'"); } | yLOCAL__ETC yINPUT - { GRAMMARP->m_pinAnsi = true; VARIO(INPUT); + { VARIO(INPUT); BBUNSUP($1, "Unsupported: property port 'local'"); } ; @@ -6743,7 +6739,6 @@ checker_declaration: // ==IEEE: part of checker_declaration $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); if ($2) $1->addStmtsp($2); if ($4) $1->addStmtsp($4); - GRAMMARP->m_modp = nullptr; SYMP->popScope($1); GRAMMARP->endLabel($6, $1, $6); } ; @@ -6756,8 +6751,7 @@ checkerFront: // IEEE: part of checker_declaration $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); $$->timeunit(PARSEP->timeLastUnit()); $$->unconnectedDrive(PARSEP->unconnectedDrive()); - SYMP->pushNew($$); - GRAMMARP->m_modp = $$; } + SYMP->pushNew($$); } ; checker_port_listE: // IEEE: [ ( [ checker_port_list ] ) ] @@ -6833,7 +6827,6 @@ class_declaration: // ==IEEE: part of class_declaration classFront parameter_port_listE classExtendsE classImplementsE ';' /*mid*/ { // Allow resolving types declared in base extends class if ($3) SYMP->importExtends($3); - GRAMMARP->m_insideClass = true; } /*cont*/ class_itemListE yENDCLASS endLabelE { $$ = $1; $1->addMembersp($2); @@ -6842,7 +6835,6 @@ class_declaration: // ==IEEE: part of class_declaration $1->addExtendsp($4); $1->addMembersp($7); SYMP->popScope($$); - GRAMMARP->m_insideClass = false; GRAMMARP->endLabel($9, $1, $9); } ; diff --git a/test_regress/t/t_param_implicit_local_bad.out b/test_regress/t/t_param_implicit_local_bad.out new file mode 100644 index 000000000..ef6479300 --- /dev/null +++ b/test_regress/t/t_param_implicit_local_bad.out @@ -0,0 +1,23 @@ +%Error-PINNOTFOUND: t/t_param_implicit_local_bad.v:15:20: Parameter pin not found: '__paramNumber2' + 15 | NestedCls #(1, 2) cls; + | ^ + ... For error description see https://verilator.org/warn/PINNOTFOUND?v=latest +%Error-PINNOTFOUND: t/t_param_implicit_local_bad.v:17:21: Parameter pin not found: '__paramNumber3' + 17 | mod1 # ( 3, 4, 5 ) i_mod1 (); + | ^ +%Error-PINNOTFOUND: t/t_param_implicit_local_bad.v:19:15: Parameter pin not found: '__paramNumber1' + 19 | mod3 # ( 7, 24, 25 ) i_mod3 (); + | ^ +%Error-PINNOTFOUND: t/t_param_implicit_local_bad.v:19:18: Parameter pin not found: '__paramNumber2' + 19 | mod3 # ( 7, 24, 25 ) i_mod3 (); + | ^~ +%Error-PINNOTFOUND: t/t_param_implicit_local_bad.v:19:22: Parameter pin not found: '__paramNumber3' + 19 | mod3 # ( 7, 24, 25 ) i_mod3 (); + | ^~ +%Error-PINNOTFOUND: t/t_param_implicit_local_bad.v:20:22: Parameter pin not found: '__paramNumber3' + 20 | intf1 # ( 8, 15, 17 ) i_intf1 (); + | ^~ +%Error-PINNOTFOUND: t/t_param_implicit_local_bad.v:21:22: Parameter pin not found: '__paramNumber3' + 21 | prgm1 # ( 9, 40, 41 ) i_prgm1 (); + | ^~ +%Error: Exiting due to diff --git a/test_regress/t/t_param_implicit_local_bad.pl b/test_regress/t/t_param_implicit_local_bad.pl new file mode 100755 index 000000000..a60503a1f --- /dev/null +++ b/test_regress/t/t_param_implicit_local_bad.pl @@ -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(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_param_implicit_local_bad.v b/test_regress/t/t_param_implicit_local_bad.v new file mode 100644 index 000000000..a6252f77d --- /dev/null +++ b/test_regress/t/t_param_implicit_local_bad.v @@ -0,0 +1,55 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Anthony Donlon. +// SPDX-License-Identifier: CC0-1.0 + + +module t; + class NestedCls #( + parameter A = 0 + ); + parameter B = 0; + endclass + + NestedCls #(1, 2) cls; + + mod1 # ( 3, 4, 5 ) i_mod1 (); + mod2 # ( 5, 12, 13 ) i_mod2 (); + mod3 # ( 7, 24, 25 ) i_mod3 (); + intf1 # ( 8, 15, 17 ) i_intf1 (); + prgm1 # ( 9, 40, 41 ) i_prgm1 (); +endmodule + +`define CHECK_PARAMS if (A**2 + B**2 != C**2) $error("A**2 + B**2 != C**2") + +module mod1 # ( + parameter A = 1, B = 1 +); + parameter C = 1; + `CHECK_PARAMS; +endmodule + +module mod2 (); + parameter A = 1, B = 1, C = 1; + `CHECK_PARAMS; +endmodule + +module mod3 #() (); + parameter A = 1, B = 1, C = 1; + `CHECK_PARAMS; +endmodule + +interface intf1 # ( + parameter A = 1, B = 1 +); + parameter C = 1; + `CHECK_PARAMS; +endinterface + +program prgm1 # ( + parameter A = 1, B = 1 +); + parameter C = 1; + `CHECK_PARAMS; +endprogram diff --git a/test_regress/t/t_param_named.v b/test_regress/t/t_param_named.v index 633b6a220..523b65138 100644 --- a/test_regress/t/t_param_named.v +++ b/test_regress/t/t_param_named.v @@ -11,10 +11,7 @@ module t (/*AUTOARG*/ parameter PAR = 3; input clk; -`ifdef verilator - // Else it becomes a localparam, per IEEE 4.10.1, but we don't check it defparam m3.FROMDEFP = 19; -`endif m3 #(.P3(PAR), .P2(2)) @@ -36,7 +33,8 @@ module m3 parameter UNCH = 99, parameter P1 = 10, parameter P2 = 20, - P3 = 30 + P3 = 30, + parameter FROMDEFP = 11 ) (/*AUTOARG*/ // Inputs @@ -45,8 +43,6 @@ module m3 input clk; localparam LOC = 13; - parameter FROMDEFP = 11; - initial begin $display("%x %x %x",P1,P2,P3); end @@ -55,8 +51,6 @@ module m3 if (P1 !== 10) $stop; if (P2 !== 2) $stop; if (P3 !== 3) $stop; -`ifdef verilator if (FROMDEFP !== 19) $stop; -`endif end endmodule From d2c72a7f21cdbdcf5464bbb9c735ce6f49df0d44 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 25 Sep 2023 12:30:25 -0400 Subject: [PATCH 022/157] CI: Disable m32 runs --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2ef21b11c..ee8fc9162 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -108,7 +108,7 @@ jobs: compiler: - { cc: clang, cxx: clang++ } - { cc: gcc, cxx: g++ } - m32: [0, 1] + m32: [0] suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, vltmt-0, vltmt-1] exclude: # Build pull requests only with ubuntu-22.04 and without m32 From be45a9b7d50baef222ac388feb222fbb359829ad Mon Sep 17 00:00:00 2001 From: Anthony Donlon <4056887+donlon@users.noreply.github.com> Date: Wed, 27 Sep 2023 03:05:57 +0800 Subject: [PATCH 023/157] Style: Update clang-format config to make formatted code consistent between versions. No functional change (#4520) --- .clang-format | 3 +++ include/verilated_funcs.h | 4 ++-- src/V3Number.cpp | 6 ++---- test_regress/t/t_dpi_qw_c.cpp | 2 +- test_regress/t/t_dpi_var.cpp | 2 +- test_regress/t/t_mem_multi_io2.cpp | 2 +- test_regress/t/t_trace_two_cc.cpp | 2 +- test_regress/t/t_var_sc_bv.cpp | 17 ++++++++--------- test_regress/t/t_vpi_time_cb.cpp | 2 -- test_regress/t/t_vpi_zero_time_cb.cpp | 2 +- 10 files changed, 20 insertions(+), 22 deletions(-) diff --git a/.clang-format b/.clang-format index 39b753e7a..3e8142bf7 100644 --- a/.clang-format +++ b/.clang-format @@ -112,6 +112,9 @@ SpacesBeforeTrailingComments: 2 SpacesInAngles: false SpacesInContainerLiterals: true SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 0 + Maximum: -1 SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Cpp11 diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index a33b9023b..32ab2268e 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -344,8 +344,8 @@ uint64_t vl_time_pow10(int n) VL_PURE; // Output clean // EMIT_RULE: VL_CLEAN: oclean=clean; obits=lbits; -#define VL_CLEAN_II(obits, lbits, lhs) ((lhs)&VL_MASK_I(obits)) -#define VL_CLEAN_QQ(obits, lbits, lhs) ((lhs)&VL_MASK_Q(obits)) +#define VL_CLEAN_II(obits, lbits, lhs) ((lhs) & (VL_MASK_I(obits))) +#define VL_CLEAN_QQ(obits, lbits, lhs) ((lhs) & (VL_MASK_Q(obits))) // EMIT_RULE: VL_ASSIGNCLEAN: oclean=clean; obits==lbits; #define VL_ASSIGNCLEAN_W(obits, owp, lwp) VL_CLEAN_WW((obits), (owp), (lwp)) diff --git a/src/V3Number.cpp b/src/V3Number.cpp index 38e7de3a2..702c4c1ca 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -314,8 +314,7 @@ void V3Number::create(const char* sourcep) { case 'o': case 'c': { - switch (std::tolower(*cp)) { - // clang-format off + switch (std::tolower(*cp)) { // clang-format off case '0': setBit(obit++, 0); setBit(obit++, 0); setBit(obit++, 0); break; case '1': setBit(obit++, 1); setBit(obit++, 0); setBit(obit++, 0); break; case '2': setBit(obit++, 0); setBit(obit++, 1); setBit(obit++, 0); break; @@ -335,8 +334,7 @@ void V3Number::create(const char* sourcep) { } case 'h': { - switch (std::tolower(*cp)) { - // clang-format off + switch (std::tolower(*cp)) { // clang-format off case '0': setBit(obit++,0); setBit(obit++,0); setBit(obit++,0); setBit(obit++,0); break; case '1': setBit(obit++,1); setBit(obit++,0); setBit(obit++,0); setBit(obit++,0); break; case '2': setBit(obit++,0); setBit(obit++,1); setBit(obit++,0); setBit(obit++,0); break; diff --git a/test_regress/t/t_dpi_qw_c.cpp b/test_regress/t/t_dpi_qw_c.cpp index 7a18e6b83..751e1c331 100644 --- a/test_regress/t/t_dpi_qw_c.cpp +++ b/test_regress/t/t_dpi_qw_c.cpp @@ -33,7 +33,7 @@ void poke_value(int i) { const char* const scopeNamep = svGetNameFromScope(svGetScope()); printf("svGetNameFromScope=\"%s\"\n", scopeNamep); -// clang-format off + // clang-format off #ifdef VERILATOR static int didDump = 0; if (didDump++ == 0) { diff --git a/test_regress/t/t_dpi_var.cpp b/test_regress/t/t_dpi_var.cpp index eac0571fe..13c3020e0 100644 --- a/test_regress/t/t_dpi_var.cpp +++ b/test_regress/t/t_dpi_var.cpp @@ -121,7 +121,7 @@ int main(int argc, char** argv) { // Note null name - we're flattening it out ""}}; -// clang-format off + // clang-format off #ifdef VERILATOR # ifdef TEST_VERBOSE contextp->scopesDump(); diff --git a/test_regress/t/t_mem_multi_io2.cpp b/test_regress/t/t_mem_multi_io2.cpp index 14e71c1a4..24269b14c 100644 --- a/test_regress/t/t_mem_multi_io2.cpp +++ b/test_regress/t/t_mem_multi_io2.cpp @@ -48,7 +48,7 @@ int main() #endif // loop through every possibility and check the result -// clang-format off + // clang-format off #ifdef SYSTEMC_VERSION sc_start(1, SC_NS); # define ASSIGN(s, v) s.write(v) diff --git a/test_regress/t/t_trace_two_cc.cpp b/test_regress/t/t_trace_two_cc.cpp index 92d9d33f9..46ad12913 100644 --- a/test_regress/t/t_trace_two_cc.cpp +++ b/test_regress/t/t_trace_two_cc.cpp @@ -37,7 +37,7 @@ int main(int argc, char** argv) { ap = new VM_PREFIX{contextp.get(), "topa"}; bp = new Vt_trace_two_b{contextp.get(), "topb"}; -// clang-format off + // clang-format off #ifdef TEST_HDR_TRACE contextp->traceEverOn(true); # ifdef TEST_FST diff --git a/test_regress/t/t_var_sc_bv.cpp b/test_regress/t/t_var_sc_bv.cpp index 306810635..cb0b93ed2 100644 --- a/test_regress/t/t_var_sc_bv.cpp +++ b/test_regress/t/t_var_sc_bv.cpp @@ -108,21 +108,20 @@ int main() #endif -// clang-format off #ifdef SYSTEMC_VERSION sc_start(1, SC_NS); #else tb->eval(); #endif // This testcase is testing multi-thread safe VL_ASSIGN_SBW and VL_ASSIGN_WSB macros. - // Testbench is assigning different number of bits from VlWide input_var variable to different inputs. - // Values around multiple of 30 (i.e. BITS_PER_DIGIT defined in SystemC sc_nbdefs.h) are tested with the special care, since - // it is the value by which the data_ptr of sc_biguint underlying data type is increased by (and not expected 32, as width of uint32_t). - // Correctness of the output is compared against the 'old' macro, which is correct but has multi-threaded issue since it's using range function. - // Second part is testing VL_ASSIGN_WSB in a reverse way, it is reading signals from the previous test, - // and comparing the output with (fraction) of VlWide input_var variable. - - // clang-format on + // Testbench is assigning different number of bits from VlWide input_var variable to different + // inputs. Values around multiple of 30 (i.e. BITS_PER_DIGIT defined in SystemC sc_nbdefs.h) + // are tested with the special care, since it is the value by which the data_ptr of sc_biguint + // underlying data type is increased by (and not expected 32, as width of uint32_t). + // Correctness of the output is compared against the 'old' macro, which is correct but has + // multi-threaded issue since it's using range function. Second part is testing VL_ASSIGN_WSB + // in a reverse way, it is reading signals from the previous test, and comparing the output + // with (fraction) of VlWide input_var variable. VL_ASSIGN_SBW(29, i_29_s, input_var); VL_ASSIGN_SBW_MT_ISSUE(29, i_29_old_s, input_var); VL_ASSIGN_SBW(30, i_30_s, input_var); diff --git a/test_regress/t/t_vpi_time_cb.cpp b/test_regress/t/t_vpi_time_cb.cpp index b26a1fb1f..8bc06e2f1 100644 --- a/test_regress/t/t_vpi_time_cb.cpp +++ b/test_regress/t/t_vpi_time_cb.cpp @@ -35,11 +35,9 @@ int main(int argc, char** argv) { // Note null name - we're flattening it out ""}}; -// clang-format off #ifdef TEST_VERBOSE contextp->scopesDump(); #endif - // clang-format on #if VM_TRACE contextp->traceEverOn(true); diff --git a/test_regress/t/t_vpi_zero_time_cb.cpp b/test_regress/t/t_vpi_zero_time_cb.cpp index e94e11164..32cf2fe6a 100644 --- a/test_regress/t/t_vpi_zero_time_cb.cpp +++ b/test_regress/t/t_vpi_zero_time_cb.cpp @@ -116,7 +116,7 @@ int main(int argc, char** argv) { // Note null name - we're flattening it out ""}}; -// clang-format off + // clang-format off #ifdef VERILATOR # ifdef TEST_VERBOSE contextp->scopesDump(); From 229ce1aecf8c54c3d107fee26eab96f1251962ec Mon Sep 17 00:00:00 2001 From: Anthony Donlon <4056887+donlon@users.noreply.github.com> Date: Wed, 27 Sep 2023 03:42:15 +0800 Subject: [PATCH 024/157] Fix handling input file path separator (#4515) (#4516) --- src/V3EmitCFunc.h | 2 +- src/V3EmitCMake.cpp | 25 ++++---- src/V3EmitMk.cpp | 5 +- src/V3Error.cpp | 10 +--- src/V3File.cpp | 2 +- src/V3FileLine.cpp | 100 +++++++++++++++---------------- src/V3Options.cpp | 66 ++++++++++---------- src/V3Os.cpp | 75 ++++++++++++++++++++--- src/V3Os.h | 29 +++++---- src/V3ParseGrammar.cpp | 64 ++------------------ src/V3PreProc.cpp | 2 +- src/V3Sched.cpp | 3 +- src/V3String.cpp | 65 ++++++++++++++++++++ src/V3String.h | 3 + src/Verilator.cpp | 3 +- src/verilog.y | 8 +-- test_regress/t/t_pp_line.out | 16 +++++ test_regress/t/t_pp_line.pl | 18 ++++++ test_regress/t/t_pp_line.v | 15 +++++ test_regress/t/t_pp_line_bad.out | 19 ++++-- test_regress/t/t_pp_line_bad.pl | 3 +- test_regress/t/t_pp_line_bad.v | 8 ++- 22 files changed, 335 insertions(+), 206 deletions(-) create mode 100644 test_regress/t/t_pp_line.out create mode 100755 test_regress/t/t_pp_line.pl create mode 100644 test_regress/t/t_pp_line.v diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 8dbe3ca70..f9b3bd3d6 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -636,7 +636,7 @@ public: puts("vlSymsp->_traceDumpOpen();\n"); } else { puts("VL_PRINTF_MT(\"-Info: "); - puts(protect(nodep->fileline()->filename())); + puts(V3OutFormatter::quoteNameControls(protect(nodep->fileline()->filename()))); puts(":"); puts(cvtToStr(nodep->fileline()->lineno())); puts(": $dumpvar ignored, as Verilated without --trace"); diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp index 6598da9a8..bd065144d 100644 --- a/src/V3EmitCMake.cpp +++ b/src/V3EmitCMake.cpp @@ -43,15 +43,11 @@ class CMakeEmitter final { template static string cmake_list(const List& strs) { string s; - if (strs.begin() != strs.end()) { - s.append("\""); - s.append(VString::quoteAny(*strs.begin(), '"', '\\')); - s.append("\""); - for (typename List::const_iterator it = ++strs.begin(); it != strs.end(); ++it) { - s.append(" \""); - s.append(VString::quoteAny(*it, '"', '\\')); - s.append("\""); - } + for (auto it = strs.begin(); it != strs.end(); ++it) { + s += '"'; + s += V3OutFormatter::quoteNameControls(*it); + s += '"'; + if (it != strs.end()) s += ' '; } return s; } @@ -63,13 +59,13 @@ class CMakeEmitter final { static void cmake_set_raw(std::ofstream& of, const string& name, const string& raw_value, const string& cache_type = "", const string& docstring = "") { of << "set(" << name << " " << raw_value; - if (!cache_type.empty()) of << " CACHE " << cache_type << " \"" << docstring << "\""; + if (!cache_type.empty()) of << " CACHE " << cache_type << " \"" << docstring << '"'; of << ")\n"; } static void cmake_set(std::ofstream& of, const string& name, const string& value, const string& cache_type = "", const string& docstring = "") { - const string raw_value = "\"" + value + "\""; + const string raw_value = '"' + value + '"'; cmake_set_raw(of, name, raw_value, cache_type, docstring); } @@ -88,9 +84,10 @@ class CMakeEmitter final { *of << "# which becomes available after executing `find_package(verilator).\n"; *of << "\n### Constants...\n"; - cmake_set(*of, "PERL", V3Options::getenvPERL(), "FILEPATH", - "Perl executable (from $PERL)"); - cmake_set(*of, "VERILATOR_ROOT", V3Options::getenvVERILATOR_ROOT(), "PATH", + cmake_set(*of, "PERL", V3OutFormatter::quoteNameControls(V3Options::getenvPERL()), + "FILEPATH", "Perl executable (from $PERL)"); + cmake_set(*of, "VERILATOR_ROOT", + V3OutFormatter::quoteNameControls(V3Options::getenvVERILATOR_ROOT()), "PATH", "Path to Verilator kit (from $VERILATOR_ROOT)"); *of << "\n### Compiler flags...\n"; diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index 3f38e5119..bdf088c6a 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -154,9 +154,10 @@ public: } of.puts("\n### Constants...\n"); of.puts("# Perl executable (from $PERL)\n"); - of.puts("PERL = " + V3Options::getenvPERL() + "\n"); + of.puts("PERL = " + V3OutFormatter::quoteNameControls(V3Options::getenvPERL()) + "\n"); of.puts("# Path to Verilator kit (from $VERILATOR_ROOT)\n"); - of.puts("VERILATOR_ROOT = " + V3Options::getenvVERILATOR_ROOT() + "\n"); + of.puts("VERILATOR_ROOT = " + + V3OutFormatter::quoteNameControls(V3Options::getenvVERILATOR_ROOT()) + "\n"); of.puts("# SystemC include directory with systemc.h (from $SYSTEMC_INCLUDE)\n"); of.puts(string{"SYSTEMC_INCLUDE ?= "} + V3Options::getenvSYSTEMC_INCLUDE() + "\n"); of.puts("# SystemC library directory with libsystemc.a (from $SYSTEMC_LIBDIR)\n"); diff --git a/src/V3Error.cpp b/src/V3Error.cpp index 5d915f9c5..1194cd7e3 100644 --- a/src/V3Error.cpp +++ b/src/V3Error.cpp @@ -16,6 +16,7 @@ // clang-format off #include "V3Error.h" +#include "V3Os.h" #ifndef V3ERROR_NO_GLOBAL_ # include "V3Ast.h" # include "V3Global.h" @@ -262,13 +263,8 @@ void V3Error::init() { string V3Error::lineStr(const char* filename, int lineno) VL_PURE { std::ostringstream out; - const char* const fnslashp = std::strrchr(filename, '/'); - if (fnslashp) filename = fnslashp + 1; - out << filename << ":" << std::dec << lineno << ":"; - const char* const spaces = " "; - size_t numsp = out.str().length(); - if (numsp > 20) numsp = 20; - out << (spaces + numsp); + out << V3Os::filenameNonDir(filename) << ":" << std::dec << lineno << ":"; + out << std::string(std::max(0, 20 - static_cast(out.str().length())), ' '); return out.str(); } diff --git a/src/V3File.cpp b/src/V3File.cpp index 157e8d028..7a669f30d 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -859,7 +859,7 @@ void V3OutFormatter::putcNoTracking(char chr) { string V3OutFormatter::quoteNameControls(const string& namein, V3OutFormatter::Language lang) VL_PURE { // Encode control chars into output-appropriate escapes - // Reverse is V3Parse::deQuote + // Reverse is VString::unquoteSVString string out; if (lang == LA_XML) { // Encode chars into XML string diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index e97db97b2..a8bf044a6 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -203,63 +203,62 @@ string FileLine::xmlDetailedLocation() const { } string FileLine::lineDirectiveStrg(int enterExit) const { - return std::string{"`line "} + cvtToStr(lastLineno()) + " \"" + filename() + "\" " - + cvtToStr(enterExit) + "\n"; + return std::string{"`line "} + cvtToStr(lastLineno()) + " \"" + + V3OutFormatter::quoteNameControls(filename()) + "\" " + cvtToStr(enterExit) + "\n"; } void FileLine::lineDirective(const char* textp, int& enterExitRef) { // Handle `line directive // Does not parse streamNumber/streamLineno as the next input token // will come from the same stream as the previous line. + do { + int lineNo; + // Skip `line + while (*textp && std::isspace(*textp)) ++textp; + while (*textp && !std::isspace(*textp)) ++textp; + while (*textp && std::isspace(*textp)) ++textp; - // Skip `line - while (*textp && std::isspace(*textp)) ++textp; - while (*textp && !std::isspace(*textp)) ++textp; - while (*textp && (std::isspace(*textp) || *textp == '"')) ++textp; + // Grab linenumber + const char* const ln = textp; + while (*textp && !std::isspace(*textp)) ++textp; + if (0 == strncmp(ln, "`__LINE__", textp - ln)) { + // Special case - see docs - don't change other than accounting for `line itself + lineNo = lineno() + 1; + } else if (std::isdigit(*ln)) { + lineNo = std::atoi(ln); + } else { + break; // Fail + } + lineno(lineNo); + while (*textp && (std::isspace(*textp))) ++textp; - // Grab linenumber - bool fail = false; - const char* const ln = textp; - while (*textp && !std::isspace(*textp)) ++textp; - if (0 == strncmp(ln, "`__LINE__", strlen("`__LINE__"))) { - // Special case - see docs - don't change other than accounting for `line itself - lineno(lineno() + 1); - } - if (std::isdigit(*ln)) { - lineno(std::atoi(ln)); - } else { - fail = true; - } - while (*textp && (std::isspace(*textp))) ++textp; - if (*textp != '"') fail = true; - while (*textp && (std::isspace(*textp) || *textp == '"')) ++textp; + // Grab filename + if (*textp != '"') break; // Fail + const char* const fn = ++textp; + while (*textp && *textp != '"') ++textp; + if (*textp != '"') break; // Fail + string errMsg; + const string& parsedFilename = VString::unquoteSVString(string{fn, textp}, errMsg); + if (!errMsg.empty()) this->v3error(errMsg.c_str()); + filename(parsedFilename); + ++textp; + while (*textp && std::isspace(*textp)) ++textp; - // Grab filename - const char* const fn = textp; - while (*textp && !(std::isspace(*textp) || *textp == '"')) ++textp; - if (textp != fn) { - string strfn = fn; - strfn = strfn.substr(0, textp - fn); - filename(strfn); - } else { - fail = true; - } + // Grab level + if (!std::isdigit(*textp)) break; // Fail + const int level = std::atoi(textp); + if (level < 0 || level >= 3) break; // Fail + /// TODO: store lineno/filename only when the `line directive is valid + /// lineno(lineNo); + /// filename(filenameNew); + enterExitRef = level; + return; + } while (false); - // Grab level - while (*textp && (std::isspace(*textp) || *textp == '"')) ++textp; - if (std::isdigit(*textp)) { - enterExitRef = std::atoi(textp); - if (enterExitRef >= 3) fail = true; - } else { - enterExitRef = 0; - fail = true; - } - - if (fail && v3Global.opt.pedantic()) { - v3error("`line was not properly formed with '`line number \"filename\" level'\n"); - } - - // printf ("PPLINE %d '%s'\n", s_lineno, s_filename.c_str()); + // Fail + // TODO: show correct place of the code + v3error("`line was not properly formed with '`line number \"filename\" level'\n"); + enterExitRef = 0; } void FileLine::forwardToken(const char* textp, size_t size, bool trackLines) { @@ -293,12 +292,7 @@ FileLine* FileLine::copyOrSameFileLine() { string FileLine::filebasename() const VL_MT_SAFE { return V3Os::filenameNonDir(filename()); } -string FileLine::filebasenameNoExt() const { - string name = filebasename(); - string::size_type pos; - if ((pos = name.find('.')) != string::npos) name = name.substr(0, pos); - return name; -} +string FileLine::filebasenameNoExt() const { return V3Os::filenameNonDirExt(filename()); } string FileLine::firstColumnLetters() const VL_MT_SAFE { const char a = ((firstColumn() / 26) % 26) + 'a'; diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 42e33a040..9b816f63d 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -81,19 +81,21 @@ public: // ACCESSOR METHODS void addIncDirUser(const string& incdir) { - const auto itFoundPair = m_incDirUserSet.insert(incdir); + const string& dir = V3Os::filenameCleanup(incdir); + const auto itFoundPair = m_incDirUserSet.insert(dir); if (itFoundPair.second) { // cppcheck-suppress stlFindInsert // cppcheck 1.90 bug - m_incDirUsers.push_back(incdir); - m_incDirFallbacks.remove(incdir); // User has priority over Fallback - m_incDirFallbackSet.erase(incdir); // User has priority over Fallback + m_incDirUsers.push_back(dir); + m_incDirFallbacks.remove(dir); // User has priority over Fallback + m_incDirFallbackSet.erase(dir); // User has priority over Fallback } } void addIncDirFallback(const string& incdir) { - if (m_incDirUserSet.find(incdir) + const string& dir = V3Os::filenameCleanup(incdir); + if (m_incDirUserSet.find(dir) == m_incDirUserSet.end()) { // User has priority over Fallback - const auto itFoundPair = m_incDirFallbackSet.insert(incdir); - if (itFoundPair.second) m_incDirFallbacks.push_back(incdir); + const auto itFoundPair = m_incDirFallbackSet.insert(dir); + if (itFoundPair.second) m_incDirFallbacks.push_back(dir); } } void addLangExt(const string& langext, const V3LangCode& lc) { @@ -508,20 +510,16 @@ string V3Options::fileExists(const string& filename) { return ""; // Not found } // Check if it is a directory, ignore if so - string filenameOut = V3Os::filenameFromDirBase(dir, basename); + string filenameOut = V3Os::filenameJoin(dir, basename); if (!fileStatNormal(filenameOut)) return ""; // Directory return filenameOut; } string V3Options::filePathCheckOneDir(const string& modname, const string& dirname) { for (const string& i : m_impp->m_libExtVs) { - const string fn = V3Os::filenameFromDirBase(dirname, modname + i); + const string fn = V3Os::filenameJoin(dirname, modname + i); string exists = fileExists(fn); - if (exists != "") { - // Strip ./, it just looks ugly - if (exists.substr(0, 2) == "./") exists.erase(0, 2); - return exists; - } + if (exists != "") return exists; } return ""; } @@ -548,29 +546,30 @@ string V3Options::filePath(FileLine* fl, const string& modname, const string& la // Find a filename to read the specified module name, // using the incdir and libext's. // Return "" if not found. - if (!V3Os::filenameIsRel(modname)) { - // modname is an absolute path, so can find getStdPackagePath() - string exists = filePathCheckOneDir(modname, ""); + const string filename = V3Os::filenameCleanup(modname); + if (!V3Os::filenameIsRel(filename)) { + // filename is an absolute path, so can find getStdPackagePath() + string exists = filePathCheckOneDir(filename, ""); if (exists != "") return exists; } for (const string& dir : m_impp->m_incDirUsers) { - string exists = filePathCheckOneDir(modname, dir); + string exists = filePathCheckOneDir(filename, dir); if (exists != "") return exists; } for (const string& dir : m_impp->m_incDirFallbacks) { - string exists = filePathCheckOneDir(modname, dir); + string exists = filePathCheckOneDir(filename, dir); if (exists != "") return exists; } if (m_relativeIncludes) { - const string exists = filePathCheckOneDir(modname, lastpath); + const string exists = filePathCheckOneDir(filename, lastpath); if (exists != "") return V3Os::filenameRealPath(exists); } // Warn and return not found if (errmsg != "") { - fl->v3error(errmsg + modname); - filePathLookedMsg(fl, modname); + fl->v3error(errmsg + filename); + filePathLookedMsg(fl, filename); } return ""; } @@ -592,13 +591,13 @@ void V3Options::filePathLookedMsg(FileLine* fl, const string& modname) { std::cerr << V3Error::warnMoreStandalone() << "... Looked in:" << endl; for (const string& dir : m_impp->m_incDirUsers) { for (const string& ext : m_impp->m_libExtVs) { - const string fn = V3Os::filenameFromDirBase(dir, modname + ext); + const string fn = V3Os::filenameJoin(dir, modname + ext); std::cerr << V3Error::warnMoreStandalone() << " " << fn << endl; } } for (const string& dir : m_impp->m_incDirFallbacks) { for (const string& ext : m_impp->m_libExtVs) { - const string fn = V3Os::filenameFromDirBase(dir, modname + ext); + const string fn = V3Os::filenameJoin(dir, modname + ext); std::cerr << V3Error::warnMoreStandalone() << " " << fn << endl; } } @@ -657,7 +656,7 @@ string V3Options::getenvMAKEFLAGS() { // } string V3Options::getenvPERL() { // - return V3Os::getenvStr("PERL", "perl"); + return V3Os::filenameCleanup(V3Os::getenvStr("PERL", "perl")); } string V3Options::getenvSYSTEMC() { @@ -669,7 +668,7 @@ string V3Options::getenvSYSTEMC() { var = defenv; V3Os::setenvStr("SYSTEMC", var, "Hardcoded at build time"); } - return var; + return V3Os::filenameCleanup(var); } string V3Options::getenvSYSTEMC_ARCH() { @@ -718,9 +717,9 @@ string V3Options::getenvSYSTEMC_INCLUDE() { } if (var == "") { const string sc = getenvSYSTEMC(); - if (sc != "") var = sc + "/include"; + if (sc != "") var = V3Os::filenameJoin(sc, "include"); } - return var; + return V3Os::filenameCleanup(var); } string V3Options::getenvSYSTEMC_LIBDIR() { @@ -735,9 +734,9 @@ string V3Options::getenvSYSTEMC_LIBDIR() { if (var == "") { const string sc = getenvSYSTEMC(); const string arch = getenvSYSTEMC_ARCH(); - if (sc != "" && arch != "") var = sc + "/lib-" + arch; + if (sc != "" && arch != "") var = V3Os::filenameJoin(sc, "lib-" + arch); } - return var; + return V3Os::filenameCleanup(var); } string V3Options::getenvVERILATOR_ROOT() { @@ -750,11 +749,11 @@ string V3Options::getenvVERILATOR_ROOT() { V3Os::setenvStr("VERILATOR_ROOT", var, "Hardcoded at build time"); } if (var == "") v3fatal("$VERILATOR_ROOT needs to be in environment\n"); - return var; + return V3Os::filenameCleanup(var); } string V3Options::getStdPackagePath() { - return getenvVERILATOR_ROOT() + "/include/verilated_std.sv"; + return V3Os::filenameJoin(getenvVERILATOR_ROOT(), "include", "verilated_std.sv"); } string V3Options::getSupported(const string& var) { @@ -1890,7 +1889,8 @@ void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) VL string V3Options::parseFileArg(const string& optdir, const string& relfilename) { string filename = V3Os::filenameSubstitute(relfilename); - if (optdir != "." && V3Os::filenameIsRel(filename)) filename = optdir + "/" + filename; + if (optdir != "." && V3Os::filenameIsRel(filename)) + filename = V3Os::filenameJoin(optdir, filename); return filename; } diff --git a/src/V3Os.cpp b/src/V3Os.cpp index 01d9db383..8763725c1 100644 --- a/src/V3Os.cpp +++ b/src/V3Os.cpp @@ -124,15 +124,46 @@ void V3Os::setenvStr(const string& envvar, const string& value, const string& wh //###################################################################### // Generic filename utilities -static bool isSlash(char ch) VL_PURE { return ch == '/' || ch == '\\'; } +#if defined(_WIN32) || defined(__MINGW32__) +static constexpr char V3OS_SLASH = '\\'; +#else +static constexpr char V3OS_SLASH = '/'; +#endif -string V3Os::filenameFromDirBase(const string& dir, const string& basename) VL_PURE { - // Don't return ./{filename} because if filename was absolute, that makes it relative - if (dir.empty() || dir == ".") { - return basename; - } else { - return dir + "/" + basename; +static bool isSlash(char ch) VL_PURE { +#if defined(_WIN32) || defined(__MINGW32__) + return ch == '/' || ch == '\\'; +#else + return ch == '/'; +#endif +} + +string V3Os::filenameCleanup(const string& filename) VL_PURE { + string str; + str.reserve(filename.length()); + bool lastIsSlash = false; + for (const char ch : filename) { + const bool lastIsSlashOld = lastIsSlash; + lastIsSlash = isSlash(ch); + if (lastIsSlash && lastIsSlashOld) continue; + str += ch; } + if (str.size() > 1 && isSlash(str.back())) str.pop_back(); + while (str.size() > 2 && str[0] == '.' && isSlash(str[1])) str.erase(0, 2); + return str; +} + +string V3Os::filenameJoin(std::initializer_list paths) VL_PURE { + string fullpath; + for (const auto& item : paths) { + if (item.empty() || item == ".") { + continue; + } else { + if (!fullpath.empty()) fullpath += V3OS_SLASH; + fullpath += item; + } + } + return fullpath; } string V3Os::filenameDir(const string& filename) VL_PURE { @@ -144,7 +175,7 @@ string V3Os::filenameDir(const string& filename) VL_PURE { if (it.base() == filename.begin()) { return "."; } else { - return {filename.begin(), (++it).base()}; + return string{filename.begin(), (++it).base()}; } } @@ -164,6 +195,10 @@ string V3Os::filenameNonExt(const string& filename) VL_PURE { return base; } +string V3Os::filenameNonDirExt(const string& filename) VL_PURE { + return filenameNonExt(filenameNonDir(filename)); +} + string V3Os::filenameSubstitute(const string& filename) { string result; // cppcheck-has-bug-suppress unusedLabel @@ -392,3 +427,27 @@ int V3Os::system(const string& command) { return exit_code; } } + +void V3Os::selfTest() { +#ifdef VL_DEBUG + UASSERT_SELFTEST(string, filenameCleanup(""), ""); + UASSERT_SELFTEST(string, filenameCleanup("."), "."); + UASSERT_SELFTEST(string, filenameCleanup(".."), ".."); + UASSERT_SELFTEST(string, filenameCleanup("/"), "/"); + UASSERT_SELFTEST(string, filenameCleanup("../"), ".."); + UASSERT_SELFTEST(string, filenameCleanup("//"), "/"); + UASSERT_SELFTEST(string, filenameCleanup("//."), "/."); + UASSERT_SELFTEST(string, filenameCleanup("./"), "."); + UASSERT_SELFTEST(string, filenameCleanup("././"), "."); + UASSERT_SELFTEST(string, filenameCleanup(".///"), "."); + UASSERT_SELFTEST(string, filenameCleanup("a"), "a"); + UASSERT_SELFTEST(string, filenameCleanup("a/"), "a"); + UASSERT_SELFTEST(string, filenameCleanup("a/b"), "a/b"); + UASSERT_SELFTEST(string, filenameCleanup("././//./a/b"), "a/b"); + UASSERT_SELFTEST(string, filenameCleanup(".//./a///"), "a"); + UASSERT_SELFTEST(string, filenameCleanup("///a/./b///."), "/a/./b/."); + UASSERT_SELFTEST(string, filenameCleanup("aaa/bbb/ccc/"), "aaa/bbb/ccc"); + UASSERT_SELFTEST(string, filenameCleanup("./aaa/bbb/ccc/"), "aaa/bbb/ccc"); + UASSERT_SELFTEST(string, filenameCleanup("../aaa/bbb/ccc/"), "../aaa/bbb/ccc"); +#endif +} diff --git a/src/V3Os.h b/src/V3Os.h index da1bcb1d0..3bf69ca17 100644 --- a/src/V3Os.h +++ b/src/V3Os.h @@ -35,22 +35,28 @@ public: static void setenvStr(const string& envvar, const string& value, const string& why); // METHODS (generic filename utilities) - static string filenameFromDirBase(const string& dir, const string& basename) VL_PURE; - ///< Return non-directory part of filename + ///< @return concatenated path + static string filenameJoin(std::initializer_list paths) VL_PURE; + template + static string filenameJoin(Args... args) VL_PURE { + return filenameJoin({args...}); + }; + ///< @return file path without repeated separators and ./ prefix + static string filenameCleanup(const string& filename) VL_PURE; + ///< @return non-directory part of filename static string filenameNonDir(const string& filename) VL_PURE; - ///< Return non-extensioned (no .) part of filename + ///< @return non-extensioned (no .) part of filename static string filenameNonExt(const string& filename) VL_PURE; - ///< Return basename of filename - static string filenameNonDirExt(const string& filename) VL_PURE { - return filenameNonExt(filenameNonDir(filename)); - } - ///< Return directory part of filename + ///< @return basename of filename + static string filenameNonDirExt(const string& filename) VL_PURE; + ///< @return directory part of filename static string filenameDir(const string& filename) VL_PURE; - /// Return filename with env vars removed + ///< @return filename with env vars removed static string filenameSubstitute(const string& filename); - ///< Return realpath of filename + ///< @return realpath of filename static string filenameRealPath(const string& filename) VL_PURE; - static bool filenameIsRel(const string& filename) VL_PURE; ///< True if relative + ///< @return filename is relative + static bool filenameIsRel(const string& filename) VL_PURE; // METHODS (file utilities) static string getline(std::istream& is, char delim = '\n'); @@ -72,6 +78,7 @@ public: // METHODS (sub command) /// Run system command, returns the exit code of the child process. static int system(const string& command); + static void selfTest(); }; #endif // Guard diff --git a/src/V3ParseGrammar.cpp b/src/V3ParseGrammar.cpp index 10be43782..384ec1ffa 100644 --- a/src/V3ParseGrammar.cpp +++ b/src/V3ParseGrammar.cpp @@ -251,63 +251,9 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name, return nodep; } -string V3ParseGrammar::deQuote(FileLine* fileline, string text) { - // Fix up the quoted strings the user put in, for example "\"" becomes " - // Reverse is V3OutFormatter::quoteNameControls(...) - bool quoted = false; - string newtext; - unsigned char octal_val = 0; - int octal_digits = 0; - for (string::const_iterator cp = text.begin(); cp != text.end(); ++cp) { - if (quoted) { - if (std::isdigit(*cp)) { - octal_val = octal_val * 8 + (*cp - '0'); - if (++octal_digits == 3) { - octal_digits = 0; - quoted = false; - newtext += octal_val; - } - } else { - if (octal_digits) { - // Spec allows 1-3 digits - octal_digits = 0; - quoted = false; - newtext += octal_val; - --cp; // Backup to reprocess terminating character as non-escaped - continue; - } - quoted = false; - if (*cp == 'n') { - newtext += '\n'; - } else if (*cp == 'a') { - newtext += '\a'; // SystemVerilog 3.1 - } else if (*cp == 'f') { - newtext += '\f'; // SystemVerilog 3.1 - } else if (*cp == 'r') { - newtext += '\r'; - } else if (*cp == 't') { - newtext += '\t'; - } else if (*cp == 'v') { - newtext += '\v'; // SystemVerilog 3.1 - } else if (*cp == 'x' && std::isxdigit(cp[1]) - && std::isxdigit(cp[2])) { // SystemVerilog 3.1 -#define vl_decodexdigit(c) ((std::isdigit(c) ? ((c) - '0') : (std::tolower((c)) - 'a' + 10))) - newtext - += static_cast(16 * vl_decodexdigit(cp[1]) + vl_decodexdigit(cp[2])); - cp += 2; - } else if (std::isalnum(*cp)) { - fileline->v3error("Unknown escape sequence: \\" << *cp); - break; - } else { - newtext += *cp; - } - } - } else if (*cp == '\\') { - quoted = true; - octal_digits = 0; - } else { - newtext += *cp; - } - } - return newtext; +string V3ParseGrammar::unquoteString(FileLine* fileline, string text) { + string errMsg; + string res = VString::unquoteSVString(text, errMsg); + if (!errMsg.empty()) fileline->v3error(errMsg.c_str()); + return res; } diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index 075d677d2..7769dd41a 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -358,7 +358,7 @@ string V3PreProcImp::removeDefines(const string& text) { string rtnsym = text; for (int loopprevent = 0; loopprevent < 100; loopprevent++) { string xsym = rtnsym; - if (xsym.substr(0, 1) == "`") xsym.replace(0, 1, ""); + if (xsym[0] == '`') xsym.erase(0, 1); if (defExists(xsym)) { val = defValue(xsym); if (val != rtnsym) { diff --git a/src/V3Sched.cpp b/src/V3Sched.cpp index 32386e38b..b3849955d 100644 --- a/src/V3Sched.cpp +++ b/src/V3Sched.cpp @@ -663,7 +663,8 @@ std::pair makeEvalLoop(AstNetlist* netlistp, const s newcallp->dtypeSetVoid(); blockp->addNodesp(newcallp->makeStmt()); add("#endif\n"); - add("VL_FATAL_MT(\"" + file + "\", " + line + ", \"\", "); + add("VL_FATAL_MT(\"" + V3OutFormatter::quoteNameControls(file) + "\", " + line + + ", \"\", "); add("\"" + name + " region did not converge.\");\n"); } diff --git a/src/V3String.cpp b/src/V3String.cpp index 5ed5279e1..c23a15705 100644 --- a/src/V3String.cpp +++ b/src/V3String.cpp @@ -20,6 +20,7 @@ #include "V3String.h" #include "V3Error.h" +#include "V3FileLine.h" #ifndef V3ERROR_NO_GLOBAL_ #include "V3Global.h" @@ -130,6 +131,70 @@ string VString::escapeStringForPath(const string& str) { return result; } +static int vl_decodexdigit(char c) { + return std::isdigit(c) ? c - '0' : std::tolower(c) - 'a' + 10; +} + +string VString::unquoteSVString(const string& text, string& errOut) { + bool quoted = false; + string newtext; + newtext.reserve(text.size()); + unsigned char octal_val = 0; + int octal_digits = 0; + for (string::const_iterator cp = text.begin(); cp != text.end(); ++cp) { + if (quoted) { + if (std::isdigit(*cp)) { + octal_val = octal_val * 8 + (*cp - '0'); + if (++octal_digits == 3) { + octal_digits = 0; + quoted = false; + newtext += octal_val; + } + } else { + if (octal_digits) { + // Spec allows 1-3 digits + octal_digits = 0; + quoted = false; + newtext += octal_val; + --cp; // Backup to reprocess terminating character as non-escaped + continue; + } + quoted = false; + if (*cp == 'n') { + newtext += '\n'; + } else if (*cp == 'a') { + newtext += '\a'; // SystemVerilog 3.1 + } else if (*cp == 'f') { + newtext += '\f'; // SystemVerilog 3.1 + } else if (*cp == 'r') { + newtext += '\r'; + } else if (*cp == 't') { + newtext += '\t'; + } else if (*cp == 'v') { + newtext += '\v'; // SystemVerilog 3.1 + } else if (*cp == 'x' && std::isxdigit(cp[1]) + && std::isxdigit(cp[2])) { // SystemVerilog 3.1 + newtext + += static_cast(16 * vl_decodexdigit(cp[1]) + vl_decodexdigit(cp[2])); + cp += 2; + } else if (std::isalnum(*cp)) { + errOut = "Unknown escape sequence: \\"; + errOut += *cp; + break; + } else { + newtext += *cp; + } + } + } else if (*cp == '\\') { + quoted = true; + octal_digits = 0; + } else { + newtext += *cp; + } + } + return newtext; +} + string VString::spaceUnprintable(const string& str) VL_PURE { string result; for (const char c : str) { diff --git a/src/V3String.h b/src/V3String.h index cbca5de56..33c792757 100644 --- a/src/V3String.h +++ b/src/V3String.h @@ -102,6 +102,9 @@ public: // Surround a raw string by double quote and escape if necessary // e.g. input abc's becomes "\"abc\'s\"" static string escapeStringForPath(const string& str); + // Convert SV quoted string input from source code to normal form. + // Reverse is V3OutFormatter::quoteNameControls(...) + static string unquoteSVString(const string& text, string& errOut); // Escape path in Windows // e.g. input `C:\Program Files\My Program\My Program.exe` becomes // `C:\\Program\ Files\\My\ Program\\My\ Program.exe` diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 10b0fb06d..cb2109ea0 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -642,6 +642,7 @@ static void verilate(const string& argString) { { const V3MtDisabledLockGuard mtDisabler{v3MtDisabledLock()}; + V3Os::selfTest(); VHashSha256::selfTest(); VSpellCheck::selfTest(); V3Graph::selfTest(); @@ -782,7 +783,7 @@ int main(int argc, char** argv) { V3PreShell::boot(); // Command option parsing - v3Global.opt.buildDepBin(VString::escapeStringForPath(argv[0])); + v3Global.opt.buildDepBin(V3Os::filenameCleanup(argv[0])); v3Global.opt.parseOpts(new FileLine{FileLine::commandLineFilename()}, argc - 1, argv + 1); // Validate settings (aka Boost.Program_options) diff --git a/src/verilog.y b/src/verilog.y index 2b9120969..39f2e31ff 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -129,7 +129,7 @@ public: AstNode* attrsp) VL_MT_DISABLED; AstNode* createSupplyExpr(FileLine* fileline, const string& name, int value) VL_MT_DISABLED; AstText* createTextQuoted(FileLine* fileline, const string& text) { - string newtext = deQuote(fileline, text); + string newtext = GRAMMARP->unquoteString(fileline, text); return new AstText{fileline, newtext}; } AstNode* createCellOrIfaceRef(FileLine* fileline, const string& name, AstPin* pinlistp, @@ -253,7 +253,7 @@ public: return createArray(dtypep, rangearraysp, isPacked); } } - string deQuote(FileLine* fileline, string text) VL_MT_DISABLED; + string unquoteString(FileLine* fileline, string text) VL_MT_DISABLED; void checkDpiVer(FileLine* fileline, const string& str) { if (str != "DPI-C" && !v3Global.opt.bboxSys()) { fileline->v3error("Unsupported DPI type '" << str << "': Use 'DPI-C'"); @@ -5675,13 +5675,13 @@ parseRefBase: // yaSTRING shouldn't be used directly, instead via an abstraction below str: // yaSTRING but with \{escapes} need decoded - yaSTRING { $$ = PARSEP->newString(GRAMMARP->deQuote($1, *$1)); } + yaSTRING { $$ = PARSEP->newString(GRAMMARP->unquoteString($1, *$1)); } ; strAsInt: yaSTRING { // Numeric context, so IEEE 1800-2017 11.10.3 "" is a "\000" - $$ = new AstConst{$1, AstConst::VerilogStringLiteral{}, GRAMMARP->deQuote($1, *$1)}; } + $$ = new AstConst{$1, AstConst::VerilogStringLiteral{}, GRAMMARP->unquoteString($1, *$1)}; } ; strAsIntIgnore: // strAsInt, but never matches for when expr shouldn't parse strings diff --git a/test_regress/t/t_pp_line.out b/test_regress/t/t_pp_line.out new file mode 100644 index 000000000..a3e32422f --- /dev/null +++ b/test_regress/t/t_pp_line.out @@ -0,0 +1,16 @@ +-Info: some file:100:1: aaaaaaaa + : ... note: In instance 't' + 100 | $info("aaaaaaaa"); + | ^~~~~ +-Info: some file:101:1: bbbbbbbb + : ... note: In instance 't' + 101 | $info("bbbbbbbb"); + | ^~~~~ +-Info: somefile.v:200:1: cccccccc + : ... note: In instance 't' + 200 | $info("cccccccc"); + | ^~~~~ +-Info: /a/somefile.v:300:1: dddddddd + : ... note: In instance 't' + 300 | $info("dddddddd"); + | ^~~~~ diff --git a/test_regress/t/t_pp_line.pl b/test_regress/t/t_pp_line.pl new file mode 100755 index 000000000..d1ed9a923 --- /dev/null +++ b/test_regress/t/t_pp_line.pl @@ -0,0 +1,18 @@ +#!/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(linter => 1); + +lint( + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_pp_line.v b/test_regress/t/t_pp_line.v new file mode 100644 index 000000000..ac991e550 --- /dev/null +++ b/test_regress/t/t_pp_line.v @@ -0,0 +1,15 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Anthony Donlon. +// SPDX-License-Identifier: CC0-1.0 + +module t; +`line 100 "some file" 0 +$info("aaaaaaaa"); +$info("bbbbbbbb"); +`line 200 "somefile.v" 0 +$info("cccccccc"); +`line 300 "/a/somefile.v" 0 +$info("dddddddd"); +endmodule diff --git a/test_regress/t/t_pp_line_bad.out b/test_regress/t/t_pp_line_bad.out index 062cbf6af..8365b61c6 100644 --- a/test_regress/t/t_pp_line_bad.out +++ b/test_regress/t/t_pp_line_bad.out @@ -1,13 +1,22 @@ %Error: t/t_pp_line_bad.v:100:1: `line was not properly formed with '`line number "filename" level' 100 | `line 100 | ^ -%Error: somefile:100:1: `line was not properly formed with '`line number "filename" level' - 100 | `line 100 +%Error: t/t_pp_line_bad.v:200:1: `line was not properly formed with '`line number "filename" level' + 200 | `line 100 + | ^ +%Error: t/t_pp_line_bad.v:300:1: `line was not properly formed with '`line number "filename" level' + 300 | `line 100 + | ^ +%Error: some file:400:1: `line was not properly formed with '`line number "filename" level' + 400 | `line 100 + | ^ +%Error: somefile:500:1: `line was not properly formed with '`line number "filename" level' + 500 | `line 100 + | ^ +%Error: some file:600:1: `line was not properly formed with '`line number "filename" level' + 600 | `line 100 | ^ -%Error: somefile:100:1: `line was not properly formed with '`line number "filename" level' %Error: t/t_pp_line_bad.v:7:1: Define or directive not defined: '`line' 7 | `line | ^~~~~ -%Error: somefile:100:1: `line was not properly formed with '`line number "filename" level' - t/t_pp_line_bad.v:101:1: ... note: In file included from 't_pp_line_bad.v' %Error: Exiting due to diff --git a/test_regress/t/t_pp_line_bad.pl b/test_regress/t/t_pp_line_bad.pl index 9de6b85ee..a60503a1f 100755 --- a/test_regress/t/t_pp_line_bad.pl +++ b/test_regress/t/t_pp_line_bad.pl @@ -8,10 +8,9 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(vlt => 1); +scenarios(linter => 1); lint( - verilator_flags2 => ["-Wpedantic"], fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_pp_line_bad.v b/test_regress/t/t_pp_line_bad.v index e1ac808a4..0d41247a1 100644 --- a/test_regress/t/t_pp_line_bad.v +++ b/test_regress/t/t_pp_line_bad.v @@ -6,6 +6,8 @@ `line `line 100 -`line 100 somefile 1 -`line 100 "somefile" -`line 100 "somefile" 3 +`line 200 somefile +`line 300 "somefile 1 +`line 400 "some file" +`line 500 "somefile" 3 +`line 600 "some file" 3 From 36c824d9733567c631b14560379d27062a7a6992 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 26 Sep 2023 18:37:39 -0400 Subject: [PATCH 025/157] Add trace() API even when Verilated without --trace (#4462). --- Changes | 1 + src/V3EmitCModel.cpp | 32 ++++++++++++++++--------- test_regress/t/t_trace_noflag_bad.out | 2 ++ test_regress/t/t_trace_noflag_bad.pl | 27 +++++++++++++++++++++ test_regress/t/t_trace_noflag_bad.v | 14 +++++++++++ test_regress/t/t_trace_noflag_bad_c.cpp | 24 +++++++++++++++++++ 6 files changed, 89 insertions(+), 11 deletions(-) create mode 100644 test_regress/t/t_trace_noflag_bad.out create mode 100755 test_regress/t/t_trace_noflag_bad.pl create mode 100644 test_regress/t/t_trace_noflag_bad.v create mode 100644 test_regress/t/t_trace_noflag_bad_c.cpp diff --git a/Changes b/Changes index a23881b92..283efe579 100644 --- a/Changes +++ b/Changes @@ -13,6 +13,7 @@ Verilator 5.017 devel **Minor:** +* Add trace() API even when Verilated without --trace (#4462). [phelter] * Support randc (#4349). * Support resizing function call inout arguments (#4467). diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp index 8eff11e6f..9c694d37c 100644 --- a/src/V3EmitCModel.cpp +++ b/src/V3EmitCModel.cpp @@ -197,15 +197,13 @@ class EmitCModel final : public EmitCFunc { puts("/// Returns time at next time slot. Aborts if !eventsPending()\n"); puts("uint64_t nextTimeSlot();\n"); - if (v3Global.opt.trace()) { - puts("/// Trace signals in the model; called by application code\n"); - puts("void trace(" + v3Global.opt.traceClassBase() - + "C* tfp, int levels, int options = 0);\n"); - if (optSystemC()) { - puts("/// SC tracing; avoid overloaded virtual function lint warning\n"); - puts("void trace(sc_trace_file* tfp) const override { " - "::sc_core::sc_module::trace(tfp); }\n"); - } + puts("/// Trace signals in the model; called by application code\n"); + puts("void trace(" + v3Global.opt.traceClassBase() + + "C* tfp, int levels, int options = 0);\n"); + if (v3Global.opt.trace() && optSystemC()) { + puts("/// SC tracing; avoid overloaded virtual function lint warning\n"); + puts("void trace(sc_trace_file* tfp) const override { " + "::sc_core::sc_module::trace(tfp); }\n"); } if (!optSystemC()) { @@ -591,6 +589,15 @@ class EmitCModel final : public EmitCFunc { puts("}\n"); } + void emitTraceOffMethods(AstNodeModule* modp) { + putSectionDelimiter("Trace configuration"); + // ::trace + puts("\nVL_ATTR_COLD void " + topClassName() + "::trace("); + puts(v3Global.opt.traceClassBase() + "C* tfp, int levels, int options) {\n"); + puts(/**/ "vl_fatal(__FILE__, __LINE__, __FILE__,\"'" + topClassName() + + +"::trace()' called on model that was Verilated without --trace option\");\n"); + puts("}\n"); + } void emitSerializationFunctions() { putSectionDelimiter("Model serialization"); @@ -635,8 +642,11 @@ class EmitCModel final : public EmitCFunc { emitDestructorImplementation(); emitStandardMethods1(modp); emitStandardMethods2(modp); - if (v3Global.opt.trace()) { emitTraceMethods(modp); } - if (v3Global.opt.savable()) { emitSerializationFunctions(); } + if (v3Global.opt.trace()) + emitTraceMethods(modp); + else + emitTraceOffMethods(modp); + if (v3Global.opt.savable()) emitSerializationFunctions(); VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); } diff --git a/test_regress/t/t_trace_noflag_bad.out b/test_regress/t/t_trace_noflag_bad.out new file mode 100644 index 000000000..e8156e0c9 --- /dev/null +++ b/test_regress/t/t_trace_noflag_bad.out @@ -0,0 +1,2 @@ +%Error: Vt_trace_noflag_bad.cpp:106: 'Vt_trace_noflag_bad::trace()' called on model that was Verilated without --trace option +Aborting... diff --git a/test_regress/t/t_trace_noflag_bad.pl b/test_regress/t/t_trace_noflag_bad.pl new file mode 100755 index 000000000..8271fa41d --- /dev/null +++ b/test_regress/t/t_trace_noflag_bad.pl @@ -0,0 +1,27 @@ +#!/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); + +compile( + # We need to list verilated_vcd_c.cpp because without --trace Verilator + # won't build it itself automatically. + verilator_flags2 => ["--cc --exe $Self->{t_dir}/$Self->{name}_c.cpp verilated_vcd_c.cpp"], + make_top_shell => 0, + make_main => 0, + ); + +execute( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_trace_noflag_bad.v b/test_regress/t/t_trace_noflag_bad.v new file mode 100644 index 000000000..fc9beb176 --- /dev/null +++ b/test_regress/t/t_trace_noflag_bad.v @@ -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, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + int i; + initial begin + i = 10; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_trace_noflag_bad_c.cpp b/test_regress/t/t_trace_noflag_bad_c.cpp new file mode 100644 index 000000000..1fccdddd3 --- /dev/null +++ b/test_regress/t/t_trace_noflag_bad_c.cpp @@ -0,0 +1,24 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +// +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2010 by Yu-Sheng Lin. +// SPDX-License-Identifier: CC0-1.0 + +#include +#include + +#include "Vt_trace_noflag_bad.h" + +int main(int argc, char** argv) { + std::unique_ptr contextp{new VerilatedContext}; + contextp->traceEverOn(true); + std::unique_ptr tfp{new VerilatedVcdC}; + const std::unique_ptr topp{new VM_PREFIX{contextp.get()}}; + topp->trace(tfp.get(), 99); // Error! + tfp->open(VL_STRINGIFY(TEST_OBJ_DIR) "/dump.vcd"); // Error! shall put to the next line! + tfp->dump(0); + tfp->close(); + return 0; +} From 72b4a742453422ef79a26b169e8e9ebb69e32eb2 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 26 Sep 2023 19:58:09 -0400 Subject: [PATCH 026/157] Fix clang error on last commit --- src/V3EmitCModel.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp index 9c694d37c..2ceeafbde 100644 --- a/src/V3EmitCModel.cpp +++ b/src/V3EmitCModel.cpp @@ -642,10 +642,11 @@ class EmitCModel final : public EmitCFunc { emitDestructorImplementation(); emitStandardMethods1(modp); emitStandardMethods2(modp); - if (v3Global.opt.trace()) + if (v3Global.opt.trace()) { emitTraceMethods(modp); - else + } else if (!v3Global.opt.systemC()) { emitTraceOffMethods(modp); + } if (v3Global.opt.savable()) emitSerializationFunctions(); VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); From a948be184c0abf9d7edbe2004d1ddce1d514991c Mon Sep 17 00:00:00 2001 From: Justin Thiel Date: Tue, 26 Sep 2023 20:35:23 -0400 Subject: [PATCH 027/157] Tests: Add t_interface_localparam_unsup (#3857 partial) (#3858) --- docs/CONTRIBUTORS | 1 + .../t/t_interface_localparam_unsup.out | 5 ++ .../t/t_interface_localparam_unsup.pl | 23 +++++++++ test_regress/t/t_interface_localparam_unsup.v | 51 +++++++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 test_regress/t/t_interface_localparam_unsup.out create mode 100755 test_regress/t/t_interface_localparam_unsup.pl create mode 100644 test_regress/t/t_interface_localparam_unsup.v diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index b80f0bfc3..92c0ec46c 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -88,6 +88,7 @@ Josh Redford Julian Daube Julie Schwartz Julien Margetts +Justin Thiel Kaleb Barrett Kamil Rakoczy Kanad Kanhere diff --git a/test_regress/t/t_interface_localparam_unsup.out b/test_regress/t/t_interface_localparam_unsup.out new file mode 100644 index 000000000..1ac204e0e --- /dev/null +++ b/test_regress/t/t_interface_localparam_unsup.out @@ -0,0 +1,5 @@ +*-* All Finished *-* +top.t.intf: symbolsPerBeat 16, symbolsPerBeatDivBy2 8, mismatch 0 +top.t.theCore.core_intf: symbolsPerBeat 64, symbolsPerBeatDivBy2 8, mismatch 1 +%Error: t/t_interface_localparam_unsup.v:23: Verilog $stop +Aborting... diff --git a/test_regress/t/t_interface_localparam_unsup.pl b/test_regress/t/t_interface_localparam_unsup.pl new file mode 100755 index 000000000..fa08b1e33 --- /dev/null +++ b/test_regress/t/t_interface_localparam_unsup.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, +); + +ok(1); +1; diff --git a/test_regress/t/t_interface_localparam_unsup.v b/test_regress/t/t_interface_localparam_unsup.v new file mode 100644 index 000000000..6deb411ae --- /dev/null +++ b/test_regress/t/t_interface_localparam_unsup.v @@ -0,0 +1,51 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Justin Thiel. +// SPDX-License-Identifier: CC0-1.0 + +interface SimpleIntf +#( + parameter int symbolsPerBeat = 16 +) +(); + + // This value is calculated incorrectly for other instances of + // this interface when it is accessed via the HDL for any other + // instance of this interface + localparam int symbolsPerBeatDivBy2 = symbolsPerBeat/2; + + localparam bit mismatch = (symbolsPerBeat != (2*symbolsPerBeatDivBy2) ); + + initial begin + $write("%m: symbolsPerBeat %0d, symbolsPerBeatDivBy2 %0d, mismatch %0d\n", + symbolsPerBeat, symbolsPerBeatDivBy2, mismatch); + if (mismatch) $stop; + end + +endinterface + +module Core( + SimpleIntf intf +); + + // NOTE: When this line is commented out the test will pass + localparam intf_symbolsPerBeatDivBy2 = intf.symbolsPerBeatDivBy2; + + localparam int core_intf_symbolsPerBeat = 64; + SimpleIntf #(.symbolsPerBeat(core_intf_symbolsPerBeat)) core_intf (); + +endmodule + +module t(); + + SimpleIntf intf(); + + Core theCore (.intf); + + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From 018d766179509e532482952c39214cbea3b8db26 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 26 Sep 2023 21:07:43 -0400 Subject: [PATCH 028/157] Fix clang error (#4462) --- src/V3EmitCModel.cpp | 8 +++++--- test_regress/driver.pl | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp index 2ceeafbde..25a7368c0 100644 --- a/src/V3EmitCModel.cpp +++ b/src/V3EmitCModel.cpp @@ -197,9 +197,11 @@ class EmitCModel final : public EmitCFunc { puts("/// Returns time at next time slot. Aborts if !eventsPending()\n"); puts("uint64_t nextTimeSlot();\n"); - puts("/// Trace signals in the model; called by application code\n"); - puts("void trace(" + v3Global.opt.traceClassBase() - + "C* tfp, int levels, int options = 0);\n"); + if (v3Global.opt.trace() || !optSystemC()) { + puts("/// Trace signals in the model; called by application code\n"); + puts("void trace(" + v3Global.opt.traceClassBase() + + "C* tfp, int levels, int options = 0);\n"); + } if (v3Global.opt.trace() && optSystemC()) { puts("/// SC tracing; avoid overloaded virtual function lint warning\n"); puts("void trace(sc_trace_file* tfp) const override { " diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 69c8cccb4..05b4c2ed9 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -2245,6 +2245,7 @@ sub files_identical { $l1[$l] =~ s/CPU Time: +[0-9.]+ seconds[^\n]+/CPU Time: ###/mig; $l1[$l] =~ s/\?v=[0-9.]+/?v=latest/mig; # warning URL $l1[$l] =~ s/_h[0-9a-f]{8}_/_h########_/mg; + $l1[$l] =~ s!%Error: \./!%Error: !mg; # clang gives ./ while GCC does not $l1[$l] =~ s/ \/[^ ]+\/verilated_std.sv/ verilated_std.sv/mg; if ($l1[$l] =~ s/Exiting due to.*/Exiting due to/mig) { splice @l1, $l+1; # Trunc rest From ad343f8260cf429e786e73cace8ecf5e96654937 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 26 Sep 2023 22:15:48 -0400 Subject: [PATCH 029/157] Add warning on interface instantiation without parens (#4094). --- Changes | 1 + src/V3AstNodeOther.h | 4 ++++ src/V3LinkCells.cpp | 6 ++++++ src/verilog.y | 7 ++++--- test_regress/t/t_fuzz_genintf_bad.v | 2 +- .../t/t_interface_paren_missing_bad.out | 5 +++++ .../t/t_interface_paren_missing_bad.pl | 19 +++++++++++++++++++ .../t/t_interface_paren_missing_bad.v | 15 +++++++++++++++ test_regress/t/t_interface_virtual.v | 2 +- test_regress/t/t_interface_virtual_bad.v | 4 ++-- 10 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 test_regress/t/t_interface_paren_missing_bad.out create mode 100755 test_regress/t/t_interface_paren_missing_bad.pl create mode 100644 test_regress/t/t_interface_paren_missing_bad.v diff --git a/Changes b/Changes index 283efe579..6c60e88e3 100644 --- a/Changes +++ b/Changes @@ -14,6 +14,7 @@ Verilator 5.017 devel **Minor:** * Add trace() API even when Verilated without --trace (#4462). [phelter] +* Add warning on interface instantiation without parens (#4094). [Gökçe Aydos] * Support randc (#4349). * Support resizing function call inout arguments (#4467). diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 2908bbe95..ee393ad9d 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -776,6 +776,7 @@ class AstCell final : public AstNode { string m_modName; // Module the cell instances AstNodeModule* m_modp = nullptr; // [AfterLink] Pointer to module instanced bool m_hasIfaceVar : 1; // True if a Var has been created for this cell + bool m_hasNoParens : 1; // Instantiation has no parenthesis bool m_recursive : 1; // Self-recursive module bool m_trace : 1; // Trace this cell public: @@ -787,6 +788,7 @@ public: , m_origName{instName} , m_modName{modName} , m_hasIfaceVar{false} + , m_hasNoParens{false} , m_recursive{false} , m_trace{true} { this->addPinsp(pinsp); @@ -810,6 +812,8 @@ public: void modp(AstNodeModule* nodep) { m_modp = nodep; } bool hasIfaceVar() const { return m_hasIfaceVar; } void hasIfaceVar(bool flag) { m_hasIfaceVar = flag; } + bool hasNoParens() const { return m_hasNoParens; } + void hasNoParens(bool flag) { m_hasNoParens = flag; } void trace(bool flag) { m_trace = flag; } bool isTrace() const { return m_trace; } void recursive(bool flag) { m_recursive = flag; } diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp index d98a9158b..4d18030eb 100644 --- a/src/V3LinkCells.cpp +++ b/src/V3LinkCells.cpp @@ -455,6 +455,12 @@ private: nodep->addNextHere(varp); nodep->hasIfaceVar(true); } + if (nodep->hasNoParens()) { + nodep->v3error("Interface instantiation " + << nodep->prettyNameQ() << " requires parenthesis\n" + << nodep->warnMore() << "... Suggest use '" << nodep->prettyName() + << "()'"); + } } if (nodep->modp()) { // iterateChildren(nodep); diff --git a/src/verilog.y b/src/verilog.y index 39f2e31ff..6d06f969e 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -133,7 +133,7 @@ public: return new AstText{fileline, newtext}; } AstNode* createCellOrIfaceRef(FileLine* fileline, const string& name, AstPin* pinlistp, - AstNodeRange* rangelistp) { + AstNodeRange* rangelistp, bool parens) { // Must clone m_instParamp as may be comma'ed list of instances VSymEnt* const foundp = SYMP->symCurrentp()->findIdFallback(name); if (foundp && VN_IS(foundp->nodep(), Port)) { @@ -155,6 +155,7 @@ public: pinlistp, (GRAMMARP->m_instParamp ? GRAMMARP->m_instParamp->cloneTree(true) : nullptr), GRAMMARP->scrubRange(rangelistp)}; + nodep->hasNoParens(!parens); nodep->trace(GRAMMARP->allTracingOn(fileline)); return nodep; } @@ -3187,9 +3188,9 @@ instnameList: instnameParen: id instRangeListE '(' cellpinListE ')' - { $$ = GRAMMARP->createCellOrIfaceRef($1, *$1, $4, $2); } + { $$ = GRAMMARP->createCellOrIfaceRef($1, *$1, $4, $2, true); } | id instRangeListE - { $$ = GRAMMARP->createCellOrIfaceRef($1, *$1, nullptr, $2); } + { $$ = GRAMMARP->createCellOrIfaceRef($1, *$1, nullptr, $2, false); } //UNSUP instRangeListE '(' cellpinListE ')' { UNSUP } // UDP // // Adding above and switching to the Verilog-Perl syntax // // causes a shift conflict due to use of idClassSel inside exprScope. diff --git a/test_regress/t/t_fuzz_genintf_bad.v b/test_regress/t/t_fuzz_genintf_bad.v index 53df6dea8..99fad227c 100644 --- a/test_regress/t/t_fuzz_genintf_bad.v +++ b/test_regress/t/t_fuzz_genintf_bad.v @@ -18,7 +18,7 @@ module m1 endmodule module t; - intf ifs; + intf ifs(); m1 m0( j.e(0), diff --git a/test_regress/t/t_interface_paren_missing_bad.out b/test_regress/t/t_interface_paren_missing_bad.out new file mode 100644 index 000000000..161dad3fc --- /dev/null +++ b/test_regress/t/t_interface_paren_missing_bad.out @@ -0,0 +1,5 @@ +%Error: t/t_interface_paren_missing_bad.v:13:9: Interface instantiation 'intf_i' requires parenthesis + : ... Suggest use 'intf_i()' + 13 | intf intf_i; + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_interface_paren_missing_bad.pl b/test_regress/t/t_interface_paren_missing_bad.pl new file mode 100755 index 000000000..b564041ff --- /dev/null +++ b/test_regress/t/t_interface_paren_missing_bad.pl @@ -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 2023 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 => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_interface_paren_missing_bad.v b/test_regress/t/t_interface_paren_missing_bad.v new file mode 100644 index 000000000..c1a9edae4 --- /dev/null +++ b/test_regress/t/t_interface_paren_missing_bad.v @@ -0,0 +1,15 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Interface instantiation without paranthesis +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Goekce Aydos. +// SPDX-License-Identifier: CC0-1.0 + +interface intf; +endinterface + +module t; + intf intf_i; + initial $finish; +endmodule diff --git a/test_regress/t/t_interface_virtual.v b/test_regress/t/t_interface_virtual.v index 878df0995..0e05cf47e 100644 --- a/test_regress/t/t_interface_virtual.v +++ b/test_regress/t/t_interface_virtual.v @@ -25,7 +25,7 @@ endclass module t (/*AUTOARG*/); - PBus ia, ib; + PBus ia(), ib(); virtual PBus va, vb; virtual PBus.phy pa, pb; Cls ca, cb; diff --git a/test_regress/t/t_interface_virtual_bad.v b/test_regress/t/t_interface_virtual_bad.v index 3c4f690da..55c99e285 100644 --- a/test_regress/t/t_interface_virtual_bad.v +++ b/test_regress/t/t_interface_virtual_bad.v @@ -19,8 +19,8 @@ typedef virtual PBus vpbus_t; module t (/*AUTOARG*/); - PBus p8; - QBus q8; + PBus p8(); + QBus q8(); vpbus_t v8; virtual PBus.phy v8_phy; logic data; From 84ccb230989a1c5d35f356cb782cbb441e40df16 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 26 Sep 2023 22:43:17 -0400 Subject: [PATCH 030/157] Fix C++11 compiler constexpr return error --- include/verilated_types.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/include/verilated_types.h b/include/verilated_types.h index 4fac347f1..6a1a3bfac 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -69,7 +69,7 @@ extern std::string VL_TO_STRING_W(int words, const WDataInP obj); #define VL_INOUTW(name, msb, lsb, words) VlWide name ///< Declare bidir signal, 65+ bits #define VL_OUT8(name, msb, lsb) CData name ///< Declare output signal, 1-8 bits #define VL_OUT16(name, msb, lsb) SData name ///< Declare output signal, 9-16 bits -#define VL_OUT64(name, msb, lsb) QData name ///< Declare output signal, 33-64bits +#define VL_OUT64(name, msb, lsb) QData name ///< Declare output signal, 33-64 bits #define VL_OUT(name, msb, lsb) IData name ///< Declare output signal, 17-32 bits #define VL_OUTW(name, msb, lsb, words) VlWide name ///< Declare output signal, 65+ bits @@ -77,11 +77,8 @@ extern std::string VL_TO_STRING_W(int words, const WDataInP obj); // Functions needed here constexpr IData VL_CLOG2_CE_Q(QData lhs) VL_PURE { - if (VL_UNLIKELY(!lhs)) return 0; - --lhs; - int shifts = 0; - for (; lhs != 0; ++shifts) lhs = lhs >> 1ULL; - return shifts; + // constexpr usage only! Recuses to meet C++11 constexpr func limitations + return lhs <= 1 ? 0 : VL_CLOG2_CE_Q((lhs + 1) >> 1ULL) + 1; } //=================================================================== From 2385ab8294f042a3594d542d308646eb588e3283 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 26 Sep 2023 22:53:25 -0400 Subject: [PATCH 031/157] Tests: randc now supported --- test_regress/t/t_class_unsup_bad.pl | 1 - test_regress/t/t_func_arg_complex.pl | 2 +- test_regress/t/t_uvm_all.pl | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/test_regress/t/t_class_unsup_bad.pl b/test_regress/t/t_class_unsup_bad.pl index 33a7f3beb..009248fc5 100755 --- a/test_regress/t/t_class_unsup_bad.pl +++ b/test_regress/t/t_class_unsup_bad.pl @@ -12,7 +12,6 @@ scenarios(vlt => 1); lint( fails => 1, - verilator_flags2 => ['-Wno-RANDC'], expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_func_arg_complex.pl b/test_regress/t/t_func_arg_complex.pl index 02e61ae8f..433693b72 100755 --- a/test_regress/t/t_func_arg_complex.pl +++ b/test_regress/t/t_func_arg_complex.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); compile( - v_flags2 => ["-Wno-PKGNODECL -Wno-UNPACKED -Wno-RANDC -Wno-IMPLICITSTATIC -Wno-CONSTRAINTIGN -Wno-MISINDENT", + v_flags2 => ["-Wno-PKGNODECL -Wno-UNPACKED -Wno-IMPLICITSTATIC -Wno-CONSTRAINTIGN -Wno-MISINDENT", "--error-limit 200"], ); diff --git a/test_regress/t/t_uvm_all.pl b/test_regress/t/t_uvm_all.pl index 23cc4f82d..2b328c903 100755 --- a/test_regress/t/t_uvm_all.pl +++ b/test_regress/t/t_uvm_all.pl @@ -12,7 +12,7 @@ scenarios(vlt => 1); compile( v_flags2 => ["--timing", - "-Wno-PKGNODECL -Wno-RANDC -Wno-IMPLICITSTATIC -Wno-CONSTRAINTIGN -Wno-MISINDENT", + "-Wno-PKGNODECL -Wno-IMPLICITSTATIC -Wno-CONSTRAINTIGN -Wno-MISINDENT", "-Wno-WIDTHEXPAND -Wno-WIDTHTRUNC -Wno-CASTCONST -Wno-REALCVT", "--error-limit 200 --debug-exit-uvm"], verilator_make_gmake => 0, From e49ae663a605ac1a91b1e048560817c115e68317 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 28 Sep 2023 22:45:00 -0400 Subject: [PATCH 032/157] Fix constification of $realtobits, $bitstoreal (#4522). --- Changes | 1 + src/V3Number.cpp | 20 ++++++++++++-------- test_regress/t/t_math_real.v | 4 ++++ test_regress/t/t_package.v | 8 ++++++++ 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/Changes b/Changes index 6c60e88e3..77040d98b 100644 --- a/Changes +++ b/Changes @@ -15,6 +15,7 @@ Verilator 5.017 devel * Add trace() API even when Verilated without --trace (#4462). [phelter] * Add warning on interface instantiation without parens (#4094). [Gökçe Aydos] +* Fix constification of $realtobits, $bitstoreal (#4522). [Andrew Nolte] * Support randc (#4349). * Support resizing function call inout arguments (#4467). diff --git a/src/V3Number.cpp b/src/V3Number.cpp index 702c4c1ca..b6d2a519c 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -2388,19 +2388,23 @@ V3Number& V3Number::opRToIRoundS(const V3Number& lhs) { V3Number& V3Number::opRealToBits(const V3Number& lhs) { NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_DOUBLE_ARGS1(lhs); - // Conveniently our internal format is identical so we can copy bits... if (lhs.width() != 64 || width() != 64) v3fatalSrc("Real operation on wrong sized number"); - m_data.setLogic(); - opAssign(lhs); - return *this; + union { + double m_d; + uint64_t m_v; + } u; + u.m_d = lhs.toDouble(); + return setQuad(u.m_v); } V3Number& V3Number::opBitsToRealD(const V3Number& lhs) { NUM_ASSERT_OP_ARGS1(lhs); - // Conveniently our internal format is identical so we can copy bits... if (lhs.width() != 64 || width() != 64) v3fatalSrc("Real operation on wrong sized number"); - m_data.setDouble(); - opAssign(lhs); - return *this; + union { + double m_d; + uint64_t m_v; + } u; + u.m_v = lhs.toUQuad(); + return setDouble(u.m_d); } V3Number& V3Number::opNegateD(const V3Number& lhs) { NUM_ASSERT_OP_ARGS1(lhs); diff --git a/test_regress/t/t_math_real.v b/test_regress/t/t_math_real.v index 6e0584d5f..f9ee46d5b 100644 --- a/test_regress/t/t_math_real.v +++ b/test_regress/t/t_math_real.v @@ -97,6 +97,10 @@ module t (/*AUTOARG*/ for (r=1.0; r<2.0; r=r+0.1) i++; if (i!=10) $stop; // bug + ci64 = $realtobits(1.444); + if (ci64 != 64'h3ff71a9fbe76c8b4) $stop; + r = $bitstoreal(64'h3ff71a9fbe76c8b4); + if (r != 1.444) $stop; r = $bitstoreal($realtobits(1.414)); if (r != 1.414) $stop; // bug diff --git a/test_regress/t/t_package.v b/test_regress/t/t_package.v index 12bd01ab6..db29474f6 100644 --- a/test_regress/t/t_package.v +++ b/test_regress/t/t_package.v @@ -23,6 +23,12 @@ package p2; function [3:0] plustwo(input [3:0] i); plustwo = i+2; endfunction + + function automatic bit realCompare(real r); + logic [63:0] b = $realtobits(r); + return b > 0; + endfunction + endpackage module t (/*AUTOARG*/ @@ -55,10 +61,12 @@ endmodule module t2; import p::*; import p2::plustwo; + import p2::realCompare; import p2::package2_type_t; package_type_t vp; package2_type_t vp2; initial begin + bit x = realCompare(1.0); if (plusone(1) !== 2) $stop; if (plustwo(1) !== 3) $stop; if (p::pi !== 123 && p::pi !== 124) $stop; // may race with other initial, so either value From 44e7d2ebe6c6fbd09ae939623623d8ea3e599690 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Fri, 29 Sep 2023 12:23:51 +0200 Subject: [PATCH 033/157] Internals: rename VPurity class and related functions. No functional change (#4523) --- src/V3Ast.h | 12 ++++++------ src/V3AstNodeExpr.h | 24 ++++++++++++----------- src/V3AstNodeOther.h | 4 ++-- src/V3AstNodes.cpp | 46 ++++++++++++++++++++++---------------------- 4 files changed, 44 insertions(+), 42 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index 22e4fd846..7772581d4 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -167,16 +167,16 @@ inline std::ostream& operator<<(std::ostream& os, const VLifetime& rhs) { // ###################################################################### -class VPurity final { - // Used in some nodes to cache the result of isPure method +class VIsCached final { + // Used in some nodes to cache results of boolean methods public: - enum en : uint8_t { NOT_CACHED, PURE, IMPURE }; + enum en : uint8_t { NOT_CACHED, YES, NO }; enum en m_e; - VPurity() + VIsCached() : m_e{NOT_CACHED} {} bool isCached() const { return m_e != NOT_CACHED; } - bool isPure() const { return m_e == PURE; } - void setPurity(bool pure) { m_e = pure ? PURE : IMPURE; } + bool get() const { return m_e == YES; } + void set(bool flag) { m_e = flag ? YES : NO; } void clearCache() { m_e = NOT_CACHED; } }; diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 823c26a05..5b6da8b42 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -70,7 +70,7 @@ class AstNodeBiop VL_NOT_FINAL : public AstNodeExpr { // Binary expression // @astgen op1 := lhsp : AstNodeExpr // @astgen op2 := rhsp : AstNodeExpr - VPurity m_purity; // Pure state + VIsCached m_purity; // Pure state protected: AstNodeBiop(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp) @@ -101,7 +101,7 @@ public: void clearCachedPurity() override; private: - bool getPurity() const { return lhsp()->isPure() && rhsp()->isPure(); } + bool getPurityRecurse() const { return lhsp()->isPure() && rhsp()->isPure(); } }; class AstNodeBiCom VL_NOT_FINAL : public AstNodeBiop { // Binary expr with commutative properties @@ -228,7 +228,7 @@ class AstNodeFTaskRef VL_NOT_FINAL : public AstNodeExpr { string m_dotted; // Dotted part of scope the name()ed task/func is under or "" string m_inlinedDots; // Dotted hierarchy flattened out bool m_pli = false; // Pli system call ($name) - VPurity m_purity; // Pure state + VIsCached m_purity; // Pure state protected: AstNodeFTaskRef(VNType t, FileLine* fl, AstNode* namep, AstNodeExpr* pinsp) @@ -268,7 +268,7 @@ public: void clearCachedPurity() override; private: - bool getPurity() const; + bool getPurityRecurse() const; }; class AstNodePreSel VL_NOT_FINAL : public AstNodeExpr { // Something that becomes an AstSel @@ -276,7 +276,7 @@ class AstNodePreSel VL_NOT_FINAL : public AstNodeExpr { // @astgen op2 := rhsp : AstNodeExpr // @astgen op3 := thsp : Optional[AstNodeExpr] // @astgen op4 := attrp : Optional[AstAttrOf] - VPurity m_purity; // Pure state + VIsCached m_purity; // Pure state protected: AstNodePreSel(VNType t, FileLine* fl, AstNodeExpr* fromp, AstNodeExpr* rhsp, AstNodeExpr* thsp) @@ -299,7 +299,7 @@ public: void clearCachedPurity() override; private: - bool getPurity() const { + bool getPurityRecurse() const { return fromp()->isPure() && rhsp()->isPure() && (!thsp() || thsp()->isPure()); } }; @@ -309,7 +309,7 @@ class AstNodeQuadop VL_NOT_FINAL : public AstNodeExpr { // @astgen op2 := rhsp : AstNodeExpr // @astgen op3 := thsp : AstNodeExpr // @astgen op4 := fhsp : AstNodeExpr - VPurity m_purity; // Pure state + VIsCached m_purity; // Pure state protected: AstNodeQuadop(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, AstNodeExpr* thsp, @@ -343,7 +343,7 @@ public: void clearCachedPurity() override; private: - bool getPurity() const { + bool getPurityRecurse() const { return lhsp()->isPure() && rhsp()->isPure() && thsp()->isPure() && fhsp()->isPure(); } }; @@ -365,7 +365,7 @@ class AstNodeTriop VL_NOT_FINAL : public AstNodeExpr { // @astgen op1 := lhsp : AstNodeExpr // @astgen op2 := rhsp : AstNodeExpr // @astgen op3 := thsp : AstNodeExpr - VPurity m_purity; // Pure state + VIsCached m_purity; // Pure state protected: AstNodeTriop(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, AstNodeExpr* thsp) @@ -396,7 +396,9 @@ public: void clearCachedPurity() override; private: - bool getPurity() const { return lhsp()->isPure() && rhsp()->isPure() && thsp()->isPure(); } + bool getPurityRecurse() const { + return lhsp()->isPure() && rhsp()->isPure() && thsp()->isPure(); + } }; class AstNodeCond VL_NOT_FINAL : public AstNodeTriop { // @astgen alias op1 := condp @@ -446,7 +448,7 @@ public: class AstNodeUniop VL_NOT_FINAL : public AstNodeExpr { // Unary expression // @astgen op1 := lhsp : AstNodeExpr - VPurity m_purity; // Pure state + VIsCached m_purity; // Pure state protected: AstNodeUniop(VNType t, FileLine* fl, AstNodeExpr* lhsp) diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index ee393ad9d..e41d614d2 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -88,7 +88,7 @@ private: bool m_virtual : 1; // Virtual method in class bool m_needProcess : 1; // Implements part of a process that allocates std::process VLifetime m_lifetime; // Lifetime - VPurity m_purity; // Pure state + VIsCached m_purity; // Pure state protected: AstNodeFTask(VNType t, FileLine* fl, const string& name, AstNode* stmtsp) @@ -195,7 +195,7 @@ public: } private: - bool getPurity() const; + bool getPurityRecurse() const; }; class AstNodeFile VL_NOT_FINAL : public AstNode { // Emitted Output file diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 3ba281286..7dd6ffee7 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -51,7 +51,7 @@ AstIface* AstIfaceRefDType::ifaceViaCellp() const { const char* AstNodeFTaskRef::broken() const { BROKEN_RTN(m_taskp && !m_taskp->brokeExists()); BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); - BROKEN_RTN(m_purity.isCached() && m_purity.isPure() != getPurity()); + BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse()); return nullptr; } @@ -68,8 +68,8 @@ bool AstNodeFTaskRef::isPure() { // cached. return false; } else { - if (!m_purity.isCached()) m_purity.setPurity(this->getPurity()); - return m_purity.isPure(); + if (!m_purity.isCached()) m_purity.set(this->getPurityRecurse()); + return m_purity.get(); } } @@ -78,7 +78,7 @@ void AstNodeFTaskRef::clearCachedPurity() { if (AstNodeExpr* const exprp = VN_CAST(backp(), NodeExpr)) exprp->clearCachedPurity(); } -bool AstNodeFTaskRef::getPurity() const { +bool AstNodeFTaskRef::getPurityRecurse() const { AstNodeFTask* const taskp = this->taskp(); // Unlinked yet, so treat as impure if (!taskp) return false; @@ -146,11 +146,11 @@ const char* AstNodeCCall::broken() const { } bool AstNodeCCall::isPure() { return funcp()->dpiPure(); } bool AstNodeUniop::isPure() { - if (!m_purity.isCached()) m_purity.setPurity(lhsp()->isPure()); - return m_purity.isPure(); + if (!m_purity.isCached()) m_purity.set(lhsp()->isPure()); + return m_purity.get(); } const char* AstNodeUniop::broken() const { - BROKEN_RTN(m_purity.isCached() && m_purity.isPure() != lhsp()->isPure()); + BROKEN_RTN(m_purity.isCached() && m_purity.get() != lhsp()->isPure()); return nullptr; } void AstNodeUniop::clearCachedPurity() { @@ -159,11 +159,11 @@ void AstNodeUniop::clearCachedPurity() { } bool AstNodeBiop::isPure() { - if (!m_purity.isCached()) m_purity.setPurity(getPurity()); - return m_purity.isPure(); + if (!m_purity.isCached()) m_purity.set(getPurityRecurse()); + return m_purity.get(); } const char* AstNodeBiop::broken() const { - BROKEN_RTN(m_purity.isCached() && m_purity.isPure() != getPurity()); + BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse()); return nullptr; } void AstNodeBiop::clearCachedPurity() { @@ -172,11 +172,11 @@ void AstNodeBiop::clearCachedPurity() { } bool AstNodeTriop::isPure() { - if (!m_purity.isCached()) m_purity.setPurity(getPurity()); - return m_purity.isPure(); + if (!m_purity.isCached()) m_purity.set(getPurityRecurse()); + return m_purity.get(); } const char* AstNodeTriop::broken() const { - BROKEN_RTN(m_purity.isCached() && m_purity.isPure() != getPurity()); + BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse()); return nullptr; } void AstNodeTriop::clearCachedPurity() { @@ -185,11 +185,11 @@ void AstNodeTriop::clearCachedPurity() { } bool AstNodePreSel::isPure() { - if (!m_purity.isCached()) m_purity.setPurity(getPurity()); - return m_purity.isPure(); + if (!m_purity.isCached()) m_purity.set(getPurityRecurse()); + return m_purity.get(); } const char* AstNodePreSel::broken() const { - BROKEN_RTN(m_purity.isCached() && m_purity.isPure() != getPurity()); + BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse()); return nullptr; } void AstNodePreSel::clearCachedPurity() { @@ -198,11 +198,11 @@ void AstNodePreSel::clearCachedPurity() { } bool AstNodeQuadop::isPure() { - if (!m_purity.isCached()) m_purity.setPurity(getPurity()); - return m_purity.isPure(); + if (!m_purity.isCached()) m_purity.set(getPurityRecurse()); + return m_purity.get(); } const char* AstNodeQuadop::broken() const { - BROKEN_RTN(m_purity.isCached() && m_purity.isPure() != getPurity()); + BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse()); return nullptr; } void AstNodeQuadop::clearCachedPurity() { @@ -2311,14 +2311,14 @@ void AstNodeFTask::dump(std::ostream& str) const { if ((dpiImport() || dpiExport()) && cname() != name()) str << " [c=" << cname() << "]"; } bool AstNodeFTask::isPure() { - if (!m_purity.isCached()) m_purity.setPurity(getPurity()); - return m_purity.isPure(); + if (!m_purity.isCached()) m_purity.set(getPurityRecurse()); + return m_purity.get(); } const char* AstNodeFTask::broken() const { - BROKEN_RTN(m_purity.isCached() && m_purity.isPure() != getPurity()); + BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse()); return nullptr; } -bool AstNodeFTask::getPurity() const { +bool AstNodeFTask::getPurityRecurse() const { if (this->dpiImport()) return this->dpiPure(); // Check the list of statements if it contains any impure statement // or any write reference to a variable that isn't an automatic function local. From 33787c6add3976ca35f9e9065d639b6439318151 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 1 Oct 2023 12:46:35 -0400 Subject: [PATCH 034/157] Internals: Fix number nodep cloning, and assert stays consistent (#4528 partial) --- src/V3AstNodeExpr.h | 5 +++++ src/V3Number.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 5b6da8b42..727cdca6e 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -1053,6 +1053,11 @@ public: const AstConst* const sp = static_cast(samep); return num().isCaseEq(sp->num()); } + void cloneRelink() override { m_num.nodep(this); } + const char* broken() const override { + BROKEN_RTN(m_num.nodep() && m_num.nodep() != this); + return nullptr; + } int instrCount() const override { return widthInstrs(); } bool isEqAllOnes() const { return num().isEqAllOnes(width()); } bool isEqAllOnesV() const { return num().isEqAllOnes(widthMinV()); } diff --git a/src/V3Number.h b/src/V3Number.h index e76c854c4..acab8420e 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -357,6 +357,7 @@ class V3Number final { public: void nodep(AstNode* nodep) VL_MT_STABLE; + AstNode* nodep() const VL_MT_SAFE { return m_nodep; } // For debug only FileLine* fileline() const VL_MT_SAFE { return m_fileline; } V3Number& setZero(); V3Number& setQuad(uint64_t value); From 732d03f4e5999879adf53de5864fa09849d84e29 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 1 Oct 2023 13:00:16 -0400 Subject: [PATCH 035/157] Fix conversion of integers in $display %e (#4528). --- Changes | 1 + src/V3Width.cpp | 1 + test_regress/t/t_display_real.out | 2 ++ test_regress/t/t_display_real.v | 3 +++ 4 files changed, 7 insertions(+) diff --git a/Changes b/Changes index 77040d98b..f40cebad4 100644 --- a/Changes +++ b/Changes @@ -16,6 +16,7 @@ Verilator 5.017 devel * Add trace() API even when Verilated without --trace (#4462). [phelter] * Add warning on interface instantiation without parens (#4094). [Gökçe Aydos] * Fix constification of $realtobits, $bitstoreal (#4522). [Andrew Nolte] +* Fix conversion of integers in $display '%e' (#4528). [muzafferkal] * Support randc (#4349). * Support resizing function call inout arguments (#4467). diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 3cc703257..0c73d9116 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -4893,6 +4893,7 @@ private: } break; } + case 'e': // FALLTHRU case 'f': // FALLTHRU case 'g': { if (argp) { diff --git a/test_regress/t/t_display_real.out b/test_regress/t/t_display_real.out index bf94bb29a..eb6fb770f 100644 --- a/test_regress/t/t_display_real.out +++ b/test_regress/t/t_display_real.out @@ -20,4 +20,6 @@ r8= 3 n1=1 n2=0.1 n1=1 n2=0.1 r8= 3 + +iconst=0.000000e+00 0.000000 0 *-* All Finished *-* diff --git a/test_regress/t/t_display_real.v b/test_regress/t/t_display_real.v index 1e5de3684..33e15d81c 100644 --- a/test_regress/t/t_display_real.v +++ b/test_regress/t/t_display_real.v @@ -11,6 +11,7 @@ module t; real n3; initial n3 = 1.2345e-15; real n4; initial n4 = 2.579e+15; reg [7:0] r8; initial r8 = 3; + integer iconst = 0; initial begin // Display formatting @@ -36,6 +37,8 @@ module t; $display; $display("r8=%d n1=%g n2=%g", r8, n1, n2); $display("n1=%g n2=%g r8=%d", n1, n2, r8); + $display; + $display("iconst=%e %f %g", iconst, iconst, iconst); $write("*-* All Finished *-*\n"); $finish; end From 1b8228b6421843f5d92b93258b588510df20c97c Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Tue, 3 Oct 2023 13:23:20 +0200 Subject: [PATCH 036/157] Fix stream operations with operands of struct type (#4531) (#4532) --- src/V3Width.cpp | 2 +- test_regress/t/t_stream_struct.pl | 21 +++++++++ test_regress/t/t_stream_struct.v | 74 +++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100755 test_regress/t/t_stream_struct.pl create mode 100644 test_regress/t/t_stream_struct.v diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 0c73d9116..1d6468001 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -843,7 +843,7 @@ private: } else { nodep->v3error("Slice size isn't a constant or basic data type."); } - const AstNodeDType* const lhsDtypep = nodep->lhsp()->dtypep(); + const AstNodeDType* const lhsDtypep = nodep->lhsp()->dtypep()->skipRefToEnump(); if (VN_IS(lhsDtypep, DynArrayDType) || VN_IS(lhsDtypep, QueueDType)) { nodep->dtypeSetStream(); } else if (VN_IS(lhsDtypep, UnpackArrayDType) || lhsDtypep->isCompound()) { diff --git a/test_regress/t/t_stream_struct.pl b/test_regress/t/t_stream_struct.pl new file mode 100755 index 000000000..aabcde63e --- /dev/null +++ b/test_regress/t/t_stream_struct.pl @@ -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 2020 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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_stream_struct.v b/test_regress/t/t_stream_struct.v new file mode 100644 index 000000000..c3a1fcde3 --- /dev/null +++ b/test_regress/t/t_stream_struct.v @@ -0,0 +1,74 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc = 0; + reg [63:0] crc; + reg [63:0] sum; + + // Take CRC data and apply to testblock inputs + wire [63:0] in = crc[63:0]; + + /*AUTOWIRE*/ + // Beginning of automatic wires (for undeclared instantiated-module outputs) + logic [63:0] out; // From test of Test.v + // End of automatics + + Test test(/*AUTOINST*/ + // Outputs + .out (out[63:0]), + // Inputs + .in (in[63:0])); + + // Test loop + always @ (posedge clk) begin +`ifdef TEST_VERBOSE + $write("[%0t] cyc==%0d crc=%x out=%x\n", $time, cyc, crc, out); +`endif + cyc <= cyc + 1; + crc <= {crc[62:0], crc[63] ^ crc[2] ^ crc[0]}; + sum <= out ^ {sum[62:0], sum[63] ^ sum[2] ^ sum[0]}; + if (cyc == 0) begin + // Setup + crc <= 64'h5aef0c8d_d70a4497; + sum <= '0; + end + else if (cyc < 10) begin + sum <= '0; + end + else if (cyc == 99) begin + $write("[%0t] cyc==%0d crc=%x sum=%x\n", $time, cyc, crc, sum); + if (crc !== 64'hc77bb9b3784ea091) $stop; + // What checksum will we end up with (above print should match) +`define EXPECTED_SUM 64'h29271cf844d6f90c + if (sum !== `EXPECTED_SUM) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule + +module Test ( + input wire [63:0] in, + output logic [63:0] out); + + typedef struct packed { + logic [63:0] dummy; + } data_t; + + function automatic logic [63:0] reverse(data_t d); + return {<<{d}}; + endfunction + + assign out = reverse(in); + +endmodule From a3c154dcd3fb0ec4768eaa3be2c3dd7b648376b3 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Tue, 3 Oct 2023 14:32:18 +0200 Subject: [PATCH 037/157] Fix this in a constructor (#4533) --- include/verilated_types.h | 5 +++-- test_regress/t/t_class_this_constructor.pl | 21 +++++++++++++++++ test_regress/t/t_class_this_constructor.v | 26 ++++++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_class_this_constructor.pl create mode 100644 test_regress/t/t_class_this_constructor.v diff --git a/include/verilated_types.h b/include/verilated_types.h index 6a1a3bfac..cb40b0e82 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -1477,7 +1477,7 @@ class VlClass VL_NOT_FINAL : public VlDeletable { public: // CONSTRUCTORS - VlClass() = default; + VlClass() { refCountInc(); } VlClass(const VlClass& copied) {} ~VlClass() override = default; }; @@ -1526,8 +1526,9 @@ public: // () required here to avoid narrowing conversion warnings, // when a new() has an e.g. CData type and passed a 1U. : m_objp{new T_Class(std::forward(args)...)} { + // refCountInc was moved to the constructor of T_Class + // to fix self references in constructor. m_objp->m_deleterp = &deleter; - refCountInc(); } // Explicit to avoid implicit conversion from 0 explicit VlClassRef(T_Class* objp) diff --git a/test_regress/t/t_class_this_constructor.pl b/test_regress/t/t_class_this_constructor.pl new file mode 100755 index 000000000..aabcde63e --- /dev/null +++ b/test_regress/t/t_class_this_constructor.pl @@ -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 2020 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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_this_constructor.v b/test_regress/t/t_class_this_constructor.v new file mode 100644 index 000000000..944d737db --- /dev/null +++ b/test_regress/t/t_class_this_constructor.v @@ -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, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Cls; + bit x = 1'b0; + function new; + Cls c; + if (c == this) begin + x = 1'b1; + end + endfunction +endclass + +module t (/*AUTOARG*/); + Cls c; + initial begin + c = new; + if (c.x) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From f84907313709db0e5cafb495f7c5fcc53f67c41a Mon Sep 17 00:00:00 2001 From: Todd Strader Date: Tue, 3 Oct 2023 19:55:25 -0400 Subject: [PATCH 038/157] Fix non-inlined interface tracing (#3984) (#4530) --- src/CMakeLists.txt | 2 + src/Makefile_obj.in | 1 + src/V3Inline.cpp | 83 ----------- src/V3Interface.cpp | 129 ++++++++++++++++++ src/V3Interface.h | 34 +++++ src/Verilator.cpp | 3 + test_regress/t/t_interface_ref_trace_noinl.pl | 28 ++++ .../t/t_interface_ref_trace_noinl_notrace.pl | 24 ++++ 8 files changed, 221 insertions(+), 83 deletions(-) create mode 100644 src/V3Interface.cpp create mode 100644 src/V3Interface.h create mode 100755 test_regress/t/t_interface_ref_trace_noinl.pl create mode 100755 test_regress/t/t_interface_ref_trace_noinl_notrace.pl diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 396d79fd6..393eba402 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -96,6 +96,7 @@ set(HEADERS V3Inline.h V3Inst.h V3InstrCount.h + V3Interface.h V3LangCode.h V3LanguageWords.h V3Life.h @@ -243,6 +244,7 @@ set(COMMON_SOURCES V3Inline.cpp V3Inst.cpp V3InstrCount.cpp + V3Interface.cpp V3Life.cpp V3LifePost.cpp V3LinkCells.cpp diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 162da5d85..b076f1a2a 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -219,6 +219,7 @@ RAW_OBJS = \ V3Inline.o \ V3Inst.o \ V3InstrCount.o \ + V3Interface.o \ V3Life.o \ V3LifePost.o \ V3LinkCells.o \ diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index 996e9d9bf..f704c9fb7 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -623,88 +623,6 @@ public: } }; -//###################################################################### -// Track interface references under the Cell they reference - -class InlineIntfRefVisitor final : public VNVisitor { -private: - // NODE STATE - // AstVar::user1p() // AstCell which this Var points to - const VNUser1InUse m_inuser1; - const VNUser2InUse m_inuser2; - - string m_scope; // Scope name - - // VISITORS - void visit(AstNetlist* nodep) override { iterateChildren(nodep->topModulep()); } - void visit(AstCell* nodep) override { - VL_RESTORER(m_scope); - if (m_scope.empty()) { - m_scope = nodep->name(); - } else { - m_scope += "__DOT__" + nodep->name(); - } - - if (VN_IS(nodep->modp(), Iface)) { - nodep->addIntfRefsp(new AstIntfRef{nodep->fileline(), m_scope}); - } - { - AstNodeModule* const modp = nodep->modp(); - // Pass Cell pointers down to the next module - for (AstPin* pinp = nodep->pinsp(); pinp; pinp = VN_AS(pinp->nextp(), Pin)) { - AstVar* const varp = pinp->modVarp(); - const AstVarRef* const varrefp = VN_CAST(pinp->exprp(), VarRef); - if (!varrefp) continue; - const AstVar* const fromVarp = varrefp->varp(); - const AstIfaceRefDType* const irdtp = VN_CAST(fromVarp->dtypep(), IfaceRefDType); - if (!irdtp) continue; - - AstCell* cellp; - if ((cellp = VN_CAST(fromVarp->user1p(), Cell)) || (cellp = irdtp->cellp())) { - varp->user1p(cellp); - const string alias = m_scope + "__DOT__" + pinp->name(); - cellp->addIntfRefsp(new AstIntfRef{pinp->fileline(), alias}); - } - } - - iterateChildren(modp); - } - } - void visit(AstAssignVarScope* nodep) override { - // Reference - const AstVarRef* const reflp = VN_CAST(nodep->lhsp(), VarRef); - // What the reference refers to - const AstVarRef* const refrp = VN_CAST(nodep->rhsp(), VarRef); - if (!(reflp && refrp)) return; - - const AstVar* const varlp = reflp->varp(); - const AstVar* const varrp = refrp->varp(); - if (!(varlp && varrp)) return; - - AstCell* cellp = VN_CAST(varrp->user1p(), Cell); - if (!cellp) { - const AstIfaceRefDType* const irdtp = VN_CAST(varrp->dtypep(), IfaceRefDType); - if (!irdtp) return; - - cellp = irdtp->cellp(); - } - if (!cellp) return; - string alias; - if (!m_scope.empty()) alias = m_scope + "__DOT__"; - alias += varlp->name(); - cellp->addIntfRefsp(new AstIntfRef{varlp->fileline(), alias}); - } - //-------------------- - void visit(AstNodeExpr*) override {} // Accelerate - void visit(AstNodeStmt*) override {} // Accelerate - void visit(AstNode* nodep) override { iterateChildren(nodep); } - -public: - // CONSTRUCTORS - explicit InlineIntfRefVisitor(AstNode* nodep) { iterate(nodep); } - ~InlineIntfRefVisitor() override = default; -}; - //###################################################################### // Inline class functions @@ -730,6 +648,5 @@ void V3Inline::inlineAll(AstNetlist* nodep) { } } - { InlineIntfRefVisitor{nodep}; } V3Global::dumpCheckGlobalTree("inline", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Interface.cpp b/src/V3Interface.cpp new file mode 100644 index 000000000..a0b641885 --- /dev/null +++ b/src/V3Interface.cpp @@ -0,0 +1,129 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Interface references for tracing +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2023 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 +// +//************************************************************************* +// V3Interface's Transformations: +// +// Each module: +// Look for CELL... +// Keep track of scope and concrete interface along the way +// Find all interface references +// Add INTFREF to concrete interface's list of references +// +//************************************************************************* + +#define VL_MT_DISABLED_CODE_UNIT 1 + +#include "config_build.h" +#include "verilatedos.h" + +#include "V3Interface.h" + +#include "V3Ast.h" +#include "V3Global.h" + +VL_DEFINE_DEBUG_FUNCTIONS; + +//###################################################################### +// Track interface references under the Cell they reference + +class InlineIntfRefVisitor final : public VNVisitor { +private: + // NODE STATE + // AstVar::user1p() // AstCell which this Var points to + const VNUser1InUse m_inuser1; + const VNUser2InUse m_inuser2; + + string m_scope; // Scope name + + // VISITORS + void visit(AstNetlist* nodep) override { iterateChildren(nodep->topModulep()); } + void visit(AstCell* nodep) override { + VL_RESTORER(m_scope); + if (m_scope.empty()) { + m_scope = nodep->name(); + } else { + m_scope += "__DOT__" + nodep->name(); + } + + if (VN_IS(nodep->modp(), Iface)) { + nodep->addIntfRefsp(new AstIntfRef{nodep->fileline(), m_scope}); + } + { + AstNodeModule* const modp = nodep->modp(); + // Pass Cell pointers down to the next module + for (AstPin* pinp = nodep->pinsp(); pinp; pinp = VN_AS(pinp->nextp(), Pin)) { + AstVar* const varp = pinp->modVarp(); + const AstVarRef* const varrefp = VN_CAST(pinp->exprp(), VarRef); + if (!varrefp) continue; + const AstVar* const fromVarp = varrefp->varp(); + const AstIfaceRefDType* const irdtp = VN_CAST(fromVarp->dtypep(), IfaceRefDType); + if (!irdtp) continue; + + AstCell* cellp; + if ((cellp = VN_CAST(fromVarp->user1p(), Cell)) || (cellp = irdtp->cellp())) { + varp->user1p(cellp); + const string alias = m_scope + "__DOT__" + pinp->name(); + cellp->addIntfRefsp(new AstIntfRef{pinp->fileline(), alias}); + } + } + + iterateChildren(modp); + } + } + void visit(AstAssignVarScope* nodep) override { + // Reference + const AstVarRef* const reflp = VN_CAST(nodep->lhsp(), VarRef); + // What the reference refers to + const AstVarRef* const refrp = VN_CAST(nodep->rhsp(), VarRef); + if (!(reflp && refrp)) return; + + const AstVar* const varlp = reflp->varp(); + const AstVar* const varrp = refrp->varp(); + if (!(varlp && varrp)) return; + + AstCell* cellp = VN_CAST(varrp->user1p(), Cell); + if (!cellp) { + const AstIfaceRefDType* const irdtp = VN_CAST(varrp->dtypep(), IfaceRefDType); + if (!irdtp) return; + + cellp = irdtp->cellp(); + } + if (!cellp) return; + string alias; + if (!m_scope.empty()) alias = m_scope + "__DOT__"; + alias += varlp->name(); + cellp->addIntfRefsp(new AstIntfRef{varlp->fileline(), alias}); + } + //-------------------- + void visit(AstNodeExpr*) override {} // Accelerate + void visit(AstNodeStmt*) override {} // Accelerate + void visit(AstNode* nodep) override { iterateChildren(nodep); } + +public: + // CONSTRUCTORS + explicit InlineIntfRefVisitor(AstNode* nodep) { iterate(nodep); } + ~InlineIntfRefVisitor() override = default; +}; + +//###################################################################### +// Interface class functions + +void V3Interface::interfaceAll(AstNetlist* nodep) { + UINFO(2, __FUNCTION__ << ": " << endl); + + { InlineIntfRefVisitor{nodep}; } + + V3Global::dumpCheckGlobalTree("interface", 0, dumpTreeLevel() >= 3); +} diff --git a/src/V3Interface.h b/src/V3Interface.h new file mode 100644 index 000000000..08bea3574 --- /dev/null +++ b/src/V3Interface.h @@ -0,0 +1,34 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Interface references for tracing +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2023 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 +// +//************************************************************************* + +#ifndef VERILATOR_V3INTERFACE_H_ +#define VERILATOR_V3INTERFACE_H_ + +#include "config_build.h" +#include "verilatedos.h" + +#include "V3ThreadSafety.h" + +class AstNetlist; + +//============================================================================ + +class V3Interface final { +public: + static void interfaceAll(AstNetlist* nodep) VL_MT_DISABLED; +}; + +#endif // Guard diff --git a/src/Verilator.cpp b/src/Verilator.cpp index cb2109ea0..99af25820 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -58,6 +58,7 @@ #include "V3HierBlock.h" #include "V3Inline.h" #include "V3Inst.h" +#include "V3Interface.h" #include "V3Life.h" #include "V3LifePost.h" #include "V3LinkDot.h" @@ -274,6 +275,8 @@ static void process() { } } + if (v3Global.opt.trace()) V3Interface::interfaceAll(v3Global.rootp()); + if (v3Global.opt.fDfgPostInline()) { // Post inline DFG optimization V3DfgOptimizer::optimize(v3Global.rootp(), "post inline"); diff --git a/test_regress/t/t_interface_ref_trace_noinl.pl b/test_regress/t/t_interface_ref_trace_noinl.pl new file mode 100755 index 000000000..f183f40d1 --- /dev/null +++ b/test_regress/t/t_interface_ref_trace_noinl.pl @@ -0,0 +1,28 @@ +#!/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-2009 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(simulator => 1); + +top_filename("t/t_interface_ref_trace.v"); +golden_filename("t/t_interface_ref_trace.out"); + +compile( + verilator_flags2 => ['-fno-inline --trace-structs --trace'], + ); + +execute( + check_finished => 1, + ); + +vcd_identical($Self->trace_filename, + $Self->{golden_filename}); + +ok(1); +1; diff --git a/test_regress/t/t_interface_ref_trace_noinl_notrace.pl b/test_regress/t/t_interface_ref_trace_noinl_notrace.pl new file mode 100755 index 000000000..b41a3654b --- /dev/null +++ b/test_regress/t/t_interface_ref_trace_noinl_notrace.pl @@ -0,0 +1,24 @@ +#!/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-2009 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(simulator => 1); + +top_filename("t/t_interface_ref_trace.v"); + +compile( + verilator_flags2 => ['-fno-inline'], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; From 537650a2cd1bca1b18f6c87657612022fe41dffc Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 3 Oct 2023 22:10:50 -0400 Subject: [PATCH 039/157] Fix stream of 32 bit (#4536). --- Changes | 1 + include/verilated_funcs.h | 2 +- test_regress/t/t_stream5.pl | 23 +++++++++++++++++++++++ test_regress/t/t_stream5.v | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100755 test_regress/t/t_stream5.pl create mode 100644 test_regress/t/t_stream5.v diff --git a/Changes b/Changes index f40cebad4..9af06d980 100644 --- a/Changes +++ b/Changes @@ -17,6 +17,7 @@ Verilator 5.017 devel * Add warning on interface instantiation without parens (#4094). [Gökçe Aydos] * Fix constification of $realtobits, $bitstoreal (#4522). [Andrew Nolte] * Fix conversion of integers in $display '%e' (#4528). [muzafferkal] +* Fix stream of 32 bit (#4536). [Julien Faucher] * Support randc (#4349). * Support resizing function call inout arguments (#4467). diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index 32ab2268e..22285812e 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -1437,7 +1437,7 @@ static inline IData VL_STREAML_FAST_III(int lbits, IData ld, IData rd_log2) VL_P if (rd_log2) { const uint32_t lbitsFloor = lbits & ~VL_MASK_I(rd_log2); // max multiple of rd <= lbits const uint32_t lbitsRem = lbits - lbitsFloor; // number of bits in most-sig slice (MSS) - const IData msbMask = VL_MASK_I(lbitsRem) << lbitsFloor; // mask to sel only bits in MSS + const IData msbMask = lbitsFloor == 32 ? 0UL : VL_MASK_I(lbitsRem) << lbitsFloor; ret = (ret & ~msbMask) | ((ret & msbMask) << ((VL_UL(1) << rd_log2) - lbitsRem)); } switch (rd_log2) { diff --git a/test_regress/t/t_stream5.pl b/test_regress/t/t_stream5.pl new file mode 100755 index 000000000..b8493bd06 --- /dev/null +++ b/test_regress/t/t_stream5.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 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(simulator => 1); + +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_stream5.v b/test_regress/t/t_stream5.v new file mode 100644 index 000000000..1eab118d9 --- /dev/null +++ b/test_regress/t/t_stream5.v @@ -0,0 +1,37 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + + logic [15:0] i16; + logic [15:0] o16; + logic [31:0] i32; + logic [31:0] o32; + logic [63:0] i64; + logic [63:0] o64; + + always_comb begin + o16 = {<<4{i16}}; + o32 = {<<4{i32}}; + o64 = {<<4{i64}}; + end + + initial begin + i16 = 16'hfade; + i32 = 32'hcafefade; + i64 = 64'hdeaddeedcafefade; + #100ns; + $display("o16=0x%h i16=0x%h", o16, i16); + if (o16 != 16'hEDAF) $stop; + $display("o32=0x%h i32=0x%h", o32, i32); + if (o32 != 32'hEDAFEFAC) $stop; + $display("o64=0x%h i64=0x%h", o64, i64); + if (o64 != 64'hEDAFEFACDEEDDAED) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From 45162652dec80d3914b3407876674548506f33f1 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 4 Oct 2023 20:13:59 -0400 Subject: [PATCH 040/157] Commentary --- docs/guide/languages.rst | 55 +++++++++++++--------------------------- 1 file changed, 18 insertions(+), 37 deletions(-) diff --git a/docs/guide/languages.rst b/docs/guide/languages.rst index 6eeb84fb1..21b18914d 100644 --- a/docs/guide/languages.rst +++ b/docs/guide/languages.rst @@ -237,11 +237,9 @@ optimizations will be disabled around the latch. Structures and Unions --------------------- -Presently Verilator only supports packed structs and packed unions. Rand -and randc tags on members are ignored. All structures and unions are -represented as a single vector, which means that generating one member of a -structure from blocking, and another from non-blocking assignments is -unsupported. +All structures and unions are scheduled together, which means that +generating one member of a structure from blocking, and another from +non-blocking assignments is unsupported. .. _Unknown States: @@ -320,20 +318,6 @@ there will be considered a two-state variable that is read and written instead of a four-state variable. -Functions & Tasks ------------------ - -All functions and tasks will be inlined (will not become functions in C.) -The only support provided is simple statements in tasks (which may -affect global variables). - -Recursive functions and tasks are not supported. All inputs and outputs -are automatic as if they had the Verilog 2001 "automatic" keyword -prepended. (If you don't know what this means, Verilator will do what you -probably expect, what C does. The default behavior of Verilog is -different.) - - Gate Primitives --------------- @@ -383,24 +367,6 @@ Verilator does not support SEREs yet. All assertion and coverage statements must be simple expressions that complete in one cycle. -Force statement ---------------- - -Verilator supports the procedural `force` (and corresponding `release`) -statement. However, the behavior of the `force` statement does not entirely -comply with IEEE 1800. According to the standard, -when a procedural statement of the form `force a = b;` is executed, the -simulation should behave as if, from that point forwards, a continuous -assignment `assign a = b;` has been added to override the drivers of `a`. -More specifically: the value of `a` should be updated whenever the value of -`b` changes, until a `release a;` statement is executed. -Verilator instead evaluates the current value of `b` when the `force` -statement is executed, and forces `a` to that value, without updating it -until a new `force` or `release` statement is encountered that applies to -`a`. This non-standard behavior is nevertheless consistent with some other -simulators. - - Encrypted Verilog ----------------- @@ -471,6 +437,21 @@ disable provide loop break and continue functionality before SystemVerilog added the break and continue keywords. +force, release + Verilator supports the procedural `force` (and corresponding `release`) + statement. However, the behavior of the `force` statement does not + entirely comply with IEEE 1800. According to the standard, when a + procedural statement of the form `force a = b;` is executed, the + simulation should behave as if, from that point forwards, a continuous + assignment `assign a = b;` has been added to override the drivers of `a`. + More specifically: the value of `a` should be updated whenever the value + of `b` changes, until a `release a;` statement is executed. Verilator + instead evaluates the current value of `b` when the `force` statement is + executed, and forces `a` to that value, without updating it until a new + `force` or `release` statement is encountered that applies to `a`. This + non-standard behavior is nevertheless consistent with some other + simulators. + inside Inside expressions may not include unpacked array traversal or $ as an upper bound. Case inside and case matches are also unsupported. From 25fa1d7c6a61edb91de6f1fe0bc7c3c0e0bab337 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 4 Oct 2023 20:16:05 -0400 Subject: [PATCH 041/157] Commentary: Changes update --- Changes | 17 ++++++++++++++--- docs/spelling.txt | 4 ++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/Changes b/Changes index 9af06d980..2cf70f114 100644 --- a/Changes +++ b/Changes @@ -15,11 +15,22 @@ Verilator 5.017 devel * Add trace() API even when Verilated without --trace (#4462). [phelter] * Add warning on interface instantiation without parens (#4094). [Gökçe Aydos] -* Fix constification of $realtobits, $bitstoreal (#4522). [Andrew Nolte] -* Fix conversion of integers in $display '%e' (#4528). [muzafferkal] -* Fix stream of 32 bit (#4536). [Julien Faucher] * Support randc (#4349). * Support resizing function call inout arguments (#4467). +* Support converting parameters inside modules to localparams (#4511). [Anthony Donlon] +* Fix conversion of impure logical expressions to bit expressions (#487 partial) (#4437). [Ryszard Rozak, Antmicro Ltd.] +* Fix passing arguments by reference (#3385 partial) (#4489). [Ryszard Rozak, Antmicro Ltd.] +* Fix multithreading handling to separate by code units that use/never use it (#4228). [Mariusz Glebocki, Antmicro Ltd.] +* Fix usage of annotation options (#4486) (#4504). [Michal Czyz] +* Fix detecting local vars in nested forks (#4493) (#4506). [Kamil Rakoczy] +* Fix handling input file path separator (#4515) (#4516). [Anthony Donlon] +* Fix mis-support for parameterized UDPs (#4518). [Anthony Donlon] +* Fix constant conversion of $realtobits, $bitstoreal (#4522). [Andrew Nolte] +* Fix conversion of integers in $display '%e' (#4528). [muzafferkal] +* Fix non-inlined interface tracing (#3984) (#4530). [Todd Strader] +* Fix stream operations with operands of struct type (#4531) (#4532). [Ryszard Rozak, Antmicro Ltd.] +* Fix 'this' in a constructor (#4533). [Ryszard Rozak, Antmicro Ltd.] +* Fix stream shift operator of 32 bits (#4536). [Julien Faucher] Verilator 5.016 2023-09-16 diff --git a/docs/spelling.txt b/docs/spelling.txt index d55530c50..a0321e494 100644 --- a/docs/spelling.txt +++ b/docs/spelling.txt @@ -89,6 +89,7 @@ Engstrom Enzo Eugen Fabrizio +Faucher Fekete Ferrandi Flachs @@ -722,6 +723,7 @@ multithreading musl mutexes mux +muzafferkal myftptoyman mysignal namespace @@ -760,6 +762,7 @@ pdf perf perftools pgo +phelter picoChip pinIndex pinout @@ -815,6 +818,7 @@ readmemb readmemh realpath realtime +realtobits recoding recrem redeclaring From 1c738c6b83867d220f2338f2ea9eaa4e9e3d20b0 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Thu, 5 Oct 2023 13:21:33 +0200 Subject: [PATCH 042/157] Fix object destruction after a copy constructor (#4540) (#4541) --- include/verilated_types.h | 2 +- test_regress/t/t_class_copy2.pl | 21 +++++++++++++++++++ test_regress/t/t_class_copy2.v | 36 +++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100755 test_regress/t/t_class_copy2.pl create mode 100644 test_regress/t/t_class_copy2.v diff --git a/include/verilated_types.h b/include/verilated_types.h index cb40b0e82..9eae185d5 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -1478,7 +1478,7 @@ class VlClass VL_NOT_FINAL : public VlDeletable { public: // CONSTRUCTORS VlClass() { refCountInc(); } - VlClass(const VlClass& copied) {} + VlClass(const VlClass& copied) { refCountInc(); } ~VlClass() override = default; }; diff --git a/test_regress/t/t_class_copy2.pl b/test_regress/t/t_class_copy2.pl new file mode 100755 index 000000000..aabcde63e --- /dev/null +++ b/test_regress/t/t_class_copy2.pl @@ -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 2020 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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_copy2.v b/test_regress/t/t_class_copy2.v new file mode 100644 index 000000000..9fb72e670 --- /dev/null +++ b/test_regress/t/t_class_copy2.v @@ -0,0 +1,36 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); + +class Cls; + bit x = 1; +endclass + +module t (/*AUTOARG*/); + Cls obj1; + Cls obj2; + + initial begin + obj1 = new; + `checkh(obj1.x, 1); + + obj1.x = 0; + obj2 = new obj1; + `checkh(obj2.x, 0); + + obj2.x = 1; + `checkh(obj1.x, 0); + `checkh(obj2.x, 1); + + obj2.x = 0; + `checkh(obj2.x, 0); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From 106664b94271b22008ba3badddfbd0baa666fee5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 5 Oct 2023 08:40:46 -0400 Subject: [PATCH 043/157] Internals: Fix long lines. No functional change. --- src/verilog.y | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/verilog.y b/src/verilog.y index 6d06f969e..fd0c18ca9 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -4465,7 +4465,8 @@ taskId: funcId: // IEEE: function_data_type_or_implicit + part of function_body_declaration // // IEEE: function_data_type_or_implicit must be expanded here to prevent conflict - // // function_data_type expanded here to prevent conflicts with implicit_type:empty vs data_type:ID + // // function_data_type expanded here to prevent conflicts with + // // implicit_type:empty vs data_type:ID /**/ fIdScoped { $$ = $1; $$->fvarp(new AstBasicDType{$1, LOGIC_IMPLICIT}); @@ -4932,7 +4933,7 @@ fexpr: // For use as first part of statement (disam //UNSUP // //UNSUP //--------------------- //UNSUP // // IEEE: expr -//UNSUP | BISONPRE_COPY(expr,{s/~l~/ev_/g; s/~r~/ev_/g; s/~p~/ev_/g; s/~noPar__IGNORE~'.'/yP_PAR__IGNORE /g;}) // {copied} +//UNSUP | BISONPRE_COPY(expr,{s/~l~/ev_/g; s/~r~/ev_/g; s/~p~/ev_/g; s/~noPar__IGNORE~'.'/yP_PAR__IGNORE /g;}) // {copied} //UNSUP // //UNSUP // // IEEE: '(' event_expression ')' //UNSUP // // expr:'(' x ')' conflicts with event_expression:'(' event_expression ')' @@ -5722,7 +5723,8 @@ clocking_eventE: // IEEE: optional clocking_event clocking_event: // IEEE: clocking_event '@' id - { $$ = new AstSenItem{$2, VEdgeType::ET_CHANGED, new AstParseRef{$2, VParseRefExp::PX_TEXT, *$2, nullptr, nullptr}}; } + { $$ = new AstSenItem{$2, VEdgeType::ET_CHANGED, + new AstParseRef{$2, VParseRefExp::PX_TEXT, *$2, nullptr, nullptr}}; } | '@' '(' event_expression ')' { $$ = $3; } ; @@ -5787,9 +5789,12 @@ clocking_skew: // IEEE: clocking_skew ; cycle_delay: // IEEE: cycle_delay - yP_POUNDPOUND yaINTNUM { $$ = new AstDelay{$1, new AstConst{$2, *$2}, true}; } - | yP_POUNDPOUND id { $$ = new AstDelay{$1, new AstParseRef{$2, VParseRefExp::PX_TEXT, *$2, nullptr, nullptr}, true}; } - | yP_POUNDPOUND '(' expr ')' { $$ = new AstDelay{$1, $3, true}; } + yP_POUNDPOUND yaINTNUM + { $$ = new AstDelay{$1, new AstConst{$2, *$2}, true}; } + | yP_POUNDPOUND id + { $$ = new AstDelay{$1, new AstParseRef{$2, VParseRefExp::PX_TEXT, *$2, nullptr, nullptr}, true}; } + | yP_POUNDPOUND '(' expr ')' + { $$ = new AstDelay{$1, $3, true}; } ; //************************************************ From 800a789f5065cb580edf2ed36a8c23b8d732caf4 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 6 Oct 2023 21:33:31 -0400 Subject: [PATCH 044/157] Fix inlining of real functions miscasting (#4543). --- Changes | 1 + src/V3Cast.cpp | 8 ++++++-- src/V3Const.cpp | 2 +- test_regress/t/t_func_real_exprstmt.pl | 21 +++++++++++++++++++++ test_regress/t/t_func_real_exprstmt.v | 23 +++++++++++++++++++++++ 5 files changed, 52 insertions(+), 3 deletions(-) create mode 100755 test_regress/t/t_func_real_exprstmt.pl create mode 100644 test_regress/t/t_func_real_exprstmt.v diff --git a/Changes b/Changes index 2cf70f114..2b3e63fac 100644 --- a/Changes +++ b/Changes @@ -31,6 +31,7 @@ Verilator 5.017 devel * Fix stream operations with operands of struct type (#4531) (#4532). [Ryszard Rozak, Antmicro Ltd.] * Fix 'this' in a constructor (#4533). [Ryszard Rozak, Antmicro Ltd.] * Fix stream shift operator of 32 bits (#4536). [Julien Faucher] +* Fix inlining of real functions miscasting (#4543). [Andrew Nolte] Verilator 5.016 2023-09-16 diff --git a/src/V3Cast.cpp b/src/V3Cast.cpp index 7362f9c71..4fb3b868e 100644 --- a/src/V3Cast.cpp +++ b/src/V3Cast.cpp @@ -58,7 +58,7 @@ class CastVisitor final : public VNVisitor { private: // NODE STATE // Entire netlist: - // AstNode::user() // bool. Indicates node is of known size + // AstNode::user1() // bool. Indicates node is of known size const VNUser1InUse m_inuser1; // STATE @@ -66,12 +66,12 @@ private: // METHODS void insertCast(AstNodeExpr* nodep, int needsize) { // We'll insert ABOVE passed node - UINFO(4, " NeedCast " << nodep << endl); VNRelinker relinkHandle; nodep->unlinkFrBack(&relinkHandle); // AstCCast* const castp = new AstCCast{nodep->fileline(), nodep, needsize, nodep->widthMin()}; + UINFO(4, " MadeCast " << static_cast(castp) << " for " << nodep << endl); relinkHandle.relink(castp); // if (debug() > 8) castp->dumpTree("- castins: "); // @@ -170,6 +170,10 @@ private: ensureLower32Cast(nodep); nodep->user1(1); } + void visit(AstExprStmt* nodep) override { + iterateChildren(nodep); + nodep->user1(1); + } void visit(AstNegate* nodep) override { iterateChildren(nodep); nodep->user1(nodep->lhsp()->user1()); diff --git a/src/V3Const.cpp b/src/V3Const.cpp index ea0e4bea6..087f4b3af 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1375,7 +1375,7 @@ private: AstNode* afterComment(AstNode* nodep) { // Ignore comments, such as to determine if a AstIf is empty. // nodep may be null, if so return null. - while (nodep && VN_IS(nodep, Comment)) { nodep = nodep->nextp(); } + while (nodep && VN_IS(nodep, Comment)) nodep = nodep->nextp(); return nodep; } diff --git a/test_regress/t/t_func_real_exprstmt.pl b/test_regress/t/t_func_real_exprstmt.pl new file mode 100755 index 000000000..859050d63 --- /dev/null +++ b/test_regress/t/t_func_real_exprstmt.pl @@ -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 2023 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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_func_real_exprstmt.v b/test_regress/t/t_func_real_exprstmt.v new file mode 100644 index 000000000..4df720960 --- /dev/null +++ b/test_regress/t/t_func_real_exprstmt.v @@ -0,0 +1,23 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder +// SPDX-License-Identifier: CC0-1.0 + +module t; + + function automatic real logWrapper(real x); + return $ln(x); + endfunction + + initial begin + // See bug4543 + $display("bad x=%f, y=%f", logWrapper(10.0), 1.0 * logWrapper(10.0)); + $display("noc x=%f, y=%f", $ln(10.0), 1.0 * $ln(10.0)); + if (logWrapper(10.0) != $ln(10.0)) $stop; + if (logWrapper(10.0) != 1.0 * logWrapper(10.0)) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From 0e0df1fb3b430b1fd964142e71eb8d444e9f9320 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 6 Oct 2023 22:38:46 -0400 Subject: [PATCH 045/157] Fix enum functions in localparams (#3999). --- Changes | 1 + src/V3AstNodeDType.h | 9 +++++++++ src/V3Width.cpp | 7 ++++--- src/V3WidthCommit.h | 7 ++++++- test_regress/t/t_enum_const_methods.v | 9 +++++++++ 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/Changes b/Changes index 2b3e63fac..a2b96cf76 100644 --- a/Changes +++ b/Changes @@ -19,6 +19,7 @@ Verilator 5.017 devel * Support resizing function call inout arguments (#4467). * Support converting parameters inside modules to localparams (#4511). [Anthony Donlon] * Fix conversion of impure logical expressions to bit expressions (#487 partial) (#4437). [Ryszard Rozak, Antmicro Ltd.] +* Fix enum functions in localparams (#3999). [Andrew Nolte] * Fix passing arguments by reference (#3385 partial) (#4489). [Ryszard Rozak, Antmicro Ltd.] * Fix multithreading handling to separate by code units that use/never use it (#4228). [Mariusz Glebocki, Antmicro Ltd.] * Fix usage of annotation options (#4486) (#4504). [Michal Czyz] diff --git a/src/V3AstNodeDType.h b/src/V3AstNodeDType.h index b8ee2c72e..e1353b9a1 100644 --- a/src/V3AstNodeDType.h +++ b/src/V3AstNodeDType.h @@ -754,10 +754,14 @@ class AstEnumDType final : public AstNodeDType { // Parents: TYPEDEF/MODULE // @astgen op1 := childDTypep : Optional[AstNodeDType] // @astgen op2 := itemsp : List[AstEnumItem] +public: + using TableMap = std::map; + private: string m_name; // Name from upper typedef, if any AstNodeDType* m_refDTypep = nullptr; // Elements are of this type after V3Width const int m_uniqueNum = 0; + TableMap m_tableMap; // Created table for V3Width only to remove duplicates public: AstEnumDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstEnumItem* itemsp) @@ -770,9 +774,12 @@ public: widthFromSub(subDTypep()); } ASTGEN_MEMBERS_AstEnumDType; + const char* broken() const override { BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) || (!m_refDTypep && childDTypep()))); + BROKEN_RTN(std::any_of(m_tableMap.begin(), m_tableMap.end(), + [](const auto& p) { return !p.second->brokeExists(); })); return nullptr; } void cloneRelink() override { @@ -809,6 +816,8 @@ public: return count; } bool isCompound() const override { return false; } + TableMap& tableMap() { return m_tableMap; } + const TableMap& tableMap() const { return m_tableMap; } }; class AstIfaceRefDType final : public AstNodeDType { // Reference to an interface, either for a port, or inside parent cell diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 1d6468001..7f7e8214f 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -7193,8 +7193,9 @@ private: } AstVar* enumVarp(AstEnumDType* nodep, VAttrType attrType, bool assoc, uint32_t msbdim) { // Return a variable table which has specified dimension properties for this variable - const auto pos = m_tableMap.find(std::make_pair(nodep, attrType)); - if (pos != m_tableMap.end()) return pos->second; + const auto& tableMapr = nodep->tableMap(); + const auto pos = tableMapr.find(attrType); + if (pos != tableMapr.end()) return pos->second; UINFO(9, "Construct Venumtab attr=" << attrType.ascii() << " assoc=" << assoc << " max=" << msbdim << " for " << nodep << endl); AstNodeDType* basep; @@ -7276,7 +7277,7 @@ private: } } userIterate(varp, nullptr); // May have already done $unit so must do this var - m_tableMap.emplace(std::make_pair(nodep, attrType), varp); + nodep->tableMap().emplace(attrType, varp); return varp; } diff --git a/src/V3WidthCommit.h b/src/V3WidthCommit.h index 959bde51b..ec538084c 100644 --- a/src/V3WidthCommit.h +++ b/src/V3WidthCommit.h @@ -184,13 +184,18 @@ private: nodep->replaceWith(nodep->lhsp()->unlinkFrBack()); VL_DO_DANGLING(pushDeletep(nodep), nodep); } - void visit(AstNodeDType* nodep) override { // + void visit(AstNodeDType* nodep) override { + // Note some specific dtypes have unique visitors visitIterateNodeDType(nodep); } void visit(AstNodeUOrStructDType* nodep) override { if (nodep->user1SetOnce()) return; // Process once visitIterateNodeDType(nodep); } + void visit(AstEnumDType* nodep) override { + nodep->tableMap().clear(); // Only needed up through V3Width process + visitIterateNodeDType(nodep); + } void visit(AstParamTypeDType* nodep) override { if (nodep->user1SetOnce()) return; // Process once visitIterateNodeDType(nodep); diff --git a/test_regress/t/t_enum_const_methods.v b/test_regress/t/t_enum_const_methods.v index e5ce9e979..547a19a02 100644 --- a/test_regress/t/t_enum_const_methods.v +++ b/test_regress/t/t_enum_const_methods.v @@ -36,11 +36,20 @@ module t (); localparam string e0_name = get_name(E0); + function automatic enm_t get_2(); + enm_t enm; + enm = E0; + return enm.next.next; + endfunction + + localparam enm_t enum_2 = get_2(); + initial begin if (enum_first != E0) $stop; if (enum_last != E2) $stop; if (enum_second != E1) $stop; if (e0_name != "E0") $stop; + if (enum_2 != E2) $stop; $write("*-* All Finished *-*\n"); $finish; end From e2343c03e07db2c40c6a7d71512220e36155f9d9 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 6 Oct 2023 23:18:26 -0400 Subject: [PATCH 046/157] Internals: Create V3WidthCommit from overly fat header. No functional change intended. --- src/CMakeLists.txt | 2 + src/Makefile_obj.in | 3 +- src/V3Width.cpp | 12 +-- src/V3Width.h | 2 - src/V3WidthCommit.cpp | 236 ++++++++++++++++++++++++++++++++++++++++++ src/V3WidthCommit.h | 235 +---------------------------------------- src/V3WidthRemove.h | 63 +++++++++++ src/Verilator.cpp | 3 +- 8 files changed, 312 insertions(+), 244 deletions(-) create mode 100644 src/V3WidthCommit.cpp create mode 100644 src/V3WidthRemove.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 393eba402..b2fbf9f4d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -166,6 +166,7 @@ set(HEADERS V3Waiver.h V3Width.h V3WidthCommit.h + V3WidthRemove.h VlcBucket.h VlcOptions.h VlcPoint.h @@ -298,6 +299,7 @@ set(COMMON_SOURCES V3VariableOrder.cpp V3Waiver.cpp V3Width.cpp + V3WidthCommit.cpp V3WidthSel.cpp V3ParseImp.cpp V3ParseGrammar.cpp diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index b076f1a2a..36ae799bb 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -278,6 +278,7 @@ RAW_OBJS = \ V3VariableOrder.o \ V3Waiver.o \ V3Width.o \ + V3WidthCommit.o \ V3WidthSel.o \ # verilator_coverage @@ -291,7 +292,7 @@ NON_STANDALONE_HEADERS = \ V3AstNodeOther.h \ V3DfgVertices.h \ V3ThreadPool.h \ - V3WidthCommit.h \ + V3WidthRemove.h \ AST_DEFS := \ V3AstNodeDType.h \ diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 7f7e8214f..b87fe81e4 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -77,12 +77,13 @@ #include "V3Randomize.h" #include "V3String.h" #include "V3Task.h" +#include "V3WidthCommit.h" #include // More code; this file was getting too large; see actions there #define VERILATOR_V3WIDTH_CPP_ -#include "V3WidthCommit.h" +#include "V3WidthRemove.h" VL_DEFINE_DEBUG_FUNCTIONS; @@ -4311,8 +4312,7 @@ private: if (VN_IS(valuep, Const)) { // Forming a AstConcat will cause problems with // unsized (uncommitted sized) constants - if (AstConst* const newp - = WidthCommitVisitor::newIfConstCommitSize(VN_AS(valuep, Const))) { + if (AstConst* const newp = V3WidthCommit::newIfConstCommitSize(VN_AS(valuep, Const))) { VL_DO_DANGLING(pushDeletep(valuep), valuep); valuep = newp; } @@ -7614,9 +7614,3 @@ AstNode* V3Width::widthGenerateParamsEdit( // No WidthRemoveVisitor, as don't want to drop $signed etc inside gen blocks return nodep; } - -void V3Width::widthCommit(AstNetlist* nodep) { - UINFO(2, __FUNCTION__ << ": " << endl); - { WidthCommitVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("widthcommit", 0, dumpTreeLevel() >= 6); -} diff --git a/src/V3Width.h b/src/V3Width.h index 29021146f..fd9f17af5 100644 --- a/src/V3Width.h +++ b/src/V3Width.h @@ -33,8 +33,6 @@ public: static void width(AstNetlist* nodep) VL_MT_DISABLED; static AstNode* widthParamsEdit(AstNode* nodep) VL_MT_DISABLED; static AstNode* widthGenerateParamsEdit(AstNode* nodep) VL_MT_DISABLED; - // Final step... Mark all widths as equal - static void widthCommit(AstNetlist* nodep) VL_MT_DISABLED; static AstNodeDType* getCommonClassTypep(AstNode* nodep1, AstNode* nodep2) VL_MT_DISABLED; diff --git a/src/V3WidthCommit.cpp b/src/V3WidthCommit.cpp new file mode 100644 index 000000000..295d3be8d --- /dev/null +++ b/src/V3WidthCommit.cpp @@ -0,0 +1,236 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Commit expression widths +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2023 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 +// +//************************************************************************* +// +// Remove all $signed, $unsigned, we're done with them. +// +// This step is only called on real V3Width, not intermediate e.g. widthParams +// +//************************************************************************* + +#define VL_MT_DISABLED_CODE_UNIT 1 + +#include "config_build.h" +#include "verilatedos.h" + +#include "V3WidthCommit.h" + +VL_DEFINE_DEBUG_FUNCTIONS; + +//###################################################################### +// Now that all widthing is complete, +// Copy all width() to widthMin(). V3Const expects this + +class WidthCommitVisitor final : public VNVisitor { + // NODE STATE + // AstVar::user1p -> bool, processed + const VNUser1InUse m_inuser1; + + // STATE + AstNodeModule* m_modp = nullptr; + +public: + // METHODS + VL_DEFINE_DEBUG_FUNCTIONS; + +private: + // METHODS + void editDType(AstNode* nodep) { + // Edit dtypes for this node + nodep->dtypep(editOneDType(nodep->dtypep())); + } + AstNodeDType* editOneDType(AstNodeDType* nodep) { + // See if the dtype/refDType can be converted to a standard one + // This reduces the number of dtypes in the system, and since + // dtypep() figures into sameTree() results in better optimizations + if (!nodep) return nullptr; + // Recurse to handle the data type, as may change the size etc of this type + if (!nodep->user1()) iterate(nodep); + // Look for duplicate + if (AstBasicDType* const bdtypep = VN_CAST(nodep, BasicDType)) { + AstBasicDType* const newp = nodep->findInsertSameDType(bdtypep); + if (newp != bdtypep && debug() >= 9) { + UINFO(9, "dtype replacement "); + nodep->dumpSmall(std::cout); + std::cout << " ----> "; + newp->dumpSmall(std::cout); + std::cout << std::endl; + } + return newp; + } + return nodep; + } + void classEncapCheck(AstNode* nodep, AstNode* defp, AstClass* defClassp) { + // Call on non-local class to check local/protected status and complain + bool local = false; + bool prot = false; + if (const auto varp = VN_CAST(defp, Var)) { + local = varp->isHideLocal(); + prot = varp->isHideProtected(); + } else if (const auto ftaskp = VN_CAST(defp, NodeFTask)) { + local = ftaskp->isHideLocal(); + prot = ftaskp->isHideProtected(); + } else { + nodep->v3fatalSrc("ref to unhandled definition type " << defp->prettyTypeName()); + } + if (local || prot) { + const auto refClassp = VN_CAST(m_modp, Class); + const char* how = nullptr; + if (local && defClassp && refClassp != defClassp) { + how = "'local'"; + } else if (prot && defClassp && !AstClass::isClassExtendedFrom(refClassp, defClassp)) { + how = "'protected'"; + } + if (how) { + UINFO(9, "refclass " << refClassp << endl); + UINFO(9, "defclass " << defClassp << endl); + nodep->v3warn(ENCAPSULATED, nodep->prettyNameQ() + << " is hidden as " << how + << " within this context (IEEE 1800-2017 8.18)\n" + << nodep->warnContextPrimary() << endl + << nodep->warnOther() + << "... Location of definition" << endl + << defp->warnContextSecondary()); + } + } + } + + // VISITORS + void visit(AstNodeModule* nodep) override { + VL_RESTORER(m_modp); + { + m_modp = nodep; + iterateChildren(nodep); + editDType(nodep); + } + } + void visit(AstConst* nodep) override { + if (nodep->user1SetOnce()) return; // Process once + UASSERT_OBJ(nodep->dtypep(), nodep, "No dtype"); + iterate(nodep->dtypep()); // Do datatype first + if (AstConst* const newp = V3WidthCommit::newIfConstCommitSize(nodep)) { + nodep->replaceWith(newp); + AstNode* const oldp = nodep; + nodep = newp; + // if (debug() > 4) oldp->dumpTree("- fixConstSize_old: "); + // if (debug() > 4) newp->dumpTree("- _new: "); + VL_DO_DANGLING(pushDeletep(oldp), oldp); + } + editDType(nodep); + } + void visit(AstCastWrap* nodep) override { + iterateChildren(nodep); + editDType(nodep); + UINFO(6, " Replace " << nodep << " w/ " << nodep->lhsp() << endl); + nodep->replaceWith(nodep->lhsp()->unlinkFrBack()); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } + void visit(AstNodeDType* nodep) override { + // Note some specific dtypes have unique visitors + visitIterateNodeDType(nodep); + } + void visit(AstNodeUOrStructDType* nodep) override { + if (nodep->user1SetOnce()) return; // Process once + visitIterateNodeDType(nodep); + } + void visit(AstEnumDType* nodep) override { + nodep->tableMap().clear(); // Only needed up through V3Width process + visitIterateNodeDType(nodep); + } + void visit(AstParamTypeDType* nodep) override { + if (nodep->user1SetOnce()) return; // Process once + visitIterateNodeDType(nodep); + // Move to type table as all dtype pointers must resolve there + nodep->unlinkFrBack(); // Make non-child + v3Global.rootp()->typeTablep()->addTypesp(nodep); + } + void visitIterateNodeDType(AstNodeDType* nodep) { + // Rather than use dtypeChg which may make new nodes, we edit in place, + // as we don't need to preserve any widthMin's, and every dtype with the same width + // gets an identical edit. + if (nodep->user1SetOnce()) return; // Process once + nodep->widthMinFromWidth(); + // Too late to any unspecified sign to be anything but unsigned + if (nodep->numeric().isNosign()) nodep->numeric(VSigning::UNSIGNED); + iterateChildren(nodep); + nodep->virtRefDTypep(editOneDType(nodep->virtRefDTypep())); + nodep->virtRefDType2p(editOneDType(nodep->virtRefDType2p())); + } + void visit(AstNodeFTask* nodep) override { + iterateChildren(nodep); + editDType(nodep); + AstClass* classp = VN_CAST(m_modp, Class); + if (nodep->classMethod() && nodep->pureVirtual() && classp && !classp->isInterfaceClass() + && !classp->isVirtual()) { + nodep->v3error( + "Illegal to have 'pure virtual' in non-virtual class (IEEE 1800-2017 8.21)"); + } + } + void visit(AstNodeVarRef* nodep) override { + iterateChildren(nodep); + editDType(nodep); + classEncapCheck(nodep, nodep->varp(), VN_CAST(nodep->classOrPackagep(), Class)); + } + void visit(AstNodeFTaskRef* nodep) override { + iterateChildren(nodep); + editDType(nodep); + classEncapCheck(nodep, nodep->taskp(), VN_CAST(nodep->classOrPackagep(), Class)); + } + void visit(AstMemberSel* nodep) override { + iterateChildren(nodep); + editDType(nodep); + if (auto* const classrefp = VN_CAST(nodep->fromp()->dtypep(), ClassRefDType)) { + classEncapCheck(nodep, nodep->varp(), classrefp->classp()); + } // else might be struct, etc + } + void visit(AstVar* nodep) override { + iterateChildren(nodep); + editDType(nodep); + if (nodep->isFuncLocal() && nodep->direction() == VDirection::INPUT && nodep->valuep()) { + // It's the default value of optional argument. + // Such values are added to function calls in V3Width so can be removed now + pushDeletep(nodep->valuep()->unlinkFrBack()); + } + } + void visit(AstNodePreSel* nodep) override { // LCOV_EXCL_LINE + // This check could go anywhere after V3Param + nodep->v3fatalSrc("Presels should have been removed before this point"); + } + void visit(AstNode* nodep) override { + iterateChildren(nodep); + editDType(nodep); + } + +public: + // CONSTRUCTORS + explicit WidthCommitVisitor(AstNetlist* nodep) { + // Were changing widthMin's, so the table is now somewhat trashed + nodep->typeTablep()->clearCache(); + iterate(nodep); + // Don't want to AstTypeTable::repairCache, as all needed nodes + // have been added back in; a repair would prevent dead nodes from + // being detected + } + ~WidthCommitVisitor() override = default; +}; + +//###################################################################### +// V3WidthCommit class functions + +void V3WidthCommit::widthCommit(AstNetlist* nodep) { + UINFO(2, __FUNCTION__ << ": " << endl); + { WidthCommitVisitor{nodep}; } // Destruct before checking + V3Global::dumpCheckGlobalTree("widthcommit", 0, dumpTreeLevel() >= 6); +} diff --git a/src/V3WidthCommit.h b/src/V3WidthCommit.h index ec538084c..4c61e0da8 100644 --- a/src/V3WidthCommit.h +++ b/src/V3WidthCommit.h @@ -23,60 +23,10 @@ #include "V3Ast.h" #include "V3Error.h" -// clang-format off -#ifndef VERILATOR_V3WIDTH_CPP_ -# error "V3WidthCommit for V3Width internal use only" -#endif -// clang-format on - -//###################################################################### - -/// Remove all $signed, $unsigned, we're done with them. -/// This step is only called on real V3Width, not intermediate e.g. widthParams - -class WidthRemoveVisitor final : public VNVisitor { - // METHODS - VL_DEFINE_DEBUG_FUNCTIONS; - - void replaceWithSignedVersion(AstNode* nodep, AstNode* newp) { - UINFO(6, " Replace " << nodep << " w/ " << newp << endl); - nodep->replaceWith(newp); - newp->dtypeFrom(nodep); - VL_DO_DANGLING(pushDeletep(nodep), nodep); - } - - // VISITORS - void visit(AstSigned* nodep) override { - VL_DO_DANGLING(replaceWithSignedVersion(nodep, nodep->lhsp()->unlinkFrBack()), nodep); - } - void visit(AstUnsigned* nodep) override { - VL_DO_DANGLING(replaceWithSignedVersion(nodep, nodep->lhsp()->unlinkFrBack()), nodep); - } - void visit(AstNode* nodep) override { iterateChildren(nodep); } +//============================================================================ +class V3WidthCommit final { public: - // CONSTRUCTORS - WidthRemoveVisitor() = default; - ~WidthRemoveVisitor() override = default; - AstNode* mainAcceptEdit(AstNode* nodep) { return iterateSubtreeReturnEdits(nodep); } -}; - -//###################################################################### -// Now that all widthing is complete, -// Copy all width() to widthMin(). V3Const expects this - -class WidthCommitVisitor final : public VNVisitor { - // NODE STATE - // AstVar::user1p -> bool, processed - const VNUser1InUse m_inuser1; - - // STATE - AstNodeModule* m_modp = nullptr; - -public: - // METHODS - VL_DEFINE_DEBUG_FUNCTIONS; - static AstConst* newIfConstCommitSize(AstConst* nodep) { if (((nodep->dtypep()->width() != nodep->num().width()) || !nodep->num().sized()) && !nodep->num().isString()) { // Need to force the number from unsized to sized @@ -92,185 +42,8 @@ public: } } -private: - // METHODS - void editDType(AstNode* nodep) { - // Edit dtypes for this node - nodep->dtypep(editOneDType(nodep->dtypep())); - } - AstNodeDType* editOneDType(AstNodeDType* nodep) { - // See if the dtype/refDType can be converted to a standard one - // This reduces the number of dtypes in the system, and since - // dtypep() figures into sameTree() results in better optimizations - if (!nodep) return nullptr; - // Recurse to handle the data type, as may change the size etc of this type - if (!nodep->user1()) iterate(nodep); - // Look for duplicate - if (AstBasicDType* const bdtypep = VN_CAST(nodep, BasicDType)) { - AstBasicDType* const newp = nodep->findInsertSameDType(bdtypep); - if (newp != bdtypep && debug() >= 9) { - UINFO(9, "dtype replacement "); - nodep->dumpSmall(std::cout); - std::cout << " ----> "; - newp->dumpSmall(std::cout); - std::cout << std::endl; - } - return newp; - } - return nodep; - } - void classEncapCheck(AstNode* nodep, AstNode* defp, AstClass* defClassp) { - // Call on non-local class to check local/protected status and complain - bool local = false; - bool prot = false; - if (const auto varp = VN_CAST(defp, Var)) { - local = varp->isHideLocal(); - prot = varp->isHideProtected(); - } else if (const auto ftaskp = VN_CAST(defp, NodeFTask)) { - local = ftaskp->isHideLocal(); - prot = ftaskp->isHideProtected(); - } else { - nodep->v3fatalSrc("ref to unhandled definition type " << defp->prettyTypeName()); - } - if (local || prot) { - const auto refClassp = VN_CAST(m_modp, Class); - const char* how = nullptr; - if (local && defClassp && refClassp != defClassp) { - how = "'local'"; - } else if (prot && defClassp && !AstClass::isClassExtendedFrom(refClassp, defClassp)) { - how = "'protected'"; - } - if (how) { - UINFO(9, "refclass " << refClassp << endl); - UINFO(9, "defclass " << defClassp << endl); - nodep->v3warn(ENCAPSULATED, nodep->prettyNameQ() - << " is hidden as " << how - << " within this context (IEEE 1800-2017 8.18)\n" - << nodep->warnContextPrimary() << endl - << nodep->warnOther() - << "... Location of definition" << endl - << defp->warnContextSecondary()); - } - } - } - - // VISITORS - void visit(AstNodeModule* nodep) override { - VL_RESTORER(m_modp); - { - m_modp = nodep; - iterateChildren(nodep); - editDType(nodep); - } - } - void visit(AstConst* nodep) override { - if (nodep->user1SetOnce()) return; // Process once - UASSERT_OBJ(nodep->dtypep(), nodep, "No dtype"); - iterate(nodep->dtypep()); // Do datatype first - if (AstConst* const newp = newIfConstCommitSize(nodep)) { - nodep->replaceWith(newp); - AstNode* const oldp = nodep; - nodep = newp; - // if (debug() > 4) oldp->dumpTree("- fixConstSize_old: "); - // if (debug() > 4) newp->dumpTree("- _new: "); - VL_DO_DANGLING(pushDeletep(oldp), oldp); - } - editDType(nodep); - } - void visit(AstCastWrap* nodep) override { - iterateChildren(nodep); - editDType(nodep); - UINFO(6, " Replace " << nodep << " w/ " << nodep->lhsp() << endl); - nodep->replaceWith(nodep->lhsp()->unlinkFrBack()); - VL_DO_DANGLING(pushDeletep(nodep), nodep); - } - void visit(AstNodeDType* nodep) override { - // Note some specific dtypes have unique visitors - visitIterateNodeDType(nodep); - } - void visit(AstNodeUOrStructDType* nodep) override { - if (nodep->user1SetOnce()) return; // Process once - visitIterateNodeDType(nodep); - } - void visit(AstEnumDType* nodep) override { - nodep->tableMap().clear(); // Only needed up through V3Width process - visitIterateNodeDType(nodep); - } - void visit(AstParamTypeDType* nodep) override { - if (nodep->user1SetOnce()) return; // Process once - visitIterateNodeDType(nodep); - // Move to type table as all dtype pointers must resolve there - nodep->unlinkFrBack(); // Make non-child - v3Global.rootp()->typeTablep()->addTypesp(nodep); - } - void visitIterateNodeDType(AstNodeDType* nodep) { - // Rather than use dtypeChg which may make new nodes, we edit in place, - // as we don't need to preserve any widthMin's, and every dtype with the same width - // gets an identical edit. - if (nodep->user1SetOnce()) return; // Process once - nodep->widthMinFromWidth(); - // Too late to any unspecified sign to be anything but unsigned - if (nodep->numeric().isNosign()) nodep->numeric(VSigning::UNSIGNED); - iterateChildren(nodep); - nodep->virtRefDTypep(editOneDType(nodep->virtRefDTypep())); - nodep->virtRefDType2p(editOneDType(nodep->virtRefDType2p())); - } - void visit(AstNodeFTask* nodep) override { - iterateChildren(nodep); - editDType(nodep); - AstClass* classp = VN_CAST(m_modp, Class); - if (nodep->classMethod() && nodep->pureVirtual() && classp && !classp->isInterfaceClass() - && !classp->isVirtual()) { - nodep->v3error( - "Illegal to have 'pure virtual' in non-virtual class (IEEE 1800-2017 8.21)"); - } - } - void visit(AstNodeVarRef* nodep) override { - iterateChildren(nodep); - editDType(nodep); - classEncapCheck(nodep, nodep->varp(), VN_CAST(nodep->classOrPackagep(), Class)); - } - void visit(AstNodeFTaskRef* nodep) override { - iterateChildren(nodep); - editDType(nodep); - classEncapCheck(nodep, nodep->taskp(), VN_CAST(nodep->classOrPackagep(), Class)); - } - void visit(AstMemberSel* nodep) override { - iterateChildren(nodep); - editDType(nodep); - if (auto* const classrefp = VN_CAST(nodep->fromp()->dtypep(), ClassRefDType)) { - classEncapCheck(nodep, nodep->varp(), classrefp->classp()); - } // else might be struct, etc - } - void visit(AstVar* nodep) override { - iterateChildren(nodep); - editDType(nodep); - if (nodep->isFuncLocal() && nodep->direction() == VDirection::INPUT && nodep->valuep()) { - // It's the default value of optional argument. - // Such values are added to function calls in V3Width so can be removed now - pushDeletep(nodep->valuep()->unlinkFrBack()); - } - } - void visit(AstNodePreSel* nodep) override { // LCOV_EXCL_LINE - // This check could go anywhere after V3Param - nodep->v3fatalSrc("Presels should have been removed before this point"); - } - void visit(AstNode* nodep) override { - iterateChildren(nodep); - editDType(nodep); - } - -public: - // CONSTRUCTORS - explicit WidthCommitVisitor(AstNetlist* nodep) { - // Were changing widthMin's, so the table is now somewhat trashed - nodep->typeTablep()->clearCache(); - iterate(nodep); - // Don't want to AstTypeTable::repairCache, as all needed nodes - // have been added back in; a repair would prevent dead nodes from - // being detected - } - ~WidthCommitVisitor() override = default; + // Final step... Mark all widths as equal + static void widthCommit(AstNetlist* nodep) VL_MT_DISABLED; }; //###################################################################### diff --git a/src/V3WidthRemove.h b/src/V3WidthRemove.h new file mode 100644 index 000000000..23469299e --- /dev/null +++ b/src/V3WidthRemove.h @@ -0,0 +1,63 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Cleanup stage in V3Width +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2023 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 +// +//************************************************************************* + +#ifndef VERILATOR_V3WIDTHREMOVE_H_ +#define VERILATOR_V3WIDTHREMOVE_H_ + +#include "config_build.h" +#include "verilatedos.h" + +#include "V3Ast.h" +#include "V3Error.h" + +// clang-format off +#ifndef VERILATOR_V3WIDTH_CPP_ +# error "V3WidthRemove for V3Width internal use only" +#endif +// clang-format on + +//###################################################################### + +class WidthRemoveVisitor final : public VNVisitor { + // METHODS + VL_DEFINE_DEBUG_FUNCTIONS; + + void replaceWithSignedVersion(AstNode* nodep, AstNode* newp) { + UINFO(6, " Replace " << nodep << " w/ " << newp << endl); + nodep->replaceWith(newp); + newp->dtypeFrom(nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } + + // VISITORS + void visit(AstSigned* nodep) override { + VL_DO_DANGLING(replaceWithSignedVersion(nodep, nodep->lhsp()->unlinkFrBack()), nodep); + } + void visit(AstUnsigned* nodep) override { + VL_DO_DANGLING(replaceWithSignedVersion(nodep, nodep->lhsp()->unlinkFrBack()), nodep); + } + void visit(AstNode* nodep) override { iterateChildren(nodep); } + +public: + // CONSTRUCTORS + WidthRemoveVisitor() = default; + ~WidthRemoveVisitor() override = default; + AstNode* mainAcceptEdit(AstNode* nodep) { return iterateSubtreeReturnEdits(nodep); } +}; + +//###################################################################### + +#endif // Guard diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 99af25820..e5ba41c55 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -104,6 +104,7 @@ #include "V3VariableOrder.h" #include "V3Waiver.h" #include "V3Width.h" +#include "V3WidthCommit.h" #include @@ -189,7 +190,7 @@ static void process() { V3Error::abortIfErrors(); // Commit to the widths we've chosen; Make widthMin==width - V3Width::widthCommit(v3Global.rootp()); + V3WidthCommit::widthCommit(v3Global.rootp()); v3Global.assertDTypesResolved(true); v3Global.widthMinUsage(VWidthMinUsage::MATCHES_WIDTH); From 1d3d59243c321e14f9672d4dc04af147bbf656b0 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 7 Oct 2023 14:29:46 -0400 Subject: [PATCH 047/157] Fix preprocessor to show `line 2 on resumed file per IEEE. --- Changes | 1 + src/V3PreLex.l | 4 ++-- test_regress/t/t_lint_eofline.out | 2 +- test_regress/t/t_pipe_filter.out | 10 +++++----- test_regress/t/t_pp_pragma_bad.out | 2 +- test_regress/t/t_preproc.out | 18 +++++++++--------- test_regress/t/t_preproc_comments.out | 18 +++++++++--------- test_regress/t/t_preproc_def09.out | 2 +- 8 files changed, 29 insertions(+), 28 deletions(-) diff --git a/Changes b/Changes index a2b96cf76..64c4f6832 100644 --- a/Changes +++ b/Changes @@ -33,6 +33,7 @@ Verilator 5.017 devel * Fix 'this' in a constructor (#4533). [Ryszard Rozak, Antmicro Ltd.] * Fix stream shift operator of 32 bits (#4536). [Julien Faucher] * Fix inlining of real functions miscasting (#4543). [Andrew Nolte] +* Fix preprocessor to show `line 2 on resumed file. Verilator 5.016 2023-09-16 diff --git a/src/V3PreLex.l b/src/V3PreLex.l index 9c84b9ed5..3209aa8bf 100644 --- a/src/V3PreLex.l +++ b/src/V3PreLex.l @@ -583,7 +583,7 @@ string V3PreLex::endOfStream(bool& againr) { } else if (curStreamp()->m_termState == 2) { // Now ending `line curStreamp()->m_termState = 3; - return curFilelinep()->lineDirectiveStrg(2); // Exit old file + return curFilelinep()->lineDirectiveStrg(0); // THe "2" exit is below } else { // Final shutdown phase for a stream, we can finally change the // current fileline to the new stream @@ -603,7 +603,7 @@ string V3PreLex::endOfStream(bool& againr) { if (curStreamp()->m_eof) { return ""; } else { - return curFilelinep()->lineDirectiveStrg(0); // Reenter resumed file + return curFilelinep()->lineDirectiveStrg(2); // Reenter resumed file } } } diff --git a/test_regress/t/t_lint_eofline.out b/test_regress/t/t_lint_eofline.out index d4f4a5251..3de26aff4 100644 --- a/test_regress/t/t_lint_eofline.out +++ b/test_regress/t/t_lint_eofline.out @@ -1,3 +1,3 @@ `line 1 "obj_vlt/t_lint_eofline/t_lint_eofline_bad.v" 1 -`line 2 "obj_vlt/t_lint_eofline/t_lint_eofline_bad.v" 2 +`line 2 "obj_vlt/t_lint_eofline/t_lint_eofline_bad.v" 0 diff --git a/test_regress/t/t_pipe_filter.out b/test_regress/t/t_pipe_filter.out index 60d00f061..77571bb19 100644 --- a/test_regress/t/t_pipe_filter.out +++ b/test_regress/t/t_pipe_filter.out @@ -35,8 +35,8 @@ inc line 7; inc line 8; inc line 9; -`line 14 "t/t_pipe_filter_inc.vh" 2 -`line 14 "t/t_pipe_filter.v" 0 +`line 14 "t/t_pipe_filter_inc.vh" 0 +`line 14 "t/t_pipe_filter.v" 2 `line 15 "t/t_pipe_filter.v" 0 @@ -59,12 +59,12 @@ inc line 7; inc line 8; inc line 9; -`line 14 "t/t_pipe_filter_inc.vh" 2 -`line 16 "t/t_pipe_filter.v" 0 +`line 14 "t/t_pipe_filter_inc.vh" 0 +`line 16 "t/t_pipe_filter.v" 2 `line 18 "t/t_pipe_filter.v" 0 example line 15; example line 16; -`line 21 "t/t_pipe_filter.v" 2 +`line 21 "t/t_pipe_filter.v" 0 diff --git a/test_regress/t/t_pp_pragma_bad.out b/test_regress/t/t_pp_pragma_bad.out index 713607531..7e36d642b 100644 --- a/test_regress/t/t_pp_pragma_bad.out +++ b/test_regress/t/t_pp_pragma_bad.out @@ -13,5 +13,5 @@ `line 7 "t/t_pp_pragma_bad.v" 0 `pragma -`line 9 "t/t_pp_pragma_bad.v" 2 +`line 9 "t/t_pp_pragma_bad.v" 0 %Error: Exiting due to diff --git a/test_regress/t/t_preproc.out b/test_regress/t/t_preproc.out index 6e09e8fcd..83cefad3a 100644 --- a/test_regress/t/t_preproc.out +++ b/test_regress/t/t_preproc.out @@ -50,12 +50,12 @@ At file "t/t_preproc_inc2.vh" line 5 -`line 110 "inc3_a_filename_from_line_directive" 2 -`line 7 "t/t_preproc_inc2.vh" 0 +`line 110 "inc3_a_filename_from_line_directive" 0 +`line 7 "t/t_preproc_inc2.vh" 2 -`line 9 "t/t_preproc_inc2.vh" 2 -`line 10 "t/t_preproc.v" 0 +`line 9 "t/t_preproc_inc2.vh" 0 +`line 10 "t/t_preproc.v" 2 `line 12 "t/t_preproc.v" 0 @@ -372,8 +372,8 @@ begin addr <= ({regs[6], regs[7]}); wdata <= (rdata); wr <= 1; end more `line 6 "t/t_preproc_inc4.vh" 0 -`line 8 "t/t_preproc_inc4.vh" 2 -`line 236 "t/t_preproc.v" 0 +`line 8 "t/t_preproc_inc4.vh" 0 +`line 236 "t/t_preproc.v" 2 `line 237 "t/t_preproc.v" 0 @@ -701,8 +701,8 @@ hello4hello4hello4hello4 `line 6 "t/t_preproc_inc4.vh" 0 -`line 8 "t/t_preproc_inc4.vh" 2 -`line 444 "t/t_preproc.v" 0 +`line 8 "t/t_preproc_inc4.vh" 0 +`line 444 "t/t_preproc.v" 2 `line 445 "t/t_preproc.v" 0 @@ -1045,4 +1045,4 @@ predef 2 2 -`line 729 "t/t_preproc.v" 2 +`line 729 "t/t_preproc.v" 0 diff --git a/test_regress/t/t_preproc_comments.out b/test_regress/t/t_preproc_comments.out index ba69fa2c0..8b01ff8bf 100644 --- a/test_regress/t/t_preproc_comments.out +++ b/test_regress/t/t_preproc_comments.out @@ -50,12 +50,12 @@ At file "t/t_preproc_inc2.vh" line 5 -`line 110 "inc3_a_filename_from_line_directive" 2 -`line 7 "t/t_preproc_inc2.vh" 0 +`line 110 "inc3_a_filename_from_line_directive" 0 +`line 7 "t/t_preproc_inc2.vh" 2 -`line 9 "t/t_preproc_inc2.vh" 2 -`line 10 "t/t_preproc.v" 0 +`line 9 "t/t_preproc_inc2.vh" 0 +`line 10 "t/t_preproc.v" 2 `line 12 "t/t_preproc.v" 0 @@ -372,8 +372,8 @@ begin addr <= ({regs[6], regs[7]}); wdata <= (rdata); wr <= 1; end more `line 6 "t/t_preproc_inc4.vh" 0 -`line 8 "t/t_preproc_inc4.vh" 2 -`line 236 "t/t_preproc.v" 0 +`line 8 "t/t_preproc_inc4.vh" 0 +`line 236 "t/t_preproc.v" 2 `line 237 "t/t_preproc.v" 0 @@ -706,8 +706,8 @@ hello4hello4hello4hello4 `line 6 "t/t_preproc_inc4.vh" 0 -`line 8 "t/t_preproc_inc4.vh" 2 -`line 444 "t/t_preproc.v" 0 +`line 8 "t/t_preproc_inc4.vh" 0 +`line 444 "t/t_preproc.v" 2 `line 445 "t/t_preproc.v" 0 @@ -1050,4 +1050,4 @@ predef 2 2 // After `undefineall above, for testing --dump-defines -`line 729 "t/t_preproc.v" 2 +`line 729 "t/t_preproc.v" 0 diff --git a/test_regress/t/t_preproc_def09.out b/test_regress/t/t_preproc_def09.out index 1958e614e..f6abcc305 100644 --- a/test_regress/t/t_preproc_def09.out +++ b/test_regress/t/t_preproc_def09.out @@ -84,4 +84,4 @@ HERE-72 - Line71 `line 74 "t/t_preproc_def09.v" 0 -`line 76 "t/t_preproc_def09.v" 2 +`line 76 "t/t_preproc_def09.v" 0 From 7f38414276e359c768351e1a2e293fd845eb44f1 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 8 Oct 2023 01:02:23 -0400 Subject: [PATCH 048/157] Internals: Rename addIgnoreMatch. No functional change. --- docs/guide/warnings.rst | 7 ++++--- src/V3Config.cpp | 10 +++++----- src/V3Config.h | 2 +- src/verilog.y | 10 +++++----- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst index b7cf29a81..48c0888f9 100644 --- a/docs/guide/warnings.rst +++ b/docs/guide/warnings.rst @@ -2046,17 +2046,18 @@ List Of Warnings .. include:: ../../docs/gen/ex_WIDTHEXPAND_1_fixed.rst + .. option:: WIDTHTRUNC - A more granular WIDTH warning, for when a value is truncated + A more granular WIDTH warning, for when a value is truncated. .. option:: WIDTHEXPAND - A more granular WIDTH warning, for when a value is zero expanded + A more granular WIDTH warning, for when a value is zero expanded. .. option:: WIDTHXZEXPAND - A more granular WIDTH warning, for when a value is X/Z expanded + A more granular WIDTH warning, for when a value is X/Z expanded. .. option:: WIDTHCONCAT diff --git a/src/V3Config.cpp b/src/V3Config.cpp index de968acab..a221f92e8 100644 --- a/src/V3Config.cpp +++ b/src/V3Config.cpp @@ -303,7 +303,7 @@ public: m_ignLines.insert(V3ConfigIgnoresLine{code, lineno, on}); m_lastIgnore.it = m_ignLines.begin(); } - void addWaiver(V3ErrorCode code, const string& match) { + void addIgnoreMatch(V3ErrorCode code, const string& match) { m_waivers.push_back(std::make_pair(code, match)); } @@ -518,6 +518,10 @@ void V3Config::addIgnore(V3ErrorCode code, bool on, const string& filename, int } } +void V3Config::addIgnoreMatch(V3ErrorCode code, const string& filename, const string& match) { + V3ConfigResolver::s().files().at(filename).addIgnoreMatch(code, match); +} + void V3Config::addInline(FileLine* fl, const string& module, const string& ftask, bool on) { if (ftask.empty()) { V3ConfigResolver::s().modules().at(module).setInline(on); @@ -590,10 +594,6 @@ void V3Config::addVarAttr(FileLine* fl, const string& module, const string& ftas } } -void V3Config::addWaiver(V3ErrorCode code, const string& filename, const string& match) { - V3ConfigResolver::s().files().at(filename).addWaiver(code, match); -} - void V3Config::applyCase(AstCase* nodep) { const string& filename = nodep->fileline()->filename(); V3ConfigFile* filep = V3ConfigResolver::s().files().resolve(filename); diff --git a/src/V3Config.h b/src/V3Config.h index bee0ea59e..6b49a0997 100644 --- a/src/V3Config.h +++ b/src/V3Config.h @@ -34,6 +34,7 @@ public: static void addCoverageBlockOff(const string& file, int lineno); static void addCoverageBlockOff(const string& module, const string& blockname); static void addIgnore(V3ErrorCode code, bool on, const string& filename, int min, int max); + static void addIgnoreMatch(V3ErrorCode code, const string& filename, const string& match); static void addInline(FileLine* fl, const string& module, const string& ftask, bool on); static void addModulePragma(const string& module, VPragmaType pragma); static void addProfileData(FileLine* fl, const string& model, const string& key, @@ -41,7 +42,6 @@ public: static void addScopeTraceOn(bool on, const string& scope, int levels); static void addVarAttr(FileLine* fl, const string& module, const string& ftask, const string& signal, VAttrType type, AstSenTree* nodep); - static void addWaiver(V3ErrorCode code, const string& filename, const string& match); static void applyCase(AstCase* nodep); static void applyCoverageBlock(AstNodeModule* modulep, AstBegin* nodep); diff --git a/src/verilog.y b/src/verilog.y index fd0c18ca9..31581e891 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -7213,9 +7213,9 @@ vltItem: | vltOffFront yVLT_D_FILE yaSTRING { V3Config::addIgnore($1, false, *$3, 0, 0); } | vltOffFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM - { V3Config::addIgnore($1, false, *$3, $5->toUInt(), $5->toUInt()+1); } + { V3Config::addIgnore($1, false, *$3, $5->toUInt(), $5->toUInt() + 1); } | vltOffFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM '-' yaINTNUM - { V3Config::addIgnore($1, false, *$3, $5->toUInt(), $7->toUInt()+1); } + { V3Config::addIgnore($1, false, *$3, $5->toUInt(), $7->toUInt() + 1); } | vltOffFront yVLT_D_SCOPE yaSTRING { if ($1 != V3ErrorCode::I_TRACING) { $1->v3error("Argument -scope only supported for tracing_on/off"); @@ -7232,16 +7232,16 @@ vltItem: { if (($1 == V3ErrorCode::I_COVERAGE) || ($1 == V3ErrorCode::I_TRACING)) { $1->v3error("Argument -match only supported for lint_off"); } else { - V3Config::addWaiver($1, *$3, *$5); + V3Config::addIgnoreMatch($1, *$3, *$5); }} | vltOnFront { V3Config::addIgnore($1, true, "*", 0, 0); } | vltOnFront yVLT_D_FILE yaSTRING { V3Config::addIgnore($1, true, *$3, 0, 0); } | vltOnFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM - { V3Config::addIgnore($1, true, *$3, $5->toUInt(), $5->toUInt()+1); } + { V3Config::addIgnore($1, true, *$3, $5->toUInt(), $5->toUInt() + 1); } | vltOnFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM '-' yaINTNUM - { V3Config::addIgnore($1, true, *$3, $5->toUInt(), $7->toUInt()+1); } + { V3Config::addIgnore($1, true, *$3, $5->toUInt(), $7->toUInt() + 1); } | vltOnFront yVLT_D_SCOPE yaSTRING { if ($1 != V3ErrorCode::I_TRACING) { $1->v3error("Argument -scope only supported for tracing_on/off"); From 622f0c047c736278d7f06d0d885def72aaca703a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 8 Oct 2023 20:38:45 -0400 Subject: [PATCH 049/157] Fix reporting `line at wrong spot. Rework some internal fileline parsing functions. --- src/V3FileLine.cpp | 40 +++++++++++++++++++++++--------- src/V3FileLine.h | 4 ++++ src/V3ParseImp.cpp | 2 +- src/V3ParseImp.h | 3 +-- src/verilog.l | 2 +- src/verilog.y | 4 ++-- test_regress/t/t_pp_line_bad.out | 33 ++++++++++++++++---------- test_regress/t/t_pp_line_bad.pl | 1 + 8 files changed, 60 insertions(+), 29 deletions(-) diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index a8bf044a6..56f5090a1 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -208,17 +208,30 @@ string FileLine::lineDirectiveStrg(int enterExit) const { } void FileLine::lineDirective(const char* textp, int& enterExitRef) { + string newFilename; + int newLineno = -1; + lineDirectiveParse(textp, newFilename /*ref*/, newLineno /*ref*/, enterExitRef); + if (enterExitRef != -1) { + filename(newFilename); + lineno(newLineno); + } else { // Advance line number to account for bogus `line + linenoInc(); + } +} + +void FileLine::lineDirectiveParse(const char* textp, string& filenameRef, int& linenoRef, + int& enterExitRef) { // Handle `line directive // Does not parse streamNumber/streamLineno as the next input token // will come from the same stream as the previous line. do { - int lineNo; // Skip `line while (*textp && std::isspace(*textp)) ++textp; while (*textp && !std::isspace(*textp)) ++textp; while (*textp && std::isspace(*textp)) ++textp; // Grab linenumber + int lineNo; const char* const ln = textp; while (*textp && !std::isspace(*textp)) ++textp; if (0 == strncmp(ln, "`__LINE__", textp - ln)) { @@ -229,7 +242,6 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) { } else { break; // Fail } - lineno(lineNo); while (*textp && (std::isspace(*textp))) ++textp; // Grab filename @@ -240,7 +252,6 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) { string errMsg; const string& parsedFilename = VString::unquoteSVString(string{fn, textp}, errMsg); if (!errMsg.empty()) this->v3error(errMsg.c_str()); - filename(parsedFilename); ++textp; while (*textp && std::isspace(*textp)) ++textp; @@ -248,17 +259,16 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) { if (!std::isdigit(*textp)) break; // Fail const int level = std::atoi(textp); if (level < 0 || level >= 3) break; // Fail - /// TODO: store lineno/filename only when the `line directive is valid - /// lineno(lineNo); - /// filename(filenameNew); + + linenoRef = lineNo; + filenameRef = parsedFilename; enterExitRef = level; return; } while (false); // Fail - // TODO: show correct place of the code v3error("`line was not properly formed with '`line number \"filename\" level'\n"); - enterExitRef = 0; + enterExitRef = -1; } void FileLine::forwardToken(const char* textp, size_t size, bool trackLines) { @@ -273,14 +283,22 @@ void FileLine::forwardToken(const char* textp, size_t size, bool trackLines) { } } +void FileLine::applyIgnores() { +#ifndef V3ERROR_NO_GLOBAL_ + V3Config::applyIgnores(this); // Toggle warnings based on global config file +#endif +} + +FileLine* FileLine::copyOrSameFileLineApplied() { + applyIgnores(); + return copyOrSameFileLine(); +} + FileLine* FileLine::copyOrSameFileLine() { // When a fileline is "used" to produce a node, calls this function. // Return this, or a copy of this // There are often more than one token per line, thus we use the // same pointer as long as we're on the same line, file & warn state. -#ifndef V3ERROR_NO_GLOBAL_ - V3Config::applyIgnores(this); // Toggle warnings based on global config file -#endif static FileLine* lastNewp = nullptr; if (lastNewp && *lastNewp == *this) { // Compares lineno, filename, etc return lastNewp; diff --git a/src/V3FileLine.h b/src/V3FileLine.h index 15541f418..03cf71695 100644 --- a/src/V3FileLine.h +++ b/src/V3FileLine.h @@ -195,7 +195,9 @@ public: , m_parent{fromp->m_parent} { if (m_contentp) m_contentp->refInc(); } + void applyIgnores(); FileLine* copyOrSameFileLine(); + FileLine* copyOrSameFileLineApplied(); static void deleteAllRemaining(); ~FileLine(); #ifdef VL_LEAK_CHECKS @@ -221,6 +223,8 @@ public: void filename(const string& name) { m_filenameno = singleton().nameToNumber(name); } void parent(FileLine* fileline) { m_parent = fileline; } void lineDirective(const char* textp, int& enterExitRef); + void lineDirectiveParse(const char* textp, string& filenameRef, int& linenoRef, + int& enterExitRef); void linenoInc() { m_lastLineno++; m_lastColumn = 1; diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index 1da582004..0e082d402 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -72,7 +72,7 @@ V3ParseImp::~V3ParseImp() { void V3ParseImp::lexPpline(const char* textp) { // Handle lexer `line directive - FileLine* const prevFl = copyOrSameFileLine(); + FileLine* const prevFl = lexFileline()->copyOrSameFileLineApplied(); int enterExit; lexFileline()->lineDirective(textp, enterExit /*ref*/); if (enterExit == 1) { // Enter diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index 743b4ec14..439edf510 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -176,8 +176,8 @@ public: bool precSet, double precVal) VL_MT_DISABLED; VTimescale timeLastUnit() const { return m_timeLastUnit; } + void lexFileline(FileLine* fl) { m_lexFileline = fl; } FileLine* lexFileline() const { return m_lexFileline; } - FileLine* lexCopyOrSameFileLine() { return lexFileline()->copyOrSameFileLine(); } static void lexErrorPreprocDirective(FileLine* fl, const char* textp) VL_MT_DISABLED; static string lexParseTag(const char* textp) VL_MT_DISABLED; static double lexParseTimenum(const char* text) VL_MT_DISABLED; @@ -243,7 +243,6 @@ public: // Return next token, for bison, since bison isn't class based, use a global THIS AstNetlist* rootp() const { return m_rootp; } - FileLine* copyOrSameFileLine() { return bisonLastFileline()->copyOrSameFileLine(); } bool inLibrary() const { return m_inLibrary; } VOptionBool unconnectedDrive() const { return m_unconnectedDrive; } void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; } diff --git a/src/verilog.l b/src/verilog.l index 3ac7873b3..102a43195 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -40,7 +40,7 @@ // Use this to break between tokens whereever not return'ing a token (e.g. skipping inside lexer) #define FL_BRK (PARSEP->lexFileline()->startToken()) -#define CRELINE() (PARSEP->lexCopyOrSameFileLine()) +#define CRELINE() (PARSEP->lexFileline()->copyOrSameFileLineApplied()) #define FL \ do { \ diff --git a/src/verilog.y b/src/verilog.y index 31581e891..cfc01f62a 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -309,8 +309,8 @@ int V3ParseGrammar::s_modTypeImpNum = 0; //====================================================================== // Macro functions -#define CRELINE() \ - (PARSEP->copyOrSameFileLine()) // Only use in empty rules, so lines point at beginnings +// Only use in empty rules, so lines point at beginnings +#define CRELINE() (PARSEP->bisonLastFileline()->copyOrSameFileLineApplied()) #define FILELINE_OR_CRE(nodep) ((nodep) ? (nodep)->fileline() : CRELINE()) #define VARRESET_LIST(decl) \ diff --git a/test_regress/t/t_pp_line_bad.out b/test_regress/t/t_pp_line_bad.out index 8365b61c6..fc54a045d 100644 --- a/test_regress/t/t_pp_line_bad.out +++ b/test_regress/t/t_pp_line_bad.out @@ -1,22 +1,31 @@ -%Error: t/t_pp_line_bad.v:100:1: `line was not properly formed with '`line number "filename" level' - 100 | `line 100 +%Error: t/t_pp_line_bad.v:8:1: `line was not properly formed with '`line number "filename" level' + 8 | `line 100 | ^ -%Error: t/t_pp_line_bad.v:200:1: `line was not properly formed with '`line number "filename" level' - 200 | `line 100 +%Error: t/t_pp_line_bad.v:8:1: `line was not properly formed with '`line number "filename" level' +%Error: t/t_pp_line_bad.v:9:1: `line was not properly formed with '`line number "filename" level' + 9 | `line 200 somefile | ^ -%Error: t/t_pp_line_bad.v:300:1: `line was not properly formed with '`line number "filename" level' - 300 | `line 100 +%Error: t/t_pp_line_bad.v:9:1: `line was not properly formed with '`line number "filename" level' +%Error: t/t_pp_line_bad.v:10:1: `line was not properly formed with '`line number "filename" level' + 10 | `line 300 "somefile 1 | ^ -%Error: some file:400:1: `line was not properly formed with '`line number "filename" level' - 400 | `line 100 +%Error: t/t_pp_line_bad.v:10:1: `line was not properly formed with '`line number "filename" level' +%Error: t/t_pp_line_bad.v:11:1: `line was not properly formed with '`line number "filename" level' + 11 | `line 400 "some file" | ^ -%Error: somefile:500:1: `line was not properly formed with '`line number "filename" level' - 500 | `line 100 +%Error: t/t_pp_line_bad.v:11:1: `line was not properly formed with '`line number "filename" level' +%Error: t/t_pp_line_bad.v:12:1: `line was not properly formed with '`line number "filename" level' + 12 | `line 500 "somefile" 3 | ^ -%Error: some file:600:1: `line was not properly formed with '`line number "filename" level' - 600 | `line 100 +%Error: t/t_pp_line_bad.v:12:1: `line was not properly formed with '`line number "filename" level' +%Error: t/t_pp_line_bad.v:13:1: `line was not properly formed with '`line number "filename" level' + 13 | `line 600 "some file" 3 | ^ +%Error: t/t_pp_line_bad.v:13:1: `line was not properly formed with '`line number "filename" level' %Error: t/t_pp_line_bad.v:7:1: Define or directive not defined: '`line' 7 | `line | ^~~~~ +%Error: t/t_pp_line_bad.v:15:1: `line was not properly formed with '`line number "filename" level' +%Error: t/t_pp_line_bad.v:17:1: `line was not properly formed with '`line number "filename" level' +%Error: t/t_pp_line_bad.v:19:1: `line was not properly formed with '`line number "filename" level' %Error: Exiting due to diff --git a/test_regress/t/t_pp_line_bad.pl b/test_regress/t/t_pp_line_bad.pl index a60503a1f..887b07b64 100755 --- a/test_regress/t/t_pp_line_bad.pl +++ b/test_regress/t/t_pp_line_bad.pl @@ -11,6 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(linter => 1); lint( + verilator_flags2 => ['-no-std'], fails => 1, expect_filename => $Self->{golden_filename}, ); From 472ad90d837448ebc8e1647d54bbc4fa5bed681a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 9 Oct 2023 04:12:01 -0400 Subject: [PATCH 050/157] Change lint_off to not propagate upwards to files including where the lint_off is. --- Changes | 1 + docs/guide/warnings.rst | 28 +++++++++++++------- src/V3ParseImp.cpp | 22 ++++++++++----- test_regress/t/t_lint_warn_incfile2_bad.out | 5 ++++ test_regress/t/t_lint_warn_incfile2_bad.pl | 22 +++++++++++++++ test_regress/t/t_lint_warn_incfile2_bad.v | 14 ++++++++++ test_regress/t/t_lint_warn_incfile2_bad_b.vh | 10 +++++++ test_regress/t/t_pp_line_bad.out | 4 +-- test_regress/t/t_vlt_warn_file_bad.out | 5 ++++ test_regress/t/t_vlt_warn_file_bad.pl | 22 +++++++++++++++ test_regress/t/t_vlt_warn_file_bad.v | 12 +++++++++ test_regress/t/t_vlt_warn_file_bad.vlt | 10 +++++++ test_regress/t/t_vlt_warn_file_bad_b.vh | 9 +++++++ 13 files changed, 145 insertions(+), 19 deletions(-) create mode 100644 test_regress/t/t_lint_warn_incfile2_bad.out create mode 100755 test_regress/t/t_lint_warn_incfile2_bad.pl create mode 100644 test_regress/t/t_lint_warn_incfile2_bad.v create mode 100644 test_regress/t/t_lint_warn_incfile2_bad_b.vh create mode 100644 test_regress/t/t_vlt_warn_file_bad.out create mode 100755 test_regress/t/t_vlt_warn_file_bad.pl create mode 100644 test_regress/t/t_vlt_warn_file_bad.v create mode 100644 test_regress/t/t_vlt_warn_file_bad.vlt create mode 100644 test_regress/t/t_vlt_warn_file_bad_b.vh diff --git a/Changes b/Changes index 64c4f6832..dc07f520b 100644 --- a/Changes +++ b/Changes @@ -18,6 +18,7 @@ Verilator 5.017 devel * Support randc (#4349). * Support resizing function call inout arguments (#4467). * Support converting parameters inside modules to localparams (#4511). [Anthony Donlon] +* Change lint_off to not propagate upwards to files including where the lint_off is. * Fix conversion of impure logical expressions to bit expressions (#487 partial) (#4437). [Ryszard Rozak, Antmicro Ltd.] * Fix enum functions in localparams (#3999). [Andrew Nolte] * Fix passing arguments by reference (#3385 partial) (#4489). [Ryszard Rozak, Antmicro Ltd.] diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst index 48c0888f9..4588fd28b 100644 --- a/docs/guide/warnings.rst +++ b/docs/guide/warnings.rst @@ -12,10 +12,18 @@ Disabling Warnings Warnings may be disabled in multiple ways: -#. Disable the warning in the source code. When the warning is printed, it - will include a warning code. Surround the offending line with a - :code:`/*verilator&32;lint_off*/` and :code:`/*verilator&32;lint_on*/` - metacomment pair: +#. Disable the warning globally by invoking Verilator with the + :code:`-Wno-{warning-code}` option. + + Global disables should be avoided, as they removes all checking across + the source files, and prevents other users from compiling the sources + without knowing the magic set of disables needed to compile those + sources successfully. + +#. Disable the warning in the design source code. When the warning is + printed, it will include a warning code. Surround the offending line + with a :code:`/*verilator&32;lint_off*/` and + :code:`/*verilator&32;lint_on*/` metacomment pair: .. code-block:: sv @@ -23,6 +31,12 @@ Warnings may be disabled in multiple ways: if (`DEF_THAT_IS_EQ_ZERO <= 3) $stop; // verilator lint_on UNSIGNED + + A lint_off in the design source code will propagate down to any child + files (files later included by the file with the lint_off), but will not + propagate upwards to any parent file (file that included the file with + the lint_off). + #. Disable the warning using :ref:`Configuration Files` with a :option:`lint_off` command. This is useful when a script suppresses warnings, and the Verilog source should not be changed. This method also @@ -32,12 +46,6 @@ Warnings may be disabled in multiple ways: lint_off -rule UNSIGNED -file "*/example.v" -line 1 -#. Disable the warning globally invoking Verilator with the - :code:`-Wno-{warning-code}` option. This should be avoided, as it - removes all checking across the designs, and prevents other users from - compiling your code without knowing the magic set of disables needed to - compile your design successfully. - Error And Warning Format ======================== diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index 0e082d402..cb23e938f 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -72,15 +72,25 @@ V3ParseImp::~V3ParseImp() { void V3ParseImp::lexPpline(const char* textp) { // Handle lexer `line directive - FileLine* const prevFl = lexFileline()->copyOrSameFileLineApplied(); - int enterExit; - lexFileline()->lineDirective(textp, enterExit /*ref*/); + // FileLine* const prevFl = lexFileline(); + string newFilename; + int newLineno = -1; + int enterExit = 0; + lexFileline()->lineDirectiveParse(textp, newFilename /*ref*/, newLineno /*ref*/, enterExit /*ref*/); if (enterExit == 1) { // Enter + FileLine* const prevFl = lexFileline()->copyOrSameFileLine(); // Without applyIgnores + FileLine* const newFl = new FileLine{prevFl}; // Not copyOrSameFileLine as need to keep old value + lexFileline(newFl); lexFileline()->parent(prevFl); } else if (enterExit == 2) { // Exit - FileLine* upFl = lexFileline()->parent(); - if (upFl) upFl = upFl->parent(); - if (upFl) lexFileline()->parent(upFl); + if (FileLine* upFl = lexFileline()->parent()) { + lexFileline(upFl); // Restore warning state to upper file + } + } + if (enterExit != -1) { // Line/fn change + lexFileline()->filename(newFilename); + lexFileline()->lineno(newLineno); + lexFileline()->applyIgnores(); } } diff --git a/test_regress/t/t_lint_warn_incfile2_bad.out b/test_regress/t/t_lint_warn_incfile2_bad.out new file mode 100644 index 000000000..5060cbd21 --- /dev/null +++ b/test_regress/t/t_lint_warn_incfile2_bad.out @@ -0,0 +1,5 @@ +%Warning-WIDTHTRUNC: t/t_lint_warn_incfile2_bad.v:13:17: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's CONST '64'h1' generates 64 bits. + : ... note: In instance 't' + ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest + ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. +%Error: Exiting due to diff --git a/test_regress/t/t_lint_warn_incfile2_bad.pl b/test_regress/t/t_lint_warn_incfile2_bad.pl new file mode 100755 index 000000000..b3cdb56a9 --- /dev/null +++ b/test_regress/t/t_lint_warn_incfile2_bad.pl @@ -0,0 +1,22 @@ +#!/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(vlt => 1); + +lint( + # See also t/t_lint_warn_incfile1_bad + # See also t/t_vlt_warn_file_bad + verilator_flags2 => ["--no-std"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_lint_warn_incfile2_bad.v b/test_regress/t/t_lint_warn_incfile2_bad.v new file mode 100644 index 000000000..0d821dcd8 --- /dev/null +++ b/test_regress/t/t_lint_warn_incfile2_bad.v @@ -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, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// Check that lint_off doesn't propagate from include, for post-preprocessor warnings + +`include "t_lint_warn_incfile2_bad_b.vh" + +module t; + sub sub(); + int warn_t = 64'h1; // Not suppressed - should warn +endmodule diff --git a/test_regress/t/t_lint_warn_incfile2_bad_b.vh b/test_regress/t/t_lint_warn_incfile2_bad_b.vh new file mode 100644 index 000000000..aae34e35c --- /dev/null +++ b/test_regress/t/t_lint_warn_incfile2_bad_b.vh @@ -0,0 +1,10 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module sub; + // verilator lint_off WIDTHTRUNC + int warn_sub = 64'h1; // Suppressed +endmodule diff --git a/test_regress/t/t_pp_line_bad.out b/test_regress/t/t_pp_line_bad.out index fc54a045d..3041d5dfa 100644 --- a/test_regress/t/t_pp_line_bad.out +++ b/test_regress/t/t_pp_line_bad.out @@ -25,7 +25,5 @@ %Error: t/t_pp_line_bad.v:7:1: Define or directive not defined: '`line' 7 | `line | ^~~~~ -%Error: t/t_pp_line_bad.v:15:1: `line was not properly formed with '`line number "filename" level' -%Error: t/t_pp_line_bad.v:17:1: `line was not properly formed with '`line number "filename" level' -%Error: t/t_pp_line_bad.v:19:1: `line was not properly formed with '`line number "filename" level' +%Error: t/t_pp_line_bad.v:14:1: `line was not properly formed with '`line number "filename" level' %Error: Exiting due to diff --git a/test_regress/t/t_vlt_warn_file_bad.out b/test_regress/t/t_vlt_warn_file_bad.out new file mode 100644 index 000000000..6ff3c6fe0 --- /dev/null +++ b/test_regress/t/t_vlt_warn_file_bad.out @@ -0,0 +1,5 @@ +%Warning-WIDTHTRUNC: t/t_vlt_warn_file_bad.v:11:17: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's CONST '64'h1' generates 64 bits. + : ... note: In instance 't' + ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest + ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. +%Error: Exiting due to diff --git a/test_regress/t/t_vlt_warn_file_bad.pl b/test_regress/t/t_vlt_warn_file_bad.pl new file mode 100755 index 000000000..83d974461 --- /dev/null +++ b/test_regress/t/t_vlt_warn_file_bad.pl @@ -0,0 +1,22 @@ +#!/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(vlt => 1); + +lint( + # See also t/t_lint_warn_incfile1_bad + # See also t/t_lint_warn_incfile2_bad + verilator_flags2 => ["--no-std t/t_vlt_warn_file_bad.vlt"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_vlt_warn_file_bad.v b/test_regress/t/t_vlt_warn_file_bad.v new file mode 100644 index 000000000..89ef7bfc2 --- /dev/null +++ b/test_regress/t/t_vlt_warn_file_bad.v @@ -0,0 +1,12 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`include "t_vlt_warn_file_bad_b.vh" + +module t; + sub sub(); + int warn_t = 64'h1; +endmodule diff --git a/test_regress/t/t_vlt_warn_file_bad.vlt b/test_regress/t/t_vlt_warn_file_bad.vlt new file mode 100644 index 000000000..14107e8a0 --- /dev/null +++ b/test_regress/t/t_vlt_warn_file_bad.vlt @@ -0,0 +1,10 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`verilator_config + +// Test that this -file rule doesn't turn off warnings in t/t_vlt_warn_file_bad.v +lint_off -rule WIDTHTRUNC -file "t/t_vlt_warn_file_bad_b.vh" diff --git a/test_regress/t/t_vlt_warn_file_bad_b.vh b/test_regress/t/t_vlt_warn_file_bad_b.vh new file mode 100644 index 000000000..bf1bb1067 --- /dev/null +++ b/test_regress/t/t_vlt_warn_file_bad_b.vh @@ -0,0 +1,9 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module sub; + int warn_sub = 64'h1; +endmodule From e114dfda6d5c8ea6444c25f5b8257d4d0a7630d1 Mon Sep 17 00:00:00 2001 From: github action Date: Mon, 9 Oct 2023 08:14:14 +0000 Subject: [PATCH 051/157] Apply 'make format' --- src/V3ParseImp.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index cb23e938f..e2bfdedcf 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -76,10 +76,12 @@ void V3ParseImp::lexPpline(const char* textp) { string newFilename; int newLineno = -1; int enterExit = 0; - lexFileline()->lineDirectiveParse(textp, newFilename /*ref*/, newLineno /*ref*/, enterExit /*ref*/); + lexFileline()->lineDirectiveParse(textp, newFilename /*ref*/, newLineno /*ref*/, + enterExit /*ref*/); if (enterExit == 1) { // Enter FileLine* const prevFl = lexFileline()->copyOrSameFileLine(); // Without applyIgnores - FileLine* const newFl = new FileLine{prevFl}; // Not copyOrSameFileLine as need to keep old value + FileLine* const newFl + = new FileLine{prevFl}; // Not copyOrSameFileLine as need to keep old value lexFileline(newFl); lexFileline()->parent(prevFl); } else if (enterExit == 2) { // Exit From 8d99bdac254fec6d1449e1d00468ad12fd17c997 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 9 Oct 2023 05:03:57 -0400 Subject: [PATCH 052/157] Internals: Move afterCommentp to AstNode. No functional change. --- src/V3Ast.h | 9 +++++++++ src/V3Const.cpp | 14 ++++---------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index 7772581d4..a2fbe15cd 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -2040,6 +2040,15 @@ public: void dumpTreeDot(std::ostream& os = std::cout) const; void dumpTreeDotFile(const string& filename, bool append = false, bool doDump = true); + // METHODS - static advancement + static AstNode* afterCommentp(AstNode* nodep) { + // Skip over comments starting at provided nodep, + // such as to determine if a AstIf is empty. + // nodep may be null, if so return nullptr. + while (nodep && VN_IS(nodep, Comment)) nodep = nodep->nextp(); + return nodep; + } + // METHODS - queries // Changes control flow, disable some optimizations virtual bool isBrancher() const { return false; } diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 087f4b3af..6432a7eb5 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1372,13 +1372,6 @@ private: return true; } - AstNode* afterComment(AstNode* nodep) { - // Ignore comments, such as to determine if a AstIf is empty. - // nodep may be null, if so return null. - while (nodep && VN_IS(nodep, Comment)) nodep = nodep->nextp(); - return nodep; - } - // Extraction checks bool warnSelect(AstSel* nodep) { if (m_doGenerate) { @@ -1459,7 +1452,7 @@ private: const AstNodeIf* const lowerIfp = VN_CAST(nodep->thensp(), NodeIf); if (!lowerIfp || lowerIfp->nextp()) return false; if (nodep->type() != lowerIfp->type()) return false; - if (afterComment(lowerIfp->elsesp())) return false; + if (AstNode::afterCommentp(lowerIfp->elsesp())) return false; return true; } bool ifConcatMergeableBiop(const AstNode* nodep) { @@ -3007,7 +3000,8 @@ private: nodep->unlinkFrBack(); } VL_DO_DANGLING(nodep->deleteTree(), nodep); - } else if (!afterComment(nodep->thensp()) && !afterComment(nodep->elsesp())) { + } else if (!AstNode::afterCommentp(nodep->thensp()) + && !AstNode::afterCommentp(nodep->elsesp())) { if (!nodep->condp()->isPure()) { // Condition has side effect - leave - perhaps in // future simplify to remove all but side effect terms @@ -3015,7 +3009,7 @@ private: // Empty block, remove it VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } - } else if (!afterComment(nodep->thensp())) { + } else if (!AstNode::afterCommentp(nodep->thensp())) { UINFO(4, "IF({x}) nullptr {...} => IF(NOT{x}}: " << nodep << endl); AstNodeExpr* const condp = nodep->condp(); AstNode* const elsesp = nodep->elsesp(); From b306715b4acd9d27745d7dd532f37ac84c4ace03 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 9 Oct 2023 05:50:31 -0400 Subject: [PATCH 053/157] Optimize empty expression statements (#4544). --- Changes | 1 + src/V3Ast.cpp | 2 ++ src/V3Ast.h | 30 ++++++++++++++++++++------ src/V3AstNodeExpr.h | 5 ++++- src/V3Const.cpp | 10 +++++++++ src/V3Dead.cpp | 1 + src/V3Life.cpp | 1 + test_regress/t/t_func_real_exprstmt.pl | 6 ++++++ 8 files changed, 48 insertions(+), 8 deletions(-) diff --git a/Changes b/Changes index dc07f520b..63b868510 100644 --- a/Changes +++ b/Changes @@ -19,6 +19,7 @@ Verilator 5.017 devel * Support resizing function call inout arguments (#4467). * Support converting parameters inside modules to localparams (#4511). [Anthony Donlon] * Change lint_off to not propagate upwards to files including where the lint_off is. +* Optimize empty expression statements (#4544). * Fix conversion of impure logical expressions to bit expressions (#487 partial) (#4437). [Ryszard Rozak, Antmicro Ltd.] * Fix enum functions in localparams (#3999). [Andrew Nolte] * Fix passing arguments by reference (#3385 partial) (#4489). [Ryszard Rozak, Antmicro Ltd.] diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 35f6606f9..3e26ad7cd 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -33,6 +33,8 @@ VL_DEFINE_DEBUG_FUNCTIONS; //====================================================================== // Statics +uint32_t VIsCached::s_cachedCntGbl = 1; + uint64_t AstNode::s_editCntLast = 0; uint64_t AstNode::s_editCntGbl = 0; // Hot cache line diff --git a/src/V3Ast.h b/src/V3Ast.h index a2fbe15cd..a6daaa584 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -169,15 +169,31 @@ inline std::ostream& operator<<(std::ostream& os, const VLifetime& rhs) { class VIsCached final { // Used in some nodes to cache results of boolean methods + // If cachedCnt == 0, not cached + // else if cachedCnt == s_cachedCntGbl, then m_state is if cached + uint32_t m_cachedCnt : 31; // Mark of when cache was computed + uint32_t m_state : 1; + static uint32_t s_cachedCntGbl; // Global computed count + static constexpr uint32_t MAX_CNT = (1UL << 31) - 1; // Max for m_cachedCnt + public: - enum en : uint8_t { NOT_CACHED, YES, NO }; - enum en m_e; VIsCached() - : m_e{NOT_CACHED} {} - bool isCached() const { return m_e != NOT_CACHED; } - bool get() const { return m_e == YES; } - void set(bool flag) { m_e = flag ? YES : NO; } - void clearCache() { m_e = NOT_CACHED; } + : m_cachedCnt{0} + , m_state{0} {} + bool isCached() const { return m_cachedCnt == s_cachedCntGbl; } + bool get() const { return m_state; } + void set(bool flag) { + m_cachedCnt = s_cachedCntGbl; + m_state = flag; + } + void clearCache() { + m_cachedCnt = 0; + m_state = 0; + } + static void clearCacheTree() { + ++s_cachedCntGbl; + UASSERT_STATIC(s_cachedCntGbl < MAX_CNT, "Overflow of cache counting"); + } }; // ###################################################################### diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 727cdca6e..002b980c5 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -1176,7 +1176,10 @@ public: string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return true; } - bool isPure() override { return false; } + bool isPure() override { + if (AstNode::afterCommentp(stmtsp())) return false; + return resultp()->isPure(); + } bool same(const AstNode*) const override { return true; } }; class AstFError final : public AstNodeExpr { diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 6432a7eb5..031269f78 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -2689,6 +2689,15 @@ private: << nodep->varp()->prettyNameQ()); } } + void visit(AstExprStmt* nodep) override { + iterateChildren(nodep); + if (!AstNode::afterCommentp(nodep->stmtsp())) { + UINFO(8, "ExprStmt(...) " << nodep << " " << nodep->resultp() << endl); + nodep->replaceWith(nodep->resultp()->unlinkFrBack()); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + // Removing the ExprStmt might have made something impure above now pure + } + } void visit(AstEnumItemRef* nodep) override { iterateChildren(nodep); UASSERT_OBJ(nodep->itemp(), nodep, "Not linked"); @@ -3718,6 +3727,7 @@ public: } AstNode* mainAcceptEdit(AstNode* nodep) { + VIsCached::clearCacheTree(); // Avoid using any stale isPure // Operate starting at a random place return iterateSubtreeReturnEdits(nodep); } diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index 6a0f8ae7a..428538e1c 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -533,6 +533,7 @@ public: // We may have removed some datatypes, cleanup nodep->typeTablep()->repairCache(); + VIsCached::clearCacheTree(); // Removing assignments may affect isPure } ~DeadVisitor() override = default; }; diff --git a/src/V3Life.cpp b/src/V3Life.cpp index a20c17252..5fd69a27f 100644 --- a/src/V3Life.cpp +++ b/src/V3Life.cpp @@ -517,5 +517,6 @@ void V3Life::lifeAll(AstNetlist* nodep) { LifeState state; LifeTopVisitor{nodep, &state}; } // Destruct before checking + VIsCached::clearCacheTree(); // Removing assignments may affect isPure V3Global::dumpCheckGlobalTree("life", 0, dumpTreeLevel() >= 3); } diff --git a/test_regress/t/t_func_real_exprstmt.pl b/test_regress/t/t_func_real_exprstmt.pl index 859050d63..e8d0aa63b 100755 --- a/test_regress/t/t_func_real_exprstmt.pl +++ b/test_regress/t/t_func_real_exprstmt.pl @@ -11,8 +11,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( + verilator_flags2 => ["--stats"], ); +if ($Self->{vlt_all}) { + # Check no EXPRSTMTs in final output - should get optimized away + file_grep_not($Self->{stats}, qr/Node count, EXPRSTMT/i); +} + execute( check_finished => 1, ); From 5b06c60318b9709d28efdaae8c7261d2ffab6555 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Mon, 9 Oct 2023 15:45:09 +0200 Subject: [PATCH 054/157] Internals: Change deleteTree to pushDeletep (#4548). No functional change intended. --- src/V3Const.cpp | 176 ++++++++++++++++++++++++------------------------ 1 file changed, 88 insertions(+), 88 deletions(-) diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 031269f78..297cfb1f8 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -997,7 +997,7 @@ private: } if (ccastp) { andp->replaceWith(ccastp); - VL_DO_DANGLING(andp->deleteTree(), andp); + VL_DO_DANGLING(pushDeletep(andp), andp); return true; } return false; @@ -1074,7 +1074,7 @@ private: newp->thenp()->dtypeFrom(nodep); // As And might have been to change widths newp->elsep()->dtypeFrom(nodep); nodep->replaceWith(newp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); return true; } bool matchMaskedOr(AstAnd* nodep) { @@ -1105,15 +1105,15 @@ private: if (orLIsRedundant && orRIsRedundant) { nodep->replaceWith( new AstConst{nodep->fileline(), AstConst::DTyped{}, nodep->dtypep()}); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); return true; } else if (orLIsRedundant) { orp->replaceWith(orp->rhsp()->unlinkFrBack()); - VL_DO_DANGLING(orp->deleteTree(), orp); + VL_DO_DANGLING(pushDeletep(orp), orp); return false; // input node is still valid, keep going } else if (orRIsRedundant) { orp->replaceWith(orp->lhsp()->unlinkFrBack()); - VL_DO_DANGLING(orp->deleteTree(), orp); + VL_DO_DANGLING(pushDeletep(orp), orp); return false; // input node is still valid, keep going } else { return false; @@ -1131,7 +1131,7 @@ private: rhsp->unlinkFrBack(); nodep->replaceWith(rhsp); rhsp->dtypeFrom(nodep); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); return true; } return false; @@ -1183,7 +1183,7 @@ private: if (newp) { UINFO(4, "Transformed leaf of bit tree to " << newp << std::endl); nodep->replaceWith(newp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } if (debug() >= 9) { // LCOV_EXCL_START @@ -1347,14 +1347,14 @@ private: // if (debug() >= 9) nodep->dumpTree("- BI(EXTEND)-in: "); smallerp->unlinkFrBack(); - VL_DO_DANGLING(extendp->unlinkFrBack()->deleteTree(), extendp); // aka nodep->lhsp. + VL_DO_DANGLING(pushDeletep(extendp->unlinkFrBack()), extendp); // aka nodep->lhsp. nodep->rhsp(smallerp); constp->unlinkFrBack(); V3Number num{constp, subsize}; num.opAssign(constp->num()); nodep->lhsp(new AstConst{constp->fileline(), num}); - VL_DO_DANGLING(constp->deleteTree(), constp); + VL_DO_DANGLING(pushDeletep(constp), constp); if (debug() >= 9) nodep->dumpTree("- BI(EXTEND)-ou: "); return true; } @@ -1550,7 +1550,7 @@ private: if (debug() > 5) oldp->dumpTree("- const_old: "); if (debug() > 5) newp->dumpTree("- _new: "); oldp->replaceWith(newp); - VL_DO_DANGLING(oldp->deleteTree(), oldp); + VL_DO_DANGLING(pushDeletep(oldp), oldp); } void replaceNum(AstNode* nodep, uint32_t val) { V3Number num{nodep, nodep->width(), val}; @@ -1581,7 +1581,7 @@ private: checkp->unlinkFrBack()}; newp->dtypeFrom(nodep); nodep->replaceWith(newp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } } void replaceAllOnes(AstNode* nodep) { @@ -1626,7 +1626,7 @@ private: if (debug() > 5) oldp->dumpTree("- const_old: "); if (debug() > 5) newp->dumpTree("- _new: "); oldp->replaceWith(newp); - VL_DO_DANGLING(oldp->deleteTree(), oldp); + VL_DO_DANGLING(pushDeletep(oldp), oldp); } //---------------------------------------- // Replacement functions. @@ -1639,7 +1639,7 @@ private: // This may adversely affect the operation of the node being replaced. childp->dtypeFrom(nodep); nodep->replaceWith(childp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } void replaceWChildBool(AstNode* nodep, AstNodeExpr* childp) { // NODE(..., CHILD(...)) -> REDOR(CHILD(...)) @@ -1649,7 +1649,7 @@ private: } else { nodep->replaceWith(new AstRedOr{childp->fileline(), childp}); } - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } //! Replace a ternary node with its RHS after iterating @@ -1740,16 +1740,16 @@ private: lp->dtypeFrom(nodep); nodep->lhsp(lrp); nodep->rhsp(rrp); - VL_DO_DANGLING(rp->deleteTree(), rp); - VL_DO_DANGLING(rlp->deleteTree(), rlp); + VL_DO_DANGLING(pushDeletep(rp), rp); + VL_DO_DANGLING(pushDeletep(rlp), rlp); } else if (operandsSame(lrp, rrp)) { lp->lhsp(nodep); lp->rhsp(rrp); lp->dtypeFrom(nodep); nodep->lhsp(llp); nodep->rhsp(rlp); - VL_DO_DANGLING(rp->deleteTree(), rp); - VL_DO_DANGLING(lrp->deleteTree(), lrp); + VL_DO_DANGLING(pushDeletep(rp), rp); + VL_DO_DANGLING(pushDeletep(lrp), lrp); } else { nodep->v3fatalSrc("replaceAndOr on something operandAndOrSame shouldn't have matched"); } @@ -1770,8 +1770,8 @@ private: nodep->lhsp(llp); nodep->rhsp(rlp); nodep->dtypep(llp->dtypep()); // dtype of Biop is before shift. - VL_DO_DANGLING(rp->deleteTree(), rp); - VL_DO_DANGLING(rrp->deleteTree(), rrp); + VL_DO_DANGLING(pushDeletep(rp), rp); + VL_DO_DANGLING(pushDeletep(rrp), rrp); // nodep->dumpTree("- repShiftSame_new: "); } void replaceConcatSel(AstConcat* nodep) { @@ -1791,9 +1791,9 @@ private: << endl); nodep->replaceWith(newselp); - VL_DO_DANGLING(lselp->deleteTree(), lselp); - VL_DO_DANGLING(rselp->deleteTree(), rselp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(lselp), lselp); + VL_DO_DANGLING(pushDeletep(rselp), rselp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } void replaceConcatMerge(AstConcat* nodep) { // {llp OP lrp, rlp OP rrp} => {llp, rlp} OP {lrp, rrp}, where OP = AND/OR/XOR @@ -1811,9 +1811,9 @@ private: lp->rhsp()->replaceWith(newrp); lp->dtypeChgWidthSigned(newlp->width(), newlp->width(), VSigning::UNSIGNED); UINFO(5, "merged " << nodep << endl); - VL_DO_DANGLING(rp->unlinkFrBack()->deleteTree(), rp); + VL_DO_DANGLING(pushDeletep(rp->unlinkFrBack()), rp); nodep->replaceWith(lp->unlinkFrBack()); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); iterate(lp->lhsp()); iterate(lp->rhsp()); } else { @@ -1830,7 +1830,7 @@ private: : static_cast(new AstExtend{nodep->fileline(), arg0p})); newp->dtypeFrom(nodep); nodep->replaceWith(newp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } void replacePowShift(AstNodeBiop* nodep) { // Pow or PowS UINFO(5, "POW(2,b)->SHIFTL(1,b) " << nodep << endl); @@ -1840,7 +1840,7 @@ private: newp->dtypeFrom(nodep); newp->lhsp()->dtypeFrom(nodep); nodep->replaceWith(newp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } void replaceMulShift(AstMul* nodep) { // Mul, but not MulS as not simple shift UINFO(5, "MUL(2^n,b)->SHIFTL(b,n) " << nodep << endl); @@ -1850,7 +1850,7 @@ private: = new AstShiftL{nodep->fileline(), opp, new AstConst(nodep->fileline(), amount)}; newp->dtypeFrom(nodep); nodep->replaceWith(newp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } void replaceDivShift(AstDiv* nodep) { // Mul, but not MulS as not simple shift UINFO(5, "DIV(b,2^n)->SHIFTR(b,n) " << nodep << endl); @@ -1860,7 +1860,7 @@ private: = new AstShiftR{nodep->fileline(), opp, new AstConst(nodep->fileline(), amount)}; newp->dtypeFrom(nodep); nodep->replaceWith(newp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } void replaceModAnd(AstModDiv* nodep) { // Mod, but not ModS as not simple shift UINFO(5, "MOD(b,2^n)->AND(b,2^n-1) " << nodep << endl); @@ -1872,7 +1872,7 @@ private: = new AstAnd{nodep->fileline(), opp, new AstConst{nodep->fileline(), mask}}; newp->dtypeFrom(nodep); nodep->replaceWith(newp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } void replaceShiftOp(AstNodeBiop* nodep) { UINFO(5, "SHIFT(AND(a,b),CONST)->AND(SHIFT(a,CONST),SHIFT(b,CONST)) " << nodep << endl); @@ -1909,8 +1909,8 @@ private: const int shift1 = VN_AS(shift1p, Const)->toUInt(); const int shift2 = VN_AS(shift2p, Const)->toUInt(); const int newshift = shift1 + shift2; - VL_DO_DANGLING(shift1p->deleteTree(), shift1p); - VL_DO_DANGLING(shift2p->deleteTree(), shift2p); + VL_DO_DANGLING(pushDeletep(shift1p), shift1p); + VL_DO_DANGLING(pushDeletep(shift2p), shift2p); nodep->lhsp(ap); nodep->rhsp(new AstConst(nodep->fileline(), newshift)); iterate(nodep); // Further reduce, either node may have more reductions. @@ -1921,8 +1921,8 @@ private: int shift2 = VN_AS(shift2p, Const)->toUInt(); if (VN_IS(nodep, ShiftR)) shift2 = -shift2; const int newshift = shift1 + shift2; - VL_DO_DANGLING(shift1p->deleteTree(), shift1p); - VL_DO_DANGLING(shift2p->deleteTree(), shift2p); + VL_DO_DANGLING(pushDeletep(shift1p), shift1p); + VL_DO_DANGLING(pushDeletep(shift2p), shift2p); AstNodeExpr* newp; V3Number mask1{nodep, nodep->width()}; V3Number ones{nodep, nodep->width()}; @@ -1949,11 +1949,11 @@ private: newp = new AstAnd{nodep->fileline(), newp, new AstConst{nodep->fileline(), mask}}; newp->dtypeFrom(nodep); nodep->replaceWith(newp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); // newp->dumpTree("- repShiftShift_new: "); iterate(newp); // Further reduce, either node may have more reductions. } - VL_DO_DANGLING(lhsp->deleteTree(), lhsp); + VL_DO_DANGLING(pushDeletep(lhsp), lhsp); } bool replaceAssignMultiSel(AstNodeAssign* nodep) { @@ -2009,8 +2009,8 @@ private: } // pnewp->dumpTree("- conew: "); nodep->replaceWith(newp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); - VL_DO_DANGLING(nextp->unlinkFrBack()->deleteTree(), nextp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + VL_DO_DANGLING(pushDeletep(nextp->unlinkFrBack()), nextp); return true; } @@ -2037,7 +2037,7 @@ private: nodep->v3error("Wire inputs its own output, creating circular logic (wire x=x)"); return false; // Don't delete the assign, or V3Gate will freak out } else { - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); return true; } } else if (m_doV && VN_IS(nodep->lhsp(), Concat) && nodep->isPure()) { @@ -2127,8 +2127,8 @@ private: if (debug() >= 9 && newp) newp->dumpTreeAndNext(cout, "- _new: "); nodep->addNextHere(newp); // Cleanup - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - VL_DO_DANGLING(conp->deleteTree(), conp); + VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); + VL_DO_DANGLING(pushDeletep(conp), conp); // Further reduce, either node may have more reductions. return true; } else if (m_doV && VN_IS(nodep->rhsp(), StreamR)) { @@ -2146,7 +2146,7 @@ private: srcp = new AstCvtDynArrayToPacked{srcp->fileline(), srcp, srcDTypep}; } nodep->rhsp(srcp); - VL_DO_DANGLING(streamp->deleteTree(), streamp); + VL_DO_DANGLING(pushDeletep(streamp), streamp); // Further reduce, any of the nodes may have more reductions. return true; } else if (m_doV && VN_IS(nodep->lhsp(), StreamL)) { @@ -2188,7 +2188,7 @@ private: } nodep->lhsp(dstp); nodep->rhsp(srcp); - VL_DO_DANGLING(streamp->deleteTree(), streamp); + VL_DO_DANGLING(pushDeletep(streamp), streamp); // Further reduce, any of the nodes may have more reductions. return true; } else if (m_doV && VN_IS(nodep->rhsp(), StreamL)) { @@ -2238,7 +2238,7 @@ private: // widthMin no longer applicable if different C-expanded width newp->dtypeSetLogicSized(nodep->width(), VSigning::UNSIGNED); nodep->replaceWith(newp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); if (debug() >= 9) newp->dumpTree("- _new: "); } @@ -2264,7 +2264,7 @@ private: newp->fileline(nodep->fileline()); UINFO(4, "Simulate->" << newp << endl); nodep->replaceWith(newp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } } @@ -2296,7 +2296,7 @@ private: iterateChildren(nodep); if (!nodep->stmtsp()) { nodep->unlinkFrBack(); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } } void visit(AstScope* nodep) override { @@ -2329,7 +2329,7 @@ private: UINFO(4, "Concat(Rand,Rand) => Rand: " << nodep << endl); aRandp->dtypeFrom(nodep); // I.e. the total width nodep->replaceWith(aRandp->unlinkFrBack()); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); return true; } bool matchSelRand(AstSel* nodep) { @@ -2340,7 +2340,7 @@ private: UINFO(4, "Sel(Rand) => Rand: " << nodep << endl); aRandp->dtypeFrom(nodep); // I.e. the total width nodep->replaceWith(aRandp->unlinkFrBack()); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); return true; } int operandConcatMove(AstConcat* nodep) { @@ -2380,7 +2380,7 @@ private: // If bp was a concat, then we have this exact same form again! // Recurse rather then calling node->iterate to prevent 2^n recursion! if (operandConcatMove(abConcp)) moveConcat(abConcp); - VL_DO_DANGLING(bcConcp->deleteTree(), bcConcp); + VL_DO_DANGLING(pushDeletep(bcConcp), bcConcp); } else { AstConcat* const abConcp = VN_AS(nodep->lhsp(), Concat); abConcp->unlinkFrBack(); @@ -2391,7 +2391,7 @@ private: nodep->lhsp(ap); nodep->rhsp(bcConcp); if (operandConcatMove(bcConcp)) moveConcat(bcConcp); - VL_DO_DANGLING(abConcp->deleteTree(), abConcp); + VL_DO_DANGLING(pushDeletep(abConcp), abConcp); } } @@ -2421,7 +2421,7 @@ private: lhsp->cloneTreePure(false)}}; newp->dtypeFrom(nodep); nodep->replaceWith(newp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } void replaceSelSel(AstSel* nodep) { @@ -2437,8 +2437,8 @@ private: if (VN_IS(lsb1p, Const) && VN_IS(lsb2p, Const)) { newlsbp = new AstConst{lsb1p->fileline(), VN_AS(lsb1p, Const)->toUInt() + VN_AS(lsb2p, Const)->toUInt()}; - VL_DO_DANGLING(lsb1p->deleteTree(), lsb1p); - VL_DO_DANGLING(lsb2p->deleteTree(), lsb2p); + VL_DO_DANGLING(pushDeletep(lsb1p), lsb1p); + VL_DO_DANGLING(pushDeletep(lsb2p), lsb2p); } else { // Width is important, we need the width of the fromp's expression, not the // potentially smaller lsb1p's width, but don't insert a redundant AstExtend. @@ -2458,7 +2458,7 @@ private: } AstSel* const newp = new AstSel{nodep->fileline(), fromp, newlsbp, widthp}; nodep->replaceWith(newp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } void replaceSelConcat(AstSel* nodep) { @@ -2489,7 +2489,7 @@ private: conRhsp->width() - nodep->lsbConst()}}; nodep->replaceWith(newp); } - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } bool operandSelReplicate(AstSel* nodep) { // SEL(REPLICATE(from,rep),lsb,width) => SEL(from,0,width) as long @@ -2513,7 +2513,7 @@ private: new AstConst{lsbp->fileline(), lsbp->toUInt() % fromp->width()}, widthp}; newp->dtypeFrom(nodep); nodep->replaceWith(newp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); return true; } bool operandRepRep(AstReplicate* nodep) { @@ -2532,7 +2532,7 @@ private: = new AstReplicate{nodep->fileline(), from2p, cnt1p->toUInt() * cnt2p->toUInt()}; newp->dtypeFrom(nodep); nodep->replaceWith(newp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); return true; } bool operandConcatSame(AstConcat* nodep) { @@ -2562,7 +2562,7 @@ private: AstReplicate* const newp = new AstReplicate{nodep->fileline(), from1p, cnt1 + cnt2}; newp->dtypeFrom(nodep); nodep->replaceWith(newp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); return true; } void replaceSelIntoBiop(AstSel* nodep) { @@ -2580,7 +2580,7 @@ private: fromp->rhsp(new AstSel{nodep->fileline(), birhsp, lsbp, widthp}); fromp->dtypeFrom(nodep); nodep->replaceWith(fromp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } void replaceSelIntoUniop(AstSel* nodep) { // SEL(NOT(a),1,bit) => NOT(SEL(a,bit)) @@ -2594,7 +2594,7 @@ private: fromp->lhsp(new AstSel{nodep->fileline(), bilhsp, lsbp, widthp}); fromp->dtypeFrom(nodep); nodep->replaceWith(fromp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } void visit(AstAttrOf* nodep) override { @@ -2626,7 +2626,7 @@ private: fromp->dtypeFrom( VN_AS(fromp->dtypep()->skipRefp(), NodeArrayDType)->subDTypep()); } - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } } m_selp = nullptr; @@ -2674,12 +2674,12 @@ private: // support arrays of arrays or other stuff AstNode* const newp = valuep->cloneTree(false); nodep->replaceWith(newp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); did = true; } else if (nodep->varp()->isParam() && VN_IS(valuep, Unbounded)) { AstNode* const newp = valuep->cloneTree(false); nodep->replaceWith(newp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); did = true; } } @@ -2694,7 +2694,7 @@ private: if (!AstNode::afterCommentp(nodep->stmtsp())) { UINFO(8, "ExprStmt(...) " << nodep << " " << nodep->resultp() << endl); nodep->replaceWith(nodep->resultp()->unlinkFrBack()); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); // Removing the ExprStmt might have made something impure above now pure } } @@ -2747,13 +2747,13 @@ private: } else { nodep->replaceWith(new AstSenItem{nodep->fileline(), AstSenItem::Never{}}); } - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } else { - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); } } else { // Otherwise it may compute a result that needs to settle out nodep->replaceWith(new AstSenItem{nodep->fileline(), AstSenItem::Combo{}}); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } } else if (m_doNConst && VN_IS(nodep->sensp(), Not)) { // V3Gate may propagate NOTs into clocks... Just deal with it @@ -2767,7 +2767,7 @@ private: UINFO(8, "senItem(NOT...) " << nodep << " " << invert << endl); if (invert) nodep->edgeType(nodep->edgeType().invert()); sensp->replaceWith(lastSensp->unlinkFrBack()); - VL_DO_DANGLING(sensp->deleteTree(), sensp); + VL_DO_DANGLING(pushDeletep(sensp), sensp); } } @@ -2906,7 +2906,7 @@ private: // Remove identical expressions if (lItemp->edgeType() == rItemp->edgeType()) { - VL_DO_DANGLING(rItemp->unlinkFrBack()->deleteTree(), rItemp); + VL_DO_DANGLING(pushDeletep(rItemp->unlinkFrBack()), rItemp); nextp = lItemp; } @@ -2923,7 +2923,7 @@ private: const V3Number lNum{lConstp->num()}; lConstp->num().opOr(lNum, rConstp->num()); // Remove redundant term - VL_DO_DANGLING(rItemp->unlinkFrBack()->deleteTree(), rItemp); + VL_DO_DANGLING(pushDeletep(rItemp->unlinkFrBack()), rItemp); nextp = lItemp; } } @@ -2968,7 +2968,7 @@ private: AstInitial* const newinitp = new AstInitial{ nodep->fileline(), new AstAssign{nodep->fileline(), varrefp, exprp}}; m_modp->addStmtsp(newinitp); - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); // Set the initial value right in the variable so we can constant propagate AstNode* const initvaluep = exprp->cloneTree(false); varrefp->varp()->valuep(initvaluep); @@ -2981,7 +2981,7 @@ private: AstRelease* const newRp = new AstRelease{flp, concatp->rhsp()->unlinkFrBack()}; nodep->replaceWith(newLp); newLp->addNextHere(newRp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); visit(newLp); visit(newRp); } @@ -3008,7 +3008,7 @@ private: } else { nodep->unlinkFrBack(); } - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } else if (!AstNode::afterCommentp(nodep->thensp()) && !AstNode::afterCommentp(nodep->elsesp())) { if (!nodep->condp()->isPure()) { @@ -3016,7 +3016,7 @@ private: // future simplify to remove all but side effect terms } else { // Empty block, remove it - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); } } else if (!AstNode::afterCommentp(nodep->thensp())) { UINFO(4, "IF({x}) nullptr {...} => IF(NOT{x}}: " << nodep << endl); @@ -3025,7 +3025,7 @@ private: condp->unlinkFrBackWithNext(); elsesp->unlinkFrBackWithNext(); if (nodep->thensp()) { // Must have been comment - nodep->thensp()->unlinkFrBackWithNext()->deleteTree(); + pushDeletep(nodep->thensp()->unlinkFrBackWithNext()); } nodep->condp(new AstLogNot{condp->fileline(), condp}); // LogNot, as C++ optimization also possible @@ -3042,7 +3042,7 @@ private: ifp->isBoundsCheck(nodep->isBoundsCheck()); // Copy bounds check info ifp->branchPred(nodep->branchPred().invert()); nodep->replaceWith(ifp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } else if (ifSameAssign(nodep)) { UINFO( 4, @@ -3055,7 +3055,7 @@ private: AstNodeExpr* const falsep = elsesp->rhsp()->unlinkFrBack(); thensp->rhsp(new AstCond{truep->fileline(), condp, truep, falsep}); nodep->replaceWith(thensp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } else if (false // Disabled, as vpm assertions are faster // without due to short-circuiting && operandIfIf(nodep)) { @@ -3066,7 +3066,7 @@ private: AstNodeExpr* const lowerCondp = lowerIfp->condp()->unlinkFrBackWithNext(); nodep->condp(new AstLogAnd{lowerIfp->fileline(), condp, lowerCondp}); lowerIfp->replaceWith(lowerThensp); - VL_DO_DANGLING(lowerIfp->deleteTree(), lowerIfp); + VL_DO_DANGLING(pushDeletep(lowerIfp), lowerIfp); } else if (operandBoolShift(nodep->condp())) { replaceBoolShift(nodep->condp()); } @@ -3126,7 +3126,7 @@ private: scopeNamep->unlinkFrBackWithNext(); pformatp->scopeNamep(scopeNamep); } - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); return true; } void visit(AstSFormatF* nodep) override { @@ -3174,7 +3174,7 @@ private: << argp << endl); // fmt = out w/ replace % with %% as it must be literal. fmt = VString::quotePercent(out); - VL_DO_DANGLING(argp->unlinkFrBack()->deleteTree(), argp); + VL_DO_DANGLING(pushDeletep(argp->unlinkFrBack()), argp); } argp = nextp; } @@ -3234,7 +3234,7 @@ private: } else { nodep->unlinkFrBack(); } - VL_DO_DANGLING(nodep->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } else if (nodep->condp()->isNeqZero()) { if (!thisWhileHasJumpDelay) { nodep->v3warn(INFINITELOOP, "Infinite loop (condition always true)"); @@ -3257,13 +3257,13 @@ private: // Ignored, can eliminate early void visit(AstSysIgnore* nodep) override { iterateChildren(nodep); - if (m_doNConst) VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + if (m_doNConst) VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); } void visit(AstStmtExpr* nodep) override { iterateChildren(nodep); if (!nodep->exprp() || VN_IS(nodep->exprp(), Const)) { - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); return; } // TODO if there's an ExprStmt underneath just keep lower statements @@ -3283,14 +3283,14 @@ private: iterateChildren(nodep); // Jump to label where label immediately follows this go is not useful if (nodep->labelp() == VN_CAST(nodep->nextp(), JumpLabel)) { - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); // Keep the label, might be other jumps pointing to it, gets cleaned later return; } if (m_doExpensive) { // Any non-label statements (at this statement level) can never execute while (nodep->nextp() && !VN_IS(nodep->nextp(), JumpLabel)) { - nodep->nextp()->unlinkFrBack()->deleteTree(); + pushDeletep(nodep->nextp()->unlinkFrBack()); } // If last statement in a jump label we have JumpLabel(...., JumpGo) // Often caused by "return" in a Verilog function. The Go is pointless, remove. @@ -3299,7 +3299,7 @@ private: if (aboveBlockp == nodep->labelp()->blockp()) { if (aboveBlockp->endStmtsp() == nodep->labelp()) { UINFO(4, "JUMPGO => last remove " << nodep << endl); - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); return; } } @@ -3325,8 +3325,8 @@ private: } else { nodep->unlinkFrBack(); } - nodep->labelp()->unlinkFrBack()->deleteTree(); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + pushDeletep(nodep->labelp()->unlinkFrBack()); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } } From a5ee8b39efb6b96e2160a5fc157755967329ec0f Mon Sep 17 00:00:00 2001 From: Mariusz Glebocki Date: Mon, 9 Oct 2023 23:43:27 +0200 Subject: [PATCH 055/157] Internals: Remove use of V3Width code from V3AstNodes (#4537). No functional change intended. `getCommonClassTypep` and its helper code has been moved to AstNode class. This is a lot better place for this functionality. Moreover, it allowed to get rid of the dependency on V3Width from generic AST-related code. --- src/V3Ast.cpp | 96 ++++++++++++++++++++++++++++ src/V3Ast.h | 43 +++++++++++++ src/V3AstNodes.cpp | 3 +- src/V3Width.cpp | 154 +++++++-------------------------------------- src/V3Width.h | 2 - 5 files changed, 163 insertions(+), 135 deletions(-) diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 3e26ad7cd..6115dabf8 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -1461,6 +1461,102 @@ AstNodeDType* AstNode::findStreamDType() const { return v3Global.rootp()->typeTablep()->findStreamDType(fileline()); } +static const AstNodeDType* computeCastableBase(const AstNodeDType* nodep) { + while (true) { + if (const AstPackArrayDType* const packp = VN_CAST(nodep, PackArrayDType)) { + nodep = packp->subDTypep(); + continue; + } else if (const AstNodeDType* const refp = nodep->skipRefToEnump()) { + if (refp != nodep) { + nodep = refp; + continue; + } + } + return nodep; + } +} + +static VCastable computeCastableImp(const AstNodeDType* toDtp, const AstNodeDType* fromDtp, + const AstNode* fromConstp) { + const VCastable castable = VCastable::UNSUPPORTED; + toDtp = toDtp->skipRefToEnump(); + fromDtp = fromDtp->skipRefToEnump(); + if (toDtp == fromDtp) return VCastable::SAMEISH; + if (toDtp->similarDType(fromDtp)) return VCastable::SAMEISH; + // UNSUP unpacked struct/unions (treated like BasicDType) + const AstNodeDType* fromBaseDtp = computeCastableBase(fromDtp); + + const bool fromNumericable = VN_IS(fromBaseDtp, BasicDType) || VN_IS(fromBaseDtp, EnumDType) + || VN_IS(fromBaseDtp, StreamDType) + || VN_IS(fromBaseDtp, NodeUOrStructDType); + + const AstNodeDType* toBaseDtp = computeCastableBase(toDtp); + const bool toNumericable + = VN_IS(toBaseDtp, BasicDType) || VN_IS(toBaseDtp, NodeUOrStructDType); + + if (toBaseDtp == fromBaseDtp) { + return VCastable::COMPATIBLE; + } else if (toNumericable) { + if (fromNumericable) return VCastable::COMPATIBLE; + } else if (VN_IS(toDtp, EnumDType)) { + if (VN_IS(fromBaseDtp, EnumDType) && toDtp->sameTree(fromDtp)) + return VCastable::ENUM_IMPLICIT; + if (fromNumericable) return VCastable::ENUM_EXPLICIT; + } else if (VN_IS(toDtp, ClassRefDType) && VN_IS(fromConstp, Const)) { + if (VN_IS(fromConstp, Const) && VN_AS(fromConstp, Const)->num().isNull()) + return VCastable::COMPATIBLE; + } else if (VN_IS(toDtp, ClassRefDType) && VN_IS(fromDtp, ClassRefDType)) { + const auto toClassp = VN_AS(toDtp, ClassRefDType)->classp(); + const auto fromClassp = VN_AS(fromDtp, ClassRefDType)->classp(); + const bool downcast = AstClass::isClassExtendedFrom(toClassp, fromClassp); + const bool upcast = AstClass::isClassExtendedFrom(fromClassp, toClassp); + if (upcast) { + return VCastable::COMPATIBLE; + } else if (downcast) { + return VCastable::DYNAMIC_CLASS; + } else { + return VCastable::INCOMPATIBLE; + } + } + return castable; +} + +VCastable AstNode::computeCastable(const AstNodeDType* toDtp, const AstNodeDType* fromDtp, + const AstNode* fromConstp) { + const auto castable = computeCastableImp(toDtp, fromDtp, fromConstp); + UINFO(9, " castable=" << castable << " for " << toDtp << endl); + UINFO(9, " =?= " << fromDtp << endl); + UINFO(9, " const= " << fromConstp << endl); + return castable; +} + +AstNodeDType* AstNode::getCommonClassTypep(AstNode* nodep1, AstNode* nodep2) { + // Return the class type that both nodep1 and nodep2 are castable to. + // If both are null, return the type of null constant. + // If one is a class and one is null, return AstClassRefDType that points to that class. + // If no common class type exists, return nullptr. + + // First handle cases with null values and when one class is a super class of the other. + if (VN_IS(nodep1, Const)) std::swap(nodep1, nodep2); + { + const VCastable castable = computeCastable(nodep1->dtypep(), nodep2->dtypep(), nodep2); + if (castable == VCastable::SAMEISH || castable == VCastable::COMPATIBLE) { + return nodep1->dtypep(); + } else if (castable == VCastable::DYNAMIC_CLASS) { + return nodep2->dtypep(); + } + } + + AstClassRefDType* classDtypep1 = VN_CAST(nodep1->dtypep(), ClassRefDType); + while (classDtypep1) { + const VCastable castable = computeCastable(classDtypep1, nodep2->dtypep(), nodep2); + if (castable == VCastable::COMPATIBLE) return classDtypep1; + AstClassExtends* const extendsp = classDtypep1->classp()->extendsp(); + classDtypep1 = extendsp ? VN_AS(extendsp->dtypep(), ClassRefDType) : nullptr; + } + return nullptr; +} + //###################################################################### // VNDeleter diff --git a/src/V3Ast.h b/src/V3Ast.h index a6daaa584..38dba7714 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1249,6 +1249,45 @@ inline std::ostream& operator<<(std::ostream& os, const VUseType& rhs) { // ###################################################################### +class VCastable final { +public: + enum en : uint8_t { + UNSUPPORTED, + SAMEISH, + COMPATIBLE, + ENUM_EXPLICIT, + ENUM_IMPLICIT, + DYNAMIC_CLASS, + INCOMPATIBLE, + _ENUM_MAX // Leave last + }; + enum en m_e; + const char* ascii() const { + static const char* const names[] + = {"UNSUPPORTED", "SAMEISH", "COMPATIBLE", "ENUM_EXPLICIT", + "ENUM_IMPLICIT", "DYNAMIC_CLASS", "INCOMPATIBLE"}; + return names[m_e]; + } + VCastable() + : m_e{UNSUPPORTED} {} + // cppcheck-suppress noExplicitConstructor + constexpr VCastable(en _e) + : m_e{_e} {} + explicit VCastable(int _e) + : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning + constexpr operator en() const { return m_e; } +}; +constexpr bool operator==(const VCastable& lhs, const VCastable& rhs) { + return lhs.m_e == rhs.m_e; +} +constexpr bool operator==(const VCastable& lhs, VCastable::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(VCastable::en lhs, const VCastable& rhs) { return lhs == rhs.m_e; } +inline std::ostream& operator<<(std::ostream& os, const VCastable& rhs) { + return os << rhs.ascii(); +} + +// ###################################################################### + class VBasicTypeKey final { public: const int m_width; // From AstNodeDType: Bit width of operation @@ -1989,6 +2028,10 @@ public: AstNodeDType* findBasicDType(VBasicDTypeKwd kwd) const; static AstBasicDType* findInsertSameDType(AstBasicDType* nodep); + static VCastable computeCastable(const AstNodeDType* toDtp, const AstNodeDType* fromDtp, + const AstNode* fromConstp); + static AstNodeDType* getCommonClassTypep(AstNode* nodep1, AstNode* nodep2); + // METHODS - dump and error void v3errorEnd(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex); void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 7dd6ffee7..507bcfbbc 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -25,7 +25,6 @@ #include "V3Hasher.h" #include "V3PartitionGraph.h" // Just for mtask dumping #include "V3String.h" -#include "V3Width.h" #include "V3Ast__gen_macros.h" // Generated by 'astgen' @@ -217,7 +216,7 @@ AstNodeCond::AstNodeCond(VNType t, FileLine* fl, AstNodeExpr* condp, AstNodeExpr UASSERT_OBJ(elsep, this, "No elsep expression"); if (thenp->isClassHandleValue() && elsep->isClassHandleValue()) { // Get the most-deriving class type that both arguments can be casted to. - AstNodeDType* const commonClassTypep = V3Width::getCommonClassTypep(thenp, elsep); + AstNodeDType* const commonClassTypep = getCommonClassTypep(thenp, elsep); UASSERT_OBJ(commonClassTypep, this, "No common base class exists"); dtypep(commonClassTypep); } else { diff --git a/src/V3Width.cpp b/src/V3Width.cpp index b87fe81e4..cecd6ad1b 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -108,21 +108,6 @@ std::ostream& operator<<(std::ostream& str, const Determ& rhs) { return str << s_det[rhs]; } -enum Castable : uint8_t { - UNSUPPORTED, - SAMEISH, - COMPATIBLE, - ENUM_EXPLICIT, - ENUM_IMPLICIT, - DYNAMIC_CLASS, - INCOMPATIBLE -}; -std::ostream& operator<<(std::ostream& str, const Castable& rhs) { - static const char* const s_det[] - = {"UNSUP", "IDENT", "COMPAT", "ENUM_EXP", "ENUM_IMP", "DYN_CLS", "INCOMPAT"}; - return str << s_det[rhs]; -} - #define v3widthWarn(lhs, rhs, msg) \ v3errorEnd( \ v3errorBuildMessage(V3Error::v3errorPrep((lhs) < (rhs) ? V3ErrorCode::WIDTHTRUNC \ @@ -518,7 +503,7 @@ private: if (nodep->thenp()->isClassHandleValue() && nodep->elsep()->isClassHandleValue()) { // Get the most-deriving class type that both arguments can be casted to. commonClassTypep - = V3Width::getCommonClassTypep(nodep->thenp(), nodep->elsep()); + = AstNode::getCommonClassTypep(nodep->thenp(), nodep->elsep()); } if (commonClassTypep) { nodep->dtypep(commonClassTypep); @@ -1842,12 +1827,12 @@ private: AstNodeDType* const toDtp = nodep->top()->dtypep()->skipRefToEnump(); AstNodeDType* const fromDtp = nodep->fromp()->dtypep()->skipRefToEnump(); FileLine* const fl = nodep->fileline(); - const auto castable = computeCastable(toDtp, fromDtp, nodep->fromp()); + const auto castable = AstNode::computeCastable(toDtp, fromDtp, nodep->fromp()); AstNode* newp; - if (castable == DYNAMIC_CLASS) { + if (castable == VCastable::DYNAMIC_CLASS) { // Keep in place, will compute at runtime return; - } else if (castable == ENUM_EXPLICIT || castable == ENUM_IMPLICIT) { + } else if (castable == VCastable::ENUM_EXPLICIT || castable == VCastable::ENUM_IMPLICIT) { // TODO is from is a constant we could simplify, though normal constant // elimination should do much the same // Form: "( ((v > size) ? false : enum_valid[v[N:0]]) @@ -1885,7 +1870,7 @@ private: nodep->fromp()->unlinkFrBack()}, new AstConst{fl, AstConst::Signed32{}, 1}}, new AstConst{fl, AstConst::Signed32{}, 0}}; - } else if (castable == SAMEISH || castable == COMPATIBLE) { + } else if (castable == VCastable::SAMEISH || castable == VCastable::COMPATIBLE) { nodep->v3warn(CASTCONST, "$cast will always return one as " << toDtp->prettyDTypeNameQ() << " is always castable from " @@ -1896,7 +1881,7 @@ private: new AstAssign{fl, nodep->top()->unlinkFrBack(), new AstCast{fl, nodep->fromp()->unlinkFrBack(), toDtp}}, new AstConst{fl, AstConst::Signed32{}, 1}}; - } else if (castable == INCOMPATIBLE) { + } else if (castable == VCastable::INCOMPATIBLE) { newp = new AstConst{fl, 0}; nodep->v3warn(CASTCONST, "$cast will always return zero as " << toDtp->prettyDTypeNameQ() << " is not castable from " @@ -1941,23 +1926,24 @@ private: userIterateAndNext(nodep->fromp(), WidthVP{SELF, PRELIM}.p()); AstNodeDType* const toDtp = nodep->dtypep()->skipRefToEnump(); AstNodeDType* const fromDtp = nodep->fromp()->dtypep()->skipRefToEnump(); - const auto castable = computeCastable(toDtp, fromDtp, nodep->fromp()); + const auto castable = AstNode::computeCastable(toDtp, fromDtp, nodep->fromp()); bool bad = false; - if (castable == UNSUPPORTED) { + if (castable == VCastable::UNSUPPORTED) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: static cast to " << toDtp->prettyDTypeNameQ() << " from " << fromDtp->prettyDTypeNameQ()); bad = true; - } else if (castable == SAMEISH || castable == COMPATIBLE || castable == ENUM_IMPLICIT - || castable == ENUM_EXPLICIT) { + } else if (castable == VCastable::SAMEISH || castable == VCastable::COMPATIBLE + || castable == VCastable::ENUM_IMPLICIT + || castable == VCastable::ENUM_EXPLICIT) { ; // Continue - } else if (castable == DYNAMIC_CLASS) { + } else if (castable == VCastable::DYNAMIC_CLASS) { nodep->v3error("Dynamic, not static cast, required to cast " << toDtp->prettyDTypeNameQ() << " from " << fromDtp->prettyDTypeNameQ() << '\n' << nodep->warnMore() << "... Suggest dynamic $cast"); bad = true; - } else if (castable == INCOMPATIBLE) { + } else if (castable == VCastable::INCOMPATIBLE) { nodep->v3error("Incompatible types to static cast to " << toDtp->prettyDTypeNameQ() << " from " << fromDtp->prettyDTypeNameQ() << '\n'); @@ -4407,7 +4393,8 @@ private: "Case(type) statement requires items that have type() items"); } else { AstNodeDType* const condDtp = VN_AS(condAttrp->fromp(), NodeDType); - if (computeCastable(exprDtp, condDtp, nodep) == SAMEISH) { + if (AstNode::computeCastable(exprDtp, condDtp, nodep) + == VCastable::SAMEISH) { hit = true; break; } @@ -6004,7 +5991,8 @@ private: UINFO(9, "==type lhsDtp " << lhsDtp << endl); UINFO(9, "==type rhsDtp " << lhsDtp << endl); const bool invert = VN_IS(nodep, NeqT); - const bool identical = computeCastable(lhsDtp, rhsDtp, nodep) == SAMEISH; + const bool identical + = AstNode::computeCastable(lhsDtp, rhsDtp, nodep) == VCastable::SAMEISH; UINFO(9, "== " << identical << endl); const bool eq = invert ^ identical; AstNode* const newp = new AstConst{nodep->fileline(), AstConst::BitTrue{}, eq}; @@ -6641,9 +6629,11 @@ private: if (expBasicp && underBasicp) { if (const AstEnumDType* const expEnump = VN_CAST(expDTypep->skipRefToEnump(), EnumDType)) { - const auto castable = computeCastable(expEnump, underp->dtypep(), underp); - if (castable != SAMEISH && castable != COMPATIBLE && castable != ENUM_IMPLICIT - && !VN_IS(underp, Cast) && !VN_IS(underp, CastDynamic) && !m_enumItemp + const auto castable + = AstNode::computeCastable(expEnump, underp->dtypep(), underp); + if (castable != VCastable::SAMEISH && castable != VCastable::COMPATIBLE + && castable != VCastable::ENUM_IMPLICIT && !VN_IS(underp, Cast) + && !VN_IS(underp, CastDynamic) && !m_enumItemp && !nodep->fileline()->warnIsOff(V3ErrorCode::ENUMVALUE) && warnOn) { underp->v3warn(ENUMVALUE, "Implicit conversion to enum " @@ -7363,68 +7353,9 @@ private: return false; } - //---------------------------------------------------------------------- - // METHODS - casting - static Castable computeCastableImp(const AstNodeDType* toDtp, const AstNodeDType* fromDtp, - const AstNode* fromConstp) { - const Castable castable = UNSUPPORTED; - toDtp = toDtp->skipRefToEnump(); - fromDtp = fromDtp->skipRefToEnump(); - if (toDtp == fromDtp) return SAMEISH; - if (toDtp->similarDType(fromDtp)) return SAMEISH; - // UNSUP unpacked struct/unions (treated like BasicDType) - const AstNodeDType* fromBaseDtp = computeCastableBase(fromDtp); - - const bool fromNumericable - = VN_IS(fromBaseDtp, BasicDType) || VN_IS(fromBaseDtp, EnumDType) - || VN_IS(fromBaseDtp, StreamDType) || VN_IS(fromBaseDtp, NodeUOrStructDType); - - const AstNodeDType* toBaseDtp = computeCastableBase(toDtp); - const bool toNumericable - = VN_IS(toBaseDtp, BasicDType) || VN_IS(toBaseDtp, NodeUOrStructDType); - - if (toBaseDtp == fromBaseDtp) { - return COMPATIBLE; - } else if (toNumericable) { - if (fromNumericable) return COMPATIBLE; - } else if (VN_IS(toDtp, EnumDType)) { - if (VN_IS(fromBaseDtp, EnumDType) && toDtp->sameTree(fromDtp)) return ENUM_IMPLICIT; - if (fromNumericable) return ENUM_EXPLICIT; - } else if (VN_IS(toDtp, ClassRefDType) && VN_IS(fromConstp, Const)) { - if (VN_IS(fromConstp, Const) && VN_AS(fromConstp, Const)->num().isNull()) - return COMPATIBLE; - } else if (VN_IS(toDtp, ClassRefDType) && VN_IS(fromDtp, ClassRefDType)) { - const auto toClassp = VN_AS(toDtp, ClassRefDType)->classp(); - const auto fromClassp = VN_AS(fromDtp, ClassRefDType)->classp(); - const bool downcast = AstClass::isClassExtendedFrom(toClassp, fromClassp); - const bool upcast = AstClass::isClassExtendedFrom(fromClassp, toClassp); - if (upcast) { - return COMPATIBLE; - } else if (downcast) { - return DYNAMIC_CLASS; - } else { - return INCOMPATIBLE; - } - } - return castable; - } - static const AstNodeDType* computeCastableBase(const AstNodeDType* nodep) { - while (true) { - if (const AstPackArrayDType* const packp = VN_CAST(nodep, PackArrayDType)) { - nodep = packp->subDTypep(); - continue; - } else if (const AstNodeDType* const refp = nodep->skipRefToEnump()) { - if (refp != nodep) { - nodep = refp; - continue; - } - } - return nodep; - } - } - //---------------------------------------------------------------------- // METHODS - special type detection + void assertAtStatement(AstNode* nodep) { if (VL_UNCOVERABLE(m_vup && !m_vup->selfDtm())) { UINFO(1, "-: " << m_vup << endl); @@ -7529,15 +7460,6 @@ public: return userIterateSubtreeReturnEdits(nodep, WidthVP{SELF, BOTH}.p()); } ~WidthVisitor() override = default; - - static Castable computeCastable(const AstNodeDType* toDtp, const AstNodeDType* fromDtp, - const AstNode* fromConstp) { - const auto castable = computeCastableImp(toDtp, fromDtp, fromConstp); - UINFO(9, " castable=" << castable << " for " << toDtp << endl); - UINFO(9, " =?= " << fromDtp << endl); - UINFO(9, " const= " << fromConstp << endl); - return castable; - } }; //###################################################################### @@ -7555,36 +7477,6 @@ void V3Width::width(AstNetlist* nodep) { } // Destruct before checking V3Global::dumpCheckGlobalTree("width", 0, dumpTreeLevel() >= 3); } - -AstNodeDType* V3Width::getCommonClassTypep(AstNode* nodep1, AstNode* nodep2) { - // Return the class type that both nodep1 and nodep2 are castable to. - // If both are null, return the type of null constant. - // If one is a class and one is null, return AstClassRefDType that points to that class. - // If no common class type exists, return nullptr. - - // First handle cases with null values and when one class is a super class of the other. - if (VN_IS(nodep1, Const)) std::swap(nodep1, nodep2); - { - const Castable castable - = WidthVisitor::computeCastable(nodep1->dtypep(), nodep2->dtypep(), nodep2); - if (castable == SAMEISH || castable == COMPATIBLE) { - return nodep1->dtypep(); - } else if (castable == DYNAMIC_CLASS) { - return nodep2->dtypep(); - } - } - - AstClassRefDType* classDtypep1 = VN_CAST(nodep1->dtypep(), ClassRefDType); - while (classDtypep1) { - const Castable castable - = WidthVisitor::computeCastable(classDtypep1, nodep2->dtypep(), nodep2); - if (castable == COMPATIBLE) return classDtypep1; - AstClassExtends* const extendsp = classDtypep1->classp()->extendsp(); - classDtypep1 = extendsp ? VN_AS(extendsp->dtypep(), ClassRefDType) : nullptr; - } - return nullptr; -} - //! Single node parameter propagation //! Smaller step... Only do a single node for parameter propagation AstNode* V3Width::widthParamsEdit(AstNode* nodep) { diff --git a/src/V3Width.h b/src/V3Width.h index fd9f17af5..0ac3a6b25 100644 --- a/src/V3Width.h +++ b/src/V3Width.h @@ -34,8 +34,6 @@ public: static AstNode* widthParamsEdit(AstNode* nodep) VL_MT_DISABLED; static AstNode* widthGenerateParamsEdit(AstNode* nodep) VL_MT_DISABLED; - static AstNodeDType* getCommonClassTypep(AstNode* nodep1, AstNode* nodep2) VL_MT_DISABLED; - // For use only in WidthVisitor // Replace AstSelBit, etc with AstSel/AstArraySel // Returns replacement node if nodep was deleted, or null if none. From a4b7c39a9abf32b4c3c964bdc9d1c772c72147cf Mon Sep 17 00:00:00 2001 From: Gus Smith Date: Tue, 10 Oct 2023 14:53:02 -0700 Subject: [PATCH 056/157] Fix Verilated Makefile to get CXX etc. from enviorment (#4549) (#4554) --- docs/CONTRIBUTORS | 1 + include/verilated.mk.in | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 92c0ec46c..09c1ae87b 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -49,6 +49,7 @@ Glen Gibb Gökçe Aydos Graham Rushton Guokai Chen +Gus Smith Gustav Svensk Harald Heckmann Hennadii Chernyshchyk diff --git a/include/verilated.mk.in b/include/verilated.mk.in index 4f138288b..6b0bda50d 100644 --- a/include/verilated.mk.in +++ b/include/verilated.mk.in @@ -9,12 +9,12 @@ # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 ###################################################################### -AR = @AR@ -CXX = @CXX@ -LINK = @CXX@ +AR ?= @AR@ +CXX ?= @CXX@ +LINK ?= @CXX@ OBJCACHE ?= @OBJCACHE@ -PERL = @PERL@ -PYTHON3 = @PYTHON3@ +PERL ?= @PERL@ +PYTHON3 ?= @PYTHON3@ CFG_WITH_CCWARN = @CFG_WITH_CCWARN@ CFG_WITH_LONGTESTS = @CFG_WITH_LONGTESTS@ From 7ce0bd1181d00c4bca0867717b1f5ed0356782bb Mon Sep 17 00:00:00 2001 From: Anthony Donlon <4056887+donlon@users.noreply.github.com> Date: Tue, 10 Oct 2023 22:55:40 +0100 Subject: [PATCH 057/157] Fix broken link error for enum references (#4551) --- src/V3AstNodeExpr.h | 4 +-- src/V3AstNodes.cpp | 6 +++++ test_regress/t/t_enum_param_class.pl | 21 ++++++++++++++++ test_regress/t/t_enum_param_class.v | 37 ++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 3 deletions(-) create mode 100755 test_regress/t/t_enum_param_class.pl create mode 100644 test_regress/t/t_enum_param_class.v diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 002b980c5..a4126dad0 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -1144,9 +1144,7 @@ public: string name() const override VL_MT_STABLE { return itemp()->name(); } int instrCount() const override { return 0; } const char* broken() const override; - void cloneRelink() override { - if (m_itemp->clonep()) m_itemp = m_itemp->clonep(); - } + void cloneRelink() override; bool same(const AstNode* samep) const override { const AstEnumItemRef* const sp = static_cast(samep); return itemp() == sp->itemp(); diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 507bcfbbc..7ba41a926 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1614,6 +1614,12 @@ const char* AstEnumItemRef::broken() const { BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); return nullptr; } +void AstEnumItemRef::cloneRelink() { + if (m_itemp->clonep()) m_itemp = m_itemp->clonep(); + if (m_classOrPackagep && m_classOrPackagep->clonep()) { + m_classOrPackagep = m_classOrPackagep->clonep(); + } +} void AstIfaceRefDType::dump(std::ostream& str) const { this->AstNodeDType::dump(str); if (cellName() != "") str << " cell=" << cellName(); diff --git a/test_regress/t/t_enum_param_class.pl b/test_regress/t/t_enum_param_class.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_enum_param_class.pl @@ -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 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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_enum_param_class.v b/test_regress/t/t_enum_param_class.v new file mode 100644 index 000000000..c59f4b523 --- /dev/null +++ b/test_regress/t/t_enum_param_class.v @@ -0,0 +1,37 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Anthony Donlon. +// SPDX-License-Identifier: CC0-1.0 + +/// (See bug4551) +/// Verilator creates an AstEnumItemRef for each reference. If the enum is inside a parameterizable class/module, it +/// should be handled properly. + +class ClsParam #( + int A = 0 +); + typedef enum int { + EN_A = A + 0, + EN_B = A + 1, + EN_C = A + 2 + } enums_t; + + int val = EN_C; + function int test(); + return EN_C; + endfunction +endclass; + +module t; + // localparam ENUM_VAL = ClsParam#(100)::EN_C; // TODO: Unsupported: dotted expressions in parameters + // $info("ENUM_VAL: %0d", ENUM_VAL); + + ClsParam#(100) cls = new; + initial begin + if (cls.test() != 102) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From 1fd8e772b0920684495d6367b58ac34e8f1c2ad0 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 10 Oct 2023 20:40:21 -0400 Subject: [PATCH 058/157] Fix loss of warning source content with `line enter (due to earlier commit 472ad90d837448ebc8e1647d54bbc4fa5bed681a). --- src/V3FileLine.h | 1 + src/V3ParseImp.cpp | 5 ++++- test_regress/t/t_lint_warn_incfile2_bad.out | 2 ++ test_regress/t/t_lint_warn_line_bad.out | 7 +++++++ test_regress/t/t_lint_warn_line_bad.pl | 22 +++++++++++++++++++++ test_regress/t/t_lint_warn_line_bad.v | 14 +++++++++++++ test_regress/t/t_vlt_warn_file_bad.out | 2 ++ 7 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 test_regress/t/t_lint_warn_line_bad.out create mode 100755 test_regress/t/t_lint_warn_line_bad.pl create mode 100644 test_regress/t/t_lint_warn_line_bad.v diff --git a/src/V3FileLine.h b/src/V3FileLine.h index 03cf71695..cdc6ab748 100644 --- a/src/V3FileLine.h +++ b/src/V3FileLine.h @@ -210,6 +210,7 @@ public: lineno(num); m_contentLineno = static_cast(num); } + void contentLinenoFrom(const FileLine* fromp) { m_contentLineno = fromp->m_contentLineno; } void lineno(int num) { m_firstLineno = num; m_lastLineno = num; diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index e2bfdedcf..1a058be02 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -85,8 +85,11 @@ void V3ParseImp::lexPpline(const char* textp) { lexFileline(newFl); lexFileline()->parent(prevFl); } else if (enterExit == 2) { // Exit + const FileLine* const prevFl = lexFileline(); if (FileLine* upFl = lexFileline()->parent()) { - lexFileline(upFl); // Restore warning state to upper file + // Must copy upFl as may be existing nodes that use the FileLine value + lexFileline(new FileLine{upFl}); // Restore warning state to upper file + lexFileline()->contentLinenoFrom(prevFl); } } if (enterExit != -1) { // Line/fn change diff --git a/test_regress/t/t_lint_warn_incfile2_bad.out b/test_regress/t/t_lint_warn_incfile2_bad.out index 5060cbd21..bea3e325b 100644 --- a/test_regress/t/t_lint_warn_incfile2_bad.out +++ b/test_regress/t/t_lint_warn_incfile2_bad.out @@ -1,5 +1,7 @@ %Warning-WIDTHTRUNC: t/t_lint_warn_incfile2_bad.v:13:17: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's CONST '64'h1' generates 64 bits. : ... note: In instance 't' + 13 | int warn_t = 64'h1; + | ^~~~~ ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. %Error: Exiting due to diff --git a/test_regress/t/t_lint_warn_line_bad.out b/test_regress/t/t_lint_warn_line_bad.out new file mode 100644 index 000000000..eec0f2982 --- /dev/null +++ b/test_regress/t/t_lint_warn_line_bad.out @@ -0,0 +1,7 @@ +%Warning-WIDTHTRUNC: the_line_file:13:17: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's CONST '64'h1' generates 64 bits. + : ... note: In instance 't' + 13 | int warn_t = 64'h1; + | ^~~~~ + ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest + ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. +%Error: Exiting due to diff --git a/test_regress/t/t_lint_warn_line_bad.pl b/test_regress/t/t_lint_warn_line_bad.pl new file mode 100755 index 000000000..b3cdb56a9 --- /dev/null +++ b/test_regress/t/t_lint_warn_line_bad.pl @@ -0,0 +1,22 @@ +#!/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(vlt => 1); + +lint( + # See also t/t_lint_warn_incfile1_bad + # See also t/t_vlt_warn_file_bad + verilator_flags2 => ["--no-std"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_lint_warn_line_bad.v b/test_regress/t/t_lint_warn_line_bad.v new file mode 100644 index 000000000..0c219e8a7 --- /dev/null +++ b/test_regress/t/t_lint_warn_line_bad.v @@ -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, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// Check that `line `__LINE__ still shows proper warning context + +`line `__LINE__ "the_line_file" 1 +`line `__LINE__ "the_line_file" 2 + +module t; + int warn_t = 64'h1; // Not suppressed - should warn +endmodule diff --git a/test_regress/t/t_vlt_warn_file_bad.out b/test_regress/t/t_vlt_warn_file_bad.out index 6ff3c6fe0..77804160c 100644 --- a/test_regress/t/t_vlt_warn_file_bad.out +++ b/test_regress/t/t_vlt_warn_file_bad.out @@ -1,5 +1,7 @@ %Warning-WIDTHTRUNC: t/t_vlt_warn_file_bad.v:11:17: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's CONST '64'h1' generates 64 bits. : ... note: In instance 't' + 11 | int warn_t = 64'h1; + | ^~~~~ ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. %Error: Exiting due to From bd4eede6b47bc894f73ba6151f2ffe63db8feb3d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 10 Oct 2023 20:43:32 -0400 Subject: [PATCH 059/157] Commentary: Changes update --- Changes | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changes b/Changes index 63b868510..0c7f831d4 100644 --- a/Changes +++ b/Changes @@ -34,7 +34,10 @@ Verilator 5.017 devel * Fix stream operations with operands of struct type (#4531) (#4532). [Ryszard Rozak, Antmicro Ltd.] * Fix 'this' in a constructor (#4533). [Ryszard Rozak, Antmicro Ltd.] * Fix stream shift operator of 32 bits (#4536). [Julien Faucher] +* Fix object destruction after a copy constructor (#4540) (#4541). [Ryszard Rozak, Antmicro Ltd.] * Fix inlining of real functions miscasting (#4543). [Andrew Nolte] +* Fix Verilated Makefile to get CXX etc. from environment (#4549) (#4554). [Gus Smith] +* Fix broken link error for enum references (#4551). [Anthony Donlon] * Fix preprocessor to show `line 2 on resumed file. From d699caf255412d4bfdc45886139329be500acd1d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 12 Oct 2023 04:22:58 -0400 Subject: [PATCH 060/157] Revert fix Verilated Makefile to get CXX etc. from environment (#4549) (#4554). --- Changes | 1 - include/verilated.mk.in | 14 +++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Changes b/Changes index 0c7f831d4..c34674158 100644 --- a/Changes +++ b/Changes @@ -36,7 +36,6 @@ Verilator 5.017 devel * Fix stream shift operator of 32 bits (#4536). [Julien Faucher] * Fix object destruction after a copy constructor (#4540) (#4541). [Ryszard Rozak, Antmicro Ltd.] * Fix inlining of real functions miscasting (#4543). [Andrew Nolte] -* Fix Verilated Makefile to get CXX etc. from environment (#4549) (#4554). [Gus Smith] * Fix broken link error for enum references (#4551). [Anthony Donlon] * Fix preprocessor to show `line 2 on resumed file. diff --git a/include/verilated.mk.in b/include/verilated.mk.in index 6b0bda50d..4c97a82e4 100644 --- a/include/verilated.mk.in +++ b/include/verilated.mk.in @@ -9,13 +9,17 @@ # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 ###################################################################### -AR ?= @AR@ -CXX ?= @CXX@ -LINK ?= @CXX@ +# Tool names. +# These are computed at configuration time, and most are not ?= +# to avoid picking up potentilly incorrect Make implicit variables +AR = @AR@ +CXX = @CXX@ +LINK = @CXX@ OBJCACHE ?= @OBJCACHE@ -PERL ?= @PERL@ -PYTHON3 ?= @PYTHON3@ +PERL = @PERL@ +PYTHON3 = @PYTHON3@ +# Configuration time options CFG_WITH_CCWARN = @CFG_WITH_CCWARN@ CFG_WITH_LONGTESTS = @CFG_WITH_LONGTESTS@ From edfd3d72064df6e9690dd8d44cbc148f13dfc1a6 Mon Sep 17 00:00:00 2001 From: Varun Koyyalagunta Date: Thu, 12 Oct 2023 17:08:58 -0500 Subject: [PATCH 061/157] Fix large constant buffer overflow (#4556) --- include/verilated_funcs.h | 56 ++++++++-------- test_regress/t/t_struct_param_overflow.pl | 21 ++++++ test_regress/t/t_struct_param_overflow.v | 81 +++++++++++++++++++++++ 3 files changed, 130 insertions(+), 28 deletions(-) create mode 100755 test_regress/t/t_struct_param_overflow.pl create mode 100644 test_regress/t/t_struct_param_overflow.v diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index 22285812e..4037b23c4 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -2111,60 +2111,60 @@ static inline WDataOutP VL_CONST_W_8X(int obits, WDataOutP o, VL_C_END_(obits, 8); } // -static inline WDataOutP VL_CONSTHI_W_1X(int obits, int lsb, WDataOutP obase, +static inline WDataOutP VL_CONSTHI_W_1X(int obits, int lsb, WDataOutP o, EData d0) VL_MT_SAFE { - WDataOutP o = obase + VL_WORDS_I(lsb); - o[0] = d0; + WDataOutP ohi = o + VL_WORDS_I(lsb); + ohi[0] = d0; VL_C_END_(obits, VL_WORDS_I(lsb) + 1); } -static inline WDataOutP VL_CONSTHI_W_2X(int obits, int lsb, WDataOutP obase, +static inline WDataOutP VL_CONSTHI_W_2X(int obits, int lsb, WDataOutP o, EData d1, EData d0) VL_MT_SAFE { - WDataOutP o = obase + VL_WORDS_I(lsb); - o[0] = d0; o[1] = d1; + WDataOutP ohi = o + VL_WORDS_I(lsb); + ohi[0] = d0; ohi[1] = d1; VL_C_END_(obits, VL_WORDS_I(lsb) + 2); } -static inline WDataOutP VL_CONSTHI_W_3X(int obits, int lsb, WDataOutP obase, +static inline WDataOutP VL_CONSTHI_W_3X(int obits, int lsb, WDataOutP o, EData d2, EData d1, EData d0) VL_MT_SAFE { - WDataOutP o = obase + VL_WORDS_I(lsb); - o[0] = d0; o[1] = d1; o[2] = d2; + WDataOutP ohi = o + VL_WORDS_I(lsb); + ohi[0] = d0; ohi[1] = d1; ohi[2] = d2; VL_C_END_(obits, VL_WORDS_I(lsb) + 3); } -static inline WDataOutP VL_CONSTHI_W_4X(int obits, int lsb, WDataOutP obase, +static inline WDataOutP VL_CONSTHI_W_4X(int obits, int lsb, WDataOutP o, EData d3, EData d2, EData d1, EData d0) VL_MT_SAFE { - WDataOutP o = obase + VL_WORDS_I(lsb); - o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3; + WDataOutP ohi = o + VL_WORDS_I(lsb); + ohi[0] = d0; ohi[1] = d1; ohi[2] = d2; ohi[3] = d3; VL_C_END_(obits, VL_WORDS_I(lsb) + 4); } -static inline WDataOutP VL_CONSTHI_W_5X(int obits, int lsb, WDataOutP obase, +static inline WDataOutP VL_CONSTHI_W_5X(int obits, int lsb, WDataOutP o, EData d4, EData d3, EData d2, EData d1, EData d0) VL_MT_SAFE { - WDataOutP o = obase + VL_WORDS_I(lsb); - o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3; - o[4] = d4; + WDataOutP ohi = o + VL_WORDS_I(lsb); + ohi[0] = d0; ohi[1] = d1; ohi[2] = d2; ohi[3] = d3; + ohi[4] = d4; VL_C_END_(obits, VL_WORDS_I(lsb) + 5); } -static inline WDataOutP VL_CONSTHI_W_6X(int obits, int lsb, WDataOutP obase, +static inline WDataOutP VL_CONSTHI_W_6X(int obits, int lsb, WDataOutP o, EData d5, EData d4, EData d3, EData d2, EData d1, EData d0) VL_MT_SAFE { - WDataOutP o = obase + VL_WORDS_I(lsb); - o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3; - o[4] = d4; o[5] = d5; + WDataOutP ohi = o + VL_WORDS_I(lsb); + ohi[0] = d0; ohi[1] = d1; ohi[2] = d2; ohi[3] = d3; + ohi[4] = d4; ohi[5] = d5; VL_C_END_(obits, VL_WORDS_I(lsb) + 6); } -static inline WDataOutP VL_CONSTHI_W_7X(int obits, int lsb, WDataOutP obase, +static inline WDataOutP VL_CONSTHI_W_7X(int obits, int lsb, WDataOutP o, EData d6, EData d5, EData d4, EData d3, EData d2, EData d1, EData d0) VL_MT_SAFE { - WDataOutP o = obase + VL_WORDS_I(lsb); - o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3; - o[4] = d4; o[5] = d5; o[6] = d6; + WDataOutP ohi = o + VL_WORDS_I(lsb); + ohi[0] = d0; ohi[1] = d1; ohi[2] = d2; ohi[3] = d3; + ohi[4] = d4; ohi[5] = d5; ohi[6] = d6; VL_C_END_(obits, VL_WORDS_I(lsb) + 7); } -static inline WDataOutP VL_CONSTHI_W_8X(int obits, int lsb, WDataOutP obase, +static inline WDataOutP VL_CONSTHI_W_8X(int obits, int lsb, WDataOutP o, EData d7, EData d6, EData d5, EData d4, EData d3, EData d2, EData d1, EData d0) VL_MT_SAFE { - WDataOutP o = obase + VL_WORDS_I(lsb); - o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3; - o[4] = d4; o[5] = d5; o[6] = d6; o[7] = d7; + WDataOutP ohi = o + VL_WORDS_I(lsb); + ohi[0] = d0; ohi[1] = d1; ohi[2] = d2; ohi[3] = d3; + ohi[4] = d4; ohi[5] = d5; ohi[6] = d6; ohi[7] = d7; VL_C_END_(obits, VL_WORDS_I(lsb) + 8); } diff --git a/test_regress/t/t_struct_param_overflow.pl b/test_regress/t/t_struct_param_overflow.pl new file mode 100755 index 000000000..859050d63 --- /dev/null +++ b/test_regress/t/t_struct_param_overflow.pl @@ -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 2023 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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_struct_param_overflow.v b/test_regress/t/t_struct_param_overflow.v new file mode 100644 index 000000000..97f3220ec --- /dev/null +++ b/test_regress/t/t_struct_param_overflow.v @@ -0,0 +1,81 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Varun Koyyalagunta. +// SPDX-License-Identifier: CC0-1.0 + +package config_pkg; + + localparam int unsigned N = 10; + + typedef struct packed { + logic [N-1:0][31:0] lo; + logic [N-1:0][31:0] hi; + logic [100-1:0][31:0] x; + int unsigned n; + } config_struct; + + function automatic logic subcheck(logic[31:0] lo, logic[31:0] hi, logic[31:0] val); + return lo <= val && val < hi; + endfunction + + function automatic logic check(config_struct cfg, logic[31:0] val); + logic[N-1:0] good = '0; + logic[N-1:0] bad = '0; + for (int i = 0; i < cfg.n; i++) begin + good[i] = subcheck(cfg.lo[i], cfg.hi[i], val); + end + for (int i = cfg.n; i < N; i++) begin + bad[i] = !(cfg.lo[i] == '0 && cfg.hi[i] == '0); + end + return good != '0 && bad == '0; + endfunction + +endpackage : config_pkg + +module t(/*AUTOARG*/ + // Inputs + clk +); + + input clk; + import config_pkg::*; + + parameter config_struct MY_CONFIG = '{ + lo: {((N-3)*32)'('0), 32'h00, 32'h10, 32'h20}, + hi: {((N-3)*32)'('0), 32'h10, 32'h20, 32'h30}, + x : 3200'h0deadbeef, + n : 3 + }; + + struct_submodule #(.MY_CONFIG(MY_CONFIG)) a_submodule_I (.clk); +endmodule : t + +module struct_submodule + import config_pkg::*; + #( + parameter config_struct MY_CONFIG = '0 + ) ( + input clk + ); + + logic [31:0] val; + logic c; + int count = 0; + + assign val = 3; + assign c = check(MY_CONFIG, count); + + always @(posedge clk) begin + count <= count + 1; + if (c != '1) begin + $error("c not 1"); + $stop; + end + if (count >= 10) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule : struct_submodule From 7eb09c3445d16544cb5fd70a9942d36f1315dad4 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 14 Oct 2023 15:19:19 -0400 Subject: [PATCH 062/157] Fix instance arrays connecting to array of structs (#4557). --- Changes | 1 + src/V3Inst.cpp | 6 ++-- test_regress/t/t_inst_array_struct.pl | 21 ++++++++++++ test_regress/t/t_inst_array_struct.v | 48 +++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 3 deletions(-) create mode 100755 test_regress/t/t_inst_array_struct.pl create mode 100644 test_regress/t/t_inst_array_struct.v diff --git a/Changes b/Changes index c34674158..4859331fe 100644 --- a/Changes +++ b/Changes @@ -37,6 +37,7 @@ Verilator 5.017 devel * Fix object destruction after a copy constructor (#4540) (#4541). [Ryszard Rozak, Antmicro Ltd.] * Fix inlining of real functions miscasting (#4543). [Andrew Nolte] * Fix broken link error for enum references (#4551). [Anthony Donlon] +* Fix instance arrays connecting to array of structs (#4557). [raphmaster] * Fix preprocessor to show `line 2 on resumed file. diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index 5f0455714..605dfbd0e 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -326,10 +326,10 @@ private: = nodep->exprp()->dtypep()->dimensions(false); UINFO(4, " PINVAR " << nodep->modVarp() << endl); UINFO(4, " EXP " << nodep->exprp() << endl); - UINFO(4, " modwidth ew=" << expwidth << " pw=" << modwidth << " ed=" << expDim.first - << "," << expDim.second << " pd=" << pinDim.first << "," + UINFO(4, " expwidth=" << expwidth << " modwidth=" << modwidth << " expDim(p,u)=" << expDim.first + << "," << expDim.second << " pinDim(p,u)=" << pinDim.first << "," << pinDim.second << endl); - if (expDim.first == pinDim.first && expDim.second == pinDim.second + 1) { + if (expDim.second == pinDim.second + 1) { // Connection to array, where array dimensions match the instant dimension const AstRange* const rangep = VN_AS(nodep->exprp()->dtypep(), UnpackArrayDType)->rangep(); diff --git a/test_regress/t/t_inst_array_struct.pl b/test_regress/t/t_inst_array_struct.pl new file mode 100755 index 000000000..859050d63 --- /dev/null +++ b/test_regress/t/t_inst_array_struct.pl @@ -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 2023 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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_inst_array_struct.v b/test_regress/t/t_inst_array_struct.v new file mode 100644 index 000000000..35831162e --- /dev/null +++ b/test_regress/t/t_inst_array_struct.v @@ -0,0 +1,48 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + typedef struct packed { + bit one; + bit two; + } ps_t; + + ps_t in0 [2]; + ps_t out0 [2]; + + bit [1:0] in1 [2] = {{1'b1, 1'b0}, {1'b0, 1'b1}}; + bit [1:0] out1 [2]; + + Sub sub0 [2] (in0, out0); + Sub sub1 [2] (in1, out1); + + int cyc; + + always @ (posedge clk) begin + cyc <= cyc + 1; + in0 = {{1'b1, 1'b0}, {1'b0, 1'b1}}; + if (cyc == 9) begin + $display("%p %p", in0, out0); + $display("%p %p", in1, out1); + if (out0[0] != 2'h2 || out0[1] != 2'h1) $stop; + if (out1[0] != 2'h2 || out1[1] != 2'h1) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule + +module Sub + (input bit [1:0] in, + output bit [1:0] out); + assign out = in; +endmodule From fa8eaf73558ba88f984d239f2871c2fb447b2db1 Mon Sep 17 00:00:00 2001 From: github action Date: Sat, 14 Oct 2023 19:20:22 +0000 Subject: [PATCH 063/157] Apply 'make format' --- src/V3Inst.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index 605dfbd0e..dd3e7e283 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -326,9 +326,10 @@ private: = nodep->exprp()->dtypep()->dimensions(false); UINFO(4, " PINVAR " << nodep->modVarp() << endl); UINFO(4, " EXP " << nodep->exprp() << endl); - UINFO(4, " expwidth=" << expwidth << " modwidth=" << modwidth << " expDim(p,u)=" << expDim.first - << "," << expDim.second << " pinDim(p,u)=" << pinDim.first << "," - << pinDim.second << endl); + UINFO(4, " expwidth=" << expwidth << " modwidth=" << modwidth + << " expDim(p,u)=" << expDim.first << "," << expDim.second + << " pinDim(p,u)=" << pinDim.first << "," << pinDim.second + << endl); if (expDim.second == pinDim.second + 1) { // Connection to array, where array dimensions match the instant dimension const AstRange* const rangep From b5a6b34968d3c87780e6e03104f9ab97f4e024b1 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 14 Oct 2023 18:28:47 -0400 Subject: [PATCH 064/157] Tests: Remove old hack from before unpacked structs --- test_regress/t/t_sv_cpu_code/ports.sv | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/test_regress/t/t_sv_cpu_code/ports.sv b/test_regress/t/t_sv_cpu_code/ports.sv index 3eeb00b3d..da9dbc25b 100644 --- a/test_regress/t/t_sv_cpu_code/ports.sv +++ b/test_regress/t/t_sv_cpu_code/ports.sv @@ -6,12 +6,6 @@ // Contributed by M W Lund, Atmel Corporation. -`ifdef VERILATOR //TODO - `define PACKED packed -`else - `define packed -`endif - module ports #( parameter ID = 1 ) @@ -42,12 +36,12 @@ module ports // **** Interal Registers **** - struct `PACKED + struct { logic [7:0][1:0] in; logic [7:0] dir; logic [7:0] out; - struct `PACKED + struct { logic [7:2] reserved; logic pullupen; From 411f563cbea549bb727df76b38e4493430fd7b3f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 14 Oct 2023 22:20:42 -0400 Subject: [PATCH 065/157] Internals: Remove unneeded pure checks. No functional change. --- src/V3Const.cpp | 2 +- src/V3Tristate.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 297cfb1f8..d3a95ae7b 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1884,7 +1884,7 @@ private: AstNodeExpr* const ap = lhsp->lhsp()->unlinkFrBack(); AstNodeExpr* const bp = lhsp->rhsp()->unlinkFrBack(); AstNodeBiop* const shift1p = nodep; - AstNodeBiop* const shift2p = nodep->cloneTreePure(true); + AstNodeBiop* const shift2p = nodep->cloneTree(true); shift1p->lhsp(ap); shift1p->rhsp(shiftp->cloneTreePure(true)); shift2p->lhsp(bp); diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index f13c1dfa0..00e92e6e9 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -518,14 +518,14 @@ class TristateVisitor final : public TristateBaseVisitor { // Unlink lhsp before copying to save unnecessary copy of lhsp AstNodeExpr* const lhsp = extendp->lhsp()->unlinkFrBack(); - AstExtend* const enExtendp = extendp->cloneTreePure(false); + AstExtend* const enExtendp = extendp->cloneTree(false); extendp->lhsp(lhsp); AstNodeExpr* 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)) { AstNodeExpr* const fromp = selp->fromp()->unlinkFrBack(); - AstSel* const enSelp = selp->cloneTreePure(false); + AstSel* const enSelp = selp->cloneTree(false); selp->fromp(fromp); AstNodeExpr* const enFromp = getEnExprBasedOnOriginalp(fromp); enSelp->fromp(enFromp); From 3940a214d0f8ece08ec4a29ed05808f51ca32b36 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 14 Oct 2023 22:22:00 -0400 Subject: [PATCH 066/157] Internals: Reorder some shift functions for next commit. No functional change. --- include/verilated_funcs.h | 40 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index 4037b23c4..57c47d46d 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -1647,6 +1647,14 @@ static inline void _vl_shiftl_inplace_w(int obits, WDataOutP iowp, // EMIT_RULE: VL_SHIFTL: oclean=lclean; rclean==clean; // Important: Unlike most other funcs, the shift might well be a computed // expression. Thus consider this when optimizing. (And perhaps have 2 funcs?) +static inline IData VL_SHIFTL_IIQ(int obits, int, int, IData lhs, QData rhs) VL_MT_SAFE { + if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0; + return VL_CLEAN_II(obits, obits, lhs << rhs); +} +static inline QData VL_SHIFTL_QQQ(int obits, int, int, QData lhs, QData rhs) VL_MT_SAFE { + if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0; + return VL_CLEAN_QQ(obits, obits, lhs << rhs); +} static inline WDataOutP VL_SHIFTL_WWI(int obits, int, int, WDataOutP owp, WDataInP const lwp, IData rd) VL_MT_SAFE { const int word_shift = VL_BITWORD_E(rd); @@ -1686,10 +1694,6 @@ static inline IData VL_SHIFTL_IIW(int obits, int, int rbits, IData lhs, } return VL_CLEAN_II(obits, obits, lhs << rwp[0]); } -static inline IData VL_SHIFTL_IIQ(int obits, int, int, IData lhs, QData rhs) VL_MT_SAFE { - if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0; - return VL_CLEAN_II(obits, obits, lhs << rhs); -} static inline QData VL_SHIFTL_QQW(int obits, int, int rbits, QData lhs, WDataInP const rwp) VL_MT_SAFE { for (int i = 1; i < VL_WORDS_I(rbits); ++i) { @@ -1700,14 +1704,18 @@ static inline QData VL_SHIFTL_QQW(int obits, int, int rbits, QData lhs, // Above checks rwp[1]==0 so not needed in below shift return VL_CLEAN_QQ(obits, obits, lhs << (static_cast(rwp[0]))); } -static inline QData VL_SHIFTL_QQQ(int obits, int, int, QData lhs, QData rhs) VL_MT_SAFE { - if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0; - return VL_CLEAN_QQ(obits, obits, lhs << rhs); -} // EMIT_RULE: VL_SHIFTR: oclean=lclean; rclean==clean; // Important: Unlike most other funcs, the shift might well be a computed // expression. Thus consider this when optimizing. (And perhaps have 2 funcs?) +static inline IData VL_SHIFTR_IIQ(int obits, int, int, IData lhs, QData rhs) VL_PURE { + if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0; + return VL_CLEAN_QQ(obits, obits, lhs >> rhs); +} +static inline QData VL_SHIFTR_QQQ(int obits, int, int, QData lhs, QData rhs) VL_PURE { + if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0; + return VL_CLEAN_QQ(obits, obits, lhs >> rhs); +} static inline WDataOutP VL_SHIFTR_WWI(int obits, int, int, WDataOutP owp, WDataInP const lwp, IData rd) VL_MT_SAFE { const int word_shift = VL_BITWORD_E(rd); // Maybe 0 @@ -1751,30 +1759,18 @@ static inline WDataOutP VL_SHIFTR_WWQ(int obits, int lbits, int rbits, WDataOutP static inline IData VL_SHIFTR_IIW(int obits, int, int rbits, IData lhs, WDataInP const rwp) VL_PURE { for (int i = 1; i < VL_WORDS_I(rbits); ++i) { - if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more - return 0; - } + if (VL_UNLIKELY(rwp[i])) return 0; // Huge shift 1>>32 or more } return VL_CLEAN_II(obits, obits, lhs >> rwp[0]); } static inline QData VL_SHIFTR_QQW(int obits, int, int rbits, QData lhs, WDataInP const rwp) VL_PURE { for (int i = 1; i < VL_WORDS_I(rbits); ++i) { - if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more - return 0; - } + if (VL_UNLIKELY(rwp[i])) return 0; // Huge shift 1>>32 or more } // Above checks rwp[1]==0 so not needed in below shift return VL_CLEAN_QQ(obits, obits, lhs >> (static_cast(rwp[0]))); } -static inline IData VL_SHIFTR_IIQ(int obits, int, int, IData lhs, QData rhs) VL_PURE { - if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0; - return VL_CLEAN_QQ(obits, obits, lhs >> rhs); -} -static inline QData VL_SHIFTR_QQQ(int obits, int, int, QData lhs, QData rhs) VL_PURE { - if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0; - return VL_CLEAN_QQ(obits, obits, lhs >> rhs); -} // EMIT_RULE: VL_SHIFTRS: oclean=false; lclean=clean, rclean==clean; static inline IData VL_SHIFTRS_III(int obits, int lbits, int, IData lhs, IData rhs) VL_PURE { From 46f8a659b37f3d3ff259f1bfa5939ece2acf3387 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 14 Oct 2023 22:34:37 -0400 Subject: [PATCH 067/157] Fix shift to remove operation side effects (#4563). --- Changes | 1 + include/verilated_funcs.h | 29 ++++++++-- src/V3AstNodeExpr.h | 76 +++++++++++++++++++++++++ src/V3Const.cpp | 24 +++++--- src/V3Premit.cpp | 72 +++++++++-------------- test_regress/t/t_const_opt.pl | 2 +- test_regress/t/t_const_opt_no_expand.pl | 2 +- test_regress/t/t_math_shift_side.pl | 21 +++++++ test_regress/t/t_math_shift_side.v | 40 +++++++++++++ 9 files changed, 206 insertions(+), 61 deletions(-) create mode 100755 test_regress/t/t_math_shift_side.pl create mode 100644 test_regress/t/t_math_shift_side.v diff --git a/Changes b/Changes index 4859331fe..73f5a63f5 100644 --- a/Changes +++ b/Changes @@ -38,6 +38,7 @@ Verilator 5.017 devel * Fix inlining of real functions miscasting (#4543). [Andrew Nolte] * Fix broken link error for enum references (#4551). [Anthony Donlon] * Fix instance arrays connecting to array of structs (#4557). [raphmaster] +* Fix shift to remove operation side effects (#4563). * Fix preprocessor to show `line 2 on resumed file. diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index 57c47d46d..db24cfe9c 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -1647,10 +1647,20 @@ static inline void _vl_shiftl_inplace_w(int obits, WDataOutP iowp, // EMIT_RULE: VL_SHIFTL: oclean=lclean; rclean==clean; // Important: Unlike most other funcs, the shift might well be a computed // expression. Thus consider this when optimizing. (And perhaps have 2 funcs?) +// If RHS (rd/rwp) is larger than the output, zeros (or all ones for >>>) must be returned +// (This corresponds to AstShift*Ovr Ast nodes) +static inline IData VL_SHIFTL_III(int obits, int, int, IData lhs, IData rhs) VL_MT_SAFE { + if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0; + return lhs << rhs; // Small is common so not clean return +} static inline IData VL_SHIFTL_IIQ(int obits, int, int, IData lhs, QData rhs) VL_MT_SAFE { if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0; return VL_CLEAN_II(obits, obits, lhs << rhs); } +static inline QData VL_SHIFTL_QQI(int obits, int, int, QData lhs, IData rhs) VL_MT_SAFE { + if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0; + return lhs << rhs; // Small is common so not clean return +} static inline QData VL_SHIFTL_QQQ(int obits, int, int, QData lhs, QData rhs) VL_MT_SAFE { if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0; return VL_CLEAN_QQ(obits, obits, lhs << rhs); @@ -1692,7 +1702,7 @@ static inline IData VL_SHIFTL_IIW(int obits, int, int rbits, IData lhs, return 0; } } - return VL_CLEAN_II(obits, obits, lhs << rwp[0]); + return VL_SHIFTL_III(obits, obits, 32, lhs, rwp[0]); } static inline QData VL_SHIFTL_QQW(int obits, int, int rbits, QData lhs, WDataInP const rwp) VL_MT_SAFE { @@ -1702,16 +1712,24 @@ static inline QData VL_SHIFTL_QQW(int obits, int, int rbits, QData lhs, } } // Above checks rwp[1]==0 so not needed in below shift - return VL_CLEAN_QQ(obits, obits, lhs << (static_cast(rwp[0]))); + return VL_SHIFTL_QQI(obits, obits, 32, lhs, rwp[0]); } // EMIT_RULE: VL_SHIFTR: oclean=lclean; rclean==clean; // Important: Unlike most other funcs, the shift might well be a computed // expression. Thus consider this when optimizing. (And perhaps have 2 funcs?) +static inline IData VL_SHIFTR_III(int obits, int, int, IData lhs, IData rhs) VL_PURE { + if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0; + return lhs >> rhs; // Small is common so assumed not clean +} static inline IData VL_SHIFTR_IIQ(int obits, int, int, IData lhs, QData rhs) VL_PURE { if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0; return VL_CLEAN_QQ(obits, obits, lhs >> rhs); } +static inline QData VL_SHIFTR_QQI(int obits, int, int, QData lhs, IData rhs) VL_PURE { + if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0; + return lhs >> rhs; // Small is common so assumed not clean +} static inline QData VL_SHIFTR_QQQ(int obits, int, int, QData lhs, QData rhs) VL_PURE { if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0; return VL_CLEAN_QQ(obits, obits, lhs >> rhs); @@ -1761,15 +1779,14 @@ static inline IData VL_SHIFTR_IIW(int obits, int, int rbits, IData lhs, for (int i = 1; i < VL_WORDS_I(rbits); ++i) { if (VL_UNLIKELY(rwp[i])) return 0; // Huge shift 1>>32 or more } - return VL_CLEAN_II(obits, obits, lhs >> rwp[0]); + return VL_SHIFTR_III(obits, obits, 32, lhs, rwp[0]); } static inline QData VL_SHIFTR_QQW(int obits, int, int rbits, QData lhs, WDataInP const rwp) VL_PURE { for (int i = 1; i < VL_WORDS_I(rbits); ++i) { if (VL_UNLIKELY(rwp[i])) return 0; // Huge shift 1>>32 or more } - // Above checks rwp[1]==0 so not needed in below shift - return VL_CLEAN_QQ(obits, obits, lhs >> (static_cast(rwp[0]))); + return VL_SHIFTR_QQI(obits, obits, 32, lhs, rwp[0]); } // EMIT_RULE: VL_SHIFTRS: oclean=false; lclean=clean, rclean==clean; @@ -1779,11 +1796,13 @@ static inline IData VL_SHIFTRS_III(int obits, int lbits, int, IData lhs, IData r // must use lbits for sign; lbits might != obits, // an EXTEND(SHIFTRS(...)) can became a SHIFTRS(...) within same 32/64 bit word length const IData sign = -(lhs >> (lbits - 1)); // ffff_ffff if negative + if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return sign & VL_MASK_I(obits); const IData signext = ~(VL_MASK_I(lbits) >> rhs); // One with bits where we've shifted "past" return (lhs >> rhs) | (sign & VL_CLEAN_II(obits, obits, signext)); } static inline QData VL_SHIFTRS_QQI(int obits, int lbits, int, QData lhs, IData rhs) VL_PURE { const QData sign = -(lhs >> (lbits - 1)); + if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return sign & VL_MASK_Q(obits); const QData signext = ~(VL_MASK_Q(lbits) >> rhs); return (lhs >> rhs) | (sign & VL_CLEAN_QQ(obits, obits, signext)); } diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index a4126dad0..009e4478b 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -3279,6 +3279,30 @@ public: bool sizeMattersLhs() const override { return true; } bool sizeMattersRhs() const override { return false; } }; +class AstShiftLOvr final : public AstNodeBiop { + // Like ShiftL but checks for an over shift and returns zeros + // TODO: All Verilog shifts should start as these and later get demoted to AstShiftL +public: + AstShiftLOvr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0) + : ASTGEN_SUPER_ShiftLOvr(fl, lhsp, rhsp) { + if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); + } + ASTGEN_MEMBERS_AstShiftLOvr; + AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override { + return new AstShiftLOvr{fileline(), lhsp, rhsp}; + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opShiftL(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f<< %r)"; } + string emitC() override { return "VL_SHIFTL_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + string emitSimpleOperator() override { return ""; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return true; } + bool sizeMattersRhs() const override { return false; } +}; class AstShiftR final : public AstNodeBiop { public: AstShiftR(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0) @@ -3304,6 +3328,31 @@ public: bool sizeMattersLhs() const override { return false; } bool sizeMattersRhs() const override { return false; } }; +class AstShiftROvr final : public AstNodeBiop { + // Like ShiftR but checks for an over shift and returns zeros + // TODO: All Verilog shifts should start as these and later get demoted to AstShiftR +public: + AstShiftROvr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0) + : ASTGEN_SUPER_ShiftROvr(fl, lhsp, rhsp) { + if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); + } + ASTGEN_MEMBERS_AstShiftROvr; + AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override { + return new AstShiftROvr{fileline(), lhsp, rhsp}; + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opShiftR(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f>> %r)"; } + string emitC() override { return "VL_SHIFTR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + string emitSimpleOperator() override { return ""; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + // LHS size might be > output size, so don't want to force size + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } +}; class AstShiftRS final : public AstNodeBiop { // Shift right with sign extension, >>> operator // Output data type's width determines which bit is used for sign extension @@ -3330,6 +3379,33 @@ public: bool sizeMattersRhs() const override { return false; } bool signedFlavor() const override { return true; } }; +class AstShiftRSOvr final : public AstNodeBiop { + // Shift right with sign extension, >>> operator, checks for an over shift and returns zeros + // Output data type's width determines which bit is used for sign extension + // TODO: All Verilog shifts should start as these and later get demoted to AstShiftRSOvr +public: + AstShiftRSOvr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0) + : ASTGEN_SUPER_ShiftRSOvr(fl, lhsp, rhsp) { + // Important that widthMin be correct, as opExtend requires it after V3Expand + if (setwidth) dtypeSetLogicSized(setwidth, VSigning::SIGNED); + } + ASTGEN_MEMBERS_AstShiftRSOvr; + AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override { + return new AstShiftRSOvr{fileline(), lhsp, rhsp}; + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opShiftRS(lhs, rhs, lhsp()->widthMinV()); + } + string emitVerilog() override { return "%k(%l %f>>> %r)"; } + string emitC() override { return "VL_SHIFTRS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + string emitSimpleOperator() override { return ""; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + bool signedFlavor() const override { return true; } +}; class AstSub final : public AstNodeBiop { public: AstSub(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp) diff --git a/src/V3Const.cpp b/src/V3Const.cpp index d3a95ae7b..1435d3ab0 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -3391,9 +3391,12 @@ private: TREEOP ("AstPowUS {$lhsp.isZero, !$rhsp.isZero}", "replaceZeroChkPure(nodep,$rhsp)"); TREEOP ("AstPowSU {$lhsp.isZero, !$rhsp.isZero}", "replaceZeroChkPure(nodep,$rhsp)"); TREEOP ("AstOr {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)"); - TREEOP ("AstShiftL{$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)"); - TREEOP ("AstShiftR{$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)"); - TREEOP ("AstShiftRS{$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)"); + TREEOP ("AstShiftL {$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)"); + TREEOP ("AstShiftLOvr {$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)"); + TREEOP ("AstShiftR {$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)"); + TREEOP ("AstShiftROvr {$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)"); + TREEOP ("AstShiftRS {$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)"); + TREEOP ("AstShiftRSOvr{$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)"); TREEOP ("AstXor {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)"); TREEOP ("AstSub {$lhsp.isZero, $rhsp}", "AstNegate{$rhsp}"); TREEOP ("AstAdd {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)"); @@ -3403,9 +3406,12 @@ private: TREEOP ("AstMul {$lhsp, $rhsp.isZero}", "replaceZeroChkPure(nodep,$lhsp)"); TREEOP ("AstMulS {$lhsp, $rhsp.isZero}", "replaceZeroChkPure(nodep,$lhsp)"); TREEOP ("AstOr {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)"); - TREEOP ("AstShiftL{$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)"); - TREEOP ("AstShiftR{$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)"); - TREEOP ("AstShiftRS{$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)"); + TREEOP ("AstShiftL {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)"); + TREEOP ("AstShiftLOvr {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)"); + TREEOP ("AstShiftR {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)"); + TREEOP ("AstShiftROvr {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)"); + TREEOP ("AstShiftRS {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)"); + TREEOP ("AstShiftRSOvr{$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)"); TREEOP ("AstSub {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)"); TREEOP ("AstXor {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)"); // Non-zero on one side or the other @@ -3500,8 +3506,10 @@ private: TREEOPV("AstNot {$lhsp.castGteS, $lhsp.width1}", "AstLtS {$lhsp->castGteS()->lhsp(),$lhsp->castGteS()->rhsp()}"); TREEOP ("AstLogNot{$lhsp.castGteS}", "AstLtS {$lhsp->castGteS()->lhsp(),$lhsp->castGteS()->rhsp()}"); // Not common, but avoids compiler warnings about over shifting - TREEOP ("AstShiftL{operandHugeShiftL(nodep)}", "replaceZero(nodep)"); - TREEOP ("AstShiftR{operandHugeShiftR(nodep)}", "replaceZero(nodep)"); + TREEOP ("AstShiftL {operandHugeShiftL(nodep)}", "replaceZero(nodep)"); + TREEOP ("AstShiftLOvr{operandHugeShiftL(nodep)}", "replaceZero(nodep)"); + TREEOP ("AstShiftR {operandHugeShiftR(nodep)}", "replaceZero(nodep)"); + TREEOP ("AstShiftROvr{operandHugeShiftR(nodep)}", "replaceZero(nodep)"); TREEOP ("AstShiftL{operandShiftOp(nodep)}", "replaceShiftOp(nodep)"); TREEOP ("AstShiftR{operandShiftOp(nodep)}", "replaceShiftOp(nodep)"); TREEOP ("AstShiftL{operandShiftShift(nodep)}", "replaceShiftShift(nodep)"); diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 78a748543..40ffc1c9e 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -49,11 +49,8 @@ class PremitVisitor final : public VNVisitor { private: // NODE STATE // AstNodeExpr::user() -> bool. True if iterated already - // AstShiftL::user2() -> bool. True if converted to conditional - // AstShiftR::user2() -> bool. True if converted to conditional // *::user3() -> Used when visiting AstNodeAssign const VNUser1InUse m_inuser1; - const VNUser2InUse m_inuser2; // STATE - across all visitors VDouble0 m_extractedToConstPool; // Statistic tracking @@ -236,47 +233,33 @@ private: } void visitShift(AstNodeBiop* nodep) { // Shifts of > 32/64 bits in C++ will wrap-around and generate non-0s - if (!nodep->user2SetOnce()) { - UINFO(4, " ShiftFix " << nodep << endl); - const AstConst* const shiftp = VN_CAST(nodep->rhsp(), Const); - if (shiftp && shiftp->num().mostSetBitP1() > 32) { - shiftp->v3error( - "Unsupported: Shifting of by over 32-bit number isn't supported." - << " (This isn't a shift of 32 bits, but a shift of 2^32, or 4 billion!)\n"); - } - if (nodep->widthMin() <= 64 // Else we'll use large operators which work right - // C operator's width must be < maximum shift which is - // based on Verilog width - && nodep->width() < (1LL << nodep->rhsp()->widthMin())) { - VNRelinker replaceHandle; - nodep->unlinkFrBack(&replaceHandle); - AstNodeExpr* constzerop; - const int m1value - = nodep->widthMin() - 1; // Constant of width-1; not changing dtype width - if (nodep->signedFlavor()) { - // Then over shifting gives the sign bit, not all zeros - // Note *NOT* clean output -- just like normal shift! - // Create equivalent of VL_SIGNONES_(node_width) - constzerop = new AstNegate{ - nodep->fileline(), - new AstShiftR{nodep->fileline(), nodep->lhsp()->cloneTreePure(false), - new AstConst(nodep->fileline(), m1value), nodep->width()}}; - } else { - constzerop = new AstConst{nodep->fileline(), AstConst::WidthedValue{}, - nodep->width(), 0}; - } - constzerop->dtypeFrom(nodep); // unsigned - - AstNodeExpr* const constwidthp - = new AstConst(nodep->fileline(), AstConst::WidthedValue{}, - nodep->rhsp()->widthMin(), m1value); - constwidthp->dtypeFrom(nodep->rhsp()); // unsigned - AstCond* const newp = new AstCond{nodep->fileline(), - new AstGte{nodep->fileline(), constwidthp, - nodep->rhsp()->cloneTreePure(false)}, - nodep, constzerop}; - replaceHandle.relink(newp); + UINFO(4, " ShiftFix " << nodep << endl); + const AstConst* const shiftp = VN_CAST(nodep->rhsp(), Const); + if (shiftp && shiftp->num().mostSetBitP1() > 32) { + shiftp->v3error( + "Unsupported: Shifting of by over 32-bit number isn't supported." + << " (This isn't a shift of 32 bits, but a shift of 2^32, or 4 billion!)\n"); + } + if (nodep->widthMin() <= 64 // Else we'll use large operators which work right + // C operator's width must be < maximum shift which is + // based on Verilog width + && nodep->width() < (1LL << nodep->rhsp()->widthMin())) { + AstNode* newp; + if (VN_IS(nodep, ShiftL)) { + newp = new AstShiftLOvr{nodep->fileline(), nodep->lhsp()->unlinkFrBack(), + nodep->rhsp()->unlinkFrBack()}; + } else if (VN_IS(nodep, ShiftR)) { + newp = new AstShiftROvr{nodep->fileline(), nodep->lhsp()->unlinkFrBack(), + nodep->rhsp()->unlinkFrBack()}; + } else { + UASSERT_OBJ(VN_IS(nodep, ShiftRS), nodep, "Bad case"); + newp = new AstShiftRSOvr{nodep->fileline(), nodep->lhsp()->unlinkFrBack(), + nodep->rhsp()->unlinkFrBack()}; } + newp->dtypeFrom(nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + return; } iterateChildren(nodep); checkNode(nodep); @@ -403,9 +386,6 @@ public: } }; -//---------------------------------------------------------------------- -// Top loop - //###################################################################### // Premit class functions diff --git a/test_regress/t/t_const_opt.pl b/test_regress/t/t_const_opt.pl index c01b55613..9d9becae5 100755 --- a/test_regress/t/t_const_opt.pl +++ b/test_regress/t/t_const_opt.pl @@ -20,7 +20,7 @@ execute( ); if ($Self->{vlt}) { - file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 39); + file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 36); } ok(1); 1; diff --git a/test_regress/t/t_const_opt_no_expand.pl b/test_regress/t/t_const_opt_no_expand.pl index db812ea9a..d4701df03 100755 --- a/test_regress/t/t_const_opt_no_expand.pl +++ b/test_regress/t/t_const_opt_no_expand.pl @@ -21,7 +21,7 @@ execute( ); if ($Self->{vlt}) { - file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 2); + file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 1); } ok(1); 1; diff --git a/test_regress/t/t_math_shift_side.pl b/test_regress/t/t_math_shift_side.pl new file mode 100755 index 000000000..859050d63 --- /dev/null +++ b/test_regress/t/t_math_shift_side.pl @@ -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 2023 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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_math_shift_side.v b/test_regress/t/t_math_shift_side.v new file mode 100644 index 000000000..fe3c66924 --- /dev/null +++ b/test_regress/t/t_math_shift_side.v @@ -0,0 +1,40 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Cls; + int m_n_bits; + + function int get_n_bytes; + return ((m_n_bits - 1) / 8) + 1; + endfunction + +endclass + +module t(/*AUTOARG*/); + + int i; + + initial begin + Cls c; + c = new; + + c.m_n_bits = 23; + if (c.get_n_bytes() != 3) $stop; + + i = 1 << c.get_n_bytes(); + if (i != 8) $stop; + + i = 32'h1234 >> c.get_n_bytes(); + if (i != 32'h246) $stop; + + i = 32'shffffffff >>> c.get_n_bytes(); + if (i != 32'hffffffff) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From 684aba0e901738398fc92d0cd6b550ce5bbbbb92 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 15 Oct 2023 06:25:42 -0400 Subject: [PATCH 068/157] Fix purity calculation during V3Const simplifying Ast --- src/V3Ast.cpp | 2 +- src/V3Ast.h | 11 ++++++----- src/V3AstNodeExpr.h | 7 ------- src/V3AstNodes.cpp | 26 -------------------------- src/V3Inline.cpp | 2 +- src/V3LinkDot.cpp | 1 + src/V3Premit.cpp | 2 +- src/V3Scope.cpp | 2 +- src/V3Task.cpp | 2 +- 9 files changed, 12 insertions(+), 43 deletions(-) diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 6115dabf8..e85a2f980 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -33,7 +33,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; //====================================================================== // Statics -uint32_t VIsCached::s_cachedCntGbl = 1; +uint64_t VIsCached::s_cachedCntGbl = 1; uint64_t AstNode::s_editCntLast = 0; uint64_t AstNode::s_editCntGbl = 0; // Hot cache line diff --git a/src/V3Ast.h b/src/V3Ast.h index 38dba7714..7fb97634d 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -171,10 +171,9 @@ class VIsCached final { // Used in some nodes to cache results of boolean methods // If cachedCnt == 0, not cached // else if cachedCnt == s_cachedCntGbl, then m_state is if cached - uint32_t m_cachedCnt : 31; // Mark of when cache was computed - uint32_t m_state : 1; - static uint32_t s_cachedCntGbl; // Global computed count - static constexpr uint32_t MAX_CNT = (1UL << 31) - 1; // Max for m_cachedCnt + uint64_t m_cachedCnt : 63; // Mark of when cache was computed + uint64_t m_state : 1; + static uint64_t s_cachedCntGbl; // Global computed count public: VIsCached() @@ -192,7 +191,8 @@ public: } static void clearCacheTree() { ++s_cachedCntGbl; - UASSERT_STATIC(s_cachedCntGbl < MAX_CNT, "Overflow of cache counting"); + // 64 bits so won't overflow + // UASSERT_STATIC(s_cachedCntGbl < MAX_CNT, "Overflow of cache counting"); } }; @@ -1956,6 +1956,7 @@ public: uint64_t editCount() const { return m_editCount; } void editCountInc() { m_editCount = ++s_editCntGbl; // Preincrement, so can "watch AstNode::s_editCntGbl=##" + VIsCached::clearCacheTree(); // Any edit clears all caching } #else void editCountInc() { ++s_editCntGbl; } diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 009e4478b..580c5e3ce 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -64,7 +64,6 @@ public: // Wrap This expression into an AstStmtExpr to denote it occurs in statement position inline AstStmtExpr* makeStmt(); - virtual void clearCachedPurity(){}; // Most nodes don't cache their purity }; class AstNodeBiop VL_NOT_FINAL : public AstNodeExpr { // Binary expression @@ -98,7 +97,6 @@ public: bool same(const AstNode*) const override { return true; } bool isPure() override; const char* broken() const override; - void clearCachedPurity() override; private: bool getPurityRecurse() const { return lhsp()->isPure() && rhsp()->isPure(); } @@ -265,7 +263,6 @@ public: string emitVerilog() final override { V3ERROR_NA_RETURN(""); } string emitC() final override { V3ERROR_NA_RETURN(""); } bool cleanOut() const final override { V3ERROR_NA_RETURN(true); } - void clearCachedPurity() override; private: bool getPurityRecurse() const; @@ -296,7 +293,6 @@ public: bool cleanOut() const final override { V3ERROR_NA_RETURN(true); } bool isPure() override; const char* broken() const override; - void clearCachedPurity() override; private: bool getPurityRecurse() const { @@ -340,7 +336,6 @@ public: bool same(const AstNode*) const override { return true; } bool isPure() override; const char* broken() const override; - void clearCachedPurity() override; private: bool getPurityRecurse() const { @@ -393,7 +388,6 @@ public: bool same(const AstNode*) const override { return true; } bool isPure() override; const char* broken() const override; - void clearCachedPurity() override; private: bool getPurityRecurse() const { @@ -473,7 +467,6 @@ public: bool same(const AstNode*) const override { return true; } bool isPure() override; const char* broken() const override; - void clearCachedPurity() override; }; class AstNodeSystemUniopD VL_NOT_FINAL : public AstNodeUniop { public: diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 7ba41a926..ccd0c24ed 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -72,11 +72,6 @@ bool AstNodeFTaskRef::isPure() { } } -void AstNodeFTaskRef::clearCachedPurity() { - m_purity.clearCache(); - if (AstNodeExpr* const exprp = VN_CAST(backp(), NodeExpr)) exprp->clearCachedPurity(); -} - bool AstNodeFTaskRef::getPurityRecurse() const { AstNodeFTask* const taskp = this->taskp(); // Unlinked yet, so treat as impure @@ -152,11 +147,6 @@ const char* AstNodeUniop::broken() const { BROKEN_RTN(m_purity.isCached() && m_purity.get() != lhsp()->isPure()); return nullptr; } -void AstNodeUniop::clearCachedPurity() { - m_purity.clearCache(); - if (AstNodeExpr* const exprp = VN_CAST(backp(), NodeExpr)) exprp->clearCachedPurity(); -} - bool AstNodeBiop::isPure() { if (!m_purity.isCached()) m_purity.set(getPurityRecurse()); return m_purity.get(); @@ -165,10 +155,6 @@ const char* AstNodeBiop::broken() const { BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse()); return nullptr; } -void AstNodeBiop::clearCachedPurity() { - m_purity.clearCache(); - if (AstNodeExpr* const exprp = VN_CAST(backp(), NodeExpr)) exprp->clearCachedPurity(); -} bool AstNodeTriop::isPure() { if (!m_purity.isCached()) m_purity.set(getPurityRecurse()); @@ -178,10 +164,6 @@ const char* AstNodeTriop::broken() const { BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse()); return nullptr; } -void AstNodeTriop::clearCachedPurity() { - m_purity.clearCache(); - if (AstNodeExpr* const exprp = VN_CAST(backp(), NodeExpr)) exprp->clearCachedPurity(); -} bool AstNodePreSel::isPure() { if (!m_purity.isCached()) m_purity.set(getPurityRecurse()); @@ -191,10 +173,6 @@ const char* AstNodePreSel::broken() const { BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse()); return nullptr; } -void AstNodePreSel::clearCachedPurity() { - m_purity.clearCache(); - if (AstNodeExpr* const exprp = VN_CAST(backp(), NodeExpr)) exprp->clearCachedPurity(); -} bool AstNodeQuadop::isPure() { if (!m_purity.isCached()) m_purity.set(getPurityRecurse()); @@ -204,10 +182,6 @@ const char* AstNodeQuadop::broken() const { BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse()); return nullptr; } -void AstNodeQuadop::clearCachedPurity() { - m_purity.clearCache(); - if (AstNodeExpr* const exprp = VN_CAST(backp(), NodeExpr)) exprp->clearCachedPurity(); -} AstNodeCond::AstNodeCond(VNType t, FileLine* fl, AstNodeExpr* condp, AstNodeExpr* thenp, AstNodeExpr* elsep) diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index f704c9fb7..4735bc079 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -174,7 +174,7 @@ private: // MethodCalls not currently supported by inliner, so keep linked if (!nodep->classOrPackagep() && !VN_IS(nodep, MethodCall)) { nodep->taskp(nullptr); - nodep->clearCachedPurity(); + VIsCached::clearCacheTree(); } iterateChildren(nodep); } diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 7ea95b46f..dd9a6548c 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -3726,6 +3726,7 @@ public: // Link class functions void V3LinkDot::linkDotGuts(AstNetlist* rootp, VLinkDotStep step) { + VIsCached::clearCacheTree(); // Avoid using any stale isPure if (debug() >= 5 || dumpTreeLevel() >= 9) { v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot.tree")); } diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 40ffc1c9e..57a5c3826 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -331,7 +331,7 @@ private: // We're going to need the expression several times in the expanded code, // so might as well make it a common expression createDeepTemp(nodep->condp(), false); - nodep->clearCachedPurity(); + VIsCached::clearCacheTree(); } checkNode(nodep); } diff --git a/src/V3Scope.cpp b/src/V3Scope.cpp index c68b14fe8..c60a8c935 100644 --- a/src/V3Scope.cpp +++ b/src/V3Scope.cpp @@ -396,7 +396,7 @@ private: UINFO(9, " New pkg-taskref " << nodep << endl); } else if (!VN_IS(nodep, MethodCall)) { nodep->taskp(nullptr); - nodep->clearCachedPurity(); + VIsCached::clearCacheTree(); UINFO(9, " New pkg-taskref " << nodep << endl); } iterateChildren(nodep); diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 576342885..5e1ce27a0 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -1469,9 +1469,9 @@ private: beginp = new AstExprStmt{nodep->fileline(), beginp, outrefp}; // AstExprStmt is currently treated as impure, so clear the cached purity of its // parents - nodep->clearCachedPurity(); nodep->replaceWith(beginp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + VIsCached::clearCacheTree(); } else { insertBeforeStmt(nodep, beginp); if (nodep->taskp()->isFunction()) { From c14eae6d5620efe159ac3f35c92eed6d233536cd Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 15 Oct 2023 06:44:35 -0400 Subject: [PATCH 069/157] Add SIDEEFFECT warning on mishandled side effect cases (#487 partial) --- Changes | 1 + docs/guide/warnings.rst | 33 ++++++++++++++++++++++++ src/V3Ast.cpp | 27 ++++++++++++------- src/V3Ast.h | 8 +++--- src/V3Error.h | 7 +++-- src/V3LinkInc.cpp | 20 -------------- test_regress/t/t_altera_lpm.v | 2 ++ test_regress/t/t_expr_incr_unsup.out | 10 +++++-- test_regress/t/t_lint_sideeffect_bad.out | 24 +++++++++++++++++ test_regress/t/t_lint_sideeffect_bad.pl | 19 ++++++++++++++ test_regress/t/t_lint_sideeffect_bad.v | 22 ++++++++++++++++ test_regress/t/t_stmt_incr_unsup.out | 10 +++++-- test_regress/t/t_sv_cpu_code/ports.sv | 2 ++ 13 files changed, 145 insertions(+), 40 deletions(-) create mode 100644 test_regress/t/t_lint_sideeffect_bad.out create mode 100755 test_regress/t/t_lint_sideeffect_bad.pl create mode 100644 test_regress/t/t_lint_sideeffect_bad.v diff --git a/Changes b/Changes index 73f5a63f5..cc313c39f 100644 --- a/Changes +++ b/Changes @@ -13,6 +13,7 @@ Verilator 5.017 devel **Minor:** +* Add SIDEEFFECT warning on mishandled side effect cases. * Add trace() API even when Verilated without --trace (#4462). [phelter] * Add warning on interface instantiation without parens (#4094). [Gökçe Aydos] * Support randc (#4349). diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst index 4588fd28b..2691e9acf 100644 --- a/docs/guide/warnings.rst +++ b/docs/guide/warnings.rst @@ -1514,6 +1514,39 @@ List Of Warnings modeled values, or DPI calls. +.. option:: SIDEEFFECT + + Warns that an expression has a side effect that might not properly be + executed by Verilator. + + This often represents a bug in Verilator, as opposed to a bad code + construct, however the Verilog code can typically be changed to avoid + the warning. + + Faulty example: + + .. code-block:: sv + :linenos: + :emphasize-lines: 1 + + x = y[a++]; + + This example warns because Verilator does not currently handle side + effects inside array subscripts; the a++ may be executed multiple times. + + Rewrite the code to avoid expression side effects, typically by using a + temporary: + + .. code-block:: sv + :linenos: + + temp = a++; + x = y[temp]; + + Ignoring this warning may make Verilator simulations differ from other + simulators. + + .. option:: SPLITVAR Warns that a variable with a :option:`/*verilator&32;split_var*/` diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index e85a2f980..30ebd67cf 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -801,26 +801,33 @@ void AstNode::swapWith(AstNode* bp) { //====================================================================== // Clone -AstNode* AstNode::cloneTreeIter() { +AstNode* AstNode::cloneTreeIter(bool needPure) { // private: Clone single node and children + if (VL_UNLIKELY(needPure && !isPure())) { + this->v3warn(SIDEEFFECT, + "Expression side effect may be mishandled\n" + << this->warnMore() + << "... Suggest use a temporary variable in place of this expression"); + // this->v3fatalSrc("cloneTreePure debug backtrace"); // Comment in to debug where caused it + } AstNode* const newp = this->clone(); - if (this->m_op1p) newp->op1p(this->m_op1p->cloneTreeIterList()); - if (this->m_op2p) newp->op2p(this->m_op2p->cloneTreeIterList()); - if (this->m_op3p) newp->op3p(this->m_op3p->cloneTreeIterList()); - if (this->m_op4p) newp->op4p(this->m_op4p->cloneTreeIterList()); + if (this->m_op1p) newp->op1p(this->m_op1p->cloneTreeIterList(needPure)); + if (this->m_op2p) newp->op2p(this->m_op2p->cloneTreeIterList(needPure)); + if (this->m_op3p) newp->op3p(this->m_op3p->cloneTreeIterList(needPure)); + if (this->m_op4p) newp->op4p(this->m_op4p->cloneTreeIterList(needPure)); newp->m_iterpp = nullptr; newp->clonep(this); // Save pointers to/from both to simplify relinking. this->clonep(newp); // Save pointers to/from both to simplify relinking. return newp; } -AstNode* AstNode::cloneTreeIterList() { +AstNode* AstNode::cloneTreeIterList(bool needPure) { // private: Clone list of nodes, set m_headtailp AstNode* newheadp = nullptr; AstNode* newtailp = nullptr; // Audited to make sure this is never nullptr for (AstNode* oldp = this; oldp; oldp = oldp->m_nextp) { - AstNode* const newp = oldp->cloneTreeIter(); + AstNode* const newp = oldp->cloneTreeIter(needPure); newp->m_headtailp = nullptr; newp->m_backp = newtailp; if (newtailp) newtailp->m_nextp = newp; @@ -832,14 +839,14 @@ AstNode* AstNode::cloneTreeIterList() { return newheadp; } -AstNode* AstNode::cloneTree(bool cloneNextLink) { +AstNode* AstNode::cloneTree(bool cloneNextLink, bool needPure) { debugTreeChange(this, "-cloneThs: ", __LINE__, cloneNextLink); cloneClearTree(); AstNode* newp; if (cloneNextLink && this->m_nextp) { - newp = cloneTreeIterList(); + newp = cloneTreeIterList(needPure); } else { - newp = cloneTreeIter(); + newp = cloneTreeIter(needPure); newp->m_nextp = nullptr; newp->m_headtailp = newp; } diff --git a/src/V3Ast.h b/src/V3Ast.h index 7fb97634d..402f4b8eb 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1713,8 +1713,8 @@ class AstNode VL_NOT_FINAL { } private: - AstNode* cloneTreeIter(); - AstNode* cloneTreeIterList(); + AstNode* cloneTreeIter(bool needPure); + AstNode* cloneTreeIterList(bool needPure); void checkTreeIter(const AstNode* prevBackp) const VL_MT_STABLE; bool gateTreeIter() const; static bool sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ignNext, @@ -2074,8 +2074,8 @@ public: AstNode* belowp); // When calling, "this" is second argument // METHODS - Iterate on a tree - AstNode* cloneTree(bool cloneNextLink); // Not const, as sets clonep() on original nodep // - AstNode* cloneTreePure(bool cloneNextLink) { return cloneTree(cloneNextLink); } + AstNode* cloneTree(bool cloneNextLink, bool needPure = false); // Not const, as sets clonep() on original nodep + AstNode* cloneTreePure(bool cloneNextLink) { return cloneTree(cloneNextLink, true); } bool gateTree() { return gateTreeIter(); } // Is tree isGateOptimizable? inline bool sameTree(const AstNode* node2p) const; // Does tree of this == node2p? // Does tree of this == node2p?, not allowing non-isGateOptimizable diff --git a/src/V3Error.h b/src/V3Error.h index 87c6c0bad..3513c3902 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -136,6 +136,7 @@ public: RISEFALLDLY, // Unsupported: rise/fall/turn-off delays SELRANGE, // Selection index out of range SHORTREAL, // Shortreal not supported + SIDEEFFECT, // Sideeffect ignored SPLITVAR, // Cannot split the variable STATICVAR, // Static variable declared in a loop with a declaration assignment STMTDLY, // Delayed statement @@ -203,7 +204,8 @@ public: "MULTIDRIVEN", "MULTITOP", "NEWERSTD", "NOLATCH", "NULLPORT", "PINCONNECTEMPTY", "PINMISSING", "PINNOCONNECT", "PINNOTFOUND", "PKGNODECL", "PROCASSWIRE", "PROFOUTOFDATE", "PROTECTED", "RANDC", "REALCVT", "REDEFMACRO", "RISEFALLDLY", - "SELRANGE", "SHORTREAL", "SPLITVAR", "STATICVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET", + "SELRANGE", "SHORTREAL", "SIDEEFFECT", "SPLITVAR", + "STATICVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET", "TICKCOUNT", "TIMESCALEMOD", "UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS", "UNPACKED", "UNSIGNED", "UNUSEDGENVAR", "UNUSEDPARAM", "UNUSEDSIGNAL", @@ -231,7 +233,8 @@ public: } // Warnings to mention manual bool mentionManual() const VL_MT_SAFE { - return (m_e == EC_FATALSRC || m_e == SYMRSVDWORD || m_e == ZERODLY || pretendError()); + return (m_e == EC_FATALSRC || m_e == SIDEEFFECT || m_e == SYMRSVDWORD || m_e == ZERODLY + || pretendError()); } // Warnings that are lint only bool lintError() const VL_MT_SAFE { diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp index 49b775ab9..4e2381ff7 100644 --- a/src/V3LinkInc.cpp +++ b/src/V3LinkInc.cpp @@ -220,16 +220,6 @@ private: } void prepost_stmt_visit(AstNodeTriop* nodep) { iterateChildren(nodep); - - // Currently we can't reference the target, so we just copy the AST both for read and - // write, but doing so would double any side-effects, so as a safety measure all - // statements which could have side-effects are banned at the moment. - if (!nodep->rhsp()->isPure()) { - nodep->rhsp()->v3warn(E_UNSUPPORTED, - "Unsupported: Inc/Dec of expression with side-effects"); - return; - } - AstConst* const constp = VN_AS(nodep->lhsp(), Const); UASSERT_OBJ(nodep, constp, "Expecting CONST"); AstConst* const newconstp = constp->cloneTree(true); @@ -250,16 +240,6 @@ private: } void prepost_expr_visit(AstNodeTriop* nodep) { iterateChildren(nodep); - - // Currently we can't reference the target, so we just copy the AST both for read and - // write, but doing so would double any side-effects, so as a safety measure all - // statements which could have side-effects are banned at the moment. - if (!nodep->rhsp()->isPure()) { - nodep->rhsp()->v3warn(E_UNSUPPORTED, - "Unsupported: Inc/Dec of expression with side-effects"); - return; - } - if (m_unsupportedHere) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: Incrementation in this context."); return; diff --git a/test_regress/t/t_altera_lpm.v b/test_regress/t/t_altera_lpm.v index 0a3671e49..95e16b454 100644 --- a/test_regress/t/t_altera_lpm.v +++ b/test_regress/t/t_altera_lpm.v @@ -2557,12 +2557,14 @@ module lpm_clshift ( // ALWAYS CONSTRUCT BLOCK always @(data or i_direction or distance) begin + // verilator lint_off SIDEEFFECT if ((lpm_shifttype == "LOGICAL") || (lpm_shifttype == "UNUSED")) {tmp_overflow, tmp_underflow, tmp_result} = LogicShift(data, distance, i_direction); else if (lpm_shifttype == "ARITHMETIC") {tmp_overflow, tmp_underflow, tmp_result} = ArithShift(data, distance, i_direction); else if (lpm_shifttype == "ROTATE") {tmp_overflow, tmp_underflow, tmp_result} = RotateShift(data, distance, i_direction); + // verilator lint_on SIDEEFFECT end always @(posedge i_clock or posedge i_aclr) diff --git a/test_regress/t/t_expr_incr_unsup.out b/test_regress/t/t_expr_incr_unsup.out index 6f899d2ac..3f28464b5 100644 --- a/test_regress/t/t_expr_incr_unsup.out +++ b/test_regress/t/t_expr_incr_unsup.out @@ -1,5 +1,11 @@ -%Error-UNSUPPORTED: t/t_expr_incr_unsup.v:17:34: Unsupported: Inc/Dec of expression with side-effects +%Warning-SIDEEFFECT: t/t_expr_incr_unsup.v:17:34: Expression side effect may be mishandled + : ... Suggest use a temporary variable in place of this expression 17 | $display("Value: %d", arr[postincrement_i()]++); | ^ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest + ... For warning description see https://verilator.org/warn/SIDEEFFECT?v=latest + ... Use "/* verilator lint_off SIDEEFFECT */" and lint_on around source to disable this message. +%Warning-SIDEEFFECT: t/t_expr_incr_unsup.v:17:35: Expression side effect may be mishandled + : ... Suggest use a temporary variable in place of this expression + 17 | $display("Value: %d", arr[postincrement_i()]++); + | ^~~~~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_sideeffect_bad.out b/test_regress/t/t_lint_sideeffect_bad.out new file mode 100644 index 000000000..7b2dbd3f4 --- /dev/null +++ b/test_regress/t/t_lint_sideeffect_bad.out @@ -0,0 +1,24 @@ +%Warning-SIDEEFFECT: t/t_lint_sideeffect_bad.v:19:31: Expression side effect may be mishandled + : ... note: In instance 't' + : ... Suggest use a temporary variable in place of this expression + 19 | $display("0x%8x", array[$c(0) +: 32]); + | ^~ + ... For warning description see https://verilator.org/warn/SIDEEFFECT?v=latest + ... Use "/* verilator lint_off SIDEEFFECT */" and lint_on around source to disable this message. +%Warning-SIDEEFFECT: t/t_lint_sideeffect_bad.v:12:13: Expression side effect may be mishandled + : ... Suggest use a temporary variable in place of this expression + 12 | case ($c("1")) + | ^~ +%Warning-SIDEEFFECT: t/t_lint_sideeffect_bad.v:13:10: Expression side effect may be mishandled + : ... Suggest use a temporary variable in place of this expression + 13 | 1: $stop; + | ^ +%Warning-SIDEEFFECT: t/t_lint_sideeffect_bad.v:14:10: Expression side effect may be mishandled + : ... Suggest use a temporary variable in place of this expression + 14 | 2: $stop; + | ^ +%Warning-SIDEEFFECT: t/t_lint_sideeffect_bad.v:15:10: Expression side effect may be mishandled + : ... Suggest use a temporary variable in place of this expression + 15 | 3: $stop; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_lint_sideeffect_bad.pl b/test_regress/t/t_lint_sideeffect_bad.pl new file mode 100755 index 000000000..a82cf66cb --- /dev/null +++ b/test_regress/t/t_lint_sideeffect_bad.pl @@ -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; diff --git a/test_regress/t/t_lint_sideeffect_bad.v b/test_regress/t/t_lint_sideeffect_bad.v new file mode 100644 index 000000000..d153b846e --- /dev/null +++ b/test_regress/t/t_lint_sideeffect_bad.v @@ -0,0 +1,22 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + + logic [63:0] array = 64'hfeedf00d12345678; + + initial begin + case ($c("1")) + 1: $stop; + 2: $stop; + 3: $stop; + default: $stop; + endcase + + $display("0x%8x", array[$c(0) +: 32]); + end + +endmodule diff --git a/test_regress/t/t_stmt_incr_unsup.out b/test_regress/t/t_stmt_incr_unsup.out index 9bc34d883..c7c313981 100644 --- a/test_regress/t/t_stmt_incr_unsup.out +++ b/test_regress/t/t_stmt_incr_unsup.out @@ -1,5 +1,11 @@ -%Error-UNSUPPORTED: t/t_stmt_incr_unsup.v:17:12: Unsupported: Inc/Dec of expression with side-effects +%Warning-SIDEEFFECT: t/t_stmt_incr_unsup.v:17:12: Expression side effect may be mishandled + : ... Suggest use a temporary variable in place of this expression 17 | arr[postincrement_i()]++; | ^ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest + ... For warning description see https://verilator.org/warn/SIDEEFFECT?v=latest + ... Use "/* verilator lint_off SIDEEFFECT */" and lint_on around source to disable this message. +%Warning-SIDEEFFECT: t/t_stmt_incr_unsup.v:17:13: Expression side effect may be mishandled + : ... Suggest use a temporary variable in place of this expression + 17 | arr[postincrement_i()]++; + | ^~~~~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_sv_cpu_code/ports.sv b/test_regress/t/t_sv_cpu_code/ports.sv index da9dbc25b..5cfeeccbb 100644 --- a/test_regress/t/t_sv_cpu_code/ports.sv +++ b/test_regress/t/t_sv_cpu_code/ports.sv @@ -112,10 +112,12 @@ module ports // - Setup read multiplexer - for ( j = PORTID_A; j <= PORTID_D; j++ ) begin + // verilator lint_off SIDEEFFECT if ( padsif.IsPort( j ) ) data[j] = '{ port[j].dir, port[j].out, 8'h00, 8'h00 }; else data[j] = '{ 8'h00, 8'h00, 8'h00, 8'h00 }; + // verilator lint_on SIDEEFFECT end // - Connect "genbusif" - From afecde87d813abd08db917672980b9431f1ca967 Mon Sep 17 00:00:00 2001 From: github action Date: Sun, 15 Oct 2023 11:00:14 +0000 Subject: [PATCH 070/157] Apply 'make format' --- src/V3Ast.cpp | 3 ++- src/V3Ast.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 30ebd67cf..2c4353ffb 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -808,7 +808,8 @@ AstNode* AstNode::cloneTreeIter(bool needPure) { "Expression side effect may be mishandled\n" << this->warnMore() << "... Suggest use a temporary variable in place of this expression"); - // this->v3fatalSrc("cloneTreePure debug backtrace"); // Comment in to debug where caused it + // this->v3fatalSrc("cloneTreePure debug backtrace"); // Comment in to debug where caused + // it } AstNode* const newp = this->clone(); if (this->m_op1p) newp->op1p(this->m_op1p->cloneTreeIterList(needPure)); diff --git a/src/V3Ast.h b/src/V3Ast.h index 402f4b8eb..8e97c4e34 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -2074,7 +2074,8 @@ public: AstNode* belowp); // When calling, "this" is second argument // METHODS - Iterate on a tree - AstNode* cloneTree(bool cloneNextLink, bool needPure = false); // Not const, as sets clonep() on original nodep + AstNode* cloneTree(bool cloneNextLink, + bool needPure = false); // Not const, as sets clonep() on original nodep AstNode* cloneTreePure(bool cloneNextLink) { return cloneTree(cloneNextLink, true); } bool gateTree() { return gateTreeIter(); } // Is tree isGateOptimizable? inline bool sameTree(const AstNode* node2p) const; // Does tree of this == node2p? From 4e2c63c8cb5ced2486cb067b21e9df6be407c298 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Mon, 16 Oct 2023 01:53:35 +0900 Subject: [PATCH 071/157] Support concatenation of unpacked arrays (#4558) --- src/V3Slice.cpp | 148 +++++++++++++++++----- src/V3Width.cpp | 7 +- test_regress/t/t_unpacked_concat.pl | 21 +++ test_regress/t/t_unpacked_concat.v | 102 +++++++++++++++ test_regress/t/t_unpacked_concat_bad.out | 4 - test_regress/t/t_unpacked_concat_bad2.out | 13 ++ test_regress/t/t_unpacked_concat_bad2.pl | 19 +++ test_regress/t/t_unpacked_concat_bad2.v | 34 +++++ 8 files changed, 314 insertions(+), 34 deletions(-) create mode 100755 test_regress/t/t_unpacked_concat.pl create mode 100644 test_regress/t/t_unpacked_concat.v create mode 100644 test_regress/t/t_unpacked_concat_bad2.out create mode 100755 test_regress/t/t_unpacked_concat_bad2.pl create mode 100644 test_regress/t/t_unpacked_concat_bad2.v diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp index 3282e9ef2..3df645406 100644 --- a/src/V3Slice.cpp +++ b/src/V3Slice.cpp @@ -56,6 +56,9 @@ class SliceVisitor final : public VNVisitor { // AstNodeUniop::user1() -> bool. True if find is complete // AstArraySel::user1p() -> AstVarRef. The VarRef that the final ArraySel points to const VNUser1InUse m_inuser1; + // AstInitArray::user2() -> Previously accessed itemIdx + // AstInitItem::user2() -> Corresponding first elemIdx + const VNUser2InUse m_inuser2; // STATE AstNode* m_assignp = nullptr; // Assignment we are under @@ -63,7 +66,8 @@ class SliceVisitor final : public VNVisitor { bool m_okInitArray = false; // Allow InitArray children // METHODS - AstNodeExpr* cloneAndSel(AstNode* nodep, int elements, int offset) { + + AstNodeExpr* cloneAndSel(AstNode* nodep, int elements, int elemIdx) { // Insert an ArraySel, except for a few special cases const AstUnpackArrayDType* const arrayp = VN_CAST(nodep->dtypep()->skipRefp(), UnpackArrayDType); @@ -87,40 +91,126 @@ class SliceVisitor final : public VNVisitor { } m_assignError = true; elements = 1; - offset = 0; + elemIdx = 0; } AstNodeExpr* newp; - if (const AstInitArray* const initp = VN_CAST(nodep, InitArray)) { - UINFO(9, " cloneInitArray(" << elements << "," << offset << ") " << nodep << endl); - const int leOffset = !arrayp->rangep()->ascending() - ? arrayp->rangep()->elementsConst() - 1 - offset - : offset; - AstNodeExpr* const itemp = initp->getIndexDefaultedValuep(leOffset); - if (!itemp) { - nodep->v3error("Array initialization has too few elements, need element " - << offset); + if (AstInitArray* const initp = VN_CAST(nodep, InitArray)) { + UINFO(9, " cloneInitArray(" << elements << "," << elemIdx << ") " << nodep << endl); + + auto considerOrder = [](const auto* nodep, int idxFromLeft) -> int { + return !nodep->rangep()->ascending() + ? nodep->rangep()->elementsConst() - 1 - idxFromLeft + : idxFromLeft; + }; + newp = nullptr; + int itemIdx = 0; + int i = 0; + if (const int prevItemIdx = initp->user2()) { + const AstInitArray::KeyItemMap& itemMap = initp->map(); + const auto it = itemMap.find(considerOrder(arrayp, prevItemIdx)); + if (it != itemMap.end()) { + const AstInitItem* itemp = it->second; + if (itemp->user2() && itemp->user2() < elemIdx) { + // Let's resume traversal from the previous position + itemIdx = prevItemIdx; + i = itemp->user2(); + } + } } - newp = itemp ? itemp->cloneTreePure(false) : new AstConst{nodep->fileline(), 0}; + const AstNodeDType* const expectedItemDTypep = arrayp->subDTypep()->skipRefp(); + while (i <= elemIdx) { + AstNodeExpr* const itemp + = initp->getIndexDefaultedValuep(considerOrder(arrayp, itemIdx)); + if (!itemp && !m_assignError) { + nodep->v3error("Array initialization has too few elements, need element " + << elemIdx); + m_assignError = true; + } + const AstNodeDType* itemRawDTypep = itemp->dtypep()->skipRefp(); + const VCastable castable + = AstNode::computeCastable(expectedItemDTypep, itemRawDTypep, itemp); + if (castable == VCastable::SAMEISH || castable == VCastable::COMPATIBLE) { + if (i == elemIdx) { + newp = itemp->cloneTreePure(false); + break; + } else { // Check the next item + ++i; + ++itemIdx; + } + } else { + const AstUnpackArrayDType* const itemDTypep + = VN_CAST(itemRawDTypep, UnpackArrayDType); + if (!itemDTypep + || !expectedItemDTypep->same(itemDTypep->subDTypep()->skipRefp())) { + if (!m_assignError) { + itemp->v3error("Item is incompatible with the array type."); + } + m_assignError = true; + break; + } + if (i + itemDTypep->elementsConst() + > elemIdx) { // This item contains the element + int offset = considerOrder(itemDTypep, elemIdx - i); + if (AstSliceSel* const slicep = VN_CAST(itemp, SliceSel)) { + offset += slicep->declRange().lo(); + newp = new AstArraySel{nodep->fileline(), + slicep->lhsp()->cloneTreePure(false), offset}; + } else { + newp = new AstArraySel{nodep->fileline(), itemp->cloneTreePure(false), + offset}; + } + + if (!m_assignError && elemIdx + 1 == elements + && i + itemDTypep->elementsConst() > elements) { + nodep->v3error("Array initialization has too many elements. " + << elements << " elements are expected, but at least " + << i + itemDTypep->elementsConst() + << " elements exist."); + m_assignError = true; + } + break; + } else { // Check the next item + i += itemDTypep->elementsConst(); + ++itemIdx; + } + } + } + if (elemIdx + 1 == elements && static_cast(itemIdx) + 1 < initp->map().size() + && !m_assignError) { + nodep->v3error("Array initialization has too many elements. " + << elements << " elements are expected, but at least " + << i + initp->map().size() - itemIdx << " elements exist."); + m_assignError = true; + } + if (newp) { + const AstInitArray::KeyItemMap& itemMap = initp->map(); + const auto it = itemMap.find(considerOrder(arrayp, itemIdx)); + if (it != itemMap.end()) { // Remember current position for the next invocation. + initp->user2(itemIdx); + it->second->user2(i); + } + } + if (!newp) newp = new AstConst{nodep->fileline(), 0}; } else if (AstNodeCond* const snodep = VN_CAST(nodep, NodeCond)) { - UINFO(9, " cloneCond(" << elements << "," << offset << ") " << nodep << endl); + UINFO(9, " cloneCond(" << elements << "," << elemIdx << ") " << nodep << endl); return snodep->cloneType(snodep->condp()->cloneTreePure(false), - cloneAndSel(snodep->thenp(), elements, offset), - cloneAndSel(snodep->elsep(), elements, offset)); + cloneAndSel(snodep->thenp(), elements, elemIdx), + cloneAndSel(snodep->elsep(), elements, elemIdx)); } else if (const AstSliceSel* const snodep = VN_CAST(nodep, SliceSel)) { - UINFO(9, " cloneSliceSel(" << elements << "," << offset << ") " << nodep << endl); + UINFO(9, " cloneSliceSel(" << elements << "," << elemIdx << ") " << nodep << endl); const int leOffset = (snodep->declRange().lo() + (!snodep->declRange().ascending() - ? snodep->declRange().elements() - 1 - offset - : offset)); + ? snodep->declRange().elements() - 1 - elemIdx + : elemIdx)); newp = new AstArraySel{nodep->fileline(), snodep->fromp()->cloneTreePure(false), leOffset}; } else if (VN_IS(nodep, ArraySel) || VN_IS(nodep, NodeVarRef) || VN_IS(nodep, NodeSel) || VN_IS(nodep, CMethodHard) || VN_IS(nodep, MemberSel) || VN_IS(nodep, ExprStmt)) { - UINFO(9, " cloneSel(" << elements << "," << offset << ") " << nodep << endl); + UINFO(9, " cloneSel(" << elements << "," << elemIdx << ") " << nodep << endl); const int leOffset = !arrayp->rangep()->ascending() - ? arrayp->rangep()->elementsConst() - 1 - offset - : offset; + ? arrayp->rangep()->elementsConst() - 1 - elemIdx + : elemIdx; newp = new AstArraySel{nodep->fileline(), VN_AS(nodep, NodeExpr)->cloneTreePure(false), leOffset}; } else { @@ -149,10 +239,10 @@ class SliceVisitor final : public VNVisitor { // elements AstNodeAssign* newlistp = nullptr; const int elements = arrayp->rangep()->elementsConst(); - for (int offset = 0; offset < elements; ++offset) { + for (int elemIdx = 0; elemIdx < elements; ++elemIdx) { AstNodeAssign* const newp - = nodep->cloneType(cloneAndSel(nodep->lhsp(), elements, offset), - cloneAndSel(nodep->rhsp(), elements, offset)); + = nodep->cloneType(cloneAndSel(nodep->lhsp(), elements, elemIdx), + cloneAndSel(nodep->rhsp(), elements, elemIdx)); if (debug() >= 9) newp->dumpTree("- new: "); newlistp = AstNode::addNext(newlistp, newp); } @@ -199,12 +289,12 @@ class SliceVisitor final : public VNVisitor { << " on non-slicable (e.g. non-vector) right-hand-side operand"); } else { const int elements = adtypep->rangep()->elementsConst(); - for (int offset = 0; offset < elements; ++offset) { + for (int elemIdx = 0; elemIdx < elements; ++elemIdx) { // EQ(a,b) -> LOGAND(EQ(ARRAYSEL(a,0), ARRAYSEL(b,0)), ...[1]) - AstNodeBiop* const clonep - = VN_AS(nodep->cloneType(cloneAndSel(nodep->lhsp(), elements, offset), - cloneAndSel(nodep->rhsp(), elements, offset)), - NodeBiop); + AstNodeBiop* const clonep = VN_AS( + nodep->cloneType(cloneAndSel(nodep->lhsp(), elements, elemIdx), + cloneAndSel(nodep->rhsp(), elements, elemIdx)), + NodeBiop); if (!logp) { logp = clonep; } else { diff --git a/src/V3Width.cpp b/src/V3Width.cpp index cecd6ad1b..cc6f2551d 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -4120,6 +4120,7 @@ private: PatVecMap patmap = patVectorMap(nodep, range); UINFO(9, "ent " << range.left() << " to " << range.right() << endl); AstNode* newp = nullptr; + bool allConstant = true; for (int entn = 0, ent = range.left(); entn < range.elements(); ++entn, ent += range.leftToRightInc()) { AstPatMember* newpatp = nullptr; @@ -4129,7 +4130,10 @@ private: if (defaultp) { newpatp = defaultp->cloneTree(false); patp = newpatp; - } else { + } else if (!(VN_IS(arrayDtp, UnpackArrayDType) && !allConstant)) { + // If arrayDtp is an unpacked array and item is not constant, + // the number of elemnt cannot be determined here as the dtype of each element + // is not set yet. V3Slice checks for such cases. nodep->v3error("Assignment pattern missed initializing elements: " << ent); } } else { @@ -4140,6 +4144,7 @@ private: if (patp) { // Don't want the RHS an array patp->dtypep(arrayDtp->subDTypep()); + allConstant &= VN_IS(patp->lhssp(), Const); AstNodeExpr* const valuep = patternMemberValueIterate(patp); if (VN_IS(arrayDtp, UnpackArrayDType)) { if (!newp) { diff --git a/test_regress/t/t_unpacked_concat.pl b/test_regress/t/t_unpacked_concat.pl new file mode 100755 index 000000000..354bf40cc --- /dev/null +++ b/test_regress/t/t_unpacked_concat.pl @@ -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 2019 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(simulator => 1); + +compile( + ); +execute( + check_finished => 1, + ); + + +ok(1); +1; diff --git a/test_regress/t/t_unpacked_concat.v b/test_regress/t/t_unpacked_concat.v new file mode 100644 index 000000000..1c73f8ffd --- /dev/null +++ b/test_regress/t/t_unpacked_concat.v @@ -0,0 +1,102 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Yutetsu TAKATSUKASA. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + typedef int AI3[1:3]; + AI3 A3; + int A9[1:9]; + + logic [2:0] s0; + logic [2:0] s1[1:3]; + logic [2:0] s2[3:1]; + logic [2:0] s3[2:8]; + logic [2:0] s4[8:2]; + + initial begin + s0 = 3'd1; + s1[1] = 3'd2; + s1[2] = 3'd3; + s1[3] = 3'd4; + s2[1] = 3'd5; + s2[2] = 3'd6; + s2[3] = 3'd7; + + A3 = '{1, 2, 3}; + A9 = {A3, 4, 5, A3, 6}; + if (A9[1] != 1) $stop; + if (A9[2] != 2) $stop; + if (A9[3] != 3) $stop; + if (A9[4] != 4) $stop; + if (A9[5] != 5) $stop; + if (A9[6] != 1) $stop; + if (A9[7] != 2) $stop; + if (A9[8] != 3) $stop; + if (A9[9] != 6) $stop; + + s3 = {s0, s1, s2}; + if (s3[2] != s0) $stop; + if (s3[3] != s1[1]) $stop; + if (s3[4] != s1[2]) $stop; + if (s3[5] != s1[3]) $stop; + if (s3[6] != s2[3]) $stop; + if (s3[7] != s2[2]) $stop; + if (s3[8] != s2[1]) $stop; + + s3[2:8] = {s0, s1[1:2], s1[3], s2[3], s2[2:1]}; + if (s3[2] != s0) $stop; + if (s3[3] != s1[1]) $stop; + if (s3[4] != s1[2]) $stop; + if (s3[5] != s1[3]) $stop; + if (s3[6] != s2[3]) $stop; + if (s3[7] != s2[2]) $stop; + if (s3[8] != s2[1]) $stop; + + s3 = {s0, s1[1], s1[2:3], s2[3:2], s2[1]}; + if (s3[2] != s0) $stop; + if (s3[3] != s1[1]) $stop; + if (s3[4] != s1[2]) $stop; + if (s3[5] != s1[3]) $stop; + if (s3[6] != s2[3]) $stop; + if (s3[7] != s2[2]) $stop; + if (s3[8] != s2[1]) $stop; + + s4 = {s0, s1, s2}; + if (s4[8] != s0) $stop; + if (s4[7] != s1[1]) $stop; + if (s4[6] != s1[2]) $stop; + if (s4[5] != s1[3]) $stop; + if (s4[4] != s2[3]) $stop; + if (s4[3] != s2[2]) $stop; + if (s4[2] != s2[1]) $stop; + + s4[8:2] = {s0, s1[1:2], s1[3], s2[3], s2[2:1]}; + if (s4[8] != s0) $stop; + if (s4[7] != s1[1]) $stop; + if (s4[6] != s1[2]) $stop; + if (s4[5] != s1[3]) $stop; + if (s4[4] != s2[3]) $stop; + if (s4[3] != s2[2]) $stop; + if (s4[2] != s2[1]) $stop; + + s4 = {s0, s1[1], s1[2:3], s2[3:2], s2[1]}; + if (s4[8] != s0) $stop; + if (s4[7] != s1[1]) $stop; + if (s4[6] != s1[2]) $stop; + if (s4[5] != s1[3]) $stop; + if (s4[4] != s2[3]) $stop; + if (s4[3] != s2[2]) $stop; + if (s4[2] != s2[1]) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_unpacked_concat_bad.out b/test_regress/t/t_unpacked_concat_bad.out index 4f2954473..e2c0f4797 100644 --- a/test_regress/t/t_unpacked_concat_bad.out +++ b/test_regress/t/t_unpacked_concat_bad.out @@ -3,8 +3,4 @@ 17 | localparam bit_int_t count_bits [1:0] = {2{$bits(count_t)}}; | ^ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error: t/t_unpacked_concat_bad.v:17:46: Assignment pattern missed initializing elements: 0 - : ... note: In instance 't' - 17 | localparam bit_int_t count_bits [1:0] = {2{$bits(count_t)}}; - | ^ %Error: Exiting due to diff --git a/test_regress/t/t_unpacked_concat_bad2.out b/test_regress/t/t_unpacked_concat_bad2.out new file mode 100644 index 000000000..1a5e93630 --- /dev/null +++ b/test_regress/t/t_unpacked_concat_bad2.out @@ -0,0 +1,13 @@ +%Error: t/t_unpacked_concat_bad2.v:25:15: Array initialization has too many elements. 2 elements are expected, but at least 5 elements exist. + 25 | s1 = {s0, s2}; + | ^ +%Error: t/t_unpacked_concat_bad2.v:26:23: Array initialization has too many elements. 4 elements are expected, but at least 5 elements exist. + 26 | s2 = {s1, s0, s0, s0}; + | ^ +%Error: t/t_unpacked_concat_bad2.v:28:17: Item is incompatible with the array type. + 28 | s2 = {s0, s3}; + | ^~ +%Error: t/t_unpacked_concat_bad2.v:30:19: Item is incompatible with the array type. + 30 | A9_logic = {A3, 4, 5, A3, 6}; + | ^~ +%Error: Exiting due to diff --git a/test_regress/t/t_unpacked_concat_bad2.pl b/test_regress/t/t_unpacked_concat_bad2.pl new file mode 100755 index 000000000..63947fd00 --- /dev/null +++ b/test_regress/t/t_unpacked_concat_bad2.pl @@ -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 2019 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 => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_unpacked_concat_bad2.v b/test_regress/t/t_unpacked_concat_bad2.v new file mode 100644 index 000000000..ba3800237 --- /dev/null +++ b/test_regress/t/t_unpacked_concat_bad2.v @@ -0,0 +1,34 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Yutetsu TAKATSUKASA. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + logic [7:0] s0; + logic [7:0] s1[1:2]; + logic [7:0] s2[1:4]; + logic [7:0] s3[2][2]; + + typedef int AI3[1:3]; + AI3 A3; + logic [31:0] A9_logic[1:9]; + + initial begin + // RHS has too many elements. + s1 = {s0, s2}; + s2 = {s1, s0, s0, s0}; + // Incompatible type + s2 = {s0, s3}; + + A9_logic = {A3, 4, 5, A3, 6}; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From 4427f03b08550ae9fb0aba6aca4f5c8d4127f15e Mon Sep 17 00:00:00 2001 From: Anthony Donlon <4056887+donlon@users.noreply.github.com> Date: Sun, 15 Oct 2023 17:59:36 +0100 Subject: [PATCH 072/157] Fix error message for invalid parameter overrides (#4559) --- src/V3LinkDot.cpp | 105 ++++++++++-------- src/V3Param.cpp | 8 +- src/V3String.cpp | 11 ++ src/V3String.h | 3 + test_regress/t/t_class_param_bad1.out | 4 +- .../t/t_class_param_override_local_bad.out | 8 +- test_regress/t/t_dist_warn_coverage.pl | 2 - test_regress/t/t_inst_param_override_bad.out | 19 ++++ test_regress/t/t_inst_param_override_bad.pl | 19 ++++ test_regress/t/t_inst_param_override_bad.v | 45 ++++++++ test_regress/t/t_inst_pin_place_bad.out | 4 +- test_regress/t/t_lint_pindup_bad.out | 10 +- test_regress/t/t_lint_pinnotfound_bad.out | 2 +- test_regress/t/t_param_implicit_local_bad.out | 14 +-- 14 files changed, 182 insertions(+), 72 deletions(-) create mode 100644 test_regress/t/t_inst_param_override_bad.out create mode 100755 test_regress/t/t_inst_param_override_bad.pl create mode 100644 test_regress/t/t_inst_param_override_bad.v diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index dd9a6548c..1d8cbce88 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -224,8 +224,22 @@ public: // METHODS static string nodeTextType(AstNode* nodep) { - if (VN_IS(nodep, Var)) { - return "variable"; + if (const AstVar* const varp = VN_CAST(nodep, Var)) { + if (varp->isIO() || varp->isIfaceRef()) { + return "port"; + } else if (varp->isGParam()) { + return "parameter"; + } else if (varp->varType() == VVarType::LPARAM) { + return "local parameter"; + } else { + return "variable"; + } + } else if (const AstParamTypeDType* const dtypep = VN_CAST(nodep, ParamTypeDType)) { + if (dtypep->isGParam()) { + return "type parameter"; + } else { + return "local type parameter"; + } } else if (VN_IS(nodep, Cell)) { return "instance"; } else if (VN_IS(nodep, Task)) { @@ -236,8 +250,6 @@ public: return "block"; } else if (VN_IS(nodep, Iface)) { return "interface"; - } else if (VN_IS(nodep, ParamTypeDType)) { - return "parameter type"; } else { return nodep->prettyTypeName(); } @@ -2262,11 +2274,6 @@ private: m_ds.init(srcp); iterate(nodep); } - bool checkPinRef(AstPin* pinp, VVarType refVarType) { - // In instantiations of modules/ifaces, we shouldn't connect port pins to submodule's - // parameters or vice versa - return pinp->param() == refVarType.isParam(); - } void updateVarUse(AstVar* nodep) { // Avoid dotted.PARAM false positive when in a parameter block // that is if ()'ed off by same dotted name as another block @@ -2365,49 +2372,57 @@ private: if (!nodep->modVarp()) { UASSERT_OBJ(m_pinSymp, nodep, "Pin not under instance?"); VSymEnt* const foundp = m_pinSymp->findIdFlat(nodep->name()); - const char* const whatp = nodep->param() ? "parameter pin" : "pin"; - bool pinCheckFail = false; - if (foundp) { - if (AstVar* const refp = VN_CAST(foundp->nodep(), Var)) { - if (!refp->isIO() && !refp->isParam() && !refp->isIfaceRef()) { - nodep->v3error(ucfirst(whatp) - << " is not an in/out/inout/param/interface: " - << nodep->prettyNameQ()); - } else if (!checkPinRef(nodep, refp->varType())) { - pinCheckFail = true; - } else { - nodep->modVarp(refp); - markAndCheckPinDup(nodep, refp, whatp); - } - } else if (AstParamTypeDType* const refp - = VN_CAST(foundp->nodep(), ParamTypeDType)) { - if (!checkPinRef(nodep, refp->varType())) { - pinCheckFail = true; - } else { - nodep->modPTypep(refp); - markAndCheckPinDup(nodep, refp, whatp); - } - } else { - nodep->v3error(ucfirst(whatp) << " not found: " << nodep->prettyNameQ()); - } - } - if (!foundp || pinCheckFail) { + const char* const whatp = nodep->param() ? "parameter" : "pin"; + if (!foundp) { if (nodep->name() == "__paramNumber1" && m_cellp && VN_IS(m_cellp->modp(), Primitive)) { // Primitive parameter is really a delay we can just ignore VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); return; + } else { + const string suggest + = (nodep->param() ? m_statep->suggestSymFlat(m_pinSymp, nodep->name(), + LinkNodeMatcherVarParam{}) + : m_statep->suggestSymFlat(m_pinSymp, nodep->name(), + LinkNodeMatcherVarIO{})); + nodep->v3warn(PINNOTFOUND, + ucfirst(whatp) + << " not found: " << nodep->prettyNameQ() << '\n' + << (suggest.empty() ? "" : nodep->warnMore() + suggest)); + return; } - const string suggest - = (nodep->param() ? m_statep->suggestSymFlat(m_pinSymp, nodep->name(), - LinkNodeMatcherVarParam{}) - : m_statep->suggestSymFlat(m_pinSymp, nodep->name(), - LinkNodeMatcherVarIO{})); - nodep->v3warn(PINNOTFOUND, - ucfirst(whatp) - << " not found: " << nodep->prettyNameQ() << '\n' - << (suggest.empty() ? "" : nodep->warnMore() + suggest)); } + VVarType refVarType = VVarType::UNKNOWN; + bool wrongPinType = false; + if (AstVar* const varp = VN_CAST(foundp->nodep(), Var)) { + if (varp->isIO() || varp->isParam() || varp->isIfaceRef()) { + refVarType = varp->varType(); + nodep->modVarp(varp); + } else { + wrongPinType = true; + } + } else if (AstParamTypeDType* const typep = VN_CAST(foundp->nodep(), ParamTypeDType)) { + refVarType = typep->varType(); + nodep->modPTypep(typep); + } else { + wrongPinType = true; + } + // Don't connect parameter pin to module ports or vice versa + if (nodep->param() != (refVarType == VVarType::GPARAM)) wrongPinType = true; + if (wrongPinType) { + string targetType = LinkDotState::nodeTextType(foundp->nodep()); + targetType = VString::aOrAn(targetType) + ' ' + targetType; + if (nodep->param()) { + nodep->v3error("Instance attempts to override " + << nodep->prettyNameQ() << " as a " << whatp << ", but it is " + << targetType); + } else { + nodep->v3error("Instance attempts to connect to " + << nodep->prettyNameQ() << ", but it is " << targetType); + } + return; + } + markAndCheckPinDup(nodep, foundp->nodep(), whatp); } // Early return() above when deleted } diff --git a/src/V3Param.cpp b/src/V3Param.cpp index ce5ded6a8..8bc5358a6 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -699,8 +699,8 @@ class ParamProcessor final : public VNDeleter { if (!pinp->exprp()) return; // No-connect if (AstVar* const modvarp = pinp->modVarp()) { if (!modvarp->isGParam()) { - pinp->v3error("Attempted parameter setting of non-parameter: Param " - << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); + pinp->v3fatalSrc("Attempted parameter setting of non-parameter: Param " + << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); } else if (VN_IS(pinp->exprp(), InitArray) && arraySubDTypep(modvarp->subDTypep())) { // Array assigned to array AstNode* const exprp = pinp->exprp(); @@ -761,8 +761,8 @@ class ParamProcessor final : public VNDeleter { } } } else { - pinp->v3error("Parameter not found in sub-module: Param " - << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); + pinp->v3fatalSrc("Parameter not found in sub-module: Param " + << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); } } diff --git a/src/V3String.cpp b/src/V3String.cpp index c23a15705..e42bee71d 100644 --- a/src/V3String.cpp +++ b/src/V3String.cpp @@ -273,6 +273,17 @@ bool VString::endsWith(const string& str, const string& suffix) { if (str.length() < suffix.length()) return false; return str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0; } +string VString::aOrAn(const char* word) { + switch (word[0]) { + case '\0': return ""; + case 'a': + case 'e': + case 'i': + case 'o': + case 'u': return "an"; + default: return "a"; + } +} //###################################################################### // VHashSha256 diff --git a/src/V3String.h b/src/V3String.h index 33c792757..149ce2d43 100644 --- a/src/V3String.h +++ b/src/V3String.h @@ -130,6 +130,9 @@ public: static bool endsWith(const string& str, const string& suffix); // Return true if char is valid character in word static bool isWordChar(char c) { return isalnum(c) || c == '_'; } + // Return proper article (a/an) for a word. May be inaccurate for some special words + static string aOrAn(const char* word); + static string aOrAn(const string& word) { return aOrAn(word.c_str()); } }; //###################################################################### diff --git a/test_regress/t/t_class_param_bad1.out b/test_regress/t/t_class_param_bad1.out index 756f6e838..55071fadd 100644 --- a/test_regress/t/t_class_param_bad1.out +++ b/test_regress/t/t_class_param_bad1.out @@ -1,9 +1,9 @@ -%Error-PINNOTFOUND: t/t_class_param_bad1.v:12:11: Parameter pin not found: 'PARAMBAD' +%Error-PINNOTFOUND: t/t_class_param_bad1.v:12:11: Parameter not found: 'PARAMBAD' : ... Suggested alternative: 'PARAMB' 12 | Cls #(.PARAMBAD(1)) c; | ^~~~~~~~ ... For error description see https://verilator.org/warn/PINNOTFOUND?v=latest -%Error-PINNOTFOUND: t/t_class_param_bad1.v:13:14: Parameter pin not found: '__paramNumber2' +%Error-PINNOTFOUND: t/t_class_param_bad1.v:13:14: Parameter not found: '__paramNumber2' 13 | Cls #(13, 1) cd; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_class_param_override_local_bad.out b/test_regress/t/t_class_param_override_local_bad.out index dacafe468..37c671895 100644 --- a/test_regress/t/t_class_param_override_local_bad.out +++ b/test_regress/t/t_class_param_override_local_bad.out @@ -1,14 +1,14 @@ -%Error-PINNOTFOUND: t/t_class_param_override_local_bad.v:23:30: Parameter pin not found: '__paramNumber1' +%Error-PINNOTFOUND: t/t_class_param_override_local_bad.v:23:30: Parameter not found: '__paramNumber1' 23 | class Cls3 implements Icls1#(2), Icls2#(0); | ^ ... For error description see https://verilator.org/warn/PINNOTFOUND?v=latest -%Error-PINNOTFOUND: t/t_class_param_override_local_bad.v:23:41: Parameter pin not found: '__paramNumber1' +%Error-PINNOTFOUND: t/t_class_param_override_local_bad.v:23:41: Parameter not found: '__paramNumber1' 23 | class Cls3 implements Icls1#(2), Icls2#(0); | ^ -%Error-PINNOTFOUND: t/t_class_param_override_local_bad.v:29:23: Parameter pin not found: '__paramNumber1' +%Error-PINNOTFOUND: t/t_class_param_override_local_bad.v:29:23: Parameter not found: '__paramNumber1' 29 | automatic Cls1#(bit) cls1 = new; | ^~~ -%Error-PINNOTFOUND: t/t_class_param_override_local_bad.v:30:23: Parameter pin not found: '__paramNumber1' +%Error-PINNOTFOUND: t/t_class_param_override_local_bad.v:30:23: Parameter not found: '__paramNumber1' 30 | automatic Cls2#(1) cls2 = new; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_dist_warn_coverage.pl b/test_regress/t/t_dist_warn_coverage.pl index 25b6be901..558a35b3d 100755 --- a/test_regress/t/t_dist_warn_coverage.pl +++ b/test_regress/t/t_dist_warn_coverage.pl @@ -39,7 +39,6 @@ foreach my $s ( 'Array initialization has too few elements, need element ', 'Assigned pin is neither input nor output', 'Assignment pattern with no members', - 'Attempted parameter setting of non-parameter: Param ', 'Can\'t find varpin scope of ', 'Can\'t resolve module reference: \'', 'Cannot write preprocessor output: ', @@ -60,7 +59,6 @@ foreach my $s ( 'Modport not referenced as .', 'Modport not referenced from underneath an interface: ', 'Non-interface used as an interface: ', - 'Parameter not found in sub-module: Param ', 'Parameter type pin value isn\'t a type: Param ', 'Parameter type variable isn\'t a type: Param ', 'Pattern replication value of 0 is not legal.', diff --git a/test_regress/t/t_inst_param_override_bad.out b/test_regress/t/t_inst_param_override_bad.out new file mode 100644 index 000000000..13f027a3b --- /dev/null +++ b/test_regress/t/t_inst_param_override_bad.out @@ -0,0 +1,19 @@ +%Error: t/t_inst_param_override_bad.v:33:23: Instance attempts to override 'PACKED_DATA_WIDTH' as a parameter, but it is a local parameter + 33 | axi_stream_if # (.PACKED_DATA_WIDTH(10)) axis1(clk); + | ^~~~~~~~~~~~~~~~~ +%Error: t/t_inst_param_override_bad.v:35:23: Instance attempts to override 'mytask' as a parameter, but it is a task + 35 | axi_stream_if # (.mytask(10)) axis2(clk); + | ^~~~~~ +%Error: t/t_inst_param_override_bad.v:37:23: Instance attempts to override 'my_genvar' as a parameter, but it is a variable + 37 | axi_stream_if # (.my_genvar(10)) axis3(clk); + | ^~~~~~~~~ +%Error: t/t_inst_param_override_bad.v:39:23: Instance attempts to override 'clk' as a parameter, but it is a port + 39 | axi_stream_if # (.clk(10)) axis4(clk); + | ^~~ +%Error: t/t_inst_param_override_bad.v:41:23: Instance attempts to override 'tvalid' as a parameter, but it is a variable + 41 | axi_stream_if # (.tvalid(10)) axis5(clk); + | ^~~~~~ +%Error: t/t_inst_param_override_bad.v:43:23: Instance attempts to override 'i_sub' as a parameter, but it is an instance + 43 | axi_stream_if # (.i_sub(10)) axis6(clk); + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_inst_param_override_bad.pl b/test_regress/t/t_inst_param_override_bad.pl new file mode 100755 index 000000000..376c2d2ee --- /dev/null +++ b/test_regress/t/t_inst_param_override_bad.pl @@ -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 2023 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; diff --git a/test_regress/t/t_inst_param_override_bad.v b/test_regress/t/t_inst_param_override_bad.v new file mode 100644 index 000000000..8ac842b23 --- /dev/null +++ b/test_regress/t/t_inst_param_override_bad.v @@ -0,0 +1,45 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Anthony Donlon. +// SPDX-License-Identifier: CC0-1.0 + +module sub(); +endmodule + +interface axi_stream_if #( + parameter int DATA_WIDTH = 64, + parameter type TUSER_TYPE = logic +) ( + input clk +); + + task mytask(); + endtask : mytask + + genvar my_genvar; + + logic tvalid; + + sub i_sub(); + + localparam PACKED_DATA_WIDTH = DATA_WIDTH + DATA_WIDTH / 8 + 1 + $bits(TUSER_TYPE); +endinterface + +module t; + logic clk; + + // overriding a localparam + axi_stream_if # (.PACKED_DATA_WIDTH(10)) axis1(clk); + // overriding a non-var + axi_stream_if # (.mytask(10)) axis2(clk); + // overriding a non-port/interface/param var + axi_stream_if # (.my_genvar(10)) axis3(clk); + // overriding a port + axi_stream_if # (.clk(10)) axis4(clk); + // overriding a signal + axi_stream_if # (.tvalid(10)) axis5(clk); + // overriding an instance + axi_stream_if # (.i_sub(10)) axis6(clk); + +endmodule diff --git a/test_regress/t/t_inst_pin_place_bad.out b/test_regress/t/t_inst_pin_place_bad.out index 0d3f845a6..8cc323ac1 100644 --- a/test_regress/t/t_inst_pin_place_bad.out +++ b/test_regress/t/t_inst_pin_place_bad.out @@ -3,10 +3,10 @@ | ^~~~~ ... For warning description see https://verilator.org/warn/PINMISSING?v=latest ... Use "/* verilator lint_off PINMISSING */" and lint_on around source to disable this message. -%Error-PINNOTFOUND: t/t_inst_pin_place_bad.v:22:10: Pin not found: 'PARAM_A' +%Error: t/t_inst_pin_place_bad.v:22:10: Instance attempts to connect to 'PARAM_A', but it is a parameter 22 | .PARAM_A(1) | ^~~~~~~ -%Error-PINNOTFOUND: t/t_inst_pin_place_bad.v:20:10: Parameter pin not found: 'pin_1' +%Error: t/t_inst_pin_place_bad.v:20:10: Instance attempts to override 'pin_1' as a parameter, but it is a port 20 | .pin_1(1) | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_pindup_bad.out b/test_regress/t/t_lint_pindup_bad.out index 94b81c87b..7cdb90a6c 100644 --- a/test_regress/t/t_lint_pindup_bad.out +++ b/test_regress/t/t_lint_pindup_bad.out @@ -13,20 +13,20 @@ : ... Suggested alternative: 'exists' 22 | .nexist(i2) | ^~~~~~ -%Error-PINNOTFOUND: t/t_lint_pindup_bad.v:16:9: Parameter pin not found: 'NEXIST' +%Error-PINNOTFOUND: t/t_lint_pindup_bad.v:16:9: Parameter not found: 'NEXIST' : ... Suggested alternative: 'EXIST' 16 | .NEXIST(1), | ^~~~~~ -%Error: t/t_lint_pindup_bad.v:17:9: Duplicate parameter pin connection: 'P' +%Error: t/t_lint_pindup_bad.v:17:9: Duplicate parameter connection: 'P' 17 | .P(2), | ^ - t/t_lint_pindup_bad.v:15:8: ... Location of original parameter pin connection + t/t_lint_pindup_bad.v:15:8: ... Location of original parameter connection 15 | #(, | ^ -%Error: t/t_lint_pindup_bad.v:18:9: Duplicate parameter pin connection: 'P' +%Error: t/t_lint_pindup_bad.v:18:9: Duplicate parameter connection: 'P' 18 | .P(3)) | ^ - t/t_lint_pindup_bad.v:15:8: ... Location of original parameter pin connection + t/t_lint_pindup_bad.v:15:8: ... Location of original parameter connection 15 | #(, | ^ %Error: Exiting due to diff --git a/test_regress/t/t_lint_pinnotfound_bad.out b/test_regress/t/t_lint_pinnotfound_bad.out index 81a6f40e5..6aded1ba0 100644 --- a/test_regress/t/t_lint_pinnotfound_bad.out +++ b/test_regress/t/t_lint_pinnotfound_bad.out @@ -2,7 +2,7 @@ 12 | b b_inst1 (.x(1'b0)); | ^ ... For error description see https://verilator.org/warn/PINNOTFOUND?v=latest -%Error-PINNOTFOUND: t/t_lint_pinnotfound_bad.v:13:6: Parameter pin not found: 'PX' +%Error-PINNOTFOUND: t/t_lint_pinnotfound_bad.v:13:6: Parameter not found: 'PX' 13 | b #(.PX(1'b0)) b_inst2 (); | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_param_implicit_local_bad.out b/test_regress/t/t_param_implicit_local_bad.out index ef6479300..159b4f135 100644 --- a/test_regress/t/t_param_implicit_local_bad.out +++ b/test_regress/t/t_param_implicit_local_bad.out @@ -1,23 +1,23 @@ -%Error-PINNOTFOUND: t/t_param_implicit_local_bad.v:15:20: Parameter pin not found: '__paramNumber2' +%Error-PINNOTFOUND: t/t_param_implicit_local_bad.v:15:20: Parameter not found: '__paramNumber2' 15 | NestedCls #(1, 2) cls; | ^ ... For error description see https://verilator.org/warn/PINNOTFOUND?v=latest -%Error-PINNOTFOUND: t/t_param_implicit_local_bad.v:17:21: Parameter pin not found: '__paramNumber3' +%Error-PINNOTFOUND: t/t_param_implicit_local_bad.v:17:21: Parameter not found: '__paramNumber3' 17 | mod1 # ( 3, 4, 5 ) i_mod1 (); | ^ -%Error-PINNOTFOUND: t/t_param_implicit_local_bad.v:19:15: Parameter pin not found: '__paramNumber1' +%Error-PINNOTFOUND: t/t_param_implicit_local_bad.v:19:15: Parameter not found: '__paramNumber1' 19 | mod3 # ( 7, 24, 25 ) i_mod3 (); | ^ -%Error-PINNOTFOUND: t/t_param_implicit_local_bad.v:19:18: Parameter pin not found: '__paramNumber2' +%Error-PINNOTFOUND: t/t_param_implicit_local_bad.v:19:18: Parameter not found: '__paramNumber2' 19 | mod3 # ( 7, 24, 25 ) i_mod3 (); | ^~ -%Error-PINNOTFOUND: t/t_param_implicit_local_bad.v:19:22: Parameter pin not found: '__paramNumber3' +%Error-PINNOTFOUND: t/t_param_implicit_local_bad.v:19:22: Parameter not found: '__paramNumber3' 19 | mod3 # ( 7, 24, 25 ) i_mod3 (); | ^~ -%Error-PINNOTFOUND: t/t_param_implicit_local_bad.v:20:22: Parameter pin not found: '__paramNumber3' +%Error-PINNOTFOUND: t/t_param_implicit_local_bad.v:20:22: Parameter not found: '__paramNumber3' 20 | intf1 # ( 8, 15, 17 ) i_intf1 (); | ^~ -%Error-PINNOTFOUND: t/t_param_implicit_local_bad.v:21:22: Parameter pin not found: '__paramNumber3' +%Error-PINNOTFOUND: t/t_param_implicit_local_bad.v:21:22: Parameter not found: '__paramNumber3' 21 | prgm1 # ( 9, 40, 41 ) i_prgm1 (); | ^~ %Error: Exiting due to From 4fdaa463285a3ea59fab5dc3b2dad8394dbc97a8 Mon Sep 17 00:00:00 2001 From: Anthony Donlon <4056887+donlon@users.noreply.github.com> Date: Sun, 15 Oct 2023 18:01:32 +0100 Subject: [PATCH 073/157] Fix using functions/tasks following class definition inside module (#4553) --- src/V3Global.h | 6 ++-- src/V3LinkDot.cpp | 50 +++++++++++++-------------- test_regress/t/t_class_nested_link.pl | 21 +++++++++++ test_regress/t/t_class_nested_link.v | 45 ++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 27 deletions(-) create mode 100755 test_regress/t/t_class_nested_link.pl create mode 100644 test_regress/t/t_class_nested_link.v diff --git a/src/V3Global.h b/src/V3Global.h index a25a3f274..126392ad9 100644 --- a/src/V3Global.h +++ b/src/V3Global.h @@ -41,12 +41,13 @@ class V3HierBlockPlan; //====================================================================== // Restorer -/// Save a given variable's value on the stack, restoring it at -/// end-of-stope. +/// Save a given variable's value on the stack, restoring it at end-of-scope. // Object must be named, or it will not persist until end-of-scope. // Constructor needs () or GCC 4.8 false warning. #define VL_RESTORER(var) \ const VRestorer::type> restorer_##var(var); +/// Get the copy of the variable previously saved by VL_RESTORER() +#define VL_RESTORER_PREV(var) restorer_##var.saved() // Object used by VL_RESTORER. This object must be an auto variable, not // allocated on the heap or otherwise. @@ -60,6 +61,7 @@ public: : m_ref{permr} , m_saved{permr} {} ~VRestorer() { m_ref = m_saved; } + const T& saved() const { return m_saved; } VL_UNCOPYABLE(VRestorer); }; diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 1d8cbce88..3b129d741 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1050,12 +1050,11 @@ class LinkDotFindVisitor final : public VNVisitor { } else { VL_RESTORER(m_blockp); VL_RESTORER(m_curSymp); - VSymEnt* const oldCurSymp = m_curSymp; { m_blockp = nodep; m_curSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_classOrPackagep); - m_curSymp->fallbackp(oldCurSymp); + m_curSymp->fallbackp(VL_RESTORER_PREV(m_curSymp)); // Iterate iterateChildren(nodep); } @@ -1440,12 +1439,11 @@ class LinkDotFindVisitor final : public VNVisitor { void visit(AstForeach* nodep) override { // Symbol table needs nodep->name() as the index variable's name VL_RESTORER(m_curSymp); - VSymEnt* const oldCurSymp = m_curSymp; { ++m_modWithNum; m_curSymp = m_statep->insertBlock(m_curSymp, "__Vforeach" + cvtToStr(m_modWithNum), nodep, m_classOrPackagep); - m_curSymp->fallbackp(oldCurSymp); + m_curSymp->fallbackp(VL_RESTORER_PREV(m_curSymp)); // DOT(x, SELLOOPVARS(var, loops)) -> SELLOOPVARS(DOT(x, var), loops) if (AstDot* const dotp = VN_CAST(nodep->arrayp(), Dot)) { if (AstSelLoopVars* const loopvarsp = VN_CAST(dotp->rhsp(), SelLoopVars)) { @@ -1520,12 +1518,11 @@ class LinkDotFindVisitor final : public VNVisitor { // Symbol table needs nodep->name() as the index variable's name // Iteration will pickup the AstVar we made under AstWith VL_RESTORER(m_curSymp); - VSymEnt* const oldCurSymp = m_curSymp; { ++m_modWithNum; m_curSymp = m_statep->insertBlock(m_curSymp, "__Vwith" + cvtToStr(m_modWithNum), nodep, m_classOrPackagep); - m_curSymp->fallbackp(oldCurSymp); + m_curSymp->fallbackp(VL_RESTORER_PREV(m_curSymp)); UASSERT_OBJ(nodep->indexArgRefp(), nodep, "Missing lambda argref"); UASSERT_OBJ(nodep->valueArgRefp(), nodep, "Missing lambda argref"); // Insert argref's name into symbol table @@ -1927,11 +1924,10 @@ class LinkDotIfaceVisitor final : public VNVisitor { // Modport: Remember its name for later resolution UINFO(5, " fiv: " << nodep << endl); VL_RESTORER(m_curSymp); - VSymEnt* const oldCurSymp = m_curSymp; { // Create symbol table for the vars m_curSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, nullptr); - m_curSymp->fallbackp(oldCurSymp); + m_curSymp->fallbackp(VL_RESTORER_PREV(m_curSymp)); iterateChildren(nodep); } } @@ -2461,7 +2457,8 @@ private: m_ds.m_dotErr = true; } else { const auto classp = VN_AS(classSymp->nodep(), Class); - if (!classp->extendsp()) { + const auto cextp = classp->extendsp(); + if (!cextp) { nodep->v3error("'super' used on non-extended class (IEEE 1800-2017 8.15)"); m_ds.m_dotErr = true; } else { @@ -2469,8 +2466,6 @@ private: && m_extendsParam.find(classp) != m_extendsParam.end()) { m_ds.m_unresolvedClass = true; } else { - const auto cextp = classp->extendsp(); - UASSERT_OBJ(cextp, nodep, "Bad super extends link"); const auto baseClassp = cextp->classp(); UASSERT_OBJ(baseClassp, nodep, "Bad superclass"); m_ds.m_dotSymp = m_statep->getNodeSym(baseClassp); @@ -3151,12 +3146,16 @@ private: } else { string baddot; VSymEnt* okSymp = nullptr; - VSymEnt* dotSymp = nodep->dotted().empty() - ? m_ds.m_dotSymp // Non-'super.' dotted reference - : m_curSymp; // Start search at dotted point - // of same name under a subtask isn't a relevant hit however a - // function under a begin/end is. So we want begins, but not - // the function + VSymEnt* dotSymp; + if (nodep->dotted().empty()) { + // Non-'super.' dotted reference + dotSymp = m_ds.m_dotSymp; + } else { + // Start search at module, as a variable of same name under a subtask isn't a + // relevant hit however a function under a begin/end is. So we want begins, but + // not the function + dotSymp = m_curSymp; + } if (nodep->classOrPackagep()) { // Look only in specified package dotSymp = m_statep->getNodeSym(nodep->classOrPackagep()); UINFO(8, " Override classOrPackage " << dotSymp << endl); @@ -3335,7 +3334,7 @@ private: void visit(AstNodeBlock* nodep) override { UINFO(5, " " << nodep << endl); checkNoDot(nodep); - VSymEnt* const oldCurSymp = m_curSymp; + VL_RESTORER(m_curSymp); { if (nodep->name() != "") { m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep); @@ -3343,7 +3342,7 @@ private: } iterateChildren(nodep); } - m_ds.m_dotSymp = m_curSymp = oldCurSymp; + m_ds.m_dotSymp = VL_RESTORER_PREV(m_curSymp); UINFO(5, " cur=se" << cvtToHex(m_curSymp) << endl); } void visit(AstNodeFTask* nodep) override { @@ -3368,7 +3367,7 @@ private: nodep->v3error("Definition not found for extern " + nodep->prettyNameQ()); } } - VSymEnt* const oldCurSymp = m_curSymp; + VL_RESTORER(m_curSymp); { m_ftaskp = nodep; m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep); @@ -3383,28 +3382,28 @@ private: } } } - m_ds.m_dotSymp = m_curSymp = oldCurSymp; + m_ds.m_dotSymp = VL_RESTORER_PREV(m_curSymp); m_ftaskp = nullptr; } void visit(AstForeach* nodep) override { UINFO(5, " " << nodep << endl); checkNoDot(nodep); - VSymEnt* const oldCurSymp = m_curSymp; + VL_RESTORER(m_curSymp); { m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep); iterateChildren(nodep); } - m_ds.m_dotSymp = m_curSymp = oldCurSymp; + m_ds.m_dotSymp = VL_RESTORER_PREV(m_curSymp); } void visit(AstWith* nodep) override { UINFO(5, " " << nodep << endl); checkNoDot(nodep); - VSymEnt* const oldCurSymp = m_curSymp; + VL_RESTORER(m_curSymp); { m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep); iterateChildren(nodep); } - m_ds.m_dotSymp = m_curSymp = oldCurSymp; + m_ds.m_dotSymp = VL_RESTORER_PREV(m_curSymp); } void visit(AstLambdaArgRef* nodep) override { UINFO(5, " " << nodep << endl); @@ -3582,6 +3581,7 @@ private: } } } + m_ds.m_dotSymp = VL_RESTORER_PREV(m_curSymp); } void visit(AstRefDType* nodep) override { // Resolve its reference diff --git a/test_regress/t/t_class_nested_link.pl b/test_regress/t/t_class_nested_link.pl new file mode 100755 index 000000000..1aa73f80a --- /dev/null +++ b/test_regress/t/t_class_nested_link.pl @@ -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 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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_nested_link.v b/test_regress/t/t_class_nested_link.v new file mode 100644 index 000000000..def276cc9 --- /dev/null +++ b/test_regress/t/t_class_nested_link.v @@ -0,0 +1,45 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Anthony Donlon. +// SPDX-License-Identifier: CC0-1.0 + +/// Test for bug4553 + +// bit0: 'new' called +// bit1: 'myfunc' called +// bit2: 'myfunc' in class called +int calls = 0; + +module t; + // int calls = 0; // TODO: Error: Internal Error: Can't locate varref scope + + function void myfunc(); + calls |= 32'b10; + endfunction : myfunc + + class Cls #(int A = 0); + function new(); + calls |= 32'b1; + endfunction : new + function void myfunc(); + calls |= 32'b100; + endfunction : myfunc + endclass + + Cls #(100) cls; + + // this block is following the definition of Cls + initial begin + cls = new; + myfunc(); + + if (calls != 32'b011) begin + $write("calls: %0b\n", calls); + $stop; + end + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From bba3487dc420b5fa7367020bc3733e06efdb2199 Mon Sep 17 00:00:00 2001 From: Anthony Donlon <4056887+donlon@users.noreply.github.com> Date: Sun, 15 Oct 2023 20:15:46 +0100 Subject: [PATCH 074/157] Internals: Fix hash and comparison function for AstBasicDType (#4564) --- src/V3AstNodes.cpp | 8 +++----- src/V3Hasher.cpp | 1 + 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index ccd0c24ed..df65365c4 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -277,11 +277,9 @@ int AstBasicDType::widthTotalBytes() const { bool AstBasicDType::same(const AstNode* samep) const { const AstBasicDType* const sp = static_cast(samep); - if (!rangep() && !sp->rangep() && m == sp->m) { - return true; - } else { - return m == sp->m && rangep() && rangep()->sameTree(sp->rangep()); - } + if (!(m == sp->m) || numeric() != sp->numeric()) return false; + if (!rangep() && !sp->rangep()) return true; + return rangep() && rangep()->sameTree(sp->rangep()); } int AstNodeUOrStructDType::widthTotalBytes() const { diff --git a/src/V3Hasher.cpp b/src/V3Hasher.cpp index f0a4d2bfa..0e13e18d5 100644 --- a/src/V3Hasher.cpp +++ b/src/V3Hasher.cpp @@ -143,6 +143,7 @@ private: void visit(AstBasicDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { m_hash += nodep->keyword(); + m_hash += nodep->numeric(); m_hash += nodep->nrange().left(); m_hash += nodep->nrange().right(); }); From 25dde58297059c6f4bdfbdb1c31ef532591d1a6d Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Mon, 16 Oct 2023 18:17:52 +0900 Subject: [PATCH 075/157] Internals: Use VN_AS instead of static_cast. Fix some wrong types. (#4561) --- src/V3AstNodeDType.h | 56 ++++++++++++++++++++++++-------------------- src/V3AstNodeExpr.h | 30 ++++++++++++------------ src/V3AstNodeOther.h | 30 ++++++++++++------------ src/V3AstNodes.cpp | 28 +++++++++++----------- 4 files changed, 74 insertions(+), 70 deletions(-) diff --git a/src/V3AstNodeDType.h b/src/V3AstNodeDType.h index e1353b9a1..dd5efe25d 100644 --- a/src/V3AstNodeDType.h +++ b/src/V3AstNodeDType.h @@ -160,14 +160,14 @@ public: if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); } bool same(const AstNode* samep) const override { - const AstNodeArrayDType* const asamep = static_cast(samep); + const AstNodeArrayDType* const asamep = VN_DBG_AS(samep, NodeArrayDType); return (hi() == asamep->hi() && subDTypep() == asamep->subDTypep() && rangenp()->sameTree(asamep->rangenp())); } // HashedDT doesn't recurse, so need to check children bool similarDType(const AstNodeDType* samep) const override { - const AstNodeArrayDType* const asamep = static_cast(samep); - return (asamep && type() == samep->type() && hi() == asamep->hi() - && rangenp()->sameTree(asamep->rangenp()) + if (type() != samep->type()) return false; + const AstNodeArrayDType* const asamep = VN_DBG_AS(samep, NodeArrayDType); + return (hi() == asamep->hi() && rangenp()->sameTree(asamep->rangenp()) && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); } AstNodeDType* getChildDTypep() const override { return childDTypep(); } @@ -314,14 +314,15 @@ public: if (m_keyDTypep && m_keyDTypep->clonep()) m_keyDTypep = m_keyDTypep->clonep(); } bool same(const AstNode* samep) const override { - const AstAssocArrayDType* const asamep = static_cast(samep); + const AstAssocArrayDType* const asamep = VN_DBG_AS(samep, AssocArrayDType); if (!asamep->subDTypep()) return false; if (!asamep->keyDTypep()) return false; return (subDTypep() == asamep->subDTypep() && keyDTypep() == asamep->keyDTypep()); } bool similarDType(const AstNodeDType* samep) const override { - const AstAssocArrayDType* const asamep = static_cast(samep); - return type() == samep->type() && asamep->subDTypep() + if (type() != samep->type()) return false; + const AstAssocArrayDType* const asamep = VN_DBG_AS(samep, AssocArrayDType); + return asamep->subDTypep() && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); } string prettyDTypeName() const override; @@ -507,7 +508,7 @@ public: public: ASTGEN_MEMBERS_AstCDType; bool same(const AstNode* samep) const override { - const AstCDType* const asamep = static_cast(samep); + const AstCDType* const asamep = VN_DBG_AS(samep, CDType); return m_name == asamep->m_name; } bool similarDType(const AstNodeDType* samep) const override { return same(samep); } @@ -547,7 +548,7 @@ public: const char* broken() const override; void cloneRelink() override; bool same(const AstNode* samep) const override { - const AstClassRefDType* const asamep = static_cast(samep); + const AstClassRefDType* const asamep = VN_DBG_AS(samep, ClassRefDType); return (m_classp == asamep->m_classp && m_classOrPackagep == asamep->m_classOrPackagep); } bool similarDType(const AstNodeDType* samep) const override { @@ -596,7 +597,7 @@ public: if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); } bool same(const AstNode* samep) const override { - const AstConstDType* const sp = static_cast(samep); + const AstConstDType* const sp = VN_DBG_AS(samep, ConstDType); return (m_refDTypep == sp->m_refDTypep); } bool similarDType(const AstNodeDType* samep) const override { @@ -645,7 +646,7 @@ public: ASTGEN_MEMBERS_AstDefImplicitDType; int uniqueNum() const { return m_uniqueNum; } bool same(const AstNode* samep) const override { - const AstDefImplicitDType* const sp = static_cast(samep); + const AstDefImplicitDType* const sp = VN_DBG_AS(samep, DefImplicitDType); return uniqueNum() == sp->uniqueNum(); } bool similarDType(const AstNodeDType* samep) const override { @@ -696,13 +697,14 @@ public: if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); } bool same(const AstNode* samep) const override { - const AstAssocArrayDType* const asamep = static_cast(samep); + const AstDynArrayDType* const asamep = VN_DBG_AS(samep, DynArrayDType); if (!asamep->subDTypep()) return false; return subDTypep() == asamep->subDTypep(); } bool similarDType(const AstNodeDType* samep) const override { - const AstAssocArrayDType* const asamep = static_cast(samep); - return type() == samep->type() && asamep->subDTypep() + if (type() != samep->type()) return false; + const AstDynArrayDType* const asamep = VN_DBG_AS(samep, DynArrayDType); + return asamep->subDTypep() && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); } string prettyDTypeName() const override; @@ -787,7 +789,7 @@ public: } int uniqueNum() const { return m_uniqueNum; } bool same(const AstNode* samep) const override { - const AstEnumDType* const sp = static_cast(samep); + const AstEnumDType* const sp = VN_DBG_AS(samep, EnumDType); return uniqueNum() == sp->uniqueNum(); } bool similarDType(const AstNodeDType* samep) const override { return this == samep; } @@ -982,9 +984,9 @@ public: AstNodeDType* skipRefToConstp() const override { return subDTypep()->skipRefToConstp(); } AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); } bool similarDType(const AstNodeDType* samep) const override { - const AstParamTypeDType* const sp = static_cast(samep); - return type() == samep->type() && sp - && this->subDTypep()->skipRefp()->similarDType(sp->subDTypep()->skipRefp()); + if (type() != samep->type()) return false; + const AstParamTypeDType* const sp = VN_DBG_AS(samep, ParamTypeDType); + return this->subDTypep()->skipRefp()->similarDType(sp->subDTypep()->skipRefp()); } int widthAlignBytes() const override { return dtypep()->widthAlignBytes(); } int widthTotalBytes() const override { return dtypep()->widthTotalBytes(); } @@ -1055,13 +1057,14 @@ public: if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); } bool same(const AstNode* samep) const override { - const AstQueueDType* const asamep = static_cast(samep); + const AstQueueDType* const asamep = VN_DBG_AS(samep, QueueDType); if (!asamep->subDTypep()) return false; return (subDTypep() == asamep->subDTypep()); } bool similarDType(const AstNodeDType* samep) const override { - const AstQueueDType* const asamep = static_cast(samep); - return type() == samep->type() && asamep->subDTypep() + if (type() != samep->type()) return false; + const AstQueueDType* const asamep = VN_DBG_AS(samep, QueueDType); + return asamep->subDTypep() && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); } void dumpSmall(std::ostream& str) const override; @@ -1119,7 +1122,7 @@ public: const char* broken() const override; void cloneRelink() override; bool same(const AstNode* samep) const override { - const AstRefDType* const asamep = static_cast(samep); + const AstRefDType* const asamep = VN_DBG_AS(samep, RefDType); return (m_typedefp == asamep->m_typedefp && m_refDTypep == asamep->m_refDTypep && m_name == asamep->m_name && m_classOrPackagep == asamep->m_classOrPackagep); } @@ -1197,13 +1200,14 @@ public: if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); } bool same(const AstNode* samep) const override { - const AstNodeArrayDType* const asamep = static_cast(samep); + const AstSampleQueueDType* const asamep = VN_DBG_AS(samep, SampleQueueDType); if (!asamep->subDTypep()) return false; return (subDTypep() == asamep->subDTypep()); } bool similarDType(const AstNodeDType* samep) const override { - const AstSampleQueueDType* const asamep = static_cast(samep); - return type() == samep->type() && asamep->subDTypep() + if (type() != samep->type()) return false; + const AstSampleQueueDType* const asamep = VN_DBG_AS(samep, SampleQueueDType); + return asamep->subDTypep() && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); } void dumpSmall(std::ostream& str) const override; @@ -1396,7 +1400,7 @@ public: ASTGEN_MEMBERS_AstUnpackArrayDType; string prettyDTypeName() const override; bool same(const AstNode* samep) const override { - const AstUnpackArrayDType* const sp = static_cast(samep); + const AstUnpackArrayDType* const sp = VN_DBG_AS(samep, UnpackArrayDType); return m_isCompound == sp->m_isCompound; } // Outer dimension comes first. The first element is this node. diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 580c5e3ce..37a360170 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -198,7 +198,7 @@ public: const char* broken() const override; int instrCount() const override { return INSTR_COUNT_CALL; } bool same(const AstNode* samep) const override { - const AstNodeCCall* const asamep = static_cast(samep); + const AstNodeCCall* const asamep = VN_DBG_AS(samep, NodeCCall); return (funcp() == asamep->funcp() && argTypes() == asamep->argTypes()); } bool isGateOptimizable() const override { return false; } @@ -640,7 +640,7 @@ public: string name() const override VL_MT_STABLE { return m_name; } // * = Var name void name(const string& name) override { m_name = name; } bool same(const AstNode* samep) const override { - const AstCMethodHard* asamep = static_cast(samep); + const AstCMethodHard* const asamep = VN_DBG_AS(samep, CMethodHard); return (m_name == asamep->m_name); } bool isPure() override { return m_pure; } @@ -772,7 +772,7 @@ public: } bool same(const AstNode* samep) const override { return (m_classOrPackageNodep - == static_cast(samep)->m_classOrPackageNodep); + == VN_DBG_AS(samep, ClassOrPackageRef)->m_classOrPackageNodep); } void dump(std::ostream& str = std::cout) const override; string name() const override VL_MT_STABLE { return m_name; } // * = Var name @@ -1043,7 +1043,7 @@ public: string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return true; } bool same(const AstNode* samep) const override { - const AstConst* const sp = static_cast(samep); + const AstConst* const sp = VN_DBG_AS(samep, Const); return num().isCaseEq(sp->num()); } void cloneRelink() override { m_num.nodep(this); } @@ -1139,7 +1139,7 @@ public: const char* broken() const override; void cloneRelink() override; bool same(const AstNode* samep) const override { - const AstEnumItemRef* const sp = static_cast(samep); + const AstEnumItemRef* const sp = VN_DBG_AS(samep, EnumItemRef); return itemp() == sp->itemp(); } AstEnumItem* itemp() const VL_MT_STABLE { return m_itemp; } @@ -1297,7 +1297,7 @@ public: bool isOutputter() override { return true; } // SPECIAL: makes output bool cleanOut() const override { return false; } bool same(const AstNode* samep) const override { - return text() == static_cast(samep)->text(); + return text() == VN_DBG_AS(samep, FScanF)->text(); } string text() const { return m_text; } // * = Text to display void text(const string& text) { m_text = text; } @@ -1426,7 +1426,7 @@ public: bool same(const AstNode* samep) const override { // Only works if exact same children, instead should override comparison // of children list, and instead use map-vs-map key/value compare - return m_map == static_cast(samep)->m_map; + return m_map == VN_DBG_AS(samep, InitArray)->m_map; } void addValuep(AstNodeExpr* newp) { addIndexValuep(m_map.size(), newp); } const KeyItemMap& map() const { return m_map; } @@ -1582,7 +1582,7 @@ public: void dump(std::ostream& str) const override; string name() const override VL_MT_STABLE { return m_name; } // * = Var name bool same(const AstNode* samep) const override { - const AstParseRef* const asamep = static_cast(samep); + const AstParseRef* const asamep = VN_DBG_AS(samep, ParseRef); return (expect() == asamep->expect() && m_name == asamep->m_name); } void name(const string& name) override { m_name = name; } @@ -1777,7 +1777,7 @@ public: string name() const override VL_MT_STABLE { return m_text; } int instrCount() const override { return INSTR_COUNT_PLI; } bool same(const AstNode* samep) const override { - return text() == static_cast(samep)->text(); + return text() == VN_DBG_AS(samep, SFormatF)->text(); } string verilogKwd() const override { return "$sformatf"; } string text() const { return m_text; } // * = Text to display @@ -1819,7 +1819,7 @@ public: bool isOutputter() override { return true; } // SPECIAL: makes output bool cleanOut() const override { return false; } bool same(const AstNode* samep) const override { - return text() == static_cast(samep)->text(); + return text() == VN_DBG_AS(samep, SScanF)->text(); } string text() const { return m_text; } // * = Text to display void text(const string& text) { m_text = text; } @@ -1859,8 +1859,8 @@ public: } ASTGEN_MEMBERS_AstScopeName; bool same(const AstNode* samep) const override { - return (m_dpiExport == static_cast(samep)->m_dpiExport - && m_forFormat == static_cast(samep)->m_forFormat); + const AstScopeName* const sp = VN_DBG_AS(samep, ScopeName); + return (m_dpiExport == sp->m_dpiExport && m_forFormat == sp->m_forFormat); } string emitVerilog() override { return ""; } string emitC() override { V3ERROR_NA_RETURN(""); } @@ -2003,7 +2003,7 @@ public: return VN_IS(fromp()->dtypep()->skipRefp(), StructDType); } bool same(const AstNode* samep) const override { - const AstStructSel* const sp = static_cast(samep); + const AstStructSel* const sp = VN_DBG_AS(samep, StructSel); return m_name == sp->m_name; } int instrCount() const override { return widthInstrs(); } @@ -4749,7 +4749,7 @@ public: bool cleanLhs() const override { return true; } bool sizeMattersLhs() const override { return false; } // Special cased in V3Cast bool same(const AstNode* samep) const override { - return size() == static_cast(samep)->size(); + return size() == VN_DBG_AS(samep, CCast)->size(); } void dump(std::ostream& str = std::cout) const override; // @@ -5543,7 +5543,7 @@ public: bool cleanOut() const override { return true; } int instrCount() const override { return widthInstrs(); } bool same(const AstNode* samep) const override { - const AstVarXRef* asamep = static_cast(samep); + const AstVarXRef* asamep = VN_DBG_AS(samep, VarXRef); return (selfPointer() == asamep->selfPointer() && varp() == asamep->varp() && name() == asamep->name() && dotted() == asamep->dotted()); } diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index e41d614d2..91c015958 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -484,7 +484,7 @@ public: bool isOutputter() override { return true; } bool isUnlikely() const override { return true; } bool same(const AstNode* samep) const override { - return isHex() == static_cast(samep)->isHex(); + return isHex() == VN_DBG_AS(samep, NodeReadWriteMem)->isHex(); } bool isHex() const { return m_isHex; } virtual const char* cFuncPrefixp() const = 0; @@ -503,7 +503,7 @@ public: ASTGEN_MEMBERS_AstNodeText; void dump(std::ostream& str = std::cout) const override; bool same(const AstNode* samep) const override { - const AstNodeText* asamep = static_cast(samep); + const AstNodeText* asamep = VN_DBG_AS(samep, NodeText); return text() == asamep->text(); } const string& text() const VL_MT_SAFE { return m_text; } @@ -645,7 +645,7 @@ public: bool maybePointedTo() const override { return true; } void dump(std::ostream& str = std::cout) const override; bool same(const AstNode* samep) const override { - const AstCFunc* const asamep = static_cast(samep); + const AstCFunc* const asamep = VN_DBG_AS(samep, CFunc); return ((isTrace() == asamep->isTrace()) && (rtnTypeVoid() == asamep->rtnTypeVoid()) && (argTypes() == asamep->argTypes()) && (baseCtors() == asamep->baseCtors()) && isLoose() == asamep->isLoose() @@ -1013,7 +1013,7 @@ public: bool isOutputter() override { return true; } // SPECIAL: $display makes output bool isUnlikely() const override { return true; } bool same(const AstNode* samep) const override { - return displayType() == static_cast(samep)->displayType(); + return displayType() == VN_DBG_AS(samep, ElabDisplay)->displayType(); } int instrCount() const override { return INSTR_COUNT_PLI; } VDisplayType displayType() const { return m_displayType; } @@ -1347,7 +1347,7 @@ public: VPragmaType pragType() const { return m_pragType; } // *=type of the pragma bool isPredictOptimizable() const override { return false; } bool same(const AstNode* samep) const override { - return pragType() == static_cast(samep)->pragType(); + return pragType() == VN_DBG_AS(samep, Pragma)->pragType(); } }; class AstPropSpec final : public AstNode { @@ -1382,7 +1382,7 @@ public: } ASTGEN_MEMBERS_AstPull; bool same(const AstNode* samep) const override { - return direction() == static_cast(samep)->direction(); + return direction() == VN_DBG_AS(samep, Pull)->direction(); } uint32_t direction() const { return (uint32_t)m_direction; } }; @@ -1462,7 +1462,7 @@ public: ASTGEN_MEMBERS_AstSenItem; void dump(std::ostream& str) const override; bool same(const AstNode* samep) const override { - return edgeType() == static_cast(samep)->edgeType(); + return edgeType() == VN_DBG_AS(samep, SenItem)->edgeType(); } VEdgeType edgeType() const { return m_edgeType; } void edgeType(VEdgeType type) { @@ -2611,7 +2611,7 @@ public: void hier(const string& flag) { m_hier = flag; } void comment(const string& flag) { m_text = flag; } bool same(const AstNode* samep) const override { - const AstCoverDecl* const asamep = static_cast(samep); + const AstCoverDecl* const asamep = VN_DBG_AS(samep, CoverDecl); return (fileline() == asamep->fileline() && linescov() == asamep->linescov() && hier() == asamep->hier() && comment() == asamep->comment()); } @@ -2640,7 +2640,7 @@ public: void dump(std::ostream& str) const override; int instrCount() const override { return 1 + 2 * INSTR_COUNT_LD; } bool same(const AstNode* samep) const override { - return declp() == static_cast(samep)->declp(); + return declp() == VN_DBG_AS(samep, CoverInc)->declp(); } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } @@ -2747,7 +2747,7 @@ public: bool isOutputter() override { return true; } // SPECIAL: $display makes output bool isUnlikely() const override { return true; } bool same(const AstNode* samep) const override { - return displayType() == static_cast(samep)->displayType(); + return displayType() == VN_DBG_AS(samep, Display)->displayType(); } int instrCount() const override { return INSTR_COUNT_PLI; } VDisplayType displayType() const { return m_displayType; } @@ -2924,7 +2924,7 @@ public: void dump(std::ostream& str) const override; int instrCount() const override { return INSTR_COUNT_BRANCH; } bool same(const AstNode* samep) const override { - return labelp() == static_cast(samep)->labelp(); + return labelp() == VN_DBG_AS(samep, JumpGo)->labelp(); } bool isGateOptimizable() const override { return false; } bool isBrancher() const override { @@ -2955,7 +2955,7 @@ public: void dump(std::ostream& str) const override; int instrCount() const override { return 0; } bool same(const AstNode* samep) const override { - return blockp() == static_cast(samep)->blockp(); + return blockp() == VN_DBG_AS(samep, JumpLabel)->blockp(); } AstJumpBlock* blockp() const { return m_blockp; } }; @@ -2974,7 +2974,7 @@ public: bool isOutputter() override { return true; } // Though deleted before opt int instrCount() const override { return INSTR_COUNT_PLI; } bool same(const AstNode* samep) const override { - return m_off == static_cast(samep)->m_off; + return m_off == VN_DBG_AS(samep, MonitorOff)->m_off; } bool off() const { return m_off; } }; @@ -3253,7 +3253,7 @@ public: int instrCount() const override { return 10 + 2 * INSTR_COUNT_LD; } bool hasDType() const override { return true; } bool same(const AstNode* samep) const override { - return declp() == static_cast(samep)->declp(); + return declp() == VN_DBG_AS(samep, TraceInc)->declp(); } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } @@ -3463,7 +3463,7 @@ public: ASTGEN_MEMBERS_AstCase; string verilogKwd() const override { return casez() ? "casez" : casex() ? "casex" : "case"; } bool same(const AstNode* samep) const override { - return m_casex == static_cast(samep)->m_casex; + return m_casex == VN_DBG_AS(samep, Case)->m_casex; } bool casex() const { return m_casex == VCaseType::CT_CASEX; } bool casez() const { return m_casex == VCaseType::CT_CASEZ; } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index df65365c4..c06e60907 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -276,7 +276,7 @@ int AstBasicDType::widthTotalBytes() const { } bool AstBasicDType::same(const AstNode* samep) const { - const AstBasicDType* const sp = static_cast(samep); + const AstBasicDType* const sp = VN_DBG_AS(samep, BasicDType); if (!(m == sp->m) || numeric() != sp->numeric()) return false; if (!rangep() && !sp->rangep()) return true; return rangep() && rangep()->sameTree(sp->rangep()); @@ -1703,7 +1703,7 @@ AstNodeUOrStructDType* AstMemberDType::getChildStructp() const { } bool AstMemberSel::same(const AstNode* samep) const { - const AstMemberSel* const sp = static_cast(samep); + const AstMemberSel* const sp = VN_DBG_AS(samep, MemberSel); return sp != nullptr && access() == sp->access() && fromp()->same(sp->fromp()) && name() == sp->name() && varp()->same(sp->varp()); } @@ -2061,13 +2061,14 @@ void AstWildcardArrayDType::dumpSmall(std::ostream& str) const { str << "[*]"; } bool AstWildcardArrayDType::same(const AstNode* samep) const { - const AstNodeArrayDType* const asamep = static_cast(samep); + const AstWildcardArrayDType* const asamep = VN_DBG_AS(samep, WildcardArrayDType); if (!asamep->subDTypep()) return false; return (subDTypep() == asamep->subDTypep()); } bool AstWildcardArrayDType::similarDType(const AstNodeDType* samep) const { - const AstNodeArrayDType* const asamep = static_cast(samep); - return type() == samep->type() && asamep->subDTypep() + if (type() != samep->type()) return false; + const AstWildcardArrayDType* const asamep = VN_DBG_AS(samep, WildcardArrayDType); + return asamep->subDTypep() && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); } void AstSampleQueueDType::dumpSmall(std::ostream& str) const { @@ -2079,13 +2080,14 @@ void AstUnsizedArrayDType::dumpSmall(std::ostream& str) const { str << "[]"; } bool AstUnsizedArrayDType::same(const AstNode* samep) const { - const AstNodeArrayDType* const asamep = static_cast(samep); + const AstUnsizedArrayDType* const asamep = VN_DBG_AS(samep, UnsizedArrayDType); if (!asamep->subDTypep()) return false; return (subDTypep() == asamep->subDTypep()); } bool AstUnsizedArrayDType::similarDType(const AstNodeDType* samep) const { - const AstNodeArrayDType* const asamep = static_cast(samep); - return type() == samep->type() && asamep->subDTypep() + if (type() != samep->type()) return false; + const AstUnsizedArrayDType* const asamep = VN_DBG_AS(samep, UnsizedArrayDType); + return asamep->subDTypep() && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); } void AstEmptyQueueDType::dumpSmall(std::ostream& str) const { @@ -2112,7 +2114,7 @@ void AstVarScope::dump(std::ostream& str) const { } } bool AstVarScope::same(const AstNode* samep) const { - const AstVarScope* const asamep = static_cast(samep); + const AstVarScope* const asamep = VN_DBG_AS(samep, VarScope); return varp()->same(asamep->varp()) && scopep()->same(asamep->scopep()); } void AstNodeVarRef::dump(std::ostream& str) const { @@ -2146,9 +2148,7 @@ const char* AstVarRef::broken() const { BROKEN_RTN(!varp()); return AstNodeVarRef::broken(); } -bool AstVarRef::same(const AstNode* samep) const { - return same(static_cast(samep)); -} +bool AstVarRef::same(const AstNode* samep) const { return same(VN_DBG_AS(samep, VarRef)); } int AstVarRef::instrCount() const { // Account for the target of hard-coded method calls as just an address computation if (const AstCMethodHard* const callp = VN_CAST(backp(), CMethodHard)) { @@ -2189,7 +2189,7 @@ void AstVar::dump(std::ostream& str) const { str << " " << varType(); } bool AstVar::same(const AstNode* samep) const { - const AstVar* const asamep = static_cast(samep); + const AstVar* const asamep = VN_DBG_AS(samep, Var); return name() == asamep->name() && varType() == asamep->varType(); } void AstScope::dump(std::ostream& str) const { @@ -2199,7 +2199,7 @@ void AstScope::dump(std::ostream& str) const { str << " [modp=" << reinterpret_cast(modp()) << "]"; } bool AstScope::same(const AstNode* samep) const { - const AstScope* const asamep = static_cast(samep); + const AstScope* const asamep = VN_DBG_AS(samep, Scope); return name() == asamep->name() && ((!aboveScopep() && !asamep->aboveScopep()) || (aboveScopep() && asamep->aboveScopep() From ad3bcbb1bb0a8afe63e842d7214682b562f0807f Mon Sep 17 00:00:00 2001 From: Aleksander Kiryk Date: Mon, 16 Oct 2023 14:02:29 +0200 Subject: [PATCH 076/157] Support `disable fork` (#4125) (#4569) --- include/verilated_types.h | 33 +++- src/V3AstNodeOther.h | 14 +- src/V3AstNodes.cpp | 1 + src/V3EmitCFunc.cpp | 5 +- src/V3EmitCFunc.h | 7 +- src/V3LinkJump.cpp | 2 +- src/V3SchedTiming.cpp | 10 +- src/V3Timing.cpp | 145 ++++++++++++------ src/V3Width.cpp | 10 +- test_regress/t/t_disable.out | 5 + test_regress/t/t_disable.pl | 20 +++ test_regress/t/t_disable.v | 19 +++ test_regress/t/t_disable_fork1.pl | 23 +++ test_regress/t/t_disable_fork1.v | 49 ++++++ test_regress/t/t_disable_fork2.pl | 23 +++ test_regress/t/t_disable_fork2.v | 58 +++++++ test_regress/t/t_disable_fork3.pl | 23 +++ test_regress/t/t_disable_fork3.v | 18 +++ test_regress/t/t_disable_fork_notiming.out | 6 + test_regress/t/t_disable_fork_notiming.pl | 20 +++ test_regress/t/t_disable_fork_notiming.v | 9 ++ test_regress/t/t_fork_disable.out | 10 -- test_regress/t/t_uvm_pkg_todo.vh | 12 +- test_regress/t/t_wait_fork.out | 6 + .../t/{t_fork_disable.pl => t_wait_fork.pl} | 0 .../t/{t_fork_disable.v => t_wait_fork.v} | 0 26 files changed, 441 insertions(+), 87 deletions(-) create mode 100644 test_regress/t/t_disable.out create mode 100755 test_regress/t/t_disable.pl create mode 100644 test_regress/t/t_disable.v create mode 100755 test_regress/t/t_disable_fork1.pl create mode 100644 test_regress/t/t_disable_fork1.v create mode 100755 test_regress/t/t_disable_fork2.pl create mode 100644 test_regress/t/t_disable_fork2.v create mode 100755 test_regress/t/t_disable_fork3.pl create mode 100644 test_regress/t/t_disable_fork3.v create mode 100644 test_regress/t/t_disable_fork_notiming.out create mode 100755 test_regress/t/t_disable_fork_notiming.pl create mode 100644 test_regress/t/t_disable_fork_notiming.v delete mode 100644 test_regress/t/t_fork_disable.out create mode 100644 test_regress/t/t_wait_fork.out rename test_regress/t/{t_fork_disable.pl => t_wait_fork.pl} (100%) rename test_regress/t/{t_fork_disable.v => t_wait_fork.v} (100%) diff --git a/include/verilated_types.h b/include/verilated_types.h index 9eae185d5..876a78511 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -81,11 +81,16 @@ constexpr IData VL_CLOG2_CE_Q(QData lhs) VL_PURE { return lhs <= 1 ? 0 : VL_CLOG2_CE_Q((lhs + 1) >> 1ULL) + 1; } -//=================================================================== -// VlProcess stores metadata of running processes +// Metadata of processes +class VlProcess; + +using VlProcessRef = std::shared_ptr; + class VlProcess final { // MEMBERS int m_state; // Current state of the process + VlProcessRef m_parentp = nullptr; // Parent process, if exists + std::set m_children; // Active child processes public: // TYPES @@ -98,16 +103,34 @@ public: }; // CONSTRUCTORS + // Construct independent process VlProcess() : m_state{RUNNING} {} + // Construct child process of parent + VlProcess(VlProcessRef parentp) + : m_state{RUNNING} + , m_parentp{parentp} { + m_parentp->attach(this); + } + + ~VlProcess() { + if (m_parentp) m_parentp->detach(this); + } + + void attach(VlProcess* childp) { m_children.insert(childp); } + void detach(VlProcess* childp) { m_children.erase(childp); } - // METHODS int state() { return m_state; } void state(int s) { m_state = s; } + void disable() { + state(KILLED); + disable_fork(); + } + void disable_fork() { + for (VlProcess* childp : m_children) childp->disable(); + } }; -using VlProcessRef = std::shared_ptr; - inline std::string VL_TO_STRING(const VlProcessRef& p) { return std::string("process"); } //=================================================================== diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 91c015958..2fea7ff71 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -86,7 +86,7 @@ private: bool m_recursive : 1; // Recursive or part of recursion bool m_underGenerate : 1; // Under generate (for warning) bool m_virtual : 1; // Virtual method in class - bool m_needProcess : 1; // Implements part of a process that allocates std::process + bool m_needProcess : 1; // Needs access to VlProcess of the caller VLifetime m_lifetime; // Lifetime VIsCached m_purity; // Pure state @@ -300,7 +300,7 @@ class AstNodeProcedure VL_NOT_FINAL : public AstNode { // IEEE procedure: initial, final, always // @astgen op2 := stmtsp : List[AstNode] // Note: op1 is used in some sub-types only bool m_suspendable : 1; // Is suspendable by a Delay, EventControl, etc. - bool m_needProcess : 1; // Implements part of a process that allocates std::process + bool m_needProcess : 1; // Uses VlProcess protected: AstNodeProcedure(VNType t, FileLine* fl, AstNode* stmtsp) : AstNode{t, fl} { @@ -608,7 +608,7 @@ private: bool m_dpiImportPrototype : 1; // This is the DPI import prototype (i.e.: provided by user) bool m_dpiImportWrapper : 1; // Wrapper for invoking DPI import prototype from generated code bool m_dpiTraceInit : 1; // DPI trace_init - bool m_needProcess : 1; // Implements part of a process that allocates std::process + bool m_needProcess : 1; // Needs access to VlProcess of the caller public: AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType = "") : ASTGEN_SUPER_CFunc(fl) { @@ -2096,19 +2096,23 @@ class AstBegin final : public AstNodeBlock { // Parents: statement // @astgen op1 := genforp : Optional[AstNode] - bool m_generate; // Underneath a generate - const bool m_implied; // Not inserted by user + bool m_generate : 1; // Underneath a generate + bool m_needProcess : 1; // Uses VlProcess + const bool m_implied : 1; // Not inserted by user public: // Node that puts name into the output stream AstBegin(FileLine* fl, const string& name, AstNode* stmtsp, bool generate = false, bool implied = false) : ASTGEN_SUPER_Begin(fl, name, stmtsp) , m_generate{generate} + , m_needProcess{false} , m_implied{implied} {} ASTGEN_MEMBERS_AstBegin; void dump(std::ostream& str) const override; void generate(bool flag) { m_generate = flag; } bool generate() const { return m_generate; } + void setNeedProcess() { m_needProcess = true; } + bool needProcess() const { return m_needProcess; } bool implied() const { return m_implied; } }; class AstFork final : public AstNodeBlock { diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index c06e60907..4720c4b01 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -2321,6 +2321,7 @@ void AstBegin::dump(std::ostream& str) const { if (generate()) str << " [GEN]"; if (genforp()) str << " [GENFOR]"; if (implied()) str << " [IMPLIED]"; + if (needProcess()) str << " [NPRC]"; } void AstCoverDecl::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); diff --git a/src/V3EmitCFunc.cpp b/src/V3EmitCFunc.cpp index 0264059a3..deb4ceb61 100644 --- a/src/V3EmitCFunc.cpp +++ b/src/V3EmitCFunc.cpp @@ -410,7 +410,8 @@ void EmitCFunc::displayNode(AstNode* nodep, AstScopeName* scopenamep, const stri displayEmit(nodep, isScan); } -void EmitCFunc::emitCCallArgs(const AstNodeCCall* nodep, const string& selfPointer) { +void EmitCFunc::emitCCallArgs(const AstNodeCCall* nodep, const string& selfPointer, + bool inProcess) { puts("("); bool comma = false; if (nodep->funcp()->isLoose() && !nodep->funcp()->isStatic()) { @@ -422,6 +423,8 @@ void EmitCFunc::emitCCallArgs(const AstNodeCCall* nodep, const string& selfPoint if (comma) puts(", "); if (VN_IS(nodep->backp(), CAwait) || !nodep->funcp()->isCoroutine()) { puts("vlProcess"); + } else if (inProcess) { + puts("std::make_shared(vlProcess)"); } else { puts("std::make_shared()"); } diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index f9b3bd3d6..871ec3624 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -205,7 +205,7 @@ public: } void emitOpName(AstNode* nodep, const string& format, AstNode* lhsp, AstNode* rhsp, AstNode* thsp); - void emitCCallArgs(const AstNodeCCall* nodep, const string& selfPointer); + void emitCCallArgs(const AstNodeCCall* nodep, const string& selfPointer, bool inProcess); void emitDereference(const string& pointer); void emitCvtPackStr(AstNode* nodep); void emitCvtWideArray(AstNode* nodep, AstNode* fromp); @@ -500,7 +500,7 @@ public: } puts(funcp->nameProtect()); } - emitCCallArgs(nodep, nodep->selfPointerProtect(m_useSelfForThis)); + emitCCallArgs(nodep, nodep->selfPointerProtect(m_useSelfForThis), m_cfuncp->needProcess()); } void visit(AstCMethodCall* nodep) override { const AstCFunc* const funcp = nodep->funcp(); @@ -508,7 +508,7 @@ public: iterateConst(nodep->fromp()); putbs("->"); puts(funcp->nameProtect()); - emitCCallArgs(nodep, ""); + emitCCallArgs(nodep, "", m_cfuncp->needProcess()); } void visit(AstCAwait* nodep) override { puts("co_await "); @@ -613,6 +613,7 @@ public: puts("]);\n"); } } + void visit(AstDisableFork* nodep) override { puts("vlProcess->disable_fork();\n"); } void visit(AstCReturn* nodep) override { puts("return ("); iterateAndNextConstNull(nodep->lhsp()); diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp index 68807a097..d0aa33e64 100644 --- a/src/V3LinkJump.cpp +++ b/src/V3LinkJump.cpp @@ -330,7 +330,7 @@ private: AstJumpLabel* const labelp = findAddLabel(beginp, false); nodep->addNextHere(new AstJumpGo{nodep->fileline(), labelp}); } else { - nodep->v3warn(E_UNSUPPORTED, "Unsupported: disable fork"); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: disabling fork by name"); } nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp index c3ffa9ef6..e072814e7 100644 --- a/src/V3SchedTiming.cpp +++ b/src/V3SchedTiming.cpp @@ -279,7 +279,6 @@ void transformForks(AstNetlist* const netlistp) { // STATE bool m_inClass = false; // Are we in a class? bool m_beginHasAwaits = false; // Does the current begin have awaits? - bool m_beginNeedProcess = false; // Does the current begin have process::self dependency? AstFork* m_forkp = nullptr; // Current fork AstCFunc* m_funcp = nullptr; // Current function @@ -358,9 +357,8 @@ void transformForks(AstNetlist* const netlistp) { UASSERT_OBJ(m_forkp, nodep, "Begin outside of a fork"); // Start with children, so later we only find awaits that are actually in this begin m_beginHasAwaits = false; - m_beginNeedProcess = false; iterateChildrenConst(nodep); - if (m_beginHasAwaits || m_beginNeedProcess) { + if (m_beginHasAwaits || nodep->needProcess()) { UASSERT_OBJ(!nodep->name().empty(), nodep, "Begin needs a name"); // Create a function to put this begin's statements in FileLine* const flp = nodep->fileline(); @@ -384,7 +382,7 @@ void transformForks(AstNetlist* const netlistp) { } // Put the begin's statements in the function, delete the begin newfuncp->addStmtsp(nodep->stmtsp()->unlinkFrBackWithNext()); - if (m_beginNeedProcess) { + if (nodep->needProcess()) { newfuncp->setNeedProcess(); newfuncp->addStmtsp(new AstCStmt{nodep->fileline(), "vlProcess->state(VlProcess::FINISHED);\n"}); @@ -405,10 +403,6 @@ void transformForks(AstNetlist* const netlistp) { m_beginHasAwaits = true; iterateChildrenConst(nodep); } - void visit(AstCCall* nodep) override { - if (nodep->funcp()->needProcess()) m_beginNeedProcess = true; - iterateChildrenConst(nodep); - } void visit(AstExprStmt* nodep) override { iterateChildren(nodep); } //-------------------- diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index 6a10731b6..d2d6bae96 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -12,11 +12,27 @@ // Version 2.0. // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 // -// TimingSuspendableVisitor locates all C++ functions and processes that contain timing controls, -// and marks them as suspendable. If a process calls a suspendable function, then it is also marked -// as suspendable. If a function calls or overrides a suspendable function, it is also marked as -// suspendable. TimingSuspendableVisitor creates a dependency graph to propagate this property. It -// does not perform any AST transformations. +// TimingSuspendableVisitor does not perform any AST transformations. +// Instead it propagates two types of flags: +// - flag "suspendable": (for detecting what will need to become a coroutine) +// The visitor locates all C++ functions and processes that contain timing controls, +// and marks them as suspendable. If a process calls a suspendable function, +// then it is also marked as suspendable. If a function calls or overrides +// a suspendable function, it is also marked as suspendable. +// TimingSuspendableVisitor creates a dependency graph to propagate this property. +// - flag "needs process": (for detecting what needs a VlProcess argument in signature) +// The visitor distinguishes 4 types of nodes: +// - T_ALLOCS_PROC: nodes that can allocate VlProcess (forks, always, initial etc.), +// - T_FORCES_PROC: nodes that make it necessary for the previous type to allocate VlProcess +// (like process::self which then wraps it, allowing use inside Verilog). +// - T_NEEDS_PROC: nodes that should obtain VlProcess if it will be allocated +// (all of the previous type + timing controls, so they could update process state), +// - T_HAS_PROC: nodes that are going to be emitted with a VlProcess argument. +// T_FORCES_PROC and T_NEEDS_PROC are propagated upwards up to the nodes of type T_ALLOCS_PROC, +// this is to detect which processes have to allocate VlProcess. Then nodes of these processes +// get marked as T_HAS_PROC and the flag is propagated downwards through nodes +// type T_NEEDS_PROC. Using only nodes type T_NEEDS_PROC assures the flags are only propagated +// through paths leading to nodes that actually use VlProcess. // // TimingControlVisitor is the one that actually performs transformations: // - for each intra-assignment timing control: @@ -70,8 +86,10 @@ VL_DEFINE_DEBUG_FUNCTIONS; enum NodeFlag : uint8_t { T_SUSPENDEE = 1 << 0, // Suspendable (due to dependence on another suspendable) T_SUSPENDER = 1 << 1, // Suspendable (has timing control) - T_HAS_PROC = 1 << 2, // Has an associated std::process - T_CALLS_PROC_SELF = 1 << 3, // Calls std::process::self + T_ALLOCS_PROC = 1 << 2, // Can allocate VlProcess + T_FORCES_PROC = 1 << 3, // Forces VlProcess allocation + T_NEEDS_PROC = 1 << 4, // Needs access to VlProcess if it's allocated + T_HAS_PROC = 1 << 5, // Has VlProcess argument in the signature }; enum ForkType : uint8_t { @@ -86,6 +104,11 @@ enum PropagationType : uint8_t { P_SIGNATURE = 3, // Propagation required to maintain C++ function's signature requirements }; +// Add timing flag to a node +static void addFlags(AstNode* const nodep, uint8_t flags) { nodep->user2(nodep->user2() | flags); } +// Check if a node has ALL of the expected flags set +static bool hasFlags(AstNode* const nodep, uint8_t flags) { return !(~nodep->user2() & flags); } + // ###################################################################### // Detect nodes affected by timing and/or requiring a process @@ -126,8 +149,8 @@ private: class SuspendDepVtx final : public DepVtx { VL_RTTI_IMPL(SuspendDepVtx, DepVtx) string dotColor() const override { - if (nodep()->user2() & T_SUSPENDER) return "red"; - if (nodep()->user2() & T_SUSPENDEE) return "blue"; + if (hasFlags(nodep(), T_SUSPENDER)) return "red"; + if (hasFlags(nodep(), T_SUSPENDEE)) return "blue"; return "black"; } @@ -140,8 +163,9 @@ private: class NeedsProcDepVtx final : public DepVtx { VL_RTTI_IMPL(NeedsProcDepVtx, DepVtx) string dotColor() const override { - if (nodep()->user2() & T_CALLS_PROC_SELF) return "red"; - if (nodep()->user2() & T_HAS_PROC) return "blue"; + if (hasFlags(nodep(), T_HAS_PROC)) return "blue"; + if (hasFlags(nodep(), T_NEEDS_PROC)) return "green"; + if (hasFlags(nodep(), T_FORCES_PROC)) return "red"; return "black"; } @@ -198,10 +222,10 @@ private: if (!nodep->user5p()) nodep->user5p(new NeedsProcDepVtx{&m_procGraph, nodep, classp}); return nodep->user5u().to(); } - // Set timing flag of a node + // Pass timing flag between nodes bool passFlag(const AstNode* from, AstNode* to, NodeFlag flag) { if ((from->user2() & flag) && !(to->user2() & flag)) { - to->user2(to->user2() | flag); + addFlags(to, flag); return true; } return false; @@ -216,6 +240,15 @@ private: } } template + void propagateFlagsIf(DepVtx* const vxp, NodeFlag flag, Predicate p) { + auto* const parentp = vxp->nodep(); + for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep = edgep->outNextp()) { + auto* const depVxp = static_cast(edgep->top()); + AstNode* const depp = depVxp->nodep(); + if (p(edgep) && passFlag(parentp, depp, flag)) propagateFlagsIf(depVxp, flag, p); + } + } + template void propagateFlagsReversedIf(DepVtx* const vxp, NodeFlag flag, Predicate p) { auto* const parentp = vxp->nodep(); for (V3GraphEdge* edgep = vxp->inBeginp(); edgep; edgep = edgep->inNextp()) { @@ -236,17 +269,22 @@ private: void visit(AstNodeProcedure* nodep) override { VL_RESTORER(m_procp); m_procp = nodep; - if (nodep->needProcess()) nodep->user2(T_HAS_PROC | T_CALLS_PROC_SELF); + getNeedsProcDepVtx(nodep); + addFlags(nodep, T_ALLOCS_PROC); if (VN_IS(nodep, Always)) { UINFO(1, "Always does " << (nodep->needProcess() ? "" : "NOT ") << "need process\n"); } iterateChildren(nodep); } + void visit(AstDisableFork* nodep) override { + visit(static_cast(nodep)); + addFlags(m_procp, T_FORCES_PROC | T_NEEDS_PROC); + } void visit(AstCFunc* nodep) override { VL_RESTORER(m_procp); m_procp = nodep; iterateChildren(nodep); - if (nodep->needProcess()) nodep->user2(T_HAS_PROC | T_CALLS_PROC_SELF); + if (nodep->needProcess()) addFlags(nodep, T_FORCES_PROC | T_NEEDS_PROC); DepVtx* const sVxp = getSuspendDepVtx(nodep); DepVtx* const pVxp = getNeedsProcDepVtx(nodep); if (!m_classp) return; @@ -287,9 +325,12 @@ private: new V3GraphEdge{&m_suspGraph, getSuspendDepVtx(nodep->funcp()), getSuspendDepVtx(m_procp), m_underFork ? P_FORK : P_CALL}; - if (!m_underFork) - new V3GraphEdge{&m_procGraph, getNeedsProcDepVtx(nodep->funcp()), - getNeedsProcDepVtx(m_procp), P_CALL}; + new V3GraphEdge{&m_procGraph, getNeedsProcDepVtx(nodep->funcp()), + getNeedsProcDepVtx(m_procp), P_CALL}; + + if (m_underFork && !(m_underFork & F_MIGHT_SUSPEND)) { + addFlags(nodep, T_NEEDS_PROC | T_ALLOCS_PROC); + } iterateChildren(nodep); } @@ -301,9 +342,12 @@ private: new V3GraphEdge{&m_suspGraph, getSuspendDepVtx(nodep), getSuspendDepVtx(m_procp), m_underFork ? P_FORK : P_CALL}; - if (!m_underFork) - new V3GraphEdge{&m_procGraph, getNeedsProcDepVtx(nodep), getNeedsProcDepVtx(m_procp), - P_CALL}; + new V3GraphEdge{&m_procGraph, getNeedsProcDepVtx(nodep), getNeedsProcDepVtx(m_procp), + P_CALL}; + + if (m_underFork && !(m_underFork & F_MIGHT_SUSPEND)) { + addFlags(nodep, T_NEEDS_PROC | T_ALLOCS_PROC); + } m_procp = nodep; m_underFork = 0; @@ -316,7 +360,7 @@ private: // so that transformForks() in V3SchedTiming gets called and // removes all forks and begins if (nodep->isTimingControl() && m_procp) { - m_procp->user2(T_SUSPENDEE | T_SUSPENDER); + addFlags(m_procp, T_SUSPENDEE | T_SUSPENDER); m_underFork |= F_MIGHT_SUSPEND; } m_underFork |= F_MIGHT_NEED_PROC; @@ -325,7 +369,7 @@ private: void visit(AstNode* nodep) override { if (nodep->isTimingControl()) { v3Global.setUsesTiming(); - if (m_procp) m_procp->user2(T_SUSPENDEE | T_SUSPENDER); + if (m_procp) addFlags(m_procp, T_SUSPENDEE | T_SUSPENDER | T_NEEDS_PROC); } iterateChildren(nodep); } @@ -342,22 +386,35 @@ public: // Propagate suspendability for (V3GraphVertex* vxp = m_suspGraph.verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { DepVtx* const depVxp = static_cast(vxp); - if (depVxp->nodep()->user2() & T_SUSPENDEE) propagateFlags(depVxp, T_SUSPENDEE); + if (hasFlags(depVxp->nodep(), T_SUSPENDEE)) propagateFlags(depVxp, T_SUSPENDEE); } if (dumpGraphLevel() >= 6) m_suspGraph.dumpDotFilePrefixed("timing_deps"); - // Propagate process + + // Propagate T_HAS_PROCESS for (V3GraphVertex* vxp = m_procGraph.verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { DepVtx* const depVxp = static_cast(vxp); - if (depVxp->nodep()->user2() & T_HAS_PROC) propagateFlags(depVxp, T_HAS_PROC); - } - // Propagate process downwards (from caller to callee) for suspendable calls - for (V3GraphVertex* vxp = m_suspGraph.verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { - DepVtx* const depVxp = static_cast(vxp); - if (depVxp->nodep()->user2() & T_HAS_PROC) - propagateFlagsReversedIf(depVxp, T_HAS_PROC, [&](const V3GraphEdge* e) -> bool { - return (e->weight() != P_FORK) - && (static_cast(e->top())->nodep()->user2() & T_SUSPENDEE); + // Find processes that'll allocate VlProcess + if (hasFlags(depVxp->nodep(), T_FORCES_PROC)) { + propagateFlagsIf(depVxp, T_FORCES_PROC, [&](const V3GraphEdge* e) -> bool { + return !hasFlags(static_cast(e->fromp())->nodep(), T_ALLOCS_PROC); }); + } + // Mark nodes on paths between processes and statements that use VlProcess + if (hasFlags(depVxp->nodep(), T_NEEDS_PROC)) { + propagateFlagsIf(depVxp, T_NEEDS_PROC, [&](const V3GraphEdge* e) -> bool { + return !hasFlags(static_cast(e->top())->nodep(), T_ALLOCS_PROC); + }); + } + } + for (V3GraphVertex* vxp = m_procGraph.verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { + DepVtx* const depVxp = static_cast(vxp); + // Mark nodes that will be emitted with a VlProcess argument + if (hasFlags(depVxp->nodep(), T_ALLOCS_PROC | T_FORCES_PROC)) { + addFlags(depVxp->nodep(), T_HAS_PROC); + propagateFlagsReversedIf(depVxp, T_HAS_PROC, [&](const V3GraphEdge* e) -> bool { + return hasFlags(static_cast(e->fromp())->nodep(), T_NEEDS_PROC); + }); + } } if (dumpGraphLevel() >= 6) m_procGraph.dumpDotFilePrefixed("proc_deps"); } @@ -586,7 +643,7 @@ private: void addProcessInfo(AstCMethodHard* const methodp) const { FileLine* const flp = methodp->fileline(); AstCExpr* const ap = new AstCExpr{ - flp, m_procp && (m_procp->user2() & T_HAS_PROC) ? "vlProcess" : "nullptr", 0}; + flp, m_procp && (hasFlags(m_procp, T_HAS_PROC)) ? "vlProcess" : "nullptr", 0}; ap->dtypeSetVoid(); methodp->addPinsp(ap); } @@ -697,8 +754,8 @@ private: VL_RESTORER(m_procp); m_procp = nodep; iterateChildren(nodep); - if (nodep->user2() & T_SUSPENDEE) nodep->setSuspendable(); - if (nodep->user2() & T_HAS_PROC) nodep->setNeedProcess(); + if (hasFlags(nodep, T_SUSPENDEE)) nodep->setSuspendable(); + if (hasFlags(nodep, T_HAS_PROC)) nodep->setNeedProcess(); } void visit(AstInitial* nodep) override { visit(static_cast(nodep)); @@ -719,11 +776,11 @@ private: // Workaround for killing `always` processes (doing that is pretty much UB) // TODO: Disallow killing `always` at runtime (throw an error) - if (nodep->user2() & T_HAS_PROC) nodep->user2(nodep->user2() | T_SUSPENDEE); + if (hasFlags(nodep, T_HAS_PROC)) addFlags(nodep, T_SUSPENDEE); iterateChildren(nodep); - if (nodep->user2() & T_HAS_PROC) nodep->setNeedProcess(); - if (!(nodep->user2() & T_SUSPENDEE)) return; + if (hasFlags(nodep, T_HAS_PROC)) nodep->setNeedProcess(); + if (!hasFlags(nodep, T_SUSPENDEE)) return; nodep->setSuspendable(); FileLine* const flp = nodep->fileline(); AstSenTree* const sensesp = m_activep->sensesp(); @@ -744,8 +801,8 @@ private: VL_RESTORER(m_procp); m_procp = nodep; iterateChildren(nodep); - if (nodep->user2() & T_HAS_PROC) nodep->setNeedProcess(); - if (!(nodep->user2() & T_SUSPENDEE)) return; + if (hasFlags(nodep, T_HAS_PROC)) nodep->setNeedProcess(); + if (!(hasFlags(nodep, T_SUSPENDEE))) return; nodep->rtnType("VlCoroutine"); // If in a class, create a shared pointer to 'this' @@ -768,7 +825,7 @@ private: } } void visit(AstNodeCCall* nodep) override { - if ((nodep->funcp()->user2() & T_SUSPENDEE) && !nodep->user1SetOnce()) { // If suspendable + if (hasFlags(nodep->funcp(), T_SUSPENDEE) && !nodep->user1SetOnce()) { // If suspendable VNRelinker relinker; nodep->unlinkFrBack(&relinker); AstCAwait* const awaitp = new AstCAwait{nodep->fileline(), nodep}; @@ -1048,6 +1105,7 @@ private: void visit(AstBegin* nodep) override { VL_RESTORER(m_procp); m_procp = nodep; + if (hasFlags(nodep, T_HAS_PROC)) nodep->setNeedProcess(); iterateChildren(nodep); } void visit(AstFork* nodep) override { @@ -1061,6 +1119,7 @@ private: while (stmtp) { if (!VN_IS(stmtp, Begin)) { auto* const beginp = new AstBegin{stmtp->fileline(), "", nullptr}; + if (hasFlags(stmtp, T_HAS_PROC)) addFlags(beginp, T_HAS_PROC); stmtp->replaceWith(beginp); beginp->addStmtsp(stmtp); stmtp = beginp; diff --git a/src/V3Width.cpp b/src/V3Width.cpp index cc6f2551d..ed55d1b36 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -696,8 +696,14 @@ private: } } void visit(AstDisableFork* nodep) override { - nodep->v3warn(E_UNSUPPORTED, "Unsupported: disable fork statements"); - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + if (nodep->fileline()->timingOn()) { + if (v3Global.opt.timing().isSetFalse()) { + nodep->v3warn(E_NOTIMING, "Support for disable fork statement requires --timing"); + } else if (!v3Global.opt.timing().isSetTrue()) { + nodep->v3warn(E_NEEDTIMINGOPT, "Use --timing or --no-timing to specify how " + << "disable fork should be handled"); + } + } } void visit(AstWaitFork* nodep) override { nodep->v3warn(E_UNSUPPORTED, "Unsupported: wait fork statements"); diff --git a/test_regress/t/t_disable.out b/test_regress/t/t_disable.out new file mode 100644 index 000000000..d59e8bc0f --- /dev/null +++ b/test_regress/t/t_disable.out @@ -0,0 +1,5 @@ +%Error-UNSUPPORTED: t/t_disable.v:11:10: Unsupported: disabling fork by name + 11 | disable foo; + | ^~~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_disable.pl b/test_regress/t/t_disable.pl new file mode 100755 index 000000000..e68534982 --- /dev/null +++ b/test_regress/t/t_disable.pl @@ -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 2023 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( + verilator_flags2 => ['--lint-only --timing'], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_disable.v b/test_regress/t/t_disable.v new file mode 100644 index 000000000..78cdb2f21 --- /dev/null +++ b/test_regress/t/t_disable.v @@ -0,0 +1,19 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + + initial begin + fork : foo + disable foo; + #1 $stop; + join_none + #2; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_disable_fork1.pl b/test_regress/t/t_disable_fork1.pl new file mode 100755 index 000000000..b8493bd06 --- /dev/null +++ b/test_regress/t/t_disable_fork1.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 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(simulator => 1); + +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_disable_fork1.v b/test_regress/t/t_disable_fork1.v new file mode 100644 index 000000000..e1f5cc711 --- /dev/null +++ b/test_regress/t/t_disable_fork1.v @@ -0,0 +1,49 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +`define N 3 + +class Cls; + task runforks(integer n); + for (integer i = 0; i < n; i++) fork + #1 $stop; + join_none + endtask +endclass + +module t; + Cls cls = new; + + initial begin + // run forks + for (integer i = 0; i < `N; i++) fork + #1 $stop; + join_none + + // run forks inside a method + cls.runforks(`N); + + // run forks in forks + for (integer i = 0; i < `N; i++) fork + for (integer j = 0; j < `N; j++) fork + #1 $stop; + join_none + join_none + + for (integer i = 0; i < `N; i++) fork + cls.runforks(`N); + join_none + + // kill them all + disable fork; + + // check if we can still fork + fork + #2 $write("*-* All Finished *-*\n"); + #3 $finish; + join_none + end +endmodule diff --git a/test_regress/t/t_disable_fork2.pl b/test_regress/t/t_disable_fork2.pl new file mode 100755 index 000000000..b8493bd06 --- /dev/null +++ b/test_regress/t/t_disable_fork2.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 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(simulator => 1); + +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_disable_fork2.v b/test_regress/t/t_disable_fork2.v new file mode 100644 index 000000000..118e3e7f5 --- /dev/null +++ b/test_regress/t/t_disable_fork2.v @@ -0,0 +1,58 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +// USING THIS FOR DEBUGGING PROCESS PROPAGATION: +// +// The example contains most cases that were problematic during the +// works on support of 'disable fork' statement, including: +// +// - indirect use of disable fork (through a task), +// - indirect use of forks that are to be disabled, +// - forks in forks, +// - a function taking VlProcess argument shared between a process that +// allocates VlProcess, and one that doesnt, +// - a function that has a delay and obtains VlProcess argument, +// - a function that has a delay and doesn't obtain it. +// +// Blocks below contain info on whether they should (YES) or shouldn't (NO) +// be emitted as functions with a VlProcess argument. +// +// To check if that corresponds to reality, see blue nodes in proc_deps.dot + +class Cls; + task print; /*NO*/ + $write("*-* All "); + endtask + task disable_fork_func; /*YES*/ + disable fork; + endtask + task common_func; /*YES*/ + fork /*YES*/ #1; join_none + endtask + task fork_func; /*YES*/ + fork /*YES*/ #1 $stop; join_none + endtask + task delay_func; /*NO*/ + fork /*NO*/ #1 $write("Finished *-*\n"); join_none + endtask +endclass + +module t; + Cls cls = new; + + initial begin /*YES*/ + fork /*YES*/ cls.common_func(); join_none + cls.fork_func(); + cls.disable_fork_func(); + cls.print(); + end + + initial begin /*NO*/ + cls.delay_func(); + cls.common_func(); + fork /*YES*/ disable fork; join_none + end +endmodule diff --git a/test_regress/t/t_disable_fork3.pl b/test_regress/t/t_disable_fork3.pl new file mode 100755 index 000000000..b8493bd06 --- /dev/null +++ b/test_regress/t/t_disable_fork3.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 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(simulator => 1); + +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_disable_fork3.v b/test_regress/t/t_disable_fork3.v new file mode 100644 index 000000000..4fc5f1759 --- /dev/null +++ b/test_regress/t/t_disable_fork3.v @@ -0,0 +1,18 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t; + initial begin + fork begin + fork begin + #3 $stop; + end join_none + #1; + end join_none + #2 disable fork; + end + initial #4 $write("*-* All Finished *-*\n"); +endmodule diff --git a/test_regress/t/t_disable_fork_notiming.out b/test_regress/t/t_disable_fork_notiming.out new file mode 100644 index 000000000..63f71caef --- /dev/null +++ b/test_regress/t/t_disable_fork_notiming.out @@ -0,0 +1,6 @@ +%Error-NOTIMING: t/t_disable_fork_notiming.v:8:12: Support for disable fork statement requires --timing + : ... note: In instance 't' + 8 | initial disable fork; + | ^~~~~~~ + ... For error description see https://verilator.org/warn/NOTIMING?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_disable_fork_notiming.pl b/test_regress/t/t_disable_fork_notiming.pl new file mode 100755 index 000000000..1a013a057 --- /dev/null +++ b/test_regress/t/t_disable_fork_notiming.pl @@ -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 2023 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(simulator => 1); + +compile( + expect_filename => $Self->{golden_filename}, + v_flags2 => ["--no-timing"], + fails => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_disable_fork_notiming.v b/test_regress/t/t_disable_fork_notiming.v new file mode 100644 index 000000000..21ac2743e --- /dev/null +++ b/test_regress/t/t_disable_fork_notiming.v @@ -0,0 +1,9 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t; + initial disable fork; +endmodule diff --git a/test_regress/t/t_fork_disable.out b/test_regress/t/t_fork_disable.out deleted file mode 100644 index 4a245ec4d..000000000 --- a/test_regress/t/t_fork_disable.out +++ /dev/null @@ -1,10 +0,0 @@ -%Error-UNSUPPORTED: t/t_fork_disable.v:16:7: Unsupported: disable fork statements - : ... note: In instance 't' - 16 | disable fork; - | ^~~~~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_fork_disable.v:17:7: Unsupported: wait fork statements - : ... note: In instance 't' - 17 | wait fork; - | ^~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_uvm_pkg_todo.vh b/test_regress/t/t_uvm_pkg_todo.vh index f3f21fa0d..30f708ef3 100644 --- a/test_regress/t/t_uvm_pkg_todo.vh +++ b/test_regress/t/t_uvm_pkg_todo.vh @@ -11190,9 +11190,7 @@ task uvm_phase::execute_phase(); end end join_any -//TODO issue #4125 - Support disable fork -//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:11187:12: Unsupported: disable fork statements -//TODO disable fork; + disable fork; end join end @@ -15172,9 +15170,7 @@ class uvm_heartbeat extends uvm_object; end @(m_stop_event); join_any -//TODO issue #4125 - Support disable fork -//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:15167:12: Unsupported: disable fork statements -//TODO disable fork; + disable fork; endtask endclass class uvm_heartbeat_callback extends uvm_objection_callback; @@ -19218,9 +19214,7 @@ task uvm_sequencer_base::m_wait_for_available_sequence(); join_any end join_any -//TODO issue #4125 - Support disable fork -//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:19213:12: Unsupported: disable fork statements -//TODO disable fork; + disable fork; end join endtask diff --git a/test_regress/t/t_wait_fork.out b/test_regress/t/t_wait_fork.out new file mode 100644 index 000000000..b9cf141c8 --- /dev/null +++ b/test_regress/t/t_wait_fork.out @@ -0,0 +1,6 @@ +%Error-UNSUPPORTED: t/t_wait_fork.v:17:7: Unsupported: wait fork statements + : ... note: In instance 't' + 17 | wait fork; + | ^~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_fork_disable.pl b/test_regress/t/t_wait_fork.pl similarity index 100% rename from test_regress/t/t_fork_disable.pl rename to test_regress/t/t_wait_fork.pl diff --git a/test_regress/t/t_fork_disable.v b/test_regress/t/t_wait_fork.v similarity index 100% rename from test_regress/t/t_fork_disable.v rename to test_regress/t/t_wait_fork.v From bc9ff6d1bf192f8af0ce44879469cbb8174ab097 Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Mon, 16 Oct 2023 17:05:39 +0200 Subject: [PATCH 077/157] Fix interface comparison (#4570) --- src/V3Width.cpp | 3 ++- test_regress/t/t_interface_virtual.out | 4 ++++ test_regress/t/t_interface_virtual.v | 5 +++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index ed55d1b36..20d5d4954 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -6681,7 +6681,8 @@ private: // child node's width to end up correct for the assignment (etc) widthCheckSized(nodep, side, VN_AS(underp, NodeExpr), expDTypep, extendRule, warnOn); - } else if (!VN_IS(expDTypep->skipRefp(), IfaceRefDType) + } else if (!VN_IS(nodep, Eq) && !VN_IS(nodep, Neq) + && !VN_IS(expDTypep->skipRefp(), IfaceRefDType) && VN_IS(underp->dtypep()->skipRefp(), IfaceRefDType)) { underp->v3error(ucfirst(nodep->prettyOperatorName()) << " expected non-interface on " << side << " but " diff --git a/test_regress/t/t_interface_virtual.out b/test_regress/t/t_interface_virtual.out index 2e63964b4..315bffb65 100644 --- a/test_regress/t/t_interface_virtual.out +++ b/test_regress/t/t_interface_virtual.out @@ -1,3 +1,7 @@ +va==vb? 1 +va!=vb? 0 +va==vb? 0 +va!=vb? 1 va.addr=aa va.data=11 ia.addr=aa ia.data=11 vb.addr=bb vb.data=22 ib.addr=bb ib.data=22 ca.fa.addr=a0 ca.fa.data=11 ca.fa.addr=b0 ca.fb.data=22 diff --git a/test_regress/t/t_interface_virtual.v b/test_regress/t/t_interface_virtual.v index 0e05cf47e..2b36e1a30 100644 --- a/test_regress/t/t_interface_virtual.v +++ b/test_regress/t/t_interface_virtual.v @@ -33,7 +33,12 @@ module t (/*AUTOARG*/); initial begin va = ia; + vb = ia; + $display("va==vb? %b", va==vb); + $display("va!=vb? %b", va!=vb); vb = ib; + $display("va==vb? %b", va==vb); + $display("va!=vb? %b", va!=vb); ca = new; cb = new; From 99ea16d7fde77d6f27e19d73f2fa68245dcaa7ef Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Mon, 16 Oct 2023 17:06:41 +0200 Subject: [PATCH 078/157] Fix dynamic triggers for named events (#4571) --- include/verilated_timing.cpp | 3 ++- include/verilated_timing.h | 4 ++++ src/V3AstNodes.cpp | 1 + src/V3Timing.cpp | 7 +++++++ test_regress/t/t_timing_debug2.out | 11 +---------- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/include/verilated_timing.cpp b/include/verilated_timing.cpp index 30b3fbf7f..c14eaf2c7 100644 --- a/include/verilated_timing.cpp +++ b/include/verilated_timing.cpp @@ -153,11 +153,12 @@ void VlTriggerScheduler::dump(const char* eventDescription) const { // VlDynamicTriggerScheduler:: Methods bool VlDynamicTriggerScheduler::evaluate() { + m_anyTriggered = false; VL_DEBUG_IF(dump();); std::swap(m_suspended, m_evaluated); for (auto& coro : m_evaluated) coro.resume(); m_evaluated.clear(); - return !m_triggered.empty(); + return m_anyTriggered; } void VlDynamicTriggerScheduler::doPostUpdates() { diff --git a/include/verilated_timing.h b/include/verilated_timing.h index 54b505e2a..48646de69 100644 --- a/include/verilated_timing.h +++ b/include/verilated_timing.h @@ -275,6 +275,7 @@ public: // co_await __VdynSched.evaluation(); //
;
 //         __Vtrigger = ;
+//         __VdynShed.anyTriggered(__Vtrigger);
 //         [optionally] co_await __VdynSched.postUpdate();
 //         ;
 //     }
@@ -288,6 +289,7 @@ class VlDynamicTriggerScheduler final {
     using VlCoroutineVec = std::vector;
 
     // MEMBERS
+    bool m_anyTriggered = false;  // If true, at least one trigger was set
     VlCoroutineVec m_suspended;  // Suspended coroutines awaiting trigger evaluation
     VlCoroutineVec m_evaluated;  // Coroutines currently being evaluated (for evaluate())
     VlCoroutineVec m_triggered;  // Coroutines whose triggers were set, and are awaiting resumption
@@ -313,6 +315,8 @@ class VlDynamicTriggerScheduler final {
 public:
     // Evaluates all dynamic triggers (resumed coroutines that co_await evaluation())
     bool evaluate();
+    // Called by coroutines that evaluate triggers to notify the scheduler if any triggers were set
+    void anyTriggered(bool triggered) { m_anyTriggered = m_anyTriggered || triggered; }
     // Runs post updates for all dynamic triggers (resumes coroutines that co_await postUpdate())
     void doPostUpdates();
     // Resumes all coroutines whose triggers are set (those that co_await resumption())
diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp
index 4720c4b01..c48ef68ec 100644
--- a/src/V3AstNodes.cpp
+++ b/src/V3AstNodes.cpp
@@ -2424,6 +2424,7 @@ int AstCMethodHard::instrCount() const {
 void AstCMethodHard::setPurity() {
     static const std::map isPureMethod{{"andNot", false},
                                                           {"any", true},
+                                                          {"anyTriggered", false},
                                                           {"assign", false},
                                                           {"at", true},
                                                           {"atBack", true},
diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp
index d2d6bae96..132d3d6bf 100644
--- a/src/V3Timing.cpp
+++ b/src/V3Timing.cpp
@@ -931,6 +931,13 @@ private:
             }
             // Then the trigger check and assignment
             loopp->addStmtsp(assignp);
+            // Let the dynamic trigger scheduler know if this trigger was set
+            // If it was, a call to the scheduler's evaluate() will return true
+            AstCMethodHard* const anyTriggeredMethodp = new AstCMethodHard{
+                flp, new AstVarRef{flp, getCreateDynamicTriggerScheduler(), VAccess::WRITE},
+                "anyTriggered", new AstVarRef{flp, trigvscp, VAccess::READ}};
+            anyTriggeredMethodp->dtypeSetVoid();
+            loopp->addStmtsp(anyTriggeredMethodp->makeStmt());
             // If the post update is destructive (e.g. event vars are cleared), create an await for
             // the post update step
             if (destructivePostUpdate(sensesp)) {
diff --git a/test_regress/t/t_timing_debug2.out b/test_regress/t/t_timing_debug2.out
index 6698864f4..0e22dcd4e 100644
--- a/test_regress/t/t_timing_debug2.out
+++ b/test_regress/t/t_timing_debug2.out
@@ -649,6 +649,7 @@
 -V{t#,#}         Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting the post update step
 -V{t#,#}+    Vt_timing_debug2___024root___dump_triggers__act
 -V{t#,#}         'act' region trigger index 0 is active: @([event] t.ec.e)
+-V{t#,#}         'act' region trigger index 2 is active: @([true] __VdynSched.evaluate())
 -V{t#,#}         Doing post updates for processes:
 -V{t#,#}           - Process waiting at t/t_timing_class.v:37
 -V{t#,#}             Resuming: Process waiting at t/t_timing_class.v:37
@@ -657,16 +658,6 @@
 -V{t#,#}+    Vt_timing_debug2___024root___timing_resume
 -V{t#,#}         No ready processes waiting for @([event] t.ec.e)
 -V{t#,#}         Resuming processes waiting for @([event] t.ec.e)
--V{t#,#}+    Vt_timing_debug2___024root___eval_act
--V{t#,#}+    Vt_timing_debug2___024root___eval_triggers__act
--V{t#,#}         Suspended processes waiting for dynamic trigger evaluation:
--V{t#,#}           - Process waiting at t/t_timing_class.v:101
--V{t#,#}             Resuming: Process waiting at t/t_timing_class.v:101
--V{t#,#}         Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:101
--V{t#,#}+    Vt_timing_debug2___024root___dump_triggers__act
--V{t#,#}         'act' region trigger index 2 is active: @([true] __VdynSched.evaluate())
--V{t#,#}+    Vt_timing_debug2___024root___timing_commit
--V{t#,#}+    Vt_timing_debug2___024root___timing_resume
 -V{t#,#}         Resuming processes:
 -V{t#,#}           - Process waiting at t/t_timing_class.v:37
 -V{t#,#}             Resuming: Process waiting at t/t_timing_class.v:37

From e99fd2892b5590219afd4818a7941b1486c18e51 Mon Sep 17 00:00:00 2001
From: Ryszard Rozak 
Date: Tue, 17 Oct 2023 09:26:53 +0200
Subject: [PATCH 079/157] Make VNDeleter a member of VNVisitor. No function
 change. (#4573)

---
 src/V3Ast.h     | 14 ++++++++++----
 src/V3Const.cpp | 16 +++++++++-------
 src/V3Order.cpp | 11 ++++++-----
 src/V3Param.cpp |  5 +++--
 4 files changed, 28 insertions(+), 18 deletions(-)

diff --git a/src/V3Ast.h b/src/V3Ast.h
index 8e97c4e34..8c6282876 100644
--- a/src/V3Ast.h
+++ b/src/V3Ast.h
@@ -1502,7 +1502,7 @@ public:
 // nodes needs to be deferred to a later time, because pointers to the
 // removed nodes might still exist.
 
-class VNDeleter VL_NOT_FINAL {
+class VNDeleter final {
     // MEMBERS
     std::vector m_deleteps;  // Nodes to delete
 
@@ -1515,11 +1515,11 @@ public:
         m_deleteps.push_back(nodep);
     }
 
-    // Delete all previously pushed nodes (by callint deleteTree)
+    // Delete all previously pushed nodes (by calling deleteTree)
     void doDeletes();
 
     // Do the deletions on destruction
-    virtual ~VNDeleter() { doDeletes(); }
+    ~VNDeleter() { doDeletes(); }
 };
 
 //######################################################################
@@ -1528,7 +1528,7 @@ public:
 // This only has the constant fuctions for non-modifying visitors.
 // For more typical usage see VNVisitor
 
-class VNVisitorConst VL_NOT_FINAL : public VNDeleter {
+class VNVisitorConst VL_NOT_FINAL {
     friend class AstNode;
 
 public:
@@ -1546,6 +1546,7 @@ public:
     inline void iterateAndNextConstNullBackwards(AstNode* nodep);
 
     virtual void visit(AstNode* nodep) = 0;
+    virtual ~VNVisitorConst() {}
 #include "V3Ast__gen_visitor_decls.h"  // From ./astgen
 };
 
@@ -1554,6 +1555,7 @@ public:
 // type without changing the base classes.  See "Modern C++ Design".
 
 class VNVisitor VL_NOT_FINAL : public VNVisitorConst {
+    VNDeleter m_deleter;  // Used to delay deletion of nodes
 public:
     /// Call visit()s on nodep
     inline void iterate(AstNode* nodep);
@@ -1565,6 +1567,10 @@ public:
     inline void iterateAndNextNull(AstNode* nodep);
     /// Return edited nodep; see comments in V3Ast.cpp
     inline AstNode* iterateSubtreeReturnEdits(AstNode* nodep);
+
+    VNDeleter& deleter() { return m_deleter; }
+    void pushDeletep(AstNode* nodep) { deleter().pushDeletep(nodep); }
+    void doDeletes() { deleter().doDeletes(); }
 };
 
 //######################################################################
diff --git a/src/V3Const.cpp b/src/V3Const.cpp
index 1435d3ab0..c2b3e1b1b 100644
--- a/src/V3Const.cpp
+++ b/src/V3Const.cpp
@@ -673,7 +673,7 @@ public:
     // Reduction ops are transformed in the same way.
     // &{v[0], v[1]} => 2'b11 == (2'b11 & v)
     static AstNodeExpr* simplify(AstNodeExpr* nodep, int resultWidth, unsigned externalOps,
-                                 VDouble0& reduction) {
+                                 VDouble0& reduction, VNDeleter& deleterr) {
         UASSERT_OBJ(1 <= resultWidth && resultWidth <= 64, nodep, "resultWidth out of range");
 
         // Walk tree, gathering all terms referenced in expression
@@ -716,7 +716,7 @@ public:
                 }
                 // Set width and widthMin precisely
                 resultp->dtypeChgWidth(resultWidth, 1);
-                for (AstNode* const termp : termps) termp->deleteTree();
+                for (AstNode* const termp : termps) deleterr.pushDeletep(termp);
                 return resultp;
             }
             const ResultTerm result = v->getResultTerm();
@@ -792,7 +792,7 @@ public:
 
         // Only substitute the result if beneficial as determined by operation count
         if (visitor.m_ops <= resultOps) {
-            for (AstNode* const termp : termps) termp->deleteTree();
+            for (AstNode* const termp : termps) deleterr.pushDeletep(termp);
             return nullptr;
         }
 
@@ -1012,7 +1012,7 @@ private:
         return (lp && rp && lp->width() == rp->width() && lp->type() == rp->type()
                 && (operandsSame(lp->lhsp(), rp->lhsp()) || operandsSame(lp->rhsp(), rp->rhsp())));
     }
-    static bool matchOrAndNot(AstNodeBiop* nodep) {
+    bool matchOrAndNot(AstNodeBiop* nodep) {
         // AstOr{$a, AstAnd{AstNot{$b}, $c}} if $a.width1, $a==$b => AstOr{$a,$c}
         // Someday we'll sort the biops completely and this can be simplified
         // This often results from our simplified clock generation:
@@ -1043,7 +1043,7 @@ private:
         if (!operandsSame(ap, bp)) return false;
         // Do it
         cp->unlinkFrBack();
-        VL_DO_DANGLING(andp->unlinkFrBack()->deleteTree(), andp);
+        VL_DO_DANGLING(pushDeletep(andp->unlinkFrBack()), andp);
         VL_DANGLING(notp);
         // Replace whichever branch is now dangling
         if (nodep->rhsp()) {
@@ -1175,9 +1175,11 @@ private:
         const AstAnd* const andp = VN_CAST(nodep, And);
         const int width = nodep->width();
         if (andp && isConst(andp->lhsp(), 1)) {  // 1 & BitOpTree
-            newp = ConstBitOpTreeVisitor::simplify(andp->rhsp(), width, 1, m_statBitOpReduction);
+            newp = ConstBitOpTreeVisitor::simplify(andp->rhsp(), width, 1, m_statBitOpReduction,
+                                                   deleter());
         } else {  // BitOpTree
-            newp = ConstBitOpTreeVisitor::simplify(nodep, width, 0, m_statBitOpReduction);
+            newp = ConstBitOpTreeVisitor::simplify(nodep, width, 0, m_statBitOpReduction,
+                                                   deleter());
         }
 
         if (newp) {
diff --git a/src/V3Order.cpp b/src/V3Order.cpp
index f0047b81e..c3ba10a93 100644
--- a/src/V3Order.cpp
+++ b/src/V3Order.cpp
@@ -801,7 +801,7 @@ struct MTaskVxIdLessThan final {
 //######################################################################
 // OrderProcess class
 
-class OrderProcess final : VNDeleter {
+class OrderProcess final {
     // NODE STATE
     //  AstNode::user4  -> Used by V3Const::constifyExpensiveEdit
 
@@ -829,6 +829,7 @@ class OrderProcess final : VNDeleter {
     friend class OrderMoveDomScope;
     V3List m_pomReadyDomScope;  // List of ready domain/scope pairs, by loopId
     std::map, unsigned> m_funcNums;  // Function ordinals
+    VNDeleter m_deleter;  // Used to delay deletion of nodes
 
     // METHODS
 
@@ -900,10 +901,10 @@ class OrderProcess final : VNDeleter {
         , m_deleteDomainp{makeDeleteDomainSenTree(netlistp->fileline())}
         , m_tag{tag}
         , m_slow{slow} {
-        pushDeletep(m_deleteDomainp);
+        m_deleter.pushDeletep(m_deleteDomainp);
     }
 
-    ~OrderProcess() override = default;
+    ~OrderProcess() = default;
 
 public:
     // Order the logic
@@ -1223,7 +1224,7 @@ AstActive* OrderProcess::processMoveOneLogic(const OrderLogicVertex* lvertexp,
         needProcess = procp->needProcess();
         if (suspendable) slow = slow && !VN_IS(procp, Always);
         nodep = procp->stmtsp();
-        pushDeletep(procp);
+        m_deleter.pushDeletep(procp);
     }
 
     // Put suspendable processes into individual functions on their own
@@ -1270,7 +1271,7 @@ AstActive* OrderProcess::processMoveOneLogic(const OrderLogicVertex* lvertexp,
         if (nodep->backp()) nodep->unlinkFrBack();
 
         if (domainp == m_deleteDomainp) {
-            VL_DO_DANGLING(pushDeletep(nodep), nodep);
+            VL_DO_DANGLING(m_deleter.pushDeletep(nodep), nodep);
         } else {
             newFuncpr->addStmtsp(nodep);
             // Add in the number of nodes we're adding
diff --git a/src/V3Param.cpp b/src/V3Param.cpp
index 8bc5358a6..2479c7f0d 100644
--- a/src/V3Param.cpp
+++ b/src/V3Param.cpp
@@ -223,7 +223,7 @@ public:
 //######################################################################
 // Remove parameters from cells and build new modules
 
-class ParamProcessor final : public VNDeleter {
+class ParamProcessor final {
     // NODE STATE - Local
     //   AstVar::user4()        // int    Global parameter number (for naming new module)
     //                          //        (0=not processed, 1=iterated, but no number,
@@ -277,6 +277,7 @@ class ParamProcessor final : public VNDeleter {
     using DefaultValueMap = std::map;
     // Default parameter values of hierarchical blocks
     std::map m_defaultParameterValues;
+    VNDeleter m_deleter;  // Used to delay deletion of nodes
 
     // METHODS
 
@@ -868,7 +869,7 @@ class ParamProcessor final : public VNDeleter {
                 AstClass* classCopyp = VN_AS(srcModpr, Class)->cloneTree(false);
                 // It is a temporary copy of the original class node, stored in order to create
                 // another instances. It is needed only during class instantiation.
-                pushDeletep(classCopyp);
+                m_deleter.pushDeletep(classCopyp);
                 srcModpr->user4p(classCopyp);
                 storeOriginalParams(classCopyp);
             }

From 45edcbb03ed9e0820d1b483a6c6199b98f81ae48 Mon Sep 17 00:00:00 2001
From: Ryszard Rozak 
Date: Tue, 17 Oct 2023 13:38:45 +0200
Subject: [PATCH 080/157] Fix logical expressions with class objects - caching
 in v3Const (#4552)

---
 src/V3AstNodeOther.h                    |  4 +++
 src/V3Const.cpp                         | 48 +++++++++++++++++++++++--
 src/V3Task.cpp                          |  1 +
 test_regress/t/t_class_short_circuit.pl | 21 +++++++++++
 test_regress/t/t_class_short_circuit.v  | 33 +++++++++++++++++
 test_regress/t/t_const_opt.pl           |  2 +-
 6 files changed, 105 insertions(+), 4 deletions(-)
 create mode 100755 test_regress/t/t_class_short_circuit.pl
 create mode 100644 test_regress/t/t_class_short_circuit.v

diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h
index 2fea7ff71..568a0f5b8 100644
--- a/src/V3AstNodeOther.h
+++ b/src/V3AstNodeOther.h
@@ -609,6 +609,7 @@ private:
     bool m_dpiImportWrapper : 1;  // Wrapper for invoking DPI import prototype from generated code
     bool m_dpiTraceInit : 1;  // DPI trace_init
     bool m_needProcess : 1;  // Needs access to VlProcess of the caller
+    bool m_recursive : 1;  // Recursive or part of recursion
 public:
     AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType = "")
         : ASTGEN_SUPER_CFunc(fl) {
@@ -637,6 +638,7 @@ public:
         m_dpiImportPrototype = false;
         m_dpiImportWrapper = false;
         m_dpiTraceInit = false;
+        m_recursive = false;
     }
     ASTGEN_MEMBERS_AstCFunc;
     string name() const override VL_MT_STABLE { return m_name; }
@@ -716,6 +718,8 @@ public:
     void dpiTraceInit(bool flag) { m_dpiTraceInit = flag; }
     bool dpiTraceInit() const { return m_dpiTraceInit; }
     bool isCoroutine() const { return m_rtnType == "VlCoroutine"; }
+    void recursive(bool flag) { m_recursive = flag; }
+    bool recursive() const { return m_recursive; }
     // Special methods
     bool emptyBody() const {
         return argsp() == nullptr && initsp() == nullptr && stmtsp() == nullptr
diff --git a/src/V3Const.cpp b/src/V3Const.cpp
index c2b3e1b1b..d42bb07b0 100644
--- a/src/V3Const.cpp
+++ b/src/V3Const.cpp
@@ -900,6 +900,7 @@ private:
     bool m_doNConst = false;  // Enable non-constant-child simplifications
     bool m_doV = false;  // Verilog, not C++ conversion
     bool m_doGenerate = false;  // Postpone width checking inside generate
+    bool m_convertLogicToBit = false;  // Convert logical operators to bitwise
     bool m_hasJumpDelay = false;  // JumpGo or Delay under this while
     bool m_underRecFunc = false;  // Under a recursive function
     AstNodeModule* m_modp = nullptr;  // Current module
@@ -910,6 +911,7 @@ private:
     const bool m_globalPass;  // ConstVisitor invoked as a global pass
     static uint32_t s_globalPassNum;  // Counts number of times ConstVisitor invoked as global pass
     V3UniqueNames m_concswapNames;  // For generating unique temporary variable names
+    std::map m_containsMemberAccess;  // Caches results of matchBiopToBitwise
 
     // METHODS
 
@@ -2322,6 +2324,46 @@ private:
         iterate(nodep);  // Again?
     }
 
+    bool containsMemberAccessRecurse(const AstNode* const nodep) {
+        if (!nodep) return false;
+        const auto it = m_containsMemberAccess.lower_bound(nodep);
+        if (it != m_containsMemberAccess.end() && it->first == nodep) return it->second;
+        bool result = false;
+        if (VN_IS(nodep, MemberSel) || VN_IS(nodep, MethodCall) || VN_IS(nodep, CMethodCall)) {
+            result = true;
+        } else if (const AstNodeFTaskRef* const funcRefp = VN_CAST(nodep, NodeFTaskRef)) {
+            if (containsMemberAccessRecurse(funcRefp->taskp())) result = true;
+        } else if (const AstNodeCCall* const funcRefp = VN_CAST(nodep, NodeCCall)) {
+            if (containsMemberAccessRecurse(funcRefp->funcp())) result = true;
+        } else if (const AstNodeFTask* const funcp = VN_CAST(nodep, NodeFTask)) {
+            // Assume that it has a member access
+            if (funcp->recursive()) result = true;
+        } else if (const AstCFunc* const funcp = VN_CAST(nodep, CFunc)) {
+            if (funcp->recursive()) result = true;
+        }
+        if (!result) {
+            result = containsMemberAccessRecurse(nodep->op1p())
+                     || containsMemberAccessRecurse(nodep->op2p())
+                     || containsMemberAccessRecurse(nodep->op3p())
+                     || containsMemberAccessRecurse(nodep->op4p());
+        }
+        if (!result && !VN_IS(nodep, NodeFTask)
+            && !VN_IS(nodep, CFunc)  // don't enter into next function
+            && containsMemberAccessRecurse(nodep->nextp())) {
+            result = true;
+        }
+        m_containsMemberAccess.insert(it, std::make_pair(nodep, result));
+        return result;
+    }
+
+    bool matchBiopToBitwise(AstNodeBiop* const nodep) {
+        if (!m_convertLogicToBit) return false;
+        if (!nodep->lhsp()->width1()) return false;
+        if (!nodep->rhsp()->width1()) return false;
+        if (!nodep->isPure()) return false;
+        if (containsMemberAccessRecurse(nodep)) return false;
+        return true;
+    }
     bool matchConcatRand(AstConcat* nodep) {
         //    CONCAT(RAND, RAND) - created by Chisel code
         AstRand* const aRandp = VN_CAST(nodep->lhsp(), Rand);
@@ -3598,8 +3640,8 @@ private:
     TREEOPV("AstOneHot{$lhsp.width1}",          "replaceWLhs(nodep)");
     TREEOPV("AstOneHot0{$lhsp.width1}",         "replaceNum(nodep,1)");
     // Binary AND/OR is faster than logical and/or (usually)
-    TREEOPV("AstLogAnd{$lhsp.width1, $rhsp.width1, nodep->isPure()}", "AstAnd{$lhsp,$rhsp}");
-    TREEOPV("AstLogOr {$lhsp.width1, $rhsp.width1, nodep->isPure()}", "AstOr{$lhsp,$rhsp}");
+    TREEOPV("AstLogAnd{matchBiopToBitwise(nodep)}", "AstAnd{$lhsp,$rhsp}");
+    TREEOPV("AstLogOr {matchBiopToBitwise(nodep)}", "AstOr{$lhsp,$rhsp}");
     TREEOPV("AstLogNot{$lhsp.width1}",  "AstNot{$lhsp}");
     // CONCAT(CONCAT({a},{b}),{c}) -> CONCAT({a},CONCAT({b},{c}))
     // CONCAT({const},CONCAT({const},{c})) -> CONCAT((constifiedCONC{const|const},{c}))
@@ -3718,7 +3760,7 @@ public:
         case PROC_GENERATE:       m_doV = true;  m_doNConst = true; m_params = true;
                                   m_required = true; m_doGenerate = true; break;
         case PROC_LIVE:           break;
-        case PROC_V_WARN:         m_doV = true;  m_doNConst = true; m_warn = true; break;
+        case PROC_V_WARN:         m_doV = true;  m_doNConst = true; m_warn = true; m_convertLogicToBit = true; break;
         case PROC_V_NOWARN:       m_doV = true;  m_doNConst = true; break;
         case PROC_V_EXPENSIVE:    m_doV = true;  m_doNConst = true; m_doExpensive = true; break;
         case PROC_CPP:            m_doV = false; m_doNConst = true; m_doCpp = true; break;
diff --git a/src/V3Task.cpp b/src/V3Task.cpp
index 5e1ce27a0..993ee99a5 100644
--- a/src/V3Task.cpp
+++ b/src/V3Task.cpp
@@ -1226,6 +1226,7 @@ private:
         cfuncp->dpiExportImpl(nodep->dpiExport());
         cfuncp->dpiImportWrapper(nodep->dpiImport());
         cfuncp->dpiTraceInit(nodep->dpiTraceInit());
+        cfuncp->recursive(nodep->recursive());
         if (nodep->dpiImport() || nodep->dpiExport()) {
             cfuncp->isStatic(true);
             cfuncp->isLoose(true);
diff --git a/test_regress/t/t_class_short_circuit.pl b/test_regress/t/t_class_short_circuit.pl
new file mode 100755
index 000000000..aabcde63e
--- /dev/null
+++ b/test_regress/t/t_class_short_circuit.pl
@@ -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 2020 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(simulator => 1);
+
+compile(
+    );
+
+execute(
+    check_finished => 1,
+    );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_class_short_circuit.v b/test_regress/t/t_class_short_circuit.v
new file mode 100644
index 000000000..dd7477267
--- /dev/null
+++ b/test_regress/t/t_class_short_circuit.v
@@ -0,0 +1,33 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed under the Creative Commons Public Domain, for
+// any use, without warranty, 2023 by Antmicro Ltd.
+// SPDX-License-Identifier: CC0-1.0
+
+class Cls;
+   int x;
+   function new;
+      x = 10;
+   endfunction
+   function bit set_x(int a);
+      x = a;
+      return 1;
+   endfunction
+   function int get_x;
+      return x;
+   endfunction
+endclass
+
+module t (/*AUTOARG*/);
+   initial begin
+      Cls cls;
+      if (cls != null && cls.x == 10) $stop;
+      if (cls != null && cls.get_x() == 10) $stop;
+      cls = new;
+      if (!cls.set_x(1) || cls.x != 1) $stop;
+      if (!cls.set_x(2) || cls.get_x() != 2) $stop;
+
+      $write("*-* All Finished *-*\n");
+      $finish;
+   end
+endmodule
diff --git a/test_regress/t/t_const_opt.pl b/test_regress/t/t_const_opt.pl
index 9d9becae5..c46c13c54 100755
--- a/test_regress/t/t_const_opt.pl
+++ b/test_regress/t/t_const_opt.pl
@@ -20,7 +20,7 @@ execute(
     );
 
 if ($Self->{vlt}) {
-    file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 36);
+    file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 37);
 }
 ok(1);
 1;

From 3bb9c7ee92168417aeba130a64b1dac330bd19db Mon Sep 17 00:00:00 2001
From: Ryszard Rozak 
Date: Tue, 17 Oct 2023 17:15:24 +0200
Subject: [PATCH 081/157] Fix dictionaries with keys of class types (#4576)

---
 include/verilated_types.h      |  4 ++++
 test_regress/t/t_class_dict.pl | 21 +++++++++++++++++++++
 test_regress/t/t_class_dict.v  | 30 ++++++++++++++++++++++++++++++
 3 files changed, 55 insertions(+)
 create mode 100755 test_regress/t/t_class_dict.pl
 create mode 100644 test_regress/t/t_class_dict.v

diff --git a/include/verilated_types.h b/include/verilated_types.h
index 876a78511..b296689d9 100644
--- a/include/verilated_types.h
+++ b/include/verilated_types.h
@@ -1629,6 +1629,10 @@ public:
     bool operator!=(const VlClassRef& rhs) const {
         return m_objp != rhs.m_objp;
     };
+    template 
+    bool operator<(const VlClassRef& rhs) const {
+        return m_objp < rhs.m_objp;
+    };
 };
 
 template 
diff --git a/test_regress/t/t_class_dict.pl b/test_regress/t/t_class_dict.pl
new file mode 100755
index 000000000..aabcde63e
--- /dev/null
+++ b/test_regress/t/t_class_dict.pl
@@ -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 2020 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(simulator => 1);
+
+compile(
+    );
+
+execute(
+    check_finished => 1,
+    );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_class_dict.v b/test_regress/t/t_class_dict.v
new file mode 100644
index 000000000..5002474c8
--- /dev/null
+++ b/test_regress/t/t_class_dict.v
@@ -0,0 +1,30 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed under the Creative Commons Public Domain, for
+// any use, without warranty, 2023 by Antmicro Ltd.
+// SPDX-License-Identifier: CC0-1.0
+
+`define stop $stop
+`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d:  got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
+
+class Cls;
+   int x;
+   function new(int a);
+      x = a;
+   endfunction
+endclass
+
+module t (/*AUTOARG*/);
+   initial begin
+      int dict[Cls];
+      Cls c1 = new(1);
+      Cls c2 = new(2);
+      dict[c1] = 1;
+      dict[c2] = 2;
+      `checkh(dict[c1], 1);
+      `checkh(dict[c2], 2);
+
+      $write("*-* All Finished *-*\n");
+      $finish;
+   end
+endmodule

From 431bb1ed165b0e3ec7731b17af4df84f83c79739 Mon Sep 17 00:00:00 2001
From: Wilson Snyder 
Date: Tue, 17 Oct 2023 22:49:28 -0400
Subject: [PATCH 082/157] Support compiling Verilator with gcc/clang
 precompiled headers (#4579)

---
 Changes                    |   1 +
 configure.ac               |  15 +++++
 src/Makefile_obj.in        | 126 +++++++++++++++++++++++--------------
 src/V3Active.cpp           |   7 +--
 src/V3ActiveTop.cpp        |   7 +--
 src/V3Assert.cpp           |   8 +--
 src/V3AssertPre.cpp        |   7 +--
 src/V3Ast.cpp              |   7 +--
 src/V3AstNodes.cpp         |   2 +
 src/V3Begin.cpp            |  10 +--
 src/V3Branch.cpp           |  10 +--
 src/V3Broken.cpp           |   6 +-
 src/V3CCtors.cpp           |   7 +--
 src/V3CUse.cpp             |  12 +---
 src/V3Case.cpp             |   9 +--
 src/V3Cast.cpp             |  10 +--
 src/V3Class.cpp            |   7 +--
 src/V3Clean.cpp            |  10 +--
 src/V3Clock.cpp            |   9 +--
 src/V3Combine.cpp          |   7 +--
 src/V3Common.cpp           |   7 +--
 src/V3Config.cpp           |   6 +-
 src/V3Coverage.cpp         |   9 +--
 src/V3CoverageJoin.cpp     |   6 +-
 src/V3Dead.cpp             |   9 +--
 src/V3Delayed.cpp          |   9 +--
 src/V3Depth.cpp            |   9 +--
 src/V3DepthBlock.cpp       |   9 +--
 src/V3Descope.cpp          |   9 +--
 src/V3Dfg.cpp              |   5 +-
 src/V3DfgAstToDfg.cpp      |   8 +--
 src/V3DfgDecomposition.cpp |   5 +-
 src/V3DfgDfgToAst.cpp      |   6 +-
 src/V3DfgOptimizer.cpp     |   8 +--
 src/V3DfgPasses.cpp        |   6 +-
 src/V3DfgPeephole.cpp      |   6 +-
 src/V3DupFinder.cpp        |   9 +--
 src/V3EmitCBase.cpp        |   3 +-
 src/V3EmitCConstPool.cpp   |   5 +-
 src/V3EmitCFunc.cpp        |   5 +-
 src/V3EmitCHeaders.cpp     |   5 +-
 src/V3EmitCImp.cpp         |   6 +-
 src/V3EmitCInlines.cpp     |   4 +-
 src/V3EmitCMain.cpp        |   6 +-
 src/V3EmitCMake.cpp        |   6 +-
 src/V3EmitCModel.cpp       |   6 +-
 src/V3EmitCSyms.cpp        |   6 +-
 src/V3EmitMk.cpp           |   6 +-
 src/V3EmitV.cpp            |   6 +-
 src/V3EmitXml.cpp          |   7 +--
 src/V3Expand.cpp           |   9 +--
 src/V3File.cpp             |   5 +-
 src/V3Force.cpp            |   7 +--
 src/V3Fork.cpp             |  10 +--
 src/V3Gate.cpp             |   8 +--
 src/V3Global.cpp           |   6 +-
 src/V3Hasher.cpp           |   3 +-
 src/V3HierBlock.cpp        |   4 +-
 src/V3Inline.cpp           |   9 +--
 src/V3Inst.cpp             |   9 +--
 src/V3InstrCount.cpp       |   7 +--
 src/V3Interface.cpp        |   8 +--
 src/V3Life.cpp             |   8 +--
 src/V3LifePost.cpp         |   7 +--
 src/V3LinkCells.cpp        |   9 +--
 src/V3LinkDot.cpp          |   9 +--
 src/V3LinkInc.cpp          |   8 +--
 src/V3LinkJump.cpp         |   8 +--
 src/V3LinkLValue.cpp       |  10 +--
 src/V3LinkLevel.cpp        |  10 +--
 src/V3LinkParse.cpp        |   9 +--
 src/V3LinkResolve.cpp      |  10 +--
 src/V3Localize.cpp         |   7 +--
 src/V3MergeCond.cpp        |   7 +--
 src/V3Name.cpp             |   7 +--
 src/V3Number.cpp           |   6 +-
 src/V3Options.cpp          |   4 +-
 src/V3Order.cpp            |   9 +--
 src/V3Param.cpp            |   8 +--
 src/V3Partition.cpp        |   6 +-
 src/V3PchAstMT.h           |  42 +++++++++++++
 src/V3PchAstNoMT.h         |  46 ++++++++++++++
 src/V3Premit.cpp           |   9 +--
 src/V3ProtectLib.cpp       |   6 +-
 src/V3Randomize.cpp        |   6 +-
 src/V3Reloop.cpp           |   9 +--
 src/V3Sched.cpp            |   6 +-
 src/V3SchedAcyclic.cpp     |   8 +--
 src/V3SchedPartition.cpp   |   8 +--
 src/V3SchedReplicate.cpp   |   7 +--
 src/V3SchedTiming.cpp      |   6 +-
 src/V3Scope.cpp            |  10 +--
 src/V3Scoreboard.cpp       |   5 +-
 src/V3Slice.cpp            |   8 +--
 src/V3Split.cpp            |   9 +--
 src/V3SplitAs.cpp          |   9 +--
 src/V3SplitVar.cpp         |   9 +--
 src/V3Stats.cpp            |   6 +-
 src/V3StatsReport.cpp      |   5 +-
 src/V3Subst.cpp            |   7 +--
 src/V3TSP.cpp              |   8 +--
 src/V3Table.cpp            |   7 +--
 src/V3Task.cpp             |   8 +--
 src/V3ThreadPool.h         |   2 +-
 src/V3Timing.cpp           |   7 +--
 src/V3Trace.cpp            |   7 +--
 src/V3TraceDecl.cpp        |   7 +--
 src/V3Tristate.cpp         |  10 +--
 src/V3Undriven.cpp         |   9 +--
 src/V3Unknown.cpp          |   9 +--
 src/V3Unroll.cpp           |   9 +--
 src/V3VariableOrder.cpp    |   8 +--
 src/V3Width.cpp            |   8 +--
 src/V3WidthCommit.cpp      |   2 +-
 src/V3WidthSel.cpp         |   7 +--
 115 files changed, 294 insertions(+), 736 deletions(-)
 create mode 100644 src/V3PchAstMT.h
 create mode 100644 src/V3PchAstNoMT.h

diff --git a/Changes b/Changes
index cc313c39f..54ec9600e 100644
--- a/Changes
+++ b/Changes
@@ -19,6 +19,7 @@ Verilator 5.017 devel
 * Support randc (#4349).
 * Support resizing function call inout arguments (#4467).
 * Support converting parameters inside modules to localparams (#4511). [Anthony Donlon]
+* Support compilation with precompiled headers with Make and GCC or CLang.
 * Change lint_off to not propagate upwards to files including where the lint_off is.
 * Optimize empty expression statements (#4544).
 * Fix conversion of impure logical expressions to bit expressions (#487 partial) (#4437). [Ryszard Rozak, Antmicro Ltd.]
diff --git a/configure.ac b/configure.ac
index c508bcfb9..f0c79da98 100644
--- a/configure.ac
+++ b/configure.ac
@@ -560,6 +560,21 @@ Verilator requires a C++11 or newer compiler.]])
 fi
 AC_SUBST(CFG_CXXFLAGS_STD)
 
+# Compiler precompiled header options (assumes either gcc or clang++)
+AC_MSG_CHECKING([for $CXX precompile header include option])
+if $CXX --help | grep include-pch >/dev/null 2>/dev/null ; then
+   # clang
+   CFG_CXXFLAGS_PCH_I=-include-pch
+   CFG_GCH_IF_CLANG=.gch
+else
+   # GCC
+   CFG_CXXFLAGS_PCH_I=-include
+   CFG_GCH_IF_CLANG=
+fi
+AC_MSG_RESULT($CFG_CXXFLAGS_PCH_I)
+AC_SUBST(CFG_CXXFLAGS_PCH_I)
+AC_SUBST(CFG_GCH_IF_CLANG)
+
 # Checks for library functions.
 AC_CHECK_MEMBER([struct stat.st_mtim.tv_nsec],
     [AC_DEFINE([HAVE_STAT_NSEC],[1],[Defined if struct stat has st_mtim.tv_nsec])],
diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in
index 36ae799bb..4efc14c87 100644
--- a/src/Makefile_obj.in
+++ b/src/Makefile_obj.in
@@ -67,6 +67,11 @@ CFG_CXXFLAGS_PARSER = @CFG_CXXFLAGS_PARSER@
 CFG_CXXFLAGS_WEXTRA = @CFG_CXXFLAGS_WEXTRA@
 CFG_LDFLAGS_SRC = @CFG_LDFLAGS_SRC@
 CFG_LIBS = @CFG_LIBS@
+CFG_CXXFLAGS_PCH = -x c++-header
+# Compiler option to put in front of filename to read precompiled header
+CFG_CXXFLAGS_PCH_I = @CFG_CXXFLAGS_PCH_I@
+# Compiler's filename prefix for precompiled headers, .gch if clang, empty if GCC
+CFG_GCH_IF_CLANG = @CFG_GCH_IF_CLANG@
 
 #### End of system configuration section. ####
 
@@ -129,6 +134,11 @@ BISONPRE = $(srcdir)/bisonpre
 FLEXFIX = $(srcdir)/flexfix
 VLCOVGEN = $(srcdir)/vlcovgen
 
+######################################################################
+# CCACHE flags (via environment as no command line option available)
+CCACHE_SLOPPINESS ?= pch_defines,time_macros
+export CCACHE_SLOPPINESS
+
 ######################################################################
 #### Top level
 
@@ -151,16 +161,54 @@ maintainer-copy::
 #### Top executable
 
 RAW_OBJS = \
+	V3Const__gen.o \
+	V3Error.o \
+	V3FileLine.o \
+	V3Graph.o \
+	V3GraphAcyc.o \
+	V3GraphAlg.o \
+	V3GraphPathChecker.o \
+	V3GraphTest.o \
+	V3Hash.o \
+	V3OptionParser.o \
+	V3Os.o \
+	V3ParseGrammar.o \
+	V3ParseImp.o \
+	V3ParseLex.o \
+	V3PreProc.o \
+	V3PreShell.o \
+	V3String.o \
+	V3ThreadPool.o \
+	V3Waiver.o \
 	Verilator.o \
+
+RAW_OBJS_PCH_ASTMT = \
+	V3Ast.o \
+	V3AstNodes.o \
+	V3Broken.o \
+	V3Config.o \
+	V3EmitCBase.o \
+	V3EmitCConstPool.o \
+	V3EmitCFunc.o \
+	V3EmitCHeaders.o \
+	V3EmitCImp.o \
+	V3EmitCInlines.o \
+	V3EmitV.o \
+	V3File.o \
+	V3Global.o \
+	V3Hasher.o \
+	V3Number.o \
+	V3Options.o \
+	V3Stats.o \
+	V3StatsReport.o \
+
+RAW_OBJS_PCH_ASTNOMT = \
 	V3Active.o \
 	V3ActiveTop.o \
 	V3Assert.o \
 	V3AssertPre.o \
-	V3Ast.o \
-	V3AstNodes.o \
 	V3Begin.o \
 	V3Branch.o \
-	V3Broken.o \
 	V3CCtors.o \
 	V3CUse.o \
 	V3Case.o \
@@ -170,8 +218,6 @@ RAW_OBJS = \
 	V3Clock.o \
 	V3Combine.o \
 	V3Common.o \
-	V3Config.o \
-	V3Const__gen.o \
 	V3Coverage.o \
 	V3CoverageJoin.o \
 	V3Dead.o \
@@ -187,34 +233,16 @@ RAW_OBJS = \
 	V3DfgPasses.o \
 	V3DfgPeephole.o \
 	V3DupFinder.o \
-	V3EmitCBase.o \
-	V3EmitCConstPool.o \
-	V3EmitCFunc.o \
-	V3EmitCHeaders.o \
-	V3EmitCImp.o \
-	V3EmitCInlines.o \
 	V3EmitCMain.o \
 	V3EmitCMake.o \
 	V3EmitCModel.o \
 	V3EmitCSyms.o \
 	V3EmitMk.o \
-	V3EmitV.o \
 	V3EmitXml.o \
-	V3Error.o \
 	V3Expand.o \
-	V3File.o \
-	V3FileLine.o \
 	V3Force.o \
 	V3Fork.o \
 	V3Gate.o \
-	V3Global.o \
-	V3Graph.o \
-	V3GraphAcyc.o \
-	V3GraphAlg.o \
-	V3GraphPathChecker.o \
-	V3GraphTest.o \
-	V3Hash.o \
-	V3Hasher.o \
 	V3HierBlock.o \
 	V3Inline.o \
 	V3Inst.o \
@@ -233,18 +261,9 @@ RAW_OBJS = \
 	V3Localize.o \
 	V3MergeCond.o \
 	V3Name.o \
-	V3Number.o \
-	V3OptionParser.o \
-	V3Options.o \
 	V3Order.o \
-	V3Os.o \
 	V3Param.o \
-	V3ParseGrammar.o \
-	V3ParseImp.o \
-	V3ParseLex.o \
 	V3Partition.o \
-	V3PreProc.o \
-	V3PreShell.o \
 	V3Premit.o \
 	V3ProtectLib.o \
 	V3Randomize.o \
@@ -260,14 +279,10 @@ RAW_OBJS = \
 	V3Split.o \
 	V3SplitAs.o \
 	V3SplitVar.o \
-	V3Stats.o \
-	V3StatsReport.o \
-	V3String.o \
 	V3Subst.o \
 	V3TSP.o \
 	V3Table.o \
 	V3Task.o \
-	V3ThreadPool.o \
 	V3Timing.o \
 	V3Trace.o \
 	V3TraceDecl.o \
@@ -276,7 +291,6 @@ RAW_OBJS = \
 	V3Unknown.o \
 	V3Unroll.o \
 	V3VariableOrder.o \
-	V3Waiver.o \
 	V3Width.o \
 	V3WidthCommit.o \
 	V3WidthSel.o \
@@ -286,21 +300,21 @@ VLCOV_OBJS = \
 	VlcMain.o \
 
 NON_STANDALONE_HEADERS = \
-	V3AstInlines.h  \
-	V3AstNodeDType.h  \
-	V3AstNodeExpr.h  \
-	V3AstNodeOther.h  \
-	V3DfgVertices.h  \
+	V3AstInlines.h \
+	V3AstNodeDType.h \
+	V3AstNodeExpr.h \
+	V3AstNodeOther.h \
+	V3DfgVertices.h \
 	V3ThreadPool.h \
 	V3WidthRemove.h \
 
 AST_DEFS := \
-  V3AstNodeDType.h \
-  V3AstNodeExpr.h \
-  V3AstNodeOther.h \
+	V3AstNodeDType.h \
+	V3AstNodeExpr.h \
+	V3AstNodeOther.h \
 
 DFG_DEFS := \
-  V3DfgVertices.h
+	V3DfgVertices.h
 
 #### astgen common flags
 
@@ -312,7 +326,7 @@ ASTGENFLAGS += $(foreach f,$(DFG_DEFS),--dfgdef $f)
 
 ifeq ($(VL_VLCOV),)
 PREDEP_H = V3Ast__gen_forward_class_decls.h
-OBJS += $(RAW_OBJS)
+OBJS += $(RAW_OBJS) $(RAW_OBJS_PCH_ASTMT) $(RAW_OBJS_PCH_ASTNOMT)
 else
 PREDEP_H =
 OBJS += $(VLCOV_OBJS)
@@ -332,6 +346,8 @@ V3Number_test: V3Number_test.o
 
 .SECONDARY:
 
+%.gch: %
+	$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} ${CFG_CXXFLAGS_PCH} $< -o $@
 %.o: %.cpp
 	$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@
 %.o: %.c
@@ -349,6 +365,22 @@ V3ParseImp.o: V3ParseImp.cpp V3ParseBison.c
 V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp
 	$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
 
+define CXX_ASTMT_template
+$(1): $(basename $(1)).cpp V3PchAstMT.h.gch
+	$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} ${CFG_CXXFLAGS_PCH_I} V3PchAstMT.h${CFG_GCH_IF_CLANG} -c $(srcdir)/$(basename $(1)).cpp -o $(1)
+
+endef
+
+$(foreach obj,$(RAW_OBJS_PCH_ASTMT),$(eval $(call CXX_ASTMT_template,$(obj))))
+
+define CXX_ASTNOMT_template
+$(1): $(basename $(1)).cpp V3PchAstNoMT.h.gch
+	$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} ${CFG_CXXFLAGS_PCH_I} V3PchAstNoMT.h${CFG_GCH_IF_CLANG} -c $(srcdir)/$(basename $(1)).cpp -o $(1)
+
+endef
+
+$(foreach obj,$(RAW_OBJS_PCH_ASTNOMT),$(eval $(call CXX_ASTNOMT_template,$(obj))))
+
 #### Generated files
 
 # Target rule called before parallel build to make generated files
diff --git a/src/V3Active.cpp b/src/V3Active.cpp
index 857c34045..4930b9293 100644
--- a/src/V3Active.cpp
+++ b/src/V3Active.cpp
@@ -26,16 +26,11 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Active.h"
 
-#include "V3Ast.h"
 #include "V3Const.h"
-#include "V3Global.h"
 #include "V3Graph.h"
 
 #include 
diff --git a/src/V3ActiveTop.cpp b/src/V3ActiveTop.cpp
index 4dc193116..4239525b9 100644
--- a/src/V3ActiveTop.cpp
+++ b/src/V3ActiveTop.cpp
@@ -23,16 +23,11 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3ActiveTop.h"
 
-#include "V3Ast.h"
 #include "V3Const.h"
-#include "V3Global.h"
 #include "V3SenTree.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp
index b13fae8c0..3f8278e5b 100644
--- a/src/V3Assert.cpp
+++ b/src/V3Assert.cpp
@@ -14,16 +14,10 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Assert.h"
 
-#include "V3Ast.h"
-#include "V3Error.h"
-#include "V3Global.h"
 #include "V3Stats.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp
index bf416c276..d0689361f 100644
--- a/src/V3AssertPre.cpp
+++ b/src/V3AssertPre.cpp
@@ -19,16 +19,11 @@
 //      Transform clocking blocks into imperative logic
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3AssertPre.h"
 
-#include "V3Ast.h"
 #include "V3Const.h"
-#include "V3Global.h"
 #include "V3Task.h"
 #include "V3UniqueNames.h"
 
diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp
index 2c4353ffb..f7441655c 100644
--- a/src/V3Ast.cpp
+++ b/src/V3Ast.cpp
@@ -14,16 +14,11 @@
 //
 //*************************************************************************
 
-#include "config_build.h"
-#include "verilatedos.h"
-
-#include "V3Ast.h"
+#include "V3PchAstMT.h"
 
 #include "V3Broken.h"
 #include "V3EmitV.h"
 #include "V3File.h"
-#include "V3Global.h"
-#include "V3String.h"
 
 #include 
 #include 
diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp
index c48ef68ec..1c2519ad6 100644
--- a/src/V3AstNodes.cpp
+++ b/src/V3AstNodes.cpp
@@ -14,6 +14,8 @@
 //
 //*************************************************************************
 
+#include "V3PchAstMT.h"
+
 #include "config_build.h"
 #include "verilatedos.h"
 
diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp
index 1ff68713b..b4fa16a24 100644
--- a/src/V3Begin.cpp
+++ b/src/V3Begin.cpp
@@ -26,18 +26,10 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Begin.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
-
-#include 
-
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3Branch.cpp b/src/V3Branch.cpp
index f24307808..e297f59a9 100644
--- a/src/V3Branch.cpp
+++ b/src/V3Branch.cpp
@@ -23,18 +23,10 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Branch.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
-
-#include 
-
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3Broken.cpp b/src/V3Broken.cpp
index 54e761246..9ae17efb9 100644
--- a/src/V3Broken.cpp
+++ b/src/V3Broken.cpp
@@ -22,14 +22,10 @@
 //
 //*************************************************************************
 
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstMT.h"
 
 #include "V3Broken.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
-
 // This visitor does not edit nodes, and is called at error-exit, so should use constant iterators
 #include "V3AstConstOnly.h"
 
diff --git a/src/V3CCtors.cpp b/src/V3CCtors.cpp
index 1727126ed..1f8abb5c3 100644
--- a/src/V3CCtors.cpp
+++ b/src/V3CCtors.cpp
@@ -24,17 +24,12 @@
 //      This transformation honors outputSplitCFuncs.
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3CCtors.h"
 
 #include "V3EmitCBase.h"
-#include "V3Global.h"
 
-#include 
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3CUse.cpp b/src/V3CUse.cpp
index 05215f5bc..748909c2e 100644
--- a/src/V3CUse.cpp
+++ b/src/V3CUse.cpp
@@ -22,20 +22,10 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3CUse.h"
 
-#include "V3Ast.h"
-#include "V3FileLine.h"
-#include "V3Global.h"
-
-#include 
-#include 
-
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3Case.cpp b/src/V3Case.cpp
index 53cc524ce..89458cda8 100644
--- a/src/V3Case.cpp
+++ b/src/V3Case.cpp
@@ -34,19 +34,12 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Case.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
 #include "V3Stats.h"
 
-#include 
-
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 #define CASE_OVERLAP_WIDTH 16  // Maximum width we can check for overlaps in
diff --git a/src/V3Cast.cpp b/src/V3Cast.cpp
index 4fb3b868e..0290c944e 100644
--- a/src/V3Cast.cpp
+++ b/src/V3Cast.cpp
@@ -37,18 +37,10 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Cast.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
-
-#include 
-
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3Class.cpp b/src/V3Class.cpp
index e71de0dab..ef0eddf9b 100644
--- a/src/V3Class.cpp
+++ b/src/V3Class.cpp
@@ -20,15 +20,10 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Class.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
 #include "V3UniqueNames.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Clean.cpp b/src/V3Clean.cpp
index 9023fadd7..00ddad214 100644
--- a/src/V3Clean.cpp
+++ b/src/V3Clean.cpp
@@ -23,18 +23,10 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Clean.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
-
-#include 
-
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3Clock.cpp b/src/V3Clock.cpp
index 6a66f45e5..98596e135 100644
--- a/src/V3Clock.cpp
+++ b/src/V3Clock.cpp
@@ -27,19 +27,12 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Clock.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
 #include "V3Sched.h"
 
-#include 
-
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3Combine.cpp b/src/V3Combine.cpp
index f6fcd3260..2b858de6c 100644
--- a/src/V3Combine.cpp
+++ b/src/V3Combine.cpp
@@ -19,17 +19,12 @@
 //      Also drop empty CFuncs
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Combine.h"
 
-#include "V3Ast.h"
 #include "V3AstUserAllocator.h"
 #include "V3DupFinder.h"
-#include "V3Global.h"
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3Common.cpp b/src/V3Common.cpp
index d6e08d083..6288ccea9 100644
--- a/src/V3Common.cpp
+++ b/src/V3Common.cpp
@@ -20,16 +20,11 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Common.h"
 
-#include "V3Ast.h"
 #include "V3EmitCBase.h"
-#include "V3Global.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3Config.cpp b/src/V3Config.cpp
index a221f92e8..566021160 100644
--- a/src/V3Config.cpp
+++ b/src/V3Config.cpp
@@ -14,17 +14,13 @@
 //
 //*************************************************************************
 
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstMT.h"
 
 #include "V3Config.h"
 
-#include "V3Global.h"
 #include "V3String.h"
 
-#include 
 #include 
-#include 
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Coverage.cpp b/src/V3Coverage.cpp
index 85c9af732..4d04e00cc 100644
--- a/src/V3Coverage.cpp
+++ b/src/V3Coverage.cpp
@@ -24,17 +24,10 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Coverage.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
-
-#include 
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3CoverageJoin.cpp b/src/V3CoverageJoin.cpp
index 58176cd69..76f0e7bdf 100644
--- a/src/V3CoverageJoin.cpp
+++ b/src/V3CoverageJoin.cpp
@@ -17,15 +17,11 @@
 //      If two COVERTOGGLEs have same VARSCOPE, combine them
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3CoverageJoin.h"
 
 #include "V3DupFinder.h"
-#include "V3Global.h"
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp
index 428538e1c..768887b5f 100644
--- a/src/V3Dead.cpp
+++ b/src/V3Dead.cpp
@@ -33,17 +33,10 @@
 // here after scoping to allow more dead node removal.
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Dead.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
-
-#include 
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp
index eba736d48..3a829d22d 100644
--- a/src/V3Delayed.cpp
+++ b/src/V3Delayed.cpp
@@ -48,20 +48,13 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Delayed.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
 #include "V3Stats.h"
 
-#include 
 #include 
-#include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3Depth.cpp b/src/V3Depth.cpp
index 7f1012f50..a459a26c7 100644
--- a/src/V3Depth.cpp
+++ b/src/V3Depth.cpp
@@ -23,19 +23,12 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Depth.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
 #include "V3UniqueNames.h"
 
-#include 
-
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3DepthBlock.cpp b/src/V3DepthBlock.cpp
index b0e65d136..378f83d0c 100644
--- a/src/V3DepthBlock.cpp
+++ b/src/V3DepthBlock.cpp
@@ -20,18 +20,11 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3DepthBlock.h"
 
-#include "V3Ast.h"
 #include "V3EmitCBase.h"
-#include "V3Global.h"
-
-#include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3Descope.cpp b/src/V3Descope.cpp
index 8b68ca011..c603204f0 100644
--- a/src/V3Descope.cpp
+++ b/src/V3Descope.cpp
@@ -22,18 +22,11 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Descope.h"
 
-#include "V3Ast.h"
 #include "V3EmitCBase.h"
-#include "V3Global.h"
-
-#include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3Dfg.cpp b/src/V3Dfg.cpp
index 4e70c94ac..9cda7d02a 100644
--- a/src/V3Dfg.cpp
+++ b/src/V3Dfg.cpp
@@ -14,10 +14,7 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Dfg.h"
 
diff --git a/src/V3DfgAstToDfg.cpp b/src/V3DfgAstToDfg.cpp
index c4aa2d1be..3b23986ff 100644
--- a/src/V3DfgAstToDfg.cpp
+++ b/src/V3DfgAstToDfg.cpp
@@ -26,16 +26,10 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
-#include "config_build.h"
-#include "verilatedos.h"
-
-#include "V3Ast.h"
 #include "V3Dfg.h"
 #include "V3DfgPasses.h"
-#include "V3Error.h"
-#include "V3Global.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3DfgDecomposition.cpp b/src/V3DfgDecomposition.cpp
index 31bb001ce..200d12610 100644
--- a/src/V3DfgDecomposition.cpp
+++ b/src/V3DfgDecomposition.cpp
@@ -18,10 +18,7 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Dfg.h"
 #include "V3File.h"
diff --git a/src/V3DfgDfgToAst.cpp b/src/V3DfgDfgToAst.cpp
index 43728cef9..a5d0a14a9 100644
--- a/src/V3DfgDfgToAst.cpp
+++ b/src/V3DfgDfgToAst.cpp
@@ -26,16 +26,12 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Dfg.h"
 #include "V3DfgPasses.h"
 #include "V3UniqueNames.h"
 
-#include 
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3DfgOptimizer.cpp b/src/V3DfgOptimizer.cpp
index 0a514723b..ea49de41e 100644
--- a/src/V3DfgOptimizer.cpp
+++ b/src/V3DfgOptimizer.cpp
@@ -18,19 +18,13 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3DfgOptimizer.h"
 
-#include "V3Ast.h"
 #include "V3AstUserAllocator.h"
 #include "V3Dfg.h"
 #include "V3DfgPasses.h"
-#include "V3Error.h"
-#include "V3Global.h"
 #include "V3Graph.h"
 #include "V3UniqueNames.h"
 
diff --git a/src/V3DfgPasses.cpp b/src/V3DfgPasses.cpp
index 44026320e..f65b77897 100644
--- a/src/V3DfgPasses.cpp
+++ b/src/V3DfgPasses.cpp
@@ -14,9 +14,7 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3DfgPasses.h"
 
@@ -24,8 +22,6 @@
 #include "V3Global.h"
 #include "V3String.h"
 
-#include 
-
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 V3DfgCseContext::~V3DfgCseContext() {
diff --git a/src/V3DfgPeephole.cpp b/src/V3DfgPeephole.cpp
index c3d969a8e..f162c9ec9 100644
--- a/src/V3DfgPeephole.cpp
+++ b/src/V3DfgPeephole.cpp
@@ -21,18 +21,14 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3DfgPeephole.h"
 
-#include "V3Ast.h"
 #include "V3Dfg.h"
 #include "V3DfgPasses.h"
 #include "V3Stats.h"
 
-#include 
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3DupFinder.cpp b/src/V3DupFinder.cpp
index f1e3ab956..58a889931 100644
--- a/src/V3DupFinder.cpp
+++ b/src/V3DupFinder.cpp
@@ -14,20 +14,13 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3DupFinder.h"
 
-#include "V3Ast.h"
 #include "V3File.h"
-#include "V3Global.h"
 
-#include 
 #include 
-#include 
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3EmitCBase.cpp b/src/V3EmitCBase.cpp
index 5a173f38b..c382554c4 100644
--- a/src/V3EmitCBase.cpp
+++ b/src/V3EmitCBase.cpp
@@ -14,8 +14,7 @@
 //
 //*************************************************************************
 
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstMT.h"
 
 #include "V3EmitCBase.h"
 
diff --git a/src/V3EmitCConstPool.cpp b/src/V3EmitCConstPool.cpp
index 27503551c..656bffcd8 100644
--- a/src/V3EmitCConstPool.cpp
+++ b/src/V3EmitCConstPool.cpp
@@ -14,15 +14,12 @@
 //
 //*************************************************************************
 
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstMT.h"
 
 #include "V3EmitC.h"
 #include "V3EmitCConstInit.h"
 #include "V3File.h"
-#include "V3Global.h"
 #include "V3Stats.h"
-#include "V3String.h"
 
 #include 
 #include 
diff --git a/src/V3EmitCFunc.cpp b/src/V3EmitCFunc.cpp
index deb4ceb61..461d6496e 100644
--- a/src/V3EmitCFunc.cpp
+++ b/src/V3EmitCFunc.cpp
@@ -14,13 +14,10 @@
 //
 //*************************************************************************
 
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstMT.h"
 
 #include "V3EmitCFunc.h"
 
-#include "V3Global.h"
-#include "V3String.h"
 #include "V3TSP.h"
 
 #include 
diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp
index 4f63aa5b0..8d9f71c8d 100644
--- a/src/V3EmitCHeaders.cpp
+++ b/src/V3EmitCHeaders.cpp
@@ -14,13 +14,10 @@
 //
 //*************************************************************************
 
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstMT.h"
 
-#include "V3Ast.h"
 #include "V3EmitC.h"
 #include "V3EmitCConstInit.h"
-#include "V3Global.h"
 
 #include 
 #include 
diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp
index f84e9442c..e640634c9 100644
--- a/src/V3EmitCImp.cpp
+++ b/src/V3EmitCImp.cpp
@@ -14,14 +14,10 @@
 //
 //*************************************************************************
 
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstMT.h"
 
-#include "V3Ast.h"
 #include "V3EmitC.h"
 #include "V3EmitCFunc.h"
-#include "V3Global.h"
-#include "V3String.h"
 #include "V3ThreadPool.h"
 #include "V3UniqueNames.h"
 
diff --git a/src/V3EmitCInlines.cpp b/src/V3EmitCInlines.cpp
index e2603371e..6425a367c 100644
--- a/src/V3EmitCInlines.cpp
+++ b/src/V3EmitCInlines.cpp
@@ -14,12 +14,10 @@
 //
 //*************************************************************************
 
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstMT.h"
 
 #include "V3EmitC.h"
 #include "V3EmitCBase.h"
-#include "V3Global.h"
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3EmitCMain.cpp b/src/V3EmitCMain.cpp
index 873519d5d..4a9f9c496 100644
--- a/src/V3EmitCMain.cpp
+++ b/src/V3EmitCMain.cpp
@@ -14,16 +14,12 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3EmitCMain.h"
 
 #include "V3EmitC.h"
 #include "V3EmitCBase.h"
-#include "V3Global.h"
 
 #include 
 
diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp
index bd065144d..ca548d68b 100644
--- a/src/V3EmitCMake.cpp
+++ b/src/V3EmitCMake.cpp
@@ -14,15 +14,11 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3EmitCMake.h"
 
 #include "V3EmitCBase.h"
-#include "V3Global.h"
 #include "V3HierBlock.h"
 #include "V3Os.h"
 
diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp
index 25a7368c0..53c5339fb 100644
--- a/src/V3EmitCModel.cpp
+++ b/src/V3EmitCModel.cpp
@@ -14,14 +14,10 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3EmitC.h"
 #include "V3EmitCFunc.h"
-#include "V3Global.h"
 #include "V3UniqueNames.h"
 
 #include 
diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp
index 4a041d784..4642ac016 100644
--- a/src/V3EmitCSyms.cpp
+++ b/src/V3EmitCSyms.cpp
@@ -14,14 +14,10 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3EmitC.h"
 #include "V3EmitCBase.h"
-#include "V3Global.h"
 #include "V3LanguageWords.h"
 #include "V3PartitionGraph.h"
 
diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp
index bdf088c6a..e55ff26f5 100644
--- a/src/V3EmitMk.cpp
+++ b/src/V3EmitMk.cpp
@@ -14,15 +14,11 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3EmitMk.h"
 
 #include "V3EmitCBase.h"
-#include "V3Global.h"
 #include "V3HierBlock.h"
 #include "V3Os.h"
 
diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp
index 2f0e40351..38bca92ba 100644
--- a/src/V3EmitV.cpp
+++ b/src/V3EmitV.cpp
@@ -14,16 +14,12 @@
 //
 //*************************************************************************
 
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstMT.h"
 
 #include "V3EmitV.h"
 
 #include "V3EmitCBase.h"
-#include "V3Global.h"
 
-#include 
-#include 
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3EmitXml.cpp b/src/V3EmitXml.cpp
index 9065a24b7..d2cb7d621 100644
--- a/src/V3EmitXml.cpp
+++ b/src/V3EmitXml.cpp
@@ -14,16 +14,11 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3EmitXml.h"
 
 #include "V3EmitCBase.h"
-#include "V3Global.h"
-#include "V3String.h"
 
 #include 
 #include 
diff --git a/src/V3Expand.cpp b/src/V3Expand.cpp
index 2bfe49c5a..af67ad82e 100644
--- a/src/V3Expand.cpp
+++ b/src/V3Expand.cpp
@@ -25,20 +25,13 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Expand.h"
 
-#include "V3Ast.h"
 #include "V3Const.h"
-#include "V3Global.h"
 #include "V3Stats.h"
 
-#include 
-
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3File.cpp b/src/V3File.cpp
index 7a669f30d..97a26d572 100644
--- a/src/V3File.cpp
+++ b/src/V3File.cpp
@@ -14,13 +14,10 @@
 //
 //*************************************************************************
 
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstMT.h"
 
 #include "V3File.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
 #include "V3Os.h"
 #include "V3String.h"
 
diff --git a/src/V3Force.cpp b/src/V3Force.cpp
index 51437482b..93a3d4a08 100644
--- a/src/V3Force.cpp
+++ b/src/V3Force.cpp
@@ -37,16 +37,11 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Force.h"
 
 #include "V3AstUserAllocator.h"
-#include "V3Error.h"
-#include "V3Global.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3Fork.cpp b/src/V3Fork.cpp
index bce03b9fa..098104d11 100644
--- a/src/V3Fork.cpp
+++ b/src/V3Fork.cpp
@@ -38,21 +38,13 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Fork.h"
 
-#include "V3Ast.h"
 #include "V3AstNodeExpr.h"
-#include "V3Error.h"
-#include "V3Global.h"
 #include "V3MemberMap.h"
 
-#include 
-#include 
 #include 
 #include 
 
diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp
index a1594e185..0f0bb61cc 100644
--- a/src/V3Gate.cpp
+++ b/src/V3Gate.cpp
@@ -21,22 +21,16 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Gate.h"
 
-#include "V3Ast.h"
 #include "V3AstUserAllocator.h"
 #include "V3Const.h"
 #include "V3DupFinder.h"
-#include "V3Global.h"
 #include "V3Graph.h"
 #include "V3Stats.h"
 
-#include 
 #include 
 #include 
 #include 
diff --git a/src/V3Global.cpp b/src/V3Global.cpp
index 82dd6e584..f4ebc182a 100644
--- a/src/V3Global.cpp
+++ b/src/V3Global.cpp
@@ -14,12 +14,8 @@
 //
 //*************************************************************************
 
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstMT.h"
 
-#include "V3Global.h"
-
-#include "V3Ast.h"
 #include "V3File.h"
 #include "V3HierBlock.h"
 #include "V3LinkCells.h"
diff --git a/src/V3Hasher.cpp b/src/V3Hasher.cpp
index 0e13e18d5..e58dce546 100644
--- a/src/V3Hasher.cpp
+++ b/src/V3Hasher.cpp
@@ -14,8 +14,7 @@
 //
 //*************************************************************************
 
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstMT.h"
 
 #include "V3Hasher.h"
 
diff --git a/src/V3HierBlock.cpp b/src/V3HierBlock.cpp
index 331c8cbc9..f1624493b 100644
--- a/src/V3HierBlock.cpp
+++ b/src/V3HierBlock.cpp
@@ -72,12 +72,10 @@
 //       Used for b) and c).
 //       This options is repeated for all instantiating hierarchical blocks.
 
-#define VL_MT_DISABLED_CODE_UNIT 1
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3HierBlock.h"
 
-#include "V3Ast.h"
-#include "V3Error.h"
 #include "V3File.h"
 #include "V3Os.h"
 #include "V3Stats.h"
diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp
index 4735bc079..dbc3e7bb9 100644
--- a/src/V3Inline.cpp
+++ b/src/V3Inline.cpp
@@ -24,21 +24,14 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Inline.h"
 
-#include "V3Ast.h"
 #include "V3AstUserAllocator.h"
-#include "V3Global.h"
 #include "V3Inst.h"
 #include "V3Stats.h"
-#include "V3String.h"
 
-#include 
 #include 
 #include 
 
diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp
index dd3e7e283..fa5b2da3c 100644
--- a/src/V3Inst.cpp
+++ b/src/V3Inst.cpp
@@ -21,18 +21,11 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Inst.h"
 
-#include "V3Ast.h"
 #include "V3Const.h"
-#include "V3Global.h"
-
-#include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3InstrCount.cpp b/src/V3InstrCount.cpp
index 7e363ba17..95bbdaa06 100644
--- a/src/V3InstrCount.cpp
+++ b/src/V3InstrCount.cpp
@@ -15,15 +15,10 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3InstrCount.h"
 
-#include "V3Ast.h"
-
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Interface.cpp b/src/V3Interface.cpp
index a0b641885..de504d25c 100644
--- a/src/V3Interface.cpp
+++ b/src/V3Interface.cpp
@@ -23,16 +23,10 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Interface.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
-
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3Life.cpp b/src/V3Life.cpp
index 5fd69a27f..84ee05d60 100644
--- a/src/V3Life.cpp
+++ b/src/V3Life.cpp
@@ -23,19 +23,13 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Life.h"
 
-#include "V3Ast.h"
 #include "V3Const.h"
-#include "V3Global.h"
 #include "V3Stats.h"
 
-#include 
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3LifePost.cpp b/src/V3LifePost.cpp
index 35728e5de..6692a3ebf 100644
--- a/src/V3LifePost.cpp
+++ b/src/V3LifePost.cpp
@@ -24,15 +24,10 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3LifePost.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
 #include "V3GraphPathChecker.h"
 #include "V3PartitionGraph.h"
 #include "V3Stats.h"
diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp
index 4d18030eb..14bcfee31 100644
--- a/src/V3LinkCells.cpp
+++ b/src/V3LinkCells.cpp
@@ -23,21 +23,14 @@
 //              Link to module that instantiates it
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3LinkCells.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
 #include "V3Graph.h"
 #include "V3Parse.h"
 #include "V3SymTable.h"
 
-#include 
-#include 
 #include 
 #include 
 
diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp
index 3b129d741..473545166 100644
--- a/src/V3LinkDot.cpp
+++ b/src/V3LinkDot.cpp
@@ -61,22 +61,15 @@
 //      b          (VSymEnt->AstCell)
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3LinkDot.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
 #include "V3Graph.h"
 #include "V3MemberMap.h"
 #include "V3String.h"
 #include "V3SymTable.h"
 
-#include 
-#include 
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp
index 4e2381ff7..d4a00861c 100644
--- a/src/V3LinkInc.cpp
+++ b/src/V3LinkInc.cpp
@@ -36,16 +36,10 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3LinkInc.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
-
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp
index d0aa33e64..e777ac164 100644
--- a/src/V3LinkJump.cpp
+++ b/src/V3LinkJump.cpp
@@ -29,18 +29,12 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3LinkJump.h"
 
-#include "V3Ast.h"
 #include "V3AstUserAllocator.h"
-#include "V3Global.h"
 
-#include 
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp
index 9431731a3..11a1e4499 100644
--- a/src/V3LinkLValue.cpp
+++ b/src/V3LinkLValue.cpp
@@ -18,18 +18,10 @@
 //          Set lvalue() attributes on appropriate VARREFs.
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3LinkLValue.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
-
-#include 
-
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp
index dbb0631da..9c0500239 100644
--- a/src/V3LinkLevel.cpp
+++ b/src/V3LinkLevel.cpp
@@ -19,18 +19,10 @@
 //          Create new MODULE TOP with connections to below signals
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3LinkLevel.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
-
-#include 
-#include 
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp
index 5b863df9c..b3371c2a3 100644
--- a/src/V3LinkParse.cpp
+++ b/src/V3LinkParse.cpp
@@ -18,19 +18,12 @@
 //          Move some attributes around
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3LinkParse.h"
 
-#include "V3Ast.h"
 #include "V3Config.h"
-#include "V3Global.h"
 
-#include 
-#include 
 #include 
 #include 
 
diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp
index e3767407c..b0636a298 100644
--- a/src/V3LinkResolve.cpp
+++ b/src/V3LinkResolve.cpp
@@ -24,21 +24,13 @@
 //          SenItems: Convert pos/negedge of non-simple signals to temporaries
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3LinkResolve.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
 #include "V3String.h"
 #include "V3Task.h"
 
-#include 
-#include 
-
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3Localize.cpp b/src/V3Localize.cpp
index 16500e84d..d26a86175 100644
--- a/src/V3Localize.cpp
+++ b/src/V3Localize.cpp
@@ -22,16 +22,11 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Localize.h"
 
-#include "V3Ast.h"
 #include "V3AstUserAllocator.h"
-#include "V3Global.h"
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3MergeCond.cpp b/src/V3MergeCond.cpp
index 5598a5cdf..b9e08ea22 100644
--- a/src/V3MergeCond.cpp
+++ b/src/V3MergeCond.cpp
@@ -72,17 +72,12 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3MergeCond.h"
 
-#include "V3Ast.h"
 #include "V3AstUserAllocator.h"
 #include "V3DupFinder.h"
-#include "V3Global.h"
 #include "V3Hasher.h"
 #include "V3Stats.h"
 
diff --git a/src/V3Name.cpp b/src/V3Name.cpp
index 56896ef58..9825a3bac 100644
--- a/src/V3Name.cpp
+++ b/src/V3Name.cpp
@@ -19,15 +19,10 @@
 //              Prepend __PVT__ to variable names
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Name.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
 #include "V3LanguageWords.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Number.cpp b/src/V3Number.cpp
index b6d2a519c..acc6e6639 100644
--- a/src/V3Number.cpp
+++ b/src/V3Number.cpp
@@ -14,14 +14,10 @@
 //
 //*************************************************************************
 
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstMT.h"
 
 #include "V3Number.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
-
 #include 
 #include 
 #include 
diff --git a/src/V3Options.cpp b/src/V3Options.cpp
index 9b816f63d..554af3421 100644
--- a/src/V3Options.cpp
+++ b/src/V3Options.cpp
@@ -14,12 +14,10 @@
 //
 //*************************************************************************
 
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstMT.h"
 
 #include "V3Options.h"
 
-#include "V3Ast.h"
 #include "V3Error.h"
 #include "V3File.h"
 #include "V3Global.h"
diff --git a/src/V3Order.cpp b/src/V3Order.cpp
index c3ba10a93..b3af14abc 100644
--- a/src/V3Order.cpp
+++ b/src/V3Order.cpp
@@ -71,19 +71,14 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Order.h"
 
-#include "V3Ast.h"
 #include "V3AstUserAllocator.h"
 #include "V3Const.h"
 #include "V3EmitV.h"
 #include "V3File.h"
-#include "V3Global.h"
 #include "V3Graph.h"
 #include "V3GraphStream.h"
 #include "V3List.h"
@@ -96,10 +91,8 @@
 #include "V3SplitVar.h"
 #include "V3Stats.h"
 
-#include 
 #include 
 #include 
-#include 
 #include 
 #include 
 #include 
diff --git a/src/V3Param.cpp b/src/V3Param.cpp
index 2479c7f0d..4133df59f 100644
--- a/src/V3Param.cpp
+++ b/src/V3Param.cpp
@@ -44,17 +44,12 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Param.h"
 
-#include "V3Ast.h"
 #include "V3Case.h"
 #include "V3Const.h"
-#include "V3Global.h"
 #include "V3Hasher.h"
 #include "V3Os.h"
 #include "V3Parse.h"
@@ -63,7 +58,6 @@
 
 #include 
 #include 
-#include 
 #include 
 #include 
 
diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp
index d2e27a85b..16e7d612c 100644
--- a/src/V3Partition.cpp
+++ b/src/V3Partition.cpp
@@ -14,10 +14,7 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Partition.h"
 
@@ -34,7 +31,6 @@
 #include "V3Stats.h"
 #include "V3UniqueNames.h"
 
-#include 
 #include 
 #include 
 #include 
diff --git a/src/V3PchAstMT.h b/src/V3PchAstMT.h
new file mode 100644
index 000000000..50590fd6a
--- /dev/null
+++ b/src/V3PchAstMT.h
@@ -0,0 +1,42 @@
+// -*- mode: C++; c-file-style: "cc-mode" -*-
+//*************************************************************************
+// Code available from: https://verilator.org
+//
+// Copyright 2003-2023 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
+//
+//*************************************************************************
+// DESCRIPTION: Verilator: Precompilable header of V3Ast, multithreaded
+//
+//*************************************************************************
+
+#ifndef VERILATOR_V3PCHASTMT_H_
+#define VERILATOR_V3PCHASTMT_H_
+
+#ifdef VL_PCH_INCLUDED
+#error "Including multiple V3Pch*.h flavors"
+#endif
+#define VL_PCH_INCLUDED
+
+#include "config_build.h"
+#include "verilatedos.h"
+
+#include 
+
+#include "V3Ast.h"
+#include "V3Broken.h"
+#include "V3Error.h"
+#include "V3FileLine.h"
+#include "V3FunctionTraits.h"
+#include "V3Global.h"
+#include "V3Mutex.h"
+#include "V3Number.h"
+#include "V3Options.h"
+#include "V3StdFuture.h"
+#include "V3String.h"
+#include "V3ThreadSafety.h"
+
+#endif  // Guard
diff --git a/src/V3PchAstNoMT.h b/src/V3PchAstNoMT.h
new file mode 100644
index 000000000..0ac7907a8
--- /dev/null
+++ b/src/V3PchAstNoMT.h
@@ -0,0 +1,46 @@
+// -*- mode: C++; c-file-style: "cc-mode" -*-
+//*************************************************************************
+// Code available from: https://verilator.org
+//
+// Copyright 2003-2023 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
+//
+//*************************************************************************
+// DESCRIPTION: Verilator: Precompilable header of V3Ast, non-multithreaded
+//
+//*************************************************************************
+
+#ifndef VERILATOR_V3PCHASTNOMT_H_
+#define VERILATOR_V3PCHASTNOMT_H_
+
+#ifdef VL_PCH_INCLUDED
+#error "Including multiple V3Pch*.h flavors"
+#endif
+#define VL_PCH_INCLUDED
+
+#define VL_MT_DISABLED_CODE_UNIT 1
+
+#include "config_build.h"
+#include "verilatedos.h"
+
+#include 
+#include 
+#include 
+
+#include "V3Ast.h"
+#include "V3Broken.h"
+#include "V3Error.h"
+#include "V3FileLine.h"
+#include "V3FunctionTraits.h"
+#include "V3Global.h"
+#include "V3Mutex.h"
+#include "V3Number.h"
+#include "V3Options.h"
+#include "V3StdFuture.h"
+#include "V3String.h"
+#include "V3ThreadSafety.h"
+
+#endif  // Guard
diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp
index 57a5c3826..c6ebaacee 100644
--- a/src/V3Premit.cpp
+++ b/src/V3Premit.cpp
@@ -24,20 +24,13 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Premit.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
 #include "V3Stats.h"
 #include "V3UniqueNames.h"
 
-#include 
-
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 constexpr int STATIC_CONST_MIN_WIDTH = 256;  // Minimum size to extract to static constant
diff --git a/src/V3ProtectLib.cpp b/src/V3ProtectLib.cpp
index 08a415395..0fa0c4c2a 100644
--- a/src/V3ProtectLib.cpp
+++ b/src/V3ProtectLib.cpp
@@ -14,14 +14,10 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3ProtectLib.h"
 
-#include "V3Global.h"
 #include "V3Hasher.h"
 #include "V3String.h"
 #include "V3Task.h"
diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp
index b544690d1..5c39b78d2 100644
--- a/src/V3Randomize.cpp
+++ b/src/V3Randomize.cpp
@@ -24,14 +24,10 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Randomize.h"
 
-#include "V3Ast.h"
 #include "V3MemberMap.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Reloop.cpp b/src/V3Reloop.cpp
index b50f21b67..55f07fe35 100644
--- a/src/V3Reloop.cpp
+++ b/src/V3Reloop.cpp
@@ -29,19 +29,12 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Reloop.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
 #include "V3Stats.h"
 
-#include 
-
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3Sched.cpp b/src/V3Sched.cpp
index b3849955d..a7012d151 100644
--- a/src/V3Sched.cpp
+++ b/src/V3Sched.cpp
@@ -35,14 +35,10 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Sched.h"
 
-#include "V3Ast.h"
 #include "V3EmitCBase.h"
 #include "V3EmitV.h"
 #include "V3Order.h"
diff --git a/src/V3SchedAcyclic.cpp b/src/V3SchedAcyclic.cpp
index d6d9d73ce..f70022350 100644
--- a/src/V3SchedAcyclic.cpp
+++ b/src/V3SchedAcyclic.cpp
@@ -33,14 +33,8 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
-#include "config_build.h"
-#include "verilatedos.h"
-
-#include "V3Ast.h"
-#include "V3Error.h"
-#include "V3Global.h"
 #include "V3Graph.h"
 #include "V3Sched.h"
 #include "V3SenTree.h"
diff --git a/src/V3SchedPartition.cpp b/src/V3SchedPartition.cpp
index c7c3fb29b..a5cbfd3c9 100644
--- a/src/V3SchedPartition.cpp
+++ b/src/V3SchedPartition.cpp
@@ -34,15 +34,9 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
-#include "config_build.h"
-#include "verilatedos.h"
-
-#include "V3Ast.h"
 #include "V3EmitV.h"
-#include "V3Error.h"
-#include "V3Global.h"
 #include "V3Graph.h"
 #include "V3Sched.h"
 
diff --git a/src/V3SchedReplicate.cpp b/src/V3SchedReplicate.cpp
index 037fd3593..9ef1fcdb0 100644
--- a/src/V3SchedReplicate.cpp
+++ b/src/V3SchedReplicate.cpp
@@ -34,13 +34,8 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
-#include "config_build.h"
-#include "verilatedos.h"
-
-#include "V3Ast.h"
-#include "V3Error.h"
 #include "V3Graph.h"
 #include "V3Sched.h"
 
diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp
index e072814e7..56a89ed24 100644
--- a/src/V3SchedTiming.cpp
+++ b/src/V3SchedTiming.cpp
@@ -24,13 +24,9 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3EmitCBase.h"
-#include "V3Error.h"
 #include "V3Sched.h"
 
 #include 
diff --git a/src/V3Scope.cpp b/src/V3Scope.cpp
index c60a8c935..4f6efb93e 100644
--- a/src/V3Scope.cpp
+++ b/src/V3Scope.cpp
@@ -21,18 +21,10 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Scope.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
-
-#include 
-#include 
 #include 
 #include 
 
diff --git a/src/V3Scoreboard.cpp b/src/V3Scoreboard.cpp
index 5d25cdf76..1a26dbc2f 100644
--- a/src/V3Scoreboard.cpp
+++ b/src/V3Scoreboard.cpp
@@ -14,10 +14,7 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Scoreboard.h"
 
diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp
index 3df645406..0076094e0 100644
--- a/src/V3Slice.cpp
+++ b/src/V3Slice.cpp
@@ -35,16 +35,10 @@
 // simplified to look primarily for SLICESELs.
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Slice.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
-
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //*************************************************************************
diff --git a/src/V3Split.cpp b/src/V3Split.cpp
index aa0ac31f0..c543aec1d 100644
--- a/src/V3Split.cpp
+++ b/src/V3Split.cpp
@@ -77,20 +77,13 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Split.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
 #include "V3Graph.h"
 #include "V3Stats.h"
 
-#include 
-#include 
 #include 
 #include 
 #include 
diff --git a/src/V3SplitAs.cpp b/src/V3SplitAs.cpp
index 80be47d77..26898c676 100644
--- a/src/V3SplitAs.cpp
+++ b/src/V3SplitAs.cpp
@@ -21,19 +21,12 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3SplitAs.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
 #include "V3Stats.h"
 
-#include 
-
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp
index e940918b8..8711f4bc6 100644
--- a/src/V3SplitVar.cpp
+++ b/src/V3SplitVar.cpp
@@ -110,20 +110,13 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3SplitVar.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
 #include "V3Stats.h"
 #include "V3UniqueNames.h"
 
-#include   // sort
-#include 
 #include 
 #include 
 
diff --git a/src/V3Stats.cpp b/src/V3Stats.cpp
index f79da45e4..3f89004df 100644
--- a/src/V3Stats.cpp
+++ b/src/V3Stats.cpp
@@ -14,14 +14,10 @@
 //
 //*************************************************************************
 
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstMT.h"
 
 #include "V3Stats.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
-
 // This visitor does not edit nodes, and is called at error-exit, so should use constant iterators
 #include "V3AstConstOnly.h"
 
diff --git a/src/V3StatsReport.cpp b/src/V3StatsReport.cpp
index c725a40f5..a41f116d6 100644
--- a/src/V3StatsReport.cpp
+++ b/src/V3StatsReport.cpp
@@ -14,17 +14,14 @@
 //
 //*************************************************************************
 
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstMT.h"
 
-#include "V3Ast.h"
 #include "V3File.h"
 #include "V3Global.h"
 #include "V3Os.h"
 #include "V3Stats.h"
 
 #include 
-#include 
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Subst.cpp b/src/V3Subst.cpp
index b214a860f..7c2465dad 100644
--- a/src/V3Subst.cpp
+++ b/src/V3Subst.cpp
@@ -22,15 +22,10 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Subst.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3TSP.cpp b/src/V3TSP.cpp
index cdc296c45..583db4ab4 100644
--- a/src/V3TSP.cpp
+++ b/src/V3TSP.cpp
@@ -19,19 +19,13 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3TSP.h"
 
-#include "V3Error.h"
 #include "V3File.h"
-#include "V3Global.h"
 #include "V3Graph.h"
 
-#include 
 #include 
 #include 
 #include 
diff --git a/src/V3Table.cpp b/src/V3Table.cpp
index ec9bb4167..cfdc10717 100644
--- a/src/V3Table.cpp
+++ b/src/V3Table.cpp
@@ -21,15 +21,10 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Table.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
 #include "V3Simulate.h"
 #include "V3Stats.h"
 
diff --git a/src/V3Task.cpp b/src/V3Task.cpp
index 993ee99a5..a410f06a6 100644
--- a/src/V3Task.cpp
+++ b/src/V3Task.cpp
@@ -23,21 +23,15 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Task.h"
 
-#include "V3Ast.h"
 #include "V3Const.h"
 #include "V3EmitCBase.h"
-#include "V3Global.h"
 #include "V3Graph.h"
 #include "V3LinkLValue.h"
 
-#include 
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3ThreadPool.h b/src/V3ThreadPool.h
index f2564710e..ccfa2f88c 100644
--- a/src/V3ThreadPool.h
+++ b/src/V3ThreadPool.h
@@ -17,7 +17,7 @@
 #ifndef _V3THREADPOOL_H_
 #define _V3THREADPOOL_H_ 1
 
-#if defined(VL_MT_DISABLED_CODE_UNIT)
+#ifdef VL_MT_DISABLED_CODE_UNIT
 #error "Source file has been declared as MT_DISABLED, threads use is prohibited."
 #endif
 
diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp
index 132d3d6bf..65948a526 100644
--- a/src/V3Timing.cpp
+++ b/src/V3Timing.cpp
@@ -60,17 +60,12 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Timing.h"
 
-#include "V3Ast.h"
 #include "V3Const.h"
 #include "V3EmitV.h"
-#include "V3Global.h"
 #include "V3Graph.h"
 #include "V3MemberMap.h"
 #include "V3SenExprBuilder.h"
diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp
index c698e1f99..653ba6548 100644
--- a/src/V3Trace.cpp
+++ b/src/V3Trace.cpp
@@ -35,21 +35,16 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Trace.h"
 
 #include "V3DupFinder.h"
 #include "V3EmitCBase.h"
-#include "V3Global.h"
 #include "V3Graph.h"
 #include "V3Stats.h"
 
 #include 
-#include 
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp
index d7c69efc7..284936660 100644
--- a/src/V3TraceDecl.cpp
+++ b/src/V3TraceDecl.cpp
@@ -20,10 +20,7 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3TraceDecl.h"
 
@@ -31,10 +28,8 @@
 
 #include "V3Config.h"
 #include "V3EmitCBase.h"
-#include "V3Global.h"
 #include "V3Stats.h"
 
-#include 
 #include 
 #include 
 #include 
diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp
index 00e92e6e9..a584d1748 100644
--- a/src/V3Tristate.cpp
+++ b/src/V3Tristate.cpp
@@ -115,22 +115,14 @@
 // unsupported.
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Tristate.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
 #include "V3Graph.h"
 #include "V3Inst.h"
 #include "V3Stats.h"
 
-#include 
-#include 
-
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3Undriven.cpp b/src/V3Undriven.cpp
index ece583f21..09d6e5043 100644
--- a/src/V3Undriven.cpp
+++ b/src/V3Undriven.cpp
@@ -23,19 +23,12 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Undriven.h"
 
-#include "V3Ast.h"
-#include "V3Global.h"
 #include "V3Stats.h"
-#include "V3String.h"
 
-#include 
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp
index 4ad6c78b9..625055393 100644
--- a/src/V3Unknown.cpp
+++ b/src/V3Unknown.cpp
@@ -28,21 +28,14 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Unknown.h"
 
-#include "V3Ast.h"
 #include "V3Const.h"
-#include "V3Global.h"
 #include "V3Stats.h"
 #include "V3UniqueNames.h"
 
-#include 
-
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3Unroll.cpp b/src/V3Unroll.cpp
index 59a6efa7b..f2a7af31b 100644
--- a/src/V3Unroll.cpp
+++ b/src/V3Unroll.cpp
@@ -24,21 +24,14 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Unroll.h"
 
-#include "V3Ast.h"
 #include "V3Const.h"
-#include "V3Global.h"
 #include "V3Simulate.h"
 #include "V3Stats.h"
 
-#include 
-
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3VariableOrder.cpp b/src/V3VariableOrder.cpp
index 707a8d391..2fbea7c75 100644
--- a/src/V3VariableOrder.cpp
+++ b/src/V3VariableOrder.cpp
@@ -20,20 +20,14 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3VariableOrder.h"
 
-#include "V3Ast.h"
 #include "V3AstUserAllocator.h"
 #include "V3EmitCBase.h"
-#include "V3Global.h"
 #include "V3TSP.h"
 
-#include 
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Width.cpp b/src/V3Width.cpp
index 20d5d4954..f5f9c85e8 100644
--- a/src/V3Width.cpp
+++ b/src/V3Width.cpp
@@ -63,15 +63,11 @@
 // iterateSubtreeReturnEdits.
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
-
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "V3Width.h"
 
 #include "V3Const.h"
-#include "V3Global.h"
 #include "V3MemberMap.h"
 #include "V3Number.h"
 #include "V3Randomize.h"
@@ -79,8 +75,6 @@
 #include "V3Task.h"
 #include "V3WidthCommit.h"
 
-#include 
-
 // More code; this file was getting too large; see actions there
 #define VERILATOR_V3WIDTH_CPP_
 #include "V3WidthRemove.h"
diff --git a/src/V3WidthCommit.cpp b/src/V3WidthCommit.cpp
index 295d3be8d..abfb20bab 100644
--- a/src/V3WidthCommit.cpp
+++ b/src/V3WidthCommit.cpp
@@ -20,7 +20,7 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include "config_build.h"
 #include "verilatedos.h"
diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp
index c15d64add..8c8aa4bb4 100644
--- a/src/V3WidthSel.cpp
+++ b/src/V3WidthSel.cpp
@@ -26,14 +26,9 @@
 //
 //*************************************************************************
 
-#define VL_MT_DISABLED_CODE_UNIT 1
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
-#include "config_build.h"
-#include "verilatedos.h"
-
-#include "V3Ast.h"
 #include "V3Const.h"
-#include "V3Global.h"
 #include "V3Width.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;

From 770cd24f27c1bff41f3b6a9e47f563413c5062eb Mon Sep 17 00:00:00 2001
From: github action 
Date: Wed, 18 Oct 2023 02:50:27 +0000
Subject: [PATCH 083/157] Apply 'make format'

---
 src/V3Active.cpp           | 3 +--
 src/V3ActiveTop.cpp        | 3 +--
 src/V3Assert.cpp           | 3 +--
 src/V3AssertPre.cpp        | 3 +--
 src/V3Ast.cpp              | 3 +--
 src/V3AstNodes.cpp         | 3 +--
 src/V3Begin.cpp            | 4 ++--
 src/V3Branch.cpp           | 4 ++--
 src/V3Broken.cpp           | 4 ++--
 src/V3CCtors.cpp           | 3 +--
 src/V3CUse.cpp             | 4 ++--
 src/V3Case.cpp             | 3 +--
 src/V3Cast.cpp             | 4 ++--
 src/V3Class.cpp            | 3 +--
 src/V3Clean.cpp            | 4 ++--
 src/V3Clock.cpp            | 3 +--
 src/V3Combine.cpp          | 3 +--
 src/V3Common.cpp           | 3 +--
 src/V3Config.cpp           | 3 +--
 src/V3Coverage.cpp         | 4 ++--
 src/V3CoverageJoin.cpp     | 3 +--
 src/V3Dead.cpp             | 4 ++--
 src/V3Delayed.cpp          | 3 +--
 src/V3Depth.cpp            | 3 +--
 src/V3DepthBlock.cpp       | 3 +--
 src/V3Descope.cpp          | 3 +--
 src/V3Dfg.cpp              | 3 +--
 src/V3DfgAstToDfg.cpp      | 3 +--
 src/V3DfgDecomposition.cpp | 3 +--
 src/V3DfgDfgToAst.cpp      | 3 +--
 src/V3DfgOptimizer.cpp     | 3 +--
 src/V3DfgPasses.cpp        | 3 +--
 src/V3DfgPeephole.cpp      | 3 +--
 src/V3DupFinder.cpp        | 3 +--
 src/V3EmitCBase.cpp        | 3 +--
 src/V3EmitCConstPool.cpp   | 3 +--
 src/V3EmitCFunc.cpp        | 3 +--
 src/V3EmitCHeaders.cpp     | 3 +--
 src/V3EmitCImp.cpp         | 3 +--
 src/V3EmitCInlines.cpp     | 3 +--
 src/V3EmitCMain.cpp        | 3 +--
 src/V3EmitCMake.cpp        | 3 +--
 src/V3EmitCModel.cpp       | 3 +--
 src/V3EmitCSyms.cpp        | 3 +--
 src/V3EmitMk.cpp           | 3 +--
 src/V3EmitV.cpp            | 3 +--
 src/V3EmitXml.cpp          | 3 +--
 src/V3Expand.cpp           | 3 +--
 src/V3File.cpp             | 3 +--
 src/V3Force.cpp            | 3 +--
 src/V3Fork.cpp             | 3 +--
 src/V3Gate.cpp             | 3 +--
 src/V3Global.cpp           | 3 +--
 src/V3Hasher.cpp           | 4 ++--
 src/V3HierBlock.cpp        | 3 +--
 src/V3Inline.cpp           | 3 +--
 src/V3Inst.cpp             | 3 +--
 src/V3InstrCount.cpp       | 4 ++--
 src/V3Interface.cpp        | 4 ++--
 src/V3Life.cpp             | 3 +--
 src/V3LifePost.cpp         | 3 +--
 src/V3LinkCells.cpp        | 3 +--
 src/V3LinkDot.cpp          | 3 +--
 src/V3LinkInc.cpp          | 4 ++--
 src/V3LinkJump.cpp         | 3 +--
 src/V3LinkLValue.cpp       | 4 ++--
 src/V3LinkLevel.cpp        | 4 ++--
 src/V3LinkParse.cpp        | 3 +--
 src/V3LinkResolve.cpp      | 3 +--
 src/V3Localize.cpp         | 3 +--
 src/V3MergeCond.cpp        | 3 +--
 src/V3Name.cpp             | 3 +--
 src/V3Number.cpp           | 4 ++--
 src/V3Options.cpp          | 3 +--
 src/V3Order.cpp            | 3 +--
 src/V3Param.cpp            | 3 +--
 src/V3Partition.cpp        | 3 +--
 src/V3PchAstMT.h           | 4 ++--
 src/V3PchAstNoMT.h         | 8 ++++----
 src/V3Premit.cpp           | 3 +--
 src/V3ProtectLib.cpp       | 3 +--
 src/V3Randomize.cpp        | 3 +--
 src/V3Reloop.cpp           | 3 +--
 src/V3Sched.cpp            | 3 +--
 src/V3SchedAcyclic.cpp     | 3 +--
 src/V3SchedPartition.cpp   | 3 +--
 src/V3SchedReplicate.cpp   | 3 +--
 src/V3SchedTiming.cpp      | 3 +--
 src/V3Scope.cpp            | 4 ++--
 src/V3Scoreboard.cpp       | 4 ++--
 src/V3Slice.cpp            | 4 ++--
 src/V3Split.cpp            | 3 +--
 src/V3SplitAs.cpp          | 3 +--
 src/V3SplitVar.cpp         | 3 +--
 src/V3Stats.cpp            | 4 ++--
 src/V3StatsReport.cpp      | 3 +--
 src/V3Subst.cpp            | 3 +--
 src/V3TSP.cpp              | 3 +--
 src/V3Table.cpp            | 3 +--
 src/V3Task.cpp             | 3 +--
 src/V3Timing.cpp           | 3 +--
 src/V3Trace.cpp            | 3 +--
 src/V3TraceDecl.cpp        | 3 +--
 src/V3Tristate.cpp         | 3 +--
 src/V3Undriven.cpp         | 3 +--
 src/V3Unknown.cpp          | 3 +--
 src/V3Unroll.cpp           | 3 +--
 src/V3VariableOrder.cpp    | 3 +--
 src/V3Width.cpp            | 3 +--
 src/V3WidthCommit.cpp      | 4 ++--
 src/V3WidthSel.cpp         | 3 +--
 111 files changed, 135 insertions(+), 224 deletions(-)

diff --git a/src/V3Active.cpp b/src/V3Active.cpp
index 4930b9293..a49d9f0d9 100644
--- a/src/V3Active.cpp
+++ b/src/V3Active.cpp
@@ -26,12 +26,11 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Active.h"
 
 #include "V3Const.h"
 #include "V3Graph.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 
diff --git a/src/V3ActiveTop.cpp b/src/V3ActiveTop.cpp
index 4239525b9..b3e74bc17 100644
--- a/src/V3ActiveTop.cpp
+++ b/src/V3ActiveTop.cpp
@@ -23,11 +23,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3ActiveTop.h"
 
 #include "V3Const.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3SenTree.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp
index 3f8278e5b..bab7e8a7a 100644
--- a/src/V3Assert.cpp
+++ b/src/V3Assert.cpp
@@ -14,10 +14,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Assert.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp
index d0689361f..263fccf74 100644
--- a/src/V3AssertPre.cpp
+++ b/src/V3AssertPre.cpp
@@ -19,11 +19,10 @@
 //      Transform clocking blocks into imperative logic
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3AssertPre.h"
 
 #include "V3Const.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Task.h"
 #include "V3UniqueNames.h"
 
diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp
index f7441655c..6c14af667 100644
--- a/src/V3Ast.cpp
+++ b/src/V3Ast.cpp
@@ -14,11 +14,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstMT.h"
-
 #include "V3Broken.h"
 #include "V3EmitV.h"
 #include "V3File.h"
+#include "V3PchAstMT.h"
 
 #include 
 #include 
diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp
index 1c2519ad6..48e054209 100644
--- a/src/V3AstNodes.cpp
+++ b/src/V3AstNodes.cpp
@@ -14,8 +14,6 @@
 //
 //*************************************************************************
 
-#include "V3PchAstMT.h"
-
 #include "config_build.h"
 #include "verilatedos.h"
 
@@ -26,6 +24,7 @@
 #include "V3Graph.h"
 #include "V3Hasher.h"
 #include "V3PartitionGraph.h"  // Just for mtask dumping
+#include "V3PchAstMT.h"
 #include "V3String.h"
 
 #include "V3Ast__gen_macros.h"  // Generated by 'astgen'
diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp
index b4fa16a24..5c7b9282c 100644
--- a/src/V3Begin.cpp
+++ b/src/V3Begin.cpp
@@ -26,10 +26,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Begin.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3Branch.cpp b/src/V3Branch.cpp
index e297f59a9..f57d980c5 100644
--- a/src/V3Branch.cpp
+++ b/src/V3Branch.cpp
@@ -23,10 +23,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Branch.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3Broken.cpp b/src/V3Broken.cpp
index 9ae17efb9..7f861c694 100644
--- a/src/V3Broken.cpp
+++ b/src/V3Broken.cpp
@@ -22,10 +22,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstMT.h"
-
 #include "V3Broken.h"
 
+#include "V3PchAstMT.h"
+
 // This visitor does not edit nodes, and is called at error-exit, so should use constant iterators
 #include "V3AstConstOnly.h"
 
diff --git a/src/V3CCtors.cpp b/src/V3CCtors.cpp
index 1f8abb5c3..2c4eaa09d 100644
--- a/src/V3CCtors.cpp
+++ b/src/V3CCtors.cpp
@@ -24,11 +24,10 @@
 //      This transformation honors outputSplitCFuncs.
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3CCtors.h"
 
 #include "V3EmitCBase.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 
diff --git a/src/V3CUse.cpp b/src/V3CUse.cpp
index 748909c2e..5f6c77a68 100644
--- a/src/V3CUse.cpp
+++ b/src/V3CUse.cpp
@@ -22,10 +22,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3CUse.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3Case.cpp b/src/V3Case.cpp
index 89458cda8..8e44063c7 100644
--- a/src/V3Case.cpp
+++ b/src/V3Case.cpp
@@ -34,10 +34,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Case.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Cast.cpp b/src/V3Cast.cpp
index 0290c944e..edd77577b 100644
--- a/src/V3Cast.cpp
+++ b/src/V3Cast.cpp
@@ -37,10 +37,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Cast.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3Class.cpp b/src/V3Class.cpp
index ef0eddf9b..0712ae11f 100644
--- a/src/V3Class.cpp
+++ b/src/V3Class.cpp
@@ -20,10 +20,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Class.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3UniqueNames.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Clean.cpp b/src/V3Clean.cpp
index 00ddad214..cf175572b 100644
--- a/src/V3Clean.cpp
+++ b/src/V3Clean.cpp
@@ -23,10 +23,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Clean.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3Clock.cpp b/src/V3Clock.cpp
index 98596e135..4e642fc39 100644
--- a/src/V3Clock.cpp
+++ b/src/V3Clock.cpp
@@ -27,10 +27,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Clock.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Sched.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Combine.cpp b/src/V3Combine.cpp
index 2b858de6c..0d73f7b29 100644
--- a/src/V3Combine.cpp
+++ b/src/V3Combine.cpp
@@ -19,12 +19,11 @@
 //      Also drop empty CFuncs
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Combine.h"
 
 #include "V3AstUserAllocator.h"
 #include "V3DupFinder.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3Common.cpp b/src/V3Common.cpp
index 6288ccea9..210d4c47c 100644
--- a/src/V3Common.cpp
+++ b/src/V3Common.cpp
@@ -20,11 +20,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Common.h"
 
 #include "V3EmitCBase.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3Config.cpp b/src/V3Config.cpp
index 566021160..0ca224128 100644
--- a/src/V3Config.cpp
+++ b/src/V3Config.cpp
@@ -14,10 +14,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstMT.h"
-
 #include "V3Config.h"
 
+#include "V3PchAstMT.h"
 #include "V3String.h"
 
 #include 
diff --git a/src/V3Coverage.cpp b/src/V3Coverage.cpp
index 4d04e00cc..55fa334ab 100644
--- a/src/V3Coverage.cpp
+++ b/src/V3Coverage.cpp
@@ -24,10 +24,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Coverage.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3CoverageJoin.cpp b/src/V3CoverageJoin.cpp
index 76f0e7bdf..6fe7cc7ed 100644
--- a/src/V3CoverageJoin.cpp
+++ b/src/V3CoverageJoin.cpp
@@ -17,11 +17,10 @@
 //      If two COVERTOGGLEs have same VARSCOPE, combine them
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3CoverageJoin.h"
 
 #include "V3DupFinder.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp
index 768887b5f..a4ab80abc 100644
--- a/src/V3Dead.cpp
+++ b/src/V3Dead.cpp
@@ -33,10 +33,10 @@
 // here after scoping to allow more dead node removal.
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Dead.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp
index 3a829d22d..7041da397 100644
--- a/src/V3Delayed.cpp
+++ b/src/V3Delayed.cpp
@@ -48,10 +48,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Delayed.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3Depth.cpp b/src/V3Depth.cpp
index a459a26c7..66aa89349 100644
--- a/src/V3Depth.cpp
+++ b/src/V3Depth.cpp
@@ -23,10 +23,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Depth.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3UniqueNames.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3DepthBlock.cpp b/src/V3DepthBlock.cpp
index 378f83d0c..3ea035bfe 100644
--- a/src/V3DepthBlock.cpp
+++ b/src/V3DepthBlock.cpp
@@ -20,11 +20,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3DepthBlock.h"
 
 #include "V3EmitCBase.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3Descope.cpp b/src/V3Descope.cpp
index c603204f0..4576cabe0 100644
--- a/src/V3Descope.cpp
+++ b/src/V3Descope.cpp
@@ -22,11 +22,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Descope.h"
 
 #include "V3EmitCBase.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3Dfg.cpp b/src/V3Dfg.cpp
index 9cda7d02a..ff6da033c 100644
--- a/src/V3Dfg.cpp
+++ b/src/V3Dfg.cpp
@@ -14,11 +14,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Dfg.h"
 
 #include "V3File.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3DfgAstToDfg.cpp b/src/V3DfgAstToDfg.cpp
index 3b23986ff..3cf450615 100644
--- a/src/V3DfgAstToDfg.cpp
+++ b/src/V3DfgAstToDfg.cpp
@@ -26,10 +26,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Dfg.h"
 #include "V3DfgPasses.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3DfgDecomposition.cpp b/src/V3DfgDecomposition.cpp
index 200d12610..3a0e41ee9 100644
--- a/src/V3DfgDecomposition.cpp
+++ b/src/V3DfgDecomposition.cpp
@@ -18,10 +18,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Dfg.h"
 #include "V3File.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 #include 
diff --git a/src/V3DfgDfgToAst.cpp b/src/V3DfgDfgToAst.cpp
index a5d0a14a9..056d747ad 100644
--- a/src/V3DfgDfgToAst.cpp
+++ b/src/V3DfgDfgToAst.cpp
@@ -26,10 +26,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Dfg.h"
 #include "V3DfgPasses.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3UniqueNames.h"
 
 #include 
diff --git a/src/V3DfgOptimizer.cpp b/src/V3DfgOptimizer.cpp
index ea49de41e..53cb79546 100644
--- a/src/V3DfgOptimizer.cpp
+++ b/src/V3DfgOptimizer.cpp
@@ -18,14 +18,13 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3DfgOptimizer.h"
 
 #include "V3AstUserAllocator.h"
 #include "V3Dfg.h"
 #include "V3DfgPasses.h"
 #include "V3Graph.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3UniqueNames.h"
 
 #include 
diff --git a/src/V3DfgPasses.cpp b/src/V3DfgPasses.cpp
index f65b77897..2616d5df0 100644
--- a/src/V3DfgPasses.cpp
+++ b/src/V3DfgPasses.cpp
@@ -14,12 +14,11 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3DfgPasses.h"
 
 #include "V3Dfg.h"
 #include "V3Global.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3String.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3DfgPeephole.cpp b/src/V3DfgPeephole.cpp
index f162c9ec9..206505a07 100644
--- a/src/V3DfgPeephole.cpp
+++ b/src/V3DfgPeephole.cpp
@@ -21,12 +21,11 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3DfgPeephole.h"
 
 #include "V3Dfg.h"
 #include "V3DfgPasses.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3DupFinder.cpp b/src/V3DupFinder.cpp
index 58a889931..e81092c3a 100644
--- a/src/V3DupFinder.cpp
+++ b/src/V3DupFinder.cpp
@@ -14,11 +14,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3DupFinder.h"
 
 #include "V3File.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 #include 
diff --git a/src/V3EmitCBase.cpp b/src/V3EmitCBase.cpp
index c382554c4..bb6e09ad2 100644
--- a/src/V3EmitCBase.cpp
+++ b/src/V3EmitCBase.cpp
@@ -14,10 +14,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstMT.h"
-
 #include "V3EmitCBase.h"
 
+#include "V3PchAstMT.h"
 #include "V3Task.h"
 
 //######################################################################
diff --git a/src/V3EmitCConstPool.cpp b/src/V3EmitCConstPool.cpp
index 656bffcd8..cabd546f6 100644
--- a/src/V3EmitCConstPool.cpp
+++ b/src/V3EmitCConstPool.cpp
@@ -14,11 +14,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstMT.h"
-
 #include "V3EmitC.h"
 #include "V3EmitCConstInit.h"
 #include "V3File.h"
+#include "V3PchAstMT.h"
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3EmitCFunc.cpp b/src/V3EmitCFunc.cpp
index 461d6496e..b033a4ccf 100644
--- a/src/V3EmitCFunc.cpp
+++ b/src/V3EmitCFunc.cpp
@@ -14,10 +14,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstMT.h"
-
 #include "V3EmitCFunc.h"
 
+#include "V3PchAstMT.h"
 #include "V3TSP.h"
 
 #include 
diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp
index 8d9f71c8d..2861df5ad 100644
--- a/src/V3EmitCHeaders.cpp
+++ b/src/V3EmitCHeaders.cpp
@@ -14,10 +14,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstMT.h"
-
 #include "V3EmitC.h"
 #include "V3EmitCConstInit.h"
+#include "V3PchAstMT.h"
 
 #include 
 #include 
diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp
index e640634c9..34ec4ee16 100644
--- a/src/V3EmitCImp.cpp
+++ b/src/V3EmitCImp.cpp
@@ -14,10 +14,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstMT.h"
-
 #include "V3EmitC.h"
 #include "V3EmitCFunc.h"
+#include "V3PchAstMT.h"
 #include "V3ThreadPool.h"
 #include "V3UniqueNames.h"
 
diff --git a/src/V3EmitCInlines.cpp b/src/V3EmitCInlines.cpp
index 6425a367c..64070760a 100644
--- a/src/V3EmitCInlines.cpp
+++ b/src/V3EmitCInlines.cpp
@@ -14,10 +14,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstMT.h"
-
 #include "V3EmitC.h"
 #include "V3EmitCBase.h"
+#include "V3PchAstMT.h"
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3EmitCMain.cpp b/src/V3EmitCMain.cpp
index 4a9f9c496..67a9424e1 100644
--- a/src/V3EmitCMain.cpp
+++ b/src/V3EmitCMain.cpp
@@ -14,12 +14,11 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3EmitCMain.h"
 
 #include "V3EmitC.h"
 #include "V3EmitCBase.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 
diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp
index ca548d68b..666a5f8d5 100644
--- a/src/V3EmitCMake.cpp
+++ b/src/V3EmitCMake.cpp
@@ -14,13 +14,12 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3EmitCMake.h"
 
 #include "V3EmitCBase.h"
 #include "V3HierBlock.h"
 #include "V3Os.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 
diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp
index 53c5339fb..e025154eb 100644
--- a/src/V3EmitCModel.cpp
+++ b/src/V3EmitCModel.cpp
@@ -14,10 +14,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3EmitC.h"
 #include "V3EmitCFunc.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3UniqueNames.h"
 
 #include 
diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp
index 4642ac016..1f3f9e80d 100644
--- a/src/V3EmitCSyms.cpp
+++ b/src/V3EmitCSyms.cpp
@@ -14,12 +14,11 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3EmitC.h"
 #include "V3EmitCBase.h"
 #include "V3LanguageWords.h"
 #include "V3PartitionGraph.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 #include 
diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp
index e55ff26f5..d39cadee8 100644
--- a/src/V3EmitMk.cpp
+++ b/src/V3EmitMk.cpp
@@ -14,13 +14,12 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3EmitMk.h"
 
 #include "V3EmitCBase.h"
 #include "V3HierBlock.h"
 #include "V3Os.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp
index 38bca92ba..3a272fa9c 100644
--- a/src/V3EmitV.cpp
+++ b/src/V3EmitV.cpp
@@ -14,11 +14,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstMT.h"
-
 #include "V3EmitV.h"
 
 #include "V3EmitCBase.h"
+#include "V3PchAstMT.h"
 
 #include 
 
diff --git a/src/V3EmitXml.cpp b/src/V3EmitXml.cpp
index d2cb7d621..62db4f1c0 100644
--- a/src/V3EmitXml.cpp
+++ b/src/V3EmitXml.cpp
@@ -14,11 +14,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3EmitXml.h"
 
 #include "V3EmitCBase.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 #include 
diff --git a/src/V3Expand.cpp b/src/V3Expand.cpp
index af67ad82e..4cee48560 100644
--- a/src/V3Expand.cpp
+++ b/src/V3Expand.cpp
@@ -25,11 +25,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Expand.h"
 
 #include "V3Const.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3File.cpp b/src/V3File.cpp
index 97a26d572..c1fd8e59e 100644
--- a/src/V3File.cpp
+++ b/src/V3File.cpp
@@ -14,11 +14,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstMT.h"
-
 #include "V3File.h"
 
 #include "V3Os.h"
+#include "V3PchAstMT.h"
 #include "V3String.h"
 
 #include 
diff --git a/src/V3Force.cpp b/src/V3Force.cpp
index 93a3d4a08..af464e333 100644
--- a/src/V3Force.cpp
+++ b/src/V3Force.cpp
@@ -37,11 +37,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Force.h"
 
 #include "V3AstUserAllocator.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3Fork.cpp b/src/V3Fork.cpp
index 098104d11..545605226 100644
--- a/src/V3Fork.cpp
+++ b/src/V3Fork.cpp
@@ -38,12 +38,11 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Fork.h"
 
 #include "V3AstNodeExpr.h"
 #include "V3MemberMap.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 #include 
diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp
index 0f0bb61cc..756d78625 100644
--- a/src/V3Gate.cpp
+++ b/src/V3Gate.cpp
@@ -21,14 +21,13 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Gate.h"
 
 #include "V3AstUserAllocator.h"
 #include "V3Const.h"
 #include "V3DupFinder.h"
 #include "V3Graph.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3Global.cpp b/src/V3Global.cpp
index f4ebc182a..4013f3097 100644
--- a/src/V3Global.cpp
+++ b/src/V3Global.cpp
@@ -14,13 +14,12 @@
 //
 //*************************************************************************
 
-#include "V3PchAstMT.h"
-
 #include "V3File.h"
 #include "V3HierBlock.h"
 #include "V3LinkCells.h"
 #include "V3Parse.h"
 #include "V3ParseSym.h"
+#include "V3PchAstMT.h"
 #include "V3Stats.h"
 
 //######################################################################
diff --git a/src/V3Hasher.cpp b/src/V3Hasher.cpp
index e58dce546..b9201c628 100644
--- a/src/V3Hasher.cpp
+++ b/src/V3Hasher.cpp
@@ -14,10 +14,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstMT.h"
-
 #include "V3Hasher.h"
 
+#include "V3PchAstMT.h"
+
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3HierBlock.cpp b/src/V3HierBlock.cpp
index f1624493b..4e5371288 100644
--- a/src/V3HierBlock.cpp
+++ b/src/V3HierBlock.cpp
@@ -72,12 +72,11 @@
 //       Used for b) and c).
 //       This options is repeated for all instantiating hierarchical blocks.
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3HierBlock.h"
 
 #include "V3File.h"
 #include "V3Os.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 #include "V3String.h"
 
diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp
index dbc3e7bb9..afaf26507 100644
--- a/src/V3Inline.cpp
+++ b/src/V3Inline.cpp
@@ -24,12 +24,11 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Inline.h"
 
 #include "V3AstUserAllocator.h"
 #include "V3Inst.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp
index fa5b2da3c..80c385968 100644
--- a/src/V3Inst.cpp
+++ b/src/V3Inst.cpp
@@ -21,11 +21,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Inst.h"
 
 #include "V3Const.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3InstrCount.cpp b/src/V3InstrCount.cpp
index 95bbdaa06..23353c9b3 100644
--- a/src/V3InstrCount.cpp
+++ b/src/V3InstrCount.cpp
@@ -15,10 +15,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3InstrCount.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Interface.cpp b/src/V3Interface.cpp
index de504d25c..63644c598 100644
--- a/src/V3Interface.cpp
+++ b/src/V3Interface.cpp
@@ -23,10 +23,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Interface.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3Life.cpp b/src/V3Life.cpp
index 84ee05d60..49e6d0f3b 100644
--- a/src/V3Life.cpp
+++ b/src/V3Life.cpp
@@ -23,11 +23,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Life.h"
 
 #include "V3Const.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3LifePost.cpp b/src/V3LifePost.cpp
index 6692a3ebf..e908a8a8a 100644
--- a/src/V3LifePost.cpp
+++ b/src/V3LifePost.cpp
@@ -24,12 +24,11 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3LifePost.h"
 
 #include "V3GraphPathChecker.h"
 #include "V3PartitionGraph.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include   // for std::unique_ptr -> auto_ptr or unique_ptr
diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp
index 14bcfee31..570b1d3ed 100644
--- a/src/V3LinkCells.cpp
+++ b/src/V3LinkCells.cpp
@@ -23,12 +23,11 @@
 //              Link to module that instantiates it
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3LinkCells.h"
 
 #include "V3Graph.h"
 #include "V3Parse.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3SymTable.h"
 
 #include 
diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp
index 473545166..490ca4d71 100644
--- a/src/V3LinkDot.cpp
+++ b/src/V3LinkDot.cpp
@@ -61,12 +61,11 @@
 //      b          (VSymEnt->AstCell)
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3LinkDot.h"
 
 #include "V3Graph.h"
 #include "V3MemberMap.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3String.h"
 #include "V3SymTable.h"
 
diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp
index d4a00861c..79f31bb48 100644
--- a/src/V3LinkInc.cpp
+++ b/src/V3LinkInc.cpp
@@ -36,10 +36,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3LinkInc.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp
index e777ac164..7a62c06f9 100644
--- a/src/V3LinkJump.cpp
+++ b/src/V3LinkJump.cpp
@@ -29,11 +29,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3LinkJump.h"
 
 #include "V3AstUserAllocator.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 
diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp
index 11a1e4499..5972b535c 100644
--- a/src/V3LinkLValue.cpp
+++ b/src/V3LinkLValue.cpp
@@ -18,10 +18,10 @@
 //          Set lvalue() attributes on appropriate VARREFs.
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3LinkLValue.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp
index 9c0500239..dea26b2f2 100644
--- a/src/V3LinkLevel.cpp
+++ b/src/V3LinkLevel.cpp
@@ -19,10 +19,10 @@
 //          Create new MODULE TOP with connections to below signals
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3LinkLevel.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp
index b3371c2a3..aa1cc7d82 100644
--- a/src/V3LinkParse.cpp
+++ b/src/V3LinkParse.cpp
@@ -18,11 +18,10 @@
 //          Move some attributes around
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3LinkParse.h"
 
 #include "V3Config.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 #include 
diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp
index b0636a298..ba1eeaa06 100644
--- a/src/V3LinkResolve.cpp
+++ b/src/V3LinkResolve.cpp
@@ -24,10 +24,9 @@
 //          SenItems: Convert pos/negedge of non-simple signals to temporaries
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3LinkResolve.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3String.h"
 #include "V3Task.h"
 
diff --git a/src/V3Localize.cpp b/src/V3Localize.cpp
index d26a86175..aebd9f23c 100644
--- a/src/V3Localize.cpp
+++ b/src/V3Localize.cpp
@@ -22,11 +22,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Localize.h"
 
 #include "V3AstUserAllocator.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3MergeCond.cpp b/src/V3MergeCond.cpp
index b9e08ea22..aab950d34 100644
--- a/src/V3MergeCond.cpp
+++ b/src/V3MergeCond.cpp
@@ -72,13 +72,12 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3MergeCond.h"
 
 #include "V3AstUserAllocator.h"
 #include "V3DupFinder.h"
 #include "V3Hasher.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3Name.cpp b/src/V3Name.cpp
index 9825a3bac..64574a5a4 100644
--- a/src/V3Name.cpp
+++ b/src/V3Name.cpp
@@ -19,11 +19,10 @@
 //              Prepend __PVT__ to variable names
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Name.h"
 
 #include "V3LanguageWords.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3Number.cpp b/src/V3Number.cpp
index acc6e6639..00551a50d 100644
--- a/src/V3Number.cpp
+++ b/src/V3Number.cpp
@@ -14,10 +14,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstMT.h"
-
 #include "V3Number.h"
 
+#include "V3PchAstMT.h"
+
 #include 
 #include 
 #include 
diff --git a/src/V3Options.cpp b/src/V3Options.cpp
index 554af3421..d6ec1d0df 100644
--- a/src/V3Options.cpp
+++ b/src/V3Options.cpp
@@ -14,8 +14,6 @@
 //
 //*************************************************************************
 
-#include "V3PchAstMT.h"
-
 #include "V3Options.h"
 
 #include "V3Error.h"
@@ -24,6 +22,7 @@
 #include "V3Mutex.h"
 #include "V3OptionParser.h"
 #include "V3Os.h"
+#include "V3PchAstMT.h"
 #include "V3PreShell.h"
 #include "V3String.h"
 
diff --git a/src/V3Order.cpp b/src/V3Order.cpp
index b3af14abc..c8b7dda5e 100644
--- a/src/V3Order.cpp
+++ b/src/V3Order.cpp
@@ -71,8 +71,6 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Order.h"
 
 #include "V3AstUserAllocator.h"
@@ -86,6 +84,7 @@
 #include "V3OrderMoveGraph.h"
 #include "V3Partition.h"
 #include "V3PartitionGraph.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Sched.h"
 #include "V3SenTree.h"
 #include "V3SplitVar.h"
diff --git a/src/V3Param.cpp b/src/V3Param.cpp
index 4133df59f..acae4012b 100644
--- a/src/V3Param.cpp
+++ b/src/V3Param.cpp
@@ -44,8 +44,6 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Param.h"
 
 #include "V3Case.h"
@@ -53,6 +51,7 @@
 #include "V3Hasher.h"
 #include "V3Os.h"
 #include "V3Parse.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Unroll.h"
 #include "V3Width.h"
 
diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp
index 16e7d612c..93ad86a9f 100644
--- a/src/V3Partition.cpp
+++ b/src/V3Partition.cpp
@@ -14,8 +14,6 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Partition.h"
 
 #include "V3Config.h"
@@ -27,6 +25,7 @@
 #include "V3Os.h"
 #include "V3PairingHeap.h"
 #include "V3PartitionGraph.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Scoreboard.h"
 #include "V3Stats.h"
 #include "V3UniqueNames.h"
diff --git a/src/V3PchAstMT.h b/src/V3PchAstMT.h
index 50590fd6a..af0c3b25a 100644
--- a/src/V3PchAstMT.h
+++ b/src/V3PchAstMT.h
@@ -24,8 +24,6 @@
 #include "config_build.h"
 #include "verilatedos.h"
 
-#include 
-
 #include "V3Ast.h"
 #include "V3Broken.h"
 #include "V3Error.h"
@@ -39,4 +37,6 @@
 #include "V3String.h"
 #include "V3ThreadSafety.h"
 
+#include 
+
 #endif  // Guard
diff --git a/src/V3PchAstNoMT.h b/src/V3PchAstNoMT.h
index 0ac7907a8..2ecde3fd5 100644
--- a/src/V3PchAstNoMT.h
+++ b/src/V3PchAstNoMT.h
@@ -26,10 +26,6 @@
 #include "config_build.h"
 #include "verilatedos.h"
 
-#include 
-#include 
-#include 
-
 #include "V3Ast.h"
 #include "V3Broken.h"
 #include "V3Error.h"
@@ -43,4 +39,8 @@
 #include "V3String.h"
 #include "V3ThreadSafety.h"
 
+#include 
+#include 
+#include 
+
 #endif  // Guard
diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp
index c6ebaacee..9a6858352 100644
--- a/src/V3Premit.cpp
+++ b/src/V3Premit.cpp
@@ -24,10 +24,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Premit.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 #include "V3UniqueNames.h"
 
diff --git a/src/V3ProtectLib.cpp b/src/V3ProtectLib.cpp
index 0fa0c4c2a..e85c70d84 100644
--- a/src/V3ProtectLib.cpp
+++ b/src/V3ProtectLib.cpp
@@ -14,11 +14,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3ProtectLib.h"
 
 #include "V3Hasher.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3String.h"
 #include "V3Task.h"
 
diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp
index 5c39b78d2..60cb72f0c 100644
--- a/src/V3Randomize.cpp
+++ b/src/V3Randomize.cpp
@@ -24,11 +24,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Randomize.h"
 
 #include "V3MemberMap.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3Reloop.cpp b/src/V3Reloop.cpp
index 55f07fe35..8dbc82dd8 100644
--- a/src/V3Reloop.cpp
+++ b/src/V3Reloop.cpp
@@ -29,10 +29,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Reloop.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Sched.cpp b/src/V3Sched.cpp
index a7012d151..2aa86bd2b 100644
--- a/src/V3Sched.cpp
+++ b/src/V3Sched.cpp
@@ -35,13 +35,12 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Sched.h"
 
 #include "V3EmitCBase.h"
 #include "V3EmitV.h"
 #include "V3Order.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3SenExprBuilder.h"
 #include "V3Stats.h"
 
diff --git a/src/V3SchedAcyclic.cpp b/src/V3SchedAcyclic.cpp
index f70022350..4df41bb9c 100644
--- a/src/V3SchedAcyclic.cpp
+++ b/src/V3SchedAcyclic.cpp
@@ -33,9 +33,8 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Graph.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Sched.h"
 #include "V3SenTree.h"
 #include "V3SplitVar.h"
diff --git a/src/V3SchedPartition.cpp b/src/V3SchedPartition.cpp
index a5cbfd3c9..b9c0619fa 100644
--- a/src/V3SchedPartition.cpp
+++ b/src/V3SchedPartition.cpp
@@ -34,10 +34,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3EmitV.h"
 #include "V3Graph.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Sched.h"
 
 #include 
diff --git a/src/V3SchedReplicate.cpp b/src/V3SchedReplicate.cpp
index 9ef1fcdb0..c37ae0c7d 100644
--- a/src/V3SchedReplicate.cpp
+++ b/src/V3SchedReplicate.cpp
@@ -34,9 +34,8 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Graph.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Sched.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp
index 56a89ed24..4c1523bd0 100644
--- a/src/V3SchedTiming.cpp
+++ b/src/V3SchedTiming.cpp
@@ -24,9 +24,8 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3EmitCBase.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Sched.h"
 
 #include 
diff --git a/src/V3Scope.cpp b/src/V3Scope.cpp
index 4f6efb93e..a5fb65652 100644
--- a/src/V3Scope.cpp
+++ b/src/V3Scope.cpp
@@ -21,10 +21,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Scope.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include 
 #include 
 
diff --git a/src/V3Scoreboard.cpp b/src/V3Scoreboard.cpp
index 1a26dbc2f..253b958cf 100644
--- a/src/V3Scoreboard.cpp
+++ b/src/V3Scoreboard.cpp
@@ -14,10 +14,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Scoreboard.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 class ScoreboardTestElem;
 
 struct Key {
diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp
index 0076094e0..b63e5b71a 100644
--- a/src/V3Slice.cpp
+++ b/src/V3Slice.cpp
@@ -35,10 +35,10 @@
 // simplified to look primarily for SLICESELs.
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Slice.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //*************************************************************************
diff --git a/src/V3Split.cpp b/src/V3Split.cpp
index c543aec1d..075259dd2 100644
--- a/src/V3Split.cpp
+++ b/src/V3Split.cpp
@@ -77,11 +77,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Split.h"
 
 #include "V3Graph.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3SplitAs.cpp b/src/V3SplitAs.cpp
index 26898c676..98699725d 100644
--- a/src/V3SplitAs.cpp
+++ b/src/V3SplitAs.cpp
@@ -21,10 +21,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3SplitAs.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp
index 8711f4bc6..01523c59b 100644
--- a/src/V3SplitVar.cpp
+++ b/src/V3SplitVar.cpp
@@ -110,10 +110,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3SplitVar.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 #include "V3UniqueNames.h"
 
diff --git a/src/V3Stats.cpp b/src/V3Stats.cpp
index 3f89004df..fca92184a 100644
--- a/src/V3Stats.cpp
+++ b/src/V3Stats.cpp
@@ -14,10 +14,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstMT.h"
-
 #include "V3Stats.h"
 
+#include "V3PchAstMT.h"
+
 // This visitor does not edit nodes, and is called at error-exit, so should use constant iterators
 #include "V3AstConstOnly.h"
 
diff --git a/src/V3StatsReport.cpp b/src/V3StatsReport.cpp
index a41f116d6..d24c4bb23 100644
--- a/src/V3StatsReport.cpp
+++ b/src/V3StatsReport.cpp
@@ -14,11 +14,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstMT.h"
-
 #include "V3File.h"
 #include "V3Global.h"
 #include "V3Os.h"
+#include "V3PchAstMT.h"
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3Subst.cpp b/src/V3Subst.cpp
index 7c2465dad..3a43b05a8 100644
--- a/src/V3Subst.cpp
+++ b/src/V3Subst.cpp
@@ -22,10 +22,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Subst.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3TSP.cpp b/src/V3TSP.cpp
index 583db4ab4..85c2c575d 100644
--- a/src/V3TSP.cpp
+++ b/src/V3TSP.cpp
@@ -19,12 +19,11 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3TSP.h"
 
 #include "V3File.h"
 #include "V3Graph.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 #include 
diff --git a/src/V3Table.cpp b/src/V3Table.cpp
index cfdc10717..30c0850db 100644
--- a/src/V3Table.cpp
+++ b/src/V3Table.cpp
@@ -21,10 +21,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Table.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Simulate.h"
 #include "V3Stats.h"
 
diff --git a/src/V3Task.cpp b/src/V3Task.cpp
index a410f06a6..ceeed9e00 100644
--- a/src/V3Task.cpp
+++ b/src/V3Task.cpp
@@ -23,14 +23,13 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Task.h"
 
 #include "V3Const.h"
 #include "V3EmitCBase.h"
 #include "V3Graph.h"
 #include "V3LinkLValue.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 
diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp
index 65948a526..a875d5dc3 100644
--- a/src/V3Timing.cpp
+++ b/src/V3Timing.cpp
@@ -60,14 +60,13 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Timing.h"
 
 #include "V3Const.h"
 #include "V3EmitV.h"
 #include "V3Graph.h"
 #include "V3MemberMap.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3SenExprBuilder.h"
 #include "V3SenTree.h"
 #include "V3UniqueNames.h"
diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp
index 653ba6548..36a4bb0e3 100644
--- a/src/V3Trace.cpp
+++ b/src/V3Trace.cpp
@@ -35,13 +35,12 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Trace.h"
 
 #include "V3DupFinder.h"
 #include "V3EmitCBase.h"
 #include "V3Graph.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp
index 284936660..7e287f5fe 100644
--- a/src/V3TraceDecl.cpp
+++ b/src/V3TraceDecl.cpp
@@ -20,14 +20,13 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3TraceDecl.h"
 
 #include "verilated_trace_defs.h"  // For VLT_TRACE_SCOPE_*
 
 #include "V3Config.h"
 #include "V3EmitCBase.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp
index a584d1748..84788265b 100644
--- a/src/V3Tristate.cpp
+++ b/src/V3Tristate.cpp
@@ -115,12 +115,11 @@
 // unsupported.
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Tristate.h"
 
 #include "V3Graph.h"
 #include "V3Inst.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Undriven.cpp b/src/V3Undriven.cpp
index 09d6e5043..2c2df44ff 100644
--- a/src/V3Undriven.cpp
+++ b/src/V3Undriven.cpp
@@ -23,10 +23,9 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Undriven.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp
index 625055393..3d429998e 100644
--- a/src/V3Unknown.cpp
+++ b/src/V3Unknown.cpp
@@ -28,11 +28,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Unknown.h"
 
 #include "V3Const.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 #include "V3UniqueNames.h"
 
diff --git a/src/V3Unroll.cpp b/src/V3Unroll.cpp
index f2a7af31b..3a5beea92 100644
--- a/src/V3Unroll.cpp
+++ b/src/V3Unroll.cpp
@@ -24,11 +24,10 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Unroll.h"
 
 #include "V3Const.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Simulate.h"
 #include "V3Stats.h"
 
diff --git a/src/V3VariableOrder.cpp b/src/V3VariableOrder.cpp
index 2fbea7c75..4275f5499 100644
--- a/src/V3VariableOrder.cpp
+++ b/src/V3VariableOrder.cpp
@@ -20,12 +20,11 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3VariableOrder.h"
 
 #include "V3AstUserAllocator.h"
 #include "V3EmitCBase.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3TSP.h"
 
 #include 
diff --git a/src/V3Width.cpp b/src/V3Width.cpp
index f5f9c85e8..533da7a26 100644
--- a/src/V3Width.cpp
+++ b/src/V3Width.cpp
@@ -63,13 +63,12 @@
 // iterateSubtreeReturnEdits.
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Width.h"
 
 #include "V3Const.h"
 #include "V3MemberMap.h"
 #include "V3Number.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Randomize.h"
 #include "V3String.h"
 #include "V3Task.h"
diff --git a/src/V3WidthCommit.cpp b/src/V3WidthCommit.cpp
index abfb20bab..16813f88a 100644
--- a/src/V3WidthCommit.cpp
+++ b/src/V3WidthCommit.cpp
@@ -20,13 +20,13 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "config_build.h"
 #include "verilatedos.h"
 
 #include "V3WidthCommit.h"
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp
index 8c8aa4bb4..f2c875738 100644
--- a/src/V3WidthSel.cpp
+++ b/src/V3WidthSel.cpp
@@ -26,9 +26,8 @@
 //
 //*************************************************************************
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 #include "V3Const.h"
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Width.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;

From 13989b965d259644303692db4127b0df10bf99f8 Mon Sep 17 00:00:00 2001
From: Wilson Snyder 
Date: Tue, 17 Oct 2023 20:50:40 -0400
Subject: [PATCH 084/157] Tests: Add --binary with split, to check parallel
 builds

---
 test_regress/t/t_flag_binary_parallel.pl | 30 ++++++++++++++++++++++++
 1 file changed, 30 insertions(+)
 create mode 100755 test_regress/t/t_flag_binary_parallel.pl

diff --git a/test_regress/t/t_flag_binary_parallel.pl b/test_regress/t/t_flag_binary_parallel.pl
new file mode 100755
index 000000000..0305abd74
--- /dev/null
+++ b/test_regress/t/t_flag_binary_parallel.pl
@@ -0,0 +1,30 @@
+#!/usr/bin/env perl
+if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
+# DESCRIPTION: Verilator: Verilog Test driver/expect definition
+#
+# Copyright 2019 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(simulator => 1);
+
+top_filename("t/t_flag_main.v");
+
+compile(
+    verilator_flags => [# Custom as don't want -cc
+                        "-Mdir $Self->{obj_dir}",
+                        "--debug-check", ],
+    verilator_flags2 => ['--binary', '--output-split 1'],
+    verilator_make_cmake => 0,
+    verilator_make_gmake => 0,
+    make_main => 0,
+    );
+
+execute(
+    check_finished => 1,
+    );
+
+ok(1);
+1;

From 3914176bc4cef5279e2bf822b9642b4fd5373feb Mon Sep 17 00:00:00 2001
From: Wilson Snyder 
Date: Wed, 18 Oct 2023 06:06:00 -0400
Subject: [PATCH 085/157] Internals: Remove unused IGNORED to fix MSVC warning.
 No functional change intended.

---
 src/verilog.l | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/src/verilog.l b/src/verilog.l
index 102a43195..8bb6c07bd 100644
--- a/src/verilog.l
+++ b/src/verilog.l
@@ -82,7 +82,6 @@ static double lexParseDouble(FileLine* fl, const char* textp, size_t length) {
 %s ATTRMODE QQQ STRING TABLE
 %s VA5 SAX VLT
 %s SYSCHDR SYSCINT SYSCIMP SYSCIMPH SYSCCTOR SYSCDTOR
-%s IGNORE
 
 ws      [ \t\f\r]+
 wsnr    [ \t\f]+
@@ -1010,7 +1009,7 @@ vnum    {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
   /* Common for all SYSC header states */
   /* OPTIMIZE: we return one per line, make it one for the entire block */
   /* If add to this list also add to V3LanguageWords.h */
-{
+{
   "`accelerate"                         { FL_FWD; FL_BRK; }  // Verilog-XL compatibility
   "`autoexpand_vectornets"              { FL_FWD; FL_BRK; }  // Verilog-XL compatibility
   "`celldefine"                         { FL_FWD; PARSEP->lexFileline()->celldefineOn(true); FL_BRK; }
@@ -1097,10 +1096,9 @@ vnum    {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
 [ \t]*[^` \t\n\r][^\n\r]*{crnl}       { FL; yylval.strp = PARSEP->newString(yytext); return yaSCIMPH; }
 [ \t]*[^` \t\n\r][^\n\r]*{crnl}       { FL; yylval.strp = PARSEP->newString(yytext); return yaSCCTOR; }
 [ \t]*[^` \t\n\r][^\n\r]*{crnl}       { FL; yylval.strp = PARSEP->newString(yytext); return yaSCDTOR; }
-[ \t]*[^` \t\n\r][^\n\r]*{crnl}         { FL_FWD; FL_BRK; }
 
   /* Pick up text-type data */
-{
+{
   {wsnr}*               { yymore(); }
   {crnl}                { yymore(); }
 }

From 28625451dd2d5160f8fd121d72b9af593a381ca6 Mon Sep 17 00:00:00 2001
From: Wilson Snyder 
Date: Wed, 18 Oct 2023 06:07:05 -0400
Subject: [PATCH 086/157] Fix MSVC makefile list (part of previous commit)

---
 src/CMakeLists.txt | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index b2fbf9f4d..a4b3fed12 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -44,9 +44,10 @@ set(HEADERS
     V3Begin.h
     V3Branch.h
     V3Broken.h
+    V3CCtors.h
+    V3CUse.h
     V3Case.h
     V3Cast.h
-    V3CCtors.h
     V3Class.h
     V3Clean.h
     V3Clock.h
@@ -56,7 +57,6 @@ set(HEADERS
     V3Const.h
     V3Coverage.h
     V3CoverageJoin.h
-    V3CUse.h
     V3Dead.h
     V3Delayed.h
     V3Depth.h
@@ -105,8 +105,8 @@ set(HEADERS
     V3LinkDot.h
     V3LinkInc.h
     V3LinkJump.h
-    V3LinkLevel.h
     V3LinkLValue.h
+    V3LinkLevel.h
     V3LinkParse.h
     V3LinkResolve.h
     V3List.h
@@ -127,10 +127,12 @@ set(HEADERS
     V3ParseSym.h
     V3Partition.h
     V3PartitionGraph.h
+    V3PchAstMT.h
+    V3PchAstNoMT.h
     V3PreLex.h
-    V3Premit.h
     V3PreProc.h
     V3PreShell.h
+    V3Premit.h
     V3ProtectLib.h
     V3Randomize.h
     V3Reloop.h
@@ -149,6 +151,7 @@ set(HEADERS
     V3String.h
     V3Subst.h
     V3SymTable.h
+    V3TSP.h
     V3Table.h
     V3Task.h
     V3ThreadPool.h
@@ -157,7 +160,6 @@ set(HEADERS
     V3Trace.h
     V3TraceDecl.h
     V3Tristate.h
-    V3TSP.h
     V3Undriven.h
     V3UniqueNames.h
     V3Unknown.h

From 51a18225adc6270701ce2be361e45ed3a8ff86db Mon Sep 17 00:00:00 2001
From: Wilson Snyder 
Date: Wed, 18 Oct 2023 06:37:38 -0400
Subject: [PATCH 087/157] cmake: Fix missing headers

---
 src/CMakeLists.txt | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a4b3fed12..f31871b65 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -111,7 +111,10 @@ set(HEADERS
     V3LinkResolve.h
     V3List.h
     V3Localize.h
+    V3MemberMap.h
     V3MergeCond.h
+    V3Mutex.h
+    V3Name.h
     V3Name.h
     V3Number.h
     V3OptionParser.h
@@ -136,6 +139,7 @@ set(HEADERS
     V3ProtectLib.h
     V3Randomize.h
     V3Reloop.h
+    V3Rtti.h
     V3Sched.h
     V3Scope.h
     V3Scoreboard.h

From b5828a7ce990de997aca40a573ef13cf05b9488a Mon Sep 17 00:00:00 2001
From: Wilson Snyder 
Date: Wed, 18 Oct 2023 06:37:46 -0400
Subject: [PATCH 088/157] Fix header order botched by clang-format in recent
 commit.

---
 .clang-format              | 2 ++
 src/V3Active.cpp           | 3 ++-
 src/V3ActiveTop.cpp        | 3 ++-
 src/V3Assert.cpp           | 3 ++-
 src/V3AssertPre.cpp        | 3 ++-
 src/V3Ast.cpp              | 3 ++-
 src/V3AstNodes.cpp         | 6 +-----
 src/V3Begin.cpp            | 4 ++--
 src/V3Branch.cpp           | 4 ++--
 src/V3Broken.cpp           | 4 ++--
 src/V3CCtors.cpp           | 3 ++-
 src/V3CUse.cpp             | 4 ++--
 src/V3Case.cpp             | 3 ++-
 src/V3Cast.cpp             | 4 ++--
 src/V3Class.cpp            | 3 ++-
 src/V3Clean.cpp            | 4 ++--
 src/V3Clock.cpp            | 3 ++-
 src/V3Combine.cpp          | 3 ++-
 src/V3Common.cpp           | 3 ++-
 src/V3Config.cpp           | 3 ++-
 src/V3Coverage.cpp         | 4 ++--
 src/V3CoverageJoin.cpp     | 3 ++-
 src/V3Dead.cpp             | 4 ++--
 src/V3Delayed.cpp          | 3 ++-
 src/V3Depth.cpp            | 3 ++-
 src/V3DepthBlock.cpp       | 3 ++-
 src/V3Descope.cpp          | 3 ++-
 src/V3Dfg.cpp              | 3 ++-
 src/V3DfgAstToDfg.cpp      | 3 ++-
 src/V3DfgDecomposition.cpp | 3 ++-
 src/V3DfgDfgToAst.cpp      | 3 ++-
 src/V3DfgOptimizer.cpp     | 3 ++-
 src/V3DfgPasses.cpp        | 3 ++-
 src/V3DfgPeephole.cpp      | 3 ++-
 src/V3DupFinder.cpp        | 3 ++-
 src/V3EmitCBase.cpp        | 3 ++-
 src/V3EmitCConstPool.cpp   | 3 ++-
 src/V3EmitCFunc.cpp        | 3 ++-
 src/V3EmitCHeaders.cpp     | 3 ++-
 src/V3EmitCImp.cpp         | 3 ++-
 src/V3EmitCInlines.cpp     | 3 ++-
 src/V3EmitCMain.cpp        | 3 ++-
 src/V3EmitCMake.cpp        | 3 ++-
 src/V3EmitCModel.cpp       | 3 ++-
 src/V3EmitCSyms.cpp        | 3 ++-
 src/V3EmitMk.cpp           | 3 ++-
 src/V3EmitV.cpp            | 3 ++-
 src/V3EmitXml.cpp          | 3 ++-
 src/V3Expand.cpp           | 3 ++-
 src/V3File.cpp             | 3 ++-
 src/V3Force.cpp            | 3 ++-
 src/V3Fork.cpp             | 3 ++-
 src/V3Gate.cpp             | 3 ++-
 src/V3Global.cpp           | 3 ++-
 src/V3Hasher.cpp           | 4 ++--
 src/V3HierBlock.cpp        | 3 ++-
 src/V3Inline.cpp           | 3 ++-
 src/V3Inst.cpp             | 3 ++-
 src/V3InstrCount.cpp       | 4 ++--
 src/V3Interface.cpp        | 4 ++--
 src/V3Life.cpp             | 3 ++-
 src/V3LifePost.cpp         | 3 ++-
 src/V3LinkCells.cpp        | 3 ++-
 src/V3LinkDot.cpp          | 3 ++-
 src/V3LinkInc.cpp          | 4 ++--
 src/V3LinkJump.cpp         | 3 ++-
 src/V3LinkLValue.cpp       | 4 ++--
 src/V3LinkLevel.cpp        | 4 ++--
 src/V3LinkParse.cpp        | 3 ++-
 src/V3LinkResolve.cpp      | 3 ++-
 src/V3Localize.cpp         | 3 ++-
 src/V3MergeCond.cpp        | 3 ++-
 src/V3Name.cpp             | 3 ++-
 src/V3Number.cpp           | 4 ++--
 src/V3Options.cpp          | 3 ++-
 src/V3Order.cpp            | 3 ++-
 src/V3Param.cpp            | 3 ++-
 src/V3Partition.cpp        | 3 ++-
 src/V3Premit.cpp           | 3 ++-
 src/V3ProtectLib.cpp       | 3 ++-
 src/V3Randomize.cpp        | 3 ++-
 src/V3Reloop.cpp           | 3 ++-
 src/V3Sched.cpp            | 3 ++-
 src/V3SchedAcyclic.cpp     | 3 ++-
 src/V3SchedPartition.cpp   | 3 ++-
 src/V3SchedReplicate.cpp   | 3 ++-
 src/V3SchedTiming.cpp      | 3 ++-
 src/V3Scope.cpp            | 4 ++--
 src/V3Scoreboard.cpp       | 4 ++--
 src/V3Slice.cpp            | 4 ++--
 src/V3Split.cpp            | 3 ++-
 src/V3SplitAs.cpp          | 3 ++-
 src/V3SplitVar.cpp         | 3 ++-
 src/V3Stats.cpp            | 4 ++--
 src/V3StatsReport.cpp      | 3 ++-
 src/V3Subst.cpp            | 3 ++-
 src/V3TSP.cpp              | 3 ++-
 src/V3Table.cpp            | 3 ++-
 src/V3Task.cpp             | 3 ++-
 src/V3Timing.cpp           | 3 ++-
 src/V3Trace.cpp            | 3 ++-
 src/V3TraceDecl.cpp        | 3 ++-
 src/V3Tristate.cpp         | 3 ++-
 src/V3Undriven.cpp         | 3 ++-
 src/V3Unknown.cpp          | 3 ++-
 src/V3Unroll.cpp           | 3 ++-
 src/V3VariableOrder.cpp    | 3 ++-
 src/V3Width.cpp            | 3 ++-
 src/V3WidthCommit.cpp      | 4 ++--
 src/V3WidthSel.cpp         | 3 ++-
 110 files changed, 219 insertions(+), 133 deletions(-)

diff --git a/.clang-format b/.clang-format
index 3e8142bf7..8178613b6 100644
--- a/.clang-format
+++ b/.clang-format
@@ -63,6 +63,8 @@ ForEachMacros:
 SortIncludes:    true
 IncludeBlocks:   Regroup
 IncludeCategories:
+  - Regex:           '"V3Pch.*\.h"'
+    Priority:        -2 # Precompiled headers
   - Regex:           '"(config_build|verilated_config|verilatedos)\.h"'
     Priority:        -1 # Sepecials before main header
   - Regex:           '(<|")verilated.*'
diff --git a/src/V3Active.cpp b/src/V3Active.cpp
index a49d9f0d9..4930b9293 100644
--- a/src/V3Active.cpp
+++ b/src/V3Active.cpp
@@ -26,11 +26,12 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Active.h"
 
 #include "V3Const.h"
 #include "V3Graph.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 
diff --git a/src/V3ActiveTop.cpp b/src/V3ActiveTop.cpp
index b3e74bc17..4239525b9 100644
--- a/src/V3ActiveTop.cpp
+++ b/src/V3ActiveTop.cpp
@@ -23,10 +23,11 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3ActiveTop.h"
 
 #include "V3Const.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3SenTree.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp
index bab7e8a7a..3f8278e5b 100644
--- a/src/V3Assert.cpp
+++ b/src/V3Assert.cpp
@@ -14,9 +14,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Assert.h"
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp
index 263fccf74..d0689361f 100644
--- a/src/V3AssertPre.cpp
+++ b/src/V3AssertPre.cpp
@@ -19,10 +19,11 @@
 //      Transform clocking blocks into imperative logic
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3AssertPre.h"
 
 #include "V3Const.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Task.h"
 #include "V3UniqueNames.h"
 
diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp
index 6c14af667..f7441655c 100644
--- a/src/V3Ast.cpp
+++ b/src/V3Ast.cpp
@@ -14,10 +14,11 @@
 //
 //*************************************************************************
 
+#include "V3PchAstMT.h"
+
 #include "V3Broken.h"
 #include "V3EmitV.h"
 #include "V3File.h"
-#include "V3PchAstMT.h"
 
 #include 
 #include 
diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp
index 48e054209..5af783789 100644
--- a/src/V3AstNodes.cpp
+++ b/src/V3AstNodes.cpp
@@ -14,17 +14,13 @@
 //
 //*************************************************************************
 
-#include "config_build.h"
-#include "verilatedos.h"
+#include "V3PchAstMT.h"
 
-#include "V3Ast.h"
 #include "V3EmitCBase.h"
 #include "V3File.h"
-#include "V3Global.h"
 #include "V3Graph.h"
 #include "V3Hasher.h"
 #include "V3PartitionGraph.h"  // Just for mtask dumping
-#include "V3PchAstMT.h"
 #include "V3String.h"
 
 #include "V3Ast__gen_macros.h"  // Generated by 'astgen'
diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp
index 5c7b9282c..b4fa16a24 100644
--- a/src/V3Begin.cpp
+++ b/src/V3Begin.cpp
@@ -26,10 +26,10 @@
 //
 //*************************************************************************
 
-#include "V3Begin.h"
-
 #include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
+#include "V3Begin.h"
+
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3Branch.cpp b/src/V3Branch.cpp
index f57d980c5..e297f59a9 100644
--- a/src/V3Branch.cpp
+++ b/src/V3Branch.cpp
@@ -23,10 +23,10 @@
 //
 //*************************************************************************
 
-#include "V3Branch.h"
-
 #include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
+#include "V3Branch.h"
+
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3Broken.cpp b/src/V3Broken.cpp
index 7f861c694..9ae17efb9 100644
--- a/src/V3Broken.cpp
+++ b/src/V3Broken.cpp
@@ -22,10 +22,10 @@
 //
 //*************************************************************************
 
-#include "V3Broken.h"
-
 #include "V3PchAstMT.h"
 
+#include "V3Broken.h"
+
 // This visitor does not edit nodes, and is called at error-exit, so should use constant iterators
 #include "V3AstConstOnly.h"
 
diff --git a/src/V3CCtors.cpp b/src/V3CCtors.cpp
index 2c4eaa09d..1f8abb5c3 100644
--- a/src/V3CCtors.cpp
+++ b/src/V3CCtors.cpp
@@ -24,10 +24,11 @@
 //      This transformation honors outputSplitCFuncs.
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3CCtors.h"
 
 #include "V3EmitCBase.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 
diff --git a/src/V3CUse.cpp b/src/V3CUse.cpp
index 5f6c77a68..748909c2e 100644
--- a/src/V3CUse.cpp
+++ b/src/V3CUse.cpp
@@ -22,10 +22,10 @@
 //
 //*************************************************************************
 
-#include "V3CUse.h"
-
 #include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
+#include "V3CUse.h"
+
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3Case.cpp b/src/V3Case.cpp
index 8e44063c7..89458cda8 100644
--- a/src/V3Case.cpp
+++ b/src/V3Case.cpp
@@ -34,9 +34,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Case.h"
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Cast.cpp b/src/V3Cast.cpp
index edd77577b..0290c944e 100644
--- a/src/V3Cast.cpp
+++ b/src/V3Cast.cpp
@@ -37,10 +37,10 @@
 //
 //*************************************************************************
 
-#include "V3Cast.h"
-
 #include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
+#include "V3Cast.h"
+
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3Class.cpp b/src/V3Class.cpp
index 0712ae11f..ef0eddf9b 100644
--- a/src/V3Class.cpp
+++ b/src/V3Class.cpp
@@ -20,9 +20,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Class.h"
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3UniqueNames.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Clean.cpp b/src/V3Clean.cpp
index cf175572b..00ddad214 100644
--- a/src/V3Clean.cpp
+++ b/src/V3Clean.cpp
@@ -23,10 +23,10 @@
 //
 //*************************************************************************
 
-#include "V3Clean.h"
-
 #include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
+#include "V3Clean.h"
+
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3Clock.cpp b/src/V3Clock.cpp
index 4e642fc39..98596e135 100644
--- a/src/V3Clock.cpp
+++ b/src/V3Clock.cpp
@@ -27,9 +27,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Clock.h"
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Sched.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Combine.cpp b/src/V3Combine.cpp
index 0d73f7b29..2b858de6c 100644
--- a/src/V3Combine.cpp
+++ b/src/V3Combine.cpp
@@ -19,11 +19,12 @@
 //      Also drop empty CFuncs
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Combine.h"
 
 #include "V3AstUserAllocator.h"
 #include "V3DupFinder.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3Common.cpp b/src/V3Common.cpp
index 210d4c47c..6288ccea9 100644
--- a/src/V3Common.cpp
+++ b/src/V3Common.cpp
@@ -20,10 +20,11 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Common.h"
 
 #include "V3EmitCBase.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3Config.cpp b/src/V3Config.cpp
index 0ca224128..566021160 100644
--- a/src/V3Config.cpp
+++ b/src/V3Config.cpp
@@ -14,9 +14,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstMT.h"
+
 #include "V3Config.h"
 
-#include "V3PchAstMT.h"
 #include "V3String.h"
 
 #include 
diff --git a/src/V3Coverage.cpp b/src/V3Coverage.cpp
index 55fa334ab..4d04e00cc 100644
--- a/src/V3Coverage.cpp
+++ b/src/V3Coverage.cpp
@@ -24,10 +24,10 @@
 //
 //*************************************************************************
 
-#include "V3Coverage.h"
-
 #include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
+#include "V3Coverage.h"
+
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3CoverageJoin.cpp b/src/V3CoverageJoin.cpp
index 6fe7cc7ed..76f0e7bdf 100644
--- a/src/V3CoverageJoin.cpp
+++ b/src/V3CoverageJoin.cpp
@@ -17,10 +17,11 @@
 //      If two COVERTOGGLEs have same VARSCOPE, combine them
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3CoverageJoin.h"
 
 #include "V3DupFinder.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp
index a4ab80abc..768887b5f 100644
--- a/src/V3Dead.cpp
+++ b/src/V3Dead.cpp
@@ -33,10 +33,10 @@
 // here after scoping to allow more dead node removal.
 //*************************************************************************
 
-#include "V3Dead.h"
-
 #include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
+#include "V3Dead.h"
+
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp
index 7041da397..3a829d22d 100644
--- a/src/V3Delayed.cpp
+++ b/src/V3Delayed.cpp
@@ -48,9 +48,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Delayed.h"
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3Depth.cpp b/src/V3Depth.cpp
index 66aa89349..a459a26c7 100644
--- a/src/V3Depth.cpp
+++ b/src/V3Depth.cpp
@@ -23,9 +23,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Depth.h"
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3UniqueNames.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3DepthBlock.cpp b/src/V3DepthBlock.cpp
index 3ea035bfe..378f83d0c 100644
--- a/src/V3DepthBlock.cpp
+++ b/src/V3DepthBlock.cpp
@@ -20,10 +20,11 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3DepthBlock.h"
 
 #include "V3EmitCBase.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3Descope.cpp b/src/V3Descope.cpp
index 4576cabe0..c603204f0 100644
--- a/src/V3Descope.cpp
+++ b/src/V3Descope.cpp
@@ -22,10 +22,11 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Descope.h"
 
 #include "V3EmitCBase.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3Dfg.cpp b/src/V3Dfg.cpp
index ff6da033c..9cda7d02a 100644
--- a/src/V3Dfg.cpp
+++ b/src/V3Dfg.cpp
@@ -14,10 +14,11 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Dfg.h"
 
 #include "V3File.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3DfgAstToDfg.cpp b/src/V3DfgAstToDfg.cpp
index 3cf450615..3b23986ff 100644
--- a/src/V3DfgAstToDfg.cpp
+++ b/src/V3DfgAstToDfg.cpp
@@ -26,9 +26,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Dfg.h"
 #include "V3DfgPasses.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3DfgDecomposition.cpp b/src/V3DfgDecomposition.cpp
index 3a0e41ee9..200d12610 100644
--- a/src/V3DfgDecomposition.cpp
+++ b/src/V3DfgDecomposition.cpp
@@ -18,9 +18,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Dfg.h"
 #include "V3File.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 #include 
diff --git a/src/V3DfgDfgToAst.cpp b/src/V3DfgDfgToAst.cpp
index 056d747ad..a5d0a14a9 100644
--- a/src/V3DfgDfgToAst.cpp
+++ b/src/V3DfgDfgToAst.cpp
@@ -26,9 +26,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Dfg.h"
 #include "V3DfgPasses.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3UniqueNames.h"
 
 #include 
diff --git a/src/V3DfgOptimizer.cpp b/src/V3DfgOptimizer.cpp
index 53cb79546..ea49de41e 100644
--- a/src/V3DfgOptimizer.cpp
+++ b/src/V3DfgOptimizer.cpp
@@ -18,13 +18,14 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3DfgOptimizer.h"
 
 #include "V3AstUserAllocator.h"
 #include "V3Dfg.h"
 #include "V3DfgPasses.h"
 #include "V3Graph.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3UniqueNames.h"
 
 #include 
diff --git a/src/V3DfgPasses.cpp b/src/V3DfgPasses.cpp
index 2616d5df0..f65b77897 100644
--- a/src/V3DfgPasses.cpp
+++ b/src/V3DfgPasses.cpp
@@ -14,11 +14,12 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3DfgPasses.h"
 
 #include "V3Dfg.h"
 #include "V3Global.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3String.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3DfgPeephole.cpp b/src/V3DfgPeephole.cpp
index 206505a07..f162c9ec9 100644
--- a/src/V3DfgPeephole.cpp
+++ b/src/V3DfgPeephole.cpp
@@ -21,11 +21,12 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3DfgPeephole.h"
 
 #include "V3Dfg.h"
 #include "V3DfgPasses.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3DupFinder.cpp b/src/V3DupFinder.cpp
index e81092c3a..58a889931 100644
--- a/src/V3DupFinder.cpp
+++ b/src/V3DupFinder.cpp
@@ -14,10 +14,11 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3DupFinder.h"
 
 #include "V3File.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 #include 
diff --git a/src/V3EmitCBase.cpp b/src/V3EmitCBase.cpp
index bb6e09ad2..c382554c4 100644
--- a/src/V3EmitCBase.cpp
+++ b/src/V3EmitCBase.cpp
@@ -14,9 +14,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstMT.h"
+
 #include "V3EmitCBase.h"
 
-#include "V3PchAstMT.h"
 #include "V3Task.h"
 
 //######################################################################
diff --git a/src/V3EmitCConstPool.cpp b/src/V3EmitCConstPool.cpp
index cabd546f6..656bffcd8 100644
--- a/src/V3EmitCConstPool.cpp
+++ b/src/V3EmitCConstPool.cpp
@@ -14,10 +14,11 @@
 //
 //*************************************************************************
 
+#include "V3PchAstMT.h"
+
 #include "V3EmitC.h"
 #include "V3EmitCConstInit.h"
 #include "V3File.h"
-#include "V3PchAstMT.h"
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3EmitCFunc.cpp b/src/V3EmitCFunc.cpp
index b033a4ccf..461d6496e 100644
--- a/src/V3EmitCFunc.cpp
+++ b/src/V3EmitCFunc.cpp
@@ -14,9 +14,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstMT.h"
+
 #include "V3EmitCFunc.h"
 
-#include "V3PchAstMT.h"
 #include "V3TSP.h"
 
 #include 
diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp
index 2861df5ad..8d9f71c8d 100644
--- a/src/V3EmitCHeaders.cpp
+++ b/src/V3EmitCHeaders.cpp
@@ -14,9 +14,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstMT.h"
+
 #include "V3EmitC.h"
 #include "V3EmitCConstInit.h"
-#include "V3PchAstMT.h"
 
 #include 
 #include 
diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp
index 34ec4ee16..e640634c9 100644
--- a/src/V3EmitCImp.cpp
+++ b/src/V3EmitCImp.cpp
@@ -14,9 +14,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstMT.h"
+
 #include "V3EmitC.h"
 #include "V3EmitCFunc.h"
-#include "V3PchAstMT.h"
 #include "V3ThreadPool.h"
 #include "V3UniqueNames.h"
 
diff --git a/src/V3EmitCInlines.cpp b/src/V3EmitCInlines.cpp
index 64070760a..6425a367c 100644
--- a/src/V3EmitCInlines.cpp
+++ b/src/V3EmitCInlines.cpp
@@ -14,9 +14,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstMT.h"
+
 #include "V3EmitC.h"
 #include "V3EmitCBase.h"
-#include "V3PchAstMT.h"
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3EmitCMain.cpp b/src/V3EmitCMain.cpp
index 67a9424e1..4a9f9c496 100644
--- a/src/V3EmitCMain.cpp
+++ b/src/V3EmitCMain.cpp
@@ -14,11 +14,12 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3EmitCMain.h"
 
 #include "V3EmitC.h"
 #include "V3EmitCBase.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 
diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp
index 666a5f8d5..ca548d68b 100644
--- a/src/V3EmitCMake.cpp
+++ b/src/V3EmitCMake.cpp
@@ -14,12 +14,13 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3EmitCMake.h"
 
 #include "V3EmitCBase.h"
 #include "V3HierBlock.h"
 #include "V3Os.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 
diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp
index e025154eb..53c5339fb 100644
--- a/src/V3EmitCModel.cpp
+++ b/src/V3EmitCModel.cpp
@@ -14,9 +14,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3EmitC.h"
 #include "V3EmitCFunc.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3UniqueNames.h"
 
 #include 
diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp
index 1f3f9e80d..4642ac016 100644
--- a/src/V3EmitCSyms.cpp
+++ b/src/V3EmitCSyms.cpp
@@ -14,11 +14,12 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3EmitC.h"
 #include "V3EmitCBase.h"
 #include "V3LanguageWords.h"
 #include "V3PartitionGraph.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 #include 
diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp
index d39cadee8..e55ff26f5 100644
--- a/src/V3EmitMk.cpp
+++ b/src/V3EmitMk.cpp
@@ -14,12 +14,13 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3EmitMk.h"
 
 #include "V3EmitCBase.h"
 #include "V3HierBlock.h"
 #include "V3Os.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp
index 3a272fa9c..38bca92ba 100644
--- a/src/V3EmitV.cpp
+++ b/src/V3EmitV.cpp
@@ -14,10 +14,11 @@
 //
 //*************************************************************************
 
+#include "V3PchAstMT.h"
+
 #include "V3EmitV.h"
 
 #include "V3EmitCBase.h"
-#include "V3PchAstMT.h"
 
 #include 
 
diff --git a/src/V3EmitXml.cpp b/src/V3EmitXml.cpp
index 62db4f1c0..d2cb7d621 100644
--- a/src/V3EmitXml.cpp
+++ b/src/V3EmitXml.cpp
@@ -14,10 +14,11 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3EmitXml.h"
 
 #include "V3EmitCBase.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 #include 
diff --git a/src/V3Expand.cpp b/src/V3Expand.cpp
index 4cee48560..af67ad82e 100644
--- a/src/V3Expand.cpp
+++ b/src/V3Expand.cpp
@@ -25,10 +25,11 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Expand.h"
 
 #include "V3Const.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3File.cpp b/src/V3File.cpp
index c1fd8e59e..97a26d572 100644
--- a/src/V3File.cpp
+++ b/src/V3File.cpp
@@ -14,10 +14,11 @@
 //
 //*************************************************************************
 
+#include "V3PchAstMT.h"
+
 #include "V3File.h"
 
 #include "V3Os.h"
-#include "V3PchAstMT.h"
 #include "V3String.h"
 
 #include 
diff --git a/src/V3Force.cpp b/src/V3Force.cpp
index af464e333..93a3d4a08 100644
--- a/src/V3Force.cpp
+++ b/src/V3Force.cpp
@@ -37,10 +37,11 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Force.h"
 
 #include "V3AstUserAllocator.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3Fork.cpp b/src/V3Fork.cpp
index 545605226..098104d11 100644
--- a/src/V3Fork.cpp
+++ b/src/V3Fork.cpp
@@ -38,11 +38,12 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Fork.h"
 
 #include "V3AstNodeExpr.h"
 #include "V3MemberMap.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 #include 
diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp
index 756d78625..0f0bb61cc 100644
--- a/src/V3Gate.cpp
+++ b/src/V3Gate.cpp
@@ -21,13 +21,14 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Gate.h"
 
 #include "V3AstUserAllocator.h"
 #include "V3Const.h"
 #include "V3DupFinder.h"
 #include "V3Graph.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3Global.cpp b/src/V3Global.cpp
index 4013f3097..f4ebc182a 100644
--- a/src/V3Global.cpp
+++ b/src/V3Global.cpp
@@ -14,12 +14,13 @@
 //
 //*************************************************************************
 
+#include "V3PchAstMT.h"
+
 #include "V3File.h"
 #include "V3HierBlock.h"
 #include "V3LinkCells.h"
 #include "V3Parse.h"
 #include "V3ParseSym.h"
-#include "V3PchAstMT.h"
 #include "V3Stats.h"
 
 //######################################################################
diff --git a/src/V3Hasher.cpp b/src/V3Hasher.cpp
index b9201c628..e58dce546 100644
--- a/src/V3Hasher.cpp
+++ b/src/V3Hasher.cpp
@@ -14,10 +14,10 @@
 //
 //*************************************************************************
 
-#include "V3Hasher.h"
-
 #include "V3PchAstMT.h"
 
+#include "V3Hasher.h"
+
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3HierBlock.cpp b/src/V3HierBlock.cpp
index 4e5371288..f1624493b 100644
--- a/src/V3HierBlock.cpp
+++ b/src/V3HierBlock.cpp
@@ -72,11 +72,12 @@
 //       Used for b) and c).
 //       This options is repeated for all instantiating hierarchical blocks.
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3HierBlock.h"
 
 #include "V3File.h"
 #include "V3Os.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 #include "V3String.h"
 
diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp
index afaf26507..dbc3e7bb9 100644
--- a/src/V3Inline.cpp
+++ b/src/V3Inline.cpp
@@ -24,11 +24,12 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Inline.h"
 
 #include "V3AstUserAllocator.h"
 #include "V3Inst.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp
index 80c385968..fa5b2da3c 100644
--- a/src/V3Inst.cpp
+++ b/src/V3Inst.cpp
@@ -21,10 +21,11 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Inst.h"
 
 #include "V3Const.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3InstrCount.cpp b/src/V3InstrCount.cpp
index 23353c9b3..95bbdaa06 100644
--- a/src/V3InstrCount.cpp
+++ b/src/V3InstrCount.cpp
@@ -15,10 +15,10 @@
 //
 //*************************************************************************
 
-#include "V3InstrCount.h"
-
 #include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
+#include "V3InstrCount.h"
+
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Interface.cpp b/src/V3Interface.cpp
index 63644c598..de504d25c 100644
--- a/src/V3Interface.cpp
+++ b/src/V3Interface.cpp
@@ -23,10 +23,10 @@
 //
 //*************************************************************************
 
-#include "V3Interface.h"
-
 #include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
+#include "V3Interface.h"
+
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3Life.cpp b/src/V3Life.cpp
index 49e6d0f3b..84ee05d60 100644
--- a/src/V3Life.cpp
+++ b/src/V3Life.cpp
@@ -23,10 +23,11 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Life.h"
 
 #include "V3Const.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3LifePost.cpp b/src/V3LifePost.cpp
index e908a8a8a..6692a3ebf 100644
--- a/src/V3LifePost.cpp
+++ b/src/V3LifePost.cpp
@@ -24,11 +24,12 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3LifePost.h"
 
 #include "V3GraphPathChecker.h"
 #include "V3PartitionGraph.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include   // for std::unique_ptr -> auto_ptr or unique_ptr
diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp
index 570b1d3ed..14bcfee31 100644
--- a/src/V3LinkCells.cpp
+++ b/src/V3LinkCells.cpp
@@ -23,11 +23,12 @@
 //              Link to module that instantiates it
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3LinkCells.h"
 
 #include "V3Graph.h"
 #include "V3Parse.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3SymTable.h"
 
 #include 
diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp
index 490ca4d71..473545166 100644
--- a/src/V3LinkDot.cpp
+++ b/src/V3LinkDot.cpp
@@ -61,11 +61,12 @@
 //      b          (VSymEnt->AstCell)
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3LinkDot.h"
 
 #include "V3Graph.h"
 #include "V3MemberMap.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3String.h"
 #include "V3SymTable.h"
 
diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp
index 79f31bb48..d4a00861c 100644
--- a/src/V3LinkInc.cpp
+++ b/src/V3LinkInc.cpp
@@ -36,10 +36,10 @@
 //
 //*************************************************************************
 
-#include "V3LinkInc.h"
-
 #include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
+#include "V3LinkInc.h"
+
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp
index 7a62c06f9..e777ac164 100644
--- a/src/V3LinkJump.cpp
+++ b/src/V3LinkJump.cpp
@@ -29,10 +29,11 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3LinkJump.h"
 
 #include "V3AstUserAllocator.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 
diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp
index 5972b535c..11a1e4499 100644
--- a/src/V3LinkLValue.cpp
+++ b/src/V3LinkLValue.cpp
@@ -18,10 +18,10 @@
 //          Set lvalue() attributes on appropriate VARREFs.
 //*************************************************************************
 
-#include "V3LinkLValue.h"
-
 #include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
+#include "V3LinkLValue.h"
+
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp
index dea26b2f2..9c0500239 100644
--- a/src/V3LinkLevel.cpp
+++ b/src/V3LinkLevel.cpp
@@ -19,10 +19,10 @@
 //          Create new MODULE TOP with connections to below signals
 //*************************************************************************
 
-#include "V3LinkLevel.h"
-
 #include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
+#include "V3LinkLevel.h"
+
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp
index aa1cc7d82..b3371c2a3 100644
--- a/src/V3LinkParse.cpp
+++ b/src/V3LinkParse.cpp
@@ -18,10 +18,11 @@
 //          Move some attributes around
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3LinkParse.h"
 
 #include "V3Config.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 #include 
diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp
index ba1eeaa06..b0636a298 100644
--- a/src/V3LinkResolve.cpp
+++ b/src/V3LinkResolve.cpp
@@ -24,9 +24,10 @@
 //          SenItems: Convert pos/negedge of non-simple signals to temporaries
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3LinkResolve.h"
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3String.h"
 #include "V3Task.h"
 
diff --git a/src/V3Localize.cpp b/src/V3Localize.cpp
index aebd9f23c..d26a86175 100644
--- a/src/V3Localize.cpp
+++ b/src/V3Localize.cpp
@@ -22,10 +22,11 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Localize.h"
 
 #include "V3AstUserAllocator.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3MergeCond.cpp b/src/V3MergeCond.cpp
index aab950d34..b9e08ea22 100644
--- a/src/V3MergeCond.cpp
+++ b/src/V3MergeCond.cpp
@@ -72,12 +72,13 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3MergeCond.h"
 
 #include "V3AstUserAllocator.h"
 #include "V3DupFinder.h"
 #include "V3Hasher.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3Name.cpp b/src/V3Name.cpp
index 64574a5a4..9825a3bac 100644
--- a/src/V3Name.cpp
+++ b/src/V3Name.cpp
@@ -19,10 +19,11 @@
 //              Prepend __PVT__ to variable names
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Name.h"
 
 #include "V3LanguageWords.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3Number.cpp b/src/V3Number.cpp
index 00551a50d..acc6e6639 100644
--- a/src/V3Number.cpp
+++ b/src/V3Number.cpp
@@ -14,10 +14,10 @@
 //
 //*************************************************************************
 
-#include "V3Number.h"
-
 #include "V3PchAstMT.h"
 
+#include "V3Number.h"
+
 #include 
 #include 
 #include 
diff --git a/src/V3Options.cpp b/src/V3Options.cpp
index d6ec1d0df..554af3421 100644
--- a/src/V3Options.cpp
+++ b/src/V3Options.cpp
@@ -14,6 +14,8 @@
 //
 //*************************************************************************
 
+#include "V3PchAstMT.h"
+
 #include "V3Options.h"
 
 #include "V3Error.h"
@@ -22,7 +24,6 @@
 #include "V3Mutex.h"
 #include "V3OptionParser.h"
 #include "V3Os.h"
-#include "V3PchAstMT.h"
 #include "V3PreShell.h"
 #include "V3String.h"
 
diff --git a/src/V3Order.cpp b/src/V3Order.cpp
index c8b7dda5e..b3af14abc 100644
--- a/src/V3Order.cpp
+++ b/src/V3Order.cpp
@@ -71,6 +71,8 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Order.h"
 
 #include "V3AstUserAllocator.h"
@@ -84,7 +86,6 @@
 #include "V3OrderMoveGraph.h"
 #include "V3Partition.h"
 #include "V3PartitionGraph.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Sched.h"
 #include "V3SenTree.h"
 #include "V3SplitVar.h"
diff --git a/src/V3Param.cpp b/src/V3Param.cpp
index acae4012b..4133df59f 100644
--- a/src/V3Param.cpp
+++ b/src/V3Param.cpp
@@ -44,6 +44,8 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Param.h"
 
 #include "V3Case.h"
@@ -51,7 +53,6 @@
 #include "V3Hasher.h"
 #include "V3Os.h"
 #include "V3Parse.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Unroll.h"
 #include "V3Width.h"
 
diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp
index 93ad86a9f..16e7d612c 100644
--- a/src/V3Partition.cpp
+++ b/src/V3Partition.cpp
@@ -14,6 +14,8 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Partition.h"
 
 #include "V3Config.h"
@@ -25,7 +27,6 @@
 #include "V3Os.h"
 #include "V3PairingHeap.h"
 #include "V3PartitionGraph.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Scoreboard.h"
 #include "V3Stats.h"
 #include "V3UniqueNames.h"
diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp
index 9a6858352..c6ebaacee 100644
--- a/src/V3Premit.cpp
+++ b/src/V3Premit.cpp
@@ -24,9 +24,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Premit.h"
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 #include "V3UniqueNames.h"
 
diff --git a/src/V3ProtectLib.cpp b/src/V3ProtectLib.cpp
index e85c70d84..0fa0c4c2a 100644
--- a/src/V3ProtectLib.cpp
+++ b/src/V3ProtectLib.cpp
@@ -14,10 +14,11 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3ProtectLib.h"
 
 #include "V3Hasher.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3String.h"
 #include "V3Task.h"
 
diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp
index 60cb72f0c..5c39b78d2 100644
--- a/src/V3Randomize.cpp
+++ b/src/V3Randomize.cpp
@@ -24,10 +24,11 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Randomize.h"
 
 #include "V3MemberMap.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 VL_DEFINE_DEBUG_FUNCTIONS;
 
diff --git a/src/V3Reloop.cpp b/src/V3Reloop.cpp
index 8dbc82dd8..55f07fe35 100644
--- a/src/V3Reloop.cpp
+++ b/src/V3Reloop.cpp
@@ -29,9 +29,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Reloop.h"
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Sched.cpp b/src/V3Sched.cpp
index 2aa86bd2b..a7012d151 100644
--- a/src/V3Sched.cpp
+++ b/src/V3Sched.cpp
@@ -35,12 +35,13 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Sched.h"
 
 #include "V3EmitCBase.h"
 #include "V3EmitV.h"
 #include "V3Order.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3SenExprBuilder.h"
 #include "V3Stats.h"
 
diff --git a/src/V3SchedAcyclic.cpp b/src/V3SchedAcyclic.cpp
index 4df41bb9c..f70022350 100644
--- a/src/V3SchedAcyclic.cpp
+++ b/src/V3SchedAcyclic.cpp
@@ -33,8 +33,9 @@
 //
 //*************************************************************************
 
-#include "V3Graph.h"
 #include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
+#include "V3Graph.h"
 #include "V3Sched.h"
 #include "V3SenTree.h"
 #include "V3SplitVar.h"
diff --git a/src/V3SchedPartition.cpp b/src/V3SchedPartition.cpp
index b9c0619fa..a5cbfd3c9 100644
--- a/src/V3SchedPartition.cpp
+++ b/src/V3SchedPartition.cpp
@@ -34,9 +34,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3EmitV.h"
 #include "V3Graph.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Sched.h"
 
 #include 
diff --git a/src/V3SchedReplicate.cpp b/src/V3SchedReplicate.cpp
index c37ae0c7d..9ef1fcdb0 100644
--- a/src/V3SchedReplicate.cpp
+++ b/src/V3SchedReplicate.cpp
@@ -34,8 +34,9 @@
 //
 //*************************************************************************
 
-#include "V3Graph.h"
 #include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
+#include "V3Graph.h"
 #include "V3Sched.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp
index 4c1523bd0..56a89ed24 100644
--- a/src/V3SchedTiming.cpp
+++ b/src/V3SchedTiming.cpp
@@ -24,8 +24,9 @@
 //
 //*************************************************************************
 
-#include "V3EmitCBase.h"
 #include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
+#include "V3EmitCBase.h"
 #include "V3Sched.h"
 
 #include 
diff --git a/src/V3Scope.cpp b/src/V3Scope.cpp
index a5fb65652..4f6efb93e 100644
--- a/src/V3Scope.cpp
+++ b/src/V3Scope.cpp
@@ -21,10 +21,10 @@
 //
 //*************************************************************************
 
-#include "V3Scope.h"
-
 #include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
+#include "V3Scope.h"
+
 #include 
 #include 
 
diff --git a/src/V3Scoreboard.cpp b/src/V3Scoreboard.cpp
index 253b958cf..1a26dbc2f 100644
--- a/src/V3Scoreboard.cpp
+++ b/src/V3Scoreboard.cpp
@@ -14,10 +14,10 @@
 //
 //*************************************************************************
 
-#include "V3Scoreboard.h"
-
 #include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
+#include "V3Scoreboard.h"
+
 class ScoreboardTestElem;
 
 struct Key {
diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp
index b63e5b71a..0076094e0 100644
--- a/src/V3Slice.cpp
+++ b/src/V3Slice.cpp
@@ -35,10 +35,10 @@
 // simplified to look primarily for SLICESELs.
 //*************************************************************************
 
-#include "V3Slice.h"
-
 #include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
+#include "V3Slice.h"
+
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //*************************************************************************
diff --git a/src/V3Split.cpp b/src/V3Split.cpp
index 075259dd2..c543aec1d 100644
--- a/src/V3Split.cpp
+++ b/src/V3Split.cpp
@@ -77,10 +77,11 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Split.h"
 
 #include "V3Graph.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3SplitAs.cpp b/src/V3SplitAs.cpp
index 98699725d..26898c676 100644
--- a/src/V3SplitAs.cpp
+++ b/src/V3SplitAs.cpp
@@ -21,9 +21,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3SplitAs.h"
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp
index 01523c59b..8711f4bc6 100644
--- a/src/V3SplitVar.cpp
+++ b/src/V3SplitVar.cpp
@@ -110,9 +110,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3SplitVar.h"
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 #include "V3UniqueNames.h"
 
diff --git a/src/V3Stats.cpp b/src/V3Stats.cpp
index fca92184a..3f89004df 100644
--- a/src/V3Stats.cpp
+++ b/src/V3Stats.cpp
@@ -14,10 +14,10 @@
 //
 //*************************************************************************
 
-#include "V3Stats.h"
-
 #include "V3PchAstMT.h"
 
+#include "V3Stats.h"
+
 // This visitor does not edit nodes, and is called at error-exit, so should use constant iterators
 #include "V3AstConstOnly.h"
 
diff --git a/src/V3StatsReport.cpp b/src/V3StatsReport.cpp
index d24c4bb23..a41f116d6 100644
--- a/src/V3StatsReport.cpp
+++ b/src/V3StatsReport.cpp
@@ -14,10 +14,11 @@
 //
 //*************************************************************************
 
+#include "V3PchAstMT.h"
+
 #include "V3File.h"
 #include "V3Global.h"
 #include "V3Os.h"
-#include "V3PchAstMT.h"
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3Subst.cpp b/src/V3Subst.cpp
index 3a43b05a8..7c2465dad 100644
--- a/src/V3Subst.cpp
+++ b/src/V3Subst.cpp
@@ -22,9 +22,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Subst.h"
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3TSP.cpp b/src/V3TSP.cpp
index 85c2c575d..583db4ab4 100644
--- a/src/V3TSP.cpp
+++ b/src/V3TSP.cpp
@@ -19,11 +19,12 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3TSP.h"
 
 #include "V3File.h"
 #include "V3Graph.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 #include 
diff --git a/src/V3Table.cpp b/src/V3Table.cpp
index 30c0850db..cfdc10717 100644
--- a/src/V3Table.cpp
+++ b/src/V3Table.cpp
@@ -21,9 +21,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Table.h"
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Simulate.h"
 #include "V3Stats.h"
 
diff --git a/src/V3Task.cpp b/src/V3Task.cpp
index ceeed9e00..a410f06a6 100644
--- a/src/V3Task.cpp
+++ b/src/V3Task.cpp
@@ -23,13 +23,14 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Task.h"
 
 #include "V3Const.h"
 #include "V3EmitCBase.h"
 #include "V3Graph.h"
 #include "V3LinkLValue.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 
 #include 
 
diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp
index a875d5dc3..65948a526 100644
--- a/src/V3Timing.cpp
+++ b/src/V3Timing.cpp
@@ -60,13 +60,14 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Timing.h"
 
 #include "V3Const.h"
 #include "V3EmitV.h"
 #include "V3Graph.h"
 #include "V3MemberMap.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3SenExprBuilder.h"
 #include "V3SenTree.h"
 #include "V3UniqueNames.h"
diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp
index 36a4bb0e3..653ba6548 100644
--- a/src/V3Trace.cpp
+++ b/src/V3Trace.cpp
@@ -35,12 +35,13 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Trace.h"
 
 #include "V3DupFinder.h"
 #include "V3EmitCBase.h"
 #include "V3Graph.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp
index 7e287f5fe..284936660 100644
--- a/src/V3TraceDecl.cpp
+++ b/src/V3TraceDecl.cpp
@@ -20,13 +20,14 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3TraceDecl.h"
 
 #include "verilated_trace_defs.h"  // For VLT_TRACE_SCOPE_*
 
 #include "V3Config.h"
 #include "V3EmitCBase.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp
index 84788265b..a584d1748 100644
--- a/src/V3Tristate.cpp
+++ b/src/V3Tristate.cpp
@@ -115,11 +115,12 @@
 // unsupported.
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Tristate.h"
 
 #include "V3Graph.h"
 #include "V3Inst.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Undriven.cpp b/src/V3Undriven.cpp
index 2c2df44ff..09d6e5043 100644
--- a/src/V3Undriven.cpp
+++ b/src/V3Undriven.cpp
@@ -23,9 +23,10 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Undriven.h"
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 
 #include 
diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp
index 3d429998e..625055393 100644
--- a/src/V3Unknown.cpp
+++ b/src/V3Unknown.cpp
@@ -28,10 +28,11 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Unknown.h"
 
 #include "V3Const.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Stats.h"
 #include "V3UniqueNames.h"
 
diff --git a/src/V3Unroll.cpp b/src/V3Unroll.cpp
index 3a5beea92..f2a7af31b 100644
--- a/src/V3Unroll.cpp
+++ b/src/V3Unroll.cpp
@@ -24,10 +24,11 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Unroll.h"
 
 #include "V3Const.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Simulate.h"
 #include "V3Stats.h"
 
diff --git a/src/V3VariableOrder.cpp b/src/V3VariableOrder.cpp
index 4275f5499..2fbea7c75 100644
--- a/src/V3VariableOrder.cpp
+++ b/src/V3VariableOrder.cpp
@@ -20,11 +20,12 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3VariableOrder.h"
 
 #include "V3AstUserAllocator.h"
 #include "V3EmitCBase.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3TSP.h"
 
 #include 
diff --git a/src/V3Width.cpp b/src/V3Width.cpp
index 533da7a26..f5f9c85e8 100644
--- a/src/V3Width.cpp
+++ b/src/V3Width.cpp
@@ -63,12 +63,13 @@
 // iterateSubtreeReturnEdits.
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "V3Width.h"
 
 #include "V3Const.h"
 #include "V3MemberMap.h"
 #include "V3Number.h"
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
 #include "V3Randomize.h"
 #include "V3String.h"
 #include "V3Task.h"
diff --git a/src/V3WidthCommit.cpp b/src/V3WidthCommit.cpp
index 16813f88a..abfb20bab 100644
--- a/src/V3WidthCommit.cpp
+++ b/src/V3WidthCommit.cpp
@@ -20,13 +20,13 @@
 //
 //*************************************************************************
 
+#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
 #include "config_build.h"
 #include "verilatedos.h"
 
 #include "V3WidthCommit.h"
 
-#include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
-
 VL_DEFINE_DEBUG_FUNCTIONS;
 
 //######################################################################
diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp
index f2c875738..8c8aa4bb4 100644
--- a/src/V3WidthSel.cpp
+++ b/src/V3WidthSel.cpp
@@ -26,8 +26,9 @@
 //
 //*************************************************************************
 
-#include "V3Const.h"
 #include "V3PchAstNoMT.h"  // VL_MT_DISABLED_CODE_UNIT
+
+#include "V3Const.h"
 #include "V3Width.h"
 
 VL_DEFINE_DEBUG_FUNCTIONS;

From 8b44a54bb225257690748acbe046935849053085 Mon Sep 17 00:00:00 2001
From: Wilson Snyder 
Date: Wed, 18 Oct 2023 08:08:15 -0400
Subject: [PATCH 089/157] Support Verilated precompiled header compilations
 (#4580)

---
 include/verilated.mk.in               | 56 +++++++++++++++-----
 src/CMakeLists.txt                    |  1 +
 src/Makefile_obj.in                   |  1 +
 src/V3EmitC.h                         |  3 +-
 src/V3EmitCBase.h                     |  7 +--
 src/V3EmitCImp.cpp                    |  5 +-
 src/V3EmitCModel.cpp                  |  6 +--
 src/V3EmitCPch.cpp                    | 73 +++++++++++++++++++++++++++
 src/V3EmitCSyms.cpp                   |  2 +-
 src/Verilator.cpp                     |  1 +
 test_regress/t/t_trace_noflag_bad.out |  2 +-
 11 files changed, 130 insertions(+), 27 deletions(-)
 create mode 100644 src/V3EmitCPch.cpp

diff --git a/include/verilated.mk.in b/include/verilated.mk.in
index 4c97a82e4..49837598b 100644
--- a/include/verilated.mk.in
+++ b/include/verilated.mk.in
@@ -35,6 +35,12 @@ CFG_CXXFLAGS_NO_UNUSED = @CFG_CXXFLAGS_NO_UNUSED@
 CFG_CXXFLAGS_WEXTRA = @CFG_CXXFLAGS_WEXTRA@
 # Compiler flags that enable coroutine support
 CFG_CXXFLAGS_COROUTINES = @CFG_CXXFLAGS_COROUTINES@
+# Compiler flags when creating a precompiled header
+CFG_CXXFLAGS_PCH = -x c++-header
+# Compiler option to put in front of filename to read precompiled header
+CFG_CXXFLAGS_PCH_I = @CFG_CXXFLAGS_PCH_I@
+# Compiler's filename prefix for precompiled headers, .gch if clang, empty if GCC
+CFG_GCH_IF_CLANG = @CFG_GCH_IF_CLANG@
 # Linker flags
 CFG_LDFLAGS_VERILATED = @CFG_LDFLAGS_VERILATED@
 # Linker libraries for multithreading
@@ -47,6 +53,12 @@ VERILATOR_COVERAGE = $(PERL) $(VERILATOR_ROOT)/bin/verilator_coverage
 VERILATOR_INCLUDER = $(PYTHON3) $(VERILATOR_ROOT)/bin/verilator_includer
 VERILATOR_CCACHE_REPORT = $(PYTHON3) $(VERILATOR_ROOT)/bin/verilator_ccache_report
 
+######################################################################
+# CCACHE flags (via environment as no command line option available)
+
+CCACHE_SLOPPINESS ?= pch_defines,time_macros
+export CCACHE_SLOPPINESS
+
 ######################################################################
 # Make checks
 
@@ -166,11 +178,17 @@ endif
 VM_FAST += $(VM_CLASSES_FAST) $(VM_SUPPORT_FAST)
 VM_SLOW += $(VM_CLASSES_SLOW) $(VM_SUPPORT_SLOW)
 
+# Precompiled header filename
+VK_PCH_H = $(VM_PREFIX)__pch.h
+# Compiler read-a-precompiled-header option for precompiled header filename
+VK_PCH_I_FAST = $(CFG_CXXFLAGS_PCH_I) $(VM_PREFIX)__pch.h.fast$(CFG_GCH_IF_CLANG)
+VK_PCH_I_SLOW = $(CFG_CXXFLAGS_PCH_I) $(VM_PREFIX)__pch.h.slow$(CFG_GCH_IF_CLANG)
+
 #######################################################################
 ### Overall Objects Linking
 
-VK_FAST_OBJS = $(addsuffix .o, $(VM_FAST))
-VK_SLOW_OBJS = $(addsuffix .o, $(VM_SLOW))
+VK_OBJS_FAST = $(addsuffix .o, $(VM_FAST))
+VK_OBJS_SLOW = $(addsuffix .o, $(VM_SLOW))
 
 VK_USER_OBJS = $(addsuffix .o, $(VM_USER_CLASSES))
 
@@ -197,7 +215,7 @@ else
   # Parallel build: Each .cpp file by itself. This can be somewhat slower for
   # very small designs and examples, but is a lot faster for large designs.
 
-  VK_OBJS += $(VK_FAST_OBJS) $(VK_SLOW_OBJS)
+  VK_OBJS += $(VK_OBJS_FAST) $(VK_OBJS_SLOW)
 endif
 
 # When archiving just objects (.o), use single $(AR) run
@@ -241,18 +259,30 @@ $(VM_PREFIX)__ALL.a: $(VK_OBJS) $(VM_HIER_LIBS)
 ### Compile rules
 
 ifneq ($(VM_DEFAULT_RULES),0)
-# Anything not in $(VK_SLOW_OBJS) or $(VK_GLOBAL_OBJS), including verilated.o
+# Anything not in $(VK_OBJS_SLOW) or $(VK_GLOBAL_OBJS), including verilated.o
 # and user files passed on the Verilator command line use this rule.
 # We put OPT_FAST/OPT_SLOW/OPT_GLOBAL before the other flags to
 # allow USER_CPPFLAGS to override them
 %.o: %.cpp
 	$(OBJCACHE) $(CXX) $(OPT_FAST) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
 
-$(VK_SLOW_OBJS): %.o: %.cpp
-	$(OBJCACHE) $(CXX) $(OPT_SLOW) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
+$(VK_OBJS_FAST): %.o: %.cpp $(VK_PCH_H).fast.gch
+	$(OBJCACHE) $(CXX) $(OPT_FAST) $(CXXFLAGS) $(CPPFLAGS) $(VK_PCH_I_FAST) -c -o $@ $<
+
+$(VK_OBJS_SLOW): %.o: %.cpp $(VK_PCH_H).slow.gch
+	$(OBJCACHE) $(CXX) $(OPT_SLOW) $(CXXFLAGS) $(CPPFLAGS) $(VK_PCH_I_SLOW) -c -o $@ $<
 
 $(VK_GLOBAL_OBJS): %.o: %.cpp
 	$(OBJCACHE) $(CXX) $(OPT_GLOBAL) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
+
+# Precompile a header file
+# PCH's compiler flags must match exactly the fast/slow arguments used in the .cpp file,
+# or the PCH file won't be used.
+%.fast.gch: %
+	$(OBJCACHE) $(CXX) $(OPT_FAST) $(CXXFLAGS) $(CPPFLAGS) $(CFG_CXXFLAGS_PCH) $< -o $@
+%.slow.gch: %
+	$(OBJCACHE) $(CXX) $(OPT_SLOW) $(CXXFLAGS) $(CPPFLAGS) $(CFG_CXXFLAGS_PCH) $< -o $@
+
 endif
 
 #Default rule embedded in make:
@@ -300,19 +330,21 @@ endif
 
 debug-make::
 	@echo
-	@echo CXXFLAGS: $(CXXFLAGS)
 	@echo CPPFLAGS: $(CPPFLAGS)
+	@echo CXXFLAGS: $(CXXFLAGS)
 	@echo OPT_FAST: $(OPT_FAST)
 	@echo OPT_SLOW: $(OPT_SLOW)
-	@echo VM_PREFIX:  $(VM_PREFIX)
-	@echo VM_PARALLEL_BUILDS:  $(VM_PARALLEL_BUILDS)
+	@echo VK_OBJS: $(VK_OBJS)
+	@echo VK_OBJS_FAST: $(VK_OBJS_FAST)
+	@echo VK_OBJS_SLOW: $(VK_OBJS_SLOW)
 	@echo VM_CLASSES_FAST: $(VM_CLASSES_FAST)
 	@echo VM_CLASSES_SLOW: $(VM_CLASSES_SLOW)
-	@echo VM_SUPPORT_FAST: $(VM_SUPPORT_FAST)
-	@echo VM_SUPPORT_SLOW: $(VM_SUPPORT_SLOW)
 	@echo VM_GLOBAL_FAST: $(VM_GLOBAL_FAST)
 	@echo VM_GLOBAL_SLOW: $(VM_GLOBAL_SLOW)
-	@echo VK_OBJS: $(VK_OBJS)
+	@echo VM_PARALLEL_BUILDS:  $(VM_PARALLEL_BUILDS)
+	@echo VM_PREFIX:  $(VM_PREFIX)
+	@echo VM_SUPPORT_FAST: $(VM_SUPPORT_FAST)
+	@echo VM_SUPPORT_SLOW: $(VM_SUPPORT_SLOW)
 	@echo
 
 ######################################################################
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f31871b65..8124e0ee3 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -228,6 +228,7 @@ set(COMMON_SOURCES
     V3EmitCMain.cpp
     V3EmitCMake.cpp
     V3EmitCModel.cpp
+    V3EmitCPch.cpp
     V3EmitCSyms.cpp
     V3EmitMk.cpp
     V3EmitV.cpp
diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in
index 4efc14c87..8c79c0066 100644
--- a/src/Makefile_obj.in
+++ b/src/Makefile_obj.in
@@ -193,6 +193,7 @@ RAW_OBJS_PCH_ASTMT = \
 	V3EmitCHeaders.o \
 	V3EmitCImp.o \
 	V3EmitCInlines.o \
+	V3EmitCPch.o \
 	V3EmitV.o \
 	V3File.o \
 	V3Global.o \
diff --git a/src/V3EmitC.h b/src/V3EmitC.h
index 4ee9460cf..bbca3be0d 100644
--- a/src/V3EmitC.h
+++ b/src/V3EmitC.h
@@ -27,12 +27,13 @@
 class V3EmitC final {
 public:
     static void emitcConstPool() VL_MT_DISABLED;
+    static void emitcFiles() VL_MT_DISABLED;
     static void emitcHeaders() VL_MT_DISABLED;
     static void emitcImp();
     static void emitcInlines() VL_MT_DISABLED;
     static void emitcModel() VL_MT_DISABLED;
+    static void emitcPch() VL_MT_DISABLED;
     static void emitcSyms(bool dpiHdrOnly = false) VL_MT_DISABLED;
-    static void emitcFiles() VL_MT_DISABLED;
 };
 
 #endif  // Guard
diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h
index 5abf33271..7067f8ed6 100644
--- a/src/V3EmitCBase.h
+++ b/src/V3EmitCBase.h
@@ -55,6 +55,7 @@ public:
         return className + "* const __restrict vlSelf VL_ATTR_UNUSED = static_cast<" + className
                + "*>(voidSelf);\n";
     }
+    static string pchClassName() VL_MT_STABLE { return v3Global.opt.prefix() + "__pch"; }
     static string symClassName() VL_MT_STABLE {
         return v3Global.opt.prefix() + "_" + VIdProtect::protect("_Syms");
     }
@@ -62,6 +63,9 @@ public:
     static string symClassAssign() {
         return symClassName() + "* const __restrict vlSymsp VL_ATTR_UNUSED = vlSelf->vlSymsp;\n";
     }
+    static string topClassName() VL_MT_SAFE {  // Return name of top wrapper module
+        return v3Global.opt.prefix();
+    }
     static string prefixNameProtect(const AstNode* nodep) {  // C++ name with prefix
         return v3Global.opt.modPrefix() + "_" + VIdProtect::protect(nodep->name());
     }
@@ -104,9 +108,6 @@ public:
         return v3Global.opt.protectIds() ? "" : in;
     }
     static string funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp = nullptr);
-    static string topClassName() VL_MT_SAFE {  // Return name of top wrapper module
-        return v3Global.opt.prefix();
-    }
     static AstCFile* newCFile(const string& filename, bool slow, bool source);
     static AstCFile* createCFile(const string& filename, bool slow, bool source) VL_MT_SAFE;
     string cFuncArgs(const AstCFunc* nodep);
diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp
index e640634c9..e20320052 100644
--- a/src/V3EmitCImp.cpp
+++ b/src/V3EmitCImp.cpp
@@ -190,11 +190,8 @@ class EmitCImp final : EmitCFunc {
         puts("// DESCRIPTION: Verilator output: Design implementation internals\n");
         puts("// See " + topClassName() + ".h for the primary calling header\n");
 
-        // Include files
-        puts("\n#include \"verilated.h\"\n");
-        if (v3Global.dpi()) puts("#include \"verilated_dpi.h\"\n");
         puts("\n");
-        puts("#include \"" + symClassName() + ".h\"\n");
+        puts("#include \"" + pchClassName() + ".h\"\n");
         for (const string& name : headers) puts("#include \"" + name + ".h\"\n");
 
         emitTextSection(m_modp, VNType::atScImpHdr);
diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp
index 53c5339fb..5abad82d7 100644
--- a/src/V3EmitCModel.cpp
+++ b/src/V3EmitCModel.cpp
@@ -627,14 +627,10 @@ class EmitCModel final : public EmitCFunc {
              "Model implementation (design independent parts)\n");
 
         puts("\n");
-        puts("#include \"" + topClassName() + ".h\"\n");
-        puts("#include \"" + symClassName() + ".h\"\n");
+        puts("#include \"" + pchClassName() + ".h\"\n");
         if (v3Global.opt.trace()) {
             puts("#include \"" + v3Global.opt.traceSourceLang() + ".h\"\n");
         }
-        if (v3Global.dpi()) {  //
-            puts("#include \"verilated_dpi.h\"\n");
-        }
 
         emitConstructorImplementation(modp);
         emitDestructorImplementation();
diff --git a/src/V3EmitCPch.cpp b/src/V3EmitCPch.cpp
new file mode 100644
index 000000000..1cd6ed965
--- /dev/null
+++ b/src/V3EmitCPch.cpp
@@ -0,0 +1,73 @@
+// -*- mode: C++; c-file-style: "cc-mode" -*-
+//*************************************************************************
+// Code available from: https://verilator.org
+//
+// Copyright 2003-2023 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
+//
+//*************************************************************************
+// DESCRIPTION: Verilator: Emit C++ for precompiled header include
+//
+
+#include "V3PchAstMT.h"
+
+#include "V3EmitC.h"
+#include "V3EmitCBase.h"
+#include "V3File.h"
+
+VL_DEFINE_DEBUG_FUNCTIONS;
+
+//######################################################################
+// Precompiled header emitter
+
+class EmitCPch final : EmitCBase {
+public:
+    // METHODS
+
+    void emitPch() {
+        // Generate the makefile
+        V3OutCFile of{v3Global.opt.makeDir() + "/" + pchClassName() + ".h"};
+        of.putsHeader();
+        of.puts("// DESCRIPTION: Verilator output: Precompiled header\n");
+        of.puts("//\n");
+        of.puts("// Internal details; most user sources do not need this header,\n");
+        of.puts("// unless using verilator public meta comments.\n");
+        of.puts("// Suggest use " + topClassName() + ".h instead.\n");
+        of.puts("\n");
+
+        of.putsGuard();
+
+        of.puts("\n");
+        of.puts("// GCC and Clang only will precompile headers (PCH) for the first header.\n");
+        of.puts("// So, make sure this is the one and only PCH.\n");
+        of.puts("// If multiple module's includes are needed, use individual includes.\n");
+        of.puts("#ifdef VL_PCH_INCLUDED\n");
+        of.puts("# error \"Including multiple precompiled header files\"\n");
+        of.puts("#endif\n");
+        of.puts("#define VL_PCH_INCLUDED\n");
+
+        of.puts("\n");
+        of.puts("\n#include \"verilated.h\"\n");
+        if (v3Global.dpi()) of.puts("#include \"verilated_dpi.h\"\n");
+
+        of.puts("\n");
+        of.puts("#include \"" + symClassName() + ".h\"\n");
+        of.puts("#include \"" + topClassName() + ".h\"\n");
+
+        of.putsEndGuard();
+    }
+
+public:
+    explicit EmitCPch() { emitPch(); }
+};
+
+//######################################################################
+// EmitC static functions
+
+void V3EmitC::emitcPch() {
+    UINFO(2, __FUNCTION__ << ": " << endl);
+    EmitCPch{};
+}
diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp
index 4642ac016..8ac652a4b 100644
--- a/src/V3EmitCSyms.cpp
+++ b/src/V3EmitCSyms.cpp
@@ -606,7 +606,7 @@ void EmitCSyms::emitSymImpPreamble() {
     puts("\n");
 
     // Includes
-    puts("#include \"" + symClassName() + ".h\"\n");
+    puts("#include \"" + pchClassName() + ".h\"\n");
     puts("#include \"" + topClassName() + ".h\"\n");
     for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep;
          nodep = VN_AS(nodep->nextp(), NodeModule)) {
diff --git a/src/Verilator.cpp b/src/Verilator.cpp
index e5ba41c55..1a4c0bdc6 100644
--- a/src/Verilator.cpp
+++ b/src/Verilator.cpp
@@ -559,6 +559,7 @@ static void process() {
             V3EmitC::emitcSyms();
             V3EmitC::emitcConstPool();
             V3EmitC::emitcModel();
+            V3EmitC::emitcPch();
             V3EmitC::emitcHeaders();
         } else if (v3Global.opt.dpiHdrOnly()) {
             V3EmitC::emitcSyms(true);
diff --git a/test_regress/t/t_trace_noflag_bad.out b/test_regress/t/t_trace_noflag_bad.out
index e8156e0c9..66a2974a8 100644
--- a/test_regress/t/t_trace_noflag_bad.out
+++ b/test_regress/t/t_trace_noflag_bad.out
@@ -1,2 +1,2 @@
-%Error: Vt_trace_noflag_bad.cpp:106: 'Vt_trace_noflag_bad::trace()' called on model that was Verilated without --trace option
+%Error: Vt_trace_noflag_bad.cpp:105: 'Vt_trace_noflag_bad::trace()' called on model that was Verilated without --trace option
 Aborting...

From 493f1da2664c151aab135cf1d0783f011ffeb6e5 Mon Sep 17 00:00:00 2001
From: Wilson Snyder 
Date: Wed, 18 Oct 2023 08:09:42 -0400
Subject: [PATCH 090/157] Fix compile warning on unused member function
 variable (#4567).

---
 Changes                                   |  1 +
 configure.ac                              |  7 +++---
 test_regress/t/t_class_func_arg_unused.pl | 21 ++++++++++++++++
 test_regress/t/t_class_func_arg_unused.v  | 29 +++++++++++++++++++++++
 4 files changed, 55 insertions(+), 3 deletions(-)
 create mode 100755 test_regress/t/t_class_func_arg_unused.pl
 create mode 100644 test_regress/t/t_class_func_arg_unused.v

diff --git a/Changes b/Changes
index 54ec9600e..c174db240 100644
--- a/Changes
+++ b/Changes
@@ -41,6 +41,7 @@ Verilator 5.017 devel
 * Fix broken link error for enum references (#4551). [Anthony Donlon]
 * Fix instance arrays connecting to array of structs (#4557). [raphmaster]
 * Fix shift to remove operation side effects (#4563).
+* Fix compile warning on unused member function variable (#4567).
 * Fix preprocessor to show `line 2 on resumed file.
 
 
diff --git a/configure.ac b/configure.ac
index f0c79da98..4620e3b47 100644
--- a/configure.ac
+++ b/configure.ac
@@ -443,14 +443,15 @@ m4_foreach([cflag],[
         [-Qunused-arguments],
         [-Wno-bool-operation],
         [-Wno-constant-logical-operand],
-        [-Wno-tautological-bitwise-compare],
         [-Wno-parentheses-equality],
+        [-Wno-shadow],
         [-Wno-sign-compare],
+        [-Wno-tautological-bitwise-compare],
         [-Wno-uninitialized],
+        [-Wno-unused-but-set-parameter],
         [-Wno-unused-but-set-variable],
         [-Wno-unused-parameter],
-        [-Wno-unused-variable],
-        [-Wno-shadow]],[
+        [-Wno-unused-variable]],[
     _MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,cflag)
     # CMake will test what flags work itself, so pass all flags through to it
     CFG_CXX_FLAGS_CMAKE="$CFG_CXX_FLAGS_CMAKE cflag"
diff --git a/test_regress/t/t_class_func_arg_unused.pl b/test_regress/t/t_class_func_arg_unused.pl
new file mode 100755
index 000000000..859050d63
--- /dev/null
+++ b/test_regress/t/t_class_func_arg_unused.pl
@@ -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 2023 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(simulator => 1);
+
+compile(
+    );
+
+execute(
+    check_finished => 1,
+    );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_class_func_arg_unused.v b/test_regress/t/t_class_func_arg_unused.v
new file mode 100644
index 000000000..0907ebe33
--- /dev/null
+++ b/test_regress/t/t_class_func_arg_unused.v
@@ -0,0 +1,29 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed under the Creative Commons Public Domain, for
+// any use, without warranty, 2023 by Wilson Snyder.
+// SPDX-License-Identifier: CC0-1.0
+
+package uvm_pkg;
+
+class uvm_reg_field; // extends uvm_object;
+   function void configure(bit overde, bit is_rand);
+      if (overde) is_rand = 0;
+      if (!is_rand) ;   // value.rand_mode(0);
+      // See issue #4567
+   endfunction
+endclass
+
+endpackage
+
+module t(/*AUTOARG*/);
+
+   initial begin
+      uvm_pkg::uvm_reg_field c = new;
+      c.configure(1, 0);
+      c.configure(0, 0);
+      $write("*-* All Finished *-*\n");
+      $finish;
+   end
+
+endmodule

From 263697e4914f64479bb7b00fdc07a369d91ac4f6 Mon Sep 17 00:00:00 2001
From: Wilson Snyder 
Date: Wed, 18 Oct 2023 08:15:55 -0400
Subject: [PATCH 091/157] Commentary (#4580)

---
 include/verilated.mk.in | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/include/verilated.mk.in b/include/verilated.mk.in
index 49837598b..59a94486f 100644
--- a/include/verilated.mk.in
+++ b/include/verilated.mk.in
@@ -259,9 +259,11 @@ $(VM_PREFIX)__ALL.a: $(VK_OBJS) $(VM_HIER_LIBS)
 ### Compile rules
 
 ifneq ($(VM_DEFAULT_RULES),0)
-# Anything not in $(VK_OBJS_SLOW) or $(VK_GLOBAL_OBJS), including verilated.o
-# and user files passed on the Verilator command line use this rule.
-# We put OPT_FAST/OPT_SLOW/OPT_GLOBAL before the other flags to
+# Compilation rule for anything not in $(VK_OBJS_FAST), $(VK_OBJS_SLOW), or
+# $(VK_GLOBAL_OBJS) including verilated.o.  This typically means user files
+# passed on the Verilator command line.
+#
+# These rules put OPT_FAST/OPT_SLOW/OPT_GLOBAL before the other flags to
 # allow USER_CPPFLAGS to override them
 %.o: %.cpp
 	$(OBJCACHE) $(CXX) $(OPT_FAST) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
@@ -276,8 +278,8 @@ $(VK_GLOBAL_OBJS): %.o: %.cpp
 	$(OBJCACHE) $(CXX) $(OPT_GLOBAL) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
 
 # Precompile a header file
-# PCH's compiler flags must match exactly the fast/slow arguments used in the .cpp file,
-# or the PCH file won't be used.
+# PCH's compiler flags must match exactly the rules' above FAST/SLOW
+# arguments used for the .cpp files, or the PCH file won't be used.
 %.fast.gch: %
 	$(OBJCACHE) $(CXX) $(OPT_FAST) $(CXXFLAGS) $(CPPFLAGS) $(CFG_CXXFLAGS_PCH) $< -o $@
 %.slow.gch: %

From 8720841c487054b0f2ef37599f17ab1b5dd7ce6c Mon Sep 17 00:00:00 2001
From: Krzysztof Bieganski 
Date: Wed, 18 Oct 2023 22:49:20 +0200
Subject: [PATCH 092/157] Fix to not remap local assign intravals in forks
 (#4583)

---
 src/V3SchedTiming.cpp              | 18 +++++++++++-------
 test_regress/t/t_fork_jumpblock.pl | 23 +++++++++++++++++++++++
 test_regress/t/t_fork_jumpblock.v  | 23 +++++++++++++++++++++++
 3 files changed, 57 insertions(+), 7 deletions(-)
 create mode 100755 test_regress/t/t_fork_jumpblock.pl
 create mode 100644 test_regress/t/t_fork_jumpblock.v

diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp
index 56a89ed24..3a8dd6b89 100644
--- a/src/V3SchedTiming.cpp
+++ b/src/V3SchedTiming.cpp
@@ -289,13 +289,17 @@ void transformForks(AstNetlist* const netlistp) {
                 AstVar* const varp = refp->varp();
                 AstBasicDType* const dtypep = varp->dtypep()->basicp();
                 bool passByValue = false;
-                if (VString::startsWith(varp->name(), "__Vintra")) {
-                    // Pass it by value to the new function, as otherwise there are issues with
-                    // -flocalize (see t_timing_intra_assign)
-                    passByValue = true;
-                } else if (!varp->user1() || !varp->isFuncLocal()) {
-                    // Not func local, or not declared before the fork. Their lifetime is longer
-                    // than the forked process. Skip
+                if (!varp->isFuncLocal()) {
+                    if (VString::startsWith(varp->name(), "__Vintra")) {
+                        // Pass it by value to the new function, as otherwise there are issues with
+                        // -flocalize (see t_timing_intra_assign)
+                        passByValue = true;
+                    } else {
+                        // Not func local. Its lifetime is longer than the forked process. Skip
+                        return;
+                    }
+                } else if (!varp->user1()) {
+                    // Not declared before the fork. It cannot outlive the forked process
                     return;
                 } else if (dtypep && dtypep->isForkSync()) {
                     // We can just pass it by value to the new function
diff --git a/test_regress/t/t_fork_jumpblock.pl b/test_regress/t/t_fork_jumpblock.pl
new file mode 100755
index 000000000..bc632ee01
--- /dev/null
+++ b/test_regress/t/t_fork_jumpblock.pl
@@ -0,0 +1,23 @@
+#!/usr/bin/env perl
+if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
+# DESCRIPTION: Verilator: Verilog Test driver/expect definition
+#
+# Copyright 2019 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(simulator => 1);
+
+compile(
+    verilator_flags2 => ["--exe --main --timing"],
+    make_main => 0,
+    );
+
+execute(
+    check_finished => 1,
+    );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_fork_jumpblock.v b/test_regress/t/t_fork_jumpblock.v
new file mode 100644
index 000000000..13ef8e9f3
--- /dev/null
+++ b/test_regress/t/t_fork_jumpblock.v
@@ -0,0 +1,23 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed into the Public Domain, for any use,
+// without warranty, 2023 by Antmicro Ltd.
+// SPDX-License-Identifier: CC0-1.0
+
+class bar;
+    task foo(logic r);
+        int a, b;
+        if (r) return;
+        fork a = #1 b; join_none
+    endtask
+endclass
+
+module t;
+    bar b = new;
+
+    initial begin
+        b.foo(0);
+        $write("*-* All Finished *-*\n");
+        $finish;
+    end
+endmodule

From b7233d063f788b8bc354cd2346160c50223436d2 Mon Sep 17 00:00:00 2001
From: Wilson Snyder 
Date: Wed, 18 Oct 2023 17:36:09 -0400
Subject: [PATCH 093/157] Internals: Fix same() called outside of sameTree
 (#4561).

---
 src/V3Ast.h        | 8 +++++++-
 src/V3AstNodes.cpp | 2 +-
 src/V3Const.cpp    | 2 +-
 src/V3Gate.cpp     | 2 +-
 src/V3Reloop.cpp   | 6 +++---
 src/V3Slice.cpp    | 2 +-
 6 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/src/V3Ast.h b/src/V3Ast.h
index 8c6282876..2bc4fe06d 100644
--- a/src/V3Ast.h
+++ b/src/V3Ast.h
@@ -1773,6 +1773,9 @@ protected:
         UASSERT_STATIC(s_cloneCntGbl, "Rollover");
     }
 
+    // Use instead isSame(), this is for each Ast* class, and assumes node is of same type
+    virtual bool same(const AstNode*) const { return true; }
+
 public:
     // ACCESSORS
     VNType type() const VL_MT_SAFE { return m_type; }
@@ -2137,7 +2140,10 @@ public:
     // statement is unlikely to be taken
     virtual bool isUnlikely() const { return false; }
     virtual int instrCount() const { return 0; }
-    virtual bool same(const AstNode*) const { return true; }
+    // Iff node is identical to anouther node
+    virtual bool isSame(const AstNode* samep) const {
+        return type() == samep->type() && same(samep);
+    }
     // Iff has a data type; dtype() must be non null
     virtual bool hasDType() const VL_MT_SAFE { return false; }
     // Iff has a non-null childDTypep(), as generic node function
diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp
index 5af783789..bddc62d9d 100644
--- a/src/V3AstNodes.cpp
+++ b/src/V3AstNodes.cpp
@@ -1701,7 +1701,7 @@ AstNodeUOrStructDType* AstMemberDType::getChildStructp() const {
 
 bool AstMemberSel::same(const AstNode* samep) const {
     const AstMemberSel* const sp = VN_DBG_AS(samep, MemberSel);
-    return sp != nullptr && access() == sp->access() && fromp()->same(sp->fromp())
+    return sp != nullptr && access() == sp->access() && fromp()->isSame(sp->fromp())
            && name() == sp->name() && varp()->same(sp->varp());
 }
 
diff --git a/src/V3Const.cpp b/src/V3Const.cpp
index d42bb07b0..1e3685e5b 100644
--- a/src/V3Const.cpp
+++ b/src/V3Const.cpp
@@ -1434,7 +1434,7 @@ private:
             // Avoid comparing widthMin's, which results in lost optimization attempts
             // If cleanup sameGateTree to be smarter, this can be restored.
             // return node1p->sameGateTree(node2p);
-            return node1p->same(node2p);
+            return node1p->isSame(node2p);
         } else {
             return false;
         }
diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp
index 0f0bb61cc..a641b1e9f 100644
--- a/src/V3Gate.cpp
+++ b/src/V3Gate.cpp
@@ -1000,7 +1000,7 @@ static void eliminate(AstNode* logicp,
         // Substitute in the new tree
         UASSERT_OBJ(nodep->access().isReadOnly(), nodep,
                     "Can't replace lvalue assignments with const var");
-        UASSERT_OBJ(!(VN_IS(substp, NodeVarRef) && nodep->same(substp)),
+        UASSERT_OBJ(!(VN_IS(substp, NodeVarRef) && nodep->isSame(substp)),
                     // Prevent an infinite loop...
                     substp, "Replacing node with itself; perhaps circular logic?");
         // The replacement
diff --git a/src/V3Reloop.cpp b/src/V3Reloop.cpp
index 55f07fe35..9700bce27 100644
--- a/src/V3Reloop.cpp
+++ b/src/V3Reloop.cpp
@@ -207,10 +207,10 @@ private:
         if (m_mgSelLp) {  // Old merge
             if (m_mgCfuncp == m_cfuncp  // In same function
                 && m_mgNextp == nodep  // Consecutive node
-                && m_mgVarrefLp->same(lvarrefp)  // Same array on left hand side
+                && m_mgVarrefLp->isSame(lvarrefp)  // Same array on left hand side
                 && (m_mgConstRp  // On the right hand side either ...
-                        ? (rconstp && m_mgConstRp->same(rconstp))  // ... same constant
-                        : (rselp && m_mgVarrefRp->same(rvarrefp)))  // ... or same array
+                        ? (rconstp && m_mgConstRp->isSame(rconstp))  // ... same constant
+                        : (rselp && m_mgVarrefRp->isSame(rvarrefp)))  // ... or same array
                 && (lindex == m_mgIndexLo - 1 || lindex == m_mgIndexHi + 1)  // Left index +/- 1
                 && (m_mgConstRp || lindex == rindex + m_mgOffset)  // Same right index offset
             ) {
diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp
index 0076094e0..cc479b95c 100644
--- a/src/V3Slice.cpp
+++ b/src/V3Slice.cpp
@@ -135,7 +135,7 @@ class SliceVisitor final : public VNVisitor {
                     const AstUnpackArrayDType* const itemDTypep
                         = VN_CAST(itemRawDTypep, UnpackArrayDType);
                     if (!itemDTypep
-                        || !expectedItemDTypep->same(itemDTypep->subDTypep()->skipRefp())) {
+                        || !expectedItemDTypep->isSame(itemDTypep->subDTypep()->skipRefp())) {
                         if (!m_assignError) {
                             itemp->v3error("Item is incompatible with the array type.");
                         }

From 0c2bab1f69284afb8b6e744253a5dda098ecc26f Mon Sep 17 00:00:00 2001
From: Wilson Snyder 
Date: Wed, 18 Oct 2023 17:51:25 -0400
Subject: [PATCH 094/157] Fix method narrowing conversion compiler error
 (#4568).

---
 Changes                              |  1 +
 src/V3Cast.cpp                       |  5 +++
 src/V3EmitCFunc.h                    |  4 ++
 test_regress/t/t_struct_cons_cast.pl | 21 ++++++++++
 test_regress/t/t_struct_cons_cast.v  | 57 ++++++++++++++++++++++++++++
 5 files changed, 88 insertions(+)
 create mode 100755 test_regress/t/t_struct_cons_cast.pl
 create mode 100644 test_regress/t/t_struct_cons_cast.v

diff --git a/Changes b/Changes
index c174db240..873f5d1c3 100644
--- a/Changes
+++ b/Changes
@@ -42,6 +42,7 @@ Verilator 5.017 devel
 * Fix instance arrays connecting to array of structs (#4557). [raphmaster]
 * Fix shift to remove operation side effects (#4563).
 * Fix compile warning on unused member function variable (#4567).
+* Fix method narrowing conversion compiler error (#4568).
 * Fix preprocessor to show `line 2 on resumed file.
 
 
diff --git a/src/V3Cast.cpp b/src/V3Cast.cpp
index 0290c944e..871ba5b16 100644
--- a/src/V3Cast.cpp
+++ b/src/V3Cast.cpp
@@ -162,6 +162,11 @@ private:
         ensureLower32Cast(nodep);
         nodep->user1(1);
     }
+    void visit(AstConsPackMember* nodep) override {
+        iterateChildren(nodep);
+        if (VN_IS(nodep->rhsp()->dtypep()->skipRefp(), BasicDType)) ensureCast(nodep->rhsp());
+        nodep->user1(1);
+    }
     void visit(AstExprStmt* nodep) override {
         iterateChildren(nodep);
         nodep->user1(1);
diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h
index 871ec3624..0de6e001b 100644
--- a/src/V3EmitCFunc.h
+++ b/src/V3EmitCFunc.h
@@ -1130,6 +1130,10 @@ public:
         // Extending a value of the same word width is just a NOP.
         if (const AstClassRefDType* const classDtypep = VN_CAST(nodep->dtypep(), ClassRefDType)) {
             puts("(" + classDtypep->cType("", false, false) + ")(");
+        } else if (nodep->size() <= VL_BYTESIZE) {
+            puts("(CData)(");
+        } else if (nodep->size() <= VL_SHORTSIZE) {
+            puts("(SData)(");
         } else if (nodep->size() <= VL_IDATASIZE) {
             puts("(IData)(");
         } else {
diff --git a/test_regress/t/t_struct_cons_cast.pl b/test_regress/t/t_struct_cons_cast.pl
new file mode 100755
index 000000000..859050d63
--- /dev/null
+++ b/test_regress/t/t_struct_cons_cast.pl
@@ -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 2023 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(simulator => 1);
+
+compile(
+    );
+
+execute(
+    check_finished => 1,
+    );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_struct_cons_cast.v b/test_regress/t/t_struct_cons_cast.v
new file mode 100644
index 000000000..f821b2f33
--- /dev/null
+++ b/test_regress/t/t_struct_cons_cast.v
@@ -0,0 +1,57 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed under the Creative Commons Public Domain, for
+// any use, without warranty, 2023 by Wilson Snyder.
+// SPDX-License-Identifier: CC0-1.0
+
+class uvm_policy;
+   typedef enum {
+                 NEVER,
+                 STARTED,
+                 FINISHED
+                 } recursion_state_e;
+endclass
+
+typedef enum {
+              UVM_DEFAULT_POLICY = 0,
+              UVM_DEEP           = (1<<16),
+              UVM_SHALLOW        = (1<<17),
+              UVM_REFERENCE      = (1<<18)
+              } uvm_recursion_policy_enum;
+
+class Cls;
+   typedef struct {
+      uvm_policy::recursion_state_e state;
+      bit         ret_val;
+   } state_info_t;
+
+   state_info_t m_recur_states/*[uvm_object][uvm_object]*/[uvm_recursion_policy_enum];
+
+   automatic function uvm_recursion_policy_enum get_recursion_policy();
+      return UVM_DEEP;
+   endfunction
+
+   automatic function bit get_ret_val();
+      return $c(1);
+   endfunction
+
+   automatic function void test();
+      bit ret_val;
+      ret_val = $c1(1);
+      // See issue #4568
+      m_recur_states[get_recursion_policy()] = '{uvm_policy::FINISHED, ret_val};
+   endfunction
+
+endclass
+
+module t;
+
+   initial begin
+      Cls c;
+      c = new;
+      $display("%p", c);
+      $write("*-* All Finished *-*\n");
+      $finish;
+   end
+
+endmodule

From 5af271cf3af2a2276530e347dfb1a03493fd8632 Mon Sep 17 00:00:00 2001
From: Wilson Snyder 
Date: Thu, 19 Oct 2023 18:33:58 -0400
Subject: [PATCH 095/157] Fix display optimization ignoring side effects
 (#4585).

---
 Changes                             |  1 +
 src/V3Ast.h                         |  2 ++
 src/V3Const.cpp                     |  2 ++
 test_regress/t/t_display_impure.out |  3 +++
 test_regress/t/t_display_impure.pl  | 24 ++++++++++++++++++++++++
 test_regress/t/t_display_impure.v   | 19 +++++++++++++++++++
 6 files changed, 51 insertions(+)
 create mode 100644 test_regress/t/t_display_impure.out
 create mode 100755 test_regress/t/t_display_impure.pl
 create mode 100644 test_regress/t/t_display_impure.v

diff --git a/Changes b/Changes
index 873f5d1c3..7ec977f93 100644
--- a/Changes
+++ b/Changes
@@ -43,6 +43,7 @@ Verilator 5.017 devel
 * Fix shift to remove operation side effects (#4563).
 * Fix compile warning on unused member function variable (#4567).
 * Fix method narrowing conversion compiler error (#4568).
+* Fix display optimization ignoring side effects (#4585).
 * Fix preprocessor to show `line 2 on resumed file.
 
 
diff --git a/src/V3Ast.h b/src/V3Ast.h
index 2bc4fe06d..a17cc84e0 100644
--- a/src/V3Ast.h
+++ b/src/V3Ast.h
@@ -2132,6 +2132,8 @@ public:
     virtual bool isPredictOptimizable() const { return !isTimingControl(); }
     // Else a $display, etc, that must be ordered with other displays
     virtual bool isPure() { return true; }
+    // Iff isPure on current node and any nextp()
+    bool isPureAndNext() { return isPure() && (!nextp() || nextp()->isPure()); }
     // Else a AstTime etc that can't be substituted out
     virtual bool isSubstOptimizable() const { return true; }
     // An event control, delay, wait, etc.
diff --git a/src/V3Const.cpp b/src/V3Const.cpp
index 1e3685e5b..bb68a436b 100644
--- a/src/V3Const.cpp
+++ b/src/V3Const.cpp
@@ -3149,6 +3149,8 @@ private:
         // right line numbers, nor scopeNames as might be different scopes (late in process)
         if (!m_doCpp && pformatp->exprsp()) return false;
         if (!m_doCpp && nformatp->exprsp()) return false;
+        if (pformatp->exprsp() && !pformatp->exprsp()->isPureAndNext()) return false;
+        if (nformatp->exprsp() && !nformatp->exprsp()->isPureAndNext()) return false;
         // Avoid huge merges
         static constexpr int DISPLAY_MAX_MERGE_LENGTH = 500;
         if (pformatp->text().length() + nformatp->text().length() > DISPLAY_MAX_MERGE_LENGTH)
diff --git a/test_regress/t/t_display_impure.out b/test_regress/t/t_display_impure.out
new file mode 100644
index 000000000..fcf5005f5
--- /dev/null
+++ b/test_regress/t/t_display_impure.out
@@ -0,0 +1,3 @@
+          1
+          2
+*-* All Finished *-*
diff --git a/test_regress/t/t_display_impure.pl b/test_regress/t/t_display_impure.pl
new file mode 100755
index 000000000..61f6d3396
--- /dev/null
+++ b/test_regress/t/t_display_impure.pl
@@ -0,0 +1,24 @@
+#!/usr/bin/env perl
+if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
+# DESCRIPTION: Verilator: Verilog Test driver/expect definition
+#
+# Copyright 2023 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);
+
+compile(
+    verilator_flags2 => ["--exe --main --timing"],
+    make_main => 0,
+    );
+
+execute(
+    check_finished => 1,
+    expect_filename => $Self->{golden_filename},
+    );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_display_impure.v b/test_regress/t/t_display_impure.v
new file mode 100644
index 000000000..ad24975d3
--- /dev/null
+++ b/test_regress/t/t_display_impure.v
@@ -0,0 +1,19 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed under the Creative Commons Public Domain, for
+// any use, without warranty, 2023 by Antmicro Ltd.
+// SPDX-License-Identifier: CC0-1.0
+
+function integer f;
+   static integer i = 0;
+   return ++i;
+endfunction
+
+module t;
+   initial begin
+      $display("%d", f());
+      $display("%d", f());
+      $write("*-* All Finished *-*\n");
+      $finish;
+   end
+endmodule

From a773a525593a2a1dc8f90885230b68cc03a2223f Mon Sep 17 00:00:00 2001
From: Wilson Snyder 
Date: Thu, 19 Oct 2023 19:26:36 -0400
Subject: [PATCH 096/157] Cleanup some IEEE references

---
 docs/guide/warnings.rst                            |  2 +-
 include/verilated.cpp                              |  2 +-
 src/V3Assert.cpp                                   |  2 +-
 src/V3AssertPre.cpp                                |  2 +-
 src/V3LinkDot.cpp                                  |  2 +-
 src/V3LinkParse.cpp                                |  4 ++--
 src/V3Number.cpp                                   |  4 ++--
 test_regress/t/t_assert_disable_bad.v              |  2 +-
 test_regress/t/t_assert_procedural_clk.out         |  4 ++--
 test_regress/t/t_class_param_enum_bad.v            |  2 +-
 test_regress/t/t_event_copy.v                      |  2 +-
 test_regress/t/t_interface_import_param.v          |  2 +-
 test_regress/t/t_math_arith.v                      |  2 +-
 test_regress/t/t_param_array3.v                    |  2 +-
 test_regress/t/t_queue_method.v                    |  2 +-
 test_regress/t/t_stream_integer_type_unsup.v       |  2 +-
 test_regress/t/t_structu_dataType_assignment.v     | 10 +++++-----
 test_regress/t/t_structu_dataType_assignment_bad.v |  2 +-
 test_regress/t/t_sys_readmem_bad_end.out           |  2 +-
 19 files changed, 26 insertions(+), 26 deletions(-)

diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst
index 2691e9acf..0a85765c7 100644
--- a/docs/guide/warnings.rst
+++ b/docs/guide/warnings.rst
@@ -1174,7 +1174,7 @@ List Of Warnings
 
    Warns that a feature requires a newer standard of Verilog or SystemVerilog
    than the one specified by the :vlopt:`--language` option. For example, unsized
-   unbased literals (`'0`, `'1`, `'z`, `'x`) require 1800-2005 or later.
+   unbased literals (`'0`, `'1`, `'z`, `'x`) require IEEE 1800-2005 or later.
 
    To avoid this warning, use a Verilog or SystemVerilog standard that
    supports the feature. Alternatively, modify your code to use a different
diff --git a/include/verilated.cpp b/include/verilated.cpp
index 41a1df170..0794d4dd2 100644
--- a/include/verilated.cpp
+++ b/include/verilated.cpp
@@ -2094,7 +2094,7 @@ bool VlReadMem::get(QData& addrr, std::string& valuer) {
 
     if (VL_UNLIKELY(m_end != ~0ULL && m_addr <= m_end && !m_anyAddr)) {
         VL_WARN_MT(m_filename.c_str(), m_linenum, "",
-                   "$readmem file ended before specified final address (IEEE 2017 21.4)");
+                   "$readmem file ended before specified final address (IEEE 1800-2017 21.4)");
     }
 
     return false;  // EOF
diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp
index 3f8278e5b..f99a9ced8 100644
--- a/src/V3Assert.cpp
+++ b/src/V3Assert.cpp
@@ -154,7 +154,7 @@ private:
             if (m_procedurep) {
                 // To support this need queue of asserts to activate
                 nodep->v3error("Unsupported: Procedural concurrent assertion with"
-                               " clocking event inside always (IEEE 1800-2917 16.14.6)");
+                               " clocking event inside always (IEEE 1800-2017 16.14.6)");
             }
         }
         //
diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp
index d0689361f..c06f3b93f 100644
--- a/src/V3AssertPre.cpp
+++ b/src/V3AssertPre.cpp
@@ -15,7 +15,7 @@
 //*************************************************************************
 //  Pre steps:
 //      Attach clocks to each assertion
-//      Substitute property references by property body (IEEE Std 1800-2012, section 16.12.1).
+//      Substitute property references by property body (IEEE 1800-2012 16.12.1).
 //      Transform clocking blocks into imperative logic
 //*************************************************************************
 
diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp
index 473545166..a6f052659 100644
--- a/src/V3LinkDot.cpp
+++ b/src/V3LinkDot.cpp
@@ -2127,7 +2127,7 @@ private:
                          new AstNew{fl, nullptr}};
         AstNodeStmt* const superNewStmtp = superNewp->makeStmt();
         for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
-            // super.new shall be the first statement (section 8.15 of IEEE Std 1800-2017)
+            // super.new shall be the first statement (IEEE 1800-2017 8.15)
             // but some nodes (such as variable declarations and typedefs) should stay before
             if (VN_IS(stmtp, NodeStmt)) {
                 stmtp->addHereThisAsNext(superNewStmtp);
diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp
index b3371c2a3..9c9b349e2 100644
--- a/src/V3LinkParse.cpp
+++ b/src/V3LinkParse.cpp
@@ -573,8 +573,8 @@ private:
         } else if (VN_IS(bracketp, SelLoopVars)) {
             // Ok
         } else {
-            nodep->v3error("Syntax error; foreach missing bracketed loop variable (IEEE "
-                           "1800-2017 12.7.3)");
+            nodep->v3error("Syntax error; foreach missing bracketed loop variable"
+                           " (IEEE 1800-2017 12.7.3)");
             VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
             return;
         }
diff --git a/src/V3Number.cpp b/src/V3Number.cpp
index acc6e6639..91403a532 100644
--- a/src/V3Number.cpp
+++ b/src/V3Number.cpp
@@ -252,8 +252,8 @@ void V3Number::create(const char* sourcep) {
                                 << width() << " bit number: " << sourcep << '\n'
                                 << ((!sized() && !warned++) ? (
                                         V3Error::warnMore() + "... As that number was unsized"
-                                        + " ('d...) it is limited to 32 bits (IEEE 1800-2017 "
-                                          "5.7.1)\n"
+                                        + " ('d...) it is limited to 32 bits"
+                                          " (IEEE 1800-2017 5.7.1)\n"
                                         + V3Error::warnMore() + "... Suggest adding a size to it.")
                                                             : ""));
                         while (*(cp + 1)) cp++;  // Skip ahead so don't get multiple warnings
diff --git a/test_regress/t/t_assert_disable_bad.v b/test_regress/t/t_assert_disable_bad.v
index cb0f84b7d..07b3bc342 100644
--- a/test_regress/t/t_assert_disable_bad.v
+++ b/test_regress/t/t_assert_disable_bad.v
@@ -23,6 +23,6 @@ module t (/*AUTOARG*/
    endproperty
 
    // Test should fail due to duplicated disable iff statements
-   // (IEEE Std 1800-2012, section 16.12.1).
+   // (IEEE 1800-2012 16.12.1).
    assert property (disable iff (val == 0) check(1, 1));
 endmodule
diff --git a/test_regress/t/t_assert_procedural_clk.out b/test_regress/t/t_assert_procedural_clk.out
index 98cbce1d6..365914727 100644
--- a/test_regress/t/t_assert_procedural_clk.out
+++ b/test_regress/t/t_assert_procedural_clk.out
@@ -1,8 +1,8 @@
-%Error: t/t_assert_procedural_clk.v:21:13: Unsupported: Procedural concurrent assertion with clocking event inside always (IEEE 1800-2917 16.14.6)
+%Error: t/t_assert_procedural_clk.v:21:13: Unsupported: Procedural concurrent assertion with clocking event inside always (IEEE 1800-2017 16.14.6)
                                          : ... note: In instance 't'
    21 |             assume property (@(posedge clk) cyc == 9);
       |             ^~~~~~
-%Error: t/t_assert_procedural_clk.v:22:13: Unsupported: Procedural concurrent assertion with clocking event inside always (IEEE 1800-2917 16.14.6)
+%Error: t/t_assert_procedural_clk.v:22:13: Unsupported: Procedural concurrent assertion with clocking event inside always (IEEE 1800-2017 16.14.6)
                                          : ... note: In instance 't'
    22 |             assume property (@(negedge clk) cyc == 9);
       |             ^~~~~~
diff --git a/test_regress/t/t_class_param_enum_bad.v b/test_regress/t/t_class_param_enum_bad.v
index 55b5e824c..8a3fe88bb 100644
--- a/test_regress/t/t_class_param_enum_bad.v
+++ b/test_regress/t/t_class_param_enum_bad.v
@@ -15,7 +15,7 @@ endclass
 module t;
    initial begin
       Converter#(enum_t) conv1 = new;
-      // enum types does not match with other types (sections 6.22.1 and 6.22.4 of IEEE Std 1800-2017)
+      // enum types does not match with other types (IEEE 1800-2017 6.22.1 and 6.22.4)
       // The assignment and the function call should throw an error.
       Converter#(bit) conv2 = conv1;
       conv1.toInt(0);
diff --git a/test_regress/t/t_event_copy.v b/test_regress/t/t_event_copy.v
index 7a26fb3d9..88882259f 100644
--- a/test_regress/t/t_event_copy.v
+++ b/test_regress/t/t_event_copy.v
@@ -99,7 +99,7 @@ module t(/*AUTOARG*/
          // are ever pointed to by an EVENTREF.
          e4 = e3;  // Old handle to e4
          e3 = e2;  // Same event, also triggers e2
-         // IEEE 2017 15.5.5.1 says that this causes a merge, and the below
+         // IEEE 1800-2017 15.5.5.1 says that this causes a merge, and the below
          // should also activate the "old e3".  However we could not find any
          // simulator that actually does this.  Instead the "old e3" becomes
          // unreachable (via old handle), but is reachable by "e4" as assigned
diff --git a/test_regress/t/t_interface_import_param.v b/test_regress/t/t_interface_import_param.v
index 82969649d..043c9d184 100644
--- a/test_regress/t/t_interface_import_param.v
+++ b/test_regress/t/t_interface_import_param.v
@@ -1,7 +1,7 @@
 // DESCRIPTION: Verilator: Verilog Test module
 //
 // A test that a package import declaration can preceed a parameter port list
-// in an interface declaration. See 25.3 of the 1800-2017 LRM.
+// in an interface declaration. See IEEE 1800-2017 25.3.
 //
 // This file ONLY is placed into the Public Domain, for any use,
 // without warranty, 2013 by Jeremy Bennett.
diff --git a/test_regress/t/t_math_arith.v b/test_regress/t/t_math_arith.v
index f2c1d366e..4477c931e 100644
--- a/test_regress/t/t_math_arith.v
+++ b/test_regress/t/t_math_arith.v
@@ -159,7 +159,7 @@ module t (/*AUTOARG*/
          if (bug764_p11 !== 4'b000x) $stop;
          if (~& bug764_p11 !== 1'b1) $stop;
          //verilator lint_on WIDTH
-         // However IEEE 2017 5.7.1 says for constants that smaller-sizes do extend
+         // However IEEE 1800-2017 5.7.1 says for constants that smaller-sizes do extend
          if (4'bx !== 4'bxxxx) $stop;
          if (4'bz !== 4'bzzzz) $stop;
          if (4'b1 !== 4'b0001) $stop;
diff --git a/test_regress/t/t_param_array3.v b/test_regress/t/t_param_array3.v
index 667276578..fe38c5ecd 100644
--- a/test_regress/t/t_param_array3.v
+++ b/test_regress/t/t_param_array3.v
@@ -25,7 +25,7 @@ module t;
       if (SUMS[1] != 4+3) $stop;
       if (SUMS[2] != 4+3+2) $stop;
       if (SUMS[3] != 4+3+2+1) $stop;
-      // According to section 13.4.3 of IEEE Std 1800-2017,
+      // According to IEEE 1800-2017 13.4.3
       // execution at elaboration has no effect on the initial values
       // of the variables used either at simulation time or among
       // multiple invocations of a function at elaboration time
diff --git a/test_regress/t/t_queue_method.v b/test_regress/t/t_queue_method.v
index 090ac5a9f..fb05890bb 100644
--- a/test_regress/t/t_queue_method.v
+++ b/test_regress/t/t_queue_method.v
@@ -81,7 +81,7 @@ module t (/*AUTOARG*/);
       string_qv = string_q.unique(s) with (s.toupper);
       `checkh(string_qv.size(), 2);
       qi = q.unique_index; qv.sort;
-      // According to 7.12.1 of IEEE Std 1800-2017, it is not specified which index of duplicated value should be returned
+      // According to IEEE 1800-2017 7.12.1, it is not specified which index of duplicated value should be returned
       `checkh(qi.size(), 4);
       qi.delete(1);
       v = $sformatf("%p", qi); `checks(v, "'{'h0, 'h3, 'h4} ");
diff --git a/test_regress/t/t_stream_integer_type_unsup.v b/test_regress/t/t_stream_integer_type_unsup.v
index bb7c94533..91dec557e 100644
--- a/test_regress/t/t_stream_integer_type_unsup.v
+++ b/test_regress/t/t_stream_integer_type_unsup.v
@@ -1,5 +1,5 @@
 // DESCRIPTION: Verilator: Verilog Test module
-// Ref. to  IEEE Std 1800-2017  11.4.14 & A.8.1
+// Ref. to IEEE 1800-2017 11.4.14 & A.8.1
 //
 // stream pack/unpack for integer_type only
 // slice_size ::= simple_type | constant_expression
diff --git a/test_regress/t/t_structu_dataType_assignment.v b/test_regress/t/t_structu_dataType_assignment.v
index 5839b375a..6f6a32d44 100644
--- a/test_regress/t/t_structu_dataType_assignment.v
+++ b/test_regress/t/t_structu_dataType_assignment.v
@@ -8,17 +8,17 @@
 
 module top();
 
-  typedef struct { // IEEE 1800-2017 SV CH:5.10
+  typedef struct { // IEEE 1800-2017 5.10
     int a;
     shortint b;
   } ab_struct;
 
-  typedef struct { // IEEE 1800-2017 SV CH:10.9.2
+  typedef struct { // IEEE 1800-2017 10.9.2
   int x;
   int y;
   } st_struct;
 
-  typedef struct { // IEEE 1800-2017 SV CH:10.9.2
+  typedef struct { // IEEE 1800-2017 10.9.2
     logic [7:0] a;
     bit b;
     bit signed [31:0] c;
@@ -26,7 +26,7 @@ module top();
   } sa_struct;
 
 
-  typedef struct { // IEEE 1800-2017 SV CH:10.9.2
+  typedef struct { // IEEE 1800-2017 10.9.2
     int A;
     struct {
     int B, C;
@@ -34,7 +34,7 @@ module top();
   } DEF_struct;
 
 
-  typedef struct { // IEEE 1800-2017 SV CH:10.9.2
+  typedef struct { // IEEE 1800-2017 10.9.2
     int A;
     struct {
       int B, C;
diff --git a/test_regress/t/t_structu_dataType_assignment_bad.v b/test_regress/t/t_structu_dataType_assignment_bad.v
index 6ab523bbf..4733d46ca 100644
--- a/test_regress/t/t_structu_dataType_assignment_bad.v
+++ b/test_regress/t/t_structu_dataType_assignment_bad.v
@@ -9,7 +9,7 @@
 module top();
 
 
-  typedef struct { // IEEE 1800-2017 SV CH:10.9.2
+  typedef struct { // IEEE 1800-2017 10.9.2
     int A;
     struct {
     int B, C;
diff --git a/test_regress/t/t_sys_readmem_bad_end.out b/test_regress/t/t_sys_readmem_bad_end.out
index 4c6aaf01f..a9de0a692 100644
--- a/test_regress/t/t_sys_readmem_bad_end.out
+++ b/test_regress/t/t_sys_readmem_bad_end.out
@@ -1,2 +1,2 @@
-%Warning: t/t_sys_readmem_bad_end.mem:12: $readmem file ended before specified final address (IEEE 2017 21.4)
+%Warning: t/t_sys_readmem_bad_end.mem:12: $readmem file ended before specified final address (IEEE 1800-2017 21.4)
 *-* All Finished *-*

From 4cc42133b51d294e66b22e68bfb93b349fd2b74d Mon Sep 17 00:00:00 2001
From: Wilson Snyder 
Date: Thu, 19 Oct 2023 20:13:27 -0400
Subject: [PATCH 097/157] Internals: Rename some parser rules. No functional
 change.

---
 src/verilog.y | 107 ++++++++++++++++++++++++--------------------------
 1 file changed, 52 insertions(+), 55 deletions(-)

diff --git a/src/verilog.y b/src/verilog.y
index cfc01f62a..3bd0218ab 100644
--- a/src/verilog.y
+++ b/src/verilog.y
@@ -1758,7 +1758,7 @@ program_generate_item:           // ==IEEE: program_generate_item
         |       generate_region                         { $$ = $1; }
                                 // not in IEEE, but presumed so can do yBEGIN ... yEND
         |       genItemBegin                            { $$ = $1; }
-        |       elaboration_system_task                 { $$ = $1; }
+        |       severity_system_task                    { $$ = $1; }
         ;
 
 extern_tf_declaration:           // ==IEEE: extern_tf_declaration
@@ -2397,7 +2397,7 @@ data_declaration:        // ==IEEE: data_declaration
         //                      // "yVIRTUAL yID yID" looks just like a data_declaration
         //                      // Therefore the virtual_interface_declaration term isn't used
         //                      // 1800-2009:
-        |       net_type_declaration                    { $$ = $1; }
+        |       nettype_declaration                     { $$ = $1; }
         |       vlTag                                   { $$ = nullptr; }
         ;
 
@@ -2489,15 +2489,15 @@ data_declarationVarFrontClass:  // IEEE: part of data_declaration (for class_pro
         //                      // = class_new is in variable_decl_assignment
         ;
 
-net_type_declaration:  // IEEE: net_type_declaration
-                yNETTYPE data_type idAny/*net_type_identifier*/ ';'
+nettype_declaration:  // IEEE: nettype_declaration/net_type_declaration
+                yNETTYPE data_type idAny/*nettype_identifier*/ ';'
                         { $$ = nullptr; BBUNSUP($1, "Unsupported: nettype"); }
         //                      // package_scope part of data_type
         |       yNETTYPE data_type idAny yWITH__ETC packageClassScopeE id/*tf_identifier*/ ';'
                         { $$ = nullptr; BBUNSUP($1, "Unsupported: nettype"); }
-        |       yNETTYPE packageClassScopeE id/*net_type_identifier*/ idAny/*net_type_identifier*/ ';'
+        |       yNETTYPE packageClassScopeE id/*nettype_identifier*/ idAny/*nettype_identifier*/ ';'
                         { $$ = nullptr; BBUNSUP($1, "Unsupported: nettype"); }
-        |       yNETTYPE packageClassScopeE id/*net_type_identifier*/ idAny/*net_type_identifier*/
+        |       yNETTYPE packageClassScopeE id/*nettype_identifier*/ idAny/*nettype_identifier*/
         /*cont*/   yWITH__ETC packageClassScopeE id/*tf_identifier*/ ';'
                         { $$ = nullptr; BBUNSUP($1, "Unsupported: nettype"); }
         ;
@@ -2653,7 +2653,7 @@ module_common_item:      // ==IEEE: module_common_item
         |       always_construct                        { $$ = $1; }
         |       loop_generate_construct                 { $$ = $1; }
         |       conditional_generate_construct          { $$ = $1; }
-        |       elaboration_system_task                 { $$ = $1; }
+        |       severity_system_task                    { $$ = $1; }
         |       sigAttrScope                            { $$ = nullptr; }
         //
         |       error ';'                               { $$ = nullptr; }
@@ -3222,7 +3222,7 @@ cellpinListE:
                 { VARRESET_LIST(UNKNOWN); } cellpinItListE   { $$ = $2; VARRESET_NONLIST(UNKNOWN); }
         ;
 
-cellparamItListE:         // IEEE: list_of_parameter_assignmente
+cellparamItListE:         // IEEE: list_of_parameter_value_assignments/list_of_parameter_assignments
                 cellparamItemE                          { $$ = $1; }
         |       cellparamItListE ',' cellparamItemE     { $$ = addNextNull($1, $3); }
         ;
@@ -3798,11 +3798,11 @@ case_itemList:       // IEEE: { case_item + ... }
         |       case_itemList yDEFAULT colon stmtBlock          { $$ = $1->addNext(new AstCaseItem{$2, nullptr, $4}); }
         ;
 
-case_inside_itemList:        // IEEE: { case_inside_item + open_range_list ... }
-                open_range_list colon stmtBlock                 { $$ = new AstCaseItem{$2, $1, $3}; }
+case_inside_itemList:        // IEEE: { case_inside_item + range_list ... }
+                range_list colon stmtBlock                      { $$ = new AstCaseItem{$2, $1, $3}; }
         |       yDEFAULT colon stmtBlock                        { $$ = new AstCaseItem{$1, nullptr, $3}; }
         |       yDEFAULT stmtBlock                              { $$ = new AstCaseItem{$1, nullptr, $2}; }
-        |       case_inside_itemList open_range_list colon stmtBlock { $$ = $1->addNext(new AstCaseItem{$3, $2, $4}); }
+        |       case_inside_itemList range_list colon stmtBlock { $$ = $1->addNext(new AstCaseItem{$3, $2, $4}); }
         |       case_inside_itemList yDEFAULT stmtBlock         { $$ = $1->addNext(new AstCaseItem{$2, nullptr, $3}); }
         |       case_inside_itemList yDEFAULT colon stmtBlock   { $$ = $1->addNext(new AstCaseItem{$2, nullptr, $4}); }
         ;
@@ -3813,16 +3813,12 @@ rand_case_itemList:       // IEEE: { rand_case_item + ... }
         |       rand_case_itemList expr colon stmtBlock         { $$ = $1->addNext(new AstCaseItem{$3, $2, $4}); }
         ;
 
-open_range_list:     // ==IEEE: open_range_list + open_value_range
-                open_value_range                        { $$ = $1; }
-        |       open_range_list ',' open_value_range    { $$ = $1->addNext($3); }
-        ;
-
-open_value_range:    // ==IEEE: open_value_range
+range_list:     // ==IEEE: range_list/open_range_list + value_range/open_value_range
                 value_range                             { $$ = $1; }
+        |       range_list ',' value_range              { $$ = $1->addNext($3); }
         ;
 
-value_range:         // ==IEEE: value_range
+value_range:         // ==IEEE: value_range/open_value_range
                 expr                                    { $$ = $1; }
         |       '[' expr ':' expr ']'                   { $$ = new AstInsideRange{$1, $2, $4}; }
         ;
@@ -4326,12 +4322,12 @@ system_f_call_or_t:      // IEEE: part of system_tf_call (can be task
         |       yD_VALUEPLUSARGS '(' expr ',' expr ')'  { $$ = new AstValuePlusArgs{$1, $3, $5}; }
         ;
 
-elaboration_system_task: // IEEE: elaboration_system_task (1800-2009)
+severity_system_task: // IEEE: severity_system_task/elaboration_severity_system_task (1800-2009)
         //                      // TODO: These currently just make initial statements, should instead give runtime error
-                elaboration_system_task_guts ';'        { $$ = new AstInitial{$1, $1}; }
+                severity_system_task_guts ';'           { $$ = new AstInitial{$1, $1}; }
         ;
 
-elaboration_system_task_guts:    // IEEE: part of elaboration_system_task (1800-2009)
+severity_system_task_guts:    // IEEE: part of severity_system_task (1800-2009)
         //                      // $fatal first argument is exit number, must be constant
                 yD_INFO parenE                          { $$ = new AstElabDisplay{$1, VDisplayType::DT_INFO, nullptr}; }
         |       yD_INFO '(' exprList ')'                { $$ = new AstElabDisplay{$1, VDisplayType::DT_INFO, $3}; }
@@ -4817,7 +4813,7 @@ expr:                // IEEE: part of expression/constant_expression/
         |       ~l~expr '?' ~r~expr ':' ~r~expr         { $$ = new AstCond{$2, $1, $3, $5}; }
         //
         //                      // IEEE: inside_expression
-        |       ~l~expr yINSIDE '{' open_range_list '}' { $$ = new AstInside{$2, $1, $4}; }
+        |       ~l~expr yINSIDE '{' range_list '}'      { $$ = new AstInside{$2, $1, $4}; }
         //
         //                      // IEEE: tagged_union_expression
         //UNSUP yTAGGED id/*member*/ %prec prTAGGED             { UNSUP }
@@ -4833,7 +4829,8 @@ expr:                // IEEE: part of expression/constant_expression/
         //
         //                      // IEEE: "... hierarchical_identifier select"  see below
         //
-        //                      // IEEE: empty_queue (IEEE 1800-2017 empty_unpacked_array_concatenation)
+        //                      // IEEE: empty_unpacked_array_concatenation
+        //                      // IEEE: (aka empty_queue, empty_unpacked_array_concatenation)
         |       '{' '}'                                 { $$ = new AstEmptyQueue{$1}; }
         //
         //                      // IEEE: concatenation/constant_concatenation
@@ -6325,7 +6322,7 @@ boolean_abbrev:  // ==IEEE: boolean_abbrev
         |       yP_BRAPLUSKET
                         { $$ = new AstConst{$1, AstConst::BitFalse{}};
                           BBUNSUP($1, "Unsupported: [+] boolean abbrev expression"); }
-        //                      // IEEE: non_consecutive_repetition
+        //                      // IEEE: nonconsecutive_repetition/non_consecutive_repetition
         |       yP_BRAEQ constExpr ']'
                         { $$ = $2; BBUNSUP($1, "Unsupported: [= boolean abbrev expression"); }
         |       yP_BRAEQ constExpr ':' constExpr ']'
@@ -6438,13 +6435,13 @@ bins_or_options:  // ==IEEE: bins_or_options
         //                      // Superset of IEEE - we allow []'s in more places
                 coverage_option                         { $$ = $1; }
         //                      // Can't use wildcardE as results in conflicts
-        |       bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' iffE
+        |       bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE
                         { $$ = nullptr; BBUNSUP($4, "Unsupported: cover bin specification"); }
-        |       bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' yWITH__CUR '{' cgexpr '}' iffE
+        |       bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__CUR '{' cgexpr '}' iffE
                         { $$ = nullptr; BBUNSUP($8, "Unsupported: cover bin 'with' specification"); }
-        |       yWILDCARD bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' iffE
+        |       yWILDCARD bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE
                         { $$ = nullptr; BBUNSUP($5, "Unsupported: cover bin 'wildcard' specification"); }
-        |       yWILDCARD bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' yWITH__CUR '{' cgexpr '}' iffE
+        |       yWILDCARD bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__CUR '{' cgexpr '}' iffE
                         { $$ = nullptr; BBUNSUP($9, "Unsupported: cover bin 'wildcard' 'with' specification"); }
         //
         //                      // cgexpr part of trans_list
@@ -6623,51 +6620,51 @@ hierarchical_btf_identifier:  // ==IEEE: hierarchical_btf_identifier
 // Randsequence
 
 randsequence_statement:  // ==IEEE: randsequence_statement
-                yRANDSEQUENCE '(' ')' productionList yENDSEQUENCE
+                yRANDSEQUENCE '(' ')' rs_productionList yENDSEQUENCE
                         { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence"); }
-        |       yRANDSEQUENCE '(' id/*production_identifier*/ ')' productionList yENDSEQUENCE
+        |       yRANDSEQUENCE '(' id/*rs_production_identifier*/ ')' rs_productionList yENDSEQUENCE
                         { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence"); }
         ;
 
-productionList:  // IEEE: production+
-                production                              { $$ = $1; }
-        |       productionList production               { $$ = addNextNull($1, $2); }
+rs_productionList:  // IEEE: rs_production+
+                rs_production                           { $$ = $1; }
+        |       rs_productionList rs_production         { $$ = addNextNull($1, $2); }
         ;
 
-production:  // ==IEEE: production
-                productionFront ':' rs_ruleList ';'
+rs_production:  // ==IEEE: rs_production
+                rs_productionFront ':' rs_ruleList ';'
                         { // TODO makes a function, probably want a new Ast type instead
                           SYMP->popScope($$);
                           $$ = nullptr; BBUNSUP($2, "Unsupported: randsequence production"); }
         ;
 
-productionFront:  // IEEE: part of production
+rs_productionFront:  // IEEE: part of rs_production
                 funcId/*production_identifier*/         { $$ = $1; }
         |       funcId '(' tf_port_listE ')'            { $$ = $1; $$->addStmtsp($3); }
         ;
 
-rs_ruleList:  // IEEE: rs_rule+ part of production
+rs_ruleList:  // IEEE: rs_rule+ part of rs_production
                 rs_rule                                 { $$ = $1; }
         |       rs_ruleList '|' rs_rule                 { $$ = addNextNull($1, $3); }
         ;
 
 rs_rule:  // ==IEEE: rs_rule
                 rs_production_list                      { $$ = $1; }
-        |       rs_production_list yP_COLONEQ weight_specification
+        |       rs_production_list yP_COLONEQ rs_weight_specification
                         { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence rule"); }
-        |       rs_production_list yP_COLONEQ weight_specification rs_code_block
+        |       rs_production_list yP_COLONEQ rs_weight_specification rs_code_block
                         { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence rule"); }
         ;
 
 rs_production_list:  // ==IEEE: rs_production_list
                 rs_prodList                             { $$ = $1; }
-        |       yRAND yJOIN /**/         production_item production_itemList
+        |       yRAND yJOIN rs_production_item rs_production_itemList
                         { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence production list"); }
-        |       yRAND yJOIN '(' expr ')' production_item production_itemList
+        |       yRAND yJOIN '(' expr ')' rs_production_item rs_production_itemList
                         { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence production list"); }
         ;
 
-weight_specification:  // ==IEEE: weight_specification
+rs_weight_specification:  // ==IEEE: rs_weight_specification
                 intnumAsConst                           { $$ = $1; }
         |       idClassSel/*ps_identifier*/             { $$ = $1; }
         |       '(' expr ')'                            { $$ = $2; }
@@ -6694,27 +6691,27 @@ rs_prodList:  // IEEE: rs_prod+
         ;
 
 rs_prod:  // ==IEEE: rs_prod
-                production_item                         { $$ = $1; }
+                rs_production_item                       { $$ = $1; }
         |       rs_code_block                           { $$ = $1; }
         //                      // IEEE: rs_if_else
-        |       yIF '(' expr ')' production_item %prec prLOWER_THAN_ELSE
+        |       yIF '(' expr ')' rs_production_item %prec prLOWER_THAN_ELSE
                         { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence if"); }
-        |       yIF '(' expr ')' production_item yELSE production_item
+        |       yIF '(' expr ')' rs_production_item yELSE rs_production_item
                         { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence if"); }
         //                      // IEEE: rs_repeat
-        |       yREPEAT '(' expr ')' production_item
+        |       yREPEAT '(' expr ')' rs_production_item
                         { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence repeat"); }
         //                      // IEEE: rs_case
         |       yCASE '(' expr ')' rs_case_itemList yENDCASE
                         { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence case"); }
         ;
 
-production_itemList:  // IEEE: production_item+
-                production_item                         { $$ = $1; }
-        |       production_itemList production_item     { $$ = addNextNull($1, $2); }
+rs_production_itemList:  // IEEE: rs_production_item+
+                rs_production_item                         { $$ = $1; }
+        |       rs_production_itemList rs_production_item  { $$ = addNextNull($1, $2); }
         ;
 
-production_item:  // ==IEEE: production_item
+rs_production_item:  // ==IEEE: rs_production_item
                 id/*production_identifier*/
                         { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence production id"); }
         |       id/*production_identifier*/ '(' list_of_argumentsE ')'
@@ -6727,11 +6724,11 @@ rs_case_itemList:  // IEEE: rs_case_item+
         ;
 
 rs_case_item:  // ==IEEE: rs_case_item
-                caseCondList ':' production_item ';'
+                caseCondList ':' rs_production_item ';'
                         { $$ = nullptr; BBUNSUP($2, "Unsupported: randsequence case item"); }
-        |       yDEFAULT production_item ';'
+        |       yDEFAULT rs_production_item ';'
                         { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence case item"); }
-        |       yDEFAULT ':' production_item ';'
+        |       yDEFAULT ':' rs_production_item ';'
                         { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence case item"); }
         ;
 
@@ -6813,7 +6810,7 @@ checker_generate_item:  // ==IEEE: checker_generate_item
         |       c_conditional_generate_construct        { $$ = $1; }
         |       c_generate_region                       { $$ = $1; }
         //
-        |       elaboration_system_task                 { $$ = $1; }
+        |       severity_system_task                    { $$ = $1; }
         ;
 
 //UNSUPchecker_instantiation:
@@ -7148,7 +7145,7 @@ constraint_expression:  // ==IEEE: constraint_expression
         |       ySOFT expr/*expression_or_dist*/ ';'    { $$ = nullptr; /*UNSUP-no-UVM*/ }
         //                      // 1800-2012:
         //                      // IEEE: uniqueness_constraint ';'
-        |       yUNIQUE '{' open_range_list '}'         { $$ = nullptr; /*UNSUP-no-UVM*/ }
+        |       yUNIQUE '{' range_list '}'              { $$ = nullptr; /*UNSUP-no-UVM*/ }
         //                      // IEEE: expr yP_MINUSGT constraint_set
         //                      // Conflicts with expr:"expr yP_MINUSGT expr"; rule moved there
         //

From 05bb7fa821858e40dcc49d9fdc33c96ed6e77eb7 Mon Sep 17 00:00:00 2001
From: Wilson Snyder 
Date: Fri, 20 Oct 2023 02:37:11 -0400
Subject: [PATCH 098/157] Tests: Use UVM with UVM_NO_DPI defined

---
 test_regress/t/t_uvm_all.v       |   2 +
 test_regress/t/t_uvm_pkg_all.vh  | 131 +++++++++++++++++++++----------
 test_regress/t/t_uvm_pkg_todo.vh | 131 +++++++++++++++++++++----------
 test_regress/t/t_uvm_todo.pl     |   1 +
 test_regress/t/t_uvm_todo.v      |   2 +
 5 files changed, 185 insertions(+), 82 deletions(-)

diff --git a/test_regress/t/t_uvm_all.v b/test_regress/t/t_uvm_all.v
index 32f1ff78c..594c95679 100644
--- a/test_regress/t/t_uvm_all.v
+++ b/test_regress/t/t_uvm_all.v
@@ -4,6 +4,8 @@
 // any use, without warranty, 2023 by Wilson Snyder.
 // SPDX-License-Identifier: CC0-1.0
 
+`define UVM_NO_DPI
+
 `include "t_uvm_pkg_all.vh"
 
 module t(/*AUTOARG*/);
diff --git a/test_regress/t/t_uvm_pkg_all.vh b/test_regress/t/t_uvm_pkg_all.vh
index a2fd611b6..2c97fecb3 100644
--- a/test_regress/t/t_uvm_pkg_all.vh
+++ b/test_regress/t/t_uvm_pkg_all.vh
@@ -35,39 +35,91 @@
 package uvm_pkg;
 parameter int UVM_HDL_MAX_WIDTH = 1024;
 typedef logic [UVM_HDL_MAX_WIDTH-1:0] uvm_hdl_data_t;
-  import "DPI-C" context function int uvm_hdl_check_path(string path);
-  import "DPI-C" context function int uvm_hdl_deposit(string path, uvm_hdl_data_t value);
-  import "DPI-C" context function int uvm_hdl_force(string path, uvm_hdl_data_t value);
-  task uvm_hdl_force_time(string path, uvm_hdl_data_t value, time force_time = 0);
-    if (force_time == 0) begin
-      void'(uvm_hdl_deposit(path, value));
-      return;
-    end
-    if (!uvm_hdl_force(path, value))
-      return;
-    #force_time;
-    void'(uvm_hdl_release_and_read(path, value));
+  function int uvm_hdl_check_path(string path);
+    uvm_report_fatal("UVM_HDL_CHECK_PATH",
+      $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
+    return 0;
+  endfunction
+  function int uvm_hdl_deposit(string path, uvm_hdl_data_t value);
+    uvm_report_fatal("UVM_HDL_DEPOSIT",
+      $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
+    return 0;
+  endfunction
+  function int uvm_hdl_force(string path, uvm_hdl_data_t value);
+    uvm_report_fatal("UVM_HDL_FORCE",
+      $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
+    return 0;
+  endfunction
+  task uvm_hdl_force_time(string path, uvm_hdl_data_t value, time force_time=0);
+    uvm_report_fatal("UVM_HDL_FORCE_TIME",
+      $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
   endtask
-  import "DPI-C" context function int uvm_hdl_release_and_read(string path, inout uvm_hdl_data_t value);
-  import "DPI-C" context function int uvm_hdl_release(string path);
-  import "DPI-C" context function int uvm_hdl_read(string path, output uvm_hdl_data_t value);
-import "DPI-C" function string uvm_dpi_get_next_arg_c (int init);
-import "DPI-C" function string uvm_dpi_get_tool_name_c ();
-import "DPI-C" function string uvm_dpi_get_tool_version_c ();
+  function int uvm_hdl_release(string path, output uvm_hdl_data_t value);
+    uvm_report_fatal("UVM_HDL_RELEASE",
+      $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
+    return 0;
+  endfunction
+  function int uvm_hdl_read(string path, output uvm_hdl_data_t value);
+    uvm_report_fatal("UVM_HDL_READ",
+      $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
+    return 0;
+  endfunction
 function string uvm_dpi_get_next_arg(int init=0);
-  return uvm_dpi_get_next_arg_c(init);
+  return "";
 endfunction
 function string uvm_dpi_get_tool_name();
-  return uvm_dpi_get_tool_name_c();
+  return "?";
 endfunction
 function string uvm_dpi_get_tool_version();
-  return uvm_dpi_get_tool_version_c();
+  return "?";
+endfunction
+function chandle uvm_dpi_regcomp(string regex); return null; endfunction
+function int uvm_dpi_regexec(chandle preg, string str); return 0; endfunction
+function void uvm_dpi_regfree(chandle preg); endfunction
+function int uvm_re_match(string re, string str);
+  int e, es, s, ss;
+  string tmp;
+  e  = 0; s  = 0;
+  es = 0; ss = 0;
+  if(re.len() == 0)
+    return 0;
+  if(re[0] == "^")
+    re = re.substr(1, re.len()-1);
+  while (s != str.len() && re.getc(e) != "*") begin
+    if ((re.getc(e) != str.getc(s)) && (re.getc(e) != "?"))
+      return 1;
+    e++; s++;
+  end
+  while (s != str.len()) begin
+    if (re.getc(e) == "*") begin
+      e++;
+      if (e == re.len()) begin
+        return 0;
+      end
+      es = e;
+      ss = s+1;
+    end
+    else if (re.getc(e) == str.getc(s) || re.getc(e) == "?") begin
+      e++;
+      s++;
+    end
+    else begin
+      e = es;
+      s = ss++;
+    end
+  end
+  while (e < re.len() && re.getc(e) == "*")
+    e++;
+  if(e == re.len()) begin
+    return 0;
+  end
+  else begin
+    return 1;
+  end
+endfunction
+function string uvm_glob_to_re(string glob);
+  return glob;
 endfunction
-import "DPI-C" function chandle uvm_dpi_regcomp(string regex);
-import "DPI-C" function int uvm_dpi_regexec(chandle preg, string str);
-import "DPI-C" function void uvm_dpi_regfree(chandle preg);
-import "DPI-C" context function int uvm_re_match(string re, string str);
-import "DPI-C" context function string uvm_glob_to_re(string glob);
   typedef class uvm_cmdline_processor;
 parameter string UVM_VERSION_STRING = "Accellera:1800.2-2017:UVM:1.0";
 function string uvm_revision_string();
@@ -12920,22 +12972,13 @@ task uvm_root::run_test(string test_name="");
         testname_plusarg = 0;
         uvm_objection::m_init_objections();
         m_do_dump_args();
-        test_name_count = clp.get_arg_values("+UVM_TESTNAME=", test_names);
-        if (test_name_count > 0) begin
-                test_name = test_names[0];
+        if ($value$plusargs("UVM_TESTNAME=%s", test_name)) begin
+   begin
+     if (uvm_report_enabled(UVM_NONE,UVM_INFO,"NO_DPI_TSTNAME"))
+       uvm_report_info ("NO_DPI_TSTNAME", "UVM_NO_DPI defined--getting UVM_TESTNAME directly, without DPI", UVM_NONE, "t/uvm/src/base/uvm_root.svh", 517, "", 1);
+   end
                 testname_plusarg = 1;
         end
-        if (test_name_count > 1) begin
-                string test_list;
-                string sep;
-                for (int i = 0; i < test_names.size(); i++) begin
-                        if (i != 0)
-                                sep = ", ";
-                        test_list = {test_list, sep, test_names[i]};
-                end
-                uvm_report_warning("MULTTST",
-                        $sformatf("Multiple (%0d) +UVM_TESTNAME arguments provided on the command line.  '%s' will be used.  Provided list: %s.", test_name_count, test_name, test_list), UVM_NONE);
-        end
         if (test_name != "") begin
                 if(m_children.exists("uvm_test_top")) begin
                         uvm_report_fatal("TTINST",
@@ -13308,7 +13351,9 @@ function void uvm_root::m_check_verbosity();
         int verb_count;
         int plusarg;
         int verbosity = UVM_MEDIUM;
-        verb_count = clp.get_arg_values("+UVM_VERBOSITY=", verb_settings);
+        verb_count = $value$plusargs("UVM_VERBOSITY=%s",verb_string);
+        if (verb_count)
+                verb_settings.push_back(verb_string);
         if (verb_count > 0) begin
                 verb_string = verb_settings[0];
                 plusarg = 1;
@@ -15425,6 +15470,10 @@ class uvm_component_name_check_visitor extends uvm_visitor#(uvm_component);
   virtual function void begin_v();
     uvm_coreservice_t cs = uvm_coreservice_t::get();
     _root =  cs.get_root();
+   begin
+     if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/COMP/NAMECHECK"))
+       uvm_report_info ("UVM/COMP/NAMECHECK", "This implementation of the component name checks requires DPI to be enabled", UVM_NONE, "t/uvm/src/base/uvm_traversal.svh", 289, "", 1);
+   end
   endfunction
 endclass
 virtual class uvm_set_get_dap_base#(type T=int) extends uvm_object;
diff --git a/test_regress/t/t_uvm_pkg_todo.vh b/test_regress/t/t_uvm_pkg_todo.vh
index 30f708ef3..0d71f3de3 100644
--- a/test_regress/t/t_uvm_pkg_todo.vh
+++ b/test_regress/t/t_uvm_pkg_todo.vh
@@ -35,39 +35,91 @@
 package uvm_pkg;
 parameter int UVM_HDL_MAX_WIDTH = 1024;
 typedef logic [UVM_HDL_MAX_WIDTH-1:0] uvm_hdl_data_t;
-  import "DPI-C" context function int uvm_hdl_check_path(string path);
-  import "DPI-C" context function int uvm_hdl_deposit(string path, uvm_hdl_data_t value);
-  import "DPI-C" context function int uvm_hdl_force(string path, uvm_hdl_data_t value);
-  task uvm_hdl_force_time(string path, uvm_hdl_data_t value, time force_time = 0);
-    if (force_time == 0) begin
-      void'(uvm_hdl_deposit(path, value));
-      return;
-    end
-    if (!uvm_hdl_force(path, value))
-      return;
-    #force_time;
-    void'(uvm_hdl_release_and_read(path, value));
+  function int uvm_hdl_check_path(string path);
+    uvm_report_fatal("UVM_HDL_CHECK_PATH",
+      $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
+    return 0;
+  endfunction
+  function int uvm_hdl_deposit(string path, uvm_hdl_data_t value);
+    uvm_report_fatal("UVM_HDL_DEPOSIT",
+      $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
+    return 0;
+  endfunction
+  function int uvm_hdl_force(string path, uvm_hdl_data_t value);
+    uvm_report_fatal("UVM_HDL_FORCE",
+      $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
+    return 0;
+  endfunction
+  task uvm_hdl_force_time(string path, uvm_hdl_data_t value, time force_time=0);
+    uvm_report_fatal("UVM_HDL_FORCE_TIME",
+      $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
   endtask
-  import "DPI-C" context function int uvm_hdl_release_and_read(string path, inout uvm_hdl_data_t value);
-  import "DPI-C" context function int uvm_hdl_release(string path);
-  import "DPI-C" context function int uvm_hdl_read(string path, output uvm_hdl_data_t value);
-import "DPI-C" function string uvm_dpi_get_next_arg_c (int init);
-import "DPI-C" function string uvm_dpi_get_tool_name_c ();
-import "DPI-C" function string uvm_dpi_get_tool_version_c ();
+  function int uvm_hdl_release(string path, output uvm_hdl_data_t value);
+    uvm_report_fatal("UVM_HDL_RELEASE",
+      $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
+    return 0;
+  endfunction
+  function int uvm_hdl_read(string path, output uvm_hdl_data_t value);
+    uvm_report_fatal("UVM_HDL_READ",
+      $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
+    return 0;
+  endfunction
 function string uvm_dpi_get_next_arg(int init=0);
-  return uvm_dpi_get_next_arg_c(init);
+  return "";
 endfunction
 function string uvm_dpi_get_tool_name();
-  return uvm_dpi_get_tool_name_c();
+  return "?";
 endfunction
 function string uvm_dpi_get_tool_version();
-  return uvm_dpi_get_tool_version_c();
+  return "?";
+endfunction
+function chandle uvm_dpi_regcomp(string regex); return null; endfunction
+function int uvm_dpi_regexec(chandle preg, string str); return 0; endfunction
+function void uvm_dpi_regfree(chandle preg); endfunction
+function int uvm_re_match(string re, string str);
+  int e, es, s, ss;
+  string tmp;
+  e  = 0; s  = 0;
+  es = 0; ss = 0;
+  if(re.len() == 0)
+    return 0;
+  if(re[0] == "^")
+    re = re.substr(1, re.len()-1);
+  while (s != str.len() && re.getc(e) != "*") begin
+    if ((re.getc(e) != str.getc(s)) && (re.getc(e) != "?"))
+      return 1;
+    e++; s++;
+  end
+  while (s != str.len()) begin
+    if (re.getc(e) == "*") begin
+      e++;
+      if (e == re.len()) begin
+        return 0;
+      end
+      es = e;
+      ss = s+1;
+    end
+    else if (re.getc(e) == str.getc(s) || re.getc(e) == "?") begin
+      e++;
+      s++;
+    end
+    else begin
+      e = es;
+      s = ss++;
+    end
+  end
+  while (e < re.len() && re.getc(e) == "*")
+    e++;
+  if(e == re.len()) begin
+    return 0;
+  end
+  else begin
+    return 1;
+  end
+endfunction
+function string uvm_glob_to_re(string glob);
+  return glob;
 endfunction
-import "DPI-C" function chandle uvm_dpi_regcomp(string regex);
-import "DPI-C" function int uvm_dpi_regexec(chandle preg, string str);
-import "DPI-C" function void uvm_dpi_regfree(chandle preg);
-import "DPI-C" context function int uvm_re_match(string re, string str);
-import "DPI-C" context function string uvm_glob_to_re(string glob);
   typedef class uvm_cmdline_processor;
 parameter string UVM_VERSION_STRING = "Accellera:1800.2-2017:UVM:1.0";
 function string uvm_revision_string();
@@ -12926,22 +12978,13 @@ task uvm_root::run_test(string test_name="");
         testname_plusarg = 0;
         uvm_objection::m_init_objections();
         m_do_dump_args();
-        test_name_count = clp.get_arg_values("+UVM_TESTNAME=", test_names);
-        if (test_name_count > 0) begin
-                test_name = test_names[0];
+        if ($value$plusargs("UVM_TESTNAME=%s", test_name)) begin
+   begin
+     if (uvm_report_enabled(UVM_NONE,UVM_INFO,"NO_DPI_TSTNAME"))
+       uvm_report_info ("NO_DPI_TSTNAME", "UVM_NO_DPI defined--getting UVM_TESTNAME directly, without DPI", UVM_NONE, "t/uvm/src/base/uvm_root.svh", 517, "", 1);
+   end
                 testname_plusarg = 1;
         end
-        if (test_name_count > 1) begin
-                string test_list;
-                string sep;
-                for (int i = 0; i < test_names.size(); i++) begin
-                        if (i != 0)
-                                sep = ", ";
-                        test_list = {test_list, sep, test_names[i]};
-                end
-                uvm_report_warning("MULTTST",
-                        $sformatf("Multiple (%0d) +UVM_TESTNAME arguments provided on the command line.  '%s' will be used.  Provided list: %s.", test_name_count, test_name, test_list), UVM_NONE);
-        end
         if (test_name != "") begin
                 if(m_children.exists("uvm_test_top")) begin
                         uvm_report_fatal("TTINST",
@@ -13314,7 +13357,9 @@ function void uvm_root::m_check_verbosity();
         int verb_count;
         int plusarg;
         int verbosity = UVM_MEDIUM;
-        verb_count = clp.get_arg_values("+UVM_VERBOSITY=", verb_settings);
+        verb_count = $value$plusargs("UVM_VERBOSITY=%s",verb_string);
+        if (verb_count)
+                verb_settings.push_back(verb_string);
         if (verb_count > 0) begin
                 verb_string = verb_settings[0];
                 plusarg = 1;
@@ -15433,6 +15478,10 @@ class uvm_component_name_check_visitor extends uvm_visitor#(uvm_component);
   virtual function void begin_v();
     uvm_coreservice_t cs = uvm_coreservice_t::get();
     _root =  cs.get_root();
+   begin
+     if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/COMP/NAMECHECK"))
+       uvm_report_info ("UVM/COMP/NAMECHECK", "This implementation of the component name checks requires DPI to be enabled", UVM_NONE, "t/uvm/src/base/uvm_traversal.svh", 289, "", 1);
+   end
   endfunction
 endclass
 virtual class uvm_set_get_dap_base#(type T=int) extends uvm_object;
diff --git a/test_regress/t/t_uvm_todo.pl b/test_regress/t/t_uvm_todo.pl
index 9fb3de36f..5d005a5d2 100755
--- a/test_regress/t/t_uvm_todo.pl
+++ b/test_regress/t/t_uvm_todo.pl
@@ -17,6 +17,7 @@ compile(
                  "-Wno-REALCVT", # TODO note mostly related to $realtime - could suppress or fix upstream
                  "-Wno-ZERODLY", # TODO issue #4494, add support
                  ],
+    make_flags => '-k -j ' . ::max_procs(),
     verilator_make_gmake => 0,
     );
 
diff --git a/test_regress/t/t_uvm_todo.v b/test_regress/t/t_uvm_todo.v
index 20bd2827d..c702f39f3 100644
--- a/test_regress/t/t_uvm_todo.v
+++ b/test_regress/t/t_uvm_todo.v
@@ -4,6 +4,8 @@
 // any use, without warranty, 2023 by Wilson Snyder.
 // SPDX-License-Identifier: CC0-1.0
 
+`define UVM_NO_DPI
+
 `include "t_uvm_pkg_todo.vh"
 
 module t(/*AUTOARG*/);

From 83a0085c4d799292350254c437c834d3fa6d302b Mon Sep 17 00:00:00 2001
From: Aleksander Kiryk 
Date: Fri, 20 Oct 2023 13:13:57 +0200
Subject: [PATCH 099/157] Support `wait fork` (#4586)

---
 include/verilated_types.h        | 12 +++++++++---
 src/V3AstNodeExpr.h              |  1 +
 src/V3AstNodeOther.h             |  1 +
 src/V3EmitCFunc.h                |  2 +-
 src/V3EmitV.cpp                  |  2 +-
 src/V3Timing.cpp                 | 18 ++++++++++++++++--
 src/V3Width.cpp                  | 12 ++++++++++--
 test_regress/t/t_uvm_pkg_todo.vh |  4 +---
 test_regress/t/t_wait_fork.out   |  6 ------
 test_regress/t/t_wait_fork.pl    | 11 +++++++----
 test_regress/t/t_wait_fork.v     | 11 +++++++----
 11 files changed, 54 insertions(+), 26 deletions(-)
 delete mode 100644 test_regress/t/t_wait_fork.out

diff --git a/include/verilated_types.h b/include/verilated_types.h
index b296689d9..da517c372 100644
--- a/include/verilated_types.h
+++ b/include/verilated_types.h
@@ -120,15 +120,21 @@ public:
     void attach(VlProcess* childp) { m_children.insert(childp); }
     void detach(VlProcess* childp) { m_children.erase(childp); }
 
-    int state() { return m_state; }
+    int state() const { return m_state; }
     void state(int s) { m_state = s; }
     void disable() {
         state(KILLED);
-        disable_fork();
+        disableFork();
     }
-    void disable_fork() {
+    void disableFork() {
         for (VlProcess* childp : m_children) childp->disable();
     }
+    bool completed() const { return state() == FINISHED || state() == KILLED; }
+    bool completedFork() const {
+        for (const VlProcess* const childp : m_children)
+            if (!childp->completed()) return false;
+        return true;
+    }
 };
 
 inline std::string VL_TO_STRING(const VlProcessRef& p) { return std::string("process"); }
diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h
index 37a360170..f9de8e512 100644
--- a/src/V3AstNodeExpr.h
+++ b/src/V3AstNodeExpr.h
@@ -617,6 +617,7 @@ public:
     string emitVerilog() override { V3ERROR_NA_RETURN(""); }
     string emitC() override { V3ERROR_NA_RETURN(""); }
     bool same(const AstNode* /*samep*/) const override { return true; }
+    bool isPure() override { return pure(); }
     bool pure() const { return m_pure; }
     void pure(bool flag) { m_pure = flag; }
 };
diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h
index 568a0f5b8..45946401b 100644
--- a/src/V3AstNodeOther.h
+++ b/src/V3AstNodeOther.h
@@ -3325,6 +3325,7 @@ public:
     explicit AstWaitFork(FileLine* fl)
         : ASTGEN_SUPER_WaitFork(fl) {}
     ASTGEN_MEMBERS_AstWaitFork;
+    bool isTimingControl() const override { return true; }
 };
 class AstWhile final : public AstNodeStmt {
     // @astgen op1 := precondsp : List[AstNode]
diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h
index 0de6e001b..dbf5026a0 100644
--- a/src/V3EmitCFunc.h
+++ b/src/V3EmitCFunc.h
@@ -613,7 +613,7 @@ public:
             puts("]);\n");
         }
     }
-    void visit(AstDisableFork* nodep) override { puts("vlProcess->disable_fork();\n"); }
+    void visit(AstDisableFork* nodep) override { puts("vlProcess->disableFork();\n"); }
     void visit(AstCReturn* nodep) override {
         puts("return (");
         iterateAndNextConstNull(nodep->lhsp());
diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp
index 38bca92ba..d8fc2b42e 100644
--- a/src/V3EmitV.cpp
+++ b/src/V3EmitV.cpp
@@ -408,7 +408,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
     void visit(AstCExpr* nodep) override {
         putfs(nodep, "$_CEXPR(");
         iterateAndNextConstNull(nodep->exprsp());
-        puts(");\n");
+        puts(")");
     }
     void visit(AstUCStmt* nodep) override {
         putfs(nodep, "$c(");
diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp
index 65948a526..ebeeb7fe9 100644
--- a/src/V3Timing.cpp
+++ b/src/V3Timing.cpp
@@ -275,6 +275,10 @@ private:
         visit(static_cast(nodep));
         addFlags(m_procp, T_FORCES_PROC | T_NEEDS_PROC);
     }
+    void visit(AstWaitFork* nodep) override {
+        visit(static_cast(nodep));
+        addFlags(m_procp, T_FORCES_PROC | T_NEEDS_PROC);
+    }
     void visit(AstCFunc* nodep) override {
         VL_RESTORER(m_procp);
         m_procp = nodep;
@@ -573,8 +577,11 @@ private:
     // Returns true if we are under a class or the given tree has any references to locals. These
     // are cases where static, globally-evaluated triggers are not suitable.
     bool needDynamicTrigger(AstNode* const nodep) const {
-        return m_classp || nodep->exists([](const AstNodeVarRef* const refp) {
-            return refp->varp()->isFuncLocal();
+        return m_classp || nodep->exists([](AstNode* const nodep) {
+            if (AstNodeVarRef* varp = VN_CAST(nodep, NodeVarRef)) {
+                return varp->varp()->isFuncLocal();
+            }
+            return !nodep->isPure();
         });
     }
     // Returns true if the given trigger expression needs a destructive post update after trigger
@@ -1050,6 +1057,13 @@ private:
         // var
         alwaysp->addNextHere(nodep);
     }
+    void visit(AstWaitFork* nodep) override {
+        AstCExpr* const exprp = new AstCExpr{nodep->fileline(), "vlProcess->completedFork()", 1};
+        exprp->pure(false);
+        AstWait* const waitp = new AstWait{nodep->fileline(), exprp, nullptr};
+        nodep->replaceWith(waitp);
+        VL_DO_DANGLING(nodep->deleteTree(), nodep);
+    }
     void visit(AstWait* nodep) override {
         // Wait on changed events related to the vars in the wait statement
         FileLine* const flp = nodep->fileline();
diff --git a/src/V3Width.cpp b/src/V3Width.cpp
index f5f9c85e8..30407d90d 100644
--- a/src/V3Width.cpp
+++ b/src/V3Width.cpp
@@ -693,6 +693,7 @@ private:
         if (nodep->fileline()->timingOn()) {
             if (v3Global.opt.timing().isSetFalse()) {
                 nodep->v3warn(E_NOTIMING, "Support for disable fork statement requires --timing");
+                VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
             } else if (!v3Global.opt.timing().isSetTrue()) {
                 nodep->v3warn(E_NEEDTIMINGOPT, "Use --timing or --no-timing to specify how "
                                                    << "disable fork should be handled");
@@ -700,8 +701,15 @@ private:
         }
     }
     void visit(AstWaitFork* nodep) override {
-        nodep->v3warn(E_UNSUPPORTED, "Unsupported: wait fork statements");
-        VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
+        if (nodep->fileline()->timingOn()) {
+            if (v3Global.opt.timing().isSetFalse()) {
+                nodep->v3warn(E_NOTIMING, "Support for disable fork statement requires --timing");
+                VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
+            } else if (!v3Global.opt.timing().isSetTrue()) {
+                nodep->v3warn(E_NEEDTIMINGOPT, "Use --timing or --no-timing to specify how "
+                                                   << "disable fork should be handled");
+            }
+        }
     }
     void visit(AstToLowerN* nodep) override {
         if (m_vup->prelim()) {
diff --git a/test_regress/t/t_uvm_pkg_todo.vh b/test_regress/t/t_uvm_pkg_todo.vh
index 0d71f3de3..c798374cc 100644
--- a/test_regress/t/t_uvm_pkg_todo.vh
+++ b/test_regress/t/t_uvm_pkg_todo.vh
@@ -14809,9 +14809,7 @@ class uvm_objection extends uvm_report_object;
       if (m_trace_mode)
         m_report(obj,source_obj,description,count,"all_dropped");
       all_dropped(obj,source_obj,description, count);
-//TODO issue #4465 - Support wait fork
-//TODO  %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:14761:7: Unsupported: wait fork statements
-//TODO      wait fork;
+      wait fork;
       if (m_source_count.exists(obj) && m_source_count[obj] == 0)
         m_source_count.delete(obj);
       if (m_total_count.exists(obj) && m_total_count[obj] == 0)
diff --git a/test_regress/t/t_wait_fork.out b/test_regress/t/t_wait_fork.out
deleted file mode 100644
index b9cf141c8..000000000
--- a/test_regress/t/t_wait_fork.out
+++ /dev/null
@@ -1,6 +0,0 @@
-%Error-UNSUPPORTED: t/t_wait_fork.v:17:7: Unsupported: wait fork statements
-                                        : ... note: In instance 't'
-   17 |       wait fork;
-      |       ^~~~
-                    ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
-%Error: Exiting due to
diff --git a/test_regress/t/t_wait_fork.pl b/test_regress/t/t_wait_fork.pl
index 0ca21a5ca..0db50fc52 100755
--- a/test_regress/t/t_wait_fork.pl
+++ b/test_regress/t/t_wait_fork.pl
@@ -10,10 +10,13 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
 
 scenarios(linter => 1);
 
-lint(
-    verilator_flags2 => ['--lint-only --timing'],
-    fails => 1,
-    expect_filename => $Self->{golden_filename},
+compile(
+    verilator_flags2 => ["--exe --main --timing"],
+    make_main => 0,
+    );
+
+execute(
+    check_finished => 1,
     );
 
 ok(1);
diff --git a/test_regress/t/t_wait_fork.v b/test_regress/t/t_wait_fork.v
index f404a53c2..65fbff20a 100644
--- a/test_regress/t/t_wait_fork.v
+++ b/test_regress/t/t_wait_fork.v
@@ -8,13 +8,16 @@ module t(/*AUTOARG*/);
 
    logic never;
 
+   integer n = 0;
+
    initial begin
-      fork
-         #10;
-         #10;
-      join_none
       disable fork;
+      fork
+         #10 if (n != 0) $stop; else n = 1;
+         #15 if (n != 1) $stop; else n = 2;
+      join_none
       wait fork;
+      if (n != 2) $stop;
       $write("*-* All Finished *-*\n");
       $finish;
    end

From c7a0613c57827f0f9267fbfb0a064b5133a76678 Mon Sep 17 00:00:00 2001
From: Mariusz Glebocki 
Date: Fri, 20 Oct 2023 21:47:09 +0200
Subject: [PATCH 100/157] Support Clang 16 (#4592)

---
 configure.ac              | 10 ++++++----
 include/verilated_types.h | 28 ++++++++++++++--------------
 2 files changed, 20 insertions(+), 18 deletions(-)

diff --git a/configure.ac b/configure.ac
index 4620e3b47..ade69cf7a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -371,10 +371,9 @@ _MY_CXX_CHECK_OPT(CFG_CXXFLAGS_WEXTRA,-Wthread-safety)
 AC_SUBST(CFG_CXXFLAGS_WEXTRA)
 
 # Flags for coroutine support for dynamic scheduling
-_MY_CXX_CHECK_IFELSE(
-  -fcoroutines-ts,
-  [CFG_CXXFLAGS_COROUTINES="-fcoroutines-ts"],
-  [CFG_CXXFLAGS_COROUTINES="-fcoroutines"])
+_MY_CXX_CHECK_SET(CFG_CXXFLAGS_COROUTINES,-fcoroutines-ts)
+_MY_CXX_CHECK_SET(CFG_CXXFLAGS_COROUTINES,-fcoroutines)
+_MY_CXX_CHECK_SET(CFG_CXXFLAGS_COROUTINES,-fcoroutines-ts -Wno-deprecated-experimental-coroutine)
 AC_SUBST(CFG_CXXFLAGS_COROUTINES)
 
 # HAVE_COROUTINES
@@ -442,7 +441,10 @@ m4_foreach([cflag],[
         [-mno-cet],
         [-Qunused-arguments],
         [-Wno-bool-operation],
+        [-Wno-c++11-narrowing],
         [-Wno-constant-logical-operand],
+        [-Wno-non-pod-varargs],
+        [-Wno-overloaded-virtual],
         [-Wno-parentheses-equality],
         [-Wno-shadow],
         [-Wno-sign-compare],
diff --git a/include/verilated_types.h b/include/verilated_types.h
index da517c372..4dd4505d4 100644
--- a/include/verilated_types.h
+++ b/include/verilated_types.h
@@ -250,20 +250,6 @@ template 
 class VlRandC final {
     T_Value m_remaining = 0;  // Number of values to pull before re-randomize
     T_Value m_lfsr = 1;  // LFSR state
-    // Polynomials are first listed at https://users.ece.cmu.edu/~koopman/lfsr/
-    static constexpr uint64_t s_polynomials[] = {
-        0x0ULL,  // 0 never used (constant, no randomization)
-        0x0ULL,  // 1
-        0x3ULL,        0x5ULL,       0x9ULL,        0x12ULL,       0x21ULL,
-        0x41ULL,       0x8eULL,      0x108ULL,      0x204ULL,      0x402ULL,
-        0x829ULL,      0x100dULL,    0x2015ULL,     0x4001ULL,
-        0x8016ULL,  // 16
-        0x10004ULL,    0x20040ULL,   0x40013ULL,    0x80004ULL,    0x100002ULL,
-        0x200001ULL,   0x400010ULL,  0x80000dULL,   0x1000004ULL,  0x2000023ULL,
-        0x4000013ULL,  0x8000004ULL, 0x10000002ULL, 0x20000029ULL, 0x40000004ULL,
-        0x80000057ULL,  // 32
-        0x100000029ULL  // 33
-    };
 
 public:
     // CONSTRUCTORS
@@ -274,6 +260,20 @@ public:
     // METHODS
     T_Value randomize(VlRNG& rngr) {
         if (VL_UNLIKELY(!m_remaining)) reseed(rngr);
+        // Polynomials are first listed at https://users.ece.cmu.edu/~koopman/lfsr/
+        static constexpr uint64_t s_polynomials[] = {
+            0x0ULL,  // 0 never used (constant, no randomization)
+            0x0ULL,  // 1
+            0x3ULL,        0x5ULL,       0x9ULL,        0x12ULL,       0x21ULL,
+            0x41ULL,       0x8eULL,      0x108ULL,      0x204ULL,      0x402ULL,
+            0x829ULL,      0x100dULL,    0x2015ULL,     0x4001ULL,
+            0x8016ULL,  // 16
+            0x10004ULL,    0x20040ULL,   0x40013ULL,    0x80004ULL,    0x100002ULL,
+            0x200001ULL,   0x400010ULL,  0x80000dULL,   0x1000004ULL,  0x2000023ULL,
+            0x4000013ULL,  0x8000004ULL, 0x10000002ULL, 0x20000029ULL, 0x40000004ULL,
+            0x80000057ULL,  // 32
+            0x100000029ULL  // 33
+        };
         constexpr uint32_t clogWidth = VL_CLOG2_CE_Q(T_numValues) + 1;
         constexpr uint32_t lfsrWidth = (clogWidth < 2) ? 2 : clogWidth;
         constexpr T_Value polynomial = static_cast(s_polynomials[lfsrWidth]);

From 7b12f6a1dd37632a3a6696d599d9947b0057ccf0 Mon Sep 17 00:00:00 2001
From: Krzysztof Bieganski 
Date: Sat, 21 Oct 2023 02:01:45 +0200
Subject: [PATCH 101/157] Support NBAs in non-inlined functions/tasks (#4496)
 (#4572)

---
 src/V3AstNodeOther.h                          |   6 +
 src/V3AstNodes.cpp                            |   2 +
 src/V3Delayed.cpp                             |   8 +-
 src/V3Sched.cpp                               | 187 ++++++++++--------
 src/V3Timing.cpp                              |  69 ++++++-
 test_regress/t/t_assigndly_dynamic.pl         |  32 +++
 test_regress/t/t_assigndly_dynamic.v          |  55 ++++++
 .../t/t_assigndly_dynamic_notiming.out        |   6 +
 .../t/t_assigndly_dynamic_notiming.pl         |  20 ++
 test_regress/t/t_assigndly_dynamic_notiming.v |  12 ++
 test_regress/t/t_uvm_pkg_todo.vh              |   4 +-
 11 files changed, 306 insertions(+), 95 deletions(-)
 create mode 100755 test_regress/t/t_assigndly_dynamic.pl
 create mode 100644 test_regress/t/t_assigndly_dynamic.v
 create mode 100644 test_regress/t/t_assigndly_dynamic_notiming.out
 create mode 100755 test_regress/t/t_assigndly_dynamic_notiming.pl
 create mode 100644 test_regress/t/t_assigndly_dynamic_notiming.v

diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h
index 45946401b..61c66ba79 100644
--- a/src/V3AstNodeOther.h
+++ b/src/V3AstNodeOther.h
@@ -1195,6 +1195,8 @@ class AstNetlist final : public AstNode {
     AstCFunc* m_evalNbap = nullptr;  // The '_eval__nba' function
     AstVarScope* m_dpiExportTriggerp = nullptr;  // The DPI export trigger variable
     AstVar* m_delaySchedulerp = nullptr;  // The delay scheduler variable
+    AstVarScope* m_nbaEventp = nullptr;  // The NBA event variable
+    AstVarScope* m_nbaEventTriggerp = nullptr;  // If set to 1, the NBA event should get triggered
     AstTopScope* m_topScopep = nullptr;  // The singleton AstTopScope under the top module
     VTimescale m_timeunit;  // Global time unit
     VTimescale m_timeprecision;  // Global time precision
@@ -1224,6 +1226,10 @@ public:
     void dpiExportTriggerp(AstVarScope* varScopep) { m_dpiExportTriggerp = varScopep; }
     AstVar* delaySchedulerp() const { return m_delaySchedulerp; }
     void delaySchedulerp(AstVar* const varScopep) { m_delaySchedulerp = varScopep; }
+    AstVarScope* nbaEventp() const { return m_nbaEventp; }
+    void nbaEventp(AstVarScope* const varScopep) { m_nbaEventp = varScopep; }
+    AstVarScope* nbaEventTriggerp() const { return m_nbaEventTriggerp; }
+    void nbaEventTriggerp(AstVarScope* const varScopep) { m_nbaEventTriggerp = varScopep; }
     void stdPackagep(AstPackage* const packagep) { m_stdPackagep = packagep; }
     AstPackage* stdPackagep() const { return m_stdPackagep; }
     AstTopScope* topScopep() const { return m_topScopep; }
diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp
index bddc62d9d..09dd075c2 100644
--- a/src/V3AstNodes.cpp
+++ b/src/V3AstNodes.cpp
@@ -1936,6 +1936,8 @@ const char* AstNetlist::broken() const {
     BROKEN_RTN(m_dpiExportTriggerp && !m_dpiExportTriggerp->brokeExists());
     BROKEN_RTN(m_topScopep && !m_topScopep->brokeExists());
     BROKEN_RTN(m_delaySchedulerp && !m_delaySchedulerp->brokeExists());
+    BROKEN_RTN(m_nbaEventp && !m_nbaEventp->brokeExists());
+    BROKEN_RTN(m_nbaEventTriggerp && !m_nbaEventTriggerp->brokeExists());
     return nullptr;
 }
 AstPackage* AstNetlist::dollarUnitPkgAddp() {
diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp
index 3a829d22d..35f18d0b0 100644
--- a/src/V3Delayed.cpp
+++ b/src/V3Delayed.cpp
@@ -520,8 +520,12 @@ private:
         m_nextDlyp
             = VN_CAST(nodep->nextp(), AssignDly);  // Next assignment in same block, maybe nullptr.
         if (m_cfuncp) {
-            nodep->v3warn(E_UNSUPPORTED,
-                          "Unsupported: Delayed assignment inside public function/task");
+            if (!v3Global.rootp()->nbaEventp()) {
+                nodep->v3warn(
+                    E_NOTIMING,
+                    "Delayed assignment in a non-inlined function/task requires --timing");
+            }
+            return;
         }
         UASSERT_OBJ(m_procp, nodep, "Delayed assignment not under process");
         const bool isArray = VN_IS(nodep->lhsp(), ArraySel)
diff --git a/src/V3Sched.cpp b/src/V3Sched.cpp
index a7012d151..2b40f2a16 100644
--- a/src/V3Sched.cpp
+++ b/src/V3Sched.cpp
@@ -587,18 +587,27 @@ const TriggerKit createTriggers(AstNetlist* netlistp, AstCFunc* const initFuncp,
     return {vscp, funcp, dumpp, map};
 }
 
+//============================================================================
+// EvalLoop contains elements of an evaluation loop created by makeEvalLoop()
+
+struct EvalLoop {
+    // Loop iteration counter for enforcing the converge limit
+    AstVarScope* counterp = nullptr;
+    // The loop condition
+    AstVarScope* continuep = nullptr;
+    // The loop itself and statements around it
+    AstNodeStmt* stmtsp = nullptr;
+};
+
 //============================================================================
 // Helpers to construct an evaluation loop.
 
-AstNodeStmt* buildLoop(AstNetlist* netlistp, const string& name,
-                       const std::function& build)  //
+AstNodeStmt* buildLoop(AstNetlist* netlistp, AstVarScope* const condp,
+                       const std::function& build)  //
 {
     AstTopScope* const topScopep = netlistp->topScopep();
     AstScope* const scopeTopp = topScopep->scopep();
     FileLine* const flp = scopeTopp->fileline();
-    // Create the loop condition variable
-    AstVarScope* const condp = scopeTopp->createTemp("__V" + name + "Continue", 1);
-    condp->varp()->noReset(true);
     // Initialize the loop condition variable to true
     AstNodeStmt* const resp = setVar(condp, 1);
     // Add the loop
@@ -607,16 +616,15 @@ AstNodeStmt* buildLoop(AstNetlist* netlistp, const string& name,
     // Clear the loop condition variable in the loop
     loopp->addStmtsp(setVar(condp, 0));
     // Build the body
-    build(condp, loopp);
+    build(loopp);
     // Done
     return resp;
 };
 
-std::pair makeEvalLoop(AstNetlist* netlistp, const string& tag,
-                                                   const string& name, AstVarScope* trigVscp,
-                                                   AstCFunc* trigDumpp,
-                                                   std::function computeTriggers,
-                                                   std::function makeBody) {
+EvalLoop makeEvalLoop(AstNetlist* netlistp, const string& tag, const string& name,
+                      AstVarScope* trigVscp, AstCFunc* trigDumpp,
+                      std::function computeTriggers,
+                      std::function makeBody) {
     UASSERT_OBJ(trigVscp->dtypep()->basicp()->isTriggerVec(), trigVscp, "Not TRIGGERVEC");
     AstTopScope* const topScopep = netlistp->topScopep();
     AstScope* const scopeTopp = topScopep->scopep();
@@ -625,8 +633,11 @@ std::pair makeEvalLoop(AstNetlist* netlistp, const s
     AstVarScope* const counterp = scopeTopp->createTemp("__V" + tag + "IterCount", 32);
     counterp->varp()->noReset(true);
 
+    AstVarScope* const continuep = scopeTopp->createTemp("__V" + tag + "Continue", 1);
+    continuep->varp()->noReset(true);
+
     AstNodeStmt* nodep = setVar(counterp, 0);
-    nodep->addNext(buildLoop(netlistp, tag, [&](AstVarScope* continuep, AstWhile* loopp) {
+    nodep->addNext(buildLoop(netlistp, continuep, [&](AstWhile* loopp) {
         // Compute triggers
         loopp->addStmtsp(computeTriggers());
         // Invoke body if triggered
@@ -678,7 +689,7 @@ std::pair makeEvalLoop(AstNetlist* netlistp, const s
         }
     }));
 
-    return {counterp, nodep};
+    return {counterp, continuep, nodep};
 }
 
 //============================================================================
@@ -723,7 +734,7 @@ void createSettle(AstNetlist* netlistp, AstCFunc* const initFuncp, SenExprBuilde
     splitCheck(stlFuncp);
 
     // Create the eval loop
-    const auto& pair = makeEvalLoop(
+    const auto& loop = makeEvalLoop(
         netlistp, "stl", "Settle", trig.m_vscp, trig.m_dumpp,
         [&]() {  // Trigger
             AstCCall* const callp = new AstCCall{stlFuncp->fileline(), trig.m_funcp};
@@ -737,10 +748,10 @@ void createSettle(AstNetlist* netlistp, AstCFunc* const initFuncp, SenExprBuilde
         });
 
     // Add the first iteration trigger to the trigger computation function
-    trig.addFirstIterationTriggerAssignment(pair.first, firstIterationTrigger);
+    trig.addFirstIterationTriggerAssignment(loop.counterp, firstIterationTrigger);
 
     // Add the eval loop to the top function
-    funcp->addStmtsp(pair.second);
+    funcp->addStmtsp(loop.stmtsp);
 }
 
 //============================================================================
@@ -812,7 +823,7 @@ AstNode* createInputCombLoop(AstNetlist* netlistp, AstCFunc* const initFuncp,
     splitCheck(icoFuncp);
 
     // Create the eval loop
-    const auto& pair = makeEvalLoop(
+    const auto& loop = makeEvalLoop(
         netlistp, "ico", "Input combinational", trig.m_vscp, trig.m_dumpp,
         [&]() {  // Trigger
             AstCCall* const callp = new AstCCall{icoFuncp->fileline(), trig.m_funcp};
@@ -826,10 +837,10 @@ AstNode* createInputCombLoop(AstNetlist* netlistp, AstCFunc* const initFuncp,
         });
 
     // Add the first iteration trigger to the trigger computation function
-    trig.addFirstIterationTriggerAssignment(pair.first, firstIterationTrigger);
+    trig.addFirstIterationTriggerAssignment(loop.counterp, firstIterationTrigger);
 
     // Return the eval loop itself
-    return pair.second;
+    return loop.stmtsp;
 }
 
 //============================================================================
@@ -884,72 +895,86 @@ void createEval(AstNetlist* netlistp,  //
     if (icoLoop) funcp->addStmtsp(icoLoop);
 
     // Create the active eval loop
-    AstNodeStmt* const activeEvalLoopp
-        = makeEvalLoop(
-              netlistp, "act", "Active", actKit.m_vscp, actKit.m_dumpp,
-              [&]() {  // Trigger
-                  AstNodeStmt* resultp = nullptr;
+    const auto& activeEvalLoop = makeEvalLoop(
+        netlistp, "act", "Active", actKit.m_vscp, actKit.m_dumpp,
+        [&]() {  // Trigger
+            AstNodeStmt* resultp = nullptr;
 
-                  // Compute the current triggers
-                  {
-                      AstCCall* const trigsp = new AstCCall{flp, actKit.m_triggerComputep};
-                      trigsp->dtypeSetVoid();
-                      resultp = AstNode::addNext(resultp, trigsp->makeStmt());
-                  }
+            // Compute the current triggers
+            {
+                AstCCall* const trigsp = new AstCCall{flp, actKit.m_triggerComputep};
+                trigsp->dtypeSetVoid();
+                resultp = AstNode::addNext(resultp, trigsp->makeStmt());
+            }
 
-                  // Commit trigger awaits from the previous iteration
-                  if (AstCCall* const commitp = timingKit.createCommit(netlistp)) {
-                      resultp = AstNode::addNext(resultp, commitp->makeStmt());
-                  }
+            // Commit trigger awaits from the previous iteration
+            if (AstCCall* const commitp = timingKit.createCommit(netlistp)) {
+                resultp = AstNode::addNext(resultp, commitp->makeStmt());
+            }
 
-                  return resultp;
-              },
-              [&]() {  // Body
-                  // Compute the pre triggers
-                  AstNodeStmt* resultp
-                      = createTriggerAndNotCall(flp, preTrigsp, actKit.m_vscp, nbaKit.m_vscp);
-                  // Latch the active trigger flags under the NBA trigger flags
-                  resultp = AstNode::addNext(
-                      resultp, createTriggerSetCall(flp, nbaKit.m_vscp, actKit.m_vscp));
-                  // Resume triggered timing schedulers
-                  if (AstCCall* const resumep = timingKit.createResume(netlistp)) {
-                      resultp = AstNode::addNext(resultp, resumep->makeStmt());
-                  }
-                  // Invoke body function
-                  {
-                      AstCCall* const callp = new AstCCall{flp, actKit.m_funcp};
-                      callp->dtypeSetVoid();
-                      resultp = AstNode::addNext(resultp, callp->makeStmt());
-                  }
+            return resultp;
+        },
+        [&]() {  // Body
+            // Compute the pre triggers
+            AstNodeStmt* resultp
+                = createTriggerAndNotCall(flp, preTrigsp, actKit.m_vscp, nbaKit.m_vscp);
+            // Latch the active trigger flags under the NBA trigger flags
+            resultp = AstNode::addNext(resultp,
+                                       createTriggerSetCall(flp, nbaKit.m_vscp, actKit.m_vscp));
+            // Resume triggered timing schedulers
+            if (AstCCall* const resumep = timingKit.createResume(netlistp)) {
+                resultp = AstNode::addNext(resultp, resumep->makeStmt());
+            }
+            // Invoke body function
+            {
+                AstCCall* const callp = new AstCCall{flp, actKit.m_funcp};
+                callp->dtypeSetVoid();
+                resultp = AstNode::addNext(resultp, callp->makeStmt());
+            }
 
-                  return resultp;
-              })
-              .second;
+            return resultp;
+        });
 
     // Create the NBA eval loop. This uses the Active eval loop in the trigger section.
-    AstNodeStmt* topEvalLoopp
-        = makeEvalLoop(
-              netlistp, "nba", "NBA", nbaKit.m_vscp, nbaKit.m_dumpp,
-              [&]() {  // Trigger
-                  // Reset NBA triggers
-                  AstNodeStmt* resultp = createTriggerClearCall(flp, nbaKit.m_vscp);
-                  // Run the Active eval loop
-                  resultp = AstNode::addNext(resultp, activeEvalLoopp);
-                  return resultp;
-              },
-              [&]() {  // Body
-                  AstCCall* const callp = new AstCCall{flp, nbaKit.m_funcp};
-                  callp->dtypeSetVoid();
-                  AstNodeStmt* resultp = callp->makeStmt();
-                  // Latch the NBA trigger flags under the following region's trigger flags
-                  AstVarScope* const nextVscp = obsKit.m_vscp ? obsKit.m_vscp : reactKit.m_vscp;
-                  if (nextVscp) {
-                      resultp = AstNode::addNext(
-                          resultp, createTriggerSetCall(flp, nextVscp, nbaKit.m_vscp));
-                  }
-                  return resultp;
-              })
-              .second;
+    const auto& nbaEvalLoop = makeEvalLoop(
+        netlistp, "nba", "NBA", nbaKit.m_vscp, nbaKit.m_dumpp,
+        [&]() {  // Trigger
+            // Reset NBA triggers
+            AstNodeStmt* resultp = createTriggerClearCall(flp, nbaKit.m_vscp);
+            // Run the Active eval loop
+            resultp = AstNode::addNext(resultp, activeEvalLoop.stmtsp);
+            return resultp;
+        },
+        [&]() {  // Body
+            AstCCall* const callp = new AstCCall{flp, nbaKit.m_funcp};
+            callp->dtypeSetVoid();
+            AstNodeStmt* resultp = callp->makeStmt();
+            // Latch the NBA trigger flags under the following region's trigger flags
+            AstVarScope* const nextVscp = obsKit.m_vscp ? obsKit.m_vscp : reactKit.m_vscp;
+            if (nextVscp) {
+                resultp = AstNode::addNext(resultp,
+                                           createTriggerSetCall(flp, nextVscp, nbaKit.m_vscp));
+            }
+            return resultp;
+        });
+
+    // If the NBA event exists, trigger it in 'nba'
+    if (netlistp->nbaEventp()) {
+        UASSERT(netlistp->nbaEventTriggerp(), "NBA event trigger var should exist");
+        AstIf* const ifp
+            = new AstIf{flp, new AstVarRef{flp, netlistp->nbaEventTriggerp(), VAccess::READ}};
+        ifp->addThensp(setVar(nbaEvalLoop.continuep, 1));
+        ifp->addThensp(setVar(netlistp->nbaEventTriggerp(), 0));
+        AstCMethodHard* const firep = new AstCMethodHard{
+            flp, new AstVarRef{flp, netlistp->nbaEventp(), VAccess::WRITE}, "fire"};
+        firep->dtypeSetVoid();
+        ifp->addThensp(firep->makeStmt());
+        activeEvalLoop.stmtsp->addNext(ifp);
+        netlistp->nbaEventp(nullptr);
+        netlistp->nbaEventTriggerp(nullptr);
+    }
+
+    AstNodeStmt* topEvalLoopp = nbaEvalLoop.stmtsp;
 
     if (obsKit.m_funcp) {
         // Create the Observed eval loop. This uses the NBA eval loop in the trigger section.
@@ -974,7 +999,7 @@ void createEval(AstNetlist* netlistp,  //
                       }
                       return resultp;
                   })
-                  .second;
+                  .stmtsp;
     }
 
     if (reactKit.m_funcp) {
@@ -993,7 +1018,7 @@ void createEval(AstNetlist* netlistp,  //
                                callp->dtypeSetVoid();
                                return callp->makeStmt();
                            })
-                           .second;
+                           .stmtsp;
     }
     funcp->addStmtsp(topEvalLoopp);
 
diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp
index ebeeb7fe9..0d170c90c 100644
--- a/src/V3Timing.cpp
+++ b/src/V3Timing.cpp
@@ -365,6 +365,10 @@ private:
         m_underFork |= F_MIGHT_NEED_PROC;
         iterateChildren(nodep);
     }
+    void visit(AstAssignDly* nodep) override {
+        if (!VN_IS(m_procp, NodeProcedure)) v3Global.setUsesTiming();
+        visit(static_cast(nodep));
+    }
     void visit(AstNode* nodep) override {
         if (nodep->isTimingControl()) {
             v3Global.setUsesTiming();
@@ -451,8 +455,10 @@ private:
     double m_timescaleFactor = 1.0;  // Factor to scale delays by
     int m_forkCnt = 0;  // Number of forks inside a module
     bool m_underJumpBlock = false;  // True if we are inside of a jump-block
+    bool m_underProcedure = false;  // True if we are under an always or initial
 
     // Unique names
+    V3UniqueNames m_dlyforkNames{"__Vdlyfork"};  // Names for temp AssignW vars
     V3UniqueNames m_contAssignVarNames{"__VassignWtmp"};  // Names for temp AssignW vars
     V3UniqueNames m_intraValueNames{"__Vintraval"};  // Intra assign delay value var names
     V3UniqueNames m_intraIndexNames{"__Vintraidx"};  // Intra assign delay index var names
@@ -574,6 +580,31 @@ private:
         m_netlistp->topScopep()->addSenTreesp(m_dynamicSensesp);
         return m_dynamicSensesp;
     }
+    // Creates the event variable to trigger in NBA region
+    AstEventControl* createNbaEventControl(FileLine* flp) {
+        if (!m_netlistp->nbaEventp()) {
+            auto* const nbaEventDtp = new AstBasicDType{m_scopeTopp->fileline(),
+                                                        VBasicDTypeKwd::EVENT, VSigning::UNSIGNED};
+            m_netlistp->typeTablep()->addTypesp(nbaEventDtp);
+            m_netlistp->nbaEventp(m_scopeTopp->createTemp("__VnbaEvent", nbaEventDtp));
+            v3Global.setHasEvents();
+        }
+        return new AstEventControl{
+            flp,
+            new AstSenTree{
+                flp, new AstSenItem{flp, VEdgeType::ET_EVENT,
+                                    new AstVarRef{flp, m_netlistp->nbaEventp(), VAccess::READ}}},
+            nullptr};
+    }
+    // Creates the variable that, if set, causes the NBA event to be triggered
+    AstAssign* createNbaEventTriggerAssignment(FileLine* flp) {
+        if (!m_netlistp->nbaEventTriggerp()) {
+            m_netlistp->nbaEventTriggerp(m_scopeTopp->createTemp("__VnbaEventTrigger", 1));
+        }
+        return new AstAssign{flp,
+                             new AstVarRef{flp, m_netlistp->nbaEventTriggerp(), VAccess::WRITE},
+                             new AstConst{flp, AstConst::BitTrue{}}};
+    }
     // Returns true if we are under a class or the given tree has any references to locals. These
     // are cases where static, globally-evaluated triggers are not suitable.
     bool needDynamicTrigger(AstNode* const nodep) const {
@@ -755,6 +786,8 @@ private:
     void visit(AstNodeProcedure* nodep) override {
         VL_RESTORER(m_procp);
         m_procp = nodep;
+        VL_RESTORER(m_underProcedure);
+        m_underProcedure = true;
         iterateChildren(nodep);
         if (hasFlags(nodep, T_SUSPENDEE)) nodep->setSuspendable();
         if (hasFlags(nodep, T_HAS_PROC)) nodep->setNeedProcess();
@@ -775,7 +808,8 @@ private:
         if (nodep->user1SetOnce()) return;
         VL_RESTORER(m_procp);
         m_procp = nodep;
-
+        VL_RESTORER(m_underProcedure);
+        m_underProcedure = true;
         // Workaround for killing `always` processes (doing that is pretty much UB)
         // TODO: Disallow killing `always` at runtime (throw an error)
         if (hasFlags(nodep, T_HAS_PROC)) addFlags(nodep, T_SUSPENDEE);
@@ -981,20 +1015,37 @@ private:
     void visit(AstNodeAssign* nodep) override {
         // Only process once to avoid infinite loops (due to the net delay)
         if (nodep->user1SetOnce()) return;
-        AstNode* const controlp = factorOutTimingControl(nodep);
-        if (!controlp) return;
-        // Handle the intra assignment timing control
         FileLine* const flp = nodep->fileline();
-        if (VN_IS(nodep, AssignDly)) {
-            // If it's an NBA with an intra assignment delay, put it in a fork
+        AstNode* controlp = factorOutTimingControl(nodep);
+        const bool inAssignDly = VN_IS(nodep, AssignDly);
+        // Handle the intra assignment timing control
+        // Transform if:
+        // * there's a timing control in the assignment
+        // * the assignment is an AssignDly and it's in a non-inlined function
+        if (!controlp && (!inAssignDly || m_underProcedure)) return;
+        // Insert new vars before the timing control if we're in a function; in a process we can't
+        // do that. These intra-assignment vars will later be passed to forked processes by value.
+        AstNode* insertBeforep = m_underProcedure ? nullptr : controlp;
+        // Special case for NBA
+        if (inAssignDly) {
+            // Put it in a fork so it doesn't block
             auto* const forkp = new AstFork{flp, "", nullptr};
             forkp->joinType(VJoinType::JOIN_NONE);
+            if (!m_underProcedure) {
+                // If it's in a function, it won't be handled by V3Delayed
+                // Put it behind an additional named event that gets triggered in the NBA region
+                AstEventControl* const nbaEventControlp = createNbaEventControl(flp);
+                AstAssign* const trigAssignp = createNbaEventTriggerAssignment(flp);
+                nodep->replaceWith(trigAssignp);
+                trigAssignp->addNextHere(nbaEventControlp);
+                nbaEventControlp->addStmtsp(nodep);
+                insertBeforep = forkp;
+                if (!controlp) controlp = nbaEventControlp;
+            }
             controlp->replaceWith(forkp);
             forkp->addStmtsp(controlp);
         }
-        // Insert new vars before the timing control if we're in a function; in a process we can't
-        // do that. These intra-assignment vars will later be passed to forked processes by value.
-        AstNode* const insertBeforep = m_classp ? controlp : nullptr;
+        UASSERT_OBJ(nodep, controlp, "Assignment should have timing control");
         addCLocalScope(flp, insertBeforep);
         // Function for replacing values with intermediate variables
         const auto replaceWithIntermediate = [&](AstNodeExpr* const valuep,
diff --git a/test_regress/t/t_assigndly_dynamic.pl b/test_regress/t/t_assigndly_dynamic.pl
new file mode 100755
index 000000000..3576e3ffb
--- /dev/null
+++ b/test_regress/t/t_assigndly_dynamic.pl
@@ -0,0 +1,32 @@
+#!/usr/bin/env perl
+if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
+# DESCRIPTION: Verilator: Verilog Test driver/expect definition
+#
+# Copyright 2019 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(simulator => 1);
+
+compile(
+    verilator_flags2 => ["--exe --main --timing"],
+    make_main => 0,
+    );
+
+execute(
+    check_finished => 1,
+    );
+
+compile(
+    verilator_flags2 => ["--exe --main --timing +define+WITH_DELAY"],
+    make_main => 0,
+    );
+
+execute(
+    check_finished => 1,
+    );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_assigndly_dynamic.v b/test_regress/t/t_assigndly_dynamic.v
new file mode 100644
index 000000000..9183eb767
--- /dev/null
+++ b/test_regress/t/t_assigndly_dynamic.v
@@ -0,0 +1,55 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed into the Public Domain, for any use,
+// without warranty, 2023 by Antmicro Ltd.
+// SPDX-License-Identifier: CC0-1.0
+
+`ifdef WITH_DELAY
+`define DELAY #1
+`define TIME_AFTER_FIRST_WAIT 2
+`define TIME_AFTER_SECOND_WAIT 3
+`else
+`define DELAY
+`define TIME_AFTER_FIRST_WAIT 1
+`define TIME_AFTER_SECOND_WAIT 1
+`endif
+
+class nba_waiter;
+    // Task taken from UVM
+    task wait_for_nba_region;
+        int nba;
+        int next_nba;
+        next_nba++;
+        nba <= `DELAY next_nba;
+        @(nba);
+    endtask
+endclass
+
+module t;
+    nba_waiter waiter = new;
+    event e;
+    int cnt = 0;
+
+    initial begin
+        #1 ->e;
+        if (cnt != 0) $stop;
+        cnt++;
+        waiter.wait_for_nba_region;
+        ->e;
+        if (cnt != 2) $stop;
+        if ($time != `TIME_AFTER_FIRST_WAIT) $stop;
+        cnt++;
+        waiter.wait_for_nba_region;
+        if (cnt != 4) $stop;
+        if ($time != `TIME_AFTER_SECOND_WAIT) $stop;
+        $write("*-* All Finished *-*\n");
+        $finish;
+    end
+
+    initial begin
+        @e if (cnt != 1) $stop;
+        cnt++;
+        @e if (cnt != 3) $stop;
+        cnt++;
+    end
+endmodule
diff --git a/test_regress/t/t_assigndly_dynamic_notiming.out b/test_regress/t/t_assigndly_dynamic_notiming.out
new file mode 100644
index 000000000..7fe77946a
--- /dev/null
+++ b/test_regress/t/t_assigndly_dynamic_notiming.out
@@ -0,0 +1,6 @@
+%Error-NOTIMING: t/t_assigndly_dynamic_notiming.v:10:13: Delayed assignment in a non-inlined function/task requires --timing
+                                                       : ... note: In instance '$unit::foo'
+   10 |         qux <= '1;
+      |             ^~
+                 ... For error description see https://verilator.org/warn/NOTIMING?v=latest
+%Error: Exiting due to
diff --git a/test_regress/t/t_assigndly_dynamic_notiming.pl b/test_regress/t/t_assigndly_dynamic_notiming.pl
new file mode 100755
index 000000000..1e658d937
--- /dev/null
+++ b/test_regress/t/t_assigndly_dynamic_notiming.pl
@@ -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 2019 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(simulator => 1);
+
+compile(
+    verilator_flags2 => ["--no-timing"],
+    fails => 1,
+    expect_filename => $Self->{golden_filename},
+    );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_assigndly_dynamic_notiming.v b/test_regress/t/t_assigndly_dynamic_notiming.v
new file mode 100644
index 000000000..f4b96c4de
--- /dev/null
+++ b/test_regress/t/t_assigndly_dynamic_notiming.v
@@ -0,0 +1,12 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed into the Public Domain, for any use,
+// without warranty, 2023 by Antmicro Ltd.
+// SPDX-License-Identifier: CC0-1.0
+
+class foo;
+    task bar;
+        int qux;
+        qux <= '1;
+    endtask
+endclass
diff --git a/test_regress/t/t_uvm_pkg_todo.vh b/test_regress/t/t_uvm_pkg_todo.vh
index c798374cc..edaf36b07 100644
--- a/test_regress/t/t_uvm_pkg_todo.vh
+++ b/test_regress/t/t_uvm_pkg_todo.vh
@@ -918,9 +918,7 @@ task uvm_wait_for_nba_region;
   int nba;
   int next_nba;
   next_nba++;
-//TODO issue #4496 - Delayed assignment inside public function/task
-//TODO  %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:875:7: Unsupported: Delayed assignment inside public function/task
-//TODO  nba <= next_nba;
+  nba <= next_nba;
   @(nba);
 endtask
 function automatic void uvm_split_string (string str, byte sep, ref string values[$]);

From f8b7fb72b897f213306b97592e08a7fd49bee9e4 Mon Sep 17 00:00:00 2001
From: Wilson Snyder 
Date: Sat, 21 Oct 2023 02:36:29 -0400
Subject: [PATCH 102/157] Fix fault on empty clocking block (#4593).

---
 Changes                                  |  1 +
 src/V3SchedTiming.cpp                    |  6 +++++-
 test_regress/t/t_clocking_empty_block.pl | 23 +++++++++++++++++++++++
 test_regress/t/t_clocking_empty_block.v  | 21 +++++++++++++++++++++
 4 files changed, 50 insertions(+), 1 deletion(-)
 create mode 100755 test_regress/t/t_clocking_empty_block.pl
 create mode 100644 test_regress/t/t_clocking_empty_block.v

diff --git a/Changes b/Changes
index 7ec977f93..266dae696 100644
--- a/Changes
+++ b/Changes
@@ -44,6 +44,7 @@ Verilator 5.017 devel
 * Fix compile warning on unused member function variable (#4567).
 * Fix method narrowing conversion compiler error (#4568).
 * Fix display optimization ignoring side effects (#4585).
+* Fix fault on empty clocking block (#4593). [Alex Mykyta]
 * Fix preprocessor to show `line 2 on resumed file.
 
 
diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp
index 3a8dd6b89..368201f05 100644
--- a/src/V3SchedTiming.cpp
+++ b/src/V3SchedTiming.cpp
@@ -395,7 +395,11 @@ void transformForks(AstNetlist* const netlistp) {
             } else {
                 // The begin has neither awaits nor a process::self call, just inline the
                 // statements
-                nodep->replaceWith(nodep->stmtsp()->unlinkFrBackWithNext());
+                if (nodep->stmtsp()) {
+                    nodep->replaceWith(nodep->stmtsp()->unlinkFrBackWithNext());
+                } else {
+                    nodep->unlinkFrBack();
+                }
             }
             VL_DO_DANGLING(nodep->deleteTree(), nodep);
         }
diff --git a/test_regress/t/t_clocking_empty_block.pl b/test_regress/t/t_clocking_empty_block.pl
new file mode 100755
index 000000000..b8493bd06
--- /dev/null
+++ b/test_regress/t/t_clocking_empty_block.pl
@@ -0,0 +1,23 @@
+#!/usr/bin/env perl
+if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
+# DESCRIPTION: Verilator: Verilog Test driver/expect definition
+#
+# Copyright 2023 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(simulator => 1);
+
+compile(
+    verilator_flags2 => ["--exe --main --timing"],
+    make_main => 0,
+    );
+
+execute(
+    check_finished => 1,
+    );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_clocking_empty_block.v b/test_regress/t/t_clocking_empty_block.v
new file mode 100644
index 000000000..8210ffcfd
--- /dev/null
+++ b/test_regress/t/t_clocking_empty_block.v
@@ -0,0 +1,21 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed under the Creative Commons Public Domain, for
+// any use, without warranty, 2023 by Alex Mykyta.
+// SPDX-License-Identifier: CC0-1.0
+
+module t();
+   logic clk = 0;
+   logic x;
+   logic y;
+   always #1ns clk = ~clk;
+   clocking cb @(posedge clk);
+      output #1ns x;
+      input  #1step y;
+   endclocking
+   initial begin
+      repeat(10) @(posedge clk);
+      $display("*-* All Finished *-*");
+      $finish();
+   end
+endmodule

From 26e378596382e654f5e39e17e6bc61942feb55c2 Mon Sep 17 00:00:00 2001
From: Quentin Corradi <12198691+dwRchyngqxs@users.noreply.github.com>
Date: Sat, 21 Oct 2023 07:43:49 +0100
Subject: [PATCH 103/157] Fix PLI/DPI user defined system task/function grammar
 (#4587) (#4588)

According to 1800-2017 36.3, 1800-2017 A.9.3, 1364-2005 20.2 and 1364-2005 A.9.3, user defined system task and function identifiers can use the same character set for the second character as all the following characters.
---
 docs/CONTRIBUTORS | 1 +
 src/verilog.l     | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS
index 09c1ae87b..80b58a622 100644
--- a/docs/CONTRIBUTORS
+++ b/docs/CONTRIBUTORS
@@ -137,6 +137,7 @@ Pierre-Henri Horrein
 Pieter Kapsenberg
 Piotr Binkowski
 Qingyao Sun
+Quentin Corradi
 Rafal Kapuscik
 Raynard Qiao
 Richard Myers
diff --git a/src/verilog.l b/src/verilog.l
index 8bb6c07bd..7d43128b0 100644
--- a/src/verilog.l
+++ b/src/verilog.l
@@ -630,7 +630,7 @@ vnum    {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
 
   /* Default PLI rule */
 {
-  "$"[a-zA-Z_$][a-zA-Z0-9_$]*   { const string str (yytext, yyleng);
+  "$"[a-zA-Z0-9_$]+     { const string str (yytext, yyleng);
                                   yylval.strp = PARSEP->newString(AstNode::encodeName(str));
                                   FL; return yaD_PLI;
                                 }

From cbc2f9eb328f7b99a5c6a12cf65c4e53b55f1867 Mon Sep 17 00:00:00 2001
From: Geza Lore 
Date: Sat, 21 Oct 2023 11:34:36 +0100
Subject: [PATCH 104/157] Do not overwrite LD_LIBRARY_PATH in t_flag_ldflags

---
 test_regress/t/t_flag_ldflags.pl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test_regress/t/t_flag_ldflags.pl b/test_regress/t/t_flag_ldflags.pl
index 8f5aa8958..33d73877b 100755
--- a/test_regress/t/t_flag_ldflags.pl
+++ b/test_regress/t/t_flag_ldflags.pl
@@ -45,7 +45,7 @@ if ($^O eq "darwin") {
 
 execute(
     check_finished => 1,
-    run_env => "LD_LIBRARY_PATH=$Self->{obj_dir}",
+    run_env => "LD_LIBRARY_PATH=$Self->{obj_dir}:$ENV{LD_LIBRARY_PATH}",
     );
 
 ok(1);

From d1c787540623ad22fc734a18d0cc896a8ca393cd Mon Sep 17 00:00:00 2001
From: Geza Lore 
Date: Sat, 21 Oct 2023 13:53:56 +0100
Subject: [PATCH 105/157] Fix conditionals on obsolete --threads 0

Since we removed --threads 0 support, the 'threads()' option always
returns a value >= 1. Remove corresponding dead code.

Some of the coverage counters appear to use atomics even if the model is
single threaded. I'm under the impression this was a bug originally so
those ones I changed to use threads() > 1 instead.
---
 src/V3EmitCFunc.h      | 2 +-
 src/V3EmitCHeaders.cpp | 2 +-
 src/V3EmitCImp.cpp     | 4 ++--
 src/V3EmitCMake.cpp    | 4 +---
 src/V3EmitCModel.cpp   | 4 ++--
 src/V3EmitCSyms.cpp    | 2 +-
 src/V3EmitMk.cpp       | 2 +-
 src/V3HierBlock.cpp    | 9 ++-------
 src/V3Options.cpp      | 8 ++++----
 src/V3Options.h        | 2 +-
 10 files changed, 16 insertions(+), 23 deletions(-)

diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h
index dbf5026a0..a90368ace 100644
--- a/src/V3EmitCFunc.h
+++ b/src/V3EmitCFunc.h
@@ -603,7 +603,7 @@ public:
         puts(");\n");
     }
     void visit(AstCoverInc* nodep) override {
-        if (v3Global.opt.threads()) {
+        if (v3Global.opt.threads() > 1) {
             puts("vlSymsp->__Vcoverage[");
             puts(cvtToStr(nodep->declp()->dataDeclThisp()->binNum()));
             puts("].fetch_add(1, std::memory_order_relaxed);\n");
diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp
index 8d9f71c8d..df00d1bef 100644
--- a/src/V3EmitCHeaders.cpp
+++ b/src/V3EmitCHeaders.cpp
@@ -170,7 +170,7 @@ class EmitCHeader final : public EmitCConstInit {
         if (v3Global.opt.coverage() && !VN_IS(modp, Class)) {
             decorateFirst(first, section);
             puts("void __vlCoverInsert(");
-            puts(v3Global.opt.threads() ? "std::atomic" : "uint32_t");
+            puts(v3Global.opt.threads() > 1 ? "std::atomic" : "uint32_t");
             puts("* countp, bool enable, const char* filenamep, int lineno, int column,\n");
             puts("const char* hierp, const char* pagep, const char* commentp, const char* "
                  "linescovp);\n");
diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp
index e20320052..7ec3acee9 100644
--- a/src/V3EmitCImp.cpp
+++ b/src/V3EmitCImp.cpp
@@ -307,12 +307,12 @@ class EmitCImp final : EmitCFunc {
             // function. This gets around gcc slowness constructing all of the template
             // arguments.
             puts("void " + prefixNameProtect(m_modp) + "::__vlCoverInsert(");
-            puts(v3Global.opt.threads() ? "std::atomic" : "uint32_t");
+            puts(v3Global.opt.threads() > 1 ? "std::atomic" : "uint32_t");
             puts("* countp, bool enable, const char* filenamep, int lineno, int column,\n");
             puts("const char* hierp, const char* pagep, const char* commentp, const char* "
                  "linescovp) "
                  "{\n");
-            if (v3Global.opt.threads()) {
+            if (v3Global.opt.threads() > 1) {
                 puts("assert(sizeof(uint32_t) == sizeof(std::atomic));\n");
                 puts("uint32_t* count32p = reinterpret_cast(countp);\n");
             } else {
diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp
index ca548d68b..1cf10b01c 100644
--- a/src/V3EmitCMake.cpp
+++ b/src/V3EmitCMake.cpp
@@ -160,9 +160,7 @@ class CMakeEmitter final {
         if (v3Global.usesTiming()) {
             global.emplace_back("${VERILATOR_ROOT}/include/verilated_timing.cpp");
         }
-        if (v3Global.opt.threads()) {
-            global.emplace_back("${VERILATOR_ROOT}/include/verilated_threads.cpp");
-        }
+        global.emplace_back("${VERILATOR_ROOT}/include/verilated_threads.cpp");
         if (v3Global.opt.usesProfiler()) {
             global.emplace_back("${VERILATOR_ROOT}/include/verilated_profiler.cpp");
         }
diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp
index 5abad82d7..b7caefa54 100644
--- a/src/V3EmitCModel.cpp
+++ b/src/V3EmitCModel.cpp
@@ -420,7 +420,7 @@ class EmitCModel final : public EmitCFunc {
         if (v3Global.opt.threads() == 1) {
             puts("Verilated::endOfThreadMTask(vlSymsp->__Vm_evalMsgQp);\n");
         }
-        if (v3Global.opt.threads()) puts("Verilated::endOfEval(vlSymsp->__Vm_evalMsgQp);\n");
+        puts("Verilated::endOfEval(vlSymsp->__Vm_evalMsgQp);\n");
 
         if (v3Global.opt.profExec()) puts("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).evalEnd();\n");
         puts("}\n");
@@ -482,7 +482,7 @@ class EmitCModel final : public EmitCFunc {
         puts("const char* " + topClassName() + "::modelName() const { return \"" + topClassName()
              + "\"; }\n");
         puts("unsigned " + topClassName() + "::threads() const { return "
-             + cvtToStr(std::max(1, v3Global.opt.threads())) + "; }\n");
+             + cvtToStr(v3Global.opt.threads()) + "; }\n");
         puts("void " + topClassName()
              + "::prepareClone() const { contextp()->prepareClone(); }\n");
         puts("void " + topClassName() + "::atClone() const {\n");
diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp
index 8ac652a4b..85ccaae23 100644
--- a/src/V3EmitCSyms.cpp
+++ b/src/V3EmitCSyms.cpp
@@ -489,7 +489,7 @@ void EmitCSyms::emitSymHdr() {
 
     if (m_coverBins) {
         puts("\n// COVERAGE\n");
-        puts(v3Global.opt.threads() ? "std::atomic" : "uint32_t");
+        puts(v3Global.opt.threads() > 1 ? "std::atomic" : "uint32_t");
         puts(" __Vcoverage[");
         puts(cvtToStr(m_coverBins));
         puts("];\n");
diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp
index e55ff26f5..8bea8b362 100644
--- a/src/V3EmitMk.cpp
+++ b/src/V3EmitMk.cpp
@@ -106,7 +106,7 @@ public:
                     }
                     if (v3Global.usesProbDist()) putMakeClassEntry(of, "verilated_probdist.cpp");
                     if (v3Global.usesTiming()) putMakeClassEntry(of, "verilated_timing.cpp");
-                    if (v3Global.opt.threads()) putMakeClassEntry(of, "verilated_threads.cpp");
+                    putMakeClassEntry(of, "verilated_threads.cpp");
                     if (v3Global.opt.usesProfiler()) {
                         putMakeClassEntry(of, "verilated_profiler.cpp");
                     }
diff --git a/src/V3HierBlock.cpp b/src/V3HierBlock.cpp
index f1624493b..b21a6e099 100644
--- a/src/V3HierBlock.cpp
+++ b/src/V3HierBlock.cpp
@@ -159,7 +159,7 @@ V3StringList V3HierBlock::commandArgs(bool forCMake) const {
     opts.push_back(" --lib-create " + modp()->name());  // possibly mangled name
     if (v3Global.opt.protectKeyProvided())
         opts.push_back(" --protect-key " + v3Global.opt.protectKeyDefaulted());
-    opts.push_back(" --hierarchical-child " + cvtToStr(std::max(1, v3Global.opt.threads())));
+    opts.push_back(" --hierarchical-child " + cvtToStr(v3Global.opt.threads()));
 
     const StrGParams gparamsStr = stringifyParams(gparams(), true);
     for (StrGParams::const_iterator paramIt = gparamsStr.begin(); paramIt != gparamsStr.end();
@@ -227,9 +227,6 @@ void V3HierBlock::writeCommandArgsFile(bool forCMake) const {
     for (const string& opt : commandOpts) *of << opt << "\n";
     *of << hierBlockArgs().front() << "\n";
     for (const auto& hierblockp : m_children) *of << hierblockp->hierBlockArgs().front() << "\n";
-    // Hierarchical blocks should not use multi-threading,
-    // but needs to be thread safe when top is multi-threaded.
-    if (v3Global.opt.threads() > 0) *of << "--threads 1\n";
     *of << v3Global.opt.allArgsStringForHierBlock(false) << "\n";
 }
 
@@ -425,9 +422,7 @@ void V3HierBlockPlan::writeCommandArgsFiles(bool forCMake) const {
     if (v3Global.opt.protectKeyProvided()) {
         *of << "--protect-key " << v3Global.opt.protectKeyDefaulted() << "\n";
     }
-    if (v3Global.opt.threads() > 0) {
-        *of << "--threads " << cvtToStr(v3Global.opt.threads()) << "\n";
-    }
+    *of << "--threads " << cvtToStr(v3Global.opt.threads()) << "\n";
     *of << (v3Global.opt.systemC() ? "--sc" : "--cc") << "\n";
     *of << v3Global.opt.allArgsStringForHierBlock(true) << "\n";
 }
diff --git a/src/V3Options.cpp b/src/V3Options.cpp
index 554af3421..d64519e07 100644
--- a/src/V3Options.cpp
+++ b/src/V3Options.cpp
@@ -875,11 +875,8 @@ void V3Options::notify() VL_MT_DISABLED {
     }
 
     if (trace()) {
-        // With --trace-fst, --trace-threads implies --threads 1 unless explicitly specified
-        if (traceFormat().fst() && traceThreads() && !threads()) m_threads = 1;
-
         // With --trace, --trace-threads is ignored
-        if (traceFormat().vcd()) m_traceThreads = threads() ? 1 : 0;
+        if (traceFormat().vcd()) m_traceThreads = 1;
     }
 
     UASSERT(!(useTraceParallel() && useTraceOffload()),
@@ -906,6 +903,9 @@ void V3Options::notify() VL_MT_DISABLED {
         m_dumpLevel["tree"] = m_dumpLevel["tree-dot"];
     }
 
+    // Sanity check of expected configuration
+    UASSERT(threads() >= 1, "'threads()' must return a value >= 1");
+
     // Preprocessor defines based on options used
     if (timing().isSetTrue()) V3PreShell::defineCmdLine("VERILATOR_TIMING", "1");
 }
diff --git a/src/V3Options.h b/src/V3Options.h
index 6378c8545..259462fe8 100644
--- a/src/V3Options.h
+++ b/src/V3Options.h
@@ -549,7 +549,7 @@ public:
     int traceThreads() const { return m_traceThreads; }
     bool useTraceOffload() const { return trace() && traceFormat().fst() && traceThreads() > 1; }
     bool useTraceParallel() const {
-        return trace() && traceFormat().vcd() && threads() && (threads() > 1 || hierChild() > 1);
+        return trace() && traceFormat().vcd() && (threads() > 1 || hierChild() > 1);
     }
     bool useFstWriterThread() const { return traceThreads() && traceFormat().fst(); }
     unsigned vmTraceThreads() const {

From 332a687aefb014c2e3d711ae86f9cf993967423e Mon Sep 17 00:00:00 2001
From: Wilson Snyder 
Date: Sat, 21 Oct 2023 10:35:07 -0400
Subject: [PATCH 106/157] Commentary

---
 ci/ci-ccache-maint.bash | 1 +
 ci/ci-script.bash       | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/ci/ci-ccache-maint.bash b/ci/ci-ccache-maint.bash
index 0c0cf00e6..ee0195a8d 100755
--- a/ci/ci-ccache-maint.bash
+++ b/ci/ci-ccache-maint.bash
@@ -26,4 +26,5 @@ if git log --format=%B -n 1 "$COMMIT" | grep -q -i '\[CI\s\+ccache\s\+clear\]';
 fi
 
 # Dump stats, then zero stats
+# 22.04: ccache -s -v -z
 ccache -s -z
diff --git a/ci/ci-script.bash b/ci/ci-script.bash
index 225c9b50c..1ce2da5e5 100755
--- a/ci/ci-script.bash
+++ b/ci/ci-script.bash
@@ -49,6 +49,7 @@ if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then
     ./configure --enable-longtests --enable-ccwarn ${CI_M32:+--enable-m32}
     ccache -z
     "$MAKE" -j "$NPROC" -k
+    # 22.04: ccache -s -v
     ccache -s
     if [ "$CI_OS_NAME" = "osx" ]; then
       file bin/verilator_bin
@@ -180,6 +181,7 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
       fatal "Unknown test: $TESTS"
       ;;
   esac
+  # 22.04: ccache -s -v
   ccache -s
 
   # Upload coverage data

From afaa02709cfe3379c973b6c056093299c217abb7 Mon Sep 17 00:00:00 2001
From: Wilson Snyder 
Date: Sat, 21 Oct 2023 10:38:46 -0400
Subject: [PATCH 107/157] CI: Increase CCACHE_MAXSIZE (#4595)

---
 .github/workflows/build.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index ee8fc9162..ca68a4957 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -63,7 +63,7 @@ jobs:
       CC: ${{ matrix.compiler.cc }}
       CXX: ${{ matrix.compiler.cxx }}
       CACHE_BASE_KEY: build-${{ matrix.os }}-${{ matrix.compiler.cc }}-m32=${{ matrix.m32 }}
-      CCACHE_MAXSIZE: 250M # Per build matrix entry (2000M in total)
+      CCACHE_MAXSIZE: 1000M # Per build matrix entry (* 5 = 5000M in total)
       VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ matrix.os }}-${{ matrix.compiler.cc }}${{ matrix.m32 && '-m32' || '' }}.tar.gz
     steps:
 
@@ -136,7 +136,7 @@ jobs:
       CC: ${{ matrix.compiler.cc }}
       CXX: ${{ matrix.compiler.cxx }}
       CACHE_BASE_KEY: test-${{ matrix.os }}-${{ matrix.compiler.cc }}-m32=${{ matrix.m32 }}-${{ matrix.suite }}
-      CCACHE_MAXSIZE: 64M # Per build matrix entry (2160M in total)
+      CCACHE_MAXSIZE: 100M # Per build per suite (* 5 * 5 = 2500M in total)
       VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ matrix.os }}-${{ matrix.compiler.cc }}${{ matrix.m32 && '-m32' || '' }}.tar.gz
     steps:
 

From 1075b006b56e21646d11605eac4879fba53cd43a Mon Sep 17 00:00:00 2001
From: Geza Lore 
Date: Sat, 21 Oct 2023 14:48:20 +0100
Subject: [PATCH 108/157] Consider children of AstConcat in V3InstrCount

Previously V3InstrCount used to completely ignore an AstConcat,
including its children (see the rational in the comment). The problem is
the operands can be huge and expensive compound expressions (especially
since DFG), and not just a simple variable reference. This fix gains
some MT speed improvement.
---
 src/V3InstrCount.cpp | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/src/V3InstrCount.cpp b/src/V3InstrCount.cpp
index 95bbdaa06..b7dfff1e1 100644
--- a/src/V3InstrCount.cpp
+++ b/src/V3InstrCount.cpp
@@ -146,11 +146,9 @@ private:
     }
     void visit(AstConcat* nodep) override {
         if (m_ignoreRemaining) return;
-        // Nop.
-        //
-        // Ignore concat. The problem with counting concat is that when we
-        // have many things concatted together, it's not a single
-        // operation, but this:
+        // Ignore the cost of the concat node itself. The problem with
+        // counting concat is that when we have many things concatted
+        // together, it's not a single operation, but this:
         //
         //  concat(a, concat(b, concat(c, concat(d, ... ))))
         //
@@ -162,7 +160,8 @@ private:
         // cost is linear with the size of the data. We don't need to count
         // the concat at all to reflect a linear cost; it's already there
         // in the width of the destination (which we count) and the sum of
-        // the widths of the operands (ignored here).
+        // the cost of the operands.
+        iterateChildrenConst(nodep);
         markCost(nodep);
     }
     void visit(AstNodeIf* nodep) override {

From eae942b91c3a88fc3cdaac671522a2c645521c07 Mon Sep 17 00:00:00 2001
From: Wilson Snyder 
Date: Sat, 21 Oct 2023 12:48:19 -0400
Subject: [PATCH 109/157] Internals: Fix some lint-py warnings

---
 docs/bin/vl_sphinx_extract    | 2 +-
 docs/guide/conf.py            | 2 +-
 examples/xml_py/vl_file_copy  | 4 ++--
 examples/xml_py/vl_hier_graph | 4 ++--
 nodist/code_coverage          | 2 +-
 nodist/install_test           | 2 +-
 src/astgen                    | 4 ++--
 7 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/docs/bin/vl_sphinx_extract b/docs/bin/vl_sphinx_extract
index 5c446a327..b607bd9d0 100755
--- a/docs/bin/vl_sphinx_extract
+++ b/docs/bin/vl_sphinx_extract
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-# pylint: disable=C0112,C0114,C0115,C0116,C0209,C0301,R0201,R0903
+# pylint: disable=C0112,C0114,C0115,C0116,C0209,C0301,R0903
 # -*- Python -*- See copyright, etc below
 ######################################################################
 
diff --git a/docs/guide/conf.py b/docs/guide/conf.py
index d022012c2..e8d5c0234 100644
--- a/docs/guide/conf.py
+++ b/docs/guide/conf.py
@@ -230,4 +230,4 @@ spelling_ignore_contributor_names = True
 
 breathe_projects = {"verilated": "_build/doxygen/verilated/xml/"}
 breathe_default_project = "verilated"
-breathe_default_members = ('members')
+breathe_default_members = 'members'
diff --git a/examples/xml_py/vl_file_copy b/examples/xml_py/vl_file_copy
index b221eba6a..b8ac1e34c 100755
--- a/examples/xml_py/vl_file_copy
+++ b/examples/xml_py/vl_file_copy
@@ -60,8 +60,8 @@ class VlFileCopy:
             print("\t%s " % command)
         status = subprocess.call(command, shell=True)
         if status != 0:
-            raise Exception("Command failed running Verilator with '" +
-                            command + "', stopped")
+            raise RuntimeError("Command failed running Verilator with '" +
+                               command + "', stopped")
 
 
 #######################################################################
diff --git a/examples/xml_py/vl_hier_graph b/examples/xml_py/vl_hier_graph
index a2e82fabd..faa79ed2d 100755
--- a/examples/xml_py/vl_hier_graph
+++ b/examples/xml_py/vl_hier_graph
@@ -83,8 +83,8 @@ class VlHierGraph:
             print("\t%s " % command)
         status = subprocess.call(command, shell=True)
         if status != 0:
-            raise Exception("Command failed running Verilator with '" +
-                            command + "', stopped")
+            raise RuntimeError("Command failed running Verilator with '" +
+                               command + "', stopped")
 
 
 #######################################################################
diff --git a/nodist/code_coverage b/nodist/code_coverage
index 2fe0d13ac..5eb472bc3 100755
--- a/nodist/code_coverage
+++ b/nodist/code_coverage
@@ -316,7 +316,7 @@ def run(command):
     print("\t%s" % command)
     status = subprocess.call(command, shell=True)
     if status < 0:
-        raise Exception("%Error: Command failed " + command + ", stopped")
+        raise RuntimeError("%Error: Command failed " + command + ", stopped")
 
 
 def unlink_ok(filename):
diff --git a/nodist/install_test b/nodist/install_test
index 423400c45..3929d825b 100755
--- a/nodist/install_test
+++ b/nodist/install_test
@@ -104,7 +104,7 @@ def run(command):
     os.system(command)
     status = subprocess.call(command, shell=True)
     if status < 0:
-        raise Exception("%Error: Command failed " + command + ", stopped")
+        raise RuntimeError("%Error: Command failed " + command + ", stopped")
 
 
 #######################################################################
diff --git a/src/astgen b/src/astgen
index 761313ee5..0ace3f347 100755
--- a/src/astgen
+++ b/src/astgen
@@ -350,7 +350,7 @@ class Cpt:
 
     def _exec_syms_recurse(self, aref):
         for sym in aref:
-            if type(sym) is list:
+            if isinstance(sym, list):
                 self._exec_syms_recurse(sym)
             elif re.search(r'^\$.*', sym):
                 if sym not in self._exec_syms:
@@ -365,7 +365,7 @@ class Cpt:
                 first = False
                 continue
             out += ", "
-            if type(sym) is list:
+            if isinstance(sym, list):
                 out += self._exec_new_recurse(sym)
             elif re.match(r'^\$.*', sym):
                 out += self._exec_syms[sym]

From b78ea0682956c580d72bdf28e29b72492cae0df4 Mon Sep 17 00:00:00 2001
From: Geza Lore 
Date: Sat, 21 Oct 2023 15:29:18 +0100
Subject: [PATCH 110/157] Make VL_LOCK_SPINS configurable

It's unlikely one value fits all use case, so making VL_LOCK_SPINS
configurable at model build time.

For testing, we reduce the value as we expect high contention.
---
 include/verilated.h       | 2 ++
 test_regress/Makefile_obj | 3 +++
 2 files changed, 5 insertions(+)

diff --git a/include/verilated.h b/include/verilated.h
index 250f4a83d..eb35276c2 100644
--- a/include/verilated.h
+++ b/include/verilated.h
@@ -164,7 +164,9 @@ inline constexpr size_t roundUpToMultipleOf(size_t value) {
 // Return current thread ID (or 0), not super fast, cache if needed
 extern uint32_t VL_THREAD_ID() VL_MT_SAFE;
 
+#ifndef VL_LOCK_SPINS
 #define VL_LOCK_SPINS 50000  /// Number of times to spin for a mutex before yielding
+#endif
 
 /// Mutex, wrapped to allow -fthread_safety checks
 class VL_CAPABILITY("mutex") VerilatedMutex final {
diff --git a/test_regress/Makefile_obj b/test_regress/Makefile_obj
index 237ab1224..297f3d560 100644
--- a/test_regress/Makefile_obj
+++ b/test_regress/Makefile_obj
@@ -39,6 +39,9 @@ CPPFLAGS += $(CPPFLAGS_DRIVER)
 CPPFLAGS += $(CPPFLAGS_DRIVER2)
 CPPFLAGS += $(CPPFLAGS_ADD)
 
+# Reduce spin count for faster testing
+CPPFLAGS += -DVL_LOCK_SPINS=10000
+
 ifeq ($(CFG_WITH_LONGTESTS),yes)
   ifeq ($(DRIVER_STD),newest)
     CPPFLAGS += $(CFG_CXXFLAGS_STD)

From 10d33238b9f970adcbfd66fe91e8f2297bde27d0 Mon Sep 17 00:00:00 2001
From: Geza Lore 
Date: Sat, 21 Oct 2023 15:39:44 +0100
Subject: [PATCH 111/157] Do not merge entry/exit MTasks during coarsening

---
 src/V3Partition.cpp | 38 +++++++++++++++++++++++++++-----------
 src/V3Partition.h   |  4 ++++
 2 files changed, 31 insertions(+), 11 deletions(-)

diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp
index 16e7d612c..b1e2edb21 100644
--- a/src/V3Partition.cpp
+++ b/src/V3Partition.cpp
@@ -1256,12 +1256,18 @@ private:
     PartPropagateCp m_forwardPropagator{m_slowAsserts};  // Forward propagator
     PartPropagateCp m_reversePropagator{m_slowAsserts};  // Reverse propagator
 
+    LogicMTask* const m_entryMTaskp;  // Singular source vertex of the dependency graph
+    LogicMTask* const m_exitMTaskp;  // Singular sink vertex of the dependency graph
+
 public:
     // CONSTRUCTORS
-    PartContraction(V3Graph* mtasksp, uint32_t scoreLimit, bool slowAsserts)
+    PartContraction(V3Graph* mtasksp, uint32_t scoreLimit, LogicMTask* entryMTaskp,
+                    LogicMTask* exitMTaskp, bool slowAsserts)
         : m_mtasksp{mtasksp}
         , m_scoreLimit{scoreLimit}
-        , m_slowAsserts{slowAsserts} {}
+        , m_slowAsserts{slowAsserts}
+        , m_entryMTaskp{entryMTaskp}
+        , m_exitMTaskp{exitMTaskp} {}
 
     // METHODS
     void go() {
@@ -1377,6 +1383,16 @@ public:
                 continue;
             }
 
+            // Avoid merging the entry/exit nodes. This would create serialization, by forcing the
+            // merged MTask to run before/after everything else. Empirically this helps
+            // performance in a modest way by allowing other MTasks to start earlier.
+            if (MTaskEdge* const edgep = mergeCanp->toMTaskEdge()) {
+                if (edgep->fromp() == m_entryMTaskp || edgep->top() == m_exitMTaskp) {
+                    m_sb.remove(mergeCanp);
+                    continue;
+                }
+            }
+
             // Avoid merging any edge that would create a cycle.
             //
             // For example suppose we begin with vertices A, B, C and edges
@@ -1742,7 +1758,7 @@ private:
         // slowAsserts.
         PartContraction ec{&mtasks,
                            // Any CP limit >chain_len should work:
-                           chain_len * 2, false /* slowAsserts */};
+                           chain_len * 2, nullptr, nullptr, false /* slowAsserts */};
         ec.go();
 
         PartParallelismEst check{&mtasks};
@@ -1796,7 +1812,7 @@ private:
         }
 
         partInitCriticalPaths(&mtasks);
-        PartContraction{&mtasks, 20, true}.go();
+        PartContraction{&mtasks, 20, nullptr, nullptr, true}.go();
 
         PartParallelismEst check{&mtasks};
         check.traverse();
@@ -2644,7 +2660,7 @@ uint32_t V3Partition::setupMTaskDeps(V3Graph* mtasksp) {
     // Artificial single entry point vertex in the MTask graph to allow sibling merges.
     // This is required as otherwise disjoint sub-graphs could not be merged, but the
     // coarsening algorithm assumes that the graph is connected.
-    LogicMTask* const entryMTask = new LogicMTask{mtasksp, nullptr};
+    m_entryMTaskp = new LogicMTask{mtasksp, nullptr};
 
     // The V3InstrCount within LogicMTask will set user5 on each AST
     // node, to assert that we never count any node twice.
@@ -2665,7 +2681,7 @@ uint32_t V3Partition::setupMTaskDeps(V3Graph* mtasksp) {
 
     // Artificial single exit point vertex in the MTask graph to allow sibling merges.
     // this enables merging MTasks with no downstream dependents if that is the ideal merge.
-    LogicMTask* const exitMTask = new LogicMTask{mtasksp, nullptr};
+    m_exitMTaskp = new LogicMTask{mtasksp, nullptr};
 
     // Create the mtask->mtask dependency edges based on the dependencies between MTaskMoveVertex
     // vertices.
@@ -2674,7 +2690,7 @@ uint32_t V3Partition::setupMTaskDeps(V3Graph* mtasksp) {
         LogicMTask* const mtaskp = static_cast(vtxp);
 
         // Entry and exit vertices handled separately
-        if (VL_UNLIKELY((mtaskp == entryMTask) || (mtaskp == exitMTask))) continue;
+        if (VL_UNLIKELY((mtaskp == m_entryMTaskp) || (mtaskp == m_exitMTaskp))) continue;
 
         // At this point, there should only be one MTaskMoveVertex per LogicMTask
         UASSERT_OBJ(mtaskp->vertexListp()->size() == 1, mtaskp, "Multiple MTaskMoveVertex");
@@ -2714,11 +2730,11 @@ uint32_t V3Partition::setupMTaskDeps(V3Graph* mtasksp) {
         nextp = vtxp->verticesNextp();
         LogicMTask* const mtaskp = static_cast(vtxp);
 
-        if (VL_UNLIKELY((mtaskp == entryMTask) || (mtaskp == exitMTask))) continue;
+        if (VL_UNLIKELY((mtaskp == m_entryMTaskp) || (mtaskp == m_exitMTaskp))) continue;
 
         // Add the entry/exit edges
-        if (mtaskp->inEmpty()) new MTaskEdge{mtasksp, entryMTask, mtaskp, 1};
-        if (mtaskp->outEmpty()) new MTaskEdge{mtasksp, mtaskp, exitMTask, 1};
+        if (mtaskp->inEmpty()) new MTaskEdge{mtasksp, m_entryMTaskp, mtaskp, 1};
+        if (mtaskp->outEmpty()) new MTaskEdge{mtasksp, mtaskp, m_exitMTaskp, 1};
     }
 
     return totalGraphCost;
@@ -2786,7 +2802,7 @@ void V3Partition::go(V3Graph* mtasksp) {
     // Some tests disable this, hence the test on threadsCoarsen().
     // Coarsening is always enabled in production.
     if (v3Global.opt.threadsCoarsen()) {
-        PartContraction{mtasksp, cpLimit,
+        PartContraction{mtasksp, cpLimit, m_entryMTaskp, m_exitMTaskp,
                         // --debugPartition is used by tests
                         // to enable slow assertions.
                         v3Global.opt.debugPartition()}
diff --git a/src/V3Partition.h b/src/V3Partition.h
index caac97371..5aba6b009 100644
--- a/src/V3Partition.h
+++ b/src/V3Partition.h
@@ -41,6 +41,10 @@ class V3Partition final {
     // MEMBERS
     const OrderGraph* const m_orderGraphp;  // The OrderGraph
     const V3Graph* const m_fineDepsGraphp;  // Fine-grained dependency graph
+
+    LogicMTask* m_entryMTaskp = nullptr;  // Singular source vertex of the dependency graph
+    LogicMTask* m_exitMTaskp = nullptr;  // Singular sink vertex of the dependency graph
+
 public:
     // CONSTRUCTORS
     explicit V3Partition(const OrderGraph* orderGraphp, const V3Graph* fineDepsGraphp)

From a09506a0ad95b02168b4c733e94394c40f8543ca Mon Sep 17 00:00:00 2001
From: Geza Lore 
Date: Sat, 21 Oct 2023 18:01:45 +0100
Subject: [PATCH 112/157] Trivial simplification of V3EmitCModel

Still some remains of the --threads 0 mode. Remove unnecessary complexity
from V3EmitCModel. (Also don't pretend there is an MTask in single
threaded mode, when there really isn't.)
---
 include/verilated.cpp                 |  1 +
 include/verilated.h                   |  1 +
 src/V3EmitCModel.cpp                  | 10 ------
 test_regress/t/t_timing_debug1.out    | 45 ---------------------------
 test_regress/t/t_timing_debug2.out    | 21 -------------
 test_regress/t/t_trace_noflag_bad.out |  2 +-
 test_regress/t/t_verilated_debug.out  |  2 --
 7 files changed, 3 insertions(+), 79 deletions(-)

diff --git a/include/verilated.cpp b/include/verilated.cpp
index 0794d4dd2..dd574a93e 100644
--- a/include/verilated.cpp
+++ b/include/verilated.cpp
@@ -3024,6 +3024,7 @@ void Verilated::endOfEval(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
     // It should be ok to call into endOfEvalGuts, it returns immediately
     // if there are no transactions.
     VL_DEBUG_IF(VL_DBG_MSGF("End-of-eval cleanup\n"););
+    VerilatedThreadMsgQueue::flush(evalMsgQp);
     evalMsgQp->process();
 }
 
diff --git a/include/verilated.h b/include/verilated.h
index eb35276c2..4e4503a8d 100644
--- a/include/verilated.h
+++ b/include/verilated.h
@@ -921,6 +921,7 @@ public:
 
     // Internal: Called at end of each thread mtask, before finishing eval
     static void endOfThreadMTask(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
+        mtaskId(0);
         if (VL_UNLIKELY(t_s.t_endOfEvalReqd)) endOfThreadMTaskGuts(evalMsgQp);
     }
     // Internal: Called at end of eval loop
diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp
index b7caefa54..ac2c5c316 100644
--- a/src/V3EmitCModel.cpp
+++ b/src/V3EmitCModel.cpp
@@ -401,13 +401,6 @@ class EmitCModel final : public EmitCFunc {
         puts(topModNameProtected + "__" + protect("_eval_settle") + "(&(vlSymsp->TOP));\n");
         puts("}\n");
 
-        if (v3Global.opt.threads() == 1) {
-            const uint32_t mtaskId = 0;
-            putsDecoration("// MTask " + cvtToStr(mtaskId) + " start\n");
-            puts("VL_DEBUG_IF(VL_DBG_MSGF(\"MTask" + cvtToStr(mtaskId) + " starting\\n\"););\n");
-            puts("Verilated::mtaskId(" + cvtToStr(mtaskId) + ");\n");
-        }
-
         if (v3Global.opt.profExec()) {
             puts("vlSymsp->__Vm_executionProfilerp->configure();\n");
             puts("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).evalBegin();\n");
@@ -417,9 +410,6 @@ class EmitCModel final : public EmitCFunc {
         puts(topModNameProtected + "__" + protect("_eval") + "(&(vlSymsp->TOP));\n");
 
         putsDecoration("// Evaluate cleanup\n");
-        if (v3Global.opt.threads() == 1) {
-            puts("Verilated::endOfThreadMTask(vlSymsp->__Vm_evalMsgQp);\n");
-        }
         puts("Verilated::endOfEval(vlSymsp->__Vm_evalMsgQp);\n");
 
         if (v3Global.opt.profExec()) puts("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).evalEnd();\n");
diff --git a/test_regress/t/t_timing_debug1.out b/test_regress/t/t_timing_debug1.out
index 337319d92..540f6e60d 100644
--- a/test_regress/t/t_timing_debug1.out
+++ b/test_regress/t/t_timing_debug1.out
@@ -32,7 +32,6 @@
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__stl
 -V{t#,#}+    Vt_timing_debug1___024root___dump_triggers__stl
 -V{t#,#}         No triggers active
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -65,7 +64,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -125,7 +123,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -164,7 +161,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -198,7 +194,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -250,7 +245,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -315,7 +309,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -358,7 +351,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -391,7 +383,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -448,7 +439,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -486,7 +476,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -519,7 +508,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -570,7 +558,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -608,7 +595,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -646,7 +632,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -679,7 +664,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -730,7 +714,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -768,7 +751,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -801,7 +783,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -874,7 +855,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -908,7 +888,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -946,7 +925,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -979,7 +957,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -1036,7 +1013,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -1074,7 +1050,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -1107,7 +1082,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -1144,7 +1118,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -1195,7 +1168,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -1233,7 +1205,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -1266,7 +1237,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -1317,7 +1287,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -1355,7 +1324,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -1422,7 +1390,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -1455,7 +1422,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -1512,7 +1478,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -1550,7 +1515,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -1583,7 +1547,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -1634,7 +1597,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -1676,7 +1638,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -1709,7 +1670,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -1760,7 +1720,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -1798,7 +1757,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -1831,7 +1789,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -1882,7 +1839,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
@@ -1945,7 +1901,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step
 -V{t#,#}+    Vt_timing_debug1___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval
 -V{t#,#}+    Vt_timing_debug1___024root___eval_triggers__act
diff --git a/test_regress/t/t_timing_debug2.out b/test_regress/t/t_timing_debug2.out
index 0e22dcd4e..02f53ec34 100644
--- a/test_regress/t/t_timing_debug2.out
+++ b/test_regress/t/t_timing_debug2.out
@@ -77,7 +77,6 @@
 -V{t#,#}+      Vt_timing_debug2_t___eval_initial__TOP__t__8
 -V{t#,#}+      Vt_timing_debug2_t___eval_initial__TOP__t__9
 -V{t#,#}+    Vt_timing_debug2___024root___eval_settle
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval_triggers__act
@@ -93,7 +92,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step
 -V{t#,#}+    Vt_timing_debug2___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval_triggers__act
@@ -154,7 +152,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step
 -V{t#,#}+    Vt_timing_debug2___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval_triggers__act
@@ -206,7 +203,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step
 -V{t#,#}+    Vt_timing_debug2___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval_triggers__act
@@ -266,7 +262,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step
 -V{t#,#}+    Vt_timing_debug2___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval_triggers__act
@@ -352,7 +347,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step
 -V{t#,#}+    Vt_timing_debug2___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval_triggers__act
@@ -442,7 +436,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step
 -V{t#,#}+    Vt_timing_debug2___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval_triggers__act
@@ -515,7 +508,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step
 -V{t#,#}+    Vt_timing_debug2___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval_triggers__act
@@ -605,7 +597,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step
 -V{t#,#}+    Vt_timing_debug2___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval_triggers__act
@@ -695,7 +686,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step
 -V{t#,#}+    Vt_timing_debug2___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval_triggers__act
@@ -759,7 +749,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step
 -V{t#,#}+    Vt_timing_debug2___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval_triggers__act
@@ -803,7 +792,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step
 -V{t#,#}+    Vt_timing_debug2___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval_triggers__act
@@ -846,7 +834,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step
 -V{t#,#}+    Vt_timing_debug2___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval_triggers__act
@@ -908,7 +895,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step
 -V{t#,#}+    Vt_timing_debug2___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval_triggers__act
@@ -951,7 +937,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step
 -V{t#,#}+    Vt_timing_debug2___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval_triggers__act
@@ -1018,7 +1003,6 @@
 -V{t#,#}+    Vt_timing_debug2___024root___eval_debug_assertions
 -V{t#,#}+        Vt_timing_debug2_t__03a__03aForkDelayClass::~
 -V{t#,#}+        Vt_timing_debug2_t__03a__03aForkClass::~
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval_triggers__act
@@ -1052,7 +1036,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step
 -V{t#,#}+    Vt_timing_debug2___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval_triggers__act
@@ -1088,7 +1071,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step
 -V{t#,#}+    Vt_timing_debug2___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval_triggers__act
@@ -1121,7 +1103,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step
 -V{t#,#}+    Vt_timing_debug2___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval_triggers__act
@@ -1155,7 +1136,6 @@
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step
 -V{t#,#}+    Vt_timing_debug2___024root___eval_debug_assertions
 -V{t#,#}+        Vt_timing_debug2_t__03a__03aAssignDelayClass::~
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval_triggers__act
@@ -1186,7 +1166,6 @@
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step
 -V{t#,#}+    Vt_timing_debug2___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval
 -V{t#,#}+    Vt_timing_debug2___024root___eval_triggers__act
diff --git a/test_regress/t/t_trace_noflag_bad.out b/test_regress/t/t_trace_noflag_bad.out
index 66a2974a8..658b49c8d 100644
--- a/test_regress/t/t_trace_noflag_bad.out
+++ b/test_regress/t/t_trace_noflag_bad.out
@@ -1,2 +1,2 @@
-%Error: Vt_trace_noflag_bad.cpp:105: 'Vt_trace_noflag_bad::trace()' called on model that was Verilated without --trace option
+%Error: Vt_trace_noflag_bad.cpp:101: 'Vt_trace_noflag_bad::trace()' called on model that was Verilated without --trace option
 Aborting...
diff --git a/test_regress/t/t_verilated_debug.out b/test_regress/t/t_verilated_debug.out
index 55cf9f490..ef9dbeddd 100644
--- a/test_regress/t/t_verilated_debug.out
+++ b/test_regress/t/t_verilated_debug.out
@@ -13,7 +13,6 @@ internalsDump:
 -V{t#,#}+    Vt_verilated_debug___024root___eval_initial__TOP
   Data: w96: 000000aa 000000bb 000000cc 
 -V{t#,#}+    Vt_verilated_debug___024root___eval_settle
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_verilated_debug___024root___eval
 -V{t#,#}+    Vt_verilated_debug___024root___eval_triggers__act
@@ -22,7 +21,6 @@ internalsDump:
 -V{t#,#}End-of-eval cleanup
 -V{t#,#}+++++TOP Evaluate Vt_verilated_debug::eval_step
 -V{t#,#}+    Vt_verilated_debug___024root___eval_debug_assertions
--V{t#,#}MTask0 starting
 -V{t#,#}+ Eval
 -V{t#,#}+    Vt_verilated_debug___024root___eval
 -V{t#,#}+    Vt_verilated_debug___024root___eval_triggers__act

From 52f2b9ef5886652fa8c12708cc10114ea2fc71e2 Mon Sep 17 00:00:00 2001
From: Geza Lore 
Date: Sat, 21 Oct 2023 20:24:20 +0100
Subject: [PATCH 113/157] Remove pointless test

t_optm_if_cond was a test for a then non-existent optimization to merge
conditionals. V3MergeCond implements this and has its own tests.
---
 test_regress/t/t_optm_if_cond.pl | 22 ------------
 test_regress/t/t_optm_if_cond.v  | 57 --------------------------------
 2 files changed, 79 deletions(-)
 delete mode 100755 test_regress/t/t_optm_if_cond.pl
 delete mode 100644 test_regress/t/t_optm_if_cond.v

diff --git a/test_regress/t/t_optm_if_cond.pl b/test_regress/t/t_optm_if_cond.pl
deleted file mode 100755
index 3215fbf08..000000000
--- a/test_regress/t/t_optm_if_cond.pl
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env perl
-if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
-# DESCRIPTION: Verilator: Verilog Test driver/expect definition
-#
-# Copyright 2019 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);
-
-compile(
-    verilator_flags2 => ['--stats', "-fno-merge-cond"],
-    );
-
-if ($Self->{vlt_all}) {
-    file_grep($Self->{stats}, qr/Node count, IF  +\d+ +\d+ +\d+ +\d+ +(\d+)/, 28);
-}
-
-ok(1);
-1;
diff --git a/test_regress/t/t_optm_if_cond.v b/test_regress/t/t_optm_if_cond.v
deleted file mode 100644
index f9509efad..000000000
--- a/test_regress/t/t_optm_if_cond.v
+++ /dev/null
@@ -1,57 +0,0 @@
-// DESCRIPTION: Verilator: Verilog Test module
-//
-// This file ONLY is placed under the Creative Commons Public Domain, for
-// any use, without warranty, 2020 by Wilson Snyder.
-// SPDX-License-Identifier: CC0-1.0
-
-module t(/*AUTOARG*/
-   // Outputs
-   q0, q1, q2, q3, q4,
-   // Inputs
-   clk, rst, en, i0, i1, i2, i3, i4
-   );
-   input clk;
-
-   input rst;
-   input en;
-   output int q0;   input int i0;
-   output int q1;   input int i1;
-   output int q2;   input int i2;
-   output int q3;   input int i3;
-   output int q4;   input int i4;
-
-   always @ (posedge clk) begin
-      if (rst) begin
-         if (en) q0 <= i0;
-      end
-      else q0 <= 0;
-
-      if (rst) begin
-         if (en) q1 <= i1;
-      end
-      else q1 <= 0;
-
-      if (rst) begin
-         if (en) q2 <= i2;
-      end
-      else q2 <= 0;
-
-      if (rst) begin
-         if (en) q3 <= i3;
-      end
-      else q3 <= 0;
-   end
-
-   always_comb begin
-      q4 = i4;
-      if (q4 == 0) begin
-         // Conflicts with condition
-         q4 = 1;
-      end
-      if (q4 == 0) begin
-         // Conflicts with condition
-         q4 = 2;
-      end
-   end
-
-endmodule

From 146cdc020d84db9a26aa65f82ca60d65c49a4032 Mon Sep 17 00:00:00 2001
From: Geza Lore 
Date: Sat, 21 Oct 2023 20:30:02 +0100
Subject: [PATCH 114/157] Remove V3AstConstOnly.h

This is now redundant with the introduction of VNVisitorConst
---
 src/CMakeLists.txt   |  1 -
 src/V3AstConstOnly.h | 29 -----------------------------
 src/V3Broken.cpp     |  4 ----
 src/V3Stats.cpp      |  3 ---
 4 files changed, 37 deletions(-)
 delete mode 100644 src/V3AstConstOnly.h

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 8124e0ee3..fdf215082 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -35,7 +35,6 @@ set(HEADERS
     V3Assert.h
     V3AssertPre.h
     V3Ast.h
-    V3AstConstOnly.h
     V3AstInlines.h
     V3AstNodeDType.h
     V3AstNodeExpr.h
diff --git a/src/V3AstConstOnly.h b/src/V3AstConstOnly.h
deleted file mode 100644
index f785a3239..000000000
--- a/src/V3AstConstOnly.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// -*- mode: C++; c-file-style: "cc-mode" -*-
-//*************************************************************************
-// DESCRIPTION: Verilator: Ast node structure
-//
-// Code available from: https://verilator.org
-//
-//*************************************************************************
-//
-// Copyright 2003-2023 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
-//
-//*************************************************************************
-
-#ifndef VERILATOR_V3ASTCONSTONLY_H_
-#define VERILATOR_V3ASTCONSTONLY_H_
-
-// Include only in visitors that do not not edit nodes, so should use constant iterators
-#define iterateAndNext error_use_iterateAndNextConst
-#define iterateChildren error_use_iterateChildrenConst
-
-#define addNext error_no_addNext_in_ConstOnlyVisitor
-#define replaceWith error_no_replaceWith_in_ConstOnlyVisitor
-#define deleteTree error_no_deleteTree_in_ConstOnlyVisitor
-#define unlinkFrBack error_no_unlinkFrBack_in_ConstOnlyVisitor
-
-#endif  // Guard
diff --git a/src/V3Broken.cpp b/src/V3Broken.cpp
index 9ae17efb9..5daa4f5a8 100644
--- a/src/V3Broken.cpp
+++ b/src/V3Broken.cpp
@@ -26,10 +26,6 @@
 
 #include "V3Broken.h"
 
-// This visitor does not edit nodes, and is called at error-exit, so should use constant iterators
-#include "V3AstConstOnly.h"
-
-#include 
 #include 
 
 VL_DEFINE_DEBUG_FUNCTIONS;
diff --git a/src/V3Stats.cpp b/src/V3Stats.cpp
index 3f89004df..f79c8145a 100644
--- a/src/V3Stats.cpp
+++ b/src/V3Stats.cpp
@@ -18,9 +18,6 @@
 
 #include "V3Stats.h"
 
-// This visitor does not edit nodes, and is called at error-exit, so should use constant iterators
-#include "V3AstConstOnly.h"
-
 #include 
 #include 
 

From 4c0edd2efb20309d8dd18d6ae355949918797c22 Mon Sep 17 00:00:00 2001
From: Geza Lore 
Date: Wed, 10 May 2023 12:12:34 +0100
Subject: [PATCH 115/157] Improve --prof-exec infrastructure and report

Again --prof-exec have bit-rotted a little with all the recent changes
to the structure of the generated code. This patch contains a few
improvements:
- Repalce the eval/evl_loop begin/end events with generic
  section_push/section_pop events, that can be arbitrarily sprinkled
  into the generate code (so long as they are matched correctly) to
  measure various sections. The report then contains a nested profile
  of the sections, and the VCD trace shows the section names.
- Better handling of exec graphs
- Clearer overall statistics
---
 bin/verilator_gantt                  | 615 +++++++++++++++------------
 docs/guide/exe_verilator_gantt.rst   |  14 +-
 include/verilated_profiler.cpp       |  23 +-
 include/verilated_profiler.h         |  24 +-
 src/V3EmitCModel.cpp                 |   4 +-
 src/V3Order.cpp                      |  12 +-
 src/V3Partition.cpp                  |   8 +
 src/V3Sched.cpp                      |  20 +-
 test_regress/t/t_gantt.pl            |   2 +-
 test_regress/t/t_gantt_io.dat        |  12 +-
 test_regress/t/t_gantt_io.out        |  49 ++-
 test_regress/t/t_gantt_io.vcd.out    | 320 +++++++-------
 test_regress/t/t_gantt_io_arm.dat    |   8 +-
 test_regress/t/t_gantt_io_arm.out    |  49 ++-
 test_regress/t/t_gantt_io_noproc.dat |  12 +-
 test_regress/t/t_gantt_io_noproc.out |  49 ++-
 test_regress/t/t_gantt_two.pl        |   2 +-
 17 files changed, 662 insertions(+), 561 deletions(-)

diff --git a/bin/verilator_gantt b/bin/verilator_gantt
index 0015cb57f..60814b209 100755
--- a/bin/verilator_gantt
+++ b/bin/verilator_gantt
@@ -1,33 +1,32 @@
 #!/usr/bin/env python3
-# pylint: disable=C0103,C0114,C0116,C0209,C0301,R0914,R0912,R0915,W0511,eval-used
+# pylint: disable=C0103,C0114,C0116,C0209,C0301,R0914,R0912,R0915,W0511,W0603,eval-used
 ######################################################################
 
 import argparse
+import bisect
 import collections
 import math
 import re
 import statistics
 # from pprint import pprint
 
-Threads = collections.defaultdict(lambda: collections.defaultdict(lambda: {}))
-Mtasks = collections.defaultdict(lambda: {})
-Evals = collections.defaultdict(lambda: {})
-EvalLoops = collections.defaultdict(lambda: {})
+Sections = []
+LongestVcdStrValueLength = 0
+Threads = collections.defaultdict(lambda: [])  # List of records per thread id
+Mtasks = collections.defaultdict(lambda: {'elapsed': 0, 'end': 0})
+Cpus = collections.defaultdict(lambda: {'mtask_time': 0})
 Global = {
     'args': {},
     'cpuinfo': collections.defaultdict(lambda: {}),
-    'rdtsc_cycle_time': 0,
     'stats': {}
 }
+ElapsedTime = None  # total elapsed time
+ExecGraphTime = 0  # total elapsed time excuting an exec graph
+ExecGraphIntervals = []  # list of (start, end) pairs
 
 ######################################################################
 
 
-def process(filename):
-    read_data(filename)
-    report()
-
-
 def read_data(filename):
     with open(filename, "r", encoding="utf8") as fh:
         re_thread = re.compile(r'^VLPROFTHREAD (\d+)$')
@@ -39,14 +38,17 @@ def read_data(filename):
         re_arg1 = re.compile(r'VLPROF arg\s+(\S+)\+([0-9.]*)\s*')
         re_arg2 = re.compile(r'VLPROF arg\s+(\S+)\s+([0-9.]*)\s*$')
         re_stat = re.compile(r'VLPROF stat\s+(\S+)\s+([0-9.]+)')
-        re_time = re.compile(r'rdtsc time = (\d+) ticks')
         re_proc_cpu = re.compile(r'VLPROFPROC processor\s*:\s*(\d+)\s*$')
         re_proc_dat = re.compile(r'VLPROFPROC ([a-z_ ]+)\s*:\s*(.*)$')
         cpu = None
         thread = None
+        execGraphStart = None
 
-        lastEvalBeginTick = None
-        lastEvalLoopBeginTick = None
+        global LongestVcdStrValueLength
+        global ExecGraphTime
+
+        SectionStack = []
+        mTaskThread = {}
 
         for line in fh:
             recordMatch = re_record.match(line)
@@ -54,29 +56,31 @@ def read_data(filename):
                 kind, tick, payload = recordMatch.groups()
                 tick = int(tick)
                 payload = payload.strip()
-                if kind == "EVAL_BEGIN":
-                    Evals[tick]['start'] = tick
-                    lastEvalBeginTick = tick
-                elif kind == "EVAL_END":
-                    Evals[lastEvalBeginTick]['end'] = tick
-                    lastEvalBeginTick = None
-                elif kind == "EVAL_LOOP_BEGIN":
-                    EvalLoops[tick]['start'] = tick
-                    lastEvalLoopBeginTick = tick
-                elif kind == "EVAL_LOOP_END":
-                    EvalLoops[lastEvalLoopBeginTick]['end'] = tick
-                    lastEvalLoopBeginTick = None
+                if kind == "SECTION_PUSH":
+                    LongestVcdStrValueLength = max(LongestVcdStrValueLength,
+                                                   len(payload))
+                    SectionStack.append(payload)
+                    Sections.append((tick, tuple(SectionStack)))
+                elif kind == "SECTION_POP":
+                    assert SectionStack, "SECTION_POP without SECTION_PUSH"
+                    SectionStack.pop()
+                    Sections.append((tick, tuple(SectionStack)))
                 elif kind == "MTASK_BEGIN":
                     mtask, predict_start, ecpu = re_payload_mtaskBegin.match(
                         payload).groups()
                     mtask = int(mtask)
                     predict_start = int(predict_start)
                     ecpu = int(ecpu)
-                    Threads[thread][tick]['mtask'] = mtask
-                    Threads[thread][tick]['predict_start'] = predict_start
-                    Threads[thread][tick]['cpu'] = ecpu
-                    if 'elapsed' not in Mtasks[mtask]:
-                        Mtasks[mtask] = {'end': 0, 'elapsed': 0}
+                    mTaskThread[mtask] = thread
+                    records = Threads[thread]
+                    assert not records or records[-1]['start'] <= records[-1][
+                        'end'] <= tick
+                    records.append({
+                        'start': tick,
+                        'mtask': mtask,
+                        'predict_start': predict_start,
+                        'cpu': ecpu
+                    })
                     Mtasks[mtask]['begin'] = tick
                     Mtasks[mtask]['thread'] = thread
                     Mtasks[mtask]['predict_start'] = predict_start
@@ -86,11 +90,18 @@ def read_data(filename):
                     mtask = int(mtask)
                     predict_cost = int(predict_cost)
                     begin = Mtasks[mtask]['begin']
-                    Threads[thread][begin]['end'] = tick
-                    Threads[thread][begin]['predict_cost'] = predict_cost
+                    record = Threads[mTaskThread[mtask]][-1]
+                    record['end'] = tick
+                    record['predict_cost'] = predict_cost
                     Mtasks[mtask]['elapsed'] += tick - begin
                     Mtasks[mtask]['predict_cost'] = predict_cost
                     Mtasks[mtask]['end'] = max(Mtasks[mtask]['end'], tick)
+                elif kind == "EXEC_GRAPH_BEGIN":
+                    execGraphStart = tick
+                elif kind == "EXEC_GRAPH_END":
+                    ExecGraphTime += tick - execGraphStart
+                    ExecGraphIntervals.append((execGraphStart, tick))
+                    execGraphStart = None
                 elif Args.debug:
                     print("-Unknown execution trace record: %s" % line)
             elif re_thread.match(line):
@@ -109,7 +120,7 @@ def read_data(filename):
             elif re_proc_cpu.match(line):
                 match = re_proc_cpu.match(line)
                 cpu = int(match.group(1))
-            elif cpu and re_proc_dat.match(line):
+            elif cpu is not None and re_proc_dat.match(line):
                 match = re_proc_dat.match(line)
                 term = match.group(1)
                 value = match.group(2)
@@ -121,11 +132,6 @@ def read_data(filename):
                 pass
             elif Args.debug:
                 print("-Unk: %s" % line)
-            # TODO -- this is parsing text printed by a client.
-            # Really, verilator proper should generate this
-            # if it's useful...
-            if re_time.match(line):
-                Global['rdtsc_cycle_time'] = re_time.group(1)
 
 
 def re_match_result(regexp, line, result_to):
@@ -144,125 +150,33 @@ def report():
         plus = "+" if re.match(r'^\+', arg) else " "
         print("  %s%s%s" % (arg, plus, Global['args'][arg]))
 
+    for records in Threads.values():
+        for record in records:
+            cpu = record['cpu']
+            elapsed = record['end'] - record['start']
+            Cpus[cpu]['mtask_time'] += elapsed
+
+    global ElapsedTime
+    ElapsedTime = int(Global['stats']['ticks'])
     nthreads = int(Global['stats']['threads'])
-    Global['cpus'] = {}
-    for thread in Threads:
-        # Make potentially multiple characters per column
-        for start in Threads[thread]:
-            if not Threads[thread][start]:
-                continue
-            cpu = Threads[thread][start]['cpu']
-            elapsed = Threads[thread][start]['end'] - start
-            if cpu not in Global['cpus']:
-                Global['cpus'][cpu] = {'cpu_time': 0}
-            Global['cpus'][cpu]['cpu_time'] += elapsed
+    ncpus = max(len(Cpus), 1)
 
-    measured_mt_mtask_time = 0
-    predict_mt_mtask_time = 0
-    long_mtask_time = 0
-    measured_last_end = 0
-    predict_last_end = 0
-    for mtask in Mtasks:
-        measured_mt_mtask_time += Mtasks[mtask]['elapsed']
-        predict_mt_mtask_time += Mtasks[mtask]['predict_cost']
-        measured_last_end = max(measured_last_end, Mtasks[mtask]['end'])
-        predict_last_end = max(
-            predict_last_end,
-            Mtasks[mtask]['predict_start'] + Mtasks[mtask]['predict_cost'])
-        long_mtask_time = max(long_mtask_time, Mtasks[mtask]['elapsed'])
-    Global['measured_last_end'] = measured_last_end
-    Global['predict_last_end'] = predict_last_end
-
-    # If we know cycle time in the same (rdtsc) units,
-    # this will give us an actual utilization number,
-    # (how effectively we keep the cores busy.)
-    #
-    # It also gives us a number we can compare against
-    # serial mode, to estimate the overhead of data sharing,
-    # which will show up in the total elapsed time. (Overhead
-    # of synchronization and scheduling should not.)
-    print("\nAnalysis:")
-    print("  Total threads             = %d" % nthreads)
-    print("  Total mtasks              = %d" % len(Mtasks))
-    ncpus = max(len(Global['cpus']), 1)
-    print("  Total cpus used           = %d" % ncpus)
-    print("  Total yields              = %d" %
-          int(Global['stats'].get('yields', 0)))
-    print("  Total evals               = %d" % len(Evals))
-    print("  Total eval loops          = %d" % len(EvalLoops))
-    if Mtasks:
-        print("  Total eval time           = %d rdtsc ticks" %
-              Global['measured_last_end'])
-        print("  Longest mtask time        = %d rdtsc ticks" % long_mtask_time)
-        print("  All-thread mtask time     = %d rdtsc ticks" %
-              measured_mt_mtask_time)
-        long_efficiency = long_mtask_time / (Global.get(
-            'measured_last_end', 1) or 1)
-        print("  Longest-thread efficiency = %0.1f%%" %
-              (long_efficiency * 100.0))
-        mt_efficiency = measured_mt_mtask_time / (
-            Global.get('measured_last_end', 1) * nthreads or 1)
-        print("  All-thread efficiency     = %0.1f%%" %
-              (mt_efficiency * 100.0))
-        print("  All-thread speedup        = %0.1f" %
-              (mt_efficiency * nthreads))
-        if Global['rdtsc_cycle_time'] > 0:
-            ut = measured_mt_mtask_time / Global['rdtsc_cycle_time']
-            print("tot_mtask_cpu=" + measured_mt_mtask_time + " cyc=" +
-                  Global['rdtsc_cycle_time'] + " ut=" + ut)
-
-        predict_mt_efficiency = predict_mt_mtask_time / (
-            Global.get('predict_last_end', 1) * nthreads or 1)
-        print("\nPrediction (what Verilator used for scheduling):")
-        print("  All-thread efficiency     = %0.1f%%" %
-              (predict_mt_efficiency * 100.0))
-        print("  All-thread speedup        = %0.1f" %
-              (predict_mt_efficiency * nthreads))
-
-        p2e_ratios = []
-        min_p2e = 1000000
-        min_mtask = None
-        max_p2e = -1000000
-        max_mtask = None
-
-        for mtask in sorted(Mtasks.keys()):
-            if Mtasks[mtask]['elapsed'] > 0:
-                if Mtasks[mtask]['predict_cost'] == 0:
-                    Mtasks[mtask]['predict_cost'] = 1  # don't log(0) below
-                p2e_ratio = math.log(Mtasks[mtask]['predict_cost'] /
-                                     Mtasks[mtask]['elapsed'])
-                p2e_ratios.append(p2e_ratio)
-
-                if p2e_ratio > max_p2e:
-                    max_p2e = p2e_ratio
-                    max_mtask = mtask
-                if p2e_ratio < min_p2e:
-                    min_p2e = p2e_ratio
-                    min_mtask = mtask
-
-        print("\nMTask statistics:")
-        print("  min log(p2e) = %0.3f" % min_p2e, end="")
-        print("  from mtask %d (predict %d," %
-              (min_mtask, Mtasks[min_mtask]['predict_cost']),
-              end="")
-        print(" elapsed %d)" % Mtasks[min_mtask]['elapsed'])
-        print("  max log(p2e) = %0.3f" % max_p2e, end="")
-        print("  from mtask %d (predict %d," %
-              (max_mtask, Mtasks[max_mtask]['predict_cost']),
-              end="")
-        print(" elapsed %d)" % Mtasks[max_mtask]['elapsed'])
-
-        stddev = statistics.pstdev(p2e_ratios)
-        mean = statistics.mean(p2e_ratios)
-        print("  mean = %0.3f" % mean)
-        print("  stddev = %0.3f" % stddev)
-        print("  e ^ stddev = %0.3f" % math.exp(stddev))
+    print("\nSummary:")
+    print("  Total elapsed time = {} rdtsc ticks".format(ElapsedTime))
+    print("  Parallelized code  = {:.2%} of elapsed time".format(
+        ExecGraphTime / ElapsedTime))
+    print("  Total threads      = %d" % nthreads)
+    print("  Total CPUs used    = %d" % ncpus)
+    print("  Total mtasks       = %d" % len(Mtasks))
+    print("  Total yields       = %d" % int(Global['stats'].get('yields', 0)))
 
+    report_mtasks()
     report_cpus()
+    report_sections()
 
     if nthreads > ncpus:
         print()
-        print("%%Warning: There were fewer CPUs (%d) then threads (%d)." %
+        print("%%Warning: There were fewer CPUs (%d) than threads (%d)." %
               (ncpus, nthreads))
         print("        : See docs on use of numactl.")
     else:
@@ -279,32 +193,130 @@ def report():
     print()
 
 
+def report_mtasks():
+    if not Mtasks:
+        return
+
+    nthreads = int(Global['stats']['threads'])
+
+    # If we know cycle time in the same (rdtsc) units,
+    # this will give us an actual utilization number,
+    # (how effectively we keep the cores busy.)
+    #
+    # It also gives us a number we can compare against
+    # serial mode, to estimate the overhead of data sharing,
+    # which will show up in the total elapsed time. (Overhead
+    # of synchronization and scheduling should not.)
+    total_mtask_time = 0
+    thread_mtask_time = collections.defaultdict(lambda: 0)
+    long_mtask_time = 0
+    long_mtask = None
+    predict_mtask_time = 0
+    predict_elapsed = 0
+    for mtaskId in Mtasks:
+        record = Mtasks[mtaskId]
+        predict_mtask_time += record['predict_cost']
+        total_mtask_time += record['elapsed']
+        thread_mtask_time[record['thread']] += record['elapsed']
+        predict_end = record['predict_start'] + record['predict_cost']
+        predict_elapsed = max(predict_elapsed, predict_end)
+        if record['elapsed'] > long_mtask_time:
+            long_mtask_time = record['elapsed']
+            long_mtask = mtaskId
+    Global['predict_last_end'] = predict_elapsed
+
+    serialTime = ElapsedTime - ExecGraphTime
+
+    def subReport(elapsed, work):
+        print("  Thread utilization = {:7.2%}".format(work /
+                                                      (elapsed * nthreads)))
+        print("  Speedup            = {:6.3}x".format(work / elapsed))
+
+    print("\nParallelized code, measured:")
+    subReport(ExecGraphTime, total_mtask_time)
+
+    print("\nParallelized code, predicted during static scheduling:")
+    subReport(predict_elapsed, predict_mtask_time)
+
+    print("\nAll code, measured:")
+    subReport(ElapsedTime, serialTime + total_mtask_time)
+
+    print("\nAll code, measured, scaled by predicted speedup:")
+    expectedParallelSpeedup = predict_mtask_time / predict_elapsed
+    scaledElapsed = serialTime + total_mtask_time / expectedParallelSpeedup
+    subReport(scaledElapsed, serialTime + total_mtask_time)
+
+    p2e_ratios = []
+    min_p2e = 1000000
+    min_mtask = None
+    max_p2e = -1000000
+    max_mtask = None
+
+    for mtask in sorted(Mtasks.keys()):
+        if Mtasks[mtask]['elapsed'] > 0:
+            if Mtasks[mtask]['predict_cost'] == 0:
+                Mtasks[mtask]['predict_cost'] = 1  # don't log(0) below
+            p2e_ratio = math.log(Mtasks[mtask]['predict_cost'] /
+                                 Mtasks[mtask]['elapsed'])
+            p2e_ratios.append(p2e_ratio)
+
+            if p2e_ratio > max_p2e:
+                max_p2e = p2e_ratio
+                max_mtask = mtask
+            if p2e_ratio < min_p2e:
+                min_p2e = p2e_ratio
+                min_mtask = mtask
+
+    print("\nMTask statistics:")
+    print("  Longest mtask id = {}".format(long_mtask))
+    print("  Longest mtask time = {:.2%} of time elapsed in parallelized code".
+          format(long_mtask_time / ExecGraphTime))
+    print("  min log(p2e) = %0.3f" % min_p2e, end="")
+
+    print("  from mtask %d (predict %d," %
+          (min_mtask, Mtasks[min_mtask]['predict_cost']),
+          end="")
+    print(" elapsed %d)" % Mtasks[min_mtask]['elapsed'])
+    print("  max log(p2e) = %0.3f" % max_p2e, end="")
+    print("  from mtask %d (predict %d," %
+          (max_mtask, Mtasks[max_mtask]['predict_cost']),
+          end="")
+    print(" elapsed %d)" % Mtasks[max_mtask]['elapsed'])
+
+    stddev = statistics.pstdev(p2e_ratios)
+    mean = statistics.mean(p2e_ratios)
+    print("  mean = %0.3f" % mean)
+    print("  stddev = %0.3f" % stddev)
+    print("  e ^ stddev = %0.3f" % math.exp(stddev))
+
+
 def report_cpus():
-    print("\nCPUs:")
+    print("\nCPU info:")
 
     Global['cpu_sockets'] = collections.defaultdict(lambda: 0)
     Global['cpu_socket_cores'] = collections.defaultdict(lambda: 0)
 
-    for cpu in sorted(Global['cpus'].keys()):
-        print("  cpu %d: " % cpu, end='')
-        print("cpu_time=%d" % Global['cpus'][cpu]['cpu_time'], end='')
-
-        socket = None
+    print("   Id | Time spent executing MTask | Socket | Core | Model")
+    print("      | % of elapsed ticks / ticks |        |      |")
+    print("  ====|============================|========|======|======")
+    for cpu in sorted(Cpus):
+        socket = ""
+        core = ""
+        model = ""
         if cpu in Global['cpuinfo']:
             cpuinfo = Global['cpuinfo'][cpu]
             if 'physical_id' in cpuinfo and 'core_id' in cpuinfo:
-                socket = int(cpuinfo['physical_id'])
+                socket = cpuinfo['physical_id']
                 Global['cpu_sockets'][socket] += 1
-                print(" socket=%d" % socket, end='')
-
-                core = int(cpuinfo['core_id'])
-                Global['cpu_socket_cores'][str(socket) + "__" + str(core)] += 1
-                print(" core=%d" % core, end='')
+                core = cpuinfo['core_id']
+                Global['cpu_socket_cores'][socket + "__" + core] += 1
 
             if 'model_name' in cpuinfo:
                 model = cpuinfo['model_name']
-                print("  %s" % model, end='')
-        print()
+
+        print("  {:3d} | {:7.2%} / {:16d} | {:>6s} | {:>4s} | {}".format(
+            cpu, Cpus[cpu]['mtask_time'] / ElapsedTime,
+            Cpus[cpu]['mtask_time'], socket, core, model))
 
     if len(Global['cpu_sockets']) > 1:
         Global['cpu_sockets_warning'] = True
@@ -313,25 +325,68 @@ def report_cpus():
                 Global['cpu_socket_cores_warning'] = True
 
 
+def report_sections():
+    if not Sections:
+        return
+    print("\nSection profile:")
+
+    totalTime = collections.defaultdict(lambda: 0)
+    selfTime = collections.defaultdict(lambda: 0)
+
+    sectionTree = [0, {}, 1]  # [selfTime, childTrees, numberOfTimesEntered]
+    prevTime = 0
+    prevStack = ()
+    for time, stack in Sections:
+        if len(stack) > len(prevStack):
+            scope = sectionTree
+            for item in stack:
+                scope = scope[1].setdefault(item, [0, {}, 0])
+            scope[2] += 1
+        dt = time - prevTime
+        scope = sectionTree
+        for item in prevStack:
+            scope = scope[1].setdefault(item, [0, {}, 0])
+        scope[0] += dt
+
+        if prevStack:
+            for name in prevStack:
+                totalTime[name] += dt
+            selfTime[prevStack[-1]] += dt
+        prevTime = time
+        prevStack = stack
+
+    def treeSum(tree):
+        n = tree[0]
+        for subTree in tree[1].values():
+            n += treeSum(subTree)
+        return n
+
+    # Make sure the tree sums to the elapsed time
+    sectionTree[0] += ElapsedTime - treeSum(sectionTree)
+
+    def printTree(prefix, name, entries, tree):
+        print("  {:7.2%} | {:7.2%} | {:8} | {:10.2f} | {}".format(
+            treeSum(tree) / ElapsedTime, tree[0] / ElapsedTime, tree[2],
+            tree[2] / entries, prefix + name))
+        for k in sorted(tree[1], key=lambda _: -treeSum(tree[1][_])):
+            printTree(prefix + "  ", k, tree[2], tree[1][k])
+
+    print(" Total    | Self    | Total    | Relative   | Section")
+    print(" time     | time    | entries  | entries    |  name  ")
+    print("==========|=========|==========|============|========")
+    printTree("", "*TOTAL*", 1, sectionTree)
+
+
 ######################################################################
 
 
 def write_vcd(filename):
     print("Writing %s" % filename)
     with open(filename, "w", encoding="utf8") as fh:
-        vcd = {
-            'values':
-            collections.defaultdict(lambda: {}),  # {