Add ENUMITEMWIDTH error, and apply to X-extended and ranged values.
This commit is contained in:
parent
cefe1845df
commit
2f199f20cf
1
Changes
1
Changes
|
|
@ -13,6 +13,7 @@ Verilator 5.039 devel
|
||||||
|
|
||||||
**Other:**
|
**Other:**
|
||||||
|
|
||||||
|
* Add ENUMITEMWIDTH error, and apply to X-extended and ranged values.
|
||||||
* Support member-level triggers for virtual interfaces (#5166) (#6148). [Yilou Wang]
|
* Support member-level triggers for virtual interfaces (#5166) (#6148). [Yilou Wang]
|
||||||
* Support disable dotted references (#6154). [Ryszard Rozak, Antmicro Ltd.]
|
* Support disable dotted references (#6154). [Ryszard Rozak, Antmicro Ltd.]
|
||||||
* Support randomize() on class member selects (#6161). [Igor Zaworski, Antmicro Ltd.]
|
* Support randomize() on class member selects (#6161). [Igor Zaworski, Antmicro Ltd.]
|
||||||
|
|
|
||||||
|
|
@ -709,6 +709,28 @@ List Of Warnings
|
||||||
missing."
|
missing."
|
||||||
|
|
||||||
|
|
||||||
|
.. option:: ENUMITEMWIDTH
|
||||||
|
|
||||||
|
An error that an enum item value is being assigned from a value which
|
||||||
|
would be truncated (similar to :option:`WIDTHTRUNC`), or from a sized
|
||||||
|
literal constant with a different bit width (similar to
|
||||||
|
:option:`WIDTHTRUNC` or :option:`WIDTHEXPAND`). IEEE requires this
|
||||||
|
error, but it may be disabled.
|
||||||
|
|
||||||
|
Faulty example:
|
||||||
|
|
||||||
|
.. code-block:: sv
|
||||||
|
:linenos:
|
||||||
|
:emphasize-lines: 2
|
||||||
|
|
||||||
|
typedef enum [3:0] {
|
||||||
|
WRONG_WIDTH = 33'h3 //<--- Warning
|
||||||
|
} enum_t;
|
||||||
|
|
||||||
|
To repair, correct the size of the item's value directly, or use a cast,
|
||||||
|
so the resulting width matches the enum's width.
|
||||||
|
|
||||||
|
|
||||||
.. option:: ENUMVALUE
|
.. option:: ENUMVALUE
|
||||||
|
|
||||||
An error that an enum data type value is being assigned from another data
|
An error that an enum data type value is being assigned from another data
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,7 @@ public:
|
||||||
DEPRECATED, // Feature will be deprecated
|
DEPRECATED, // Feature will be deprecated
|
||||||
ENCAPSULATED, // Error: local/protected violation
|
ENCAPSULATED, // Error: local/protected violation
|
||||||
ENDLABEL, // End lable name mismatch
|
ENDLABEL, // End lable name mismatch
|
||||||
|
ENUMITEMWIDTH, // Error: enum item width mismatch
|
||||||
ENUMVALUE, // Error: enum type needs explicit cast
|
ENUMVALUE, // Error: enum type needs explicit cast
|
||||||
EOFNEWLINE, // End-of-file missing newline
|
EOFNEWLINE, // End-of-file missing newline
|
||||||
GENCLK, // Generated Clock. Historical, never issued.
|
GENCLK, // Generated Clock. Historical, never issued.
|
||||||
|
|
@ -204,8 +205,8 @@ public:
|
||||||
"CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CASTCONST", "CDCRSTLOGIC", "CLKDATA",
|
"CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CASTCONST", "CDCRSTLOGIC", "CLKDATA",
|
||||||
"CMPCONST", "COLONPLUS", "COMBDLY", "CONSTRAINTIGN", "CONTASSREG", "COVERIGN",
|
"CMPCONST", "COLONPLUS", "COMBDLY", "CONSTRAINTIGN", "CONTASSREG", "COVERIGN",
|
||||||
"DECLFILENAME", "DEFOVERRIDE", "DEFPARAM", "DEPRECATED",
|
"DECLFILENAME", "DEFOVERRIDE", "DEFPARAM", "DEPRECATED",
|
||||||
"ENCAPSULATED", "ENDLABEL", "ENUMVALUE", "EOFNEWLINE", "GENCLK",
|
"ENCAPSULATED", "ENDLABEL", "ENUMITEMWIDTH", "ENUMVALUE", "EOFNEWLINE",
|
||||||
"GENUNNAMED", "HIERBLOCK",
|
"GENCLK", "GENUNNAMED", "HIERBLOCK",
|
||||||
"IFDEPTH", "IGNOREDRETURN",
|
"IFDEPTH", "IGNOREDRETURN",
|
||||||
"IMPERFECTSCH", "IMPLICIT", "IMPLICITSTATIC", "IMPORTSTAR", "IMPURE",
|
"IMPERFECTSCH", "IMPLICIT", "IMPLICITSTATIC", "IMPORTSTAR", "IMPURE",
|
||||||
"INCABSPATH", "INFINITELOOP", "INITIALDLY", "INSECURE",
|
"INCABSPATH", "INFINITELOOP", "INITIALDLY", "INSECURE",
|
||||||
|
|
@ -219,7 +220,8 @@ public:
|
||||||
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS",
|
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS",
|
||||||
"UNPACKED", "UNSIGNED", "UNUSEDGENVAR", "UNUSEDLOOP" ,"UNUSEDPARAM", "UNUSEDSIGNAL",
|
"UNPACKED", "UNSIGNED", "UNUSEDGENVAR", "UNUSEDLOOP" ,"UNUSEDPARAM", "UNUSEDSIGNAL",
|
||||||
"USERERROR", "USERFATAL", "USERINFO", "USERWARN",
|
"USERERROR", "USERFATAL", "USERINFO", "USERWARN",
|
||||||
"VARHIDDEN", "WAITCONST", "WIDTH", "WIDTHCONCAT", "WIDTHEXPAND", "WIDTHTRUNC", "WIDTHXZEXPAND", "ZERODLY", "ZEROREPL",
|
"VARHIDDEN", "WAITCONST", "WIDTH", "WIDTHCONCAT", "WIDTHEXPAND", "WIDTHTRUNC", "WIDTHXZEXPAND",
|
||||||
|
"ZERODLY", "ZEROREPL",
|
||||||
" MAX"
|
" MAX"
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
@ -249,9 +251,9 @@ public:
|
||||||
bool pretendError() const VL_MT_SAFE {
|
bool pretendError() const VL_MT_SAFE {
|
||||||
return (m_e == ASSIGNIN || m_e == BADSTDPRAGMA || m_e == BADVLTPRAGMA || m_e == BLKANDNBLK
|
return (m_e == ASSIGNIN || m_e == BADSTDPRAGMA || m_e == BADVLTPRAGMA || m_e == BLKANDNBLK
|
||||||
|| m_e == BLKLOOPINIT || m_e == CONTASSREG || m_e == ENCAPSULATED
|
|| m_e == BLKLOOPINIT || m_e == CONTASSREG || m_e == ENCAPSULATED
|
||||||
|| m_e == ENDLABEL || m_e == ENUMVALUE || m_e == IMPURE || m_e == MODMISSING
|
|| m_e == ENDLABEL || m_e == ENUMITEMWIDTH || m_e == ENUMVALUE || m_e == IMPURE
|
||||||
|| m_e == PINNOTFOUND || m_e == PKGNODECL || m_e == PROCASSWIRE
|
|| m_e == MODMISSING || m_e == PINNOTFOUND || m_e == PKGNODECL
|
||||||
|| m_e == ZEROREPL // Says IEEE
|
|| m_e == PROCASSWIRE || m_e == ZEROREPL // Says IEEE
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Warnings to mention manual
|
// Warnings to mention manual
|
||||||
|
|
|
||||||
|
|
@ -369,6 +369,10 @@ public:
|
||||||
&& m_lastLineno == rhs.m_lastLineno && m_lastColumn == rhs.m_lastColumn
|
&& m_lastLineno == rhs.m_lastLineno && m_lastColumn == rhs.m_lastColumn
|
||||||
&& m_filenameno == rhs.m_filenameno && m_msgEnIdx == rhs.m_msgEnIdx);
|
&& m_filenameno == rhs.m_filenameno && m_msgEnIdx == rhs.m_msgEnIdx);
|
||||||
}
|
}
|
||||||
|
bool equalFirstLineCol(const FileLine& rhs) const {
|
||||||
|
return (m_filenameno == rhs.m_filenameno && m_firstLineno == rhs.m_firstLineno
|
||||||
|
&& m_firstColumn == rhs.m_firstColumn);
|
||||||
|
}
|
||||||
// Returns -1 if (*this) should come before rhs after sorted. 1 for the opposite case. 0 for
|
// Returns -1 if (*this) should come before rhs after sorted. 1 for the opposite case. 0 for
|
||||||
// equivalent.
|
// equivalent.
|
||||||
int operatorCompare(const FileLine& rhs) const {
|
int operatorCompare(const FileLine& rhs) const {
|
||||||
|
|
|
||||||
|
|
@ -267,16 +267,17 @@ class LinkParseVisitor final : public VNVisitor {
|
||||||
const int left = nodep->rangep()->leftConst();
|
const int left = nodep->rangep()->leftConst();
|
||||||
const int right = nodep->rangep()->rightConst();
|
const int right = nodep->rangep()->rightConst();
|
||||||
const int increment = (left > right) ? -1 : 1;
|
const int increment = (left > right) ? -1 : 1;
|
||||||
int offset_from_init = 0;
|
uint32_t offset_from_init = 0;
|
||||||
AstEnumItem* addp = nullptr;
|
AstEnumItem* addp = nullptr;
|
||||||
FileLine* const flp = nodep->fileline();
|
FileLine* const flp = nodep->fileline();
|
||||||
for (int i = left; i != (right + increment); i += increment, offset_from_init++) {
|
for (int i = left; i != (right + increment); i += increment, ++offset_from_init) {
|
||||||
const string name = nodep->name() + cvtToStr(i);
|
const string name = nodep->name() + cvtToStr(i);
|
||||||
AstNodeExpr* valuep = nullptr;
|
AstNodeExpr* valuep = nullptr;
|
||||||
if (nodep->valuep()) {
|
if (nodep->valuep()) {
|
||||||
|
// V3Width looks for Adds with same fileline as the EnumItem
|
||||||
valuep
|
valuep
|
||||||
= new AstAdd{flp, nodep->valuep()->cloneTree(true),
|
= new AstAdd{flp, nodep->valuep()->cloneTree(true),
|
||||||
new AstConst(flp, AstConst::Unsized32{}, offset_from_init)};
|
new AstConst{flp, AstConst::Unsized32{}, offset_from_init}};
|
||||||
}
|
}
|
||||||
addp = AstNode::addNext(addp, new AstEnumItem{flp, name, nullptr, valuep});
|
addp = AstNode::addNext(addp, new AstEnumItem{flp, name, nullptr, valuep});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1188,7 +1188,7 @@ uint32_t V3Number::countOnes() const {
|
||||||
|
|
||||||
uint32_t V3Number::mostSetBitP1() const {
|
uint32_t V3Number::mostSetBitP1() const {
|
||||||
for (int bit = width() - 1; bit >= 0; bit--) {
|
for (int bit = width() - 1; bit >= 0; bit--) {
|
||||||
if (bitIs1(bit)) return bit + 1;
|
if (!bitIs0(bit)) return bit + 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2553,9 +2553,16 @@ class WidthVisitor final : public VNVisitor {
|
||||||
// Default type is int, but common to assign narrower values, so minwidth from value
|
// Default type is int, but common to assign narrower values, so minwidth from value
|
||||||
userIterateAndNext(nodep->valuep(), WidthVP{CONTEXT_DET, PRELIM}.p());
|
userIterateAndNext(nodep->valuep(), WidthVP{CONTEXT_DET, PRELIM}.p());
|
||||||
bool warnOn = true;
|
bool warnOn = true;
|
||||||
if (const AstConst* const constp = VN_CAST(nodep->valuep(), Const)) {
|
AstNodeExpr* valuep = nodep->valuep();
|
||||||
|
if (const AstAdd* const anodep = VN_CAST(valuep, Add)) {
|
||||||
|
// If constructed by V3LinkParse due to "enumitem[N_REPEATS] value"
|
||||||
|
if (anodep->fileline()->equalFirstLineCol(*(nodep->fileline())))
|
||||||
|
valuep = anodep->lhsp();
|
||||||
|
}
|
||||||
|
if (const AstConst* const constp = VN_CAST(valuep, Const)) {
|
||||||
if (static_cast<int>(constp->num().mostSetBitP1()) > nodep->width()) {
|
if (static_cast<int>(constp->num().mostSetBitP1()) > nodep->width()) {
|
||||||
constp->v3error("Enum value exceeds width of enum type (IEEE 1800-2023 6.19)");
|
constp->v3warn(ENUMITEMWIDTH,
|
||||||
|
"Enum value exceeds width of enum type (IEEE 1800-2023 6.19)");
|
||||||
warnOn = false; // Prevent normal WIDTHTRUNC
|
warnOn = false; // Prevent normal WIDTHTRUNC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,20 @@
|
||||||
%Error: t/t_enum_bad_value.v:10:19: Enum value exceeds width of enum type (IEEE 1800-2023 6.19)
|
%Error-ENUMITEMWIDTH: t/t_enum_bad_value.v:12:37: Enum value exceeds width of enum type (IEEE 1800-2023 6.19)
|
||||||
: ... note: In instance 't'
|
: ... note: In instance 't'
|
||||||
10 | VALUE_BAD = 8
|
12 | typedef enum [2:0] { VALUE_BAD1 = 8 } enum_t;
|
||||||
| ^
|
| ^
|
||||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
... For error description see https://verilator.org/warn/ENUMITEMWIDTH?v=latest
|
||||||
|
%Error-ENUMITEMWIDTH: t/t_enum_bad_value.v:14:29: Enum value exceeds width of enum type (IEEE 1800-2023 6.19)
|
||||||
|
: ... note: In instance 't'
|
||||||
|
14 | enum bit [4:0] {BAD2[4] = 100} bad2;
|
||||||
|
| ^~~
|
||||||
|
%Warning-WIDTHTRUNC: t/t_enum_bad_value.v:14:19: Operator ADD expects 5 bits on the LHS, but LHS's CONST '?32?sh64' generates 32 or 7 bits.
|
||||||
|
: ... note: In instance 't'
|
||||||
|
14 | enum bit [4:0] {BAD2[4] = 100} bad2;
|
||||||
|
| ^~~~
|
||||||
|
... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest
|
||||||
|
... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message.
|
||||||
|
%Error-ENUMITEMWIDTH: t/t_enum_bad_value.v:16:28: Enum value exceeds width of enum type (IEEE 1800-2023 6.19)
|
||||||
|
: ... note: In instance 't'
|
||||||
|
16 | enum logic [3:0] {BAD3 = 5'bxxxxx} bad3;
|
||||||
|
| ^~~~~~~~
|
||||||
%Error: Exiting due to
|
%Error: Exiting due to
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,14 @@
|
||||||
|
|
||||||
module t();
|
module t();
|
||||||
|
|
||||||
typedef enum [2:0] {
|
enum bit signed [3:0] {OK1 = -1} ok1_t; // As is signed, loss of 1 bits is ok per IEEE
|
||||||
VALUE_BAD = 8
|
enum bit signed [3:0] {OK2 = 3} ok2_t;
|
||||||
} enum_t;
|
|
||||||
|
|
||||||
|
typedef enum [2:0] { VALUE_BAD1 = 8 } enum_t;
|
||||||
|
|
||||||
|
enum bit [4:0] {BAD2[4] = 100} bad2;
|
||||||
|
|
||||||
|
enum logic [3:0] {BAD3 = 5'bxxxxx} bad3;
|
||||||
|
|
||||||
|
initial $stop;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue