diff --git a/src/V3Active.cpp b/src/V3Active.cpp index aa6658e07..f8dc3044e 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -160,7 +160,9 @@ public: class ActiveDlyVisitor : public ActiveBaseVisitor { private: - bool m_combo; // Combo logic + bool m_combo; // Combo logic + AstNode* m_alwaysp; // Always we're under + AstNode* m_assignp; // In assign // VISITORS virtual void visit(AstAssignDly* nodep, AstNUser*) { if (m_combo) { @@ -176,12 +178,30 @@ private: } virtual void visit(AstAssign* nodep, AstNUser*) { if (!m_combo) { - // Convert to a non-delayed assignment - nodep->v3warn(BLKSEQ,"Blocking assignments (=) in sequential (flop or latch) block; suggest delayed assignments (<=)."); + AstNode* las = m_assignp; + m_assignp = nodep; + nodep->lhsp()->iterateAndNext(*this); + m_assignp = las; + } + } + virtual void visit(AstVarRef* nodep, AstNUser*) { + AstVar* varp=nodep->varp(); + if (!m_combo + && m_assignp + && !varp->isUsedLoopIdx() // Ignore loop indicies + && !varp->isTemp() + ) { + // Allow turning off warnings on the always, or the variable also + if (!m_alwaysp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ) + && !m_assignp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ) + && !varp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ) + ) { + m_alwaysp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); // Complain just once for the entire always + varp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); + nodep->v3warn(BLKSEQ,"Blocking assignments (=) in sequential (flop or latch) block; suggest delayed assignments (<=)."); + } } } - // Empty visitors, speed things up - virtual void visit(AstNodeMath* nodep, AstNUser*) {} //-------------------- virtual void visit(AstNode* nodep, AstNUser*) { nodep->iterateChildren(*this); @@ -189,7 +209,9 @@ private: public: // CONSTUCTORS ActiveDlyVisitor(AstNode* nodep, bool combo) { + m_alwaysp = nodep; m_combo = combo; + m_assignp = NULL; nodep->accept(*this); } virtual ~ActiveDlyVisitor() {} diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 61af43c22..efa3a3ac1 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -553,6 +553,7 @@ private: bool m_sigUserRWPublic:1; // User C code accesses this signal, read-write bool m_usedClock:1; // Signal used as a clock bool m_usedParam:1; // Parameter is referenced (on link; later signals not setup) + bool m_usedLoopIdx:1; // Variable subject of for unrolling bool m_funcLocal:1; // Local variable for a function bool m_funcReturn:1; // Return variable for a function bool m_attrClockEn:1;// User clock enable attribute @@ -567,7 +568,7 @@ private: m_input=false; m_output=false; m_tristate=false; m_primaryIO=false; m_sc=false; m_scClocked=false; m_scSensitive=false; - m_usedClock=false; m_usedParam=false; + m_usedClock=false; m_usedParam=false; m_usedLoopIdx=false; m_sigPublic=false; m_sigModPublic=false; m_sigUserRdPublic=false; m_sigUserRWPublic=false; m_funcLocal=false; m_funcReturn=false; m_attrClockEn=false; m_attrIsolateAssign=false; m_attrSFormat=false; @@ -635,6 +636,7 @@ public: void attrSFormat(bool flag) { m_attrSFormat = flag; } void usedClock(bool flag) { m_usedClock = flag; } void usedParam(bool flag) { m_usedParam = flag; } + void usedLoopIdx(bool flag) { m_usedLoopIdx = flag; } void sigPublic(bool flag) { m_sigPublic = flag; } void sigModPublic(bool flag) { m_sigModPublic = flag; } void sigUserRdPublic(bool flag) { m_sigUserRdPublic = flag; if (flag) sigPublic(true); } @@ -675,6 +677,7 @@ public: bool isBitLogic() const { AstBasicDType* bdtypep = basicp(); return bdtypep && bdtypep->isBitLogic(); } bool isUsedClock() const { return m_usedClock; } bool isUsedParam() const { return m_usedParam; } + bool isUsedLoopIdx() const { return m_usedLoopIdx; } bool isSc() const { return m_sc; } bool isScQuad() const; bool isScBv() const; diff --git a/src/V3Unroll.cpp b/src/V3Unroll.cpp index e0072089f..7c0d9fc4b 100644 --- a/src/V3Unroll.cpp +++ b/src/V3Unroll.cpp @@ -250,6 +250,9 @@ private: incp->unlinkFrBackWithNext(); stmtsp = stmtsp->addNextNull(incp); // Maybe null if no body } + // Mark variable to disable some later warnings + m_forVarp->usedLoopIdx(true); + // If it's a While, then incp is already part of bodysp. V3Number loopValue(nodep->fileline(), m_forVarp->width()); // May differ in size from numInitp loopValue.opAssign(numInit); diff --git a/test_regress/t/t_lint_blksync_bad.v b/test_regress/t/t_lint_blksync_bad.v index d5618f9ce..423b4a8bc 100644 --- a/test_regress/t/t_lint_blksync_bad.v +++ b/test_regress/t/t_lint_blksync_bad.v @@ -9,13 +9,19 @@ module t (/*AUTOARG*/ ); input clk; + integer i; + reg sync_blk; + reg sync_blk2; reg sync_nblk; + reg sync2_ok; + reg sync3_ok; reg combo_blk; reg combo_nblk; always @(posedge clk) begin sync_blk = 1'b1; + sync_blk2 = 1'b1; // Only warn once per block sync_nblk <= 1'b1; end @@ -24,5 +30,18 @@ module t (/*AUTOARG*/ combo_nblk <= 1'b1; end -endmodule + always @(posedge clk) begin + for (int i=0; i<20; i++) begin + sync2_ok <= 1'b1; + end + end + always @(posedge clk) begin + sync3_ok <= f(sync3_ok); + end + + function f (input v); + f = ~v; + endfunction + +endmodule