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:
Bartłomiej Chmiel
2025-10-10 16:16:15 +02:00
committed by GitHub
co-authored by Wilson Snyder
parent 2ac7cf51a9
commit 31e73f1645
29 changed files with 1488 additions and 390 deletions
+98 -12
View File
@@ -37,7 +37,9 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
AstSenTree* m_sentreep = nullptr; // Domain for printing one a ALWAYS under a ACTIVE
bool m_suppressSemi = false; // Non-statement, don't print ;
bool m_suppressVarSemi = false; // Suppress emitting semicolon for AstVars
bool m_suppressSampled = false; // Suppress emitting sampled in assertion properties
bool m_arrayPost = false; // Print array information that goes after identifier (vs after)
bool m_prefixed = true; // Whether constants need to be prefixed
std::deque<AstNodeArrayDType*> m_packedps; // Packed arrays to print with BasicDType
std::unordered_map<AstJumpBlock*, size_t> m_labelNumbers; // Label numbers for JumpBlocks
@@ -79,14 +81,13 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
}
void visit(AstPort* nodep) override {}
void visit(AstNodeFTask* nodep) override {
const bool func = nodep->isFunction() || nodep->name() == "new";
putfs(nodep, func ? "function" : "task");
putfs(nodep, nodep->verilogKwd());
puts(" ");
puts(nodep->prettyName());
puts(";\n");
// Only putfs the first time for each visitor; later for same node is putqs
iterateAndNextConstNull(nodep->stmtsp());
putfs(nodep, func ? "endfunction\n" : "endtask\n");
putqs(nodep, "end" + nodep->verilogKwd() + "\n");
}
void visit(AstGenBlock* nodep) override {
@@ -466,9 +467,11 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
puts(")");
}
void visit(AstSampled* nodep) override {
putfs(nodep, "$sampled(");
iterateAndNextConstNull(nodep->exprp());
puts(")");
if (!m_suppressSampled) {
putfs(nodep, "$sampled(");
iterateAndNextConstNull(nodep->exprp());
puts(")");
}
}
void visit(AstRising* nodep) override {
putfs(nodep, "$rising(");
@@ -757,6 +760,47 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
puts(nodep->prettyName());
puts(";\n");
}
void visit(AstNodeCoverOrAssert* nodep) override {
if (AstPExpr* const pexprp = VN_CAST(nodep->propp(), PExpr)) {
iterateAndNextConstNull(pexprp);
}
putfs(nodep, nodep->verilogKwd() + " ");
if (nodep->type() == VAssertType::OBSERVED_DEFERRED_IMMEDIATE) {
puts("#0 ");
} else if (nodep->type() == VAssertType::FINAL_DEFERRED_IMMEDIATE) {
puts("final ");
} else if (nodep->type() == VAssertType::CONCURRENT) {
puts("property ");
}
iterateConstNull(nodep->sentreep());
puts("(");
if (const AstPExpr* const pexprp = VN_CAST(nodep->propp(), PExpr)) {
iterateAndNextConstNull(pexprp->condp());
} else {
if (AstSampled* const sampledp = VN_CAST(nodep->propp(), Sampled)) {
iterateAndNextConstNull(sampledp->exprp());
} else {
iterateAndNextConstNull(nodep->propp());
}
}
if (!VN_IS(nodep, Restrict)) {
puts(") begin\n");
iterateAndNextConstNull(nodep->passsp());
puts("end\n");
} else {
puts(");\n");
}
if (const AstAssert* const assertp = VN_CAST(nodep, Assert)) {
puts("else begin\n");
iterateAndNextConstNull(assertp->failsp());
puts("end\n");
} else if (const AstAssertIntrinsic* const assertp = VN_CAST(nodep, AssertIntrinsic)) {
puts("else begin\n");
iterateAndNextConstNull(assertp->failsp());
puts("end\n");
}
}
void visit(AstAssocArrayDType* nodep) override {
if (!m_arrayPost) {
iterateConst(nodep->subDTypep());
@@ -934,9 +978,11 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
} else {
putfs(nodep, nodep->prettyName());
}
puts("(");
iterateAndNextConstNull(nodep->pinsp());
puts(")");
if (!VN_IS(nodep->taskp(), Property)) {
puts("(");
iterateAndNextConstNull(nodep->pinsp());
puts(")");
}
}
void visit(AstCCall* nodep) override {
puts(nodep->funcp()->name());
@@ -949,6 +995,36 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
puts(nodep->verilogKwd());
puts(";\n");
}
void visit(AstPropSpec* nodep) override {
if (!VN_IS(nodep->propp(), FuncRef)) {
// Same dumping as in AstSenTree
putfs(nodep, "@(");
for (AstNode* expp = nodep->sensesp(); expp; expp = expp->nextp()) {
iterateConst(expp);
if (expp->nextp()) putqs(expp->nextp(), " or ");
}
puts(")");
}
if (nodep->disablep()) {
puts(" disable iff ");
iterateConst(nodep->disablep());
}
puts(" ");
iterateConstNull(nodep->propp());
puts("\n");
}
void visit(AstPExpr* nodep) override {
iterateAndNextConstNull(nodep->precondp()); // condp emitted by AstNodeCoverOrAssert
}
void visit(AstSExpr* nodep) override {
{
VL_RESTORER(m_suppressSemi);
m_suppressSemi = true;
iterateConstNull(nodep->delayp());
}
iterateConstNull(nodep->exprp());
}
// Terminals
void visit(AstVarRef* nodep) override {
@@ -977,7 +1053,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
puts(nodep->prettyName());
}
}
void visit(AstConst* nodep) override { putfs(nodep, nodep->num().ascii(true, true)); }
void visit(AstConst* nodep) override { putfs(nodep, nodep->num().ascii(m_prefixed, true)); }
// Just iterate
void visit(AstTopScope* nodep) override { iterateChildrenConst(nodep); }
@@ -1003,9 +1079,19 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
}
void visit(AstDelay* nodep) override {
puts(""); // this is for proper alignment
puts("#");
if (nodep->isCycleDelay()) {
puts("##");
} else {
puts("#");
}
VL_RESTORER(m_prefixed);
m_prefixed = false;
iterateConst(nodep->lhsp());
puts(";\n");
if (!m_suppressSemi) {
puts(";\n");
} else {
puts(" ");
}
iterateAndNextConstNull(nodep->stmtsp());
}
void visit(AstCAwait* nodep) override {