Add ALWNEVER warning, for `always @*` that never execute (#6291) (#6303)

This commit is contained in:
Wilson Snyder 2025-08-18 12:00:53 -04:00 committed by GitHub
parent 53c59e7ac7
commit c90f9e53b7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 192 additions and 42 deletions

View File

@ -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 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 ALWNEVER warning, for `always @*` that never execute (#6291).
* Add error on class 'function static'.
* Add `-DVERILATOR=1` definition to compiler flags when using verilated.mk.
* Support member-level triggers for virtual interfaces (#5166) (#6148). [Yilou Wang]

View File

@ -0,0 +1,4 @@
.. comment: generated by t_event_control_star_never_bad
.. code-block:: sv
always @* a = 100;

View File

@ -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)

View File

@ -111,6 +111,27 @@ List Of Warnings
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
.. TODO better example

View File

@ -406,6 +406,7 @@ public:
ET_TRUE,
//
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_STATIC, // static variable initializers (runs before 'initial')
ET_INITIAL, // 'initial' statements
@ -423,6 +424,7 @@ public:
true, // ET_TRUE
false, // ET_COMBO
false, // ET_COMBO_STAR
false, // ET_HYBRID
false, // ET_STATIC
false, // ET_INITIAL
@ -443,13 +445,13 @@ public:
}
const char* ascii() const {
static const char* const names[]
= {"CHANGED", "BOTH", "POS", "NEG", "EVENT", "TRUE",
"COMBO", "HYBRID", "STATIC", "INITIAL", "FINAL", "NEVER"};
= {"CHANGED", "BOTH", "POS", "NEG", "EVENT", "TRUE", "COMBO",
"COMBO_STAR", "HYBRID", "STATIC", "INITIAL", "FINAL", "NEVER"};
return names[m_e];
}
const char* verilogKwd() const {
static const char* const names[]
= {"[changed]", "edge", "posedge", "negedge", "[event]", "[true]",
= {"[changed]", "edge", "posedge", "negedge", "[event]", "[true]", "*",
"*", "[hybrid]", "[static]", "[initial]", "[final]", "[never]"};
return names[m_e];
}

View File

@ -1533,7 +1533,10 @@ public:
AstNodeVarRef* varrefp() const { return VN_CAST(sensp(), NodeVarRef); }
//
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 isStatic() const { return edgeType() == VEdgeType::ET_STATIC; }
bool isInitial() const { return edgeType() == VEdgeType::ET_INITIAL; }
@ -1550,6 +1553,10 @@ public:
addSensesp(sensesp);
}
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 dumpJson(std::ostream& str) const override;
bool maybePointedTo() const override VL_MT_SAFE { return true; }

View File

@ -1254,7 +1254,7 @@ bool AstSenTree::hasFinal() const {
bool AstSenTree::hasCombo() const {
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(senp->nextp(), SenItem)) {
if (senp->isCombo()) return true;
if (senp->isComboOrStar()) return true;
}
return false;
}

View File

@ -80,8 +80,10 @@ class ClockVisitor final : public VNVisitor {
AstNodeExpr* senEqnp = nullptr;
for (AstSenItem* senp = nodesp; senp; senp = VN_AS(senp->nextp(), SenItem)) {
UASSERT_OBJ(senp->edgeType() == VEdgeType::ET_TRUE, senp, "Should have been lowered");
AstNodeExpr* const senOnep = senp->sensp()->cloneTree(false);
senEqnp = senEqnp ? new AstOr{senp->fileline(), senEqnp, senOnep} : senOnep;
if (senp->sensp()) {
AstNodeExpr* const senOnep = senp->sensp()->cloneTree(false);
senEqnp = senEqnp ? new AstOr{senp->fileline(), senEqnp, senOnep} : senOnep;
}
}
return senEqnp;
}

View File

@ -1119,7 +1119,8 @@ class DelayedVisitor final : public VNVisitor {
// First gather all senItems
AstSenItem* senItemp = nullptr;
for (AstSenTree* const domainp : m_timingDomains) {
senItemp = AstNode::addNext(senItemp, domainp->sensesp()->cloneTree(true));
if (domainp->sensesp())
senItemp = AstNode::addNext(senItemp, domainp->sensesp()->cloneTree(true));
}
m_timingDomains.clear();
// Add them to all nba targets we gathered in this process

View File

@ -71,6 +71,7 @@ public:
EC_FIRST_WARN, // Just a code so the program knows where to start warnings
//
ALWCOMBORDER, // Always_comb with unordered statements
ALWNEVER, // always will never execute
ASCRANGE, // Ascending bit range vector
ASSIGNDLY, // Assignment delays
ASSIGNIN, // Assigning to input
@ -203,18 +204,18 @@ public:
// Errors
"LIFETIME", "NEEDTIMINGOPT", "NOTIMING", "PORTSHORT", "TASKNSVAR", "UNSUPPORTED",
// Warnings
" EC_FIRST_WARN", "ALWCOMBORDER", "ASCRANGE", "ASSIGNDLY", "ASSIGNIN", "BADSTDPRAGMA",
"BADVLTPRAGMA", "BLKANDNBLK", "BLKLOOPINIT", "BLKSEQ", "BSSPACE", "CASEINCOMPLETE",
"CASEOVERLAP", "CASEWITHX", "CASEX", "CASTCONST", "CDCRSTLOGIC", "CLKDATA", "CMPCONST",
"COLONPLUS", "COMBDLY", "CONSTRAINTIGN", "CONTASSREG", "COVERIGN", "DECLFILENAME",
"DEFOVERRIDE", "DEFPARAM", "DEPRECATED", "ENCAPSULATED", "ENDLABEL", "ENUMITEMWIDTH",
"ENUMVALUE", "EOFNEWLINE", "GENCLK", "GENUNNAMED", "HIERBLOCK", "IFDEPTH",
"IGNOREDRETURN", "IMPERFECTSCH", "IMPLICIT", "IMPLICITSTATIC", "IMPORTSTAR", "IMPURE",
"INCABSPATH", "INFINITELOOP", "INITIALDLY", "INSECURE", "LATCH", "LITENDIAN",
"MINTYPMAXDLY", "MISINDENT", "MODDUP", "MODMISSING", "MULTIDRIVEN", "MULTITOP",
"NEWERSTD", "NOEFFECT", "NOLATCH", "NONSTD", "NULLPORT", "PARAMNODEFAULT",
"PINCONNECTEMPTY", "PINMISSING", "PINNOCONNECT", "PINNOTFOUND", "PKGNODECL",
"PREPROCZERO", "PROCASSINIT", "PROCASSWIRE", "PROFOUTOFDATE", "PROTECTED",
" EC_FIRST_WARN", "ALWCOMBORDER", "ALWNEVER", "ASCRANGE", "ASSIGNDLY", "ASSIGNIN",
"BADSTDPRAGMA", "BADVLTPRAGMA", "BLKANDNBLK", "BLKLOOPINIT", "BLKSEQ", "BSSPACE",
"CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CASTCONST", "CDCRSTLOGIC",
"CLKDATA", "CMPCONST", "COLONPLUS", "COMBDLY", "CONSTRAINTIGN", "CONTASSREG",
"COVERIGN", "DECLFILENAME", "DEFOVERRIDE", "DEFPARAM", "DEPRECATED", "ENCAPSULATED",
"ENDLABEL", "ENUMITEMWIDTH", "ENUMVALUE", "EOFNEWLINE", "GENCLK", "GENUNNAMED",
"HIERBLOCK", "IFDEPTH", "IGNOREDRETURN", "IMPERFECTSCH", "IMPLICIT", "IMPLICITSTATIC",
"IMPORTSTAR", "IMPURE", "INCABSPATH", "INFINITELOOP", "INITIALDLY", "INSECURE",
"LATCH", "LITENDIAN", "MINTYPMAXDLY", "MISINDENT", "MODDUP", "MODMISSING",
"MULTIDRIVEN", "MULTITOP", "NEWERSTD", "NOEFFECT", "NOLATCH", "NONSTD", "NULLPORT",
"PARAMNODEFAULT", "PINCONNECTEMPTY", "PINMISSING", "PINNOCONNECT", "PINNOTFOUND",
"PKGNODECL", "PREPROCZERO", "PROCASSINIT", "PROCASSWIRE", "PROFOUTOFDATE", "PROTECTED",
"PROTOTYPEMIS", "RANDC", "REALCVT", "REDEFMACRO", "RISEFALLDLY", "SELRANGE",
"SHORTREAL", "SIDEEFFECT", "SPECIFYIGN", "SPLITVAR", "STATICVAR", "STMTDLY",
"SYMRSVDWORD", "SYNCASYNCNET", "TICKCOUNT", "TIMESCALEMOD", "UNDRIVEN", "UNOPT",

View File

@ -835,7 +835,7 @@ class LinkParseVisitor final : public VNVisitor {
if (alwaysp && alwaysp->keyword() == VAlwaysKwd::ALWAYS_COMB) {
alwaysp->v3error("Event control statements not legal under always_comb "
"(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);
} else if (alwaysp && !alwaysp->sentreep()) {
// If the event control is at the top, move the sentree to the always

View File

@ -162,9 +162,11 @@ class SchedGraphBuilder final : public VNVisitor {
SchedSenVertex* const vtxp = new SchedSenVertex{m_graphp, senItemp};
// Connect up the variable references
senItemp->sensp()->foreach([&](AstVarRef* refp) {
new V3GraphEdge{m_graphp, getVarVertex(refp->varScopep()), vtxp, 1};
});
if (senItemp->sensp()) {
senItemp->sensp()->foreach([&](AstVarRef* refp) {
new V3GraphEdge{m_graphp, getVarVertex(refp->varScopep()), vtxp, 1};
});
}
// Store back to hash map so we can find it next time
pair.first->second = vtxp;

View File

@ -905,8 +905,11 @@ class TimingControlVisitor final : public VNVisitor {
void visit(AstEventControl* nodep) override {
// Do not allow waiting on local named events, as they get enqueued for clearing, but can
// go out of scope before that happens
if (!nodep->sentreep())
if (!nodep->sentreep()) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: no sense equation (@*)");
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
return;
}
FileLine* const flp = nodep->fileline();
// Relink child statements after the event control
if (nodep->stmtsp()) nodep->addNextHere(nodep->stmtsp()->unlinkFrBackWithNext());

View File

@ -6556,6 +6556,7 @@ class WidthVisitor final : public VNVisitor {
userIterateChildren(nodep, nullptr);
}
void visit(AstSenItem* nodep) override {
if (nodep->isComboStar()) return;
UASSERT_OBJ(nodep->isClocked(), nodep, "Invalid edge");
// Optimize concat/replicate senitems; this has to be done here at the latest, otherwise we
// emit WIDTHCONCAT if there are unsized constants

View File

@ -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 {
switch (nodep->attrType()) {
case VAttrType::FUNC_ARG_PROTO: // FALLTHRU

View File

@ -160,14 +160,17 @@ public:
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}};
}
AstSenTree* createSenTreeDotStar(FileLine* fl) {
return new AstSenTree{fl, new AstSenItem{fl, VEdgeType::ET_COMBO_STAR, nullptr}};
}
AstNodeExpr* createGlobalClockParseRef(FileLine* fl) {
return new AstParseRef{fl, VParseRefExp::PX_TEXT, "__024global_clock", nullptr, nullptr};
}
AstSenTree* createGlobalClockSenTree(FileLine* fl) {
return createClockSenTree(fl, createGlobalClockParseRef(fl));
return createSenTreeChanged(fl, createGlobalClockParseRef(fl));
}
AstNode* createNettype(FileLine* fl, const string& name) {
// 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
// // Verilator only - event_control attached to always
yALWAYS stmtBlock { $$ = new AstAlways{$1, VAlwaysKwd::ALWAYS, nullptr, $2}; }
| yALWAYS_FF stmtBlock { $$ = new AstAlways{$1, VAlwaysKwd::ALWAYS_FF, 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
'@' '(' event_expression ')' { $$ = new AstSenTree{$1, $3}; }
| '@' '(' '*' ')' { $$ = nullptr; }
| '@' '*' { $$ = nullptr; }
| '@' '(' '*' ')' { $$ = GRAMMARP->createSenTreeDotStar($1); }
| '@' '*' { $$ = GRAMMARP->createSenTreeDotStar($1); }
;
event_control<senTreep>: // ==IEEE: event_control
// UNSUP: Needs alignment with IEEE event_control and clocking_event
'@' '(' '*' ')' { $$ = nullptr; }
| '@' '*' { $$ = nullptr; }
'@' '(' '*' ')' { $$ = GRAMMARP->createSenTreeDotStar($1); }
| '@' '*' { $$ = GRAMMARP->createSenTreeDotStar($1); }
// // IEEE: clocking_event
| '@' '(' event_expression ')' { $$ = new AstSenTree{$1, $3}; }
// // 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_CHANGED '(' expr ')' { $$ = new AstLogNot{$1, new AstStable{$1, $3, nullptr}}; }
| 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 ')'
{ $$ = new AstLogNot{$1, new AstStable{$1, $3, GRAMMARP->createGlobalClockSenTree($1)}}; }
| 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_EXP '(' expr ')' { $$ = new AstExpD{$1, $3}; }
| 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_FEOF '(' expr ')' { $$ = new AstFEof{$1, $3}; }
| 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 ',' expr ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_RIGHT, $3, $5}; }
| 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_RTOI '(' expr ')' { $$ = new AstRToIS{$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
{ $$ = new AstSel{$1, new AstTime{$1, VTimescale{VTimescale::NONE}}, 0, 32}; }
| 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_TAN '(' expr ')' { $$ = new AstTanD{$1, $3}; }
| yD_TANH '(' expr ')' { $$ = new AstTanhD{$1, $3}; }

View File

@ -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;
| ^
| ^
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: Verilator internal fault, sorry. Suggest trying --debug --gdbbt
%Error: Command Failed
%Error: Exiting due to

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -26,7 +26,7 @@ module t (/*AUTOARG*/
sync_nblk <= 1'b1;
end
always @* begin
always_comb begin
combo_blk = 1'b1;
combo_nblk <= 1'b1;
end

View File

@ -214,7 +214,7 @@ module t (/*AUTOARG*/
reg signed [ 82:0] W0226 ; //=47A4301EE3FB4133EE3DA
always @* begin : Block144
always_comb begin : Block144
W0226 = 83'sh47A4301EE3FB4133EE3DA;
if ((W0226 >>> 8'sh1a) != 83'sh7ffffff1e90c07b8fed04) if (check) $stop;
end