parent
39b646349f
commit
8ed0acf1ec
|
|
@ -90,6 +90,58 @@ public:
|
|||
explicit DefaultDisablePropagateVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
};
|
||||
|
||||
// Lower a sequence used as an event control ('@seq', IEEE 1800-2023 9.4.2.4) into a
|
||||
// synthesized event fired by an internal 'cover sequence' on each end-of-match
|
||||
class SeqEventLowerVisitor final : public VNVisitor {
|
||||
// STATE
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
V3UniqueNames m_names{"__VseqEvent"}; // Synthesized event names
|
||||
|
||||
// VISITORS
|
||||
void visit(AstNodeModule* nodep) override {
|
||||
VL_RESTORER(m_modp);
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstSenItem* nodep) override {
|
||||
AstFuncRef* const funcrefp = VN_CAST(nodep->sensp(), FuncRef);
|
||||
if (funcrefp && VN_IS(funcrefp->taskp(), Sequence)) {
|
||||
FileLine* const flp = nodep->fileline();
|
||||
AstVar* const eventp = new AstVar{flp, VVarType::MODULETEMP, m_names.get(nodep),
|
||||
m_modp->findBasicDType(VBasicDTypeKwd::EVENT)};
|
||||
eventp->lifetime(VLifetime::STATIC_EXPLICIT);
|
||||
m_modp->addStmtsp(eventp);
|
||||
v3Global.setHasEvents();
|
||||
funcrefp->unlinkFrBack();
|
||||
nodep->sensp(new AstVarRef{flp, eventp, VAccess::READ});
|
||||
const bool automaticActual = funcrefp->exists([](const AstNodeVarRef* refp) {
|
||||
return refp->varp() && refp->varp()->lifetime().isAutomatic();
|
||||
});
|
||||
if (automaticActual) {
|
||||
nodep->v3error("Arguments to a sequence used as an event control must be"
|
||||
" static (IEEE 1800-2023 9.4.2.4)");
|
||||
VN_AS(funcrefp->taskp(), Sequence)->isReferenced(false);
|
||||
VL_DO_DANGLING(pushDeletep(funcrefp), funcrefp);
|
||||
return;
|
||||
}
|
||||
AstFireEvent* const firep
|
||||
= new AstFireEvent{flp, new AstVarRef{flp, eventp, VAccess::WRITE}, false};
|
||||
AstCover* const coverp
|
||||
= new AstCover{flp, new AstPropSpec{flp, nullptr, nullptr, funcrefp}, firep,
|
||||
VAssertType::CONCURRENT};
|
||||
coverp->isCoverSeq(true);
|
||||
coverp->isSeqEvent(true);
|
||||
m_modp->addStmtsp(coverp);
|
||||
return;
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
explicit SeqEventLowerVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void V3AssertCommon::collectDefaultDisable(AstNetlist* nodep) {
|
||||
|
|
@ -97,6 +149,11 @@ void V3AssertCommon::collectDefaultDisable(AstNetlist* nodep) {
|
|||
{ DefaultDisablePropagateVisitor{nodep}; }
|
||||
}
|
||||
|
||||
void V3AssertCommon::lowerSequenceEvents(AstNetlist* nodep) {
|
||||
{ SeqEventLowerVisitor{nodep}; }
|
||||
V3Global::dumpCheckGlobalTree("assertseqevent", 0, dumpTreeEitherLevel() >= 3);
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// AssertDeFutureVisitor
|
||||
// If any AstFuture, then move all non-future varrefs to be one cycle behind,
|
||||
|
|
@ -546,14 +603,19 @@ class AssertVisitor final : public VNVisitor {
|
|||
|
||||
bool selfDestruct = false;
|
||||
bool passspGated = false;
|
||||
if (const AstCover* const snodep = VN_CAST(nodep, Cover)) {
|
||||
const AstCover* const coverp = VN_CAST(nodep, Cover);
|
||||
// A sequence event control is not an assertion directive; no assertion control
|
||||
const bool seqEvent = coverp && coverp->isSeqEvent();
|
||||
if (coverp) {
|
||||
++m_statCover;
|
||||
if (!v3Global.opt.coverageUser()) {
|
||||
if (seqEvent) {
|
||||
// Keep the event-fire action, with no coverage bucket
|
||||
} else if (!v3Global.opt.coverageUser()) {
|
||||
selfDestruct = true;
|
||||
} else {
|
||||
// V3Coverage assigned us a bucket to increment.
|
||||
AstCoverInc* const covincp = VN_AS(snodep->coverincsp(), CoverInc);
|
||||
UASSERT_OBJ(covincp, snodep, "Missing AstCoverInc under assertion");
|
||||
AstCoverInc* const covincp = VN_AS(coverp->coverincsp(), CoverInc);
|
||||
UASSERT_OBJ(covincp, coverp, "Missing AstCoverInc under assertion");
|
||||
covincp->unlinkFrBackWithNext(); // next() might have AstAssign for trace
|
||||
if (message != "") covincp->declp()->comment(message);
|
||||
if (passsp) {
|
||||
|
|
@ -597,7 +659,8 @@ class AssertVisitor final : public VNVisitor {
|
|||
FileLine* const flp = nodep->fileline();
|
||||
bool passspAlreadyGated = false;
|
||||
if (passsp && VN_IS(passsp, If)) passspAlreadyGated = VN_AS(passsp, If)->user1();
|
||||
if (passsp && !passspGated && !passspAlreadyGated && !VN_IS(propExprp, PExpr)) {
|
||||
if (passsp && !passspGated && !passspAlreadyGated && !VN_IS(propExprp, PExpr)
|
||||
&& !seqEvent) {
|
||||
passsp = newIfAssertPassOn(passsp, nodep->directive(), nodep->userType(),
|
||||
/*vacuous=*/false);
|
||||
}
|
||||
|
|
@ -607,7 +670,7 @@ class AssertVisitor final : public VNVisitor {
|
|||
AstNode* bodysp = assertBody(nodep, propExprp, passsp, failsp);
|
||||
if (disablep) bodysp = new AstIf{flp, new AstLogNot{flp, disablep}, bodysp};
|
||||
// Add assertOn check last, for better combining
|
||||
bodysp = newIfAssertOn(bodysp, nodep->directive(), nodep->userType());
|
||||
if (!seqEvent) bodysp = newIfAssertOn(bodysp, nodep->directive(), nodep->userType());
|
||||
if (sentreep) bodysp = new AstAlways{flp, VAlwaysKwd::ALWAYS, sentreep, bodysp};
|
||||
|
||||
if (passsp && !passsp->backp()) VL_DO_DANGLING(pushDeletep(passsp), passsp);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
class V3AssertCommon final {
|
||||
public:
|
||||
static void collectDefaultDisable(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
static void lowerSequenceEvents(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
class V3Assert final {
|
||||
|
|
|
|||
|
|
@ -287,6 +287,8 @@ class SvaNfaBuilder final {
|
|||
// not just the first. Builder builds parallel-branch (no first-match-wins)
|
||||
// topology when true. Default false preserves cover_property semantics.
|
||||
bool m_isCoverSeq = false;
|
||||
// Unsupported endpoint topology must reject, not ignore, or the wait hangs
|
||||
bool m_isSeqEvent = false;
|
||||
|
||||
struct RangeDelayRejectInfo final {
|
||||
SvaStateVertex* startp = nullptr;
|
||||
|
|
@ -294,6 +296,15 @@ class SvaNfaBuilder final {
|
|||
int rhsLen = 0;
|
||||
};
|
||||
|
||||
void warnEndpointUnsupported(FileLine* flp, const string& what) const {
|
||||
if (m_isSeqEvent) {
|
||||
flp->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: sequence used as an event control with " << what);
|
||||
} else {
|
||||
flp->v3warn(COVERIGN, "Ignoring unsupported: cover sequence with " << what);
|
||||
}
|
||||
}
|
||||
|
||||
AstNodeExpr* throughoutCond(AstNodeExpr* baseCondp, FileLine* flp) {
|
||||
if (m_throughoutStack.empty()) return baseCondp;
|
||||
// AND all throughout conditions (supports nesting)
|
||||
|
|
@ -574,8 +585,7 @@ class SvaNfaBuilder final {
|
|||
// overlapping ends and the nested-sequence merge collapses them, so
|
||||
// reject those for a cover sequence rather than under-count.
|
||||
if (m_isCoverSeq && (range > kChainLimit || VN_IS(rhsExprp, SExpr))) {
|
||||
flp->v3warn(COVERIGN,
|
||||
"Ignoring unsupported: cover sequence with this ranged cycle delay");
|
||||
warnEndpointUnsupported(flp, "this ranged cycle delay");
|
||||
outErrorEmitted = true;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -881,8 +891,7 @@ class SvaNfaBuilder final {
|
|||
// terminal, so a cover sequence would under-count. Reject the ranged form
|
||||
// (the single-count b[->N] has one end and is enumerated correctly).
|
||||
if (m_isCoverSeq && hasMax && maxN > minN) {
|
||||
flp->v3warn(COVERIGN,
|
||||
"Ignoring unsupported: cover sequence with a ranged goto repetition");
|
||||
warnEndpointUnsupported(flp, "a ranged goto repetition");
|
||||
return BuildResult::failWithError();
|
||||
}
|
||||
|
||||
|
|
@ -946,8 +955,7 @@ class SvaNfaBuilder final {
|
|||
// than under-count. Plain boolean disjunction has one end per cycle and
|
||||
// is handled by the OR-fold.
|
||||
if (m_isCoverSeq && (lhs.termVertexp != entryVtxp || rhs.termVertexp != entryVtxp)) {
|
||||
flp->v3warn(COVERIGN,
|
||||
"Ignoring unsupported: cover sequence with a sequence operand of 'or'");
|
||||
warnEndpointUnsupported(flp, "a sequence operand of 'or'");
|
||||
return BuildResult::failWithError();
|
||||
}
|
||||
SvaStateVertex* const mergeVtxp = scopedCreateVertex();
|
||||
|
|
@ -1442,11 +1450,12 @@ class SvaNfaBuilder final {
|
|||
|
||||
public:
|
||||
SvaNfaBuilder(SvaGraph& graph, AstNodeModule* modp, V3UniqueNames& propTempNames,
|
||||
bool isCoverSeq = false)
|
||||
bool isCoverSeq = false, bool isSeqEvent = false)
|
||||
: m_graph{graph}
|
||||
, m_modp{modp}
|
||||
, m_propTempNames{propTempNames}
|
||||
, m_isCoverSeq{isCoverSeq} {}
|
||||
, m_isCoverSeq{isCoverSeq}
|
||||
, m_isSeqEvent{isSeqEvent} {}
|
||||
|
||||
// Reset scope between antecedent and consequent: liveness must not leak.
|
||||
void resetScope() {
|
||||
|
|
@ -2876,11 +2885,17 @@ class AssertNfaVisitor final : public VNVisitor {
|
|||
bool senTreeOwned = false; // True if we created senTreep locally
|
||||
AstPropSpec* const propSpecp = VN_CAST(assertp->propp(), PropSpec);
|
||||
UASSERT_OBJ(propSpecp, assertp, "Concurrent assertion must have PropSpec");
|
||||
AstCover* const coverp = VN_CAST(assertp, Cover);
|
||||
const bool isCover = coverp != nullptr;
|
||||
const bool isCoverSeq = coverp && coverp->isCoverSeq();
|
||||
// A sequence event control is not an assertion directive; no default
|
||||
// disable iff, no assertion control
|
||||
const bool isSeqEvent = coverp && coverp->isSeqEvent();
|
||||
// Inherit module defaults (IEEE 14.12, 16.15) when assertion has none.
|
||||
if (!propSpecp->sensesp() && m_defaultClockingp) {
|
||||
propSpecp->sensesp(m_defaultClockingp->sensesp()->cloneTree(true));
|
||||
}
|
||||
if (!propSpecp->disablep() && m_defaultDisablep) {
|
||||
if (!propSpecp->disablep() && m_defaultDisablep && !isSeqEvent) {
|
||||
propSpecp->disablep(m_defaultDisablep->condp()->cloneTreePure(true));
|
||||
}
|
||||
if (!senTreep && propSpecp->sensesp()) {
|
||||
|
|
@ -2892,12 +2907,9 @@ class AssertNfaVisitor final : public VNVisitor {
|
|||
if (!senTreep) return;
|
||||
|
||||
FileLine* const flp = assertp->fileline();
|
||||
const bool isCover = VN_IS(assertp, Cover);
|
||||
AstCover* const coverp = VN_CAST(assertp, Cover);
|
||||
const bool isCoverSeq = coverp && coverp->isCoverSeq();
|
||||
|
||||
SvaGraph graph;
|
||||
SvaNfaBuilder builder{graph, m_modp, m_propTempNames, isCoverSeq};
|
||||
SvaNfaBuilder builder{graph, m_modp, m_propTempNames, isCoverSeq, isSeqEvent};
|
||||
|
||||
const BuildResult result = buildAssertionGraph(builder, graph, seqBodyp, parts, flp);
|
||||
if (result.valid()) wireMatchAndMidSources(graph, result, flp);
|
||||
|
|
@ -2939,13 +2951,16 @@ class AssertNfaVisitor final : public VNVisitor {
|
|||
std::vector<AstNodeExpr*> perMidSrcs;
|
||||
|
||||
AstNodeExpr* const alwaysTriggerp
|
||||
= assertOnCond(flp, assertp->userType(), assertp->directive());
|
||||
= isSeqEvent ? new AstConst{flp, AstConst::BitTrue{}}
|
||||
: assertOnCond(flp, assertp->userType(), assertp->directive());
|
||||
AstNodeExpr* const outputExprp = m_loweringp->lower(
|
||||
flp, graph, alwaysTriggerp, senTreep, result.finalCondp, isCover,
|
||||
disableExprp ? disableExprp->cloneTreePure(false) : nullptr, negated,
|
||||
needMatch ? &matchExprp : nullptr, disableCntVarp, snapshotVarp,
|
||||
needPerSrcFail ? &requiredStepSrcs : nullptr, isCoverSeq ? &perMidSrcs : nullptr,
|
||||
assertp->userType(), assertp->directive());
|
||||
isSeqEvent ? VAssertType{VAssertType::INTERNAL} : assertp->userType(),
|
||||
isSeqEvent ? VAssertDirectiveType{VAssertDirectiveType::INTERNAL}
|
||||
: assertp->directive());
|
||||
|
||||
AstSenTree* const perSrcSenTreep
|
||||
= (requiredStepSrcs.size() >= 2) ? senTreep->cloneTree(false) : nullptr;
|
||||
|
|
|
|||
|
|
@ -1466,7 +1466,9 @@ private:
|
|||
iterateAndNextNull(nodep->sensesp());
|
||||
if (m_senip && m_senip != nodep->sensesp())
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Only one PSL clock allowed per assertion");
|
||||
if (!nodep->disablep() && m_defaultDisablep) {
|
||||
const AstCover* const coverp = VN_CAST(nodep->backp(), Cover);
|
||||
const bool seqEvent = coverp && coverp->isSeqEvent();
|
||||
if (!nodep->disablep() && m_defaultDisablep && !seqEvent) {
|
||||
nodep->disablep(m_defaultDisablep->condp()->cloneTreePure(true));
|
||||
}
|
||||
m_disablep = nodep->disablep();
|
||||
|
|
|
|||
|
|
@ -1612,6 +1612,8 @@ class AstCover final : public AstNodeCoverOrAssert {
|
|||
// @astgen op3 := coverincsp: List[AstNode] // Coverage node
|
||||
bool m_isCoverSeq = false; // 'cover sequence' (IEEE 1800-2023 16.14.3): fires per
|
||||
// end-of-match, not per property success
|
||||
bool m_isSeqEvent = false; // Synthesized for a sequence used as an event control
|
||||
// (IEEE 1800-2023 9.4.2.4)
|
||||
public:
|
||||
ASTGEN_MEMBERS_AstCover;
|
||||
AstCover(FileLine* fl, AstNode* propp, AstNode* stmtsp, VAssertType type,
|
||||
|
|
@ -1622,6 +1624,8 @@ public:
|
|||
void dumpJson(std::ostream& str) const override;
|
||||
bool isCoverSeq() const { return m_isCoverSeq; }
|
||||
void isCoverSeq(bool flag) { m_isCoverSeq = flag; }
|
||||
bool isSeqEvent() const { return m_isSeqEvent; }
|
||||
void isSeqEvent(bool flag) { m_isSeqEvent = flag; }
|
||||
};
|
||||
class AstRestrict final : public AstNodeCoverOrAssert {
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -2241,9 +2241,11 @@ void AstNodeCoverOrAssert::dumpJson(std::ostream& str) const {
|
|||
void AstCover::dump(std::ostream& str) const {
|
||||
this->AstNodeCoverOrAssert::dump(str);
|
||||
if (isCoverSeq()) str << " [COVERSEQ]";
|
||||
if (isSeqEvent()) str << " [SEQEVENT]";
|
||||
}
|
||||
void AstCover::dumpJson(std::ostream& str) const {
|
||||
dumpJsonBoolFuncIf(str, isCoverSeq);
|
||||
dumpJsonBoolFuncIf(str, isSeqEvent);
|
||||
this->AstNodeCoverOrAssert::dumpJson(str);
|
||||
}
|
||||
void AstClocking::dump(std::ostream& str) const {
|
||||
|
|
|
|||
|
|
@ -261,6 +261,7 @@ static void process() {
|
|||
// Assertion insertion
|
||||
// After we've added block coverage, but before other nasty transforms
|
||||
V3AssertCommon::collectDefaultDisable(v3Global.rootp());
|
||||
V3AssertCommon::lowerSequenceEvents(v3Global.rootp());
|
||||
V3AssertNfa::assertNfaAll(v3Global.rootp());
|
||||
// V3AssertProp removed: NFA subsumes multi-cycle property lowering.
|
||||
// Unsupported constructs fall through to V3AssertPre.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
#!/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.compile(verilator_flags2=['--timing'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 PlanV GmbH
|
||||
// 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 (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
module t (
|
||||
input clk
|
||||
);
|
||||
int unsigned crc = 32'h1;
|
||||
bit a, b, c;
|
||||
bit a1, a2, a3, b1;
|
||||
int cyc;
|
||||
int seq_hits, seq_hits2, ref_hits, one_hits, dc_hits;
|
||||
int rng_hits, rng_ref;
|
||||
|
||||
// verilog_format: off // verible does not support clocking events inside sequence declarations
|
||||
sequence seq;
|
||||
@(posedge clk) a ##1 b ##1 c;
|
||||
endsequence
|
||||
|
||||
sequence seq_one;
|
||||
@(posedge clk) a;
|
||||
endsequence
|
||||
|
||||
sequence seq_rng;
|
||||
@(posedge clk) a ##[1:3] b;
|
||||
endsequence
|
||||
// verilog_format: on
|
||||
|
||||
// seq_dc inherits the default clocking; counts must match seq
|
||||
default clocking @(posedge clk);
|
||||
endclocking
|
||||
|
||||
sequence seq_dc;
|
||||
a ##1 b ##1 c;
|
||||
endsequence
|
||||
|
||||
// ref_hits and rng_ref are independent shift-register oracles;
|
||||
// simultaneous end points resume a blocked waiter once
|
||||
initial forever begin
|
||||
@seq;
|
||||
seq_hits = seq_hits + 1;
|
||||
end
|
||||
initial forever begin
|
||||
@seq;
|
||||
seq_hits2 = seq_hits2 + 1;
|
||||
end
|
||||
initial forever begin
|
||||
@seq_one;
|
||||
one_hits = one_hits + 1;
|
||||
end
|
||||
initial forever begin
|
||||
@seq_dc;
|
||||
dc_hits = dc_hits + 1;
|
||||
end
|
||||
initial forever begin
|
||||
@seq_rng;
|
||||
rng_hits = rng_hits + 1;
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (a2 && b1 && c) ref_hits = ref_hits + 1;
|
||||
if (b && (a1 || a2 || a3)) rng_ref = rng_ref + 1;
|
||||
a3 <= a2;
|
||||
a2 <= a1;
|
||||
a1 <= a;
|
||||
b1 <= b;
|
||||
end
|
||||
|
||||
// a/b/c bit spacing exceeds the ##2 window to decorrelate the LFSR taps
|
||||
always @(posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
crc <= {crc[30:0], crc[31] ^ crc[21] ^ crc[1] ^ crc[0]};
|
||||
a <= crc[0];
|
||||
b <= crc[4];
|
||||
c <= crc[8];
|
||||
if (cyc == 60) $finish;
|
||||
end
|
||||
|
||||
// Counts read in final (Postponed) to avoid same-timestep races.
|
||||
final begin
|
||||
`checkd(seq_hits, 14);
|
||||
`checkd(seq_hits2, 14);
|
||||
`checkd(ref_hits, 14);
|
||||
`checkd(one_hits, 30);
|
||||
`checkd(dc_hits, 14);
|
||||
`checkd(rng_hits, 26);
|
||||
`checkd(rng_ref, 26);
|
||||
$write("*-* All Finished *-*\n");
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
%Error: t/t_assert_seq_event_bad.v:19:7: Arguments to a sequence used as an event control must be static (IEEE 1800-2023 9.4.2.4)
|
||||
: ... note: In instance 't'
|
||||
19 | @(s_arg(x));
|
||||
| ^~~~~
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%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(expect_filename=test.golden_filename, verilator_flags2=['--timing'], fails=True)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 PlanV GmbH
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (
|
||||
input clk
|
||||
);
|
||||
|
||||
// verilog_format: off
|
||||
sequence s_arg(x);
|
||||
@(posedge clk) x;
|
||||
endsequence
|
||||
// verilog_format: on
|
||||
|
||||
task automatic f;
|
||||
bit x = 1;
|
||||
@(s_arg(x));
|
||||
endtask
|
||||
|
||||
initial f();
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/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.compile(verilator_flags2=['--timing'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 PlanV GmbH
|
||||
// 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 (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
module t (
|
||||
input clk
|
||||
);
|
||||
int unsigned crc = 32'h1;
|
||||
bit a, b, rst;
|
||||
bit a1;
|
||||
int cyc;
|
||||
int hits, ref_hits, one_hits, one_ref;
|
||||
|
||||
// Neither the default disable iff nor $assertoff may suppress a sequence event control
|
||||
default disable iff (rst);
|
||||
|
||||
// verilog_format: off // verible does not support clocking events inside sequence declarations
|
||||
sequence seq;
|
||||
@(posedge clk) a ##1 b;
|
||||
endsequence
|
||||
|
||||
sequence seq_one;
|
||||
@(posedge clk) 1;
|
||||
endsequence
|
||||
// verilog_format: on
|
||||
|
||||
initial begin
|
||||
$assertoff;
|
||||
#300 $assertkill;
|
||||
end
|
||||
|
||||
initial forever begin
|
||||
@seq;
|
||||
hits = hits + 1;
|
||||
end
|
||||
initial forever begin
|
||||
@seq_one;
|
||||
one_hits = one_hits + 1;
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (a1 && b) ref_hits = ref_hits + 1;
|
||||
one_ref = one_ref + 1;
|
||||
a1 <= a;
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
crc <= {crc[30:0], crc[31] ^ crc[21] ^ crc[1] ^ crc[0]};
|
||||
a <= crc[0];
|
||||
b <= crc[4];
|
||||
rst <= crc[2];
|
||||
end
|
||||
|
||||
always @(negedge clk) begin
|
||||
if (cyc == 60) $finish;
|
||||
end
|
||||
|
||||
final begin
|
||||
`checkd(hits, ref_hits);
|
||||
`checkd(one_hits, one_ref);
|
||||
`checkd(hits, 19);
|
||||
`checkd(one_hits, 60);
|
||||
$write("*-* All Finished *-*\n");
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
%Error-UNSUPPORTED: t/t_assert_seq_event_unsup.v:18:5: Unsupported: non-edge clocking event on a sequence; use an edge such as @(posedge clk)
|
||||
: ... note: In instance 't'
|
||||
18 | @(g) a ##1 b;
|
||||
| ^
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error-UNSUPPORTED: t/t_assert_seq_event_unsup.v:28:30: Unsupported: sequence used as an event control with a sequence operand of 'or'
|
||||
28 | @(posedge clk) (a ##1 b) or (a ##2 b);
|
||||
| ^~
|
||||
%Error-UNSUPPORTED: t/t_assert_seq_event_unsup.v:21:12: Unsupported: sequence referenced outside assertion property
|
||||
: ... note: In instance 't'
|
||||
21 | sequence s_ref;
|
||||
| ^~~~~
|
||||
%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(expect_filename=test.golden_filename, verilator_flags2=['--timing'], fails=True)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 PlanV GmbH
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (
|
||||
input clk
|
||||
);
|
||||
bit a, b;
|
||||
logic g = 0;
|
||||
|
||||
default clocking @(posedge clk);
|
||||
endclocking
|
||||
|
||||
// verilog_format: off
|
||||
sequence s_nonedge;
|
||||
@(g) a ##1 b;
|
||||
endsequence
|
||||
|
||||
sequence s_ref;
|
||||
@(posedge clk) a;
|
||||
endsequence
|
||||
|
||||
// Legal but its endpoint topology is not buildable, so the wait could never
|
||||
// resume; rejected rather than silently ignored.
|
||||
sequence s_or;
|
||||
@(posedge clk) (a ##1 b) or (a ##2 b);
|
||||
endsequence
|
||||
// verilog_format: on
|
||||
|
||||
// Legal: p is never asserted, so s_ref stays referenced outside any
|
||||
// assertion property, which is not yet supported.
|
||||
property p;
|
||||
s_ref;
|
||||
endproperty
|
||||
|
||||
initial begin
|
||||
@s_nonedge;
|
||||
@s_or;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -1318,6 +1318,21 @@ module Vt_debug_emitv_sub;
|
|||
endfunction
|
||||
real r;
|
||||
endmodule
|
||||
module Vt_debug_emitv_seq_event;
|
||||
input logic clk;
|
||||
bit a;
|
||||
bit b;
|
||||
bit c;
|
||||
sequence sq;
|
||||
@(posedge clk) a##1 b##1 c
|
||||
endsequence
|
||||
initial begin
|
||||
begin
|
||||
|
||||
???? // EVENTCONTROL
|
||||
@( sq())end
|
||||
end
|
||||
endmodule
|
||||
package Vt_debug_emitv_p;
|
||||
logic pkgvar;
|
||||
endpackage
|
||||
|
|
|
|||
|
|
@ -138,6 +138,7 @@ module t (/*AUTOARG*/
|
|||
endfunction
|
||||
|
||||
sub sub(.*);
|
||||
seq_event seq_event(.*);
|
||||
|
||||
initial begin
|
||||
int other;
|
||||
|
|
@ -443,6 +444,16 @@ module sub(input logic clk);
|
|||
real r;
|
||||
endmodule
|
||||
|
||||
module seq_event(input logic clk);
|
||||
bit a, b, c;
|
||||
sequence sq;
|
||||
@(posedge clk) a ##1 b ##1 c;
|
||||
endsequence
|
||||
initial begin
|
||||
@sq;
|
||||
end
|
||||
endmodule
|
||||
|
||||
package p;
|
||||
logic pkgvar;
|
||||
endpackage
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
%Error: t/t_sequence_ref_bad.v:14:6: Concurrent assertion has no clock (IEEE 1800-2023 16.16)
|
||||
: ... note: In instance 't'
|
||||
: ... Suggest provide a clocking event, a default clocking, or a clocked procedural context
|
||||
14 | @s_one;
|
||||
| ^~~~~
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error: Exiting due to
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
%Error-UNSUPPORTED: t/t_sequence_ref_unsup.v:9:12: Unsupported: sequence referenced outside assertion property
|
||||
: ... note: In instance 't'
|
||||
9 | sequence s_one;
|
||||
| ^~~~~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: Exiting due to
|
||||
Loading…
Reference in New Issue