Fix untyped dtype error on sampling functions with property arguments (#8060)
Signed-off-by: Artur Bieniek <abieniek@antmicro.com>
This commit is contained in:
parent
0b51926fff
commit
e962efca12
|
|
@ -387,8 +387,7 @@ class AssertVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
AstSampled* newSampledExpr(AstNodeExpr* nodep) {
|
||||
AstSampled* const sampledp = new AstSampled{nodep->fileline(), nodep, nodep->dtypep()};
|
||||
return sampledp;
|
||||
return new AstSampled{nodep->fileline(), nodep, nodep->dtypep(), true};
|
||||
}
|
||||
AstVarRef* newMonitorNumVarRefp(const AstNode* nodep, VAccess access) {
|
||||
if (!m_monitorNumVarp) {
|
||||
|
|
|
|||
|
|
@ -215,8 +215,7 @@ static AstConst* newTypedConstp(FileLine* const flp, const AstNodeDType* const d
|
|||
}
|
||||
|
||||
static AstNodeExpr* sampled(AstNodeExpr* exprp) {
|
||||
AstSampled* const sp = new AstSampled{exprp->fileline(), exprp, exprp->dtypep()};
|
||||
return sp;
|
||||
return new AstSampled{exprp->fileline(), exprp, exprp->dtypep(), true};
|
||||
}
|
||||
|
||||
static string assertCtlGetCall(const char* query, VAssertType type,
|
||||
|
|
|
|||
|
|
@ -79,6 +79,14 @@ private:
|
|||
|
||||
// METHODS
|
||||
|
||||
static void checkSamplingFuncDType(AstNodeExpr* nodep, const AstNode* exprp) {
|
||||
const AstNodeDType* const dtypep = exprp->dtypep()->skipRefp();
|
||||
if (!dtypep->isIntegralOrPacked()) {
|
||||
nodep->v3error("Expected numeric type, but got a " << dtypep->prettyDTypeNameQ()
|
||||
<< " data type");
|
||||
}
|
||||
}
|
||||
|
||||
AstSenTree* newSenTree(AstNode* nodep, AstSenTree* useTreep = nullptr,
|
||||
AstNodeCoverOrAssert* cassertp = nullptr) {
|
||||
// Create sentree based on clocked or default clock
|
||||
|
|
@ -372,7 +380,7 @@ private:
|
|||
// #1step means the value that is sampled is always the signal's last value
|
||||
// before the clock edge (IEEE 1800-2023 14.4)
|
||||
AstSampled* const sampledp
|
||||
= new AstSampled{flp, exprp->cloneTreePure(false), exprp->dtypep()};
|
||||
= new AstSampled{flp, exprp->cloneTreePure(false), exprp->dtypep(), true};
|
||||
AstAssign* const assignp = new AstAssign{flp, refp, sampledp};
|
||||
m_clockingp->addNextHere(new AstAlways{
|
||||
flp, VAlwaysKwd::ALWAYS,
|
||||
|
|
@ -683,6 +691,7 @@ private:
|
|||
void visit(AstFalling* nodep) override {
|
||||
if (nodep->user1SetOnce()) return;
|
||||
iterateChildren(nodep);
|
||||
checkSamplingFuncDType(nodep, nodep->exprp());
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
||||
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
|
||||
|
|
@ -696,6 +705,7 @@ private:
|
|||
void visit(AstFell* nodep) override {
|
||||
if (nodep->user1SetOnce()) return;
|
||||
iterateChildren(nodep);
|
||||
checkSamplingFuncDType(nodep, nodep->exprp());
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
||||
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
|
||||
|
|
@ -712,11 +722,13 @@ private:
|
|||
void visit(AstFuture* nodep) override {
|
||||
if (nodep->user1SetOnce()) return;
|
||||
iterateChildren(nodep);
|
||||
checkSamplingFuncDType(nodep, nodep->exprp());
|
||||
AstSenTree* const sentreep = nodep->sentreep();
|
||||
if (sentreep) VL_DO_DANGLING(pushDeletep(sentreep->unlinkFrBack()), sentreep);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
}
|
||||
void visit(AstPast* nodep) override {
|
||||
checkSamplingFuncDType(nodep, nodep->exprp());
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
iterateChildren(nodep);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
|
|
@ -774,6 +786,7 @@ private:
|
|||
void visit(AstRising* nodep) override {
|
||||
if (nodep->user1SetOnce()) return;
|
||||
iterateChildren(nodep);
|
||||
checkSamplingFuncDType(nodep, nodep->exprp());
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
||||
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
|
||||
|
|
@ -787,6 +800,7 @@ private:
|
|||
void visit(AstRose* nodep) override {
|
||||
if (nodep->user1SetOnce()) return;
|
||||
iterateChildren(nodep);
|
||||
checkSamplingFuncDType(nodep, nodep->exprp());
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
||||
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
|
||||
|
|
@ -849,7 +863,8 @@ private:
|
|||
|
||||
// Assertion condition check
|
||||
AstLoop* const loopp = new AstLoop{flp};
|
||||
AstNodeExpr* const condp = new AstSampled{flp, nodep->exprp()->unlinkFrBack(), nullptr};
|
||||
AstSampled* const condp
|
||||
= new AstSampled{flp, nodep->exprp()->unlinkFrBack(), nullptr, true};
|
||||
loopp->addStmtsp(new AstLoopTest{flp, loopp, new AstLogNot{flp, condp}});
|
||||
loopp->addStmtsp(new AstEventControl{flp, sentreep, nullptr});
|
||||
|
||||
|
|
@ -916,6 +931,7 @@ private:
|
|||
void visit(AstStable* nodep) override {
|
||||
if (nodep->user1SetOnce()) return;
|
||||
iterateChildren(nodep);
|
||||
checkSamplingFuncDType(nodep, nodep->exprp());
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
||||
AstSenTree* sentreep = nodep->sentreep();
|
||||
|
|
@ -931,6 +947,7 @@ private:
|
|||
void visit(AstSteady* nodep) override {
|
||||
if (nodep->user1SetOnce()) return;
|
||||
iterateChildren(nodep);
|
||||
checkSamplingFuncDType(nodep, nodep->exprp());
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
||||
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
|
||||
|
|
@ -941,6 +958,10 @@ private:
|
|||
nodep->replaceWith(exprp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void visit(AstSampled* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (!nodep->internal()) checkSamplingFuncDType(nodep, nodep->exprp());
|
||||
}
|
||||
|
||||
// Validate repetition count: must be a non-negative elaboration-time constant.
|
||||
// Shared by goto [->N] and nonconsecutive [=N] repetition.
|
||||
|
|
@ -1310,8 +1331,8 @@ private:
|
|||
// this tick, p is not required. For s_until_with, p must be true on the q tick too.
|
||||
AstNodeExpr* const rawLhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const rawRhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstSampled* const lhsp = new AstSampled{flp, rawLhsp, rawLhsp->dtypep()};
|
||||
AstSampled* const rhsp = new AstSampled{flp, rawRhsp, rawRhsp->dtypep()};
|
||||
AstSampled* const lhsp = new AstSampled{flp, rawLhsp, rawLhsp->dtypep(), true};
|
||||
AstSampled* const rhsp = new AstSampled{flp, rawRhsp, rawRhsp->dtypep(), true};
|
||||
AstNodeExpr* finalCondp = rhsp->cloneTreePure(false);
|
||||
if (nodep->isOverlapping()) {
|
||||
finalCondp = new AstLogAnd{flp, lhsp->cloneTreePure(false), finalCondp};
|
||||
|
|
@ -1470,7 +1491,7 @@ private:
|
|||
if (!VN_AS(nodep->backp(), NodeCoverOrAssert)->immediate()) {
|
||||
const AstNodeDType* const propDtp = nodep->propp()->dtypep();
|
||||
nodep->propp(new AstSampled{nodep->fileline(), nodep->propp()->unlinkFrBack(),
|
||||
propDtp->dtypep()});
|
||||
propDtp->dtypep(), true});
|
||||
}
|
||||
// cover counts non-vacuous matches only (IEEE 1800-2023 16.15.2), so an
|
||||
// implication antecedent must hold; assert passes vacuously instead.
|
||||
|
|
|
|||
|
|
@ -2555,19 +2555,26 @@ public:
|
|||
class AstSampled final : public AstNodeExpr {
|
||||
// Verilog $sampled
|
||||
// @astgen op1 := exprp : AstNode<AstNodeExpr|AstPropSpec>
|
||||
bool m_internal : 1; // Internally created, not from a source $sampled
|
||||
public:
|
||||
AstSampled(FileLine* fl, AstNode* exprp, AstNodeDType* dtypep)
|
||||
: ASTGEN_SUPER_Sampled(fl) {
|
||||
AstSampled(FileLine* fl, AstNode* exprp, AstNodeDType* dtypep, bool internal = false)
|
||||
: ASTGEN_SUPER_Sampled(fl)
|
||||
, m_internal{internal} {
|
||||
this->exprp(exprp);
|
||||
this->dtypep(dtypep);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstSampled;
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
string emitVerilog() override { return "$sampled(%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 0; }
|
||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
bool sameNode(const AstNode* samep) const override {
|
||||
return m_internal == VN_DBG_AS(samep, Sampled)->m_internal;
|
||||
}
|
||||
bool internal() const { return m_internal; }
|
||||
bool isSystemFunc() const override { return true; }
|
||||
};
|
||||
class AstScopeName final : public AstNodeExpr {
|
||||
|
|
|
|||
|
|
@ -3081,6 +3081,14 @@ void AstSFormatF::dumpJson(std::ostream& str) const {
|
|||
dumpJsonBoolFuncIf(str, exprFormat);
|
||||
dumpJsonBoolFuncIf(str, optionalFormat);
|
||||
}
|
||||
void AstSampled::dump(std::ostream& str) const {
|
||||
this->AstNodeExpr::dump(str);
|
||||
if (internal()) str << " [INTERNAL]";
|
||||
}
|
||||
void AstSampled::dumpJson(std::ostream& str) const {
|
||||
dumpJsonBoolFuncIf(str, internal);
|
||||
dumpJsonGen(str);
|
||||
}
|
||||
void AstSel::dump(std::ostream& str) const {
|
||||
this->AstNodeBiop::dump(str);
|
||||
str << " widthConst=" << this->widthConst();
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ class SliceVisitor final : public VNVisitor {
|
|||
UINFO(9, " cloneSliceSel(" << elements << "," << elemIdx << ") " << nodep);
|
||||
AstNodeExpr* const exprp = VN_AS(snodep->exprp(), NodeExpr);
|
||||
AstNodeExpr* const selp = cloneAndSel(exprp, elements, elemIdx, needPure);
|
||||
return new AstSampled{nodep->fileline(), selp, nullptr};
|
||||
return new AstSampled{nodep->fileline(), selp, nullptr, snodep->internal()};
|
||||
} else if (AstExprStmt* const snodep = VN_CAST(nodep, ExprStmt)) {
|
||||
UINFO(9, " cloneExprStmt(" << elements << "," << elemIdx << ") " << nodep);
|
||||
AstNodeExpr* const resultSelp
|
||||
|
|
|
|||
|
|
@ -1519,7 +1519,8 @@ class WidthVisitor final : public VNVisitor {
|
|||
void visit(AstFell* nodep) override {
|
||||
assertAtExpr(nodep);
|
||||
if (m_vup->prelim()) {
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH,
|
||||
/* deferUntyped */ true);
|
||||
userIterate(nodep->sentreep(), nullptr);
|
||||
nodep->dtypeSetBit();
|
||||
}
|
||||
|
|
@ -1527,14 +1528,16 @@ class WidthVisitor final : public VNVisitor {
|
|||
void visit(AstFalling* nodep) override {
|
||||
assertAtExpr(nodep);
|
||||
if (m_vup->prelim()) {
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH,
|
||||
/* deferUntyped */ true);
|
||||
nodep->dtypeSetBit();
|
||||
}
|
||||
}
|
||||
void visit(AstFuture* nodep) override {
|
||||
assertAtExpr(nodep);
|
||||
if (m_vup->prelim()) {
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH,
|
||||
/* deferUntyped */ true);
|
||||
userIterate(nodep->sentreep(), nullptr);
|
||||
nodep->dtypeFrom(nodep->exprp());
|
||||
}
|
||||
|
|
@ -1542,10 +1545,12 @@ class WidthVisitor final : public VNVisitor {
|
|||
void visit(AstPast* nodep) override {
|
||||
assertAtExpr(nodep);
|
||||
if (m_vup->prelim()) {
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH,
|
||||
/* deferUntyped */ true);
|
||||
nodep->dtypeFrom(nodep->exprp());
|
||||
if (nodep->ticksp()) {
|
||||
iterateCheckSizedSelf(nodep, "Ticks", nodep->ticksp(), SELF, BOTH);
|
||||
iterateCheckSizedSelf(nodep, "Ticks", nodep->ticksp(), SELF, BOTH,
|
||||
/* deferUntyped */ true);
|
||||
V3Const::constifyParamsEdit(nodep->ticksp()); // ticksp may change
|
||||
const AstConst* const constp = VN_CAST(nodep->ticksp(), Const);
|
||||
if (!constp) {
|
||||
|
|
@ -1670,14 +1675,16 @@ class WidthVisitor final : public VNVisitor {
|
|||
void visit(AstRising* nodep) override {
|
||||
assertAtExpr(nodep);
|
||||
if (m_vup->prelim()) {
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH,
|
||||
/* deferUntyped */ true);
|
||||
nodep->dtypeSetBit();
|
||||
}
|
||||
}
|
||||
void visit(AstRose* nodep) override {
|
||||
assertAtExpr(nodep);
|
||||
if (m_vup->prelim()) {
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH,
|
||||
/* deferUntyped */ true);
|
||||
userIterate(nodep->sentreep(), nullptr);
|
||||
nodep->dtypeSetBit();
|
||||
}
|
||||
|
|
@ -1686,7 +1693,8 @@ class WidthVisitor final : public VNVisitor {
|
|||
void visit(AstSampled* nodep) override {
|
||||
assertAtExpr(nodep);
|
||||
if (m_vup->prelim()) {
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH,
|
||||
/* deferUntyped */ true);
|
||||
nodep->dtypeFrom(nodep->exprp());
|
||||
}
|
||||
}
|
||||
|
|
@ -1743,7 +1751,8 @@ class WidthVisitor final : public VNVisitor {
|
|||
void visit(AstStable* nodep) override {
|
||||
assertAtExpr(nodep);
|
||||
if (m_vup->prelim()) {
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH,
|
||||
/* deferUntyped */ true);
|
||||
userIterate(nodep->sentreep(), nullptr);
|
||||
nodep->dtypeSetBit();
|
||||
}
|
||||
|
|
@ -1751,7 +1760,8 @@ class WidthVisitor final : public VNVisitor {
|
|||
void visit(AstSteady* nodep) override {
|
||||
assertAtExpr(nodep);
|
||||
if (m_vup->prelim()) {
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH,
|
||||
/* deferUntyped */ true);
|
||||
nodep->dtypeSetBit();
|
||||
}
|
||||
}
|
||||
|
|
@ -7532,7 +7542,10 @@ class WidthVisitor final : public VNVisitor {
|
|||
<< pinDTypep->prettyDTypeNameQ());
|
||||
continue;
|
||||
}
|
||||
if (!portp->basicp() || portp->basicp()->isOpaque()) {
|
||||
// An untyped formal preserves the actual argument's self-determined type.
|
||||
if (portp->basicp() && portp->basicp()->untyped()) {
|
||||
iterateCheckSelf(nodep, "Function Argument", pinp, SELF, FINAL);
|
||||
} else if (!portp->basicp() || portp->basicp()->isOpaque()) {
|
||||
// Output args: at return caller = callee, reverse direction.
|
||||
checkClassAssign(nodep, "Function Argument", pinp, portDTypep,
|
||||
portp->direction() == VDirection::OUTPUT);
|
||||
|
|
@ -9081,7 +9094,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
(void)underp; // cppcheck
|
||||
}
|
||||
void iterateCheckSizedSelf(AstNode* parentp, const char* side, AstNode* underp, Determ determ,
|
||||
Stage stage) {
|
||||
Stage stage, bool deferUntyped = false) {
|
||||
// Coerce child to any sized-number data type; child is self-determined
|
||||
// i.e. isolated from expected type.
|
||||
// e.g. parentp=CONCAT, underp=lhs in CONCAT(lhs,rhs)
|
||||
|
|
@ -9095,7 +9108,10 @@ class WidthVisitor final : public VNVisitor {
|
|||
AstNodeDType* const expDTypep = underp->dtypep();
|
||||
underp = iterateCheck(parentp, side, underp, SELF, FINAL, expDTypep, EXTEND_EXP);
|
||||
AstNodeDType* const checkDtp = expDTypep->skipRefToEnump();
|
||||
if (!checkDtp->isIntegralOrPacked()) {
|
||||
// Sampling functions may still reference an untyped property formal here.
|
||||
// V3AssertPre checks the actual type after property argument substitution.
|
||||
if (!checkDtp->isIntegralOrPacked()
|
||||
&& !(deferUntyped && checkDtp->basicp() && checkDtp->basicp()->untyped())) {
|
||||
parentp->v3error("Expected numeric type, but got a " << checkDtp->prettyDTypeNameQ()
|
||||
<< " data type");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ module t (
|
|||
input clk
|
||||
);
|
||||
|
||||
global clocking @(posedge clk);
|
||||
endclocking
|
||||
|
||||
int cyc = 0;
|
||||
logic [4:0] val = 0;
|
||||
|
||||
|
|
@ -20,6 +23,27 @@ module t (
|
|||
@(posedge clk) cyc % 2 == cyc_mod_2 |=> val == expected;
|
||||
endproperty
|
||||
|
||||
property sampled_values(signal);
|
||||
@(posedge clk) ($changed(signal) == $changed(cyc))
|
||||
&& ($changed_gclk(signal) == $changed_gclk(cyc))
|
||||
&& ($changing_gclk(signal) == $changing_gclk(cyc))
|
||||
&& ($falling_gclk(signal) == $falling_gclk(cyc))
|
||||
&& ($fell(signal) == $fell(cyc))
|
||||
&& ($fell_gclk(signal) == $fell_gclk(cyc))
|
||||
&& ($future_gclk(signal) == $future_gclk(cyc))
|
||||
&& ($past(signal) == $past(cyc))
|
||||
&& ($past_gclk(signal) == $past_gclk(cyc))
|
||||
&& ($rising_gclk(signal) == $rising_gclk(cyc))
|
||||
&& ($rose(signal) == $rose(cyc))
|
||||
&& ($rose_gclk(signal) == $rose_gclk(cyc))
|
||||
&& ($sampled(signal) == $sampled(cyc))
|
||||
&& ($stable(signal) == $stable(cyc))
|
||||
&& ($stable_gclk(signal) == $stable_gclk(cyc))
|
||||
&& ($steady_gclk(signal) == $steady_gclk(cyc));
|
||||
endproperty
|
||||
|
||||
assert property (sampled_values(cyc));
|
||||
|
||||
assert property (check(0, 5'b11111))
|
||||
else begin
|
||||
// Assertion should pass
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
%Error: t/t_property_untyped_bad.v:17:20: Expected numeric type, but got a 'int$[0:1]' data type
|
||||
: ... note: In instance 't'
|
||||
17 | @(posedge clk) $changed(signal)
|
||||
| ^~~~~~~~
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error: t/t_property_untyped_bad.v:18:8: Expected numeric type, but got a 'int$[0:1]' data type
|
||||
: ... note: In instance 't'
|
||||
18 | && $changed_gclk(signal)
|
||||
| ^~~~~~~~~~~~~
|
||||
%Error: t/t_property_untyped_bad.v:19:8: Expected numeric type, but got a 'int$[0:1]' data type
|
||||
: ... note: In instance 't'
|
||||
19 | && $changing_gclk(signal)
|
||||
| ^~~~~~~~~~~~~~
|
||||
%Error: t/t_property_untyped_bad.v:20:8: Expected numeric type, but got a 'int$[0:1]' data type
|
||||
: ... note: In instance 't'
|
||||
20 | && $falling_gclk(signal)
|
||||
| ^~~~~~~~~~~~~
|
||||
%Error: t/t_property_untyped_bad.v:21:8: Expected numeric type, but got a 'int$[0:1]' data type
|
||||
: ... note: In instance 't'
|
||||
21 | && $fell(signal)
|
||||
| ^~~~~
|
||||
%Error: t/t_property_untyped_bad.v:22:8: Expected numeric type, but got a 'int$[0:1]' data type
|
||||
: ... note: In instance 't'
|
||||
22 | && $fell_gclk(signal)
|
||||
| ^~~~~~~~~~
|
||||
%Error: t/t_property_untyped_bad.v:23:8: Expected numeric type, but got a 'int$[0:1]' data type
|
||||
: ... note: In instance 't'
|
||||
23 | && $future_gclk(signal)
|
||||
| ^~~~~~~~~~~~
|
||||
%Error: t/t_property_untyped_bad.v:24:8: Expected numeric type, but got a 'int$[0:1]' data type
|
||||
: ... note: In instance 't'
|
||||
24 | && $past(signal)
|
||||
| ^~~~~
|
||||
%Error: t/t_property_untyped_bad.v:25:8: Expected numeric type, but got a 'int$[0:1]' data type
|
||||
: ... note: In instance 't'
|
||||
25 | && $past_gclk(signal)
|
||||
| ^~~~~~~~~~
|
||||
%Error: t/t_property_untyped_bad.v:26:8: Expected numeric type, but got a 'int$[0:1]' data type
|
||||
: ... note: In instance 't'
|
||||
26 | && $rising_gclk(signal)
|
||||
| ^~~~~~~~~~~~
|
||||
%Error: t/t_property_untyped_bad.v:27:8: Expected numeric type, but got a 'int$[0:1]' data type
|
||||
: ... note: In instance 't'
|
||||
27 | && $rose(signal)
|
||||
| ^~~~~
|
||||
%Error: t/t_property_untyped_bad.v:28:8: Expected numeric type, but got a 'int$[0:1]' data type
|
||||
: ... note: In instance 't'
|
||||
28 | && $rose_gclk(signal)
|
||||
| ^~~~~~~~~~
|
||||
%Error: t/t_property_untyped_bad.v:29:8: Expected numeric type, but got a 'int$[0:1]' data type
|
||||
: ... note: In instance 't'
|
||||
29 | && $sampled(signal)
|
||||
| ^~~~~~~~
|
||||
%Error: t/t_property_untyped_bad.v:30:8: Expected numeric type, but got a 'int$[0:1]' data type
|
||||
: ... note: In instance 't'
|
||||
30 | && $stable(signal)
|
||||
| ^~~~~~~
|
||||
%Error: t/t_property_untyped_bad.v:31:8: Expected numeric type, but got a 'int$[0:1]' data type
|
||||
: ... note: In instance 't'
|
||||
31 | && $stable_gclk(signal)
|
||||
| ^~~~~~~~~~~~
|
||||
%Error: t/t_property_untyped_bad.v:32:8: Expected numeric type, but got a 'int$[0:1]' data type
|
||||
: ... note: In instance 't'
|
||||
32 | && $steady_gclk(signal);
|
||||
| ^~~~~~~~~~~~
|
||||
%Error: Exiting due to
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# 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, verilator_flags2=['--assert'])
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (
|
||||
input clk
|
||||
);
|
||||
|
||||
global clocking @(posedge clk);
|
||||
endclocking
|
||||
|
||||
int values[2];
|
||||
|
||||
property sampled_values(signal);
|
||||
@(posedge clk) $changed(signal)
|
||||
&& $changed_gclk(signal)
|
||||
&& $changing_gclk(signal)
|
||||
&& $falling_gclk(signal)
|
||||
&& $fell(signal)
|
||||
&& $fell_gclk(signal)
|
||||
&& $future_gclk(signal)
|
||||
&& $past(signal)
|
||||
&& $past_gclk(signal)
|
||||
&& $rising_gclk(signal)
|
||||
&& $rose(signal)
|
||||
&& $rose_gclk(signal)
|
||||
&& $sampled(signal)
|
||||
&& $stable(signal)
|
||||
&& $stable_gclk(signal)
|
||||
&& $steady_gclk(signal);
|
||||
endproperty
|
||||
|
||||
assert property (sampled_values(values));
|
||||
endmodule
|
||||
Loading…
Reference in New Issue