diff --git a/include/verilated_types.h b/include/verilated_types.h index b1cd61c80..a0f007d79 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -804,6 +804,17 @@ public: } return VlQueue{}; } + // Map method (IEEE 1800-2023 7.12.5) + template + VlQueue> map(T_Func with_func) const { + VlQueue> out; + IData index = 0; + for (const auto& i : m_deque) { + out.push_back(with_func(index, i)); + ++index; + } + return out; + } // Reduction operators VlQueue min() const { @@ -1532,6 +1543,13 @@ public: } return VlQueue{}; } + // Map method (IEEE 1800-2023 7.12.5) + template + VlQueue> map(T_Func with_func) const { + VlQueue> out; + for (IData i = 0; i < N_Depth; ++i) out.push_back(with_func(i, m_storage[i])); + return out; + } // Reduction operators VlQueue min() const { diff --git a/src/V3AstAttr.h b/src/V3AstAttr.h index 4d383337e..eebe39a92 100644 --- a/src/V3AstAttr.h +++ b/src/V3AstAttr.h @@ -758,6 +758,7 @@ public: ARRAY_FIRST, ARRAY_INSIDE, ARRAY_LAST, + ARRAY_MAP, ARRAY_MAX, ARRAY_MIN, ARRAY_NEXT, @@ -903,6 +904,7 @@ inline std::ostream& operator<<(std::ostream& os, const VCMethod& rhs) { {ARRAY_FIRST, "first", false}, \ {ARRAY_INSIDE, "inside", true}, \ {ARRAY_LAST, "last", false}, \ + {ARRAY_MAP, "map", true}, \ {ARRAY_MAX, "max", true}, \ {ARRAY_MIN, "min", true}, \ {ARRAY_NEXT, "next", false}, \ diff --git a/src/V3Width.cpp b/src/V3Width.cpp index b0e949f87..3e58a3481 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -4241,9 +4241,18 @@ class WidthVisitor final : public VNVisitor { newp->dtypep(newp->findQueueIndexDType()); if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else if (nodep->name() == "map") { - nodep->v3warn(E_UNSUPPORTED, - "Unsupported: Array 'map' method (IEEE 1800-2023 7.12.5)"); - nodep->dtypeFrom(adtypep->subDTypep()); // Best guess + // map() - IEEE 1800-2023 7.12.5 + // Returns a queue with same element count, each element is the with expression result + AstWith* const withp + = methodWithClause(nodep, true, false, adtypep->subDTypep(), + nodep->findUInt32DType(), adtypep->subDTypep()); + methodOkArguments(nodep, 0, 0); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); + newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), + VCMethod::ARRAY_MAP}; + newp->withp(withp); + newp->dtypep(queueDTypeIndexedBy(withp ? withp->dtypep() : adtypep->subDTypep())); + if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } return newp; } diff --git a/test_regress/t/t_array_method.v b/test_regress/t/t_array_method.v index 186046820..3b1c1921e 100644 --- a/test_regress/t/t_array_method.v +++ b/test_regress/t/t_array_method.v @@ -114,6 +114,13 @@ module t; i = q.xor with (item + 1); `checkh(i, 32'hb); + // map method + q = '{1, 2, 3, 4, 5}; + qv = q.map() with (item * 2); + `checkp(qv, "'{'h2, 'h4, 'h6, 'h8, 'ha}"); + qv = q.map(x) with (x + x.index); + `checkp(qv, "'{'h1, 'h3, 'h5, 'h7, 'h9}"); + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_array_method_map.out b/test_regress/t/t_array_method_map.out deleted file mode 100644 index 3e1bac262..000000000 --- a/test_regress/t/t_array_method_map.out +++ /dev/null @@ -1,11 +0,0 @@ -%Error-UNSUPPORTED: t/t_array_method_map.v:19:13: Unsupported: Array 'map' method (IEEE 1800-2023 7.12.5) - : ... note: In instance 't' - 19 | res = a.map(el) with (el == 200); - | ^~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error: t/t_array_method_map.v:19:13: Unknown built-in array method 'map' - : ... note: In instance 't' - 19 | res = a.map(el) with (el == 200); - | ^~~ - ... 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_array_method_map.py b/test_regress/t/t_array_method_map.py deleted file mode 100755 index 20b96a7d7..000000000 --- a/test_regress/t/t_array_method_map.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/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: 2024 Wilson Snyder -# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 - -import vltest_bootstrap - -test.scenarios('simulator') - -test.compile(fails=test.vlt_all, expect_filename=test.golden_filename) - -if not test.vlt_all: - test.execute() - -test.passes() diff --git a/test_regress/t/t_array_method_map.v b/test_regress/t/t_array_method_map.v deleted file mode 100644 index 849307035..000000000 --- a/test_regress/t/t_array_method_map.v +++ /dev/null @@ -1,25 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed under the Creative Commons Public Domain. -// SPDX-FileCopyrightText: 2024 Wilson Snyder -// 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 - -module t; - - initial begin - automatic int res[]; - automatic int a[3] = '{100, 200, 300}; - - // TODO results not known to be correct - res = a.map(el) with (el == 200); - `checkh(res.size, 3); - `checkh(res[0], 0); - `checkh(res[1], 1); - `checkh(res[2], 0); - end -endmodule diff --git a/test_regress/t/t_queue_method.v b/test_regress/t/t_queue_method.v index 743bc4716..3e57ca148 100644 --- a/test_regress/t/t_queue_method.v +++ b/test_regress/t/t_queue_method.v @@ -254,6 +254,16 @@ module t; b = string_q.product with (item inside {"a", "bc", "def", "ghij"}); `checkh(b, 1'b1); + // map method + q = '{1, 2, 3, 4, 5}; + qv = q.map() with (item * 2); + `checkp(qv, "'{'h2, 'h4, 'h6, 'h8, 'ha}"); + qv = q.map(x) with (x + x.index); + `checkp(qv, "'{'h1, 'h3, 'h5, 'h7, 'h9}"); + qe.delete(); + qv = qe.map() with (item * 2); + `checkh(qv.size, 0); + $write("*-* All Finished *-*\n"); $finish; end