Support trivial SV assertions
git-svn-id: file://localhost/svn/verilator/trunk/verilator@898 77ca24e4-aefa-0310-84f0-b9a241c72d87
This commit is contained in:
parent
98282114c9
commit
79ab50d84f
|
|
@ -903,17 +903,21 @@ declarations inside port lists.
|
||||||
Verilator supports the `begin_keywords and `end_keywords compiler
|
Verilator supports the `begin_keywords and `end_keywords compiler
|
||||||
directives.
|
directives.
|
||||||
|
|
||||||
Verilator supports the uwire, $countones, $isunknown, $onehot and $onehot0
|
Verilator partially supports the uwire keyword.
|
||||||
keywords. Verilator partially supports the uwire keyword.
|
|
||||||
|
|
||||||
=head1 SYSTEMVERILOG (IEEE 1800-2005) SUPPORT
|
=head1 SYSTEMVERILOG (IEEE 1800-2005) SUPPORT
|
||||||
|
|
||||||
Verilator currently has very minimal support for SystemVerilog.
|
Verilator currently has very minimal support for SystemVerilog as they
|
||||||
|
become more common, contact the author if a feature you need is missing.
|
||||||
|
|
||||||
Verilator implements the full SystemVerilog 1800-2005 preprocessor subset,
|
Verilator implements the full SystemVerilog 1800-2005 preprocessor subset,
|
||||||
including function call-like preprocessor defines. Verilator also
|
including function call-like preprocessor defines.
|
||||||
implements $bits, $countones, $isunknown, $onehot, and $onehot0,
|
|
||||||
always_comb, always_ff, always_latch, and final.
|
Verilator supports $bits, $countones, $error, $fatal, $info, $isunknown,
|
||||||
|
$onehot, $onehot0, $warning, always_comb, always_ff, always_latch, and
|
||||||
|
final.
|
||||||
|
|
||||||
|
Verilator partially supports assert.
|
||||||
|
|
||||||
=head1 SUGAR/PSL SUPPORT
|
=head1 SUGAR/PSL SUPPORT
|
||||||
|
|
||||||
|
|
@ -934,18 +938,16 @@ report, true.
|
||||||
Verilator implements these operators: -> (logical if).
|
Verilator implements these operators: -> (logical if).
|
||||||
|
|
||||||
Verilator does not support SEREs yet. All assertion and coverage
|
Verilator does not support SEREs yet. All assertion and coverage
|
||||||
statements must be simple expressions that complete in one cycle.
|
statements must be simple expressions that complete in one cycle. PSL
|
||||||
(Arguably SEREs are the whole point of PSL, but one must start somewhere.)
|
vmode/vprop/vunits are not supported. PSL statements must be in the module
|
||||||
|
they reference, at the module level where you would put an
|
||||||
PSL vmode/vprop/vunits are not supported. PSL statements must be in the
|
|
||||||
module they reference, at the module level where you would put an
|
|
||||||
initial... statement.
|
initial... statement.
|
||||||
|
|
||||||
Verilator only supports (posedge CLK) or (negedge CLK), where CLK is the
|
Verilator only supports (posedge CLK) or (negedge CLK), where CLK is the
|
||||||
name of a one bit signal. You may not use arbitrary expressions as
|
name of a one bit signal. You may not use arbitrary expressions as
|
||||||
assertion clocks.
|
assertion clocks.
|
||||||
|
|
||||||
=head1 SYNTHESIS DIRECTIVE ASSERTIONS
|
=head1 SYNTHESIS DIRECTIVE ASSERTION SUPPORT
|
||||||
|
|
||||||
With the --assert switch, Verilator reads any "//synopsys full_case" or "//
|
With the --assert switch, Verilator reads any "//synopsys full_case" or "//
|
||||||
synopsys parallel_case" directives. The same applies to any "//cadence" or
|
synopsys parallel_case" directives. The same applies to any "//cadence" or
|
||||||
|
|
@ -1354,6 +1356,17 @@ will give a width warning and wrap around the power-of-2 size. For
|
||||||
non-power-of-2 sizes, it will return a unspecified constant of the
|
non-power-of-2 sizes, it will return a unspecified constant of the
|
||||||
appropriate width.
|
appropriate width.
|
||||||
|
|
||||||
|
=head2 Assertions
|
||||||
|
|
||||||
|
Verilator is beginning to add support for assertions. Verilator currently
|
||||||
|
only converts assertions to simple "if (...) error" statements, and
|
||||||
|
coverage statements to increment the line counters described in the
|
||||||
|
coverage section.
|
||||||
|
|
||||||
|
Verilator does not support SEREs yet. All assertion and coverage
|
||||||
|
statements must be simple expressions that complete in one cycle.
|
||||||
|
(Arguably SEREs are much of the point, but one must start somewhere.)
|
||||||
|
|
||||||
=head1 LANGUAGE KEYWORD LIMITATIONS
|
=head1 LANGUAGE KEYWORD LIMITATIONS
|
||||||
|
|
||||||
This section describes specific limitations for each language keyword.
|
This section describes specific limitations for each language keyword.
|
||||||
|
|
|
||||||
105
src/V3Assert.cpp
105
src/V3Assert.cpp
|
|
@ -47,28 +47,58 @@ private:
|
||||||
V3Double0 m_statAsCover; // Statistic tracking
|
V3Double0 m_statAsCover; // Statistic tracking
|
||||||
V3Double0 m_statAsPsl; // Statistic tracking
|
V3Double0 m_statAsPsl; // Statistic tracking
|
||||||
V3Double0 m_statAsFull; // Statistic tracking
|
V3Double0 m_statAsFull; // Statistic tracking
|
||||||
|
V3Double0 m_statAsSV; // Statistic tracking
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
AstNode* newFireAssert(AstNode* nodep, const string& message) {
|
string assertDisplayMessage(AstNode* nodep, const string& prefix, const string& message) {
|
||||||
AstNode* bodysp = new AstDisplay
|
return (string("[%0t] "+prefix+": ")+nodep->fileline()->filebasename()
|
||||||
(nodep->fileline(), '\0',
|
+":"+cvtToStr(nodep->fileline()->lineno())
|
||||||
(string("[%0t] %%Error: ")+nodep->fileline()->filebasename()
|
+": Assertion failed in %m"
|
||||||
+":"+cvtToStr(nodep->fileline()->lineno())
|
+((message != "")?": ":"")+message
|
||||||
+": Assertion failed in %m"
|
+"\\n");
|
||||||
+((message != "")?": ":"")+message
|
}
|
||||||
+"\\n"),
|
void replaceDisplay(AstDisplay* nodep, const string& prefix) {
|
||||||
NULL,
|
nodep->displayType(AstDisplayType::WRITE);
|
||||||
new AstTime(nodep->fileline()));
|
nodep->text(assertDisplayMessage(nodep, prefix, nodep->text()));
|
||||||
bodysp->addNext(new AstStop (nodep->fileline()));
|
AstNode* timesp = nodep->exprsp(); if (timesp) timesp->unlinkFrBack();
|
||||||
|
timesp = timesp->addNext(new AstTime(nodep->fileline()));
|
||||||
|
nodep->exprsp(timesp);
|
||||||
|
}
|
||||||
|
|
||||||
|
AstNode* newIfAssertOn(AstNode* nodep) {
|
||||||
// Add a internal if to check assertions are on.
|
// Add a internal if to check assertions are on.
|
||||||
// Don't make this a AND term, as it's unlikely to need to test this.
|
// Don't make this a AND term, as it's unlikely to need to test this.
|
||||||
bodysp = new AstIf (nodep->fileline(),
|
return new AstIf (nodep->fileline(),
|
||||||
new AstCMath(nodep->fileline(), "Verilated::assertOn()", 1),
|
// If assertions are off, have constant propagation rip them out later
|
||||||
bodysp, NULL);
|
// This allows syntax errors and such to be detected normally.
|
||||||
|
(v3Global.opt.assertOn()
|
||||||
|
? (AstNode*)(new AstCMath(nodep->fileline(), "Verilated::assertOn()", 1))
|
||||||
|
: (AstNode*)(new AstConst(nodep->fileline(), V3Number(nodep->fileline(), 1, 0)))),
|
||||||
|
nodep, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
AstNode* newIfCoverageOn(AstNode* nodep) {
|
||||||
|
// Add a internal if to check coverage is on
|
||||||
|
// Don't make this a AND term, as it's unlikely to need to test this.
|
||||||
|
return new AstIf (nodep->fileline(),
|
||||||
|
// If assertions are off, have constant propagation rip them out later
|
||||||
|
// This allows syntax errors and such to be detected normally.
|
||||||
|
(v3Global.opt.coverage()
|
||||||
|
? (AstNode*)(new AstConst(nodep->fileline(), V3Number(nodep->fileline(), 1, 1)))
|
||||||
|
: (AstNode*)(new AstConst(nodep->fileline(), V3Number(nodep->fileline(), 1, 0)))),
|
||||||
|
nodep, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
AstNode* newFireAssert(AstNode* nodep, const string& message) {
|
||||||
|
AstDisplay* dispp = new AstDisplay (nodep->fileline(), AstDisplayType::ERROR, message, NULL, NULL);
|
||||||
|
AstNode* bodysp = dispp;
|
||||||
|
replaceDisplay(dispp, "%%Error"); // Convert to standard DISPLAY format
|
||||||
|
bodysp->addNext(new AstStop (nodep->fileline()));
|
||||||
|
bodysp = newIfAssertOn(bodysp);
|
||||||
return bodysp;
|
return bodysp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void newAssertion(AstNode* nodep, AstNode* propp, AstSenTree* sentreep, const string& message) {
|
void newPslAssertion(AstNode* nodep, AstNode* propp, AstSenTree* sentreep, const string& message) {
|
||||||
propp->unlinkFrBack();
|
propp->unlinkFrBack();
|
||||||
sentreep->unlinkFrBack();
|
sentreep->unlinkFrBack();
|
||||||
//
|
//
|
||||||
|
|
@ -114,6 +144,28 @@ private:
|
||||||
pushDeletep(nodep); nodep=NULL;
|
pushDeletep(nodep); nodep=NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void newVAssertion(AstVAssert* nodep, AstNode* propp) {
|
||||||
|
propp->unlinkFrBackWithNext();
|
||||||
|
AstNode* passsp = nodep->passsp(); if (passsp) passsp->unlinkFrBackWithNext();
|
||||||
|
AstNode* failsp = nodep->failsp(); if (failsp) failsp->unlinkFrBackWithNext();
|
||||||
|
//
|
||||||
|
if (nodep->castVAssert()) {
|
||||||
|
if (passsp) passsp = newIfAssertOn(passsp);
|
||||||
|
if (failsp) failsp = newIfAssertOn(failsp);
|
||||||
|
} else {
|
||||||
|
nodep->v3fatalSrc("Unknown node type");
|
||||||
|
}
|
||||||
|
|
||||||
|
AstIf* ifp = new AstIf (nodep->fileline(), propp, passsp, failsp);
|
||||||
|
AstNode* newp = ifp;
|
||||||
|
if (nodep->castVAssert()) ifp->branchPred(AstBranchPred::UNLIKELY);
|
||||||
|
//
|
||||||
|
// Install it
|
||||||
|
nodep->replaceWith(newp);
|
||||||
|
// Bye
|
||||||
|
pushDeletep(nodep); nodep=NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// VISITORS //========== Case assertions
|
// VISITORS //========== Case assertions
|
||||||
virtual void visit(AstCase* nodep, AstNUser*) {
|
virtual void visit(AstCase* nodep, AstNUser*) {
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
|
|
@ -163,16 +215,34 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
// VISITORS //========== Statements
|
// VISITORS //========== Statements
|
||||||
|
virtual void visit(AstDisplay* nodep, AstNUser*) {
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
// Replace the special types with standard text
|
||||||
|
if (nodep->displayType()==AstDisplayType::INFO) {
|
||||||
|
replaceDisplay(nodep, "-Info");
|
||||||
|
} else if (nodep->displayType()==AstDisplayType::WARNING) {
|
||||||
|
replaceDisplay(nodep, "%%Warning");
|
||||||
|
} else if (nodep->displayType()==AstDisplayType::ERROR
|
||||||
|
|| nodep->displayType()==AstDisplayType::FATAL) {
|
||||||
|
replaceDisplay(nodep, "%%Error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtual void visit(AstPslCover* nodep, AstNUser*) {
|
virtual void visit(AstPslCover* nodep, AstNUser*) {
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
newAssertion(nodep, nodep->propp(), nodep->sentreep(), nodep->name()); nodep=NULL;
|
newPslAssertion(nodep, nodep->propp(), nodep->sentreep(), nodep->name()); nodep=NULL;
|
||||||
m_statAsCover++;
|
m_statAsCover++;
|
||||||
}
|
}
|
||||||
virtual void visit(AstPslAssert* nodep, AstNUser*) {
|
virtual void visit(AstPslAssert* nodep, AstNUser*) {
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
newAssertion(nodep, nodep->propp(), nodep->sentreep(), nodep->name()); nodep=NULL;
|
newPslAssertion(nodep, nodep->propp(), nodep->sentreep(), nodep->name()); nodep=NULL;
|
||||||
m_statAsPsl++;
|
m_statAsPsl++;
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstVAssert* nodep, AstNUser*) {
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
newVAssertion(nodep, nodep->propp()); nodep=NULL;
|
||||||
|
m_statAsSV++;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||||
m_modp = nodep;
|
m_modp = nodep;
|
||||||
|
|
@ -203,6 +273,7 @@ public:
|
||||||
}
|
}
|
||||||
virtual ~AssertVisitor() {
|
virtual ~AssertVisitor() {
|
||||||
V3Stats::addStat("Assertions, PSL asserts", m_statAsPsl);
|
V3Stats::addStat("Assertions, PSL asserts", m_statAsPsl);
|
||||||
|
V3Stats::addStat("Assertions, SystemVerilog asserts", m_statAsSV);
|
||||||
V3Stats::addStat("Assertions, cover statements", m_statAsCover);
|
V3Stats::addStat("Assertions, cover statements", m_statAsCover);
|
||||||
V3Stats::addStat("Assertions, full/parallel case", m_statAsFull);
|
V3Stats::addStat("Assertions, full/parallel case", m_statAsFull);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -789,7 +789,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append) {
|
||||||
if (logsp->fail()) v3fatalSrc("Can't write "<<filename);
|
if (logsp->fail()) v3fatalSrc("Can't write "<<filename);
|
||||||
*logsp<<"Tree Dump from <e"<<dec<<editCountLast()<<">";
|
*logsp<<"Tree Dump from <e"<<dec<<editCountLast()<<">";
|
||||||
*logsp<<" to <e"<<dec<<editCountGbl()<<">"<<endl;
|
*logsp<<" to <e"<<dec<<editCountGbl()<<">"<<endl;
|
||||||
if (editCountGbl()==editCountLast() && 0) { // Off, as messes up tree diffing
|
if (editCountGbl()==editCountLast() && 1) { // Off, as messes up tree diffing
|
||||||
*logsp<<endl;
|
*logsp<<endl;
|
||||||
*logsp<<"No changes since last dump!\n";
|
*logsp<<"No changes since last dump!\n";
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
29
src/V3Ast.h
29
src/V3Ast.h
|
|
@ -250,6 +250,34 @@ public:
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|
||||||
|
class AstDisplayType {
|
||||||
|
public:
|
||||||
|
enum en {
|
||||||
|
DISPLAY,
|
||||||
|
WRITE,
|
||||||
|
INFO,
|
||||||
|
ERROR,
|
||||||
|
WARNING,
|
||||||
|
FATAL
|
||||||
|
};
|
||||||
|
enum en m_e;
|
||||||
|
inline AstDisplayType () {};
|
||||||
|
inline AstDisplayType (en _e) : m_e(_e) {};
|
||||||
|
explicit inline AstDisplayType (int _e) : m_e(static_cast<en>(_e)) {};
|
||||||
|
operator en () const { return m_e; };
|
||||||
|
bool addNewline() const { return m_e!=WRITE; }
|
||||||
|
bool needScopeTracking() const { return m_e!=DISPLAY && m_e!=WRITE; }
|
||||||
|
const char* ascii() const {
|
||||||
|
static const char* names[] = {
|
||||||
|
"display","write","info","error","warning","fatal"};
|
||||||
|
return names[m_e];};
|
||||||
|
};
|
||||||
|
inline bool operator== (AstDisplayType lhs, AstDisplayType rhs) { return (lhs.m_e == rhs.m_e); }
|
||||||
|
inline bool operator== (AstDisplayType lhs, AstDisplayType::en rhs) { return (lhs.m_e == rhs); }
|
||||||
|
inline bool operator== (AstDisplayType::en lhs, AstDisplayType rhs) { return (lhs == rhs.m_e); }
|
||||||
|
|
||||||
|
//######################################################################
|
||||||
|
|
||||||
class AstParseRefExp {
|
class AstParseRefExp {
|
||||||
public:
|
public:
|
||||||
enum en {
|
enum en {
|
||||||
|
|
@ -906,6 +934,7 @@ public:
|
||||||
virtual ~AstNodePli() {}
|
virtual ~AstNodePli() {}
|
||||||
virtual string name() const { return m_text; }
|
virtual string name() const { return m_text; }
|
||||||
virtual int instrCount() const { return instrCountPli(); }
|
virtual int instrCount() const { return instrCountPli(); }
|
||||||
|
void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output
|
||||||
AstNode* exprsp() const { return op1p()->castNode(); } // op1 = Expressions to output
|
AstNode* exprsp() const { return op1p()->castNode(); } // op1 = Expressions to output
|
||||||
string text() const { return m_text; } // * = Text to display
|
string text() const { return m_text; } // * = Text to display
|
||||||
void text(const string& text) { m_text=text; }
|
void text(const string& text) { m_text=text; }
|
||||||
|
|
|
||||||
|
|
@ -1236,19 +1236,19 @@ struct AstDisplay : public AstNodePli {
|
||||||
// Parents: stmtlist
|
// Parents: stmtlist
|
||||||
// Children: file which must be a varref, MATH to print
|
// Children: file which must be a varref, MATH to print
|
||||||
private:
|
private:
|
||||||
char m_newline;
|
AstDisplayType m_displayType;
|
||||||
public:
|
public:
|
||||||
AstDisplay(FileLine* fileline, char newln, const string& text, AstNode* filep, AstNode* exprsp)
|
AstDisplay(FileLine* fileline, AstDisplayType dispType, const string& text, AstNode* filep, AstNode* exprsp)
|
||||||
: AstNodePli (fileline, text, exprsp) {
|
: AstNodePli (fileline, text, exprsp) {
|
||||||
setNOp2p(filep);
|
setNOp2p(filep);
|
||||||
m_newline = newln;
|
m_displayType = dispType;
|
||||||
}
|
}
|
||||||
virtual ~AstDisplay() {}
|
virtual ~AstDisplay() {}
|
||||||
virtual AstType type() const { return AstType::DISPLAY;}
|
virtual AstType type() const { return AstType::DISPLAY;}
|
||||||
virtual AstNode* clone() { return new AstDisplay(*this); }
|
virtual AstNode* clone() { return new AstDisplay(*this); }
|
||||||
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
|
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
|
||||||
virtual string verilogKwd() const { return (filep() ? ((newline() == '\n')?"$fdisplay":"$fwrite")
|
virtual string verilogKwd() const { return (filep() ? (string)"$f"+(string)displayType().ascii()
|
||||||
: ((newline() == '\n')?"$display":"$write")); };
|
: (string)"$"+(string)displayType().ascii()); }
|
||||||
virtual bool isGateOptimizable() const { return false; }
|
virtual bool isGateOptimizable() const { return false; }
|
||||||
virtual bool isPredictOptimizable() const { return false; }
|
virtual bool isPredictOptimizable() const { return false; }
|
||||||
virtual bool isSplittable() const { return false; } // SPECIAL: $display has 'visual' ordering
|
virtual bool isSplittable() const { return false; } // SPECIAL: $display has 'visual' ordering
|
||||||
|
|
@ -1256,16 +1256,19 @@ public:
|
||||||
virtual bool isUnlikely() const { return true; }
|
virtual bool isUnlikely() const { return true; }
|
||||||
virtual V3Hash sameHash() const { return V3Hash(text()); }
|
virtual V3Hash sameHash() const { return V3Hash(text()); }
|
||||||
virtual bool same(AstNode* samep) const {
|
virtual bool same(AstNode* samep) const {
|
||||||
return newline()==samep->castDisplay()->newline()
|
return displayType()==samep->castDisplay()->displayType()
|
||||||
&& text()==samep->castDisplay()->text(); }
|
&& text()==samep->castDisplay()->text(); }
|
||||||
// op1 used by AstNodePli
|
// op1 used by AstNodePli
|
||||||
char newline() const { return m_newline; } // * = Add a newline for $display
|
AstDisplayType displayType() const { return m_displayType; }
|
||||||
|
void displayType(AstDisplayType type) { m_displayType = type; }
|
||||||
|
bool addNewline() const { return displayType().addNewline(); } // * = Add a newline for $display
|
||||||
AstNode* filep() const { return op2p(); }
|
AstNode* filep() const { return op2p(); }
|
||||||
void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); }
|
void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); }
|
||||||
AstNode* scopeAttrp() const { return op3p(); }
|
AstNode* scopeAttrp() const { return op3p(); }
|
||||||
AstText* scopeTextp() const { return op3p()->castText(); }
|
AstText* scopeTextp() const { return op3p()->castText(); }
|
||||||
void scopeAttrp(AstNode* nodep) { addOp3p(nodep); }
|
void scopeAttrp(AstNode* nodep) { addOp3p(nodep); }
|
||||||
bool needScopeTracking() { return name().find("%m") != string::npos; }
|
bool needScopeTracking() { return (displayType().needScopeTracking()
|
||||||
|
|| name().find("%m") != string::npos); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstFClose : public AstNodeStmt {
|
struct AstFClose : public AstNodeStmt {
|
||||||
|
|
@ -2617,6 +2620,30 @@ struct AstReplicate : public AstNodeBiop {
|
||||||
virtual int instrCount() const { return widthInstrs()*2; }
|
virtual int instrCount() const { return widthInstrs()*2; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//======================================================================
|
||||||
|
// SysVerilog assertions
|
||||||
|
|
||||||
|
struct AstVAssert : public AstNodeStmt {
|
||||||
|
// Verilog Assertion
|
||||||
|
// Parents: {statement list}
|
||||||
|
// Children: expression, if pass statements, if fail statements
|
||||||
|
AstVAssert(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp)
|
||||||
|
: AstNodeStmt(fl) {
|
||||||
|
addOp1p(propp);
|
||||||
|
addNOp2p(passsp);
|
||||||
|
addNOp3p(failsp);
|
||||||
|
}
|
||||||
|
virtual ~AstVAssert() {}
|
||||||
|
virtual AstType type() const { return AstType::VASSERT;}
|
||||||
|
virtual AstNode* clone() { return new AstVAssert(*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; }
|
||||||
|
AstNode* propp() const { return op1p(); } // op1 = property
|
||||||
|
AstNode* passsp() const { return op2p(); } // op2 = if passes
|
||||||
|
AstNode* failsp() const { return op3p(); } // op3 = if fails
|
||||||
|
};
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// PSL
|
// PSL
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -472,7 +472,8 @@ private:
|
||||||
ifstmtp->addNext(new AstIf(fl,
|
ifstmtp->addNext(new AstIf(fl,
|
||||||
new AstLt (fl, new AstConst(fl, 100),
|
new AstLt (fl, new AstConst(fl, 100),
|
||||||
new AstVarRef(fl, countVarp, false)),
|
new AstVarRef(fl, countVarp, false)),
|
||||||
(new AstDisplay (fl, '\n', "%%Error: Verilated model didn't converge", NULL, NULL))
|
(new AstDisplay (fl, AstDisplayType::DISPLAY,
|
||||||
|
"%%Error: Verilated model didn't converge", NULL, NULL))
|
||||||
->addNext(new AstStop (fl)),
|
->addNext(new AstStop (fl)),
|
||||||
NULL));
|
NULL));
|
||||||
untilp->addBodysp(new AstIf(fl, new AstNeq(fl, new AstConst(fl, 0),
|
untilp->addBodysp(new AstIf(fl, new AstNeq(fl, new AstConst(fl, 0),
|
||||||
|
|
|
||||||
|
|
@ -160,8 +160,8 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Not really any way the user could do this, and we'd need to come up with some return value
|
// Not really any way the user could do this, and we'd need to come up with some return value
|
||||||
//newfuncp->addStmtsp(new AstDisplay (newfuncp->fileline(),
|
//newfuncp->addStmtsp(new AstDisplay (newfuncp->fileline(), AstDisplayType::DISPLAY,
|
||||||
// '\n', string("%%Error: ")+name+"() called with bad scope", NULL));
|
// string("%%Error: ")+name+"() called with bad scope", NULL));
|
||||||
//newfuncp->addStmtsp(new AstStop (newfuncp->fileline()));
|
//newfuncp->addStmtsp(new AstStop (newfuncp->fileline()));
|
||||||
if (debug()>=9) newfuncp->dumpTree(cout," newfunc: ");
|
if (debug()>=9) newfuncp->dumpTree(cout," newfunc: ");
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1013,7 +1013,6 @@ void EmitCStmts::displayArg(AstDisplay* dispp, AstNode** elistp, string fmt, cha
|
||||||
|
|
||||||
void EmitCStmts::visit(AstDisplay* nodep, AstNUser*) {
|
void EmitCStmts::visit(AstDisplay* nodep, AstNUser*) {
|
||||||
string vformat = nodep->text();
|
string vformat = nodep->text();
|
||||||
bool addNewline = (nodep->newline() == '\n');
|
|
||||||
AstNode* elistp = nodep->exprsp();
|
AstNode* elistp = nodep->exprsp();
|
||||||
|
|
||||||
// Convert Verilog display to C printf formats
|
// Convert Verilog display to C printf formats
|
||||||
|
|
@ -1076,7 +1075,7 @@ void EmitCStmts::visit(AstDisplay* nodep, AstNUser*) {
|
||||||
if (elistp != NULL) {
|
if (elistp != NULL) {
|
||||||
nodep->v3error("Extra arguments for $display format\n");
|
nodep->v3error("Extra arguments for $display format\n");
|
||||||
}
|
}
|
||||||
if (addNewline) emitDispState.pushFormat("\\n");
|
if (nodep->addNewline()) emitDispState.pushFormat("\\n");
|
||||||
displayEmit(nodep);
|
displayEmit(nodep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ private:
|
||||||
// Below state needs to be preserved between each module call.
|
// Below state needs to be preserved between each module call.
|
||||||
AstModule* m_modp; // Current module
|
AstModule* m_modp; // Current module
|
||||||
AstNodeFTask* m_ftaskp; // Function or task we're inside
|
AstNodeFTask* m_ftaskp; // Function or task we're inside
|
||||||
|
AstVAssert* m_assertp; // Current assertion
|
||||||
|
|
||||||
//int debug() { return 9; }
|
//int debug() { return 9; }
|
||||||
|
|
||||||
|
|
@ -72,6 +73,13 @@ private:
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
m_modp = NULL;
|
m_modp = NULL;
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstVAssert* nodep, AstNUser*) {
|
||||||
|
if (m_assertp) nodep->v3error("Assert not allowed under another assert");
|
||||||
|
m_assertp = nodep;
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
m_assertp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void visit(AstVar* nodep, AstNUser*) {
|
virtual void visit(AstVar* nodep, AstNUser*) {
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (nodep->arraysp() && nodep->isIO()) {
|
if (nodep->arraysp() && nodep->isIO()) {
|
||||||
|
|
@ -320,6 +328,13 @@ private:
|
||||||
virtual void visit(AstDisplay* nodep, AstNUser*) {
|
virtual void visit(AstDisplay* nodep, AstNUser*) {
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (nodep->filep()) expectDescriptor(nodep, nodep->filep()->castNodeVarRef());
|
if (nodep->filep()) expectDescriptor(nodep, nodep->filep()->castNodeVarRef());
|
||||||
|
if (!m_assertp
|
||||||
|
&& (nodep->displayType() == AstDisplayType::INFO
|
||||||
|
|| nodep->displayType() == AstDisplayType::WARNING
|
||||||
|
|| nodep->displayType() == AstDisplayType::ERROR
|
||||||
|
|| nodep->displayType() == AstDisplayType::FATAL)) {
|
||||||
|
nodep->v3error(nodep->verilogKwd()+" only allowed under a assertion.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void visit(AstScCtor* nodep, AstNUser*) {
|
virtual void visit(AstScCtor* nodep, AstNUser*) {
|
||||||
|
|
@ -348,6 +363,7 @@ public:
|
||||||
LinkResolveVisitor(AstNetlist* rootp) {
|
LinkResolveVisitor(AstNetlist* rootp) {
|
||||||
m_ftaskp = NULL;
|
m_ftaskp = NULL;
|
||||||
m_modp = NULL;
|
m_modp = NULL;
|
||||||
|
m_assertp = NULL;
|
||||||
//
|
//
|
||||||
rootp->accept(*this);
|
rootp->accept(*this);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -575,6 +575,13 @@ private:
|
||||||
nodep->propp()->iterateAndNext(*this,WidthVP(1,1,BOTH).p());
|
nodep->propp()->iterateAndNext(*this,WidthVP(1,1,BOTH).p());
|
||||||
widthCheckReduce(nodep,"Property",nodep->propp(),1,1); // it's like a if() condition.
|
widthCheckReduce(nodep,"Property",nodep->propp(),1,1); // it's like a if() condition.
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstVAssert* nodep, AstNUser*) {
|
||||||
|
// TOP LEVEL NODE
|
||||||
|
nodep->propp()->iterateAndNext(*this,WidthVP(1,1,BOTH).p());
|
||||||
|
nodep->passsp()->iterateAndNext(*this);
|
||||||
|
nodep->failsp()->iterateAndNext(*this);
|
||||||
|
widthCheckReduce(nodep,"Property",nodep->propp(),1,1); // it's like a if() condition.
|
||||||
|
}
|
||||||
virtual void visit(AstPin* nodep, AstNUser*) {
|
virtual void visit(AstPin* nodep, AstNUser*) {
|
||||||
//if (debug()) nodep->dumpTree(cout,"- PinPre: ");
|
//if (debug()) nodep->dumpTree(cout,"- PinPre: ");
|
||||||
// TOP LEVEL NODE
|
// TOP LEVEL NODE
|
||||||
|
|
|
||||||
|
|
@ -159,13 +159,11 @@ void process () {
|
||||||
|
|
||||||
// Assertion insertion
|
// Assertion insertion
|
||||||
// After we've added block coverage, but before other nasty transforms
|
// After we've added block coverage, but before other nasty transforms
|
||||||
if (v3Global.opt.assertOn() || v3Global.opt.psl()) {
|
V3AssertPre::assertPreAll(v3Global.rootp());
|
||||||
V3AssertPre::assertPreAll(v3Global.rootp());
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("assertpre.tree"));
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("assertpre.tree"));
|
//
|
||||||
//
|
V3Assert::assertAll(v3Global.rootp());
|
||||||
V3Assert::assertAll(v3Global.rootp());
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("assert.tree"));
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("assert.tree"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add top level wrapper with instance pointing to old top
|
// Add top level wrapper with instance pointing to old top
|
||||||
// Must do this after we know the width of any parameters
|
// Must do this after we know the width of any parameters
|
||||||
|
|
|
||||||
|
|
@ -297,9 +297,13 @@ escid \\[^ \t\f\r\n]+
|
||||||
/* System Tasks */
|
/* System Tasks */
|
||||||
"$bits" {yylval.fileline = CRELINE(); return yD_BITS;}
|
"$bits" {yylval.fileline = CRELINE(); return yD_BITS;}
|
||||||
"$countones" {yylval.fileline = CRELINE(); return yD_COUNTONES;}
|
"$countones" {yylval.fileline = CRELINE(); return yD_COUNTONES;}
|
||||||
|
"$error" {yylval.fileline = CRELINE(); return yD_ERROR;}
|
||||||
|
"$fatal" {yylval.fileline = CRELINE(); return yD_FATAL;}
|
||||||
|
"$info" {yylval.fileline = CRELINE(); return yD_INFO;}
|
||||||
"$isunknown" {yylval.fileline = CRELINE(); return yD_ISUNKNOWN;}
|
"$isunknown" {yylval.fileline = CRELINE(); return yD_ISUNKNOWN;}
|
||||||
"$onehot" {yylval.fileline = CRELINE(); return yD_ONEHOT;}
|
"$onehot" {yylval.fileline = CRELINE(); return yD_ONEHOT;}
|
||||||
"$onehot0" {yylval.fileline = CRELINE(); return yD_ONEHOT0;}
|
"$onehot0" {yylval.fileline = CRELINE(); return yD_ONEHOT0;}
|
||||||
|
"$warning" {yylval.fileline = CRELINE(); return yD_WARNING;}
|
||||||
/* Keywords */
|
/* Keywords */
|
||||||
"always_comb" {yylval.fileline = CRELINE(); return yALWAYS;}
|
"always_comb" {yylval.fileline = CRELINE(); return yALWAYS;}
|
||||||
"always_ff" {yylval.fileline = CRELINE(); return yALWAYS;}
|
"always_ff" {yylval.fileline = CRELINE(); return yALWAYS;}
|
||||||
|
|
@ -395,8 +399,9 @@ escid \\[^ \t\f\r\n]+
|
||||||
|
|
||||||
/* SystemVerilog ONLY not PSL; different rules for PSL as specified below */
|
/* SystemVerilog ONLY not PSL; different rules for PSL as specified below */
|
||||||
<S05>{
|
<S05>{
|
||||||
|
/* Keywords */
|
||||||
|
"assert" {yylval.fileline = CRELINE(); return yASSERT;}
|
||||||
/* Generic unsupported warnings */
|
/* Generic unsupported warnings */
|
||||||
"assert" {yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext);}
|
|
||||||
"assume" {yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext);}
|
"assume" {yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext);}
|
||||||
"before" {yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext);}
|
"before" {yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext);}
|
||||||
"const" {yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext);}
|
"const" {yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext);}
|
||||||
|
|
@ -424,8 +429,8 @@ escid \\[^ \t\f\r\n]+
|
||||||
/* Special things */
|
/* Special things */
|
||||||
"psl" { ; } // 'psl' may occur in middle of statement, so easier just to suppress
|
"psl" { ; } // 'psl' may occur in middle of statement, so easier just to suppress
|
||||||
/* Keywords */
|
/* Keywords */
|
||||||
"assert" {yylval.fileline = CRELINE(); return yASSERT;}
|
"assert" {yylval.fileline = CRELINE(); return yPSL_ASSERT;}
|
||||||
"assume" {yylval.fileline = CRELINE(); return yASSERT;} //==assert
|
"assume" {yylval.fileline = CRELINE(); return yPSL_ASSERT;} //==assert
|
||||||
"before_!" {yyerrorf("Illegal syntax, use before!_ instead of %s",yytext);}
|
"before_!" {yyerrorf("Illegal syntax, use before!_ instead of %s",yytext);}
|
||||||
"clock" {yylval.fileline = CRELINE(); return yCLOCK;}
|
"clock" {yylval.fileline = CRELINE(); return yCLOCK;}
|
||||||
"countones" {yylval.fileline = CRELINE(); return yD_COUNTONES;}
|
"countones" {yylval.fileline = CRELINE(); return yD_COUNTONES;}
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,11 @@ public:
|
||||||
static AstVar* createVariable(FileLine* fileline, string name, AstRange* arrayp);
|
static AstVar* createVariable(FileLine* fileline, string name, AstRange* arrayp);
|
||||||
static AstNode* createSupplyExpr(FileLine* fileline, string name, int value);
|
static AstNode* createSupplyExpr(FileLine* fileline, string name, int value);
|
||||||
static AstText* createTextQuoted(FileLine* fileline, string text);
|
static AstText* createTextQuoted(FileLine* fileline, string text);
|
||||||
|
static AstDisplay* createDisplayError(FileLine* fileline) {
|
||||||
|
AstDisplay* nodep = new AstDisplay(fileline,AstDisplayType::ERROR, "", NULL,NULL);
|
||||||
|
nodep->addNext(new AstStop(fileline));
|
||||||
|
return nodep;
|
||||||
|
}
|
||||||
static string deQuote(FileLine* fileline, string text);
|
static string deQuote(FileLine* fileline, string text);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -140,15 +145,20 @@ class AstSenTree;
|
||||||
%token<fileline> yREPORT "report"
|
%token<fileline> yREPORT "report"
|
||||||
%token<fileline> yTRUE "true"
|
%token<fileline> yTRUE "true"
|
||||||
|
|
||||||
|
%token<fileline> yPSL_ASSERT "PSL assert"
|
||||||
|
|
||||||
%token<fileline> yD_BITS "$bits"
|
%token<fileline> yD_BITS "$bits"
|
||||||
%token<fileline> yD_C "$c"
|
%token<fileline> yD_C "$c"
|
||||||
%token<fileline> yD_COUNTONES "$countones"
|
%token<fileline> yD_COUNTONES "$countones"
|
||||||
%token<fileline> yD_DISPLAY "$display"
|
%token<fileline> yD_DISPLAY "$display"
|
||||||
|
%token<fileline> yD_ERROR "$error"
|
||||||
|
%token<fileline> yD_FATAL "$fatal"
|
||||||
%token<fileline> yD_FCLOSE "$fclose"
|
%token<fileline> yD_FCLOSE "$fclose"
|
||||||
%token<fileline> yD_FDISPLAY "$fdisplay"
|
%token<fileline> yD_FDISPLAY "$fdisplay"
|
||||||
%token<fileline> yD_FINISH "$finish"
|
%token<fileline> yD_FINISH "$finish"
|
||||||
%token<fileline> yD_FOPEN "$fopen"
|
%token<fileline> yD_FOPEN "$fopen"
|
||||||
%token<fileline> yD_FWRITE "$fwrite"
|
%token<fileline> yD_FWRITE "$fwrite"
|
||||||
|
%token<fileline> yD_INFO "$info"
|
||||||
%token<fileline> yD_ISUNKNOWN "$isunknown"
|
%token<fileline> yD_ISUNKNOWN "$isunknown"
|
||||||
%token<fileline> yD_ONEHOT "$onehot"
|
%token<fileline> yD_ONEHOT "$onehot"
|
||||||
%token<fileline> yD_ONEHOT0 "$onehot0"
|
%token<fileline> yD_ONEHOT0 "$onehot0"
|
||||||
|
|
@ -158,6 +168,7 @@ class AstSenTree;
|
||||||
%token<fileline> yD_STOP "$stop"
|
%token<fileline> yD_STOP "$stop"
|
||||||
%token<fileline> yD_TIME "$time"
|
%token<fileline> yD_TIME "$time"
|
||||||
%token<fileline> yD_UNSIGNED "$unsigned"
|
%token<fileline> yD_UNSIGNED "$unsigned"
|
||||||
|
%token<fileline> yD_WARNING "$warning"
|
||||||
%token<fileline> yD_WRITE "$write"
|
%token<fileline> yD_WRITE "$write"
|
||||||
|
|
||||||
%token<fileline> yVL_CLOCK "/*verilator sc_clock*/"
|
%token<fileline> yVL_CLOCK "/*verilator sc_clock*/"
|
||||||
|
|
@ -232,7 +243,8 @@ class AstSenTree;
|
||||||
%type<nodep> defpList defpOne
|
%type<nodep> defpList defpOne
|
||||||
%type<sentreep> sensitivityE
|
%type<sentreep> sensitivityE
|
||||||
%type<senitemp> senList senitem senitemEdge
|
%type<senitemp> senList senitem senitemEdge
|
||||||
%type<nodep> stmtBlock stmtList stmt stateCaseForIf
|
%type<nodep> stmtBlock stmtList stmt labeledStmt stateCaseForIf
|
||||||
|
%type<nodep> assertStmt
|
||||||
%type<beginp> beginNamed
|
%type<beginp> beginNamed
|
||||||
%type<casep> caseStmt
|
%type<casep> caseStmt
|
||||||
%type<caseitemp> caseList
|
%type<caseitemp> caseList
|
||||||
|
|
@ -257,6 +269,7 @@ class AstSenTree;
|
||||||
%type<nodep> gateOrList gateNorList gateXorList gateXnorList
|
%type<nodep> gateOrList gateNorList gateXorList gateXnorList
|
||||||
%type<assignwp> gateBuf gateNot gateAnd gateNand gateOr gateNor gateXor gateXnor
|
%type<assignwp> gateBuf gateNot gateAnd gateNand gateOr gateNor gateXor gateXnor
|
||||||
%type<nodep> gateAndPinList gateOrPinList gateXorPinList
|
%type<nodep> gateAndPinList gateOrPinList gateXorPinList
|
||||||
|
%type<nodep> commaEListE
|
||||||
|
|
||||||
%type<nodep> pslStmt pslDir pslDirOne pslProp
|
%type<nodep> pslStmt pslDir pslDirOne pslProp
|
||||||
%type<nodep> pslDecl
|
%type<nodep> pslDecl
|
||||||
|
|
@ -652,6 +665,9 @@ stmtList: stmtBlock { $$ = $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
stmt: ';' { $$ = NULL; }
|
stmt: ';' { $$ = NULL; }
|
||||||
|
| labeledStmt { $$ = $1; }
|
||||||
|
| yID ':' labeledStmt { $$ = new AstBegin($2, *$1, $3); } /*S05 block creation rule*/
|
||||||
|
|
||||||
| varRefDotBit yLTE delayE expr ';' { $$ = new AstAssignDly($2,$1,$4); }
|
| varRefDotBit yLTE delayE expr ';' { $$ = new AstAssignDly($2,$1,$4); }
|
||||||
| varRefDotBit '=' delayE expr ';' { $$ = new AstAssign($2,$1,$4); }
|
| varRefDotBit '=' delayE expr ';' { $$ = new AstAssign($2,$1,$4); }
|
||||||
| varRefDotBit '=' yD_FOPEN '(' expr ',' expr ')' ';' { $$ = new AstFOpen($3,$1,$5,$7); }
|
| varRefDotBit '=' yD_FOPEN '(' expr ',' expr ')' ';' { $$ = new AstFOpen($3,$1,$5,$7); }
|
||||||
|
|
@ -666,21 +682,31 @@ stmt: ';' { $$ = NULL; }
|
||||||
| stateCaseForIf { $$ = $1; }
|
| stateCaseForIf { $$ = $1; }
|
||||||
| taskRef ';' { $$ = $1; }
|
| taskRef ';' { $$ = $1; }
|
||||||
|
|
||||||
| yD_DISPLAY ';' { $$ = new AstDisplay($1,'\n',"",NULL,NULL); }
|
| yD_DISPLAY ';' { $$ = new AstDisplay($1,AstDisplayType::DISPLAY,"", NULL,NULL); }
|
||||||
| yD_DISPLAY '(' ySTRING ')' ';' { $$ = new AstDisplay($1,'\n',*$3,NULL,NULL); }
|
| yD_DISPLAY '(' ySTRING commaEListE ')' ';' { $$ = new AstDisplay($1,AstDisplayType::DISPLAY,*$3,NULL,$4); }
|
||||||
| yD_DISPLAY '(' ySTRING ',' eList ')' ';' { $$ = new AstDisplay($1,'\n',*$3,NULL,$5); }
|
| yD_WRITE '(' ySTRING commaEListE ')' ';' { $$ = new AstDisplay($1,AstDisplayType::WRITE, *$3,NULL,$4); }
|
||||||
| yD_WRITE '(' ySTRING ')' ';' { $$ = new AstDisplay($1,'\0',*$3,NULL,NULL); }
|
| yD_FDISPLAY '(' varRefDotBit ',' ySTRING commaEListE ')' ';' { $$ = new AstDisplay($1,AstDisplayType::DISPLAY,*$5,$3,$6); }
|
||||||
| yD_WRITE '(' ySTRING ',' eList ')' ';' { $$ = new AstDisplay($1,'\0',*$3,NULL,$5); }
|
| yD_FWRITE '(' varRefDotBit ',' ySTRING commaEListE ')' ';' { $$ = new AstDisplay($1,AstDisplayType::WRITE, *$5,$3,$6); }
|
||||||
| yD_FDISPLAY '(' varRefDotBit ',' ySTRING ')' ';' { $$ = new AstDisplay($1,'\n',*$5,$3,NULL); }
|
| yD_INFO ';' { $$ = new AstDisplay($1,AstDisplayType::INFO, "", NULL,NULL); }
|
||||||
| yD_FDISPLAY '(' varRefDotBit ',' ySTRING ',' eList ')' ';' { $$ = new AstDisplay($1,'\n',*$5,$3,$7); }
|
| yD_INFO '(' ySTRING commaEListE ')' ';' { $$ = new AstDisplay($1,AstDisplayType::INFO, *$3,NULL,$4); }
|
||||||
| yD_FWRITE '(' varRefDotBit ',' ySTRING ')' ';' { $$ = new AstDisplay($1,'\0',*$5,$3,NULL); }
|
| yD_WARNING ';' { $$ = new AstDisplay($1,AstDisplayType::WARNING,"", NULL,NULL); }
|
||||||
| yD_FWRITE '(' varRefDotBit ',' ySTRING ',' eList ')' ';' { $$ = new AstDisplay($1,'\0',*$5,$3,$7); }
|
| yD_WARNING '(' ySTRING commaEListE ')' ';' { $$ = new AstDisplay($1,AstDisplayType::WARNING,*$3,NULL,$4); }
|
||||||
|
| yD_ERROR ';' { $$ = V3Parse::createDisplayError($1); }
|
||||||
|
| yD_ERROR '(' ySTRING commaEListE ')' ';' { $$ = new AstDisplay($1,AstDisplayType::ERROR, *$3,NULL,$4); $$->addNext(new AstStop($1)); }
|
||||||
|
| yD_FATAL ';' { $$ = new AstDisplay($1,AstDisplayType::FATAL, "", NULL,NULL); $$->addNext(new AstStop($1)); }
|
||||||
|
| yD_FATAL '(' expr ')' ';' { $$ = new AstDisplay($1,AstDisplayType::FATAL, "", NULL,NULL); $$->addNext(new AstStop($1)); }
|
||||||
|
| yD_FATAL '(' expr ',' ySTRING commaEListE ')' ';' { $$ = new AstDisplay($1,AstDisplayType::FATAL, *$5,NULL,$6); $$->addNext(new AstStop($1)); }
|
||||||
|
|
||||||
| yD_READMEMB '(' expr ',' varRefMem ')' ';' { $$ = new AstReadMem($1,false,$3,$5,NULL,NULL); }
|
| yD_READMEMB '(' expr ',' varRefMem ')' ';' { $$ = new AstReadMem($1,false,$3,$5,NULL,NULL); }
|
||||||
| yD_READMEMB '(' expr ',' varRefMem ',' expr ')' ';' { $$ = new AstReadMem($1,false,$3,$5,$7,NULL); }
|
| yD_READMEMB '(' expr ',' varRefMem ',' expr ')' ';' { $$ = new AstReadMem($1,false,$3,$5,$7,NULL); }
|
||||||
| yD_READMEMB '(' expr ',' varRefMem ',' expr ',' expr ')' ';' { $$ = new AstReadMem($1,false,$3,$5,$7,$9); }
|
| yD_READMEMB '(' expr ',' varRefMem ',' expr ',' expr ')' ';' { $$ = new AstReadMem($1,false,$3,$5,$7,$9); }
|
||||||
| yD_READMEMH '(' expr ',' varRefMem ')' ';' { $$ = new AstReadMem($1,true, $3,$5,NULL,NULL); }
|
| yD_READMEMH '(' expr ',' varRefMem ')' ';' { $$ = new AstReadMem($1,true, $3,$5,NULL,NULL); }
|
||||||
| yD_READMEMH '(' expr ',' varRefMem ',' expr ')' ';' { $$ = new AstReadMem($1,true, $3,$5,$7,NULL); }
|
| yD_READMEMH '(' expr ',' varRefMem ',' expr ')' ';' { $$ = new AstReadMem($1,true, $3,$5,$7,NULL); }
|
||||||
| yD_READMEMH '(' expr ',' varRefMem ',' expr ',' expr ')' ';' { $$ = new AstReadMem($1,true, $3,$5,$7,$9); }
|
| yD_READMEMH '(' expr ',' varRefMem ',' expr ',' expr ')' ';' { $$ = new AstReadMem($1,true, $3,$5,$7,$9); }
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
labeledStmt: assertStmt { $$ = $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
stateCaseForIf: caseStmt caseAttrE caseList yENDCASE { $$ = $1; $1->addItemsp($3); }
|
stateCaseForIf: caseStmt caseAttrE caseList yENDCASE { $$ = $1; $1->addItemsp($3); }
|
||||||
|
|
@ -692,6 +718,11 @@ stateCaseForIf: caseStmt caseAttrE caseList yENDCASE { $$ = $1; $1->addItemsp($3
|
||||||
,$13);}
|
,$13);}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
assertStmt: yASSERT '(' expr ')' stmtBlock %prec yLOWER_THAN_ELSE { $$ = new AstVAssert($1,$3,$5, V3Parse::createDisplayError($1)); }
|
||||||
|
| yASSERT '(' expr ')' yELSE stmtBlock { $$ = new AstVAssert($1,$3,NULL,$6); }
|
||||||
|
| yASSERT '(' expr ')' stmtBlock yELSE stmtBlock { $$ = new AstVAssert($1,$3,$5,$7); }
|
||||||
|
;
|
||||||
|
|
||||||
caseStmt: yCASE '(' expr ')' { $$ = V3Parse::s_caseAttrp = new AstCase($1,false,$3,NULL); }
|
caseStmt: yCASE '(' expr ')' { $$ = V3Parse::s_caseAttrp = new AstCase($1,false,$3,NULL); }
|
||||||
| yCASEX '(' expr ')' { $$ = V3Parse::s_caseAttrp = new AstCase($1,true,$3,NULL); $1->v3warn(CASEX,"Suggest casez (with ?'s) in place of casex (with X's)\n"); }
|
| yCASEX '(' expr ')' { $$ = V3Parse::s_caseAttrp = new AstCase($1,true,$3,NULL); $1->v3warn(CASEX,"Suggest casez (with ?'s) in place of casex (with X's)\n"); }
|
||||||
| yCASEZ '(' expr ')' { $$ = V3Parse::s_caseAttrp = new AstCase($1,true,$3,NULL); }
|
| yCASEZ '(' expr ')' { $$ = V3Parse::s_caseAttrp = new AstCase($1,true,$3,NULL); }
|
||||||
|
|
@ -834,6 +865,11 @@ eList: expr { $$ = $1; }
|
||||||
| eList ',' expr { $$ = $1;$1->addNext($3); }
|
| eList ',' expr { $$ = $1;$1->addNext($3); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
commaEListE: /* empty */ { $$ = NULL; }
|
||||||
|
| ',' eList { $$ = $2; }
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
// Gate declarations
|
// Gate declarations
|
||||||
gateDecl: yBUF gateBufList ';' { $$ = $2; }
|
gateDecl: yBUF gateBufList ';' { $$ = $2; }
|
||||||
| yNOT gateNotList ';' { $$ = $2; }
|
| yNOT gateNotList ';' { $$ = $2; }
|
||||||
|
|
@ -1013,8 +1049,8 @@ pslDir: yID ':' pslDirOne { $$ = $3; } // ADD: Create label on $1
|
||||||
;
|
;
|
||||||
|
|
||||||
//ADD: | yRESTRICT pslSequence ';' { $$ = PSLUNSUP(new AstPslRestrict($1,$2)); }
|
//ADD: | yRESTRICT pslSequence ';' { $$ = PSLUNSUP(new AstPslRestrict($1,$2)); }
|
||||||
pslDirOne: yASSERT pslProp ';' { $$ = new AstPslAssert($1,$2); }
|
pslDirOne: yPSL_ASSERT pslProp ';' { $$ = new AstPslAssert($1,$2); }
|
||||||
| yASSERT pslProp yREPORT ySTRING ';' { $$ = new AstPslAssert($1,$2,*$4); }
|
| yPSL_ASSERT pslProp yREPORT ySTRING ';' { $$ = new AstPslAssert($1,$2,*$4); }
|
||||||
| yCOVER pslProp ';' { $$ = new AstPslCover($1,$2); }
|
| yCOVER pslProp ';' { $$ = new AstPslCover($1,$2); }
|
||||||
| yCOVER pslProp yREPORT ySTRING ';' { $$ = new AstPslCover($1,$2,*$4); }
|
| yCOVER pslProp yREPORT ySTRING ';' { $$ = new AstPslCover($1,$2,*$4); }
|
||||||
;
|
;
|
||||||
|
|
|
||||||
|
|
@ -200,7 +200,7 @@ sub new {
|
||||||
vcs_flags2 => [], # Overridden in some sim files
|
vcs_flags2 => [], # Overridden in some sim files
|
||||||
# NC
|
# NC
|
||||||
nc => 0,
|
nc => 0,
|
||||||
nc_flags => [split(/\s+/,"+licqueue +nowarn+LIBNOU +define+nc=1 -q +assert +sv31a")],
|
nc_flags => [split(/\s+/,"+licqueue +nowarn+LIBNOU +define+nc=1 -q +assert +sv")],
|
||||||
nc_flags2 => [], # Overridden in some sim files
|
nc_flags2 => [], # Overridden in some sim files
|
||||||
# Verilator
|
# Verilator
|
||||||
'v3' => 0,
|
'v3' => 0,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
|
||||||
|
# $Id$
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2003-2007 by Wilson Snyder. This program is free software; you can
|
||||||
|
# redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# General Public License or the Perl Artistic License.
|
||||||
|
|
||||||
|
compile (
|
||||||
|
v_flags2 => [$Last_Self->{v3}?'--assert':($Last_Self->{nc}?'+assert':'')],
|
||||||
|
);
|
||||||
|
|
||||||
|
execute (
|
||||||
|
check_finished=>1,
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
// $Id$
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed into the Public Domain, for any use,
|
||||||
|
// without warranty, 2007 by Wilson Snyder.
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/
|
||||||
|
// Inputs
|
||||||
|
clk
|
||||||
|
);
|
||||||
|
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
reg toggle;
|
||||||
|
|
||||||
|
integer cyc; initial cyc=1;
|
||||||
|
wire [7:0] cyc_copy = cyc[7:0];
|
||||||
|
|
||||||
|
always @ (negedge clk) begin
|
||||||
|
AssertionFalse1: assert (cyc<100);
|
||||||
|
assert (!(cyc==5) || toggle);
|
||||||
|
// FIX cover {cyc==3 || cyc==4};
|
||||||
|
// FIX cover {cyc==9} report "DefaultClock,expect=1";
|
||||||
|
// FIX cover {(cyc==5)->toggle} report "ToggleLogIf,expect=1";
|
||||||
|
end
|
||||||
|
|
||||||
|
always @ (posedge clk) begin
|
||||||
|
if (cyc!=0) begin
|
||||||
|
cyc <= cyc + 1;
|
||||||
|
toggle <= !cyc[0];
|
||||||
|
if (cyc==9) begin
|
||||||
|
`ifdef FAILING_ASSERTIONS
|
||||||
|
assert (0) else $info;
|
||||||
|
assert (0) else $info("Info message");
|
||||||
|
assert (0) else $info("Info message, cyc=%d", cyc);
|
||||||
|
InWarningBlock: assert (0) else $warning("Warning....");
|
||||||
|
InErrorBlock: assert (0) else $error("Error....");
|
||||||
|
assert (0) else $fatal(1,"Fatal....");
|
||||||
|
`endif
|
||||||
|
end
|
||||||
|
if (cyc==10) begin
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
|
||||||
|
# $Id$
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2003-2007 by Wilson Snyder. This program is free software; you can
|
||||||
|
# redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# General Public License or the Perl Artistic License.
|
||||||
|
|
||||||
|
top_filename("t/t_assert_basic.v");
|
||||||
|
|
||||||
|
compile (
|
||||||
|
v_flags2 => [$Last_Self->{v3}?'--assert --sp --coverage-user':''],
|
||||||
|
);
|
||||||
|
|
||||||
|
execute (
|
||||||
|
check_finished=>1,
|
||||||
|
);
|
||||||
|
|
||||||
|
#Needs work
|
||||||
|
print "-Info: NOT checking for coverage\n";
|
||||||
|
#file_grep ($Last_Self->{coverage_filename}, qr/t=>'psl_cover',o=>'cover',c=>2\);/);
|
||||||
|
#file_grep ($Last_Self->{coverage_filename}, qr/DefaultClock.*,c=>1\);/);
|
||||||
|
#file_grep ($Last_Self->{coverage_filename}, qr/ToggleLogIf.*,c=>9\);/);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
|
||||||
|
# $Id$
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2003-2007 by Wilson Snyder. This program is free software; you can
|
||||||
|
# redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# General Public License or the Perl Artistic License.
|
||||||
|
|
||||||
|
top_filename("t/t_assert_basic.v");
|
||||||
|
|
||||||
|
compile (
|
||||||
|
v_flags2 => ['+define+FAILING_ASSERTIONS',
|
||||||
|
$Last_Self->{v3}?'--assert':($Last_Self->{nc}?'+assert':'')],
|
||||||
|
fails => $Last_Self->{nc},
|
||||||
|
);
|
||||||
|
|
||||||
|
execute (
|
||||||
|
fails => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
|
||||||
|
# $Id$
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2003-2007 by Wilson Snyder. This program is free software; you can
|
||||||
|
# redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# General Public License or the Perl Artistic License.
|
||||||
|
|
||||||
|
top_filename("t/t_assert_basic.v");
|
||||||
|
|
||||||
|
compile (
|
||||||
|
v_flags2 => [],
|
||||||
|
);
|
||||||
|
|
||||||
|
execute (
|
||||||
|
check_finished=>1,
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
Loading…
Reference in New Issue