Support future sampled value functions.
This commit is contained in:
parent
7affb3e580
commit
ac2a75fbb5
1
Changes
1
Changes
|
|
@ -40,6 +40,7 @@ Verilator 5.039 devel
|
|||
* Support parameter resolution of 1D unpacked array slices (#6257) (#6268). [Michael Bedford Taylor]
|
||||
* Support generic interfaces (#6272). [Igor Zaworski, Antmicro Ltd.]
|
||||
* Support disabling a fork from within that fork (#6314). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Support future sampled value functions.
|
||||
* Change control file `public_flat_*` and other signal attributes to support __ in names (#6140).
|
||||
* Change runtime to exit() instead of abort(), unless under +verilated+debug.
|
||||
* Change `$display("%p")` to remove space after `}`.
|
||||
|
|
|
|||
121
src/V3Assert.cpp
121
src/V3Assert.cpp
|
|
@ -22,6 +22,98 @@
|
|||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
//######################################################################
|
||||
// AssertDeFuture
|
||||
// If any AstFuture, then move all non-future varrefs to be one cycle behind,
|
||||
// see IEEE 1800-2023 16.9.4.
|
||||
|
||||
class AssertDeFuture final : public VNVisitor {
|
||||
// STATE - across all visitors
|
||||
AstNodeModule* const m_modp; // Module future is underneath
|
||||
const AstFuture* m_futurep; // First AstFuture found
|
||||
const unsigned m_pastNum; // Prefix unique number for this module
|
||||
std::map<AstVar*, AstVar*> m_delayedVars; // Old to delayed variable mapping
|
||||
// STATE - for current visit position (use VL_RESTORER)
|
||||
bool m_inFuture = false; // Inside a future
|
||||
bool m_unsupported = false; // Printed unsupported
|
||||
|
||||
// METHODS
|
||||
void unsupported(AstNode* nodep) {
|
||||
if (m_unsupported) return;
|
||||
m_unsupported = true;
|
||||
nodep->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported/illegal: future value function used with expression with "
|
||||
<< nodep->prettyOperatorName());
|
||||
}
|
||||
// VISITORS
|
||||
void visit(AstFuture* nodep) override {
|
||||
VL_RESTORER(m_inFuture);
|
||||
m_inFuture = true;
|
||||
iterateChildren(nodep);
|
||||
// Done with the future, this subexpression is current-time
|
||||
nodep->replaceWith(nodep->exprp()->unlinkFrBack());
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void visit(AstNodeVarRef* nodep) override {
|
||||
if (nodep->user1SetOnce()) return;
|
||||
if (m_inFuture || m_unsupported)
|
||||
return; // Need user1 set above, don't process when Future is removed
|
||||
if (nodep->access().isWriteOrRW()) {
|
||||
unsupported(nodep);
|
||||
return;
|
||||
}
|
||||
auto it = m_delayedVars.find(nodep->varp());
|
||||
AstVar* outvarp;
|
||||
if (it == m_delayedVars.end()) {
|
||||
AstSenTree* const sentreep = m_futurep->sentreep();
|
||||
AstAlways* const alwaysp = new AstAlways{nodep->fileline(), VAlwaysKwd::ALWAYS,
|
||||
sentreep->cloneTree(false), nullptr};
|
||||
m_modp->addStmtsp(alwaysp);
|
||||
outvarp = new AstVar{nodep->fileline(), VVarType::MODULETEMP,
|
||||
"__Vnotfuture" + cvtToStr(m_pastNum) + "_" + nodep->name(),
|
||||
nodep->dtypep()};
|
||||
m_modp->addStmtsp(outvarp);
|
||||
AstVarRef* varRefAWritep = new AstVarRef{nodep->fileline(), outvarp, VAccess::WRITE};
|
||||
varRefAWritep->user1(true);
|
||||
AstNodeVarRef* varRefAReadp = nodep->cloneTree(false);
|
||||
varRefAReadp->user1(true);
|
||||
AstNode* const assp = new AstAssignDly{nodep->fileline(), varRefAWritep, varRefAReadp};
|
||||
alwaysp->addStmtsp(assp);
|
||||
m_delayedVars.emplace(nodep->varp(), outvarp);
|
||||
} else {
|
||||
outvarp = it->second;
|
||||
}
|
||||
AstVarRef* newp = new AstVarRef{nodep->fileline(), outvarp, VAccess::READ};
|
||||
newp->user1(true);
|
||||
UINFO(9, "DeFuture " << nodep << " becomes " << newp);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void visit(AstNodeFTaskRef* nodep) override { unsupported(nodep); }
|
||||
void visit(AstMethodCall* nodep) override { unsupported(nodep); }
|
||||
void visit(AstNode* nodep) override {
|
||||
if (!nodep->isPure()) unsupported(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit AssertDeFuture(AstNode* nodep, AstNodeModule* modp, unsigned pastNum)
|
||||
: m_modp{modp}
|
||||
, m_pastNum{pastNum} {
|
||||
// See if any Future before we process
|
||||
if (nodep->forall([&](const AstFuture* futurep) -> bool {
|
||||
m_futurep = futurep;
|
||||
return false;
|
||||
}))
|
||||
return;
|
||||
// UINFOTREE(9, nodep, "", "defuture-in");
|
||||
visit(nodep); // Nodep may get deleted
|
||||
// UINFOTREE(9, nodep, "", "defuture-ou");
|
||||
}
|
||||
~AssertDeFuture() = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// AssertVisitor
|
||||
|
||||
|
|
@ -32,7 +124,7 @@ class AssertVisitor final : public VNVisitor {
|
|||
|
||||
// NODE STATE/TYPES
|
||||
// Cleared on netlist
|
||||
// AstNode::user() -> bool. True if processed
|
||||
// AstNode::user1() -> bool. True if processed
|
||||
const VNUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
|
|
@ -203,9 +295,12 @@ class AssertVisitor final : public VNVisitor {
|
|||
return bodysp;
|
||||
}
|
||||
|
||||
void newPslAssertion(AstNodeCoverOrAssert* nodep, AstNode* failsp) {
|
||||
void visitAssertionIterate(AstNodeCoverOrAssert* nodep, AstNode* failsp) {
|
||||
if (m_beginp && nodep->name() == "") nodep->name(m_beginp->name());
|
||||
|
||||
{ AssertDeFuture{nodep->propp(), m_modp, m_modPastNum++}; }
|
||||
iterateChildren(nodep);
|
||||
|
||||
AstNodeExpr* const propp = VN_AS(nodep->propp()->unlinkFrBackWithNext(), NodeExpr);
|
||||
AstSenTree* const sentreep = nodep->sentreep();
|
||||
const string& message = nodep->name();
|
||||
|
|
@ -449,6 +544,13 @@ class AssertVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
void visit(AstFuture* nodep) override {
|
||||
nodep->v3error("Future sampled value function called outside property or sequence "
|
||||
"expression (IEEE 16.9.4)");
|
||||
nodep->replaceWith(new AstConst{nodep->fileline(), 0});
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
|
||||
//========== Past
|
||||
void visit(AstPast* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -599,9 +701,8 @@ class AssertVisitor final : public VNVisitor {
|
|||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void visit(AstAssert* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
newPslAssertion(nodep, nodep->failsp());
|
||||
void visit(AstAssert* nodep) override { //
|
||||
visitAssertionIterate(nodep, nodep->failsp());
|
||||
}
|
||||
void visit(AstAssertCtl* nodep) override {
|
||||
if (VN_IS(m_modp, Class) || VN_IS(m_modp, Iface)) {
|
||||
|
|
@ -678,13 +779,11 @@ class AssertVisitor final : public VNVisitor {
|
|||
}
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void visit(AstAssertIntrinsic* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
newPslAssertion(nodep, nodep->failsp());
|
||||
void visit(AstAssertIntrinsic* nodep) override { //
|
||||
visitAssertionIterate(nodep, nodep->failsp());
|
||||
}
|
||||
void visit(AstCover* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
newPslAssertion(nodep, nullptr);
|
||||
void visit(AstCover* nodep) override { //
|
||||
visitAssertionIterate(nodep, nullptr);
|
||||
}
|
||||
void visit(AstRestrict* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
|
|
|
|||
|
|
@ -453,6 +453,19 @@ private:
|
|||
if (!nodep->immediate()) nodep->sentreep(newSenTree(nodep));
|
||||
clearAssertInfo();
|
||||
}
|
||||
void visit(AstFalling* nodep) override {
|
||||
if (nodep->user1SetOnce()) return;
|
||||
iterateChildren(nodep);
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
||||
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
|
||||
AstNodeExpr* const futurep = new AstFuture{fl, exprp, newSenTree(nodep)};
|
||||
futurep->dtypeFrom(exprp);
|
||||
exprp = new AstAnd{fl, exprp->cloneTreePure(false), new AstNot{fl, futurep}};
|
||||
exprp->dtypeSetBit();
|
||||
nodep->replaceWith(exprp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void visit(AstFell* nodep) override {
|
||||
if (nodep->user1SetOnce()) return;
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -469,11 +482,31 @@ private:
|
|||
nodep->sentreep(newSenTree(nodep, sentreep));
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void visit(AstFuture* nodep) override {
|
||||
if (nodep->user1SetOnce()) return;
|
||||
iterateChildren(nodep);
|
||||
AstSenTree* const sentreep = nodep->sentreep();
|
||||
if (sentreep) sentreep->unlinkFrBack();
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
}
|
||||
void visit(AstPast* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
iterateChildren(nodep);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
}
|
||||
void visit(AstRising* nodep) override {
|
||||
if (nodep->user1SetOnce()) return;
|
||||
iterateChildren(nodep);
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
||||
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
|
||||
AstNodeExpr* const futurep = new AstFuture{fl, exprp, newSenTree(nodep)};
|
||||
futurep->dtypeFrom(exprp);
|
||||
exprp = new AstAnd{fl, new AstNot{fl, exprp->cloneTreePure(false)}, futurep};
|
||||
exprp->dtypeSetBit();
|
||||
nodep->replaceWith(exprp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void visit(AstRose* nodep) override {
|
||||
if (nodep->user1SetOnce()) return;
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -505,6 +538,19 @@ private:
|
|||
nodep->sentreep(newSenTree(nodep, sentreep));
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void visit(AstSteady* nodep) override {
|
||||
if (nodep->user1SetOnce()) return;
|
||||
iterateChildren(nodep);
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
||||
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
|
||||
AstNodeExpr* const futurep = new AstFuture{fl, exprp, newSenTree(nodep)};
|
||||
futurep->dtypeFrom(exprp);
|
||||
exprp = new AstEq{fl, exprp->cloneTreePure(false), futurep};
|
||||
exprp->dtypeSetBit();
|
||||
nodep->replaceWith(exprp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
|
||||
void visit(AstImplication* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
|
|
|
|||
|
|
@ -1489,6 +1489,22 @@ public:
|
|||
bool cleanOut() const override { return false; }
|
||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstFalling final : public AstNodeExpr {
|
||||
// Verilog $falling_gclk
|
||||
// @astgen op1 := exprp : AstNodeExpr
|
||||
public:
|
||||
AstFalling(FileLine* fl, AstNodeExpr* exprp)
|
||||
: ASTGEN_SUPER_Falling(fl) {
|
||||
this->exprp(exprp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstFalling;
|
||||
string emitVerilog() override { return "$falling_gclk(%l)"; }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstFell final : public AstNodeExpr {
|
||||
// Verilog $fell
|
||||
// @astgen op1 := exprp : AstNodeExpr
|
||||
|
|
@ -1507,6 +1523,24 @@ public:
|
|||
int instrCount() const override { return widthInstrs(); }
|
||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstFuture final : public AstNodeExpr {
|
||||
// Verilog $future_gclk
|
||||
// @astgen op1 := exprp : AstNodeExpr
|
||||
// @astgen op2 := sentreep : Optional[AstSenTree]
|
||||
public:
|
||||
AstFuture(FileLine* fl, AstNodeExpr* exprp, AstSenTree* sentreep)
|
||||
: ASTGEN_SUPER_Future(fl) {
|
||||
this->exprp(exprp);
|
||||
this->sentreep(sentreep);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstFuture;
|
||||
string emitVerilog() override { return "$future_gclk(%l)"; }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstGatePin final : public AstNodeExpr {
|
||||
// Possibly expand a gate primitive input pin value to match the range of the gate primitive
|
||||
// @astgen op1 := exprp : AstNodeExpr // Pin expression
|
||||
|
|
@ -1888,6 +1922,22 @@ public:
|
|||
int instrCount() const override { return INSTR_COUNT_PLI; }
|
||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstRising final : public AstNodeExpr {
|
||||
// Verilog $rising_gclk
|
||||
// @astgen op1 := exprp : AstNodeExpr
|
||||
public:
|
||||
AstRising(FileLine* fl, AstNodeExpr* exprp)
|
||||
: ASTGEN_SUPER_Rising(fl) {
|
||||
this->exprp(exprp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstRising;
|
||||
string emitVerilog() override { return "$rising_gclk(%l)"; }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstRose final : public AstNodeExpr {
|
||||
// Verilog $rose
|
||||
// @astgen op1 := exprp : AstNodeExpr
|
||||
|
|
@ -2147,6 +2197,22 @@ public:
|
|||
bool cleanOut() const override { return true; }
|
||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstSteady final : public AstNodeExpr {
|
||||
// Verilog $steady_gclk
|
||||
// @astgen op1 := exprp : AstNodeExpr
|
||||
public:
|
||||
AstSteady(FileLine* fl, AstNodeExpr* exprp)
|
||||
: ASTGEN_SUPER_Steady(fl) {
|
||||
this->exprp(exprp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstSteady;
|
||||
string emitVerilog() override { return "$steady_gclk(%l)"; }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstStructSel final : public AstNodeExpr {
|
||||
// Unpacked struct/union member access
|
||||
// Parents: math|stmt
|
||||
|
|
|
|||
|
|
@ -426,6 +426,11 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
|||
iterateAndNextConstNull(nodep->exprp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstRising* nodep) override {
|
||||
putfs(nodep, "$rising(");
|
||||
iterateAndNextConstNull(nodep->exprp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstRose* nodep) override {
|
||||
putfs(nodep, "$rose(");
|
||||
iterateAndNextConstNull(nodep->exprp());
|
||||
|
|
@ -444,6 +449,16 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
|||
}
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstFalling* nodep) override {
|
||||
putfs(nodep, "$falling(");
|
||||
iterateAndNextConstNull(nodep->exprp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstFuture* nodep) override {
|
||||
putfs(nodep, "$future(");
|
||||
iterateAndNextConstNull(nodep->exprp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstStable* nodep) override {
|
||||
putfs(nodep, "$stable(");
|
||||
iterateAndNextConstNull(nodep->exprp());
|
||||
|
|
@ -453,6 +468,11 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
|||
}
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstSteady* nodep) override {
|
||||
putfs(nodep, "$steady(");
|
||||
iterateAndNextConstNull(nodep->exprp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstReturn* nodep) override {
|
||||
putfs(nodep, "return ");
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
|
|
|
|||
|
|
@ -1344,6 +1344,19 @@ class WidthVisitor final : public VNVisitor {
|
|||
nodep->dtypeSetBit();
|
||||
}
|
||||
}
|
||||
void visit(AstFalling* nodep) override {
|
||||
if (m_vup->prelim()) {
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
|
||||
nodep->dtypeSetBit();
|
||||
}
|
||||
}
|
||||
void visit(AstFuture* nodep) override {
|
||||
if (m_vup->prelim()) {
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
|
||||
userIterate(nodep->sentreep(), nullptr);
|
||||
nodep->dtypeFrom(nodep->exprp());
|
||||
}
|
||||
}
|
||||
void visit(AstPast* nodep) override {
|
||||
if (m_vup->prelim()) {
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
|
||||
|
|
@ -1369,6 +1382,12 @@ class WidthVisitor final : public VNVisitor {
|
|||
userIterate(nodep->sentreep(), nullptr);
|
||||
}
|
||||
}
|
||||
void visit(AstRising* nodep) override {
|
||||
if (m_vup->prelim()) {
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
|
||||
nodep->dtypeSetBit();
|
||||
}
|
||||
}
|
||||
void visit(AstRose* nodep) override {
|
||||
if (m_vup->prelim()) {
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
|
||||
|
|
@ -1431,6 +1450,12 @@ class WidthVisitor final : public VNVisitor {
|
|||
nodep->dtypeSetBit();
|
||||
}
|
||||
}
|
||||
void visit(AstSteady* nodep) override {
|
||||
if (m_vup->prelim()) {
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
|
||||
nodep->dtypeSetBit();
|
||||
}
|
||||
}
|
||||
|
||||
void visit(AstStmtExpr* nodep) override {
|
||||
assertAtStatement(nodep);
|
||||
|
|
|
|||
|
|
@ -471,13 +471,16 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
|||
"$bits" { FL; return yD_BITS; }
|
||||
"$changed" { FL; return yD_CHANGED; }
|
||||
"$changed_gclk" { FL; return yD_CHANGED_GCLK; }
|
||||
"$changing_gclk" { FL; return yD_CHANGING_GCLK; }
|
||||
"$countbits" { FL; return yD_COUNTBITS; }
|
||||
"$countones" { FL; return yD_COUNTONES; }
|
||||
"$dimensions" { FL; return yD_DIMENSIONS; }
|
||||
"$error" { FL; return yD_ERROR; }
|
||||
"$falling_gclk" { FL; return yD_FALLING_GCLK; }
|
||||
"$fatal" { FL; return yD_FATAL; }
|
||||
"$fell" { FL; return yD_FELL; }
|
||||
"$fell_gclk" { FL; return yD_FELL_GCLK; }
|
||||
"$future_gclk" { FL; return yD_FUTURE_GCLK; }
|
||||
"$high" { FL; return yD_HIGH; }
|
||||
"$increment" { FL; return yD_INCREMENT; }
|
||||
"$inferred_disable" { FL; return yD_INFERRED_DISABLE; }
|
||||
|
|
@ -491,12 +494,14 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
|||
"$past" { FL; return yD_PAST; }
|
||||
"$past_gclk" { FL; return yD_PAST_GCLK; }
|
||||
"$right" { FL; return yD_RIGHT; }
|
||||
"$rising_gclk" { FL; return yD_RISING_GCLK; }
|
||||
"$root" { FL; return yD_ROOT; }
|
||||
"$rose" { FL; return yD_ROSE; }
|
||||
"$rose_gclk" { FL; return yD_ROSE_GCLK; }
|
||||
"$size" { FL; return yD_SIZE; }
|
||||
"$stable" { FL; return yD_STABLE; }
|
||||
"$stable_gclk" { FL; return yD_STABLE_GCLK; }
|
||||
"$steady_gclk" { FL; return yD_STEADY_GCLK; }
|
||||
"$unpacked_dimensions" { FL; return yD_UNPACKED_DIMENSIONS; }
|
||||
"$warning" { FL; return yD_WARNING; }
|
||||
/* SV2005 Keywords */
|
||||
|
|
|
|||
|
|
@ -853,6 +853,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
|
|||
%token<fl> yD_CEIL "$ceil"
|
||||
%token<fl> yD_CHANGED "$changed"
|
||||
%token<fl> yD_CHANGED_GCLK "$changed_gclk"
|
||||
%token<fl> yD_CHANGING_GCLK "$changing_gclk"
|
||||
%token<fl> yD_CLOG2 "$clog2"
|
||||
%token<fl> yD_COS "$cos"
|
||||
%token<fl> yD_COSH "$cosh"
|
||||
|
|
@ -881,6 +882,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
|
|||
%token<fl> yD_ERROR "$error"
|
||||
%token<fl> yD_EXIT "$exit"
|
||||
%token<fl> yD_EXP "$exp"
|
||||
%token<fl> yD_FALLING_GCLK "$falling_gclk"
|
||||
%token<fl> yD_FATAL "$fatal"
|
||||
%token<fl> yD_FCLOSE "$fclose"
|
||||
%token<fl> yD_FDISPLAY "$fdisplay"
|
||||
|
|
@ -910,6 +912,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
|
|||
%token<fl> yD_FSTROBEH "$fstrobeh"
|
||||
%token<fl> yD_FSTROBEO "$fstrobeo"
|
||||
%token<fl> yD_FTELL "$ftell"
|
||||
%token<fl> yD_FUTURE_GCLK "$future_gclk"
|
||||
%token<fl> yD_FWRITE "$fwrite"
|
||||
%token<fl> yD_FWRITEB "$fwriteb"
|
||||
%token<fl> yD_FWRITEH "$fwriteh"
|
||||
|
|
@ -946,6 +949,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
|
|||
%token<fl> yD_REALTOBITS "$realtobits"
|
||||
%token<fl> yD_REWIND "$rewind"
|
||||
%token<fl> yD_RIGHT "$right"
|
||||
%token<fl> yD_RISING_GCLK "$rising_gclk"
|
||||
%token<fl> yD_ROOT "$root"
|
||||
%token<fl> yD_ROSE "$rose"
|
||||
%token<fl> yD_ROSE_GCLK "$rose_gclk"
|
||||
|
|
@ -965,6 +969,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
|
|||
%token<fl> yD_STABLE "$stable"
|
||||
%token<fl> yD_STABLE_GCLK "$stable_gclk"
|
||||
%token<fl> yD_STACKTRACE "$stacktrace"
|
||||
%token<fl> yD_STEADY_GCLK "$steady_gclk"
|
||||
%token<fl> yD_STIME "$stime"
|
||||
%token<fl> yD_STOP "$stop"
|
||||
%token<fl> yD_STROBE "$strobe"
|
||||
|
|
@ -4490,6 +4495,8 @@ system_f_call_or_t<nodeExprp>: // IEEE: part of system_tf_call (can be task
|
|||
{ $$ = new AstLogNot{$1, new AstStable{$1, $3, GRAMMARP->createSenTreeChanged($1, $5)}}; }
|
||||
| yD_CHANGED_GCLK '(' expr ')'
|
||||
{ $$ = new AstLogNot{$1, new AstStable{$1, $3, GRAMMARP->createGlobalClockSenTree($1)}}; }
|
||||
| yD_CHANGING_GCLK '(' expr ')'
|
||||
{ $$ = new AstLogNot{$1, new AstSteady{$1, $3}}; }
|
||||
| yD_CLOG2 '(' expr ')' { $$ = new AstCLog2{$1, $3}; }
|
||||
| yD_COS '(' expr ')' { $$ = new AstCosD{$1, $3}; }
|
||||
| yD_COSH '(' expr ')' { $$ = new AstCoshD{$1, $3}; }
|
||||
|
|
@ -4509,6 +4516,7 @@ system_f_call_or_t<nodeExprp>: // IEEE: part of system_tf_call (can be task
|
|||
| yD_DIST_T '(' expr ',' expr ')' { $$ = new AstDistT{$1, $3, $5}; }
|
||||
| yD_DIST_UNIFORM '(' expr ',' expr ',' expr ')' { $$ = new AstDistUniform{$1, $3, $5, $7}; }
|
||||
| yD_EXP '(' expr ')' { $$ = new AstExpD{$1, $3}; }
|
||||
| yD_FALLING_GCLK '(' expr ')' { $$ = new AstFalling{$1, $3}; }
|
||||
| yD_FELL '(' expr ')' { $$ = new AstFell{$1, $3, nullptr}; }
|
||||
| yD_FELL '(' expr ',' expr ')' { $$ = new AstFell{$1, $3, GRAMMARP->createSenTreeChanged($1, $5)}; }
|
||||
| yD_FELL_GCLK '(' expr ')' { $$ = new AstFell{$1, $3, GRAMMARP->createGlobalClockSenTree($1)}; }
|
||||
|
|
@ -4523,6 +4531,7 @@ system_f_call_or_t<nodeExprp>: // IEEE: part of system_tf_call (can be task
|
|||
| yD_FREAD '(' expr ',' expr ',' expr ',' expr ')' { $$ = new AstFRead{$1, $3, $5, $7, $9}; }
|
||||
| yD_FREAD '(' expr ',' expr ',' ',' expr ')' { $$ = new AstFRead{$1, $3, $5, nullptr, $8}; }
|
||||
| yD_FREWIND '(' expr ')' { $$ = new AstFRewind{$1, $3}; }
|
||||
| yD_FUTURE_GCLK '(' expr ')' { $$ = new AstFuture{$1, $3, nullptr}; }
|
||||
| yD_FLOOR '(' expr ')' { $$ = new AstFloorD{$1, $3}; }
|
||||
| yD_FSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstFScanF{$1, *$5, $3, $6}; }
|
||||
| yD_FSEEK '(' expr ',' expr ',' expr ')' { $$ = new AstFSeek{$1, $3, $5, $7}; }
|
||||
|
|
@ -4562,6 +4571,7 @@ system_f_call_or_t<nodeExprp>: // IEEE: part of system_tf_call (can be task
|
|||
| yD_REWIND '(' expr ')' { $$ = new AstFSeek{$1, $3, new AstConst{$1, 0}, new AstConst{$1, 0}}; }
|
||||
| yD_RIGHT '(' exprOrDataType ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_RIGHT, $3, nullptr}; }
|
||||
| yD_RIGHT '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_RIGHT, $3, $5}; }
|
||||
| yD_RISING_GCLK '(' expr ')' { $$ = new AstRising{$1, $3}; }
|
||||
| yD_ROSE '(' expr ')' { $$ = new AstRose{$1, $3, nullptr}; }
|
||||
| yD_ROSE '(' expr ',' expr ')' { $$ = new AstRose{$1, $3, GRAMMARP->createSenTreeChanged($1, $5)}; }
|
||||
| yD_ROSE_GCLK '(' expr ')' { $$ = new AstRose{$1, $3, GRAMMARP->createGlobalClockSenTree($1)}; }
|
||||
|
|
@ -4576,11 +4586,12 @@ system_f_call_or_t<nodeExprp>: // IEEE: part of system_tf_call (can be task
|
|||
| yD_SIZE '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_SIZE, $3, $5}; }
|
||||
| yD_SQRT '(' expr ')' { $$ = new AstSqrtD{$1, $3}; }
|
||||
| yD_SSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstSScanF{$1, *$5, $3, $6}; }
|
||||
| yD_STIME parenE
|
||||
{ $$ = new AstSel{$1, new AstTime{$1, VTimescale{VTimescale::NONE}}, 0, 32}; }
|
||||
| yD_STABLE '(' expr ')' { $$ = new AstStable{$1, $3, nullptr}; }
|
||||
| yD_STABLE '(' expr ',' expr ')' { $$ = new AstStable{$1, $3, GRAMMARP->createSenTreeChanged($1, $5)}; }
|
||||
| yD_STABLE_GCLK '(' expr ')' { $$ = new AstStable{$1, $3, GRAMMARP->createGlobalClockSenTree($1)}; }
|
||||
| yD_STEADY_GCLK '(' expr ')' { $$ = new AstSteady{$1, $3}; }
|
||||
| yD_STIME parenE
|
||||
{ $$ = new AstSel{$1, new AstTime{$1, VTimescale{VTimescale::NONE}}, 0, 32}; }
|
||||
| yD_TAN '(' expr ')' { $$ = new AstTanD{$1, $3}; }
|
||||
| yD_TANH '(' expr ')' { $$ = new AstTanhD{$1, $3}; }
|
||||
| yD_TESTPLUSARGS '(' expr ')' { $$ = new AstTestPlusArgs{$1, $3}; }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=['--assert'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkd(gotv, expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
module t (
|
||||
/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
global clocking @(posedge clk);
|
||||
endclocking
|
||||
|
||||
logic a;
|
||||
|
||||
//PASSES:
|
||||
int count_not_stable; // Counts changes
|
||||
assert property (@(posedge clk) $stable(a))
|
||||
else count_not_stable = count_not_stable + 1;
|
||||
|
||||
int count_not_stable_gclk; // Counts changes
|
||||
assert property (@(posedge clk) $stable_gclk(a))
|
||||
else count_not_stable_gclk = count_not_stable_gclk + 1;
|
||||
|
||||
int count_changing_gclk;
|
||||
assert property (@(posedge clk) $changing_gclk(a)) count_changing_gclk = count_changing_gclk + 1;
|
||||
|
||||
int count_falling_gclk;
|
||||
assert property (@(posedge clk) $falling_gclk(a)) count_falling_gclk = count_falling_gclk + 1;
|
||||
|
||||
int count_future_gclk; // Counts changes
|
||||
assert property (@(posedge clk) $future_gclk(a) != a) count_future_gclk = count_future_gclk + 1;
|
||||
|
||||
int count_rising_gclk;
|
||||
assert property (@(posedge clk) $rising_gclk(a)) count_rising_gclk = count_rising_gclk + 1;
|
||||
|
||||
int count_not_steady_gclk; // Counts changes
|
||||
assert property (@(posedge clk) $steady_gclk(a))
|
||||
else count_not_steady_gclk = count_not_steady_gclk + 1;
|
||||
|
||||
int cyc = 0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
`ifdef TEST_VERBOSE
|
||||
$display("[%0t] cyc=%0d a=%0x gs=%x gsc=%x", $time, cyc, a, count_not_stable,
|
||||
count_not_stable_gclk);
|
||||
`endif
|
||||
cyc <= cyc + 1;
|
||||
if (cyc <= 3) begin
|
||||
a <= 0;
|
||||
count_not_stable = 0;
|
||||
count_not_stable_gclk = 0;
|
||||
end
|
||||
else if (cyc == 4) begin
|
||||
a <= 0; // stable
|
||||
end
|
||||
else if (cyc == 5) begin
|
||||
a <= 1; // rise
|
||||
end
|
||||
else if (cyc == 6) begin
|
||||
a <= 1; // stable
|
||||
end
|
||||
else if (cyc == 7) begin
|
||||
a <= 0; // fall
|
||||
end
|
||||
else if (cyc == 10) begin
|
||||
`checkd(count_not_stable, 2);
|
||||
`checkd(count_not_stable_gclk, 2);
|
||||
`checkd(count_changing_gclk, 2);
|
||||
`checkd(count_falling_gclk, 1);
|
||||
`checkd(count_future_gclk, 2);
|
||||
`checkd(count_rising_gclk, 1);
|
||||
`checkd(count_not_steady_gclk, 2);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
%Error: t/t_assert_future_bad.v:18:31: Future sampled value function called outside property or sequence expression (IEEE 16.9.4)
|
||||
: ... note: In instance 't'
|
||||
18 | else $display("Future=%0d", $future_gclk(a));
|
||||
| ^~~~~~~~~~~~
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error: t/t_assert_future_bad.v:21:31: Future sampled value function called outside property or sequence expression (IEEE 16.9.4)
|
||||
: ... note: In instance 't'
|
||||
21 | else $display("Future=%0d", $rising_gclk(a));
|
||||
| ^~~~~~~~~~~~
|
||||
%Error: t/t_assert_future_bad.v:24:31: Future sampled value function called outside property or sequence expression (IEEE 16.9.4)
|
||||
: ... note: In instance 't'
|
||||
24 | else $display("Future=%0d", $falling_gclk(a));
|
||||
| ^~~~~~~~~~~~~
|
||||
%Error: t/t_assert_future_bad.v:27:31: Future sampled value function called outside property or sequence expression (IEEE 16.9.4)
|
||||
: ... note: In instance 't'
|
||||
27 | else $display("Future=%0d", $steady_gclk(a));
|
||||
| ^~~~~~~~~~~~
|
||||
%Error: t/t_assert_future_bad.v:30:31: Future sampled value function called outside property or sequence expression (IEEE 16.9.4)
|
||||
: ... note: In instance 't'
|
||||
30 | else $display("Future=%0d", $changing_gclk(a));
|
||||
| ^~~~~~~~~~~~~~
|
||||
%Error: Exiting due to
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('linter')
|
||||
|
||||
test.lint(fails=True, expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t ( /*AUTOARG*/
|
||||
// Inputs
|
||||
a, clk
|
||||
);
|
||||
input a;
|
||||
input clk;
|
||||
|
||||
global clocking @(posedge clk);
|
||||
endclocking
|
||||
|
||||
assert property (@(posedge clk) 1 == 1)
|
||||
else $display("Future=%0d", $future_gclk(a));
|
||||
|
||||
assert property (@(posedge clk) 1 == 1)
|
||||
else $display("Future=%0d", $rising_gclk(a));
|
||||
|
||||
assert property (@(posedge clk) 1 == 1)
|
||||
else $display("Future=%0d", $falling_gclk(a));
|
||||
|
||||
assert property (@(posedge clk) 1 == 1)
|
||||
else $display("Future=%0d", $steady_gclk(a));
|
||||
|
||||
assert property (@(posedge clk) 1 == 1)
|
||||
else $display("Future=%0d", $changing_gclk(a));
|
||||
|
||||
initial $stop;
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
%Error-UNSUPPORTED: t/t_assert_future_unsup.v:21:54: Unsupported/illegal: future value function used with expression with operator FUNCREF 'func'
|
||||
: ... note: In instance 't'
|
||||
21 | assert property (@(posedge clk) $future_gclk(a) == func(a));
|
||||
| ^~~~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: Exiting due to
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.lint(fails=True, expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t ( /*AUTOARG*/
|
||||
// Inputs
|
||||
a, clk
|
||||
);
|
||||
input a;
|
||||
input clk;
|
||||
|
||||
function logic func(input logic i);
|
||||
return i;
|
||||
endfunction
|
||||
|
||||
global clocking @(posedge clk);
|
||||
endclocking
|
||||
|
||||
assert property (@(posedge clk) $future_gclk(a) == func(a));
|
||||
|
||||
endmodule
|
||||
Loading…
Reference in New Issue