From 7bd96c2876cd8850b4bad599ab8559a975ef1b9f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 27 Feb 2013 22:59:17 -0500 Subject: [PATCH] Internals: Tristate commentary --- src/V3Tristate.cpp | 68 ++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index f7de1e31b..8631f6e34 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -52,6 +52,9 @@ // to an input and the __out port carries the output driver signal and // the __en port carried the output enable for that driver. // +// Note 1800-2012 adds user defined resolution functions. This suggests +// long term this code should be scoped-based and resolve all nodes at once +// rather than hierarchically. //************************************************************************* #include "config_build.h" @@ -222,6 +225,7 @@ public: } } m_graph.clear(); + AstNode::user5ClearTree(); // Wipe all node user5p's that point to vertexes } void graphWalk(AstNodeModule* nodep) { //if (debug()>=9) m_graph.dumpDotFilePrefixed("tri_pre__"+nodep->name()); @@ -494,6 +498,7 @@ class TristateVisitor : public TristateBaseVisitor { // Now go through the lhs driver map and generate the output // enable logic for any tristates. + // Note there might not be any drivers. for (VarMap::iterator nextit, it = m_lhsmap.begin(); it != m_lhsmap.end(); it = nextit) { nextit = it; ++nextit; AstVar* invarp = (*it).first; @@ -518,8 +523,8 @@ class TristateVisitor : public TristateBaseVisitor { // if this is the top level so that we can force the final // tristate resolution at the top. AstVar* envarp = NULL; - AstVar* outvarp = NULL; - AstVar* lhsp = invarp; + AstVar* outvarp = NULL; // __out + AstVar* lhsp = invarp; // Variable to assign drive-value to ( or __out) if (!nodep->isTop() && invarp->isIO()) { // This var becomes an input invarp->varType2In(); // convert existing port to type input @@ -589,12 +594,10 @@ class TristateVisitor : public TristateBaseVisitor { undrivenp = ((!undrivenp) ? tmp : new AstAnd(nodep->fileline(), tmp, undrivenp)); } - if (!undrivenp) { // No drivers on the bus V3Number ones(nodep->fileline(), lhsp->width()); ones.setAllBits1(); undrivenp = new AstConst(nodep->fileline(), ones); } - if (!outvarp) { // This is the final resolution of the tristate, so we apply // the pull direction to any undriven pins. @@ -617,7 +620,7 @@ class TristateVisitor : public TristateBaseVisitor { new AstVarRef(envarp->fileline(), envarp, true), enp)); } - + // __out (child) or (parent) = drive-value expression AstNode* assp = new AstAssignW(lhsp->fileline(), new AstVarRef(lhsp->fileline(), lhsp, @@ -661,7 +664,7 @@ class TristateVisitor : public TristateBaseVisitor { AstConst* enp = new AstConst(fl, numz0); nodep->replaceWith(newconstp); pushDeletep(nodep); nodep = NULL; - newconstp->user1p(enp); + newconstp->user1p(enp); // propagate up constant with non-Z bits as 1 } } } @@ -698,7 +701,7 @@ class TristateVisitor : public TristateBaseVisitor { // two expressions with the same conditional. AstNode* enp = new AstCond(nodep->fileline(), condp->cloneTree(false), en1p, en2p); UINFO(9," newcond "<user1p(enp); + nodep->user1p(enp); // propagate up COND(lhsp->enable, rhsp->enable) expr1p->user1p(NULL); expr2p->user1p(NULL); } @@ -735,7 +738,7 @@ class TristateVisitor : public TristateBaseVisitor { AstNode* enp = new AstSel(nodep->fileline(), en1p, nodep->lsbp()->cloneTree(true), nodep->widthp()->cloneTree(true)); UINFO(9," newsel "<user1p(enp); + nodep->user1p(enp); // propagate up SEL(fromp->enable, value) m_tgraph.didProcess(nodep); } } @@ -783,7 +786,7 @@ class TristateVisitor : public TristateBaseVisitor { AstNode* en2p = getEnp(expr2p); AstNode* enp = new AstConcat(nodep->fileline(), en1p, en2p); UINFO(9," newconc "<user1p(enp); + nodep->user1p(enp); // propagate up CONCAT(lhsp->enable, rhsp->enable) expr1p->user1p(NULL); expr2p->user1p(NULL); } @@ -925,14 +928,14 @@ class TristateVisitor : public TristateBaseVisitor { checkUnhandled(nodep); // Unsupported: A === 3'b000 should compare with the enables, but we don't do // so at present, we only compare if there is a z in the equation. - // Otherwise we'd need to attach an enable to every signal, then optimize then + // Otherwise we'd need to attach an enable to every signal, then optimize them // away later when we determine the signal has no tristate nodep->iterateChildren(*this); UINFO(9,dbgState()<lhsp()->castConst(); // Constification always moves const to LHS AstVarRef* varrefp = nodep->rhsp()->castVarRef(); // Input variable if (constp && constp->user1p() && varrefp) { - // 3'b1z0 -> ((3'b101 == __en) && (3'b100 == __in)) + // 3'b1z0 -> ((3'b101 == in__en) && (3'b100 == in)) varrefp->unlinkFrBack(); FileLine* fl = nodep->fileline(); V3Number oneIfEn = constp->user1p()->castNode()->castConst()->num(); // visit(AstConst) already split into en/ones @@ -1021,19 +1024,20 @@ class TristateVisitor : public TristateBaseVisitor { // ENABLE: -> (VARREF(trisig__pinen) // Added complication is the signal may be an output/inout or just input with tie off (or not) up top // PIN PORT NEW PORTS AND CONNECTIONS - // N/C input in(from-resolver), __out(to-resolver-only), __en(to-resolver-only) + // N/C input in(from-resolver), __en(to-resolver-only), __out(to-resolver-only) // N/C inout Spec says illegal // N/C output Unsupported; Illegal? - // wire input in(from-resolver-with-wire-value), __out(to-resolver-only), __en(to-resolver-only) - // wire inout in, __out, __en - // wire output in, __out, __en - // const input in(from-resolver-with-const-value), __out(to-resolver-only), __en(to-resolver-only) - // const inout Spec says illegal - // const output Unsupported; Illegal? + // wire input in(from-resolver-with-wire-value), __en(from-resolver-wire), __out(to-resolver-only) + // wire inout in, __en, __out + // wire output in, __en, __out + // const input in(from-resolver-with-const-value), __en(from-resolver-const), __out(to-resolver-only) + // const inout Spec says illegal + // const output Unsupported; Illegal? virtual void visit(AstPin* nodep, AstNUser*) { if (m_graphing) { if (nodep->user2() & U2_GRAPHING) return; // This pin is already expanded nodep->user2(U2_GRAPHING); + // Find child module's new variables. AstVar* enModVarp = (AstVar*) nodep->modVarp()->user1p(); if (!enModVarp) { if (nodep->exprp()) { @@ -1048,7 +1052,7 @@ class TristateVisitor : public TristateBaseVisitor { if (debug()>=9) nodep->dumpTree(cout,"-pin-pre: "); // Empty/in-only; need Z to propagate - bool inOnlyProcessing = (nodep->exprp() + bool inDeclProcessing = (nodep->exprp() && nodep->modVarp()->isInOnly() // Need to consider the original state instead of current state // as we converted tristates to inputs, which do not want to have this. @@ -1060,7 +1064,7 @@ class TristateVisitor : public TristateBaseVisitor { nodep->modVarp()->isOutput())); m_tgraph.setTristate(ucVarp); // We don't need a driver on the wire; the lack of one will default to tristate - } else if (inOnlyProcessing) { // Not an input that was a converted tristate + } else if (inDeclProcessing) { // Not an input that was a converted tristate // Input only may have driver in underneath module which would stomp // the input value. So make a temporary connection. AstAssignW* reAssignp = V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp, true, true); @@ -1077,7 +1081,7 @@ class TristateVisitor : public TristateBaseVisitor { AstVar* enVarp = new AstVar(nodep->fileline(), AstVarType::MODULETEMP, nodep->name() + "__en" + cvtToStr(m_unique++), - VFlagLogicPacked(), enModVarp->width()); + VFlagBitPacked(), enModVarp->width()); UINFO(9," newenv "<fileline(), nodep->pinNum(), @@ -1107,7 +1111,7 @@ class TristateVisitor : public TristateBaseVisitor { outpinp->user2(U2_BOTH); // don't iterate the pin later nodep->addNextHere(outpinp); // Simplify - if (inOnlyProcessing) { // Not an input that was a converted tristate + if (inDeclProcessing) { // Not an input that was a converted tristate // The pin is an input, but we need an output // The if() above is needed because the Visitor is simple, it will flip ArraySel's and such, // but if the pin is an input the earlier reconnectSimple made it a VarRef without any ArraySel, etc @@ -1127,29 +1131,29 @@ class TristateVisitor : public TristateBaseVisitor { if (debug()>=9 && inAssignp) inAssignp->dumpTree(cout,"-pin-as: "); // Connect enable to output signal - AstVarRef* outrefp; + AstVarRef* exprrefp; // Tristate variable that the Pin's expression refers to if (!outAssignp) { - outrefp = outpinp->exprp()->castVarRef(); + exprrefp = outpinp->exprp()->castVarRef(); } else { - outrefp = outAssignp->rhsp()->castVarRef(); // This should be the same var as the output pin + exprrefp = outAssignp->rhsp()->castVarRef(); // This should be the same var as the output pin } - if (!outrefp) { // deal with simple varref port + if (!exprrefp) { // deal with simple varref port // pinReconnect should have converted this nodep->v3error("Unsupported tristate port expression: "<exprp()->prettyTypeName()); } else { - UINFO(9,"outref "<user1p(enrefp); // Mark as now tristated; iteration will pick it up from there + UINFO(9,"outref "<user1p(enrefp); // Mark as now tristated; iteration will pick it up from there if (!outAssignp) { - mapInsertLhsVarRef(outrefp); // insertTristates will convert + mapInsertLhsVarRef(exprrefp); // insertTristates will convert // // to a varref to the __out# variable } // else the assignment deals with the connection } // Propagate any pullups/pulldowns upwards if necessary - if (outrefp) { + if (exprrefp) { if (AstPull* pullp = (AstPull*) nodep->modVarp()->user3p()) { - UINFO(9, "propagate pull on "<varp(), pullp); + UINFO(9, "propagate pull on "<varp(), pullp); } }