diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index a853690fe..92d9154b9 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2353,9 +2353,8 @@ class LinkDotResolveVisitor final : public VNVisitor { std::map m_usedPins; // Pin used in this cell, map to duplicate std::map m_modulesToRevisit; // Modules to revisit a second time AstNode* m_lastDeferredp = nullptr; // Last node which requested a revisit of its module - bool m_maybePackedArray - = false; // Array select parse trees may actually be packed array datatypes AstNodeDType* m_packedArrayDtp = nullptr; // Datatype reference for packed array + bool m_inPackedArray = false; // Currently traversing a packed array tree struct DotStates final { DotPosition m_dotPos; // Scope part of dotted resolution @@ -2811,7 +2810,7 @@ class LinkDotResolveVisitor final : public VNVisitor { // Early return() above when deleted } void visit(AstDot* nodep) override { - // Legal under a DOT: AstDot, AstParseRef, AstPackageRef, AstNodeSel + // Legal under a DOT: AstDot, AstParseRef, AstPackageRef, AstNodeSel, AstPackArrayDType // also a DOT can be part of an expression, but only above plus // AstFTaskRef are legal children // Dot(PackageRef, ParseRef(text)) @@ -3404,7 +3403,7 @@ class LinkDotResolveVisitor final : public VNVisitor { if (ok) { AstRefDType* const refp = new AstRefDType{nodep->fileline(), nodep->name()}; refp->typedefp(defp); - if (m_maybePackedArray) { + if (VN_IS(nodep->backp(), SelExtract)) { m_packedArrayDtp = refp; } else { replaceWithCheckBreak(nodep, refp); @@ -4058,11 +4057,7 @@ class LinkDotResolveVisitor final : public VNVisitor { AstNodeDType* packedArrayDtp = nullptr; // Datatype reference for packed array { VL_RESTORER(m_packedArrayDtp); - { - VL_RESTORER(m_maybePackedArray); - m_maybePackedArray = true; - iterateAndNextNull(nodep->fromp()); - } + iterateAndNextNull(nodep->fromp()); symIterateNull(nodep->rhsp(), m_curSymp); symIterateNull(nodep->thsp(), m_curSymp); @@ -4074,7 +4069,7 @@ class LinkDotResolveVisitor final : public VNVisitor { = new AstPackArrayDType(nodep->fileline(), m_packedArrayDtp, newRangep); newArrayTypep->childDTypep(m_packedArrayDtp); newArrayTypep->refDTypep(nullptr); - if (m_maybePackedArray) { + if (VN_IS(nodep->backp(), SelExtract)) { packedArrayDtp = newArrayTypep; } else { replaceWithCheckBreak(nodep, newArrayTypep); @@ -4576,8 +4571,13 @@ class LinkDotResolveVisitor final : public VNVisitor { void visit(AstAttrOf* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { - LINKDOT_VISIT_START(); - checkNoDot(nodep); + VL_RESTORER(m_inPackedArray); + if (VN_IS(nodep, PackArrayDType)) { + m_inPackedArray = true; + } else if (!m_inPackedArray) { + LINKDOT_VISIT_START(); + checkNoDot(nodep); + } iterateChildren(nodep); } diff --git a/test_regress/t/t_bitsel_2d_slice.py b/test_regress/t/t_bitsel_2d_slice.py new file mode 100755 index 000000000..c39e83d77 --- /dev/null +++ b/test_regress/t/t_bitsel_2d_slice.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_bitsel_2d_slice.v b/test_regress/t/t_bitsel_2d_slice.v new file mode 100644 index 000000000..c81e7be24 --- /dev/null +++ b/test_regress/t/t_bitsel_2d_slice.v @@ -0,0 +1,29 @@ +// 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 (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + localparam int width = 8; + typedef logic [width-1:0] [15:0] two_dee_t; + typedef logic[$clog2(width)-1:0] index_t; + + two_dee_t the_two_dee; + + initial begin + the_two_dee[index_t'(5)][7:0] = 8'hab; + the_two_dee[index_t'(5)][15:8] = 8'h12; + end + + always @ (posedge clk) begin + if (the_two_dee[5] != 16'h12ab) $stop(); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_type_param.v b/test_regress/t/t_type_param.v index 1bb4f7f9f..61ca69b19 100644 --- a/test_regress/t/t_type_param.v +++ b/test_regress/t/t_type_param.v @@ -4,6 +4,10 @@ // without warranty, 2019 by Todd Strader. // SPDX-License-Identifier: CC0-1.0 +package some_package; + typedef logic [15:0] two_bytes_t; +endpackage + module foo #(parameter type bar = logic) (output int bar_size); @@ -54,6 +58,11 @@ module t(); foo #(.bar (some_struct_t [2:0] [5:0])) foo_inst5 (.bar_size (bar_size5)); + int bar_size6; + + foo #(.bar (some_package::two_bytes_t [4-1:0])) + foo_inst6 (.bar_size (bar_size6)); + localparam bar_bits = 13; int bar_size_wrapper; @@ -106,6 +115,11 @@ module t(); bar_size5, $bits(some_struct_t) * 3 * 6); $stop(); end + if (bar_size6 != $bits(some_package::two_bytes_t)*4) begin + $display("%m: bar_size6 != bits of some_package::two_bytes_t * 4 (%0d, %0d)", + bar_size6, $bits(some_package::two_bytes_t) * 4); + $stop(); + end if (bar_size_wrapper != bar_bits) begin $display("%m: bar_size_wrapper != bar_bits (%0d, %0d)", bar_size_wrapper, bar_bits);