Add error on force/release non-constant selects.
This commit is contained in:
parent
a3d7b7d779
commit
91ae4c35b7
1
Changes
1
Changes
|
|
@ -23,6 +23,7 @@ Verilator 5.039 devel
|
||||||
* Add ALWNEVER warning, for `always @*` that never execute (#6291).
|
* Add ALWNEVER warning, for `always @*` that never execute (#6291).
|
||||||
* Add separate coverage counters for toggles 0->1 and 1->0 (#6086). [Ryszard Rozak, Antmicro Ltd.]
|
* Add separate coverage counters for toggles 0->1 and 1->0 (#6086). [Ryszard Rozak, Antmicro Ltd.]
|
||||||
* Add error on class 'function static'.
|
* Add error on class 'function static'.
|
||||||
|
* Add error on force/release non-constant selects.
|
||||||
* 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]
|
||||||
* Support unassigned virtual interfaces (#5265) (#6245). [Szymon Gizler, Antmicro Ltd.]
|
* Support unassigned virtual interfaces (#5265) (#6245). [Szymon Gizler, Antmicro Ltd.]
|
||||||
|
|
|
||||||
|
|
@ -5469,6 +5469,7 @@ class WidthVisitor final : public VNVisitor {
|
||||||
iterateCheckAssign(nodep, "Assign RHS", nodep->rhsp(), FINAL, lhsDTypep);
|
iterateCheckAssign(nodep, "Assign RHS", nodep->rhsp(), FINAL, lhsDTypep);
|
||||||
// UINFOTREE(1, nodep, "", "AssignOut");
|
// UINFOTREE(1, nodep, "", "AssignOut");
|
||||||
}
|
}
|
||||||
|
if (VN_IS(nodep, AssignForce)) checkForceReleaseLhs(nodep, nodep->lhsp());
|
||||||
if (AstNode* const controlp = nodep->timingControlp()) {
|
if (AstNode* const controlp = nodep->timingControlp()) {
|
||||||
if (VN_IS(m_ftaskp, Func)) {
|
if (VN_IS(m_ftaskp, Func)) {
|
||||||
controlp->v3error("Timing controls are not legal in functions. Suggest use a task "
|
controlp->v3error("Timing controls are not legal in functions. Suggest use a task "
|
||||||
|
|
@ -5537,6 +5538,7 @@ class WidthVisitor final : public VNVisitor {
|
||||||
userIterateAndNext(nodep->lhsp(), WidthVP{SELF, BOTH}.p());
|
userIterateAndNext(nodep->lhsp(), WidthVP{SELF, BOTH}.p());
|
||||||
UASSERT_OBJ(nodep->lhsp()->dtypep(), nodep, "How can LValue be untyped?");
|
UASSERT_OBJ(nodep->lhsp()->dtypep(), nodep, "How can LValue be untyped?");
|
||||||
UASSERT_OBJ(nodep->lhsp()->dtypep()->widthSized(), nodep, "How can LValue be unsized?");
|
UASSERT_OBJ(nodep->lhsp()->dtypep()->widthSized(), nodep, "How can LValue be unsized?");
|
||||||
|
checkForceReleaseLhs(nodep, nodep->lhsp());
|
||||||
}
|
}
|
||||||
|
|
||||||
void formatNoStringArg(AstNode* argp, char ch) {
|
void formatNoStringArg(AstNode* argp, char ch) {
|
||||||
|
|
@ -8544,7 +8546,7 @@ class WidthVisitor final : public VNVisitor {
|
||||||
const AstArg* const argp = tconnect.second;
|
const AstArg* const argp = tconnect.second;
|
||||||
const AstNode* const pinp = argp->exprp();
|
const AstNode* const pinp = argp->exprp();
|
||||||
if (!pinp) continue; // Argument error we'll find later
|
if (!pinp) continue; // Argument error we'll find later
|
||||||
if (hasOpenArrayIterateDType(portp->dtypep())) portp->dtypep(pinp->dtypep());
|
if (hasOpenArrayDTypeRecurse(portp->dtypep())) portp->dtypep(pinp->dtypep());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -8552,7 +8554,7 @@ class WidthVisitor final : public VNVisitor {
|
||||||
bool hasOpen = false;
|
bool hasOpen = false;
|
||||||
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||||
if (AstVar* const portp = VN_CAST(stmtp, Var)) {
|
if (AstVar* const portp = VN_CAST(stmtp, Var)) {
|
||||||
if (portp->isDpiOpenArray() || hasOpenArrayIterateDType(portp->dtypep())) {
|
if (portp->isDpiOpenArray() || hasOpenArrayDTypeRecurse(portp->dtypep())) {
|
||||||
portp->isDpiOpenArray(true);
|
portp->isDpiOpenArray(true);
|
||||||
hasOpen = true;
|
hasOpen = true;
|
||||||
}
|
}
|
||||||
|
|
@ -8560,10 +8562,10 @@ class WidthVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
return hasOpen;
|
return hasOpen;
|
||||||
}
|
}
|
||||||
bool hasOpenArrayIterateDType(AstNodeDType* nodep) {
|
bool hasOpenArrayDTypeRecurse(AstNodeDType* nodep) {
|
||||||
// Return true iff this datatype or child has an openarray
|
// Return true iff this datatype or child has an openarray
|
||||||
if (VN_IS(nodep, UnsizedArrayDType)) return true;
|
if (VN_IS(nodep, UnsizedArrayDType)) return true;
|
||||||
if (nodep->subDTypep()) return hasOpenArrayIterateDType(nodep->subDTypep()->skipRefp());
|
if (nodep->subDTypep()) return hasOpenArrayDTypeRecurse(nodep->subDTypep()->skipRefp());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
AstNodeDType* dtypeNotIntAtomOrVecRecurse(AstNodeDType* nodep, bool ranged = false) {
|
AstNodeDType* dtypeNotIntAtomOrVecRecurse(AstNodeDType* nodep, bool ranged = false) {
|
||||||
|
|
@ -8599,6 +8601,44 @@ class WidthVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
return nodep;
|
return nodep;
|
||||||
}
|
}
|
||||||
|
void checkForceReleaseLhs(AstNode* nodep, AstNode* lhsp) {
|
||||||
|
// V3Force can't check as vector may have expanded, or propagated constant into index
|
||||||
|
if (AstNode* const selNodep = selectNonConstantRecurse(lhsp))
|
||||||
|
nodep->v3error((VN_IS(nodep, Release) ? "Release"s : "Force"s)
|
||||||
|
+ " left-hand-side must not have variable bit/part select "
|
||||||
|
"(IEEE 1800-2023 10.6.2)\n"
|
||||||
|
<< nodep->warnContextPrimary() << '\n'
|
||||||
|
<< selNodep->warnOther() << "... Location of non-constant index\n"
|
||||||
|
<< selNodep->warnContextSecondary());
|
||||||
|
}
|
||||||
|
AstNode* selectNonConstantRecurse(AstNode* nodep, bool inSel = false) {
|
||||||
|
// If node has a non-constant select, return that select
|
||||||
|
AstNode* resultp = nullptr;
|
||||||
|
if (AstNodeSel* const anodep = VN_CAST(nodep, NodeSel)) {
|
||||||
|
resultp = selectNonConstantRecurse(anodep->fromp(), inSel);
|
||||||
|
if (resultp) return resultp;
|
||||||
|
resultp = selectNonConstantRecurse(anodep->bitp(), true);
|
||||||
|
} else if (AstSel* const anodep = VN_CAST(nodep, Sel)) {
|
||||||
|
resultp = selectNonConstantRecurse(anodep->fromp(), inSel);
|
||||||
|
if (resultp) return resultp;
|
||||||
|
resultp = selectNonConstantRecurse(anodep->lsbp(), true);
|
||||||
|
} else if (AstNodeVarRef* const anodep = VN_CAST(nodep, NodeVarRef)) {
|
||||||
|
if (inSel && !anodep->varp()->isParam() && !anodep->varp()->isGenVar()) return anodep;
|
||||||
|
} else {
|
||||||
|
if (AstNode* const refp = nodep->op1p())
|
||||||
|
resultp = selectNonConstantRecurse(refp, inSel);
|
||||||
|
if (resultp) return resultp;
|
||||||
|
if (AstNode* const refp = nodep->op2p())
|
||||||
|
resultp = selectNonConstantRecurse(refp, inSel);
|
||||||
|
if (resultp) return resultp;
|
||||||
|
if (AstNode* const refp = nodep->op3p())
|
||||||
|
resultp = selectNonConstantRecurse(refp, inSel);
|
||||||
|
if (resultp) return resultp;
|
||||||
|
if (AstNode* const refp = nodep->op4p())
|
||||||
|
resultp = selectNonConstantRecurse(refp, inSel);
|
||||||
|
}
|
||||||
|
return resultp;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// METHODS - special type detection
|
// METHODS - special type detection
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
%Error: t/t_force_select_bad.v:24:5: Force left-hand-side must not have variable bit/part select (IEEE 1800-2023 10.6.2)
|
||||||
|
: ... note: In instance 't'
|
||||||
|
24 | force array1[bad_index] = 1'b1;
|
||||||
|
| ^~~~~
|
||||||
|
t/t_force_select_bad.v:24:18: ... Location of non-constant index
|
||||||
|
24 | force array1[bad_index] = 1'b1;
|
||||||
|
| ^~~~~~~~~
|
||||||
|
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||||
|
%Error: t/t_force_select_bad.v:25:5: Release left-hand-side must not have variable bit/part select (IEEE 1800-2023 10.6.2)
|
||||||
|
: ... note: In instance 't'
|
||||||
|
25 | release array1[bad_index];
|
||||||
|
| ^~~~~~~
|
||||||
|
t/t_force_select_bad.v:25:20: ... Location of non-constant index
|
||||||
|
25 | release array1[bad_index];
|
||||||
|
| ^~~~~~~~~
|
||||||
|
%Error: t/t_force_select_bad.v:26:5: Force left-hand-side must not have variable bit/part select (IEEE 1800-2023 10.6.2)
|
||||||
|
: ... note: In instance 't'
|
||||||
|
26 | force vec[bad_index+:1] = 1'b1;
|
||||||
|
| ^~~~~
|
||||||
|
t/t_force_select_bad.v:26:15: ... Location of non-constant index
|
||||||
|
26 | force vec[bad_index+:1] = 1'b1;
|
||||||
|
| ^~~~~~~~~
|
||||||
|
%Error: t/t_force_select_bad.v:27:5: Release left-hand-side must not have variable bit/part select (IEEE 1800-2023 10.6.2)
|
||||||
|
: ... note: In instance 't'
|
||||||
|
27 | release vec[bad_index+:1];
|
||||||
|
| ^~~~~~~
|
||||||
|
t/t_force_select_bad.v:27:17: ... Location of non-constant index
|
||||||
|
27 | release vec[bad_index+:1];
|
||||||
|
| ^~~~~~~~~
|
||||||
|
%Error: Exiting due to
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
#!/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.lint(fails=True, expect_filename=test.golden_filename)
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
// 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;
|
||||||
|
wire array1[2:1];
|
||||||
|
wire [2:-1] vec;
|
||||||
|
|
||||||
|
integer bad_index = 1;
|
||||||
|
|
||||||
|
parameter P_ONE = 1;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
force array1[P_ONE] = 1'b1; // ok
|
||||||
|
release array1[P_ONE]; // ok
|
||||||
|
force vec[P_ONE+:1] = 1'b1; // ok
|
||||||
|
release vec[P_ONE+:1]; // ok
|
||||||
|
|
||||||
|
// IEEE 1800-2023 10.6.2 [A force] shall not be a bit-select or a
|
||||||
|
// part-select of a [non-constant] variable or of a net with a user-defined
|
||||||
|
// nettype.
|
||||||
|
force array1[bad_index] = 1'b1; // <---- BAD not constant index
|
||||||
|
release array1[bad_index]; // <---- BAD not constant index
|
||||||
|
force vec[bad_index+:1] = 1'b1; // <---- BAD not constant index
|
||||||
|
release vec[bad_index+:1]; // <---- BAD not constant index
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue