forked from github/verilator
Internals: Common insert function in tristate. No functional change.
This commit is contained in:
parent
33c8bf886e
commit
2c9e2b2e3c
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user