diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 7f2c31754..31ecce928 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -298,10 +298,10 @@ class AssertVisitor final : public VNVisitor { AstNode* const precondps = pExpr->precondp(); UASSERT_OBJ(precondps, pExpr, "Should have precondition"); precondps->unlinkFrBackWithNext()->addNext(ifp); - AstNodeStmt* const assertOnp - = newIfAssertOn(precondps, nodep->directive(), nodep->type()); - AstFork* const forkp = new AstFork{precondps->fileline(), "", assertOnp}; - forkp->joinType(VJoinType::JOIN_NONE); + AstNodeStmt* const aonp = newIfAssertOn(precondps, nodep->directive(), nodep->type()); + FileLine* const flp = precondps->fileline(); + AstFork* const forkp = new AstFork{flp, VJoinType::JOIN_NONE}; + forkp->addForksp(new AstBegin{flp, "", aonp, true}); return forkp; } diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp index d697767c5..1c7885a67 100644 --- a/src/V3AssertPre.cpp +++ b/src/V3AssertPre.cpp @@ -247,8 +247,8 @@ private: // Create a fork so that this AlwaysObserved can be retriggered before the // assignment happens. Also then it can be combo, avoiding the need for creating // new triggers. - AstFork* const forkp = new AstFork{flp, "", ifp}; - forkp->joinType(VJoinType::JOIN_NONE); + AstFork* const forkp = new AstFork{flp, VJoinType::JOIN_NONE}; + forkp->addForksp(new AstBegin{flp, "", ifp, true}); // Use Observed for this to make sure we do not miss the event m_clockingp->addNextHere(new AstAlwaysObserved{ flp, new AstSenTree{flp, m_clockingp->sensesp()->cloneTree(false)}, forkp}); diff --git a/src/V3AstAttr.h b/src/V3AstAttr.h index bd52bd825..0645f9892 100644 --- a/src/V3AstAttr.h +++ b/src/V3AstAttr.h @@ -1300,6 +1300,7 @@ public: : m_e{_e} {} explicit VJoinType(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning + constexpr operator en() const { return m_e; } const char* ascii() const { static const char* const names[] = {"JOIN", "JOIN_ANY", "JOIN_NONE"}; return names[m_e]; diff --git a/src/V3AstNodeStmt.h b/src/V3AstNodeStmt.h index 444a129d7..0825e6b27 100644 --- a/src/V3AstNodeStmt.h +++ b/src/V3AstNodeStmt.h @@ -69,17 +69,16 @@ public: }; class AstNodeBlock VL_NOT_FINAL : public AstNodeStmt { // A Begin/fork block - // @astgen op2 := stmtsp : List[AstNode] // Parents: statement + // @astgen op1 := declsp : List[AstNode] // Declarations inside block + // @astgen op2 := stmtsp : List[AstNode] // Sequential statements inside block string m_name; // Name of block bool m_unnamed; // Originally unnamed (name change does not affect this) protected: - AstNodeBlock(VNType t, FileLine* fl, const string& name, AstNode* stmtsp) + AstNodeBlock(VNType t, FileLine* fl, const string& name) : AstNodeStmt{t, fl} - , m_name{name} { - addStmtsp(stmtsp); - m_unnamed = (name == ""); - } + , m_name{name} + , m_unnamed{name == ""} {} public: ASTGEN_MEMBERS_AstNodeBlock; @@ -1351,17 +1350,16 @@ public: // === AstNodeBlock === class AstBegin final : public AstNodeBlock { - // A Begin/end named block, only exists shortly after parsing until linking - // Parents: statement - + // A 'begin'/'end' named block. 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 implied) - : ASTGEN_SUPER_Begin(fl, name, stmtsp) + : ASTGEN_SUPER_Begin(fl, name) , m_needProcess{false} - , m_implied{implied} {} + , m_implied{implied} { + addStmtsp(stmtsp); + } ASTGEN_MEMBERS_AstBegin; void dump(std::ostream& str) const override; void dumpJson(std::ostream& str) const override; @@ -1370,21 +1368,25 @@ public: bool implied() const { return m_implied; } }; class AstFork final : public AstNodeBlock { - // A fork named block - // @astgen op1 := initsp : List[AstNode] - // Parents: statement - // Children: statements - VJoinType m_joinType; // Join keyword type + // A 'fork'/'join*' named block. Note that this is a strict superset of + // AstBegin, and it does contain AstNodeBlock::stmtsp(), which are + // statements that execute sequentially before the parallel statements are + // spawned. This is necessary to implement things like local variable + // initializers properly. The parallel statements inside the fork must all + // be AstBegin, as lowering stages will introduce additional statements to + // be executed sequentially within eaach fork branch. + // + // @astgen op3 := forksp : List[AstBegin] + const VJoinType m_joinType; // Join keyword type public: - // Node that puts name into the output stream - AstFork(FileLine* fl, const string& name, AstNode* stmtsp) - : ASTGEN_SUPER_Fork(fl, name, stmtsp) {} + AstFork(FileLine* fl, VJoinType joinType, const string& name = "") + : ASTGEN_SUPER_Fork(fl, name) + , m_joinType{joinType} {} ASTGEN_MEMBERS_AstFork; bool isTimingControl() const override { return !joinType().joinNone(); } void dump(std::ostream& str) const override; void dumpJson(std::ostream& str) const override; VJoinType joinType() const { return m_joinType; } - void joinType(const VJoinType& flag) { m_joinType = flag; } }; // === AstNodeCoverOrAssert === diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index a23eb6c98..72b64604b 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -3039,7 +3039,7 @@ void AstCoverInc::dump(std::ostream& str) const { void AstCoverInc::dumpJson(std::ostream& str) const { dumpJsonGen(str); } void AstFork::dump(std::ostream& str) const { this->AstNodeBlock::dump(str); - if (!joinType().join()) str << " [" << joinType() << "]"; + str << " [" << joinType() << "]"; } void AstFork::dumpJson(std::ostream& str) const { dumpJsonStr(str, "joinType", joinType().ascii()); diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index 998be7a21..cfa58e3ed 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -80,32 +80,28 @@ class BeginVisitor final : public VNVisitor { string dot(const string& a, const string& b) { return VString::dot(a, "__DOT__", b); } - void dotNames(const std::string& name, FileLine* const flp, AstNode* stmtsp, - const char* const blockName) { + void dotNames(const std::string& name, FileLine* const flp, const char* const blockName) { UINFO(8, "nname " << m_namedScope); - if (name != "") { // Else unneeded unnamed block - // Create data for dotted variable resolution - 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 (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{flp, m_unnamedScope, blockName}; - m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells - } + // If unneeded unnamed block, whatever that means :) + if (name == "") return; + + // Create data for dotted variable resolution + std::string dottedname = name + "__DOT__"; // So always found + std::string::size_type pos; + while ((pos = dottedname.find("__DOT__")) != std::string::npos) { + const std::string ident = dottedname.substr(0, pos); + dottedname = dottedname.substr(pos + std::strlen("__DOT__")); + 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{flp, m_unnamedScope, blockName}; + m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells } } - - // Remap var names and replace lower Begins - iterateAndNextNull(stmtsp); } void liftNode(AstNode* nodep) { @@ -125,21 +121,14 @@ class BeginVisitor final : public VNVisitor { // VISITORS void visit(AstFork* nodep) override { - // Keep begins in forks to group their statements together - VL_RESTORER(m_keepBegins); - m_keepBegins = true; - // If a statement is not a begin, wrap it in a begin. This fixes an issue when the - // statement is a task call that gets inlined later (or any other statement that gets - // 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}; - stmtp->replaceWith(beginp); - beginp->addStmtsp(stmtp); - stmtp = beginp; - } + dotNames(nodep->name(), nodep->fileline(), "__FORK__"); + iterateAndNextNull(nodep->stmtsp()); + { + // Keep begins in forks to group their statements together + VL_RESTORER(m_keepBegins); + m_keepBegins = true; + iterateAndNextNull(nodep->forksp()); } - dotNames(nodep->name(), nodep->fileline(), nodep->stmtsp(), "__FORK__"); nodep->name(""); } void visit(AstForeach* nodep) override { @@ -215,7 +204,8 @@ class BeginVisitor final : public VNVisitor { 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__"); + dotNames(nodep->name(), nodep->fileline(), "__BEGIN__"); + iterateAndNextNull(nodep->itemsp()); // Repalce node with body then delete if (AstNode* const itemsp = nodep->itemsp()) { nodep->addNextHere(itemsp->unlinkFrBackWithNext()); @@ -231,7 +221,8 @@ class BeginVisitor final : public VNVisitor { { VL_RESTORER(m_keepBegins); m_keepBegins = false; - dotNames(nodep->name(), nodep->fileline(), nodep->stmtsp(), "__BEGIN__"); + dotNames(nodep->name(), nodep->fileline(), "__BEGIN__"); + iterateChildren(nodep); } // Cleanup @@ -240,6 +231,10 @@ class BeginVisitor final : public VNVisitor { return; } AstNode* addsp = nullptr; + if (AstNode* const declsp = nodep->declsp()) { + declsp->unlinkFrBackWithNext(); + addsp = AstNode::addNext(addsp, declsp); + } if (AstNode* const stmtsp = nodep->stmtsp()) { stmtsp->unlinkFrBackWithNext(); addsp = AstNode::addNext(addsp, stmtsp); diff --git a/src/V3Fork.cpp b/src/V3Fork.cpp index 9e6135690..30698b340 100644 --- a/src/V3Fork.cpp +++ b/src/V3Fork.cpp @@ -137,8 +137,8 @@ public: UASSERT_OBJ(m_instance.initialized(), m_procp, "No dynamic scope prototype"); UASSERT_OBJ(!linked(), m_instance.m_handlep, "Handle already linked"); - if (VN_IS(m_procp, Fork)) { - linkNodesOfFork(memberMap); + if (AstFork* const forkp = VN_CAST(m_procp, Fork)) { + linkNodesOfFork(memberMap, forkp); return; } @@ -221,32 +221,20 @@ private: new AstVarRef{m_procp->fileline(), m_instance.m_handlep, VAccess::WRITE}, newp}; } - void linkNodesOfFork(VMemberMap& memberMap) { - // Special case - - AstFork* const forkp = VN_AS(m_procp, Fork); - VNRelinker forkHandle; - forkp->unlinkFrBack(&forkHandle); - - AstBegin* const beginp = new AstBegin{ - forkp->fileline(), - "_Vwrapped_" + (forkp->name().empty() ? "" : forkp->name() + "_") + cvtToStr(m_id), - m_instance.m_handlep, true}; - forkHandle.relink(beginp); - - AstNode* const instAsgnp = instantiateDynScope(memberMap); - - beginp->stmtsp()->addNext(instAsgnp); - beginp->stmtsp()->addNext(forkp); - - if (forkp->initsp()) { - forkp->initsp()->foreach([forkp](AstAssign* asgnp) { - asgnp->unlinkFrBack(); - forkp->addHereThisAsNext(asgnp); - }); - } - UASSERT_OBJ(!forkp->initsp(), forkp, "Leftover nodes in block_item_declaration"); - + // Wrap Fork in Begin + void linkNodesOfFork(VMemberMap& memberMap, AstFork* forkp) { + // Replace the Fork with a Begin + const std::string name = "_Vwrapped_" // + + (forkp->name().empty() ? "" : forkp->name() + "_") // + + std::to_string(m_id); + AstBegin* const beginp = new AstBegin{forkp->fileline(), name, m_instance.m_handlep, true}; + forkp->replaceWith(beginp); + // Create the dynamic scope in the Begin + beginp->addStmtsp(instantiateDynScope(memberMap)); + // Move all sequential statements there + if (forkp->stmtsp()) beginp->addStmtsp(forkp->stmtsp()->unlinkFrBackWithNext()); + // Put the Fork back at the end of the Begin + beginp->addStmtsp(forkp); m_modp->addStmtsp(m_instance.m_classp); } @@ -386,25 +374,24 @@ class DynScopeVisitor final : public VNVisitor { const bool oldAfterTimingControl = m_afterTimingControl; ForkDynScopeFrame* framep = nullptr; - if (nodep->initsp()) framep = pushDynScopeFrame(nodep); + if (nodep->declsp() || nodep->stmtsp()) framep = pushDynScopeFrame(nodep); - for (AstNode* stmtp = nodep->initsp(); stmtp; stmtp = stmtp->nextp()) { - if (AstVar* const varp = VN_CAST(stmtp, Var)) { - // This can be probably optimized to detect cases in which dynscopes - // could be avoided - if (!framep->instance().initialized()) framep->createInstancePrototype(); - framep->captureVarInsert(varp); - bindNodeToDynScope(varp, framep); - } else { - AstAssign* const asgnp = VN_CAST(stmtp, Assign); - UASSERT_OBJ(asgnp, stmtp, - "Invalid node under block item initialization part of fork"); - bindNodeToDynScope(asgnp->lhsp(), framep); - iterate(asgnp->rhsp()); - } + // This can be probably optimized to detect cases in which dynscopes could be avoided + for (AstNode* declp = nodep->declsp(); declp; declp = declp->nextp()) { + AstVar* const varp = VN_CAST(declp, Var); + UASSERT_OBJ(varp, declp, "Invalid node under block item initialization part of fork"); + if (!framep->instance().initialized()) framep->createInstancePrototype(); + framep->captureVarInsert(varp); + bindNodeToDynScope(varp, framep); + } + for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { + AstAssign* const asgnp = VN_CAST(stmtp, Assign); + UASSERT_OBJ(asgnp, stmtp, "Invalid node under block item initialization part of fork"); + bindNodeToDynScope(asgnp->lhsp(), framep); + iterate(asgnp->rhsp()); } - for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { + for (AstNode* stmtp = nodep->forksp(); stmtp; stmtp = stmtp->nextp()) { m_afterTimingControl = false; iterate(stmtp); } @@ -470,11 +457,10 @@ 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}; - AstFork* const forkp = new AstFork{nodep->fileline(), "", beginp}; - forkp->joinType(VJoinType::JOIN_NONE); + FileLine* const flp = nodep->fileline(); + AstFork* const forkp = new AstFork{flp, VJoinType::JOIN_NONE}; nodep->replaceWith(forkp); - beginp->addStmtsp(nodep); + forkp->addForksp(new AstBegin{flp, "", nodep, false}); UINFO(9, "assign new fork " << forkp); } else { visit(static_cast(nodep)); @@ -559,7 +545,9 @@ class ForkVisitor final : public VNVisitor { return varp; } - AstNodeStmt* taskify(AstNode* stmtp) { + // Wrap body of the given Begin (an AstFork branch), in an AstTask, and + // replace body with a call to that task. Returns true iff wrapped. + bool taskify(AstBegin* beginp) { // Visit statement to gather variables (And recursively process) VL_RESTORER(m_forkLocalsp); VL_RESTORER(m_capturedVarsp); @@ -567,33 +555,26 @@ class ForkVisitor final : public VNVisitor { m_forkLocalsp.clear(); m_capturedVarsp = nullptr; m_capturedArgsp = nullptr; - iterate(stmtp); + iterate(beginp); // No need to do it if no variabels are captured - if (m_forkLocalsp.empty() && !m_capturedVarsp && !v3Global.opt.fTaskifyAll()) { - return nullptr; - } + if (m_forkLocalsp.empty() && !m_capturedVarsp && !v3Global.opt.fTaskifyAll()) return false; // Create task holding the statement and repalce statement with call to that task - FileLine* const flp = stmtp->fileline(); + FileLine* const flp = beginp->fileline(); const std::string name = "__VforkTask_" + std::to_string(m_nForkTasks++); AstTask* const taskp = new AstTask{flp, name, m_capturedVarsp}; m_tasksp = AstNode::addNext(m_tasksp, taskp); + if (beginp->declsp()) taskp->addStmtsp(beginp->declsp()->unlinkFrBackWithNext()); + if (beginp->stmtsp()) taskp->addStmtsp(beginp->stmtsp()->unlinkFrBackWithNext()); AstTaskRef* const callp = new AstTaskRef{flp, taskp, m_capturedArgsp}; - AstNodeStmt* const replacementp = callp->makeStmt(); - stmtp->replaceWith(replacementp); - if (AstBegin* const beginp = VN_CAST(stmtp, Begin)) { - taskp->addStmtsp(beginp->stmtsp()->unlinkFrBackWithNext()); - VL_DO_DANGLING(pushDeletep(beginp), beginp); - } else { - taskp->addStmtsp(stmtp); - } + beginp->addStmtsp(callp->makeStmt()); // Variables were moved under the task, so make sure they are marked as funcLocal for (AstVar* const localp : m_forkLocalsp) localp->funcLocal(true); - // Return the replacement - return replacementp; + // We did wrap the body + return true; } // VISITORS @@ -615,21 +596,18 @@ class ForkVisitor final : public VNVisitor { return; } - iterateAndNextNull(nodep->initsp()); - std::vector newps; + iterateAndNextNull(nodep->declsp()); + iterateAndNextNull(nodep->stmtsp()); + std::vector wrappedp; { VL_RESTORER(m_inFork); m_inFork = true; - for (AstNode *itemp = nodep->stmtsp(), *nextp; itemp; itemp = nextp) { - nextp = itemp->nextp(); - AstNodeStmt* const stmtp = VN_CAST(itemp, NodeStmt); - if (!stmtp) continue; - AstNodeStmt* const newp = taskify(stmtp); - if (newp) newps.push_back(newp); + for (AstBegin* itemp = nodep->forksp(); itemp; itemp = VN_AS(itemp->nextp(), Begin)) { + if (taskify(itemp)) wrappedp.push_back(itemp); } } // Analyze replacements in context of enclosing fork - for (AstNodeStmt* const stmtp : newps) iterate(stmtp); + for (AstBegin* const beginp : wrappedp) iterateAndNextNull(beginp); } void visit(AstVar* nodep) override { if (m_inFork) m_forkLocalsp.insert(nodep); diff --git a/src/V3Hasher.cpp b/src/V3Hasher.cpp index f16fc21c0..14438c196 100644 --- a/src/V3Hasher.cpp +++ b/src/V3Hasher.cpp @@ -519,11 +519,17 @@ class HasherVisitor final : public VNVisitorConst { void visit(AstNodeProcedure* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, []() {}); } - void visit(AstNodeBlock* nodep) override { - m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [this, nodep]() { // + void visit(AstBegin* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [this, nodep]() { // m_hash += nodep->name(); }); } + void visit(AstFork* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [this, nodep]() { // + m_hash += nodep->name(); + m_hash += nodep->joinType(); + }); + } void visit(AstPin* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [this, nodep]() { m_hash += nodep->name(); diff --git a/src/V3InstrCount.cpp b/src/V3InstrCount.cpp index 653db37e2..1e099fb10 100644 --- a/src/V3InstrCount.cpp +++ b/src/V3InstrCount.cpp @@ -224,9 +224,10 @@ private: void visit(AstFork* nodep) override { if (m_ignoreRemaining) return; const VisitBase vb{this, nodep}; + iterateAndNextConstNull(nodep->stmtsp()); uint32_t totalCount = m_instrCount; // Sum counts in each statement until the first await - for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { + for (AstNode* stmtp = nodep->forksp(); stmtp; stmtp = stmtp->nextp()) { reset(); iterateConst(stmtp); totalCount += m_instrCount; diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 56a2d23bd..1118e4a39 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1258,20 +1258,26 @@ class LinkDotFindVisitor final : public VNVisitor { // unnamed#'s would just confuse tracing variables in // places such as tasks, where "task ...; begin ... end" // are common. - for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { - if (VN_IS(stmtp, Var) || VN_IS(stmtp, 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; + const auto containsDecl = [](const AstNode* nodesp) -> bool { + for (const AstNode* np = nodesp; np; np = np->nextp()) { + if (VN_IS(np, Var) || VN_IS(np, Foreach)) return true; } + return false; + }; + bool needName = nodep->declsp() || containsDecl(nodep->stmtsp()); + if (const AstFork* const forkp = VN_CAST(nodep, Fork)) { + needName = needName || containsDecl(forkp->forksp()); + } + if (needName) { + const std::string stepStr + = m_statep->forPrimary() ? "" : std::to_string(m_statep->stepNumber()) + "_"; + std::string name; + 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); } } if (nodep->name() == "") { diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp index ee831dc3a..952d772ca 100644 --- a/src/V3LinkJump.cpp +++ b/src/V3LinkJump.cpp @@ -48,7 +48,7 @@ class LinkJumpVisitor final : public VNVisitor { // AstBegin/etc::user1() -> AstJumpBlock*, for body of this loop // AstFinish::user1() -> bool, processed // AstNode::user2() -> AstJumpBlock*, for this block - // AstNodeBlock::user3() -> bool, true if contains a fork + // AstNodeBegin::user3() -> bool, true if contains a fork const VNUser1InUse m_user1InUse; const VNUser2InUse m_user2InUse; const VNUser3InUse m_user3InUse; @@ -80,9 +80,11 @@ class LinkJumpVisitor final : public VNVisitor { AstNode* underp = nullptr; bool under_and_next = true; - if (AstNodeBlock* const blockp = VN_CAST(nodep, NodeBlock)) { + if (AstBegin* const blockp = VN_CAST(nodep, Begin)) { + UASSERT_OBJ(!endOfIter, nodep, "No endOfIter for Begin"); underp = blockp->stmtsp(); } else if (AstNodeFTask* const fTaskp = VN_CAST(nodep, NodeFTask)) { + UASSERT_OBJ(!endOfIter, nodep, "No endOfIter for FTask"); underp = fTaskp->stmtsp(); } else if (AstForeach* const foreachp = VN_CAST(nodep, Foreach)) { if (endOfIter) { @@ -180,10 +182,10 @@ class LinkJumpVisitor final : public VNVisitor { // handle is pushed to the queue. `disable` statement is replaced with calling `kill()` // method on each element of the queue. FileLine* const fl = nodep->fileline(); - const std::string targetName = nodep->targetp()->name(); + AstNode* const targetp = nodep->targetp(); if (m_ftaskp) { - if (!m_ftaskp->exists([targetp = nodep->targetp()](const AstNodeBlock* blockp) - -> bool { return blockp == targetp; })) { + if (!m_ftaskp->exists( + [targetp](const AstNodeBlock* blockp) -> bool { return blockp == targetp; })) { // Disabling a fork, which is within the same task, is not a problem nodep->v3warn(E_UNSUPPORTED, "Unsupported: disabling fork from task / function"); } @@ -193,7 +195,7 @@ class LinkJumpVisitor final : public VNVisitor { = VN_AS(getMemberp(v3Global.rootp()->stdPackagep(), "process"), Class); // Declare queue of processes (as a global variable for simplicity) AstVar* const processQueuep = new AstVar{ - fl, VVarType::VAR, m_queueNames.get(targetName), VFlagChildDType{}, + fl, VVarType::VAR, m_queueNames.get(targetp->name()), VFlagChildDType{}, new AstQueueDType{fl, VFlagChildDType{}, new AstClassRefDType{fl, processClassp, nullptr}, nullptr}}; processQueuep->lifetime(VLifetime::STATIC_EXPLICIT); @@ -219,12 +221,21 @@ class LinkJumpVisitor final : public VNVisitor { killQueueCall->classOrPackagep(processClassp); AstStmtExpr* const killStmtp = new AstStmtExpr{fl, killQueueCall}; nodep->addNextHere(killStmtp); - if (existsBlockAbove(targetName)) { - // process::kill doesn't kill the current process immediately, because it is in the - // running state. Since the current process has to be terminated immediately, we jump - // at the end of the fork that is being disabled - AstJumpBlock* const jumpBlockp = getJumpBlock(nodep->targetp(), false); - killStmtp->addNextHere(new AstJumpGo{fl, jumpBlockp}); + + // 'process::kill' does not immediately kill the current process + // executing the disable statement (because it's in the running state). + // If the disable statement is indeed executed by a process under the + // target AstFork, then jump to the end of that fork branch. + if (VN_IS(targetp, Fork)) { + AstNodeBlock* forkBranchp = nullptr; + for (AstNodeBlock* const blockp : vlstd::reverse_view(m_blockStack)) { + if (blockp == targetp) { + AstJumpBlock* const jmpBlockp = getJumpBlock(VN_AS(forkBranchp, Begin), false); + killStmtp->addNextHere(new AstJumpGo{fl, jmpBlockp}); + break; + } + forkBranchp = blockp; + } } } static bool directlyUnderFork(const AstNode* const nodep) { @@ -247,24 +258,24 @@ class LinkJumpVisitor final : public VNVisitor { m_ftaskp = nodep; iterateChildren(nodep); } - void visit(AstNodeBlock* nodep) override { + void visit(AstBegin* nodep) override { UINFO(8, " " << nodep); - VL_RESTORER(m_inFork); VL_RESTORER(m_unrollFull); m_blockStack.push_back(nodep); - { - if (VN_IS(nodep, Fork)) { - m_inFork = true; // And remains set for children - // Mark all upper blocks also, can stop once see - // one set to avoid O(n^2) - for (auto itr : vlstd::reverse_view(m_blockStack)) { - if (itr->user3()) break; - itr->user3(true); - } - } - nodep->user3(m_inFork); - iterateChildren(nodep); + iterateChildren(nodep); + m_blockStack.pop_back(); + } + void visit(AstFork* nodep) override { + UINFO(8, " " << nodep); + VL_RESTORER(m_unrollFull); + VL_RESTORER(m_inFork); + m_inFork = true; + // Mark all upper blocks, can stop once see one set to avoid O(n^2) + for (AstNodeBlock* const blockp : vlstd::reverse_view(m_blockStack)) { + if (blockp->user3SetOnce()) break; } + m_blockStack.push_back(nodep); + iterateChildren(nodep); m_blockStack.pop_back(); } void visit(AstStmtPragma* nodep) override { @@ -392,43 +403,32 @@ class LinkJumpVisitor final : public VNVisitor { void visit(AstDisable* nodep) override { UINFO(8, " DISABLE " << nodep); AstNode* const targetp = nodep->targetp(); - FileLine* const fl = nodep->fileline(); UASSERT_OBJ(targetp, nodep, "Unlinked disable statement"); if (VN_IS(targetp, Task)) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: disabling task by name"); } else if (AstFork* const forkp = VN_CAST(targetp, Fork)) { std::vector forks; - for (AstNode* forkItemp = forkp->stmtsp(); forkItemp; forkItemp = forkItemp->nextp()) { - // 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}; - forkItemp->replaceWith(beginp); - beginp->addStmtsp(forkItemp); - // In order to continue the iteration - forkItemp = beginp; - } - forks.push_back(beginp); + for (AstBegin* itemp = forkp->forksp(); itemp; itemp = VN_AS(itemp->nextp(), Begin)) { + forks.push_back(itemp); } handleDisableOnFork(nodep, forks); } else if (AstBegin* const beginp = VN_CAST(targetp, Begin)) { - if (directlyUnderFork(beginp)) { - std::vector forks{beginp}; - handleDisableOnFork(nodep, forks); + if (existsBlockAbove(beginp->name())) { + if (beginp->user3()) { + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: disabling block that contains a fork"); + } else { + // Jump to the end of the named block + AstJumpBlock* const blockp = getJumpBlock(beginp, false); + nodep->addNextHere(new AstJumpGo{nodep->fileline(), blockp}); + } } else { - const std::string targetName = beginp->name(); - if (existsBlockAbove(targetName)) { - if (beginp->user3()) { - nodep->v3warn(E_UNSUPPORTED, - "Unsupported: disabling block that contains a fork"); - } else { - // Jump to the end of the named block - AstJumpBlock* const blockp = getJumpBlock(beginp, false); - nodep->addNextHere(new AstJumpGo{nodep->fileline(), blockp}); - } + if (directlyUnderFork(beginp)) { + std::vector forks{beginp}; + handleDisableOnFork(nodep, forks); } else { nodep->v3warn(E_UNSUPPORTED, "disable isn't underneath a begin with name: '" - << targetName << "'"); + << beginp->name() << "'"); } } } else { diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 8a5036b72..fba477e6a 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -55,6 +55,7 @@ class LinkParseVisitor final : public VNVisitor { AstNodeModule* m_modp = nullptr; // Current module AstNodeProcedure* m_procedurep = nullptr; // Current procedure AstNodeFTask* m_ftaskp = nullptr; // Current task + AstNodeBlock* m_blockp = nullptr; // Current AstNodeBlock AstNodeDType* m_dtypep = nullptr; // Current data type AstNodeExpr* m_defaultInSkewp = nullptr; // Current default input skew AstNodeExpr* m_defaultOutSkewp = nullptr; // Current default output skew @@ -377,20 +378,27 @@ class LinkParseVisitor final : public VNVisitor { if (m_procedurep && VN_IS(m_procedurep, Always)) nodep->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); if (nodep->valuep()) { - // A variable with an = value can be three things: FileLine* const fl = nodep->valuep()->fileline(); + // A variable with an = value can be 4 things: if (nodep->isParam() || (m_ftaskp && nodep->isNonOutput())) { // 1. Parameters and function inputs: It's a default to use if not overridden } else if (!m_ftaskp && !VN_IS(m_modp, Class) && nodep->isNonOutput() && !nodep->isInput()) { - // Module inout/ref/constref: const default to use + // 2. Module inout/ref/constref: const default to use nodep->v3warn(E_UNSUPPORTED, "Unsupported: Default value on module inout/ref/constref: " << nodep->prettyNameQ()); nodep->valuep()->unlinkFrBack()->deleteTree(); - } // 2. Under modules/class, it's an initial value to be loaded at time 0 via an - // AstInitial - else if (m_valueModp) { + } else if (m_blockp) { + // 3. Under blocks, it's an initial value to be under an assign + // TODO: This is wrong if it's a static variable right? + FileLine* const newfl = new FileLine{fl}; + newfl->warnOff(V3ErrorCode::E_CONSTWRITTEN, true); + m_blockp->addStmtsp( + new AstAssign{newfl, new AstVarRef{newfl, nodep, VAccess::WRITE}, + VN_AS(nodep->valuep()->unlinkFrBack(), NodeExpr)}); + } else if (m_valueModp) { + // 4. Under modules/class, it's the time 0 initialziation value // Making an AstAssign (vs AstAssignW) to a wire is an error, suppress it FileLine* const newfl = new FileLine{fl}; newfl->warnOff(V3ErrorCode::PROCASSWIRE, true); @@ -405,13 +413,8 @@ class LinkParseVisitor final : public VNVisitor { } else { nodep->addNextHere(new AstInitialStatic{newfl, assp}); } - } // 4. Under blocks, it's an initial value to be under an assign - else { - FileLine* const newfl = new FileLine{fl}; - newfl->warnOff(V3ErrorCode::E_CONSTWRITTEN, true); - nodep->addNextHere( - new AstAssign{newfl, new AstVarRef{newfl, nodep, VAccess::WRITE}, - VN_AS(nodep->valuep()->unlinkFrBack(), NodeExpr)}); + } else { + nodep->v3fatalSrc("Variable with initializer in unexpected position"); } } } @@ -762,10 +765,23 @@ class LinkParseVisitor final : public VNVisitor { } iterateChildren(nodep); } - void visit(AstBegin* nodep) override { - V3Control::applyCoverageBlock(m_modp, nodep); + void visit(AstNodeBlock* nodep) override { + { + VL_RESTORER(m_blockp); + m_blockp = nodep; + // Temporarily unlink the statements so variable initializers can be inserted in order + AstNode* const stmtsp = nodep->stmtsp(); + if (stmtsp) stmtsp->unlinkFrBackWithNext(); + iterateAndNextNull(nodep->declsp()); + nodep->addStmtsp(stmtsp); + } + + if (AstBegin* const beginp = VN_CAST(nodep, Begin)) { + V3Control::applyCoverageBlock(m_modp, beginp); + } cleanFileline(nodep); - iterateChildren(nodep); + iterateAndNextNull(nodep->stmtsp()); + if (AstFork* const forkp = VN_CAST(nodep, Fork)) iterateAndNextNull(forkp->forksp()); } void visit(AstCase* nodep) override { V3Control::applyCase(nodep); diff --git a/src/V3ParseGrammar.h b/src/V3ParseGrammar.h index 9c9fbd302..29d660154 100644 --- a/src/V3ParseGrammar.h +++ b/src/V3ParseGrammar.h @@ -304,16 +304,6 @@ public: return m_scopedSigAttr ? m_scopedSigAttr->cloneTree(true) : nullptr; } - static void addForkStmtsp(AstFork* forkp, AstNode* stmtsp) { - forkp->addStmtsp(stmtsp); - for (AstNode* stmtp = stmtsp; stmtp; stmtp = stmtp->nextp()) { - AstVar* const varp = VN_CAST(stmtp, Var); - if (!varp) break; - varp->unlinkFrBack(); - forkp->addInitsp(varp); - } - } - void createGenericIface(AstNode* const nodep, AstNodeRange* const rangep, AstNode* sigAttrListp, FileLine* const modportFileline = nullptr, const string& modportstrp = "") { @@ -334,4 +324,17 @@ public: createVariable(nodep->fileline(), nodep->name(), rangep, sigAttrListp)); m_varDecl = VVarType::VAR; } + + // Wrap all statements in the given list in an AstBegin (except those already an AstBegin) + static AstBegin* wrapInBegin(AstNodeStmt* stmtsp) { + AstBegin* resp = nullptr; + for (AstNodeStmt *nodep = stmtsp, *nextp; nodep; nodep = nextp) { + nextp = VN_AS(nodep->nextp(), NodeStmt); + if (nextp) nextp->unlinkFrBackWithNext(); + AstBegin* beginp = VN_CAST(nodep, Begin); + if (!beginp) beginp = new AstBegin{nodep->fileline(), "", nodep, true}; + resp = AstNode::addNext(resp, beginp); + } + return resp; + } }; diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp index 2d2694c9c..c6b2aaf64 100644 --- a/src/V3SchedTiming.cpp +++ b/src/V3SchedTiming.cpp @@ -360,8 +360,8 @@ void transformForks(AstNetlist* const netlistp) { // Replace self with the function calls (no co_await, as we don't want the main // process to suspend whenever any of the children do) // V3Dead could have removed all statements from the fork, so guard against it - AstNode* const stmtsp = nodep->stmtsp(); - if (stmtsp) nodep->addNextHere(stmtsp->unlinkFrBackWithNext()); + if (nodep->forksp()) nodep->addNextHere(nodep->forksp()->unlinkFrBackWithNext()); + if (nodep->stmtsp()) nodep->addNextHere(nodep->stmtsp()->unlinkFrBackWithNext()); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } void visit(AstBegin* nodep) override { diff --git a/src/V3StackCount.cpp b/src/V3StackCount.cpp index 8dc28c114..078e5b35b 100644 --- a/src/V3StackCount.cpp +++ b/src/V3StackCount.cpp @@ -142,10 +142,11 @@ private: void visit(AstFork* nodep) override { if (m_ignoreRemaining) return; const VisitBase vb{this, nodep}; + iterateAndNextConstNull(nodep->stmtsp()); uint32_t totalCount = m_stackSize; VL_RESTORER(m_ignoreRemaining); // Sum counts in each statement - for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { + for (AstNode* stmtp = nodep->forksp(); stmtp; stmtp = stmtp->nextp()) { reset(); iterateConst(stmtp); totalCount += m_stackSize; diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index a7fc4da51..095e60d78 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -731,7 +731,7 @@ class TimingControlVisitor final : public VNVisitor { = createTemp(flp, forkp->name() + "__sync", getCreateForkSyncDTypep(), insertBeforep); unsigned joinCount = 0; // Needed for join counter // Add a .done() to each begin - for (AstNode* beginp = forkp->stmtsp(); beginp; beginp = beginp->nextp()) { + for (AstNode* beginp = forkp->forksp(); beginp; beginp = beginp->nextp()) { addForkDone(VN_AS(beginp, Begin), forkVscp); joinCount++; } @@ -1025,10 +1025,7 @@ class TimingControlVisitor final : public VNVisitor { // Put it in a fork so it doesn't block // Could already be the only thing directly under a fork, reuse that if possible AstFork* forkp = !nodep->nextp() ? VN_CAST(nodep->firstAbovep(), Fork) : nullptr; - if (!forkp) { - forkp = new AstFork{flp, "", nullptr}; - forkp->joinType(VJoinType::JOIN_NONE); - } + if (!forkp) forkp = new AstFork{flp, VJoinType::JOIN_NONE}; if (!m_underProcedure) { // If it's in a function, it won't be handled by V3Delayed // Put it behind an additional named event that gets triggered in the NBA region @@ -1043,7 +1040,7 @@ class TimingControlVisitor final : public VNVisitor { controlp->replaceWith(forkp); AstBegin* beginp = VN_CAST(controlp, Begin); if (!beginp) beginp = new AstBegin{nodep->fileline(), "", controlp, false}; - forkp->addStmtsp(beginp); + forkp->addForksp(beginp); controlp = forkp; } UASSERT_OBJ(nodep, controlp, "Assignment should have timing control"); @@ -1115,11 +1112,11 @@ class TimingControlVisitor final : public VNVisitor { AstNode* const controlp = nodep->timingControlp()->unlinkFrBack(); AstAssign* const assignp = new AstAssign{nodep->fileline(), lhs1p, rhs1p, controlp}; // Put the assignment in a fork..join_none. - AstBegin* const beginp = new AstBegin{flp, "", assignp, false}; - AstFork* const forkp = new AstFork{flp, "", beginp}; - forkp->joinType(VJoinType::JOIN_NONE); + AstFork* const forkp = new AstFork{flp, VJoinType::JOIN_NONE}; nodep->replaceWith(forkp); VL_DO_DANGLING(pushDeletep(nodep), nodep); + AstBegin* const beginp = new AstBegin{flp, "", assignp, false}; + forkp->addForksp(beginp); visit(forkp); // Visit now as we need to do some post-processing // IEEE 1800-2023 10.3.3 - if the RHS value differs from the currently scheduled value to // be assigned, the currently scheduled assignment is descheduled. To keep track if an @@ -1239,21 +1236,23 @@ class TimingControlVisitor final : public VNVisitor { void visit(AstFork* nodep) override { if (nodep->user1SetOnce()) return; v3Global.setUsesTiming(); + // Create a unique name for this fork - nodep->name("__Vfork_" + cvtToStr(++m_forkCnt)); - unsigned idx = 0; // Index for naming begins - AstNode* stmtp = nodep->stmtsp(); - // Put each statement in a begin - while (stmtp) { - UASSERT_OBJ(VN_IS(stmtp, Begin), nodep, - "All statements under forks must be begins at this point"); - AstBegin* const beginp = VN_AS(stmtp, Begin); - stmtp = beginp->nextp(); - iterate(beginp); - // Even if we do not find any awaits, we cannot simply inline the process here, as new - // awaits could be added later. + nodep->name("__Vfork_" + std::to_string(++m_forkCnt)); + + // TODO: Should process nodep->stmtsp() in case an earlier pass + // inserted something there, but as of today we don't need to. + + // Process and name each fork + size_t idx = 0; // Index for naming begins + for (AstBegin *itemp = nodep->forksp(), *nextp; itemp; itemp = nextp) { + nextp = VN_AS(itemp->nextp(), Begin); + iterate(itemp); + // Note: Even if we do not find any awaits, we cannot simply inline + // the process here, as new awaits could be added later. + // Name the begin (later the name will be used for a new function) - beginp->name(nodep->name() + "__" + cvtToStr(idx++)); + itemp->name(nodep->name() + "__" + std::to_string(idx++)); } if (!nodep->joinType().joinNone()) makeForkJoin(nodep); } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index a14775b4e..7934af6b5 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -741,16 +741,17 @@ class WidthVisitor final : public VNVisitor { } if (!nodep->fileline()->timingOn() // With no statements, begin is identical - || !nodep->stmtsp() + || !nodep->forksp() || (!v3Global.opt.timing().isSetTrue() // If no --timing && (v3Global.opt.bboxUnsup() // With one statement and no timing, a begin block does as good as a // fork/join or join_any - || (!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}; + || (!nodep->forksp()->nextp() && !nodep->joinType().joinNone())))) { + AstBegin* const newp = new AstBegin{nodep->fileline(), nodep->name(), nullptr, false}; nodep->replaceWith(newp); + if (nodep->declsp()) newp->addDeclsp(nodep->declsp()->unlinkFrBackWithNext()); + if (nodep->stmtsp()) newp->addStmtsp(nodep->stmtsp()->unlinkFrBackWithNext()); + if (nodep->forksp()) newp->addStmtsp(nodep->forksp()->unlinkFrBackWithNext()); VL_DO_DANGLING(nodep->deleteTree(), nodep); } else if (v3Global.opt.timing().isSetTrue()) { VL_RESTORER(m_underFork); diff --git a/src/verilog.y b/src/verilog.y index d6fdc251e..45ba222bd 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -3360,15 +3360,23 @@ senitemEdge: // IEEE: part of event_expression seq_block: // ==IEEE: seq_block // // IEEE doesn't allow declarations in unnamed blocks, but several simulators do. // // So need AstBegin's even if unnamed to scope variables down - seq_blockFront blockDeclStmtListE yEND endLabelE - { $$ = $1; $1->addStmtsp($2); - GRAMMARP->endLabel($4, $1, $4); } + yBEGIN startLabelE blockDeclListE stmtListE yEND endLabelE + { + $$ = new AstBegin{$1, $2 ? *$2 : "", nullptr, false}; + GRAMMARP->endLabel($6, $$, $6); + $$->addDeclsp($3); + $$->addStmtsp($4); + } ; seq_blockPreId: // IEEE: seq_block, but called with leading ID - seq_blockFrontPreId blockDeclStmtListE yEND endLabelE - { $$ = $1; $1->addStmtsp($2); - GRAMMARP->endLabel($4, $1, $4); } + id yP_COLON__BEGIN yBEGIN blockDeclListE stmtListE yEND endLabelE + { + $$ = new AstBegin{$3, *$1, nullptr, false}; + GRAMMARP->endLabel($7, $$, $7); + $$->addDeclsp($4); + $$->addStmtsp($5); + } ; par_blockJoin: @@ -3378,61 +3386,28 @@ par_blockJoin: ; par_block: // ==IEEE: par_block - par_blockFront blockDeclStmtListE par_blockJoin endLabelE - { $$ = $1; $1->joinType($3); - V3ParseGrammar::addForkStmtsp($1, $2); - GRAMMARP->endLabel($4, $1, $4); } + yFORK startLabelE blockDeclListE stmtListE par_blockJoin endLabelE + { + $$ = new AstFork{$1, $5, $2 ? *$2 : ""}; + GRAMMARP->endLabel($6, $$, $6); + $$->addDeclsp($3); + $$->addForksp(V3ParseGrammar::wrapInBegin($4)); + } ; par_blockPreId: // ==IEEE: par_block but called with leading ID - par_blockFrontPreId blockDeclStmtListE par_blockJoin endLabelE - { $$ = $1; $1->joinType($3); - V3ParseGrammar::addForkStmtsp($1, $2); - GRAMMARP->endLabel($4, $1, $4); } - ; + id yP_COLON__FORK yFORK blockDeclListE stmtListE par_blockJoin endLabelE + { + $$ = new AstFork{$3, $6, *$1}; + GRAMMARP->endLabel($7, $$, $7); + $$->addDeclsp($4); + $$->addForksp(V3ParseGrammar::wrapInBegin($5)); + } + ; -seq_blockFront: // IEEE: part of seq_block - yBEGIN - { $$ = new AstBegin{$1, "", nullptr, false}; } - | yBEGIN ':' idAny/*new-block_identifier*/ - { $$ = new AstBegin{$3, *$3, nullptr, false}; } - ; - -par_blockFront: // IEEE: part of par_block - yFORK - { $$ = new AstFork{$1, "", nullptr}; } - | yFORK ':' idAny/*new-block_identifier*/ - { $$ = new AstFork{$3, *$3, nullptr}; } - ; - -seq_blockFrontPreId: // IEEE: part of seq_block/stmt with leading id - id/*block_identifier*/ yP_COLON__BEGIN yBEGIN - { $$ = new AstBegin{$3, *$1, nullptr, false}; } - ; - -par_blockFrontPreId: // IEEE: part of par_block/stmt with leading id - id/*block_identifier*/ yP_COLON__FORK yFORK - { $$ = new AstFork{$3, *$1, nullptr}; } - ; - - -blockDeclStmtList: // IEEE: { block_item_declaration } { statement or null } - // // The spec seems to suggest a empty declaration isn't ok, but most simulators take it - block_item_declarationList { $$ = $1; } - | block_item_declarationList stmtList { $$ = addNextNull($1, $2); } - | stmtList { $$ = $1; } - ; - -blockDeclStmtListE: // IEEE: [ { block_item_declaration } { statement or null } ] +blockDeclListE: // IEEE: [ block_item_declaration ] /*empty*/ { $$ = nullptr; } - | blockDeclStmtList { $$ = $1; } - ; - -block_item_declarationList: // IEEE: [ block_item_declaration ] - block_item_declaration { $$ = $1; } - | block_item_declarationList block_item_declaration { $$ = addNextNull($1, $2); } - // - | block_item_declarationList error ';' { $$ = $1; } // LCOV_EXCL_LINE + | blockDeclListE block_item_declaration { $$ = addNextNull($1, $2); } | error ';' { $$ = nullptr; } // LCOV_EXCL_LINE ; @@ -3442,6 +3417,11 @@ block_item_declaration: // ==IEEE: block_item_declaration | let_declaration { $$ = $1; } ; +stmtListE: + /*empty*/ { $$ = nullptr; } + | stmtList { $$ = $1; } + ; + stmtList: stmt { $$ = $1; } | stmtList stmt { $$ = addNextNull($1, $2); } @@ -6092,6 +6072,11 @@ strAsIntIgnore: // strAsInt, but never matches for when expr yaSTRING__IGNORE { $$ = nullptr; yyerror("Impossible token"); } ; +startLabelE: + /* empty */ { $$ = nullptr; $$ = nullptr; } + | ':' idAny { $$ = $2; $$ = $2; } + ; + endLabelE: /* empty */ { $$ = nullptr; $$ = nullptr; } | ':' idAny { $$ = $2; $$ = $2; } diff --git a/test_regress/t/t_constraint_json_only.out b/test_regress/t/t_constraint_json_only.out index fa6018ab8..926e4ed57 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","implied":false,"needProcess":false,"unnamed":true, + {"type":"BEGIN","name":"","addr":"(J)","loc":"d,71:12,71:17","implied":false,"needProcess":false,"unnamed":true,"declsp": [], "stmtsp": [ {"type":"DISPLAY","name":"","addr":"(K)","loc":"d,73:7,73:13", "fmtp": [ diff --git a/test_regress/t/t_disable_inside.v b/test_regress/t/t_disable_inside.v index 61cca422a..9b956abfc 100644 --- a/test_regress/t/t_disable_inside.v +++ b/test_regress/t/t_disable_inside.v @@ -9,13 +9,104 @@ module t; int x = 0; fork : fork_blk begin + #1; + disable fork_blk; // Disables both forked processes + $stop; + end + begin + if ($time != 0) $stop; x = 1; - disable fork_blk; - x = 2; + #2; + $stop; end join_none #1; - if (x != 1) $stop; + if (x != 1) begin + $display(x); + $stop; + end + end + + initial begin + int y = 0; + fork + begin : fork_branch + #1; + disable fork_branch; // Disables only this branch of the fork + $stop; + end + begin + if ($time != 0) $stop; + y = 1; + #2; + if ($time != 2) $stop; + y = 2; + end + join_none + #1; + if (y != 1) begin + $display(y); + $stop; + end + #1; + if (y != 2) begin + $display(y); + $stop; + end + end + + // TODO: This doesn't work due to the second fork branch not being added to + // the killQueue when the 'disable' is executed with no delay after + // the fork starts. See the case below which is the same, but the + // fork branches are in the opposite order so it happens to work. + //initial begin + // fork : fork_blk2 + // begin + // if ($time != 0) $stop; + // disable fork_blk2; + // $stop; + // end + // begin + // if ($time != 0) $stop; + // #1 $stop; + // end + // join_none + //end + + initial begin + fork : fork_blk3 + begin + if ($time != 0) $stop; + #1 $stop; + end + begin + if ($time != 0) $stop; + disable fork_blk3; + $stop; + end + join_none + end + + initial begin + fork : fork_blk4 + begin + if ($time != 0) $stop; + if ($c("false")) begin + disable fork_blk4; + $stop; + end + #1; + end + begin + if ($time != 0) $stop; + #1; + if ($time != 1) $stop; + end + join_none + end + + initial begin + #10; $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_dump_json.out b/test_regress/t/t_dump_json.out index 3ae39b1db..edd09da9f 100644 --- a/test_regress/t/t_dump_json.out +++ b/test_regress/t/t_dump_json.out @@ -166,7 +166,7 @@ ]} ], "stmtsp": [ - {"type":"BEGIN","name":"","addr":"(ZC)","loc":"e,36:27,36:32","implied":false,"needProcess":false,"unnamed":true, + {"type":"BEGIN","name":"","addr":"(ZC)","loc":"e,36:27,36:32","implied":false,"needProcess":false,"unnamed":true,"declsp": [], "stmtsp": [ {"type":"ASSIGNDLY","name":"","addr":"(AD)","loc":"e,40:11,40:13","dtypep":"UNLINKED", "rhsp": [ @@ -314,7 +314,7 @@ ]} ], "thensp": [ - {"type":"BEGIN","name":"","addr":"(BF)","loc":"e,43:21,43:26","implied":false,"needProcess":false,"unnamed":true, + {"type":"BEGIN","name":"","addr":"(BF)","loc":"e,43:21,43:26","implied":false,"needProcess":false,"unnamed":true,"declsp": [], "stmtsp": [ {"type":"ASSIGNDLY","name":"","addr":"(CF)","loc":"e,45:14,45:16","dtypep":"UNLINKED", "rhsp": [ @@ -344,7 +344,7 @@ ]} ], "thensp": [ - {"type":"BEGIN","name":"","addr":"(OF)","loc":"e,48:26,48:31","implied":false,"needProcess":false,"unnamed":true, + {"type":"BEGIN","name":"","addr":"(OF)","loc":"e,48:26,48:31","implied":false,"needProcess":false,"unnamed":true,"declsp": [], "stmtsp": [ {"type":"ASSIGNDLY","name":"","addr":"(PF)","loc":"e,49:14,49:16","dtypep":"UNLINKED", "rhsp": [ @@ -367,7 +367,7 @@ ]} ], "thensp": [ - {"type":"BEGIN","name":"","addr":"(XF)","loc":"e,51:26,51:31","implied":false,"needProcess":false,"unnamed":true,"stmtsp": []} + {"type":"BEGIN","name":"","addr":"(XF)","loc":"e,51:26,51:31","implied":false,"needProcess":false,"unnamed":true,"declsp": [],"stmtsp": []} ], "elsesp": [ {"type":"IF","name":"","addr":"(YF)","loc":"e,53:12,53:14", @@ -381,7 +381,7 @@ ]} ], "thensp": [ - {"type":"BEGIN","name":"","addr":"(CG)","loc":"e,53:27,53:32","implied":false,"needProcess":false,"unnamed":true, + {"type":"BEGIN","name":"","addr":"(CG)","loc":"e,53:27,53:32","implied":false,"needProcess":false,"unnamed":true,"declsp": [], "stmtsp": [ {"type":"DISPLAY","name":"","addr":"(DG)","loc":"e,54:10,54:16", "fmtp": [ @@ -485,7 +485,7 @@ ]} ], "stmtsp": [ - {"type":"BEGIN","name":"","addr":"(WH)","loc":"e,82:26,82:31","implied":false,"needProcess":false,"unnamed":true, + {"type":"BEGIN","name":"","addr":"(WH)","loc":"e,82:26,82:31","implied":false,"needProcess":false,"unnamed":true,"declsp": [], "stmtsp": [ {"type":"ASSIGNDLY","name":"","addr":"(XH)","loc":"e,83:11,83:13","dtypep":"UNLINKED", "rhsp": [ @@ -535,7 +535,7 @@ "assertTypesp": [ {"type":"CONST","name":"?32?sh8","addr":"(QI)","loc":"e,90:25,90:26","dtypep":"(NF)"} ],"directiveTypesp": []}, - {"type":"BEGIN","name":"blk","addr":"(RI)","loc":"e,91:15,91:18","implied":false,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"blk","addr":"(RI)","loc":"e,91:7,91:12","implied":false,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"DISABLE","name":"","addr":"(SI)","loc":"e,92:10,92:17", "targetRefp": [ @@ -547,9 +547,9 @@ ]}, {"type":"INITIAL","name":"","addr":"(UI)","loc":"e,95:4,95:11","isSuspendable":false,"needProcess":false, "stmtsp": [ - {"type":"BEGIN","name":"","addr":"(VI)","loc":"e,95:12,95:17","implied":false,"needProcess":false,"unnamed":true, + {"type":"BEGIN","name":"","addr":"(VI)","loc":"e,95:12,95:17","implied":false,"needProcess":false,"unnamed":true,"declsp": [], "stmtsp": [ - {"type":"BEGIN","name":"assert_simple_immediate_else","addr":"(WI)","loc":"e,96:7,96:35","implied":false,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assert_simple_immediate_else","addr":"(WI)","loc":"e,96:7,96:35","implied":false,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(XI)","loc":"e,96:37,96:43","type":"[SIMPLE_IMMEDIATE]", "propp": [ @@ -565,7 +565,7 @@ ],"filep": []} ],"passsp": []} ]}, - {"type":"BEGIN","name":"assert_simple_immediate_stmt","addr":"(CJ)","loc":"e,97:7,97:35","implied":false,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assert_simple_immediate_stmt","addr":"(CJ)","loc":"e,97:7,97:35","implied":false,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(DJ)","loc":"e,97:37,97:43","type":"[SIMPLE_IMMEDIATE]", "propp": [ @@ -581,7 +581,7 @@ ],"filep": []} ]} ]}, - {"type":"BEGIN","name":"assert_simple_immediate_stmt_else","addr":"(IJ)","loc":"e,98:7,98:40","implied":false,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assert_simple_immediate_stmt_else","addr":"(IJ)","loc":"e,98:7,98:40","implied":false,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(JJ)","loc":"e,98:42,98:48","type":"[SIMPLE_IMMEDIATE]", "propp": [ @@ -606,14 +606,14 @@ ],"filep": []} ]} ]}, - {"type":"BEGIN","name":"assume_simple_immediate","addr":"(RJ)","loc":"e,100:7,100:30","implied":false,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assume_simple_immediate","addr":"(RJ)","loc":"e,100:7,100:30","implied":false,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(SJ)","loc":"e,100:32,100:38","type":"[SIMPLE_IMMEDIATE]", "propp": [ {"type":"CONST","name":"?32?sh0","addr":"(TJ)","loc":"e,100:39,100:40","dtypep":"(N)"} ],"sentreep": [],"failsp": [],"passsp": []} ]}, - {"type":"BEGIN","name":"assume_simple_immediate_else","addr":"(UJ)","loc":"e,101:7,101:35","implied":false,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assume_simple_immediate_else","addr":"(UJ)","loc":"e,101:7,101:35","implied":false,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(VJ)","loc":"e,101:37,101:43","type":"[SIMPLE_IMMEDIATE]", "propp": [ @@ -629,7 +629,7 @@ ],"filep": []} ],"passsp": []} ]}, - {"type":"BEGIN","name":"assume_simple_immediate_stmt","addr":"(AK)","loc":"e,102:7,102:35","implied":false,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assume_simple_immediate_stmt","addr":"(AK)","loc":"e,102:7,102:35","implied":false,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(BK)","loc":"e,102:37,102:43","type":"[SIMPLE_IMMEDIATE]", "propp": [ @@ -645,7 +645,7 @@ ],"filep": []} ]} ]}, - {"type":"BEGIN","name":"assume_simple_immediate_stmt_else","addr":"(GK)","loc":"e,103:7,103:40","implied":false,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assume_simple_immediate_stmt_else","addr":"(GK)","loc":"e,103:7,103:40","implied":false,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(HK)","loc":"e,103:42,103:48","type":"[SIMPLE_IMMEDIATE]", "propp": [ @@ -674,7 +674,7 @@ ]}, {"type":"ALWAYS","name":"","addr":"(PK)","loc":"e,106:4,106:38","keyword":"always_comb","isSuspendable":false,"needProcess":false,"sentreep": [], "stmtsp": [ - {"type":"BEGIN","name":"assert_observed_deferred_immediate","addr":"(QK)","loc":"e,106:4,106:38","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assert_observed_deferred_immediate","addr":"(QK)","loc":"e,106:4,106:38","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(RK)","loc":"e,106:40,106:46","type":"[OBSERVED_DEFERRED_IMMEDIATE]", "propp": [ @@ -684,7 +684,7 @@ ]}, {"type":"ALWAYS","name":"","addr":"(TK)","loc":"e,107:4,107:43","keyword":"always_comb","isSuspendable":false,"needProcess":false,"sentreep": [], "stmtsp": [ - {"type":"BEGIN","name":"assert_observed_deferred_immediate_else","addr":"(UK)","loc":"e,107:4,107:43","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assert_observed_deferred_immediate_else","addr":"(UK)","loc":"e,107:4,107:43","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(VK)","loc":"e,107:45,107:51","type":"[OBSERVED_DEFERRED_IMMEDIATE]", "propp": [ @@ -703,7 +703,7 @@ ]}, {"type":"ALWAYS","name":"","addr":"(AL)","loc":"e,108:4,108:43","keyword":"always_comb","isSuspendable":false,"needProcess":false,"sentreep": [], "stmtsp": [ - {"type":"BEGIN","name":"assert_observed_deferred_immediate_stmt","addr":"(BL)","loc":"e,108:4,108:43","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assert_observed_deferred_immediate_stmt","addr":"(BL)","loc":"e,108:4,108:43","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(CL)","loc":"e,108:45,108:51","type":"[OBSERVED_DEFERRED_IMMEDIATE]", "propp": [ @@ -722,7 +722,7 @@ ]}, {"type":"ALWAYS","name":"","addr":"(HL)","loc":"e,109:4,109:48","keyword":"always_comb","isSuspendable":false,"needProcess":false,"sentreep": [], "stmtsp": [ - {"type":"BEGIN","name":"assert_observed_deferred_immediate_stmt_else","addr":"(IL)","loc":"e,109:4,109:48","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assert_observed_deferred_immediate_stmt_else","addr":"(IL)","loc":"e,109:4,109:48","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(JL)","loc":"e,109:50,109:56","type":"[OBSERVED_DEFERRED_IMMEDIATE]", "propp": [ @@ -750,7 +750,7 @@ ]}, {"type":"ALWAYS","name":"","addr":"(RL)","loc":"e,111:4,111:38","keyword":"always_comb","isSuspendable":false,"needProcess":false,"sentreep": [], "stmtsp": [ - {"type":"BEGIN","name":"assume_observed_deferred_immediate","addr":"(SL)","loc":"e,111:4,111:38","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assume_observed_deferred_immediate","addr":"(SL)","loc":"e,111:4,111:38","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(TL)","loc":"e,111:40,111:46","type":"[OBSERVED_DEFERRED_IMMEDIATE]", "propp": [ @@ -760,7 +760,7 @@ ]}, {"type":"ALWAYS","name":"","addr":"(VL)","loc":"e,112:4,112:43","keyword":"always_comb","isSuspendable":false,"needProcess":false,"sentreep": [], "stmtsp": [ - {"type":"BEGIN","name":"assume_observed_deferred_immediate_else","addr":"(WL)","loc":"e,112:4,112:43","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assume_observed_deferred_immediate_else","addr":"(WL)","loc":"e,112:4,112:43","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(XL)","loc":"e,112:45,112:51","type":"[OBSERVED_DEFERRED_IMMEDIATE]", "propp": [ @@ -779,7 +779,7 @@ ]}, {"type":"ALWAYS","name":"","addr":"(CM)","loc":"e,113:4,113:43","keyword":"always_comb","isSuspendable":false,"needProcess":false,"sentreep": [], "stmtsp": [ - {"type":"BEGIN","name":"assume_observed_deferred_immediate_stmt","addr":"(DM)","loc":"e,113:4,113:43","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assume_observed_deferred_immediate_stmt","addr":"(DM)","loc":"e,113:4,113:43","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(EM)","loc":"e,113:45,113:51","type":"[OBSERVED_DEFERRED_IMMEDIATE]", "propp": [ @@ -798,7 +798,7 @@ ]}, {"type":"ALWAYS","name":"","addr":"(JM)","loc":"e,114:4,114:48","keyword":"always_comb","isSuspendable":false,"needProcess":false,"sentreep": [], "stmtsp": [ - {"type":"BEGIN","name":"assume_observed_deferred_immediate_stmt_else","addr":"(KM)","loc":"e,114:4,114:48","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assume_observed_deferred_immediate_stmt_else","addr":"(KM)","loc":"e,114:4,114:48","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(LM)","loc":"e,114:50,114:56","type":"[OBSERVED_DEFERRED_IMMEDIATE]", "propp": [ @@ -826,7 +826,7 @@ ]}, {"type":"ALWAYS","name":"","addr":"(TM)","loc":"e,116:4,116:35","keyword":"always_comb","isSuspendable":false,"needProcess":false,"sentreep": [], "stmtsp": [ - {"type":"BEGIN","name":"assert_final_deferred_immediate","addr":"(UM)","loc":"e,116:4,116:35","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assert_final_deferred_immediate","addr":"(UM)","loc":"e,116:4,116:35","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(VM)","loc":"e,116:37,116:43","type":"[FINAL_DEFERRED_IMMEDIATE]", "propp": [ @@ -836,7 +836,7 @@ ]}, {"type":"ALWAYS","name":"","addr":"(XM)","loc":"e,117:4,117:40","keyword":"always_comb","isSuspendable":false,"needProcess":false,"sentreep": [], "stmtsp": [ - {"type":"BEGIN","name":"assert_final_deferred_immediate_else","addr":"(YM)","loc":"e,117:4,117:40","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assert_final_deferred_immediate_else","addr":"(YM)","loc":"e,117:4,117:40","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(ZM)","loc":"e,117:42,117:48","type":"[FINAL_DEFERRED_IMMEDIATE]", "propp": [ @@ -855,7 +855,7 @@ ]}, {"type":"ALWAYS","name":"","addr":"(EN)","loc":"e,118:4,118:40","keyword":"always_comb","isSuspendable":false,"needProcess":false,"sentreep": [], "stmtsp": [ - {"type":"BEGIN","name":"assert_final_deferred_immediate_stmt","addr":"(FN)","loc":"e,118:4,118:40","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assert_final_deferred_immediate_stmt","addr":"(FN)","loc":"e,118:4,118:40","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(GN)","loc":"e,118:42,118:48","type":"[FINAL_DEFERRED_IMMEDIATE]", "propp": [ @@ -874,7 +874,7 @@ ]}, {"type":"ALWAYS","name":"","addr":"(LN)","loc":"e,119:4,119:45","keyword":"always_comb","isSuspendable":false,"needProcess":false,"sentreep": [], "stmtsp": [ - {"type":"BEGIN","name":"assert_final_deferred_immediate_stmt_else","addr":"(MN)","loc":"e,119:4,119:45","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assert_final_deferred_immediate_stmt_else","addr":"(MN)","loc":"e,119:4,119:45","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(NN)","loc":"e,119:47,119:53","type":"[FINAL_DEFERRED_IMMEDIATE]", "propp": [ @@ -902,7 +902,7 @@ ]}, {"type":"ALWAYS","name":"","addr":"(VN)","loc":"e,121:4,121:35","keyword":"always_comb","isSuspendable":false,"needProcess":false,"sentreep": [], "stmtsp": [ - {"type":"BEGIN","name":"assume_final_deferred_immediate","addr":"(WN)","loc":"e,121:4,121:35","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assume_final_deferred_immediate","addr":"(WN)","loc":"e,121:4,121:35","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(XN)","loc":"e,121:37,121:43","type":"[FINAL_DEFERRED_IMMEDIATE]", "propp": [ @@ -912,7 +912,7 @@ ]}, {"type":"ALWAYS","name":"","addr":"(ZN)","loc":"e,122:4,122:40","keyword":"always_comb","isSuspendable":false,"needProcess":false,"sentreep": [], "stmtsp": [ - {"type":"BEGIN","name":"assume_final_deferred_immediate_else","addr":"(AO)","loc":"e,122:4,122:40","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assume_final_deferred_immediate_else","addr":"(AO)","loc":"e,122:4,122:40","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(BO)","loc":"e,122:42,122:48","type":"[FINAL_DEFERRED_IMMEDIATE]", "propp": [ @@ -931,7 +931,7 @@ ]}, {"type":"ALWAYS","name":"","addr":"(GO)","loc":"e,123:4,123:40","keyword":"always_comb","isSuspendable":false,"needProcess":false,"sentreep": [], "stmtsp": [ - {"type":"BEGIN","name":"assume_final_deferred_immediate_stmt","addr":"(HO)","loc":"e,123:4,123:40","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assume_final_deferred_immediate_stmt","addr":"(HO)","loc":"e,123:4,123:40","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(IO)","loc":"e,123:42,123:48","type":"[FINAL_DEFERRED_IMMEDIATE]", "propp": [ @@ -950,7 +950,7 @@ ]}, {"type":"ALWAYS","name":"","addr":"(NO)","loc":"e,124:4,124:45","keyword":"always_comb","isSuspendable":false,"needProcess":false,"sentreep": [], "stmtsp": [ - {"type":"BEGIN","name":"assume_final_deferred_immediate_stmt_else","addr":"(OO)","loc":"e,124:4,124:45","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assume_final_deferred_immediate_stmt_else","addr":"(OO)","loc":"e,124:4,124:45","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(PO)","loc":"e,124:47,124:53","type":"[FINAL_DEFERRED_IMMEDIATE]", "propp": [ @@ -989,7 +989,7 @@ {"type":"CONST","name":"?32?sh0","addr":"(BP)","loc":"e,127:22,127:23","dtypep":"(N)"} ]} ],"scopeNamep": []}, - {"type":"BEGIN","name":"assert_concurrent","addr":"(CP)","loc":"e,130:4,130:21","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assert_concurrent","addr":"(CP)","loc":"e,130:4,130:21","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(DP)","loc":"e,130:23,130:29","type":"[CONCURRENT]", "propp": [ @@ -1002,7 +1002,7 @@ ]} ],"sentreep": [],"failsp": [],"passsp": []} ]}, - {"type":"BEGIN","name":"assert_concurrent_else","addr":"(HP)","loc":"e,131:4,131:26","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assert_concurrent_else","addr":"(HP)","loc":"e,131:4,131:26","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(IP)","loc":"e,131:28,131:34","type":"[CONCURRENT]", "propp": [ @@ -1024,7 +1024,7 @@ ],"filep": []} ],"passsp": []} ]}, - {"type":"BEGIN","name":"assert_concurrent_stmt","addr":"(PP)","loc":"e,132:4,132:26","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assert_concurrent_stmt","addr":"(PP)","loc":"e,132:4,132:26","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(QP)","loc":"e,132:28,132:34","type":"[CONCURRENT]", "propp": [ @@ -1046,7 +1046,7 @@ ],"filep": []} ]} ]}, - {"type":"BEGIN","name":"assert_concurrent_stmt_else","addr":"(XP)","loc":"e,133:4,133:31","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assert_concurrent_stmt_else","addr":"(XP)","loc":"e,133:4,133:31","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(YP)","loc":"e,133:33,133:39","type":"[CONCURRENT]", "propp": [ @@ -1077,7 +1077,7 @@ ],"filep": []} ]} ]}, - {"type":"BEGIN","name":"assume_concurrent","addr":"(IQ)","loc":"e,135:4,135:21","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assume_concurrent","addr":"(IQ)","loc":"e,135:4,135:21","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(JQ)","loc":"e,135:23,135:29","type":"[CONCURRENT]", "propp": [ @@ -1090,7 +1090,7 @@ ]} ],"sentreep": [],"failsp": [],"passsp": []} ]}, - {"type":"BEGIN","name":"assume_concurrent_else","addr":"(NQ)","loc":"e,136:4,136:26","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assume_concurrent_else","addr":"(NQ)","loc":"e,136:4,136:26","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(OQ)","loc":"e,136:28,136:34","type":"[CONCURRENT]", "propp": [ @@ -1112,7 +1112,7 @@ ],"filep": []} ],"passsp": []} ]}, - {"type":"BEGIN","name":"assume_concurrent_stmt","addr":"(VQ)","loc":"e,137:4,137:26","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assume_concurrent_stmt","addr":"(VQ)","loc":"e,137:4,137:26","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(WQ)","loc":"e,137:28,137:34","type":"[CONCURRENT]", "propp": [ @@ -1134,7 +1134,7 @@ ],"filep": []} ]} ]}, - {"type":"BEGIN","name":"assume_concurrent_stmt_else","addr":"(DR)","loc":"e,138:4,138:31","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"assume_concurrent_stmt_else","addr":"(DR)","loc":"e,138:4,138:31","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"ASSERT","name":"","addr":"(ER)","loc":"e,138:33,138:39","type":"[CONCURRENT]", "propp": [ @@ -1165,7 +1165,7 @@ ],"filep": []} ]} ]}, - {"type":"BEGIN","name":"cover_concurrent","addr":"(OR)","loc":"e,140:4,140:20","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"cover_concurrent","addr":"(OR)","loc":"e,140:4,140:20","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"COVER","name":"","addr":"(PR)","loc":"e,140:22,140:27","type":"[CONCURRENT]", "propp": [ @@ -1175,7 +1175,7 @@ ]} ],"sentreep": [],"coverincsp": [],"passsp": []} ]}, - {"type":"BEGIN","name":"cover_concurrent_stmt","addr":"(SR)","loc":"e,141:4,141:25","implied":true,"needProcess":false,"unnamed":false, + {"type":"BEGIN","name":"cover_concurrent_stmt","addr":"(SR)","loc":"e,141:4,141:25","implied":true,"needProcess":false,"unnamed":false,"declsp": [], "stmtsp": [ {"type":"COVER","name":"","addr":"(TR)","loc":"e,141:27,141:32","type":"[CONCURRENT]", "propp": [ @@ -1301,7 +1301,7 @@ ]} ], "thensp": [ - {"type":"BEGIN","name":"","addr":"(QT)","loc":"d,55:44,55:49","implied":false,"needProcess":false,"unnamed":true, + {"type":"BEGIN","name":"","addr":"(QT)","loc":"d,55:44,55:49","implied":false,"needProcess":false,"unnamed":true,"declsp": [], "stmtsp": [ {"type":"STMTEXPR","name":"","addr":"(RT)","loc":"d,56:16,56:17", "exprp": [ @@ -1357,7 +1357,7 @@ ]} ], "thensp": [ - {"type":"BEGIN","name":"","addr":"(NU)","loc":"d,72:22,72:27","implied":false,"needProcess":false,"unnamed":true, + {"type":"BEGIN","name":"","addr":"(NU)","loc":"d,72:22,72:27","implied":false,"needProcess":false,"unnamed":true,"declsp": [], "stmtsp": [ {"type":"ASSIGN","name":"","addr":"(OU)","loc":"d,73:17,73:18","dtypep":"UNLINKED", "rhsp": [ @@ -1410,7 +1410,7 @@ ]} ], "thensp": [ - {"type":"BEGIN","name":"","addr":"(IV)","loc":"d,89:22,89:27","implied":false,"needProcess":false,"unnamed":true, + {"type":"BEGIN","name":"","addr":"(IV)","loc":"d,89:22,89:27","implied":false,"needProcess":false,"unnamed":true,"declsp": [], "stmtsp": [ {"type":"ASSIGN","name":"","addr":"(JV)","loc":"d,90:17,90:18","dtypep":"UNLINKED", "rhsp": [ @@ -1516,7 +1516,7 @@ ]} ], "thensp": [ - {"type":"BEGIN","name":"","addr":"(YW)","loc":"d,118:35,118:40","implied":false,"needProcess":false,"unnamed":true, + {"type":"BEGIN","name":"","addr":"(YW)","loc":"d,118:35,118:40","implied":false,"needProcess":false,"unnamed":true,"declsp": [], "stmtsp": [ {"type":"ASSIGN","name":"","addr":"(ZW)","loc":"d,119:20,119:22","dtypep":"UNLINKED", "rhsp": [ diff --git a/test_regress/t/t_fork.out b/test_regress/t/t_fork.out index 5f067c56a..a2e1e97f4 100644 --- a/test_regress/t/t_fork.out +++ b/test_regress/t/t_fork.out @@ -1,6 +1,6 @@ -%Error-NOTIMING: t/t_fork.v:10:14: Fork statements require --timing - : ... note: In instance 't' +%Error-NOTIMING: t/t_fork.v:10:7: Fork statements require --timing + : ... note: In instance 't' 10 | fork : fblk - | ^~~~ + | ^~~~ ... For error description see https://verilator.org/warn/NOTIMING?v=latest %Error: Exiting due to diff --git a/test_regress/t/t_fork_initial.v b/test_regress/t/t_fork_initial.v index 24780ede3..ef6ed69b1 100644 --- a/test_regress/t/t_fork_initial.v +++ b/test_regress/t/t_fork_initial.v @@ -8,8 +8,11 @@ module t(); initial fork reg i; i = 1'b1; - if (i != 1'b1) $stop; - $write("*-* All Finished *-*\n"); - $finish; + begin + #1; + if (i != 1'b1) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end join endmodule diff --git a/test_regress/t/t_json_only_tag.out b/test_regress/t/t_json_only_tag.out index 67e7f5fff..631588b69 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","implied":false,"needProcess":false,"unnamed":true, + {"type":"BEGIN","name":"","addr":"(GB)","loc":"d,39:12,39:17","implied":false,"needProcess":false,"unnamed":true,"declsp": [], "stmtsp": [ {"type":"STMTEXPR","name":"","addr":"(HB)","loc":"d,41:7,41:8", "exprp": [ diff --git a/test_regress/t/t_lint_block_redecl_bad.out b/test_regress/t/t_lint_block_redecl_bad.out index 95c7022c1..abc2b933d 100644 --- a/test_regress/t/t_lint_block_redecl_bad.out +++ b/test_regress/t/t_lint_block_redecl_bad.out @@ -1,8 +1,8 @@ -%Error: t/t_lint_block_redecl_bad.v:17:34: Duplicate declaration of block: 'COMB' +%Error: t/t_lint_block_redecl_bad.v:17:27: Duplicate declaration of block: 'COMB' 17 | for(i=0; i<9; i++ ) begin: COMB - | ^~~~ - t/t_lint_block_redecl_bad.v:14:35: ... Location of original declaration + | ^~~~~ + t/t_lint_block_redecl_bad.v:14:28: ... Location of original declaration 14 | for(i=0; i<10; i++ ) begin: COMB - | ^~~~ + | ^~~~~ ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. %Error: Exiting due to