diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 18f23a84e..95af49ace 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -63,6 +63,9 @@ private: AstNode* timesp = nodep->exprsp(); if (timesp) timesp->unlinkFrBack(); timesp = timesp->addNext(new AstTime(nodep->fileline())); nodep->exprsp(timesp); + if (!nodep->scopeNamep() && nodep->name().find("%m") != string::npos) { + nodep->scopeNamep(new AstScopeName(nodep->fileline())); + } } AstNode* newIfAssertOn(AstNode* nodep) { diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index bcd1190a4..9cfa4e05a 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -1271,11 +1271,8 @@ public: bool addNewline() const { return displayType().addNewline(); } // * = Add a newline for $display AstNode* filep() const { return op2p(); } void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } - AstNode* scopeAttrp() const { return op3p(); } - AstText* scopeTextp() const { return op3p()->castText(); } - void scopeAttrp(AstNode* nodep) { addOp3p(nodep); } - bool needScopeTracking() { return (displayType().needScopeTracking() - || name().find("%m") != string::npos); } + AstScopeName* scopeNamep() const { return op3p()->castScopeName(); } + void scopeNamep(AstNode* nodep) { setNOp3p(nodep); } }; struct AstFClose : public AstNodeStmt { @@ -1726,6 +1723,22 @@ public: int dimension() const { return m_dimension; } }; +struct AstScopeName : public AstNode { + // For display %m + // Parents: DISPLAY + // Children: TEXT + AstScopeName(FileLine* fl) + : AstNode(fl) {} + virtual ~AstScopeName() {} + virtual AstType type() const { return AstType::SCOPENAME;} + virtual AstNode* clone() { return new AstScopeName(*this); } + virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); } + virtual V3Hash sameHash() const { return V3Hash(); } + virtual bool same(AstNode* samep) const { return true; } + AstText* scopeAttrp() const { return op1p()->castText(); } + void scopeAttrp(AstNode* nodep) { addOp1p(nodep); } +}; + //====================================================================== // non-ary ops diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index 1a9c67572..8a5a22869 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -131,10 +131,10 @@ private: nodep->replaceWith(newp); nodep->deleteTree(); nodep=NULL; } - virtual void visit(AstDisplay* nodep, AstNUser*) { + virtual void visit(AstScopeName* nodep, AstNUser*) { // If there's a %m in the display text, we add a special node that will contain the name() // Similar code in V3Inline - if (m_beginScope != "" && nodep->needScopeTracking()) { + if (m_beginScope != "") { // To keep correct visual order, must add before other Text's AstNode* afterp = nodep->scopeAttrp(); if (afterp) afterp->unlinkFrBackWithNext(); diff --git a/src/V3Clean.cpp b/src/V3Clean.cpp index 81328b3c2..04515c071 100644 --- a/src/V3Clean.cpp +++ b/src/V3Clean.cpp @@ -196,6 +196,9 @@ private: virtual void visit(AstText* nodep, AstNUser*) { setClean (nodep, true); } + virtual void visit(AstScopeName* nodep, AstNUser*) { + setClean (nodep, true); + } virtual void visit(AstSel* nodep, AstNUser*) { operandTriop(nodep); setClean (nodep, nodep->cleanOut()); diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 9b5396550..e295a4056 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -1061,7 +1061,8 @@ void EmitCStmts::visit(AstDisplay* nodep, AstNUser*) { case 'm': { emitDispState.pushFormat("%s"); emitDispState.pushArg(NULL, "vlSymsp->name("); - for (AstText* textp=nodep->scopeTextp(); textp; textp=textp->nextp()->castText()) { + if (!nodep->scopeNamep()) nodep->v3fatalSrc("Display with %m but no AstScopeName"); + for (AstText* textp=nodep->scopeNamep()->scopeAttrp(); textp; textp=textp->nextp()->castText()) { emitDispState.pushFormat(textp->text()); } break; diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index a718f4a38..e859c10eb 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -246,6 +246,8 @@ public: virtual void visit(AstText* nodep, AstNUser*) { ofp()->putsNoTracking(nodep->text()); } + virtual void visit(AstScopeName* nodep, AstNUser*) { + } virtual void visit(AstCStmt* nodep, AstNUser*) { putbs("$_CSTMT("); nodep->bodysp()->iterateAndNext(*this); diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index 36e2f6fa2..0d8c430f3 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -233,10 +233,10 @@ private: } nodep->iterateChildren(*this); } - virtual void visit(AstDisplay* nodep, AstNUser*) { + virtual void visit(AstScopeName* nodep, AstNUser*) { // If there's a %m in the display text, we add a special node that will contain the name() // Similar code in V3Begin - if (m_cellp && nodep->needScopeTracking()) { + if (m_cellp) { // To keep correct visual order, must add before other Text's AstNode* afterp = nodep->scopeAttrp(); if (afterp) afterp->unlinkFrBackWithNext(); diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index e992b2876..8943d3c79 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -335,6 +335,10 @@ private: || nodep->displayType() == AstDisplayType::FATAL)) { nodep->v3error(nodep->verilogKwd()+" only allowed under a assertion."); } + if (nodep->displayType().needScopeTracking() + || nodep->name().find("%m") != string::npos) { + nodep->scopeNamep(new AstScopeName(nodep->fileline())); + } } virtual void visit(AstScCtor* nodep, AstNUser*) { diff --git a/src/V3Scope.cpp b/src/V3Scope.cpp index a96ea6421..28fa30289 100644 --- a/src/V3Scope.cpp +++ b/src/V3Scope.cpp @@ -198,19 +198,17 @@ private: nodep->taskp(NULL); nodep->iterateChildren(*this); } - virtual void visit(AstDisplay* nodep, AstNUser*) { + virtual void visit(AstScopeName* nodep, AstNUser*) { // If there's a %m in the display text, we add a special node that will contain the name() - if (nodep->name().find("%m") != string::npos) { - string prefix = (string)(".")+m_scopep->prettyName(); - // TOP and above will be the user's name(). - // Note 'TOP.'is stripped by prettyName, but not 'TOP'. - if (prefix != ".TOP") { - // To keep correct visual order, must add before other Text's - AstNode* afterp = nodep->scopeAttrp(); - if (afterp) afterp->unlinkFrBackWithNext(); - nodep->scopeAttrp(new AstText(nodep->fileline(), prefix)); - if (afterp) nodep->scopeAttrp(afterp); - } + string prefix = (string)(".")+m_scopep->prettyName(); + // TOP and above will be the user's name(). + // Note 'TOP.'is stripped by prettyName, but not 'TOP'. + if (prefix != ".TOP") { + // To keep correct visual order, must add before other Text's + AstNode* afterp = nodep->scopeAttrp(); + if (afterp) afterp->unlinkFrBackWithNext(); + nodep->scopeAttrp(new AstText(nodep->fileline(), prefix)); + if (afterp) nodep->scopeAttrp(afterp); } nodep->iterateChildren(*this); } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 6deb94f8a..fa8f828a8 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -385,6 +385,9 @@ private: virtual void visit(AstText* nodep, AstNUser* vup) { // Only used in CStmts which don't care.... } + virtual void visit(AstScopeName* nodep, AstNUser* vup) { + // Only used in Displays which don't care.... + } virtual void visit(AstVar* nodep, AstNUser* vup) { //if (debug()) nodep->dumpTree(cout," InitPre: "); // Must have deterministic constant width