diff --git a/src/V3Clock.cpp b/src/V3Clock.cpp index 2bcfa5f0c..b1ebdcdac 100644 --- a/src/V3Clock.cpp +++ b/src/V3Clock.cpp @@ -320,28 +320,6 @@ private: } nodep->deleteTree(); nodep = NULL; } - void moveInitial(AstActive* nodep) { - // Change to CFunc - AstNode* stmtsp = nodep->stmtsp(); - if (stmtsp) { - if (!m_scopep) nodep->v3fatalSrc("Initial Active not under scope\n"); - AstCFunc* funcp = new AstCFunc(nodep->fileline(), "_initial__"+m_scopep->nameDotless(), - m_scopep); - funcp->argTypes(EmitCBaseVisitor::symClassVar()); - funcp->symProlog(true); - funcp->slow(true); - stmtsp->unlinkFrBackWithNext(); - funcp->addStmtsp(stmtsp); - nodep->replaceWith(funcp); - // Add top level call to it - AstCCall* callp = new AstCCall(nodep->fileline(), funcp); - callp->argTypes("vlSymsp"); - m_initFuncp->addStmtsp(callp); - } else { - nodep->unlinkFrBack(); - } - nodep->deleteTree(); nodep=NULL; - } virtual void visit(AstCFunc* nodep, AstNUser*) { nodep->iterateChildren(*this); // Link to global function @@ -365,13 +343,14 @@ private: if (m_untilp) m_untilp->addBodysp(stmtsp); // In a until loop, add to body else m_settleFuncp->addStmtsp(stmtsp); // else add to top level function } + void addToInitial(AstNode* stmtsp) { + if (m_untilp) m_untilp->addBodysp(stmtsp); // In a until loop, add to body + else m_initFuncp->addStmtsp(stmtsp); // else add to top level function + } virtual void visit(AstActive* nodep, AstNUser*) { // Careful if adding variables here, ACTIVES can be under other ACTIVES // Need to save and restore any member state in AstUntilStable block - if (nodep->hasInitial()) { - moveInitial(nodep); - } - else if (!m_topScopep || !nodep->stmtsp()) { + if (!m_topScopep || !nodep->stmtsp()) { // Not at the top or empty block... // Only empty blocks should be leftover on the non-top. Killem. if (nodep->stmtsp()) nodep->v3fatalSrc("Non-empty lower active"); @@ -381,6 +360,7 @@ private: AstNode* stmtsp = nodep->stmtsp()->unlinkFrBackWithNext(); if (nodep->hasClocked()) { // Remember the latest sensitivity so we can compare it next time + if (nodep->hasInitial()) nodep->v3fatalSrc("Initial block should not have clock sensitivity"); if (m_lastSenp && nodep->sensesp()->sameTree(m_lastSenp)) { UINFO(4," sameSenseTree\n"); } else { @@ -392,6 +372,10 @@ private: } // Move statements to if m_lastIfp->addIfsp(stmtsp); + } else if (nodep->hasInitial()) { + // Don't need to: clearLastSen();, as we're adding it to different cfunc + // Move statements to function + addToInitial(stmtsp); } else if (nodep->hasSettle()) { // Don't need to: clearLastSen();, as we're adding it to different cfunc // Move statements to function diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 6635b621b..fa5965c53 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -690,7 +690,8 @@ class EmitCImp : EmitCStmts { } changep->lhsp()->iterateAndNext(*this); if (changep->lhsp()->isWide()) puts("["+cvtToStr(word)+"]"); - puts(" ^ "); + if (changep->lhsp()->isDouble()) puts(" != "); + else puts(" ^ "); changep->rhsp()->iterateAndNext(*this); if (changep->lhsp()->isWide()) puts("["+cvtToStr(word)+"]"); puts(")"); diff --git a/src/V3Order.cpp b/src/V3Order.cpp index cd36f5830..e48f8f46d 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -339,7 +339,8 @@ private: varscp->user1p(newup); } OrderUser* up = (OrderUser*)(varscp->user1p()); - return up->newVarUserVertex(&m_graph, m_scopep, varscp, type, createdp); + OrderVarVertex* varVxp = up->newVarUserVertex(&m_graph, m_scopep, varscp, type, createdp); + return varVxp; } V3GraphEdge* findEndEdge(V3GraphVertex* vertexp, AstNode* errnodep, OrderLoopEndVertex*& evertexpr) { @@ -396,41 +397,56 @@ private: void nodeMarkCircular(OrderVarVertex* vertexp, OrderEdge* edgep) { AstVarScope* nodep = vertexp->varScp(); - nodep->circular(true); - ++m_statCut[vertexp->type()]; - if (edgep) ++m_statCut[edgep->type()]; - if (vertexp->isClock()) { - // Seems obvious; no warning yet - //nodep->v3warn(GENCLK,"Signal unoptimizable: Generated clock: "<prettyName()); - } else if (nodep->varp()->isSigPublic()) { - nodep->v3warn(UNOPT,"Signal unoptimizable: Feedback to public clock or circular logic: "<prettyName()); - if (!nodep->fileline()->warnIsOff(V3ErrorCode::UNOPT)) { - nodep->fileline()->modifyWarnOff(V3ErrorCode::UNOPT, true); // Complain just once - // Give the user an example. - bool tempWeight = (edgep && edgep->weight()==0); - if (tempWeight) edgep->weight(1); // Else the below loop detect can't see the loop - m_graph.reportLoops(&OrderEdge::followComboConnected, vertexp); // calls OrderGraph::loopsVertexCb - if (tempWeight) edgep->weight(0); - } - } else { - // We don't use UNOPT, as there are lots of V2 places where it was needed, that aren't any more - // First v3warn not inside warnIsOff so we can see the suppressions with --debug - nodep->v3warn(UNOPTFLAT,"Signal unoptimizable: Feedback to clock or circular logic: "<prettyName()); - if (!nodep->fileline()->warnIsOff(V3ErrorCode::UNOPTFLAT)) { - nodep->fileline()->modifyWarnOff(V3ErrorCode::UNOPTFLAT, true); // Complain just once - // Give the user an example. - bool tempWeight = (edgep && edgep->weight()==0); - if (tempWeight) edgep->weight(1); // Else the below loop detect can't see the loop - m_graph.reportLoops(&OrderEdge::followComboConnected, vertexp); // calls OrderGraph::loopsVertexCb - if (tempWeight) edgep->weight(0); - if (v3Global.opt.reportUnoptflat()) { - // Report candidate variables for splitting - reportLoopVars(vertexp); - // Do a subgraph for the UNOPTFLAT loop - OrderGraph loopGraph; - m_graph.subtreeLoops(&OrderEdge::followComboConnected, - vertexp, &loopGraph); - loopGraph.dumpDotFilePrefixedAlways("unoptflat"); + OrderLogicVertex* fromLVtxp = NULL; + OrderLogicVertex* toLVtxp = NULL; + if (edgep) { + fromLVtxp = dynamic_cast(edgep->fromp()); + toLVtxp = dynamic_cast(edgep->top()); + } + // + if ((fromLVtxp && fromLVtxp->nodep()->castInitial()) + || (toLVtxp && toLVtxp->nodep()->castInitial())) { + // IEEE does not specify ordering between initial blocks, so we can do whatever we want + // We especially do not want to evaluate multiple times, so do not mark the edge circular + } + else { + nodep->circular(true); + ++m_statCut[vertexp->type()]; + if (edgep) ++m_statCut[edgep->type()]; + // + if (vertexp->isClock()) { + // Seems obvious; no warning yet + //nodep->v3warn(GENCLK,"Signal unoptimizable: Generated clock: "<prettyName()); + } else if (nodep->varp()->isSigPublic()) { + nodep->v3warn(UNOPT,"Signal unoptimizable: Feedback to public clock or circular logic: "<prettyName()); + if (!nodep->fileline()->warnIsOff(V3ErrorCode::UNOPT)) { + nodep->fileline()->modifyWarnOff(V3ErrorCode::UNOPT, true); // Complain just once + // Give the user an example. + bool tempWeight = (edgep && edgep->weight()==0); + if (tempWeight) edgep->weight(1); // Else the below loop detect can't see the loop + m_graph.reportLoops(&OrderEdge::followComboConnected, vertexp); // calls OrderGraph::loopsVertexCb + if (tempWeight) edgep->weight(0); + } + } else { + // We don't use UNOPT, as there are lots of V2 places where it was needed, that aren't any more + // First v3warn not inside warnIsOff so we can see the suppressions with --debug + nodep->v3warn(UNOPTFLAT,"Signal unoptimizable: Feedback to clock or circular logic: "<prettyName()); + if (!nodep->fileline()->warnIsOff(V3ErrorCode::UNOPTFLAT)) { + nodep->fileline()->modifyWarnOff(V3ErrorCode::UNOPTFLAT, true); // Complain just once + // Give the user an example. + bool tempWeight = (edgep && edgep->weight()==0); + if (tempWeight) edgep->weight(1); // Else the below loop detect can't see the loop + m_graph.reportLoops(&OrderEdge::followComboConnected, vertexp); // calls OrderGraph::loopsVertexCb + if (tempWeight) edgep->weight(0); + if (v3Global.opt.reportUnoptflat()) { + // Report candidate variables for splitting + reportLoopVars(vertexp); + // Do a subgraph for the UNOPTFLAT loop + OrderGraph loopGraph; + m_graph.subtreeLoops(&OrderEdge::followComboConnected, + vertexp, &loopGraph); + loopGraph.dumpDotFilePrefixedAlways("unoptflat"); + } } } } @@ -580,7 +596,6 @@ private: } virtual void visit(AstActive* nodep, AstNUser*) { // Create required activation blocks and add to module - if (nodep->hasInitial()) return; // Ignore initials UINFO(4," ACTIVE "<hasSettle()) { // or, we can ignore being in the settle domain + || domainp->hasSettle() // or, we can ignore being in the settle domain + || domainp->hasInitial()) { domainp = fromVertexp->domainp(); } else if (domainp->hasCombo()) { @@ -1006,7 +1027,8 @@ void OrderVisitor::processDomainsIterate(OrderEitherVertex* vertexp) { // Any combo input means this vertex must remain combo domainp = m_comboDomainp; } - else if (fromVertexp->domainp()->hasSettle()) { + else if (fromVertexp->domainp()->hasSettle() + || fromVertexp->domainp()->hasInitial()) { // Ignore that we have a constant (initial) input } else if (domainp != fromVertexp->domainp()) { diff --git a/test_regress/t/t_gen_upscope.pl b/test_regress/t/t_gen_upscope.pl index 3ff40a3b1..b6cd565dd 100755 --- a/test_regress/t/t_gen_upscope.pl +++ b/test_regress/t/t_gen_upscope.pl @@ -13,9 +13,9 @@ compile ( execute ( check_finished=>1, expect=>quotemeta( -q{created tag with scope = top.v.tag -created tag with scope = top.v.b.gen[0].tag +q{created tag with scope = top.v.b.gen[0].tag created tag with scope = top.v.b.gen[1].tag +created tag with scope = top.v.tag mod a has scope = top.v mod a has tag = top.v.tag mod b has scope = top.v.b diff --git a/test_regress/t/t_unoptflat_simple_2_bad.pl b/test_regress/t/t_unoptflat_simple_2_bad.pl index 77d7a8066..493894ecb 100755 --- a/test_regress/t/t_unoptflat_simple_2_bad.pl +++ b/test_regress/t/t_unoptflat_simple_2_bad.pl @@ -15,7 +15,7 @@ compile ( fails => 1, expect=> '.*%Warning-UNOPTFLAT: Widest candidate vars to split: -%Warning-UNOPTFLAT: t/t_unoptflat_simple_2.v:\d+: v.x, width 3, fanout 12 +%Warning-UNOPTFLAT: t/t_unoptflat_simple_2.v:\d+: v.x, width 3, fanout \d+ .*%Error: Exiting due to ', );