From 2a12b052f25add7e355a904291c4ecf953132b40 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 1 Oct 2022 12:28:16 +0100 Subject: [PATCH] DFG: handle simple always blocks --- docs/gen/ex_DIDNOTCONVERGE_msg.rst | 2 +- src/V3Delayed.cpp | 11 +++- src/V3DfgAstToDfg.cpp | 63 ++++++++++++++++++- test_regress/t/t_lint_didnotconverge_bad.out | 2 +- test_regress/t/t_order_blkandnblk_bad.out | 8 +-- test_regress/t/t_unopt_converge_unopt_bad.out | 2 +- 6 files changed, 76 insertions(+), 12 deletions(-) diff --git a/docs/gen/ex_DIDNOTCONVERGE_msg.rst b/docs/gen/ex_DIDNOTCONVERGE_msg.rst index bd055184b..86af7245a 100644 --- a/docs/gen/ex_DIDNOTCONVERGE_msg.rst +++ b/docs/gen/ex_DIDNOTCONVERGE_msg.rst @@ -1,5 +1,5 @@ .. comment: generated by t_lint_didnotconverge_bad .. code-block:: - -V{t#,#} 'stl' region trigger index 1 is active: @([hybrid] b) + -V{t#,#} 'stl' region trigger index 1 is active: @([hybrid] a) %Error: t/t_lint_didnotconverge_bad.v:7: Settle region did not converge. diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index dbff9c7dc..c7012c72b 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -109,6 +109,11 @@ private: // METHODS + const AstNode* containingAssignment(const AstNode* nodep) { + while (nodep && !VN_IS(nodep, NodeAssign)) nodep = nodep->backp(); + return nodep; + } + void markVarUsage(AstNodeVarRef* nodep, bool blocking) { // Ignore if warning is disabled on this reference (used by V3Force). if (nodep->fileline()->warnIsOff(V3ErrorCode::BLKANDNBLK)) return; @@ -122,8 +127,10 @@ private: } else { const bool last_was_blocking = lastrefp->user5(); if (last_was_blocking != blocking) { - const AstNode* const nonblockingp = blocking ? nodep : lastrefp; - const AstNode* const blockingp = blocking ? lastrefp : nodep; + const AstNode* nonblockingp = blocking ? nodep : lastrefp; + if (const AstNode* np = containingAssignment(nonblockingp)) nonblockingp = np; + const AstNode* blockingp = blocking ? lastrefp : nodep; + if (const AstNode* np = containingAssignment(blockingp)) blockingp = np; vscp->v3warn( BLKANDNBLK, "Unsupported: Blocked and non-blocking assignments to same variable: " diff --git a/src/V3DfgAstToDfg.cpp b/src/V3DfgAstToDfg.cpp index db81c7d11..c63814f90 100644 --- a/src/V3DfgAstToDfg.cpp +++ b/src/V3DfgAstToDfg.cpp @@ -212,7 +212,7 @@ class AstToDfgVisitor final : public VNVisitor { return false; } - bool convertEquation(AstNode* nodep, AstNode* lhsp, AstNode* rhsp) { + bool convertEquation(AstNode* nodep, FileLine* flp, AstNode* lhsp, AstNode* rhsp) { UASSERT_OBJ(m_uncommittedVertices.empty(), nodep, "Should not nest"); // Currently cannot handle direct assignments between unpacked types. These arise e.g. @@ -243,7 +243,7 @@ class AstToDfgVisitor final : public VNVisitor { return false; } - if (!convertAssignment(nodep->fileline(), lhsp, getVertex(rhsp))) { + if (!convertAssignment(flp, lhsp, getVertex(rhsp))) { revertUncommittedVertices(); markReferenced(nodep); return false; @@ -374,7 +374,64 @@ class AstToDfgVisitor final : public VNVisitor { return; } - convertEquation(nodep, nodep->lhsp(), nodep->rhsp()); + convertEquation(nodep, nodep->fileline(), nodep->lhsp(), nodep->rhsp()); + } + + void visit(AstAlways* nodep) override { + // Ignore sequential logic, or if there are multiple statements + const VAlwaysKwd kwd = nodep->keyword(); + if (nodep->sensesp() || !nodep->isJustOneBodyStmt() + || (kwd != VAlwaysKwd::ALWAYS && kwd != VAlwaysKwd::ALWAYS_COMB)) { + markReferenced(nodep); + return; + } + + AstNode* const stmtp = nodep->stmtsp(); + + if (AstAssign* const assignp = VN_CAST(stmtp, Assign)) { + ++m_ctx.m_inputEquations; + if (assignp->timingControlp()) { + markReferenced(stmtp); + ++m_ctx.m_nonRepTiming; + return; + } + convertEquation(nodep, assignp->fileline(), assignp->lhsp(), assignp->rhsp()); + } else if (AstIf* const ifp = VN_CAST(stmtp, If)) { + // Will only handle single assignments to the same LHS in both branches + AstAssign* const thenp = VN_CAST(ifp->thensp(), Assign); + AstAssign* const elsep = VN_CAST(ifp->elsesp(), Assign); + if (!thenp || !elsep || thenp->nextp() || elsep->nextp() + || !thenp->lhsp()->sameTree(elsep->lhsp())) { + markReferenced(stmtp); + return; + } + + ++m_ctx.m_inputEquations; + if (thenp->timingControlp() || elsep->timingControlp()) { + markReferenced(stmtp); + ++m_ctx.m_nonRepTiming; + return; + } + + // Create a conditional for the rhs by borrowing the components from the AstIf + AstCond* const rhsp = new AstCond{ifp->fileline(), // + ifp->condp()->unlinkFrBack(), // + thenp->rhsp()->unlinkFrBack(), // + elsep->rhsp()->unlinkFrBack()}; + + if (!convertEquation(nodep, ifp->fileline(), thenp->lhsp(), rhsp)) { + // Failed to convert. Mark 'rhsp', as 'convertEquation' only marks 'nodep'. + markReferenced(rhsp); + // Put the AstIf back together + ifp->condp(rhsp->condp()->unlinkFrBack()); + thenp->rhsp(rhsp->thenp()->unlinkFrBack()); + elsep->rhsp(rhsp->elsep()->unlinkFrBack()); + } + // Delete the auxiliary conditional + VL_DO_DANGLING(rhsp->deleteTree(), rhsp); + } else { + markReferenced(stmtp); + } } void visit(AstVarRef* nodep) override { diff --git a/test_regress/t/t_lint_didnotconverge_bad.out b/test_regress/t/t_lint_didnotconverge_bad.out index 526a34911..f72c08997 100644 --- a/test_regress/t/t_lint_didnotconverge_bad.out +++ b/test_regress/t/t_lint_didnotconverge_bad.out @@ -1,3 +1,3 @@ --V{t#,#} 'stl' region trigger index 1 is active: @([hybrid] b) +-V{t#,#} 'stl' region trigger index 1 is active: @([hybrid] a) %Error: t/t_lint_didnotconverge_bad.v:7: Settle region did not converge. Aborting... diff --git a/test_regress/t/t_order_blkandnblk_bad.out b/test_regress/t/t_order_blkandnblk_bad.out index 709176366..e2bcffd36 100644 --- a/test_regress/t/t_order_blkandnblk_bad.out +++ b/test_regress/t/t_order_blkandnblk_bad.out @@ -1,11 +1,11 @@ %Error-BLKANDNBLK: t/t_order_blkandnblk_bad.v:17:21: Unsupported: Blocked and non-blocking assignments to same variable: 't.array' 17 | logic [1:0][3:0] array; | ^~~~~ - t/t_order_blkandnblk_bad.v:19:16: ... Location of blocking assignment + t/t_order_blkandnblk_bad.v:19:25: ... Location of blocking assignment 19 | always_comb array[0] = i; - | ^~~~~ - t/t_order_blkandnblk_bad.v:22:6: ... Location of nonblocking assignment + | ^ + t/t_order_blkandnblk_bad.v:22:15: ... Location of nonblocking assignment 22 | array[1] <= array[0]; - | ^~~~~ + | ^~ ... For error description see https://verilator.org/warn/BLKANDNBLK?v=latest %Error: Exiting due to diff --git a/test_regress/t/t_unopt_converge_unopt_bad.out b/test_regress/t/t_unopt_converge_unopt_bad.out index ad410cbb3..7aa0e9039 100644 --- a/test_regress/t/t_unopt_converge_unopt_bad.out +++ b/test_regress/t/t_unopt_converge_unopt_bad.out @@ -4,6 +4,6 @@ ... For warning description see https://verilator.org/warn/UNOPTFLAT?v=latest ... Use "/* verilator lint_off UNOPTFLAT */" and lint_on around source to disable this message. t/t_unopt_converge.v:19:11: Example path: x - t/t_unopt_converge.v:22:4: Example path: ALWAYS + t/t_unopt_converge.v:23:9: Example path: ASSIGNW t/t_unopt_converge.v:19:11: Example path: x %Error: Exiting due to