diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index cd20c437b..d61bb0102 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -206,6 +206,7 @@ Maciej Sobkowski Marcel Chang Marco Bartoli Marco Brambilla +Marco Frank Marco Widmer Mariusz Glebocki Markus Krause diff --git a/include/verilated_types.h b/include/verilated_types.h index dd2d25d99..4d1eaed57 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -1468,6 +1468,14 @@ public: constexpr std::size_t size() const { return N_Depth; } + // Runtime slice v[loIdx +: N_Out], loIdx being an index into m_storage + template + VlUnpacked slice(int32_t loIdx) const { + VlUnpacked out; + for (std::size_t i = 0; i < N_Out; ++i) out.m_storage[i] = m_storage[loIdx + i]; + return out; + } + void fill(const T_Value& value) { std::fill(std::begin(m_storage), std::end(m_storage), value); } diff --git a/src/V3AstAttr.h b/src/V3AstAttr.h index be33e611b..3232816b3 100644 --- a/src/V3AstAttr.h +++ b/src/V3AstAttr.h @@ -854,6 +854,7 @@ inline std::ostream& operator<<(std::ostream& os, const VBranchPred& rhs) { macro(ARRAY_R_SUM, "r_sum", PURE, "") \ macro(ARRAY_R_XOR, "r_xor", PURE, "") \ macro(ARRAY_SHUFFLE, "shuffle", false, "") \ + macro(ARRAY_SLICE, "slice", PURE, "r") \ macro(ARRAY_SORT, "sort", false, "") \ macro(ARRAY_UNIQUE, "unique", PURE, "") \ macro(ARRAY_UNIQUE_INDEX, "unique_index", PURE, "") \ diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 7fb0d0bd3..bea412aa9 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -808,6 +808,11 @@ public: if (nodep->method() == VCMethod::FORCE_READ_SEL) { emitIQW(nodep); if (nodep->isWide()) puts("<" + cvtToStr(nodep->dtypep()->widthWords()) + ">"); + } else if (nodep->method() == VCMethod::ARRAY_SLICE) { + // VlUnpacked::slice(loIdx) - N_Out is the (fixed) result array size + const AstUnpackArrayDType* const adtypep + = VN_AS(nodep->dtypep()->skipRefp(), UnpackArrayDType); + puts("<" + cvtToStr(adtypep->elementsConst()) + ">"); } puts("("); bool comma = false; diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp index 6b306f90b..68a86471c 100644 --- a/src/V3Slice.cpp +++ b/src/V3Slice.cpp @@ -382,6 +382,23 @@ class SliceVisitor final : public VNVisitor { void visit(AstEqCase* nodep) override { expandBiOp(nodep); } void visit(AstNeqCase* nodep) override { expandBiOp(nodep); } + void visit(AstSliceSel* nodep) override { + // Slice used as a bare value, e.g. a $display argument. Build it via + // VlUnpacked::slice(loIdx), as DYN_SLICE already does for Queues. + iterateChildren(nodep); + AstNodeExpr* const fromp = nodep->fromp()->unlinkFrBack(); + AstConst* const lop = new AstConst{nodep->fileline(), AstConst::WidthedValue{}, 32, + static_cast(nodep->declRange().lo())}; + AstCMethodHard* const newp + = new AstCMethodHard{nodep->fileline(), fromp, VCMethod::ARRAY_SLICE}; + newp->addPinsp(lop); + newp->dtypeFrom(nodep); // Reuse the already-correct sliced array dtype + newp->didWidth(true); + newp->protect(false); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: diff --git a/test_regress/t/t_slice_display.py b/test_regress/t/t_slice_display.py new file mode 100755 index 000000000..8a938befd --- /dev/null +++ b/test_regress/t/t_slice_display.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_slice_display.v b/test_regress/t/t_slice_display.v new file mode 100644 index 000000000..a3568d321 --- /dev/null +++ b/test_regress/t/t_slice_display.v @@ -0,0 +1,75 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Marco Frank +// SPDX-License-Identifier: CC0-1.0 + +// verilog_format: off +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0) +// verilog_format: on + +// Issue #5132: an array slice used as a bare value (not the LHS/RHS of an +// assignment) hit an internal error. +module t; + byte mem[8] = '{1, 2, 3, 4, 5, 6, 7, 8}; + byte dmem[7:0] = '{10, 20, 30, 40, 50, 60, 70, 80}; + byte sub[4]; + + // Ascending declaration with a non-zero low index + byte emem[5:12] = '{201, 202, 203, 204, 205, 206, 207, 208}; + + // Wide descending declaration with a non-zero low index + logic [95:0] memwide[10:6] = '{96'hE444_4444_4444_4444_4444_4444, 96'hA000_0000_0000_0000_0000_0001, + 96'hB111_1111_1111_1111_1111_1111, 96'hC222_2222_2222_2222_2222_2222, + 96'hD333_3333_3333_3333_3333_3333}; + + // For slicing the inner and outer dimensions of a 2D array + byte mem2d[3][8] = '{'{1, 2, 3, 4, 5, 6, 7, 8}, '{11, 12, 13, 14, 15, 16, 17, 18}, + '{21, 22, 23, 24, 25, 26, 27, 28}}; + + task automatic check_arg(byte a[4]); + `checkh(a[0], 8'd1); + `checkh(a[3], 8'd4); + endtask + + initial begin + $display("%p", mem[0:3]); + + `checkh(mem[2:5][2], 8'd3); + `checkh(mem[2:5][5], 8'd6); + + `checkh(dmem[5:2][5], 8'd30); + `checkh(dmem[5:2][2], 8'd60); + + check_arg(mem[0:3]); + + `checkh(mem[0:3][2], 8'd3); + + sub = mem[0:3]; + `checkh(sub[0], 8'd1); + `checkh(sub[3], 8'd4); + + // Indexing into a slice result uses the source array's index minus the + // source array's own low bound (5 here), not the slice's own bounds. + $display("%p", emem[7:10]); + `checkh(emem[7:10][2], 8'd203); + `checkh(emem[7:10][5], 8'd206); + + $display("%p", memwide[8:6]); + + $display("%p %p", mem[1:2], dmem[6:4]); + + $display("%p", mem2d[1][2:4]); + `checkh(mem2d[1][2:4][2], 8'd13); + `checkh(mem2d[1][2:4][4], 8'd15); + + // Slicing the outer dimension yields rows (each still an array), not elements + $display("%p", mem2d[0:1]); + `checkh(mem2d[0:1][0][0], 8'd1); + `checkh(mem2d[0:1][1][3], 8'd14); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule