From f753ae25188b5aa70aaecd4fe87ab67b32e4368d Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Tue, 11 Feb 2025 18:06:34 +0100 Subject: [PATCH] Support selects on arbitrary string expressions (#5773) --- src/V3WidthSel.cpp | 16 ++++++--- test_regress/t/t_string_sel.py | 18 ++++++++++ test_regress/t/t_string_sel.v | 60 ++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 5 deletions(-) create mode 100755 test_regress/t/t_string_sel.py create mode 100644 test_regress/t/t_string_sel.v diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp index 7073cf8d4..4bb38eb1f 100644 --- a/src/V3WidthSel.cpp +++ b/src/V3WidthSel.cpp @@ -305,13 +305,19 @@ class WidthSelVisitor final : public VNVisitor { VL_DO_DANGLING(pushDeletep(nodep), nodep); } else if (VN_IS(ddtypep, BasicDType) && ddtypep->isString()) { // SELBIT(string, index) -> GETC(string, index) - const AstNodeVarRef* const varrefp = VN_CAST(fromp, NodeVarRef); - if (!varrefp) { - nodep->v3warn(E_UNSUPPORTED, - "Unsupported: String array operation on non-variable"); + AstNodeExpr* exprp = fromp; + while (true) { + if (AstMemberSel* const memberselp = VN_CAST(exprp, MemberSel)) { + exprp = memberselp->fromp(); + } else if (AstStructSel* const structselp = VN_CAST(exprp, StructSel)) { + exprp = structselp->fromp(); + } else { + break; + } } + const AstNodeVarRef* const varrefp = VN_CAST(exprp, NodeVarRef); AstNodeExpr* newp; - if (varrefp && varrefp->access().isReadOnly()) { + if (!varrefp || varrefp->access().isReadOnly()) { newp = new AstGetcN{nodep->fileline(), fromp, rhsp}; } else { newp = new AstGetcRefN{nodep->fileline(), fromp, rhsp}; diff --git a/test_regress/t/t_string_sel.py b/test_regress/t/t_string_sel.py new file mode 100755 index 000000000..b7a43ed66 --- /dev/null +++ b/test_regress/t/t_string_sel.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('vlt') + +test.compile() + +test.execute() + +test.passes() diff --git a/test_regress/t/t_string_sel.v b/test_regress/t/t_string_sel.v new file mode 100644 index 000000000..acf7478e9 --- /dev/null +++ b/test_regress/t/t_string_sel.v @@ -0,0 +1,60 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2025 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +typedef struct { + string str; +} str_s; + +class c; + string str; + function new(); + str = "foo"; + endfunction + function string get_str(); + return str; + endfunction +endclass + +module t (/*AUTOARG*/); + string str = "bar"; + + function string get_str(); + return str; + endfunction + + initial begin + c o = new; + str_s st = '{"qux"}; + string sc = {"foo", "bar"}; + + // read + if (str[0] != "b") $stop; + if (get_str()[1] != "a") $stop; + if (str[3] != "\0") $stop; + if (st.str[2] != "x") $stop; + if (st.str[99] != "\0") $stop; + if (o.str[0] != "f") $stop; + if (o.get_str()[1] != "o") $stop; + if (o.str[-1] != "\0") $stop; + if (sc[2] != "o") $stop; + if ($sformatf("foo%s", "bar")[3] != "b") $stop; + if (sc[-1] != "\0") $stop; + if (sc[6] != "\0") $stop; + if (sc[99] != "\0") $stop; + + // write + sc[5] = "z"; + if (sc != "foobaz") $stop; + o.str[0] = "b"; + if (o.str != "boo") $stop; + st.str[2] = "z"; + if (st.str != "quz") $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule