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());
|
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
|
// VISITORS
|
||||||
virtual void visit(AstConst* nodep, AstNUser*) {
|
virtual void visit(AstConst* nodep, AstNUser*) {
|
||||||
UINFO(9,(m_alhs?"alhs":"")<<" "<<nodep<<endl);
|
UINFO(9,(m_alhs?"alhs":"")<<" "<<nodep<<endl);
|
||||||
@ -648,172 +816,10 @@ class TristateVisitor : public TristateBaseVisitor {
|
|||||||
m_lhsmap.clear();
|
m_lhsmap.clear();
|
||||||
m_varvec.clear();
|
m_varvec.clear();
|
||||||
m_modp = nodep;
|
m_modp = nodep;
|
||||||
|
// Build the LHS drivers map for this module
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
// Go through all the vars and find any that are outputs without drivers
|
// Insert new logic for all tristates
|
||||||
// or inouts without high-Z logic and put a 1'bz driver on them and add
|
insertTristates(nodep);
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
m_modp = NULL;
|
m_modp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user