mirror of
https://github.com/verilator/verilator.git
synced 2026-09-05 00:41:39 +02:00
Support simple cycle delay sequence expressions inside assertion properties (#6508)
Signed-off-by: Bartłomiej Chmiel <[email protected]> Co-authored-by: Wilson Snyder <[email protected]>
This commit is contained in:
co-authored by
Wilson Snyder
parent
2ac7cf51a9
commit
31e73f1645
+106
-23
@@ -56,10 +56,15 @@ private:
|
||||
AstNodeExpr* m_disablep = nullptr; // Last disable
|
||||
// Other:
|
||||
V3UniqueNames m_cycleDlyNames{"__VcycleDly"}; // Cycle delay counter name generator
|
||||
V3UniqueNames m_propPrecondNames{"__VpropPrecond"}; // Cycle delay temporaries name generator
|
||||
bool m_inAssign = false; // True if in an AssignNode
|
||||
bool m_inAssignDlyLhs = false; // True if in AssignDly's LHS
|
||||
bool m_inSynchDrive = false; // True if in synchronous drive
|
||||
std::vector<AstVarXRef*> m_xrefsp; // list of xrefs that need name fixup
|
||||
AstNodeExpr* m_hasUnsupp = nullptr; // True if assert has unsupported construct inside
|
||||
AstPExpr* m_pExpr = nullptr; // Current AstPExpr
|
||||
bool m_hasSExpr = false; // True if assert has AstSExpr inside
|
||||
bool m_inSExpr = false; // True if in AstSExpr
|
||||
|
||||
// METHODS
|
||||
|
||||
@@ -335,16 +340,21 @@ private:
|
||||
VL_DO_DANGLING(valuep->deleteTree(), valuep);
|
||||
return;
|
||||
}
|
||||
AstSenItem* sensesp = nullptr;
|
||||
if (!m_defaultClockingp) {
|
||||
nodep->v3error("Usage of cycle delays requires default clocking"
|
||||
" (IEEE 1800-2023 14.11)");
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(valuep->deleteTree(), valuep);
|
||||
return;
|
||||
if (!m_pExpr && !m_inSExpr) {
|
||||
nodep->v3error("Usage of cycle delays requires default clocking"
|
||||
" (IEEE 1800-2023 14.11)");
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(valuep->deleteTree(), valuep);
|
||||
return;
|
||||
}
|
||||
sensesp = m_senip;
|
||||
} else {
|
||||
sensesp = m_defaultClockingp->sensesp();
|
||||
}
|
||||
AstEventControl* const controlp = new AstEventControl{
|
||||
nodep->fileline(),
|
||||
new AstSenTree{flp, m_defaultClockingp->sensesp()->cloneTree(false)}, nullptr};
|
||||
nodep->fileline(), new AstSenTree{flp, sensesp->cloneTree(false)}, nullptr};
|
||||
const std::string delayName = m_cycleDlyNames.get(nodep);
|
||||
AstVar* const cntVarp = new AstVar{flp, VVarType::BLOCKTEMP, delayName + "__counter",
|
||||
nodep->findBasicDType(VBasicDTypeKwd::UINT32)};
|
||||
@@ -408,6 +418,33 @@ private:
|
||||
}
|
||||
}
|
||||
nodep->user1(true);
|
||||
} else if (m_inSExpr && !nodep->user1()) {
|
||||
AstVar* const preVarp
|
||||
= new AstVar{nodep->varp()->fileline(), VVarType::BLOCKTEMP,
|
||||
m_propPrecondNames.get(nodep->varp()) + "__" + nodep->varp()->name(),
|
||||
nodep->varp()->dtypep()};
|
||||
preVarp->lifetime(VLifetime::STATIC_EXPLICIT);
|
||||
m_modp->addStmtsp(preVarp);
|
||||
AstVarRef* const origp
|
||||
= new AstVarRef{nodep->fileline(), nodep->varp(), VAccess::READ};
|
||||
origp->user1(true);
|
||||
AstVarRef* const precondp
|
||||
= new AstVarRef{preVarp->fileline(), preVarp, VAccess::WRITE};
|
||||
precondp->user1(true);
|
||||
|
||||
// Pack assignments in sampled as in concurrent assertions they are needed.
|
||||
// Then, in assert's propp, sample only non-precondition variables.
|
||||
AstSampled* const sampledp = new AstSampled{origp->fileline(), origp};
|
||||
sampledp->dtypeFrom(origp);
|
||||
UASSERT(m_pExpr, "Should be under assertion");
|
||||
AstAssign* const assignp = new AstAssign{m_pExpr->fileline(), precondp, sampledp};
|
||||
m_pExpr->addPrecondp(assignp);
|
||||
|
||||
AstVarRef* const precondReadp
|
||||
= new AstVarRef{preVarp->fileline(), preVarp, VAccess::READ};
|
||||
precondReadp->user1(true);
|
||||
nodep->replaceWith(precondReadp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
void visit(AstMemberSel* nodep) override {
|
||||
@@ -461,10 +498,33 @@ private:
|
||||
|
||||
void visit(AstNodeCoverOrAssert* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
|
||||
VL_RESTORER(m_hasSExpr);
|
||||
VL_RESTORER(m_hasUnsupp);
|
||||
|
||||
clearAssertInfo();
|
||||
m_pExpr = new AstPExpr{nodep->propp()->fileline()};
|
||||
m_pExpr->dtypeFrom(nodep->propp());
|
||||
|
||||
// Find Clocking's buried under nodep->exprsp
|
||||
iterateChildren(nodep);
|
||||
if (!nodep->immediate()) nodep->sentreep(newSenTree(nodep));
|
||||
if (m_hasSExpr && m_hasUnsupp) {
|
||||
if (VN_IS(m_hasUnsupp, Implication)) {
|
||||
m_hasUnsupp->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: Implication with sequence expression");
|
||||
} else {
|
||||
m_hasUnsupp->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: Disable iff with sequence expression");
|
||||
}
|
||||
if (m_pExpr) VL_DO_DANGLING(pushDeletep(m_pExpr), m_pExpr);
|
||||
} else if (m_pExpr && m_pExpr->precondp()) {
|
||||
m_pExpr->condp(VN_AS(nodep->propp()->unlinkFrBackWithNext(), NodeExpr));
|
||||
nodep->propp(m_pExpr);
|
||||
iterateAndNextNull(m_pExpr->precondp());
|
||||
} else if (m_pExpr) {
|
||||
VL_DO_DANGLING(pushDeletep(m_pExpr), m_pExpr);
|
||||
}
|
||||
clearAssertInfo();
|
||||
}
|
||||
void visit(AstFalling* nodep) override {
|
||||
@@ -488,12 +548,12 @@ private:
|
||||
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
|
||||
AstSenTree* sentreep = nodep->sentreep();
|
||||
if (sentreep) sentreep->unlinkFrBack();
|
||||
AstNodeExpr* const pastp = new AstPast{fl, exprp};
|
||||
AstPast* const pastp = new AstPast{fl, exprp};
|
||||
pastp->dtypeFrom(exprp);
|
||||
pastp->sentreep(newSenTree(nodep, sentreep));
|
||||
exprp = new AstAnd{fl, pastp, new AstNot{fl, exprp->cloneTreePure(false)}};
|
||||
exprp->dtypeSetBit();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep, sentreep));
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void visit(AstFuture* nodep) override {
|
||||
@@ -503,6 +563,10 @@ private:
|
||||
if (sentreep) VL_DO_DANGLING(pushDeletep(sentreep->unlinkFrBack()), sentreep);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
}
|
||||
void visit(AstLogNot* nodep) override {
|
||||
if (m_inSExpr) nodep->v3error("Syntax error: unexpected 'not' in sequence expression");
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstPast* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
iterateChildren(nodep);
|
||||
@@ -529,12 +593,12 @@ private:
|
||||
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
|
||||
AstSenTree* sentreep = nodep->sentreep();
|
||||
if (sentreep) sentreep->unlinkFrBack();
|
||||
AstNodeExpr* const pastp = new AstPast{fl, exprp};
|
||||
AstPast* const pastp = new AstPast{fl, exprp};
|
||||
pastp->dtypeFrom(exprp);
|
||||
pastp->sentreep(newSenTree(nodep, sentreep));
|
||||
exprp = new AstAnd{fl, new AstNot{fl, pastp}, exprp->cloneTreePure(false)};
|
||||
exprp->dtypeSetBit();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep, sentreep));
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void visit(AstStable* nodep) override {
|
||||
@@ -544,12 +608,12 @@ private:
|
||||
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
||||
AstSenTree* sentreep = nodep->sentreep();
|
||||
if (sentreep) sentreep->unlinkFrBack();
|
||||
AstNodeExpr* const pastp = new AstPast{fl, exprp};
|
||||
AstPast* const pastp = new AstPast{fl, exprp};
|
||||
pastp->dtypeFrom(exprp);
|
||||
pastp->sentreep(newSenTree(nodep, sentreep));
|
||||
exprp = new AstEq{fl, pastp, exprp->cloneTreePure(false)};
|
||||
exprp->dtypeSetBit();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep, sentreep));
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void visit(AstSteady* nodep) override {
|
||||
@@ -568,21 +632,27 @@ private:
|
||||
|
||||
void visit(AstImplication* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
m_hasUnsupp = nodep;
|
||||
|
||||
FileLine* const fl = nodep->fileline();
|
||||
iterateChildren(nodep);
|
||||
|
||||
FileLine* const flp = nodep->fileline();
|
||||
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
if (nodep->isOverlapped()) {
|
||||
nodep->replaceWith(new AstLogOr{flp, new AstLogNot{flp, lhsp}, rhsp});
|
||||
} else {
|
||||
if (m_disablep) {
|
||||
lhsp = new AstAnd{flp, new AstNot{flp, m_disablep->cloneTreePure(false)}, lhsp};
|
||||
}
|
||||
|
||||
if (m_disablep) {
|
||||
lhsp = new AstAnd{fl, new AstNot{fl, m_disablep->cloneTreePure(false)}, lhsp};
|
||||
AstPast* const pastp = new AstPast{flp, lhsp};
|
||||
pastp->dtypeFrom(lhsp);
|
||||
pastp->sentreep(newSenTree(nodep));
|
||||
AstNodeExpr* const exprp = new AstOr{flp, new AstNot{flp, pastp}, rhsp};
|
||||
exprp->dtypeSetBit();
|
||||
nodep->replaceWith(exprp);
|
||||
}
|
||||
|
||||
AstNodeExpr* const pastp = new AstPast{fl, lhsp};
|
||||
pastp->dtypeFrom(lhsp);
|
||||
AstNodeExpr* const exprp = new AstOr{fl, new AstNot{fl, pastp}, rhsp};
|
||||
exprp->dtypeSetBit();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
|
||||
@@ -614,6 +684,7 @@ private:
|
||||
}
|
||||
if (AstNodeExpr* const disablep = nodep->disablep()) {
|
||||
m_disablep = disablep;
|
||||
m_hasUnsupp = disablep;
|
||||
if (VN_IS(nodep->backp(), Cover)) {
|
||||
blockp = new AstAnd{disablep->fileline(),
|
||||
new AstNot{disablep->fileline(), disablep->unlinkFrBack()},
|
||||
@@ -627,6 +698,18 @@ private:
|
||||
nodep->replaceWith(blockp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void visit(AstSExpr* nodep) override {
|
||||
VL_RESTORER(m_inSExpr);
|
||||
m_inSExpr = true;
|
||||
m_hasSExpr = true;
|
||||
|
||||
UASSERT_OBJ(m_pExpr, nodep, "Should be under assertion");
|
||||
m_pExpr->addPrecondp(nodep->delayp()->unlinkFrBack());
|
||||
|
||||
iterateChildren(nodep);
|
||||
nodep->replaceWith(nodep->exprp()->unlinkFrBack());
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void visit(AstNodeModule* nodep) override {
|
||||
VL_RESTORER(m_defaultClockingp);
|
||||
VL_RESTORER(m_defaultDisablep);
|
||||
|
||||
Reference in New Issue
Block a user