diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 1e8d44b28..e5aadf836 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -129,7 +129,7 @@ class AssertVisitor final : public VNVisitor { // STATE AstNodeModule* m_modp = nullptr; // Last module - const AstBegin* m_beginp = nullptr; // Last begin + const AstNode* m_beginp = nullptr; // Last AstBegin/AstGenBlock unsigned m_monitorNum = 0; // Global $monitor numbering (not per module) AstVar* m_monitorNumVarp = nullptr; // $monitor number variable AstVar* m_monitorOffVarp = nullptr; // $monitoroff variable @@ -809,6 +809,13 @@ class AssertVisitor final : public VNVisitor { m_procedurep = nodep; iterateChildren(nodep); } + void visit(AstGenBlock* nodep) override { + // This code is needed rather than a visitor in V3Begin, + // because V3Assert is called before V3Begin + VL_RESTORER(m_beginp); + m_beginp = nodep; + iterateChildren(nodep); + } void visit(AstBegin* nodep) override { // This code is needed rather than a visitor in V3Begin, // because V3Assert is called before V3Begin diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp index c19dd4eaf..a61e63f8f 100644 --- a/src/V3AssertPre.cpp +++ b/src/V3AssertPre.cpp @@ -349,7 +349,7 @@ private: nodep->findBasicDType(VBasicDTypeKwd::UINT32)}; cntVarp->lifetime(VLifetime::AUTOMATIC_EXPLICIT); cntVarp->funcLocal(true); - AstBegin* const beginp = new AstBegin{flp, delayName + "__block", cntVarp, false, true}; + AstBegin* const beginp = new AstBegin{flp, delayName + "__block", cntVarp, true}; beginp->addStmtsp(new AstAssign{flp, new AstVarRef{flp, cntVarp, VAccess::WRITE}, valuep}); beginp->addStmtsp(new AstWhile{ nodep->fileline(), diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 2c66b2da8..a50382885 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -1078,8 +1078,7 @@ AstNode* AstNode::iterateSubtreeReturnEdits(VNVisitor& v) { } else if (!nodep->backp()) { // Calling on standalone tree; insert a shim node so we can keep // track, then delete it on completion - AstBegin* const tempp - = new AstBegin{nodep->fileline(), "[EditWrapper]", nodep, false, false}; + AstBegin* const tempp = new AstBegin{nodep->fileline(), "[EditWrapper]", nodep, false}; // nodep to null as may be replaced VL_DO_DANGLING(tempp->stmtsp()->accept(v), nodep); nodep = tempp->stmtsp()->unlinkFrBackWithNext(); diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 26bc726ec..d7d707d56 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -267,6 +267,13 @@ public: string name() const override VL_MT_STABLE { return m_name; } bool sameNode(const AstNode* /*samep*/) const override { return true; } }; +class AstNodeGen VL_NOT_FINAL : public AstNode { + // Generate construct +public: + AstNodeGen(VNType t, FileLine* fl) + : AstNode{t, fl} {} + ASTGEN_MEMBERS_AstNodeGen; +}; class AstNodeModule VL_NOT_FINAL : public AstNode { // A module, package, program or interface declaration; // something that can live directly under the TOP, @@ -668,21 +675,6 @@ public: string name() const override VL_MT_STABLE { return m_name; } VUseType useType() const { return m_useType; } }; -class AstCaseItem final : public AstNode { - // Single item of a case statement - // @astgen op1 := condsp : List[AstNodeExpr] - // @astgen op2 := stmtsp : List[AstNode] -public: - AstCaseItem(FileLine* fl, AstNodeExpr* condsp, AstNode* stmtsp) - : ASTGEN_SUPER_CaseItem(fl) { - addCondsp(condsp); - addStmtsp(stmtsp); - } - ASTGEN_MEMBERS_AstCaseItem; - int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } - bool isDefault() const { return condsp() == nullptr; } - bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); } -}; class AstCell final : public AstNode { // A instantiation cell or interface call (don't know which until link) // @astgen op1 := pinsp : List[AstPin] // List of port assignments @@ -1137,6 +1129,19 @@ public: V3Graph* depGraphp() { return m_depGraphp; } const V3Graph* depGraphp() const { return m_depGraphp; } }; +class AstGenCaseItem final : public AstNode { + // Single item of an AstGenCase + // @astgen op1 := condsp : List[AstNodeExpr] + // @astgen op2 := itemsp : List[AstNode] +public: + AstGenCaseItem(FileLine* fl, AstNodeExpr* condsp, AstNode* itemsp) + : ASTGEN_SUPER_GenCaseItem(fl) { + addCondsp(condsp); + addItemsp(itemsp); + } + ASTGEN_MEMBERS_AstGenCaseItem; + bool isDefault() const { return condsp() == nullptr; } +}; class AstImplicit final : public AstNode { // Create implicit wires and do nothing else, for gates that are ignored // Parents: MODULE @@ -2287,22 +2292,18 @@ public: class AstBegin final : public AstNodeBlock { // A Begin/end named block, only exists shortly after parsing until linking // Parents: statement - // @astgen op1 := genforp : Optional[AstNode] - const 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, bool implied) + AstBegin(FileLine* fl, const string& name, AstNode* stmtsp, bool implied) : 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 dumpJson(std::ostream& str) const override; - bool generate() const { return m_generate; } void setNeedProcess() { m_needProcess = true; } bool needProcess() const { return m_needProcess; } bool implied() const { return m_implied; } @@ -2463,6 +2464,74 @@ public: void dumpJson(std::ostream& str = std::cout) const override; }; +// === AstNodeGen === +class AstGenBlock final : public AstNodeGen { + // Generate 'begin' + // @astgen op1 := genforp : Optional[AstNode] + // @astgen op2 := itemsp : List[AstNode] + std::string m_name; // Name of block + const bool m_unnamed; // Originally unnamed (name change does not affect this) + const bool m_implied; // Not inserted by user + +public: + AstGenBlock(FileLine* fl, const string& name, AstNode* itemsp, bool implied) + : ASTGEN_SUPER_GenBlock(fl) + , m_name{name} + , m_unnamed{name.empty()} + , m_implied{implied} { + this->addItemsp(itemsp); + } + ASTGEN_MEMBERS_AstGenBlock; + void dump(std::ostream& str) const override; + void dumpJson(std::ostream& str) const override; + std::string name() const override VL_MT_STABLE { return m_name; } + void name(const std::string& name) override { m_name = name; } + bool unnamed() const { return m_unnamed; } + bool implied() const { return m_implied; } +}; +class AstGenCase final : public AstNodeGen { + // Generate 'case' + // @astgen op1 := exprp : AstNodeExpr // Condition (scurtinee) expression + // @astgen op2 := itemsp : List[AstGenCaseItem] +public: + AstGenCase(FileLine* fl, AstNodeExpr* exprp, AstGenCaseItem* itemsp) + : ASTGEN_SUPER_GenCase(fl) { + this->exprp(exprp); + this->addItemsp(itemsp); + } + ASTGEN_MEMBERS_AstGenCase; +}; +class AstGenFor final : public AstNodeGen { + // Generate 'for' + // @astgen op1 := initsp : List[AstNode] + // @astgen op2 := condp : AstNodeExpr + // @astgen op3 := incsp : List[AstNode] + // @astgen op4 := itemsp : List[AstNode] +public: + AstGenFor(FileLine* fl, AstNode* initsp, AstNodeExpr* condp, AstNode* incsp, AstNode* itemsp) + : ASTGEN_SUPER_GenFor(fl) { + this->addInitsp(initsp); + this->condp(condp); + this->addIncsp(incsp); + this->addItemsp(itemsp); + } + ASTGEN_MEMBERS_AstGenFor; +}; +class AstGenIf final : public AstNodeGen { + // Generate 'if' + // @astgen op1 := condp : AstNodeExpr + // @astgen op2 := thensp : List[AstNode] + // @astgen op3 := elsesp : List[AstNode] +public: + AstGenIf(FileLine* fl, AstNodeExpr* condp, AstNode* thensp, AstNode* elsesp) + : ASTGEN_SUPER_GenIf(fl) { + this->condp(condp); + this->addThensp(thensp); + this->addElsesp(elsesp); + } + ASTGEN_MEMBERS_AstGenIf; +}; + // === AstNodeModule === class AstClass final : public AstNodeModule { // @astgen op4 := extendsp : List[AstClassExtends] diff --git a/src/V3AstNodeStmt.h b/src/V3AstNodeStmt.h index 32c59eb61..e6ce9bf3e 100644 --- a/src/V3AstNodeStmt.h +++ b/src/V3AstNodeStmt.h @@ -70,21 +70,6 @@ public: bool isTimingControl() const override { return timingControlp(); } virtual bool brokeLhsMustBeLvalue() const = 0; }; -class AstNodeCase VL_NOT_FINAL : public AstNodeStmt { - // @astgen op1 := exprp : AstNodeExpr // Condition (scurtinee) expression - // @astgen op2 := itemsp : List[AstCaseItem] - // @astgen op3 := notParallelp : List[AstNode] // assertion code for non-full case's -protected: - AstNodeCase(VNType t, FileLine* fl, AstNodeExpr* exprp, AstCaseItem* itemsp) - : AstNodeStmt{t, fl} { - this->exprp(exprp); - addItemsp(itemsp); - } - -public: - ASTGEN_MEMBERS_AstNodeCase; - int instrCount() const override { return INSTR_COUNT_BRANCH; } -}; class AstNodeCoverOrAssert VL_NOT_FINAL : public AstNodeStmt { // Cover or Assert // Parents: {statement list} @@ -121,27 +106,6 @@ public: || this->type() == VAssertType::INTERNAL; } }; -class AstNodeFor VL_NOT_FINAL : public AstNodeStmt { - // @astgen op1 := initsp : List[AstNode] - // @astgen op2 := condp : AstNodeExpr - // @astgen op3 := incsp : List[AstNode] - // @astgen op4 := stmtsp : List[AstNode] -protected: - AstNodeFor(VNType t, FileLine* fl, AstNode* initsp, AstNodeExpr* condp, AstNode* incsp, - AstNode* stmtsp) - : AstNodeStmt{t, fl} { - addInitsp(initsp); - this->condp(condp); - addIncsp(incsp); - addStmtsp(stmtsp); - } - -public: - ASTGEN_MEMBERS_AstNodeFor; - bool isGateOptimizable() const override { return false; } - int instrCount() const override { return INSTR_COUNT_BRANCH; } - bool sameNode(const AstNode* /*samep*/) const override { return true; } -}; class AstNodeForeach VL_NOT_FINAL : public AstNodeStmt { // @astgen op1 := arrayp : AstNode // @astgen op2 := stmtsp : List[AstNode] @@ -218,6 +182,23 @@ public: // === Concrete node types ===================================================== +// === AstNode === +class AstCaseItem final : public AstNode { + // Single item of AstCase/AstRandCase + // @astgen op1 := condsp : List[AstNodeExpr] + // @astgen op2 := stmtsp : List[AstNode] +public: + AstCaseItem(FileLine* fl, AstNodeExpr* condsp, AstNode* stmtsp) + : ASTGEN_SUPER_CaseItem(fl) { + addCondsp(condsp); + addStmtsp(stmtsp); + } + ASTGEN_MEMBERS_AstCaseItem; + int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } + bool isDefault() const { return condsp() == nullptr; } + bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); } +}; + // === AstNodeStmt === class AstAssertCtl final : public AstNodeStmt { // @astgen op1 := controlTypep : AstNodeExpr @@ -306,6 +287,47 @@ public: bool isPredictOptimizable() const override { return false; } bool sameNode(const AstNode* /*samep*/) const override { return true; } }; +class AstCase final : public AstNodeStmt { + // Case statement + // @astgen op1 := exprp : AstNodeExpr // Condition (scurtinee) expression + // @astgen op2 := itemsp : List[AstCaseItem] + // @astgen op3 := notParallelp : List[AstNode] // assertion code for non-full case's + VCaseType m_casex; // 0=case, 1=casex, 2=casez + bool m_fullPragma = false; // Synthesis full_case + bool m_parallelPragma = false; // Synthesis parallel_case + bool m_uniquePragma = false; // unique case + bool m_unique0Pragma = false; // unique0 case + bool m_priorityPragma = false; // priority case +public: + AstCase(FileLine* fl, VCaseType casex, AstNodeExpr* exprp, AstCaseItem* itemsp) + : ASTGEN_SUPER_Case(fl) + , m_casex{casex} { + this->exprp(exprp); + addItemsp(itemsp); + } + ASTGEN_MEMBERS_AstCase; + int instrCount() const override { return INSTR_COUNT_BRANCH; } + string verilogKwd() const override { return casez() ? "casez" : casex() ? "casex" : "case"; } + bool sameNode(const AstNode* samep) const override { + 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; } + bool caseInside() const { return m_casex == VCaseType::CT_CASEINSIDE; } + bool caseSimple() const { return m_casex == VCaseType::CT_CASE; } + void caseInsideSet() { m_casex = VCaseType::CT_CASEINSIDE; } + bool fullPragma() const { return m_fullPragma; } + void fullPragma(bool flag) { m_fullPragma = flag; } + bool parallelPragma() const { return m_parallelPragma; } + void parallelPragma(bool flag) { m_parallelPragma = flag; } + bool uniquePragma() const { return m_uniquePragma; } + void uniquePragma(bool flag) { m_uniquePragma = flag; } + bool unique0Pragma() const { return m_unique0Pragma; } + void unique0Pragma(bool flag) { m_unique0Pragma = flag; } + bool priorityPragma() const { return m_priorityPragma; } + void priorityPragma(bool flag) { m_priorityPragma = flag; } + string pragmaString() const; +}; class AstComment final : public AstNodeStmt { // Some comment to put into the output stream const string m_name; // Text of comment @@ -1130,49 +1152,6 @@ public: AstAlways* convertToAlways(); }; -// === AstNodeCase === -class AstCase final : public AstNodeCase { - // Case statement - VCaseType m_casex; // 0=case, 1=casex, 2=casez - bool m_fullPragma = false; // Synthesis full_case - bool m_parallelPragma = false; // Synthesis parallel_case - bool m_uniquePragma = false; // unique case - bool m_unique0Pragma = false; // unique0 case - bool m_priorityPragma = false; // priority case -public: - AstCase(FileLine* fl, VCaseType casex, AstNodeExpr* exprp, AstCaseItem* itemsp) - : ASTGEN_SUPER_Case(fl, exprp, itemsp) - , m_casex{casex} {} - ASTGEN_MEMBERS_AstCase; - string verilogKwd() const override { return casez() ? "casez" : casex() ? "casex" : "case"; } - bool sameNode(const AstNode* samep) const override { - 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; } - bool caseInside() const { return m_casex == VCaseType::CT_CASEINSIDE; } - bool caseSimple() const { return m_casex == VCaseType::CT_CASE; } - void caseInsideSet() { m_casex = VCaseType::CT_CASEINSIDE; } - bool fullPragma() const { return m_fullPragma; } - void fullPragma(bool flag) { m_fullPragma = flag; } - bool parallelPragma() const { return m_parallelPragma; } - void parallelPragma(bool flag) { m_parallelPragma = flag; } - bool uniquePragma() const { return m_uniquePragma; } - void uniquePragma(bool flag) { m_uniquePragma = flag; } - bool unique0Pragma() const { return m_unique0Pragma; } - void unique0Pragma(bool flag) { m_unique0Pragma = flag; } - bool priorityPragma() const { return m_priorityPragma; } - void priorityPragma(bool flag) { m_priorityPragma = flag; } - string pragmaString() const; -}; -class AstGenCase final : public AstNodeCase { - // Generate Case statement -public: - AstGenCase(FileLine* fl, AstNodeExpr* exprp, AstCaseItem* itemsp) - : ASTGEN_SUPER_GenCase(fl, exprp, itemsp) {} - ASTGEN_MEMBERS_AstGenCase; -}; - // === AstNodeCoverOrAssert === class AstAssert final : public AstNodeCoverOrAssert { // @astgen op3 := failsp: List[AstNode] // Statements when propp is failing/falsey @@ -1215,14 +1194,6 @@ public: VAssertDirectiveType::RESTRICT) {} }; -// === AstNodeFor === -class AstGenFor final : public AstNodeFor { -public: - AstGenFor(FileLine* fl, AstNode* initsp, AstNodeExpr* condp, AstNode* incsp, AstNode* stmtsp) - : ASTGEN_SUPER_GenFor(fl, initsp, condp, incsp, stmtsp) {} - ASTGEN_MEMBERS_AstGenFor; -}; - // === AstNodeForeach === class AstConstraintForeach final : public AstNodeForeach { // Constraint foreach statement @@ -1245,12 +1216,7 @@ public: : ASTGEN_SUPER_ConstraintIf(fl, condp, thensp, elsesp) {} ASTGEN_MEMBERS_AstConstraintIf; }; -class AstGenIf final : public AstNodeIf { -public: - AstGenIf(FileLine* fl, AstNodeExpr* condp, AstNode* thensp, AstNode* elsesp) - : ASTGEN_SUPER_GenIf(fl, condp, thensp, elsesp) {} - ASTGEN_MEMBERS_AstGenIf; -}; + class AstIf final : public AstNodeIf { bool m_uniquePragma = false; // unique case bool m_unique0Pragma = false; // unique0 case diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 415c250b2..9e85e993c 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1928,6 +1928,18 @@ const char* AstEnumDType::broken() const { } void AstEnumItemRef::dumpJson(std::ostream& str) const { dumpJsonGen(str); } + +void AstGenBlock::dump(std::ostream& str) const { + this->AstNode::dump(str); + if (implied()) str << " [IMPLIED]"; + if (unnamed()) str << " [UNNAMED]"; +} +void AstGenBlock::dumpJson(std::ostream& str) const { + dumpJsonBoolFunc(str, implied); + dumpJsonBoolFunc(str, unnamed); + dumpJsonGen(str); +} + void AstIfaceRefDType::dump(std::ostream& str) const { this->AstNodeDType::dump(str); if (isPortDecl()) str << " [PORTDECL]"; @@ -2941,14 +2953,10 @@ void AstNodeBlock::dumpJson(std::ostream& str) const { } void AstBegin::dump(std::ostream& str) const { this->AstNodeBlock::dump(str); - if (generate()) str << " [GEN]"; - if (genforp()) str << " [GENFOR]"; if (implied()) str << " [IMPLIED]"; if (needProcess()) str << " [NPRC]"; } void AstBegin::dumpJson(std::ostream& str) const { - dumpJsonBoolFunc(str, generate); - dumpJsonBool(str, "genfor", bool(genforp())); dumpJsonBoolFunc(str, implied); dumpJsonBoolFunc(str, needProcess); dumpJsonGen(str); @@ -3258,7 +3266,7 @@ AstAlways* AstAssignW::convertToAlways() { if (hasTimingControl) { // If there's a timing control, put the assignment in a fork..join_none. This process won't // get marked as suspendable and thus will be scheduled normally - AstBegin* const beginp = new AstBegin{flp, "", bodysp, false, false}; + AstBegin* const beginp = new AstBegin{flp, "", bodysp, false}; AstFork* const forkp = new AstFork{flp, "", beginp}; forkp->joinType(VJoinType::JOIN_NONE); bodysp = forkp; diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index 4f673211b..e6db8ec4b 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -73,31 +73,32 @@ class BeginVisitor final : public VNVisitor { string dot(const string& a, const string& b) { return VString::dot(a, "__DOT__", b); } - void dotNames(const AstNodeBlock* const nodep, const char* const blockName) { + void dotNames(const std::string& name, FileLine* const flp, AstNode* stmtsp, + const char* const blockName) { UINFO(8, "nname " << m_namedScope); - if (nodep->name() != "") { // Else unneeded unnamed block + if (name != "") { // Else unneeded unnamed block // Create data for dotted variable resolution - string dottedname = nodep->name() + "__DOT__"; // So always found + string dottedname = name + "__DOT__"; // So always found string::size_type pos; while ((pos = dottedname.find("__DOT__")) != string::npos) { const string ident = dottedname.substr(0, pos); dottedname = dottedname.substr(pos + std::strlen("__DOT__")); - if (nodep->name() != "") { + if (name != "") { m_displayScope = dot(m_displayScope, ident); m_namedScope = dot(m_namedScope, ident); } m_unnamedScope = dot(m_unnamedScope, ident); // Create CellInline for dotted var resolution if (!m_ftaskp) { - AstCellInline* const inlinep = new AstCellInline{ - nodep->fileline(), m_unnamedScope, blockName, m_modp->timeunit()}; + AstCellInline* const inlinep + = new AstCellInline{flp, m_unnamedScope, blockName, m_modp->timeunit()}; m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells } } } // Remap var names and replace lower Begins - iterateAndNextNull(nodep->stmtsp()); + iterateAndNextNull(stmtsp); } void liftNode(AstNode* nodep) { @@ -125,14 +126,13 @@ class BeginVisitor final : public VNVisitor { // replaced with multiple statements) for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { if (!VN_IS(stmtp, Begin)) { - AstBegin* const beginp - = new AstBegin{stmtp->fileline(), "", nullptr, false, false}; + AstBegin* const beginp = new AstBegin{stmtp->fileline(), "", nullptr, false}; stmtp->replaceWith(beginp); beginp->addStmtsp(stmtp); stmtp = beginp; } } - dotNames(nodep, "__FORK__"); + dotNames(nodep->name(), nodep->fileline(), nodep->stmtsp(), "__FORK__"); nodep->name(""); } void visit(AstForeach* nodep) override { @@ -199,6 +199,20 @@ class BeginVisitor final : public VNVisitor { m_liftedp = nullptr; } } + void visit(AstGenBlock* nodep) override { + // GenBlocks were only useful in variable creation, change names and delete + UINFO(8, " " << nodep); + VL_RESTORER(m_displayScope); + VL_RESTORER(m_namedScope); + VL_RESTORER(m_unnamedScope); + UASSERT_OBJ(!m_keepBegins, nodep, "Should be able to eliminate all AstGenBlock"); + dotNames(nodep->name(), nodep->fileline(), nodep->itemsp(), "__BEGIN__"); + // Repalce node with body then delete + if (AstNode* const itemsp = nodep->itemsp()) { + nodep->addNextHere(itemsp->unlinkFrBackWithNext()); + } + VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); + } void visit(AstBegin* nodep) override { // Begin blocks were only useful in variable creation, change names and delete UINFO(8, " " << nodep); @@ -208,9 +222,8 @@ class BeginVisitor final : public VNVisitor { { VL_RESTORER(m_keepBegins); m_keepBegins = false; - dotNames(nodep, "__BEGIN__"); + dotNames(nodep->name(), nodep->fileline(), nodep->stmtsp(), "__BEGIN__"); } - UASSERT_OBJ(!nodep->genforp(), nodep, "GENFORs should have been expanded earlier"); // Cleanup if (m_keepBegins) { @@ -431,7 +444,7 @@ AstNode* V3Begin::convertToWhile(AstForeach* nodep) { AstNodeDType* fromDtp = fromp->dtypep()->skipRefp(); // Split into for loop // We record where the body needs to eventually go with bodyPointp - AstNode* bodyPointp = new AstBegin{nodep->fileline(), "[EditWrapper]", nullptr, false, false}; + AstNode* bodyPointp = new AstBegin{nodep->fileline(), "[EditWrapper]", nullptr, false}; AstNode* newp = nullptr; AstNode* lastp = nodep; AstVar* nestedIndexp = nullptr; diff --git a/src/V3Broken.cpp b/src/V3Broken.cpp index 765bf7160..8c7f4584e 100644 --- a/src/V3Broken.cpp +++ b/src/V3Broken.cpp @@ -382,7 +382,7 @@ void V3Broken::allowMidvisitorCheck(bool flag) { s_brokenAllowMidvisitorCheck = void V3Broken::selfTest() { // Exercise addNewed and deleted for coverage, as otherwise only used with VL_LEAK_CHECKS FileLine* const fl = new FileLine{FileLine::commandLineFilename()}; - AstNode* const newp = new AstBegin{fl, "[EditWrapper]", nullptr, false, false}; + AstNode* const newp = new AstBegin{fl, "[EditWrapper]", nullptr, false}; // Don't actually do it with VL_LEAK_CHECKS, when new/delete calls these. // Otherwise you call addNewed twice on the same address, which is an error. #ifndef VL_LEAK_CHECKS diff --git a/src/V3Case.cpp b/src/V3Case.cpp index b57e51e9f..b2f6d8f01 100644 --- a/src/V3Case.cpp +++ b/src/V3Case.cpp @@ -49,64 +49,80 @@ VL_DEFINE_DEBUG_FUNCTIONS; //###################################################################### class CaseLintVisitor final : public VNVisitorConst { - const AstNodeCase* m_caseExprp - = nullptr; // Under a CASE value node, if so the relevant case statement + // Under a CASE value node, if so the relevant case statement + const AstNode* m_casep = nullptr; // METHODS + template + static void detectMultipleDefaults(CaseItem* itemsp) { + bool hitDefault = false; + for (CaseItem* itemp = itemsp; itemp; itemp = AstNode::as(itemp->nextp())) { + if (!itemp->isDefault()) continue; + if (hitDefault) itemp->v3error("Multiple default statements in case statement."); + hitDefault = true; + } + } - void visit(AstNodeCase* nodep) override { - if (VN_IS(nodep, Case) && VN_AS(nodep, Case)->casex()) { + template + void checkXZinNonCaseX(AstNode* casep, AstNodeExpr* exprp, CaseItem* itemsp) { + VL_RESTORER(m_casep); + m_casep = casep; + iterateConst(exprp); + for (CaseItem* itemp = itemsp; itemp; itemp = AstNode::as(itemp->nextp())) { + iterateAndNextConstNull(itemp->condsp()); + } + } + + // VISITORS + void visit(AstGenCase* nodep) override { + // Detect multiple defaults + detectMultipleDefaults(nodep->itemsp()); + // Check for X/Z in non-casex statements + checkXZinNonCaseX(nodep, nodep->exprp(), nodep->itemsp()); + } + + void visit(AstCase* nodep) override { + if (nodep->casex()) { nodep->v3warn(CASEX, "Suggest casez (with ?'s) in place of casex (with X's)"); } // Detect multiple defaults - bool hitDefault = false; - for (AstCaseItem* itemp = nodep->itemsp(); itemp; - itemp = VN_AS(itemp->nextp(), CaseItem)) { - if (itemp->isDefault()) { - if (hitDefault) { - itemp->v3error("Multiple default statements in case statement."); - } - hitDefault = true; - } - } - + detectMultipleDefaults(nodep->itemsp()); // Check for X/Z in non-casex statements - { - VL_RESTORER(m_caseExprp); - m_caseExprp = nodep; - iterateConst(nodep->exprp()); - for (AstCaseItem* itemp = nodep->itemsp(); itemp; - itemp = VN_AS(itemp->nextp(), CaseItem)) { - iterateAndNextConstNull(itemp->condsp()); - } - } + checkXZinNonCaseX(nodep, nodep->exprp(), nodep->itemsp()); } void visit(AstConst* nodep) override { - // See also neverItem - if (m_caseExprp && nodep->num().isFourState()) { - if (VN_IS(m_caseExprp, GenCase)) { - nodep->v3error("Use of x/? constant in generate case statement, " - "(no such thing as 'generate casez')"); - } else if (VN_IS(m_caseExprp, Case) && VN_AS(m_caseExprp, Case)->casex()) { - // Don't sweat it, we already complained about casex in general - } else if (VN_IS(m_caseExprp, Case) - && (VN_AS(m_caseExprp, Case)->casez() - || VN_AS(m_caseExprp, Case)->caseInside())) { - if (nodep->num().isAnyX()) { - nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, " - "(perhaps intended ?/z in constant)"); - } - } else { - nodep->v3warn(CASEWITHX, "Use of x/? constant in case statement, " - "(perhaps intended casex/casez)"); - } + if (!nodep->num().isFourState()) return; + + // Error if generate case + if (VN_IS(m_casep, GenCase)) { + nodep->v3error("Use of x/? constant in generate case statement, " + "(no such thing as 'generate casez')"); + return; } + + // Otherwise must be a case statement + const AstCase* const casep = VN_AS(m_casep, Case); + + // Don't sweat it, we already complained about casex in general + if (casep->casex()) return; + + if (casep->casez() || casep->caseInside()) { + if (nodep->num().isAnyX()) { + nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, " + "(perhaps intended ?/z in constant)"); + } + return; + } + + nodep->v3warn(CASEWITHX, "Use of x/? constant in case statement, " + "(perhaps intended casex/casez)"); } void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } public: // CONSTRUCTORS - explicit CaseLintVisitor(AstNodeCase* nodep) { iterateConst(nodep); } + explicit CaseLintVisitor(AstCase* nodep) { iterateConst(nodep); } + explicit CaseLintVisitor(AstGenCase* nodep) { iterateConst(nodep); } ~CaseLintVisitor() override = default; }; @@ -562,7 +578,7 @@ class CaseVisitor final : public VNVisitor { // VISITORS void visit(AstCase* nodep) override { - V3Case::caseLint(nodep); + { CaseLintVisitor{nodep}; } iterateChildren(nodep); UINFOTREE(9, nodep, "", "case_old"); if (isCaseTreeFast(nodep) && v3Global.opt.fCase()) { @@ -605,7 +621,7 @@ void V3Case::caseAll(AstNetlist* nodep) { { CaseVisitor{nodep}; } // Destruct before checking V3Global::dumpCheckGlobalTree("case", 0, dumpTreeEitherLevel() >= 3); } -void V3Case::caseLint(AstNodeCase* nodep) { +void V3Case::caseLint(AstGenCase* nodep) { UINFO(4, __FUNCTION__ << ": "); { CaseLintVisitor{nodep}; } } diff --git a/src/V3Case.h b/src/V3Case.h index 98ce9fe73..2e7ec45eb 100644 --- a/src/V3Case.h +++ b/src/V3Case.h @@ -21,14 +21,14 @@ #include "verilatedos.h" class AstNetlist; -class AstNodeCase; +class AstGenCase; //============================================================================ class V3Case final { public: static void caseAll(AstNetlist* nodep) VL_MT_DISABLED; - static void caseLint(AstNodeCase* nodep) VL_MT_DISABLED; + static void caseLint(AstGenCase* nodep) VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3Control.cpp b/src/V3Control.cpp index 30d742dfd..37d00ccfa 100644 --- a/src/V3Control.cpp +++ b/src/V3Control.cpp @@ -259,6 +259,17 @@ public: } } + void applyBlock(AstGenBlock* nodep) { + const VPragmaType pragma = VPragmaType::COVERAGE_BLOCK_OFF; + if (!nodep->unnamed()) { + for (const string& i : m_coverageOffBlocks) { + if (VString::wildmatch(nodep->prettyOrigOrName(), i)) { + nodep->addItemsp(new AstPragma{nodep->fileline(), pragma}); + } + } + } + } + void applyBlock(AstNodeBlock* nodep) { const VPragmaType pragma = VPragmaType::COVERAGE_BLOCK_OFF; if (!nodep->unnamed()) { @@ -375,6 +386,13 @@ public: m_waivers.emplace_back(WaiverSetting{code, contents, newMatch}); } + void applyBlock(AstGenBlock* nodep) { + // Apply to block at this line + const VPragmaType pragma = VPragmaType::COVERAGE_BLOCK_OFF; + if (lineMatch(nodep->fileline()->lineno(), pragma)) { + nodep->addItemsp(new AstPragma{nodep->fileline(), pragma}); + } + } void applyBlock(AstNodeBlock* nodep) { // Apply to block at this line const VPragmaType pragma = VPragmaType::COVERAGE_BLOCK_OFF; @@ -741,6 +759,15 @@ void V3Control::applyCoverageBlock(AstNodeModule* modulep, AstBegin* nodep) { if (modp) modp->applyBlock(nodep); } +void V3Control::applyCoverageBlock(AstNodeModule* modulep, AstGenBlock* nodep) { + const string& filename = nodep->fileline()->filename(); + V3ControlFile* const filep = V3ControlResolver::s().files().resolve(filename); + if (filep) filep->applyBlock(nodep); + const string& modname = modulep->prettyOrigOrName(); + V3ControlModule* const modp = V3ControlResolver::s().modules().resolve(modname); + if (modp) modp->applyBlock(nodep); +} + void V3Control::applyIgnores(FileLine* filelinep) { const string& filename = filelinep->filename(); V3ControlFile* const filep = V3ControlResolver::s().files().resolve(filename); diff --git a/src/V3Control.h b/src/V3Control.h index fcc807620..1d1685f46 100644 --- a/src/V3Control.h +++ b/src/V3Control.h @@ -48,6 +48,7 @@ public: static void applyCase(AstCase* nodep); static void applyCoverageBlock(AstNodeModule* modulep, AstBegin* nodep); + static void applyCoverageBlock(AstNodeModule* modulep, AstGenBlock* nodep); static void applyFTask(AstNodeModule* modulep, AstNodeFTask* ftaskp); static void applyIgnores(FileLine* filelinep); static void applyModule(AstNodeModule* modulep); diff --git a/src/V3Coverage.cpp b/src/V3Coverage.cpp index 718a0a0d2..c5f271ebf 100644 --- a/src/V3Coverage.cpp +++ b/src/V3Coverage.cpp @@ -710,6 +710,16 @@ class CoverageVisitor final : public VNVisitor { lineTrack(nodep); } } + void visit(AstGenBlock* nodep) override { + // Similar to AstBegin + VL_RESTORER(m_beginHier); + if (nodep->name() != "") { + m_beginHier = m_beginHier + (m_beginHier != "" ? "__DOT__" : "") + nodep->name(); + } + iterateChildren(nodep); + lineTrack(nodep); + } + void visit(AstBegin* nodep) override { // Record the hierarchy of any named begins, so we can apply to user // coverage points. This is because there may be cov points inside @@ -718,7 +728,7 @@ class CoverageVisitor final : public VNVisitor { // covers the code in that line.) VL_RESTORER(m_beginHier); VL_RESTORER(m_inToggleOff); - if (!nodep->generate()) m_inToggleOff = true; + m_inToggleOff = true; if (nodep->name() != "") { m_beginHier = m_beginHier + (m_beginHier != "" ? "__DOT__" : "") + nodep->name(); } diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index 0fc8d95dc..25719374d 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -1297,9 +1297,6 @@ class DelayedVisitor final : public VNVisitor { // Record write reference recordWriteRef(nodep, false); } - void visit(AstNodeFor* nodep) override { // LCOV_EXCL_LINE - nodep->v3fatalSrc("For statements should have been converted to while statements"); - } void visit(AstWhile* nodep) override { VL_RESTORER(m_inLoop); m_inLoop = true; diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 2ae9b359d..9d192d302 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -680,7 +680,7 @@ public: iterateAndNextConstNull(nodep->exprp()); puts("}\n"); } - void visit(AstNodeCase* nodep) override { // LCOV_EXCL_LINE + void visit(AstCase* nodep) override { // LCOV_EXCL_LINE // In V3Case... nodep->v3fatalSrc("Case statements should have been reduced out"); } diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 8b47a33d9..a320a8daa 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -89,6 +89,54 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst { putfs(nodep, func ? "endfunction\n" : "endtask\n"); } + void visit(AstGenBlock* nodep) override { + const std::string name = nodep->name().empty() ? "" : " : " + nodep->name(); + putbs("/* generate */ begin" + name + '\n'); + iterateChildrenConst(nodep); + puts("end" + name + '\n'); + } + void visit(AstGenCase* nodep) override { + putfs(nodep, "/* generate */ case ("); + iterateAndNextConstNull(nodep->exprp()); + puts(")\n"); + iterateAndNextConstNull(nodep->itemsp()); + putqs(nodep, "endcase\n"); + } + void visit(AstGenCaseItem* nodep) override { + if (nodep->condsp()) { + iterateAndNextConstNull(nodep->condsp()); + } else { + putbs("default"); + } + iterateAndNextConstNull(nodep->itemsp()); + } + void visit(AstGenFor* nodep) override { + putfs(nodep, "/* generate */ for ("); + { + VL_RESTORER(m_suppressSemi); + m_suppressSemi = true; + iterateAndNextConstNull(nodep->initsp()); + puts(";"); + iterateAndNextConstNull(nodep->condp()); + puts(";"); + iterateAndNextConstNull(nodep->incsp()); + } + puts(") begin\n"); + iterateAndNextConstNull(nodep->itemsp()); + putqs(nodep, "end\n"); + } + void visit(AstGenIf* nodep) override { + putfs(nodep, ""); + puts("/* generate */ if ("); + iterateAndNextConstNull(nodep->condp()); + puts(") begin\n"); + iterateAndNextConstNull(nodep->thensp()); + if (nodep->elsesp()) { + putqs(nodep, "end else begin\n"); + iterateAndNextConstNull(nodep->elsesp()); + } + putqs(nodep, "end\n"); + } void visit(AstBegin* nodep) override { if (nodep->name() == "") { putbs("begin\n"); @@ -193,23 +241,19 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst { if (nodep->sensp()) puts(" "); iterateChildrenConst(nodep); } - void visit(AstNodeCase* nodep) override { + void visit(AstCase* nodep) override { putfs(nodep, ""); - if (const AstCase* const casep = VN_CAST(nodep, Case)) { - if (casep->priorityPragma()) puts("priority "); - if (casep->uniquePragma()) puts("unique "); - if (casep->unique0Pragma()) puts("unique0 "); - } + if (nodep->priorityPragma()) puts("priority "); + if (nodep->uniquePragma()) puts("unique "); + if (nodep->unique0Pragma()) puts("unique0 "); puts(nodep->verilogKwd()); puts(" ("); iterateAndNextConstNull(nodep->exprp()); puts(")\n"); - if (const AstCase* const casep = VN_CAST(nodep, Case)) { - if (casep->fullPragma() || casep->parallelPragma()) { - puts(" // synopsys"); - if (casep->fullPragma()) puts(" full_case"); - if (casep->parallelPragma()) puts(" parallel_case"); - } + if (nodep->fullPragma() || nodep->parallelPragma()) { + puts(" // synopsys"); + if (nodep->fullPragma()) puts(" full_case"); + if (nodep->parallelPragma()) puts(" parallel_case"); } iterateAndNextConstNull(nodep->itemsp()); putqs(nodep, "endcase\n"); @@ -348,21 +392,6 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst { iterateAndNextConstNull(nodep->exprsp()); puts(");\n"); } - void visit(AstNodeFor* nodep) override { - putfs(nodep, "for ("); - { - VL_RESTORER(m_suppressSemi); - m_suppressSemi = true; - iterateAndNextConstNull(nodep->initsp()); - puts(";"); - iterateAndNextConstNull(nodep->condp()); - puts(";"); - iterateAndNextConstNull(nodep->incsp()); - } - puts(") begin\n"); - iterateAndNextConstNull(nodep->stmtsp()); - putqs(nodep, "end\n"); - } void visit(AstRepeat* nodep) override { putfs(nodep, "repeat ("); iterateAndNextConstNull(nodep->countp()); diff --git a/src/V3EmitXml.cpp b/src/V3EmitXml.cpp index 19a292e46..6b210de3a 100644 --- a/src/V3EmitXml.cpp +++ b/src/V3EmitXml.cpp @@ -410,6 +410,11 @@ class HierCellsXmlVisitor final : public VNVisitorConst { m_hier = hier; m_hasChildren = true; } + void visit(AstGenBlock* nodep) override { + VL_RESTORER(m_hier); + if (nodep->name() != "") m_hier += nodep->name() + "."; + iterateChildrenConst(nodep); + } void visit(AstBegin* nodep) override { VL_RESTORER(m_hier); if (nodep->name() != "") m_hier += nodep->name() + "."; diff --git a/src/V3Fork.cpp b/src/V3Fork.cpp index fc0d54700..14811cd24 100644 --- a/src/V3Fork.cpp +++ b/src/V3Fork.cpp @@ -231,7 +231,7 @@ private: AstBegin* const beginp = new AstBegin{ forkp->fileline(), "_Vwrapped_" + (forkp->name().empty() ? "" : forkp->name() + "_") + cvtToStr(m_id), - m_instance.m_handlep, false, true}; + m_instance.m_handlep, true}; forkHandle.relink(beginp); AstNode* const instAsgnp = instantiateDynScope(memberMap); @@ -470,7 +470,7 @@ class DynScopeVisitor final : public VNVisitor { })) { nodep->user2(true); // Put it in a fork to prevent lifetime issues with the local - AstBegin* const beginp = new AstBegin{nodep->fileline(), "", nullptr, false, false}; + AstBegin* const beginp = new AstBegin{nodep->fileline(), "", nullptr, false}; AstFork* const forkp = new AstFork{nodep->fileline(), "", beginp}; forkp->joinType(VJoinType::JOIN_NONE); nodep->replaceWith(forkp); diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index ba8ff8018..d7815c1b1 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -260,6 +260,8 @@ public: return "block"; } else if (VN_IS(nodep, Iface)) { return "interface"; + } else if (VN_IS(nodep, GenBlock)) { + return "generate block"; } else { return nodep->prettyTypeName(); } @@ -295,8 +297,8 @@ public: } else if (foundp->imported()) { // From package // We don't throw VARHIDDEN as if the import is later the symbol // table's import wouldn't warn - } else if (forPrimary() && VN_IS(nodep, Begin) && VN_IS(fnodep, Begin) - && VN_AS(nodep, Begin)->generate()) { + } else if (forPrimary() && VN_IS(nodep, GenBlock) + && (VN_IS(fnodep, Begin) || VN_IS(fnodep, GenBlock))) { // Begin: ... blocks often replicate under genif/genfor, so // suppress duplicate checks. See t_gen_forif.v for an example. } else { @@ -882,7 +884,6 @@ class LinkDotFindVisitor final : public VNVisitor { string m_hierParamsName; // Name of module with hierarchical type parameters, empty when not used string m_scope; // Scope text - const AstNodeBlock* m_blockp = nullptr; // Current Begin/end block const AstNodeFTask* m_ftaskp = nullptr; // Current function/task bool m_inRecursion = false; // Inside a recursive module int m_paramNum = 0; // Parameter number, for position based connection @@ -1158,7 +1159,6 @@ class LinkDotFindVisitor final : public VNVisitor { iterateChildren(nodep); // Recurse in, preserving state VL_RESTORER(m_scope); - VL_RESTORER(m_blockp); VL_RESTORER(m_modSymp); VL_RESTORER(m_curSymp); VL_RESTORER(m_paramNum); @@ -1181,7 +1181,6 @@ class LinkDotFindVisitor final : public VNVisitor { { m_scope = m_scope + "." + nodep->name(); m_curSymp = m_modSymp = m_statep->insertCell(aboveSymp, m_modSymp, nodep, m_scope); - m_blockp = nullptr; m_inRecursion = nodep->recursive(); // We don't report NotFoundModule, as may be a unused module in a generate if (nodep->modp()) iterate(nodep->modp()); @@ -1216,6 +1215,43 @@ class LinkDotFindVisitor final : public VNVisitor { nodep->user1p(m_curSymp); iterateChildren(nodep); } + void visit(AstGenBlock* nodep) override { // FindVisitor:: + UINFO(5, " " << nodep); + if (nodep->name() == "" && nodep->unnamed()) { + // Unnamed blocks are only important when they contain var + // decls, so search for them. (Otherwise adding all the + // unnamed#'s would just confuse tracing variables in + // places such as tasks, where "task ...; begin ... end" + // are common. + for (AstNode* itemp = nodep->itemsp(); itemp; itemp = itemp->nextp()) { + if (VN_IS(itemp, Var) || VN_IS(itemp, Foreach)) { + std::string name; + const std::string stepStr = m_statep->forPrimary() + ? "" + : std::to_string(m_statep->stepNumber()) + "_"; + do { + ++m_modBlockNum; + name = "unnamedblk" + stepStr + cvtToStr(m_modBlockNum); + // Increment again if earlier pass of V3LinkDot claimed this name + } while (m_curSymp->findIdFlat(name)); + nodep->name(name); + break; + } + } + } + if (nodep->name() == "") { + iterateChildren(nodep); + } else { + VL_RESTORER(m_curSymp); + { + m_curSymp + = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_classOrPackagep); + m_curSymp->fallbackp(VL_RESTORER_PREV(m_curSymp)); + // Iterate + iterateChildren(nodep); + } + } + } void visit(AstNodeBlock* nodep) override { // FindVisitor:: UINFO(5, " " << nodep); if (nodep->name() == "" && nodep->unnamed()) { @@ -1243,10 +1279,8 @@ class LinkDotFindVisitor final : public VNVisitor { if (nodep->name() == "") { iterateChildren(nodep); } else { - VL_RESTORER(m_blockp); VL_RESTORER(m_curSymp); { - m_blockp = nodep; m_curSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_classOrPackagep); m_curSymp->fallbackp(VL_RESTORER_PREV(m_curSymp)); @@ -2331,6 +2365,9 @@ class LinkDotScopeVisitor final : public VNVisitor { // We have stored the link, we don't need these any more VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } + void visit(AstNodeGen* nodep) override { // LCOV_EXCL_LINE + nodep->v3fatalSrc("Generate constructs should have been reduced out"); + } // For speed, don't recurse things that can't have scope // Note we allow AstNodeStmt's as generates may be under them void visit(AstCell*) override {} // ScopeVisitor:: @@ -3509,6 +3546,7 @@ class LinkDotResolveVisitor final : public VNVisitor { } if (!foundp) { } else if (VN_IS(foundp->nodep(), Cell) || VN_IS(foundp->nodep(), NodeBlock) + || VN_IS(foundp->nodep(), GenBlock) || VN_IS(foundp->nodep(), Netlist) // for $root || VN_IS(foundp->nodep(), Module)) { // if top if (allowScope) { @@ -3521,14 +3559,12 @@ class LinkDotResolveVisitor final : public VNVisitor { // last component, `targetp()` field will be overwritten by next components m_ds.m_disablep->targetp(foundp->nodep()); } - if (const AstBegin* const beginp = VN_CAST(foundp->nodep(), Begin)) { - if (beginp->generate()) { - m_ds.m_genBlk = true; - if (m_ds.m_disablep) { - m_ds.m_disablep->v3warn( - E_UNSUPPORTED, - "Unsupported: Generate block referenced by disable"); - } + if (VN_IS(foundp->nodep(), GenBlock)) { + m_ds.m_genBlk = true; + if (m_ds.m_disablep) { + m_ds.m_disablep->v3warn( + E_UNSUPPORTED, + "Unsupported: Generate block referenced by disable"); } } // Upper AstDot visitor will handle it from here @@ -4472,6 +4508,21 @@ class LinkDotResolveVisitor final : public VNVisitor { LINKDOT_VISIT_START(); iterateChildren(nodep); } + void visit(AstGenBlock* nodep) override { + LINKDOT_VISIT_START(); + UINFO(5, indent() << "visit " << nodep); + checkNoDot(nodep); + { + VL_RESTORER(m_curSymp); + VL_RESTORER(m_ds); + if (nodep->name() != "") { + m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep); + UINFO(5, indent() << "cur=se" << cvtToHex(m_curSymp)); + } + iterateChildren(nodep); + } + UINFO(5, indent() << "cur=se" << cvtToHex(m_curSymp)); + } void visit(AstNodeBlock* nodep) override { LINKDOT_VISIT_START(); UINFO(5, indent() << "visit " << nodep); diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp index c45d93af0..d8b92b984 100644 --- a/src/V3LinkInc.cpp +++ b/src/V3LinkInc.cpp @@ -162,10 +162,6 @@ class LinkIncVisitor final : public VNVisitor { m_insStmtp = nullptr; // Next thing should be new statement iterateAndNextNull(nodep->stmtsp()); } - void visit(AstNodeFor* nodep) override { // LCOV_EXCL_LINE - nodep->v3fatalSrc( - "For statements should have been converted to while statements in V3Begin.cpp"); - } void visit(AstDelay* nodep) override { m_insStmtp = nodep; iterateAndNextNull(nodep->lhsp()); diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp index cc1aa8678..2796a4a45 100644 --- a/src/V3LinkJump.cpp +++ b/src/V3LinkJump.cpp @@ -289,7 +289,7 @@ class LinkJumpVisitor final : public VNVisitor { // Note var can be signed or unsigned based on original number. AstNodeExpr* const countp = nodep->countp()->unlinkFrBackWithNext(); const string name = "__Vrepeat"s + cvtToStr(m_modRepeatNum++); - AstBegin* const beginp = new AstBegin{nodep->fileline(), "", nullptr, false, true}; + AstBegin* const beginp = new AstBegin{nodep->fileline(), "", nullptr, true}; // Spec says value is integral, if negative is ignored AstVar* const varp = new AstVar{nodep->fileline(), VVarType::BLOCKTEMP, name, nodep->findSigned32DType()}; @@ -425,7 +425,7 @@ class LinkJumpVisitor final : public VNVisitor { // Further handling of disable stmt requires all forks to be begin blocks AstBegin* beginp = VN_CAST(forkItemp, Begin); if (!beginp) { - beginp = new AstBegin{fl, "", nullptr, false, false}; + beginp = new AstBegin{fl, "", nullptr, false}; forkItemp->replaceWith(beginp); beginp->addStmtsp(forkItemp); // In order to continue the iteration diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 7df26971d..195a8377c 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -111,19 +111,19 @@ class LinkParseVisitor final : public VNVisitor { iterateChildren(nodep); } - bool nestedIfBegin(AstBegin* nodep) { // Point at begin inside the GenIf + bool nestedIfBegin(AstGenBlock* nodep) { // Point at begin inside the GenIf // 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) // 1: GENIF - // -> 1:3: BEGIN [GEN] [IMPLIED] // nodep passed to this function + // -> 1:3: GENBLOCK [IMPLIED] // nodep passed to this function // 1:3:1: GENIF - // 1:3:1:2: BEGIN genblk1 [GEN] [IMPLIED] + // 1:3:1:2: GENBLOCK genblk1 [IMPLIED] const AstNode* const backp = nodep->backp(); return (nodep->implied() // User didn't provide begin/end && VN_IS(backp, GenIf) && VN_CAST(backp, GenIf)->elsesp() == nodep && !nodep->nextp() // No other statements under upper genif else - && (VN_IS(nodep->stmtsp(), GenIf)) // Begin has if underneath - && !nodep->stmtsp()->nextp()); // Has only one item + && (VN_IS(nodep->itemsp(), GenIf)) // Begin has if underneath + && !nodep->itemsp()->nextp()); // Has only one item } void checkIndent(AstNode* nodep, AstNode* childp) { @@ -657,7 +657,7 @@ class LinkParseVisitor final : public VNVisitor { void visit(AstCover* nodep) override { visitIterateNoValueMod(nodep); } void visit(AstRestrict* nodep) override { visitIterateNoValueMod(nodep); } - void visit(AstBegin* nodep) override { + void visit(AstGenBlock* nodep) override { V3Control::applyCoverageBlock(m_modp, nodep); cleanFileline(nodep); VL_RESTORER(m_beginDepth); @@ -671,13 +671,13 @@ class LinkParseVisitor final : public VNVisitor { if (nodep->genforp()) { ++m_genblkNum; if (nodep->name() == "") assignGenBlkNum = m_genblkNum; - } else if (nodep->generate() && nodep->name() == "" - && (VN_IS(backp, CaseItem) || VN_IS(backp, GenIf)) && !nestedIf) { + } else if (nodep->name() == "" && (VN_IS(backp, GenCaseItem) || VN_IS(backp, GenIf)) + && !nestedIf) { assignGenBlkNum = m_genblkAbove; } if (assignGenBlkNum != -1) { nodep->name("genblk" + cvtToStr(assignGenBlkNum)); - if (nodep->stmtsp()) { + if (nodep->itemsp()) { nodep->v3warn(GENUNNAMED, "Unnamed generate block " << nodep->prettyNameQ() << " (IEEE 1800-2023 27.6)\n" @@ -696,6 +696,31 @@ class LinkParseVisitor final : public VNVisitor { iterateChildren(nodep); } } + void visit(AstGenCase* nodep) override { + ++m_genblkNum; + cleanFileline(nodep); + VL_RESTORER(m_genblkAbove); + VL_RESTORER(m_genblkNum); + m_genblkAbove = m_genblkNum; + m_genblkNum = 0; + iterateChildren(nodep); + } + void visit(AstGenIf* nodep) override { + cleanFileline(nodep); + checkIndent(nodep, nodep->elsesp() ? nodep->elsesp() : nodep->thensp()); + const bool nestedIf = (VN_IS(nodep->backp(), GenBlock) + && nestedIfBegin(VN_CAST(nodep->backp(), GenBlock))); + if (nestedIf) { + iterateChildren(nodep); + } else { + ++m_genblkNum; + VL_RESTORER(m_genblkAbove); + VL_RESTORER(m_genblkNum); + m_genblkAbove = m_genblkNum; + m_genblkNum = 0; + iterateChildren(nodep); + } + } void visit(AstCell* nodep) override { if (nodep->origName().empty()) { if (!VN_IS(nodep->modp(), Primitive)) { // Module/Program/Iface @@ -710,31 +735,11 @@ class LinkParseVisitor final : public VNVisitor { } iterateChildren(nodep); } - void visit(AstGenCase* nodep) override { - ++m_genblkNum; + void visit(AstBegin* nodep) override { + V3Control::applyCoverageBlock(m_modp, nodep); cleanFileline(nodep); - VL_RESTORER(m_genblkAbove); - VL_RESTORER(m_genblkNum); - m_genblkAbove = m_genblkNum; - m_genblkNum = 0; iterateChildren(nodep); } - void visit(AstGenIf* nodep) override { - cleanFileline(nodep); - checkIndent(nodep, nodep->elsesp() ? nodep->elsesp() : nodep->thensp()); - const bool nestedIf - = (VN_IS(nodep->backp(), Begin) && nestedIfBegin(VN_CAST(nodep->backp(), Begin))); - if (nestedIf) { - iterateChildren(nodep); - } else { - ++m_genblkNum; - VL_RESTORER(m_genblkAbove); - VL_RESTORER(m_genblkNum); - m_genblkAbove = m_genblkNum; - m_genblkNum = 0; - iterateChildren(nodep); - } - } void visit(AstCase* nodep) override { V3Control::applyCase(nodep); cleanFileline(nodep); diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 8151b2713..a67c158a9 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -1610,7 +1610,7 @@ class ParamVisitor final : public VNVisitor { } } - void visit(AstBegin* nodep) override { + void visit(AstGenBlock* nodep) override { // Parameter substitution for generated for loops. // TODO Unlike generated IF, we don't have to worry about short-circuiting the // conditional expression, since this is currently restricted to simple @@ -1663,8 +1663,8 @@ class ParamVisitor final : public VNVisitor { V3Const::constifyParamsEdit(nodep->exprp()); // exprp may change const AstConst* const exprp = VN_AS(nodep->exprp(), Const); // Constify - for (AstCaseItem* itemp = nodep->itemsp(); itemp; - itemp = VN_AS(itemp->nextp(), CaseItem)) { + for (AstGenCaseItem* itemp = nodep->itemsp(); itemp; + itemp = VN_AS(itemp->nextp(), GenCaseItem)) { for (AstNode* ep = itemp->condsp(); ep;) { AstNode* const nextp = ep->nextp(); // May edit list iterateAndNextNull(ep); @@ -1673,8 +1673,8 @@ class ParamVisitor final : public VNVisitor { } } // Item match - for (AstCaseItem* itemp = nodep->itemsp(); itemp; - itemp = VN_AS(itemp->nextp(), CaseItem)) { + for (AstGenCaseItem* itemp = nodep->itemsp(); itemp; + itemp = VN_AS(itemp->nextp(), GenCaseItem)) { if (!itemp->isDefault()) { for (AstNode* ep = itemp->condsp(); ep; ep = ep->nextp()) { if (const AstConst* const ccondp = VN_CAST(ep, Const)) { @@ -1682,7 +1682,7 @@ class ParamVisitor final : public VNVisitor { match.opEq(ccondp->num(), exprp->num()); if (!hit && match.isNeqZero()) { hit = true; - keepp = itemp->stmtsp(); + keepp = itemp->itemsp(); } } else { itemp->v3error("Generate Case item does not evaluate to constant"); @@ -1691,12 +1691,12 @@ class ParamVisitor final : public VNVisitor { } } // Else default match - for (AstCaseItem* itemp = nodep->itemsp(); itemp; - itemp = VN_AS(itemp->nextp(), CaseItem)) { + for (AstGenCaseItem* itemp = nodep->itemsp(); itemp; + itemp = VN_AS(itemp->nextp(), GenCaseItem)) { if (itemp->isDefault()) { if (!hit) { hit = true; - keepp = itemp->stmtsp(); + keepp = itemp->itemsp(); } } } diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index 722896b89..e4f850116 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -252,7 +252,7 @@ public: // would misfire AstNode* newBlock(FileLine* fl, AstNode* nodep) { if (nodep) return nodep; - return new AstBegin{fl, "", nullptr, false, true}; + return new AstBegin{fl, "", nullptr, true}; } // Bison sometimes needs error context without a token, so remember last token's line diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 631a70dbf..6737dd5a9 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -597,7 +597,7 @@ class ConstraintExprVisitor final : public VNVisitor { { AstBegin* const tempp - = new AstBegin{fl, "[EditWrapper]", itemsp->unlinkFrBackWithNext(), false, false}; + = new AstBegin{fl, "[EditWrapper]", itemsp->unlinkFrBackWithNext(), false}; VL_DO_DANGLING(iterateAndNextNull(tempp->stmtsp()), itemsp); itemsp = tempp->stmtsp(); if (itemsp) itemsp->unlinkFrBackWithNext(); @@ -937,6 +937,10 @@ class ConstraintExprVisitor final : public VNVisitor { } VL_DO_DANGLING(nodep->deleteTree(), nodep); } + void visit(AstGenBlock* nodep) override { + // Dubious but this is what we used to do. Does that mean no randomzie + // methods work under a generage block? + } void visit(AstBegin* nodep) override {} void visit(AstConstraintForeach* nodep) override { // Convert to plain foreach @@ -951,7 +955,7 @@ class ConstraintExprVisitor final : public VNVisitor { exprsp->addNext(new AstBegin{ fl, "", new AstForeach{fl, nodep->arrayp()->unlinkFrBack(), new AstCStmt{fl, cstmtp}}, - false, true}); + true}); exprsp->addNext( new AstText{fl, "return ret.empty() ? \"#b1\" : \"(bvand\" + ret + \")\";})()"}); AstNodeExpr* const newp = new AstCExpr{fl, exprsp}; @@ -963,7 +967,7 @@ class ConstraintExprVisitor final : public VNVisitor { new AstBegin{fl, "", new AstForeach{fl, nodep->arrayp()->unlinkFrBack(), nodep->stmtsp()->unlinkFrBackWithNext()}, - false, true}); + true}); } VL_DO_DANGLING(nodep->deleteTree(), nodep); } @@ -1027,8 +1031,8 @@ class ConstraintExprVisitor final : public VNVisitor { cstmtp->addNext(iterateSubtreeReturnEdits(itemp)); cstmtp->addNext(new AstText{fl, ";"}); AstNode* const exprsp = new AstText{fl, "([&]{ std::string ret;"}; - exprsp->addNext(new AstBegin{ - fl, "", new AstForeach{fl, arrayp, new AstCStmt{fl, cstmtp}}, false, true}); + exprsp->addNext( + new AstBegin{fl, "", new AstForeach{fl, arrayp, new AstCStmt{fl, cstmtp}}, true}); exprsp->addNext( new AstText{fl, "return ret.empty() ? \"#b0\" : \"(bvor\" + ret + \")\";})()"}); AstNodeExpr* const newp = new AstCExpr{fl, exprsp}; @@ -1530,7 +1534,7 @@ class RandomizeVisitor final : public VNVisitor { new AstAssign{fl, new AstVarRef{fl, iterVarp, VAccess::WRITE}, new AstAdd{fl, new AstConst{fl, 1}, new AstVarRef{fl, iterVarp, VAccess::READ}}}}); - return new AstBegin{fl, "", stmtsp, false, true}; + return new AstBegin{fl, "", stmtsp, true}; } static AstNodeStmt* wrapIfRandMode(AstClass* classp, AstVar* const varp, AstNodeStmt* stmtp) { const RandomizeMode rmode = {.asInt = varp->user1()}; @@ -1939,7 +1943,7 @@ class RandomizeVisitor final : public VNVisitor { AstVarRef* const refp = new AstVarRef{fl, classp, memberVarp, VAccess::WRITE}; AstNodeStmt* const stmtp = newRandStmtsp(fl, refp, randcVarp, basicFvarp); if (!refp->backp()) VL_DO_DANGLING(refp->deleteTree(), refp); - basicRandomizep->addStmtsp(new AstBegin{fl, "", stmtp, false, false}); + basicRandomizep->addStmtsp(new AstBegin{fl, "", stmtp, false}); } }); } @@ -2072,7 +2076,7 @@ class RandomizeVisitor final : public VNVisitor { stmtsp->addNext(setStmtsp); stmtsp->addNext(m_stmtp); stmtsp->addNext(restoreStmtsp); - relinker.relink(new AstBegin{nodep->fileline(), "", stmtsp, false, true}); + relinker.relink(new AstBegin{nodep->fileline(), "", stmtsp, true}); } } diff --git a/src/V3Sched.cpp b/src/V3Sched.cpp index ae1b4fa9b..13e841772 100644 --- a/src/V3Sched.cpp +++ b/src/V3Sched.cpp @@ -345,7 +345,7 @@ void splitCheck(AstCFunc* ofuncp) { // Unlink all statements, then add item by item to new sub-functions AstBegin* const tempp = new AstBegin{ofuncp->fileline(), "[EditWrapper]", - ofuncp->stmtsp()->unlinkFrBackWithNext(), false, false}; + ofuncp->stmtsp()->unlinkFrBackWithNext(), false}; // Currently we do not use finalsp in V3Sched, if we do, it needs to be handled here UASSERT_OBJ(!ofuncp->finalsp(), ofuncp, "Should not have any finalps"); while (tempp->stmtsp()) { diff --git a/src/V3Simulate.h b/src/V3Simulate.h index 2c4c6a824..dc77cb410 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -991,7 +991,7 @@ private: checkNodeInfo(nodep); iterateChildrenConst(nodep); } - void visit(AstNodeCase* nodep) override { + void visit(AstCase* nodep) override { if (jumpingOver()) return; UINFO(5, " CASE " << nodep); checkNodeInfo(nodep); @@ -1083,39 +1083,6 @@ private: checkNodeInfo(nodep); } - void visit(AstNodeFor* nodep) override { - // Doing lots of Whiles is slow, so only for parameters - UINFO(5, " FOR " << nodep); - if (!m_params) { - badNodeType(nodep); - return; - } - checkNodeInfo(nodep); - if (m_checkOnly) { - iterateChildrenConst(nodep); - } else if (optimizable()) { - int loops = 0; - iterateAndNextConstNull(nodep->initsp()); - while (true) { - UINFO(5, " FOR-ITER " << nodep); - iterateAndNextConstNull(nodep->condp()); - if (!optimizable()) break; - if (!fetchConst(nodep->condp())->num().isNeqZero()) { // - break; - } - iterateAndNextConstNull(nodep->stmtsp()); - iterateAndNextConstNull(nodep->incsp()); - if (loops++ > v3Global.opt.unrollCountAdjusted(VOptionBool{}, m_params, true)) { - clearOptimizable(nodep, "Loop unrolling took too long; probably this is an" - "infinite loop, or use /*verilator unroll_full*/, or " - "set --unroll-count above " - + cvtToStr(loops)); - break; - } - } - } - } - void visit(AstWhile* nodep) override { // Doing lots of Whiles is slow, so only for parameters if (jumpingOver()) return; diff --git a/src/V3Split.cpp b/src/V3Split.cpp index dca6a21f2..1fb156076 100644 --- a/src/V3Split.cpp +++ b/src/V3Split.cpp @@ -338,7 +338,7 @@ protected: void visit(AstAlways* nodep) override = 0; void visit(AstNodeIf* nodep) override = 0; - // We don't do AstNodeFor/AstWhile loops, due to the standard question + // We don't do AstWhile loops, due to the standard question // of what is before vs. after void visit(AstAssignDly* nodep) override { diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index 7345bd773..cc2f96920 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -194,7 +194,7 @@ struct SplitVarImpl VL_NOT_FINAL { stmtp->unlinkFrBack(); // Insert begin-end because temp value may be inserted to this block later. const std::string name = "__VsplitVarBlk" + cvtToStr(modp->user1Inc(1)); - ap->addStmtsp(new AstBegin{ap->fileline(), name, stmtp, false, false}); + ap->addStmtsp(new AstBegin{ap->fileline(), name, stmtp, false}); } } @@ -204,7 +204,7 @@ struct SplitVarImpl VL_NOT_FINAL { // Insert begin-end because temp value may be inserted to this block later. FileLine* const fl = initp->fileline(); const std::string name = "__VsplitVarBlk" + cvtToStr(modp->user1Inc(1)); - initp->replaceWith(new AstInitial{fl, new AstBegin{fl, name, stmtp, false, false}}); + initp->replaceWith(new AstInitial{fl, new AstBegin{fl, name, stmtp, false}}); VL_DO_DANGLING(initp->deleteTree(), initp); } } diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 472004421..34eb47844 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -1362,7 +1362,7 @@ class TaskVisitor final : public VNVisitor { if (bodysp) { unlinkAndClone(nodep, bodysp, true); AstBegin* const tempp - = new AstBegin{nodep->fileline(), "[EditWrapper]", bodysp, false, false}; + = new AstBegin{nodep->fileline(), "[EditWrapper]", bodysp, false}; VL_DANGLING(bodysp); // If we cloned due to recursion, now need to rip out the ports // (that remained in place) then got cloned @@ -1624,10 +1624,6 @@ class TaskVisitor final : public VNVisitor { nodep->v3fatalSrc( "Foreach statements should have been converted to while statements in V3Begin.cpp"); } - void visit(AstNodeFor* nodep) override { // LCOV_EXCL_LINE - nodep->v3fatalSrc( - "For statements should have been converted to while statements in V3Begin.cpp"); - } void visit(AstNodeStmt* nodep) override { VL_RESTORER(m_insStmtp); m_insStmtp = nodep; diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index 05a9b5914..fce48e427 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -1029,7 +1029,7 @@ class TimingControlVisitor final : public VNVisitor { } controlp->replaceWith(forkp); AstBegin* beginp = VN_CAST(controlp, Begin); - if (!beginp) beginp = new AstBegin{nodep->fileline(), "", controlp, false, false}; + if (!beginp) beginp = new AstBegin{nodep->fileline(), "", controlp, false}; forkp->addStmtsp(beginp); controlp = forkp; } diff --git a/src/V3Unroll.cpp b/src/V3Unroll.cpp index f8abcc2cd..15293ed96 100644 --- a/src/V3Unroll.cpp +++ b/src/V3Unroll.cpp @@ -209,8 +209,7 @@ class UnrollVisitor final : public VNVisitor { if (loopValue) { AstConst* varValuep = new AstConst{nodep->fileline(), *loopValue}; // Iteration requires a back, so put under temporary node - AstBegin* tempp - = new AstBegin{nodep->fileline(), "[EditWrapper]", clonep, false, false}; + AstBegin* tempp = new AstBegin{nodep->fileline(), "[EditWrapper]", clonep, false}; replaceVarRef(tempp->stmtsp(), varValuep); clonep = tempp->stmtsp()->unlinkFrBackWithNext(); VL_DO_CLEAR(tempp->deleteTree(), tempp = nullptr); @@ -303,8 +302,7 @@ class UnrollVisitor final : public VNVisitor { AstNode* clonep = initp->cloneTree(true); AstConst* varValuep = new AstConst{nodep->fileline(), loopValue}; // Iteration requires a back, so put under temporary node - AstBegin* tempp - = new AstBegin{nodep->fileline(), "[EditWrapper]", clonep, false, false}; + AstBegin* tempp = new AstBegin{nodep->fileline(), "[EditWrapper]", clonep, false}; replaceVarRef(clonep, varValuep); clonep = tempp->stmtsp()->unlinkFrBackWithNext(); VL_DO_CLEAR(tempp->deleteTree(), tempp = nullptr); @@ -329,8 +327,8 @@ class UnrollVisitor final : public VNVisitor { AstConst* varValuep = new AstConst{nodep->fileline(), loopValue}; if (oneloopp) { // Iteration requires a back, so put under temporary node - AstBegin* const tempp = new AstBegin{oneloopp->fileline(), "[EditWrapper]", - oneloopp, false, false}; + AstBegin* const tempp + = new AstBegin{oneloopp->fileline(), "[EditWrapper]", oneloopp, false}; replaceVarRef(tempp->stmtsp(), varValuep); oneloopp = tempp->stmtsp()->unlinkFrBackWithNext(); VL_DO_DANGLING(tempp->deleteTree(), tempp); @@ -338,8 +336,7 @@ class UnrollVisitor final : public VNVisitor { if (m_generate) { const string index = AstNode::encodeNumber(varValuep->toSInt()); const string nname = m_beginName + "__BRA__" + index + "__KET__"; - oneloopp - = new AstBegin{oneloopp->fileline(), nname, oneloopp, true, false}; + oneloopp = new AstGenBlock{oneloopp->fileline(), nname, oneloopp, false}; } VL_DO_DANGLING(pushDeletep(varValuep), varValuep); if (newbodysp) { @@ -421,9 +418,7 @@ class UnrollVisitor final : public VNVisitor { } } void visit(AstGenFor* nodep) override { - if (!m_generate) { - iterateChildren(nodep); - } // else V3Param will recursively call each for loop to be unrolled for us + UASSERT_OBJ(m_generate, nodep, "There should be no GenFor left when unrolling all"); if (!m_varModeCheck) { // Constify before unroll call, as it may change what is underneath. if (nodep->initsp()) V3Const::constifyEdit(nodep->initsp()); // initsp may change @@ -439,7 +434,7 @@ class UnrollVisitor final : public VNVisitor { // deleted by V3Const. VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); } else if (forUnrollCheck(nodep, VOptionBool{}, nodep->initsp(), nodep->condp(), - nodep->incsp(), nodep->stmtsp())) { + nodep->incsp(), nodep->itemsp())) { VL_DO_DANGLING(pushDeletep(nodep), nodep); // Did replacement } else { nodep->v3error("For loop doesn't have genvar index, or is malformed"); @@ -448,13 +443,6 @@ class UnrollVisitor final : public VNVisitor { } } } - void visit(AstNodeFor* nodep) override { - if (m_generate) { // Ignore for's when expanding genfor's - iterateChildren(nodep); - } else { - nodep->v3fatalSrc("V3Begin should have removed standard FORs"); - } - } void visit(AstVarRef* nodep) override { if (m_varModeCheck && nodep->varp() == m_forVarp && nodep->varScopep() == m_forVscp @@ -514,18 +502,16 @@ UnrollStateful::UnrollStateful() : m_unrollerp{new UnrollVisitor} {} UnrollStateful::~UnrollStateful() { delete m_unrollerp; } -void UnrollStateful::unrollGen(AstNodeFor* nodep, const string& beginName) { +void UnrollStateful::unrollGen(AstGenFor* nodep, const string& beginName) { UINFO(5, __FUNCTION__ << ": "); m_unrollerp->process(nodep, true, beginName); } -void UnrollStateful::unrollAll(AstNetlist* nodep) { m_unrollerp->process(nodep, false, ""); } - void V3Unroll::unrollAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ":"); { - UnrollStateful unroller; - unroller.unrollAll(nodep); + UnrollVisitor visitor; + visitor.process(nodep, false, ""); } // Destruct before checking V3Global::dumpCheckGlobalTree("unroll", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Unroll.h b/src/V3Unroll.h index 50d51b86b..bc16c4a4e 100644 --- a/src/V3Unroll.h +++ b/src/V3Unroll.h @@ -38,8 +38,7 @@ public: UnrollStateful() VL_MT_DISABLED; ~UnrollStateful() VL_MT_DISABLED; // METHODS - void unrollGen(AstNodeFor* nodep, const string& beginName) VL_MT_DISABLED; - void unrollAll(AstNetlist* nodep) VL_MT_DISABLED; + void unrollGen(AstGenFor* nodep, const string& beginName) VL_MT_DISABLED; }; //============================================================================ diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 1d0167c52..ca05b8516 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -744,8 +744,7 @@ class WidthVisitor final : public VNVisitor { || (!nodep->stmtsp()->nextp() && !nodep->joinType().joinNone())))) { AstNode* stmtsp = nullptr; if (nodep->stmtsp()) stmtsp = nodep->stmtsp()->unlinkFrBack(); - AstBegin* const newp - = new AstBegin{nodep->fileline(), nodep->name(), stmtsp, false, false}; + AstBegin* const newp = new AstBegin{nodep->fileline(), nodep->name(), stmtsp, false}; nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } else if (v3Global.opt.timing().isSetTrue()) { @@ -5261,91 +5260,123 @@ class WidthVisitor final : public VNVisitor { //-------------------- // Top levels - void visit(AstNodeCase* nodep) override { + template + void handleCaseType(AstNode* casep, AstNodeExpr* exprp, CaseItem* itemsp) { + AstAttrOf* const exprap = VN_CAST(exprp, AttrOf); + if (!exprap) return; + if (exprap->attrType() != VAttrType::TYPEID) return; + + const AstNodeDType* const exprDtp = exprap->dtypep(); + UINFO(9, "case type exprDtp " << exprDtp); + // V3Param may have a pointer to this case statement, and we need + // dotted references to remain properly named, so rather than + // removing we convert it to a "normal" expression "case (1) ..." + FileLine* const newfl = casep->fileline(); + newfl->warnOff(V3ErrorCode::CASEINCOMPLETE, true); // Side effect of transform + newfl->warnOff(V3ErrorCode::CASEOVERLAP, true); // Side effect of transform + casep->fileline(newfl); + for (CaseItem* itemp = itemsp; itemp; itemp = AstNode::as(itemp->nextp())) { + if (itemp->isDefault()) continue; + bool hit = false; + for (AstNode* condp = itemp->condsp(); condp; condp = condp->nextp()) { + const AstAttrOf* const condAttrp = VN_CAST(condp, AttrOf); + if (!condAttrp) { + condp->v3error("Case(type) statement requires items that have type() items"); + } else { + AstNodeDType* const condDtp = condAttrp->dtypep(); + if (AstNode::computeCastable(exprDtp, condDtp, casep) == VCastable::SAMEISH) { + hit = true; + break; + } + } + } + pushDeletep(itemp->condsp()->unlinkFrBackWithNext()); + // Item condition becomes constant 1 if hits else 0 + itemp->addCondsp(new AstConst{newfl, AstConst::BitTrue{}, hit}); + } + exprap->replaceWith(new AstConst{newfl, AstConst::BitTrue{}}); + VL_DO_DANGLING(pushDeletep(exprap), exprap); + } + + template + void handleCase(AstNode* casep, AstNodeExpr* exprp, CaseItem* itemsp) { // IEEE-2012 12.5: // Width: MAX(expr, all items) // Signed: Only if expr, and all items signed + // Take width as maximum across all items, if any is real whole thing is real + AstNodeDType* subDTypep = exprp->dtypep(); + for (CaseItem* itemp = itemsp; itemp; itemp = AstNode::as(itemp->nextp())) { + for (AstNode* condp = itemp->condsp(); condp; condp = condp->nextp()) { + if (condp->dtypep() == subDTypep) continue; + + if (condp->dtypep()->isDouble() || subDTypep->isDouble()) { + subDTypep = casep->findDoubleDType(); + } else if (condp->dtypep()->isString() || subDTypep->isString()) { + subDTypep = casep->findStringDType(); + } else { + const int width = std::max(subDTypep->width(), condp->width()); + const int mwidth = std::max(subDTypep->widthMin(), condp->widthMin()); + const bool issigned = subDTypep->isSigned() && condp->isSigned(); + subDTypep = casep->findLogicDType(width, mwidth, VSigning::fromBool(issigned)); + } + } + } + + // Apply width + iterateCheck(casep, "Case expression", exprp, CONTEXT_DET, FINAL, subDTypep, EXTEND_EXP); + for (CaseItem* itemp = itemsp; itemp; itemp = AstNode::as(itemp->nextp())) { + for (AstNode *nextcp, *condp = itemp->condsp(); condp; condp = nextcp) { + nextcp = condp->nextp(); // Final may cause the node to get replaced + iterateCheck(casep, "Case Item", condp, CONTEXT_DET, FINAL, subDTypep, EXTEND_LHS); + } + } + } + + void visit(AstGenCase* nodep) override { assertAtStatement(nodep); + // Type check expression and case item conditions, but not bodies + userIterateAndNext(nodep->exprp(), WidthVP{CONTEXT_DET, PRELIM}.p()); + for (AstGenCaseItem *nextip, *itemp = nodep->itemsp(); itemp; itemp = nextip) { + // Prelim may cause the node to get replaced, pick up next up front + nextip = VN_AS(itemp->nextp(), GenCaseItem); + for (AstNode *nextcp, *condp = itemp->condsp(); condp; condp = nextcp) { + // Prelim may cause the node to get replaced, pick up next up front + nextcp = condp->nextp(); + VL_DO_DANGLING(userIterate(condp, WidthVP{CONTEXT_DET, PRELIM}.p()), condp); + } + } + // Deal with case(type(data_type)) + handleCaseType(nodep, nodep->exprp(), nodep->itemsp()); + // Type check + handleCase(nodep, nodep->exprp(), nodep->itemsp()); + } + void visit(AstGenFor* nodep) override { + assertAtStatement(nodep); + userIterateAndNext(nodep->initsp(), nullptr); + iterateCheckBool(nodep, "For Test Condition", nodep->condp(), BOTH); + userIterateAndNext(nodep->incsp(), nullptr); + } + void visit(AstGenIf* nodep) override { + assertAtStatement(nodep); + iterateCheckBool(nodep, "If", nodep->condp(), BOTH); + } + + void visit(AstCase* nodep) override { + assertAtStatement(nodep); + // Type check expression case item conditions and bodies userIterateAndNext(nodep->exprp(), WidthVP{CONTEXT_DET, PRELIM}.p()); for (AstCaseItem *nextip, *itemp = nodep->itemsp(); itemp; itemp = nextip) { nextip = VN_AS(itemp->nextp(), CaseItem); // Prelim may cause the node to get replaced - if (!VN_IS(nodep, GenCase)) userIterateAndNext(itemp->stmtsp(), nullptr); + userIterateAndNext(itemp->stmtsp(), nullptr); for (AstNode *nextcp, *condp = itemp->condsp(); condp; condp = nextcp) { nextcp = condp->nextp(); // Prelim may cause the node to get replaced VL_DO_DANGLING(userIterate(condp, WidthVP{CONTEXT_DET, PRELIM}.p()), condp); } } - // Deal with case(type(data_type)) - if (AstAttrOf* const exprap = VN_CAST(nodep->exprp(), AttrOf)) { - if (exprap->attrType() == VAttrType::TYPEID) { - const AstNodeDType* const exprDtp = exprap->dtypep(); - UINFO(9, "case type exprDtp " << exprDtp); - // V3Param may have a pointer to this case statement, and we need - // dotted references to remain properly named, so rather than - // removing we convert it to a "normal" expression "case (1) ..." - FileLine* const newfl = nodep->fileline(); - newfl->warnOff(V3ErrorCode::CASEINCOMPLETE, true); // Side effect of transform - newfl->warnOff(V3ErrorCode::CASEOVERLAP, true); // Side effect of transform - nodep->fileline(newfl); - for (AstCaseItem* itemp = nodep->itemsp(); itemp; - itemp = VN_AS(itemp->nextp(), CaseItem)) { - if (!itemp->isDefault()) { - bool hit = false; - for (AstNode* condp = itemp->condsp(); condp; condp = condp->nextp()) { - const AstAttrOf* const condAttrp = VN_CAST(condp, AttrOf); - if (!condAttrp) { - condp->v3error( - "Case(type) statement requires items that have type() items"); - } else { - AstNodeDType* const condDtp = condAttrp->dtypep(); - if (AstNode::computeCastable(exprDtp, condDtp, nodep) - == VCastable::SAMEISH) { - hit = true; - break; - } - } - } - pushDeletep(itemp->condsp()->unlinkFrBackWithNext()); - // Item condition becomes constant 1 if hits else 0 - itemp->addCondsp(new AstConst{newfl, AstConst::BitTrue{}, hit}); - } - } - VL_DO_DANGLING(pushDeletep(exprap->unlinkFrBack()), exprap); - nodep->exprp(new AstConst{newfl, AstConst::BitTrue{}}); - } - } - - // Take width as maximum across all items, if any is real whole thing is real - AstNodeDType* subDTypep = nodep->exprp()->dtypep(); - for (AstCaseItem* itemp = nodep->itemsp(); itemp; - itemp = VN_AS(itemp->nextp(), CaseItem)) { - for (AstNode* condp = itemp->condsp(); condp; condp = condp->nextp()) { - if (condp->dtypep() != subDTypep) { - if (condp->dtypep()->isDouble() || subDTypep->isDouble()) { - subDTypep = nodep->findDoubleDType(); - } else if (condp->dtypep()->isString() || subDTypep->isString()) { - subDTypep = nodep->findStringDType(); - } else { - const int width = std::max(subDTypep->width(), condp->width()); - const int mwidth = std::max(subDTypep->widthMin(), condp->widthMin()); - const bool issigned = subDTypep->isSigned() && condp->isSigned(); - subDTypep - = nodep->findLogicDType(width, mwidth, VSigning::fromBool(issigned)); - } - } - } - } - // Apply width - iterateCheck(nodep, "Case expression", nodep->exprp(), CONTEXT_DET, FINAL, subDTypep, - EXTEND_EXP); - for (AstCaseItem* itemp = nodep->itemsp(); itemp; - itemp = VN_AS(itemp->nextp(), CaseItem)) { - for (AstNode *nextcp, *condp = itemp->condsp(); condp; condp = nextcp) { - nextcp = condp->nextp(); // Final may cause the node to get replaced - iterateCheck(nodep, "Case Item", condp, CONTEXT_DET, FINAL, subDTypep, EXTEND_LHS); - } - } + handleCaseType(nodep, nodep->exprp(), nodep->itemsp()); + // Type check + handleCase(nodep, nodep->exprp(), nodep->itemsp()); } void visit(AstRandCase* nodep) override { // IEEE says each item is a int (32-bits), and sizes are based on natural sizing, @@ -5365,14 +5396,6 @@ class WidthVisitor final : public VNVisitor { } } - void visit(AstNodeFor* nodep) override { - assertAtStatement(nodep); - userIterateAndNext(nodep->initsp(), nullptr); - iterateCheckBool(nodep, "For Test Condition", nodep->condp(), - BOTH); // it's like an if() condition. - if (!VN_IS(nodep, GenFor)) userIterateAndNext(nodep->stmtsp(), nullptr); - userIterateAndNext(nodep->incsp(), nullptr); - } void visit(AstRepeat* nodep) override { assertAtStatement(nodep); userIterateAndNext(nodep->countp(), WidthVP{SELF, BOTH}.p()); @@ -5388,10 +5411,8 @@ class WidthVisitor final : public VNVisitor { void visit(AstNodeIf* nodep) override { assertAtStatement(nodep); // UINFOTREE(1, nodep, "", "IfPre"); - if (!VN_IS(nodep, GenIf)) { // for m_paramsOnly - userIterateAndNext(nodep->thensp(), nullptr); - userIterateAndNext(nodep->elsesp(), nullptr); - } + userIterateAndNext(nodep->thensp(), nullptr); + userIterateAndNext(nodep->elsesp(), nullptr); iterateCheckBool(nodep, "If", nodep->condp(), BOTH); // it's like an if() condition. // UINFOTREE(1, nodep, "", "IfOut"); } diff --git a/src/Verilator.cpp b/src/Verilator.cpp index df1d018fe..be46c7687 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -179,6 +179,7 @@ static void process() { // Remove parameters by cloning modules to de-parameterized versions // This requires some width calculations and constant propagation + // No more AstGenCase/AstGenFor/AstGenIf after this V3Param::param(v3Global.rootp()); V3LinkDot::linkDotParamed(v3Global.rootp()); // Cleanup as made new modules V3LinkLValue::linkLValue(v3Global.rootp()); // Resolve new VarRefs @@ -271,6 +272,7 @@ static void process() { // Task inlining & pushing BEGINs names to variables/cells // Begin processing must be after Param, before module inlining + // No more AstGenBlocks after this V3Begin::debeginAll(v3Global.rootp()); // Flatten cell names, before inliner // Expand inouts, stage 2 diff --git a/src/verilog.y b/src/verilog.y index 57655ac5e..d6a660d3a 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -2713,7 +2713,7 @@ generate_block_or_null: // IEEE: generate_block_or_null (called from gen // // IEEE: generate_block // // Must always return a BEGIN node, or nullptr - see GenFor construction ~c~generate_item - { $$ = $1 ? (new AstBegin{$1->fileline(), "", $1, true, true}) : nullptr; } + { $$ = $1 ? (new AstGenBlock{$1->fileline(), "", $1, true}) : nullptr; } | ~c~genItemBegin { $$ = $1; } ; @@ -2722,19 +2722,19 @@ c_generate_block_or_null: // IEEE: generate_block_or_null (for checkers) ; genItemBegin: // IEEE: part of generate_block - yBEGIN ~c~genItemList yEND { $$ = new AstBegin{$1, "", $2, true, false}; } + yBEGIN ~c~genItemList yEND { $$ = new AstGenBlock{$1, "", $2, false}; } | yBEGIN yEND { $$ = nullptr; } | id yP_COLON__BEGIN yBEGIN ~c~genItemList yEND endLabelE - { $$ = new AstBegin{$1, *$1, $4, true, false}; + { $$ = new AstGenBlock{$1, *$1, $4, false}; GRAMMARP->endLabel($6, *$1, $6); } | id yP_COLON__BEGIN yBEGIN yEND endLabelE - { $$ = new AstBegin{$1, *$1, nullptr, true, false}; + { $$ = new AstGenBlock{$1, *$1, nullptr, false}; GRAMMARP->endLabel($5, *$1, $5); } | yBEGIN ':' idAny ~c~genItemList yEND endLabelE - { $$ = new AstBegin{$3, *$3, $4, true, false}; + { $$ = new AstGenBlock{$3, *$3, $4, false}; GRAMMARP->endLabel($6, *$3, $6); } | yBEGIN ':' idAny yEND endLabelE - { $$ = new AstBegin{$3, *$3, nullptr, true, false}; + { $$ = new AstGenBlock{$3, *$3, nullptr, false}; GRAMMARP->endLabel($5, *$3, $5); } ; @@ -2803,27 +2803,23 @@ c_conditional_generate_construct: // IEEE: conditional_generate_construc loop_generate_construct: // ==IEEE: loop_generate_construct yFOR '(' genvar_initialization ';' expr ';' genvar_iteration ')' ~c~generate_block_or_null { // Convert BEGIN(...) to BEGIN(GENFOR(...)), as we need the BEGIN to hide the local genvar - AstBegin* lowerBegp = VN_CAST($9, Begin); - UASSERT_OBJ(!($9 && !lowerBegp), $9, "Child of GENFOR should have been begin"); - - if (!lowerBegp) lowerBegp = new AstBegin{$1, "", nullptr, true, false}; // Empty body - AstNode* const lowerNoBegp = lowerBegp->stmtsp(); - if (lowerNoBegp) lowerNoBegp->unlinkFrBackWithNext(); - // - AstBegin* const blkp = new AstBegin{$1, lowerBegp->name(), nullptr, true, true}; + AstGenBlock* lowerp = VN_CAST($9, GenBlock); + UASSERT_OBJ(!$9 || lowerp, $9, "Child of GENFOR should have been begin"); + AstNode* const itemsp = lowerp && lowerp->itemsp() ? lowerp->itemsp()->unlinkFrBackWithNext() : nullptr; + AstGenBlock* const blkp = new AstGenBlock{$1, lowerp ? lowerp->name() : "", nullptr, true}; // V3LinkDot detects BEGIN(GENFOR(...)) as a special case AstNode* initp = $3; AstNode* const varp = $3; if (VN_IS(varp, Var)) { // Genvar initp = varp->nextp(); initp->unlinkFrBackWithNext(); // Detach 2nd from varp, make 1st init - blkp->addStmtsp(varp); + blkp->addItemsp(varp); } // Statements are under 'genforp' as instances under this // for loop won't get an extra layer of hierarchy tacked on - blkp->genforp(new AstGenFor{$1, initp, $5, $7, lowerNoBegp}); + blkp->genforp(new AstGenFor{$1, initp, $5, $7, itemsp}); $$ = blkp; - VL_DO_DANGLING(lowerBegp->deleteTree(), lowerBegp); + DEL(lowerp); } ; @@ -2878,22 +2874,22 @@ genvar_iteration: // ==IEEE: genvar_iteration new AstConst{$2, AstConst::StringToParse{}, "'b1"}}}; } ; -case_generate_itemList: // IEEE: { case_generate_itemList } +case_generate_itemList: // IEEE: { case_generate_itemList } ~c~case_generate_item { $$ = $1; } | ~c~case_generate_itemList ~c~case_generate_item { $$ = $1; $1->addNext($2); } ; -c_case_generate_itemList: // IEEE: { case_generate_item } (for checkers) +c_case_generate_itemList: // IEEE: { case_generate_item } (for checkers) BISONPRE_COPY(case_generate_itemList,{s/~c~/c_/g}) // {copied} ; -case_generate_item: // ==IEEE: case_generate_item - caseCondList colon ~c~generate_block_or_null { $$ = new AstCaseItem{$2, $1, $3}; } - | yDEFAULT colon ~c~generate_block_or_null { $$ = new AstCaseItem{$1, nullptr, $3}; } - | yDEFAULT ~c~generate_block_or_null { $$ = new AstCaseItem{$1, nullptr, $2}; } +case_generate_item: // ==IEEE: case_generate_item + caseCondList colon ~c~generate_block_or_null { $$ = new AstGenCaseItem{$2, $1, $3}; } + | yDEFAULT colon ~c~generate_block_or_null { $$ = new AstGenCaseItem{$1, nullptr, $3}; } + | yDEFAULT ~c~generate_block_or_null { $$ = new AstGenCaseItem{$1, nullptr, $2}; } ; -c_case_generate_item: // IEEE: case_generate_item (for checkers) +c_case_generate_item: // IEEE: case_generate_item (for checkers) BISONPRE_COPY(case_generate_item,{s/~c~/c_/g}) // {copied} ; @@ -3409,9 +3405,9 @@ par_blockPreId: // ==IEEE: par_block but called with leading ID seq_blockFront: // IEEE: part of seq_block yBEGIN - { $$ = new AstBegin{$1, "", nullptr, false, false}; } + { $$ = new AstBegin{$1, "", nullptr, false}; } | yBEGIN ':' idAny/*new-block_identifier*/ - { $$ = new AstBegin{$3, *$3, nullptr, false, false}; } + { $$ = new AstBegin{$3, *$3, nullptr, false}; } ; par_blockFront: // IEEE: part of par_block @@ -3423,7 +3419,7 @@ par_blockFront: // IEEE: part of par_block seq_blockFrontPreId: // IEEE: part of seq_block/stmt with leading id id/*block_identifier*/ yP_COLON__BEGIN yBEGIN - { $$ = new AstBegin{$3, *$1, nullptr, false, false}; } + { $$ = new AstBegin{$3, *$1, nullptr, false}; } ; par_blockFrontPreId: // IEEE: part of par_block/stmt with leading id @@ -3468,7 +3464,7 @@ stmtList: stmt: // IEEE: statement_or_null == function_statement_or_null statement_item { $$ = $1; } // // S05 block creation rule - | id/*block_identifier*/ ':' statement_item { $$ = new AstBegin{$1, *$1, $3, false, false}; } + | id/*block_identifier*/ ':' statement_item { $$ = new AstBegin{$1, *$1, $3, false}; } // // from _or_null | ';' { $$ = nullptr; } // // labeled par_block/seq_block with leading ':' @@ -3590,7 +3586,7 @@ statement_item: // IEEE: statement_item | yDO stmtBlock yWHILE '(' expr ')' ';' { $$ = new AstDoWhile{$1, $5, $2}; } // // IEEE says array_identifier here, but dotted accepted in VMM and 1800-2009 | yFOREACH '(' idClassSelForeach ')' stmtBlock - { $$ = new AstBegin{$1, "", new AstForeach{$1, $3, $5}, false, true}; } + { $$ = new AstBegin{$1, "", new AstForeach{$1, $3, $5}, true}; } // // // IEEE: jump_statement | yRETURN ';' { $$ = new AstReturn{$1}; } @@ -3652,10 +3648,10 @@ statement_item: // IEEE: statement_item statementFor: // IEEE: part of statement yFOR beginForParen for_initialization expr ';' for_stepE ')' stmtBlock - { $$ = new AstBegin{$1, "", $3, false, true}; + { $$ = new AstBegin{$1, "", $3, true}; $$->addStmtsp(new AstWhile{$1, $4, $8, $6}); } | yFOR beginForParen for_initialization ';' for_stepE ')' stmtBlock - { $$ = new AstBegin{$1, "", $3, false, true}; + { $$ = new AstBegin{$1, "", $3, true}; $$->addStmtsp(new AstWhile{$1, new AstConst{$1, AstConst::BitTrue{}}, $7, $5}); } ; beginForParen: // IEEE: Part of statement (for loop beginning paren) @@ -6160,7 +6156,7 @@ assertion_item: // ==IEEE: assertion_item deferred_immediate_assertion_item: // ==IEEE: deferred_immediate_assertion_item deferred_immediate_assertion_statement { $$ = $1; } | id/*block_identifier*/ ':' deferred_immediate_assertion_statement - { $$ = new AstBegin{$1, *$1, $3, false, true}; } + { $$ = new AstBegin{$1, *$1, $3, true}; } ; procedural_assertion_statement: // ==IEEE: procedural_assertion_statement @@ -6216,7 +6212,7 @@ deferred_immediate_assertion_statement: // ==IEEE: deferred_immediate_as concurrent_assertion_item: // IEEE: concurrent_assertion_item concurrent_assertion_statement { $$ = $1; } | id/*block_identifier*/ ':' concurrent_assertion_statement - { $$ = new AstBegin{$1, *$1, $3, false, true}; } + { $$ = new AstBegin{$1, *$1, $3, true}; } // // IEEE: checker_instantiation // // identical to module_instantiation; see etcInst ; diff --git a/test_regress/t/t_constraint_json_only.out b/test_regress/t/t_constraint_json_only.out index 7ae46914e..fa6018ab8 100644 --- a/test_regress/t/t_constraint_json_only.out +++ b/test_regress/t/t_constraint_json_only.out @@ -5,7 +5,7 @@ {"type":"VAR","name":"p","addr":"(G)","loc":"d,69:11,69:12","dtypep":"(H)","origName":"p","isSc":false,"isPrimaryIO":false,"isPrimaryClock":false,"direction":"NONE","isConst":false,"isPullup":false,"isPulldown":false,"isSigPublic":false,"isLatched":false,"isUsedLoopIdx":false,"noReset":false,"attrIsolateAssign":false,"attrFileDescr":false,"isDpiOpenArray":false,"isFuncReturn":false,"isFuncLocal":false,"lifetime":"VSTATICI","varType":"VAR","dtypeName":"Packet","isSigUserRdPublic":false,"isSigUserRWPublic":false,"isGParam":false,"isParam":false,"attrScBv":false,"attrSFormat":false,"ignorePostWrite":false,"ignoreSchedWrite":false,"sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}, {"type":"INITIAL","name":"","addr":"(I)","loc":"d,71:4,71:11","isSuspendable":false,"needProcess":false, "stmtsp": [ - {"type":"BEGIN","name":"","addr":"(J)","loc":"d,71:12,71:17","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], + {"type":"BEGIN","name":"","addr":"(J)","loc":"d,71:12,71:17","implied":false,"needProcess":false,"unnamed":true, "stmtsp": [ {"type":"DISPLAY","name":"","addr":"(K)","loc":"d,73:7,73:13", "fmtp": [ diff --git a/test_regress/t/t_dump_json.out b/test_regress/t/t_dump_json.out index 3ff9c864e..d30f223d7 100644 --- a/test_regress/t/t_dump_json.out +++ b/test_regress/t/t_dump_json.out @@ -160,7 +160,7 @@ ]} ], "stmtsp": [ - {"type":"BEGIN","name":"","addr":"(XC)","loc":"e,36:27,36:32","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], + {"type":"BEGIN","name":"","addr":"(XC)","loc":"e,36:27,36:32","implied":false,"needProcess":false,"unnamed":true, "stmtsp": [ {"type":"ASSIGNDLY","name":"","addr":"(YC)","loc":"e,40:11,40:13","dtypep":"UNLINKED", "rhsp": [ @@ -308,7 +308,7 @@ ]} ], "thensp": [ - {"type":"BEGIN","name":"","addr":"(ZE)","loc":"e,43:21,43:26","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], + {"type":"BEGIN","name":"","addr":"(ZE)","loc":"e,43:21,43:26","implied":false,"needProcess":false,"unnamed":true, "stmtsp": [ {"type":"ASSIGNDLY","name":"","addr":"(AF)","loc":"e,45:14,45:16","dtypep":"UNLINKED", "rhsp": [ @@ -338,7 +338,7 @@ ]} ], "thensp": [ - {"type":"BEGIN","name":"","addr":"(MF)","loc":"e,48:26,48:31","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], + {"type":"BEGIN","name":"","addr":"(MF)","loc":"e,48:26,48:31","implied":false,"needProcess":false,"unnamed":true, "stmtsp": [ {"type":"ASSIGNDLY","name":"","addr":"(NF)","loc":"e,49:14,49:16","dtypep":"UNLINKED", "rhsp": [ @@ -361,7 +361,7 @@ ]} ], "thensp": [ - {"type":"BEGIN","name":"","addr":"(VF)","loc":"e,51:26,51:31","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [],"stmtsp": []} + {"type":"BEGIN","name":"","addr":"(VF)","loc":"e,51:26,51:31","implied":false,"needProcess":false,"unnamed":true,"stmtsp": []} ], "elsesp": [ {"type":"IF","name":"","addr":"(WF)","loc":"e,53:12,53:14", @@ -375,7 +375,7 @@ ]} ], "thensp": [ - {"type":"BEGIN","name":"","addr":"(AG)","loc":"e,53:27,53:32","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], + {"type":"BEGIN","name":"","addr":"(AG)","loc":"e,53:27,53:32","implied":false,"needProcess":false,"unnamed":true, "stmtsp": [ {"type":"DISPLAY","name":"","addr":"(BG)","loc":"e,54:10,54:16", "fmtp": [ @@ -479,7 +479,7 @@ ]} ], "stmtsp": [ - {"type":"BEGIN","name":"","addr":"(UH)","loc":"e,82:26,82:31","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], + {"type":"BEGIN","name":"","addr":"(UH)","loc":"e,82:26,82:31","implied":false,"needProcess":false,"unnamed":true, "stmtsp": [ {"type":"ASSIGNDLY","name":"","addr":"(VH)","loc":"e,83:11,83:13","dtypep":"UNLINKED", "rhsp": [ @@ -529,7 +529,7 @@ "assertTypesp": [ {"type":"CONST","name":"?32?sh8","addr":"(OI)","loc":"e,90:25,90:26","dtypep":"(LF)"} ],"directiveTypesp": []}, - {"type":"BEGIN","name":"blk","addr":"(PI)","loc":"e,91:15,91:18","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":false,"genforp": [], + {"type":"BEGIN","name":"blk","addr":"(PI)","loc":"e,91:15,91:18","implied":false,"needProcess":false,"unnamed":false, "stmtsp": [ {"type":"DISABLE","name":"","addr":"(QI)","loc":"e,92:10,92:17", "targetRefp": [ @@ -639,7 +639,7 @@ ]} ], "thensp": [ - {"type":"BEGIN","name":"","addr":"(GK)","loc":"d,55:44,55:49","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], + {"type":"BEGIN","name":"","addr":"(GK)","loc":"d,55:44,55:49","implied":false,"needProcess":false,"unnamed":true, "stmtsp": [ {"type":"STMTEXPR","name":"","addr":"(HK)","loc":"d,56:16,56:17", "exprp": [ @@ -695,7 +695,7 @@ ]} ], "thensp": [ - {"type":"BEGIN","name":"","addr":"(DL)","loc":"d,72:22,72:27","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], + {"type":"BEGIN","name":"","addr":"(DL)","loc":"d,72:22,72:27","implied":false,"needProcess":false,"unnamed":true, "stmtsp": [ {"type":"ASSIGN","name":"","addr":"(EL)","loc":"d,73:17,73:18","dtypep":"UNLINKED", "rhsp": [ @@ -748,7 +748,7 @@ ]} ], "thensp": [ - {"type":"BEGIN","name":"","addr":"(YL)","loc":"d,89:22,89:27","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], + {"type":"BEGIN","name":"","addr":"(YL)","loc":"d,89:22,89:27","implied":false,"needProcess":false,"unnamed":true, "stmtsp": [ {"type":"ASSIGN","name":"","addr":"(ZL)","loc":"d,90:17,90:18","dtypep":"UNLINKED", "rhsp": [ @@ -854,7 +854,7 @@ ]} ], "thensp": [ - {"type":"BEGIN","name":"","addr":"(ON)","loc":"d,118:35,118:40","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], + {"type":"BEGIN","name":"","addr":"(ON)","loc":"d,118:35,118:40","implied":false,"needProcess":false,"unnamed":true, "stmtsp": [ {"type":"ASSIGN","name":"","addr":"(PN)","loc":"d,119:20,119:22","dtypep":"UNLINKED", "rhsp": [ diff --git a/test_regress/t/t_duplicated_gen_blocks_bad.out b/test_regress/t/t_duplicated_gen_blocks_bad.out index 96296dc1a..df9a128c0 100644 --- a/test_regress/t/t_duplicated_gen_blocks_bad.out +++ b/test_regress/t/t_duplicated_gen_blocks_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_duplicated_gen_blocks_bad.v:11:12: Duplicate declaration of block: 'block' +%Error: t/t_duplicated_gen_blocks_bad.v:11:12: Duplicate declaration of generate block: 'block' : ... note: In instance 't' 11 | begin : block | ^~~~~ @@ -6,7 +6,7 @@ 9 | begin : block | ^~~~~ ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. -%Error: t/t_duplicated_gen_blocks_bad.v:15:23: Duplicate declaration of block: 'block1' +%Error: t/t_duplicated_gen_blocks_bad.v:15:23: Duplicate declaration of generate block: 'block1' : ... note: In instance 't' 15 | if (X > 1) begin : block1 | ^~~~~~ diff --git a/test_regress/t/t_json_only_begin_hier.out b/test_regress/t/t_json_only_begin_hier.out index 452f2903d..c3d82d83b 100644 --- a/test_regress/t/t_json_only_begin_hier.out +++ b/test_regress/t/t_json_only_begin_hier.out @@ -3,21 +3,21 @@ {"type":"MODULE","name":"test","addr":"(E)","loc":"d,22:8,22:12","isChecker":false,"isProgram":false,"hasGenericIface":false,"origName":"test","level":2,"modPublic":false,"inLibrary":false,"dead":false,"recursiveClone":false,"recursive":false,"timeunit":"1ps","inlinesp": [], "stmtsp": [ {"type":"VAR","name":"N","addr":"(F)","loc":"d,24:12,24:13","dtypep":"(G)","origName":"N","isSc":false,"isPrimaryIO":false,"isPrimaryClock":false,"direction":"NONE","isConst":false,"isPullup":false,"isPulldown":false,"isSigPublic":false,"isLatched":false,"isUsedLoopIdx":true,"noReset":false,"attrIsolateAssign":false,"attrFileDescr":false,"isDpiOpenArray":false,"isFuncReturn":false,"isFuncLocal":false,"lifetime":"VSTATICI","varType":"GENVAR","dtypeName":"integer","isSigUserRdPublic":false,"isSigUserRWPublic":false,"isGParam":false,"isParam":false,"attrScBv":false,"attrSFormat":false,"ignorePostWrite":false,"ignoreSchedWrite":false,"sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}, - {"type":"BEGIN","name":"FOR_GENERATE","addr":"(H)","loc":"d,25:14,25:17","generate":true,"genfor":false,"implied":true,"needProcess":false,"unnamed":false,"genforp": [],"stmtsp": []}, - {"type":"BEGIN","name":"FOR_GENERATE[0]","addr":"(I)","loc":"d,27:21,27:31","generate":true,"genfor":false,"implied":false,"needProcess":false,"unnamed":false,"genforp": [], - "stmtsp": [ + {"type":"GENBLOCK","name":"FOR_GENERATE","addr":"(H)","loc":"d,25:14,25:17","implied":true,"unnamed":false,"genforp": [],"itemsp": []}, + {"type":"GENBLOCK","name":"FOR_GENERATE[0]","addr":"(I)","loc":"d,27:21,27:31","implied":false,"unnamed":false,"genforp": [], + "itemsp": [ {"type":"CELL","name":"submod_for","addr":"(J)","loc":"d,27:21,27:31","origName":"submod_for","recursive":false,"modp":"(K)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []}, - {"type":"BEGIN","name":"genblk1","addr":"(L)","loc":"d,28:19,28:24","generate":true,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], - "stmtsp": [ + {"type":"GENBLOCK","name":"genblk1","addr":"(L)","loc":"d,28:19,28:24","implied":false,"unnamed":true,"genforp": [], + "itemsp": [ {"type":"CELL","name":"submod_2","addr":"(M)","loc":"d,29:25,29:33","origName":"submod_2","recursive":false,"modp":"(K)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []} ]}, {"type":"CELL","name":"submod_3","addr":"(N)","loc":"d,31:21,31:29","origName":"submod_3","recursive":false,"modp":"(K)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []} ]}, - {"type":"BEGIN","name":"FOR_GENERATE[1]","addr":"(O)","loc":"d,27:21,27:31","generate":true,"genfor":false,"implied":false,"needProcess":false,"unnamed":false,"genforp": [], - "stmtsp": [ + {"type":"GENBLOCK","name":"FOR_GENERATE[1]","addr":"(O)","loc":"d,27:21,27:31","implied":false,"unnamed":false,"genforp": [], + "itemsp": [ {"type":"CELL","name":"submod_for","addr":"(P)","loc":"d,27:21,27:31","origName":"submod_for","recursive":false,"modp":"(K)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []}, - {"type":"BEGIN","name":"genblk1","addr":"(Q)","loc":"d,28:19,28:24","generate":true,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], - "stmtsp": [ + {"type":"GENBLOCK","name":"genblk1","addr":"(Q)","loc":"d,28:19,28:24","implied":false,"unnamed":true,"genforp": [], + "itemsp": [ {"type":"CELL","name":"submod_2","addr":"(R)","loc":"d,29:25,29:33","origName":"submod_2","recursive":false,"modp":"(K)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []} ]}, {"type":"CELL","name":"submod_3","addr":"(S)","loc":"d,31:21,31:29","origName":"submod_3","recursive":false,"modp":"(K)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []} @@ -25,11 +25,11 @@ ]}, {"type":"MODULE","name":"submod","addr":"(K)","loc":"d,10:8,10:14","isChecker":false,"isProgram":false,"hasGenericIface":false,"origName":"submod","level":3,"modPublic":false,"inLibrary":false,"dead":false,"recursiveClone":false,"recursive":false,"timeunit":"1ps","inlinesp": [], "stmtsp": [ - {"type":"BEGIN","name":"submod_gen","addr":"(T)","loc":"d,12:19,12:29","generate":true,"genfor":false,"implied":false,"needProcess":false,"unnamed":false,"genforp": [], - "stmtsp": [ + {"type":"GENBLOCK","name":"submod_gen","addr":"(T)","loc":"d,12:19,12:29","implied":false,"unnamed":false,"genforp": [], + "itemsp": [ {"type":"VAR","name":"l1_sig","addr":"(U)","loc":"d,13:14,13:20","dtypep":"(V)","origName":"l1_sig","isSc":false,"isPrimaryIO":false,"isPrimaryClock":false,"direction":"NONE","isConst":false,"isPullup":false,"isPulldown":false,"isSigPublic":false,"isLatched":false,"isUsedLoopIdx":false,"noReset":false,"attrIsolateAssign":false,"attrFileDescr":false,"isDpiOpenArray":false,"isFuncReturn":false,"isFuncLocal":false,"lifetime":"VSTATICI","varType":"WIRE","dtypeName":"logic","isSigUserRdPublic":false,"isSigUserRWPublic":false,"isGParam":false,"isParam":false,"attrScBv":false,"attrSFormat":false,"ignorePostWrite":false,"ignoreSchedWrite":false,"sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}, - {"type":"BEGIN","name":"nested_gen","addr":"(W)","loc":"d,14:23,14:33","generate":true,"genfor":false,"implied":false,"needProcess":false,"unnamed":false,"genforp": [], - "stmtsp": [ + {"type":"GENBLOCK","name":"nested_gen","addr":"(W)","loc":"d,14:23,14:33","implied":false,"unnamed":false,"genforp": [], + "itemsp": [ {"type":"CELL","name":"submod_nested","addr":"(X)","loc":"d,15:21,15:34","origName":"submod_nested","recursive":false,"modp":"(Y)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []} ]}, {"type":"CELL","name":"submod_l1","addr":"(Z)","loc":"d,17:17,17:26","origName":"submod_l1","recursive":false,"modp":"(Y)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []} diff --git a/test_regress/t/t_json_only_tag.out b/test_regress/t/t_json_only_tag.out index a74077111..b73c21345 100644 --- a/test_regress/t/t_json_only_tag.out +++ b/test_regress/t/t_json_only_tag.out @@ -33,7 +33,7 @@ ],"scopeNamep": []}, {"type":"INITIAL","name":"","addr":"(FB)","loc":"d,39:4,39:11","isSuspendable":false,"needProcess":false, "stmtsp": [ - {"type":"BEGIN","name":"","addr":"(GB)","loc":"d,39:12,39:17","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], + {"type":"BEGIN","name":"","addr":"(GB)","loc":"d,39:12,39:17","implied":false,"needProcess":false,"unnamed":true, "stmtsp": [ {"type":"STMTEXPR","name":"","addr":"(HB)","loc":"d,41:7,41:8", "exprp": [ diff --git a/test_regress/t/t_xml_begin_hier.out b/test_regress/t/t_xml_begin_hier.out index 32276460d..efb01dd5f 100644 --- a/test_regress/t/t_xml_begin_hier.out +++ b/test_regress/t/t_xml_begin_hier.out @@ -47,30 +47,30 @@ - - + + - + - + - - + + - + - + - + - + - + - + - +