mirror of
https://github.com/verilator/verilator.git
synced 2026-09-08 10:33:20 +02:00
Support $past.
This commit is contained in:
+37
-2
@@ -45,6 +45,7 @@ private:
|
||||
// STATE
|
||||
AstNodeModule* m_modp; // Last module
|
||||
AstBegin* m_beginp; // Last begin
|
||||
unsigned m_modPastNum; // Module past numbering
|
||||
V3Double0 m_statAsCover; // Statistic tracking
|
||||
V3Double0 m_statAsPsl; // Statistic tracking
|
||||
V3Double0 m_statAsFull; // Statistic tracking
|
||||
@@ -185,6 +186,7 @@ private:
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstIf* nodep) {
|
||||
if (nodep->user1SetOnce()) return;
|
||||
if (nodep->uniquePragma() || nodep->unique0Pragma()) {
|
||||
@@ -244,7 +246,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS //========== Case assertions
|
||||
//========== Case assertions
|
||||
virtual void visit(AstCase* nodep) {
|
||||
iterateChildren(nodep);
|
||||
if (!nodep->user1SetOnce()) {
|
||||
@@ -302,7 +304,38 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS //========== Statements
|
||||
//========== Past
|
||||
virtual void visit(AstPast* nodep) {
|
||||
iterateChildren(nodep);
|
||||
uint32_t ticks = 1;
|
||||
if (nodep->ticksp()) {
|
||||
if (!VN_IS(nodep->ticksp(), Const)) nodep->v3fatalSrc("Expected constant ticks, checked in V3Width");
|
||||
ticks = VN_CAST(nodep->ticksp(), Const)->toUInt();
|
||||
}
|
||||
if (ticks<1) nodep->v3fatalSrc("0 tick should have been checked in V3Width");
|
||||
AstNode* inp = nodep->exprp()->unlinkFrBack();
|
||||
AstVar* invarp = NULL;
|
||||
AstSenTree* sentreep = nodep->sentreep(); sentreep->unlinkFrBack();
|
||||
AstAlways* alwaysp = new AstAlways(nodep->fileline(), VAlwaysKwd::ALWAYS,
|
||||
sentreep, NULL);
|
||||
m_modp->addStmtp(alwaysp);
|
||||
for (uint32_t i=0; i<ticks; ++i) {
|
||||
AstVar* outvarp = new AstVar(nodep->fileline(), AstVarType::MODULETEMP,
|
||||
"_Vpast_"+cvtToStr(m_modPastNum++)+"_"+cvtToStr(i),
|
||||
inp->dtypep());
|
||||
m_modp->addStmtp(outvarp);
|
||||
AstNode* assp = new AstAssignDly(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), outvarp, true),
|
||||
inp);
|
||||
alwaysp->addStmtp(assp);
|
||||
//if (debug()>-9) assp->dumpTree(cout, "-ass: ");
|
||||
invarp = outvarp;
|
||||
inp = new AstVarRef(nodep->fileline(), invarp, false);
|
||||
}
|
||||
nodep->replaceWith(inp);
|
||||
}
|
||||
|
||||
//========== Statements
|
||||
virtual void visit(AstDisplay* nodep) {
|
||||
iterateChildren(nodep);
|
||||
// Replace the special types with standard text
|
||||
@@ -330,6 +363,7 @@ private:
|
||||
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
m_modp = nodep;
|
||||
m_modPastNum = 0;
|
||||
//
|
||||
iterateChildren(nodep);
|
||||
// Reset defaults
|
||||
@@ -354,6 +388,7 @@ public:
|
||||
explicit AssertVisitor(AstNetlist* nodep) {
|
||||
m_beginp = NULL;
|
||||
m_modp = NULL;
|
||||
m_modPastNum = 0;
|
||||
// Process
|
||||
iterate(nodep);
|
||||
}
|
||||
|
||||
+26
-5
@@ -44,9 +44,11 @@ private:
|
||||
// NODE STATE/TYPES
|
||||
// STATE
|
||||
// Reset each module:
|
||||
AstNodeSenItem* m_seniDefaultp; // Default sensitivity (from AstDefClock)
|
||||
AstNodeSenItem* m_seniDefaultp; // Default sensitivity (from AstDefClock)
|
||||
// Reset each assertion:
|
||||
AstNodeSenItem* m_senip; // Last sensitivity
|
||||
AstNodeSenItem* m_senip; // Last sensitivity
|
||||
// Reset each always:
|
||||
AstNodeSenItem* m_seniAlwaysp; // Last sensitivity in always
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
@@ -55,7 +57,9 @@ private:
|
||||
// Create sentree based on clocked or default clock
|
||||
// Return NULL for always
|
||||
AstSenTree* newp = NULL;
|
||||
AstNodeSenItem* senip = m_senip ? m_senip : m_seniDefaultp;
|
||||
AstNodeSenItem* senip = m_senip;
|
||||
if (!senip) senip = m_seniDefaultp;
|
||||
if (!senip) senip = m_seniAlwaysp;
|
||||
if (!senip) {
|
||||
nodep->v3error("Unsupported: Unclocked assertion");
|
||||
newp = new AstSenTree(nodep->fileline(), NULL);
|
||||
@@ -68,7 +72,8 @@ private:
|
||||
m_senip = NULL;
|
||||
}
|
||||
|
||||
// VISITORS //========== Statements
|
||||
// VISITORS
|
||||
//========== Statements
|
||||
virtual void visit(AstClocking* nodep) {
|
||||
UINFO(8," CLOCKING"<<nodep<<endl);
|
||||
// Store the new default clock, reset on new module
|
||||
@@ -81,16 +86,31 @@ private:
|
||||
}
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) {
|
||||
iterateAndNextNull(nodep->sensesp());
|
||||
if (nodep->sensesp()) {
|
||||
m_seniAlwaysp = nodep->sensesp()->sensesp();
|
||||
}
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
m_seniAlwaysp = NULL;
|
||||
}
|
||||
|
||||
virtual void visit(AstNodePslCoverOrAssert* nodep) {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
clearAssertInfo();
|
||||
// Find PslClocking's burried under nodep->exprsp
|
||||
iterateChildren(nodep);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
clearAssertInfo();
|
||||
}
|
||||
virtual void visit(AstPslClocked* nodep) {
|
||||
virtual void visit(AstPast* nodep) {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
iterateChildren(nodep);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
}
|
||||
virtual void visit(AstPslClocked* nodep) {
|
||||
// No need to iterate the body, once replace will get iterated
|
||||
iterateAndNextNull(nodep->sensesp());
|
||||
if (m_senip) {
|
||||
nodep->v3error("Unsupported: Only one PSL clock allowed per assertion");
|
||||
}
|
||||
@@ -120,6 +140,7 @@ public:
|
||||
// CONSTRUCTORS
|
||||
explicit AssertPreVisitor(AstNetlist* nodep) {
|
||||
m_seniDefaultp = NULL;
|
||||
m_seniAlwaysp = NULL;
|
||||
clearAssertInfo();
|
||||
// Process
|
||||
iterate(nodep);
|
||||
|
||||
+25
-1
@@ -2155,7 +2155,7 @@ public:
|
||||
//
|
||||
virtual void dump(std::ostream& str);
|
||||
AstSenTree* sensesp() const { return VN_CAST(op1p(), SenTree); } // op1 = Sensitivity list
|
||||
AstNode* bodysp() const { return op2p(); } // op2 = Statements to evaluate
|
||||
AstNode* bodysp() const { return op2p(); } // op2 = Statements to evaluate
|
||||
void addStmtp(AstNode* nodep) { addOp2p(nodep); }
|
||||
VAlwaysKwd keyword() const { return m_keyword; }
|
||||
// Special accessors
|
||||
@@ -5193,6 +5193,30 @@ public:
|
||||
virtual string emitC() { return "hypot(%li,%ri)"; }
|
||||
};
|
||||
|
||||
class AstPast : public AstNodeMath {
|
||||
// Verilog $past
|
||||
// Parents: math
|
||||
// Children: expression
|
||||
public:
|
||||
AstPast(FileLine* fl, AstNode* exprp, AstNode* ticksp) : AstNodeMath(fl) {
|
||||
addOp1p(exprp);
|
||||
addNOp2p(ticksp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(Past)
|
||||
virtual string emitVerilog() { V3ERROR_NA; return ""; }
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { V3ERROR_NA; }
|
||||
virtual string emitC() { V3ERROR_NA; return "";}
|
||||
virtual string emitSimpleOperator() { V3ERROR_NA; return "";}
|
||||
virtual bool cleanOut() { V3ERROR_NA; return "";}
|
||||
virtual int instrCount() const { return widthInstrs(); }
|
||||
AstNode* exprp() const { return op1p(); } // op1 = expression
|
||||
AstNode* ticksp() const { return op2p(); } // op2 = ticks or NULL means 1
|
||||
AstSenTree* sentreep() const { return VN_CAST(op4p(), SenTree); } // op4 = clock domain
|
||||
void sentreep(AstSenTree* sentreep) { addOp4p(sentreep); } // op4 = clock domain
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
};
|
||||
|
||||
class AstPattern : public AstNodeMath {
|
||||
// Verilog '{a,b,c,d...}
|
||||
// Parents: AstNodeAssign, AstPattern, ...
|
||||
|
||||
@@ -332,6 +332,15 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
}
|
||||
putqs(nodep,"end\n");
|
||||
}
|
||||
virtual void visit(AstPast* nodep) {
|
||||
putfs(nodep, "$past(");
|
||||
iterateAndNextNull(nodep->exprp());
|
||||
if (nodep->ticksp()) {
|
||||
puts(",");
|
||||
iterateAndNextNull(nodep->ticksp());
|
||||
}
|
||||
puts(")");
|
||||
}
|
||||
virtual void visit(AstReturn* nodep) {
|
||||
putfs(nodep,"return ");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
|
||||
@@ -94,6 +94,7 @@ public:
|
||||
STMTDLY, // Delayed statement
|
||||
SYMRSVDWORD, // Symbol is Reserved Word
|
||||
SYNCASYNCNET, // Mixed sync + async reset
|
||||
TICKCOUNT, // Too large tick count
|
||||
UNDRIVEN, // No drivers
|
||||
UNOPT, // Unoptimizable block
|
||||
UNOPTFLAT, // Unoptimizable block after flattening
|
||||
@@ -140,6 +141,7 @@ public:
|
||||
"PINMISSING", "PINNOCONNECT", "PINCONNECTEMPTY",
|
||||
"REALCVT", "REDEFMACRO",
|
||||
"SELRANGE", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET",
|
||||
"TICKCOUNT",
|
||||
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS",
|
||||
"UNPACKED", "UNSIGNED", "UNUSED",
|
||||
"USERERROR", "USERFATAL", "USERINFO", "USERWARN",
|
||||
|
||||
@@ -798,6 +798,26 @@ private:
|
||||
// We don't size the constant until we commit the widths, as need parameters
|
||||
// to remain unsized, and numbers to remain unsized to avoid backp() warnings
|
||||
}
|
||||
virtual void visit(AstPast* nodep) {
|
||||
if (m_vup->prelim()) {
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
|
||||
nodep->dtypeFrom(nodep->exprp());
|
||||
if (nodep->ticksp()) {
|
||||
iterateCheckSizedSelf(nodep, "Ticks", nodep->ticksp(), SELF, BOTH);
|
||||
V3Const::constifyParamsEdit(nodep->ticksp()); // ticksp may change
|
||||
const AstConst* constp = VN_CAST(nodep->ticksp(), Const);
|
||||
if (!constp || constp->toSInt() < 1) {
|
||||
nodep->v3error("$past tick value must be constant and >= 1 (IEEE 2017 16.9.3)");
|
||||
nodep->ticksp()->unlinkFrBack()->deleteTree();
|
||||
} else {
|
||||
if (constp->toSInt() > 10) {
|
||||
nodep->v3warn(TICKCOUNT, "$past tick value of "<<constp->toSInt()
|
||||
<<" may have a large performance cost");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstRand* nodep) {
|
||||
if (m_vup->prelim()) {
|
||||
nodep->dtypeSetSigned32(); // Says the spec
|
||||
|
||||
@@ -444,6 +444,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
"$low" { FL; return yD_LOW; }
|
||||
"$onehot" { FL; return yD_ONEHOT; }
|
||||
"$onehot0" { FL; return yD_ONEHOT0; }
|
||||
"$past" { FL; return yD_PAST; }
|
||||
"$right" { FL; return yD_RIGHT; }
|
||||
"$size" { FL; return yD_SIZE; }
|
||||
"$unpacked_dimensions" { FL; return yD_UNPACKED_DIMENSIONS; }
|
||||
|
||||
+6
-1
@@ -485,6 +485,7 @@ class AstSenTree;
|
||||
%token<fl> yD_LOW "$low"
|
||||
%token<fl> yD_ONEHOT "$onehot"
|
||||
%token<fl> yD_ONEHOT0 "$onehot0"
|
||||
%token<fl> yD_PAST "$past"
|
||||
%token<fl> yD_POW "$pow"
|
||||
%token<fl> yD_RANDOM "$random"
|
||||
%token<fl> yD_READMEMB "$readmemb"
|
||||
@@ -2776,8 +2777,12 @@ system_f_call_or_t<nodep>: // IEEE: part of system_tf_call (can be task or func)
|
||||
| yD_LOW '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_LOW,$3,$5); }
|
||||
| yD_ONEHOT '(' expr ')' { $$ = new AstOneHot($1,$3); }
|
||||
| yD_ONEHOT0 '(' expr ')' { $$ = new AstOneHot0($1,$3); }
|
||||
| yD_PAST '(' expr ')' { $$ = new AstPast($1,$3, NULL); }
|
||||
| yD_PAST '(' expr ',' expr ')' { $$ = new AstPast($1,$3, $5); }
|
||||
| yD_PAST '(' expr ',' expr ',' expr ')' { $1->v3error("Unsupported: $past expr2 and clock arguments"); $$ = $3; }
|
||||
| yD_PAST '(' expr ',' expr ',' expr ',' expr')' { $1->v3error("Unsupported: $past expr2 and clock arguments"); $$ = $3; }
|
||||
| yD_POW '(' expr ',' expr ')' { $$ = new AstPowD($1,$3,$5); }
|
||||
| yD_RANDOM '(' expr ')' { $1->v3error("Unsupported: Seeding $random doesn't map to C++, use $c(\"srand\")"); }
|
||||
| yD_RANDOM '(' expr ')' { $1->v3error("Unsupported: Seeding $random doesn't map to C++, use $c(\"srand\")"); $$ = NULL; }
|
||||
| yD_RANDOM parenE { $$ = new AstRand($1); }
|
||||
| yD_REALTIME parenE { $$ = new AstTimeD($1); }
|
||||
| yD_REALTOBITS '(' expr ')' { $$ = new AstRealToBits($1,$3); }
|
||||
|
||||
Reference in New Issue
Block a user