Fix $countbits(..., 'z)

This commit is contained in:
Wilson Snyder 2020-11-27 21:34:40 -05:00
parent 0c6bd42da3
commit d77beecc6e
4 changed files with 63 additions and 4 deletions

View File

@ -937,10 +937,11 @@ bool V3Number::isAnyX() const {
} }
return false; return false;
} }
bool V3Number::isAnyXZ() const { bool V3Number::isAnyXZ() const { return isAnyX() || isAnyZ(); }
bool V3Number::isAnyZ() const {
if (isDouble() || isString()) return false; if (isDouble() || isString()) return false;
for (int bit = 0; bit < width(); bit++) { for (int bit = 0; bit < width(); bit++) {
if (bitIsX(bit) || bitIsZ(bit)) return true; if (bitIsZ(bit)) return true;
} }
return false; return false;
} }

View File

@ -273,6 +273,7 @@ public:
void isSigned(bool ssigned) { m_signed = ssigned; } void isSigned(bool ssigned) { m_signed = ssigned; }
bool isAnyX() const; bool isAnyX() const;
bool isAnyXZ() const; bool isAnyXZ() const;
bool isAnyZ() const;
bool isMsbXZ() const { return bitIsXZ(m_width); } bool isMsbXZ() const { return bitIsXZ(m_width); }
uint32_t toUInt() const; uint32_t toUInt() const;
vlsint32_t toSInt() const; vlsint32_t toSInt() const;

View File

@ -981,6 +981,65 @@ class TristateVisitor final : public TristateBaseVisitor {
virtual void visit(AstEqWild* nodep) override { visitEqNeqWild(nodep); } virtual void visit(AstEqWild* nodep) override { visitEqNeqWild(nodep); }
virtual void visit(AstNeqWild* nodep) override { visitEqNeqWild(nodep); } virtual void visit(AstNeqWild* nodep) override { visitEqNeqWild(nodep); }
virtual void visit(AstCountBits* nodep) override {
std::array<bool, 3> dropop;
dropop[0] = VN_IS(nodep->rhsp(), Const) && VN_CAST(nodep->rhsp(), Const)->num().isAnyZ();
dropop[1] = VN_IS(nodep->thsp(), Const) && VN_CAST(nodep->thsp(), Const)->num().isAnyZ();
dropop[2] = VN_IS(nodep->fhsp(), Const) && VN_CAST(nodep->fhsp(), Const)->num().isAnyZ();
UINFO(4, " COUNTBITS(" << dropop[0] << dropop[1] << dropop[2] << " " << nodep << endl);
AstVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef); // Input variable
if (m_graphing) {
iterateAndNextNull(nodep->lhsp());
if (!dropop[0]) iterateAndNextNull(nodep->rhsp());
if (!dropop[1]) iterateAndNextNull(nodep->thsp());
if (!dropop[2]) iterateAndNextNull(nodep->fhsp());
} else {
AstNode* nonXp = nullptr;
if (!dropop[0])
nonXp = nodep->rhsp();
else if (!dropop[1])
nonXp = nodep->thsp();
else if (!dropop[2])
nonXp = nodep->fhsp();
// Replace 'z with non-Z
if (dropop[0] || dropop[1] || dropop[2]) {
// Unsupported: A $countones('0) 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 them away later
// when we determine the signal has no tristate
if (!VN_IS(nodep->lhsp(), VarRef)) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported LHS tristate construct: "
<< nodep->prettyTypeName());
return;
}
AstVar* envarp = getCreateEnVarp(varrefp->varp());
// If any drops, we need to add in the count of Zs (from __en)
UINFO(4, " COUNTBITS('z)-> " << nodep << endl);
AstNRelinker relinkHandle;
nodep->unlinkFrBack(&relinkHandle);
AstNode* newp = new AstCountOnes(
nodep->fileline(), new AstVarRef(nodep->fileline(), envarp, VAccess::READ));
if (nonXp) { // Need to still count '0 or '1 or 'x's
if (dropop[0]) {
nodep->rhsp()->unlinkFrBack()->deleteTree();
nodep->rhsp(nonXp->cloneTree(true));
}
if (dropop[1]) {
nodep->thsp()->unlinkFrBack()->deleteTree();
nodep->thsp(nonXp->cloneTree(true));
}
if (dropop[2]) {
nodep->fhsp()->unlinkFrBack()->deleteTree();
nodep->fhsp(nonXp->cloneTree(true));
}
newp = new AstAdd(nodep->fileline(), nodep, newp);
}
if (debug() >= 9) newp->dumpTree(cout, "-countout: ");
relinkHandle.relink(newp);
}
iterateChildren(nodep);
}
}
virtual void visit(AstPull* nodep) override { virtual void visit(AstPull* nodep) override {
UINFO(9, dbgState() << nodep << endl); UINFO(9, dbgState() << nodep << endl);
AstVarRef* varrefp = nullptr; AstVarRef* varrefp = nullptr;

View File

@ -96,7 +96,6 @@ module t(/*AUTOARG*/
if ($countbits(val, '1, '1, 'x) != 7) $stop; if ($countbits(val, '1, '1, 'x) != 7) $stop;
if ($countbits(val, 'x, '0) != 25) $stop; if ($countbits(val, 'x, '0) != 25) $stop;
if ($countbits(val, 'x, '0, '1) != 32) $stop; if ($countbits(val, 'x, '0, '1) != 32) $stop;
`ifndef VERILATOR
// Optimization may depend on position of Z, so need to walk it // Optimization may depend on position of Z, so need to walk it
if ($countbits(val, 'z) != 0) $stop; if ($countbits(val, 'z) != 0) $stop;
if ($countbits(val, 'z, '1) != 7) $stop; if ($countbits(val, 'z, '1) != 7) $stop;
@ -106,7 +105,6 @@ module t(/*AUTOARG*/
if ($countbits(val, 'z, '0, '1) != 32) $stop; if ($countbits(val, 'z, '0, '1) != 32) $stop;
// //
if ($countbits(val, 'x, 'z) != 0) $stop; if ($countbits(val, 'x, 'z) != 0) $stop;
`endif
end end
else if (cyc == 1) begin else if (cyc == 1) begin
in16 <= 16'h0AF0; in16 <= 16'h0AF0;