Fix genvar check to be more strict about generate-for usage only

This commit is contained in:
Wilson Snyder 2025-08-03 16:57:12 -04:00
parent 309129ebcf
commit f106c1eaec
6 changed files with 79 additions and 48 deletions

View File

@ -52,7 +52,7 @@ class LinkResolveVisitor final : public VNVisitor {
AstNodeFTask* m_ftaskp = nullptr; // Function or task we're inside
AstNodeCoverOrAssert* m_assertp = nullptr; // Current assertion
int m_senitemCvtNum = 0; // Temporary signal counter
bool m_underGenFor = false; // Under GenFor
std::deque<AstGenFor*> m_underGenFors; // Stack of GenFor underneath
bool m_underGenerate = false; // Under GenFor/GenIf
// VISITORS
@ -139,9 +139,16 @@ class LinkResolveVisitor final : public VNVisitor {
if (nodep->varp()) { // Else due to dead code, might not have var pointer
// VarRef: Resolve its reference
nodep->varp()->usedParam(true);
// TODO should look for where genvar is valid, but for now catch
// just gross errors of using genvar outside any generate
if (nodep->varp()->isGenVar() && !m_underGenFor) {
// Look for where genvar is valid
bool ok = false;
for (AstGenFor* forp : m_underGenFors) {
if (ok) break;
if (forp->initsp())
forp->initsp()->foreach([&](AstVarRef* refp) { //
if (refp->varp() == nodep->varp()) ok = true;
});
}
if (nodep->varp()->isGenVar() && !ok) {
nodep->v3error("Genvar "
<< nodep->prettyNameQ()
<< " used outside generate for loop (IEEE 1800-2023 27.4)");
@ -503,11 +510,12 @@ class LinkResolveVisitor final : public VNVisitor {
// We keep Modport's themselves around for XML dump purposes
void visit(AstGenFor* nodep) override {
VL_RESTORER(m_underGenFor);
VL_RESTORER(m_underGenerate);
m_underGenFor = true;
m_underGenerate = true;
m_underGenFors.emplace_back(nodep);
iterateChildren(nodep);
UASSERT_OBJ(!m_underGenFors.empty(), nodep, "Underflow");
m_underGenFors.pop_back();
}
void visit(AstGenIf* nodep) override {
VL_RESTORER(m_underGenerate);

View File

@ -124,10 +124,10 @@ class UnrollVisitor final : public VNVisitor {
if (VN_IS(nodep, GenFor) && !m_forVarp->isGenVar()) {
nodep->v3error("Non-genvar used in generate for: " << m_forVarp->prettyNameQ());
} else if (!VN_IS(nodep, GenFor) && m_forVarp->isGenVar()) {
nodep->v3error("Genvar not legal in non-generate for (IEEE 1800-2023 27.4): "
<< m_forVarp->prettyNameQ() << '\n'
<< nodep->warnMore()
<< "... Suggest move for loop upwards to generate-level scope.");
// Likely impossible as V3LinkResolve will earlier throw bad genvar use error
nodep->v3error("Genvar not legal in non-generate for" // LCOV_EXCL_LINE
" (IEEE 1800-2023 27.4): "
<< m_forVarp->prettyNameQ());
}
if (m_generate) V3Const::constifyParamsEdit(initAssp->rhsp()); // rhsp may change

View File

@ -1,6 +1,20 @@
%Error: t/t_genvar_for_bad.v:25:13: Genvar not legal in non-generate for (IEEE 1800-2023 27.4): 't.i'
: ... Suggest move for loop upwards to generate-level scope.
25 | for (i=0; i<N; i=i+1) begin
| ^~~
%Error: t/t_genvar_for_bad.v:23:12: Genvar 'i' used outside generate for loop (IEEE 1800-2023 27.4)
23 | for (i = 0; i < N; i = i + 1) begin
| ^
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: t/t_genvar_for_bad.v:23:19: Genvar 'i' used outside generate for loop (IEEE 1800-2023 27.4)
23 | for (i = 0; i < N; i = i + 1) begin
| ^
%Error: t/t_genvar_for_bad.v:24:21: Genvar 'i' used outside generate for loop (IEEE 1800-2023 27.4)
24 | ov[i] <= iv[i];
| ^
%Error: t/t_genvar_for_bad.v:24:12: Genvar 'i' used outside generate for loop (IEEE 1800-2023 27.4)
24 | ov[i] <= iv[i];
| ^
%Error: t/t_genvar_for_bad.v:23:30: Genvar 'i' used outside generate for loop (IEEE 1800-2023 27.4)
23 | for (i = 0; i < N; i = i + 1) begin
| ^
%Error: t/t_genvar_for_bad.v:23:26: Genvar 'i' used outside generate for loop (IEEE 1800-2023 27.4)
23 | for (i = 0; i < N; i = i + 1) begin
| ^
%Error: Exiting due to

View File

@ -4,28 +4,25 @@
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
module t (/*AUTOARG*/
// Outputs
ov,
// Inputs
clk, iv
);
module t ( /*AUTOARG*/
// Outputs
ov,
// Inputs
clk, iv
);
parameter N = 4;
parameter N = 4;
input clk;
input [63:0] iv[N-1:0];
output logic [63:0] ov[N-1:0];
input clk;
input [63:0] iv[N-1:0];
output logic [63:0] ov[N-1:0];
genvar j; // Bypass first genvar check
genvar i;
generate
for (j=0; j<1; j=j+1) begin
always @(posedge clk) begin
for (i=0; i<N; i=i+1) begin
ov[i] <= iv[i];
end
end
genvar i;
generate
always @(posedge clk) begin
for (i = 0; i < N; i = i + 1) begin
ov[i] <= iv[i];
end
endgenerate
end
endgenerate
endmodule

View File

@ -1,8 +1,11 @@
%Error: t/t_genvar_misuse_bad.v:16:31: Genvar 'i' used outside generate for loop (IEEE 1800-2023 27.4)
16 | assign q[i] = d[i];
| ^
%Error: t/t_genvar_misuse_bad.v:15:19: Genvar 'i' used outside generate for loop (IEEE 1800-2023 27.4)
15 | assign q[i] = d[i];
| ^
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: t/t_genvar_misuse_bad.v:16:24: Genvar 'i' used outside generate for loop (IEEE 1800-2023 27.4)
16 | assign q[i] = d[i];
| ^
%Error: t/t_genvar_misuse_bad.v:15:12: Genvar 'i' used outside generate for loop (IEEE 1800-2023 27.4)
15 | assign q[i] = d[i];
| ^
%Error: t/t_genvar_misuse_bad.v:22:11: Genvar 'c' used outside generate for loop (IEEE 1800-2023 27.4)
22 | if (c);
| ^
%Error: Exiting due to

View File

@ -5,13 +5,22 @@
// SPDX-License-Identifier: CC0-1.0
// See bug408
module top
(
output logic [1:0] q,
input logic [1:0] d,
input logic clk
);
module top (
output logic [1:0] q,
input logic [1:0] d,
input logic clk
);
genvar i;
assign q[i] = d[i]; // <--- Error: Misusing genvar i
genvar a, b, c;
for (a = 0; a < 2; ++a) begin
if (a);
for (b = 0; b < 2; ++b) begin
if (a);
if (b);
if (c); // <--- Error: Misusing genvar c
end
end
genvar i;
assign q[i] = d[i];
endmodule