diff --git a/src/V3AstNodeDType.h b/src/V3AstNodeDType.h index be7973cd6..e407b5e2b 100644 --- a/src/V3AstNodeDType.h +++ b/src/V3AstNodeDType.h @@ -234,7 +234,7 @@ class AstNodeUOrStructDType VL_NOT_FINAL : public AstNodeDType { string m_name; // Name from upper typedef, if any const int m_uniqueNum; bool m_packed; - bool m_isFourstate = false; // V3Width computes + bool m_isFourstate = false; // V3Width computes; true if any member is 4-state bool m_constrainedRand = false; // True if struct has constraint expression protected: diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index b9e014a52..7f81ca8ae 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1871,9 +1871,11 @@ class LinkDotFindVisitor final : public VNVisitor { nextp = argp->nextp(); AstVar* argrefp = nullptr; if (AstParseRef* const parserefp = VN_CAST(argp, ParseRef)) { - // We use an int type, this might get changed in V3Width when types resolve + // IEEE 1800-2023 12.7.3: foreach loop variable type shall be int (2-state) + // This might get changed in V3Width when types resolve (e.g., for assoc + // arrays) argrefp = new AstVar{parserefp->fileline(), VVarType::BLOCKTEMP, - parserefp->name(), argp->findSigned32DType()}; + parserefp->name(), argp->findIntDType()}; argrefp->lifetime(VLifetime::AUTOMATIC_EXPLICIT); parserefp->replaceWith(argrefp); VL_DO_DANGLING2(parserefp->deleteTree(), parserefp, argp); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index c28de1b2a..54f5ada1e 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -5761,6 +5761,34 @@ class WidthVisitor final : public VNVisitor { } } + // IEEE 1800-2023 7.6: For unpacked arrays to be assignment compatible, + // the element types shall be equivalent (IEEE 1800-2023 6.22.2). + // Check specifically for 2-state vs 4-state mismatch for unpacked array + // to unpacked array assignments, as this is a common IEEE compliance issue. + // Note: Streaming operators and string literals have implicit conversion rules. + if (nodep->rhsp()->dtypep()) { // May be null on earlier errors + const AstNodeDType* const lhsDtp = lhsDTypep->skipRefp(); + const AstNodeDType* const rhsDtp = nodep->rhsp()->dtypep()->skipRefp(); + // Only check unpacked array to unpacked array assignments + const bool lhsIsUnpackArray + = VN_IS(lhsDtp, UnpackArrayDType) || VN_IS(lhsDtp, DynArrayDType) + || VN_IS(lhsDtp, QueueDType) || VN_IS(lhsDtp, AssocArrayDType); + const bool rhsIsUnpackArray + = VN_IS(rhsDtp, UnpackArrayDType) || VN_IS(rhsDtp, DynArrayDType) + || VN_IS(rhsDtp, QueueDType) || VN_IS(rhsDtp, AssocArrayDType); + if (lhsIsUnpackArray && rhsIsUnpackArray) { + if (lhsDtp->isFourstate() != rhsDtp->isFourstate()) { + nodep->v3error( + "Assignment between 2-state and 4-state types requires " + "equivalent element types (IEEE 1800-2023 6.22.2, 7.6)\n" + << nodep->warnMore() << "... LHS type: " << lhsDtp->prettyDTypeNameQ() + << (lhsDtp->isFourstate() ? " (4-state)" : " (2-state)") << "\n" + << nodep->warnMore() << "... RHS type: " << rhsDtp->prettyDTypeNameQ() + << (rhsDtp->isFourstate() ? " (4-state)" : " (2-state)")); + } + } + } + iterateCheckAssign(nodep, "Assign RHS", nodep->rhsp(), FINAL, lhsDTypep); // UINFOTREE(1, nodep, "", "AssignOut"); } diff --git a/test_regress/t/t_fourstate_assign.py b/test_regress/t/t_fourstate_assign.py new file mode 100755 index 000000000..e41ab0cdd --- /dev/null +++ b/test_regress/t/t_fourstate_assign.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2026 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_fourstate_assign.v b/test_regress/t/t_fourstate_assign.v new file mode 100644 index 000000000..84f46fc7e --- /dev/null +++ b/test_regress/t/t_fourstate_assign.v @@ -0,0 +1,41 @@ +// DESCRIPTION: Test for IEEE 1800-2023 6.22.2 - valid array assignments with matching state types +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2026 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + // 2-state arrays - assignment should work + bit [7:0] arr_2state_a [3:0]; + bit [7:0] arr_2state_b [3:0]; + + // 4-state arrays - assignment should work + logic [7:0] arr_4state_a [3:0]; + logic [7:0] arr_4state_b [3:0]; + + initial begin + // Initialize + arr_2state_a[0] = 8'h10; + arr_2state_a[1] = 8'h20; + arr_2state_a[2] = 8'h30; + arr_2state_a[3] = 8'h40; + + arr_4state_a[0] = 8'hA0; + arr_4state_a[1] = 8'hB0; + arr_4state_a[2] = 8'hC0; + arr_4state_a[3] = 8'hD0; + + // Valid assignments: same state types + arr_2state_b = arr_2state_a; // 2-state to 2-state: OK + arr_4state_b = arr_4state_a; // 4-state to 4-state: OK + + // Verify + if (arr_2state_b[0] !== 8'h10) $stop; + if (arr_2state_b[3] !== 8'h40) $stop; + if (arr_4state_b[0] !== 8'hA0) $stop; + if (arr_4state_b[3] !== 8'hD0) $stop; + + $write("*-* All Coverage *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_fourstate_assign_bad.out b/test_regress/t/t_fourstate_assign_bad.out new file mode 100644 index 000000000..e6a85af1b --- /dev/null +++ b/test_regress/t/t_fourstate_assign_bad.out @@ -0,0 +1,8 @@ +%Error: t/t_fourstate_assign_bad.v:23:18: Assignment between 2-state and 4-state types requires equivalent element types (IEEE 1800-2023 6.22.2, 7.6) + : ... note: In instance 't' + : ... LHS type: 'bit[7:0]$[3:0]' (2-state) + : ... RHS type: 'logic[7:0]$[3:0]' (4-state) + 23 | arr_2state = arr_4state; + | ^ + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: Exiting due to diff --git a/test_regress/t/t_fourstate_assign_bad.py b/test_regress/t/t_fourstate_assign_bad.py new file mode 100755 index 000000000..392b50fb6 --- /dev/null +++ b/test_regress/t/t_fourstate_assign_bad.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2026 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() diff --git a/test_regress/t/t_fourstate_assign_bad.v b/test_regress/t/t_fourstate_assign_bad.v new file mode 100644 index 000000000..9fce8ec11 --- /dev/null +++ b/test_regress/t/t_fourstate_assign_bad.v @@ -0,0 +1,27 @@ +// DESCRIPTION: Test for IEEE 1800-2023 6.22.2 - 4-state to 2-state type equivalence +// This should produce a type error because bit and logic are not equivalent types +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2026 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + // IEEE 6.22.2: Packed arrays are equivalent if they contain the same number + // of total bits, are either all 2-state or all 4-state, and are either all + // signed or all unsigned. + + // 2-state array + bit [7:0] arr_2state [3:0]; + + // 4-state array (should not be assignment compatible for unpacked arrays) + logic [7:0] arr_4state [3:0]; + + initial begin + // Per IEEE 7.6: For unpacked arrays to be assignment compatible, + // the element types shall be equivalent. + // bit[7:0] and logic[7:0] are NOT equivalent (one is 2-state, one is 4-state) + arr_2state = arr_4state; + $write("*-* All Coverage *-*\n"); + $stop; + end +endmodule