Merge upstream/master and resolve conflicts

This commit is contained in:
Yilou Wang 2026-04-08 13:58:28 +02:00
commit db1dd74404
32 changed files with 626 additions and 55 deletions

View File

@ -1855,8 +1855,11 @@ List Of Warnings
and #(1,2,3) AND (out, a, b); and #(1,2,3) AND (out, a, b);
Warns that rising, falling, and turn-off delays are currently unsupported. Warns that the third (turn-off) delay is currently unsupported and is
The first (rising) delay is used for all cases. ignored. Rising and falling delays are supported.
In versions before 5.048, warned that rising, falling, and turn-off delays were
unsupported. The first (rising) delay was used for all cases.
.. option:: SELRANGE .. option:: SELRANGE

View File

@ -709,9 +709,8 @@ class AssertVisitor final : public VNVisitor {
} }
VL_DO_DANGLING(pushDeletep(nodep), nodep); VL_DO_DANGLING(pushDeletep(nodep), nodep);
} }
void visit(AstVarRef* nodep) override { void visit(AstNodeVarRef* nodep) override {
iterateChildren(nodep); if (m_inSampled && !nodep->varp()->noSample()) {
if (m_inSampled && !(nodep->varp() && nodep->varp()->noSample())) {
if (!nodep->access().isReadOnly()) { if (!nodep->access().isReadOnly()) {
nodep->v3warn(E_UNSUPPORTED, nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Write to variable in sampled expression"); "Unsupported: Write to variable in sampled expression");

View File

@ -746,6 +746,7 @@ private:
AstSenTree* const senTreep = newSenTree(nodep); AstSenTree* const senTreep = newSenTree(nodep);
AstAlways* const alwaysp = new AstAlways{flp, VAlwaysKwd::ALWAYS, senTreep, ifp}; AstAlways* const alwaysp = new AstAlways{flp, VAlwaysKwd::ALWAYS, senTreep, ifp};
cntVarp->addNextHere(alwaysp); cntVarp->addNextHere(alwaysp);
// Match: cnt >= N-1 (previous cycles via NBA) && expr (current cycle)
AstNodeExpr* const cntCheckp = new AstGte{flp, new AstVarRef{flp, cntVarp, VAccess::READ}, AstNodeExpr* const cntCheckp = new AstGte{flp, new AstVarRef{flp, cntVarp, VAccess::READ},
new AstConst{flp, static_cast<uint32_t>(n - 1)}}; new AstConst{flp, static_cast<uint32_t>(n - 1)}};
cntCheckp->dtypeSetBit(); cntCheckp->dtypeSetBit();
@ -852,6 +853,7 @@ private:
AstVar* const cntVarp = new AstVar{flp, VVarType::BLOCKTEMP, name + "__counter", AstVar* const cntVarp = new AstVar{flp, VVarType::BLOCKTEMP, name + "__counter",
exprp->findBasicDType(VBasicDTypeKwd::UINT32)}; exprp->findBasicDType(VBasicDTypeKwd::UINT32)};
cntVarp->lifetime(VLifetime::AUTOMATIC_EXPLICIT); cntVarp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
cntVarp->noSample(true);
AstBegin* const beginp = new AstBegin{flp, name + "__block", cntVarp, true}; AstBegin* const beginp = new AstBegin{flp, name + "__block", cntVarp, true};
beginp->addStmtsp( beginp->addStmtsp(

View File

@ -364,8 +364,9 @@ static std::vector<SeqStep> extractTimeline(AstNodeExpr* nodep) {
if (AstConst* const constp = VN_CAST(dlyp->lhsp(), Const)) { if (AstConst* const constp = VN_CAST(dlyp->lhsp(), Const)) {
cycles = constp->toSInt(); cycles = constp->toSInt();
} else { } else {
dlyp->lhsp()->v3warn(E_UNSUPPORTED, dlyp->lhsp()->v3warn(
"Unsupported: non-constant cycle delay in sequence and/or"); E_UNSUPPORTED,
"Unsupported: non-constant cycle delay in sequence and/or/intersect");
} }
} }
// The expression after the delay // The expression after the delay
@ -386,6 +387,18 @@ static std::vector<SeqStep> extractTimeline(AstNodeExpr* nodep) {
return timeline; return timeline;
} }
// True if any AstSExpr in the subtree has a range delay (##[m:n]).
// Uses forall(): predicate returns false when a range delay is found,
// so !forall(...) means "at least one range delay exists".
static bool subtreeHasRangeDelay(const AstNode* nodep) {
return !nodep->forall([](const AstSExpr* sexprp) {
if (const AstDelay* const dlyp = VN_CAST(sexprp->delayp(), Delay)) {
if (dlyp->isRangeDelay()) return false;
}
return true;
});
}
// Lower sequence and/or to AST // Lower sequence and/or to AST
class AssertPropLowerVisitor final : public VNVisitor { class AssertPropLowerVisitor final : public VNVisitor {
// STATE // STATE
@ -624,6 +637,47 @@ class AssertPropLowerVisitor final : public VNVisitor {
VL_DO_DANGLING(nodep->deleteTree(), nodep); VL_DO_DANGLING(nodep->deleteTree(), nodep);
} }
// Lower a multi-cycle sequence 'intersect' (IEEE 1800-2023 16.9.6).
// intersect = and + equal-length constraint: both operands must match with the same duration.
// When total delays are equal constants, this is identical to 'and'; otherwise constant-false.
void lowerSeqIntersect(AstNodeBiop* nodep) {
const std::vector<SeqStep> lhsTimeline = extractTimeline(nodep->lhsp());
const std::vector<SeqStep> rhsTimeline = extractTimeline(nodep->rhsp());
int lhsTotal = 0;
for (const auto& step : lhsTimeline) lhsTotal += step.delayCycles;
int rhsTotal = 0;
for (const auto& step : rhsTimeline) rhsTotal += step.delayCycles;
if (lhsTotal != rhsTotal) {
// Lengths differ: per IEEE 16.9.6, the match set is empty -- constant-false.
// Warn the user; mismatched lengths are almost always a mistake.
// Skip when either operand had a range delay: RangeDelayExpander already
// replaced it with an FSM expression (containsSExpr returns false) and
// issued UNSUPPORTED, so no second diagnostic is needed.
if (containsSExpr(nodep->lhsp()) && containsSExpr(nodep->rhsp())) {
if (lhsTotal > rhsTotal) {
nodep->v3warn(WIDTHEXPAND, "Intersect sequence length mismatch"
" (left "
<< lhsTotal << " cycles, right " << rhsTotal
<< " cycles) -- intersection is always empty");
} else {
nodep->v3warn(WIDTHTRUNC, "Intersect sequence length mismatch"
" (left "
<< lhsTotal << " cycles, right " << rhsTotal
<< " cycles) -- intersection is always empty");
}
}
FileLine* const flp = nodep->fileline();
AstBegin* const bodyp = new AstBegin{flp, "", nullptr, true};
bodyp->addStmtsp(new AstPExprClause{flp, false});
AstPExpr* const pexprp = new AstPExpr{flp, bodyp, nodep->dtypep()};
nodep->replaceWith(pexprp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
return;
}
// Same length: length restriction is trivially satisfied, lower as 'and'.
lowerSeqAnd(nodep);
}
void visit(AstSAnd* nodep) override { void visit(AstSAnd* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
if (containsSExpr(nodep->lhsp()) || containsSExpr(nodep->rhsp())) { if (containsSExpr(nodep->lhsp()) || containsSExpr(nodep->rhsp())) {
@ -637,6 +691,19 @@ class AssertPropLowerVisitor final : public VNVisitor {
VL_DO_DANGLING(nodep->deleteTree(), nodep); VL_DO_DANGLING(nodep->deleteTree(), nodep);
} }
} }
void visit(AstSIntersect* nodep) override {
iterateChildren(nodep);
if (containsSExpr(nodep->lhsp()) || containsSExpr(nodep->rhsp())) {
lowerSeqIntersect(nodep);
} else {
// Pure boolean operands: length is always 0, lower to LogAnd
AstLogAnd* const newp = new AstLogAnd{nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
nodep->rhsp()->unlinkFrBack()};
newp->dtypeFrom(nodep);
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
}
void visit(AstSOr* nodep) override { void visit(AstSOr* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
if (containsSExpr(nodep->lhsp()) || containsSExpr(nodep->rhsp())) { if (containsSExpr(nodep->lhsp()) || containsSExpr(nodep->rhsp())) {
@ -1327,6 +1394,15 @@ class RangeDelayExpander final : public VNVisitor {
} }
} }
void visit(AstSIntersect* nodep) override {
// intersect with a range-delay operand cannot be lowered: the length-pairing
// logic requires knowing each operand's concrete length, which is dynamic.
if (subtreeHasRangeDelay(nodep->lhsp()) || subtreeHasRangeDelay(nodep->rhsp())) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: intersect with ranged cycle-delay operand");
}
iterateChildren(nodep);
}
void visit(AstSThroughout* nodep) override { void visit(AstSThroughout* nodep) override {
// Reject throughout with range-delay sequences before FSM expansion // Reject throughout with range-delay sequences before FSM expansion
// would silently lose per-tick enforcement (IEEE 1800-2023 16.9.9) // would silently lose per-tick enforcement (IEEE 1800-2023 16.9.9)

View File

@ -3699,6 +3699,30 @@ public:
bool sizeMattersRhs() const override { return false; } bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; }
}; };
class AstSIntersect final : public AstNodeBiop {
// Sequence 'intersect' (IEEE 1800-2023 16.9.6): both operands match with equal length.
// AND with a length restriction. For boolean operands, lowered to AstLogAnd.
public:
AstSIntersect(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_SIntersect(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstSIntersect;
// LCOV_EXCL_START // Lowered before these are ever called
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opLogAnd(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %fintersect %r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; }
// LCOV_EXCL_STOP
};
class AstSOr final : public AstNodeBiop { class AstSOr final : public AstNodeBiop {
// Sequence 'or' (IEEE 1800-2023 16.9.7): at least one operand sequence must match. // Sequence 'or' (IEEE 1800-2023 16.9.7): at least one operand sequence must match.
// Operates on match sets, not values. For boolean operands, lowered to AstLogOr. // Operates on match sets, not values. For boolean operands, lowered to AstLogOr.

View File

@ -543,11 +543,10 @@ class AstDelay final : public AstNodeStmt {
// Delay statement // Delay statement
// @astgen op1 := lhsp : AstNodeExpr // Delay value (or min for range) // @astgen op1 := lhsp : AstNodeExpr // Delay value (or min for range)
// @astgen op2 := stmtsp : List[AstNode] // Statements under delay // @astgen op2 := stmtsp : List[AstNode] // Statements under delay
// @astgen op3 := rhsp : Optional[AstNodeExpr] // Max delay value (range delay only) // @astgen op3 := rhsp : Optional[AstNodeExpr] // Max bound for cycle range or fall delay
// @astgen op4 := throughoutp : Optional[AstNodeExpr] // Throughout condition (IEEE 16.9.9) // @astgen op4 := throughoutp : Optional[AstNodeExpr] // Throughout condition (IEEE 16.9.9)
VTimescale m_timeunit; // Delay's time unit VTimescale m_timeunit; // Delay's time unit
const bool m_isCycle; // True if it is a cycle delay const bool m_isCycle; // True if it is a cycle delay
public: public:
AstDelay(FileLine* fl, AstNodeExpr* lhsp, bool isCycle) AstDelay(FileLine* fl, AstNodeExpr* lhsp, bool isCycle)
: ASTGEN_SUPER_Delay(fl) : ASTGEN_SUPER_Delay(fl)
@ -562,8 +561,10 @@ public:
void timeunit(const VTimescale& flag) { m_timeunit = flag; } void timeunit(const VTimescale& flag) { m_timeunit = flag; }
VTimescale timeunit() const { return m_timeunit; } VTimescale timeunit() const { return m_timeunit; }
bool isCycleDelay() const { return m_isCycle; } bool isCycleDelay() const { return m_isCycle; }
bool isRangeDelay() const { return rhsp() != nullptr; } bool isRangeDelay() const { return m_isCycle && rhsp() != nullptr; }
bool isUnbounded() const { return rhsp() && VN_IS(rhsp(), Unbounded); } bool isUnbounded() const { return isRangeDelay() && VN_IS(rhsp(), Unbounded); }
void fallDelay(AstNodeExpr* const fallDelayp) { rhsp(fallDelayp); }
AstNodeExpr* fallDelay() const { return m_isCycle ? nullptr : rhsp(); }
}; };
class AstDisable final : public AstNodeStmt { class AstDisable final : public AstNodeStmt {
// @astgen op1 := targetRefp : Optional[AstNodeExpr] // Reference to link in V3LinkDot // @astgen op1 := targetRefp : Optional[AstNodeExpr] // Reference to link in V3LinkDot

View File

@ -781,11 +781,13 @@ void DfgVertex::typeCheck(const DfgGraph& dfg) const {
} }
case VDfgType::SAnd: case VDfgType::SAnd:
case VDfgType::SIntersect:
case VDfgType::SOr: case VDfgType::SOr:
case VDfgType::SThroughout: { case VDfgType::SThroughout: {
UASSERT_OBJ(false, this, // LCOV_EXCL_START // Lowered before DFG
"SAnd/SOr/SThroughout should be removed before DFG"); // LCOV_EXCL_LINE UASSERT_OBJ(false, this, "SAnd/SIntersect/SOr/SThroughout should be removed before DFG");
return; // LCOV_EXCL_LINE return;
// LCOV_EXCL_STOP
} }
case VDfgType::LogAnd: case VDfgType::LogAnd:

View File

@ -126,6 +126,7 @@ class V3DfgCse final {
case VDfgType::StreamL: case VDfgType::StreamL:
case VDfgType::StreamR: case VDfgType::StreamR:
case VDfgType::SAnd: case VDfgType::SAnd:
case VDfgType::SIntersect:
case VDfgType::SOr: case VDfgType::SOr:
case VDfgType::SThroughout: case VDfgType::SThroughout:
case VDfgType::Sub: case VDfgType::Sub:
@ -251,6 +252,7 @@ class V3DfgCse final {
case VDfgType::ShiftRS: case VDfgType::ShiftRS:
case VDfgType::StreamL: case VDfgType::StreamL:
case VDfgType::SAnd: case VDfgType::SAnd:
case VDfgType::SIntersect:
case VDfgType::SOr: case VDfgType::SOr:
case VDfgType::SThroughout: case VDfgType::SThroughout:
case VDfgType::StreamR: case VDfgType::StreamR:

View File

@ -1127,7 +1127,15 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
} }
VL_RESTORER(m_prefixed); VL_RESTORER(m_prefixed);
m_prefixed = false; m_prefixed = false;
iterateConst(nodep->lhsp()); if (AstNodeExpr* const fallDelayp = nodep->fallDelay()) {
puts("(");
iterateConst(nodep->lhsp());
puts(", ");
iterateConst(fallDelayp);
puts(")");
} else {
iterateConst(nodep->lhsp());
}
if (!m_suppressSemi) { if (!m_suppressSemi) {
puts(";\n"); puts(";\n");
} else { } else {

View File

@ -1235,30 +1235,29 @@ class ParamProcessor final {
} }
} }
// Check if exprp is a ClassRefDType whose class is the default-parameter clone // Check if exprp's class matches origp's class after deparameterization.
// of origp's template class. This catches the case where an explicit type parameter // Handles both the simple case (user4p link from defaultsResolved) and the
// like Holder#(W#(int)) resolves to the same specialization as the implicit default // nested case where the default's inner class has non-default sub-parameters
// Holder#(), because W#(int) deparameterizes to W_ (the all-default clone of W). // (e.g., uvm_sequence#(uvm_reg_item) where uvm_reg_item != default uvm_sequence_item).
// Uses the user4p link set at line ~1658 when defaultsResolved is true. bool classTypeMatchesDefaultClone(const AstNodeDType* exprp, const AstNodeDType* origp) {
static bool classTypeMatchesDefaultClone(const AstNodeDType* exprp,
const AstNodeDType* origp) {
exprp = exprp->skipRefp(); exprp = exprp->skipRefp();
origp = origp->skipRefp(); origp = origp->skipRefp();
const auto* const exprClassRefp = VN_CAST(exprp, ClassRefDType); const auto* const exprClassRefp = VN_CAST(exprp, ClassRefDType);
const auto* const origClassRefp = VN_CAST(origp, ClassRefDType); const auto* const origClassRefp = VN_CAST(origp, ClassRefDType);
UINFO(9, "classTypeMatchesDefaultClone: exprClassRef="
<< exprClassRefp << " origClassRef=" << origClassRefp);
if (!exprClassRefp || !origClassRefp) return false; if (!exprClassRefp || !origClassRefp) return false;
// Fast path: check user4p link (set when template was deparameterized with defaults)
const AstNodeModule* const defaultClonep const AstNodeModule* const defaultClonep
= VN_CAST(origClassRefp->classp()->user4p(), Class); = VN_CAST(origClassRefp->classp()->user4p(), Class);
const bool result = defaultClonep && defaultClonep == exprClassRefp->classp(); if (defaultClonep && defaultClonep == exprClassRefp->classp()) return true;
UINFO(9, " origClass=" << origClassRefp->classp()->prettyNameQ() // Slow path: deparameterize the default type and compare the result.
<< " origClassp=" << cvtToHex(origClassRefp->classp()) if (!origClassRefp->classp()->hasGParam()) return false;
<< " user4p=" << (defaultClonep ? cvtToHex(defaultClonep) : "null") // const_cast safe: cloneTree doesn't modify the source
<< " exprClass=" << exprClassRefp->classp()->prettyNameQ() AstClassRefDType* const origClonep = static_cast<AstClassRefDType*>(
<< " exprClassp=" << cvtToHex(exprClassRefp->classp()) const_cast<AstClassRefDType*>(origClassRefp)->cloneTree(false));
<< " result=" << result); AstNodeModule* const resolvedModp = classRefDeparam(origClonep, origClassRefp->classp());
return result; const bool match = resolvedModp && VN_CAST(resolvedModp, Class) == exprClassRefp->classp();
VL_DO_DANGLING(origClonep->deleteTree(), origClonep);
return match;
} }
static bool paramConstsEqualAtMaxWidth(AstConst* exprp, AstConst* origp) { static bool paramConstsEqualAtMaxWidth(AstConst* exprp, AstConst* origp) {

View File

@ -542,6 +542,20 @@ class TimingControlVisitor final : public VNVisitor {
= timeunit.powerOfTen() - m_netlistp->timeprecision().powerOfTen(); = timeunit.powerOfTen() - m_netlistp->timeprecision().powerOfTen();
return std::pow(10.0, scalePowerOfTen); return std::pow(10.0, scalePowerOfTen);
} }
static bool staticallyNonZeroDelay(const AstNodeExpr* valuep) {
if (const AstConst* const constp = VN_CAST(valuep, Const)) return !constp->isZero();
if (const AstCond* const condp = VN_CAST(valuep, Cond)) {
return staticallyNonZeroDelay(condp->thenp())
&& staticallyNonZeroDelay(condp->elsep());
}
if (const AstMul* const mulp = VN_CAST(valuep, Mul)) {
const AstConst* const lhsConstp = VN_CAST(mulp->lhsp(), Const);
const AstConst* const rhsConstp = VN_CAST(mulp->rhsp(), Const);
if (lhsConstp && !lhsConstp->isZero()) return staticallyNonZeroDelay(mulp->rhsp());
if (rhsConstp && !rhsConstp->isZero()) return staticallyNonZeroDelay(mulp->lhsp());
}
return false;
}
// Creates the global delay scheduler variable // Creates the global delay scheduler variable
AstVarScope* getCreateDelayScheduler() { AstVarScope* getCreateDelayScheduler() {
if (m_delaySchedp) return m_delaySchedp; if (m_delaySchedp) return m_delaySchedp;
@ -1022,6 +1036,9 @@ class TimingControlVisitor final : public VNVisitor {
m_hasStaticZeroDelay = true; m_hasStaticZeroDelay = true;
// Don't warn on variable delays, as no point // Don't warn on variable delays, as no point
m_unknownDelayFlps.clear(); m_unknownDelayFlps.clear();
} else if (staticallyNonZeroDelay(valuep)) {
// Delay is dynamic, but every statically known outcome is non-zero.
// So we don't need #0 delay support and there should be no warning.
} else if (!VN_IS(valuep, Const)) { } else if (!VN_IS(valuep, Const)) {
// Delay is not known at compiile time. Conservatively schedule for #0 support, // Delay is not known at compiile time. Conservatively schedule for #0 support,
// but warn if no static #0 delays used as performance might be improved // but warn if no static #0 delays used as performance might be improved
@ -1250,6 +1267,15 @@ class TimingControlVisitor final : public VNVisitor {
AstNodeExpr* const lhs1p = nodep->lhsp()->unlinkFrBack(); AstNodeExpr* const lhs1p = nodep->lhsp()->unlinkFrBack();
AstNodeExpr* const rhs1p = nodep->rhsp()->unlinkFrBack(); AstNodeExpr* const rhs1p = nodep->rhsp()->unlinkFrBack();
AstNode* const controlp = nodep->timingControlp()->unlinkFrBack(); AstNode* const controlp = nodep->timingControlp()->unlinkFrBack();
if (AstDelay* const delayp = VN_CAST(controlp, Delay)) {
if (AstNodeExpr* fallDelayp = delayp->fallDelay()) {
fallDelayp = fallDelayp->unlinkFrBack();
// Use fall only for an all-zero value, rise otherwise.
delayp->lhsp(
new AstCond{flp, new AstEq{flp, rhs1p->cloneTree(false), new AstConst{flp, 0}},
fallDelayp, delayp->lhsp()->unlinkFrBack()});
}
}
AstAssign* const assignp = new AstAssign{nodep->fileline(), lhs1p, rhs1p, controlp}; AstAssign* const assignp = new AstAssign{nodep->fileline(), lhs1p, rhs1p, controlp};
// Put the assignment in a fork..join_none. // Put the assignment in a fork..join_none.
AstFork* const forkp = new AstFork{flp, VJoinType::JOIN_NONE}; AstFork* const forkp = new AstFork{flp, VJoinType::JOIN_NONE};

View File

@ -294,8 +294,9 @@ class WidthVisitor final : public VNVisitor {
// Widths: 1 bit out, lhs 1 bit, rhs 1 bit; Real: converts via compare with 0 // Widths: 1 bit out, lhs 1 bit, rhs 1 bit; Real: converts via compare with 0
void visit(AstLogAnd* nodep) override { visit_log_and_or(nodep); } void visit(AstLogAnd* nodep) override { visit_log_and_or(nodep); }
void visit(AstLogOr* nodep) override { visit_log_and_or(nodep); } void visit(AstLogOr* nodep) override { visit_log_and_or(nodep); }
// Sequence and/or (IEEE 1800-2023 16.9.2), same width rules as LogAnd/LogOr // Sequence and/or/intersect (IEEE 1800-2023 16.9.2), same width rules as LogAnd/LogOr
void visit(AstSAnd* nodep) override { visit_log_and_or(nodep); } void visit(AstSAnd* nodep) override { visit_log_and_or(nodep); }
void visit(AstSIntersect* nodep) override { visit_log_and_or(nodep); }
void visit(AstSOr* nodep) override { visit_log_and_or(nodep); } void visit(AstSOr* nodep) override { visit_log_and_or(nodep); }
void visit(AstLogEq* nodep) override { void visit(AstLogEq* nodep) override {
// Conversion from real not in IEEE, but a fallout // Conversion from real not in IEEE, but a fallout
@ -731,6 +732,11 @@ class WidthVisitor final : public VNVisitor {
iterateCheckBool(nodep, "default disable iff condition", nodep->condp(), BOTH); iterateCheckBool(nodep, "default disable iff condition", nodep->condp(), BOTH);
} }
void visit(AstDelay* nodep) override { void visit(AstDelay* nodep) override {
if (AstNodeExpr* const fallDelayp = nodep->fallDelay()) {
iterateCheckDelay(nodep, "delay", nodep->lhsp(), BOTH);
iterateCheckDelay(nodep, "delay", fallDelayp, BOTH);
return;
}
if (VN_IS(m_procedurep, Final)) { if (VN_IS(m_procedurep, Final)) {
nodep->v3error("Delays are not legal in final blocks (IEEE 1800-2023 9.2.3)"); nodep->v3error("Delays are not legal in final blocks (IEEE 1800-2023 9.2.3)");
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);

View File

@ -38,8 +38,7 @@
{ BBUNSUP((fl), "Unsupported: Verilog 1995 gate primitive: " << (tok)); } { BBUNSUP((fl), "Unsupported: Verilog 1995 gate primitive: " << (tok)); }
#define RISEFALLDLYUNSUP(nodep) \ #define RISEFALLDLYUNSUP(nodep) \
if (nodep->fileline()->timingOn() && v3Global.opt.timing().isSetTrue()) { \ if (nodep->fileline()->timingOn() && v3Global.opt.timing().isSetTrue()) { \
nodep->v3warn(RISEFALLDLY, \ nodep->v3warn(RISEFALLDLY, "Unsupported: turn-off delays. Ignoring the third delay"); \
"Unsupported: rising/falling/turn-off delays. Using the first delay"); \
} }
#define MINTYPMAXDLYUNSUP(nodep) \ #define MINTYPMAXDLYUNSUP(nodep) \
if (nodep->fileline()->timingOn() && v3Global.opt.timing().isSetTrue()) { \ if (nodep->fileline()->timingOn() && v3Global.opt.timing().isSetTrue()) { \
@ -3043,9 +3042,10 @@ delay_control<delayp>: //== IEEE: delay_control
| '#' '(' minTypMax ')' | '#' '(' minTypMax ')'
{ $$ = new AstDelay{$<fl>1, $3, false}; } { $$ = new AstDelay{$<fl>1, $3, false}; }
| '#' '(' minTypMax ',' minTypMax ')' | '#' '(' minTypMax ',' minTypMax ')'
{ $$ = new AstDelay{$<fl>1, $3, false}; RISEFALLDLYUNSUP($3); DEL($5); } { $$ = new AstDelay{$<fl>1, $3, false};
$$->fallDelay($5); }
| '#' '(' minTypMax ',' minTypMax ',' minTypMax ')' | '#' '(' minTypMax ',' minTypMax ',' minTypMax ')'
{ $$ = new AstDelay{$<fl>1, $5, false}; RISEFALLDLYUNSUP($5); DEL($3); DEL($7); } { $$ = new AstDelay{$<fl>1, $3, false}; $$->fallDelay($5); RISEFALLDLYUNSUP($7); DEL($7); }
; ;
delay_value<nodeExprp>: // ==IEEE:delay_value delay_value<nodeExprp>: // ==IEEE:delay_value
@ -6860,7 +6860,7 @@ sexpr<nodeExprp>: // ==IEEE: sequence_expr (The name sexpr is important as reg
{ $$ = new AstSOr{$2, $1, $3}; } { $$ = new AstSOr{$2, $1, $3}; }
// // Intersect always has an sexpr rhs // // Intersect always has an sexpr rhs
| ~p~sexpr yINTERSECT sexpr | ~p~sexpr yINTERSECT sexpr
{ $$ = $1; BBUNSUP($2, "Unsupported: intersect (in sequence expression)"); DEL($3); } { $$ = new AstSIntersect{$2, $1, $3}; }
// //
| yFIRST_MATCH '(' sexpr ')' | yFIRST_MATCH '(' sexpr ')'
{ $$ = $3; BBUNSUP($1, "Unsupported: first_match (in sequence expression)"); } { $$ = $3; BBUNSUP($1, "Unsupported: first_match (in sequence expression)"); }
@ -6894,7 +6894,7 @@ cycle_delay_range<delayp>: // IEEE: ==cycle_delay_range
// // the sv-ac committee has been asked to clarify (Mantis 1901) // // the sv-ac committee has been asked to clarify (Mantis 1901)
| yP_POUNDPOUND '[' constExpr ':' constExpr ']' | yP_POUNDPOUND '[' constExpr ':' constExpr ']'
{ $$ = new AstDelay{$1, $3, true}; { $$ = new AstDelay{$1, $3, true};
$$->rhsp($5); } $$->rhsp($5); }
| yP_POUNDPOUND yP_BRASTAR ']' | yP_POUNDPOUND yP_BRASTAR ']'
{ $$ = new AstDelay{$1, new AstConst{$1, 0}, true}; { $$ = new AstDelay{$1, new AstConst{$1, 0}, true};
$$->rhsp(new AstUnbounded{$1}); } $$->rhsp(new AstUnbounded{$1}); }

View File

@ -22,7 +22,7 @@ module t (
// verilator lint_off IMPLICIT // verilator lint_off IMPLICIT
not #(0.108) NT0 (nt0, a[0]); not #(0.108) NT0 (nt0, a[0]);
and #1 AN0 (an0, a[0], b[0]); and #1 AN0 (an0, a[0], b[0]);
nand #(2,3) ND0 (nd0, a[0], b[0], b[1]); nand #(2,3,4) ND0 (nd0, a[0], b[0], b[1]);
or OR0 (or0, a[0], b[0]); or OR0 (or0, a[0], b[0]);
nor NR0 (nr0, a[0], b[0], b[2]); nor NR0 (nr0, a[0], b[0], b[2]);
xor (xo0, a[0], b[0]); xor (xo0, a[0], b[0]);

View File

@ -1,6 +1,6 @@
%Warning-RISEFALLDLY: t/t_gate_basic.v:25:11: Unsupported: rising/falling/turn-off delays. Using the first delay %Warning-RISEFALLDLY: t/t_gate_basic.v:25:15: Unsupported: turn-off delays. Ignoring the third delay
25 | nand #(2,3) ND0 (nd0, a[0], b[0], b[1]); 25 | nand #(2,3,4) ND0 (nd0, a[0], b[0], b[1]);
| ^ | ^
... For warning description see https://verilator.org/warn/RISEFALLDLY?v=latest ... For warning description see https://verilator.org/warn/RISEFALLDLY?v=latest
... Use "/* verilator lint_off RISEFALLDLY */" and lint_on around source to disable this message. ... Use "/* verilator lint_off RISEFALLDLY */" and lint_on around source to disable this message.
%Warning-SPECIFYIGN: t/t_gate_basic.v:49:25: Ignoring unsupported: specify block construct %Warning-SPECIFYIGN: t/t_gate_basic.v:49:25: Ignoring unsupported: specify block construct

View File

@ -1,6 +1,6 @@
%Warning-RISEFALLDLY: t/t_gate_basic.v:25:11: Unsupported: rising/falling/turn-off delays. Using the first delay %Warning-RISEFALLDLY: t/t_gate_basic.v:25:15: Unsupported: turn-off delays. Ignoring the third delay
25 | nand #(2,3) ND0 (nd0, a[0], b[0], b[1]); 25 | nand #(2,3,4) ND0 (nd0, a[0], b[0], b[1]);
| ^ | ^
... For warning description see https://verilator.org/warn/RISEFALLDLY?v=latest ... For warning description see https://verilator.org/warn/RISEFALLDLY?v=latest
... Use "/* verilator lint_off RISEFALLDLY */" and lint_on around source to disable this message. ... Use "/* verilator lint_off RISEFALLDLY */" and lint_on around source to disable this message.
%Error: Exiting due to %Error: Exiting due to

View File

@ -9,11 +9,12 @@
import vltest_bootstrap import vltest_bootstrap
test.scenarios('linter') test.scenarios('vlt')
test.top_filename = "t/t_gate_basic.v" test.top_filename = "t/t_gate_basic.v"
test.lint(verilator_flags2=["-Wall", "-Wno-DECLFILENAME -Wno-SPECIFYIGN -Wno-UNUSED"], test.compile(
fails=True, verilator_flags2=["--timing", "-Wall", "-Wno-DECLFILENAME -Wno-SPECIFYIGN -Wno-UNUSED"],
expect_filename=test.golden_filename) fails=True,
expect_filename=test.golden_filename)
test.passes() test.passes()

View File

@ -24,7 +24,7 @@ module t (
int fails_b = 0; int fails_b = 0;
// First launch at cyc==2 should be canceled by reset pulse in the middle. // First launch at cyc==2 should be canceled by reset pulse in the middle.
assert property (@(posedge clk) disable iff (rst) (cyc == 2) |-> ##2 done) assert property (@(posedge clk) disable iff (rst) (t.cyc == 2) |-> ##2 done)
else fails_a++; else fails_a++;
// Second launch at cyc==8 has no reset pulse in flight and should fail once. // Second launch at cyc==8 has no reset pulse in flight and should fail once.

View File

@ -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('simulator')
test.compile(timing_loop=True, verilator_flags2=["--timing"])
test.execute()
test.passes()

View File

@ -0,0 +1,104 @@
// DESCRIPTION: Verilator: Rise/fall delays on continuous assigns and gates
//
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2026 Antmicro
// SPDX-License-Identifier: CC0-1.0
`define stop $stop
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", `__FILE__, `__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0)
`define check_scalar(exp) do begin `checkh(out_assign, exp); `checkh(out_buf, exp); `checkh(out_net, exp); end while(0)
module t;
logic in = 0;
logic [3:0] in_vec = 4'h0;
wire out_assign;
wire out_buf;
wire #(5,3) out_net;
wire [3:0] out_vec_assign;
assign #(5,3) out_assign = in;
buf #(5,3) u_buf (out_buf, in);
assign out_net = in;
assign #(5,3) out_vec_assign = in_vec;
initial begin
#4;
`check_scalar(1'b0);
`checkh(out_vec_assign, 4'h0);
// Rise canceled by a fall before the rise delay expires.
in = 1'b1;
#2;
`check_scalar(1'b0);
in = 1'b0;
#4;
`check_scalar(1'b0);
// A committed rise.
in = 1'b1;
#4;
`check_scalar(1'b0);
#1;
`check_scalar(1'b1);
// Fall canceled by a new rise before the fall delay expires.
in = 1'b0;
#2;
`check_scalar(1'b1);
in = 1'b1;
#4;
`check_scalar(1'b1);
#1;
`check_scalar(1'b1);
// A committed fall.
in = 1'b0;
#2;
`check_scalar(1'b1);
#1;
`check_scalar(1'b0);
// Whole-value vector rise canceled by a fall back to zero.
in_vec = 4'h3;
#2;
`checkh(out_vec_assign, 4'h0);
in_vec = 4'h0;
#4;
`checkh(out_vec_assign, 4'h0);
// Zero to nonzero uses the rise delay.
in_vec = 4'h3;
#4;
`checkh(out_vec_assign, 4'h0);
#1;
`checkh(out_vec_assign, 4'h3);
// Nonzero to nonzero still uses the rise delay on the whole value.
in_vec = 4'h5;
#4;
`checkh(out_vec_assign, 4'h3);
#1;
`checkh(out_vec_assign, 4'h5);
// A pending fall back to zero is canceled by a new nonzero value.
in_vec = 4'h0;
#2;
`checkh(out_vec_assign, 4'h5);
in_vec = 4'h6;
#4;
`checkh(out_vec_assign, 4'h5);
#1;
`checkh(out_vec_assign, 4'h6);
// Nonzero to zero uses the fall delay.
in_vec = 4'h0;
#2;
`checkh(out_vec_assign, 4'h6);
#1;
`checkh(out_vec_assign, 4'h0);
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -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('simulator')
test.compile(verilator_flags2=['--assert --timing'])
test.execute()
test.passes()

View File

@ -0,0 +1,82 @@
// 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 checkh(gotv, expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
// verilog_format: on
module t (
input clk
);
integer cyc = 0;
reg [63:0] crc = '0;
reg [63:0] sum = '0;
// Derive test signals from CRC
wire a = crc[0];
wire b = crc[1];
wire c = crc[2];
wire d = crc[3];
wire [63:0] result = {60'h0, d, c, b, a};
always_ff @(posedge clk) begin
`ifdef TEST_VERBOSE
$write("[%0t] cyc==%0d crc=%x a=%b b=%b c=%b d=%b\n",
$time, cyc, crc, a, b, c, d);
`endif
cyc <= cyc + 1;
crc <= {crc[62:0], crc[63] ^ crc[2] ^ crc[0]};
sum <= result ^ {sum[62:0], sum[63] ^ sum[2] ^ sum[0]};
if (cyc == 0) begin
crc <= 64'h5aef0c8d_d70a4497;
sum <= '0;
end else if (cyc < 10) begin
sum <= '0;
end else if (cyc == 99) begin
`checkh(crc, 64'hc77bb9b3784ea091);
`checkh(sum, 64'hdb7bc8bfe61f987e);
$write("*-* All Finished *-*\n");
$finish;
end
end
// =========================================================================
// Boolean intersect (length-0): equivalent to boolean AND (IEEE 16.9.6)
// =========================================================================
// Boolean intersect: when a & b, intersect succeeds (equivalent to AND)
assert property (@(posedge clk) disable iff (cyc < 2)
(a & b) |-> (a intersect b));
// Boolean intersect with constant true -- reduces to just 'a'
assert property (@(posedge clk) disable iff (cyc < 2)
a |-> (a intersect 1'b1));
// =========================================================================
// Multi-cycle sequence intersect (IEEE 1800-2023 16.9.6)
// Same-length sequences: intersect succeeds when both arms complete
// =========================================================================
// Both arms have length 1; 1'b1 guarantees completion on both sides
assert property (@(posedge clk)
(a & b) |-> (a ##1 1'b1) intersect (b ##1 1'b1));
// Both arms have length 2
assert property (@(posedge clk)
(a & b) |-> (a ##2 1'b1) intersect (b ##2 1'b1));
// Different internal structure, same total length (2 cycles each)
assert property (@(posedge clk)
(a & b) |-> (a ##1 1'b1 ##1 1'b1) intersect (b ##2 1'b1));
// Standalone constant intersect (always passes)
assert property (@(posedge clk)
(1'b1 ##1 1'b1) intersect (1'b1 ##1 1'b1));
endmodule

View File

@ -0,0 +1,13 @@
%Warning-WIDTHTRUNC: t/t_sequence_intersect_len_warn.v:16:17: Intersect sequence length mismatch (left 1 cycles, right 3 cycles) -- intersection is always empty
: ... note: In instance 't'
16 | (a ##1 b) intersect (c ##3 d));
| ^~~~~~~~~
... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest
... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message.
%Warning-WIDTHEXPAND: t/t_sequence_intersect_len_warn.v:20:17: Intersect sequence length mismatch (left 3 cycles, right 1 cycles) -- intersection is always empty
: ... note: In instance 't'
20 | (a ##3 b) intersect (c ##1 d));
| ^~~~~~~~~
... For warning description see https://verilator.org/warn/WIDTHEXPAND?v=latest
... Use "/* verilator lint_off WIDTHEXPAND */" and lint_on around source to disable this message.
%Error: Exiting due to

View File

@ -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_all')
test.compile(verilator_flags2=['--assert', '--timing', '--lint-only'],
fails=True,
expect_filename=test.golden_filename)
test.passes()

View File

@ -0,0 +1,22 @@
// 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
// verilog_lint: off
// verilog_format: on
module t (input clk);
logic a, b, c, d;
// LHS length 2, RHS length 4 -- WIDTHTRUNC (left < right)
assert property (@(posedge clk)
(a ##1 b) intersect (c ##3 d));
// LHS length 4, RHS length 2 -- WIDTHEXPAND (left > right)
assert property (@(posedge clk)
(a ##3 b) intersect (c ##1 d));
endmodule

View File

@ -0,0 +1,6 @@
%Error-UNSUPPORTED: t/t_sequence_intersect_range_unsup.v:12:21: Unsupported: intersect with ranged cycle-delay operand
: ... note: In instance 't'
12 | (a ##[1:5] b) intersect (c ##2 d));
| ^~~~~~~~~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: Exiting due to

View File

@ -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('linter')
test.compile(verilator_flags2=['--assert --timing'],
fails=True,
expect_filename=test.golden_filename)
test.passes()

View File

@ -0,0 +1,14 @@
// 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);
logic a, b, c, d;
// Range delay in intersect operand is unsupported
assert property (@(posedge clk)
(a ##[1:5] b) intersect (c ##2 d));
endmodule

View File

@ -1,4 +1,4 @@
%Error-UNSUPPORTED: t/t_sequence_nonconst_delay_unsup.v:14:40: Unsupported: non-constant cycle delay in sequence and/or %Error-UNSUPPORTED: t/t_sequence_nonconst_delay_unsup.v:14:40: Unsupported: non-constant cycle delay in sequence and/or/intersect
: ... note: In instance 't' : ... note: In instance 't'
14 | assert property (@(posedge clk) (a ##delay b) and (c ##1 d)); 14 | assert property (@(posedge clk) (a ##delay b) and (c ##1 d));
| ^~~~~ | ^~~~~

View File

@ -2,9 +2,6 @@
34 | a within(b); 34 | a within(b);
| ^~~~~~ | ^~~~~~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:50:7: Unsupported: intersect (in sequence expression)
50 | a intersect b;
| ^~~~~~~~~
%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:95:7: Unsupported: [= boolean abbrev expression %Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:95:7: Unsupported: [= boolean abbrev expression
95 | a [= 1]; 95 | a [= 1];
| ^~ | ^~

View File

@ -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('simulator')
test.compile(verilator_flags2=["--binary"])
test.execute()
test.passes()

View File

@ -0,0 +1,94 @@
// DESCRIPTION: Verilator: Verify that nested class type parameters with
// explicit-equivalent defaults resolve to the same specialization.
//
// When uvm_reg_sequence#(type BASE = uvm_sequence#(uvm_reg_item)) is
// extended with the explicit equivalent default, both must produce the
// same specialization so that $cast succeeds between them.
//
// 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
virtual class uvm_object;
endclass
class uvm_factory;
uvm_object m_type_names[string];
function uvm_object create_object_by_name(string name);
uvm_object wrapper;
if (m_type_names.exists(name)) begin
wrapper = m_type_names[name];
end
else begin
$display("%%Error: object not found '%s'", name);
$stop;
end
return wrapper;
endfunction
function void register(uvm_object obj, string name);
m_type_names[name] = obj;
endfunction
endclass
uvm_factory factory;
class uvm_sequence_item extends uvm_object;
endclass
class uvm_reg_item extends uvm_sequence_item;
endclass
virtual class uvm_sequence #(
type REQ = uvm_sequence_item,
type RSP = REQ
) extends uvm_object;
endclass
class uvm_reg_sequence #(
type BASE = uvm_sequence#(uvm_reg_item)
) extends BASE;
function new;
factory.register(this, "uvm_reg_sequence");
endfunction
endclass
class uvm_reg_hw_reset_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item));
function new;
factory.register(this, "uvm_reg_hw_reset_seq");
endfunction
endclass
module t;
initial begin
uvm_reg_hw_reset_seq rsq;
uvm_reg_sequence seq;
uvm_object obj;
int cst;
string seq_name;
factory = new;
rsq = new;
seq_name = "uvm_reg_hw_reset_seq";
obj = factory.create_object_by_name(seq_name);
if (obj == null) $stop;
cst = $cast(seq, obj);
/* verilator lint_off WIDTHTRUNC */
if (!cst || seq == null) begin
$display("%%Error: cast failed");
$stop;
end
/* verilator lint_on WIDTHTRUNC */
if (seq != rsq) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule