diff --git a/Changes b/Changes index 76f32e894..12d4e47f5 100644 --- a/Changes +++ b/Changes @@ -15,6 +15,7 @@ Verilator 5.039 devel * Add ENUMITEMWIDTH error, and apply to X-extended and ranged values. * Add NOEFFECT warning, replacing previous `foreach` error. +* Add enum base type checking per IEEE. * Support member-level triggers for virtual interfaces (#5166) (#6148). [Yilou Wang] * Support disabling a fork in additional contexts (#5432 partial) (#6174) (#6183). [Ryszard Rozak, Antmicro Ltd.] * Support disable dotted references (#6154). [Ryszard Rozak, Antmicro Ltd.] diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 7153c441a..9790d17e8 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2483,10 +2483,11 @@ class WidthVisitor final : public VNVisitor { UINFO(5, " ENUMDTYPE " << nodep); nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); nodep->dtypep(nodep); - AstBasicDType* basicp = nodep->dtypep()->skipRefp()->basicp(); - if (!basicp || !basicp->keyword().isIntNumeric()) { + AstNodeDType* basicp = nodep->dtypep()->skipRefp()->basicp(); + if (!dtypeIsIntAtomOrVecRecurse(nodep->subDTypep())) { nodep->v3error( - "Enum type must be an integer atom or vector type (IEEE 1800-2023 6.19)"); + "Enum data type must be an integer atom or vector type (IEEE 1800-2023 6.19), not " + << nodep->subDTypep()->prettyDTypeNameQ()); basicp = nodep->findSigned32DType()->basicp(); nodep->refDTypep(basicp); } @@ -8309,6 +8310,24 @@ class WidthVisitor final : public VNVisitor { if (nodep->subDTypep()) return hasOpenArrayIterateDType(nodep->subDTypep()->skipRefp()); return false; } + bool dtypeIsIntAtomOrVecRecurse(AstNodeDType* nodep, bool ranged = false) { + nodep = nodep->skipRefToEnump(); + if (AstBasicDType* const dtp = VN_CAST(nodep, BasicDType)) { + if (ranged && (!dtp->isBitLogic() || dtp->isRanged())) { + UINFO(9, "dtypeIsIntAtomOrVecRecurse false at " << nodep); + return false; // Packed when already packed + } + if (dtp->keyword().isIntNumeric()) return true; + } else if (AstPackArrayDType* const dtp = VN_CAST(nodep, PackArrayDType)) { + if (ranged) { + UINFO(9, "dtypeIsIntAtomOrVecRecurse false at " << nodep); + return false; // Packed when already packed + } + return dtypeIsIntAtomOrVecRecurse(nodep->subDTypep(), true); + } + UINFO(9, "dtypeIsIntAtomOrVecRecurse false at " << nodep); + return false; + } //---------------------------------------------------------------------- // METHODS - special type detection diff --git a/test_regress/t/t_enum_base.py b/test_regress/t/t_enum_base.py new file mode 100755 index 000000000..f989a35fb --- /dev/null +++ b/test_regress/t/t_enum_base.py @@ -0,0 +1,18 @@ +#!/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('simulator') + +test.compile() + +test.execute() + +test.passes() diff --git a/test_regress/t/t_enum_base.v b/test_regress/t/t_enum_base.v new file mode 100644 index 000000000..74a811edf --- /dev/null +++ b/test_regress/t/t_enum_base.v @@ -0,0 +1,18 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + + typedef int int_t; + typedef enum int_t {INTT_VAL = 1} intt_e; + intt_e intte; + + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_enum_base_bad.out b/test_regress/t/t_enum_base_bad.out index d46208e46..f57b5e80c 100644 --- a/test_regress/t/t_enum_base_bad.out +++ b/test_regress/t/t_enum_base_bad.out @@ -1,6 +1,30 @@ -%Error: t/t_enum_base_bad.v:13:12: Enum type must be an integer atom or vector type (IEEE 1800-2023 6.19) +%Error: t/t_enum_base_bad.v:11:11: Enum data type must be an integer atom or vector type (IEEE 1800-2023 6.19), not 'struct{}t.s_t' : ... note: In instance 't' - 13 | typedef enum s_t { - | ^~~~ + 11 | typedef enum s_t { + | ^~~~ ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: t/t_enum_base_bad.v:16:3: Enum data type must be an integer atom or vector type (IEEE 1800-2023 6.19), not 'int[1:0]' + : ... note: In instance 't' + 16 | enum int_t [1:0] { + | ^~~~ +%Error: t/t_enum_base_bad.v:21:3: Enum data type must be an integer atom or vector type (IEEE 1800-2023 6.19), not 'bit[1:0][1:0]' + : ... note: In instance 't' + 21 | enum d2_t { + | ^~~~ +%Error: t/t_enum_base_bad.v:25:3: Enum data type must be an integer atom or vector type (IEEE 1800-2023 6.19), not 'logic[1:0][1:0]' + : ... note: In instance 't' + 25 | enum logic [1:0][1:0] { + | ^~~~ +%Error: t/t_enum_base_bad.v:30:3: Enum data type must be an integer atom or vector type (IEEE 1800-2023 6.19), not 'struct{}t.str_t' + : ... note: In instance 't' + 30 | enum str_t { + | ^~~~ +%Error: t/t_enum_base_bad.v:35:3: Enum data type must be an integer atom or vector type (IEEE 1800-2023 6.19), not 'enum{}t.enum_t' + : ... note: In instance 't' + 35 | enum enum_t { + | ^~~~ +%Error: t/t_enum_base_bad.v:40:3: Enum data type must be an integer atom or vector type (IEEE 1800-2023 6.19), not 'logic$[1:0]' + : ... note: In instance 't' + 40 | enum array2_t { + | ^~~~ %Error: Exiting due to diff --git a/test_regress/t/t_enum_base_bad.v b/test_regress/t/t_enum_base_bad.v index 2647b47e8..309bae927 100644 --- a/test_regress/t/t_enum_base_bad.v +++ b/test_regress/t/t_enum_base_bad.v @@ -4,20 +4,43 @@ // any use, without warranty, 2024 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 -module t(/*AUTOARG*/); +module t; - typedef struct { - int a; - } s_t; + typedef struct {int a;} s_t; - typedef enum s_t { - EN_ZERO } bad_t; + typedef enum s_t { // BAD + EN_ZERO + } bad_t; - typedef int int_t; + typedef int int_t; + enum int_t [1:0] { // BAD enum type + INTRANGE_VAL + } intrange_e; - typedef enum int_t { EN_ONE = 1 } ok1_t; + typedef bit [1:0][1:0] d2_t; + enum d2_t { // BAD enum type + TD2_VAL + } td2_e; - s_t s; - int_t i; + enum logic [1:0][1:0] { // BAD enum type + D2_VAL + } d2_e; + + typedef struct packed {int x;} str_t; + enum str_t { // BAD enum type + STR_VAL + } str_e; + + typedef enum {ENUM_VAL} enum_t; + enum enum_t { // BAD enum type + ENUMT_VAL + } enumt_val; + + typedef logic array2_t[1:0]; + enum array2_t { // BAD enum type + ARRAY2_VAL + } array2_e; + + initial $stop; endmodule