diff --git a/include/verilated_types.h b/include/verilated_types.h index 5e030bc20..80553e039 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -613,6 +613,11 @@ public: m_deque.insert(m_deque.begin() + index, value); } + // inside (set membership operator) + bool inside(const T_Value& value) const { + return std::find(m_deque.begin(), m_deque.end(), value) != m_deque.end(); + } + // Return slice q[lsb:msb] VlQueue slice(int32_t lsb, int32_t msb) const { VlQueue out; @@ -1308,6 +1313,11 @@ public: bool operator==(const VlUnpacked& that) const { return !neq(that); } bool operator!=(const VlUnpacked& that) { return neq(that); } + // inside (set membership operator) + bool inside(const T_Value& value) const { + return std::find(std::begin(m_storage), std::end(m_storage), value) != std::end(m_storage); + } + void sort() { std::sort(std::begin(m_storage), std::end(m_storage)); } template void sort(Func with_func) { diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 8fcf46840..cceeaae55 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -2252,6 +2252,7 @@ void AstCMethodHard::setPurity() { {"first", false}, {"init", false}, {"insert", false}, + {"inside", true}, {"isFired", true}, {"isTriggered", true}, {"join", false}, diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 9fb54b425..49aa1d1fb 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2555,16 +2555,16 @@ class WidthVisitor final : public VNVisitor { // Similar logic in V3Case inewp = irangep->newAndFromInside(nodep->exprp(), irangep->lhsp()->unlinkFrBack(), irangep->rhsp()->unlinkFrBack()); - } else if (VN_IS(itemDtp, UnpackArrayDType)) { - nodep->v3error("Unsupported: inside (set membership operator) on unpacked array"); - // Need the AstInside type to persist, then - // for parameters, need V3Simulate support. - // For non-parameters, need runtime support. - continue; - } else if (VN_IS(itemDtp, AssocArrayDType) || VN_IS(itemDtp, DynArrayDType) + } else if (VN_IS(itemDtp, UnpackArrayDType) || VN_IS(itemDtp, DynArrayDType) || VN_IS(itemDtp, QueueDType)) { - nodep->v3error( - "Inside operator not legal on non-unpacked arrays (IEEE 1800-2017 11.4.13)"); + // Unsupported in parameters + inewp = new AstCMethodHard{itemp->fileline(), itemp->unlinkFrBack(), "inside", + nodep->exprp()->cloneTreePure(true)}; + inewp->dtypeSetBit(); + inewp->didWidth(true); + } else if (VN_IS(itemDtp, AssocArrayDType)) { + nodep->v3error("Inside operator not specified on associative arrays (IEEE " + "1800-2017 11.4.13)"); continue; } else { inewp = AstEqWild::newTyped(itemp->fileline(), nodep->exprp()->cloneTreePure(true), diff --git a/test_regress/t/t_inside_assoc_unsup.out b/test_regress/t/t_inside_assoc_unsup.out new file mode 100644 index 000000000..5fbed6e4f --- /dev/null +++ b/test_regress/t/t_inside_assoc_unsup.out @@ -0,0 +1,5 @@ +%Error: t/t_inside_assoc_unsup.v:12:15: Inside operator not specified on associative arrays (IEEE 1800-2017 11.4.13) + : ... note: In instance 't' + 12 | m = (10 inside {assoc}); + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_inside_queue_bad.pl b/test_regress/t/t_inside_assoc_unsup.pl similarity index 100% rename from test_regress/t/t_inside_queue_bad.pl rename to test_regress/t/t_inside_assoc_unsup.pl diff --git a/test_regress/t/t_inside_queue_bad.v b/test_regress/t/t_inside_assoc_unsup.v similarity index 79% rename from test_regress/t/t_inside_queue_bad.v rename to test_regress/t/t_inside_assoc_unsup.v index 4e3e0c9a8..c5b261233 100644 --- a/test_regress/t/t_inside_queue_bad.v +++ b/test_regress/t/t_inside_assoc_unsup.v @@ -5,16 +5,11 @@ // SPDX-License-Identifier: CC0-1.0 module t(/*AUTOARG*/); - - int q[$]; int assoc[int]; - int dyn[]; bit m; initial begin - m = (10 inside {q}); m = (10 inside {assoc}); - m = (10 inside {dyn}); end endmodule diff --git a/test_regress/t/t_inside_dyn.pl b/test_regress/t/t_inside_dyn.pl new file mode 100755 index 000000000..1aa73f80a --- /dev/null +++ b/test_regress/t/t_inside_dyn.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 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 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_inside_dyn.v b/test_regress/t/t_inside_dyn.v new file mode 100644 index 000000000..e07b9fdc1 --- /dev/null +++ b/test_regress/t/t_inside_dyn.v @@ -0,0 +1,22 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t; + int q[$] = '{1, 2, 3}; + bit dyn[] = '{0, 0}; + + initial begin + if (!(1 inside {q})) $stop; + if (4 inside {q}) $stop; + if (!(4 inside {q, 4})) $stop; + + if (!(0 inside {dyn})) $stop; + if (1 inside {dyn}) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_inside_queue_bad.out b/test_regress/t/t_inside_queue_bad.out deleted file mode 100644 index 37b7be1ad..000000000 --- a/test_regress/t/t_inside_queue_bad.out +++ /dev/null @@ -1,13 +0,0 @@ -%Error: t/t_inside_queue_bad.v:15:15: Inside operator not legal on non-unpacked arrays (IEEE 1800-2017 11.4.13) - : ... note: In instance 't' - 15 | m = (10 inside {q}); - | ^~~~~~ -%Error: t/t_inside_queue_bad.v:16:15: Inside operator not legal on non-unpacked arrays (IEEE 1800-2017 11.4.13) - : ... note: In instance 't' - 16 | m = (10 inside {assoc}); - | ^~~~~~ -%Error: t/t_inside_queue_bad.v:17:15: Inside operator not legal on non-unpacked arrays (IEEE 1800-2017 11.4.13) - : ... note: In instance 't' - 17 | m = (10 inside {dyn}); - | ^~~~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_inside_unpacked.pl b/test_regress/t/t_inside_unpacked.pl index 40f69d41d..9a15dd2cc 100755 --- a/test_regress/t/t_inside_unpacked.pl +++ b/test_regress/t/t_inside_unpacked.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); execute( check_finished => 1, - ) if !$Self->{vlt_all}; + ); ok(1); 1; diff --git a/test_regress/t/t_inside_unpacked.v b/test_regress/t/t_inside_unpacked.v index 0b0760fd8..a3d203674 100644 --- a/test_regress/t/t_inside_unpacked.v +++ b/test_regress/t/t_inside_unpacked.v @@ -10,18 +10,6 @@ module t(/*AUTOARG*/ ); input clk; - localparam int CHECKLIST_P [2:0] = '{0, 1, 2}; - - localparam HIT_LP = 1; - localparam MISS_LP = 4; - localparam HIT_INSIDE = HIT_LP inside {CHECKLIST_P}; - localparam MISS_INSIDE = MISS_LP inside {CHECKLIST_P}; - - initial begin - if (HIT_INSIDE != 1) $stop; - if (MISS_INSIDE != 0) $stop; - end - integer cyc = 0; int array [10]; diff --git a/test_regress/t/t_inside_unpacked_param.out b/test_regress/t/t_inside_unpacked_param.out new file mode 100644 index 000000000..0cae5353d --- /dev/null +++ b/test_regress/t/t_inside_unpacked_param.out @@ -0,0 +1,9 @@ +%Error: t/t_inside_unpacked_param.v:13:43: Expecting expression to be constant, but can't convert a CMETHODHARD 'inside' to constant. + : ... note: In instance 't' + 13 | localparam HIT_INSIDE = HIT_LP inside {CHECKLIST_P}; + | ^~~~~~~~~~~ +%Error: t/t_inside_unpacked_param.v:14:45: Expecting expression to be constant, but can't convert a CMETHODHARD 'inside' to constant. + : ... note: In instance 't' + 14 | localparam MISS_INSIDE = MISS_LP inside {CHECKLIST_P}; + | ^~~~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_inside_unpacked_param.pl b/test_regress/t/t_inside_unpacked_param.pl new file mode 100755 index 000000000..40f69d41d --- /dev/null +++ b/test_regress/t/t_inside_unpacked_param.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2019 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 + +scenarios(simulator => 1); + +compile( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; + +ok(1); +1; diff --git a/test_regress/t/t_inside_unpacked_param.v b/test_regress/t/t_inside_unpacked_param.v new file mode 100644 index 000000000..10f227af8 --- /dev/null +++ b/test_regress/t/t_inside_unpacked_param.v @@ -0,0 +1,22 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + + localparam int CHECKLIST_P [2:0] = '{0, 1, 2}; + + localparam HIT_LP = 1; + localparam MISS_LP = 4; + localparam HIT_INSIDE = HIT_LP inside {CHECKLIST_P}; + localparam MISS_INSIDE = MISS_LP inside {CHECKLIST_P}; + + initial begin + if (HIT_INSIDE != 1) $stop; + if (MISS_INSIDE != 0) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule