Internals: Common insert function in tristate. No functional change.

This commit is contained in:
Wilson Snyder 2012-05-05 14:55:35 -04:00
parent 33c8bf886e
commit 2c9e2b2e3c

View File

@ -202,6 +202,174 @@ class TristateVisitor : public TristateBaseVisitor {
nodep->v3error("Unsupported tristate construct: "<<nodep->prettyTypeName());
}
void insertTristates(AstNodeModule* nodep) {
// Go through all the vars and find any that are outputs without drivers
// or inouts without high-Z logic and put a 1'bz driver on them and add
// them to the lhs map so they get expanded correctly.
for (VarVec::iterator ii = m_varvec.begin(); ii != m_varvec.end(); ++ii) {
AstVar* varp = (*ii);
if (varp->isInout()
//|| varp->isOutput()
// Note unconnected output only changes behavior vs. previous versions and causes outputs
// that don't come from anywhere to possibly create connection errors.
// One example of problems is this: "output z; task t; z <= {something}; endtask"
) {
VarMap::iterator it = m_lhsmap.find(varp);
if (it == m_lhsmap.end()) {
UINFO(8," Adding driver to var "<<varp<<endl);
V3Number zeros (varp->fileline(), varp->width());
zeros.setAllBits0();
AstConst* constp = new AstConst(varp->fileline(), zeros);
AstVarRef* varrefp = new AstVarRef(varp->fileline(), varp, true);
nodep->addStmtp(new AstAssignW(varp->fileline(), varrefp, constp));
visit(varrefp, NULL);
varrefp->user1p(new AstConst(varp->fileline(),zeros));//set output enable to always be off on this assign statement so that this var is floating
}
}
}
// Now go through the lhs driver map and generate the output
// enable logic for any tristates.
for (VarMap::iterator nextit, it = m_lhsmap.begin(); it != m_lhsmap.end(); it = nextit) {
nextit = it; ++nextit;
AstVar* invarp = (*it).first;
RefVec* refs = (*it).second;
// Figure out if this var needs tristate expanded.
int needs_expanded = 0;
// If need enable signal gets expanded
if (invarp->user1p()) { needs_expanded++; }
// all inouts get expanded
if (invarp->isInout()) { needs_expanded++; }
// loop through to find all vars that have __en logic. They get expanded.
for (RefVec::iterator ii = refs->begin(); ii != refs->end(); ++ii) {
AstVarRef* refp = (*ii);
if (refp->user1p()) { needs_expanded++; }
}
if (needs_expanded == 0) {
// This var has no tristate logic, so we leave it alone.
UINFO(8, " NO TRISTATE ON:" << invarp << endl);
m_lhsmap.erase(invarp);
delete refs;
continue;
}
m_statTriSigs++;
UINFO(8, " TRISTATE EXPANDING("<<needs_expanded<<"):" << invarp << endl);
// If the lhs var is a port, then we need to create ports for
// the output (__out) and output enable (__en) signals. The
// original port gets converted to an input. Don't tristate expand
// 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;
if (!nodep->isTop() && invarp->isIO()) {
// This var becomes an input
invarp->varType2In(); // convert existing port to type input
// Create an output port (__out)
AstVar* outvarp = getCreateOutVarp(invarp);
outvarp->varType2Out();
lhsp = outvarp; // Must assign to __out, not to normal input signal
// Create an output enable port (__en)
envarp = getCreateEnVarp(invarp); // May already be created if have foo === 1'bz somewhere
envarp->varType2Out();
//
outvarp->user1p(envarp);
outvarp->user3p(invarp->user3p());
if (invarp->user3p()) UINFO(9, "propagate pull to "<<outvarp);
} else if (invarp->user1p()) {
envarp = invarp->user1p()->castNode()->castVar(); // From CASEEQ, foo === 1'bz
}
AstNode* orp = NULL;
AstNode* andp = NULL;
AstNode* enp = NULL;
AstNode* undrivenp = NULL;
// loop through the lhs drivers to build the driver resolution logic
for (RefVec::iterator ii=refs->begin(); ii != refs->end(); ++ii) {
AstVarRef* refp = (*ii);
int w = lhsp->width();
// create the new lhs driver for this var
AstVar* newlhsp = new AstVar(lhsp->fileline(),
AstVarType::MODULETEMP,
lhsp->name()+"__out"+cvtToStr(m_unique),
VFlagLogicPacked(), w);
nodep->addStmtp(newlhsp);
refp->varp(newlhsp); // assign the new var to the varref
refp->name(newlhsp->name());
// create a new var for this drivers enable signal
AstVar* newenp = new AstVar(lhsp->fileline(),
AstVarType::MODULETEMP,
lhsp->name()+"__en"+cvtToStr(m_unique++),
VFlagLogicPacked(), w);
nodep->addStmtp(newenp);
nodep->addStmtp(new AstAssignW(refp->fileline(),
new AstVarRef(refp->fileline(), newenp, true),
getEnp(refp)));
// now append this driver to the driver logic.
AstNode* ref1p = new AstVarRef(nodep->fileline(), newlhsp,false);
AstNode* ref2p = new AstVarRef(nodep->fileline(), newenp, false);
andp = new AstAnd(nodep->fileline(), ref1p, ref2p);
// or this to the others
orp = (!orp) ? andp : new AstOr(nodep->fileline(), orp, andp);
if (envarp) {
AstNode* ref3p = new AstVarRef(nodep->fileline(), newenp, false);
enp = (!enp) ? ref3p : new AstOr(ref3p->fileline(), enp, ref3p);
}
AstNode* tmp = new AstNot(newenp->fileline(), new AstVarRef(newenp->fileline(), newenp, false));
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.
V3Number pull(nodep->fileline(), lhsp->width());
AstPull* pullp = (AstPull*)lhsp->user3p();
if (pullp && pullp->direction() == 1) {
pull.setAllBits1();
UINFO(9,"Has pullup "<<pullp<<endl);
} else {
pull.setAllBits0(); // default pull direction is down.
}
undrivenp = new AstAnd(nodep->fileline(), undrivenp,
new AstConst(nodep->fileline(), pull));
orp = new AstOr(nodep->fileline(), orp, undrivenp);
}
if (envarp) {
nodep->addStmtp(new AstAssignW(enp->fileline(),
new AstVarRef(envarp->fileline(),
envarp, true), enp));
}
AstNode* assp = new AstAssignW(lhsp->fileline(),
new AstVarRef(lhsp->fileline(),
lhsp,
true),
orp);
if (debug()>=9) assp->dumpTree(cout,"-lhsp-eqn: ");
nodep->addStmtp(assp);
// Delete the map and vector list now that we have expanded it.
m_lhsmap.erase(invarp);
delete refs;
}
}
// VISITORS
virtual void visit(AstConst* nodep, AstNUser*) {
UINFO(9,(m_alhs?"alhs":"")<<" "<<nodep<<endl);
@ -648,172 +816,10 @@ class TristateVisitor : public TristateBaseVisitor {
m_lhsmap.clear();
m_varvec.clear();
m_modp = nodep;
// Build the LHS drivers map for this module
nodep->iterateChildren(*this);
// Go through all the vars and find any that are outputs without drivers
// or inouts without high-Z logic and put a 1'bz driver on them and add
// them to the lhs map so they get expanded correctly.
for (VarVec::iterator ii = m_varvec.begin(); ii != m_varvec.end(); ++ii) {
AstVar* varp = (*ii);
if (varp->isInout()
//|| varp->isOutput()
// Note unconnected output only changes behavior vs. previous versions and causes outputs
// that don't come from anywhere to possibly create connection errors.
// One example of problems is this: "output z; task t; z <= {something}; endtask"
) {
VarMap::iterator it = m_lhsmap.find(varp);
if (it == m_lhsmap.end()) {
UINFO(8," Adding driver to var "<<varp<<endl);
V3Number zeros (varp->fileline(), varp->width());
zeros.setAllBits0();
AstConst* constp = new AstConst(varp->fileline(), zeros);
AstVarRef* varrefp = new AstVarRef(varp->fileline(), varp, true);
nodep->addStmtp(new AstAssignW(varp->fileline(), varrefp, constp));
visit(varrefp, NULL);
varrefp->user1p(new AstConst(varp->fileline(),zeros));//set output enable to always be off on this assign statement so that this var is floating
}
}
}
// Now go through the lhs driver map and generate the output
// enable logic for any tristates.
for (VarMap::iterator nextit, it = m_lhsmap.begin(); it != m_lhsmap.end(); it = nextit) {
nextit = it; ++nextit;
AstVar* invarp = (*it).first;
RefVec* refs = (*it).second;
// Figure out if this var needs tristate expanded.
int needs_expanded = 0;
// If need enable signal gets expanded
if (invarp->user1p()) { needs_expanded++; }
// all inouts get expanded
if (invarp->isInout()) { needs_expanded++; }
// loop through to find all vars that have __en logic. They get expanded.
for (RefVec::iterator ii = refs->begin(); ii != refs->end(); ++ii) {
AstVarRef* refp = (*ii);
if (refp->user1p()) { needs_expanded++; }
}
if (needs_expanded == 0) {
// This var has no tristate logic, so we leave it alone.
UINFO(8, " NO TRISTATE ON:" << invarp << endl);
m_lhsmap.erase(invarp);
delete refs;
continue;
}
m_statTriSigs++;
UINFO(8, " TRISTATE EXPANDING("<<needs_expanded<<"):" << invarp << endl);
// If the lhs var is a port, then we need to create ports for
// the output (__out) and output enable (__en) signals. The
// original port gets converted to an input. Don't tristate expand
// 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;
if (!nodep->isTop() && invarp->isIO()) {
// This var becomes an input
invarp->varType2In(); // convert existing port to type input
// Create an output port (__out)
AstVar* outvarp = getCreateOutVarp(invarp);
outvarp->varType2Out();
lhsp = outvarp; // Must assign to __out, not to normal input signal
// Create an output enable port (__en)
envarp = getCreateEnVarp(invarp); // May already be created if have foo === 1'bz somewhere
envarp->varType2Out();
//
outvarp->user1p(envarp);
outvarp->user3p(invarp->user3p());
if (invarp->user3p()) UINFO(9, "propagate pull to "<<outvarp);
} else if (invarp->user1p()) {
envarp = invarp->user1p()->castNode()->castVar(); // From CASEEQ, foo === 1'bz
}
AstNode* orp = NULL;
AstNode* andp = NULL;
AstNode* enp = NULL;
AstNode* undrivenp = NULL;
// loop through the lhs drivers to build the driver resolution logic
for (RefVec::iterator ii=refs->begin(); ii != refs->end(); ++ii) {
AstVarRef* refp = (*ii);
int w = lhsp->width();
// create the new lhs driver for this var
AstVar* newlhsp = new AstVar(lhsp->fileline(),
AstVarType::MODULETEMP,
lhsp->name()+"__out"+cvtToStr(m_unique),
VFlagLogicPacked(), w);
nodep->addStmtp(newlhsp);
refp->varp(newlhsp); // assign the new var to the varref
refp->name(newlhsp->name());
// create a new var for this drivers enable signal
AstVar* newenp = new AstVar(lhsp->fileline(),
AstVarType::MODULETEMP,
lhsp->name()+"__en"+cvtToStr(m_unique++),
VFlagLogicPacked(), w);
nodep->addStmtp(newenp);
nodep->addStmtp(new AstAssignW(refp->fileline(),
new AstVarRef(refp->fileline(), newenp, true),
getEnp(refp)));
// now append this driver to the driver logic.
AstNode* ref1p = new AstVarRef(nodep->fileline(), newlhsp,false);
AstNode* ref2p = new AstVarRef(nodep->fileline(), newenp, false);
andp = new AstAnd(nodep->fileline(), ref1p, ref2p);
// or this to the others
orp = (!orp) ? andp : new AstOr(nodep->fileline(), orp, andp);
if (envarp) {
AstNode* ref3p = new AstVarRef(nodep->fileline(), newenp, false);
enp = (!enp) ? ref3p : new AstOr(ref3p->fileline(), enp, ref3p);
}
AstNode* tmp = new AstNot(newenp->fileline(), new AstVarRef(newenp->fileline(), newenp, false));
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.
V3Number pull(nodep->fileline(), lhsp->width());
AstPull* pullp = (AstPull*)lhsp->user3p();
if (pullp && pullp->direction() == 1) {
pull.setAllBits1();
UINFO(9,"Has pullup "<<pullp<<endl);
} else {
pull.setAllBits0(); // default pull direction is down.
}
undrivenp = new AstAnd(nodep->fileline(), undrivenp,
new AstConst(nodep->fileline(), pull));
orp = new AstOr(nodep->fileline(), orp, undrivenp);
}
if (envarp) {
nodep->addStmtp(new AstAssignW(enp->fileline(),
new AstVarRef(envarp->fileline(),
envarp, true), enp));
}
AstNode* assp = new AstAssignW(lhsp->fileline(),
new AstVarRef(lhsp->fileline(),
lhsp,
true),
orp);
if (debug()>=9) assp->dumpTree(cout,"-lhsp-eqn: ");
nodep->addStmtp(assp);
// Delete the map and vector list now that we have expanded it.
m_lhsmap.erase(invarp);
delete refs;
}
// Insert new logic for all tristates
insertTristates(nodep);
m_modp = NULL;
}