forked from github/verilator
Order initial statements based on variables used. Merge from bug683 branch.
This commit is contained in:
parent
3b43556c41
commit
091818483a
@ -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
|
||||
|
@ -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(")");
|
||||
|
100
src/V3Order.cpp
100
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: "<<nodep->prettyName());
|
||||
} else if (nodep->varp()->isSigPublic()) {
|
||||
nodep->v3warn(UNOPT,"Signal unoptimizable: Feedback to public clock or circular logic: "<<nodep->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: "<<nodep->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<OrderLogicVertex*>(edgep->fromp());
|
||||
toLVtxp = dynamic_cast<OrderLogicVertex*>(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: "<<nodep->prettyName());
|
||||
} else if (nodep->varp()->isSigPublic()) {
|
||||
nodep->v3warn(UNOPT,"Signal unoptimizable: Feedback to public clock or circular logic: "<<nodep->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: "<<nodep->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 "<<nodep<<endl);
|
||||
m_activep = nodep;
|
||||
m_activeSenVxp = NULL;
|
||||
@ -758,6 +773,11 @@ private:
|
||||
virtual void visit(AstCoverToggle* nodep, AstNUser*) {
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
virtual void visit(AstInitial* nodep, AstNUser*) {
|
||||
// We use initials to setup parameters and static consts's which may be referenced
|
||||
// in user initial blocks. So use ordering to sort them all out.
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
virtual void visit(AstCFunc*, AstNUser*) {
|
||||
// Ignore for now
|
||||
// We should detect what variables are set in the function, and make
|
||||
@ -996,7 +1016,8 @@ void OrderVisitor::processDomainsIterate(OrderEitherVertex* vertexp) {
|
||||
) {
|
||||
UINFO(9," from d="<<(void*)fromVertexp->domainp()<<" "<<fromVertexp<<endl);
|
||||
if (!domainp // First input to this vertex
|
||||
|| domainp->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()) {
|
||||
|
@ -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
|
||||
|
@ -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 ',
|
||||
);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user