mirror of
https://github.com/verilator/verilator.git
synced 2026-09-04 00:30:34 +02:00
Support assert properties, bug785, bug1290.
This commit is contained in:
+31
-8
@@ -88,11 +88,17 @@ private:
|
||||
return newp;
|
||||
}
|
||||
|
||||
AstNode* newFireAssert(AstNode* nodep, const string& message) {
|
||||
AstNode* newFireAssertUnchecked(AstNode* nodep, const string& message) {
|
||||
// Like newFireAssert() but omits the asserts-on check
|
||||
AstDisplay* dispp = new AstDisplay (nodep->fileline(), AstDisplayType::DT_ERROR, message, NULL, NULL);
|
||||
AstNode* bodysp = dispp;
|
||||
replaceDisplay(dispp, "%%Error"); // Convert to standard DISPLAY format
|
||||
bodysp->addNext(new AstStop (nodep->fileline()));
|
||||
return bodysp;
|
||||
}
|
||||
|
||||
AstNode* newFireAssert(AstNode* nodep, const string& message) {
|
||||
AstNode* bodysp = newFireAssertUnchecked(nodep, message);
|
||||
bodysp = newIfAssertOn(bodysp);
|
||||
return bodysp;
|
||||
}
|
||||
@@ -105,7 +111,9 @@ private:
|
||||
//
|
||||
AstNode* bodysp = NULL;
|
||||
bool selfDestruct = false;
|
||||
AstIf* ifp = NULL;
|
||||
if (AstPslCover* snodep = nodep->castPslCover()) {
|
||||
++m_statAsCover;
|
||||
if (!v3Global.opt.coverageUser()) {
|
||||
selfDestruct = true;
|
||||
} else {
|
||||
@@ -116,14 +124,30 @@ private:
|
||||
if (message!="") covincp->declp()->comment(message);
|
||||
bodysp = covincp;
|
||||
}
|
||||
|
||||
if (bodysp && stmtsp) bodysp = bodysp->addNext(stmtsp);
|
||||
ifp = new AstIf (nodep->fileline(), propp, bodysp, NULL);
|
||||
bodysp = ifp;
|
||||
|
||||
} else if (nodep->castPslAssert()) {
|
||||
++m_statAsPsl;
|
||||
// Insert an automatic error message and $stop after
|
||||
// any user-supplied statements.
|
||||
AstNode* autoMsgp = newFireAssertUnchecked(nodep, "'assert property' failed.");
|
||||
if (stmtsp) {
|
||||
stmtsp->addNext(autoMsgp);
|
||||
} else {
|
||||
stmtsp = autoMsgp;
|
||||
}
|
||||
ifp = new AstIf(nodep->fileline(), propp, NULL, stmtsp);
|
||||
// It's more LIKELY that we'll take the NULL if clause
|
||||
// than the sim-killing else clause:
|
||||
ifp->branchPred(AstBranchPred::BP_LIKELY);
|
||||
bodysp = newIfAssertOn(ifp);
|
||||
} else {
|
||||
nodep->v3fatalSrc("Unknown node type");
|
||||
}
|
||||
if (bodysp && stmtsp) bodysp = bodysp->addNext(stmtsp);
|
||||
AstIf* ifp = new AstIf (nodep->fileline(), propp, bodysp, NULL);
|
||||
bodysp = ifp;
|
||||
if (nodep->castVAssert()) ifp->branchPred(AstBranchPred::BP_UNLIKELY);
|
||||
//
|
||||
|
||||
AstNode* newp = new AstAlways (nodep->fileline(),
|
||||
VAlwaysKwd::ALWAYS,
|
||||
sentreep,
|
||||
@@ -294,12 +318,11 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstPslCover* nodep) {
|
||||
virtual void visit(AstNodePslCoverOrAssert* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (m_beginp && nodep->name() == "") nodep->name(m_beginp->name());
|
||||
newPslAssertion(nodep, nodep->propp(), nodep->sentreep(),
|
||||
nodep->stmtsp(), nodep->name()); VL_DANGLING(nodep);
|
||||
++m_statAsCover;
|
||||
}
|
||||
virtual void visit(AstVAssert* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
|
||||
+1
-1
@@ -86,7 +86,7 @@ private:
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstPslCover* nodep) {
|
||||
virtual void visit(AstNodePslCoverOrAssert* nodep) {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
clearAssertInfo();
|
||||
nodep->iterateChildren(*this);
|
||||
|
||||
+25
-10
@@ -3986,6 +3986,7 @@ class AstNodeSystemUniop : public AstNodeUniop {
|
||||
public:
|
||||
AstNodeSystemUniop(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
dtypeSetDouble(); }
|
||||
ASTNODE_BASE_FUNCS(NodeSystemUniop)
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountDoubleTrig(); }
|
||||
@@ -5260,30 +5261,44 @@ public:
|
||||
AstNode* propp() const { return op3p(); } // op3 = property
|
||||
};
|
||||
|
||||
class AstPslCover : public AstNodeStmt {
|
||||
class AstNodePslCoverOrAssert : public AstNodeStmt {
|
||||
// Psl Cover
|
||||
// Parents: {statement list}
|
||||
// Children: expression, report string
|
||||
private:
|
||||
string m_name; // Name to report
|
||||
public:
|
||||
AstPslCover(FileLine* fl, AstNode* propp, AstNode* stmtsp, const string& name="")
|
||||
AstNodePslCoverOrAssert(FileLine* fl, AstNode* propp, AstNode* stmtsp, const string& name="")
|
||||
: AstNodeStmt(fl)
|
||||
, m_name(name) {
|
||||
addOp1p(propp);
|
||||
addNOp4p(stmtsp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(PslCover)
|
||||
virtual string name() const { return m_name; } // * = Var name
|
||||
ASTNODE_BASE_FUNCS(NodePslCoverOrAssert)
|
||||
virtual string name() const { return m_name; } // * = Var name
|
||||
virtual V3Hash sameHash() const { return V3Hash(name()); }
|
||||
virtual bool same(const AstNode* samep) const { return samep->name() == name(); }
|
||||
virtual void name(const string& name) { m_name = name; }
|
||||
AstNode* propp() const { return op1p(); } // op1 = property
|
||||
AstSenTree* sentreep() const { return op2p()->castSenTree(); } // op2 = clock domain
|
||||
void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain
|
||||
AstNode* coverincp() const { return op3p(); } // op3 = coverage node
|
||||
void coverincp(AstCoverInc* nodep) { addOp3p(nodep); } // op3 = coverage node
|
||||
AstNode* stmtsp() const { return op4p(); } // op4 = statements
|
||||
AstNode* propp() const { return op1p(); } // op1 = property
|
||||
AstSenTree* sentreep() const { return op2p()->castSenTree(); } // op2 = clock domain
|
||||
void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain
|
||||
AstNode* stmtsp() const { return op4p(); } // op4 = statements
|
||||
};
|
||||
|
||||
class AstPslCover : public AstNodePslCoverOrAssert {
|
||||
public:
|
||||
ASTNODE_NODE_FUNCS(PslCover)
|
||||
AstPslCover(FileLine* fl, AstNode* propp, AstNode* stmtsp, const string& name="")
|
||||
: AstNodePslCoverOrAssert(fl, propp, stmtsp, name) {}
|
||||
AstNode* coverincp() const { return op3p(); } // op3 = coverage node
|
||||
void coverincp(AstCoverInc* nodep) { addOp3p(nodep); } // op3 = coverage node
|
||||
};
|
||||
|
||||
class AstPslAssert : public AstNodePslCoverOrAssert {
|
||||
public:
|
||||
ASTNODE_NODE_FUNCS(PslAssert)
|
||||
AstPslAssert(FileLine* fl, AstNode* propp, AstNode* stmtsp, const string& name="")
|
||||
: AstNodePslCoverOrAssert(fl, propp, stmtsp, name) {}
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
|
||||
+1
-1
@@ -2226,7 +2226,7 @@ private:
|
||||
assertAtStatement(nodep);
|
||||
userIterateChildren(nodep, WidthVP(SELF,BOTH).p());
|
||||
}
|
||||
virtual void visit(AstPslCover* nodep) {
|
||||
virtual void visit(AstNodePslCoverOrAssert* nodep) {
|
||||
assertAtStatement(nodep);
|
||||
iterateCheckBool(nodep,"Property",nodep->propp(),BOTH); // it's like an if() condition.
|
||||
userIterateAndNext(nodep->stmtsp(), NULL);
|
||||
|
||||
+7
-2
@@ -3716,9 +3716,14 @@ concurrent_assertion_item<nodep>: // IEEE: concurrent_assertion_item
|
||||
;
|
||||
|
||||
concurrent_assertion_statement<nodep>: // ==IEEE: concurrent_assertion_statement
|
||||
//UNSUP: assert/assume
|
||||
yASSERT yPROPERTY '(' property_spec ')' elseStmtBlock { $$ = new AstPslAssert($1,$4,$6); }
|
||||
// // IEEE: cover_property_statement
|
||||
yCOVER yPROPERTY '(' property_spec ')' stmtBlock { $$ = new AstPslCover($1,$4,$6); }
|
||||
| yCOVER yPROPERTY '(' property_spec ')' stmtBlock { $$ = new AstPslCover($1,$4,$6); }
|
||||
;
|
||||
|
||||
elseStmtBlock<nodep>: // Part of concurrent_assertion_statement
|
||||
';' { $$ = NULL; }
|
||||
| yELSE stmtBlock { $$ = $2; }
|
||||
;
|
||||
|
||||
property_spec<nodep>: // IEEE: property_spec
|
||||
|
||||
Reference in New Issue
Block a user