diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 52b564683..9d6b45872 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2386,6 +2386,10 @@ private: newp->protect(false); newp->makeStatement(); } + } else if (nodep->name() == "sort" || nodep->name() == "rsort" + || nodep->name() == "reverse" || nodep->name() == "shuffle") { + nodep->v3error("Array method " << nodep->prettyNameQ() + << " not legal on associative arrays"); } else { nodep->v3error("Unknown built-in associative array method " << nodep->prettyNameQ()); } diff --git a/test_regress/t/t_array_method.out b/test_regress/t/t_array_method.out new file mode 100644 index 000000000..949655f73 --- /dev/null +++ b/test_regress/t/t_array_method.out @@ -0,0 +1,70 @@ +%Error-UNSUPPORTED: t/t_array_method.v:26:14: Unsupported: with statements + 26 | q.sort with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:28:17: Unsupported: with statements + 28 | q.sort(x) with (x == 3); + | ^~~~ +%Error: t/t_array_method.v:28:14: Can't find definition of variable: 'x' + 28 | q.sort(x) with (x == 3); + | ^ +%Error-UNSUPPORTED: t/t_array_method.v:30:18: Unsupported: with statements + 30 | qe.sort(x) with (x == 3); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:35:15: Unsupported: with statements + 35 | q.rsort with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:37:19: Unsupported: with statements + 37 | qe.rsort(x) with (x == 3); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:57:19: Unsupported: with statements + 57 | qv = q.find with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:59:25: Unsupported: with statements + 59 | qv = q.find_index with (item == 2); qv.sort; + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:61:25: Unsupported: with statements + 61 | qv = q.find_first with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:63:31: Unsupported: with statements + 63 | qv = q.find_first_index with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:65:24: Unsupported: with statements + 65 | qv = q.find_last with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:67:30: Unsupported: with statements + 67 | qv = q.find_last_index with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:70:19: Unsupported: with statements + 70 | qv = q.find with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:72:25: Unsupported: with statements + 72 | qv = q.find_index with (item == 20); qv.sort; + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:74:25: Unsupported: with statements + 74 | qv = q.find_first with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:76:31: Unsupported: with statements + 76 | qv = q.find_first_index with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:78:24: Unsupported: with statements + 78 | qv = q.find_last with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:80:30: Unsupported: with statements + 80 | qv = q.find_last_index with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:96:17: Unsupported: with statements + 96 | i = q.sum with (item + 1); do if ((i) !== (32'h11)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",96, (i), (32'h11)); $stop; end while(0);; + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:98:21: Unsupported: with statements + 98 | i = q.product with (item + 1); do if ((i) !== (32'h168)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",98, (i), (32'h168)); $stop; end while(0);; + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:105:17: Unsupported: with statements + 105 | i = q.and with (item + 1); do if ((i) !== (32'b1001)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",105, (i), (32'b1001)); $stop; end while(0);; + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:107:16: Unsupported: with statements + 107 | i = q.or with (item + 1); do if ((i) !== (32'b1111)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",107, (i), (32'b1111)); $stop; end while(0);; + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:109:17: Unsupported: with statements + 109 | i = q.xor with (item + 1); do if ((i) !== (32'hb)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",109, (i), (32'hb)); $stop; end while(0);; + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_array_method.pl b/test_regress/t/t_array_method.pl new file mode 100755 index 000000000..be66c40e6 --- /dev/null +++ b/test_regress/t/t_array_method.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 2003 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_array_method.v b/test_regress/t/t_array_method.v new file mode 100644 index 000000000..90e37de31 --- /dev/null +++ b/test_regress/t/t_array_method.v @@ -0,0 +1,118 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2019 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`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); +`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); + +module t (/*AUTOARG*/); + initial begin + int q[5]; + int qe[$]; + int qv[$]; + int i; + string v; + + q = '{1, 2, 2, 4, 3}; + v = $sformatf("%p", q); `checks(v, "'{1, 2, 2, 4, 3} "); + + // NOT tested: with ... selectors + + q.sort; + v = $sformatf("%p", q); `checks(v, "'{1, 2, 2, 3, 4} "); + q.sort with (item == 2); + v = $sformatf("%p", q); `checks(v, "'{4, 3, 1, 2, 2} "); + q.sort(x) with (x == 3); + v = $sformatf("%p", q); `checks(v, "'{2, 1, 2, 4, 3} "); + qe.sort(x) with (x == 3); + v = $sformatf("%p", qe); `checks(v, "'{}"); + + q.rsort; + v = $sformatf("%p", q); `checks(v, "'{4, 3, 2, 2, 1} "); + q.rsort with (item == 2); + v = $sformatf("%p", q); `checks(v, "'{2, 2, 4, 1, 3} "); + qe.rsort(x) with (x == 3); + v = $sformatf("%p", qe); `checks(v, "'{}"); + + qv = q.unique; + v = $sformatf("%p", qv); `checks(v, "'{2, 4, 1, 3} "); + qv = qe.unique; + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.unique_index; qv.sort; + v = $sformatf("%p", qv); `checks(v, "'{0, 2, 3, 4} "); + q.reverse; + v = $sformatf("%p", q); `checks(v, "'{3, 1, 4, 2, 2} "); + qe.reverse; + v = $sformatf("%p", qe); `checks(v, "'{}"); + q.shuffle(); q.sort; + v = $sformatf("%p", q); `checks(v, "'{1, 2, 2, 3, 4} "); + qe.shuffle(); qe.sort; + v = $sformatf("%p", qe); `checks(v, "'{}"); + + // These require an with clause or are illegal + // TODO add a lint check that with clause is provided + qv = q.find with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{2, 2} "); + qv = q.find_index with (item == 2); qv.sort; + v = $sformatf("%p", qv); `checks(v, "'{1, 2} "); + qv = q.find_first with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{2} "); + qv = q.find_first_index with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{1} "); + qv = q.find_last with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{2} "); + qv = q.find_last_index with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{2} "); + + qv = q.find with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_index with (item == 20); qv.sort; + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_first with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_first_index with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_last with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_last_index with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + + qv = q.min; + v = $sformatf("%p", qv); `checks(v, "'{1} "); + qv = q.max; + v = $sformatf("%p", qv); `checks(v, "'{4} "); + + qv = qe.min; + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = qe.max; + v = $sformatf("%p", qv); `checks(v, "'{}"); + + // Reduction methods + + i = q.sum; `checkh(i, 32'hc); + i = q.sum with (item + 1); `checkh(i, 32'h11); + i = q.product; `checkh(i, 32'h30); + i = q.product with (item + 1); `checkh(i, 32'h168); + + i = qe.sum; `checkh(i, 32'h0); + i = qe.product; `checkh(i, 32'h0); + + q = '{32'b1100, 32'b1010, 32'b1100, 32'b1010, 32'b1010}; + i = q.and; `checkh(i, 32'b1000); + i = q.and with (item + 1); `checkh(i, 32'b1001); + i = q.or; `checkh(i, 32'b1110); + i = q.or with (item + 1); `checkh(i, 32'b1111); + i = q.xor; `checkh(i, 32'ha); + i = q.xor with (item + 1); `checkh(i, 32'hb); + + i = qe.and; `checkh(i, 32'b0); + i = qe.or; `checkh(i, 32'b0); + i = qe.xor; `checkh(i, 32'b0); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_assoc_meth_bad.out b/test_regress/t/t_assoc_meth_bad.out index 6b3d75789..496ecfee9 100644 --- a/test_regress/t/t_assoc_meth_bad.out +++ b/test_regress/t/t_assoc_meth_bad.out @@ -34,4 +34,20 @@ : ... In instance t 22 | a.delete(k, "bad2"); | ^~~~~~ +%Error: t/t_assoc_meth_bad.v:24:9: Array method 'sort' not legal on associative arrays + : ... In instance t + 24 | a.sort; + | ^~~~ +%Error: t/t_assoc_meth_bad.v:25:9: Array method 'rsort' not legal on associative arrays + : ... In instance t + 25 | a.rsort; + | ^~~~~ +%Error: t/t_assoc_meth_bad.v:26:9: Array method 'reverse' not legal on associative arrays + : ... In instance t + 26 | a.reverse; + | ^~~~~~~ +%Error: t/t_assoc_meth_bad.v:27:9: Array method 'shuffle' not legal on associative arrays + : ... In instance t + 27 | a.shuffle; + | ^~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_assoc_meth_bad.v b/test_regress/t/t_assoc_meth_bad.v index 7174b7844..bd4270f7f 100644 --- a/test_regress/t/t_assoc_meth_bad.v +++ b/test_regress/t/t_assoc_meth_bad.v @@ -20,5 +20,10 @@ module t (/*AUTOARG*/); v = a.last(); // Bad v = a.prev(k, "bad2"); // Bad a.delete(k, "bad2"); + + a.sort; // Not legal on assoc + a.rsort; // Not legal on assoc + a.reverse; // Not legal on assoc + a.shuffle; // Not legal on assoc end endmodule diff --git a/test_regress/t/t_assoc_method.out b/test_regress/t/t_assoc_method.out new file mode 100644 index 000000000..651f8fd92 --- /dev/null +++ b/test_regress/t/t_assoc_method.out @@ -0,0 +1,52 @@ +%Error-UNSUPPORTED: t/t_assoc_method.v:38:19: Unsupported: with statements + 38 | qv = q.find with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:40:25: Unsupported: with statements + 40 | qv = q.find_index with (item == 2); qv.sort; + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:42:25: Unsupported: with statements + 42 | qv = q.find_first with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:44:31: Unsupported: with statements + 44 | qv = q.find_first_index with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:46:24: Unsupported: with statements + 46 | qv = q.find_last with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:48:30: Unsupported: with statements + 48 | qv = q.find_last_index with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:51:19: Unsupported: with statements + 51 | qv = q.find with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:53:25: Unsupported: with statements + 53 | qv = q.find_index with (item == 20); qv.sort; + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:55:25: Unsupported: with statements + 55 | qv = q.find_first with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:57:31: Unsupported: with statements + 57 | qv = q.find_first_index with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:59:24: Unsupported: with statements + 59 | qv = q.find_last with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:61:30: Unsupported: with statements + 61 | qv = q.find_last_index with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:77:17: Unsupported: with statements + 77 | i = q.sum with (item + 1); do if ((i) !== (32'h11)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",77, (i), (32'h11)); $stop; end while(0);; + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:79:21: Unsupported: with statements + 79 | i = q.product with (item + 1); do if ((i) !== (32'h168)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",79, (i), (32'h168)); $stop; end while(0);; + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:86:17: Unsupported: with statements + 86 | i = q.and with (item + 1); do if ((i) !== (32'b1001)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",86, (i), (32'b1001)); $stop; end while(0);; + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:88:16: Unsupported: with statements + 88 | i = q.or with (item + 1); do if ((i) !== (32'b1111)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",88, (i), (32'b1111)); $stop; end while(0);; + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:90:17: Unsupported: with statements + 90 | i = q.xor with (item + 1); do if ((i) !== (32'b0110)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",90, (i), (32'b0110)); $stop; end while(0);; + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_assoc_method.pl b/test_regress/t/t_assoc_method.pl new file mode 100755 index 000000000..be66c40e6 --- /dev/null +++ b/test_regress/t/t_assoc_method.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 2003 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_assoc_method.v b/test_regress/t/t_assoc_method.v new file mode 100644 index 000000000..27586da10 --- /dev/null +++ b/test_regress/t/t_assoc_method.v @@ -0,0 +1,99 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2019 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`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); +`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); + +module t (/*AUTOARG*/); + initial begin + int q[int]; + int qe[$]; + int qv[$]; + int i; + string v; + + q = '{10:1, 11:2, 12:2, 13:4, 14:3}; + v = $sformatf("%p", q); `checks(v, "'{0xa:1, 0xb:2, 0xc:2, 0xd:4, 0xe:3} "); + + // NOT tested: with ... selectors + + //q.sort; // Not legal on assoc - see t_assoc_meth_bad + //q.rsort; // Not legal on assoc - see t_assoc_meth_bad + //q.reverse; // Not legal on assoc - see t_assoc_meth_bad + //q.shuffle; // Not legal on assoc - see t_assoc_meth_bad + + qv = q.unique; + v = $sformatf("%p", qv); `checks(v, "'{1, 2, 4, 3} "); + qv = qe.unique; + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.unique_index; qv.sort; + v = $sformatf("%p", qv); `checks(v, "'{10, 11, 13, 14} "); + + // These require an with clause or are illegal + // TODO add a lint check that with clause is provided + qv = q.find with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{2, 2} "); + qv = q.find_index with (item == 2); qv.sort; + v = $sformatf("%p", qv); `checks(v, "'{11, 12} "); + qv = q.find_first with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{2} "); + qv = q.find_first_index with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{11} "); + qv = q.find_last with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{2} "); + qv = q.find_last_index with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{12} "); + + qv = q.find with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_index with (item == 20); qv.sort; + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_first with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_first_index with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_last with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_last_index with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + + qv = q.min; + v = $sformatf("%p", qv); `checks(v, "'{1} "); + qv = q.max; + v = $sformatf("%p", qv); `checks(v, "'{4} "); + + qv = qe.min; + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = qe.max; + v = $sformatf("%p", qv); `checks(v, "'{}"); + + // Reduction methods + + i = q.sum; `checkh(i, 32'hc); + i = q.sum with (item + 1); `checkh(i, 32'h11); + i = q.product; `checkh(i, 32'h30); + i = q.product with (item + 1); `checkh(i, 32'h168); + + i = qe.sum; `checkh(i, 32'h0); + i = qe.product; `checkh(i, 32'h0); + + q = '{10:32'b1100, 11:32'b1010}; + i = q.and; `checkh(i, 32'b1000); + i = q.and with (item + 1); `checkh(i, 32'b1001); + i = q.or; `checkh(i, 32'b1110); + i = q.or with (item + 1); `checkh(i, 32'b1111); + i = q.xor; `checkh(i, 32'b0110); + i = q.xor with (item + 1); `checkh(i, 32'b0110); + + i = qe.and; `checkh(i, 32'b0); + i = qe.or; `checkh(i, 32'b0); + i = qe.xor; `checkh(i, 32'b0); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_queue_method.pl b/test_regress/t/t_queue_method.pl index f4321c541..be66c40e6 100755 --- a/test_regress/t/t_queue_method.pl +++ b/test_regress/t/t_queue_method.pl @@ -15,9 +15,9 @@ compile( expect_filename => $Self->{golden_filename}, ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; ok(1); 1;