This commit is contained in:
parent
53c59e7ac7
commit
c90f9e53b7
1
Changes
1
Changes
|
|
@ -20,6 +20,7 @@ Verilator 5.039 devel
|
||||||
* Add enum base data type, wire data type, and I/O versus data declaration checking per IEEE.
|
* Add enum base data type, wire data type, and I/O versus data declaration checking per IEEE.
|
||||||
* Add PROTOTYPEMIS error on missing and mismatching prototypes (#6206) (#6207). [Alex Solomatnikov]
|
* Add PROTOTYPEMIS error on missing and mismatching prototypes (#6206) (#6207). [Alex Solomatnikov]
|
||||||
* Add error when trying to assign class object to variable of non-class types (#6237). [Igor Zaworski, Antmicro Ltd.]
|
* Add error when trying to assign class object to variable of non-class types (#6237). [Igor Zaworski, Antmicro Ltd.]
|
||||||
|
* Add ALWNEVER warning, for `always @*` that never execute (#6291).
|
||||||
* Add error on class 'function static'.
|
* Add error on class 'function static'.
|
||||||
* Add `-DVERILATOR=1` definition to compiler flags when using verilated.mk.
|
* Add `-DVERILATOR=1` definition to compiler flags when using verilated.mk.
|
||||||
* Support member-level triggers for virtual interfaces (#5166) (#6148). [Yilou Wang]
|
* Support member-level triggers for virtual interfaces (#5166) (#6148). [Yilou Wang]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
.. comment: generated by t_event_control_star_never_bad
|
||||||
|
.. code-block:: sv
|
||||||
|
|
||||||
|
always @* a = 100;
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
.. comment: generated by t_event_control_star_never_bad
|
||||||
|
.. code-block::
|
||||||
|
|
||||||
|
%Warning-ALWNEVER: example.v:1:3 'always @*' will never execute as expression list is empty (no variables read)
|
||||||
|
|
@ -111,6 +111,27 @@ List Of Warnings
|
||||||
simulate correctly.
|
simulate correctly.
|
||||||
|
|
||||||
|
|
||||||
|
.. option:: ALWNEVER
|
||||||
|
|
||||||
|
Warning that an `always @*` statement has no variables being read,
|
||||||
|
therefore the event list is empty, and as there are no events to wake
|
||||||
|
the process up, the always will never execute.
|
||||||
|
|
||||||
|
Faulty example:
|
||||||
|
|
||||||
|
.. include:: ../../docs/gen/ex_ALWNEVER_faulty.rst
|
||||||
|
|
||||||
|
Results in:
|
||||||
|
|
||||||
|
.. include:: ../../docs/gen/ex_ALWNEVER_msg.rst
|
||||||
|
|
||||||
|
To repair, assuming the intent was to execute the statements at e.g.
|
||||||
|
time zero, instead use an `always_comb` statement.
|
||||||
|
|
||||||
|
Ignoring this warning will only suppress the lint check; it will
|
||||||
|
simulate correctly.
|
||||||
|
|
||||||
|
|
||||||
.. option:: ASCRANGE
|
.. option:: ASCRANGE
|
||||||
|
|
||||||
.. TODO better example
|
.. TODO better example
|
||||||
|
|
|
||||||
|
|
@ -406,6 +406,7 @@ public:
|
||||||
ET_TRUE,
|
ET_TRUE,
|
||||||
//
|
//
|
||||||
ET_COMBO, // Sensitive to all combo inputs to this block
|
ET_COMBO, // Sensitive to all combo inputs to this block
|
||||||
|
ET_COMBO_STAR, // Sensitive to all combo inputs to this block (from .*)
|
||||||
ET_HYBRID, // This is like ET_COMB, but with explicit sensitivity to an expression
|
ET_HYBRID, // This is like ET_COMB, but with explicit sensitivity to an expression
|
||||||
ET_STATIC, // static variable initializers (runs before 'initial')
|
ET_STATIC, // static variable initializers (runs before 'initial')
|
||||||
ET_INITIAL, // 'initial' statements
|
ET_INITIAL, // 'initial' statements
|
||||||
|
|
@ -423,6 +424,7 @@ public:
|
||||||
true, // ET_TRUE
|
true, // ET_TRUE
|
||||||
|
|
||||||
false, // ET_COMBO
|
false, // ET_COMBO
|
||||||
|
false, // ET_COMBO_STAR
|
||||||
false, // ET_HYBRID
|
false, // ET_HYBRID
|
||||||
false, // ET_STATIC
|
false, // ET_STATIC
|
||||||
false, // ET_INITIAL
|
false, // ET_INITIAL
|
||||||
|
|
@ -443,13 +445,13 @@ public:
|
||||||
}
|
}
|
||||||
const char* ascii() const {
|
const char* ascii() const {
|
||||||
static const char* const names[]
|
static const char* const names[]
|
||||||
= {"CHANGED", "BOTH", "POS", "NEG", "EVENT", "TRUE",
|
= {"CHANGED", "BOTH", "POS", "NEG", "EVENT", "TRUE", "COMBO",
|
||||||
"COMBO", "HYBRID", "STATIC", "INITIAL", "FINAL", "NEVER"};
|
"COMBO_STAR", "HYBRID", "STATIC", "INITIAL", "FINAL", "NEVER"};
|
||||||
return names[m_e];
|
return names[m_e];
|
||||||
}
|
}
|
||||||
const char* verilogKwd() const {
|
const char* verilogKwd() const {
|
||||||
static const char* const names[]
|
static const char* const names[]
|
||||||
= {"[changed]", "edge", "posedge", "negedge", "[event]", "[true]",
|
= {"[changed]", "edge", "posedge", "negedge", "[event]", "[true]", "*",
|
||||||
"*", "[hybrid]", "[static]", "[initial]", "[final]", "[never]"};
|
"*", "[hybrid]", "[static]", "[initial]", "[final]", "[never]"};
|
||||||
return names[m_e];
|
return names[m_e];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1533,7 +1533,10 @@ public:
|
||||||
AstNodeVarRef* varrefp() const { return VN_CAST(sensp(), NodeVarRef); }
|
AstNodeVarRef* varrefp() const { return VN_CAST(sensp(), NodeVarRef); }
|
||||||
//
|
//
|
||||||
bool isClocked() const { return edgeType().clockedStmt(); }
|
bool isClocked() const { return edgeType().clockedStmt(); }
|
||||||
bool isCombo() const { return edgeType() == VEdgeType::ET_COMBO; }
|
bool isComboOrStar() const {
|
||||||
|
return edgeType() == VEdgeType::ET_COMBO || edgeType() == VEdgeType::ET_COMBO_STAR;
|
||||||
|
}
|
||||||
|
bool isComboStar() const { return edgeType() == VEdgeType::ET_COMBO_STAR; }
|
||||||
bool isHybrid() const { return edgeType() == VEdgeType::ET_HYBRID; }
|
bool isHybrid() const { return edgeType() == VEdgeType::ET_HYBRID; }
|
||||||
bool isStatic() const { return edgeType() == VEdgeType::ET_STATIC; }
|
bool isStatic() const { return edgeType() == VEdgeType::ET_STATIC; }
|
||||||
bool isInitial() const { return edgeType() == VEdgeType::ET_INITIAL; }
|
bool isInitial() const { return edgeType() == VEdgeType::ET_INITIAL; }
|
||||||
|
|
@ -1550,6 +1553,10 @@ public:
|
||||||
addSensesp(sensesp);
|
addSensesp(sensesp);
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstSenTree;
|
ASTGEN_MEMBERS_AstSenTree;
|
||||||
|
bool sameNode(const AstNode* samep) const override {
|
||||||
|
const AstSenTree* const asamep = VN_DBG_AS(samep, SenTree);
|
||||||
|
return m_multi == asamep->m_multi;
|
||||||
|
}
|
||||||
void dump(std::ostream& str) const override;
|
void dump(std::ostream& str) const override;
|
||||||
void dumpJson(std::ostream& str) const override;
|
void dumpJson(std::ostream& str) const override;
|
||||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||||
|
|
|
||||||
|
|
@ -1254,7 +1254,7 @@ bool AstSenTree::hasFinal() const {
|
||||||
bool AstSenTree::hasCombo() const {
|
bool AstSenTree::hasCombo() const {
|
||||||
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
||||||
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(senp->nextp(), SenItem)) {
|
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(senp->nextp(), SenItem)) {
|
||||||
if (senp->isCombo()) return true;
|
if (senp->isComboOrStar()) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,9 +80,11 @@ class ClockVisitor final : public VNVisitor {
|
||||||
AstNodeExpr* senEqnp = nullptr;
|
AstNodeExpr* senEqnp = nullptr;
|
||||||
for (AstSenItem* senp = nodesp; senp; senp = VN_AS(senp->nextp(), SenItem)) {
|
for (AstSenItem* senp = nodesp; senp; senp = VN_AS(senp->nextp(), SenItem)) {
|
||||||
UASSERT_OBJ(senp->edgeType() == VEdgeType::ET_TRUE, senp, "Should have been lowered");
|
UASSERT_OBJ(senp->edgeType() == VEdgeType::ET_TRUE, senp, "Should have been lowered");
|
||||||
|
if (senp->sensp()) {
|
||||||
AstNodeExpr* const senOnep = senp->sensp()->cloneTree(false);
|
AstNodeExpr* const senOnep = senp->sensp()->cloneTree(false);
|
||||||
senEqnp = senEqnp ? new AstOr{senp->fileline(), senEqnp, senOnep} : senOnep;
|
senEqnp = senEqnp ? new AstOr{senp->fileline(), senEqnp, senOnep} : senOnep;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return senEqnp;
|
return senEqnp;
|
||||||
}
|
}
|
||||||
AstIf* makeActiveIf(AstSenTree* sentreep) {
|
AstIf* makeActiveIf(AstSenTree* sentreep) {
|
||||||
|
|
|
||||||
|
|
@ -1119,6 +1119,7 @@ class DelayedVisitor final : public VNVisitor {
|
||||||
// First gather all senItems
|
// First gather all senItems
|
||||||
AstSenItem* senItemp = nullptr;
|
AstSenItem* senItemp = nullptr;
|
||||||
for (AstSenTree* const domainp : m_timingDomains) {
|
for (AstSenTree* const domainp : m_timingDomains) {
|
||||||
|
if (domainp->sensesp())
|
||||||
senItemp = AstNode::addNext(senItemp, domainp->sensesp()->cloneTree(true));
|
senItemp = AstNode::addNext(senItemp, domainp->sensesp()->cloneTree(true));
|
||||||
}
|
}
|
||||||
m_timingDomains.clear();
|
m_timingDomains.clear();
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@ public:
|
||||||
EC_FIRST_WARN, // Just a code so the program knows where to start warnings
|
EC_FIRST_WARN, // Just a code so the program knows where to start warnings
|
||||||
//
|
//
|
||||||
ALWCOMBORDER, // Always_comb with unordered statements
|
ALWCOMBORDER, // Always_comb with unordered statements
|
||||||
|
ALWNEVER, // always will never execute
|
||||||
ASCRANGE, // Ascending bit range vector
|
ASCRANGE, // Ascending bit range vector
|
||||||
ASSIGNDLY, // Assignment delays
|
ASSIGNDLY, // Assignment delays
|
||||||
ASSIGNIN, // Assigning to input
|
ASSIGNIN, // Assigning to input
|
||||||
|
|
@ -203,18 +204,18 @@ public:
|
||||||
// Errors
|
// Errors
|
||||||
"LIFETIME", "NEEDTIMINGOPT", "NOTIMING", "PORTSHORT", "TASKNSVAR", "UNSUPPORTED",
|
"LIFETIME", "NEEDTIMINGOPT", "NOTIMING", "PORTSHORT", "TASKNSVAR", "UNSUPPORTED",
|
||||||
// Warnings
|
// Warnings
|
||||||
" EC_FIRST_WARN", "ALWCOMBORDER", "ASCRANGE", "ASSIGNDLY", "ASSIGNIN", "BADSTDPRAGMA",
|
" EC_FIRST_WARN", "ALWCOMBORDER", "ALWNEVER", "ASCRANGE", "ASSIGNDLY", "ASSIGNIN",
|
||||||
"BADVLTPRAGMA", "BLKANDNBLK", "BLKLOOPINIT", "BLKSEQ", "BSSPACE", "CASEINCOMPLETE",
|
"BADSTDPRAGMA", "BADVLTPRAGMA", "BLKANDNBLK", "BLKLOOPINIT", "BLKSEQ", "BSSPACE",
|
||||||
"CASEOVERLAP", "CASEWITHX", "CASEX", "CASTCONST", "CDCRSTLOGIC", "CLKDATA", "CMPCONST",
|
"CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CASTCONST", "CDCRSTLOGIC",
|
||||||
"COLONPLUS", "COMBDLY", "CONSTRAINTIGN", "CONTASSREG", "COVERIGN", "DECLFILENAME",
|
"CLKDATA", "CMPCONST", "COLONPLUS", "COMBDLY", "CONSTRAINTIGN", "CONTASSREG",
|
||||||
"DEFOVERRIDE", "DEFPARAM", "DEPRECATED", "ENCAPSULATED", "ENDLABEL", "ENUMITEMWIDTH",
|
"COVERIGN", "DECLFILENAME", "DEFOVERRIDE", "DEFPARAM", "DEPRECATED", "ENCAPSULATED",
|
||||||
"ENUMVALUE", "EOFNEWLINE", "GENCLK", "GENUNNAMED", "HIERBLOCK", "IFDEPTH",
|
"ENDLABEL", "ENUMITEMWIDTH", "ENUMVALUE", "EOFNEWLINE", "GENCLK", "GENUNNAMED",
|
||||||
"IGNOREDRETURN", "IMPERFECTSCH", "IMPLICIT", "IMPLICITSTATIC", "IMPORTSTAR", "IMPURE",
|
"HIERBLOCK", "IFDEPTH", "IGNOREDRETURN", "IMPERFECTSCH", "IMPLICIT", "IMPLICITSTATIC",
|
||||||
"INCABSPATH", "INFINITELOOP", "INITIALDLY", "INSECURE", "LATCH", "LITENDIAN",
|
"IMPORTSTAR", "IMPURE", "INCABSPATH", "INFINITELOOP", "INITIALDLY", "INSECURE",
|
||||||
"MINTYPMAXDLY", "MISINDENT", "MODDUP", "MODMISSING", "MULTIDRIVEN", "MULTITOP",
|
"LATCH", "LITENDIAN", "MINTYPMAXDLY", "MISINDENT", "MODDUP", "MODMISSING",
|
||||||
"NEWERSTD", "NOEFFECT", "NOLATCH", "NONSTD", "NULLPORT", "PARAMNODEFAULT",
|
"MULTIDRIVEN", "MULTITOP", "NEWERSTD", "NOEFFECT", "NOLATCH", "NONSTD", "NULLPORT",
|
||||||
"PINCONNECTEMPTY", "PINMISSING", "PINNOCONNECT", "PINNOTFOUND", "PKGNODECL",
|
"PARAMNODEFAULT", "PINCONNECTEMPTY", "PINMISSING", "PINNOCONNECT", "PINNOTFOUND",
|
||||||
"PREPROCZERO", "PROCASSINIT", "PROCASSWIRE", "PROFOUTOFDATE", "PROTECTED",
|
"PKGNODECL", "PREPROCZERO", "PROCASSINIT", "PROCASSWIRE", "PROFOUTOFDATE", "PROTECTED",
|
||||||
"PROTOTYPEMIS", "RANDC", "REALCVT", "REDEFMACRO", "RISEFALLDLY", "SELRANGE",
|
"PROTOTYPEMIS", "RANDC", "REALCVT", "REDEFMACRO", "RISEFALLDLY", "SELRANGE",
|
||||||
"SHORTREAL", "SIDEEFFECT", "SPECIFYIGN", "SPLITVAR", "STATICVAR", "STMTDLY",
|
"SHORTREAL", "SIDEEFFECT", "SPECIFYIGN", "SPLITVAR", "STATICVAR", "STMTDLY",
|
||||||
"SYMRSVDWORD", "SYNCASYNCNET", "TICKCOUNT", "TIMESCALEMOD", "UNDRIVEN", "UNOPT",
|
"SYMRSVDWORD", "SYNCASYNCNET", "TICKCOUNT", "TIMESCALEMOD", "UNDRIVEN", "UNOPT",
|
||||||
|
|
|
||||||
|
|
@ -835,7 +835,7 @@ class LinkParseVisitor final : public VNVisitor {
|
||||||
if (alwaysp && alwaysp->keyword() == VAlwaysKwd::ALWAYS_COMB) {
|
if (alwaysp && alwaysp->keyword() == VAlwaysKwd::ALWAYS_COMB) {
|
||||||
alwaysp->v3error("Event control statements not legal under always_comb "
|
alwaysp->v3error("Event control statements not legal under always_comb "
|
||||||
"(IEEE 1800-2023 9.2.2.2.2)\n"
|
"(IEEE 1800-2023 9.2.2.2.2)\n"
|
||||||
<< nodep->warnMore() << "... Suggest use a normal 'always'");
|
<< alwaysp->warnMore() << "... Suggest use a normal 'always'");
|
||||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||||
} else if (alwaysp && !alwaysp->sentreep()) {
|
} else if (alwaysp && !alwaysp->sentreep()) {
|
||||||
// If the event control is at the top, move the sentree to the always
|
// If the event control is at the top, move the sentree to the always
|
||||||
|
|
|
||||||
|
|
@ -162,9 +162,11 @@ class SchedGraphBuilder final : public VNVisitor {
|
||||||
SchedSenVertex* const vtxp = new SchedSenVertex{m_graphp, senItemp};
|
SchedSenVertex* const vtxp = new SchedSenVertex{m_graphp, senItemp};
|
||||||
|
|
||||||
// Connect up the variable references
|
// Connect up the variable references
|
||||||
|
if (senItemp->sensp()) {
|
||||||
senItemp->sensp()->foreach([&](AstVarRef* refp) {
|
senItemp->sensp()->foreach([&](AstVarRef* refp) {
|
||||||
new V3GraphEdge{m_graphp, getVarVertex(refp->varScopep()), vtxp, 1};
|
new V3GraphEdge{m_graphp, getVarVertex(refp->varScopep()), vtxp, 1};
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Store back to hash map so we can find it next time
|
// Store back to hash map so we can find it next time
|
||||||
pair.first->second = vtxp;
|
pair.first->second = vtxp;
|
||||||
|
|
|
||||||
|
|
@ -905,8 +905,11 @@ class TimingControlVisitor final : public VNVisitor {
|
||||||
void visit(AstEventControl* nodep) override {
|
void visit(AstEventControl* nodep) override {
|
||||||
// Do not allow waiting on local named events, as they get enqueued for clearing, but can
|
// Do not allow waiting on local named events, as they get enqueued for clearing, but can
|
||||||
// go out of scope before that happens
|
// go out of scope before that happens
|
||||||
if (!nodep->sentreep())
|
if (!nodep->sentreep()) {
|
||||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: no sense equation (@*)");
|
nodep->v3warn(E_UNSUPPORTED, "Unsupported: no sense equation (@*)");
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||||
|
return;
|
||||||
|
}
|
||||||
FileLine* const flp = nodep->fileline();
|
FileLine* const flp = nodep->fileline();
|
||||||
// Relink child statements after the event control
|
// Relink child statements after the event control
|
||||||
if (nodep->stmtsp()) nodep->addNextHere(nodep->stmtsp()->unlinkFrBackWithNext());
|
if (nodep->stmtsp()) nodep->addNextHere(nodep->stmtsp()->unlinkFrBackWithNext());
|
||||||
|
|
|
||||||
|
|
@ -6556,6 +6556,7 @@ class WidthVisitor final : public VNVisitor {
|
||||||
userIterateChildren(nodep, nullptr);
|
userIterateChildren(nodep, nullptr);
|
||||||
}
|
}
|
||||||
void visit(AstSenItem* nodep) override {
|
void visit(AstSenItem* nodep) override {
|
||||||
|
if (nodep->isComboStar()) return;
|
||||||
UASSERT_OBJ(nodep->isClocked(), nodep, "Invalid edge");
|
UASSERT_OBJ(nodep->isClocked(), nodep, "Invalid edge");
|
||||||
// Optimize concat/replicate senitems; this has to be done here at the latest, otherwise we
|
// Optimize concat/replicate senitems; this has to be done here at the latest, otherwise we
|
||||||
// emit WIDTHCONCAT if there are unsized constants
|
// emit WIDTHCONCAT if there are unsized constants
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,36 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void visit(AstAlways* nodep) override {
|
||||||
|
// As have not optimized SenTrees yet, an 'always .*' will be on first and only SenItem
|
||||||
|
if (nodep->sentreep() && nodep->sentreep()->sensesp()
|
||||||
|
&& nodep->sentreep()->sensesp()->isComboStar()) {
|
||||||
|
const bool noReads = nodep->forall(
|
||||||
|
[&](const AstNodeVarRef* refp) { return !refp->access().isReadOrRW(); });
|
||||||
|
if (noReads) {
|
||||||
|
nodep->v3warn(ALWNEVER, "'always @*' will never execute as expression list is "
|
||||||
|
"empty (no variables read)\n"
|
||||||
|
<< nodep->warnMore()
|
||||||
|
<< "... Suggest use 'always_comb'");
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Iterate will delete ComboStar sentrees, so after above
|
||||||
|
iterateChildren(nodep);
|
||||||
|
editDType(nodep);
|
||||||
|
}
|
||||||
|
void visit(AstSenTree* nodep) override {
|
||||||
|
if (nodep->sensesp() && nodep->sensesp()->isComboStar()) {
|
||||||
|
UASSERT_OBJ(!nodep->sensesp()->nextp(), nodep, "Shouldn't be senitems after .*");
|
||||||
|
// Make look like standalone always
|
||||||
|
// (Rest of code assumed this before .* existed)
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
iterateChildren(nodep);
|
||||||
|
editDType(nodep);
|
||||||
|
}
|
||||||
void visit(AstAttrOf* nodep) override {
|
void visit(AstAttrOf* nodep) override {
|
||||||
switch (nodep->attrType()) {
|
switch (nodep->attrType()) {
|
||||||
case VAttrType::FUNC_ARG_PROTO: // FALLTHRU
|
case VAttrType::FUNC_ARG_PROTO: // FALLTHRU
|
||||||
|
|
|
||||||
|
|
@ -160,14 +160,17 @@ public:
|
||||||
return new AstGatePin{rangep->fileline(), exprp, rangep->cloneTree(true)};
|
return new AstGatePin{rangep->fileline(), exprp, rangep->cloneTree(true)};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AstSenTree* createClockSenTree(FileLine* fl, AstNodeExpr* exprp) {
|
AstSenTree* createSenTreeChanged(FileLine* fl, AstNodeExpr* exprp) {
|
||||||
return new AstSenTree{fl, new AstSenItem{fl, VEdgeType::ET_CHANGED, exprp}};
|
return new AstSenTree{fl, new AstSenItem{fl, VEdgeType::ET_CHANGED, exprp}};
|
||||||
}
|
}
|
||||||
|
AstSenTree* createSenTreeDotStar(FileLine* fl) {
|
||||||
|
return new AstSenTree{fl, new AstSenItem{fl, VEdgeType::ET_COMBO_STAR, nullptr}};
|
||||||
|
}
|
||||||
AstNodeExpr* createGlobalClockParseRef(FileLine* fl) {
|
AstNodeExpr* createGlobalClockParseRef(FileLine* fl) {
|
||||||
return new AstParseRef{fl, VParseRefExp::PX_TEXT, "__024global_clock", nullptr, nullptr};
|
return new AstParseRef{fl, VParseRefExp::PX_TEXT, "__024global_clock", nullptr, nullptr};
|
||||||
}
|
}
|
||||||
AstSenTree* createGlobalClockSenTree(FileLine* fl) {
|
AstSenTree* createGlobalClockSenTree(FileLine* fl) {
|
||||||
return createClockSenTree(fl, createGlobalClockParseRef(fl));
|
return createSenTreeChanged(fl, createGlobalClockParseRef(fl));
|
||||||
}
|
}
|
||||||
AstNode* createNettype(FileLine* fl, const string& name) {
|
AstNode* createNettype(FileLine* fl, const string& name) {
|
||||||
// As nettypes are unsupported, we just alias to logic
|
// As nettypes are unsupported, we just alias to logic
|
||||||
|
|
@ -2817,7 +2820,6 @@ module_common_item<nodep>: // ==IEEE: module_common_item
|
||||||
;
|
;
|
||||||
|
|
||||||
always_construct<nodep>: // IEEE: == always_construct
|
always_construct<nodep>: // IEEE: == always_construct
|
||||||
// // Verilator only - event_control attached to always
|
|
||||||
yALWAYS stmtBlock { $$ = new AstAlways{$1, VAlwaysKwd::ALWAYS, nullptr, $2}; }
|
yALWAYS stmtBlock { $$ = new AstAlways{$1, VAlwaysKwd::ALWAYS, nullptr, $2}; }
|
||||||
| yALWAYS_FF stmtBlock { $$ = new AstAlways{$1, VAlwaysKwd::ALWAYS_FF, nullptr, $2}; }
|
| yALWAYS_FF stmtBlock { $$ = new AstAlways{$1, VAlwaysKwd::ALWAYS_FF, nullptr, $2}; }
|
||||||
| yALWAYS_LATCH stmtBlock { $$ = new AstAlways{$1, VAlwaysKwd::ALWAYS_LATCH, nullptr, $2}; }
|
| yALWAYS_LATCH stmtBlock { $$ = new AstAlways{$1, VAlwaysKwd::ALWAYS_LATCH, nullptr, $2}; }
|
||||||
|
|
@ -3492,14 +3494,14 @@ attr_event_controlE<senTreep>:
|
||||||
|
|
||||||
attr_event_control<senTreep>: // ==IEEE: event_control
|
attr_event_control<senTreep>: // ==IEEE: event_control
|
||||||
'@' '(' event_expression ')' { $$ = new AstSenTree{$1, $3}; }
|
'@' '(' event_expression ')' { $$ = new AstSenTree{$1, $3}; }
|
||||||
| '@' '(' '*' ')' { $$ = nullptr; }
|
| '@' '(' '*' ')' { $$ = GRAMMARP->createSenTreeDotStar($1); }
|
||||||
| '@' '*' { $$ = nullptr; }
|
| '@' '*' { $$ = GRAMMARP->createSenTreeDotStar($1); }
|
||||||
;
|
;
|
||||||
|
|
||||||
event_control<senTreep>: // ==IEEE: event_control
|
event_control<senTreep>: // ==IEEE: event_control
|
||||||
// UNSUP: Needs alignment with IEEE event_control and clocking_event
|
// UNSUP: Needs alignment with IEEE event_control and clocking_event
|
||||||
'@' '(' '*' ')' { $$ = nullptr; }
|
'@' '(' '*' ')' { $$ = GRAMMARP->createSenTreeDotStar($1); }
|
||||||
| '@' '*' { $$ = nullptr; }
|
| '@' '*' { $$ = GRAMMARP->createSenTreeDotStar($1); }
|
||||||
// // IEEE: clocking_event
|
// // IEEE: clocking_event
|
||||||
| '@' '(' event_expression ')' { $$ = new AstSenTree{$1, $3}; }
|
| '@' '(' event_expression ')' { $$ = new AstSenTree{$1, $3}; }
|
||||||
// // IEEE: hierarchical_event_identifier
|
// // IEEE: hierarchical_event_identifier
|
||||||
|
|
@ -4464,7 +4466,7 @@ system_f_call_or_t<nodeExprp>: // IEEE: part of system_tf_call (can be task
|
||||||
| yD_CEIL '(' expr ')' { $$ = new AstCeilD{$1, $3}; }
|
| yD_CEIL '(' expr ')' { $$ = new AstCeilD{$1, $3}; }
|
||||||
| yD_CHANGED '(' expr ')' { $$ = new AstLogNot{$1, new AstStable{$1, $3, nullptr}}; }
|
| yD_CHANGED '(' expr ')' { $$ = new AstLogNot{$1, new AstStable{$1, $3, nullptr}}; }
|
||||||
| yD_CHANGED '(' expr ',' expr ')'
|
| yD_CHANGED '(' expr ',' expr ')'
|
||||||
{ $$ = new AstLogNot{$1, new AstStable{$1, $3, GRAMMARP->createClockSenTree($1, $5)}}; }
|
{ $$ = new AstLogNot{$1, new AstStable{$1, $3, GRAMMARP->createSenTreeChanged($1, $5)}}; }
|
||||||
| yD_CHANGED_GCLK '(' expr ')'
|
| yD_CHANGED_GCLK '(' expr ')'
|
||||||
{ $$ = new AstLogNot{$1, new AstStable{$1, $3, GRAMMARP->createGlobalClockSenTree($1)}}; }
|
{ $$ = new AstLogNot{$1, new AstStable{$1, $3, GRAMMARP->createGlobalClockSenTree($1)}}; }
|
||||||
| yD_CLOG2 '(' expr ')' { $$ = new AstCLog2{$1, $3}; }
|
| yD_CLOG2 '(' expr ')' { $$ = new AstCLog2{$1, $3}; }
|
||||||
|
|
@ -4487,7 +4489,7 @@ system_f_call_or_t<nodeExprp>: // IEEE: part of system_tf_call (can be task
|
||||||
| yD_DIST_UNIFORM '(' expr ',' expr ',' expr ')' { $$ = new AstDistUniform{$1, $3, $5, $7}; }
|
| yD_DIST_UNIFORM '(' expr ',' expr ',' expr ')' { $$ = new AstDistUniform{$1, $3, $5, $7}; }
|
||||||
| yD_EXP '(' expr ')' { $$ = new AstExpD{$1, $3}; }
|
| yD_EXP '(' expr ')' { $$ = new AstExpD{$1, $3}; }
|
||||||
| yD_FELL '(' expr ')' { $$ = new AstFell{$1, $3, nullptr}; }
|
| yD_FELL '(' expr ')' { $$ = new AstFell{$1, $3, nullptr}; }
|
||||||
| yD_FELL '(' expr ',' expr ')' { $$ = new AstFell{$1, $3, GRAMMARP->createClockSenTree($1, $5)}; }
|
| yD_FELL '(' expr ',' expr ')' { $$ = new AstFell{$1, $3, GRAMMARP->createSenTreeChanged($1, $5)}; }
|
||||||
| yD_FELL_GCLK '(' expr ')' { $$ = new AstFell{$1, $3, GRAMMARP->createGlobalClockSenTree($1)}; }
|
| yD_FELL_GCLK '(' expr ')' { $$ = new AstFell{$1, $3, GRAMMARP->createGlobalClockSenTree($1)}; }
|
||||||
| yD_FEOF '(' expr ')' { $$ = new AstFEof{$1, $3}; }
|
| yD_FEOF '(' expr ')' { $$ = new AstFEof{$1, $3}; }
|
||||||
| yD_FERROR '(' expr ',' idClassSel ')' { $$ = new AstFError{$1, $3, $5}; }
|
| yD_FERROR '(' expr ',' idClassSel ')' { $$ = new AstFError{$1, $3, $5}; }
|
||||||
|
|
@ -4539,7 +4541,7 @@ system_f_call_or_t<nodeExprp>: // IEEE: part of system_tf_call (can be task
|
||||||
| yD_RIGHT '(' exprOrDataType ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_RIGHT, $3, nullptr}; }
|
| yD_RIGHT '(' exprOrDataType ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_RIGHT, $3, nullptr}; }
|
||||||
| yD_RIGHT '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_RIGHT, $3, $5}; }
|
| yD_RIGHT '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_RIGHT, $3, $5}; }
|
||||||
| yD_ROSE '(' expr ')' { $$ = new AstRose{$1, $3, nullptr}; }
|
| yD_ROSE '(' expr ')' { $$ = new AstRose{$1, $3, nullptr}; }
|
||||||
| yD_ROSE '(' expr ',' expr ')' { $$ = new AstRose{$1, $3, GRAMMARP->createClockSenTree($1, $5)}; }
|
| yD_ROSE '(' expr ',' expr ')' { $$ = new AstRose{$1, $3, GRAMMARP->createSenTreeChanged($1, $5)}; }
|
||||||
| yD_ROSE_GCLK '(' expr ')' { $$ = new AstRose{$1, $3, GRAMMARP->createGlobalClockSenTree($1)}; }
|
| yD_ROSE_GCLK '(' expr ')' { $$ = new AstRose{$1, $3, GRAMMARP->createGlobalClockSenTree($1)}; }
|
||||||
| yD_RTOI '(' expr ')' { $$ = new AstRToIS{$1, $3}; }
|
| yD_RTOI '(' expr ')' { $$ = new AstRToIS{$1, $3}; }
|
||||||
| yD_SAMPLED '(' expr ')' { $$ = new AstSampled{$1, $3}; }
|
| yD_SAMPLED '(' expr ')' { $$ = new AstSampled{$1, $3}; }
|
||||||
|
|
@ -4555,7 +4557,7 @@ system_f_call_or_t<nodeExprp>: // IEEE: part of system_tf_call (can be task
|
||||||
| yD_STIME parenE
|
| yD_STIME parenE
|
||||||
{ $$ = new AstSel{$1, new AstTime{$1, VTimescale{VTimescale::NONE}}, 0, 32}; }
|
{ $$ = new AstSel{$1, new AstTime{$1, VTimescale{VTimescale::NONE}}, 0, 32}; }
|
||||||
| yD_STABLE '(' expr ')' { $$ = new AstStable{$1, $3, nullptr}; }
|
| yD_STABLE '(' expr ')' { $$ = new AstStable{$1, $3, nullptr}; }
|
||||||
| yD_STABLE '(' expr ',' expr ')' { $$ = new AstStable{$1, $3, GRAMMARP->createClockSenTree($1, $5)}; }
|
| yD_STABLE '(' expr ',' expr ')' { $$ = new AstStable{$1, $3, GRAMMARP->createSenTreeChanged($1, $5)}; }
|
||||||
| yD_STABLE_GCLK '(' expr ')' { $$ = new AstStable{$1, $3, GRAMMARP->createGlobalClockSenTree($1)}; }
|
| yD_STABLE_GCLK '(' expr ')' { $$ = new AstStable{$1, $3, GRAMMARP->createGlobalClockSenTree($1)}; }
|
||||||
| yD_TAN '(' expr ')' { $$ = new AstTanD{$1, $3}; }
|
| yD_TAN '(' expr ')' { $$ = new AstTanD{$1, $3}; }
|
||||||
| yD_TANH '(' expr ')' { $$ = new AstTanhD{$1, $3}; }
|
| yD_TANH '(' expr ')' { $$ = new AstTanhD{$1, $3}; }
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
%Error-UNSUPPORTED: t/t_event_control_star.v:19:14: Unsupported: no sense equation (@*)
|
%Error-UNSUPPORTED: t/t_event_control_star.v:19:6: Unsupported: no sense equation (@*)
|
||||||
19 | @* a = c;
|
19 | @* a = c;
|
||||||
| ^
|
| ^
|
||||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||||
%Error: Verilator internal fault, sorry. Suggest trying --debug --gdbbt
|
%Error: Exiting due to
|
||||||
%Error: Command Failed
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
|
||||||
|
test.scenarios('simulator')
|
||||||
|
|
||||||
|
test.compile(verilator_flags2=['--binary', '-Wno-ALWNEVER'])
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2025 by Wilson Snyder.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t;
|
||||||
|
int a;
|
||||||
|
always @* a = 100;
|
||||||
|
initial begin
|
||||||
|
#1;
|
||||||
|
if (a != 0) $stop;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
%Warning-ALWNEVER: t/t_event_control_star_never.v:9:3: 'always @*' will never execute as expression list is empty (no variables read)
|
||||||
|
: ... note: In instance 't'
|
||||||
|
: ... Suggest use 'always_comb'
|
||||||
|
9 | always @* a = 100;
|
||||||
|
| ^~~~~~
|
||||||
|
... For warning description see https://verilator.org/warn/ALWNEVER?v=latest
|
||||||
|
... Use "/* verilator lint_off ALWNEVER */" and lint_on around source to disable this message.
|
||||||
|
%Error: Exiting due to
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
|
||||||
|
test.scenarios('linter')
|
||||||
|
test.top_filename = 't/t_event_control_star_never.v'
|
||||||
|
|
||||||
|
root = ".."
|
||||||
|
|
||||||
|
if not os.path.exists(root + "/.git"):
|
||||||
|
test.skip("Not in a git repository")
|
||||||
|
|
||||||
|
test.lint(verilator_flags2=['--timing'], fails=True, expect_filename=test.golden_filename)
|
||||||
|
|
||||||
|
test.extract(in_filename=test.top_filename,
|
||||||
|
out_filename=root + "/docs/gen/ex_ALWNEVER_faulty.rst",
|
||||||
|
lines="9-9")
|
||||||
|
|
||||||
|
test.extract(in_filename=test.golden_filename,
|
||||||
|
out_filename=root + "/docs/gen/ex_ALWNEVER_msg.rst",
|
||||||
|
lines="1-1")
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -26,7 +26,7 @@ module t (/*AUTOARG*/
|
||||||
sync_nblk <= 1'b1;
|
sync_nblk <= 1'b1;
|
||||||
end
|
end
|
||||||
|
|
||||||
always @* begin
|
always_comb begin
|
||||||
combo_blk = 1'b1;
|
combo_blk = 1'b1;
|
||||||
combo_nblk <= 1'b1;
|
combo_nblk <= 1'b1;
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,7 @@ module t (/*AUTOARG*/
|
||||||
|
|
||||||
reg signed [ 82:0] W0226 ; //=47A4301EE3FB4133EE3DA
|
reg signed [ 82:0] W0226 ; //=47A4301EE3FB4133EE3DA
|
||||||
|
|
||||||
always @* begin : Block144
|
always_comb begin : Block144
|
||||||
W0226 = 83'sh47A4301EE3FB4133EE3DA;
|
W0226 = 83'sh47A4301EE3FB4133EE3DA;
|
||||||
if ((W0226 >>> 8'sh1a) != 83'sh7ffffff1e90c07b8fed04) if (check) $stop;
|
if ((W0226 >>> 8'sh1a) != 83'sh7ffffff1e90c07b8fed04) if (check) $stop;
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue