From 228635918ed08902528a10fdfd082ddc82b74dbc Mon Sep 17 00:00:00 2001 From: Aditya Shevade Date: Thu, 3 Sep 2026 17:08:44 -0700 Subject: [PATCH] Fix mis-randomizing an unpacked struct member when not rand/randc (#8277) (#8278) --- src/V3Randomize.cpp | 4 ++- test_regress/t/t_randomize_method.v | 8 +++-- ...ndomize_unpacked_struct_no_rand_members.py | 18 ++++++++++ ...andomize_unpacked_struct_no_rand_members.v | 36 +++++++++++++++++++ 4 files changed, 62 insertions(+), 4 deletions(-) create mode 100755 test_regress/t/t_randomize_unpacked_struct_no_rand_members.py create mode 100644 test_regress/t/t_randomize_unpacked_struct_no_rand_members.v diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 96eb0f176..6ddd0d783 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -4073,7 +4073,9 @@ class RandomizeVisitor final : public VNVisitor { if (structDtp->packed()) { randp = newRandStmtsp(fl, stmtsp ? exprp->cloneTree(false) : exprp, nullptr, outputVarp, offset, smemberp); - } else { + } else if (smemberp->rand().isRandomizable()) { + // IEEE 1800-2023 18.4: an unpacked struct member is only + // randomized if its own declaration carries rand/randc. AstStructSel* structSelp = new AstStructSel{fl, exprp->cloneTree(false), smemberp->name()}; structSelp->dtypep(smemberp->childDTypep()); diff --git a/test_regress/t/t_randomize_method.v b/test_regress/t/t_randomize_method.v index eed69f2ed..33cc38cdd 100644 --- a/test_regress/t/t_randomize_method.v +++ b/test_regress/t/t_randomize_method.v @@ -41,9 +41,9 @@ typedef struct packed { } StructOuter; typedef struct { - int i; - StructOuter j; - Enum k; + rand int i; + rand StructOuter j; + rand Enum k; longint z; } StructUnpacked; @@ -117,6 +117,7 @@ class OtherCls; str.i = 0; str.j = '{x: 1'b0, y: ONE, z: 64'd0, s: '{a: 32'd0, b: 1'b0, c: ONE}}; str.k = ONE; + str.z = 0; endfunction endclass @@ -189,6 +190,7 @@ module t; if (derived1.i.e != 0) $stop; if (derived1.k != 0) $stop; if (other.v != 0) $stop; + if (other.str.z != 0) $stop; if (cont.b != null) $stop; if (der_int.b != 0) $stop; if (der_contain.cls2.a != 0) $stop; diff --git a/test_regress/t/t_randomize_unpacked_struct_no_rand_members.py b/test_regress/t/t_randomize_unpacked_struct_no_rand_members.py new file mode 100755 index 000000000..8a938befd --- /dev/null +++ b/test_regress/t/t_randomize_unpacked_struct_no_rand_members.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# 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_randomize_unpacked_struct_no_rand_members.v b/test_regress/t/t_randomize_unpacked_struct_no_rand_members.v new file mode 100644 index 000000000..94ff0205d --- /dev/null +++ b/test_regress/t/t_randomize_unpacked_struct_no_rand_members.v @@ -0,0 +1,36 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Aditya Shevade +// SPDX-License-Identifier: CC0-1.0 + +// IEEE 1800-2023 18.4: a member of an unpacked struct is random only if +// its own declaration carries rand/randc; the containing struct being +// rand does not imply that. Here no member does, so randomize() on obj +// must leave the whole struct untouched. +typedef struct { + int a; + bit [7:0] b; +} AllUnmarked; + +class C; + rand AllUnmarked s; + function new(); + s.a = 42; + s.b = 8'ha5; + endfunction +endclass + +module t; + initial begin + C obj; + obj = new; + repeat (10) begin + if (obj.randomize() == 0) $stop; + if (obj.s.a != 42) $stop; + if (obj.s.b != 8'ha5) $stop; + end + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule