Add PROCINITASSIGN on initial assignments to process variables (#2481).
This commit is contained in:
parent
38dd9a344e
commit
8b52bd817f
1
Changes
1
Changes
|
@ -14,6 +14,7 @@ Verilator 5.037 devel
|
||||||
**Other:**
|
**Other:**
|
||||||
|
|
||||||
* Add BADVLTPRAGMA on unknown Verilator pragmas (#5945). [Shou-Li Hsu]
|
* Add BADVLTPRAGMA on unknown Verilator pragmas (#5945). [Shou-Li Hsu]
|
||||||
|
* Add PROCINITASSIGN on initial assignments to process variables (#2481). [Niraj Menon]
|
||||||
* Fix filename backslash escapes in C code (#5947).
|
* Fix filename backslash escapes in C code (#5947).
|
||||||
* Fix sign extension of signed compared with unsigned case items (#5968).
|
* Fix sign extension of signed compared with unsigned case items (#5968).
|
||||||
* Fix constant propagation making upper bits Xs (#5969).
|
* Fix constant propagation making upper bits Xs (#5969).
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
.. comment: generated by t_lint_procassinit_bad
|
||||||
|
.. code-block:: sv
|
||||||
|
:linenos:
|
||||||
|
:emphasize-lines: 1,5
|
||||||
|
|
||||||
|
logic flop_out = 1; // <--- Warning
|
||||||
|
|
||||||
|
always @(posedge clk, negedge reset_l) begin
|
||||||
|
if (enable) begin
|
||||||
|
flop_out <= ~in; // <--- Use of initialized
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,15 @@
|
||||||
|
.. comment: generated by t_lint_procassinit_bad
|
||||||
|
.. code-block:: sv
|
||||||
|
:linenos:
|
||||||
|
:emphasize-lines: 5
|
||||||
|
|
||||||
|
logic flop2_out;
|
||||||
|
|
||||||
|
always @(posedge clk, negedge reset_l) begin
|
||||||
|
if (!reset_l) begin
|
||||||
|
flop2_out <= '1; // <--- Added reset init
|
||||||
|
end
|
||||||
|
else if (enable) begin
|
||||||
|
flop2_out <= ~in;
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,12 @@
|
||||||
|
.. comment: generated by t_lint_procassinit_bad
|
||||||
|
.. code-block::
|
||||||
|
|
||||||
|
%Warning-PROCASSINIT: example.v:1:21 Procedural assignment to declaration with initial value: 'flop_out'
|
||||||
|
: ... note: In instance 't'
|
||||||
|
: ... Location of variable initialization
|
||||||
|
26 | logic flop_out = 1;
|
||||||
|
| ^
|
||||||
|
example.v:1:10 ... Location of variable process write
|
||||||
|
: ... Perhaps should initialize instead using a reset in this process
|
||||||
|
30 | flop_out <= ~in;
|
||||||
|
| ^~~~~~~~
|
|
@ -1880,9 +1880,9 @@ Summary:
|
||||||
``-Wwarn-ASSIGNDLY`` ``-Wwarn-BLKSEQ`` ``-Wwarn-DECLFILENAME``
|
``-Wwarn-ASSIGNDLY`` ``-Wwarn-BLKSEQ`` ``-Wwarn-DECLFILENAME``
|
||||||
``-Wwarn-DEFPARAM`` ``-Wwarn-EOFNEWLINE`` ``-Wwarn-GENUNNAMED``
|
``-Wwarn-DEFPARAM`` ``-Wwarn-EOFNEWLINE`` ``-Wwarn-GENUNNAMED``
|
||||||
``-Wwarn-IMPORTSTAR`` ``-Wwarn-INCABSPATH`` ``-Wwarn-PINCONNECTEMPTY``
|
``-Wwarn-IMPORTSTAR`` ``-Wwarn-INCABSPATH`` ``-Wwarn-PINCONNECTEMPTY``
|
||||||
``-Wwarn-PINNOCONNECT`` ``-Wwarn-SYNCASYNCNET`` ``-Wwarn-UNDRIVEN``
|
``-Wwarn-PINNOCONNECT`` ``-Wwarn-PROCASSINIT`` ``-Wwarn-SYNCASYNCNET``
|
||||||
``-Wwarn-UNUSEDGENVAR`` ``-Wwarn-UNUSEDLOOP`` ``-Wwarn-UNUSEDPARAM``
|
``-Wwarn-UNDRIVEN`` ``-Wwarn-UNUSEDGENVAR`` ``-Wwarn-UNUSEDLOOP``
|
||||||
``-Wwarn-UNUSEDSIGNAL`` ``-Wwarn-VARHIDDEN``.
|
``-Wwarn-UNUSEDPARAM`` ``-Wwarn-UNUSEDSIGNAL`` ``-Wwarn-VARHIDDEN``.
|
||||||
|
|
||||||
.. option:: --x-assign <mode>
|
.. option:: --x-assign <mode>
|
||||||
|
|
||||||
|
|
|
@ -1471,6 +1471,35 @@ List Of Warnings
|
||||||
a var/reg must be used as the target of procedural assignments.
|
a var/reg must be used as the target of procedural assignments.
|
||||||
|
|
||||||
|
|
||||||
|
.. option:: PROCINITASSIGN
|
||||||
|
|
||||||
|
Warns that the specified signal is given an initial value where it is
|
||||||
|
declared, and is also driven in an always process. Typically such
|
||||||
|
initial values should instead be set using a reset signal inside the
|
||||||
|
process, to match requirements of hardware synthesis tools.
|
||||||
|
|
||||||
|
Faulty example:
|
||||||
|
|
||||||
|
.. include:: ../../docs/gen/ex_PROCINITASSIGN_faulty.rst
|
||||||
|
|
||||||
|
Results in:
|
||||||
|
|
||||||
|
.. include:: ../../docs/gen/ex_PROCINITASSIGN_msg.rst
|
||||||
|
|
||||||
|
One possible fix, adding a reset to the always:
|
||||||
|
|
||||||
|
.. include:: ../../docs/gen/ex_PROCINITASSIGN_fixed.rst
|
||||||
|
|
||||||
|
Alternatively, use an initial block for the initialization:
|
||||||
|
|
||||||
|
.. code-block:: sv
|
||||||
|
|
||||||
|
initial flop_out = 1; // <--- Fixed
|
||||||
|
|
||||||
|
Disabled by default as this is a code-style warning; it will simulate
|
||||||
|
correctly.
|
||||||
|
|
||||||
|
|
||||||
.. option:: PROFOUTOFDATE
|
.. option:: PROFOUTOFDATE
|
||||||
|
|
||||||
Warns that threads were scheduled using estimated costs, even though
|
Warns that threads were scheduled using estimated costs, even though
|
||||||
|
@ -2164,7 +2193,7 @@ List Of Warnings
|
||||||
|
|
||||||
.. include:: ../../docs/gen/ex_VARHIDDEN_msg.rst
|
.. include:: ../../docs/gen/ex_VARHIDDEN_msg.rst
|
||||||
|
|
||||||
To resolve this, rename the variable to an unique name.
|
To resolve this, rename the inner or outer variable to an unique name.
|
||||||
|
|
||||||
|
|
||||||
.. option:: WAITCONST
|
.. option:: WAITCONST
|
||||||
|
|
|
@ -12,19 +12,26 @@ module secret_impl
|
||||||
input [31:0] a,
|
input [31:0] a,
|
||||||
input [31:0] b,
|
input [31:0] b,
|
||||||
output logic [31:0] x,
|
output logic [31:0] x,
|
||||||
input clk);
|
input clk,
|
||||||
|
input reset_l);
|
||||||
|
|
||||||
logic [31:0] accum_q = 0;
|
logic [31:0] accum_q;
|
||||||
logic [31:0] secret_value = 9;
|
logic [31:0] secret_value;
|
||||||
|
|
||||||
initial $display("[%0t] %m: initialized", $time);
|
initial $display("[%0t] %m: initialized", $time);
|
||||||
|
|
||||||
always @(posedge clk) begin
|
always @(posedge clk) begin
|
||||||
accum_q <= accum_q + a;
|
if (!reset_l) begin
|
||||||
if (accum_q > 10)
|
accum_q <= 0;
|
||||||
x <= b;
|
secret_value <= 9;
|
||||||
else
|
end
|
||||||
x <= a + b + secret_value;
|
else begin
|
||||||
|
accum_q <= accum_q + a;
|
||||||
|
if (accum_q > 10)
|
||||||
|
x <= b;
|
||||||
|
else
|
||||||
|
x <= a + b + secret_value;
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
@ -8,26 +8,36 @@
|
||||||
|
|
||||||
module top (input clk);
|
module top (input clk);
|
||||||
|
|
||||||
integer cyc = 0;
|
int cyc;
|
||||||
logic [31:0] a = 0;
|
logic reset_l;
|
||||||
logic [31:0] b = 0;
|
logic [31:0] a;
|
||||||
|
logic [31:0] b;
|
||||||
logic [31:0] x;
|
logic [31:0] x;
|
||||||
|
|
||||||
verilated_secret secret (.a, .b, .x, .clk);
|
verilated_secret secret (.a, .b, .x, .clk, .reset_l);
|
||||||
|
|
||||||
always @(posedge clk) begin
|
always @(posedge clk) begin
|
||||||
$display("[%0t] cyc=%0d a=%0d b=%0d x=%0d", $time, cyc, a, b, x);
|
$display("[%0t] cyc=%0d a=%0d b=%0d x=%0d", $time, cyc, a, b, x);
|
||||||
cyc <= cyc + 1;
|
cyc <= cyc + 1;
|
||||||
if (cyc == 0) begin
|
if (cyc == 0) begin
|
||||||
|
reset_l <= 0;
|
||||||
|
a <= 0;
|
||||||
|
b <= 0;
|
||||||
|
end
|
||||||
|
else if (cyc == 1) begin
|
||||||
|
reset_l <= 1;
|
||||||
a <= 5;
|
a <= 5;
|
||||||
b <= 7;
|
b <= 7;
|
||||||
end else if (cyc == 1) begin
|
end
|
||||||
|
else if (cyc == 2) begin
|
||||||
a <= 6;
|
a <= 6;
|
||||||
b <= 2;
|
b <= 2;
|
||||||
end else if (cyc == 2) begin
|
end
|
||||||
|
else if (cyc == 3) begin
|
||||||
a <= 1;
|
a <= 1;
|
||||||
b <= 9;
|
b <= 9;
|
||||||
end else if (cyc > 3) begin
|
end
|
||||||
|
else if (cyc > 4) begin
|
||||||
$display("Done");
|
$display("Done");
|
||||||
$finish;
|
$finish;
|
||||||
end
|
end
|
||||||
|
|
|
@ -129,6 +129,7 @@ public:
|
||||||
PINNOTFOUND, // instance port name not found in it's module
|
PINNOTFOUND, // instance port name not found in it's module
|
||||||
PKGNODECL, // Error: Package/class needs to be predeclared
|
PKGNODECL, // Error: Package/class needs to be predeclared
|
||||||
PREPROCZERO, // Preprocessor expression with zero
|
PREPROCZERO, // Preprocessor expression with zero
|
||||||
|
PROCASSINIT, // Procedural assignment versus initialization
|
||||||
PROCASSWIRE, // Procedural assignment on wire
|
PROCASSWIRE, // Procedural assignment on wire
|
||||||
PROFOUTOFDATE, // Profile data out of date
|
PROFOUTOFDATE, // Profile data out of date
|
||||||
PROTECTED, // detected `pragma protected
|
PROTECTED, // detected `pragma protected
|
||||||
|
@ -206,7 +207,7 @@ public:
|
||||||
"INCABSPATH", "INFINITELOOP", "INITIALDLY", "INSECURE",
|
"INCABSPATH", "INFINITELOOP", "INITIALDLY", "INSECURE",
|
||||||
"LATCH", "LITENDIAN", "MINTYPMAXDLY", "MISINDENT", "MODDUP",
|
"LATCH", "LITENDIAN", "MINTYPMAXDLY", "MISINDENT", "MODDUP",
|
||||||
"MULTIDRIVEN", "MULTITOP", "NEWERSTD", "NOLATCH", "NONSTD", "NULLPORT", "PINCONNECTEMPTY",
|
"MULTIDRIVEN", "MULTITOP", "NEWERSTD", "NOLATCH", "NONSTD", "NULLPORT", "PINCONNECTEMPTY",
|
||||||
"PINMISSING", "PINNOCONNECT", "PINNOTFOUND", "PKGNODECL", "PREPROCZERO", "PROCASSWIRE",
|
"PINMISSING", "PINNOCONNECT", "PINNOTFOUND", "PKGNODECL", "PREPROCZERO", "PROCASSINIT", "PROCASSWIRE",
|
||||||
"PROFOUTOFDATE", "PROTECTED", "RANDC", "REALCVT", "REDEFMACRO", "RISEFALLDLY",
|
"PROFOUTOFDATE", "PROTECTED", "RANDC", "REALCVT", "REDEFMACRO", "RISEFALLDLY",
|
||||||
"SELRANGE", "SHORTREAL", "SIDEEFFECT", "SPLITVAR",
|
"SELRANGE", "SHORTREAL", "SIDEEFFECT", "SPLITVAR",
|
||||||
"STATICVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET",
|
"STATICVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET",
|
||||||
|
@ -259,9 +260,10 @@ public:
|
||||||
return (m_e == ASSIGNDLY // More than style, but for backward compatibility
|
return (m_e == ASSIGNDLY // More than style, but for backward compatibility
|
||||||
|| m_e == BLKSEQ || m_e == DECLFILENAME || m_e == DEFPARAM || m_e == EOFNEWLINE
|
|| m_e == BLKSEQ || m_e == DECLFILENAME || m_e == DEFPARAM || m_e == EOFNEWLINE
|
||||||
|| m_e == GENUNNAMED || m_e == IMPORTSTAR || m_e == INCABSPATH
|
|| m_e == GENUNNAMED || m_e == IMPORTSTAR || m_e == INCABSPATH
|
||||||
|| m_e == PINCONNECTEMPTY || m_e == PINNOCONNECT || m_e == SYNCASYNCNET
|
|| m_e == PINCONNECTEMPTY || m_e == PINNOCONNECT || m_e == PROCASSINIT
|
||||||
|| m_e == UNDRIVEN || m_e == UNUSEDGENVAR || m_e == UNUSEDLOOP
|
|| m_e == SYNCASYNCNET || m_e == UNDRIVEN || m_e == UNUSEDGENVAR
|
||||||
|| m_e == UNUSEDPARAM || m_e == UNUSEDSIGNAL || m_e == VARHIDDEN);
|
|| m_e == UNUSEDLOOP || m_e == UNUSEDPARAM || m_e == UNUSEDSIGNAL
|
||||||
|
|| m_e == VARHIDDEN);
|
||||||
}
|
}
|
||||||
// Warnings that are unused only
|
// Warnings that are unused only
|
||||||
bool unusedError() const VL_MT_SAFE {
|
bool unusedError() const VL_MT_SAFE {
|
||||||
|
|
|
@ -46,6 +46,8 @@ class UndrivenVarEntry final {
|
||||||
const FileLine* m_alwCombFileLinep = nullptr; // File line of always_comb of var if driven
|
const FileLine* m_alwCombFileLinep = nullptr; // File line of always_comb of var if driven
|
||||||
// within always_comb, else nullptr
|
// within always_comb, else nullptr
|
||||||
const AstNodeVarRef* m_nodep = nullptr; // varref if driven, else nullptr
|
const AstNodeVarRef* m_nodep = nullptr; // varref if driven, else nullptr
|
||||||
|
const AstNode* m_initStaticp = nullptr; // varref if in InitialStatic driven
|
||||||
|
const AstNode* m_procWritep = nullptr; // varref if written in process
|
||||||
const FileLine* m_nodeFileLinep = nullptr; // File line of varref if driven, else nullptr
|
const FileLine* m_nodeFileLinep = nullptr; // File line of varref if driven, else nullptr
|
||||||
bool m_underGen = false; // Under a generate
|
bool m_underGen = false; // Under a generate
|
||||||
|
|
||||||
|
@ -129,6 +131,11 @@ public:
|
||||||
m_alwCombp = alwCombp;
|
m_alwCombp = alwCombp;
|
||||||
m_alwCombFileLinep = fileLinep;
|
m_alwCombFileLinep = fileLinep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AstNode* initStaticp() const { return m_initStaticp; }
|
||||||
|
void initStaticp(const AstNode* nodep) { m_initStaticp = nodep; }
|
||||||
|
const AstNode* procWritep() const { return m_procWritep; }
|
||||||
|
void procWritep(const AstNode* nodep) { m_procWritep = nodep; }
|
||||||
void underGenerate() { m_underGen = true; }
|
void underGenerate() { m_underGen = true; }
|
||||||
bool isUnderGen() const { return m_underGen; }
|
bool isUnderGen() const { return m_underGen; }
|
||||||
bool isDrivenWhole() const { return m_wholeFlags[FLAG_DRIVEN]; }
|
bool isDrivenWhole() const { return m_wholeFlags[FLAG_DRIVEN]; }
|
||||||
|
@ -172,6 +179,18 @@ public:
|
||||||
// Combine bits into overall state
|
// Combine bits into overall state
|
||||||
AstVar* const nodep = m_varp;
|
AstVar* const nodep = m_varp;
|
||||||
|
|
||||||
|
if (initStaticp() && procWritep() && !nodep->isClassMember() && !nodep->isFuncLocal()) {
|
||||||
|
initStaticp()->v3warn(
|
||||||
|
PROCASSINIT,
|
||||||
|
"Procedural assignment to declaration with initial value: "
|
||||||
|
<< nodep->prettyNameQ() << '\n'
|
||||||
|
<< initStaticp()->warnMore() << "... Location of variable initialization\n"
|
||||||
|
<< initStaticp()->warnContextPrimary() << '\n'
|
||||||
|
<< procWritep()->warnOther() << "... Location of variable process write\n"
|
||||||
|
<< procWritep()->warnMore()
|
||||||
|
<< "... Perhaps should initialize instead using a reset in this process\n"
|
||||||
|
<< procWritep()->warnContextSecondary());
|
||||||
|
}
|
||||||
if (nodep->isGenVar()) { // Genvar
|
if (nodep->isGenVar()) { // Genvar
|
||||||
if (!nodep->isIfaceRef() && !nodep->isUsedParam() && !unusedMatch(nodep)) {
|
if (!nodep->isIfaceRef() && !nodep->isUsedParam() && !unusedMatch(nodep)) {
|
||||||
nodep->v3warn(UNUSEDGENVAR, "Genvar is not used: " << nodep->prettyNameQ());
|
nodep->v3warn(UNUSEDGENVAR, "Genvar is not used: " << nodep->prettyNameQ());
|
||||||
|
@ -277,10 +296,12 @@ class UndrivenVisitor final : public VNVisitorConst {
|
||||||
std::array<std::vector<UndrivenVarEntry*>, 3> m_entryps; // Nodes to delete when finished
|
std::array<std::vector<UndrivenVarEntry*>, 3> m_entryps; // Nodes to delete when finished
|
||||||
bool m_inBBox = false; // In black box; mark as driven+used
|
bool m_inBBox = false; // In black box; mark as driven+used
|
||||||
bool m_inContAssign = false; // In continuous assignment
|
bool m_inContAssign = false; // In continuous assignment
|
||||||
|
bool m_inInitialStatic = false; // In InitialStatic
|
||||||
bool m_inProcAssign = false; // In procedural assignment
|
bool m_inProcAssign = false; // In procedural assignment
|
||||||
bool m_inFTaskRef = false; // In function or task call
|
bool m_inFTaskRef = false; // In function or task call
|
||||||
bool m_inInoutOrRefPin = false; // Connected to pin that is inout
|
bool m_inInoutOrRefPin = false; // Connected to pin that is inout
|
||||||
const AstNodeFTask* m_taskp = nullptr; // Current task
|
const AstNodeFTask* m_taskp = nullptr; // Current task
|
||||||
|
const AstAlways* m_alwaysp = nullptr; // Current always of either type
|
||||||
const AstAlways* m_alwaysCombp = nullptr; // Current always if combo, otherwise nullptr
|
const AstAlways* m_alwaysCombp = nullptr; // Current always if combo, otherwise nullptr
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
|
@ -384,9 +405,8 @@ class UndrivenVisitor final : public VNVisitorConst {
|
||||||
nodep->v3warn(PROCASSWIRE, "Procedural assignment to wire, perhaps intended var"
|
nodep->v3warn(PROCASSWIRE, "Procedural assignment to wire, perhaps intended var"
|
||||||
<< " (IEEE 1800-2023 6.5): "
|
<< " (IEEE 1800-2023 6.5): "
|
||||||
<< nodep->prettyNameQ());
|
<< nodep->prettyNameQ());
|
||||||
}
|
} else if (m_inContAssign && !nodep->varp()->varType().isContAssignable()
|
||||||
if (m_inContAssign && !nodep->varp()->varType().isContAssignable()
|
&& !nodep->fileline()->language().systemVerilog()) {
|
||||||
&& !nodep->fileline()->language().systemVerilog()) {
|
|
||||||
nodep->v3warn(CONTASSREG,
|
nodep->v3warn(CONTASSREG,
|
||||||
"Continuous assignment to reg, perhaps intended wire"
|
"Continuous assignment to reg, perhaps intended wire"
|
||||||
<< " (IEEE 1364-2005 6.1; Verilog only, legal in SV): "
|
<< " (IEEE 1364-2005 6.1; Verilog only, legal in SV): "
|
||||||
|
@ -448,6 +468,13 @@ class UndrivenVisitor final : public VNVisitorConst {
|
||||||
if (m_alwaysCombp)
|
if (m_alwaysCombp)
|
||||||
entryp->drivenAlwaysCombWhole(m_alwaysCombp, m_alwaysCombp->fileline());
|
entryp->drivenAlwaysCombWhole(m_alwaysCombp, m_alwaysCombp->fileline());
|
||||||
}
|
}
|
||||||
|
if (nodep->access().isWriteOrRW()) {
|
||||||
|
UINFO(1, "ww is=" << m_inInitialStatic << " ipa=" << m_inProcAssign << " " << nodep
|
||||||
|
<< endl);
|
||||||
|
if (m_inInitialStatic && !entryp->initStaticp()) entryp->initStaticp(nodep);
|
||||||
|
if (m_alwaysp && m_inProcAssign && !entryp->procWritep())
|
||||||
|
entryp->procWritep(nodep);
|
||||||
|
}
|
||||||
if (m_inBBox || nodep->access().isReadOrRW()
|
if (m_inBBox || nodep->access().isReadOrRW()
|
||||||
|| fdrv
|
|| fdrv
|
||||||
// Inouts have only isWrite set, as we don't have more
|
// Inouts have only isWrite set, as we don't have more
|
||||||
|
@ -480,9 +507,16 @@ class UndrivenVisitor final : public VNVisitorConst {
|
||||||
m_inContAssign = true;
|
m_inContAssign = true;
|
||||||
iterateChildrenConst(nodep);
|
iterateChildrenConst(nodep);
|
||||||
}
|
}
|
||||||
|
void visit(AstInitialStatic* nodep) override {
|
||||||
|
VL_RESTORER(m_inInitialStatic);
|
||||||
|
m_inInitialStatic = true;
|
||||||
|
iterateChildrenConst(nodep);
|
||||||
|
}
|
||||||
void visit(AstAlways* nodep) override {
|
void visit(AstAlways* nodep) override {
|
||||||
|
VL_RESTORER(m_alwaysp);
|
||||||
VL_RESTORER(m_alwaysCombp);
|
VL_RESTORER(m_alwaysCombp);
|
||||||
AstNode::user2ClearTree();
|
AstNode::user2ClearTree();
|
||||||
|
m_alwaysp = nodep;
|
||||||
if (nodep->keyword() == VAlwaysKwd::ALWAYS_COMB) {
|
if (nodep->keyword() == VAlwaysKwd::ALWAYS_COMB) {
|
||||||
UINFO(9, " " << nodep << endl);
|
UINFO(9, " " << nodep << endl);
|
||||||
m_alwaysCombp = nodep;
|
m_alwaysCombp = nodep;
|
||||||
|
|
|
@ -26,7 +26,7 @@ module t(/*AUTOARG*/
|
||||||
);
|
);
|
||||||
input clk;
|
input clk;
|
||||||
|
|
||||||
integer cyc = 0;
|
int cyc;
|
||||||
reg [63:0] crc;
|
reg [63:0] crc;
|
||||||
reg [63:0] sum;
|
reg [63:0] sum;
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ module t (/*AUTOARG*/
|
||||||
);
|
);
|
||||||
|
|
||||||
input clk;
|
input clk;
|
||||||
integer cyc=1;
|
int cyc;
|
||||||
|
|
||||||
reg [31:0] dly0;
|
reg [31:0] dly0;
|
||||||
wire [31:0] dly1;
|
wire [31:0] dly1;
|
||||||
|
|
|
@ -12,8 +12,10 @@ module t_format_wide_decimal(/*AUTOARG*/
|
||||||
);
|
);
|
||||||
input clk;
|
input clk;
|
||||||
|
|
||||||
int cycle = 0;
|
int cycle;
|
||||||
bit [1023:0] x = '1;
|
bit [1023:0] x;
|
||||||
|
|
||||||
|
initial x = '1;
|
||||||
|
|
||||||
always @(posedge clk) begin
|
always @(posedge clk) begin
|
||||||
if (cycle == 0) begin
|
if (cycle == 0) begin
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
%Warning-PROCASSINIT: t/t_lint_procassinit_bad.v:26:21: Procedural assignment to declaration with initial value: 'flop_out'
|
||||||
|
: ... note: In instance 't'
|
||||||
|
: ... Location of variable initialization
|
||||||
|
26 | logic flop_out = 1;
|
||||||
|
| ^
|
||||||
|
t/t_lint_procassinit_bad.v:30:10: ... Location of variable process write
|
||||||
|
: ... Perhaps should initialize instead using a reset in this process
|
||||||
|
30 | flop_out <= ~in;
|
||||||
|
| ^~~~~~~~
|
||||||
|
... For warning description see https://verilator.org/warn/PROCASSINIT?v=latest
|
||||||
|
... Use "/* verilator lint_off PROCASSINIT */" and lint_on around source to disable this message.
|
||||||
|
%Warning-PROCASSINIT: t/t_lint_procassinit_bad.v:48:21: Procedural assignment to declaration with initial value: 'bad_comb'
|
||||||
|
: ... note: In instance 't'
|
||||||
|
: ... Location of variable initialization
|
||||||
|
48 | logic bad_comb = 1;
|
||||||
|
| ^
|
||||||
|
t/t_lint_procassinit_bad.v:51:7: ... Location of variable process write
|
||||||
|
: ... Perhaps should initialize instead using a reset in this process
|
||||||
|
51 | bad_comb = ok2;
|
||||||
|
| ^~~~~~~~
|
||||||
|
%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('vlt')
|
||||||
|
|
||||||
|
test.lint(verilator_flags2=['-Wall -Wno-DECLFILENAME'],
|
||||||
|
fails=True,
|
||||||
|
expect_filename=test.golden_filename)
|
||||||
|
|
||||||
|
test.extract(in_filename=test.top_filename,
|
||||||
|
out_filename="../docs/gen/ex_PROCASSINIT_faulty.rst",
|
||||||
|
lines="26-32")
|
||||||
|
|
||||||
|
test.extract(in_filename=test.top_filename,
|
||||||
|
out_filename="../docs/gen/ex_PROCASSINIT_fixed.rst",
|
||||||
|
lines="36-45")
|
||||||
|
|
||||||
|
test.extract(in_filename=test.golden_filename,
|
||||||
|
out_filename="../docs/gen/ex_PROCASSINIT_msg.rst",
|
||||||
|
lines="1-9")
|
||||||
|
|
||||||
|
test.passes()
|
|
@ -0,0 +1,56 @@
|
||||||
|
// 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(/*AUTOARG*/
|
||||||
|
// Inputs
|
||||||
|
clk, reset_l, in, enable
|
||||||
|
);
|
||||||
|
input clk;
|
||||||
|
input reset_l;
|
||||||
|
input in;
|
||||||
|
input enable;
|
||||||
|
|
||||||
|
logic ok1 = 1;
|
||||||
|
logic ok2 = 1;
|
||||||
|
logic ok3 = ok2;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
ok1 = 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
//== Faulty example
|
||||||
|
|
||||||
|
logic flop_out = 1; // <--- Warning
|
||||||
|
|
||||||
|
always @(posedge clk, negedge reset_l) begin
|
||||||
|
if (enable) begin
|
||||||
|
flop_out <= ~in; // <--- Use of initialized
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
//== Fixed example
|
||||||
|
|
||||||
|
logic flop2_out;
|
||||||
|
|
||||||
|
always @(posedge clk, negedge reset_l) begin
|
||||||
|
if (!reset_l) begin
|
||||||
|
flop2_out <= '1; // <--- Added reset init
|
||||||
|
end
|
||||||
|
else if (enable) begin
|
||||||
|
flop2_out <= ~in;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// Combo version
|
||||||
|
logic bad_comb = 1; // but this is not fine
|
||||||
|
|
||||||
|
always @* begin
|
||||||
|
bad_comb = ok2;
|
||||||
|
end
|
||||||
|
|
||||||
|
wire _unused_ok = &{1'b0, flop_out, flop2_out, bad_comb, ok1, ok2, ok3};
|
||||||
|
|
||||||
|
endmodule
|
|
@ -28,10 +28,10 @@ endmodule
|
||||||
|
|
||||||
// module unused - no warning for any of statements inside
|
// module unused - no warning for any of statements inside
|
||||||
module unused(input clk);
|
module unused(input clk);
|
||||||
reg unused_variable_while = 0;
|
bit unused_variable_while;
|
||||||
reg unused_variable_do_while = 0;
|
bit unused_variable_do_while;
|
||||||
reg unused_variable_for = 0;
|
bit unused_variable_for;
|
||||||
const logic always_false = 0;
|
const bit always_false = 0;
|
||||||
|
|
||||||
always @(posedge clk) begin
|
always @(posedge clk) begin
|
||||||
while(unused_variable_while) begin
|
while(unused_variable_while) begin
|
||||||
|
@ -259,7 +259,7 @@ module clock_init_race(input clk, input reset_l);
|
||||||
logic m_3_reset = reset_l;
|
logic m_3_reset = reset_l;
|
||||||
assign m_2_clock = clk;
|
assign m_2_clock = clk;
|
||||||
assign m_3_clock = clk;
|
assign m_3_clock = clk;
|
||||||
int m_3_counter = 0;
|
int m_3_counter;
|
||||||
initial begin
|
initial begin
|
||||||
$write("*-* START TEST *-*\n");
|
$write("*-* START TEST *-*\n");
|
||||||
end
|
end
|
||||||
|
@ -271,7 +271,7 @@ module clock_init_race(input clk, input reset_l);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
reg m_2_ticked = 1'b0;
|
bit m_2_ticked;
|
||||||
always @(posedge m_2_clock) if (!m_2_reset) begin
|
always @(posedge m_2_clock) if (!m_2_reset) begin
|
||||||
m_2_ticked = 1'b1;
|
m_2_ticked = 1'b1;
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,37 +1,37 @@
|
||||||
%Warning-STMTDLY: t/t_net_delay.v:14:11: Ignoring delay on this statement due to --no-timing
|
%Warning-STMTDLY: t/t_net_delay.v:16:11: Ignoring delay on this statement due to --no-timing
|
||||||
: ... note: In instance 't'
|
: ... note: In instance 't'
|
||||||
14 | always #2 clk = ~clk;
|
16 | always #2 clk = ~clk;
|
||||||
| ^
|
| ^
|
||||||
... For warning description see https://verilator.org/warn/STMTDLY?v=latest
|
... For warning description see https://verilator.org/warn/STMTDLY?v=latest
|
||||||
... Use "/* verilator lint_off STMTDLY */" and lint_on around source to disable this message.
|
... Use "/* verilator lint_off STMTDLY */" and lint_on around source to disable this message.
|
||||||
%Warning-STMTDLY: t/t_net_delay.v:20:14: Ignoring delay on this statement due to --no-timing
|
%Warning-STMTDLY: t/t_net_delay.v:22:14: Ignoring delay on this statement due to --no-timing
|
||||||
: ... note: In instance 't'
|
: ... note: In instance 't'
|
||||||
20 | wire[3:0] #3 val1;
|
22 | wire[3:0] #3 val1;
|
||||||
| ^
|
| ^
|
||||||
%Warning-STMTDLY: t/t_net_delay.v:21:14: Ignoring delay on this statement due to --no-timing
|
|
||||||
: ... note: In instance 't'
|
|
||||||
21 | wire[3:0] #3 val2;
|
|
||||||
| ^
|
|
||||||
%Warning-ASSIGNDLY: t/t_net_delay.v:22:14: Ignoring timing control on this assignment/primitive due to --no-timing
|
|
||||||
: ... note: In instance 't'
|
|
||||||
22 | wire[3:0] #5 val3 = cyc;
|
|
||||||
| ^
|
|
||||||
... For warning description see https://verilator.org/warn/ASSIGNDLY?v=latest
|
|
||||||
... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message.
|
|
||||||
%Warning-STMTDLY: t/t_net_delay.v:23:14: Ignoring delay on this statement due to --no-timing
|
%Warning-STMTDLY: t/t_net_delay.v:23:14: Ignoring delay on this statement due to --no-timing
|
||||||
: ... note: In instance 't'
|
: ... note: In instance 't'
|
||||||
23 | wire[3:0] #5 val4;
|
23 | wire[3:0] #3 val2;
|
||||||
| ^
|
| ^
|
||||||
%Warning-ASSIGNDLY: t/t_net_delay.v:24:14: Ignoring timing control on this assignment/primitive due to --no-timing
|
%Warning-ASSIGNDLY: t/t_net_delay.v:24:14: Ignoring timing control on this assignment/primitive due to --no-timing
|
||||||
: ... note: In instance 't'
|
: ... note: In instance 't'
|
||||||
24 | wire[3:0] #3 val5 = x, val6 = cyc;
|
24 | wire[3:0] #5 val3 = cyc;
|
||||||
| ^
|
| ^
|
||||||
%Warning-ASSIGNDLY: t/t_net_delay.v:27:11: Ignoring timing control on this assignment/primitive due to --no-timing
|
... For warning description see https://verilator.org/warn/ASSIGNDLY?v=latest
|
||||||
: ... note: In instance 't'
|
... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message.
|
||||||
27 | assign #3 val2 = cyc;
|
%Warning-STMTDLY: t/t_net_delay.v:25:14: Ignoring delay on this statement due to --no-timing
|
||||||
| ^
|
|
||||||
%Warning-STMTDLY: t/t_net_delay.v:39:26: Ignoring delay on this statement due to --no-timing
|
|
||||||
: ... note: In instance 't'
|
: ... note: In instance 't'
|
||||||
39 | always @(posedge clk) #1 begin
|
25 | wire[3:0] #5 val4;
|
||||||
|
| ^
|
||||||
|
%Warning-ASSIGNDLY: t/t_net_delay.v:26:14: Ignoring timing control on this assignment/primitive due to --no-timing
|
||||||
|
: ... note: In instance 't'
|
||||||
|
26 | wire[3:0] #3 val5 = x, val6 = cyc;
|
||||||
|
| ^
|
||||||
|
%Warning-ASSIGNDLY: t/t_net_delay.v:29:11: Ignoring timing control on this assignment/primitive due to --no-timing
|
||||||
|
: ... note: In instance 't'
|
||||||
|
29 | assign #3 val2 = cyc;
|
||||||
|
| ^
|
||||||
|
%Warning-STMTDLY: t/t_net_delay.v:41:26: Ignoring delay on this statement due to --no-timing
|
||||||
|
: ... note: In instance 't'
|
||||||
|
41 | always @(posedge clk) #1 begin
|
||||||
| ^
|
| ^
|
||||||
%Error: Exiting due to
|
%Error: Exiting due to
|
||||||
|
|
|
@ -9,14 +9,16 @@
|
||||||
|
|
||||||
module t;
|
module t;
|
||||||
// verilator lint_off UNOPTFLAT
|
// verilator lint_off UNOPTFLAT
|
||||||
|
// verilator lint_off PROCASSINIT
|
||||||
logic clk = 0;
|
logic clk = 0;
|
||||||
// verilator lint_on UNOPTFLAT
|
// verilator lint_on UNOPTFLAT
|
||||||
|
// verilator lint_on PROCASSINIT
|
||||||
always #2 clk = ~clk;
|
always #2 clk = ~clk;
|
||||||
|
|
||||||
// verilator lint_off UNDRIVEN
|
// verilator lint_off UNDRIVEN
|
||||||
wire[3:0] x;
|
wire[3:0] x;
|
||||||
// verilator lint_on UNDRIVEN
|
// verilator lint_on UNDRIVEN
|
||||||
reg[3:0] cyc = 0;
|
bit [3:0] cyc;
|
||||||
wire[3:0] #3 val1;
|
wire[3:0] #3 val1;
|
||||||
wire[3:0] #3 val2;
|
wire[3:0] #3 val2;
|
||||||
wire[3:0] #5 val3 = cyc;
|
wire[3:0] #5 val3 = cyc;
|
||||||
|
|
Loading…
Reference in New Issue