parent
18e06b1e7d
commit
cf9334f2c1
2
Changes
2
Changes
|
|
@ -217,7 +217,7 @@ Verilator 5.048 2026-04-26
|
|||
* Fix std::randomize inside {typedef array} internal error (#7481). [Yilou Wang]
|
||||
* Fix module parameters not re-evaluated upon instantiation (#7463) (#7477). [em2machine]
|
||||
* Fix infinite recursion with VERILATOR_BIN (#7496) (#7497).
|
||||
|
||||
* Add error on mixed declaration initialization with continuous assignment (#7352). [Zhi QU]
|
||||
|
||||
Verilator 5.046 2026-02-28
|
||||
==========================
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ Chuxuan Wang
|
|||
Chykon
|
||||
Congcong Cai
|
||||
Conor McCullough
|
||||
Cookie
|
||||
Dan Ruelas-Petrisko
|
||||
Daniel Bates
|
||||
Danny Oler
|
||||
|
|
|
|||
|
|
@ -521,6 +521,48 @@ List Of Warnings
|
|||
Suppressing this error will suppress the error message check; it will
|
||||
simulate as if the ``const`` as not present.
|
||||
|
||||
.. option:: CONTASSINIT
|
||||
|
||||
Error that a continuous assignment is setting a variable with an initial
|
||||
value. Use either the initial value or the continuous assignment, but not
|
||||
both.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: sv
|
||||
:emphasize-lines: 2,4
|
||||
|
||||
module t;
|
||||
logic b = 1'b0;
|
||||
logic a;
|
||||
assign b = a; //<--- Error
|
||||
endmodule
|
||||
|
||||
Results in:
|
||||
|
||||
.. code-block::
|
||||
|
||||
%Error-CONTASSINIT: example.sv:4:10: Continuous assignment to variable with initial value: 'b'
|
||||
: ... note: In instance 't'
|
||||
: ... Location of variable initialization
|
||||
2 | logic b = 1'b0;
|
||||
| ^
|
||||
example.sv:4:10: ... Location of continuous assignment
|
||||
4 | assign b = a;
|
||||
| ^
|
||||
%Error: Exiting due to 1 error(s)
|
||||
|
||||
The following is legal because the driven variable does not have a declaration
|
||||
initializer:
|
||||
|
||||
.. code-block:: sv
|
||||
|
||||
module t;
|
||||
logic b;
|
||||
logic a = 1'b0;
|
||||
assign b = a;
|
||||
endmodule
|
||||
|
||||
|
||||
.. option:: CONTASSREG
|
||||
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ public:
|
|||
I_TIMING, // Enable timing from /*verilator timing_on/off*/
|
||||
I_TRACING, // Tracing is on/off from /*verilator tracing_on/off*/
|
||||
// Error codes:
|
||||
E_CONTASSINIT, // Error: Continuous assignment versus initialization
|
||||
E_CONSTWRITTEN, // Error: Const variable being written.
|
||||
E_LIFETIME, // Error: Reference to a variable might outlive the variable.
|
||||
E_NEEDTIMINGOPT, // Error: --timing/--no-timing option not specified
|
||||
|
|
@ -217,8 +218,8 @@ public:
|
|||
" I_CELLDEFINE", " I_COVERAGE", " I_DEF_NETTYPE_WIRE", " I_LINT", " I_STYLE",
|
||||
" I_TIMING", " I_TRACING",
|
||||
// Errors
|
||||
"CONSTWRITTEN", "LIFETIME", "NEEDTIMINGOPT", "NOTIMING", "PORTSHORT", "TASKNSVAR",
|
||||
"UNSUPPORTED",
|
||||
"CONTASSINIT", "CONSTWRITTEN", "LIFETIME", "NEEDTIMINGOPT", "NOTIMING", "PORTSHORT",
|
||||
"TASKNSVAR", "UNSUPPORTED",
|
||||
// Warnings
|
||||
" EC_FIRST_WARN", "ALWCOMBORDER", "ALWNEVER", "ASCRANGE", "ASSIGNDLY", "ASSIGNEQEXPR",
|
||||
"ASSIGNIN", "BADSTDPRAGMA", "BADVLTPRAGMA", "BLKANDNBLK", "BLKLOOPINIT", "BLKSEQ",
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ class UndrivenVarEntry final {
|
|||
// within always_comb, 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_initialp = nullptr; // varref if driven in an explicit initial block
|
||||
const AstNode* m_contAssignp = nullptr; // varref if in continuous assignment driven
|
||||
const AstNode* m_procWritep = nullptr; // varref if written in process
|
||||
const FileLine* m_nodeFileLinep = nullptr; // File line of varref if driven, else nullptr
|
||||
bool m_underGen = false; // Under a generate
|
||||
|
|
@ -139,6 +141,10 @@ public:
|
|||
|
||||
const AstNode* initStaticp() const { return m_initStaticp; }
|
||||
void initStaticp(const AstNode* nodep) { m_initStaticp = nodep; }
|
||||
const AstNode* initialp() const { return m_initialp; }
|
||||
void initialp(const AstNode* nodep) { m_initialp = nodep; }
|
||||
const AstNode* contAssignp() const { return m_contAssignp; }
|
||||
void contAssignp(const AstNode* nodep) { m_contAssignp = nodep; }
|
||||
const AstNode* procWritep() const { return m_procWritep; }
|
||||
void procWritep(const AstNode* nodep) { m_procWritep = nodep; }
|
||||
void underGenerate() { m_underGen = true; }
|
||||
|
|
@ -198,6 +204,17 @@ public:
|
|||
<< "... Perhaps should initialize instead using a reset in this process\n"
|
||||
<< procWritep()->warnContextSecondary());
|
||||
}
|
||||
const AstNode* const initp = nodep->hasUserInit() ? initStaticp() : initialp();
|
||||
if (initp && contAssignp() && !nodep->isClassMember() && !nodep->isFuncLocal()) {
|
||||
initp->v3warn(
|
||||
E_CONTASSINIT,
|
||||
"Continuous assignment to variable with initial value: " << nodep->prettyNameQ()
|
||||
<< '\n'
|
||||
<< initp->warnMore() << "... Location of variable initialization\n"
|
||||
<< initp->warnContextPrimary() << '\n'
|
||||
<< contAssignp()->warnOther() << "... Location of continuous assignment\n"
|
||||
<< contAssignp()->warnContextSecondary());
|
||||
}
|
||||
if (nodep->isGenVar()) { // Genvar
|
||||
if (!nodep->isIfaceRef() && !nodep->isUsedParam() && !unusedMatch(nodep)) {
|
||||
nodep->v3warn(UNUSEDGENVAR, "Genvar is not used: " << nodep->prettyNameQ());
|
||||
|
|
@ -323,6 +340,7 @@ class UndrivenVisitor final : public VNVisitorConst {
|
|||
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_inContAssign = false; // In continuous assignment
|
||||
bool m_inInitial = false; // In explicit initial block
|
||||
bool m_inInitialSetup = false; // In InitialAutomatic*/InitialStatic* assignment LHS
|
||||
bool m_inInitialStatic = false; // In InitialStatic
|
||||
bool m_inProcAssign = false; // In procedural assignment
|
||||
|
|
@ -518,6 +536,8 @@ class UndrivenVisitor final : public VNVisitorConst {
|
|||
}
|
||||
if (nodep->access().isWriteOrRW()) {
|
||||
if (m_inInitialStatic && !entryp->initStaticp()) entryp->initStaticp(nodep);
|
||||
if (m_inInitial && !entryp->initialp()) entryp->initialp(nodep);
|
||||
if (m_inContAssign && !entryp->contAssignp()) entryp->contAssignp(nodep);
|
||||
if (m_alwaysp && m_inProcAssign && !entryp->procWritep())
|
||||
entryp->procWritep(nodep);
|
||||
}
|
||||
|
|
@ -554,11 +574,27 @@ class UndrivenVisitor final : public VNVisitorConst {
|
|||
m_inProcAssign = true;
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstAssignForce* nodep) override {
|
||||
iterateConst(nodep->rhsp());
|
||||
VL_RESTORER(m_inInitial);
|
||||
m_inInitial = false;
|
||||
iterateConst(nodep->lhsp());
|
||||
}
|
||||
void visit(AstAssignW* nodep) override {
|
||||
VL_RESTORER(m_inContAssign);
|
||||
m_inContAssign = true;
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstRelease* nodep) override {
|
||||
VL_RESTORER(m_inInitial);
|
||||
m_inInitial = false;
|
||||
iterateConst(nodep->lhsp());
|
||||
}
|
||||
void visit(AstInitial* nodep) override {
|
||||
VL_RESTORER(m_inInitial);
|
||||
m_inInitial = true;
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstInitialAutomatic* nodep) override {
|
||||
VL_RESTORER(m_inInitialSetup);
|
||||
m_inInitialSetup = true;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
interface Iface;
|
||||
logic clk = 1'b0, inp = 1'b0, io = 1'b0, out = 1'b0, out2 = 1'b0;
|
||||
logic clk = 1'b0, inp = 1'b0, io = 1'b0, out = 1'b0, out2;
|
||||
clocking cb @(posedge clk);
|
||||
input #7 inp;
|
||||
output out;
|
||||
|
|
|
|||
|
|
@ -12,10 +12,6 @@ module t (
|
|||
);
|
||||
logic a;
|
||||
logic b;
|
||||
initial begin
|
||||
a = 1'd0;
|
||||
b = 1'd0;
|
||||
end
|
||||
assign a = ~i;
|
||||
assign b = a;
|
||||
assign o = b;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
%Error-CONTASSINIT: t/t_fuzz_mixed_initialization.v:11:15: Continuous assignment to variable with initial value: 'a'
|
||||
: ... note: In instance 't'
|
||||
: ... Location of variable initialization
|
||||
11 | logic a = 1'b0;
|
||||
| ^~~~
|
||||
t/t_fuzz_mixed_initialization.v:12:12: ... Location of continuous assignment
|
||||
12 | assign a = 1'b1;
|
||||
| ^
|
||||
... For error description see https://verilator.org/warn/CONTASSINIT?v=latest
|
||||
%Error: Exiting due to
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#!/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.lint(fails=True, expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Zhi QU
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (
|
||||
output wire out
|
||||
);
|
||||
|
||||
logic a = 1'b0; // declaration initialization
|
||||
assign a = 1'b1; // continuous assignment
|
||||
|
||||
assign out = a;
|
||||
|
||||
endmodule
|
||||
|
|
@ -33,10 +33,6 @@ module t;
|
|||
wire bar2;
|
||||
`DELAY_INIT_CHECK(foo2, bar2)
|
||||
|
||||
reg foo3 = '0;
|
||||
reg bar3 = '1;
|
||||
`DELAY_INIT_CHECK(foo3, bar3)
|
||||
|
||||
initial begin
|
||||
#30;
|
||||
$write("*-* All Finished *-*\n");
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ module t (
|
|||
logic [7:0][3:0] arr;
|
||||
|
||||
logic [31:0] arr2_c;
|
||||
initial arr2_c = 0;
|
||||
logic [7:0][3:0] arr2;
|
||||
assign arr2_c = arr2;
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ module t (
|
|||
// update in **combinational** logic
|
||||
reg [1:0] x = 2'b00;
|
||||
// '{y1, y0}' should have exactly the same value as 'x', at all times
|
||||
reg y0 = 1'b0;
|
||||
reg y0;
|
||||
reg y1 = 1'b0;
|
||||
// 'z[0]' should equal '{8{x[0]}', 'z[1]' should equal '{8{x[1]}}'
|
||||
// verilator lint_off BLKANDNBLK
|
||||
|
|
@ -33,7 +33,7 @@ module t (
|
|||
struct {
|
||||
logic a;
|
||||
logic b;
|
||||
} pair = '{a: 1'b0, b: 1'b0};
|
||||
} pair;
|
||||
// verilator lint_on BLKANDNBLK
|
||||
|
||||
assign x[0] = cyc[0];
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ module top(
|
|||
reg clk_half = 0;
|
||||
|
||||
reg [31:0] cyc = 0;
|
||||
reg [31:0] a = 1, b = 2, c = 2;
|
||||
reg [31:0] a = 1, b = 2, c;
|
||||
|
||||
always @(posedge clk) begin
|
||||
$display("tick %d: a: %d, b: %d, c: %d", cyc, a, b, c);
|
||||
|
|
|
|||
|
|
@ -25,11 +25,11 @@ module t (/*AUTOARG*/
|
|||
wire fake_D;
|
||||
|
||||
logic[3:0] sh1 = 1;
|
||||
logic[3:0] sh2 = 2;
|
||||
logic[3:0] sh2;
|
||||
logic[3:0] sh3 = 3;
|
||||
logic[3:0] sh4 = 4;
|
||||
logic[3:0] sh4;
|
||||
logic[3:0] sh5 = 5;
|
||||
logic[3:0] sh6 = 6;
|
||||
logic[3:0] sh6;
|
||||
|
||||
int cyc = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t;
|
||||
logic clk1 = 0, clk2 = 0, clk3 = 0, clk4 = 0;
|
||||
logic clk1 = 0, clk2, clk3, clk4;
|
||||
always #2 clk1 = ~clk1;
|
||||
assign #1 clk2 = clk1;
|
||||
assign #1 clk3 = clk2;
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t;
|
||||
logic clk1 = 0;
|
||||
bit clk1;
|
||||
|
||||
assign #3 clk1 = ~clk1;
|
||||
|
||||
logic clk2 = 0;
|
||||
bit clk2;
|
||||
assign #11 clk2 = ~clk2;
|
||||
|
||||
int a1 = 0;
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t;
|
||||
bit clk1 = 0;
|
||||
bit clk1;
|
||||
|
||||
assign #3 clk1 = ~clk1;
|
||||
|
||||
bit clk2 = 0;
|
||||
bit clk2;
|
||||
assign #11 clk2 = ~clk2;
|
||||
|
||||
bit flag = 0;
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t;
|
||||
bit clk1 = 0;
|
||||
bit clk1;
|
||||
|
||||
assign #3 clk1 = ~clk1;
|
||||
|
||||
bit clk2 = 0;
|
||||
bit clk2;
|
||||
assign #11 clk2 = ~clk2;
|
||||
|
||||
int a1 = 0;
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ module t;
|
|||
assign i.clk = c.clk;
|
||||
Clocker clocker;
|
||||
initial begin
|
||||
i.clk = 0;
|
||||
i.v = 0;
|
||||
clocker = new;
|
||||
clocker.clk = c;
|
||||
|
|
|
|||
Loading…
Reference in New Issue