Merge upstream/master and resolve conflicts
This commit is contained in:
commit
db1dd74404
|
|
@ -1855,8 +1855,11 @@ List Of Warnings
|
|||
|
||||
and #(1,2,3) AND (out, a, b);
|
||||
|
||||
Warns that rising, falling, and turn-off delays are currently unsupported.
|
||||
The first (rising) delay is used for all cases.
|
||||
Warns that the third (turn-off) delay is currently unsupported and is
|
||||
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
|
||||
|
|
|
|||
|
|
@ -709,9 +709,8 @@ class AssertVisitor final : public VNVisitor {
|
|||
}
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void visit(AstVarRef* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (m_inSampled && !(nodep->varp() && nodep->varp()->noSample())) {
|
||||
void visit(AstNodeVarRef* nodep) override {
|
||||
if (m_inSampled && !nodep->varp()->noSample()) {
|
||||
if (!nodep->access().isReadOnly()) {
|
||||
nodep->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: Write to variable in sampled expression");
|
||||
|
|
|
|||
|
|
@ -746,6 +746,7 @@ private:
|
|||
AstSenTree* const senTreep = newSenTree(nodep);
|
||||
AstAlways* const alwaysp = new AstAlways{flp, VAlwaysKwd::ALWAYS, senTreep, ifp};
|
||||
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},
|
||||
new AstConst{flp, static_cast<uint32_t>(n - 1)}};
|
||||
cntCheckp->dtypeSetBit();
|
||||
|
|
@ -852,6 +853,7 @@ private:
|
|||
AstVar* const cntVarp = new AstVar{flp, VVarType::BLOCKTEMP, name + "__counter",
|
||||
exprp->findBasicDType(VBasicDTypeKwd::UINT32)};
|
||||
cntVarp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
|
||||
cntVarp->noSample(true);
|
||||
|
||||
AstBegin* const beginp = new AstBegin{flp, name + "__block", cntVarp, true};
|
||||
beginp->addStmtsp(
|
||||
|
|
|
|||
|
|
@ -364,8 +364,9 @@ static std::vector<SeqStep> extractTimeline(AstNodeExpr* nodep) {
|
|||
if (AstConst* const constp = VN_CAST(dlyp->lhsp(), Const)) {
|
||||
cycles = constp->toSInt();
|
||||
} else {
|
||||
dlyp->lhsp()->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: non-constant cycle delay in sequence and/or");
|
||||
dlyp->lhsp()->v3warn(
|
||||
E_UNSUPPORTED,
|
||||
"Unsupported: non-constant cycle delay in sequence and/or/intersect");
|
||||
}
|
||||
}
|
||||
// The expression after the delay
|
||||
|
|
@ -386,6 +387,18 @@ static std::vector<SeqStep> extractTimeline(AstNodeExpr* nodep) {
|
|||
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
|
||||
class AssertPropLowerVisitor final : public VNVisitor {
|
||||
// STATE
|
||||
|
|
@ -624,6 +637,47 @@ class AssertPropLowerVisitor final : public VNVisitor {
|
|||
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 {
|
||||
iterateChildren(nodep);
|
||||
if (containsSExpr(nodep->lhsp()) || containsSExpr(nodep->rhsp())) {
|
||||
|
|
@ -637,6 +691,19 @@ class AssertPropLowerVisitor final : public VNVisitor {
|
|||
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 {
|
||||
iterateChildren(nodep);
|
||||
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 {
|
||||
// Reject throughout with range-delay sequences before FSM expansion
|
||||
// would silently lose per-tick enforcement (IEEE 1800-2023 16.9.9)
|
||||
|
|
|
|||
|
|
@ -3699,6 +3699,30 @@ public:
|
|||
bool sizeMattersRhs() const override { return false; }
|
||||
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 {
|
||||
// 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.
|
||||
|
|
|
|||
|
|
@ -543,11 +543,10 @@ class AstDelay final : public AstNodeStmt {
|
|||
// Delay statement
|
||||
// @astgen op1 := lhsp : AstNodeExpr // Delay value (or min for range)
|
||||
// @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)
|
||||
VTimescale m_timeunit; // Delay's time unit
|
||||
const bool m_isCycle; // True if it is a cycle delay
|
||||
|
||||
public:
|
||||
AstDelay(FileLine* fl, AstNodeExpr* lhsp, bool isCycle)
|
||||
: ASTGEN_SUPER_Delay(fl)
|
||||
|
|
@ -562,8 +561,10 @@ public:
|
|||
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
|
||||
VTimescale timeunit() const { return m_timeunit; }
|
||||
bool isCycleDelay() const { return m_isCycle; }
|
||||
bool isRangeDelay() const { return rhsp() != nullptr; }
|
||||
bool isUnbounded() const { return rhsp() && VN_IS(rhsp(), Unbounded); }
|
||||
bool isRangeDelay() const { return m_isCycle && rhsp() != nullptr; }
|
||||
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 {
|
||||
// @astgen op1 := targetRefp : Optional[AstNodeExpr] // Reference to link in V3LinkDot
|
||||
|
|
|
|||
|
|
@ -781,11 +781,13 @@ void DfgVertex::typeCheck(const DfgGraph& dfg) const {
|
|||
}
|
||||
|
||||
case VDfgType::SAnd:
|
||||
case VDfgType::SIntersect:
|
||||
case VDfgType::SOr:
|
||||
case VDfgType::SThroughout: {
|
||||
UASSERT_OBJ(false, this,
|
||||
"SAnd/SOr/SThroughout should be removed before DFG"); // LCOV_EXCL_LINE
|
||||
return; // LCOV_EXCL_LINE
|
||||
// LCOV_EXCL_START // Lowered before DFG
|
||||
UASSERT_OBJ(false, this, "SAnd/SIntersect/SOr/SThroughout should be removed before DFG");
|
||||
return;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
case VDfgType::LogAnd:
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ class V3DfgCse final {
|
|||
case VDfgType::StreamL:
|
||||
case VDfgType::StreamR:
|
||||
case VDfgType::SAnd:
|
||||
case VDfgType::SIntersect:
|
||||
case VDfgType::SOr:
|
||||
case VDfgType::SThroughout:
|
||||
case VDfgType::Sub:
|
||||
|
|
@ -251,6 +252,7 @@ class V3DfgCse final {
|
|||
case VDfgType::ShiftRS:
|
||||
case VDfgType::StreamL:
|
||||
case VDfgType::SAnd:
|
||||
case VDfgType::SIntersect:
|
||||
case VDfgType::SOr:
|
||||
case VDfgType::SThroughout:
|
||||
case VDfgType::StreamR:
|
||||
|
|
|
|||
|
|
@ -1127,7 +1127,15 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
|||
}
|
||||
VL_RESTORER(m_prefixed);
|
||||
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) {
|
||||
puts(";\n");
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1235,30 +1235,29 @@ class ParamProcessor final {
|
|||
}
|
||||
}
|
||||
|
||||
// Check if exprp is a ClassRefDType whose class is the default-parameter clone
|
||||
// of origp's template class. This catches the case where an explicit type parameter
|
||||
// like Holder#(W#(int)) resolves to the same specialization as the implicit default
|
||||
// Holder#(), because W#(int) deparameterizes to W_ (the all-default clone of W).
|
||||
// Uses the user4p link set at line ~1658 when defaultsResolved is true.
|
||||
static bool classTypeMatchesDefaultClone(const AstNodeDType* exprp,
|
||||
const AstNodeDType* origp) {
|
||||
// Check if exprp's class matches origp's class after deparameterization.
|
||||
// Handles both the simple case (user4p link from defaultsResolved) and the
|
||||
// nested case where the default's inner class has non-default sub-parameters
|
||||
// (e.g., uvm_sequence#(uvm_reg_item) where uvm_reg_item != default uvm_sequence_item).
|
||||
bool classTypeMatchesDefaultClone(const AstNodeDType* exprp, const AstNodeDType* origp) {
|
||||
exprp = exprp->skipRefp();
|
||||
origp = origp->skipRefp();
|
||||
const auto* const exprClassRefp = VN_CAST(exprp, ClassRefDType);
|
||||
const auto* const origClassRefp = VN_CAST(origp, ClassRefDType);
|
||||
UINFO(9, "classTypeMatchesDefaultClone: exprClassRef="
|
||||
<< exprClassRefp << " origClassRef=" << origClassRefp);
|
||||
if (!exprClassRefp || !origClassRefp) return false;
|
||||
// Fast path: check user4p link (set when template was deparameterized with defaults)
|
||||
const AstNodeModule* const defaultClonep
|
||||
= VN_CAST(origClassRefp->classp()->user4p(), Class);
|
||||
const bool result = defaultClonep && defaultClonep == exprClassRefp->classp();
|
||||
UINFO(9, " origClass=" << origClassRefp->classp()->prettyNameQ()
|
||||
<< " origClassp=" << cvtToHex(origClassRefp->classp())
|
||||
<< " user4p=" << (defaultClonep ? cvtToHex(defaultClonep) : "null")
|
||||
<< " exprClass=" << exprClassRefp->classp()->prettyNameQ()
|
||||
<< " exprClassp=" << cvtToHex(exprClassRefp->classp())
|
||||
<< " result=" << result);
|
||||
return result;
|
||||
if (defaultClonep && defaultClonep == exprClassRefp->classp()) return true;
|
||||
// Slow path: deparameterize the default type and compare the result.
|
||||
if (!origClassRefp->classp()->hasGParam()) return false;
|
||||
// const_cast safe: cloneTree doesn't modify the source
|
||||
AstClassRefDType* const origClonep = static_cast<AstClassRefDType*>(
|
||||
const_cast<AstClassRefDType*>(origClassRefp)->cloneTree(false));
|
||||
AstNodeModule* const resolvedModp = classRefDeparam(origClonep, origClassRefp->classp());
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -542,6 +542,20 @@ class TimingControlVisitor final : public VNVisitor {
|
|||
= timeunit.powerOfTen() - m_netlistp->timeprecision().powerOfTen();
|
||||
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
|
||||
AstVarScope* getCreateDelayScheduler() {
|
||||
if (m_delaySchedp) return m_delaySchedp;
|
||||
|
|
@ -1022,6 +1036,9 @@ class TimingControlVisitor final : public VNVisitor {
|
|||
m_hasStaticZeroDelay = true;
|
||||
// Don't warn on variable delays, as no point
|
||||
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)) {
|
||||
// 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
|
||||
|
|
@ -1250,6 +1267,15 @@ class TimingControlVisitor final : public VNVisitor {
|
|||
AstNodeExpr* const lhs1p = nodep->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const rhs1p = nodep->rhsp()->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};
|
||||
// Put the assignment in a fork..join_none.
|
||||
AstFork* const forkp = new AstFork{flp, VJoinType::JOIN_NONE};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
void visit(AstLogAnd* 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(AstSIntersect* nodep) override { visit_log_and_or(nodep); }
|
||||
void visit(AstSOr* nodep) override { visit_log_and_or(nodep); }
|
||||
void visit(AstLogEq* nodep) override {
|
||||
// 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);
|
||||
}
|
||||
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)) {
|
||||
nodep->v3error("Delays are not legal in final blocks (IEEE 1800-2023 9.2.3)");
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
|
|
|
|||
|
|
@ -38,8 +38,7 @@
|
|||
{ BBUNSUP((fl), "Unsupported: Verilog 1995 gate primitive: " << (tok)); }
|
||||
#define RISEFALLDLYUNSUP(nodep) \
|
||||
if (nodep->fileline()->timingOn() && v3Global.opt.timing().isSetTrue()) { \
|
||||
nodep->v3warn(RISEFALLDLY, \
|
||||
"Unsupported: rising/falling/turn-off delays. Using the first delay"); \
|
||||
nodep->v3warn(RISEFALLDLY, "Unsupported: turn-off delays. Ignoring the third delay"); \
|
||||
}
|
||||
#define MINTYPMAXDLYUNSUP(nodep) \
|
||||
if (nodep->fileline()->timingOn() && v3Global.opt.timing().isSetTrue()) { \
|
||||
|
|
@ -3043,9 +3042,10 @@ delay_control<delayp>: //== IEEE: delay_control
|
|||
| '#' '(' minTypMax ')'
|
||||
{ $$ = new AstDelay{$<fl>1, $3, false}; }
|
||||
| '#' '(' minTypMax ',' minTypMax ')'
|
||||
{ $$ = new AstDelay{$<fl>1, $3, false}; RISEFALLDLYUNSUP($3); DEL($5); }
|
||||
{ $$ = new AstDelay{$<fl>1, $3, false};
|
||||
$$->fallDelay($5); }
|
||||
| '#' '(' 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
|
||||
|
|
@ -6860,7 +6860,7 @@ sexpr<nodeExprp>: // ==IEEE: sequence_expr (The name sexpr is important as reg
|
|||
{ $$ = new AstSOr{$2, $1, $3}; }
|
||||
// // Intersect always has an sexpr rhs
|
||||
| ~p~sexpr yINTERSECT sexpr
|
||||
{ $$ = $1; BBUNSUP($2, "Unsupported: intersect (in sequence expression)"); DEL($3); }
|
||||
{ $$ = new AstSIntersect{$2, $1, $3}; }
|
||||
//
|
||||
| yFIRST_MATCH '(' sexpr ')'
|
||||
{ $$ = $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)
|
||||
| yP_POUNDPOUND '[' constExpr ':' constExpr ']'
|
||||
{ $$ = new AstDelay{$1, $3, true};
|
||||
$$->rhsp($5); }
|
||||
$$->rhsp($5); }
|
||||
| yP_POUNDPOUND yP_BRASTAR ']'
|
||||
{ $$ = new AstDelay{$1, new AstConst{$1, 0}, true};
|
||||
$$->rhsp(new AstUnbounded{$1}); }
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ module t (
|
|||
// verilator lint_off IMPLICIT
|
||||
not #(0.108) NT0 (nt0, a[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]);
|
||||
nor NR0 (nr0, a[0], b[0], b[2]);
|
||||
xor (xo0, a[0], b[0]);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
%Warning-RISEFALLDLY: t/t_gate_basic.v:25:11: Unsupported: rising/falling/turn-off delays. Using the first delay
|
||||
25 | nand #(2,3) ND0 (nd0, a[0], b[0], b[1]);
|
||||
| ^
|
||||
%Warning-RISEFALLDLY: t/t_gate_basic.v:25:15: Unsupported: turn-off delays. Ignoring the third delay
|
||||
25 | nand #(2,3,4) ND0 (nd0, a[0], b[0], b[1]);
|
||||
| ^
|
||||
... 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.
|
||||
%Warning-SPECIFYIGN: t/t_gate_basic.v:49:25: Ignoring unsupported: specify block construct
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
%Warning-RISEFALLDLY: t/t_gate_basic.v:25:11: Unsupported: rising/falling/turn-off delays. Using the first delay
|
||||
25 | nand #(2,3) ND0 (nd0, a[0], b[0], b[1]);
|
||||
| ^
|
||||
%Warning-RISEFALLDLY: t/t_gate_basic.v:25:15: Unsupported: turn-off delays. Ignoring the third delay
|
||||
25 | nand #(2,3,4) ND0 (nd0, a[0], b[0], b[1]);
|
||||
| ^
|
||||
... 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.
|
||||
%Error: Exiting due to
|
||||
|
|
|
|||
|
|
@ -9,11 +9,12 @@
|
|||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('linter')
|
||||
test.scenarios('vlt')
|
||||
test.top_filename = "t/t_gate_basic.v"
|
||||
|
||||
test.lint(verilator_flags2=["-Wall", "-Wno-DECLFILENAME -Wno-SPECIFYIGN -Wno-UNUSED"],
|
||||
fails=True,
|
||||
expect_filename=test.golden_filename)
|
||||
test.compile(
|
||||
verilator_flags2=["--timing", "-Wall", "-Wno-DECLFILENAME -Wno-SPECIFYIGN -Wno-UNUSED"],
|
||||
fails=True,
|
||||
expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ module t (
|
|||
int fails_b = 0;
|
||||
|
||||
// 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++;
|
||||
|
||||
// Second launch at cyc==8 has no reset pulse in flight and should fail once.
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
@ -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'
|
||||
14 | assert property (@(posedge clk) (a ##delay b) and (c ##1 d));
|
||||
| ^~~~~
|
||||
|
|
|
|||
|
|
@ -2,9 +2,6 @@
|
|||
34 | a within(b);
|
||||
| ^~~~~~
|
||||
... 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
|
||||
95 | a [= 1];
|
||||
| ^~
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue