From 95b66feeb886598ba9a0f2a309574015a92dbc74 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 8 Feb 2020 09:16:35 -0500 Subject: [PATCH 01/50] devel release --- Changes | 3 +++ configure.ac | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Changes b/Changes index 647c2dbf9..21cb7b1d3 100644 --- a/Changes +++ b/Changes @@ -3,6 +3,9 @@ Revision history for Verilator The contributors that suggested a given feature are shown in []. Thanks! +* Verilator 4.029 devel + + * Verilator 4.028 2020-02-08 ** Support attributes (public, isolate_assignments, etc.) in configuration files. diff --git a/configure.ac b/configure.ac index 69591d834..51bb7b2a0 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[4.028 2020-02-06], +AC_INIT([Verilator],[4.029 devel], [https://verilator.org], [verilator],[https://verilator.org]) # When releasing, also update header of Changes file From 70358e8587fec91d7597d560d162fd6a9d39183c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 8 Feb 2020 10:58:07 -0500 Subject: [PATCH 02/50] Fix compiler warning. --- include/verilated.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index e740066a9..980a5980c 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -1832,7 +1832,7 @@ void VL_READMEM_N(bool hex, // Hex format, else binary QData end // Last row address to read ) VL_MT_SAFE { QData addr_max = array_lsb + depth - 1; - if (start < array_lsb) start = array_lsb; + if (start < static_cast(array_lsb)) start = array_lsb; QData addr_end = end; if (addr_end > addr_max) addr_end = addr_max; @@ -1883,7 +1883,7 @@ void VL_WRITEMEM_N(bool hex, // Hex format, else binary QData end // Last address to write, or ~0 when not specified ) VL_MT_SAFE { QData addr_max = array_lsb + depth - 1; - if (start < array_lsb) start = array_lsb; + if (start < static_cast(array_lsb)) start = array_lsb; if (end > addr_max) end = addr_max; VlWriteMem wmem(hex, bits, filename, start, end); From 02786b3f098bc93eeb129b85d053a47bbb806c13 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 12 Feb 2020 22:46:59 -0500 Subject: [PATCH 03/50] Commentary --- bin/verilator | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bin/verilator b/bin/verilator index ab3061e22..70bc8aabe 100755 --- a/bin/verilator +++ b/bin/verilator @@ -5241,6 +5241,10 @@ redistribute it and/or modify the Verilator internals under the terms of either the GNU Lesser General Public License Version 3 or the Perl Artistic License Version 2.0. +All Verilog and C++/SystemC code quoted within this documentation file are +released into the Public Domain. Many example files and test files are +likewise released into the Public Domain as described in the files +themselves. =head1 SEE ALSO From 18f8cd0529d2a8570cb275586274518bd68e0b5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20W=C3=B6lfel?= Date: Sun, 16 Feb 2020 01:17:23 +0100 Subject: [PATCH 04/50] Allow assert disable (#2168) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add +verilator+noassert flag This allows to disable the assert check per simulation argument. * Add AssertOn check for assert Insert the check AssertOn to allow disabling of asserts. Asserts can be disabled by not using the `--assert` flag or by calling `AssertOn(false)`, or passing the "+verilator+noassert" runtime flag. Add tests for this behavior. Bad tests check that the assert still causes a stop. Non bad tests check that asserts are properly disabled and cause no stop of the simulation. Fixes #2162. Signed-off-by: Tobias Wölfel * Correct file location Signed-off-by: Tobias Wölfel * Add description for single test execution Without this description it is not obvious how to run a single test from the regression test suite. Signed-off-by: Tobias Wölfel --- Changes | 2 ++ bin/verilator | 6 ++++++ docs/CONTRIBUTORS | 1 + docs/internals.adoc | 9 ++++++++- include/verilated.cpp | 3 +++ src/V3Assert.cpp | 2 +- test_regress/t/t_assert_disabled.pl | 19 ++++++++++++++++++ test_regress/t/t_assert_enabled_bad.pl | 24 +++++++++++++++++++++++ test_regress/t/t_assert_enabled_off.pl | 23 ++++++++++++++++++++++ test_regress/t/t_assert_enabled_on_bad.pl | 23 ++++++++++++++++++++++ test_regress/t/t_assert_on.v | 18 +++++++++++++++++ 11 files changed, 128 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_assert_disabled.pl create mode 100755 test_regress/t/t_assert_enabled_bad.pl create mode 100755 test_regress/t/t_assert_enabled_off.pl create mode 100755 test_regress/t/t_assert_enabled_on_bad.pl create mode 100644 test_regress/t/t_assert_on.v diff --git a/Changes b/Changes index 21cb7b1d3..cf3e97ac0 100644 --- a/Changes +++ b/Changes @@ -5,6 +5,8 @@ The contributors that suggested a given feature are shown in []. Thanks! * Verilator 4.029 devel +*** Add assertOn check for assert. [Tobias Wölfel] +*** Add +verilator+noassert flag to disable assert checking. [Tobias Wölfel] * Verilator 4.028 2020-02-08 diff --git a/bin/verilator b/bin/verilator index 70bc8aabe..41be3b13d 100755 --- a/bin/verilator +++ b/bin/verilator @@ -421,6 +421,7 @@ more information. +verilator+prof+threads+window+I Set profile duration +verilator+rand+reset+I Set random reset technique +verilator+seed+I Set random seed + +verilator+noassert Disable assert checking +verilator+V Verbose version and config +verilator+version Show version and exit @@ -1773,6 +1774,11 @@ For $random and "-x-initial unique", set the simulation runtime random seed value. If zero or not specified picks a value from the system random number generator. +=item +verilator+noassert + +Disable assert checking per runtime argument. This is the same as calling +"Verilated::assertOn(false)" in the model. + =item +verilator+V Shows the verbose version, including configuration information. diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 34ac03ccf..54f51f7ad 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -33,6 +33,7 @@ Richard Myers Sebastien Van Cauwenberghe Stefan Wallentowitz Tobias Rosenkranz +Tobias Wölfel Todd Strader Wilson Snyder Yutetsu TAKATSUKASA diff --git a/docs/internals.adoc b/docs/internals.adoc index a7e155200..94edaf247 100644 --- a/docs/internals.adoc +++ b/docs/internals.adoc @@ -631,7 +631,7 @@ Test drivers are written in PERL. All invoke the main test driver script, which can provide detailed help on all the features available when writing a test driver. - test_regress/t/driver.pl --help + test_regress/driver.pl --help For convenience, a summary of the most commonly used features is provided here. All drivers require a call to `compile` subroutine to compile the @@ -716,6 +716,13 @@ respectively 16,384 and 4,096. The method of doing this is system dependent, but on Fedora Linux it would require editing the `/etc/security/limits.conf` file as root. +=== Manual Test Execution + +A specific regression test can be executed manually. To start the "EXAMPLE" +test, run the following command. + + test_regress/t/t_EXAMPLE.pl + === Continuous Integration Verilator has a https://travis-ci.com/verilator/verilator[Travis CI environment] diff --git a/include/verilated.cpp b/include/verilated.cpp index 980a5980c..90eecfb25 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -2199,6 +2199,9 @@ void VerilatedImp::commandArgVl(const std::string& arg) { else if (commandArgVlValue(arg, "+verilator+seed+", value/*ref*/)) { Verilated::randSeed(atoi(value.c_str())); } + else if (arg == "+verilator+noassert") { + Verilated::assertOn(false); + } else if (arg == "+verilator+V") { versionDump(); // Someday more info too VL_FATAL_MT("COMMAND_LINE", 0, "", diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 6e593c339..ffd983921 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -150,7 +150,7 @@ private: // It's more LIKELY that we'll take the NULL if clause // than the sim-killing else clause: ifp->branchPred(VBranchPred::BP_LIKELY); - bodysp = ifp; + bodysp = newIfAssertOn(ifp); } else { nodep->v3fatalSrc("Unknown node type"); } diff --git a/test_regress/t/t_assert_disabled.pl b/test_regress/t/t_assert_disabled.pl new file mode 100755 index 000000000..ce40c03ef --- /dev/null +++ b/test_regress/t/t_assert_disabled.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 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. + +scenarios(simulator => 1); + +top_filename("t/t_assert_on.v"); + +compile(); + +execute(); + +ok(1); +1; diff --git a/test_regress/t/t_assert_enabled_bad.pl b/test_regress/t/t_assert_enabled_bad.pl new file mode 100755 index 000000000..e97edee06 --- /dev/null +++ b/test_regress/t/t_assert_enabled_bad.pl @@ -0,0 +1,24 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 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. + +scenarios(simulator => 1); + +top_filename("t/t_assert_on.v"); + +compile( + verilator_flags2 => ['--assert'], + nc_flags2 => ['+assert'], + ); + +execute( + fails => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_assert_enabled_off.pl b/test_regress/t/t_assert_enabled_off.pl new file mode 100755 index 000000000..68476d21b --- /dev/null +++ b/test_regress/t/t_assert_enabled_off.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 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. + +scenarios(vlt => 1); + +top_filename("t/t_assert_on.v"); + +compile( + verilator_flags2 => ["--assert"], + ); + +execute( + all_run_flags => ["+verilator+noassert"], +); + +ok(1); +1; diff --git a/test_regress/t/t_assert_enabled_on_bad.pl b/test_regress/t/t_assert_enabled_on_bad.pl new file mode 100755 index 000000000..b93de98fc --- /dev/null +++ b/test_regress/t/t_assert_enabled_on_bad.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 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. + +scenarios(vlt => 1); + +top_filename("t/t_assert_on.v"); + +compile( + verilator_flags2 => ["--assert"], + ); + +execute( + fails => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_assert_on.v b/test_regress/t/t_assert_on.v new file mode 100644 index 000000000..c6ae564e6 --- /dev/null +++ b/test_regress/t/t_assert_on.v @@ -0,0 +1,18 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2007 by Wilson Snyder. + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + always @ (posedge clk) begin + assert (0); + $finish; + end + +endmodule From 28e19cef90aea3c4f2ee241a3266220c4db8f392 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 23 Feb 2020 19:33:37 -0500 Subject: [PATCH 05/50] Fix undeclared VL_SHIFTR_WWQ, #2114. --- Changes | 8 +- include/verilated.h | 11 +++ test_regress/t/t_math_shift.v | 159 +++++++++++++++++----------------- 3 files changed, 98 insertions(+), 80 deletions(-) diff --git a/Changes b/Changes index cf3e97ac0..b54ee2cb8 100644 --- a/Changes +++ b/Changes @@ -5,8 +5,12 @@ The contributors that suggested a given feature are shown in []. Thanks! * Verilator 4.029 devel -*** Add assertOn check for assert. [Tobias Wölfel] -*** Add +verilator+noassert flag to disable assert checking. [Tobias Wölfel] +*** Add +verilator+noassert flag to disable assertion checking. [Tobias Wölfel] + +*** Add check for assertOn for asserts, #2162. [Tobias Wölfel] + +**** Fix undeclared VL_SHIFTR_WWQ, #2114. [Alex Solomatnikov] + * Verilator 4.028 2020-02-08 diff --git a/include/verilated.h b/include/verilated.h index 3c0b0f9d4..c039d3878 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -2013,6 +2013,12 @@ static inline WDataOutP VL_SHIFTR_WWW(int obits, int lbits, int rbits, } return VL_SHIFTR_WWI(obits, lbits, 32, owp, lwp, rwp[0]); } +static inline WDataOutP VL_SHIFTR_WWQ(int obits, int lbits, int rbits, + WDataOutP owp, WDataInP lwp, QData rd) VL_MT_SAFE { + WData rwp[VL_WQ_WORDS_E]; VL_SET_WQ(rwp, rd); + return VL_SHIFTR_WWW(obits, lbits, rbits, owp, lwp, rwp); +} + static inline IData VL_SHIFTR_IIW(int obits, int, int rbits, IData lhs, WDataInP rwp) VL_MT_SAFE { for (int i = 1; i < VL_WORDS_I(rbits); ++i) { if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more @@ -2098,6 +2104,11 @@ static inline WDataOutP VL_SHIFTRS_WWW(int obits, int lbits, int rbits, } return VL_SHIFTRS_WWI(obits, lbits, 32, owp, lwp, rwp[0]); } +static inline WDataOutP VL_SHIFTRS_WWQ(int obits, int lbits, int rbits, + WDataOutP owp, WDataInP lwp, QData rd) VL_MT_SAFE { + WData rwp[VL_WQ_WORDS_E]; VL_SET_WQ(rwp, rd); + return VL_SHIFTRS_WWW(obits, lbits, rbits, owp, lwp, rwp); +} static inline IData VL_SHIFTRS_IIW(int obits, int lbits, int rbits, IData lhs, WDataInP rwp) VL_MT_SAFE { EData overshift = 0; // Huge shift 1>>32 or more diff --git a/test_regress/t/t_math_shift.v b/test_regress/t/t_math_shift.v index 12de70145..dfc282320 100644 --- a/test_regress/t/t_math_shift.v +++ b/test_regress/t/t_math_shift.v @@ -5,7 +5,7 @@ module t (/*AUTOARG*/ // Outputs - ign, ign2, ign3, + ign, ign2, ign3, ign4, ign4s, // Inputs clk ); @@ -23,21 +23,24 @@ module t (/*AUTOARG*/ localparam [3:0] PBIG29 = 4'b1 << 33'h100000000; // verilator lint_on WIDTH - reg [31:0] right; - reg [31:0] left; - reg [P64-1:0] qright; - reg [P64-1:0] qleft; - reg [31:0] amt; + reg [31:0] right; + reg [31:0] left; + reg [P64-1:0] qright; + reg [P64-1:0] qleft; + reg [31:0] amt; assign ign = {31'h0, clk} >>> 4'bx; // bug760 assign ign2 = {amt[1:0] >> {22{amt[5:2]}}, amt[1:0] << (0 <<< amt[5:2])}; // bug1174 assign ign3 = {amt[1:0] >> {22{amt[5:2]}}, - amt[1:0] >> {11{amt[5:2]}}, - $signed(amt[1:0]) >>> {22{amt[5:2]}}, - $signed(amt[1:0]) >>> {11{amt[5:2]}}, - amt[1:0] << {22{amt[5:2]}}, + amt[1:0] >> {11{amt[5:2]}}, + $signed(amt[1:0]) >>> {22{amt[5:2]}}, + $signed(amt[1:0]) >>> {11{amt[5:2]}}, + amt[1:0] << {22{amt[5:2]}}, amt[1:0] << {11{amt[5:2]}}}; + wire [95:0] wamt = {amt,amt,amt}; + output wire [95:0] ign4 = wamt >> {11{amt[5:2]}}; + output wire signed [95:0] ign4s = $signed(wamt) >>> {11{amt[5:2]}}; always @* begin right = 32'h819b018a >> amt; @@ -49,76 +52,76 @@ module t (/*AUTOARG*/ integer cyc; initial cyc=1; always @ (posedge clk) begin if (cyc!=0) begin - cyc <= cyc + 1; + cyc <= cyc + 1; `ifdef TEST_VERBOSE - $write("%d %x %x %x %x\n", cyc, left, right, qleft, qright); + $write("%d %x %x %x %x\n", cyc, left, right, qleft, qright); `endif - if (cyc==1) begin - amt <= 32'd0; - if (P64 != 64) $stop; - if (5'b10110>>2 != 5'b00101) $stop; - if (5'b10110>>>2 != 5'b00101) $stop; // Note it cares about sign-ness - if (5'b10110<<2 != 5'b11000) $stop; - if (5'b10110<<<2 != 5'b11000) $stop; - if (5'sb10110>>2 != 5'sb00101) $stop; - if (5'sb10110>>>2 != 5'sb11101) $stop; - if (5'sb10110<<2 != 5'sb11000) $stop; - if (5'sb10110<<<2 != 5'sb11000) $stop; - // Allow >64 bit shifts if the shift amount is a constant - if ((64'sh458c2de282e30f8b >> 68'sh4) !== 64'sh0458c2de282e30f8) $stop; - end - if (cyc==2) begin - amt <= 32'd28; - if (left != 32'h819b018a) $stop; - if (right != 32'h819b018a) $stop; - if (qleft != 64'hf784bf8f_12734089) $stop; - if (qright != 64'hf784bf8f_12734089) $stop; - end - if (cyc==3) begin - amt <= 32'd31; - if (left != 32'ha0000000) $stop; - if (right != 32'h8) $stop; - if (qleft != 64'h0000000f784bf8f1) $stop; - if (qright != 64'h0000000f784bf8f1) $stop; - end - if (cyc==4) begin - amt <= 32'd32; - if (left != 32'h0) $stop; - if (right != 32'h1) $stop; - if (qleft != 64'h00000001ef097f1e) $stop; - if (qright != 64'h00000001ef097f1e) $stop; - end - if (cyc==5) begin - amt <= 32'd33; - if (left != 32'h0) $stop; - if (right != 32'h0) $stop; - if (qleft != 64'h00000000f784bf8f) $stop; - if (qright != 64'h00000000f784bf8f) $stop; - end - if (cyc==6) begin - amt <= 32'd64; - if (left != 32'h0) $stop; - if (right != 32'h0) $stop; - if (qleft != 64'h000000007bc25fc7) $stop; - if (qright != 64'h000000007bc25fc7) $stop; - end - if (cyc==7) begin - amt <= 32'd128; - if (left != 32'h0) $stop; - if (right != 32'h0) $stop; - if (qleft != 64'h0) $stop; - if (qright != 64'h0) $stop; - end - if (cyc==8) begin - if (left != 32'h0) $stop; - if (right != 32'h0) $stop; - if (qleft != 64'h0) $stop; - if (qright != 64'h0) $stop; - end - if (cyc==9) begin - $write("*-* All Finished *-*\n"); - $finish; - end + if (cyc==1) begin + amt <= 32'd0; + if (P64 != 64) $stop; + if (5'b10110>>2 != 5'b00101) $stop; + if (5'b10110>>>2 != 5'b00101) $stop; // Note it cares about sign-ness + if (5'b10110<<2 != 5'b11000) $stop; + if (5'b10110<<<2 != 5'b11000) $stop; + if (5'sb10110>>2 != 5'sb00101) $stop; + if (5'sb10110>>>2 != 5'sb11101) $stop; + if (5'sb10110<<2 != 5'sb11000) $stop; + if (5'sb10110<<<2 != 5'sb11000) $stop; + // Allow >64 bit shifts if the shift amount is a constant + if ((64'sh458c2de282e30f8b >> 68'sh4) !== 64'sh0458c2de282e30f8) $stop; + end + if (cyc==2) begin + amt <= 32'd28; + if (left != 32'h819b018a) $stop; + if (right != 32'h819b018a) $stop; + if (qleft != 64'hf784bf8f_12734089) $stop; + if (qright != 64'hf784bf8f_12734089) $stop; + end + if (cyc==3) begin + amt <= 32'd31; + if (left != 32'ha0000000) $stop; + if (right != 32'h8) $stop; + if (qleft != 64'h0000000f784bf8f1) $stop; + if (qright != 64'h0000000f784bf8f1) $stop; + end + if (cyc==4) begin + amt <= 32'd32; + if (left != 32'h0) $stop; + if (right != 32'h1) $stop; + if (qleft != 64'h00000001ef097f1e) $stop; + if (qright != 64'h00000001ef097f1e) $stop; + end + if (cyc==5) begin + amt <= 32'd33; + if (left != 32'h0) $stop; + if (right != 32'h0) $stop; + if (qleft != 64'h00000000f784bf8f) $stop; + if (qright != 64'h00000000f784bf8f) $stop; + end + if (cyc==6) begin + amt <= 32'd64; + if (left != 32'h0) $stop; + if (right != 32'h0) $stop; + if (qleft != 64'h000000007bc25fc7) $stop; + if (qright != 64'h000000007bc25fc7) $stop; + end + if (cyc==7) begin + amt <= 32'd128; + if (left != 32'h0) $stop; + if (right != 32'h0) $stop; + if (qleft != 64'h0) $stop; + if (qright != 64'h0) $stop; + end + if (cyc==8) begin + if (left != 32'h0) $stop; + if (right != 32'h0) $stop; + if (qleft != 64'h0) $stop; + if (qright != 64'h0) $stop; + end + if (cyc==9) begin + $write("*-* All Finished *-*\n"); + $finish; + end end end endmodule From db6ecbd57e2b038d66644fc99479d4036a8872ad Mon Sep 17 00:00:00 2001 From: Todd Strader Date: Tue, 18 Feb 2020 17:52:28 -0500 Subject: [PATCH 06/50] Test for #2169 --- test_regress/t/t_prot_lib.v | 3 ++ test_regress/t/t_prot_lib_clk_gated.pl | 74 ++++++++++++++++++++++++++ test_regress/t/t_prot_lib_secret.v | 7 ++- 3 files changed, 82 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_prot_lib_clk_gated.pl diff --git a/test_regress/t/t_prot_lib.v b/test_regress/t/t_prot_lib.v index d511fe16f..ce80add05 100644 --- a/test_regress/t/t_prot_lib.v +++ b/test_regress/t/t_prot_lib.v @@ -55,6 +55,8 @@ module t (/*AUTOARG*/ logic [3:0] [31:0] s4x32_in; logic [3:0] [31:0] s4x32_out; + wire clk_en = crc[0]; + secret secret ( .accum_in, @@ -77,6 +79,7 @@ module t (/*AUTOARG*/ .s129_out, .s4x32_in, .s4x32_out, + .clk_en, .clk); always @(posedge clk) begin diff --git a/test_regress/t/t_prot_lib_clk_gated.pl b/test_regress/t/t_prot_lib_clk_gated.pl new file mode 100755 index 000000000..9862323a7 --- /dev/null +++ b/test_regress/t/t_prot_lib_clk_gated.pl @@ -0,0 +1,74 @@ +#!/usr/bin/perl +# Makes the test run with tracing enabled by default, can be overridden +# with --notrace +unshift(@ARGV, "--trace"); +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2019 by Todd Strader. 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. + +scenarios( + vlt => 1, + xsim => 1, + ); + +$Self->{sim_time} = $Self->{benchmark} * 100 if $Self->{benchmark}; + +top_filename("t/t_prot_lib.v"); +my $secret_prefix = "secret"; +my $secret_dir = "$Self->{obj_dir}/$secret_prefix"; +mkdir $secret_dir; + +while (1) { + # Always compile the secret file with Verilator no matter what simulator + # we are testing with + run(logfile => "$secret_dir/vlt_compile.log", + cmd => ["perl", + "$ENV{VERILATOR_ROOT}/bin/verilator", + "--prefix", + "Vt_prot_lib_secret", + "-cc", + "-Mdir", + $secret_dir, + "-GGATED_CLK=1", + "--protect-lib", + $secret_prefix, + "t/t_prot_lib_secret.v"]); + last if $Self->{errors}; + + run(logfile => "$secret_dir/secret_gcc.log", + cmd=>["make", + "-C", + $secret_dir, + "-f", + "Vt_prot_lib_secret.mk"]); + last if $Self->{errors}; + + compile( + verilator_flags2 => ["$secret_dir/secret.sv", + "-LDFLAGS", + "'-L$secret_prefix -lsecret -static'"], + xsim_flags2 => ["$secret_dir/secret.sv"], + ); + + execute( + check_finished => 1, + xsim_run_flags2 => ["--sv_lib", + "$secret_dir/libsecret", + "--dpi_absolute"], + ); + + if ($Self->{vlt} && $Self->{trace}) { + # We can see the ports of the secret module + file_grep("$Self->{obj_dir}/simx.vcd", qr/accum_in/); + # but we can't see what's inside + file_grep_not("$Self->{obj_dir}/simx.vcd", qr/secret_/); + } + + ok(1); + last; +} +1; diff --git a/test_regress/t/t_prot_lib_secret.v b/test_regress/t/t_prot_lib_secret.v index b55164988..534aca6a1 100644 --- a/test_regress/t/t_prot_lib_secret.v +++ b/test_regress/t/t_prot_lib_secret.v @@ -2,7 +2,8 @@ // This file ONLY is placed into the Public Domain, for any use, // without warranty, 2019 by Todd Strader. -module secret ( +module secret #(parameter GATED_CLK = 0) + ( input [31:0] accum_in, output wire [31:0] accum_out, input accum_bypass, @@ -23,6 +24,7 @@ module secret ( output logic [128:0] s129_out, input [3:0] [31:0] s4x32_in, output logic [3:0] [31:0] s4x32_out, + input clk_en, input clk); logic [31:0] secret_accum_q = 0; @@ -30,7 +32,8 @@ module secret ( initial $display("created %m"); - always @(posedge clk) begin + wire the_clk = GATED_CLK != 0 ? clk & clk_en : clk; + always @(posedge the_clk) begin secret_accum_q <= secret_accum_q + accum_in + secret_value; end From 120f62fe854d3387e6bac702b8097e5c172c94a7 Mon Sep 17 00:00:00 2001 From: Todd Strader Date: Tue, 18 Feb 2020 18:19:55 -0500 Subject: [PATCH 07/50] Fix is probably to mark as a clock --- src/V3ProtectLib.cpp | 3 ++- test_regress/t/t_prot_lib_secret.v | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/V3ProtectLib.cpp b/src/V3ProtectLib.cpp index b44edf500..6e64d7563 100644 --- a/src/V3ProtectLib.cpp +++ b/src/V3ProtectLib.cpp @@ -353,7 +353,8 @@ class ProtectVisitor : public AstNVisitor { nodep->v3error("Unsupported: unpacked arrays with protect-lib on "<prettyNameQ()); } if (nodep->direction() == VDirection::INPUT) { - if (nodep->isUsedClock()) { + if (nodep->isUsedClock() + || nodep->attrClocker() == VVarAttrClocker::CLOCKER_YES) { handleClock(nodep); } else { handleDataInput(nodep); diff --git a/test_regress/t/t_prot_lib_secret.v b/test_regress/t/t_prot_lib_secret.v index 534aca6a1..05ca43e1b 100644 --- a/test_regress/t/t_prot_lib_secret.v +++ b/test_regress/t/t_prot_lib_secret.v @@ -25,7 +25,7 @@ module secret #(parameter GATED_CLK = 0) input [3:0] [31:0] s4x32_in, output logic [3:0] [31:0] s4x32_out, input clk_en, - input clk); + input clk /*verilator clocker*/); logic [31:0] secret_accum_q = 0; logic [31:0] secret_value = 7; From 4b4f10f5e67eda57de79b521fa8757cd750ee179 Mon Sep 17 00:00:00 2001 From: Todd Strader Date: Fri, 21 Feb 2020 05:47:00 -0500 Subject: [PATCH 08/50] Follow other clock gating examples --- test_regress/t/t_prot_lib.v | 20 +++++++++++++++++--- test_regress/t/t_prot_lib_clk_gated.pl | 1 + test_regress/t/t_prot_lib_secret.v | 14 +++++++++++++- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/test_regress/t/t_prot_lib.v b/test_regress/t/t_prot_lib.v index ce80add05..b8bb19ff2 100644 --- a/test_regress/t/t_prot_lib.v +++ b/test_regress/t/t_prot_lib.v @@ -14,7 +14,7 @@ if (cyc > 0 && sig``_in != sig``_out) begin \ $stop; \ end -module t (/*AUTOARG*/ +module t #(parameter GATED_CLK = 0) (/*AUTOARG*/ // Inputs clk ); @@ -90,8 +90,6 @@ module t (/*AUTOARG*/ cyc <= cyc + 1; crc <= {crc[62:0], crc[63]^crc[2]^crc[0]}; accum_in <= accum_in + 5; - // 7 is the secret_value inside the secret module - accum_out_expect <= accum_in + accum_out_expect + 7; `DRIVE(s1) `DRIVE(s2) `DRIVE(s8) @@ -125,6 +123,22 @@ module t (/*AUTOARG*/ end end + logic possibly_gated_clk; + if (GATED_CLK != 0) begin: yes_gated_clock + logic clk_en_latch /*verilator clock_enable*/; + /* verilator lint_off COMBDLY */ + always_comb if (clk == '0) clk_en_latch <= clk_en; + /* verilator lint_on COMBDLY */ + assign possibly_gated_clk = clk & clk_en_latch; + end else begin: no_gated_clock + assign possibly_gated_clk = clk; + end + + always @(posedge possibly_gated_clk) begin + // 7 is the secret_value inside the secret module + accum_out_expect <= accum_in + accum_out_expect + 7; + end + always @(*) begin // XSim (and maybe all event simulators?) sees the moment where // s1_in has not yet propagated to s1_out, however, they do always diff --git a/test_regress/t/t_prot_lib_clk_gated.pl b/test_regress/t/t_prot_lib_clk_gated.pl index 9862323a7..394bc08b9 100755 --- a/test_regress/t/t_prot_lib_clk_gated.pl +++ b/test_regress/t/t_prot_lib_clk_gated.pl @@ -49,6 +49,7 @@ while (1) { compile( verilator_flags2 => ["$secret_dir/secret.sv", + "-GGATED_CLK=1", "-LDFLAGS", "'-L$secret_prefix -lsecret -static'"], xsim_flags2 => ["$secret_dir/secret.sv"], diff --git a/test_regress/t/t_prot_lib_secret.v b/test_regress/t/t_prot_lib_secret.v index 05ca43e1b..85c3d5196 100644 --- a/test_regress/t/t_prot_lib_secret.v +++ b/test_regress/t/t_prot_lib_secret.v @@ -32,7 +32,19 @@ module secret #(parameter GATED_CLK = 0) initial $display("created %m"); - wire the_clk = GATED_CLK != 0 ? clk & clk_en : clk; + logic the_clk; + generate + if (GATED_CLK != 0) begin: yes_gated_clock + logic clk_en_latch /*verilator clock_enable*/; + /* verilator lint_off COMBDLY */ + always_comb if (clk == '0) clk_en_latch <= clk_en; + /* verilator lint_on COMBDLY */ + assign the_clk = clk & clk_en_latch; + end else begin: no_gated_clock + assign the_clk = clk; + end + endgenerate + always @(posedge the_clk) begin secret_accum_q <= secret_accum_q + accum_in + secret_value; end From f7d1c6ca72f0bc678e6f5590cfc31a07b6a0d733 Mon Sep 17 00:00:00 2001 From: Todd Strader Date: Fri, 21 Feb 2020 05:50:09 -0500 Subject: [PATCH 09/50] emacs verilog-batch-indent --- test_regress/t/t_prot_lib.v | 24 +++++------ test_regress/t/t_prot_lib_secret.v | 64 +++++++++++++++--------------- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/test_regress/t/t_prot_lib.v b/test_regress/t/t_prot_lib.v index b8bb19ff2..6988bc5ba 100644 --- a/test_regress/t/t_prot_lib.v +++ b/test_regress/t/t_prot_lib.v @@ -15,16 +15,16 @@ if (cyc > 0 && sig``_in != sig``_out) begin \ end module t #(parameter GATED_CLK = 0) (/*AUTOARG*/ - // Inputs - clk - ); + // Inputs + clk + ); input clk; localparam last_cyc = `ifdef TEST_BENCHMARK - `TEST_BENCHMARK; + `TEST_BENCHMARK; `else - 10; + 10; `endif genvar x; @@ -55,7 +55,7 @@ module t #(parameter GATED_CLK = 0) (/*AUTOARG*/ logic [3:0] [31:0] s4x32_in; logic [3:0] [31:0] s4x32_out; - wire clk_en = crc[0]; + wire clk_en = crc[0]; secret secret ( @@ -125,13 +125,13 @@ module t #(parameter GATED_CLK = 0) (/*AUTOARG*/ logic possibly_gated_clk; if (GATED_CLK != 0) begin: yes_gated_clock - logic clk_en_latch /*verilator clock_enable*/; - /* verilator lint_off COMBDLY */ - always_comb if (clk == '0) clk_en_latch <= clk_en; - /* verilator lint_on COMBDLY */ - assign possibly_gated_clk = clk & clk_en_latch; + logic clk_en_latch /*verilator clock_enable*/; + /* verilator lint_off COMBDLY */ + always_comb if (clk == '0) clk_en_latch <= clk_en; + /* verilator lint_on COMBDLY */ + assign possibly_gated_clk = clk & clk_en_latch; end else begin: no_gated_clock - assign possibly_gated_clk = clk; + assign possibly_gated_clk = clk; end always @(posedge possibly_gated_clk) begin diff --git a/test_regress/t/t_prot_lib_secret.v b/test_regress/t/t_prot_lib_secret.v index 85c3d5196..6f0abc1b4 100644 --- a/test_regress/t/t_prot_lib_secret.v +++ b/test_regress/t/t_prot_lib_secret.v @@ -3,45 +3,45 @@ // without warranty, 2019 by Todd Strader. module secret #(parameter GATED_CLK = 0) - ( - input [31:0] accum_in, - output wire [31:0] accum_out, - input accum_bypass, - output [31:0] accum_bypass_out, - input s1_in, - output logic s1_out, - input [1:0] s2_in, - output logic [1:0] s2_out, - input [7:0] s8_in, - output logic [7:0] s8_out, - input [32:0] s33_in, - output logic [32:0] s33_out, - input [63:0] s64_in, - output logic [63:0] s64_out, - input [64:0] s65_in, - output logic [64:0] s65_out, - input [128:0] s129_in, - output logic [128:0] s129_out, - input [3:0] [31:0] s4x32_in, - output logic [3:0] [31:0] s4x32_out, - input clk_en, - input clk /*verilator clocker*/); + ( + input [31:0] accum_in, + output wire [31:0] accum_out, + input accum_bypass, + output [31:0] accum_bypass_out, + input s1_in, + output logic s1_out, + input [1:0] s2_in, + output logic [1:0] s2_out, + input [7:0] s8_in, + output logic [7:0] s8_out, + input [32:0] s33_in, + output logic [32:0] s33_out, + input [63:0] s64_in, + output logic [63:0] s64_out, + input [64:0] s65_in, + output logic [64:0] s65_out, + input [128:0] s129_in, + output logic [128:0] s129_out, + input [3:0] [31:0] s4x32_in, + output logic [3:0] [31:0] s4x32_out, + input clk_en, + input clk /*verilator clocker*/); - logic [31:0] secret_accum_q = 0; - logic [31:0] secret_value = 7; + logic [31:0] secret_accum_q = 0; + logic [31:0] secret_value = 7; initial $display("created %m"); - logic the_clk; + logic the_clk; generate if (GATED_CLK != 0) begin: yes_gated_clock - logic clk_en_latch /*verilator clock_enable*/; - /* verilator lint_off COMBDLY */ - always_comb if (clk == '0) clk_en_latch <= clk_en; - /* verilator lint_on COMBDLY */ - assign the_clk = clk & clk_en_latch; + logic clk_en_latch /*verilator clock_enable*/; + /* verilator lint_off COMBDLY */ + always_comb if (clk == '0) clk_en_latch <= clk_en; + /* verilator lint_on COMBDLY */ + assign the_clk = clk & clk_en_latch; end else begin: no_gated_clock - assign the_clk = clk; + assign the_clk = clk; end endgenerate From 60f82961b494fbde8c80be7e19ffa563db2de008 Mon Sep 17 00:00:00 2001 From: Todd Strader Date: Mon, 24 Feb 2020 05:34:10 -0500 Subject: [PATCH 10/50] De-tabify --- test_regress/t/t_prot_lib.v | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test_regress/t/t_prot_lib.v b/test_regress/t/t_prot_lib.v index 6988bc5ba..346c54e82 100644 --- a/test_regress/t/t_prot_lib.v +++ b/test_regress/t/t_prot_lib.v @@ -15,14 +15,14 @@ if (cyc > 0 && sig``_in != sig``_out) begin \ end module t #(parameter GATED_CLK = 0) (/*AUTOARG*/ - // Inputs - clk - ); + // Inputs + clk + ); input clk; localparam last_cyc = `ifdef TEST_BENCHMARK - `TEST_BENCHMARK; + `TEST_BENCHMARK; `else 10; `endif From 8319ea6c7327b1f3382ed31daa6b69635d1c37e7 Mon Sep 17 00:00:00 2001 From: Todd Strader Date: Mon, 24 Feb 2020 05:36:09 -0500 Subject: [PATCH 11/50] Changes --- Changes | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changes b/Changes index b54ee2cb8..1b8aedeb5 100644 --- a/Changes +++ b/Changes @@ -54,6 +54,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix OpenSolaris issues, #2154. [brancoliticus] +**** Fix gated clocks under --protect-lib, #2169. [Todd Strader] + * Verilator 4.026 2020-01-11 From 23eb96579cf0e6ba27bcbef91bcb738bd0da27ad Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 24 Feb 2020 18:11:41 -0500 Subject: [PATCH 12/50] Fix duplicate __STDC_FORMAT_MACROS definition. --- include/verilatedos.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/verilatedos.h b/include/verilatedos.h index 1db5ad3e1..cc3bdd3b3 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -223,9 +223,12 @@ #ifdef __MINGW32__ # define __USE_MINGW_ANSI_STDIO 1 // Force old MinGW (GCC 5 and older) to use C99 formats -# define __STDC_FORMAT_MACROS 1 // Otherwise MinGW doesn't get PRId64 for fstapi.c #endif +// The inttypes supplied with some GCC & MINGW32 versions requires STDC_FORMAT_MACROS +// to be declared in order to get the PRIxx macros used by fstapi.c +#define __STDC_FORMAT_MACROS + #if defined(__CYGWIN__) # include @@ -273,10 +276,6 @@ typedef signed __int32 ssize_t; ///< signed size_t; returned fro #else // Linux or compliant Unix flavors, -m64 -// The inttypes supplied with some GCC versions requires STDC_FORMAT_MACROS -// to be declared in order to get the PRIxx macros used by fstapi.c -#define __STDC_FORMAT_MACROS - # include // Solaris # include // Linux and most flavors # include // __WORDSIZE From c9b74847d10fae5753e4e70dc98c815571aed12d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 24 Feb 2020 18:11:56 -0500 Subject: [PATCH 13/50] Docs: Tighter margins, save 10 pages. --- src/pod2latexfix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pod2latexfix b/src/pod2latexfix index ce6ecaab5..149e311de 100755 --- a/src/pod2latexfix +++ b/src/pod2latexfix @@ -20,7 +20,7 @@ my $Opt_DistTitle = $ARGV[0] or die "%Error: No disttitle specified,"; my $Opt_DistDate = $ARGV[1] or die "%Error: No distdate specified,"; my $header = - ("\\usepackage[left=1.7in,right=1.7in,top=1.3in,bottom=1.3in]{geometry}\n" + ("\\usepackage[left=1.0in,right=1.0in,top=1.0in,bottom=1.0in]{geometry}\n" ."\\usepackage[pdftex,bookmarks=true,bookmarksnumbered=true,hypertexnames=false,breaklinks=true,colorlinks=true,linkcolor=blue]{hyperref}\n" ."\\usepackage{fancyhdr} \\pagestyle{fancy}\n" ."\\usepackage{graphicx}\n" From 93ac79981ba85994dd8d14b7e7ea10485bcbe49e Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 24 Feb 2020 18:51:44 -0500 Subject: [PATCH 14/50] Tests: Rename t_var_dotted. No functional change. --- test_regress/t/t_var_dotted.v | 173 ------------------ test_regress/t/t_var_dotted1.v | 173 ++++++++++++++++++ ...r_dotted_inl0.pl => t_var_dotted1_inl0.pl} | 2 +- ...r_dotted_inl1.pl => t_var_dotted1_inl1.pl} | 2 +- ...r_dotted_inl2.pl => t_var_dotted1_inl2.pl} | 2 +- 5 files changed, 176 insertions(+), 176 deletions(-) delete mode 100644 test_regress/t/t_var_dotted.v create mode 100644 test_regress/t/t_var_dotted1.v rename test_regress/t/{t_var_dotted_inl0.pl => t_var_dotted1_inl0.pl} (93%) rename test_regress/t/{t_var_dotted_inl1.pl => t_var_dotted1_inl1.pl} (93%) rename test_regress/t/{t_var_dotted_inl2.pl => t_var_dotted1_inl2.pl} (93%) diff --git a/test_regress/t/t_var_dotted.v b/test_regress/t/t_var_dotted.v deleted file mode 100644 index e693d26c8..000000000 --- a/test_regress/t/t_var_dotted.v +++ /dev/null @@ -1,173 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed into the Public Domain, for any use, -// without warranty, 2006 by Wilson Snyder. - -module t (/*AUTOARG*/ - // Inputs - clk - ); - - // verilator lint_off MULTIDRIVEN - - wire [31:0] outb0c0; - wire [31:0] outb0c1; - wire [31:0] outb1c0; - wire [31:0] outb1c1; - - reg [7:0] lclmem [7:0]; - - ma ma0 (.outb0c0(outb0c0), .outb0c1(outb0c1), - .outb1c0(outb1c0), .outb1c1(outb1c1) - ); - - global_mod #(32'hf00d) global_cell (); - global_mod #(32'hf22d) global_cell2 (); - - input clk; - integer cyc=1; - always @ (posedge clk) begin - cyc <= cyc + 1; -`ifdef TEST_VERBOSE - $write("[%0t] cyc%0d: %0x %0x %0x %0x\n", $time, cyc, outb0c0, outb0c1, outb1c0, outb1c1); -`endif - if (cyc==2) begin - if (global_cell.globali != 32'hf00d) $stop; - if (global_cell2.globali != 32'hf22d) $stop; - if (outb0c0 != 32'h00) $stop; - if (outb0c1 != 32'h01) $stop; - if (outb1c0 != 32'h10) $stop; - if (outb1c1 != 32'h11) $stop; - end - if (cyc==3) begin - // Can we scope down and read and write vars? - ma0.mb0.mc0.out <= ma0.mb0.mc0.out + 32'h100; - ma0.mb0.mc1.out <= ma0.mb0.mc1.out + 32'h100; - ma0.mb1.mc0.out <= ma0.mb1.mc0.out + 32'h100; - ma0.mb1.mc1.out <= ma0.mb1.mc1.out + 32'h100; - end - if (cyc==4) begin - // Can we do dotted's inside array sels? - ma0.rmtmem[ma0.mb0.mc0.out[2:0]] = 8'h12; - lclmem[ma0.mb0.mc0.out[2:0]] = 8'h24; - if (outb0c0 != 32'h100) $stop; - if (outb0c1 != 32'h101) $stop; - if (outb1c0 != 32'h110) $stop; - if (outb1c1 != 32'h111) $stop; - end - if (cyc==5) begin - if (ma0.rmtmem[ma0.mb0.mc0.out[2:0]] != 8'h12) $stop; - if (lclmem[ma0.mb0.mc0.out[2:0]] != 8'h24) $stop; - if (outb0c0 != 32'h1100) $stop; - if (outb0c1 != 32'h2101) $stop; - if (outb1c0 != 32'h2110) $stop; - if (outb1c1 != 32'h3111) $stop; - end - if (cyc==6) begin - if (outb0c0 != 32'h31100) $stop; - if (outb0c1 != 32'h02101) $stop; - if (outb1c0 != 32'h42110) $stop; - if (outb1c1 != 32'h03111) $stop; - end - if (cyc==9) begin - $write("*-* All Finished *-*\n"); - $finish; - end - end - -endmodule - -`ifdef USE_INLINE_MID - `define INLINE_MODULE /*verilator inline_module*/ - `define INLINE_MID_MODULE /*verilator no_inline_module*/ -`else - `ifdef USE_INLINE - `define INLINE_MODULE /*verilator inline_module*/ - `define INLINE_MID_MODULE /*verilator inline_module*/ - `else - `define INLINE_MODULE /*verilator public_module*/ - `define INLINE_MID_MODULE /*verilator public_module*/ - `endif -`endif - -module global_mod; - `INLINE_MODULE - parameter INITVAL = 0; - integer globali; - initial globali = INITVAL; -endmodule - -module ma ( - output wire [31:0] outb0c0, - output wire [31:0] outb0c1, - output wire [31:0] outb1c0, - output wire [31:0] outb1c1 - ); - `INLINE_MODULE - - reg [7:0] rmtmem [7:0]; - - mb #(0) mb0 (.outc0(outb0c0), .outc1(outb0c1)); - mb #(1) mb1 (.outc0(outb1c0), .outc1(outb1c1)); -endmodule - -module mb ( - output wire [31:0] outc0, - output wire [31:0] outc1 - ); - `INLINE_MID_MODULE - parameter P2 = 0; - mc #(P2,0) mc0 (.out(outc0)); - mc #(P2,1) mc1 (.out(outc1)); - global_mod #(32'hf33d) global_cell2 (); - - wire reach_up_clk = t.clk; - always @(reach_up_clk) begin - if (P2==0) begin // Only for mb0 - if (outc0 !== t.ma0.mb0.mc0.out) $stop; // Top module name and lower instances - if (outc0 !== ma0.mb0.mc0.out) $stop; // Upper module name and lower instances - if (outc0 !== ma .mb0.mc0.out) $stop; // Upper module name and lower instances - if (outc0 !== mb.mc0.out) $stop; // This module name and lower instances - if (outc0 !== mb0.mc0.out) $stop; // Upper instance name and lower instances - if (outc0 !== mc0.out) $stop; // Lower instances - - if (outc1 !== t.ma0.mb0.mc1.out) $stop; // Top module name and lower instances - if (outc1 !== ma0.mb0.mc1.out) $stop; // Upper module name and lower instances - if (outc1 !== ma .mb0.mc1.out) $stop; // Upper module name and lower instances - if (outc1 !== mb.mc1.out) $stop; // This module name and lower instances - if (outc1 !== mb0.mc1.out) $stop; // Upper instance name and lower instances - if (outc1 !== mc1.out) $stop; // Lower instances - end - end -endmodule - -module mc (output reg [31:0] out); - `INLINE_MODULE - parameter P2 = 0; - parameter P3 = 0; - initial begin - out = {24'h0,P2[3:0],P3[3:0]}; - //$write("%m P2=%0x p3=%0x out=%x\n",P2, P3, out); - end - - // Can we look from the top module name down? - wire [31:0] reach_up_cyc = t.cyc; - - always @ (posedge t.clk) begin - //$write("[%0t] %m: Got reachup, cyc=%0d\n", $time, reach_up_cyc); - if (reach_up_cyc==2) begin - if (global_cell.globali != 32'hf00d) $stop; - if (global_cell2.globali != 32'hf33d) $stop; - end - if (reach_up_cyc==4) begin - out[15:12] <= {P2[3:0]+P3[3:0]+4'd1}; - end - if (reach_up_cyc==5) begin - // Can we set another instance? - if (P3==1) begin // Without this, there are two possible correct answers... - mc0.out[19:16] <= {mc0.out[19:16]+P2[3:0]+P3[3:0]+4'd2}; - $display("%m Set %x->%x %x %x %x %x",mc0.out, {mc0.out[19:16]+P2[3:0]+P3[3:0]+4'd2}, mc0.out[19:16],P2[3:0],P3[3:0],4'd2); - end - end - end -endmodule diff --git a/test_regress/t/t_var_dotted1.v b/test_regress/t/t_var_dotted1.v new file mode 100644 index 000000000..da1fb4c7b --- /dev/null +++ b/test_regress/t/t_var_dotted1.v @@ -0,0 +1,173 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2006 by Wilson Snyder. + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + // verilator lint_off MULTIDRIVEN + + wire [31:0] outb0c0; + wire [31:0] outb0c1; + wire [31:0] outb1c0; + wire [31:0] outb1c1; + + reg [7:0] lclmem [7:0]; + + ma ma0 (.outb0c0(outb0c0), .outb0c1(outb0c1), + .outb1c0(outb1c0), .outb1c1(outb1c1) + ); + + global_mod #(32'hf00d) global_cell (); + global_mod #(32'hf22d) global_cell2 (); + + input clk; + integer cyc=1; + always @ (posedge clk) begin + cyc <= cyc + 1; +`ifdef TEST_VERBOSE + $write("[%0t] cyc%0d: %0x %0x %0x %0x\n", $time, cyc, outb0c0, outb0c1, outb1c0, outb1c1); +`endif + if (cyc==2) begin + if (global_cell.globali != 32'hf00d) $stop; + if (global_cell2.globali != 32'hf22d) $stop; + if (outb0c0 != 32'h00) $stop; + if (outb0c1 != 32'h01) $stop; + if (outb1c0 != 32'h10) $stop; + if (outb1c1 != 32'h11) $stop; + end + if (cyc==3) begin + // Can we scope down and read and write vars? + ma0.mb0.mc0.out <= ma0.mb0.mc0.out + 32'h100; + ma0.mb0.mc1.out <= ma0.mb0.mc1.out + 32'h100; + ma0.mb1.mc0.out <= ma0.mb1.mc0.out + 32'h100; + ma0.mb1.mc1.out <= ma0.mb1.mc1.out + 32'h100; + end + if (cyc==4) begin + // Can we do dotted's inside array sels? + ma0.rmtmem[ma0.mb0.mc0.out[2:0]] = 8'h12; + lclmem[ma0.mb0.mc0.out[2:0]] = 8'h24; + if (outb0c0 != 32'h100) $stop; + if (outb0c1 != 32'h101) $stop; + if (outb1c0 != 32'h110) $stop; + if (outb1c1 != 32'h111) $stop; + end + if (cyc==5) begin + if (ma0.rmtmem[ma0.mb0.mc0.out[2:0]] != 8'h12) $stop; + if (lclmem[ma0.mb0.mc0.out[2:0]] != 8'h24) $stop; + if (outb0c0 != 32'h1100) $stop; + if (outb0c1 != 32'h2101) $stop; + if (outb1c0 != 32'h2110) $stop; + if (outb1c1 != 32'h3111) $stop; + end + if (cyc==6) begin + if (outb0c0 != 32'h31100) $stop; + if (outb0c1 != 32'h02101) $stop; + if (outb1c0 != 32'h42110) $stop; + if (outb1c1 != 32'h03111) $stop; + end + if (cyc==9) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule + +`ifdef USE_INLINE_MID + `define INLINE_MODULE /*verilator inline_module*/ + `define INLINE_MID_MODULE /*verilator no_inline_module*/ +`else + `ifdef USE_INLINE + `define INLINE_MODULE /*verilator inline_module*/ + `define INLINE_MID_MODULE /*verilator inline_module*/ + `else + `define INLINE_MODULE /*verilator public_module*/ + `define INLINE_MID_MODULE /*verilator public_module*/ + `endif +`endif + +module global_mod; + `INLINE_MODULE + parameter INITVAL = 0; + integer globali; + initial globali = INITVAL; +endmodule + +module ma ( + output wire [31:0] outb0c0, + output wire [31:0] outb0c1, + output wire [31:0] outb1c0, + output wire [31:0] outb1c1 + ); + `INLINE_MODULE + + reg [7:0] rmtmem [7:0]; + + mb #(0) mb0 (.outc0(outb0c0), .outc1(outb0c1)); + mb #(1) mb1 (.outc0(outb1c0), .outc1(outb1c1)); +endmodule + +module mb ( + output wire [31:0] outc0, + output wire [31:0] outc1 + ); + `INLINE_MID_MODULE + parameter P2 = 0; + mc #(P2,0) mc0 (.out(outc0)); + mc #(P2,1) mc1 (.out(outc1)); + global_mod #(32'hf33d) global_cell2 (); + + wire reach_up_clk = t.clk; + always @(reach_up_clk) begin + if (P2==0) begin // Only for mb0 + if (outc0 !== t.ma0.mb0.mc0.out) $stop; // Top module name and lower instances + if (outc0 !== ma0.mb0.mc0.out) $stop; // Upper module name and lower instances + if (outc0 !== ma .mb0.mc0.out) $stop; // Upper module name and lower instances + if (outc0 !== mb.mc0.out) $stop; // This module name and lower instances + if (outc0 !== mb0.mc0.out) $stop; // Upper instance name and lower instances + if (outc0 !== mc0.out) $stop; // Lower instances + + if (outc1 !== t.ma0.mb0.mc1.out) $stop; // Top module name and lower instances + if (outc1 !== ma0.mb0.mc1.out) $stop; // Upper module name and lower instances + if (outc1 !== ma .mb0.mc1.out) $stop; // Upper module name and lower instances + if (outc1 !== mb.mc1.out) $stop; // This module name and lower instances + if (outc1 !== mb0.mc1.out) $stop; // Upper instance name and lower instances + if (outc1 !== mc1.out) $stop; // Lower instances + end + end +endmodule + +module mc (output reg [31:0] out); + `INLINE_MODULE + parameter P2 = 0; + parameter P3 = 0; + initial begin + out = {24'h0,P2[3:0],P3[3:0]}; + //$write("%m P2=%0x p3=%0x out=%x\n",P2, P3, out); + end + + // Can we look from the top module name down? + wire [31:0] reach_up_cyc = t.cyc; + + always @ (posedge t.clk) begin + //$write("[%0t] %m: Got reachup, cyc=%0d\n", $time, reach_up_cyc); + if (reach_up_cyc==2) begin + if (global_cell.globali != 32'hf00d) $stop; + if (global_cell2.globali != 32'hf33d) $stop; + end + if (reach_up_cyc==4) begin + out[15:12] <= {P2[3:0]+P3[3:0]+4'd1}; + end + if (reach_up_cyc==5) begin + // Can we set another instance? + if (P3==1) begin // Without this, there are two possible correct answers... + mc0.out[19:16] <= {mc0.out[19:16]+P2[3:0]+P3[3:0]+4'd2}; + $display("%m Set %x->%x %x %x %x %x",mc0.out, {mc0.out[19:16]+P2[3:0]+P3[3:0]+4'd2}, mc0.out[19:16],P2[3:0],P3[3:0],4'd2); + end + end + end +endmodule diff --git a/test_regress/t/t_var_dotted_inl0.pl b/test_regress/t/t_var_dotted1_inl0.pl similarity index 93% rename from test_regress/t/t_var_dotted_inl0.pl rename to test_regress/t/t_var_dotted1_inl0.pl index 73474fc47..3dde25892 100755 --- a/test_regress/t/t_var_dotted_inl0.pl +++ b/test_regress/t/t_var_dotted1_inl0.pl @@ -9,7 +9,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -top_filename("t/t_var_dotted.v"); +top_filename("t/t_var_dotted1.v"); compile( v_flags2 => ['+define+NOUSE_INLINE',], diff --git a/test_regress/t/t_var_dotted_inl1.pl b/test_regress/t/t_var_dotted1_inl1.pl similarity index 93% rename from test_regress/t/t_var_dotted_inl1.pl rename to test_regress/t/t_var_dotted1_inl1.pl index 2dca3e9a2..a1676170d 100755 --- a/test_regress/t/t_var_dotted_inl1.pl +++ b/test_regress/t/t_var_dotted1_inl1.pl @@ -9,7 +9,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -top_filename("t/t_var_dotted.v"); +top_filename("t/t_var_dotted1.v"); compile( v_flags2 => ['+define+USE_INLINE',], diff --git a/test_regress/t/t_var_dotted_inl2.pl b/test_regress/t/t_var_dotted1_inl2.pl similarity index 93% rename from test_regress/t/t_var_dotted_inl2.pl rename to test_regress/t/t_var_dotted1_inl2.pl index 9d713d5ee..39dbfed77 100755 --- a/test_regress/t/t_var_dotted_inl2.pl +++ b/test_regress/t/t_var_dotted1_inl2.pl @@ -9,7 +9,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -top_filename("t/t_var_dotted.v"); +top_filename("t/t_var_dotted1.v"); compile( v_flags2 => ['+define+USE_INLINE_MID',], From 5b83484f20482cce9e95b538d6b1b386cc12e353 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 25 Feb 2020 18:57:51 -0500 Subject: [PATCH 15/50] Remove dead genblk code & some cleanups. --- src/V3AstNodes.h | 15 --------------- src/V3EmitV.cpp | 7 +------ src/V3LinkDot.cpp | 15 --------------- src/V3Param.cpp | 14 -------------- src/verilog.y | 12 +++++++----- 5 files changed, 8 insertions(+), 55 deletions(-) diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index dcba2822f..b7b5fe89e 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -2332,21 +2332,6 @@ public: //###################################################################### -class AstGenerate : public AstNode { - // A Generate/end block - // Parents: MODULE - // Children: modItems -public: - AstGenerate(FileLine* fl, AstNode* stmtsp) - : ASTGEN_SUPER(fl) { - addNOp1p(stmtsp); - } - ASTNODE_NODE_FUNCS(Generate) - // op1 = Statements - AstNode* stmtsp() const { return op1p(); } // op1 = List of statements - void addStmtp(AstNode* nodep) { addOp1p(nodep); } -}; - class AstParseRef : public AstNode { // A reference to a variable, function or task // We don't know which at parse time due to bison constraints diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index a07f6d477..afa57b8cf 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -76,7 +76,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { } virtual void visit(AstBegin* nodep) VL_OVERRIDE { - if (nodep->unnamed()) { + if (nodep->name() == "") { putbs("begin\n"); } else { putbs("begin : "+nodep->name()+"\n"); @@ -84,11 +84,6 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { iterateChildren(nodep); puts("end\n"); } - virtual void visit(AstGenerate* nodep) VL_OVERRIDE { - putfs(nodep, "generate\n"); - iterateChildren(nodep); - putqs(nodep, "end\n"); - } virtual void visit(AstFinal* nodep) VL_OVERRIDE { putfs(nodep, "final begin\n"); iterateChildren(nodep); diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index c7a045d1d..17db13e72 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -683,7 +683,6 @@ class LinkDotFindVisitor : public AstNVisitor { string m_scope; // Scope text AstBegin* m_beginp; // Current Begin/end block AstNodeFTask* m_ftaskp; // Current function/task - bool m_inGenerate; // Inside a generate bool m_inRecursion; // Inside a recursive module int m_paramNum; // Parameter number, for position based connection int m_beginNum; // Begin block number, 0=none seen @@ -891,16 +890,6 @@ class LinkDotFindVisitor : public AstNVisitor { nodep->user1p(m_curSymp); iterateChildren(nodep); } - virtual void visit(AstGenerate* nodep) VL_OVERRIDE { - // Begin: ... blocks often replicate under genif/genfor, so simply - // suppress duplicate checks. See t_gen_forif.v for an example. - bool lastInGen = m_inGenerate; - { - m_inGenerate = true; - iterateChildren(nodep); - } - m_inGenerate = lastInGen; - } virtual void visit(AstBegin* nodep) VL_OVERRIDE { UINFO(5," "<name(nodep->name()+cvtToStr(m_beginNum)); } - // Just for loop index, make special name. The [00] is so it will "dearray" to same - // name as after we expand the GENFOR - if (nodep->genforp()) nodep->name(nodep->name()); } // All blocks are numbered in the standard, IE we start with "genblk1" even if only one. if (nodep->name()=="" && nodep->unnamed()) { @@ -1202,7 +1188,6 @@ public: m_statep = statep; m_beginp = NULL; m_ftaskp = NULL; - m_inGenerate = false; m_inRecursion = false; m_paramNum = 0; m_beginNum = 0; diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 1d758de07..9b551167c 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -431,20 +431,6 @@ private: } // Generate Statements - virtual void visit(AstGenerate* nodep) VL_OVERRIDE { - if (debug()>=9) nodep->dumpTree(cout, "-genin: "); - iterateChildren(nodep); - // After expanding the generate, all statements under it can be moved - // up, and the generate block deleted as it's not relevant - if (AstNode* stmtsp = nodep->stmtsp()) { - stmtsp->unlinkFrBackWithNext(); - nodep->replaceWith(stmtsp); - if (debug()>=9) stmtsp->dumpTree(cout, "-genout: "); - } else { - nodep->unlinkFrBack(); - } - VL_DO_DANGLING(nodep->deleteTree(), nodep); - } virtual void visit(AstGenIf* nodep) VL_OVERRIDE { UINFO(9," GENIF "<condp()); diff --git a/src/verilog.y b/src/verilog.y index 9427d1b8d..211e60a0b 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -1155,7 +1155,7 @@ interface_item: // IEEE: interface_item + non_port_interface_item ; interface_generate_region: // ==IEEE: generate_region - yGENERATE interface_itemList yENDGENERATE { $$ = new AstGenerate($1, $2); } + yGENERATE interface_itemList yENDGENERATE { $$ = $2; } | yGENERATE yENDGENERATE { $$ = NULL; } ; @@ -2035,7 +2035,7 @@ bind_instantiation: // ==IEEE: bind_instantiation // different, so we copy all rules for checkers. generate_region: // ==IEEE: generate_region - yGENERATE ~c~genItemList yENDGENERATE { $$ = new AstGenerate($1, $2); } + yGENERATE ~c~genItemList yENDGENERATE { $$ = $2; } | yGENERATE yENDGENERATE { $$ = NULL; } ; @@ -2043,7 +2043,7 @@ generate_region: // ==IEEE: generate_region //UNSUP BISONPRE_COPY(generate_region,{s/~c~/c_/g}) // {copied} //UNSUP ; -generate_block_or_null: // IEEE: generate_block_or_null +generate_block_or_null: // IEEE: generate_block_or_null (called from gencase/genif/genfor) // ';' // is included in // // IEEE: generate_block // // Must always return a BEGIN node, or NULL - see GenFor construction @@ -2054,9 +2054,11 @@ generate_block_or_null: // IEEE: generate_block_or_null genItemBegin: // IEEE: part of generate_block yBEGIN ~c~genItemList yEND { $$ = new AstBegin($1,"genblk",$2,true); } | yBEGIN yEND { $$ = NULL; } - | id ':' yBEGIN ~c~genItemList yEND endLabelE { $$ = new AstBegin($1,*$1,$4,true); GRAMMARP->endLabel($6,*$1,$6); } + | id ':' yBEGIN ~c~genItemList yEND endLabelE + { $$ = new AstBegin($1,*$1,$4,true); GRAMMARP->endLabel($6,*$1,$6); } | id ':' yBEGIN yEND endLabelE { $$ = NULL; GRAMMARP->endLabel($5,*$1,$5); } - | yBEGIN ':' idAny ~c~ genItemList yEND endLabelE { $$ = new AstBegin($3,*$3,$4,true); GRAMMARP->endLabel($6,*$3,$6); } + | yBEGIN ':' idAny ~c~genItemList yEND endLabelE + { $$ = new AstBegin($3,*$3,$4,true); GRAMMARP->endLabel($6,*$3,$6); } | yBEGIN ':' idAny yEND endLabelE { $$ = NULL; GRAMMARP->endLabel($5,*$3,$5); } ; From 4c438bbc672b225404ce2d447c0f494810785bad Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 25 Feb 2020 19:01:14 -0500 Subject: [PATCH 16/50] Commentary --- bin/verilator | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/verilator b/bin/verilator index 41be3b13d..0a3beebf0 100755 --- a/bin/verilator +++ b/bin/verilator @@ -1906,13 +1906,13 @@ Now we run Verilator on our little example. We then can compile it - cd obj_dir - make -j -f Vour.mk Vour__ALL.a - make -j -f Vour.mk ../sc_main.o verilated.o + make -j -C obj_dir -f Vour.mk Vour__ALL.a + make -j -C obj_dir -f Vour.mk ../sc_main.o verilated.o And link with SystemC. Note your path to the libraries may vary, depending on the operating system. + cd obj_dir export SYSTEMC_LIBDIR=/path/to/where/libsystemc.a/exists export LD_LIBRARY_PATH=$SYSTEMC_LIBDIR:$LD_LIBRARY_PATH # Might be needed if SystemC 2.3.0 From 68b6a0b66743cc660f25cc3b660e2a5ee3189692 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 25 Feb 2020 22:21:16 -0500 Subject: [PATCH 17/50] Fix genblk naming with directly nested generate blocks, #2176. --- Changes | 2 + src/V3AstNodes.cpp | 1 + src/V3AstNodes.h | 10 +- src/V3Begin.cpp | 2 +- src/V3LinkDot.cpp | 34 +++--- src/V3LinkParse.cpp | 17 ++- src/verilog.y | 21 ++-- test_regress/t/t_gen_genblk.out | 6 + test_regress/t/t_gen_genblk.pl | 20 ++++ test_regress/t/t_gen_genblk.v | 51 +++++++++ test_regress/t/t_gen_genblk_noinl.pl | 23 ++++ test_regress/t/t_interface_gen7.v | 6 +- test_regress/t/t_var_dotted2.v | 131 ++++++++++++++++++++++ test_regress/t/t_var_dotted2_inl0.pl | 23 ++++ test_regress/t/t_var_dotted2_inl1.pl | 23 ++++ test_regress/t/t_var_dotted_dup_bad.out | 7 ++ test_regress/t/t_var_dotted_dup_bad.pl | 18 +++ test_regress/t/t_var_dotted_dup_bad.v | 20 ++++ test_regress/t/t_var_nonamebegin__log.out | 12 +- test_regress/t/t_var_notfound_bad.out | 2 +- 20 files changed, 390 insertions(+), 39 deletions(-) create mode 100644 test_regress/t/t_gen_genblk.out create mode 100755 test_regress/t/t_gen_genblk.pl create mode 100644 test_regress/t/t_gen_genblk.v create mode 100755 test_regress/t/t_gen_genblk_noinl.pl create mode 100644 test_regress/t/t_var_dotted2.v create mode 100755 test_regress/t/t_var_dotted2_inl0.pl create mode 100755 test_regress/t/t_var_dotted2_inl1.pl create mode 100644 test_regress/t/t_var_dotted_dup_bad.out create mode 100755 test_regress/t/t_var_dotted_dup_bad.pl create mode 100644 test_regress/t/t_var_dotted_dup_bad.v diff --git a/Changes b/Changes index 1b8aedeb5..986c8a9a8 100644 --- a/Changes +++ b/Changes @@ -9,6 +9,8 @@ The contributors that suggested a given feature are shown in []. Thanks! *** Add check for assertOn for asserts, #2162. [Tobias Wölfel] +*** Fix genblk naming with directly nested generate blocks, #2176. [Alexander Grobman] + **** Fix undeclared VL_SHIFTR_WWQ, #2114. [Alex Solomatnikov] diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 835758651..127026a30 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1282,6 +1282,7 @@ void AstBegin::dump(std::ostream& str) const { if (unnamed()) str<<" [UNNAMED]"; if (generate()) str<<" [GEN]"; if (genforp()) str<<" [GENFOR]"; + if (implied()) str<<" [IMPLIED]"; } void AstCoverDecl::dump(std::ostream& str) const { this->AstNode::dump(str); diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index b7b5fe89e..02d2a316c 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -3736,16 +3736,19 @@ class AstBegin : public AstNode { // Children: statements private: string m_name; // Name of block - bool m_unnamed; // Originally unnamed + bool m_unnamed; // Originally unnamed (name change does not affect this) bool m_generate; // Underneath a generate + bool m_implied; // Not inserted by user public: // Node that simply puts name into the output stream - AstBegin(FileLine* fl, const string& name, AstNode* stmtsp, bool generate=false) + AstBegin(FileLine* fl, const string& name, AstNode* stmtsp, bool generate = false, + bool implied = false) : ASTGEN_SUPER(fl) , m_name(name) { addNOp1p(stmtsp); - m_unnamed = (name==""); + m_unnamed = (name == ""); m_generate = generate; + m_implied = implied; } ASTNODE_NODE_FUNCS(Begin) virtual void dump(std::ostream& str) const; @@ -3760,6 +3763,7 @@ public: bool unnamed() const { return m_unnamed; } void generate(bool flag) { m_generate = flag; } bool generate() const { return m_generate; } + bool implied() const { return m_implied; } }; class AstInitial : public AstNode { diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index 2cb65de2e..77650f7a4 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -125,7 +125,7 @@ private: while ((pos=dottedname.find("__DOT__")) != string::npos) { string ident = dottedname.substr(0, pos); dottedname = dottedname.substr(pos+strlen("__DOT__")); - if (!nodep->unnamed()) { + if (nodep->name() != "") { if (m_namedScope=="") m_namedScope = ident; else m_namedScope = m_namedScope + "__DOT__"+ident; } diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 17db13e72..557e2769c 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -914,20 +914,24 @@ class LinkDotFindVisitor : public AstNVisitor { } } } - int oldNum = m_beginNum; - AstBegin* oldbegin = m_beginp; - VSymEnt* oldCurSymp = m_curSymp; - { - m_beginNum = 0; - m_beginp = nodep; - m_curSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_packagep); - m_curSymp->fallbackp(oldCurSymp); - // Iterate + if (nodep->name() == "") { iterateChildren(nodep); + } else { + int oldNum = m_beginNum; + AstBegin* oldbegin = m_beginp; + VSymEnt* oldCurSymp = m_curSymp; + { + m_beginNum = 0; + m_beginp = nodep; + m_curSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_packagep); + m_curSymp->fallbackp(oldCurSymp); + // Iterate + iterateChildren(nodep); + } + m_curSymp = oldCurSymp; + m_beginp = oldbegin; + m_beginNum = oldNum; } - m_curSymp = oldCurSymp; - m_beginp = oldbegin; - m_beginNum = oldNum; } virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { // NodeTask: Remember its name for later resolution @@ -2449,8 +2453,10 @@ private: checkNoDot(nodep); VSymEnt* oldCurSymp = m_curSymp; { - m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep); - UINFO(5," cur=se"<name() != "") { + m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep); + UINFO(5," cur=se"<addNext(new AstWhile(fl, condp, newp, incp)); - newp = new AstBegin(nodep->fileline(), "", stmtsp); + newp = new AstBegin(nodep->fileline(), "", stmtsp, false, true); dimension--; } //newp->dumpTree(cout, "-foreach-new:"); @@ -488,6 +488,21 @@ private: virtual void visit(AstBegin* nodep) VL_OVERRIDE { V3Config::applyCoverageBlock(m_modp, nodep); cleanFileline(nodep); + AstNode* backp = nodep->backp(); + // IEEE says directly nested item is not a new block + bool nestedIf = (nodep->implied() // User didn't provide begin/end + && (VN_IS(nodep->stmtsp(), GenIf) + || VN_IS(nodep->stmtsp(), GenCase)) // Has an if/case + && !nodep->stmtsp()->nextp()); // Has only one item + // It's not FOR(BEGIN(...)) but we earlier changed it to BEGIN(FOR(...)) + if (nodep->genforp() && nodep->name() == "") { + nodep->name("genblk"); + } + else if (nodep->generate() && nodep->name() == "" + && (VN_IS(backp, CaseItem) || VN_IS(backp, GenIf)) + && !nestedIf) { + nodep->name("genblk"); + } iterateChildren(nodep); } virtual void visit(AstCase* nodep) VL_OVERRIDE { diff --git a/src/verilog.y b/src/verilog.y index 211e60a0b..f7b9320e7 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -2047,18 +2047,18 @@ generate_block_or_null: // IEEE: generate_block_or_null (called from genc // ';' // is included in // // IEEE: generate_block // // Must always return a BEGIN node, or NULL - see GenFor construction - generate_item { $$ = $1 ? (new AstBegin($1->fileline(),"genblk",$1,true)) : NULL; } + generate_item { $$ = $1 ? (new AstBegin($1->fileline(),"",$1,true,true)) : NULL; } | genItemBegin { $$ = $1; } ; genItemBegin: // IEEE: part of generate_block - yBEGIN ~c~genItemList yEND { $$ = new AstBegin($1,"genblk",$2,true); } + yBEGIN ~c~genItemList yEND { $$ = new AstBegin($1,"",$2,true,false); } | yBEGIN yEND { $$ = NULL; } | id ':' yBEGIN ~c~genItemList yEND endLabelE - { $$ = new AstBegin($1,*$1,$4,true); GRAMMARP->endLabel($6,*$1,$6); } + { $$ = new AstBegin($1,*$1,$4,true,false); GRAMMARP->endLabel($6,*$1,$6); } | id ':' yBEGIN yEND endLabelE { $$ = NULL; GRAMMARP->endLabel($5,*$1,$5); } | yBEGIN ':' idAny ~c~genItemList yEND endLabelE - { $$ = new AstBegin($3,*$3,$4,true); GRAMMARP->endLabel($6,*$3,$6); } + { $$ = new AstBegin($3,*$3,$4,true,false); GRAMMARP->endLabel($6,*$3,$6); } | yBEGIN ':' idAny yEND endLabelE { $$ = NULL; GRAMMARP->endLabel($5,*$3,$5); } ; @@ -2116,11 +2116,11 @@ loop_generate_construct: // ==IEEE: loop_generate_construct { // Convert BEGIN(...) to BEGIN(GENFOR(...)), as we need the BEGIN to hide the local genvar AstBegin* lowerBegp = VN_CAST($9, Begin); UASSERT_OBJ(!($9 && !lowerBegp), $9, "Child of GENFOR should have been begin"); - if (!lowerBegp) lowerBegp = new AstBegin($1,"genblk",NULL,true); // Empty body + if (!lowerBegp) lowerBegp = new AstBegin($1, "genblk", NULL, true, true); // Empty body AstNode* lowerNoBegp = lowerBegp->stmtsp(); if (lowerNoBegp) lowerNoBegp->unlinkFrBackWithNext(); // - AstBegin* blkp = new AstBegin($1,lowerBegp->name(),NULL,true); + AstBegin* blkp = new AstBegin($1, lowerBegp->name(), NULL, true, true); // V3LinkDot detects BEGIN(GENFOR(...)) as a special case AstNode* initp = $3; AstNode* varp = $3; if (VN_IS(varp, Var)) { // Genvar @@ -2793,10 +2793,10 @@ statement_item: // IEEE: statement_item statementFor: // IEEE: part of statement yFOR '(' for_initialization expr ';' for_stepE ')' stmtBlock - { $$ = new AstBegin($1,"",$3); + { $$ = new AstBegin($1, "", $3, false, true); $$->addStmtsp(new AstWhile($1, $4,$8,$6)); } | yFOR '(' for_initialization ';' for_stepE ')' stmtBlock - { $$ = new AstBegin($1,"",$3); + { $$ = new AstBegin($1, "", $3, false, true); $$->addStmtsp(new AstWhile($1, new AstConst($1,AstConst::LogicTrue()),$7,$5)); } ; @@ -4473,7 +4473,7 @@ assertion_item: // ==IEEE: assertion_item deferred_immediate_assertion_item: // ==IEEE: deferred_immediate_assertion_item deferred_immediate_assertion_statement { $$ = $1; } | id/*block_identifier*/ ':' deferred_immediate_assertion_statement - { $$ = new AstBegin($1, *$1, $3); } + { $$ = new AstBegin($1, *$1, $3, false, true); } ; procedural_assertion_statement: // ==IEEE: procedural_assertion_statement @@ -4528,7 +4528,8 @@ deferred_immediate_assertion_statement: // ==IEEE: deferred_immediate_ass concurrent_assertion_item: // IEEE: concurrent_assertion_item concurrent_assertion_statement { $$ = $1; } - | id/*block_identifier*/ ':' concurrent_assertion_statement { $$ = new AstBegin($1, *$1, $3); } + | id/*block_identifier*/ ':' concurrent_assertion_statement + { $$ = new AstBegin($1, *$1, $3, false, true); } // // IEEE: checker_instantiation // // identical to module_instantiation; see etcInst ; diff --git a/test_regress/t/t_gen_genblk.out b/test_regress/t/t_gen_genblk.out new file mode 100644 index 000000000..abaca2eeb --- /dev/null +++ b/test_regress/t/t_gen_genblk.out @@ -0,0 +1,6 @@ +010: exp=top.t.show0 got=top.t.show0 +014: exp=top.t.genblk1.show1 got=top.t.genblk1.show1 +018: exp=top.t.genblk2.show2 got=top.t.genblk2.show2 +023: exp=top.t.genblk3.genblk1.show3 got=top.t.genblk3.genblk1.show3 +029: exp=top.t.x1.x3.show4 got=top.t.x1.x3.show4 +*-* All Finished *-* diff --git a/test_regress/t/t_gen_genblk.pl b/test_regress/t/t_gen_genblk.pl new file mode 100755 index 000000000..e109f0f6c --- /dev/null +++ b/test_regress/t/t_gen_genblk.pl @@ -0,0 +1,20 @@ +#!/usr/bin/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. + +scenarios(simulator => 1); + +compile( + ); + +execute( + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_gen_genblk.v b/test_regress/t/t_gen_genblk.v new file mode 100644 index 000000000..bb28c18be --- /dev/null +++ b/test_regress/t/t_gen_genblk.v @@ -0,0 +1,51 @@ +module t (/*AUTOARG*/ + // Inputs + clk, reset_l + ); + + input clk; + input reset_l; + + generate + show #(`__LINE__, "top.t.show0") show0(); + + if (0) ; + else if (0) ; + else if (1) show #(`__LINE__, "top.t.genblk1.show1") show1(); + + if (0) begin end + else if (0) begin end + else if (1) begin show #(`__LINE__, "top.t.genblk2.show2") show2(); end + + if (0) ; + else begin + if (0) begin end + else if (1) begin show #(`__LINE__, "top.t.genblk3.genblk1.show3") show3(); end + end + + if (0) ; + else begin : x1 + if (0) begin : x2 end + else if (1) begin : x3 show #(`__LINE__, "top.t.x1.x3.show4") show4(); end + end + endgenerate + + int cyc; + + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 99) begin + $write("*-* All Finished *-*\n"); + $finish; + end + + end +endmodule + +module show #(parameter LINE=0, parameter string EXPT) (); + always @ (posedge t.clk) begin + if (t.cyc == LINE) begin + $display("%03d: exp=%s got=%m", LINE, EXPT); + end + end +endmodule diff --git a/test_regress/t/t_gen_genblk_noinl.pl b/test_regress/t/t_gen_genblk_noinl.pl new file mode 100755 index 000000000..901e0993c --- /dev/null +++ b/test_regress/t/t_gen_genblk_noinl.pl @@ -0,0 +1,23 @@ +#!/usr/bin/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. + +top_filename("t_gen_genblk.v"); + +scenarios(simulator => 1); + +compile( + v_flags2 => ["-Oi"], + ); + +execute( + expect_filename => "t/t_gen_genblk.out", + ); + +ok(1); +1; diff --git a/test_regress/t/t_interface_gen7.v b/test_regress/t/t_interface_gen7.v index dcec13228..c1a0d2a41 100644 --- a/test_regress/t/t_interface_gen7.v +++ b/test_regress/t/t_interface_gen7.v @@ -24,7 +24,7 @@ module t(); generate genvar the_genvar; - begin + begin : ia for (the_genvar = 0; the_genvar < 2; the_genvar++) begin : TestIf begin assign my_intf[the_genvar].val = '1; @@ -36,7 +36,7 @@ module t(); generate genvar the_second_genvar; - begin + begin : ib intf #(.PARAM(1)) my_intf [1:0] (); for (the_second_genvar = 0; the_second_genvar < 2; the_second_genvar++) begin : TestIf begin @@ -49,7 +49,7 @@ module t(); generate genvar the_third_genvar; - begin + begin : ic for (the_third_genvar = 0; the_third_genvar < 2; the_third_genvar++) begin : TestIf begin intf #(.PARAM(1)) my_intf [1:0] (); diff --git a/test_regress/t/t_var_dotted2.v b/test_regress/t/t_var_dotted2.v new file mode 100644 index 000000000..7138dbd86 --- /dev/null +++ b/test_regress/t/t_var_dotted2.v @@ -0,0 +1,131 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty 2020 by Wilson Snyder. + +`ifdef USE_INLINE + `define INLINE_MODULE /*verilator inline_module*/ +`else + `define INLINE_MODULE /*verilator public_module*/ +`endif + +module t (/*AUTOARG*/); + +`define DRAM1(bank) mem.mem_bank[bank].dccm.dccm_bank.ram_core +`define DRAM2(bank) mem.mem_bank2[bank].dccm.dccm_bank.ram_core +`define DRAM3(bank) mem.mem_bank3[bank].dccm.dccm_bank.ram_core +`define DRAM4(bank) mem.sub4.mem_bank4[bank].dccm.dccm_bank.ram_core + + initial begin + `DRAM1(0)[3] = 130; + `DRAM1(1)[3] = 131; + `DRAM2(0)[3] = 230; + `DRAM2(1)[3] = 231; + `DRAM3(0)[3] = 330; + `DRAM3(1)[3] = 331; + `DRAM4(0)[3] = 430; + `DRAM4(1)[3] = 431; + if (`DRAM1(0)[3] !== 130) $stop; + if (`DRAM1(1)[3] !== 131) $stop; + if (`DRAM2(0)[3] !== 230) $stop; + if (`DRAM2(1)[3] !== 231) $stop; + if (`DRAM3(0)[3] !== 330) $stop; + if (`DRAM3(1)[3] !== 331) $stop; + if (`DRAM4(0)[3] !== 430) $stop; + if (`DRAM4(1)[3] !== 431) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + + eh2_lsu_dccm_mem mem (/*AUTOINST*/); + +endmodule + +module eh2_lsu_dccm_mem +#( + DCCM_INDEX_DEPTH = 8192, + DCCM_NUM_BANKS = 2 + )( +); + `INLINE_MODULE + + // 8 Banks, 16KB each (2048 x 72) + for (genvar i=0; i 1); + +top_filename("t/t_var_dotted2.v"); + +compile( + v_flags2 => ['+define+NOUSE_INLINE',], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_var_dotted2_inl1.pl b/test_regress/t/t_var_dotted2_inl1.pl new file mode 100755 index 000000000..eba0adacc --- /dev/null +++ b/test_regress/t/t_var_dotted2_inl1.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 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. + +scenarios(simulator => 1); + +top_filename("t/t_var_dotted2.v"); + +compile( + v_flags2 => ['+define+USE_INLINE',], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_var_dotted_dup_bad.out b/test_regress/t/t_var_dotted_dup_bad.out new file mode 100644 index 000000000..bcda5f416 --- /dev/null +++ b/test_regress/t/t_var_dotted_dup_bad.out @@ -0,0 +1,7 @@ +%Error: t/t_var_dotted_dup_bad.v:13: Duplicate declaration of cell: 'dccm_bank' + eh2_ram dccm_bank (.*); + ^~~~~~~~~ + t/t_var_dotted_dup_bad.v:10: ... Location of original declaration + eh2_ram dccm_bank (.*); + ^~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_var_dotted_dup_bad.pl b/test_regress/t/t_var_dotted_dup_bad.pl new file mode 100755 index 000000000..e142ae153 --- /dev/null +++ b/test_regress/t/t_var_dotted_dup_bad.pl @@ -0,0 +1,18 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2005 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. + +scenarios(vlt => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_var_dotted_dup_bad.v b/test_regress/t/t_var_dotted_dup_bad.v new file mode 100644 index 000000000..e22f6e514 --- /dev/null +++ b/test_regress/t/t_var_dotted_dup_bad.v @@ -0,0 +1,20 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty 2020 by Wilson Snyder. + +module t (/*AUTOARG*/); + + generate + begin + eh2_ram dccm_bank (.*); + end + begin + eh2_ram dccm_bank (.*); // Error: duplicate + end + endgenerate + +endmodule + +module eh2_ram (); +endmodule diff --git a/test_regress/t/t_var_nonamebegin__log.out b/test_regress/t/t_var_nonamebegin__log.out index e9277860e..441195db4 100644 --- a/test_regress/t/t_var_nonamebegin__log.out +++ b/test_regress/t/t_var_nonamebegin__log.out @@ -1,9 +1,9 @@ ingen: {mod}.genblk1 top.t.genblk1 -d3a: {mod}.d3nameda top.t.d3nameda -b2: {mod} top.t -b3n: {mod}.b3named: top.t.b3named -b3: {mod} top.t -b4: {mod} top.t +d3a: {mod}.d3nameda top.t.unnamedblk1.d3nameda +b2: {mod} top.t.unnamedblk2 +b3n: {mod}.b3named: top.t.unnamedblk2.b3named +b3: {mod} top.t.unnamedblk2.unnamedblk3 +b4: {mod} top.t.unnamedblk2.unnamedblk3.unnamedblk4 t1 {mod}.tsk top.t -t2 {mod}.tsk top.t +t2 {mod}.tsk top.t.unnamedblk7 *-* All Finished *-* diff --git a/test_regress/t/t_var_notfound_bad.out b/test_regress/t/t_var_notfound_bad.out index cad5a6c9f..44bae4abf 100644 --- a/test_regress/t/t_var_notfound_bad.out +++ b/test_regress/t/t_var_notfound_bad.out @@ -13,7 +13,7 @@ : ... Suggested alternative: 'notfuncs' i = sub.nofuncs(); ^~~~~~~ - ... Known scopes under 'nofuncs': + ... Known scopes under 'nofuncs': sub %Error: t/t_var_notfound_bad.v:21: Can't find definition of task/function: 'notask' : ... Suggested alternative: 'nottask' notask(); From 6131bcdbb08a8d8fd07171860adb0980de0c5132 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 27 Feb 2020 07:12:50 -0500 Subject: [PATCH 18/50] Verilator_gantt: Fix CPU count in report. --- bin/verilator_gantt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/verilator_gantt b/bin/verilator_gantt index 252b98c9a..574d01567 100755 --- a/bin/verilator_gantt +++ b/bin/verilator_gantt @@ -123,13 +123,13 @@ sub report { } my $nthreads = scalar keys %Threads; - $Global{cpus}{cpu_time} = {}; + $Global{cpus} = {}; foreach my $thread (keys %Threads) { # Make potentially multiple characters per column foreach my $start (keys %{$Threads{$thread}}) { my $cpu = $Threads{$thread}{$start}{cpu}; my $elapsed = $Threads{$thread}{$start}{end} - $start; - $Global{cpus}{cpu_time}{$cpu} += $elapsed; + $Global{cpus}{$cpu}{cpu_time} += $elapsed; } } From c06a97a2214cfe096e55b4535f3f9f69eba20e6b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 27 Feb 2020 07:18:15 -0500 Subject: [PATCH 19/50] Remove OBJCACHE_HOSTS; dead code. --- Makefile.in | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Makefile.in b/Makefile.in index d79d0b2ff..6f7441743 100644 --- a/Makefile.in +++ b/Makefile.in @@ -208,12 +208,6 @@ EXAMPLES_FIRST = \ EXAMPLES = $(EXAMPLES_FIRST) $(filter-out $(EXAMPLES_FIRST), $(sort $(wildcard examples/*))) -ifeq ($(OBJCACHE_JOBS),) -ifneq ($(OBJCACHE_HOSTS),) -export OBJCACHE_JOBS := -j $(shell objcache --jobs "$(OBJCACHE_HOSTS)") -endif -endif - # See uninstall also - don't put wildcards in this variable, it might uninstall other stuff VL_INST_MAN_FILES = verilator.1 verilator_coverage.1 verilator_gantt.1 verilator_profcfunc.1 From 991d81cd0a0f92487d38beb6f946c0d12c71c272 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 27 Feb 2020 07:46:34 -0500 Subject: [PATCH 20/50] Recommend -Os. --- Changes | 2 ++ bin/verilator | 9 ++++----- examples/cmake_tracing_c/CMakeLists.txt | 2 +- examples/cmake_tracing_sc/CMakeLists.txt | 2 +- examples/make_protect_lib/Makefile | 2 +- examples/make_tracing_c/Makefile | 2 +- examples/make_tracing_c/Makefile_obj | 2 +- examples/make_tracing_sc/Makefile | 2 +- examples/make_tracing_sc/Makefile_obj | 2 +- include/verilated.mk.in | 2 +- test_regress/driver.pl | 4 ++-- 11 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Changes b/Changes index 986c8a9a8..e912ff79f 100644 --- a/Changes +++ b/Changes @@ -11,6 +11,8 @@ The contributors that suggested a given feature are shown in []. Thanks! *** Fix genblk naming with directly nested generate blocks, #2176. [Alexander Grobman] +**** Use gcc -Os in examples instead of -O2 for better average performance. + **** Fix undeclared VL_SHIFTR_WWQ, #2114. [Alex Solomatnikov] diff --git a/bin/verilator b/bin/verilator index 0a3beebf0..1ec4e722c 100755 --- a/bin/verilator +++ b/bin/verilator @@ -1964,19 +1964,18 @@ OPT, OPT_FAST, or OPT_SLOW lib/verilated.mk. Or, use the -CFLAGS and/or the compiler or linker. Or, just for one run, pass them on the command line to make: - make OPT_FAST="-O2 -fno-stack-protector" -f Vour.mk Vour__ALL.a + make OPT_FAST="-Os -fno-stack-protector" -f Vour.mk Vour__ALL.a OPT_FAST specifies optimizations for those programs that are part of the fast path, mostly code that is executed every cycle. OPT_SLOW specifies optimizations for slow-path files (plus tracing), which execute only rarely, yet take a long time to compile with optimization on. OPT specifies overall optimization and affects all compiles, including those -OPT_FAST and OPT_SLOW control. For best results, use OPT="-O2", and link +OPT_FAST and OPT_SLOW control. For best results, use OPT="-Os", and link with "-static". Nearly the same results can be had with much better compile times with OPT_FAST="-O1 -fstrict-aliasing". Higher optimization -such as "-O3" may help, but gcc compile times may be excessive under O3 on -even medium sized designs. Alternatively, some larger designs report -better performance using "-Os". +such as "-O2" or "-O3" may help, but gcc compile times may be excessive +under O3 on even medium sized designs. Unfortunately, using the optimizer with SystemC files can result in compiles taking several minutes. (The SystemC libraries have many little diff --git a/examples/cmake_tracing_c/CMakeLists.txt b/examples/cmake_tracing_c/CMakeLists.txt index ab5236b3c..d26932609 100644 --- a/examples/cmake_tracing_c/CMakeLists.txt +++ b/examples/cmake_tracing_c/CMakeLists.txt @@ -34,5 +34,5 @@ add_executable(example ../make_tracing_c/sim_main.cpp) # Add the Verilated circuit to the target verilate(example COVERAGE TRACE INCLUDE_DIRS "../make_tracing_c" - VERILATOR_ARGS -f ../make_tracing_c/input.vc -O2 -x-assign 0 + VERILATOR_ARGS -f ../make_tracing_c/input.vc -Os -x-assign 0 SOURCES ../make_tracing_c/top.v) diff --git a/examples/cmake_tracing_sc/CMakeLists.txt b/examples/cmake_tracing_sc/CMakeLists.txt index f2490eb6c..20a55c06e 100644 --- a/examples/cmake_tracing_sc/CMakeLists.txt +++ b/examples/cmake_tracing_sc/CMakeLists.txt @@ -41,7 +41,7 @@ add_executable(example ../make_tracing_sc/sc_main.cpp) # Add the Verilated circuit to the target verilate(example SYSTEMC COVERAGE TRACE INCLUDE_DIRS "../make_tracing_sc" - VERILATOR_ARGS -f ../make_tracing_sc/input.vc -O2 -x-assign 0 + VERILATOR_ARGS -f ../make_tracing_sc/input.vc -Os -x-assign 0 SOURCES ../make_tracing_sc/top.v) verilator_link_systemc(example) diff --git a/examples/make_protect_lib/Makefile b/examples/make_protect_lib/Makefile index 0f9f2e1a3..b2e33a283 100644 --- a/examples/make_protect_lib/Makefile +++ b/examples/make_protect_lib/Makefile @@ -34,7 +34,7 @@ VERILATOR_FLAGS = # Generate C++ VERILATOR_FLAGS += -cc # Optimize -VERILATOR_FLAGS += -O2 -x-assign 0 +VERILATOR_FLAGS += -Os -x-assign 0 # Warn abount lint issues; may not want this on less solid designs VERILATOR_FLAGS += -Wall # Make waveforms diff --git a/examples/make_tracing_c/Makefile b/examples/make_tracing_c/Makefile index f5a3b497e..a6acdc445 100644 --- a/examples/make_tracing_c/Makefile +++ b/examples/make_tracing_c/Makefile @@ -38,7 +38,7 @@ VERILATOR_FLAGS += -cc --exe # Generate makefile dependencies (not shown as complicates the Makefile) #VERILATOR_FLAGS += -MMD # Optimize -VERILATOR_FLAGS += -O2 -x-assign 0 +VERILATOR_FLAGS += -Os -x-assign 0 # Warn abount lint issues; may not want this on less solid designs VERILATOR_FLAGS += -Wall # Make waveforms diff --git a/examples/make_tracing_c/Makefile_obj b/examples/make_tracing_c/Makefile_obj index c3eb5291d..6d07eb427 100644 --- a/examples/make_tracing_c/Makefile_obj +++ b/examples/make_tracing_c/Makefile_obj @@ -38,7 +38,7 @@ endif # SystemC takes minutes to optimize, thus it is off by default. OPT_SLOW = # Fast path optimizations. Most time is spent in these classes. -OPT_FAST = -O2 -fstrict-aliasing +OPT_FAST = -Os -fstrict-aliasing #OPT_FAST = -O #OPT_FAST = diff --git a/examples/make_tracing_sc/Makefile b/examples/make_tracing_sc/Makefile index e70053c53..ded101604 100644 --- a/examples/make_tracing_sc/Makefile +++ b/examples/make_tracing_sc/Makefile @@ -38,7 +38,7 @@ VERILATOR_FLAGS += -sc --exe # Generate makefile dependencies (not shown as complicates the Makefile) #VERILATOR_FLAGS += -MMD # Optimize -VERILATOR_FLAGS += -O2 -x-assign 0 +VERILATOR_FLAGS += -Os -x-assign 0 # Warn abount lint issues; may not want this on less solid designs VERILATOR_FLAGS += -Wall # Make waveforms diff --git a/examples/make_tracing_sc/Makefile_obj b/examples/make_tracing_sc/Makefile_obj index 7c52ba627..03ffe389b 100644 --- a/examples/make_tracing_sc/Makefile_obj +++ b/examples/make_tracing_sc/Makefile_obj @@ -46,7 +46,7 @@ endif # SystemC takes minutes to optimize, thus it is off by default. OPT_SLOW = # Fast path optimizations. Most time is spent in these classes. -OPT_FAST = -O2 -fstrict-aliasing +OPT_FAST = -Os -fstrict-aliasing #OPT_FAST = -O #OPT_FAST = diff --git a/include/verilated.mk.in b/include/verilated.mk.in index e64de5e97..b00b58272 100644 --- a/include/verilated.mk.in +++ b/include/verilated.mk.in @@ -86,7 +86,7 @@ LDLIBS += $(VM_USER_LDLIBS) # SystemC takes minutes to optimize, thus it is off by default. #OPT_SLOW = # Fast path optimizations. Most time is spent in these classes. -#OPT_FAST = -O2 -fstrict-aliasing +#OPT_FAST = -Os -fstrict-aliasing #OPT_FAST = -O #OPT_FAST = diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 24640f9c0..6e10dd113 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -1048,7 +1048,7 @@ sub compile { "-DTEST_VERBOSE=\"".($self->{verbose} ? 1 : 0)."\"", "-DTEST_SYSTEMC=\"" .($self->sc ? 1 : 0). "\"", "-DCMAKE_PREFIX_PATH=\"".(($ENV{SYSTEMC_INCLUDE}||$ENV{SYSTEMC}||'')."/..\""), - "-DTEST_OPT_FAST=\"" . ($param{benchmark}?"-O2":"") . "\"", + "-DTEST_OPT_FAST=\"" . ($param{benchmark} ? "-Os" : "") . "\"", "-DTEST_VERILATION=\"" . $::Opt_Verilation . "\"", ]); return 1 if $self->errors || $self->skips || $self->unsupporteds; @@ -1066,7 +1066,7 @@ sub compile { "TEST_OBJ_DIR=$self->{obj_dir}", "CPPFLAGS_DRIVER=-D".uc($self->{name}), ($self->{verbose} ? "CPPFLAGS_DRIVER2=-DTEST_VERBOSE=1":""), - ($param{benchmark}?"OPT_FAST=-O2":""), + ($param{benchmark} ? "OPT_FAST=-Os" : ""), "$self->{VM_PREFIX}", # bypass default rule, as we don't need archive ($param{make_flags}||""), ]); From c6b755a12ee6b953808cacd449a6551d04e3aaf1 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 27 Feb 2020 19:35:49 -0500 Subject: [PATCH 21/50] Commentary --- README.adoc | 4 ++-- bin/verilator | 14 +++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/README.adoc b/README.adoc index 395302e64..3e2eb528b 100644 --- a/README.adoc +++ b/README.adoc @@ -25,7 +25,7 @@ endif::[] ^.^| *Welcome to Verilator, the fastest free Verilog HDL simulator.* +++
+++ • Accepts synthesizable Verilog or SystemVerilog +++
+++ • Performs lint code-quality checks -+++
+++ • Compiles into multithreaded {cpp}, SystemC, or (soon) {cpp}-under-Python ++++
+++ • Compiles into multithreaded {cpp}, or SystemC +++
+++ • Creates XML to front-end your own tools <.^|image:https://www.veripool.org/img/verilator_256_200_min.png[Logo,256,200] @@ -81,7 +81,7 @@ touch of {cpp} code, Verilator is the tool for you. Verilator does not simply convert Verilog HDL to {cpp} or SystemC. Rather than only translate, Verilator compiles your code into a much faster optimized and optionally thread-partitioned model, which is in turn wrapped -inside a {cpp}/SystemC/Python module. The results are a compiled Verilog +inside a {cpp}/SystemC/{cpp}-under-Python module. The results are a compiled Verilog model that executes even on a single-thread over 10x faster than standalone SystemC, and on a single thread is about 100 times faster than interpreted Verilog simulators such as http://iverilog.icarus.com[Icarus diff --git a/bin/verilator b/bin/verilator index 1ec4e722c..bb3dbb69b 100755 --- a/bin/verilator +++ b/bin/verilator @@ -1981,9 +1981,10 @@ Unfortunately, using the optimizer with SystemC files can result in compiles taking several minutes. (The SystemC libraries have many little inlined functions that drive the compiler nuts.) -For best results, use GCC 3.3 or newer. GCC 3.2 and earlier have -optimization bugs around pointer aliasing detection, which can result in 2x -performance losses. +For best results, use the latest clang compiler (about 10% faster than +GCC). Note the now fairly old GCC 3.2 and earlier have optimization bugs +around pointer aliasing detection, which can result in 2x performance +losses. If you will be running many simulations on a single compile, investigate feedback driven compilation. With GCC, using -fprofile-arcs, then @@ -1994,6 +1995,9 @@ especially if you link in DPI code. To enable LTO on GCC, pass "-flto" in both compilation and link. Note LTO may cause excessive compile times on large designs. +Using profile driven compiler optimization, with feedback from a real +design, can yield up to30% improvements. + If you are using your own makefiles, you may want to compile the Verilated code with -DVL_INLINE_OPT=inline. This will inline functions, however this requires that all cpp files be compiled in a single compiler run. @@ -2004,7 +2008,7 @@ either oprofile or gprof to see where in the C++ code the time is spent. Run the gprof output through verilator_profcfunc and it will tell you what Verilog line numbers on which most of the time is being spent. -When done, please let the author know the results. I like to keep tabs on +When done, please let the author know the results. We like to keep tabs on how Verilator compares, and may be able to suggest additional improvements. @@ -2079,7 +2083,7 @@ After running Make, the C++ compiler may produce the following: A generic Linux/OS variable specifying what directories have shared object (.so) files. This path should include SystemC and any other shared objects -needed at simultion runtime. +needed at simulation runtime. =item OBJCACHE From 4878fe3a1fd3039cf0454e0ca9341d1383e40952 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 28 Feb 2020 19:15:08 -0500 Subject: [PATCH 22/50] Add split_var metacomment to assist UNOPTFLAT fixes, #2066. --- Changes | 2 + bin/verilator | 55 + src/Makefile_obj.in | 1 + src/V3Ast.h | 5 +- src/V3AstNodes.h | 5 +- src/V3Error.h | 3 +- src/V3LinkDot.cpp | 6 + src/V3LinkParse.cpp | 10 + src/V3Order.cpp | 41 +- src/V3SplitVar.cpp | 1310 +++++++++++++ src/V3SplitVar.h | 39 + src/Verilator.cpp | 7 +- src/verilog.l | 1 + src/verilog.y | 2 + test_regress/t/t_split_var_0.pl | 26 + test_regress/t/t_split_var_0.v | 431 +++++ test_regress/t/t_split_var_1_bad.out | 65 + test_regress/t/t_split_var_1_bad.pl | 19 + test_regress/t/t_split_var_1_bad.v | 84 + test_regress/t/t_split_var_2_trace.out | 1930 +++++++++++++++++++ test_regress/t/t_split_var_2_trace.pl | 29 + test_regress/t/t_unoptflat_simple_2_bad.out | 9 +- 22 files changed, 4058 insertions(+), 22 deletions(-) create mode 100644 src/V3SplitVar.cpp create mode 100644 src/V3SplitVar.h create mode 100755 test_regress/t/t_split_var_0.pl create mode 100644 test_regress/t/t_split_var_0.v create mode 100644 test_regress/t/t_split_var_1_bad.out create mode 100755 test_regress/t/t_split_var_1_bad.pl create mode 100644 test_regress/t/t_split_var_1_bad.v create mode 100644 test_regress/t/t_split_var_2_trace.out create mode 100755 test_regress/t/t_split_var_2_trace.pl diff --git a/Changes b/Changes index e912ff79f..558f81a11 100644 --- a/Changes +++ b/Changes @@ -5,6 +5,8 @@ The contributors that suggested a given feature are shown in []. Thanks! * Verilator 4.029 devel +** Add split_var metacomment to assist UNOPTFLAT fixes, #2066. [Yutetsu TAKATSUKASA] + *** Add +verilator+noassert flag to disable assertion checking. [Tobias Wölfel] *** Add check for assertOn for asserts, #2162. [Tobias Wölfel] diff --git a/bin/verilator b/bin/verilator index bb3dbb69b..a50add371 100755 --- a/bin/verilator +++ b/bin/verilator @@ -3420,6 +3420,33 @@ behavior. See the test_regress/t/t_dpi_display.v file for an example. Same as C in configuration files, see L for more information. +=item /*verilator split_var*/ + +Attached to a variable or a net declaration to break the variable into +multiple pieces typically to resolve UNOPTFLAT performance issues. +Typically the variables to attach this to are recommeded by Verilator +itself, see UNOPTFLAT below. + +For example, Verilator will internally convert a variable with the +metacomment such as: + + logic [7:0] x [0:1] /*verilator split_var*/; + +To: + + logic [7:0] x__BRA__0__KET__ /*verilator split_var*/; + logic [7:0] x__BRA__1__KET__ /*verilator split_var*/; + +Note that the generated packed variables retain the split_var metacomment +because they may be split into further smaller pieces accorting to the +access patterns. + +This only supports unpacked arrays, packed arrays, and packed structs of +integer types (reg, logic, bit, byte, int...); otherwise if a split was +requested but cannot occur a SPLITVAR warning is issued. Splitting large +arrays may slow donw the Verilation speed, so use this only on variables +that require it. + =item /*verilator tag */ Attached after a variable or structure member to indicate opaque (to @@ -4383,6 +4410,29 @@ Ignoring this warning may make Verilator simulations differ from other simulators, if the increased precision of real affects your model or DPI calls. +=item SPLITVAR + +Warns that a variable with a C metacomment was not split. +Some possible reasons for this are: + +* The datatype of the variable is not supported for splitting. (e.g. is a +real). + +* The access pattern of the variable can not be determined +statically. (e.g. is accessed as a memory). + +* The index of the array exceeds the array size. + +* The variable is accessed from outside using dotted reference. +(e.g. top.instance0.variable0 = 1). + +* The variable is not declared in a module, but in a package or an +interface. + +* The variable is a parameter, localparam, genvar, or queue. + +* The variable is tirstate or bidirectional. (e.g. inout or ref). + =item STMTDLY Warns that you have a statement with a delayed time in front of it, for @@ -4514,6 +4564,11 @@ being generated from an always statement that consumed high bits of the same bus processed by another series of always blocks. The fix is the same; split it into two separate signals generated from each block. +Another way to resolve this warning is to add a C metacomment +described above. This will cause the variable to be split internally, +potentially resolving the conflict. If you run with --report-unoptflat +Verilator will suggest possible candidates for C. + The UNOPTFLAT warning may also be due to clock enables, identified from the reported path going through a clock gating cell. To fix these, use the clock_enable meta comment described above. diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index f847288bb..4f677b61c 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -233,6 +233,7 @@ RAW_OBJS = \ V3Slice.o \ V3Split.o \ V3SplitAs.o \ + V3SplitVar.o \ V3Stats.o \ V3StatsReport.o \ V3String.o \ diff --git a/src/V3Ast.h b/src/V3Ast.h index 2f8c2857b..356df43d3 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -326,7 +326,8 @@ public: VAR_SC_BV, // V3LinkParse moves to AstVar::attrScBv VAR_SFORMAT, // V3LinkParse moves to AstVar::attrSFormat VAR_CLOCKER, // V3LinkParse moves to AstVar::attrClocker - VAR_NO_CLOCKER // V3LinkParse moves to AstVar::attrClocker + VAR_NO_CLOCKER, // V3LinkParse moves to AstVar::attrClocker + VAR_SPLIT_VAR // V3LinkParse moves to AstVar::attrSplitVar }; enum en m_e; const char* ascii() const { @@ -342,7 +343,7 @@ public: "VAR_BASE", "VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC", "VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD", "VAR_PUBLIC_FLAT_RW", "VAR_ISOLATE_ASSIGNMENTS", "VAR_SC_BV", "VAR_SFORMAT", "VAR_CLOCKER", - "VAR_NO_CLOCKER" + "VAR_NO_CLOCKER", "VAR_SPLIT_VAR" }; return names[m_e]; } diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 02d2a316c..448589c9b 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -1456,6 +1456,7 @@ private: bool m_attrScBv:1; // User force bit vector attribute bool m_attrIsolateAssign:1;// User isolate_assignments attribute bool m_attrSFormat:1;// User sformat attribute + bool m_attrSplitVar:1; // declared with split_var metacomment bool m_fileDescr:1; // File descriptor bool m_isConst:1; // Table contains constant data bool m_isStatic:1; // Static variable @@ -1478,7 +1479,7 @@ private: m_sigUserRdPublic = false; m_sigUserRWPublic = false; m_funcLocal = false; m_funcReturn = false; m_attrClockEn = false; m_attrScBv = false; - m_attrIsolateAssign = false; m_attrSFormat = false; + m_attrIsolateAssign = false; m_attrSFormat = false; m_attrSplitVar = false; m_fileDescr = false; m_isConst = false; m_isStatic = false; m_isPulldown = false; m_isPullup = false; m_isIfaceParent = false; m_isDpiOpenArray = false; @@ -1582,6 +1583,7 @@ public: void attrScBv(bool flag) { m_attrScBv = flag; } void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; } void attrSFormat(bool flag) { m_attrSFormat = flag; } + void attrSplitVar(bool flag) { m_attrSplitVar = flag; } void usedClock(bool flag) { m_usedClock = flag; } void usedParam(bool flag) { m_usedParam = flag; } void usedLoopIdx(bool flag) { m_usedLoopIdx = flag; } @@ -1658,6 +1660,7 @@ public: bool attrFileDescr() const { return m_fileDescr; } bool attrScClocked() const { return m_scClocked; } bool attrSFormat() const { return m_attrSFormat; } + bool attrSplitVar() const { return m_attrSplitVar; } bool attrIsolateAssign() const { return m_attrIsolateAssign; } VVarAttrClocker attrClocker() const { return m_attrClocker; } virtual string verilogKwd() const; diff --git a/src/V3Error.h b/src/V3Error.h index b6adb3681..79e8c49ae 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -102,6 +102,7 @@ public: REDEFMACRO, // Redefining existing define macro SELRANGE, // Selection index out of range SHORTREAL, // Shortreal not supported + SPLITVAR, // Cannot split the variable STMTDLY, // Delayed statement SYMRSVDWORD, // Symbol is Reserved Word SYNCASYNCNET, // Mixed sync + async reset @@ -153,7 +154,7 @@ public: "MULTIDRIVEN", "MULTITOP", "PINMISSING", "PINNOCONNECT", "PINCONNECTEMPTY", "PROCASSWIRE", "REALCVT", "REDEFMACRO", - "SELRANGE", "SHORTREAL", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET", + "SELRANGE", "SHORTREAL", "SPLITVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET", "TICKCOUNT", "UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS", "UNPACKED", "UNSIGNED", "UNUSED", diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 557e2769c..ccc9aa8d3 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2057,6 +2057,12 @@ private: AstVarXRef* refp = new AstVarXRef(nodep->fileline(), nodep->name(), m_ds.m_dotText, false); // lvalue'ness computed later refp->varp(varp); + if (varp->attrSplitVar()) { + refp->v3warn(SPLITVAR, varp->prettyNameQ() + << " has split_var metacomment but will not be split because" + << " it is accessed from another module via a dot."); + varp->attrSplitVar(false); + } m_ds.m_dotText = ""; if (m_ds.m_unresolved && m_ds.m_unlinkedScope) { string dotted = refp->dotted(); diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index cb3d2d26f..55c79ddd0 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -305,6 +305,16 @@ private: m_varp->attrSFormat(true); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } + else if (nodep->attrType() == AstAttrType::VAR_SPLIT_VAR) { + UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable"); + if (!VN_IS(m_modp, Module)) { + m_varp->v3warn(SPLITVAR, m_varp->prettyNameQ() << " has split_var metacomment, " + "but will not be split because it is not declared in a module."); + } else { + m_varp->attrSplitVar(true); + } + VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + } else if (nodep->attrType() == AstAttrType::VAR_SC_BV) { UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable"); m_varp->attrScBv(true); diff --git a/src/V3Order.cpp b/src/V3Order.cpp index 703b93b51..1644f14c8 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -91,6 +91,7 @@ #include "V3Partition.h" #include "V3PartitionGraph.h" #include "V3SenTree.h" +#include "V3SplitVar.h" #include "V3Stats.h" #include "V3Order.h" @@ -892,32 +893,48 @@ private: m_graph.userClearVertices(); // May be very large vector, so only report the "most important" // elements. Up to 10 of the widest - std::cerr< canSplitList; int lim = m_unoptflatVars.size() < 10 ? m_unoptflatVars.size() : 10; for (int i = 0; i < lim; i++) { OrderVarStdVertex* vsvertexp = m_unoptflatVars[i]; AstVar* varp = vsvertexp->varScp()->varp(); - std::cerr<fileline()<<" "<prettyName()<width()<<", fanout " - <fanout()<fileline() << " " + << varp->prettyName() << std::dec << ", width " << varp->width() + << ", fanout " << vsvertexp->fanout(); + if (canSplit) { + std::cerr <<", can split_var"; + canSplitList.insert(varp); + } + std::cerr << std::endl; } // Up to 10 of the most fanned out - std::cerr<varScp()->varp(); - std::cerr<fileline()<<" "<prettyName() - <<", width "<width() - <<", fanout "<fanout()<fileline() << " " + << varp->prettyName() << ", width " << std::dec << varp->width() + << ", fanout " << vsvertexp->fanout(); + if (canSplit) { + std::cerr << ", can split_var"; + canSplitList.insert(varp); + } + std::cerr< // sort +#include +#include +#include +#include VL_INCLUDE_UNORDERED_MAP +#include VL_INCLUDE_UNORDERED_SET + +struct SplitVarImpl { + static AstNodeAssign* newAssign(FileLine* fileline, AstNode* lhsp, AstNode* rhsp, + const AstVar* varp) { + if (varp->isFuncLocal() || varp->isFuncReturn()) { + return new AstAssign(fileline, lhsp, rhsp); + } else { + return new AstAssignW(fileline, lhsp, rhsp); + } + } + + static const char* const notSplitMsg; + + // These check functions return valid pointer to the reason text if a variable cannot be split. + + // Check if a var type can be split + static const char* cannotSplitVarTypeReason(AstVarType type) { + // Only SplitUnpackedVarVisitor can split WREAL. SplitPackedVarVisitor cannot. + const bool ok + = type == type.VAR || type == type.WIRE || type == type.PORT || type == type.WREAL; + if (ok) return NULL; + return "it is not one of variable, net, port, nor wreal"; + } + + static const char* cannotSplitVarDirectionReason(VDirection dir) { + if (dir == VDirection::REF) return "it is a ref argument"; + if (dir == VDirection::INOUT) return "it is an inout port"; + return NULL; + } + + static const char* cannotSplitConnectedPortReason(AstPin* pinp) { + AstVar* varp = pinp->modVarp(); + if (!varp) return "it is not connected"; + if (const char* reason = cannotSplitVarDirectionReason(varp->direction())) return reason; + return NULL; + } + + static const char* cannotSplitTaskReason(const AstNodeFTask* taskp) { + if (taskp->prototype()) return "the task is prototype declaration"; + if (taskp->dpiImport()) return "the task is imported from DPI-C"; + if (taskp->dpiOpenChild()) return "the task takes DPI-C open array"; + return NULL; + } + + static const char* cannotSplitVarCommonReason(const AstVar* varp) { + if (AstNodeFTask* taskp = VN_CAST(varp->backp(), NodeFTask)) { + if (const char* reason = cannotSplitTaskReason(taskp)) return reason; + } + if (const char* reason = cannotSplitVarTypeReason(varp->varType())) return reason; + if (const char* reason = cannotSplitVarDirectionReason(varp->direction())) return reason; + if (varp->isSigPublic()) return "it is public"; + if (varp->isInoutish()) return "it is bidirectional"; + if (varp->isUsedLoopIdx()) return "it is used as a loop variable"; + if (varp->isGenVar()) return "it is genvar"; + if (varp->isParam()) return "it is parameter"; + return NULL; + } + + static const char* cannotSplitPackedVarReason(const AstVar* varp); + + template + static void insertBeginCore(T_ALWAYSLIKE* ap, AstNodeStmt* stmtp, AstNodeModule* modp) { + if (ap->isJustOneBodyStmt() && ap->bodysp() == stmtp) { + stmtp->unlinkFrBack(); + // Insert begin-end because temp value may be inserted to this block later. + const std::string name = "__VsplitVarBlk" + cvtToStr(modp->varNumGetInc()); + ap->addStmtp(new AstBegin(ap->fileline(), name, stmtp)); + } + } + + static void insertBeginCore(AstInitial* initp, AstNodeStmt* stmtp, AstNodeModule* modp) { + if (initp->isJustOneBodyStmt() && initp->bodysp() == stmtp) { + stmtp->unlinkFrBack(); + // Insert begin-end because temp value may be inserted to this block later. + const std::string name = "__VsplitVarBlk" + cvtToStr(modp->varNumGetInc()); + initp->replaceWith( + new AstInitial(initp->fileline(), new AstBegin(initp->fileline(), name, stmtp))); + VL_DO_DANGLING(initp->deleteTree(), initp); + } + } + + static void insertBeginIfNecessary(AstNodeStmt* stmtp, AstNodeModule* modp) { + AstNode* backp = stmtp->backp(); + if (AstAlways* ap = VN_CAST(backp, Always)) { + insertBeginCore(ap, stmtp, modp); + } else if (AstAlwaysPublic* ap = VN_CAST(backp, AlwaysPublic)) { + insertBeginCore(ap, stmtp, modp); + } else if (AstInitial* ap = VN_CAST(backp, Initial)) { + insertBeginCore(ap, stmtp, modp); + } + } + +}; // SplitVarImpl + +const char* const SplitVarImpl::notSplitMsg + = " has split_var metacomment but will not be split because "; + +//###################################################################### +// Split Unpacked Variables +// Replacement policy: +// AstArraySel -> Just replace with the AstVarRef for the split variable +// AstVarRef -> Create a temporary variable and refer the variable +// AstSliceSel -> Create a temporary variable and refer the variable + +class UnpackRef { + // m_nodep is called in this context (AstNodeStmt, AstCell, AstNodeFTask, or AstAlways) + AstNode* m_contextp; + AstNode* m_nodep; // ArraySel, SliceSel, ArrayVarRef (entire value) + int m_index; // for ArraySel + int m_msb; // for SliceSel + int m_lsb; // for SliceSel + bool m_lvalue; + bool m_ftask; // true if the reference is in function/task. false if in module. +public: + UnpackRef(AstNode* stmtp, AstVarRef* nodep, bool ftask) + : m_contextp(stmtp) + , m_nodep(nodep) + , m_index(-1) + , m_msb(0) + , m_lsb(1) + , m_lvalue(nodep->lvalue()) + , m_ftask(ftask) {} + UnpackRef(AstNode* stmtp, AstArraySel* nodep, int idx, bool lvalue, bool ftask) + : m_contextp(stmtp) + , m_nodep(nodep) + , m_index(idx) + , m_msb(0) + , m_lsb(1) + , m_lvalue(lvalue) + , m_ftask(ftask) {} + UnpackRef(AstNode* stmtp, AstSliceSel* nodep, int msb, int lsb, bool lvalue, bool ftask) + : m_contextp(stmtp) + , m_nodep(nodep) + , m_index(msb == lsb ? msb : -1) // Equivalent to ArraySel + , m_msb(msb) + , m_lsb(lsb) + , m_lvalue(lvalue) + , m_ftask(ftask) {} + AstNode* nodep() const { return m_nodep; } + bool isSingleRef() const { + return VN_IS(m_nodep, ArraySel) || (m_msb == m_lsb && m_lsb == m_index); + } + int index() const { + UASSERT_OBJ(isSingleRef(), m_nodep, "not array sel"); + return m_index; + } + AstNode* context() const { return m_contextp; } + std::pair range() const { + UASSERT_OBJ(VN_IS(m_nodep, SliceSel), m_nodep, "not slice sel"); + return std::make_pair(m_msb, m_lsb); + } + bool lvalue() const { return m_lvalue; } + bool ftask() const { return m_ftask; } +}; + +class UnpackRefMap { +public: + struct Hash { + size_t operator()(const UnpackRef& r) const { return reinterpret_cast(r.nodep()); } + }; + struct Compare { + bool operator()(const UnpackRef& a, const UnpackRef& b) const { + return a.nodep() == b.nodep(); + } + }; + typedef std::map > MapType; + typedef MapType::iterator MapIt; + typedef MapType::value_type::second_type::iterator SetIt; + +private: + MapType m_map; + bool addCore(AstVarRef* refp, const UnpackRef& ref) { + AstVar* varp = refp->varp(); + UASSERT_OBJ(varp->attrSplitVar(), varp, " no split_var metacomment"); + MapIt it = m_map.find(varp); + if (it == m_map.end()) return false; // Not registered + const bool ok = m_map[varp].insert(ref).second; + return ok; + } + +public: + // Register a variable to split + void registerVar(AstVar* varp) { + const bool inserted + = m_map.insert(std::make_pair(varp, MapType::value_type::second_type())).second; + UASSERT_OBJ(inserted, varp, "already registered"); + } + // Register the location where a variable is used. + bool tryAdd(AstNode* context, AstVarRef* refp, AstArraySel* selp, int idx, bool ftask) { + return addCore(refp, UnpackRef(context, selp, idx, refp->lvalue(), ftask)); + } + bool tryAdd(AstNode* context, AstVarRef* refp, AstSliceSel* selp, int msb, int lsb, + bool ftask) { + return addCore(refp, UnpackRef(context, selp, msb, lsb, refp->lvalue(), ftask)); + } + bool tryAdd(AstNode* context, AstVarRef* refp, bool ftask) { + return addCore(refp, UnpackRef(context, refp, ftask)); + } + + // Remove a variable from the list to split + void remove(AstVar* varp) { + UASSERT_OBJ(varp->attrSplitVar(), varp, " no split_var metacomment"); + m_map.erase(varp); + varp->attrSplitVar(!SplitVarImpl::cannotSplitPackedVarReason(varp)); + } + bool empty() const { return m_map.empty(); } + void swap(UnpackRefMap& other) { other.m_map.swap(m_map); } + + MapIt begin() { return m_map.begin(); } + MapIt end() { return m_map.end(); } +}; + +// Compare AstNode* to get deterministic ordering when showing messages. +struct AstNodeComparator { + bool operator()(const AstNode* ap, const AstNode* bp) const { + const FileLine* afp = ap->fileline(); + const FileLine* bfp = bp->fileline(); + if (afp->firstLineno() != bfp->firstLineno()) + return afp->firstLineno() < bfp->firstLineno(); + if (afp->firstColumn() != bfp->firstColumn()) + return afp->firstColumn() < bfp->firstColumn(); + // Don't comapre its filename because it is expensive. + // Line number and column is practically enough. + // The comparison of raw pointer here is just in case. + // The comparison of this pointer may differ on different run, + // but this is just warning message order. (mostly for CI) + // Verilated result is same anyway. + return ap < bp; + } +}; + +// Found nodes for SplitPackedVarVisitor +struct RefsInModule { + std::set m_vars; + std::set m_refs; + std::set m_sels; + +public: + void add(AstVar* nodep) { m_vars.insert(nodep); } + void add(AstVarRef* nodep) { m_refs.insert(nodep); } + void add(AstSel* nodep) { m_sels.insert(nodep); } + void remove(AstNode* nodep) { + struct Visitor : public AstNVisitor { + RefsInModule& m_parent; + virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); } + virtual void visit(AstVar* nodep) VL_OVERRIDE { m_parent.m_vars.erase(nodep); } + virtual void visit(AstVarRef* nodep) VL_OVERRIDE { m_parent.m_refs.erase(nodep); } + virtual void visit(AstSel* nodep) VL_OVERRIDE { + m_parent.m_sels.erase(nodep); + iterateChildren(nodep); + } + explicit Visitor(RefsInModule& p) + : m_parent(p) {} + } v(*this); + v.iterate(nodep); + } + void visit(AstNVisitor* visitor) { + for (std::set::iterator it = m_vars.begin(), it_end = m_vars.end(); it != it_end; + ++it) { + visitor->iterate(*it); + } + for (std::set::iterator it = m_sels.begin(), it_end = m_sels.end(); it != it_end; + ++it) { + // If m_refs includes VarRef from ArraySel, remove it + // because the VarRef would not be visited in SplitPackedVarVisitor::visit(AstSel*). + if (AstVarRef* refp = VN_CAST((*it)->fromp(), VarRef)) { + m_refs.erase(refp); + } else if (AstVarRef* refp = VN_CAST((*it)->lsbp(), VarRef)) { + m_refs.erase(refp); + } else if (AstVarRef* refp = VN_CAST((*it)->widthp(), VarRef)) { + m_refs.erase(refp); + } + UASSERT_OBJ(reinterpret_cast((*it)->op1p()) != 1, *it, "stale"); + visitor->iterate(*it); + } + for (std::set::iterator it = m_refs.begin(), it_end = m_refs.end(); + it != it_end; ++it) { + UASSERT_OBJ(reinterpret_cast((*it)->op1p()) != 1, *it, "stale"); + visitor->iterate(*it); + } + } +}; + +typedef std::map SplitVarRefsMap; + +class SplitUnpackedVarVisitor : public AstNVisitor, public SplitVarImpl { + typedef std::set VarSet; + VarSet m_foundTargetVar; + UnpackRefMap m_refs; + AstNodeModule* m_modp; + // AstNodeStmt, AstCell, AstNodeFTaskRef, or AstAlways(Public) for sensitivity + AstNode* m_contextp; + AstNodeFTask* m_inFTask; + size_t m_numSplit; + // List for SplitPackedVarVisitor + SplitVarRefsMap m_refsForPackedSplit; + + static AstVarRef* isTargetVref(AstNode* nodep) { + if (AstVarRef* refp = VN_CAST(nodep, VarRef)) { + if (refp->varp()->attrSplitVar()) return refp; + } + return NULL; + } + static int outerMostSizeOfUnpackedArray(AstVar* nodep) { + AstUnpackArrayDType* dtypep = VN_CAST(nodep->dtypep()->skipRefp(), UnpackArrayDType); + UASSERT_OBJ(dtypep, nodep, "Must be unapcked array"); + return dtypep->msb() - dtypep->lsb() + 1; + } + + void setContextAndIterateChildren(AstNode* nodep) { + AstNode* origContextp = m_contextp; + { + m_contextp = nodep; + iterateChildren(nodep); + } + m_contextp = origContextp; + } + void setContextAndIterate(AstNode* contextp, AstNode* nodep) { + AstNode* origContextp = m_contextp; + { + m_contextp = contextp; + iterate(nodep); + } + m_contextp = origContextp; + } + void pushDeletep(AstNode* nodep) { // overriding AstNVisitor::pusDeletep() + UASSERT_OBJ(m_modp, nodep, "Must not NULL"); + m_refsForPackedSplit[m_modp].remove(nodep); + AstNVisitor::pushDeletep(nodep); + } + AstVar* newVar(FileLine* fl, AstVarType type, const std::string& name, AstNodeDType* dtp) { + AstVar* varp = new AstVar(fl, type, name, dtp); + UASSERT_OBJ(m_modp, varp, "Must not NULL"); + m_refsForPackedSplit[m_modp].add(varp); + return varp; + } + AstVarRef* newVarRef(FileLine* fl, AstVar* varp, bool lvalue) { + AstVarRef* refp = new AstVarRef(fl, varp, lvalue); + UASSERT_OBJ(m_modp, refp, "Must not NULL"); + m_refsForPackedSplit[m_modp].add(refp); + return refp; + } + + virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); } + virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { + UINFO(4, "Start checking " << nodep->prettyNameQ() << "\n"); + if (!VN_IS(nodep, Module)) { + UINFO(4, "Skip " << nodep->prettyNameQ() << "\n"); + return; + } + UASSERT_OBJ(!m_modp, m_modp, "Nested module declration"); + UASSERT_OBJ(m_refs.empty(), nodep, "The last module didn't finish split()"); + m_modp = nodep; + iterateChildren(nodep); + split(); + m_modp = NULL; + } + virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE { setContextAndIterateChildren(nodep); } + virtual void visit(AstCell* nodep) VL_OVERRIDE { setContextAndIterateChildren(nodep); } + virtual void visit(AstAlways* nodep) VL_OVERRIDE { + if (nodep->sensesp()) { // When visiting sensitivity list, always is the context + setContextAndIterate(nodep, nodep->sensesp()); + } + if (AstNode* bodysp = nodep->bodysp()) iterate(bodysp); + }; + virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE { + if (nodep->sensesp()) { // When visiting sensitivity list, always is the context + setContextAndIterate(nodep, nodep->sensesp()); + } + if (AstNode* bodysp = nodep->bodysp()) iterate(bodysp); + } + virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE { + AstNode* origContextp = m_contextp; + { + m_contextp = nodep; + AstNodeFTask* ftaskp = nodep->taskp(); + // Iterate arguments of a function/task. + for (AstNode *argp = nodep->pinsp(), *paramp = ftaskp->stmtsp(); argp; + argp = argp->nextp(), paramp = paramp ? paramp->nextp() : NULL) { + const char* reason = NULL; + AstVar* vparamp = NULL; + while (paramp) { + vparamp = VN_CAST(paramp, Var); + if (vparamp && vparamp->isIO()) { + reason = cannotSplitVarDirectionReason(vparamp->direction()); + break; + } + paramp = paramp->nextp(); + vparamp = NULL; + } + if (!reason && !vparamp) { + reason = "the number of argument to the task/function mismatches"; + } + m_foundTargetVar.clear(); + iterate(argp); + if (reason) { + for (VarSet::iterator it = m_foundTargetVar.begin(), + it_end = m_foundTargetVar.end(); + it != it_end; ++it) { + argp->v3warn(SPLITVAR, (*it)->prettyNameQ() + << notSplitMsg << reason << ".\n"); + m_refs.remove(*it); + } + } + m_foundTargetVar.clear(); + } + } + m_contextp = origContextp; + } + virtual void visit(AstPin* nodep) VL_OVERRIDE { + UINFO(5, nodep->modVarp()->prettyNameQ() << " pin \n"); + AstNode* exprp = nodep->exprp(); + if (!exprp) return; // Not connected pin + m_foundTargetVar.clear(); + iterate(exprp); + if (const char* reason = cannotSplitConnectedPortReason(nodep)) { + for (VarSet::iterator it = m_foundTargetVar.begin(), it_end = m_foundTargetVar.end(); + it != it_end; ++it) { + nodep->v3warn(SPLITVAR, (*it)->prettyNameQ() << notSplitMsg << reason << ".\n"); + m_refs.remove(*it); + } + m_foundTargetVar.clear(); + } + } + virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { + UASSERT_OBJ(!m_inFTask, nodep, "Nested func/task"); + if (!cannotSplitTaskReason(nodep)) { + m_inFTask = nodep; + iterateChildren(nodep); + m_inFTask = NULL; + } + } + virtual void visit(AstVar* nodep) VL_OVERRIDE { + if (!nodep->attrSplitVar()) return; // Nothing to do + if (!cannotSplitReason(nodep)) { + m_refs.registerVar(nodep); + UINFO(4, nodep->name() << " is added to candidate list.\n"); + } + m_refsForPackedSplit[m_modp].add(nodep); + } + virtual void visit(AstVarRef* nodep) VL_OVERRIDE { + if (!nodep->varp()->attrSplitVar()) return; // Nothing to do + if (m_refs.tryAdd(m_contextp, nodep, m_inFTask)) { + m_foundTargetVar.insert(nodep->varp()); + } + m_refsForPackedSplit[m_modp].add(nodep); + } + virtual void visit(AstSel* nodep) VL_OVERRIDE { + if (VN_IS(nodep->fromp(), VarRef)) m_refsForPackedSplit[m_modp].add(nodep); + iterateChildren(nodep); + } + virtual void visit(AstArraySel* nodep) VL_OVERRIDE { + if (AstVarRef* refp = isTargetVref(nodep->fromp())) { + AstConst* indexp = VN_CAST(nodep->bitp(), Const); + if (indexp) { // OK + UINFO(4, "add " << nodep << " for " << refp->varp()->prettyName() << "\n"); + if (indexp->toSInt() < outerMostSizeOfUnpackedArray(refp->varp())) { + m_refs.tryAdd(m_contextp, refp, nodep, indexp->toSInt(), m_inFTask); + } else { + nodep->bitp()->v3warn(SPLITVAR, refp->prettyNameQ() + << notSplitMsg + << "index is out of range.\n"); + m_refs.remove(refp->varp()); + } + } else { + nodep->bitp()->v3warn(SPLITVAR, refp->prettyNameQ() + << notSplitMsg + << "index cannot be determined statically.\n"); + m_refs.remove(refp->varp()); + iterate(nodep->bitp()); + } + } else { + iterateChildren(nodep); + } + } + virtual void visit(AstSliceSel* nodep) VL_OVERRIDE { + if (AstVarRef* refp = isTargetVref(nodep->fromp())) { + AstUnpackArrayDType* dtypep + = VN_CAST(refp->varp()->dtypep()->skipRefp(), UnpackArrayDType); + if (dtypep->lsb() <= nodep->declRange().lo() + && nodep->declRange().hi() <= dtypep->msb()) { // Range is ok + UINFO(4, "add " << nodep << " for " << refp->varp()->prettyName() << "\n"); + m_refs.tryAdd(m_contextp, refp, nodep, nodep->declRange().hi(), + nodep->declRange().lo(), m_inFTask); + } else { + nodep->v3warn(SPLITVAR, refp->prettyNameQ() + << notSplitMsg << "index if out of range.\n"); + m_refs.remove(refp->varp()); + } + } else { + iterateChildren(nodep); + } + } + static AstNode* toInsertPoint(AstNode* insertp) { + if (AstNodeStmt* stmtp = VN_CAST(insertp, NodeStmt)) { + if (!stmtp->isStatement()) insertp = stmtp->backp(); + } + return insertp; + } + AstVarRef* createTempVar(AstNode* context, AstNode* nodep, AstUnpackArrayDType* dtypep, + const std::string& name_prefix, std::vector& vars, + int start_idx, bool lvalue, bool ftask) { + const std::string name + = "__VsplitVar" + cvtToStr(m_modp->varNumGetInc()) + "__" + name_prefix; + AstNodeAssign* assignp = VN_CAST(context, NodeAssign); + if (assignp) { + // "always_comb a = b;" to "always_comb begin a = b; end" so that local + // variable can be added. + insertBeginIfNecessary(assignp, m_modp); + } + AstVar* varp = newVar(nodep->fileline(), AstVarType::VAR, name, dtypep); + // Variable will be registered in the caller side. + UINFO(3, varp->prettyNameQ() + << " is created lsb:" << dtypep->lsb() << " msb:" << dtypep->msb() << "\n"); + // Use AstAssign if true, otherwise AstAssignW + const bool use_simple_assign + = (context && VN_IS(context, NodeFTaskRef)) || (assignp && VN_IS(assignp, Assign)); + + for (int i = 0; i <= dtypep->msb() - dtypep->lsb(); ++i) { + AstNode* lhsp = newVarRef(nodep->fileline(), vars.at(start_idx + i), lvalue); + AstNode* rhsp = new AstArraySel(nodep->fileline(), + newVarRef(nodep->fileline(), varp, !lvalue), i); + AstNode* refp = lhsp; + UINFO(9, "Creating assign idx:" << i << " + " << start_idx << "\n"); + if (!lvalue) std::swap(lhsp, rhsp); + AstNode* newassignp; + if (use_simple_assign) { + AstNode* insertp = toInsertPoint(context); + newassignp = new AstAssign(nodep->fileline(), lhsp, rhsp); + if (lvalue) { + // If varp is LHS, this assignment must appear after the original + // assignment(context). + insertp->addNextHere(newassignp); + } else { + // If varp is RHS, this assignment comes just before the original assignment + insertp->addHereThisAsNext(newassignp); + } + } else { + newassignp = new AstAssignW(nodep->fileline(), lhsp, rhsp); + // Continuous assignment must be in module context. + varp->addNextHere(newassignp); + } + UASSERT_OBJ(!m_contextp, m_contextp, "must be null"); + setContextAndIterate(newassignp, refp); + } + return newVarRef(nodep->fileline(), varp, lvalue); + } + void connectPort(AstVar* varp, std::vector& vars, AstNode* insertp) { + UASSERT_OBJ(varp->isIO(), varp, "must be port"); + insertp = insertp ? toInsertPoint(insertp) : NULL; + const bool lvalue = varp->direction().isWritable(); + for (size_t i = 0; i < vars.size(); ++i) { + AstNode* nodes[] + = {new AstArraySel(varp->fileline(), newVarRef(varp->fileline(), varp, lvalue), i), + newVarRef(varp->fileline(), vars.at(i), !lvalue)}; + AstNode* lhsp = nodes[lvalue ? 0 : 1]; + AstNode* rhsp = nodes[lvalue ? 1 : 0]; + AstNodeAssign* assignp = newAssign(varp->fileline(), lhsp, rhsp, varp); + if (insertp) { + if (lvalue) { // Just after writing to the temporary variable + insertp->addNextHere(assignp); + } else { // Just before reading the temporary variable + insertp->addHereThisAsNext(assignp); + } + } else { + UASSERT_OBJ(VN_IS(assignp, AssignW), varp, "must be AssginW"); + vars.at(i)->addNextHere(assignp); + } + setContextAndIterate(assignp, nodes[1]); + } + } + size_t collapse(UnpackRefMap& refs) { + size_t numSplit = 0; + for (UnpackRefMap::MapIt it = refs.begin(), it_end = refs.end(); it != it_end; ++it) { + UINFO(3, "In module " << m_modp->name() << " var " << it->first->prettyNameQ() + << " which has " << it->second.size() + << " refs will be split.\n"); + AstVar* varp = it->first; + AstNode* insertp = varp; + AstUnpackArrayDType* dtypep = VN_CAST(varp->dtypep()->skipRefp(), UnpackArrayDType); + AstNodeDType* subTypep = dtypep->subDTypep(); + const bool needNext = VN_IS(subTypep, UnpackArrayDType); // Still unpacked array. + std::vector vars; + // Add the split variables + for (vlsint32_t i = 0; i <= dtypep->msb() - dtypep->lsb(); ++i) { + // Unpacked array is traced as var(idx), not var[idx]. + const std::string name + = varp->name() + AstNode::encodeName('(' + cvtToStr(i + dtypep->lsb()) + ')'); + AstVar* newp = newVar(varp->fileline(), AstVarType::VAR, name, subTypep); + newp->propagateAttrFrom(varp); + // If varp is an IO, varp will remain and will be traced. + newp->trace(!varp->isIO() && varp->isTrace()); + newp->funcLocal(varp->isFuncLocal() || varp->isFuncReturn()); + insertp->addNextHere(newp); + insertp = newp; + newp->attrSplitVar(needNext || !cannotSplitPackedVarReason(newp)); + vars.push_back(newp); + setContextAndIterate(NULL, newp); + } + for (UnpackRefMap::SetIt sit = it->second.begin(), sit_end = it->second.end(); + sit != sit_end; ++sit) { + AstNode* newp = NULL; + if (sit->isSingleRef()) { + newp = newVarRef(sit->nodep()->fileline(), vars.at(sit->index()), + sit->lvalue()); + } else { + AstVarRef* refp = VN_CAST(sit->nodep(), VarRef); + AstUnpackArrayDType* dtypep; + int lsb = 0; + if (refp) { + dtypep = VN_CAST(refp->dtypep()->skipRefp(), UnpackArrayDType); + } else { + AstSliceSel* selp = VN_CAST(sit->nodep(), SliceSel); + UASSERT_OBJ(selp, sit->nodep(), "Unexpected op is registered"); + refp = VN_CAST(selp->fromp(), VarRef); + UASSERT_OBJ(refp, selp, "Unexpected op is registered"); + dtypep = VN_CAST(selp->dtypep()->skipRefp(), UnpackArrayDType); + lsb = dtypep->lsb(); + } + AstVarRef* newrefp = createTempVar(sit->context(), refp, dtypep, varp->name(), + vars, lsb, refp->lvalue(), sit->ftask()); + newp = newrefp; + refp->varp()->addNextHere(newrefp->varp()); + UINFO(3, + "Create " << newrefp->varp()->prettyNameQ() << " for " << refp << "\n"); + } + sit->nodep()->replaceWith(newp); + pushDeletep(sit->nodep()); + setContextAndIterate(sit->context(), newp->backp()); + // AstAssign is used. So assignment is necessary for each reference. + if (varp->isIO() && (varp->isFuncLocal() || varp->isFuncReturn())) + connectPort(varp, vars, sit->context()); + } + if (varp->isIO()) { + // AssignW will be created, so just once + if (!varp->isFuncLocal() && !varp->isFuncReturn()) { + connectPort(varp, vars, NULL); + } + varp->attrSplitVar(!cannotSplitPackedVarReason(varp)); + m_refsForPackedSplit[m_modp].add(varp); + } else { + pushDeletep(varp->unlinkFrBack()); + } + ++numSplit; + } + return numSplit; + } + void split() { + for (int trial = 0; !m_refs.empty(); ++trial) { + UnpackRefMap next; + m_refs.swap(next); + const size_t n = collapse(next); + UINFO(2, n << " Variables are split " << trial << " th trial in " + << m_modp->prettyNameQ() << '\n'); + if (trial == 0) m_numSplit += n; + } + doDeletes(); + } + +public: + explicit SplitUnpackedVarVisitor(AstNetlist* nodep) + : m_refs() + , m_modp(NULL) + , m_contextp(NULL) + , m_inFTask(NULL) + , m_numSplit(0) { + iterate(nodep); + } + ~SplitUnpackedVarVisitor() { + UASSERT(m_refs.empty(), "Don't forget to call split()"); + V3Stats::addStat("SplitVar, Split unpacked arrays", m_numSplit); + } + const SplitVarRefsMap& getPackedVarRefs() const { return m_refsForPackedSplit; } + VL_DEBUG_FUNC; // Declare debug() + + // Check if the passed variable can be split. + // Even if this function returns true, the variable may not be split + // because the access to the variable cannot be determined statically. + static const char* cannotSplitReason(const AstVar* nodep) { + const std::pair dim = nodep->dtypep()->dimensions(false); + UINFO(7, nodep->prettyNameQ() + << " pub:" << nodep->isSigPublic() << " pri:" << nodep->isPrimaryIO() + << " io:" << nodep->isInoutish() << " typ:" << nodep->varType() << "\n"); + const char* reason = NULL; + // Public variable cannot be split. + // at least one unpacked dimension must exist + if (dim.second < 1 || !VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType)) + reason = "it is not an unpacked array"; + if (!reason) reason = cannotSplitVarCommonReason(nodep); + if (reason) UINFO(5, "Check " << nodep->prettyNameQ() + << " cannot split because" << reason << ".\n"); + return reason; + } +}; + +//###################################################################### +// Split packed variables + +// Split variable +class SplitNewVar { + int m_lsb; // LSB in the original bitvector + int m_bitwidth; + AstVar* m_varp; // The LSB of this variable is always 0, not m_lsb +public: + SplitNewVar(int lsb, int bitwidth, AstVar* varp = NULL) + : m_lsb(lsb) + , m_bitwidth(bitwidth) + , m_varp(varp) {} + int lsb() const { return m_lsb; } + int msb() const { return m_lsb + m_bitwidth - 1; } + int bitwidth() const { return m_bitwidth; } + void varp(AstVar* vp) { + UASSERT_OBJ(!m_varp, m_varp, "must be NULL"); + m_varp = vp; + } + AstVar* varp() const { return m_varp; } + + struct Match { + bool operator()(int bit, const SplitNewVar& a) const { + return bit < a.m_lsb + a.m_bitwidth; + } + }; +}; + +// One Entry instance for an AstVarRef instance +class PackedVarRefEntry { + AstNode* m_nodep; // Either AstSel or AstVarRef is expected. + int m_lsb; + int m_bitwidth; + +public: + PackedVarRefEntry(AstSel* selp, int lsb, int bitwidth) + : m_nodep(selp) + , m_lsb(lsb) + , m_bitwidth(bitwidth) {} + PackedVarRefEntry(AstVarRef* refp, int lsb, int bitwidth) + : m_nodep(refp) + , m_lsb(lsb) + , m_bitwidth(bitwidth) {} + AstNode* nodep() const { return m_nodep; } + int lsb() const { return m_lsb; } + int msb() const { return m_lsb + m_bitwidth - 1; } + int bitwidth() const { return m_bitwidth; } + void replaceNodeWith(AstNode* nodep) { + m_nodep->replaceWith(nodep); + VL_DO_DANGLING(m_nodep->deleteTree(), m_nodep); + } + // If this is AstVarRef and referred in the sensitivity list of always@, + // return the sensitivity item + AstSenItem* backSenItemp() const { + if (AstVarRef* refp = VN_CAST(m_nodep, VarRef)) { return VN_CAST(refp->backp(), SenItem); } + return NULL; + } +}; + +// How a variable is used +class PackedVarRef { + struct SortByFirst { + bool operator()(const std::pair& a, const std::pair& b) const { + if (a.first == b.first) return a.second < b.second; + return a.first < b.first; + } + }; + std::vector m_lhs, m_rhs; + AstBasicDType* m_basicp; // Cache the ptr since varp->dtypep()->basicp() is expensive + bool m_dedupDone; + static void dedupRefs(std::vector& refs) { + vl_unordered_map nodes; + for (size_t i = 0; i < refs.size(); ++i) { + nodes.insert(std::make_pair(refs[i].nodep(), i)); + } + std::vector vect; + vect.reserve(nodes.size()); + for (vl_unordered_map::const_iterator it = nodes.begin(), + it_end = nodes.end(); + it != it_end; ++it) { + vect.push_back(refs[it->second]); + } + refs.swap(vect); + } + +public: + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; + std::vector& lhs() { + UASSERT(m_dedupDone, "cannot read before dedup()"); + return m_lhs; + } + std::vector& rhs() { + UASSERT(m_dedupDone, "cannot read before dedup()"); + return m_rhs; + } + explicit PackedVarRef(AstVar* varp) + : m_basicp(varp->dtypep()->basicp()) + , m_dedupDone(false) {} + void append(const PackedVarRefEntry& e, bool lvalue) { + UASSERT(!m_dedupDone, "cannot add after dedup()"); + if (lvalue) + m_lhs.push_back(e); + else + m_rhs.push_back(e); + } + void dedup() { + UASSERT(!m_dedupDone, "dedup() called twice"); + dedupRefs(m_lhs); + dedupRefs(m_rhs); + m_dedupDone = true; + } + const AstBasicDType* basicp() const { return m_basicp; } + // Make a plan for variables after split + // when skipUnused==true, split variable for unread bits will not be created. + std::vector splitPlan(bool skipUnused) const { + UASSERT(m_dedupDone, "dedup() must be called before"); + std::vector plan; + std::vector > points; // + points.reserve(m_lhs.size() * 2 + 2); // 2 points will be added per one PackedVarRefEntry + for (const_iterator it = m_lhs.begin(), itend = m_lhs.end(); it != itend; ++it) { + points.push_back(std::make_pair(it->lsb(), false)); // Start of a region + points.push_back(std::make_pair(it->msb() + 1, true)); // End of a region + } + if (skipUnused && !m_rhs.empty()) { // Range to be read must be kept, so add points here + int lsb = m_basicp->msb() + 1, msb = m_basicp->lsb() - 1; + for (size_t i = 0; i < m_rhs.size(); ++i) { + lsb = std::min(lsb, m_rhs[i].lsb()); + msb = std::max(msb, m_rhs[i].msb()); + } + UASSERT_OBJ(lsb <= msb, m_basicp, "lsb:" << lsb << " msb:" << msb << " are wrong"); + points.push_back(std::make_pair(lsb, false)); + points.push_back(std::make_pair(msb + 1, true)); + } + if (!skipUnused) { // All bits are necessary + points.push_back(std::make_pair(m_basicp->lsb(), false)); + points.push_back(std::make_pair(m_basicp->msb() + 1, true)); + } + std::sort(points.begin(), points.end(), SortByFirst()); + + // Scan the sorted points and sub bitfields + int refcount = 0; + for (size_t i = 0; i + 1 < points.size(); ++i) { + const int bitwidth = points[i + 1].first - points[i].first; + if (points[i].second) { + --refcount; // End of a region + } else { + ++refcount; // Start of a region + } + UASSERT(refcount >= 0, "refcounut must not be negative"); + if (bitwidth == 0 || refcount == 0) continue; // Vacant region + plan.push_back(SplitNewVar(points[i].first, bitwidth)); + } + + return plan; + } +}; + +class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl { + AstNetlist* m_netp; + AstNodeModule* m_modp; // Current module (just for log) + int m_numSplit; // Total number of split variables + // key:variable to be split. value:location where the variable is referenced. + vl_unordered_map m_refs; + virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); } + virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { + UASSERT_OBJ(m_modp == NULL, m_modp, "Nested module declration"); + if (!VN_IS(nodep, Module)) { + UINFO(5, "Skip " << nodep->prettyNameQ() << "\n"); + return; + } + UASSERT_OBJ(m_refs.empty(), nodep, "The last module didn't finish split()"); + m_modp = nodep; + UINFO(3, "Start analyzing module " << nodep->prettyName() << '\n'); + iterateChildren(nodep); + split(); + m_modp = NULL; + } + virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { + if (!cannotSplitTaskReason(nodep)) iterateChildren(nodep); + } + virtual void visit(AstVar* nodep) VL_OVERRIDE { + if (!nodep->attrSplitVar()) return; // Nothing to do + if (const char* reason = cannotSplitReason(nodep, true)) { + nodep->v3warn(SPLITVAR, nodep->prettyNameQ() << notSplitMsg << reason); + nodep->attrSplitVar(false); + } else { // Finally find a good candidate + const bool inserted = m_refs.insert(std::make_pair(nodep, PackedVarRef(nodep))).second; + if (inserted) { UINFO(3, nodep->prettyNameQ() << " is added to candidate list.\n"); } + } + } + virtual void visit(AstVarRef* nodep) VL_OVERRIDE { + AstVar* varp = nodep->varp(); + visit(varp); + vl_unordered_map::iterator refit = m_refs.find(varp); + if (refit == m_refs.end()) return; // variable without split_var metacomment + UASSERT_OBJ(varp->attrSplitVar(), varp, "split_var attribute must be attached"); + UASSERT_OBJ(!nodep->packagep(), nodep, + "variable in package must have been dropped beforehand."); + const AstBasicDType* basicp = refit->second.basicp(); + refit->second.append(PackedVarRefEntry(nodep, basicp->lsb(), varp->width()), + nodep->lvalue()); + UINFO(5, varp->prettyName() + << " Entire bit of [" << basicp->lsb() << ":+" << varp->width() << "] \n"); + } + virtual void visit(AstSel* nodep) VL_OVERRIDE { + AstVarRef* vrefp = VN_CAST(nodep->fromp(), VarRef); + if (!vrefp) { + iterateChildren(nodep); + return; + } + + AstVar* varp = vrefp->varp(); + vl_unordered_map::iterator refit = m_refs.find(varp); + if (refit == m_refs.end()) { + iterateChildren(nodep); + return; // Variable without split_var metacomment + } + UASSERT_OBJ(varp->attrSplitVar(), varp, "split_var attribute must be attached"); + + AstConst* consts[2] = {VN_CAST(nodep->lsbp(), Const), VN_CAST(nodep->widthp(), Const)}; + if (consts[0] && consts[1]) { // OK + refit->second.append( + PackedVarRefEntry(nodep, consts[0]->toSInt() + refit->second.basicp()->lsb(), + consts[1]->toUInt()), + vrefp->lvalue()); + UINFO(5, varp->prettyName() << " [" << consts[0]->toSInt() << ":+" + << consts[1]->toSInt() << "] lsb:" << refit->second.basicp()->lsb() << "\n"); + } else { + nodep->v3warn(SPLITVAR, vrefp->prettyNameQ() << notSplitMsg + << "its bit range cannot be determined statically."); + if (!consts[0]) { + UINFO(4, "LSB " << nodep->lsbp() << " is expected to be constant, but not\n"); + } + if (!consts[1]) { + UINFO(4, "WIDTH " << nodep->widthp() << " is expected to be constant, but not\n"); + } + m_refs.erase(varp); + varp->attrSplitVar(false); + iterateChildren(nodep); + } + } + // Extract necessary bit range from a newly created variable to meet ref + static AstNode* extractBits(const PackedVarRefEntry& ref, const SplitNewVar& var, + bool lvalue) { + AstVarRef* refp = new AstVarRef(ref.nodep()->fileline(), var.varp(), lvalue); + if (ref.lsb() <= var.lsb() && var.msb() <= ref.msb()) { // Use the entire bits + return refp; + } else { // Use slice + const int lsb = std::max(ref.lsb(), var.lsb()); + const int msb = std::min(ref.msb(), var.msb()); + const int bitwidth = msb + 1 - lsb; + UINFO(4, var.varp()->prettyNameQ() << "[" << msb << ":" << lsb << "] used for " + << ref.nodep()->prettyNameQ() << '\n'); + // LSB of varp is always 0. "lsb - var.lsb()" means this. see also SplitNewVar + AstSel* selp = new AstSel(ref.nodep()->fileline(), refp, lsb - var.lsb(), bitwidth); + return selp; + } + } + static void connectPortAndVar(const std::vector& vars, AstVar* portp, + AstNode* insertp) { + for (; insertp; insertp = insertp->backp()) { + if (AstNodeStmt* stmtp = VN_CAST(insertp, NodeStmt)) { + if (stmtp->isStatement()) break; + } + } + const bool in = portp->isReadOnly(); + for (size_t i = 0; i < vars.size(); ++i) { + AstNode* rhsp = new AstSel(portp->fileline(), + new AstVarRef(portp->fileline(), portp, !in), + vars[i].lsb(), vars[i].bitwidth()); + AstNode* lhsp = new AstVarRef(portp->fileline(), vars[i].varp(), in); + if (!in) std::swap(lhsp, rhsp); + AstNodeAssign* assignp = newAssign(portp->fileline(), lhsp, rhsp, portp); + if (insertp) { + if (in) { + insertp->addHereThisAsNext(assignp); + } else { + insertp->addNextHere(assignp); + } + } else { + vars[i].varp()->addNextHere(assignp); + } + } + } + void createVars(AstVar* varp, const AstBasicDType* basicp, std::vector& vars) { + for (size_t i = 0; i < vars.size(); ++i) { + SplitNewVar* newvarp = &vars[i]; + int left = newvarp->msb(), right = newvarp->lsb(); + if (basicp->littleEndian()) std::swap(left, right); + const std::string name + = (left == right) + ? varp->name() + "__BRA__" + AstNode::encodeNumber(left) + "__KET__" + : varp->name() + "__BRA__" + AstNode::encodeNumber(left) + + AstNode::encodeName(":") + AstNode::encodeNumber(right) + + "__KET__"; + + AstBasicDType* dtypep; + switch (basicp->keyword()) { + case AstBasicDTypeKwd::BIT: + dtypep = new AstBasicDType(varp->subDTypep()->fileline(), VFlagBitPacked(), + newvarp->bitwidth()); + break; + case AstBasicDTypeKwd::LOGIC: + dtypep = new AstBasicDType(varp->subDTypep()->fileline(), VFlagLogicPacked(), + newvarp->bitwidth()); + break; + default: UASSERT_OBJ(false, basicp, "Only bit and logic are allowed"); + } + dtypep->rangep(new AstRange(varp->fileline(), newvarp->msb(), newvarp->lsb())); + dtypep->rangep()->littleEndian(basicp->littleEndian()); + newvarp->varp(new AstVar(varp->fileline(), AstVarType::VAR, name, dtypep)); + newvarp->varp()->propagateAttrFrom(varp); + newvarp->varp()->funcLocal(varp->isFuncLocal() || varp->isFuncReturn()); + // Enable this line to trace split variable directly: + // newvarp->varp()->trace(varp->isTrace()); + m_netp->typeTablep()->addTypesp(dtypep); + varp->addNextHere(newvarp->varp()); + UINFO(4, newvarp->varp()->prettyNameQ() + << " is added for " << varp->prettyNameQ() << '\n'); + } + } + static void updateReferences(AstVar* varp, PackedVarRef& ref, + const std::vector& vars) { + typedef std::vector NewVars; // Sorted by its lsb + for (int lvalue = 0; lvalue <= 1; ++lvalue) { // Refer the new split variables + std::vector& refs = lvalue ? ref.lhs() : ref.rhs(); + for (PackedVarRef::iterator refit = refs.begin(), refitend = refs.end(); + refit != refitend; ++refit) { + NewVars::const_iterator varit = std::upper_bound( + vars.begin(), vars.end(), refit->lsb(), SplitNewVar::Match()); + UASSERT_OBJ(varit != vars.end(), refit->nodep(), "Not found"); + UASSERT(!(varit->msb() < refit->lsb() || refit->msb() < varit->lsb()), + "wrong search result"); + AstNode* prevp; + bool inSentitivityList = false; + if (AstSenItem* senitemp = refit->backSenItemp()) { + AstNode* oldsenrefp = senitemp->sensp(); + oldsenrefp->replaceWith( + new AstVarRef(senitemp->fileline(), varit->varp(), false)); + VL_DO_DANGLING(oldsenrefp->deleteTree(), oldsenrefp); + prevp = senitemp; + inSentitivityList = true; + } else { + prevp = extractBits(*refit, *varit, lvalue); + } + for (int residue = refit->msb() - varit->msb(); residue > 0; + residue -= varit->bitwidth()) { + ++varit; + UASSERT_OBJ(varit != vars.end(), refit->nodep(), "not enough split variables"); + if (AstSenItem* senitemp = VN_CAST(prevp, SenItem)) { + prevp = new AstSenItem( + senitemp->fileline(), senitemp->edgeType(), + new AstVarRef(senitemp->fileline(), varit->varp(), false)); + senitemp->addNextHere(prevp); + } else { + AstNode* bitsp = extractBits(*refit, *varit, lvalue); + prevp = new AstConcat(refit->nodep()->fileline(), bitsp, prevp); + } + } + // If varp is an argument of task/func, need to update temporary var + // everytime the var is updated. See also another call of connectPortAndVar() in + // split() + if (varp->isIO() && (varp->isFuncLocal() || varp->isFuncReturn())) + connectPortAndVar(vars, varp, refit->nodep()); + if (!inSentitivityList) refit->replaceNodeWith(prevp); + UASSERT_OBJ(varit->msb() >= refit->msb(), varit->varp(), "Out of range"); + } + } + } + // Do the actual splitting operation + void split() { + for (vl_unordered_map::iterator it = m_refs.begin(), + it_end = m_refs.end(); + it != it_end; ++it) { + it->second.dedup(); + AstVar* varp = it->first; + UINFO(3, "In module " << m_modp->name() << " var " << varp->prettyNameQ() + << " which has " << it->second.lhs().size() << " lhs refs and " + << it->second.rhs().size() << " rhs refs will be split.\n"); + std::vector vars + = it->second.splitPlan(!varp->isTrace()); // If traced, all bit must be kept + if (vars.empty()) continue; + if (vars.size() == 1 && vars.front().bitwidth() == varp->width()) + continue; // No split + + createVars(varp, it->second.basicp(), vars); // Add the split variables + + updateReferences(varp, it->second, vars); + + if (varp->isIO()) { // port cannot be deleted + // If varp is a port of a module, single AssignW is sufficient + if (!(varp->isFuncLocal() || varp->isFuncReturn())) + connectPortAndVar(vars, varp, NULL); + } else if (varp->isTrace()) { + // Let's reuse the original variable for tracing + AstNode* rhsp + = new AstVarRef(vars.front().varp()->fileline(), vars.front().varp(), false); + for (size_t i = 1; i < vars.size(); ++i) { + rhsp = new AstConcat(varp->fileline(), + new AstVarRef(varp->fileline(), vars[i].varp(), false), + rhsp); + } + varp->addNextHere(newAssign(varp->fileline(), + new AstVarRef(varp->fileline(), varp, true), + rhsp, varp)); + } else { // the original variable is not used anymore. + VL_DO_DANGLING(varp->unlinkFrBack()->deleteTree(), varp); + } + ++m_numSplit; + } + m_refs.clear(); // Done + } + +public: + // When reusing the information from SplitUnpackedVarVisitor + SplitPackedVarVisitor(AstNetlist* nodep, SplitVarRefsMap& refs) + : m_netp(nodep) + , m_modp(NULL) + , m_numSplit(0) { + // If you want ignore refs and walk the tne entire AST, + // just call iterate(nodep) and disable the following for-loop. + for (SplitVarRefsMap::iterator it = refs.begin(), it_end = refs.end(); it != it_end; + ++it) { + m_modp = it->first; + it->second.visit(this); + split(); + m_modp = NULL; + } + } + ~SplitPackedVarVisitor() { + UASSERT(m_refs.empty(), "Forgot to call split()"); + V3Stats::addStat("SplitVar, Split packed variables", m_numSplit); + } + + // Check if the passed variable can be split. + // Even if this function returns true, the variable may not be split + // when the access to the variable cannot be determined statically. + static const char* cannotSplitReason(const AstVar* nodep, bool checkUnpacked) { + const char* reason = NULL; + if (AstBasicDType* const basicp = nodep->dtypep()->basicp()) { + const std::pair dim = nodep->dtypep()->dimensions(false); + // Unpacked array will be split in SplitUnpackedVarVisitor() beforehand + if (!((!checkUnpacked || dim.second == 0) && nodep->dtypep()->widthMin() > 1)) + reason = "its bitwidth is 1"; + if (!reason && !basicp->isBitLogic()) // Floating point and string are not supported + reason = "it is not an aggregate type of bit nor logic"; + if (!reason) reason = cannotSplitVarCommonReason(nodep); + } else { + reason = "its type is unknown"; + } + if (reason) UINFO(5, "Check " << nodep->prettyNameQ() + << " cannot split because" << reason << endl); + return reason; + } + VL_DEBUG_FUNC; // Declare debug() +}; + +const char* SplitVarImpl::cannotSplitPackedVarReason(const AstVar* varp) { + return SplitPackedVarVisitor::cannotSplitReason(varp, true); +} + +//###################################################################### +// Split class functions + +void V3SplitVar::splitVariable(AstNetlist* nodep) { + UINFO(2, __FUNCTION__ << ": " << endl); + SplitVarRefsMap refs; + { + SplitUnpackedVarVisitor visitor(nodep); + refs = visitor.getPackedVarRefs(); + } + V3Global::dumpCheckGlobalTree("split_var", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 9); + { SplitPackedVarVisitor visitor(nodep, refs); } + V3Global::dumpCheckGlobalTree("split_var", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 9); +} + +bool V3SplitVar::canSplitVar(const AstVar* varp) { + // If either SplitUnpackedVarVisitor or SplitPackedVarVisitor can handle, + // then accept varp. + return !SplitUnpackedVarVisitor::cannotSplitReason(varp) + || !SplitPackedVarVisitor::cannotSplitReason(varp, false); +} diff --git a/src/V3SplitVar.h b/src/V3SplitVar.h new file mode 100644 index 000000000..61a9e8db2 --- /dev/null +++ b/src/V3SplitVar.h @@ -0,0 +1,39 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Break variables into separate words to avoid UNOPTFLAT +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2020 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. +// +// Verilator is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +//************************************************************************* + +#ifndef _V3SPLITVAR_H_ +#define _V3SPLITVAR_H_ 1 + +//============================================================================ + +class AstNetlist; +class AstVar; + +class V3SplitVar { +public: + // Split variables marked with split_var metacomment. + static void splitVariable(AstNetlist* nodep); + + // Return true if the variable can be split. + // This check is not perfect. + static bool canSplitVar(const AstVar* varp); +}; + +#endif // Guard diff --git a/src/Verilator.cpp b/src/Verilator.cpp index dae14ea6c..bf74ef44d 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -82,6 +82,7 @@ #include "V3Slice.h" #include "V3Split.h" #include "V3SplitAs.h" +#include "V3SplitVar.h" #include "V3Stats.h" #include "V3String.h" #include "V3Subst.h" @@ -175,12 +176,14 @@ static void process() { V3Const::constifyAllLint(v3Global.rootp()); if (!v3Global.opt.xmlOnly()) { + // Split packed variables into multiple pieces to resolve UNOPTFLAT. + // should be after constifyAllLint() which flattens to 1D bit vector + V3SplitVar::splitVariable(v3Global.rootp()); + // Remove cell arrays (must be between V3Width and scoping) V3Inst::dearrayAll(v3Global.rootp()); V3LinkDot::linkDotArrayed(v3Global.rootp()); - } - if (!v3Global.opt.xmlOnly()) { // Task inlining & pushing BEGINs names to variables/cells // Begin processing must be after Param, before module inlining V3Begin::debeginAll(v3Global.rootp()); // Flatten cell names, before inliner diff --git a/src/verilog.l b/src/verilog.l index d6797e228..23fad9c63 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -704,6 +704,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "/*verilator public_flat_rd*/" { FL; return yVL_PUBLIC_FLAT_RD; } "/*verilator public_flat_rw*/" { FL; return yVL_PUBLIC_FLAT_RW; } // The @(edge) is converted by the preproc "/*verilator public_module*/" { FL; return yVL_PUBLIC_MODULE; } + "/*verilator split_var*/" { FL; return yVL_SPLIT_VAR; } "/*verilator sc_clock*/" { FL; return yVL_CLOCK; } "/*verilator clocker*/" { FL; return yVL_CLOCKER; } "/*verilator no_clocker*/" { FL; return yVL_NO_CLOCKER; } diff --git a/src/verilog.y b/src/verilog.y index f7b9320e7..e23427536 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -639,6 +639,7 @@ class AstSenTree; %token yVL_PUBLIC_FLAT_RD "/*verilator public_flat_rd*/" %token yVL_PUBLIC_FLAT_RW "/*verilator public_flat_rw*/" %token yVL_PUBLIC_MODULE "/*verilator public_module*/" +%token yVL_SPLIT_VAR "/*verilator split_var*/" %token yP_TICK "'" %token yP_TICKBRA "'{" @@ -2282,6 +2283,7 @@ sigAttr: | yVL_ISOLATE_ASSIGNMENTS { $$ = new AstAttrOf($1,AstAttrType::VAR_ISOLATE_ASSIGNMENTS); } | yVL_SC_BV { $$ = new AstAttrOf($1,AstAttrType::VAR_SC_BV); } | yVL_SFORMAT { $$ = new AstAttrOf($1,AstAttrType::VAR_SFORMAT); } + | yVL_SPLIT_VAR { $$ = new AstAttrOf($1,AstAttrType::VAR_SPLIT_VAR); } ; rangeListE: // IEEE: [{packed_dimension}] diff --git a/test_regress/t/t_split_var_0.pl b/test_regress/t/t_split_var_0.pl new file mode 100755 index 000000000..b74a78821 --- /dev/null +++ b/test_regress/t/t_split_var_0.pl @@ -0,0 +1,26 @@ +#!/usr/bin/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. + +scenarios(simulator => 1); + +# Travis environment offers 2 VCPUs, 2 thread setting causes the following warning. +# %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads. +# So use 6 threads here though it's not optimal in performace wise, but ok. +compile( + verilator_flags2 => ['--stats' . ($Self->{vltmt} ? ' --threads 6' : '')], + ); + +execute( + check_finished => 1, + ); + +file_grep($Self->{stats}, qr/SplitVar,\s+Split packed variables\s+(\d+)/i, 13); +file_grep($Self->{stats}, qr/SplitVar,\s+Split unpacked arrays\s+(\d+)/i, 23); +ok(1); +1; diff --git a/test_regress/t/t_split_var_0.v b/test_regress/t/t_split_var_0.v new file mode 100644 index 000000000..d7111f948 --- /dev/null +++ b/test_regress/t/t_split_var_0.v @@ -0,0 +1,431 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2020 by Yutetsu TAKATSUKASA. + +// If split_var pragma is removed, UNOPTFLAT appears. + +module barshift_1d_unpacked #(parameter DEPTH = 2, localparam WIDTH = 2**DEPTH) + (input [WIDTH-1:0] in, input [DEPTH-1:0] shift, output [WIDTH-1:0] out /*verilator split_var*/); + + localparam OFFSET = -3; + logic [WIDTH-1:0] tmp[DEPTH+OFFSET:OFFSET] /*verilator split_var*/; + generate + for(genvar i = 0; i < DEPTH; ++i) begin + always_comb + if (shift[i]) begin + /*verilator lint_off ALWCOMBORDER*/ + tmp[i+1+OFFSET] = {tmp[i+OFFSET][(1 << i)-1:0], tmp[i+OFFSET][WIDTH-1:(2**i)]}; + /*verilator lint_on ALWCOMBORDER*/ + end + else begin + tmp[i+1+OFFSET] = tmp[i+OFFSET]; + end + end + endgenerate + assign tmp[0+OFFSET] = in; + assign out[WIDTH-1-:WIDTH-1] = tmp[DEPTH+OFFSET][WIDTH-1:1]; + assign out[0] = tmp[DEPTH+OFFSET][0+:1]; +endmodule + + +module barshift_1d_unpacked_le #(parameter DEPTH = 2, localparam WIDTH = 2**DEPTH) + (input [WIDTH-1:0] in, input [DEPTH-1:0] shift, output [WIDTH-1:0] out); + + localparam OFFSET = -3; + // almost same as above module, but tmp[smaller:bigger] here. + logic [WIDTH-1:0] tmp[OFFSET:DEPTH+OFFSET] /*verilator split_var*/; + generate + for(genvar i = 0; i < DEPTH; ++i) begin + always_comb + if (shift[i]) begin + /*verilator lint_off ALWCOMBORDER*/ + tmp[i+1+OFFSET] = {tmp[i+OFFSET][(1 << i)-1:0], tmp[i+OFFSET][WIDTH-1:(2**i)]}; + /*verilator lint_on ALWCOMBORDER*/ + end + else begin + tmp[i+1+OFFSET] = tmp[i+OFFSET]; + end + end + endgenerate + assign tmp[0+OFFSET] = in; + assign out = tmp[DEPTH+OFFSET]; +endmodule + + +module barshift_1d_unpacked_struct0 #(parameter DEPTH = 2, localparam WIDTH = 2**DEPTH) + (input [WIDTH-1:0] in, input [DEPTH-1:0] shift, output [WIDTH-1:0] out); + + localparam OFFSET = 1; + typedef struct packed { logic [WIDTH-1:0] data; } data_type; + data_type tmp[DEPTH+OFFSET:OFFSET] /*verilator split_var*/; + generate + for(genvar i = 0; i < DEPTH; ++i) begin + always_comb + if (shift[i]) begin + /*verilator lint_off ALWCOMBORDER*/ + tmp[i+1+OFFSET] = {tmp[i+OFFSET][(1 << i)-1:0], tmp[i+OFFSET][WIDTH-1:(2**i)]}; + /*verilator lint_on ALWCOMBORDER*/ + end + else begin + tmp[i+1+OFFSET] = tmp[i+OFFSET]; + end + end + endgenerate + assign tmp[0+OFFSET] = in; + assign out = tmp[DEPTH+OFFSET]; +endmodule + + +module barshift_2d_unpacked #(parameter DEPTH = 2, localparam WIDTH = 2**DEPTH) + (input [WIDTH-1:0] in, input [DEPTH-1:0] shift, output [WIDTH-1:0] out); + + localparam OFFSET = 1; + localparam N = 3; + reg [WIDTH-1:0] tmp0[DEPTH+OFFSET:OFFSET][OFFSET:OFFSET+N-1] /*verilator split_var*/; + reg [WIDTH-1:0] tmp1[DEPTH+OFFSET:OFFSET][OFFSET:OFFSET+N-1] /*verilator split_var*/; + reg [WIDTH-1:0] tmp2[DEPTH+OFFSET:OFFSET][OFFSET:OFFSET+N-1]; + reg [WIDTH-1:0] tmp3[DEPTH+OFFSET:OFFSET][OFFSET:OFFSET+N-1] /*verilator split_var*/; + reg [WIDTH-1:0] tmp4[DEPTH+OFFSET:OFFSET][OFFSET:OFFSET+N-1] /*verilator split_var*/; + reg [WIDTH-1:0] tmp5[DEPTH+OFFSET:OFFSET][OFFSET:OFFSET+N-1]; + reg [WIDTH-1:0] tmp6[DEPTH+OFFSET:OFFSET][OFFSET:OFFSET+N-1] /*verilator split_var*/; + + reg [WIDTH-1:0] tmp7[DEPTH+OFFSET+1:OFFSET+1][OFFSET:OFFSET+N-1] /*verilator split_var*/; + reg [WIDTH-1:0] tmp8[DEPTH+OFFSET+3:OFFSET-1][OFFSET:OFFSET+N-1] /*verilator split_var*/; + reg [WIDTH-1:0] tmp9[DEPTH+OFFSET+3:OFFSET+3][OFFSET:OFFSET+N-1] /*verilator split_var*/; + reg [WIDTH-1:0] tmp10[DEPTH+OFFSET:OFFSET][OFFSET:OFFSET+N-1] /*verilator split_var*/; + // because tmp11 is not split for testing mixture usage of split_var and no-spliv_ar, + // UNOPTFLAT appears, but it's fine. + /*verilator lint_off UNOPTFLAT*/ + reg [WIDTH-1:0] tmp11[-1:1][DEPTH+OFFSET:OFFSET][OFFSET:OFFSET+N-1]; + /*verilator lint_on UNOPTFLAT*/ + reg [WIDTH-1:0] tmp12[-1:0][DEPTH+OFFSET:OFFSET][OFFSET:OFFSET+N-1] /*verilator split_var*/; + reg [WIDTH-1:0] tmp13[DEPTH+OFFSET:OFFSET][OFFSET:OFFSET+N-1] /*verilator split_var*/; + + generate + for(genvar i = 0; i < DEPTH; ++i) begin + for(genvar j = OFFSET; j < N + OFFSET; ++j) begin + always_comb + if (shift[i]) begin + /*verilator lint_off ALWCOMBORDER*/ + tmp0[i+1+OFFSET][j] = {tmp0[i+OFFSET][j][(1 << i)-1:0], tmp0[i+OFFSET][j][WIDTH-1:(2**i)]}; + /*verilator lint_on ALWCOMBORDER*/ + end + else begin + tmp0[i+1+OFFSET][j] = tmp0[i+OFFSET][j]; + end + end + end + for(genvar j = OFFSET; j < N + OFFSET; ++j) begin + assign tmp0[0 + OFFSET][j] = in; + end + endgenerate + assign tmp1 = tmp0; // split both side + assign tmp2 = tmp1; // split only rhs + assign tmp3 = tmp2; // split only lhs + always_comb tmp4 = tmp3; // split both side + always_comb tmp5 = tmp4; // split only rhs + always_comb tmp6 = tmp5; // split only lhs + + assign tmp7 = tmp6; + assign tmp8[DEPTH+OFFSET+1:OFFSET+1] = tmp7; + assign tmp9 = tmp8[DEPTH+OFFSET+1:OFFSET+1]; + assign tmp10[DEPTH+OFFSET:OFFSET] = tmp9[DEPTH+OFFSET+3:OFFSET+3]; + assign tmp11[1] = tmp10; + assign tmp11[-1] = tmp11[1]; + assign tmp11[0] = tmp11[-1]; + assign tmp12 = tmp11[0:1]; + assign out = tmp12[1][DEPTH+OFFSET][OFFSET]; +endmodule + + +module barshift_1d_unpacked_struct1 #(parameter DEPTH = 2, localparam WIDTH = 2**DEPTH) + (input [WIDTH-1:0] in, input [DEPTH-1:0] shift, output [WIDTH-1:0] out); + + localparam OFFSET = 2; + typedef struct packed { int data; } data_type; + data_type tmp[DEPTH+OFFSET:OFFSET] /*verilator split_var*/; + + localparam [32-WIDTH-1:0] pad = 0; + generate + for(genvar i = 0; i < DEPTH; ++i) begin + always_comb + if (shift[i]) begin + /*verilator lint_off ALWCOMBORDER*/ + tmp[i+1+OFFSET] = {pad, tmp[i+OFFSET][(1 << i)-1:0], tmp[i+OFFSET][WIDTH-1:(2**i)]}; + /*verilator lint_on ALWCOMBORDER*/ + end + else begin + tmp[i+1+OFFSET] = tmp[i+OFFSET]; + end + end + endgenerate + assign tmp[0+OFFSET] = {pad, in}; + assign out = tmp[DEPTH+OFFSET][WIDTH-1:0]; +endmodule + + +module barshift_2d_packed_array #(parameter DEPTH = 2, localparam WIDTH = 2**DEPTH) + (input [WIDTH-1:0] in, input [DEPTH-1:0] shift, output [WIDTH-1:0] out); + + localparam OFFSET = -2; + /*verilator lint_off LITENDIAN*/ + reg [OFFSET:DEPTH+OFFSET][WIDTH-1:0] tmp /*verilator split_var*/; + /*verilator lint_on LITENDIAN*/ + + generate + for(genvar i = 0; i < DEPTH; ++i) begin + always_comb + /*verilator lint_off ALWCOMBORDER*/ + if (shift[i]) begin + tmp[i+1+OFFSET] = {tmp[i+OFFSET][(1 << i)-1:0], tmp[i+OFFSET][WIDTH-1:(2**i)]}; + end + else begin + tmp[i+1+OFFSET][1:0] = tmp[i+OFFSET][1:0]; + tmp[i+1+OFFSET][WIDTH-1:2] = tmp[i+OFFSET][WIDTH-1:2]; + end + /*verilator lint_on ALWCOMBORDER*/ + end + endgenerate + assign tmp[0+OFFSET] = in; + assign out = tmp[DEPTH+OFFSET]; +endmodule + +module barshift_2d_packed_array_le #(parameter DEPTH = 2, localparam WIDTH = 2**DEPTH) + (input [WIDTH-1:0] in, input [DEPTH-1:0] shift, output [WIDTH-1:0] out); + + localparam OFFSET = -2; + /*verilator lint_off LITENDIAN*/ + reg [OFFSET:DEPTH+OFFSET][OFFSET:WIDTH-1+OFFSET] tmp /*verilator split_var*/; + /*verilator lint_on LITENDIAN*/ + + generate + for(genvar i = 0; i < DEPTH; ++i) begin + always_comb + /*verilator lint_off ALWCOMBORDER*/ + if (shift[i]) begin + tmp[i+1+OFFSET] = {tmp[i+OFFSET][WIDTH-(2**i)+OFFSET:WIDTH-1+OFFSET], tmp[i+OFFSET][OFFSET:WIDTH-(2**i)-1+OFFSET]}; + end + else begin // actulally just tmp[i+1+OFFSET] = tmp[i+OFFSET] + tmp[i+1+OFFSET][0+OFFSET:2+OFFSET] = tmp[i+OFFSET][0+OFFSET:2+OFFSET]; + tmp[i+1+OFFSET][3+OFFSET] = tmp[i+OFFSET][3+OFFSET]; + {tmp[i+1+OFFSET][4+OFFSET],tmp[i+1+OFFSET][5+OFFSET]} = {tmp[i+OFFSET][4+OFFSET], tmp[i+OFFSET][5+OFFSET]}; + {tmp[i+1+OFFSET][7+OFFSET],tmp[i+1+OFFSET][6+OFFSET]} = {tmp[i+OFFSET][7+OFFSET], tmp[i+OFFSET][6+OFFSET]}; + end + /*verilator lint_on ALWCOMBORDER*/ + end + endgenerate + assign tmp[0+OFFSET] = in; + assign out = tmp[DEPTH+OFFSET]; +endmodule + + +module barshift_1d_packed_struct #(localparam DEPTH = 3, localparam WIDTH = 2**DEPTH) + (input [WIDTH-1:0] in, input [DEPTH-1:0] shift, output [WIDTH-1:0] out); + + typedef struct packed { + logic [WIDTH-1:0] v0, v1, v2, v3; + } data_type; + wire data_type tmp /*verilator split_var*/; + + assign tmp.v0 = in; + assign tmp.v1 = shift[0] == 1'b1 ? {tmp.v0[(1 << 0)-1:0], tmp.v0[WIDTH-1:2**0]} : tmp.v0; + assign tmp.v2 = shift[1] == 1'b1 ? {tmp.v1[(1 << 1)-1:0], tmp.v1[WIDTH-1:2**1]} : tmp.v1; + assign tmp.v3 = shift[2] == 1'b1 ? {tmp.v2[(1 << 2)-1:0], tmp.v2[WIDTH-1:2**2]} : tmp.v2; + assign out = tmp.v3; +endmodule + + +module barshift_bitslice #(parameter DEPTH = 2, localparam WIDTH = 2**DEPTH) + (input [WIDTH-1:0] in, input [DEPTH-1:0] shift, output [WIDTH-1:0] out); + + /*verilator lint_off LITENDIAN*/ + wire [0:WIDTH*(DEPTH+1) - 1] tmp /*verilator split_var*/; + /*verilator lint_on LITENDIAN*/ + + generate + for(genvar i = 0; i < DEPTH; ++i) begin + always_comb + if (shift[i]) begin + tmp[WIDTH*(i+1):WIDTH*(i+1+1)-1] = {tmp[WIDTH*(i+1)-(1< 1); + +compile( + fails => 1, + verilator_flags2 => ['--stats'], + expect_filename => $Self->{golden_filename}, +); + +ok(1); +1; diff --git a/test_regress/t/t_split_var_1_bad.v b/test_regress/t/t_split_var_1_bad.v new file mode 100644 index 000000000..d3e5b9e04 --- /dev/null +++ b/test_regress/t/t_split_var_1_bad.v @@ -0,0 +1,84 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2020 by Yutetsu TAKATSUKASA. + +logic [7:0] should_show_warning_global0 /* verilator split_var */; +logic [7:0] should_show_warning_global1 [1:0] /* verilator split_var */; + +interface ifs; + logic [7:0] should_show_warning_ifs0 /* verilator split_var */; + logic [7:0] should_show_warning_ifs1 [1:0] /* verilator split_var */; +endinterface + +module t(); + // The following variables can not be splitted. will see warnings. + real should_show_warning0 /*verilator split_var*/; + string should_show_warning1 /*verilator split_var*/; + wire should_show_warning2 /*verilator split_var*/; + + logic [3:0] addr; + logic [7:0] rd_data0, rd_data1, rd_data2; + + sub0 i_sub0(.addr(addr), .rd_data(rd_data0)); + sub1 i_sub1(.addr(addr), .rd_data(rd_data2)); + sub2 i_sub2; + sub3 i_sub3; + ifs i_ifs(); + + function int bad_func(inout logic [3:0] inout_port /*verilator split_var*/, + ref logic [7:0] ref_port /*verilator split_var*/); + return 0; + endfunction + + initial begin + addr = 0; + addr = 1; + i_sub0.cannot_split1[0] = 0; + i_sub0.cannot_split1[1] = bad_func(addr, rd_data0); + $finish; + end + +endmodule + + +module sub0(input [3:0]addr, output logic [7:0] rd_data); + + logic [7:0] cannot_split0[0:15] /*verilator split_var*/; + logic [7:0] cannot_split1[0:15] /*verilator split_var*/; + always_comb + rd_data = cannot_split0[addr]; + +endmodule + + +module sub1(input [3:0]addr, output logic [7:0] rd_data); + genvar cannot_split_genvar /*verilator split_var*/; + logic [15:0] [7:0] cannot_split /*verilator split_var*/; + always_comb + rd_data = cannot_split[addr]; + +endmodule + + +module sub2; // from t_bitsel_wire_array_bad.v + + // a and b are arrays of length 1. + wire a[0:0] /* verilator split_var */ ; // Array of nets + wire b[0:0] /* verilator split_var */ ; + + assign a = 1'b0; // Only net assignment allowed + assign b = a[0]; // Only net assignment allowed + +endmodule + +module sub3; // from t_select_bad_range3.v + + logic [7:0] inwires [12:10] /* verilator split_var */; + wire [7:0] outwires [12:10] /* verilator split_var */; + + assign outwires[10] = inwires[11]; + assign outwires[11] = inwires[12]; + assign outwires[12] = inwires[13]; // must be an error here + +endmodule diff --git a/test_regress/t/t_split_var_2_trace.out b/test_regress/t/t_split_var_2_trace.out new file mode 100644 index 000000000..b922cd557 --- /dev/null +++ b/test_regress/t/t_split_var_2_trace.out @@ -0,0 +1,1930 @@ +$version Generated by VerilatedVcd $end +$date Tue Feb 11 16:07:02 2020 + $end +$timescale 1ns $end + + $scope module top $end + $var wire 1 o2 clk $end + $scope module t $end + $var wire 32 w2 DEPTH [31:0] $end + $var wire 32 )3 NUMSUB [31:0] $end + $var wire 32 !3 WIDTH [31:0] $end + $var wire 1 o2 clk $end + $var wire 64 93 expc [63:0] $end + $var wire 8 13 in [7:0] $end + $var wire 8 M- out(0) [7:0] $end + $var wire 8 N- out(1) [7:0] $end + $var wire 8 O- out(2) [7:0] $end + $var wire 8 P- out(3) [7:0] $end + $var wire 8 Q- out(4) [7:0] $end + $var wire 8 R- out(5) [7:0] $end + $var wire 8 S- out(6) [7:0] $end + $var wire 8 T- out(7) [7:0] $end + $var wire 8 U- out(8) [7:0] $end + $var wire 3 s shift [2:0] $end + $var wire 8 ?. through_tmp [7:0] $end + $scope module always_block $end + $var wire 1 O2 failed $end + $scope module unnamedblk1 $end + $var wire 32 W2 i [31:0] $end + $upscope $end + $upscope $end + $scope module i_t_array_rev $end + $var wire 1 C arrd(0) $end + $var wire 1 K arrd(1) $end + $var wire 1 o2 clk $end + $var wire 32 }5 cyc [31:0] $end + $var wire 1 _2 localbkw(0) $end + $var wire 1 g2 localbkw(1) $end + $var wire 1 S y0 $end + $var wire 1 [ y1 $end + $scope module arr_rev_u $end + $var wire 1 c arrbkw(0) $end + $var wire 1 d arrbkw(1) $end + $var wire 1 S y0 $end + $var wire 1 [ y1 $end + $upscope $end + $upscope $end + $scope module i_var_decl_with_init $end + $var wire 32 # var0 [-1:30] $end + $var wire 32 3 var1 [30:-1] $end + $var wire 32 + var2 [-1:30] $end + $var wire 32 ; var3 [30:-1] $end + $upscope $end + $scope module shifter0 $end + $var wire 32 w2 DEPTH [31:0] $end + $var wire 32 I3 OFFSET [31:0] $end + $var wire 32 !3 WIDTH [31:0] $end + $var wire 8 13 in [7:0] $end + $var wire 8 { out [7:0] $end + $var wire 3 s shift [2:0] $end + $var wire 8 -! tmp(-1) [7:0] $end + $var wire 8 %! tmp(-2) [7:0] $end + $var wire 8 13 tmp(-3) [7:0] $end + $var wire 8 5! tmp(0) [7:0] $end + $upscope $end + $scope module shifter1 $end + $var wire 32 w2 DEPTH [31:0] $end + $var wire 32 I3 OFFSET [31:0] $end + $var wire 32 !3 WIDTH [31:0] $end + $var wire 8 13 in [7:0] $end + $var wire 8 =! out [7:0] $end + $var wire 3 s shift [2:0] $end + $var wire 8 E! tmp(-1) [7:0] $end + $var wire 8 %! tmp(-2) [7:0] $end + $var wire 8 13 tmp(-3) [7:0] $end + $var wire 8 =! tmp(0) [7:0] $end + $upscope $end + $scope module shifter2 $end + $var wire 32 w2 DEPTH [31:0] $end + $var wire 32 Q3 OFFSET [31:0] $end + $var wire 32 !3 WIDTH [31:0] $end + $var wire 8 13 in [7:0] $end + $var wire 8 M! out [7:0] $end + $var wire 3 s shift [2:0] $end + $var wire 8 13 tmp(1) [7:0] $end + $var wire 8 U! tmp(2) [7:0] $end + $var wire 8 ]! tmp(3) [7:0] $end + $var wire 8 M! tmp(4) [7:0] $end + $upscope $end + $scope module shifter3 $end + $var wire 32 w2 DEPTH [31:0] $end + $var wire 32 w2 N [31:0] $end + $var wire 32 Q3 OFFSET [31:0] $end + $var wire 32 !3 WIDTH [31:0] $end + $var wire 8 13 in [7:0] $end + $var wire 8 G. out [7:0] $end + $var wire 3 s shift [2:0] $end + $var wire 8 13 tmp0(1)(1) [7:0] $end + $var wire 8 13 tmp0(1)(2) [7:0] $end + $var wire 8 13 tmp0(1)(3) [7:0] $end + $var wire 8 %! tmp0(2)(1) [7:0] $end + $var wire 8 %! tmp0(2)(2) [7:0] $end + $var wire 8 %! tmp0(2)(3) [7:0] $end + $var wire 8 e! tmp0(3)(1) [7:0] $end + $var wire 8 m! tmp0(3)(2) [7:0] $end + $var wire 8 u! tmp0(3)(3) [7:0] $end + $var wire 8 }! tmp0(4)(1) [7:0] $end + $var wire 8 '" tmp0(4)(2) [7:0] $end + $var wire 8 /" tmp0(4)(3) [7:0] $end + $var wire 8 7" tmp1(1)(1) [7:0] $end + $var wire 8 ?" tmp1(1)(2) [7:0] $end + $var wire 8 G" tmp1(1)(3) [7:0] $end + $var wire 8 O" tmp1(2)(1) [7:0] $end + $var wire 8 W" tmp1(2)(2) [7:0] $end + $var wire 8 _" tmp1(2)(3) [7:0] $end + $var wire 8 g" tmp1(3)(1) [7:0] $end + $var wire 8 o" tmp1(3)(2) [7:0] $end + $var wire 8 w" tmp1(3)(3) [7:0] $end + $var wire 8 !# tmp1(4)(1) [7:0] $end + $var wire 8 )# tmp1(4)(2) [7:0] $end + $var wire 8 1# tmp1(4)(3) [7:0] $end + $var wire 8 I+ tmp10(1)(1) [7:0] $end + $var wire 8 Q+ tmp10(1)(2) [7:0] $end + $var wire 8 Y+ tmp10(1)(3) [7:0] $end + $var wire 8 a+ tmp10(2)(1) [7:0] $end + $var wire 8 i+ tmp10(2)(2) [7:0] $end + $var wire 8 q+ tmp10(2)(3) [7:0] $end + $var wire 8 y+ tmp10(3)(1) [7:0] $end + $var wire 8 #, tmp10(3)(2) [7:0] $end + $var wire 8 +, tmp10(3)(3) [7:0] $end + $var wire 8 3, tmp10(4)(1) [7:0] $end + $var wire 8 ;, tmp10(4)(2) [7:0] $end + $var wire 8 C, tmp10(4)(3) [7:0] $end + $var wire 8 O. tmp12(-1)(1)(1) [7:0] $end + $var wire 8 W. tmp12(-1)(1)(2) [7:0] $end + $var wire 8 _. tmp12(-1)(1)(3) [7:0] $end + $var wire 8 g. tmp12(-1)(2)(1) [7:0] $end + $var wire 8 o. tmp12(-1)(2)(2) [7:0] $end + $var wire 8 w. tmp12(-1)(2)(3) [7:0] $end + $var wire 8 !/ tmp12(-1)(3)(1) [7:0] $end + $var wire 8 )/ tmp12(-1)(3)(2) [7:0] $end + $var wire 8 1/ tmp12(-1)(3)(3) [7:0] $end + $var wire 8 G. tmp12(-1)(4)(1) [7:0] $end + $var wire 8 9/ tmp12(-1)(4)(2) [7:0] $end + $var wire 8 A/ tmp12(-1)(4)(3) [7:0] $end + $var wire 8 I/ tmp12(0)(1)(1) [7:0] $end + $var wire 8 Q/ tmp12(0)(1)(2) [7:0] $end + $var wire 8 Y/ tmp12(0)(1)(3) [7:0] $end + $var wire 8 a/ tmp12(0)(2)(1) [7:0] $end + $var wire 8 i/ tmp12(0)(2)(2) [7:0] $end + $var wire 8 q/ tmp12(0)(2)(3) [7:0] $end + $var wire 8 y/ tmp12(0)(3)(1) [7:0] $end + $var wire 8 #0 tmp12(0)(3)(2) [7:0] $end + $var wire 8 +0 tmp12(0)(3)(3) [7:0] $end + $var wire 8 30 tmp12(0)(4)(1) [7:0] $end + $var wire 8 ;0 tmp12(0)(4)(2) [7:0] $end + $var wire 8 C0 tmp12(0)(4)(3) [7:0] $end + $var wire 8 [4 tmp13(1)(1) [7:0] $end + $var wire 8 c4 tmp13(1)(2) [7:0] $end + $var wire 8 k4 tmp13(1)(3) [7:0] $end + $var wire 8 s4 tmp13(2)(1) [7:0] $end + $var wire 8 {4 tmp13(2)(2) [7:0] $end + $var wire 8 %5 tmp13(2)(3) [7:0] $end + $var wire 8 -5 tmp13(3)(1) [7:0] $end + $var wire 8 55 tmp13(3)(2) [7:0] $end + $var wire 8 =5 tmp13(3)(3) [7:0] $end + $var wire 8 E5 tmp13(4)(1) [7:0] $end + $var wire 8 M5 tmp13(4)(2) [7:0] $end + $var wire 8 U5 tmp13(4)(3) [7:0] $end + $var wire 8 9# tmp2(1)(1) [7:0] $end + $var wire 8 A# tmp2(1)(2) [7:0] $end + $var wire 8 I# tmp2(1)(3) [7:0] $end + $var wire 8 Q# tmp2(2)(1) [7:0] $end + $var wire 8 Y# tmp2(2)(2) [7:0] $end + $var wire 8 a# tmp2(2)(3) [7:0] $end + $var wire 8 i# tmp2(3)(1) [7:0] $end + $var wire 8 q# tmp2(3)(2) [7:0] $end + $var wire 8 y# tmp2(3)(3) [7:0] $end + $var wire 8 #$ tmp2(4)(1) [7:0] $end + $var wire 8 +$ tmp2(4)(2) [7:0] $end + $var wire 8 3$ tmp2(4)(3) [7:0] $end + $var wire 8 ;$ tmp3(1)(1) [7:0] $end + $var wire 8 C$ tmp3(1)(2) [7:0] $end + $var wire 8 K$ tmp3(1)(3) [7:0] $end + $var wire 8 S$ tmp3(2)(1) [7:0] $end + $var wire 8 [$ tmp3(2)(2) [7:0] $end + $var wire 8 c$ tmp3(2)(3) [7:0] $end + $var wire 8 k$ tmp3(3)(1) [7:0] $end + $var wire 8 s$ tmp3(3)(2) [7:0] $end + $var wire 8 {$ tmp3(3)(3) [7:0] $end + $var wire 8 %% tmp3(4)(1) [7:0] $end + $var wire 8 -% tmp3(4)(2) [7:0] $end + $var wire 8 5% tmp3(4)(3) [7:0] $end + $var wire 8 =% tmp4(1)(1) [7:0] $end + $var wire 8 E% tmp4(1)(2) [7:0] $end + $var wire 8 M% tmp4(1)(3) [7:0] $end + $var wire 8 U% tmp4(2)(1) [7:0] $end + $var wire 8 ]% tmp4(2)(2) [7:0] $end + $var wire 8 e% tmp4(2)(3) [7:0] $end + $var wire 8 m% tmp4(3)(1) [7:0] $end + $var wire 8 u% tmp4(3)(2) [7:0] $end + $var wire 8 }% tmp4(3)(3) [7:0] $end + $var wire 8 '& tmp4(4)(1) [7:0] $end + $var wire 8 /& tmp4(4)(2) [7:0] $end + $var wire 8 7& tmp4(4)(3) [7:0] $end + $var wire 8 ?& tmp5(1)(1) [7:0] $end + $var wire 8 G& tmp5(1)(2) [7:0] $end + $var wire 8 O& tmp5(1)(3) [7:0] $end + $var wire 8 W& tmp5(2)(1) [7:0] $end + $var wire 8 _& tmp5(2)(2) [7:0] $end + $var wire 8 g& tmp5(2)(3) [7:0] $end + $var wire 8 o& tmp5(3)(1) [7:0] $end + $var wire 8 w& tmp5(3)(2) [7:0] $end + $var wire 8 !' tmp5(3)(3) [7:0] $end + $var wire 8 )' tmp5(4)(1) [7:0] $end + $var wire 8 1' tmp5(4)(2) [7:0] $end + $var wire 8 9' tmp5(4)(3) [7:0] $end + $var wire 8 A' tmp6(1)(1) [7:0] $end + $var wire 8 I' tmp6(1)(2) [7:0] $end + $var wire 8 Q' tmp6(1)(3) [7:0] $end + $var wire 8 Y' tmp6(2)(1) [7:0] $end + $var wire 8 a' tmp6(2)(2) [7:0] $end + $var wire 8 i' tmp6(2)(3) [7:0] $end + $var wire 8 q' tmp6(3)(1) [7:0] $end + $var wire 8 y' tmp6(3)(2) [7:0] $end + $var wire 8 #( tmp6(3)(3) [7:0] $end + $var wire 8 +( tmp6(4)(1) [7:0] $end + $var wire 8 3( tmp6(4)(2) [7:0] $end + $var wire 8 ;( tmp6(4)(3) [7:0] $end + $var wire 8 C( tmp7(2)(1) [7:0] $end + $var wire 8 K( tmp7(2)(2) [7:0] $end + $var wire 8 S( tmp7(2)(3) [7:0] $end + $var wire 8 [( tmp7(3)(1) [7:0] $end + $var wire 8 c( tmp7(3)(2) [7:0] $end + $var wire 8 k( tmp7(3)(3) [7:0] $end + $var wire 8 s( tmp7(4)(1) [7:0] $end + $var wire 8 {( tmp7(4)(2) [7:0] $end + $var wire 8 %) tmp7(4)(3) [7:0] $end + $var wire 8 -) tmp7(5)(1) [7:0] $end + $var wire 8 5) tmp7(5)(2) [7:0] $end + $var wire 8 =) tmp7(5)(3) [7:0] $end + $var wire 8 Y3 tmp8(0)(1) [7:0] $end + $var wire 8 a3 tmp8(0)(2) [7:0] $end + $var wire 8 i3 tmp8(0)(3) [7:0] $end + $var wire 8 q3 tmp8(1)(1) [7:0] $end + $var wire 8 y3 tmp8(1)(2) [7:0] $end + $var wire 8 #4 tmp8(1)(3) [7:0] $end + $var wire 8 E) tmp8(2)(1) [7:0] $end + $var wire 8 M) tmp8(2)(2) [7:0] $end + $var wire 8 U) tmp8(2)(3) [7:0] $end + $var wire 8 ]) tmp8(3)(1) [7:0] $end + $var wire 8 e) tmp8(3)(2) [7:0] $end + $var wire 8 m) tmp8(3)(3) [7:0] $end + $var wire 8 u) tmp8(4)(1) [7:0] $end + $var wire 8 }) tmp8(4)(2) [7:0] $end + $var wire 8 '* tmp8(4)(3) [7:0] $end + $var wire 8 /* tmp8(5)(1) [7:0] $end + $var wire 8 7* tmp8(5)(2) [7:0] $end + $var wire 8 ?* tmp8(5)(3) [7:0] $end + $var wire 8 +4 tmp8(6)(1) [7:0] $end + $var wire 8 34 tmp8(6)(2) [7:0] $end + $var wire 8 ;4 tmp8(6)(3) [7:0] $end + $var wire 8 C4 tmp8(7)(1) [7:0] $end + $var wire 8 K4 tmp8(7)(2) [7:0] $end + $var wire 8 S4 tmp8(7)(3) [7:0] $end + $var wire 8 G* tmp9(4)(1) [7:0] $end + $var wire 8 O* tmp9(4)(2) [7:0] $end + $var wire 8 W* tmp9(4)(3) [7:0] $end + $var wire 8 _* tmp9(5)(1) [7:0] $end + $var wire 8 g* tmp9(5)(2) [7:0] $end + $var wire 8 o* tmp9(5)(3) [7:0] $end + $var wire 8 w* tmp9(6)(1) [7:0] $end + $var wire 8 !+ tmp9(6)(2) [7:0] $end + $var wire 8 )+ tmp9(6)(3) [7:0] $end + $var wire 8 1+ tmp9(7)(1) [7:0] $end + $var wire 8 9+ tmp9(7)(2) [7:0] $end + $var wire 8 A+ tmp9(7)(3) [7:0] $end + $upscope $end + $scope module shifter4 $end + $var wire 32 w2 DEPTH [31:0] $end + $var wire 32 ]5 OFFSET [31:0] $end + $var wire 32 !3 WIDTH [31:0] $end + $var wire 8 13 in [7:0] $end + $var wire 8 K, out [7:0] $end + $var wire 24 m5 pad [23:0] $end + $var wire 3 s shift [2:0] $end + $var wire 32 e5 tmp(2) [31:0] $end + $var wire 32 S, tmp(3) [31:0] $end + $var wire 32 [, tmp(4) [31:0] $end + $var wire 32 c, tmp(5) [31:0] $end + $upscope $end + $scope module shifter5 $end + $var wire 32 w2 DEPTH [31:0] $end + $var wire 32 u5 OFFSET [31:0] $end + $var wire 32 !3 WIDTH [31:0] $end + $var wire 8 13 in [7:0] $end + $var wire 8 k, out [7:0] $end + $var wire 3 s shift [2:0] $end + $var wire 32 s, tmp [31:0] $end + $upscope $end + $scope module shifter6 $end + $var wire 32 w2 DEPTH [31:0] $end + $var wire 32 u5 OFFSET [31:0] $end + $var wire 32 !3 WIDTH [31:0] $end + $var wire 8 13 in [7:0] $end + $var wire 8 {, out [7:0] $end + $var wire 3 s shift [2:0] $end + $var wire 32 %- tmp [31:0] $end + $upscope $end + $scope module shifter7 $end + $var wire 32 w2 DEPTH [31:0] $end + $var wire 32 !3 WIDTH [31:0] $end + $var wire 8 13 in [7:0] $end + $var wire 8 -- out [7:0] $end + $var wire 3 s shift [2:0] $end + $var wire 32 5- tmp [31:0] $end + $upscope $end + $scope module shifter8 $end + $var wire 32 w2 DEPTH [31:0] $end + $var wire 32 !3 WIDTH [31:0] $end + $var wire 8 13 in [7:0] $end + $var wire 8 =- out [7:0] $end + $var wire 3 s shift [2:0] $end + $var wire 32 E- tmp [0:31] $end + $upscope $end + $scope module though0 $end + $var wire 32 !3 WIDTH [31:0] $end + $var wire 8 7. in [7:0] $end + $var wire 8 ?. out [7:0] $end + $var wire 1 K0 unpack_tmp(0) $end + $var wire 1 S0 unpack_tmp(1) $end + $var wire 1 [0 unpack_tmp(2) $end + $var wire 1 c0 unpack_tmp(3) $end + $var wire 1 k0 unpack_tmp(4) $end + $var wire 1 s0 unpack_tmp(5) $end + $var wire 1 {0 unpack_tmp(6) $end + $var wire 1 %1 unpack_tmp(7) $end + $scope module i_pack2unpack $end + $var wire 32 !3 WIDTH [31:0] $end + $var wire 8 7. in [7:0] $end + $var wire 1 -1 out(0) $end + $var wire 1 .1 out(1) $end + $var wire 1 /1 out(2) $end + $var wire 1 01 out(3) $end + $var wire 1 11 out(4) $end + $var wire 1 21 out(5) $end + $var wire 1 31 out(6) $end + $var wire 1 41 out(7) $end + $upscope $end + $scope module i_unpack2pack $end + $var wire 32 !3 WIDTH [31:0] $end + $var wire 1 m1 in(0) $end + $var wire 1 n1 in(1) $end + $var wire 1 o1 in(2) $end + $var wire 1 p1 in(3) $end + $var wire 1 q1 in(4) $end + $var wire 1 r1 in(5) $end + $var wire 1 s1 in(6) $end + $var wire 1 t1 in(7) $end + $var wire 8 ?. out [7:0] $end + $upscope $end + $upscope $end + $upscope $end + $upscope $end +$enddefinitions $end + + +#0 +b00000001001000110100010101100111 # +b00100000000000000000000000000000 + +b00000001001000110100000000100111 3 +b00000000000000000000000000000011 ; +1C +0K +0S +1[ +0c +1d +b000 s +b10001110 { +b10001110 %! +b10001110 -! +b10001110 5! +b10001110 =! +b10001110 E! +b10001110 M! +b10001110 U! +b10001110 ]! +b10001110 e! +b10001110 m! +b10001110 u! +b10001110 }! +b10001110 '" +b10001110 /" +b10001110 7" +b10001110 ?" +b10001110 G" +b10001110 O" +b10001110 W" +b10001110 _" +b10001110 g" +b10001110 o" +b10001110 w" +b10001110 !# +b10001110 )# +b10001110 1# +b10001110 9# +b10001110 A# +b10001110 I# +b10001110 Q# +b10001110 Y# +b10001110 a# +b10001110 i# +b10001110 q# +b10001110 y# +b10001110 #$ +b10001110 +$ +b10001110 3$ +b10001110 ;$ +b10001110 C$ +b10001110 K$ +b10001110 S$ +b10001110 [$ +b10001110 c$ +b10001110 k$ +b10001110 s$ +b10001110 {$ +b10001110 %% +b10001110 -% +b10001110 5% +b10001110 =% +b10001110 E% +b10001110 M% +b10001110 U% +b10001110 ]% +b10001110 e% +b10001110 m% +b10001110 u% +b10001110 }% +b10001110 '& +b10001110 /& +b10001110 7& +b10001110 ?& +b10001110 G& +b10001110 O& +b10001110 W& +b10001110 _& +b10001110 g& +b10001110 o& +b10001110 w& +b10001110 !' +b10001110 )' +b10001110 1' +b10001110 9' +b10001110 A' +b10001110 I' +b10001110 Q' +b10001110 Y' +b10001110 a' +b10001110 i' +b10001110 q' +b10001110 y' +b10001110 #( +b10001110 +( +b10001110 3( +b10001110 ;( +b10001110 C( +b10001110 K( +b10001110 S( +b10001110 [( +b10001110 c( +b10001110 k( +b10001110 s( +b10001110 {( +b10001110 %) +b10001110 -) +b10001110 5) +b10001110 =) +b10001110 E) +b10001110 M) +b10001110 U) +b10001110 ]) +b10001110 e) +b10001110 m) +b10001110 u) +b10001110 }) +b10001110 '* +b10001110 /* +b10001110 7* +b10001110 ?* +b10001110 G* +b10001110 O* +b10001110 W* +b10001110 _* +b10001110 g* +b10001110 o* +b10001110 w* +b10001110 !+ +b10001110 )+ +b10001110 1+ +b10001110 9+ +b10001110 A+ +b10001110 I+ +b10001110 Q+ +b10001110 Y+ +b10001110 a+ +b10001110 i+ +b10001110 q+ +b10001110 y+ +b10001110 #, +b10001110 +, +b10001110 3, +b10001110 ;, +b10001110 C, +b10001110 K, +b00000000000000000000000010001110 S, +b00000000000000000000000010001110 [, +b00000000000000000000000010001110 c, +b10001110 k, +b10001110100011101000111010001110 s, +b10001110 {, +b10001110100011101000111010001110 %- +b10001110 -- +b10001110100011101000111010001110 5- +b10001110 =- +b10001110100011101000111010001110 E- +b10001110 M- +b10001110 N- +b10001110 O- +b10001110 P- +b10001110 Q- +b10001110 R- +b10001110 S- +b10001110 T- +b10001110 U- +b10001110 7. +b10001110 ?. +b10001110 G. +b10001110 O. +b10001110 W. +b10001110 _. +b10001110 g. +b10001110 o. +b10001110 w. +b10001110 !/ +b10001110 )/ +b10001110 1/ +b10001110 9/ +b10001110 A/ +b10001110 I/ +b10001110 Q/ +b10001110 Y/ +b10001110 a/ +b10001110 i/ +b10001110 q/ +b10001110 y/ +b10001110 #0 +b10001110 +0 +b10001110 30 +b10001110 ;0 +b10001110 C0 +1K0 +0S0 +0[0 +0c0 +1k0 +1s0 +1{0 +0%1 +0-1 +1.1 +1/1 +101 +011 +021 +031 +141 +0m1 +1n1 +1o1 +1p1 +0q1 +0r1 +0s1 +1t1 +0O2 +b00000000000000000000000000000000 W2 +0_2 +0g2 +0o2 +b00000000000000000000000000000011 w2 +b00000000000000000000000000001000 !3 +b00000000000000000000000000001001 )3 +b10001110 13 +b1000111001000111101000111101000111101000011101000011101000011101 93 +b11111111111111111111111111111101 I3 +b00000000000000000000000000000001 Q3 +b00000000 Y3 +b00000000 a3 +b00000000 i3 +b00000000 q3 +b00000000 y3 +b00000000 #4 +b00000000 +4 +b00000000 34 +b00000000 ;4 +b00000000 C4 +b00000000 K4 +b00000000 S4 +b00000000 [4 +b00000000 c4 +b00000000 k4 +b00000000 s4 +b00000000 {4 +b00000000 %5 +b00000000 -5 +b00000000 55 +b00000000 =5 +b00000000 E5 +b00000000 M5 +b00000000 U5 +b00000000000000000000000000000010 ]5 +b00000000000000000000000010001110 e5 +b000000000000000000000000 m5 +b11111111111111111111111111111110 u5 +b00000000000000000000000000000000 }5 +#10 +b001 s +b01000111 { +b01000111 %! +b01000111 -! +b01000111 5! +b01000111 =! +b01000111 E! +b01000111 M! +b01000111 U! +b01000111 ]! +b01000111 e! +b01000111 m! +b01000111 u! +b01000111 }! +b01000111 '" +b01000111 /" +b01000111 O" +b01000111 W" +b01000111 _" +b01000111 g" +b01000111 o" +b01000111 w" +b01000111 !# +b01000111 )# +b01000111 1# +b01000111 Q# +b01000111 Y# +b01000111 a# +b01000111 i# +b01000111 q# +b01000111 y# +b01000111 #$ +b01000111 +$ +b01000111 3$ +b01000111 S$ +b01000111 [$ +b01000111 c$ +b01000111 k$ +b01000111 s$ +b01000111 {$ +b01000111 %% +b01000111 -% +b01000111 5% +b01000111 U% +b01000111 ]% +b01000111 e% +b01000111 m% +b01000111 u% +b01000111 }% +b01000111 '& +b01000111 /& +b01000111 7& +b01000111 W& +b01000111 _& +b01000111 g& +b01000111 o& +b01000111 w& +b01000111 !' +b01000111 )' +b01000111 1' +b01000111 9' +b01000111 Y' +b01000111 a' +b01000111 i' +b01000111 q' +b01000111 y' +b01000111 #( +b01000111 +( +b01000111 3( +b01000111 ;( +b01000111 [( +b01000111 c( +b01000111 k( +b01000111 s( +b01000111 {( +b01000111 %) +b01000111 -) +b01000111 5) +b01000111 =) +b01000111 ]) +b01000111 e) +b01000111 m) +b01000111 u) +b01000111 }) +b01000111 '* +b01000111 /* +b01000111 7* +b01000111 ?* +b01000111 _* +b01000111 g* +b01000111 o* +b01000111 w* +b01000111 !+ +b01000111 )+ +b01000111 1+ +b01000111 9+ +b01000111 A+ +b01000111 a+ +b01000111 i+ +b01000111 q+ +b01000111 y+ +b01000111 #, +b01000111 +, +b01000111 3, +b01000111 ;, +b01000111 C, +b01000111 K, +b00000000000000000000000001000111 S, +b00000000000000000000000001000111 [, +b00000000000000000000000001000111 c, +b01000111 k, +b10001110010001110100011101000111 s, +b01000111 {, +b10001110010001110100011101000111 %- +b01000111 -- +b10001110010001110100011101000111 5- +b01000111 =- +b10001110010001110100011101000111 E- +b01000111 M- +b01000111 N- +b01000111 O- +b01000111 P- +b01000111 Q- +b01000111 R- +b01000111 S- +b01000111 T- +b01000111 U- +b01000111 7. +b01000111 ?. +b01000111 G. +b01000111 g. +b01000111 o. +b01000111 w. +b01000111 !/ +b01000111 )/ +b01000111 1/ +b01000111 9/ +b01000111 A/ +b01000111 a/ +b01000111 i/ +b01000111 q/ +b01000111 y/ +b01000111 #0 +b01000111 +0 +b01000111 30 +b01000111 ;0 +b01000111 C0 +0K0 +1S0 +0k0 +1%1 +1-1 +001 +131 +041 +1m1 +0p1 +1s1 +0t1 +b00000000000000000000000000001001 W2 +1g2 +1o2 +#15 +0o2 +#20 +b010 s +b10100011 { +b10001110 %! +b10100011 -! +b10100011 5! +b10100011 =! +b10100011 E! +b10100011 M! +b10001110 U! +b10100011 ]! +b10100011 e! +b10100011 m! +b10100011 u! +b10100011 }! +b10100011 '" +b10100011 /" +b10001110 O" +b10001110 W" +b10001110 _" +b10100011 g" +b10100011 o" +b10100011 w" +b10100011 !# +b10100011 )# +b10100011 1# +b10001110 Q# +b10001110 Y# +b10001110 a# +b10100011 i# +b10100011 q# +b10100011 y# +b10100011 #$ +b10100011 +$ +b10100011 3$ +b10001110 S$ +b10001110 [$ +b10001110 c$ +b10100011 k$ +b10100011 s$ +b10100011 {$ +b10100011 %% +b10100011 -% +b10100011 5% +b10001110 U% +b10001110 ]% +b10001110 e% +b10100011 m% +b10100011 u% +b10100011 }% +b10100011 '& +b10100011 /& +b10100011 7& +b10001110 W& +b10001110 _& +b10001110 g& +b10100011 o& +b10100011 w& +b10100011 !' +b10100011 )' +b10100011 1' +b10100011 9' +b10001110 Y' +b10001110 a' +b10001110 i' +b10100011 q' +b10100011 y' +b10100011 #( +b10100011 +( +b10100011 3( +b10100011 ;( +b10001110 [( +b10001110 c( +b10001110 k( +b10100011 s( +b10100011 {( +b10100011 %) +b10100011 -) +b10100011 5) +b10100011 =) +b10001110 ]) +b10001110 e) +b10001110 m) +b10100011 u) +b10100011 }) +b10100011 '* +b10100011 /* +b10100011 7* +b10100011 ?* +b10001110 _* +b10001110 g* +b10001110 o* +b10100011 w* +b10100011 !+ +b10100011 )+ +b10100011 1+ +b10100011 9+ +b10100011 A+ +b10001110 a+ +b10001110 i+ +b10001110 q+ +b10100011 y+ +b10100011 #, +b10100011 +, +b10100011 3, +b10100011 ;, +b10100011 C, +b10100011 K, +b00000000000000000000000010001110 S, +b00000000000000000000000010100011 [, +b00000000000000000000000010100011 c, +b10100011 k, +b10001110100011101010001110100011 s, +b10100011 {, +b10001110100011101010001110100011 %- +b10100011 -- +b10001110100011101010001110100011 5- +b10100011 =- +b10001110100011101010001110100011 E- +b10100011 M- +b10100011 N- +b10100011 O- +b10100011 P- +b10100011 Q- +b10100011 R- +b10100011 S- +b10100011 T- +b10100011 U- +b10100011 7. +b10100011 ?. +b10100011 G. +b10001110 g. +b10001110 o. +b10001110 w. +b10100011 !/ +b10100011 )/ +b10100011 1/ +b10100011 9/ +b10100011 A/ +b10001110 a/ +b10001110 i/ +b10001110 q/ +b10100011 y/ +b10100011 #0 +b10100011 +0 +b10100011 30 +b10100011 ;0 +b10100011 C0 +1K0 +0S0 +1[0 +0s0 +0/1 +121 +031 +141 +0o1 +1r1 +0s1 +1t1 +1o2 +#25 +0o2 +#30 +b011 s +b11010001 { +b01000111 %! +b11010001 -! +b11010001 5! +b11010001 =! +b11010001 E! +b11010001 M! +b01000111 U! +b11010001 ]! +b11010001 e! +b11010001 m! +b11010001 u! +b11010001 }! +b11010001 '" +b11010001 /" +b01000111 O" +b01000111 W" +b01000111 _" +b11010001 g" +b11010001 o" +b11010001 w" +b11010001 !# +b11010001 )# +b11010001 1# +b01000111 Q# +b01000111 Y# +b01000111 a# +b11010001 i# +b11010001 q# +b11010001 y# +b11010001 #$ +b11010001 +$ +b11010001 3$ +b01000111 S$ +b01000111 [$ +b01000111 c$ +b11010001 k$ +b11010001 s$ +b11010001 {$ +b11010001 %% +b11010001 -% +b11010001 5% +b01000111 U% +b01000111 ]% +b01000111 e% +b11010001 m% +b11010001 u% +b11010001 }% +b11010001 '& +b11010001 /& +b11010001 7& +b01000111 W& +b01000111 _& +b01000111 g& +b11010001 o& +b11010001 w& +b11010001 !' +b11010001 )' +b11010001 1' +b11010001 9' +b01000111 Y' +b01000111 a' +b01000111 i' +b11010001 q' +b11010001 y' +b11010001 #( +b11010001 +( +b11010001 3( +b11010001 ;( +b01000111 [( +b01000111 c( +b01000111 k( +b11010001 s( +b11010001 {( +b11010001 %) +b11010001 -) +b11010001 5) +b11010001 =) +b01000111 ]) +b01000111 e) +b01000111 m) +b11010001 u) +b11010001 }) +b11010001 '* +b11010001 /* +b11010001 7* +b11010001 ?* +b01000111 _* +b01000111 g* +b01000111 o* +b11010001 w* +b11010001 !+ +b11010001 )+ +b11010001 1+ +b11010001 9+ +b11010001 A+ +b01000111 a+ +b01000111 i+ +b01000111 q+ +b11010001 y+ +b11010001 #, +b11010001 +, +b11010001 3, +b11010001 ;, +b11010001 C, +b11010001 K, +b00000000000000000000000001000111 S, +b00000000000000000000000011010001 [, +b00000000000000000000000011010001 c, +b11010001 k, +b10001110010001111101000111010001 s, +b11010001 {, +b10001110010001111101000111010001 %- +b11010001 -- +b10001110010001111101000111010001 5- +b11010001 =- +b10001110010001111101000111010001 E- +b11010001 M- +b11010001 N- +b11010001 O- +b11010001 P- +b11010001 Q- +b11010001 R- +b11010001 S- +b11010001 T- +b11010001 U- +b11010001 7. +b11010001 ?. +b11010001 G. +b01000111 g. +b01000111 o. +b01000111 w. +b11010001 !/ +b11010001 )/ +b11010001 1/ +b11010001 9/ +b11010001 A/ +b01000111 a/ +b01000111 i/ +b01000111 q/ +b11010001 y/ +b11010001 #0 +b11010001 +0 +b11010001 30 +b11010001 ;0 +b11010001 C0 +1S0 +0[0 +1c0 +0{0 +0.1 +111 +021 +131 +0n1 +1q1 +0r1 +1s1 +1o2 +#35 +0o2 +#40 +b100 s +b11101000 { +b10001110 %! +b10001110 -! +b11101000 5! +b11101000 =! +b10001110 E! +b11101000 M! +b10001110 U! +b10001110 ]! +b10001110 e! +b10001110 m! +b10001110 u! +b11101000 }! +b11101000 '" +b11101000 /" +b10001110 O" +b10001110 W" +b10001110 _" +b10001110 g" +b10001110 o" +b10001110 w" +b11101000 !# +b11101000 )# +b11101000 1# +b10001110 Q# +b10001110 Y# +b10001110 a# +b10001110 i# +b10001110 q# +b10001110 y# +b11101000 #$ +b11101000 +$ +b11101000 3$ +b10001110 S$ +b10001110 [$ +b10001110 c$ +b10001110 k$ +b10001110 s$ +b10001110 {$ +b11101000 %% +b11101000 -% +b11101000 5% +b10001110 U% +b10001110 ]% +b10001110 e% +b10001110 m% +b10001110 u% +b10001110 }% +b11101000 '& +b11101000 /& +b11101000 7& +b10001110 W& +b10001110 _& +b10001110 g& +b10001110 o& +b10001110 w& +b10001110 !' +b11101000 )' +b11101000 1' +b11101000 9' +b10001110 Y' +b10001110 a' +b10001110 i' +b10001110 q' +b10001110 y' +b10001110 #( +b11101000 +( +b11101000 3( +b11101000 ;( +b10001110 [( +b10001110 c( +b10001110 k( +b10001110 s( +b10001110 {( +b10001110 %) +b11101000 -) +b11101000 5) +b11101000 =) +b10001110 ]) +b10001110 e) +b10001110 m) +b10001110 u) +b10001110 }) +b10001110 '* +b11101000 /* +b11101000 7* +b11101000 ?* +b10001110 _* +b10001110 g* +b10001110 o* +b10001110 w* +b10001110 !+ +b10001110 )+ +b11101000 1+ +b11101000 9+ +b11101000 A+ +b10001110 a+ +b10001110 i+ +b10001110 q+ +b10001110 y+ +b10001110 #, +b10001110 +, +b11101000 3, +b11101000 ;, +b11101000 C, +b11101000 K, +b00000000000000000000000010001110 S, +b00000000000000000000000010001110 [, +b00000000000000000000000011101000 c, +b11101000 k, +b10001110100011101000111011101000 s, +b11101000 {, +b10001110100011101000111011101000 %- +b11101000 -- +b10001110100011101000111011101000 5- +b11101000 =- +b10001110100011101000111011101000 E- +b11101000 M- +b11101000 N- +b11101000 O- +b11101000 P- +b11101000 Q- +b11101000 R- +b11101000 S- +b11101000 T- +b11101000 U- +b11101000 7. +b11101000 ?. +b11101000 G. +b10001110 g. +b10001110 o. +b10001110 w. +b10001110 !/ +b10001110 )/ +b10001110 1/ +b11101000 9/ +b11101000 A/ +b10001110 a/ +b10001110 i/ +b10001110 q/ +b10001110 y/ +b10001110 #0 +b10001110 +0 +b11101000 30 +b11101000 ;0 +b11101000 C0 +1[0 +0c0 +1k0 +0%1 +0-1 +101 +011 +121 +0m1 +1p1 +0q1 +1r1 +1o2 +#45 +0o2 +#50 +b101 s +b01110100 { +b01000111 %! +b01000111 -! +b01110100 5! +b01110100 =! +b01000111 E! +b01110100 M! +b01000111 U! +b01000111 ]! +b01000111 e! +b01000111 m! +b01000111 u! +b01110100 }! +b01110100 '" +b01110100 /" +b01000111 O" +b01000111 W" +b01000111 _" +b01000111 g" +b01000111 o" +b01000111 w" +b01110100 !# +b01110100 )# +b01110100 1# +b01000111 Q# +b01000111 Y# +b01000111 a# +b01000111 i# +b01000111 q# +b01000111 y# +b01110100 #$ +b01110100 +$ +b01110100 3$ +b01000111 S$ +b01000111 [$ +b01000111 c$ +b01000111 k$ +b01000111 s$ +b01000111 {$ +b01110100 %% +b01110100 -% +b01110100 5% +b01000111 U% +b01000111 ]% +b01000111 e% +b01000111 m% +b01000111 u% +b01000111 }% +b01110100 '& +b01110100 /& +b01110100 7& +b01000111 W& +b01000111 _& +b01000111 g& +b01000111 o& +b01000111 w& +b01000111 !' +b01110100 )' +b01110100 1' +b01110100 9' +b01000111 Y' +b01000111 a' +b01000111 i' +b01000111 q' +b01000111 y' +b01000111 #( +b01110100 +( +b01110100 3( +b01110100 ;( +b01000111 [( +b01000111 c( +b01000111 k( +b01000111 s( +b01000111 {( +b01000111 %) +b01110100 -) +b01110100 5) +b01110100 =) +b01000111 ]) +b01000111 e) +b01000111 m) +b01000111 u) +b01000111 }) +b01000111 '* +b01110100 /* +b01110100 7* +b01110100 ?* +b01000111 _* +b01000111 g* +b01000111 o* +b01000111 w* +b01000111 !+ +b01000111 )+ +b01110100 1+ +b01110100 9+ +b01110100 A+ +b01000111 a+ +b01000111 i+ +b01000111 q+ +b01000111 y+ +b01000111 #, +b01000111 +, +b01110100 3, +b01110100 ;, +b01110100 C, +b01110100 K, +b00000000000000000000000001000111 S, +b00000000000000000000000001000111 [, +b00000000000000000000000001110100 c, +b01110100 k, +b10001110010001110100011101110100 s, +b01110100 {, +b10001110010001110100011101110100 %- +b01110100 -- +b10001110010001110100011101110100 5- +b01110100 =- +b10001110010001110100011101110100 E- +b01110100 M- +b01110100 N- +b01110100 O- +b01110100 P- +b01110100 Q- +b01110100 R- +b01110100 S- +b01110100 T- +b01110100 U- +b01110100 7. +b01110100 ?. +b01110100 G. +b01000111 g. +b01000111 o. +b01000111 w. +b01000111 !/ +b01000111 )/ +b01000111 1/ +b01110100 9/ +b01110100 A/ +b01000111 a/ +b01000111 i/ +b01000111 q/ +b01000111 y/ +b01000111 #0 +b01000111 +0 +b01110100 30 +b01110100 ;0 +b01110100 C0 +0K0 +1c0 +0k0 +1s0 +1/1 +001 +111 +041 +1o1 +0p1 +1q1 +0t1 +1o2 +#55 +0o2 +#60 +b110 s +b00111010 { +b10001110 %! +b10100011 -! +b00111010 5! +b00111010 =! +b10100011 E! +b00111010 M! +b10001110 U! +b10100011 ]! +b10100011 e! +b10100011 m! +b10100011 u! +b00111010 }! +b00111010 '" +b00111010 /" +b10001110 O" +b10001110 W" +b10001110 _" +b10100011 g" +b10100011 o" +b10100011 w" +b00111010 !# +b00111010 )# +b00111010 1# +b10001110 Q# +b10001110 Y# +b10001110 a# +b10100011 i# +b10100011 q# +b10100011 y# +b00111010 #$ +b00111010 +$ +b00111010 3$ +b10001110 S$ +b10001110 [$ +b10001110 c$ +b10100011 k$ +b10100011 s$ +b10100011 {$ +b00111010 %% +b00111010 -% +b00111010 5% +b10001110 U% +b10001110 ]% +b10001110 e% +b10100011 m% +b10100011 u% +b10100011 }% +b00111010 '& +b00111010 /& +b00111010 7& +b10001110 W& +b10001110 _& +b10001110 g& +b10100011 o& +b10100011 w& +b10100011 !' +b00111010 )' +b00111010 1' +b00111010 9' +b10001110 Y' +b10001110 a' +b10001110 i' +b10100011 q' +b10100011 y' +b10100011 #( +b00111010 +( +b00111010 3( +b00111010 ;( +b10001110 [( +b10001110 c( +b10001110 k( +b10100011 s( +b10100011 {( +b10100011 %) +b00111010 -) +b00111010 5) +b00111010 =) +b10001110 ]) +b10001110 e) +b10001110 m) +b10100011 u) +b10100011 }) +b10100011 '* +b00111010 /* +b00111010 7* +b00111010 ?* +b10001110 _* +b10001110 g* +b10001110 o* +b10100011 w* +b10100011 !+ +b10100011 )+ +b00111010 1+ +b00111010 9+ +b00111010 A+ +b10001110 a+ +b10001110 i+ +b10001110 q+ +b10100011 y+ +b10100011 #, +b10100011 +, +b00111010 3, +b00111010 ;, +b00111010 C, +b00111010 K, +b00000000000000000000000010001110 S, +b00000000000000000000000010100011 [, +b00000000000000000000000000111010 c, +b00111010 k, +b10001110100011101010001100111010 s, +b00111010 {, +b10001110100011101010001100111010 %- +b00111010 -- +b10001110100011101010001100111010 5- +b00111010 =- +b10001110100011101010001100111010 E- +b00111010 M- +b00111010 N- +b00111010 O- +b00111010 P- +b00111010 Q- +b00111010 R- +b00111010 S- +b00111010 T- +b00111010 U- +b00111010 7. +b00111010 ?. +b00111010 G. +b10001110 g. +b10001110 o. +b10001110 w. +b10100011 !/ +b10100011 )/ +b10100011 1/ +b00111010 9/ +b00111010 A/ +b10001110 a/ +b10001110 i/ +b10001110 q/ +b10100011 y/ +b10100011 #0 +b10100011 +0 +b00111010 30 +b00111010 ;0 +b00111010 C0 +0S0 +1k0 +0s0 +1{0 +1.1 +0/1 +101 +031 +1n1 +0o1 +1p1 +0s1 +1o2 +#65 +0o2 +#70 +b111 s +b00011101 { +b01000111 %! +b11010001 -! +b00011101 5! +b00011101 =! +b11010001 E! +b00011101 M! +b01000111 U! +b11010001 ]! +b11010001 e! +b11010001 m! +b11010001 u! +b00011101 }! +b00011101 '" +b00011101 /" +b01000111 O" +b01000111 W" +b01000111 _" +b11010001 g" +b11010001 o" +b11010001 w" +b00011101 !# +b00011101 )# +b00011101 1# +b01000111 Q# +b01000111 Y# +b01000111 a# +b11010001 i# +b11010001 q# +b11010001 y# +b00011101 #$ +b00011101 +$ +b00011101 3$ +b01000111 S$ +b01000111 [$ +b01000111 c$ +b11010001 k$ +b11010001 s$ +b11010001 {$ +b00011101 %% +b00011101 -% +b00011101 5% +b01000111 U% +b01000111 ]% +b01000111 e% +b11010001 m% +b11010001 u% +b11010001 }% +b00011101 '& +b00011101 /& +b00011101 7& +b01000111 W& +b01000111 _& +b01000111 g& +b11010001 o& +b11010001 w& +b11010001 !' +b00011101 )' +b00011101 1' +b00011101 9' +b01000111 Y' +b01000111 a' +b01000111 i' +b11010001 q' +b11010001 y' +b11010001 #( +b00011101 +( +b00011101 3( +b00011101 ;( +b01000111 [( +b01000111 c( +b01000111 k( +b11010001 s( +b11010001 {( +b11010001 %) +b00011101 -) +b00011101 5) +b00011101 =) +b01000111 ]) +b01000111 e) +b01000111 m) +b11010001 u) +b11010001 }) +b11010001 '* +b00011101 /* +b00011101 7* +b00011101 ?* +b01000111 _* +b01000111 g* +b01000111 o* +b11010001 w* +b11010001 !+ +b11010001 )+ +b00011101 1+ +b00011101 9+ +b00011101 A+ +b01000111 a+ +b01000111 i+ +b01000111 q+ +b11010001 y+ +b11010001 #, +b11010001 +, +b00011101 3, +b00011101 ;, +b00011101 C, +b00011101 K, +b00000000000000000000000001000111 S, +b00000000000000000000000011010001 [, +b00000000000000000000000000011101 c, +b00011101 k, +b10001110010001111101000100011101 s, +b00011101 {, +b10001110010001111101000100011101 %- +b00011101 -- +b10001110010001111101000100011101 5- +b00011101 =- +b10001110010001111101000100011101 E- +b00011101 M- +b00011101 N- +b00011101 O- +b00011101 P- +b00011101 Q- +b00011101 R- +b00011101 S- +b00011101 T- +b00011101 U- +b00011101 7. +b00011101 ?. +b00011101 G. +b01000111 g. +b01000111 o. +b01000111 w. +b11010001 !/ +b11010001 )/ +b11010001 1/ +b00011101 9/ +b00011101 A/ +b01000111 a/ +b01000111 i/ +b01000111 q/ +b11010001 y/ +b11010001 #0 +b11010001 +0 +b00011101 30 +b00011101 ;0 +b00011101 C0 +0[0 +1s0 +0{0 +1%1 +1-1 +0.1 +1/1 +021 +1m1 +0n1 +1o1 +0r1 +1o2 +#75 +0o2 +#80 +b000 s +b10001110 { +b10001110 %! +b10001110 -! +b10001110 5! +b10001110 =! +b10001110 E! +b10001110 M! +b10001110 U! +b10001110 ]! +b10001110 e! +b10001110 m! +b10001110 u! +b10001110 }! +b10001110 '" +b10001110 /" +b10001110 O" +b10001110 W" +b10001110 _" +b10001110 g" +b10001110 o" +b10001110 w" +b10001110 !# +b10001110 )# +b10001110 1# +b10001110 Q# +b10001110 Y# +b10001110 a# +b10001110 i# +b10001110 q# +b10001110 y# +b10001110 #$ +b10001110 +$ +b10001110 3$ +b10001110 S$ +b10001110 [$ +b10001110 c$ +b10001110 k$ +b10001110 s$ +b10001110 {$ +b10001110 %% +b10001110 -% +b10001110 5% +b10001110 U% +b10001110 ]% +b10001110 e% +b10001110 m% +b10001110 u% +b10001110 }% +b10001110 '& +b10001110 /& +b10001110 7& +b10001110 W& +b10001110 _& +b10001110 g& +b10001110 o& +b10001110 w& +b10001110 !' +b10001110 )' +b10001110 1' +b10001110 9' +b10001110 Y' +b10001110 a' +b10001110 i' +b10001110 q' +b10001110 y' +b10001110 #( +b10001110 +( +b10001110 3( +b10001110 ;( +b10001110 [( +b10001110 c( +b10001110 k( +b10001110 s( +b10001110 {( +b10001110 %) +b10001110 -) +b10001110 5) +b10001110 =) +b10001110 ]) +b10001110 e) +b10001110 m) +b10001110 u) +b10001110 }) +b10001110 '* +b10001110 /* +b10001110 7* +b10001110 ?* +b10001110 _* +b10001110 g* +b10001110 o* +b10001110 w* +b10001110 !+ +b10001110 )+ +b10001110 1+ +b10001110 9+ +b10001110 A+ +b10001110 a+ +b10001110 i+ +b10001110 q+ +b10001110 y+ +b10001110 #, +b10001110 +, +b10001110 3, +b10001110 ;, +b10001110 C, +b10001110 K, +b00000000000000000000000010001110 S, +b00000000000000000000000010001110 [, +b00000000000000000000000010001110 c, +b10001110 k, +b10001110100011101000111010001110 s, +b10001110 {, +b10001110100011101000111010001110 %- +b10001110 -- +b10001110100011101000111010001110 5- +b10001110 =- +b10001110100011101000111010001110 E- +b10001110 M- +b10001110 N- +b10001110 O- +b10001110 P- +b10001110 Q- +b10001110 R- +b10001110 S- +b10001110 T- +b10001110 U- +b10001110 7. +b10001110 ?. +b10001110 G. +b10001110 g. +b10001110 o. +b10001110 w. +b10001110 !/ +b10001110 )/ +b10001110 1/ +b10001110 9/ +b10001110 A/ +b10001110 a/ +b10001110 i/ +b10001110 q/ +b10001110 y/ +b10001110 #0 +b10001110 +0 +b10001110 30 +b10001110 ;0 +b10001110 C0 +1K0 +0c0 +1{0 +0%1 +0-1 +1.1 +011 +141 +0m1 +1n1 +0q1 +1t1 +1o2 diff --git a/test_regress/t/t_split_var_2_trace.pl b/test_regress/t/t_split_var_2_trace.pl new file mode 100755 index 000000000..64a77d139 --- /dev/null +++ b/test_regress/t/t_split_var_2_trace.pl @@ -0,0 +1,29 @@ +#!/usr/bin/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. + +scenarios(simulator => 1); +top_filename("t/t_split_var_0.v"); + +# Travis environment offers 2 VCPUs, 2 thread setting causes the following warning. +# %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads. +# So use 6 threads here though it's not optimal in performace wise, but ok. +compile( + verilator_flags2 => ['--cc --trace --stats' . ($Self->{vltmt} ? ' --threads 6' : '')], + ); + +execute( + check_finished => 1, + ); + +vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); +file_grep($Self->{stats}, qr/SplitVar,\s+Split packed variables\s+(\d+)/i, 12); +file_grep($Self->{stats}, qr/SplitVar,\s+Split unpacked arrays\s+(\d+)/i, 23); + +ok(1); +1; diff --git a/test_regress/t/t_unoptflat_simple_2_bad.out b/test_regress/t/t_unoptflat_simple_2_bad.out index f926a30e1..ff0be7f54 100644 --- a/test_regress/t/t_unoptflat_simple_2_bad.out +++ b/test_regress/t/t_unoptflat_simple_2_bad.out @@ -5,8 +5,9 @@ t/t_unoptflat_simple_2.v:14: Example path: t.x t/t_unoptflat_simple_2.v:16: Example path: ASSIGNW t/t_unoptflat_simple_2.v:14: Example path: t.x -%Warning-UNOPTFLAT: Widest candidate vars to split: -%Warning-UNOPTFLAT: t/t_unoptflat_simple_2.v:14: t.x, width 3, fanout 10 -%Warning-UNOPTFLAT: Most fanned out candidate vars to split: -%Warning-UNOPTFLAT: t/t_unoptflat_simple_2.v:14: t.x, width 3, fanout 10 + ... Widest candidate vars to split: + t/t_unoptflat_simple_2.v:14: t.x, width 3, fanout 10, can split_var + ... Most fanned out candidate vars to split: + t/t_unoptflat_simple_2.v:14: t.x, width 3, fanout 10, can split_var + ... Suggest add /*verilator split_var*/ to appropriate variables above. %Error: Exiting due to From e98a380b44b83341ec1c799db75c7deea9a9751f Mon Sep 17 00:00:00 2001 From: David Stanford Date: Sat, 29 Feb 2020 06:20:23 -0600 Subject: [PATCH 23/50] Tests: Update some tests to skip if prerequisites aren't installed (#2181) --- docs/CONTRIBUTORS | 1 + docs/install.adoc | 4 +++- docs/internals.adoc | 4 ++++ test_regress/t/t_flag_make_cmake.pl | 20 ++++++++++++-------- test_regress/t/t_vgen.pl | 20 +++++++++++--------- 5 files changed, 31 insertions(+), 18 deletions(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 54f51f7ad..8c6c42276 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -38,3 +38,4 @@ Todd Strader Wilson Snyder Yutetsu TAKATSUKASA Yves Mathieu +David Stanford diff --git a/docs/install.adoc b/docs/install.adoc index d71f8d6e8..09a74c516 100644 --- a/docs/install.adoc +++ b/docs/install.adoc @@ -98,9 +98,11 @@ Additionally, to build or run Verilator you need these standard packages: Those developing Verilator may also want these (see internals.adoc): - sudo apt-get install gdb asciidoctor graphviz + sudo apt-get install gdb asciidoctor graphviz cmake cpan install Pod::Perldoc cpan install Unix::Processors + cpan install Parallel::Forker + cpan install Bit::Vector ==== Install SystemC diff --git a/docs/internals.adoc b/docs/internals.adoc index 94edaf247..55d5e407a 100644 --- a/docs/internals.adoc +++ b/docs/internals.adoc @@ -625,6 +625,10 @@ with e.g. "sudo cpan install Parallel::Forker". * vcddiff to find differences in VCD outputs. See the readme at https://github.com/veripool/vcddiff +* Cmake for build paths that use it. + +* Bit::Vector to test vgen.pl + === Controlling the Test Driver Test drivers are written in PERL. All invoke the main test driver script, diff --git a/test_regress/t/t_flag_make_cmake.pl b/test_regress/t/t_flag_make_cmake.pl index be0628665..37ec87826 100755 --- a/test_regress/t/t_flag_make_cmake.pl +++ b/test_regress/t/t_flag_make_cmake.pl @@ -7,6 +7,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Lesser General Public License Version 3 or the Perl Artistic License # Version 2.0. + scenarios(simulator => 1); compile( @@ -14,15 +15,18 @@ compile( verilator_make_cmake => 1, ); +system("cmake --version"); +if ($? != 0) { + skip("cmake is not installed"); +} else { + my $cmakecache = $Self->{obj_dir}."/CMakeCache.txt"; + if (! -e $cmakecache) { + error("$cmakecache does not exist.") + } -my $cmakecache = $Self->{obj_dir}."/CMakeCache.txt"; -if (! -e $cmakecache) { - error("$cmakecache does not exist") + execute( + check_finished => 1, + ); } - -execute( - check_finished => 1, - ); - ok(1); 1; diff --git a/test_regress/t/t_vgen.pl b/test_regress/t/t_vgen.pl index 6ebbec5f2..16b665aa1 100755 --- a/test_regress/t/t_vgen.pl +++ b/test_regress/t/t_vgen.pl @@ -9,21 +9,23 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (eval "use Bit::Vector; return 2;" != 2) { error("Please install Bit::Vector"); } +if (eval "use Bit::Vector; return 2;" != 2) { + skip("Vgen test requires Bit::Vector"); +} else { -top_filename("$Self->{obj_dir}/vgen.v"); + top_filename("$Self->{obj_dir}/vgen.v"); -run(cmd => ["./vgen.pl", - "-o $Self->{top_filename}", - #"--seed 0", - ]); + run(cmd => ["./vgen.pl", + "-o $Self->{top_filename}", + #"--seed 0", + ]); -compile( + compile( ); -execute( + execute( check_finished => 1, ); - +} ok(1); 1; From a7bd934fe3a703ac4c8a2f3268513296bad2dfbc Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 29 Feb 2020 08:56:49 -0500 Subject: [PATCH 24/50] Tests: Cleanup false used as 0. No functional change. --- test_regress/driver.pl | 2 +- test_regress/t/t_clk_2in.cpp | 2 +- test_regress/t/t_dpi_var.cpp | 2 +- test_regress/t/t_leak.cpp | 2 +- test_regress/t/t_vpi_get.cpp | 2 +- test_regress/t/t_vpi_memory.cpp | 2 +- test_regress/t/t_vpi_module.cpp | 2 +- test_regress/t/t_vpi_time_cb.cpp | 2 +- test_regress/t/t_vpi_unimpl.cpp | 4 ++-- test_regress/t/t_vpi_var.cpp | 10 +++++----- test_regress/t/t_vpi_zero_time_cb.cpp | 2 +- 11 files changed, 16 insertions(+), 16 deletions(-) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 6e10dd113..14053faa5 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -1724,7 +1724,7 @@ sub _make_main { } $fh->print("\n"); - print $fh " delete topp; topp=NULL;\n"; + print $fh " VL_DO_DANGLING(delete topp, topp);\n"; print $fh " exit(0L);\n"; print $fh "}\n"; $fh->close(); diff --git a/test_regress/t/t_clk_2in.cpp b/test_regress/t/t_clk_2in.cpp index 0630be1a1..60d9c866e 100644 --- a/test_regress/t/t_clk_2in.cpp +++ b/test_regress/t/t_clk_2in.cpp @@ -8,7 +8,7 @@ #include #include VM_PREFIX_INCLUDE -unsigned int main_time = false; +unsigned int main_time = 0; double sc_time_stamp() { return main_time; } diff --git a/test_regress/t/t_dpi_var.cpp b/test_regress/t/t_dpi_var.cpp index 1f4f8b0a0..146ddafe0 100644 --- a/test_regress/t/t_dpi_var.cpp +++ b/test_regress/t/t_dpi_var.cpp @@ -114,7 +114,7 @@ void mon_eval() { //====================================================================== -unsigned int main_time = false; +unsigned int main_time = 0; double sc_time_stamp() { return main_time; } int main(int argc, char** argv, char** env) { diff --git a/test_regress/t/t_leak.cpp b/test_regress/t/t_leak.cpp index 559a17ce8..83db456a1 100644 --- a/test_regress/t/t_leak.cpp +++ b/test_regress/t/t_leak.cpp @@ -12,7 +12,7 @@ #include #include "Vt_leak.h" -unsigned int main_time = false; +unsigned int main_time = 0; double sc_time_stamp() { return main_time; } long long get_memory_usage() { diff --git a/test_regress/t/t_vpi_get.cpp b/test_regress/t/t_vpi_get.cpp index e2ba788e8..0bed48be3 100644 --- a/test_regress/t/t_vpi_get.cpp +++ b/test_regress/t/t_vpi_get.cpp @@ -45,7 +45,7 @@ using namespace std; #define TEST_MSG \ if (0) printf -unsigned int main_time = false; +unsigned int main_time = 0; //====================================================================== diff --git a/test_regress/t/t_vpi_memory.cpp b/test_regress/t/t_vpi_memory.cpp index 2da149eb1..ef7829a1c 100644 --- a/test_regress/t/t_vpi_memory.cpp +++ b/test_regress/t/t_vpi_memory.cpp @@ -45,7 +45,7 @@ using namespace std; #define DEBUG \ if (0) printf -unsigned int main_time = false; +unsigned int main_time = 0; //====================================================================== diff --git a/test_regress/t/t_vpi_module.cpp b/test_regress/t/t_vpi_module.cpp index 81cfae35f..8b7322dcb 100644 --- a/test_regress/t/t_vpi_module.cpp +++ b/test_regress/t/t_vpi_module.cpp @@ -45,7 +45,7 @@ using namespace std; #define DEBUG \ if (0) printf -unsigned int main_time = false; +unsigned int main_time = 0; #define CHECK_RESULT_NZ(got) \ if (!(got)) { \ diff --git a/test_regress/t/t_vpi_time_cb.cpp b/test_regress/t/t_vpi_time_cb.cpp index 7a831de1f..00a4d8443 100644 --- a/test_regress/t/t_vpi_time_cb.cpp +++ b/test_regress/t/t_vpi_time_cb.cpp @@ -43,7 +43,7 @@ using namespace std; #define TEST_MSG \ if (0) printf -unsigned int main_time = false; +unsigned int main_time = 0; unsigned int callback_count_time1 = 3; unsigned int callback_count_time2 = 4; unsigned int callback_count_start_of_sim = 0; diff --git a/test_regress/t/t_vpi_unimpl.cpp b/test_regress/t/t_vpi_unimpl.cpp index 9e3f9621d..b8f82cdb4 100644 --- a/test_regress/t/t_vpi_unimpl.cpp +++ b/test_regress/t/t_vpi_unimpl.cpp @@ -32,8 +32,8 @@ #define DEBUG \ if (0) printf -unsigned int main_time = false; -unsigned int callback_count = false; +unsigned int main_time = 0; +unsigned int callback_count = 0; //====================================================================== diff --git a/test_regress/t/t_vpi_var.cpp b/test_regress/t/t_vpi_var.cpp index 9f170cb9d..26d5deb89 100644 --- a/test_regress/t/t_vpi_var.cpp +++ b/test_regress/t/t_vpi_var.cpp @@ -45,11 +45,11 @@ using namespace std; #define TEST_MSG \ if (0) printf -unsigned int main_time = false; -unsigned int callback_count = false; -unsigned int callback_count_half = false; -unsigned int callback_count_quad = false; -unsigned int callback_count_strs = false; +unsigned int main_time = 0; +unsigned int callback_count = 0; +unsigned int callback_count_half = 0; +unsigned int callback_count_quad = 0; +unsigned int callback_count_strs = 0; unsigned int callback_count_strs_max = 500; //====================================================================== diff --git a/test_regress/t/t_vpi_zero_time_cb.cpp b/test_regress/t/t_vpi_zero_time_cb.cpp index 5694db5a4..10164ec87 100644 --- a/test_regress/t/t_vpi_zero_time_cb.cpp +++ b/test_regress/t/t_vpi_zero_time_cb.cpp @@ -43,7 +43,7 @@ using namespace std; #define TEST_MSG \ if (0) printf -unsigned int main_time = false; +unsigned int main_time = 0; unsigned int callback_count_zero_time = 0; unsigned int callback_count_start_of_sim = 0; From 082c9e0b1d91c0a7966a54438093018e13a72585 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 29 Feb 2020 09:44:51 -0500 Subject: [PATCH 25/50] Tests: Add two-design trace tests. --- test_regress/driver.pl | 2 +- test_regress/t/t_mem_multi_io2.cpp | 2 +- test_regress/t/t_trace_ena.v | 24 +++--- test_regress/t/t_trace_two_a.v | 33 ++++++++ test_regress/t/t_trace_two_b.v | 28 +++++++ test_regress/t/t_trace_two_cc.cpp | 70 ++++++++++++++++ test_regress/t/t_trace_two_cc.out | 128 +++++++++++++++++++++++++++++ test_regress/t/t_trace_two_cc.pl | 39 +++++++++ test_regress/t/t_trace_two_sc.cpp | 74 +++++++++++++++++ test_regress/t/t_trace_two_sc.out | 126 ++++++++++++++++++++++++++++ test_regress/t/t_trace_two_sc.pl | 44 ++++++++++ 11 files changed, 556 insertions(+), 14 deletions(-) create mode 100644 test_regress/t/t_trace_two_a.v create mode 100644 test_regress/t/t_trace_two_b.v create mode 100644 test_regress/t/t_trace_two_cc.cpp create mode 100644 test_regress/t/t_trace_two_cc.out create mode 100755 test_regress/t/t_trace_two_cc.pl create mode 100644 test_regress/t/t_trace_two_sc.cpp create mode 100644 test_regress/t/t_trace_two_sc.out create mode 100755 test_regress/t/t_trace_two_sc.pl diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 14053faa5..1ffa65862 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -1742,7 +1742,7 @@ sub _print_advance_time { if ($self->sc) { print $fh "#if (SYSTEMC_VERSION>=20070314)\n"; - print $fh " sc_start(${time},SC_NS);\n"; + print $fh " sc_start(${time}, SC_NS);\n"; print $fh "#else\n"; print $fh " sc_start(${time});\n"; print $fh "#endif\n"; diff --git a/test_regress/t/t_mem_multi_io2.cpp b/test_regress/t/t_mem_multi_io2.cpp index 5ba03efce..ca53cd327 100644 --- a/test_regress/t/t_mem_multi_io2.cpp +++ b/test_regress/t/t_mem_multi_io2.cpp @@ -48,7 +48,7 @@ int main() // loop through every possibility and check the result #ifdef SYSTEMC_VERSION - sc_start(1,SC_NS); + sc_start(1, SC_NS); # define ASSIGN(s,v) s.write(v) # define READ(s) s.read() #else diff --git a/test_regress/t/t_trace_ena.v b/test_regress/t/t_trace_ena.v index b47e3d671..1792cf765 100644 --- a/test_regress/t/t_trace_ena.v +++ b/test_regress/t/t_trace_ena.v @@ -15,7 +15,7 @@ module t (/*AUTOARG*/ integer b_trace_off; // verilator tracing_on integer c_trace_on; - real r; + real r; // verilator tracing_off sub sub (); @@ -23,17 +23,17 @@ module t (/*AUTOARG*/ always @ (posedge clk) begin if (cyc!=0) begin - cyc <= cyc + 1; - b_trace_off <= cyc; - c_trace_on <= b_trace_off; - r <= r + 0.1; - if (cyc==4) begin - if (c_trace_on != 2) $stop; - end - if (cyc==10) begin - $write("*-* All Finished *-*\n"); - $finish; - end + cyc <= cyc + 1; + b_trace_off <= cyc; + c_trace_on <= b_trace_off; + r <= r + 0.1; + if (cyc==4) begin + if (c_trace_on != 2) $stop; + end + if (cyc==10) begin + $write("*-* All Finished *-*\n"); + $finish; + end end end diff --git a/test_regress/t/t_trace_two_a.v b/test_regress/t/t_trace_two_a.v new file mode 100644 index 000000000..bec36d849 --- /dev/null +++ b/test_regress/t/t_trace_two_a.v @@ -0,0 +1,33 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2005 by Wilson Snyder. + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + integer cyc; initial cyc=1; + integer c_trace_on; + + sub sub (); + + always @ (posedge clk) begin + if (cyc!=0) begin + cyc <= cyc + 1; + c_trace_on <= cyc + 2; + if (cyc==10) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + end + +endmodule + +module sub; + integer inside_sub_a = 1; +endmodule diff --git a/test_regress/t/t_trace_two_b.v b/test_regress/t/t_trace_two_b.v new file mode 100644 index 000000000..4b3a6f510 --- /dev/null +++ b/test_regress/t/t_trace_two_b.v @@ -0,0 +1,28 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2005 by Wilson Snyder. + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + integer cyc; initial cyc=1; + integer c_trace_on; + real r; + + sub sub (); + + always @ (posedge clk) begin + if (cyc!=0) begin + r <= r + 0.1; + end + end +endmodule + +module sub; + integer inside_sub_a = 2; +endmodule diff --git a/test_regress/t/t_trace_two_cc.cpp b/test_regress/t/t_trace_two_cc.cpp new file mode 100644 index 000000000..9b8bcf395 --- /dev/null +++ b/test_regress/t/t_trace_two_cc.cpp @@ -0,0 +1,70 @@ +// DESCRIPTION: Verilator: Verilog Test +// +// Copyright 2003-2020 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. + +#include "verilatedos.h" +#include VM_PREFIX_INCLUDE +#include "Vt_trace_two_b.h" +#include "verilated.h" +#include "verilated_vcd_c.h" + +// Compile in place +#include "Vt_trace_two_b.cpp" +#include "Vt_trace_two_b__Syms.cpp" +#include "Vt_trace_two_b__Trace.cpp" +#include "Vt_trace_two_b__Trace__Slow.cpp" + +VM_PREFIX* ap; +Vt_trace_two_b* bp; +vluint64_t main_time = 0; +double sc_time_stamp() { return main_time; } + +int main(int argc, char** argv, char** env) { + double sim_time = 1100; + Verilated::commandArgs(argc, argv); + Verilated::debug(0); + srand48(5); + ap = new VM_PREFIX("topa"); + bp = new Vt_trace_two_b("topb"); + ap->eval(); + bp->eval(); + +#if VM_TRACE + Verilated::traceEverOn(true); + VerilatedVcdC* tfp = new VerilatedVcdC; + ap->trace(tfp, 99); + bp->trace(tfp, 99); + tfp->open(VL_STRINGIFY(TEST_OBJ_DIR) "/simx.vcd"); + if (tfp) tfp->dump(main_time); +#endif + { + ap->clk = false; + ap->clk = false; + main_time += 10; + } + while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { + ap->clk = !ap->clk; + bp->clk = ap->clk; + ap->eval(); + bp->eval(); +#if VM_TRACE + if (tfp) tfp->dump(main_time); +#endif // VM_TRACE + main_time += 5; + } + if (!Verilated::gotFinish()) { + vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish"); + } + ap->final(); + bp->final(); +#if VM_TRACE + if (tfp) tfp->close(); +#endif // VM_TRACE + + VL_DO_DANGLING(delete ap, ap); + VL_DO_DANGLING(delete bp, bp); + exit(0L); +} diff --git a/test_regress/t/t_trace_two_cc.out b/test_regress/t/t_trace_two_cc.out new file mode 100644 index 000000000..7040fadaa --- /dev/null +++ b/test_regress/t/t_trace_two_cc.out @@ -0,0 +1,128 @@ +$version Generated by VerilatedVcd $end +$date Sat Feb 29 09:09:40 2020 + $end +$timescale 1ns $end + + $scope module topa $end + $var wire 1 3 clk $end + $scope module t $end + $var wire 32 + c_trace_on [31:0] $end + $var wire 1 3 clk $end + $var wire 32 # cyc [31:0] $end + $scope module sub $end + $var wire 32 ; inside_sub_a [31:0] $end + $upscope $end + $upscope $end + $upscope $end + $scope module topb $end + $var wire 1 N clk $end + $scope module t $end + $var wire 32 ^ c_trace_on [31:0] $end + $var wire 1 N clk $end + $var wire 32 V cyc [31:0] $end + $var real 64 > r $end + $scope module sub $end + $var wire 32 f inside_sub_a [31:0] $end + $upscope $end + $upscope $end + $upscope $end +$enddefinitions $end + + +#0 +b00000000000000000000000000000001 # +b00000000000000000000000000000000 + +03 +b00000000000000000000000000000001 ; +r0 > +0N +b00000000000000000000000000000001 V +b00000000000000000000000000000000 ^ +b00000000000000000000000000000010 f +#10 +b00000000000000000000000000000010 # +b00000000000000000000000000000011 + +13 +r0.1 > +1N +#15 +03 +0N +#20 +b00000000000000000000000000000011 # +b00000000000000000000000000000100 + +13 +r0.2 > +1N +#25 +03 +0N +#30 +b00000000000000000000000000000100 # +b00000000000000000000000000000101 + +13 +r0.3 > +1N +#35 +03 +0N +#40 +b00000000000000000000000000000101 # +b00000000000000000000000000000110 + +13 +r0.4 > +1N +#45 +03 +0N +#50 +b00000000000000000000000000000110 # +b00000000000000000000000000000111 + +13 +r0.5 > +1N +#55 +03 +0N +#60 +b00000000000000000000000000000111 # +b00000000000000000000000000001000 + +13 +r0.6 > +1N +#65 +03 +0N +#70 +b00000000000000000000000000001000 # +b00000000000000000000000000001001 + +13 +r0.7 > +1N +#75 +03 +0N +#80 +b00000000000000000000000000001001 # +b00000000000000000000000000001010 + +13 +r0.7999999999999999 > +1N +#85 +03 +0N +#90 +b00000000000000000000000000001010 # +b00000000000000000000000000001011 + +13 +r0.8999999999999999 > +1N +#95 +03 +0N +#100 +b00000000000000000000000000001011 # +b00000000000000000000000000001100 + +13 +r0.9999999999999999 > +1N diff --git a/test_regress/t/t_trace_two_cc.pl b/test_regress/t/t_trace_two_cc.pl new file mode 100755 index 000000000..dc16b71ed --- /dev/null +++ b/test_regress/t/t_trace_two_cc.pl @@ -0,0 +1,39 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2020 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. + +# Test tracing with two models instanced +scenarios(vlt_all => 1); + +top_filename("t_trace_two_a.v"); + +compile( + make_main => 0, + verilator_make_gmake => 0, + top_filename => 't_trace_two_b.v', + VM_PREFIX => 'Vt_trace_two_b', + verilator_flags2 => ['-trace'], + ); + +compile( + make_main => 0, + top_filename => 't_trace_two_a.v', + verilator_flags2 => ['-exe', '-trace', "$Self->{t_dir}/t_trace_two_cc.cpp"], + ); + +execute( + check_finished => 1, + ); + +if ($Self->{vlt_all}) { + file_grep ("$Self->{obj_dir}/simx.vcd", qr/\$enddefinitions/x); + vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); +} + +ok(1); +1; diff --git a/test_regress/t/t_trace_two_sc.cpp b/test_regress/t/t_trace_two_sc.cpp new file mode 100644 index 000000000..dce33a0e1 --- /dev/null +++ b/test_regress/t/t_trace_two_sc.cpp @@ -0,0 +1,74 @@ +// DESCRIPTION: Verilator: Verilog Test +// +// Copyright 2003-2020 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. + +#include "verilatedos.h" +#include VM_PREFIX_INCLUDE +#include "Vt_trace_two_b.h" +#include "verilated.h" +#include "verilated_vcd_c.h" + +// Compile in place +#include "Vt_trace_two_b.cpp" +#include "Vt_trace_two_b__Syms.cpp" +#include "Vt_trace_two_b__Trace.cpp" +#include "Vt_trace_two_b__Trace__Slow.cpp" + +// General headers +#include "verilated.h" +#include "systemc.h" +#include "verilated_vcd_sc.h" + +VM_PREFIX* ap; +Vt_trace_two_b* bp; + +int sc_main(int argc, char** argv) { + sc_signal clk; + sc_time sim_time(1100, SC_NS); + Verilated::commandArgs(argc, argv); + Verilated::debug(0); + srand48(5); + ap = new VM_PREFIX("topa"); + bp = new Vt_trace_two_b("topb"); + ap->clk(clk); + bp->clk(clk); + +#if VM_TRACE + Verilated::traceEverOn(true); + VerilatedVcdSc* tfp = new VerilatedVcdSc; + ap->trace(tfp, 99); + bp->trace(tfp, 99); + tfp->open(VL_STRINGIFY(TEST_OBJ_DIR) "/simx.vcd"); +#endif + { + clk = false; +#if (SYSTEMC_VERSION>=20070314) + sc_start(10, SC_NS); +#else + sc_start(10); +#endif + } + while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { + clk = !clk; +#if (SYSTEMC_VERSION>=20070314) + sc_start(5, SC_NS); +#else + sc_start(5); +#endif + } + if (!Verilated::gotFinish()) { + vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish"); + } + ap->final(); + bp->final(); +#if VM_TRACE + if (tfp) tfp->close(); +#endif // VM_TRACE + + VL_DO_DANGLING(delete ap, ap); + VL_DO_DANGLING(delete bp, bp); + exit(0L); +} diff --git a/test_regress/t/t_trace_two_sc.out b/test_regress/t/t_trace_two_sc.out new file mode 100644 index 000000000..8f680510d --- /dev/null +++ b/test_regress/t/t_trace_two_sc.out @@ -0,0 +1,126 @@ +$version Generated by VerilatedVcd $end +$date Sat Feb 29 09:18:19 2020 + $end +$timescale 1ps $end + + $scope module topa $end + $scope module t $end + $var wire 32 3 c_trace_on [31:0] $end + $var wire 1 # clk $end + $var wire 32 + cyc [31:0] $end + $scope module sub $end + $var wire 32 ; inside_sub_a [31:0] $end + $upscope $end + $upscope $end + $upscope $end + $scope module topb $end + $scope module t $end + $var wire 32 ^ c_trace_on [31:0] $end + $var wire 1 > clk $end + $var wire 32 V cyc [31:0] $end + $var real 64 F r $end + $scope module sub $end + $var wire 32 f inside_sub_a [31:0] $end + $upscope $end + $upscope $end + $upscope $end +$enddefinitions $end + + +#0 +0# +b00000000000000000000000000000001 + +b00000000000000000000000000000000 3 +b00000000000000000000000000000001 ; +0> +r0 F +b00000000000000000000000000000001 V +b00000000000000000000000000000000 ^ +b00000000000000000000000000000010 f +#10000 +1# +b00000000000000000000000000000010 + +b00000000000000000000000000000011 3 +1> +r0.1 F +#15000 +0# +0> +#20000 +1# +b00000000000000000000000000000011 + +b00000000000000000000000000000100 3 +1> +r0.2 F +#25000 +0# +0> +#30000 +1# +b00000000000000000000000000000100 + +b00000000000000000000000000000101 3 +1> +r0.3 F +#35000 +0# +0> +#40000 +1# +b00000000000000000000000000000101 + +b00000000000000000000000000000110 3 +1> +r0.4 F +#45000 +0# +0> +#50000 +1# +b00000000000000000000000000000110 + +b00000000000000000000000000000111 3 +1> +r0.5 F +#55000 +0# +0> +#60000 +1# +b00000000000000000000000000000111 + +b00000000000000000000000000001000 3 +1> +r0.6 F +#65000 +0# +0> +#70000 +1# +b00000000000000000000000000001000 + +b00000000000000000000000000001001 3 +1> +r0.7 F +#75000 +0# +0> +#80000 +1# +b00000000000000000000000000001001 + +b00000000000000000000000000001010 3 +1> +r0.7999999999999999 F +#85000 +0# +0> +#90000 +1# +b00000000000000000000000000001010 + +b00000000000000000000000000001011 3 +1> +r0.8999999999999999 F +#95000 +0# +0> +#100000 +1# +b00000000000000000000000000001011 + +b00000000000000000000000000001100 3 +1> +r0.9999999999999999 F diff --git a/test_regress/t/t_trace_two_sc.pl b/test_regress/t/t_trace_two_sc.pl new file mode 100755 index 000000000..44e143b43 --- /dev/null +++ b/test_regress/t/t_trace_two_sc.pl @@ -0,0 +1,44 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2020 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. + +scenarios(simulator => 1); + +if (!$Self->have_sc) { + skip("No SystemC installed"); +} +else { + top_filename("t_trace_two_a.v"); + + compile( + make_main => 0, + verilator_make_gmake => 0, + top_filename => 't_trace_two_b.v', + VM_PREFIX => 'Vt_trace_two_b', + verilator_flags2 => ['-sc -trace'], + ); + + compile( + make_main => 0, + top_filename => 't_trace_two_a.v', + verilator_flags2 => ['-sc', '-exe', '-trace', + "$Self->{t_dir}/t_trace_two_sc.cpp"], + ); + + execute( + check_finished => 1, + ); + + if ($Self->{vlt_all}) { + file_grep ("$Self->{obj_dir}/simx.vcd", qr/\$enddefinitions/x); + vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); + } +} + +ok(1); +1; From aac02acf928c7f572a5797a7b3c5b216394b2d39 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 29 Feb 2020 10:06:52 -0500 Subject: [PATCH 26/50] Tests: Rename --- test_regress/t/t_trace_two_a.v | 6 +++--- test_regress/t/t_trace_two_b.v | 4 ++-- .../t/{t_trace_two_cc.cpp => t_trace_two_hdr_cc.cpp} | 0 .../t/{t_trace_two_cc.out => t_trace_two_hdr_cc.out} | 0 test_regress/t/{t_trace_two_cc.pl => t_trace_two_hdr_cc.pl} | 4 ++-- .../t/{t_trace_two_sc.cpp => t_trace_two_hdr_sc.cpp} | 0 .../t/{t_trace_two_sc.out => t_trace_two_hdr_sc.out} | 0 test_regress/t/{t_trace_two_sc.pl => t_trace_two_hdr_sc.pl} | 4 ++-- 8 files changed, 9 insertions(+), 9 deletions(-) rename test_regress/t/{t_trace_two_cc.cpp => t_trace_two_hdr_cc.cpp} (100%) rename test_regress/t/{t_trace_two_cc.out => t_trace_two_hdr_cc.out} (100%) rename test_regress/t/{t_trace_two_cc.pl => t_trace_two_hdr_cc.pl} (91%) rename test_regress/t/{t_trace_two_sc.cpp => t_trace_two_hdr_sc.cpp} (100%) rename test_regress/t/{t_trace_two_sc.out => t_trace_two_hdr_sc.out} (100%) rename test_regress/t/{t_trace_two_sc.pl => t_trace_two_hdr_sc.pl} (88%) diff --git a/test_regress/t/t_trace_two_a.v b/test_regress/t/t_trace_two_a.v index bec36d849..da58afecc 100644 --- a/test_regress/t/t_trace_two_a.v +++ b/test_regress/t/t_trace_two_a.v @@ -1,7 +1,7 @@ // DESCRIPTION: Verilator: Verilog Test module // // This file ONLY is placed into the Public Domain, for any use, -// without warranty, 2005 by Wilson Snyder. +// without warranty, 2020 by Wilson Snyder. module t (/*AUTOARG*/ // Inputs @@ -16,10 +16,10 @@ module t (/*AUTOARG*/ sub sub (); always @ (posedge clk) begin - if (cyc!=0) begin + if (cyc != 0) begin cyc <= cyc + 1; c_trace_on <= cyc + 2; - if (cyc==10) begin + if (cyc == 10) begin $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_trace_two_b.v b/test_regress/t/t_trace_two_b.v index 4b3a6f510..047e7a15f 100644 --- a/test_regress/t/t_trace_two_b.v +++ b/test_regress/t/t_trace_two_b.v @@ -1,7 +1,7 @@ // DESCRIPTION: Verilator: Verilog Test module // // This file ONLY is placed into the Public Domain, for any use, -// without warranty, 2005 by Wilson Snyder. +// without warranty, 2020 by Wilson Snyder. module t (/*AUTOARG*/ // Inputs @@ -17,7 +17,7 @@ module t (/*AUTOARG*/ sub sub (); always @ (posedge clk) begin - if (cyc!=0) begin + if (cyc != 0) begin r <= r + 0.1; end end diff --git a/test_regress/t/t_trace_two_cc.cpp b/test_regress/t/t_trace_two_hdr_cc.cpp similarity index 100% rename from test_regress/t/t_trace_two_cc.cpp rename to test_regress/t/t_trace_two_hdr_cc.cpp diff --git a/test_regress/t/t_trace_two_cc.out b/test_regress/t/t_trace_two_hdr_cc.out similarity index 100% rename from test_regress/t/t_trace_two_cc.out rename to test_regress/t/t_trace_two_hdr_cc.out diff --git a/test_regress/t/t_trace_two_cc.pl b/test_regress/t/t_trace_two_hdr_cc.pl similarity index 91% rename from test_regress/t/t_trace_two_cc.pl rename to test_regress/t/t_trace_two_hdr_cc.pl index dc16b71ed..3601322e4 100755 --- a/test_regress/t/t_trace_two_cc.pl +++ b/test_regress/t/t_trace_two_hdr_cc.pl @@ -23,7 +23,7 @@ compile( compile( make_main => 0, top_filename => 't_trace_two_a.v', - verilator_flags2 => ['-exe', '-trace', "$Self->{t_dir}/t_trace_two_cc.cpp"], + verilator_flags2 => ['-exe', '-trace', "$Self->{t_dir}/t_trace_two_hdr_cc.cpp"], ); execute( @@ -31,7 +31,7 @@ execute( ); if ($Self->{vlt_all}) { - file_grep ("$Self->{obj_dir}/simx.vcd", qr/\$enddefinitions/x); + file_grep("$Self->{obj_dir}/simx.vcd", qr/\$enddefinitions/x); vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); } diff --git a/test_regress/t/t_trace_two_sc.cpp b/test_regress/t/t_trace_two_hdr_sc.cpp similarity index 100% rename from test_regress/t/t_trace_two_sc.cpp rename to test_regress/t/t_trace_two_hdr_sc.cpp diff --git a/test_regress/t/t_trace_two_sc.out b/test_regress/t/t_trace_two_hdr_sc.out similarity index 100% rename from test_regress/t/t_trace_two_sc.out rename to test_regress/t/t_trace_two_hdr_sc.out diff --git a/test_regress/t/t_trace_two_sc.pl b/test_regress/t/t_trace_two_hdr_sc.pl similarity index 88% rename from test_regress/t/t_trace_two_sc.pl rename to test_regress/t/t_trace_two_hdr_sc.pl index 44e143b43..3c8de5b0b 100755 --- a/test_regress/t/t_trace_two_sc.pl +++ b/test_regress/t/t_trace_two_hdr_sc.pl @@ -27,7 +27,7 @@ else { make_main => 0, top_filename => 't_trace_two_a.v', verilator_flags2 => ['-sc', '-exe', '-trace', - "$Self->{t_dir}/t_trace_two_sc.cpp"], + "$Self->{t_dir}/t_trace_two_hdr_sc.cpp"], ); execute( @@ -35,7 +35,7 @@ else { ); if ($Self->{vlt_all}) { - file_grep ("$Self->{obj_dir}/simx.vcd", qr/\$enddefinitions/x); + file_grep("$Self->{obj_dir}/simx.vcd", qr/\$enddefinitions/x); vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); } } From 0ca0e073543c90ec925f1f76e4404911b6a65079 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 29 Feb 2020 20:41:13 -0500 Subject: [PATCH 27/50] Internals: Vcd doesn't need code when registering. No functional change intended. --- include/verilated_fst_c.h | 8 ++--- include/verilated_vcd_c.cpp | 49 +++++++++++++++-------------- test_regress/t/t_flag_make_cmake.pl | 6 ++-- 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index eda522554..5fc4aeaff 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -167,10 +167,10 @@ public: void fullArray(vluint32_t code, const vluint32_t* newval, int bits) { chgArray(code, newval, bits); } - void declTriBit (vluint32_t code, const char* name, int arraynum); - void declTriBus (vluint32_t code, const char* name, int arraynum, int msb, int lsb); - void declTriQuad (vluint32_t code, const char* name, int arraynum, int msb, int lsb); - void declTriArray (vluint32_t code, const char* name, int arraynum, int msb, int lsb); + void declTriBit(vluint32_t code, const char* name, int arraynum); + void declTriBus(vluint32_t code, const char* name, int arraynum, int msb, int lsb); + void declTriQuad(vluint32_t code, const char* name, int arraynum, int msb, int lsb); + void declTriArray(vluint32_t code, const char* name, int arraynum, int msb, int lsb); void fullTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri); void fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits); void fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits); diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index 42b930f05..87c4e8baa 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -57,8 +57,8 @@ class VerilatedVcdSingleton { private: typedef std::vector VcdVec; struct Singleton { - VerilatedMutex s_vcdMutex; ///< Protect the singleton - VcdVec s_vcdVecp VL_GUARDED_BY(s_vcdMutex); ///< List of all created traces + VerilatedMutex s_vcdMutex; ///< Protect the singleton + VcdVec s_vcdVecp VL_GUARDED_BY(s_vcdMutex); ///< List of all created traces }; static Singleton& singleton() { static Singleton s; return s; } public: @@ -96,16 +96,19 @@ public: class VerilatedVcdCallInfo { protected: friend class VerilatedVcd; - VerilatedVcdCallback_t m_initcb; ///< Initialization Callback function - VerilatedVcdCallback_t m_fullcb; ///< Full Dumping Callback function - VerilatedVcdCallback_t m_changecb; ///< Incremental Dumping Callback function - void* m_userthis; ///< Fake "this" for caller - vluint32_t m_code; ///< Starting code number + VerilatedVcdCallback_t m_initcb; ///< Initialization Callback function + VerilatedVcdCallback_t m_fullcb; ///< Full Dumping Callback function + VerilatedVcdCallback_t m_changecb; ///< Incremental Dumping Callback function + void* m_userthis; ///< Fake "this" for caller + vluint32_t m_code; ///< Starting code number (set later by traceInit) // CONSTRUCTORS VerilatedVcdCallInfo(VerilatedVcdCallback_t icb, VerilatedVcdCallback_t fcb, - VerilatedVcdCallback_t changecb, - void* ut, vluint32_t code) - : m_initcb(icb), m_fullcb(fcb), m_changecb(changecb), m_userthis(ut), m_code(code) {} + VerilatedVcdCallback_t changecb, void* ut) + : m_initcb(icb) + , m_fullcb(fcb) + , m_changecb(changecb) + , m_userthis(ut) + , m_code(1) {} ~VerilatedVcdCallInfo() {} }; @@ -230,7 +233,7 @@ void VerilatedVcd::makeNameMap() { deleteNameMap(); m_nextCode = 1; m_namemapp = new NameMap; - for (vluint32_t ent = 0; ent< m_callbacks.size(); ent++) { + for (vluint32_t ent = 0; ent < m_callbacks.size(); ent++) { VerilatedVcdCallInfo* cip = m_callbacks[ent]; cip->m_code = m_nextCode; (cip->m_initcb)(this, cip->m_userthis, cip->m_code); @@ -513,7 +516,7 @@ void VerilatedVcd::dumpHeader() { printIndent(-1); printStr("$enddefinitions $end\n\n\n"); - assert(m_modDepth==0); + assert(m_modDepth == 0); // Reclaim storage deleteNameMap(); @@ -658,19 +661,16 @@ void VerilatedVcd::fullFloat(vluint32_t code, const float newval) { //============================================================================= // Callbacks -void VerilatedVcd::addCallback( - VerilatedVcdCallback_t initcb, VerilatedVcdCallback_t fullcb, VerilatedVcdCallback_t changecb, - void* userthis) VL_MT_UNSAFE_ONE -{ +void VerilatedVcd::addCallback(VerilatedVcdCallback_t initcb, VerilatedVcdCallback_t fullcb, + VerilatedVcdCallback_t changecb, void* userthis) VL_MT_UNSAFE_ONE { m_assertOne.check(); if (VL_UNLIKELY(isOpen())) { - std::string msg = std::string("Internal: ")+__FILE__+"::"+__FUNCTION__ - +" called with already open file"; + std::string msg = std::string("Internal: ") + __FILE__ + "::" + __FUNCTION__ + + " called with already open file"; VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str()); } - VerilatedVcdCallInfo* vci - = new VerilatedVcdCallInfo(initcb, fullcb, changecb, userthis, m_nextCode); - m_callbacks.push_back(vci); + VerilatedVcdCallInfo* cip = new VerilatedVcdCallInfo(initcb, fullcb, changecb, userthis); + m_callbacks.push_back(cip); } //============================================================================= @@ -680,7 +680,7 @@ void VerilatedVcd::dumpFull(vluint64_t timeui) { m_assertOne.check(); dumpPrep(timeui); Verilated::quiesce(); - for (vluint32_t ent = 0; ent< m_callbacks.size(); ent++) { + for (vluint32_t ent = 0; ent < m_callbacks.size(); ent++) { VerilatedVcdCallInfo* cip = m_callbacks[ent]; (cip->m_fullcb)(this, cip->m_userthis, cip->m_code); } @@ -700,7 +700,7 @@ void VerilatedVcd::dump(vluint64_t timeui) { } dumpPrep(timeui); Verilated::quiesce(); - for (vluint32_t ent = 0; ent< m_callbacks.size(); ++ent) { + for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) { VerilatedVcdCallInfo* cip = m_callbacks[ent]; (cip->m_changecb)(this, cip->m_userthis, cip->m_code); } @@ -829,6 +829,7 @@ main() { #endif //******************************************************************** +// ;compile-command: "mkdir -p ../test_dir && cd ../test_dir && c++ -DVERILATED_VCD_TEST ../include/verilated_vcd_c.cpp -o verilated_vcd_c && ./verilated_vcd_c && cat test.vcd" +// // Local Variables: -// compile-command: "mkdir -p ../test_dir && cd ../test_dir && c++ -DVERILATED_VCD_TEST ../include/verilated_vcd_c.cpp -o verilated_vcd_c && ./verilated_vcd_c && cat test.vcd" // End: diff --git a/test_regress/t/t_flag_make_cmake.pl b/test_regress/t/t_flag_make_cmake.pl index 37ec87826..2acfd49b2 100755 --- a/test_regress/t/t_flag_make_cmake.pl +++ b/test_regress/t/t_flag_make_cmake.pl @@ -21,12 +21,12 @@ if ($? != 0) { } else { my $cmakecache = $Self->{obj_dir}."/CMakeCache.txt"; if (! -e $cmakecache) { - error("$cmakecache does not exist.") + error("$cmakecache does not exist.") } execute( - check_finished => 1, - ); + check_finished => 1, + ); } ok(1); 1; From 30a33a6104cd559629fa5cc54d1c0690d2615f20 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 1 Mar 2020 21:39:23 -0500 Subject: [PATCH 28/50] Add support for and , #2126. --- Changes | 2 + bin/verilator | 81 ++++++---- examples/make_tracing_c/sim_main.cpp | 39 ++--- examples/make_tracing_c/top.v | 5 + examples/make_tracing_sc/sc_main.cpp | 3 + include/verilated.cpp | 19 +++ include/verilated.h | 1 + include/verilated_fst_c.cpp | 24 +-- include/verilated_fst_c.h | 2 +- include/verilated_heavy.h | 6 + include/verilated_vcd_c.cpp | 11 +- include/verilated_vcd_c.h | 6 +- include/verilated_vcd_sc.h | 2 +- src/V3Ast.h | 26 ++++ src/V3AstNodes.h | 25 ++++ src/V3EmitC.cpp | 140 ++++++++++++++++-- src/V3EmitCInlines.cpp | 5 + src/V3EmitCMake.cpp | 4 +- src/V3EmitCSyms.cpp | 14 +- src/V3EmitMk.cpp | 4 +- src/V3Global.h | 24 +-- src/V3Options.h | 6 +- src/V3Width.cpp | 5 + src/verilog.l | 15 +- src/verilog.y | 32 +++- test_regress/t/t_leak.cpp | 6 +- test_regress/t/t_trace_dumporder_bad.out | 2 + test_regress/t/t_trace_dumporder_bad.pl | 22 +++ test_regress/t/t_trace_dumporder_bad.v | 13 ++ test_regress/t/t_trace_flag_off.out | 2 + test_regress/t/t_trace_flag_off.pl | 22 +++ test_regress/t/t_trace_flag_off.v | 13 ++ test_regress/t/t_trace_two_a.v | 49 +++++- ...race_two_hdr_cc.cpp => t_trace_two_cc.cpp} | 38 +++-- test_regress/t/t_trace_two_dump_cc.out | 102 +++++++++++++ test_regress/t/t_trace_two_dump_cc.pl | 40 +++++ test_regress/t/t_trace_two_dump_sc.out | 81 ++++++++++ test_regress/t/t_trace_two_dump_sc.pl | 45 ++++++ test_regress/t/t_trace_two_dumpfst_cc.out | 83 +++++++++++ test_regress/t/t_trace_two_dumpfst_cc.pl | 42 ++++++ test_regress/t/t_trace_two_hdr_cc.pl | 3 +- test_regress/t/t_trace_two_hdr_sc.pl | 3 +- test_regress/t/t_trace_two_hdrfst_cc.out | Bin 0 -> 2097 bytes test_regress/t/t_trace_two_hdrfst_cc.pl | 42 ++++++ test_regress/t/t_trace_two_port_cc.out | 102 +++++++++++++ test_regress/t/t_trace_two_port_cc.pl | 40 +++++ test_regress/t/t_trace_two_port_sc.out | 81 ++++++++++ test_regress/t/t_trace_two_port_sc.pl | 45 ++++++ test_regress/t/t_trace_two_portfst_cc.out | 83 +++++++++++ test_regress/t/t_trace_two_portfst_cc.pl | 42 ++++++ ...race_two_hdr_sc.cpp => t_trace_two_sc.cpp} | 13 +- 51 files changed, 1378 insertions(+), 137 deletions(-) create mode 100644 test_regress/t/t_trace_dumporder_bad.out create mode 100755 test_regress/t/t_trace_dumporder_bad.pl create mode 100644 test_regress/t/t_trace_dumporder_bad.v create mode 100644 test_regress/t/t_trace_flag_off.out create mode 100755 test_regress/t/t_trace_flag_off.pl create mode 100644 test_regress/t/t_trace_flag_off.v rename test_regress/t/{t_trace_two_hdr_cc.cpp => t_trace_two_cc.cpp} (72%) create mode 100644 test_regress/t/t_trace_two_dump_cc.out create mode 100755 test_regress/t/t_trace_two_dump_cc.pl create mode 100644 test_regress/t/t_trace_two_dump_sc.out create mode 100755 test_regress/t/t_trace_two_dump_sc.pl create mode 100755 test_regress/t/t_trace_two_dumpfst_cc.out create mode 100755 test_regress/t/t_trace_two_dumpfst_cc.pl create mode 100755 test_regress/t/t_trace_two_hdrfst_cc.out create mode 100755 test_regress/t/t_trace_two_hdrfst_cc.pl create mode 100644 test_regress/t/t_trace_two_port_cc.out create mode 100755 test_regress/t/t_trace_two_port_cc.pl create mode 100644 test_regress/t/t_trace_two_port_sc.out create mode 100755 test_regress/t/t_trace_two_port_sc.pl create mode 100755 test_regress/t/t_trace_two_portfst_cc.out create mode 100755 test_regress/t/t_trace_two_portfst_cc.pl rename test_regress/t/{t_trace_two_hdr_sc.cpp => t_trace_two_sc.cpp} (93%) diff --git a/Changes b/Changes index 558f81a11..b949dba1e 100644 --- a/Changes +++ b/Changes @@ -7,6 +7,8 @@ The contributors that suggested a given feature are shown in []. Thanks! ** Add split_var metacomment to assist UNOPTFLAT fixes, #2066. [Yutetsu TAKATSUKASA] +** Add support for $dumpfile and $dumpvars, #2126. [Alexander Grobman] + *** Add +verilator+noassert flag to disable assertion checking. [Tobias Wölfel] *** Add check for assertOn for asserts, #2162. [Tobias Wölfel] diff --git a/bin/verilator b/bin/verilator index a50add371..1714ed230 100755 --- a/bin/verilator +++ b/bin/verilator @@ -3782,17 +3782,29 @@ $unsigned, $warning. Generally supported. -=item $display, $write, $fdisplay, $fwrite, $swrite - -$display and friends must have a constant format string as the first -argument (as with C's printf). The rare usage which lists variables -standalone without a format is not supported. - =item $displayb, $displayh, $displayo, $writeb, $writeh, $writeo, etc The sized display functions are rarely used and so not supported. Replace them with a $write with the appropriate format specifier. +=item $dump/$dumpports and related + +$dumpfile or $dumpports will create a VCD or FST file (which is based on +the --trace argument given when the model was Verilated). This will take +effect starting at the next eval() call. If you have multiple Verilated +designs under the same C model, then this will dump signals only from the +design containing the $dumpvar. + +$dumpvars and $dumpports module identifier is ignored; the traced instances +will always start at the top of the design. The levels argument is also +ignored, use tracing_on/tracing_off pragmas instead. + +$dumpportson/$dumpportsoff/$dumpportsall/$dumpportslimit filename argument +is ignored, only a single trace file may be active at once. + +$dumpall/$dumpportsall, $dumpon/$dumpportson, $dumpoff/$dumpportsoff, and +$dumplimit/$dumpportlimit are currently ignored. + =item $finish, $stop The rarely used optional parameter to $finish and $stop is ignored. @@ -4835,19 +4847,20 @@ designs have topped 16GB. See the next question for tracing in SystemC mode. -Add the --trace switch to Verilator, and in your top level C code, call -Verilated::traceEverOn(true). Then create a VerilatedVcdC object, and -in your main loop call "trace_object->dump(time)" every time step, and -finally call "trace_object->close()". For an example, see below and the -examples/make_tracing_c/sim_main.cpp file of the distribution. +A. Add the --trace switch to Verilator, and in your top level C code, call +Verilated::traceEverOn(true). Then you may use $dumpfile and $dumpvars to +enable traces, same as with any Verilog simulator. See +C. -You also need to compile verilated_vcd_c.cpp and add it to your link, -preferably by adding the dependencies in $(VK_GLOBAL_OBJS) to your -Makefile's link rule. This is done for you if using the Verilator --exe -flag. - -Note you can also call ->trace on multiple Verilated objects with the same -trace file if you want all data to land in the same output file. +B. Or, for finer-grained control, or C++ files with multiple Verilated +modules you may also create the trace purely from C++. Create a +VerilatedVcdC object, and in your main loop call "trace_object->dump(time)" +every time step, and finally call "trace_object->close()". You also need +to compile verilated_vcd_c.cpp and add it to your link, preferably by +adding the dependencies in $(VK_GLOBAL_OBJS) to your Makefile's link rule. +This is done for you if using the Verilator --exe flag. Note you can also +call ->trace on multiple Verilated objects with the same trace file if you +want all data to land in the same output file. #include "verilated_vcd_c.h" ... @@ -4867,11 +4880,17 @@ trace file if you want all data to land in the same output file. =item How do I generate waveforms (traces) in SystemC? -Add the --trace switch to Verilator, and in your top level C sc_main code, -include verilated_vcd_sc.h. Then call Verilated::traceEverOn(true). Then -create a VerilatedVcdSc object as you would create a normal SystemC trace -file. For an example, see the call to VerilatedVcdSc in the -examples/make_tracing_sc/sc_main.cpp file of the distribution, and below. +A. Add the --trace switch to Verilator, and in your top level sc_main, call +Verilated::traceEverOn(true). Then you may use $dumpfile and $dumpvars to +enable traces, same as with any Verilog simulator, see the non-SystemC +example in C. This will trace only the module +containing the $dumpvar. + +B. Or, you may create a trace purely from SystemC, which may trace all +Verilated designs in the SystemC model. Create a VerilatedVcdSc object as +you would create a normal SystemC trace file. For an example, see the call +to VerilatedVcdSc in the examples/make_tracing_sc/sc_main.cpp file of the +distribution, and below. Alternatively you may use the C++ trace mechanism described in the previous question, however the timescale and timeprecision will not inherited from @@ -4901,23 +4920,23 @@ trace file if you want all data to land in the same output file. =item How do I generate FST waveforms (traces) in C++? -FST a format by GTKWave. -This version provides a basic FST support. -To dump FST format, add the --trace-fst switch to Verilator and change the include -path in the testbench to: +FST a format by GTKWave. This version provides a basic FST support. To +dump FST format, add the --trace-fst switch to Verilator and either A. use +$dumpfile/$dumpvars in Verilog as described in the VCD example above, or +B. in C++ change the include described in the VCD example above: #include "verilated_fst_c.h" VerilatedFstC* tfp = new VerilatedFstC; -Note that currently supporting both FST and VCD in a single simulation is impossible, -but such requirement could be rare. +Note that currently supporting both FST and VCD in a single simulation is +impossible, but such requirement should be rare. -=item How do I generate FST waveforms (traces) in SystemC? +=item How do I generate FST waveforms (aka dumps or traces) in SystemC? The FST library from GTKWave does not currently support SystemC; use VCD format instead. -=item How do I view waveforms (traces)? +=item How do I view waveforms (aka dumps or traces)? Verilator makes standard VCD (Value Change Dump) and FST files. VCD files are viewable with the public domain GTKWave (recommended) or Dinotrace (legacy) diff --git a/examples/make_tracing_c/sim_main.cpp b/examples/make_tracing_c/sim_main.cpp index c8003611e..1e75819f4 100644 --- a/examples/make_tracing_c/sim_main.cpp +++ b/examples/make_tracing_c/sim_main.cpp @@ -10,11 +10,6 @@ // Include model header, generated from Verilating "top.v" #include "Vtop.h" -// If "verilator --trace" is used, include the tracing class -#if VM_TRACE -# include -#endif - // Current simulation time (64-bit unsigned) vluint64_t main_time = 0; // Called by $time in Verilog @@ -36,28 +31,19 @@ int main(int argc, char** argv, char** env) { // May be overridden by commandArgs Verilated::randReset(2); + // Verilator must compute traced signals + Verilated::traceEverOn(true); + // Pass arguments so Verilated code can see them, e.g. $value$plusargs // This needs to be called before you create any model Verilated::commandArgs(argc, argv); + // Create logs/ directory in case we have traces to put under it + Verilated::mkdir("logs"); + // Construct the Verilated model, from Vtop.h generated from Verilating "top.v" Vtop* top = new Vtop; // Or use a const unique_ptr, or the VL_UNIQUE_PTR wrapper -#if VM_TRACE - // If verilator was invoked with --trace argument, - // and if at run time passed the +trace argument, turn on tracing - VerilatedVcdC* tfp = NULL; - const char* flag = Verilated::commandArgsPlusMatch("trace"); - if (flag && 0==strcmp(flag, "+trace")) { - Verilated::traceEverOn(true); // Verilator must compute traced signals - VL_PRINTF("Enabling waves into logs/vlt_dump.vcd...\n"); - tfp = new VerilatedVcdC; - top->trace(tfp, 99); // Trace 99 levels of hierarchy - Verilated::mkdir("logs"); - tfp->open("logs/vlt_dump.vcd"); // Open the dump file - } -#endif - // Set some inputs top->reset_l = !0; top->fastclk = 0; @@ -90,13 +76,11 @@ int main(int argc, char** argv, char** env) { top->in_quad += 0x12; // Evaluate model + // (If you have multiple models being simulated in the same + // timestep then instead of eval(), call eval_step() on each, then + // eval_end_step() on each.) top->eval(); -#if VM_TRACE - // Dump trace data for this cycle - if (tfp) tfp->dump(main_time); -#endif - // Read outputs VL_PRINTF("[%" VL_PRI64 "d] clk=%x rstl=%x iquad=%" VL_PRI64 "x" " -> oquad=%" VL_PRI64"x owide=%x_%08x_%08x\n", @@ -107,11 +91,6 @@ int main(int argc, char** argv, char** env) { // Final model cleanup top->final(); - // Close trace if opened -#if VM_TRACE - if (tfp) { tfp->close(); tfp = NULL; } -#endif - // Coverage analysis (since test passed) #if VM_COVERAGE Verilated::mkdir("logs"); diff --git a/examples/make_tracing_c/top.v b/examples/make_tracing_c/top.v index beae05605..0dc22d9cc 100644 --- a/examples/make_tracing_c/top.v +++ b/examples/make_tracing_c/top.v @@ -36,6 +36,11 @@ module top // Print some stuff as an example initial begin + if ($test$plusargs("trace") != 0) begin + $display("[%0t] Tracing to logs/vlt_dump.vcd...\n", $time); + $dumpfile("logs/vlt_dump.vcd"); + $dumpvars(); + end $display("[%0t] Model running...\n", $time); end diff --git a/examples/make_tracing_sc/sc_main.cpp b/examples/make_tracing_sc/sc_main.cpp index b2d704aec..381d321bf 100644 --- a/examples/make_tracing_sc/sc_main.cpp +++ b/examples/make_tracing_sc/sc_main.cpp @@ -37,6 +37,9 @@ int sc_main(int argc, char* argv[]) { // This needs to be called before you create any model Verilated::commandArgs(argc, argv); + // Create logs/ directory in case we have traces to put under it + Verilated::mkdir("logs"); + // General logfile ios::sync_with_stdio(); diff --git a/include/verilated.cpp b/include/verilated.cpp index 90eecfb25..c242b5ab5 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -1602,6 +1602,25 @@ IData VL_ATOI_N(const std::string& str, int base) VL_PURE { return static_cast(v); } +//=========================================================================== +// Dumping + +const char* vl_dumpctl_filenamep(bool setit, const std::string& filename) VL_MT_SAFE { + // This function performs both accessing and setting so it's easy to make an in-function static + static VL_THREAD_LOCAL std::string t_filename; + if (setit) { + t_filename = filename; + } else { + static VL_THREAD_LOCAL bool t_warned = false; + if (VL_UNLIKELY(t_filename.empty() && !t_warned)) { + t_warned = true; + VL_PRINTF_MT("%%Warning: $dumpvar ignored as not proceeded by $dumpfile\n"); + return ""; + } + } + return t_filename.c_str(); +} + //=========================================================================== // Readmem/writemem diff --git a/include/verilated.h b/include/verilated.h index c039d3878..97becf9c3 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -83,6 +83,7 @@ class VerilatedVar; class VerilatedVarNameMap; class VerilatedVcd; class VerilatedVcdC; +class VerilatedVcdSc; class VerilatedFst; class VerilatedFstC; diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp index 2e2533cbc..5eb69fe04 100644 --- a/include/verilated_fst_c.cpp +++ b/include/verilated_fst_c.cpp @@ -64,9 +64,12 @@ protected: vluint32_t m_code; ///< Starting code number // CONSTRUCTORS VerilatedFstCallInfo(VerilatedFstCallback_t icb, VerilatedFstCallback_t fcb, - VerilatedFstCallback_t changecb, - void* ut, vluint32_t code) - : m_initcb(icb), m_fullcb(fcb), m_changecb(changecb), m_userthis(ut), m_code(code) {} + VerilatedFstCallback_t changecb, void* ut) + : m_initcb(icb) + , m_fullcb(fcb) + , m_changecb(changecb) + , m_userthis(ut) + , m_code(1) {} ~VerilatedFstCallInfo() {} }; @@ -173,17 +176,16 @@ void VerilatedFst::declSymbol(vluint32_t code, const char* name, //============================================================================= // Callbacks -void VerilatedFst::addCallback( - VerilatedFstCallback_t initcb, VerilatedFstCallback_t fullcb, - VerilatedFstCallback_t changecb, void* userthis) VL_MT_UNSAFE_ONE { +void VerilatedFst::addCallback(VerilatedFstCallback_t initcb, VerilatedFstCallback_t fullcb, + VerilatedFstCallback_t changecb, void* userthis) VL_MT_UNSAFE_ONE { m_assertOne.check(); if (VL_UNLIKELY(isOpen())) { - std::string msg = (std::string("Internal: ")+__FILE__+"::"+__FUNCTION__ - +" called with already open file"); + std::string msg = (std::string("Internal: ") + __FILE__ + "::" + __FUNCTION__ + + " called with already open file"); VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str()); } - VerilatedFstCallInfo* vci = new VerilatedFstCallInfo(initcb, fullcb, changecb, userthis, 1); - m_callbacks.push_back(vci); + VerilatedFstCallInfo* cip = new VerilatedFstCallInfo(initcb, fullcb, changecb, userthis); + m_callbacks.push_back(cip); } //============================================================================= @@ -192,7 +194,7 @@ void VerilatedFst::addCallback( void VerilatedFst::dump(vluint64_t timeui) { if (!isOpen()) return; if (VL_UNLIKELY(m_fullDump)) { - m_fullDump = false; // No need for more full dumps + m_fullDump = false; // No more need for next dump to be full for (vluint32_t ent = 0; ent< m_callbacks.size(); ++ent) { VerilatedFstCallInfo* cip = m_callbacks[ent]; (cip->m_fullcb)(this, cip->m_userthis, cip->m_code); diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index 5fc4aeaff..f6de80bb9 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -198,7 +198,7 @@ class VerilatedFstC { VL_UNCOPYABLE(VerilatedFstC); public: explicit VerilatedFstC(void* filep=NULL) : m_sptrace(filep) {} - ~VerilatedFstC() {} + ~VerilatedFstC() { close(); } public: // ACCESSORS /// Is file open? diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index c04ee3214..ef9f2b8bc 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -441,4 +441,10 @@ inline IData VL_CMP_NN(const std::string& lhs, const std::string& rhs, bool igno extern IData VL_ATOI_N(const std::string& str, int base) VL_PURE; +//====================================================================== +// Dumping + +extern const char* vl_dumpctl_filenamep(bool setit = false, + const std::string& filename = "") VL_MT_SAFE; + #endif // Guard diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index 87c4e8baa..c9406686a 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -119,7 +119,7 @@ protected: bool VerilatedVcdFile::open(const std::string& name) VL_MT_UNSAFE { m_fd = ::open(name.c_str(), O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE|O_NONBLOCK|O_CLOEXEC, 0666); - return (m_fd>=0); + return m_fd >= 0; } void VerilatedVcdFile::close() VL_MT_UNSAFE { @@ -136,7 +136,10 @@ ssize_t VerilatedVcdFile::write(const char* bufp, ssize_t len) VL_MT_UNSAFE { // Opening/Closing VerilatedVcd::VerilatedVcd(VerilatedVcdFile* filep) - : m_isOpen(false), m_rolloverMB(0), m_modDepth(0), m_nextCode(1) { + : m_isOpen(false) + , m_rolloverMB(0) + , m_modDepth(0) + , m_nextCode(1) { // Not in header to avoid link issue if header is included without this .cpp file m_fileNewed = (filep == NULL); m_filep = m_fileNewed ? new VerilatedVcdFile : filep; @@ -156,7 +159,7 @@ VerilatedVcd::VerilatedVcd(VerilatedVcdFile* filep) void VerilatedVcd::open(const char* filename) { m_assertOne.check(); - if (isOpen()) return; + if (isOpen() || !filename || !*filename) return; // Set member variables m_filename = filename; @@ -690,7 +693,7 @@ void VerilatedVcd::dump(vluint64_t timeui) { m_assertOne.check(); if (!isOpen()) return; if (VL_UNLIKELY(m_fullDump)) { - m_fullDump = false; // No need for more full dumps + m_fullDump = false; // No more need for next dump to be full dumpFull(timeui); return; } diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index 835af7b71..690e3ec31 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -103,9 +103,9 @@ private: typedef std::vector SigVec; SigVec m_sigs; ///< Pointer to signal information typedef std::vector CallbackVec; - CallbackVec m_callbacks; ///< Routines to perform dumping + CallbackVec m_callbacks; ///< Routines to perform dumping typedef std::map NameMap; - NameMap* m_namemapp; ///< List of names for the header + NameMap* m_namemapp; ///< List of names for the header VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread @@ -445,7 +445,7 @@ class VerilatedVcdC { public: explicit VerilatedVcdC(VerilatedVcdFile* filep = NULL) : m_sptrace(filep) {} - ~VerilatedVcdC() {} + ~VerilatedVcdC() { close(); } public: // ACCESSORS /// Is file open? diff --git a/include/verilated_vcd_sc.h b/include/verilated_vcd_sc.h index f5ab1efe1..48c961c8d 100644 --- a/include/verilated_vcd_sc.h +++ b/include/verilated_vcd_sc.h @@ -62,7 +62,7 @@ public: spTrace()->set_time_resolution(sc_get_time_resolution().to_string()); # endif } - virtual ~VerilatedVcdSc() {} + virtual ~VerilatedVcdSc() { close(); } // METHODS /// Called by SystemC simulate() diff --git a/src/V3Ast.h b/src/V3Ast.h index 356df43d3..f877e4056 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -815,6 +815,32 @@ inline bool operator==(AstDisplayType::en lhs, const AstDisplayType& rhs) { //###################################################################### +class VDumpCtlType { +public: + enum en { FILE, VARS, ALL, FLUSH, LIMIT, OFF, ON }; + enum en m_e; + inline VDumpCtlType() + : m_e(ON) {} + // cppcheck-suppress noExplicitConstructor + inline VDumpCtlType(en _e) + : m_e(_e) {} + explicit inline VDumpCtlType(int _e) + : m_e(static_cast(_e)) {} + operator en() const { return m_e; } + const char* ascii() const { + static const char* const names[] = {"$dumpfile", "$dumpvars", "$dumpall", "$dumpflush", + "$dumplimit", "$dumpoff", "$dumpon"}; + return names[m_e]; + } +}; +inline bool operator==(const VDumpCtlType& lhs, const VDumpCtlType& rhs) { + return lhs.m_e == rhs.m_e; +} +inline bool operator==(const VDumpCtlType& lhs, VDumpCtlType::en rhs) { return lhs.m_e == rhs; } +inline bool operator==(VDumpCtlType::en lhs, const VDumpCtlType& rhs) { return lhs == rhs.m_e; } + +//###################################################################### + class VParseRefExp { public: enum en { diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 448589c9b..7365d6430 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -3033,6 +3033,31 @@ public: void filep(AstNodeVarRef* nodep) { setNOp3p(nodep); } }; +class AstDumpCtl : public AstNodeStmt { + // $dumpon etc + // Parents: expr + // Child: expr based on type of control statement + VDumpCtlType m_ctlType; // Type of operation +public: + AstDumpCtl(FileLine* fl, VDumpCtlType ctlType, AstNode* exprp = NULL) + : ASTGEN_SUPER(fl), m_ctlType(ctlType) { + setNOp1p(exprp); + } + ASTNODE_NODE_FUNCS(DumpCtl) + virtual string verilogKwd() const { return ctlType().ascii(); } + virtual string emitVerilog() { return "%f" + verilogKwd() + "(%l)"; } + virtual string emitC() { V3ERROR_NA; return ""; } + virtual bool isGateOptimizable() const { return false; } + virtual bool isPredictOptimizable() const { return false; } + virtual bool isOutputter() const { return true; } + virtual bool cleanOut() const { return true; } + virtual V3Hash sameHash() const { return V3Hash(); } + virtual bool same(const AstNode* samep) const { return true; } + VDumpCtlType ctlType() const { return m_ctlType; } + AstNode* exprp() const { return op1p(); } // op2 = Expressions to output + void exprp(AstNode* nodep) { setOp1p(nodep); } +}; + class AstElabDisplay : public AstNode { // Parents: stmtlist // Children: SFORMATF to generate print string diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index cd424a131..e4efa36e9 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -402,6 +402,44 @@ public: if (nodep->addNewline()) text += "\n"; displayNode(nodep, nodep->fmtp()->scopeNamep(), text, nodep->fmtp()->exprsp(), false); } + virtual void visit(AstDumpCtl* nodep) VL_OVERRIDE { + switch (nodep->ctlType()) { + case VDumpCtlType::FILE: + puts("vl_dumpctl_filenamep(true, "); + emitCvtPackStr(nodep->exprp()); + puts(");\n"); + break; + case VDumpCtlType::VARS: + // We ignore number of levels to dump in exprp() + if (v3Global.opt.trace()) { + puts("vlSymsp->TOPp->_traceDumpOpen();\n"); + } else { + puts("VL_PRINTF_MT(\"-Info: "); + puts(protect(nodep->fileline()->filename())); + puts(":"); + puts(cvtToStr(nodep->fileline()->lineno())); + puts(": $dumpvar ignored, as Verilated without --trace"); + puts("\\n\");\n"); + } + break; + case VDumpCtlType::ALL: + // $dumpall currently ignored + break; + case VDumpCtlType::FLUSH: + puts("Verilated::flushCall();\n"); // Also flush stdio, as need lock + break; + case VDumpCtlType::LIMIT: + // $dumplimit currently ignored + break; + case VDumpCtlType::OFF: + // Currently ignored as both Vcd and Fst do not support them, as would need "X" dump + break; + case VDumpCtlType::ON: + // Currently ignored as $dumpoff is also ignored + break; + default: nodep->v3fatalSrc("Bad case, unexpected " << nodep->ctlType().ascii()); + } + } virtual void visit(AstScopeName* nodep) VL_OVERRIDE { // For use under AstCCalls for dpiImports. ScopeNames under // displays are handled in AstDisplay @@ -2110,8 +2148,16 @@ void EmitCImp::emitCoverageImp(AstNodeModule* modp) { void EmitCImp::emitDestructorImp(AstNodeModule* modp) { puts("\n"); puts(prefixNameProtect(modp) + "::~" + prefixNameProtect(modp) + "() {\n"); - if (modp->isTop() && v3Global.opt.mtasks()) { - puts("delete __Vm_threadPoolp; __Vm_threadPoolp = NULL;\n"); + if (modp->isTop()) { + if (v3Global.opt.mtasks()) { + puts("delete __Vm_threadPoolp; __Vm_threadPoolp = NULL;\n"); + } + // Call via function in __Trace.cpp as this .cpp file does not have trace header + if (v3Global.needTraceDumper()) { + puts("#ifdef VM_TRACE\n"); + puts("if (VL_UNLIKELY(__VlSymsp->__Vm_dumperp)) _traceDumpClose();\n"); + puts("#endif // VM_TRACE\n"); + } } emitTextSection(AstType::atScDtor); if (modp->isTop()) puts("delete __VlSymsp; __VlSymsp=NULL;\n"); @@ -2304,7 +2350,7 @@ void EmitCImp::emitSettleLoop(const std::string& eval_call, bool initial) { } void EmitCImp::emitWrapEval(AstNodeModule* modp) { - puts("\nvoid " + prefixNameProtect(modp) + "::eval() {\n"); + puts("\nvoid " + prefixNameProtect(modp) + "::eval_step() {\n"); puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+++++TOP Evaluate " + prefixNameProtect(modp) + "::eval\\n\"); );\n"); puts(EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp; // Setup global symbol table\n"); @@ -2316,6 +2362,15 @@ void EmitCImp::emitWrapEval(AstNodeModule* modp) { putsDecoration("// Initialize\n"); puts("if (VL_UNLIKELY(!vlSymsp->__Vm_didInit)) " +protect("_eval_initial_loop")+"(vlSymsp);\n"); + if (v3Global.opt.trace()) { + puts("#ifdef VM_TRACE\n"); + putsDecoration("// Tracing\n"); + // SystemC's eval loop deals with calling trace, not us + if (v3Global.needTraceDumper() && !optSystemC()) { + puts("if (VL_UNLIKELY(vlSymsp->__Vm_dumperp)) _traceDump();\n"); + } + puts("#endif // VM_TRACE\n"); + } if (v3Global.opt.inhibitSim()) { puts("if (VL_UNLIKELY(__Vm_inhibitSim)) return;\n"); } @@ -2377,6 +2432,21 @@ void EmitCImp::emitWrapEval(AstNodeModule* modp) { puts("}\n"); splitSizeInc(10); + // + if (v3Global.needTraceDumper() && !optSystemC()) { + puts("\nvoid " + prefixNameProtect(modp) + "::eval_end_step() {\n"); + puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+eval_end_step " + prefixNameProtect(modp) + + "::eval_end_step\\n\"); );\n"); + puts("#ifdef VM_TRACE\n"); + puts(EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp; // Setup global symbol table\n"); + puts(EmitCBaseVisitor::symTopAssign()+"\n"); + putsDecoration("// Tracing\n"); + // SystemC's eval loop deals with calling trace, not us + puts("if (VL_UNLIKELY(vlSymsp->__Vm_dumperp)) _traceDump();\n"); + puts("#endif // VM_TRACE\n"); + puts("}\n"); + } + // puts("\nvoid " + prefixNameProtect(modp) + "::" + protect("_eval_initial_loop") + "(" + EmitCBaseVisitor::symClassVar() + ") {\n"); @@ -2693,11 +2763,11 @@ void EmitCImp::emitInt(AstNodeModule* modp) { ofp()->putsPrivate(!modp->isTop()); // private: unless top puts(symClassName()+"* __VlSymsp; // Symbol table\n"); ofp()->putsPrivate(false); // public: - if (modp->isTop() && v3Global.opt.inhibitSim()) { - puts("bool __Vm_inhibitSim; ///< Set true to disable evaluation of module\n"); - } - if (modp->isTop() && v3Global.opt.mtasks()) { - emitMTaskState(); + if (modp->isTop()) { + if (v3Global.opt.inhibitSim()) { + puts("bool __Vm_inhibitSim; ///< Set true to disable evaluation of module\n"); + } + if (v3Global.opt.mtasks()) emitMTaskState(); } emitCoverageDecl(modp); // may flip public/private @@ -2775,14 +2845,26 @@ void EmitCImp::emitInt(AstNodeModule* modp) { if (modp->isTop()) { puts("\n// API METHODS\n"); + string callEvalEndStep + = (v3Global.needTraceDumper() && !optSystemC()) ? "eval_end_step(); " : ""; if (optSystemC()) ofp()->putsPrivate(true); ///< eval() is invoked by our sensitive() calls. - else puts("/// Evaluate the model. Application must call when inputs change.\n"); - puts("void eval();\n"); + if (!optSystemC()) puts("/// Evaluate the model. Application must call when inputs change.\n"); + puts("void eval() { eval_step(); " + callEvalEndStep + "}\n"); + if (!optSystemC()) puts("/// Evaluate when calling multiple units/models per time step.\n"); + puts("void eval_step();\n"); + if (!optSystemC()) { + puts("/// Evaluate at end of a timestep for tracing, when using eval_step().\n"); + puts("/// Application must call after all eval() and before time changes.\n"); + puts("void eval_end_step()"); + if (callEvalEndStep == "") puts(" {}\n"); + else puts(";\n"); + } ofp()->putsPrivate(false); // public: if (!optSystemC()) puts("/// Simulation complete, run final blocks. Application must call on completion.\n"); puts("void final();\n"); if (v3Global.opt.inhibitSim()) { - puts("void inhibitSim(bool flag) { __Vm_inhibitSim=flag; } ///< Set true to disable evaluation of module\n"); + puts("/// Disable evaluation of module (e.g. turn off)\n"); + puts("void inhibitSim(bool flag) { __Vm_inhibitSim = flag; }\n"); } } @@ -2791,6 +2873,9 @@ void EmitCImp::emitInt(AstNodeModule* modp) { ofp()->putsPrivate(true); // private: puts("static void "+protect("_eval_initial_loop") +"("+EmitCBaseVisitor::symClassVar()+");\n"); + if (v3Global.needTraceDumper() && !optSystemC()) puts("void _traceDump();"); + if (v3Global.needTraceDumper()) puts("void _traceDumpOpen();"); + if (v3Global.needTraceDumper()) puts("void _traceDumpClose();"); } if (!VN_IS(modp, Class)) { @@ -2978,14 +3063,43 @@ class EmitCTrace : EmitCStmts { void emitTraceHeader() { // Includes - puts("#include \""+v3Global.opt.traceSourceName()+"_c.h\"\n"); - puts("#include \""+ symClassName() +".h\"\n"); + puts("#include \"" + v3Global.opt.traceSourceLang() + ".h\"\n"); + puts("#include \"" + symClassName() + ".h\"\n"); puts("\n"); } void emitTraceSlow() { puts("\n//======================\n\n"); + if (v3Global.needTraceDumper() && !optSystemC()) { + puts("void " + topClassName() + "::_traceDump() {\n"); + // Caller checked for __Vm_dumperp non-NULL + puts( "VerilatedLockGuard lock(__VlSymsp->__Vm_dumperMutex);\n"); + puts( "__VlSymsp->__Vm_dumperp->dump(VL_TIME_Q());\n"); + puts("}\n"); + splitSizeInc(10); + } + + if (v3Global.needTraceDumper()) { + puts("void " + topClassName() + "::_traceDumpOpen() {\n"); + puts( "if (VL_UNLIKELY(!__VlSymsp->__Vm_dumperp)) {\n"); + puts( "VerilatedLockGuard lock(__VlSymsp->__Vm_dumperMutex);\n"); + puts( "__VlSymsp->__Vm_dumperp = new " + v3Global.opt.traceClassLang() + "();\n"); + puts( "const char* cp = vl_dumpctl_filenamep();\n"); + puts( "trace(__VlSymsp->__Vm_dumperp, 0, 0);\n"); + puts( "__VlSymsp->__Vm_dumperp->open(vl_dumpctl_filenamep());\n"); + puts( "}\n"); + puts("}\n"); + splitSizeInc(10); + + puts("void " + topClassName() + "::_traceDumpClose() {\n"); + // Caller checked for __Vm_dumperp non-NULL + puts( "VerilatedLockGuard lock(__VlSymsp->__Vm_dumperMutex);\n"); + puts( "delete __VlSymsp->__Vm_dumperp; __VlSymsp->__Vm_dumperp = NULL;\n"); + puts("}\n"); + splitSizeInc(10); + } + puts("void "+topClassName()+"::trace("); puts(v3Global.opt.traceClassBase()+"C* tfp, int, int) {\n"); puts( "tfp->spTrace()->addCallback(" diff --git a/src/V3EmitCInlines.cpp b/src/V3EmitCInlines.cpp index 0090b880a..39a78e140 100644 --- a/src/V3EmitCInlines.cpp +++ b/src/V3EmitCInlines.cpp @@ -66,6 +66,11 @@ class EmitCInlines : EmitCBaseVisitor { v3Global.needHeavy(true); iterateChildren(nodep); } + virtual void visit(AstDumpCtl* nodep) VL_OVERRIDE { + if (v3Global.opt.trace()) v3Global.needTraceDumper(true); + v3Global.needHeavy(true); + iterateChildren(nodep); + } virtual void visit(AstPutcN* nodep) VL_OVERRIDE { v3Global.needHeavy(true); iterateChildren(nodep); diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp index 4d2a2a79d..2de114211 100644 --- a/src/V3EmitCMake.cpp +++ b/src/V3EmitCMake.cpp @@ -160,13 +160,13 @@ class CMakeEmitter { } if (v3Global.opt.trace()) { global.push_back("${VERILATOR_ROOT}/include/" - + v3Global.opt.traceSourceName()+"_c.cpp"); + + v3Global.opt.traceSourceBase() + "_c.cpp"); if (v3Global.opt.systemC()) { if (v3Global.opt.traceFormat() != TraceFormat::VCD) { v3error("Unsupported: This trace format is not supported in SystemC, use VCD format."); } global.push_back("${VERILATOR_ROOT}/include/" - + v3Global.opt.traceSourceName()+"_sc.cpp"); + + v3Global.opt.traceSourceLang() + ".cpp"); } } if (v3Global.opt.mtasks()) { diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 6cdc1c635..8533060a2 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -417,6 +417,13 @@ void EmitCSyms::emitSymHdr() { puts("\n// LOCAL STATE\n"); puts("const char* __Vm_namep;\n"); // Must be before subcells, as constructor order needed before _vlCoverInsert. + if (v3Global.needTraceDumper()) { + // __Vm_dumperp is local, otherwise we wouldn't know what design's eval() + // should call a global dumpperp + puts("VerilatedMutex __Vm_dumperMutex; // Protect __Vm_dumperp\n"); + puts(v3Global.opt.traceClassLang() + + "* __Vm_dumperp VL_GUARDED_BY(__Vm_dumperMutex); /// Trace class for $dump*\n"); + } if (v3Global.opt.trace()) { puts("bool __Vm_activity; ///< Used by trace routines to determine change occurred\n"); } @@ -582,10 +589,9 @@ void EmitCSyms::emitSymImp() { puts("\n// FUNCTIONS\n"); puts(symClassName()+"::"+symClassName()+"("+topClassName()+"* topp, const char* namep)\n"); puts(" // Setup locals\n"); - puts(" : __Vm_namep(namep)\n"); // No leak, as we get destroyed when the top is destroyed - if (v3Global.opt.trace()) { - puts(" , __Vm_activity(false)\n"); - } + puts(" : __Vm_namep(namep)\n"); // No leak, as gets destroyed when the top is destroyed + if (v3Global.needTraceDumper()) puts(" , __Vm_dumperp(NULL)\n"); + if (v3Global.opt.trace()) puts(" , __Vm_activity(false)\n"); puts(" , __Vm_didInit(false)\n"); puts(" // Setup submodule names\n"); char comma = ','; diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index 284e02bc4..c8a83ce2a 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -85,12 +85,12 @@ public: putMakeClassEntry(of, "verilated_cov.cpp"); } if (v3Global.opt.trace()) { - putMakeClassEntry(of, v3Global.opt.traceSourceName()+"_c.cpp"); + putMakeClassEntry(of, v3Global.opt.traceSourceBase() + "_c.cpp"); if (v3Global.opt.systemC()) { if (v3Global.opt.traceFormat() != TraceFormat::VCD) { v3error("Unsupported: This trace format is not supported in SystemC, use VCD format."); } else { - putMakeClassEntry(of, v3Global.opt.traceSourceName()+"_sc.cpp"); + putMakeClassEntry(of, v3Global.opt.traceSourceLang() + ".cpp"); } } } diff --git a/src/V3Global.h b/src/V3Global.h index 0011df4ff..da20b88cd 100644 --- a/src/V3Global.h +++ b/src/V3Global.h @@ -71,15 +71,16 @@ inline bool operator==(VWidthMinUsage::en lhs, const VWidthMinUsage& rhs) { class V3Global { // Globals - AstNetlist* m_rootp; // Root of entire netlist - VWidthMinUsage m_widthMinUsage; // What AstNode::widthMin() is used for + AstNetlist* m_rootp; // Root of entire netlist + VWidthMinUsage m_widthMinUsage; // What AstNode::widthMin() is used for - int m_debugFileNumber; // Number to append to debug files created - bool m_assertDTypesResolved; // Tree should have dtypep()'s - bool m_constRemoveXs; // Const needs to strip any Xs - bool m_needHInlines; // Need __Inlines file - bool m_needHeavy; // Need verilated_heavy.h include - bool m_dpi; // Need __Dpi include files + int m_debugFileNumber; // Number to append to debug files created + bool m_assertDTypesResolved; // Tree should have dtypep()'s + bool m_constRemoveXs; // Const needs to strip any Xs + bool m_needTraceDumper; // Need __Vm_dumperp in symbols + bool m_needHInlines; // Need __Inlines file + bool m_needHeavy; // Need verilated_heavy.h include + bool m_dpi; // Need __Dpi include files public: // Options @@ -92,6 +93,7 @@ public: m_widthMinUsage = VWidthMinUsage::LINT_WIDTH; m_assertDTypesResolved = false; m_constRemoveXs = false; + m_needTraceDumper = false; m_needHInlines = false; m_needHeavy = false; m_dpi = false; @@ -119,10 +121,12 @@ public: char digits[100]; sprintf(digits, "%03d", m_debugFileNumber); return opt.makeDir()+"/"+opt.prefix()+"_"+digits+"_"+nameComment; } + bool needTraceDumper() const { return m_needTraceDumper; } + void needTraceDumper(bool flag) { m_needTraceDumper = flag; } bool needHInlines() const { return m_needHInlines; } - void needHInlines(bool flag) { m_needHInlines=flag; } + void needHInlines(bool flag) { m_needHInlines = flag; } bool needHeavy() const { return m_needHeavy; } - void needHeavy(bool flag) { m_needHeavy=flag; } + void needHeavy(bool flag) { m_needHeavy = flag; } bool dpi() const { return m_dpi; } void dpi(bool flag) { m_dpi = flag; } }; diff --git a/src/V3Options.h b/src/V3Options.h index dac7c3402..f89ab5a45 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -467,7 +467,11 @@ class V3Options { bool oTable() const { return m_oTable; } string traceClassBase() const { return m_traceFormat.classBase(); } - string traceSourceName() const { return m_traceFormat.sourceName(); } + string traceClassLang() const { return m_traceFormat.classBase() + (systemC() ? "Sc" : "C"); } + string traceSourceBase() const { return m_traceFormat.sourceName(); } + string traceSourceLang() const { + return m_traceFormat.sourceName() + (systemC() ? "_sc" : "_c"); + } // METHODS (from main) static string version(); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 512bb9676..dc4152b46 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2872,6 +2872,11 @@ private: VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } } + virtual void visit(AstDumpCtl* nodep) VL_OVERRIDE { + assertAtStatement(nodep); + // Just let all arguments seek their natural sizes + userIterateChildren(nodep, WidthVP(SELF, BOTH).p()); + } virtual void visit(AstFOpen* nodep) VL_OVERRIDE { // Although a system function in IEEE, here a statement which sets the file pointer (MCD) assertAtStatement(nodep); diff --git a/src/verilog.l b/src/verilog.l index 23fad9c63..33b791946 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -197,6 +197,19 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$cos" { FL; return yD_COS; } "$cosh" { FL; return yD_COSH; } "$display" { FL; return yD_DISPLAY; } + "$dumpall" { FL; return yD_DUMPALL; } + "$dumpfile" { FL; return yD_DUMPFILE; } + "$dumpflush" { FL; return yD_DUMPFLUSH; } + "$dumplimit" { FL; return yD_DUMPLIMIT; } + "$dumpoff" { FL; return yD_DUMPOFF; } + "$dumpon" { FL; return yD_DUMPON; } + "$dumpports" { FL; return yD_DUMPPORTS; } + "$dumpportsall" { FL; return yD_DUMPALL; } + "$dumpportsflush" { FL; return yD_DUMPFLUSH; } + "$dumpportslimit" { FL; return yD_DUMPLIMIT; } + "$dumpportsoff" { FL; return yD_DUMPOFF; } + "$dumpportson" { FL; return yD_DUMPON; } + "$dumpvars" { FL; return yD_DUMPVARS; } "$exp" { FL; return yD_EXP; } "$fclose" { FL; return yD_FCLOSE; } "$fdisplay" { FL; return yD_FDISPLAY; } @@ -208,10 +221,10 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$floor" { FL; return yD_FLOOR; } "$fopen" { FL; return yD_FOPEN; } "$fread" { FL; return yD_FREAD; } + "$frewind" { FL; return yD_FREWIND; } "$fscanf" { FL; return yD_FSCANF; } "$fseek" { FL; return yD_FSEEK; } "$ftell" { FL; return yD_FTELL; } - "$frewind" { FL; return yD_FREWIND; } "$fullskew" { FL; return yaTIMINGSPEC; } "$fwrite" { FL; return yD_FWRITE; } "$hold" { FL; return yaTIMINGSPEC; } diff --git a/src/verilog.y b/src/verilog.y index e23427536..8ad3f5fb9 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -553,6 +553,14 @@ class AstSenTree; %token yD_COUNTONES "$countones" %token yD_DIMENSIONS "$dimensions" %token yD_DISPLAY "$display" +%token yD_DUMPALL "$dumpall" +%token yD_DUMPFILE "$dumpfile" +%token yD_DUMPFLUSH "$dumpflush" +%token yD_DUMPLIMIT "$dumplimit" +%token yD_DUMPOFF "$dumpoff" +%token yD_DUMPON "$dumpon" +%token yD_DUMPPORTS "$dumpports" +%token yD_DUMPVARS "$dumpvars" %token yD_ERROR "$error" %token yD_EXP "$exp" %token yD_FATAL "$fatal" @@ -3154,8 +3162,30 @@ system_t_call: // IEEE: system_tf_call (as task) | yaD_DPI '(' exprList ')' { $$ = new AstTaskRef($1, *$1, $3); GRAMMARP->argWrapList(VN_CAST($$, TaskRef)); } // + | yD_DUMPPORTS '(' idDotted ',' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::FILE, $5); DEL($3); + $$->addNext(new AstDumpCtl($1, VDumpCtlType::VARS, + new AstConst($1, 1))); } + | yD_DUMPPORTS '(' ',' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::FILE, $4); + $$->addNext(new AstDumpCtl($1, VDumpCtlType::VARS, + new AstConst($1, 1))); } + | yD_DUMPFILE '(' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::FILE, $3); } + | yD_DUMPVARS parenE { $$ = new AstDumpCtl($1, VDumpCtlType::VARS, + new AstConst($1, 0)); } + | yD_DUMPVARS '(' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::VARS, $3); } + | yD_DUMPVARS '(' expr ',' idDotted ')' { $$ = new AstDumpCtl($1, VDumpCtlType::VARS, $3); DEL($5); } + | yD_DUMPALL parenE { $$ = new AstDumpCtl($1, VDumpCtlType::ALL); } + | yD_DUMPALL '(' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::ALL); DEL($3); } + | yD_DUMPFLUSH parenE { $$ = new AstDumpCtl($1, VDumpCtlType::FLUSH); } + | yD_DUMPFLUSH '(' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::FLUSH); DEL($3); } + | yD_DUMPLIMIT '(' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::LIMIT, $3); } + | yD_DUMPLIMIT '(' expr ',' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::LIMIT, $3); DEL($5); } + | yD_DUMPOFF parenE { $$ = new AstDumpCtl($1, VDumpCtlType::OFF); } + | yD_DUMPOFF '(' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::OFF); DEL($3); } + | yD_DUMPON parenE { $$ = new AstDumpCtl($1, VDumpCtlType::ON); } + | yD_DUMPON '(' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::ON); DEL($3); } + // | yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? NULL : new AstUCStmt($1,$3)); } - | yD_SYSTEM '(' expr ')' { $$ = new AstSystemT($1, $3); } + | yD_SYSTEM '(' expr ')' { $$ = new AstSystemT($1, $3); } // | yD_FCLOSE '(' idClassSel ')' { $$ = new AstFClose($1, $3); } | yD_FFLUSH parenE { $$ = NULL; BBUNSUP($1, "Unsupported: $fflush of all handles does not map to C++."); } diff --git a/test_regress/t/t_leak.cpp b/test_regress/t/t_leak.cpp index 83db456a1..573286941 100644 --- a/test_regress/t/t_leak.cpp +++ b/test_regress/t/t_leak.cpp @@ -64,15 +64,15 @@ int main(int argc, char* argv[]) { vluint64_t firstUsage = get_memory_usage(); // Warmup phase - for (int i = 0; i < 1000; i++) { + for (int i = 0; i < 10; i++) { make_and_destroy(); } firstUsage = get_memory_usage(); printf("Memory size %" VL_PRI64 "d bytes\n", firstUsage); - int loops = 100*1000; + int loops = 10; for (int left = loops; left > 0;) { - for (int j = 0; j < 1000; ++j, --left) { + for (int j = 0; j < 1; ++j, --left) { make_and_destroy(); } } diff --git a/test_regress/t/t_trace_dumporder_bad.out b/test_regress/t/t_trace_dumporder_bad.out new file mode 100644 index 000000000..f73b7d67a --- /dev/null +++ b/test_regress/t/t_trace_dumporder_bad.out @@ -0,0 +1,2 @@ +%Warning: $dumpvar ignored as not proceeded by $dumpfile +*-* All Finished *-* diff --git a/test_regress/t/t_trace_dumporder_bad.pl b/test_regress/t/t_trace_dumporder_bad.pl new file mode 100755 index 000000000..cae730749 --- /dev/null +++ b/test_regress/t/t_trace_dumporder_bad.pl @@ -0,0 +1,22 @@ +#!/usr/bin/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. + +scenarios(vlt => 1); + +compile( + verilator_flags2 => ["-trace"], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_trace_dumporder_bad.v b/test_regress/t/t_trace_dumporder_bad.v new file mode 100644 index 000000000..fe443f75e --- /dev/null +++ b/test_regress/t/t_trace_dumporder_bad.v @@ -0,0 +1,13 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2020 by Wilson Snyder. + +module t(/*AUTOARG*/); + initial begin + // Check error when this missing: $dumpfile("/should/not/be/opened"); + $dumpvars; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_trace_flag_off.out b/test_regress/t/t_trace_flag_off.out new file mode 100644 index 000000000..680eb2bcf --- /dev/null +++ b/test_regress/t/t_trace_flag_off.out @@ -0,0 +1,2 @@ +-Info: t/t_trace_flag_off.v:9: $dumpvar ignored, as Verilated without --trace +*-* All Finished *-* diff --git a/test_regress/t/t_trace_flag_off.pl b/test_regress/t/t_trace_flag_off.pl new file mode 100755 index 000000000..bc3f03af6 --- /dev/null +++ b/test_regress/t/t_trace_flag_off.pl @@ -0,0 +1,22 @@ +#!/usr/bin/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. + +# Test that without --trace we get a message when turning on traces +scenarios(vlt => 1); + +compile( + ); + +execute( + expect_filename => $Self->{golden_filename}, + fails => 0, + ); + +ok(1); +1; diff --git a/test_regress/t/t_trace_flag_off.v b/test_regress/t/t_trace_flag_off.v new file mode 100644 index 000000000..b8348526f --- /dev/null +++ b/test_regress/t/t_trace_flag_off.v @@ -0,0 +1,13 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2020 by Wilson Snyder. + +module t(/*AUTOARG*/); + initial begin + $dumpfile("/should/not/be/opened"); + $dumpvars(); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_trace_two_a.v b/test_regress/t/t_trace_two_a.v index da58afecc..86533cc90 100644 --- a/test_regress/t/t_trace_two_a.v +++ b/test_regress/t/t_trace_two_a.v @@ -3,6 +3,9 @@ // This file ONLY is placed into the Public Domain, for any use, // without warranty, 2020 by Wilson Snyder. +`define CONCAT(a, b) a``b +`define STRINGIFY(x) `"x`" + module t (/*AUTOARG*/ // Inputs clk @@ -15,11 +18,55 @@ module t (/*AUTOARG*/ sub sub (); + // verilator tracing_off + string filename; + // verilator tracing_on + + initial begin +`ifdef TEST_FST + filename = {`STRINGIFY(`TEST_OBJ_DIR), "/simx.fst"}; +`else + filename = {`STRINGIFY(`TEST_OBJ_DIR), "/simx.vcd"}; +`endif + +`ifdef TEST_DUMP + $dumpfile(filename); + $dumpvars(0, top); + $dumplimit(10 * 1024 * 1024); +`elsif TEST_DUMPPORTS + $dumpports(top, filename); + $dumpportslimit(10 * 1024 * 1024, filename); +`endif + end + always @ (posedge clk) begin if (cyc != 0) begin cyc <= cyc + 1; c_trace_on <= cyc + 2; - if (cyc == 10) begin + if (cyc == 3) begin +`ifdef TEST_DUMP + $dumpoff; +`elsif TEST_DUMPPORTS + $dumpportsoff(filename); +`endif + end + else if (cyc == 5) begin +`ifdef TEST_DUMP + $dumpall; + $dumpflush; +`elsif TEST_DUMPPORTS + $dumpportsall(filename); + $dumpportsflush(filename); +`endif + end + else if (cyc == 7) begin +`ifdef TEST_DUMP + $dumpon; +`elsif TEST_DUMPPORTS + $dumpportson(filename); +`endif + end + else if (cyc == 10) begin $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_trace_two_hdr_cc.cpp b/test_regress/t/t_trace_two_cc.cpp similarity index 72% rename from test_regress/t/t_trace_two_hdr_cc.cpp rename to test_regress/t/t_trace_two_cc.cpp index 9b8bcf395..3eb7c0baa 100644 --- a/test_regress/t/t_trace_two_hdr_cc.cpp +++ b/test_regress/t/t_trace_two_cc.cpp @@ -9,7 +9,13 @@ #include VM_PREFIX_INCLUDE #include "Vt_trace_two_b.h" #include "verilated.h" -#include "verilated_vcd_c.h" +#ifdef TEST_HDR_TRACE +# ifdef TEST_FST +# include "verilated_fst_c.h" +# else +# include "verilated_vcd_c.h" +# endif +#endif // Compile in place #include "Vt_trace_two_b.cpp" @@ -26,18 +32,28 @@ int main(int argc, char** argv, char** env) { double sim_time = 1100; Verilated::commandArgs(argc, argv); Verilated::debug(0); + Verilated::traceEverOn(true); srand48(5); ap = new VM_PREFIX("topa"); bp = new Vt_trace_two_b("topb"); - ap->eval(); - bp->eval(); + ap->eval_step(); + bp->eval_step(); + ap->eval_end_step(); + bp->eval_end_step(); -#if VM_TRACE +#ifdef TEST_HDR_TRACE Verilated::traceEverOn(true); +# ifdef TEST_FST + VerilatedFstC* tfp = new VerilatedFstC; + ap->trace(tfp, 99); + bp->trace(tfp, 99); + tfp->open(VL_STRINGIFY(TEST_OBJ_DIR) "/simx.fst"); +# else VerilatedVcdC* tfp = new VerilatedVcdC; ap->trace(tfp, 99); bp->trace(tfp, 99); tfp->open(VL_STRINGIFY(TEST_OBJ_DIR) "/simx.vcd"); +# endif if (tfp) tfp->dump(main_time); #endif { @@ -48,11 +64,13 @@ int main(int argc, char** argv, char** env) { while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { ap->clk = !ap->clk; bp->clk = ap->clk; - ap->eval(); - bp->eval(); -#if VM_TRACE + ap->eval_step(); + bp->eval_step(); + ap->eval_end_step(); + bp->eval_end_step(); +#ifdef TEST_HDR_TRACE if (tfp) tfp->dump(main_time); -#endif // VM_TRACE +#endif main_time += 5; } if (!Verilated::gotFinish()) { @@ -60,9 +78,9 @@ int main(int argc, char** argv, char** env) { } ap->final(); bp->final(); -#if VM_TRACE +#ifdef TEST_HDR_TRACE if (tfp) tfp->close(); -#endif // VM_TRACE +#endif VL_DO_DANGLING(delete ap, ap); VL_DO_DANGLING(delete bp, bp); diff --git a/test_regress/t/t_trace_two_dump_cc.out b/test_regress/t/t_trace_two_dump_cc.out new file mode 100644 index 000000000..466b4c432 --- /dev/null +++ b/test_regress/t/t_trace_two_dump_cc.out @@ -0,0 +1,102 @@ +$version Generated by VerilatedVcd $end +$date Sun Mar 1 20:48:56 2020 + $end +$timescale 1ns $end + + $scope module topa $end + $var wire 1 3 clk $end + $scope module t $end + $var wire 32 + c_trace_on [31:0] $end + $var wire 1 3 clk $end + $var wire 32 # cyc [31:0] $end + $scope module sub $end + $var wire 32 ; inside_sub_a [31:0] $end + $upscope $end + $upscope $end + $upscope $end +$enddefinitions $end + + +#0 +b00000000000000000000000000000001 # +b00000000000000000000000000000000 + +03 +b00000000000000000000000000000001 ; +#0 +#10 +#10 +b00000000000000000000000000000010 # +b00000000000000000000000000000011 + +13 +#15 +#15 +03 +#20 +#20 +b00000000000000000000000000000011 # +b00000000000000000000000000000100 + +13 +#25 +#25 +03 +#30 +#30 +b00000000000000000000000000000100 # +b00000000000000000000000000000101 + +13 +#35 +#35 +03 +#40 +#40 +b00000000000000000000000000000101 # +b00000000000000000000000000000110 + +13 +#45 +#45 +03 +#50 +#50 +b00000000000000000000000000000110 # +b00000000000000000000000000000111 + +13 +#55 +#55 +03 +#60 +#60 +b00000000000000000000000000000111 # +b00000000000000000000000000001000 + +13 +#65 +#65 +03 +#70 +#70 +b00000000000000000000000000001000 # +b00000000000000000000000000001001 + +13 +#75 +#75 +03 +#80 +#80 +b00000000000000000000000000001001 # +b00000000000000000000000000001010 + +13 +#85 +#85 +03 +#90 +#90 +b00000000000000000000000000001010 # +b00000000000000000000000000001011 + +13 +#95 +#95 +03 +#100 +#100 +b00000000000000000000000000001011 # +b00000000000000000000000000001100 + +13 diff --git a/test_regress/t/t_trace_two_dump_cc.pl b/test_regress/t/t_trace_two_dump_cc.pl new file mode 100755 index 000000000..2d3e34fd4 --- /dev/null +++ b/test_regress/t/t_trace_two_dump_cc.pl @@ -0,0 +1,40 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2020 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. + +# Test tracing with two models instanced +scenarios(vlt_all => 1); + +top_filename("t_trace_two_a.v"); + +compile( + make_main => 0, + verilator_make_gmake => 0, + top_filename => 't_trace_two_b.v', + VM_PREFIX => 'Vt_trace_two_b', + verilator_flags2 => ['-trace'], + ); + +compile( + make_main => 0, + top_filename => 't_trace_two_a.v', + verilator_flags2 => ['-exe', '-trace', "$Self->{t_dir}/t_trace_two_cc.cpp"], + v_flags2 => ['+define+TEST_DUMP'], + ); + +execute( + check_finished => 1, + ); + +if ($Self->{vlt_all}) { + file_grep("$Self->{obj_dir}/simx.vcd", qr/\$enddefinitions/x); + vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); +} + +ok(1); +1; diff --git a/test_regress/t/t_trace_two_dump_sc.out b/test_regress/t/t_trace_two_dump_sc.out new file mode 100644 index 000000000..a9f2fe8aa --- /dev/null +++ b/test_regress/t/t_trace_two_dump_sc.out @@ -0,0 +1,81 @@ +$version Generated by VerilatedVcd $end +$date Sun Mar 1 20:49:13 2020 + $end +$timescale 1ps $end + + $scope module topa $end + $scope module t $end + $var wire 32 3 c_trace_on [31:0] $end + $var wire 1 # clk $end + $var wire 32 + cyc [31:0] $end + $scope module sub $end + $var wire 32 ; inside_sub_a [31:0] $end + $upscope $end + $upscope $end + $upscope $end +$enddefinitions $end + + +#0 +0# +b00000000000000000000000000000001 + +b00000000000000000000000000000000 3 +b00000000000000000000000000000001 ; +#10000 +1# +b00000000000000000000000000000010 + +b00000000000000000000000000000011 3 +#15000 +0# +#20000 +1# +b00000000000000000000000000000011 + +b00000000000000000000000000000100 3 +#25000 +0# +#30000 +1# +b00000000000000000000000000000100 + +b00000000000000000000000000000101 3 +#35000 +0# +#40000 +1# +b00000000000000000000000000000101 + +b00000000000000000000000000000110 3 +#45000 +0# +#50000 +1# +b00000000000000000000000000000110 + +b00000000000000000000000000000111 3 +#55000 +0# +#60000 +1# +b00000000000000000000000000000111 + +b00000000000000000000000000001000 3 +#65000 +0# +#70000 +1# +b00000000000000000000000000001000 + +b00000000000000000000000000001001 3 +#75000 +0# +#80000 +1# +b00000000000000000000000000001001 + +b00000000000000000000000000001010 3 +#85000 +0# +#90000 +1# +b00000000000000000000000000001010 + +b00000000000000000000000000001011 3 +#95000 +0# +#100000 +1# +b00000000000000000000000000001011 + +b00000000000000000000000000001100 3 diff --git a/test_regress/t/t_trace_two_dump_sc.pl b/test_regress/t/t_trace_two_dump_sc.pl new file mode 100755 index 000000000..6579e2cec --- /dev/null +++ b/test_regress/t/t_trace_two_dump_sc.pl @@ -0,0 +1,45 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2020 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. + +scenarios(simulator => 1); + +if (!$Self->have_sc) { + skip("No SystemC installed"); +} +else { + top_filename("t_trace_two_a.v"); + + compile( + make_main => 0, + verilator_make_gmake => 0, + top_filename => 't_trace_two_b.v', + VM_PREFIX => 'Vt_trace_two_b', + verilator_flags2 => ['-sc -trace'], + ); + + compile( + make_main => 0, + top_filename => 't_trace_two_a.v', + verilator_flags2 => ['-sc', '-exe', '-trace', + "$Self->{t_dir}/t_trace_two_sc.cpp"], + v_flags2 => ['+define+TEST_DUMP'], + ); + + execute( + check_finished => 1, + ); + + if ($Self->{vlt_all}) { + file_grep("$Self->{obj_dir}/simx.vcd", qr/\$enddefinitions/x); + vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); + } +} + +ok(1); +1; diff --git a/test_regress/t/t_trace_two_dumpfst_cc.out b/test_regress/t/t_trace_two_dumpfst_cc.out new file mode 100755 index 000000000..9141e9a39 --- /dev/null +++ b/test_regress/t/t_trace_two_dumpfst_cc.out @@ -0,0 +1,83 @@ +$date + Sun Mar 1 21:31:56 2020 + +$end +$version + fstWriter +$end +$timescale + 1ns +$end +$scope module topa $end +$var wire 1 ! clk $end +$scope module t $end +$var wire 1 ! clk $end +$var integer 32 " cyc $end +$var integer 32 # c_trace_on $end +$scope module sub $end +$var integer 32 $ inside_sub_a $end +$upscope $end +$upscope $end +$upscope $end +$enddefinitions $end +$dumpvars +#0 +0! +#10 +1! +b00000000000000000000000000000011 # +b00000000000000000000000000000010 " +#15 +0! +#20 +1! +b00000000000000000000000000000011 " +b00000000000000000000000000000100 # +#25 +0! +#30 +1! +b00000000000000000000000000000101 # +b00000000000000000000000000000100 " +#35 +0! +#40 +1! +b00000000000000000000000000000101 " +b00000000000000000000000000000110 # +#45 +0! +#50 +1! +b00000000000000000000000000000111 # +b00000000000000000000000000000110 " +#55 +0! +#60 +1! +b00000000000000000000000000000111 " +b00000000000000000000000000001000 # +#65 +0! +#70 +1! +b00000000000000000000000000001001 # +b00000000000000000000000000001000 " +#75 +0! +#80 +1! +b00000000000000000000000000001001 " +b00000000000000000000000000001010 # +#85 +0! +#90 +1! +b00000000000000000000000000001011 # +b00000000000000000000000000001010 " +#95 +0! +#100 +1! +b00000000000000000000000000001011 " +b00000000000000000000000000001100 # diff --git a/test_regress/t/t_trace_two_dumpfst_cc.pl b/test_regress/t/t_trace_two_dumpfst_cc.pl new file mode 100755 index 000000000..f19d777c0 --- /dev/null +++ b/test_regress/t/t_trace_two_dumpfst_cc.pl @@ -0,0 +1,42 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2020 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. + +# Test tracing with two models instanced +scenarios(vlt_all => 1); + +top_filename("t_trace_two_a.v"); + +compile( + make_main => 0, + verilator_make_gmake => 0, + top_filename => 't_trace_two_b.v', + VM_PREFIX => 'Vt_trace_two_b', + verilator_flags2 => ['--trace-fst-thread -DTEST_FST'], + ); + +compile( + make_main => 0, + top_filename => 't_trace_two_a.v', + verilator_flags2 => ['-exe', '--trace-fst-thread', + '-DTEST_FST', + "$Self->{t_dir}/t_trace_two_cc.cpp"], + v_flags2 => ['+define+TEST_DUMP'], + ); + +execute( + check_finished => 1, + ); + +if ($Self->{vlt_all}) { + fst2vcd($Self->trace_filename, "$Self->{obj_dir}/simx-fst2vcd.vcd"); + vcd_identical("$Self->{obj_dir}/simx-fst2vcd.vcd", $Self->{golden_filename}); +} + +ok(1); +1; diff --git a/test_regress/t/t_trace_two_hdr_cc.pl b/test_regress/t/t_trace_two_hdr_cc.pl index 3601322e4..1fbe3fd38 100755 --- a/test_regress/t/t_trace_two_hdr_cc.pl +++ b/test_regress/t/t_trace_two_hdr_cc.pl @@ -23,7 +23,8 @@ compile( compile( make_main => 0, top_filename => 't_trace_two_a.v', - verilator_flags2 => ['-exe', '-trace', "$Self->{t_dir}/t_trace_two_hdr_cc.cpp"], + make_flags => 'CPPFLAGS_ADD=-DTEST_HDR_TRACE=1', + verilator_flags2 => ['-exe', '-trace', "$Self->{t_dir}/t_trace_two_cc.cpp"], ); execute( diff --git a/test_regress/t/t_trace_two_hdr_sc.pl b/test_regress/t/t_trace_two_hdr_sc.pl index 3c8de5b0b..7cbd882a0 100755 --- a/test_regress/t/t_trace_two_hdr_sc.pl +++ b/test_regress/t/t_trace_two_hdr_sc.pl @@ -26,8 +26,9 @@ else { compile( make_main => 0, top_filename => 't_trace_two_a.v', + make_flags => 'CPPFLAGS_ADD=-DTEST_HDR_TRACE', verilator_flags2 => ['-sc', '-exe', '-trace', - "$Self->{t_dir}/t_trace_two_hdr_sc.cpp"], + "$Self->{t_dir}/t_trace_two_sc.cpp"], ); execute( diff --git a/test_regress/t/t_trace_two_hdrfst_cc.out b/test_regress/t/t_trace_two_hdrfst_cc.out new file mode 100755 index 0000000000000000000000000000000000000000..a7289d36eacaf3a8b413ea09f4599659c18f2aee GIT binary patch literal 2097 zcmb`HKX2497{;^K1E1l&I_+#Hx$B>W4W>?j7*Dyxhoa_^$WDrw`Y9ONwKIa1p&y`C zH^k7b5)u*;h^h+{YTr1ixr$;3!K(~+$(!f*K9BAAXd9%dsBk7l*oe%$+sdzxA3u0=`Yw9??dQJdUA_JB=;JfbgHUUIdk@L_e`jT-VP7idjHVt{a^O}pB@?id_?e~eB1_x7sb=r-E$vEfgK^U=SKHvDAMw))2<(*7rgzcGl9?>YTzZJcqg>$7b}x?%X6!}+MK57@yM zo3_J$xBi=kzcrBWUVl6ydjFs4`f8hzZW%tNHsk|<;`#${t?Ro@+#Ue(a3kLUTedVx literal 0 HcmV?d00001 diff --git a/test_regress/t/t_trace_two_hdrfst_cc.pl b/test_regress/t/t_trace_two_hdrfst_cc.pl new file mode 100755 index 000000000..514eca86d --- /dev/null +++ b/test_regress/t/t_trace_two_hdrfst_cc.pl @@ -0,0 +1,42 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2020 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. + +# Test tracing with two models instanced +scenarios(vlt_all => 1); + +top_filename("t_trace_two_a.v"); + +compile( + make_main => 0, + verilator_make_gmake => 0, + top_filename => 't_trace_two_b.v', + VM_PREFIX => 'Vt_trace_two_b', + verilator_flags2 => ['--trace-fst-thread'], + ); + +compile( + make_main => 0, + top_filename => 't_trace_two_a.v', + make_flags => 'CPPFLAGS_ADD="-DTEST_HDR_TRACE=1 -DTEST_FST=1"', + verilator_flags2 => ['-exe', '--trace-fst-thread', + '-DTEST_FST', + "$Self->{t_dir}/t_trace_two_cc.cpp"], + ); + +execute( + check_finished => 1, + ); + +if ($Self->{vlt_all}) { + fst2vcd($Self->trace_filename, "$Self->{obj_dir}/simx-fst2vcd.vcd"); + vcd_identical("$Self->{obj_dir}/simx-fst2vcd.vcd", $Self->{golden_filename}); +} + +ok(1); +1; diff --git a/test_regress/t/t_trace_two_port_cc.out b/test_regress/t/t_trace_two_port_cc.out new file mode 100644 index 000000000..dd2f3213c --- /dev/null +++ b/test_regress/t/t_trace_two_port_cc.out @@ -0,0 +1,102 @@ +$version Generated by VerilatedVcd $end +$date Sun Mar 1 21:32:13 2020 + $end +$timescale 1ns $end + + $scope module topa $end + $var wire 1 3 clk $end + $scope module t $end + $var wire 32 + c_trace_on [31:0] $end + $var wire 1 3 clk $end + $var wire 32 # cyc [31:0] $end + $scope module sub $end + $var wire 32 ; inside_sub_a [31:0] $end + $upscope $end + $upscope $end + $upscope $end +$enddefinitions $end + + +#0 +b00000000000000000000000000000001 # +b00000000000000000000000000000000 + +03 +b00000000000000000000000000000001 ; +#0 +#10 +#10 +b00000000000000000000000000000010 # +b00000000000000000000000000000011 + +13 +#15 +#15 +03 +#20 +#20 +b00000000000000000000000000000011 # +b00000000000000000000000000000100 + +13 +#25 +#25 +03 +#30 +#30 +b00000000000000000000000000000100 # +b00000000000000000000000000000101 + +13 +#35 +#35 +03 +#40 +#40 +b00000000000000000000000000000101 # +b00000000000000000000000000000110 + +13 +#45 +#45 +03 +#50 +#50 +b00000000000000000000000000000110 # +b00000000000000000000000000000111 + +13 +#55 +#55 +03 +#60 +#60 +b00000000000000000000000000000111 # +b00000000000000000000000000001000 + +13 +#65 +#65 +03 +#70 +#70 +b00000000000000000000000000001000 # +b00000000000000000000000000001001 + +13 +#75 +#75 +03 +#80 +#80 +b00000000000000000000000000001001 # +b00000000000000000000000000001010 + +13 +#85 +#85 +03 +#90 +#90 +b00000000000000000000000000001010 # +b00000000000000000000000000001011 + +13 +#95 +#95 +03 +#100 +#100 +b00000000000000000000000000001011 # +b00000000000000000000000000001100 + +13 diff --git a/test_regress/t/t_trace_two_port_cc.pl b/test_regress/t/t_trace_two_port_cc.pl new file mode 100755 index 000000000..31abb926b --- /dev/null +++ b/test_regress/t/t_trace_two_port_cc.pl @@ -0,0 +1,40 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2020 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. + +# Test tracing with two models instanced +scenarios(vlt_all => 1); + +top_filename("t_trace_two_a.v"); + +compile( + make_main => 0, + verilator_make_gmake => 0, + top_filename => 't_trace_two_b.v', + VM_PREFIX => 'Vt_trace_two_b', + verilator_flags2 => ['-trace'], + ); + +compile( + make_main => 0, + top_filename => 't_trace_two_a.v', + verilator_flags2 => ['-exe', '-trace', "$Self->{t_dir}/t_trace_two_cc.cpp"], + v_flags2 => ['+define+TEST_DUMPPORTS'], + ); + +execute( + check_finished => 1, + ); + +if ($Self->{vlt_all}) { + file_grep("$Self->{obj_dir}/simx.vcd", qr/\$enddefinitions/x); + vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); +} + +ok(1); +1; diff --git a/test_regress/t/t_trace_two_port_sc.out b/test_regress/t/t_trace_two_port_sc.out new file mode 100644 index 000000000..af8668106 --- /dev/null +++ b/test_regress/t/t_trace_two_port_sc.out @@ -0,0 +1,81 @@ +$version Generated by VerilatedVcd $end +$date Sun Mar 1 21:32:22 2020 + $end +$timescale 1ps $end + + $scope module topa $end + $scope module t $end + $var wire 32 3 c_trace_on [31:0] $end + $var wire 1 # clk $end + $var wire 32 + cyc [31:0] $end + $scope module sub $end + $var wire 32 ; inside_sub_a [31:0] $end + $upscope $end + $upscope $end + $upscope $end +$enddefinitions $end + + +#0 +0# +b00000000000000000000000000000001 + +b00000000000000000000000000000000 3 +b00000000000000000000000000000001 ; +#10000 +1# +b00000000000000000000000000000010 + +b00000000000000000000000000000011 3 +#15000 +0# +#20000 +1# +b00000000000000000000000000000011 + +b00000000000000000000000000000100 3 +#25000 +0# +#30000 +1# +b00000000000000000000000000000100 + +b00000000000000000000000000000101 3 +#35000 +0# +#40000 +1# +b00000000000000000000000000000101 + +b00000000000000000000000000000110 3 +#45000 +0# +#50000 +1# +b00000000000000000000000000000110 + +b00000000000000000000000000000111 3 +#55000 +0# +#60000 +1# +b00000000000000000000000000000111 + +b00000000000000000000000000001000 3 +#65000 +0# +#70000 +1# +b00000000000000000000000000001000 + +b00000000000000000000000000001001 3 +#75000 +0# +#80000 +1# +b00000000000000000000000000001001 + +b00000000000000000000000000001010 3 +#85000 +0# +#90000 +1# +b00000000000000000000000000001010 + +b00000000000000000000000000001011 3 +#95000 +0# +#100000 +1# +b00000000000000000000000000001011 + +b00000000000000000000000000001100 3 diff --git a/test_regress/t/t_trace_two_port_sc.pl b/test_regress/t/t_trace_two_port_sc.pl new file mode 100755 index 000000000..177f24f65 --- /dev/null +++ b/test_regress/t/t_trace_two_port_sc.pl @@ -0,0 +1,45 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2020 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. + +scenarios(simulator => 1); + +if (!$Self->have_sc) { + skip("No SystemC installed"); +} +else { + top_filename("t_trace_two_a.v"); + + compile( + make_main => 0, + verilator_make_gmake => 0, + top_filename => 't_trace_two_b.v', + VM_PREFIX => 'Vt_trace_two_b', + verilator_flags2 => ['-sc -trace'], + ); + + compile( + make_main => 0, + top_filename => 't_trace_two_a.v', + verilator_flags2 => ['-sc', '-exe', '-trace', + "$Self->{t_dir}/t_trace_two_sc.cpp"], + v_flags2 => ['+define+TEST_DUMPPORTS'], + ); + + execute( + check_finished => 1, + ); + + if ($Self->{vlt_all}) { + file_grep("$Self->{obj_dir}/simx.vcd", qr/\$enddefinitions/x); + vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); + } +} + +ok(1); +1; diff --git a/test_regress/t/t_trace_two_portfst_cc.out b/test_regress/t/t_trace_two_portfst_cc.out new file mode 100755 index 000000000..ec99d954e --- /dev/null +++ b/test_regress/t/t_trace_two_portfst_cc.out @@ -0,0 +1,83 @@ +$date + Sun Mar 1 21:32:04 2020 + +$end +$version + fstWriter +$end +$timescale + 1ns +$end +$scope module topa $end +$var wire 1 ! clk $end +$scope module t $end +$var wire 1 ! clk $end +$var integer 32 " cyc $end +$var integer 32 # c_trace_on $end +$scope module sub $end +$var integer 32 $ inside_sub_a $end +$upscope $end +$upscope $end +$upscope $end +$enddefinitions $end +$dumpvars +#0 +0! +#10 +1! +b00000000000000000000000000000011 # +b00000000000000000000000000000010 " +#15 +0! +#20 +1! +b00000000000000000000000000000011 " +b00000000000000000000000000000100 # +#25 +0! +#30 +1! +b00000000000000000000000000000101 # +b00000000000000000000000000000100 " +#35 +0! +#40 +1! +b00000000000000000000000000000101 " +b00000000000000000000000000000110 # +#45 +0! +#50 +1! +b00000000000000000000000000000111 # +b00000000000000000000000000000110 " +#55 +0! +#60 +1! +b00000000000000000000000000000111 " +b00000000000000000000000000001000 # +#65 +0! +#70 +1! +b00000000000000000000000000001001 # +b00000000000000000000000000001000 " +#75 +0! +#80 +1! +b00000000000000000000000000001001 " +b00000000000000000000000000001010 # +#85 +0! +#90 +1! +b00000000000000000000000000001011 # +b00000000000000000000000000001010 " +#95 +0! +#100 +1! +b00000000000000000000000000001011 " +b00000000000000000000000000001100 # diff --git a/test_regress/t/t_trace_two_portfst_cc.pl b/test_regress/t/t_trace_two_portfst_cc.pl new file mode 100755 index 000000000..cb21e0f34 --- /dev/null +++ b/test_regress/t/t_trace_two_portfst_cc.pl @@ -0,0 +1,42 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2020 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. + +# Test tracing with two models instanced +scenarios(vlt_all => 1); + +top_filename("t_trace_two_a.v"); + +compile( + make_main => 0, + verilator_make_gmake => 0, + top_filename => 't_trace_two_b.v', + VM_PREFIX => 'Vt_trace_two_b', + verilator_flags2 => ['--trace-fst-thread'], + ); + +compile( + make_main => 0, + top_filename => 't_trace_two_a.v', + verilator_flags2 => ['-exe', '--trace-fst-thread', + '-DTEST_FST', + "$Self->{t_dir}/t_trace_two_cc.cpp"], + v_flags2 => ['+define+TEST_DUMPPORTS'], + ); + +execute( + check_finished => 1, + ); + +if ($Self->{vlt_all}) { + fst2vcd($Self->trace_filename, "$Self->{obj_dir}/simx-fst2vcd.vcd"); + vcd_identical("$Self->{obj_dir}/simx-fst2vcd.vcd", $Self->{golden_filename}); +} + +ok(1); +1; diff --git a/test_regress/t/t_trace_two_hdr_sc.cpp b/test_regress/t/t_trace_two_sc.cpp similarity index 93% rename from test_regress/t/t_trace_two_hdr_sc.cpp rename to test_regress/t/t_trace_two_sc.cpp index dce33a0e1..c3c1d12ac 100644 --- a/test_regress/t/t_trace_two_hdr_sc.cpp +++ b/test_regress/t/t_trace_two_sc.cpp @@ -9,7 +9,9 @@ #include VM_PREFIX_INCLUDE #include "Vt_trace_two_b.h" #include "verilated.h" -#include "verilated_vcd_c.h" +#ifdef TEST_HDR_TRACE +# include "verilated_vcd_sc.h" +#endif // Compile in place #include "Vt_trace_two_b.cpp" @@ -20,7 +22,6 @@ // General headers #include "verilated.h" #include "systemc.h" -#include "verilated_vcd_sc.h" VM_PREFIX* ap; Vt_trace_two_b* bp; @@ -29,6 +30,7 @@ int sc_main(int argc, char** argv) { sc_signal clk; sc_time sim_time(1100, SC_NS); Verilated::commandArgs(argc, argv); + Verilated::traceEverOn(true); Verilated::debug(0); srand48(5); ap = new VM_PREFIX("topa"); @@ -36,8 +38,7 @@ int sc_main(int argc, char** argv) { ap->clk(clk); bp->clk(clk); -#if VM_TRACE - Verilated::traceEverOn(true); +#ifdef TEST_HDR_TRACE VerilatedVcdSc* tfp = new VerilatedVcdSc; ap->trace(tfp, 99); bp->trace(tfp, 99); @@ -64,9 +65,9 @@ int sc_main(int argc, char** argv) { } ap->final(); bp->final(); -#if VM_TRACE +#ifdef TEST_HDR_TRACE if (tfp) tfp->close(); -#endif // VM_TRACE +#endif VL_DO_DANGLING(delete ap, ap); VL_DO_DANGLING(delete bp, bp); From 905067d13f3abfcec61c5d2367312a10e3410ca3 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 2 Mar 2020 07:43:10 -0500 Subject: [PATCH 29/50] Fix $dumpvar multithreaded assert, broke last commit. --- include/verilated.h | 8 +++++++- include/verilated_fst_c.h | 3 +++ include/verilated_vcd_c.h | 4 ++++ src/V3EmitC.cpp | 1 + 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/verilated.h b/include/verilated.h index 97becf9c3..90aa9ff53 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -201,13 +201,19 @@ public: /// Check that the current thread ID is the same as the construction thread ID void check() VL_MT_UNSAFE_ONE { if (VL_UNCOVERABLE(m_threadid != VL_THREAD_ID())) { - fatal_different(); // LCOV_EXCL_LINE + if (m_threadid == 0) { + m_threadid = VL_THREAD_ID(); + } else { + fatal_different(); // LCOV_EXCL_LINE + } } } + void changeThread() { m_threadid = 0; } // Allow intentional change-of-thread static void fatal_different() VL_MT_SAFE; #else // !VL_THREADED || !VL_DEBUG public: void check() {} + void changeThread() {} #endif }; diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index f6de80bb9..d9c0c6281 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -66,6 +66,7 @@ private: public: explicit VerilatedFst(void* fst=NULL); ~VerilatedFst() { if (m_fst == NULL) { fstWriterClose(m_fst); } } + void changeThread() { m_assertOne.changeThread(); } bool isOpen() const { return m_fst != NULL; } void open(const char* filename) VL_MT_UNSAFE; void flush() VL_MT_UNSAFE { fstWriterFlushContext(m_fst); } @@ -199,6 +200,8 @@ class VerilatedFstC { public: explicit VerilatedFstC(void* filep=NULL) : m_sptrace(filep) {} ~VerilatedFstC() { close(); } + /// Routines can only be called from one thread; allow next call from different thread + void changeThread() { spTrace()->changeThread(); } public: // ACCESSORS /// Is file open? diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index 690e3ec31..f0a5bcb9f 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -159,6 +159,8 @@ private: public: explicit VerilatedVcd(VerilatedVcdFile* filep = NULL); ~VerilatedVcd(); + /// Routines can only be called from one thread; allow next call from different thread + void changeThread() { m_assertOne.changeThread(); } // ACCESSORS /// Set size in megabytes after which new file should be created @@ -446,6 +448,8 @@ public: explicit VerilatedVcdC(VerilatedVcdFile* filep = NULL) : m_sptrace(filep) {} ~VerilatedVcdC() { close(); } + /// Routines can only be called from one thread; allow next call from different thread + void changeThread() { spTrace()->changeThread(); } public: // ACCESSORS /// Is file open? diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index e4efa36e9..529498764 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -3088,6 +3088,7 @@ class EmitCTrace : EmitCStmts { puts( "const char* cp = vl_dumpctl_filenamep();\n"); puts( "trace(__VlSymsp->__Vm_dumperp, 0, 0);\n"); puts( "__VlSymsp->__Vm_dumperp->open(vl_dumpctl_filenamep());\n"); + puts( "__VlSymsp->__Vm_dumperp->changeThread();\n"); puts( "}\n"); puts("}\n"); splitSizeInc(10); From a7e65379fa7946fe7c628b17dbb4d272523d331a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 2 Mar 2020 17:56:42 -0500 Subject: [PATCH 30/50] Ignore $dumpflush, think causes travis thread error. --- src/V3EmitC.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 529498764..ffe1bab79 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -426,7 +426,8 @@ public: // $dumpall currently ignored break; case VDumpCtlType::FLUSH: - puts("Verilated::flushCall();\n"); // Also flush stdio, as need lock + // $dumpall currently ignored; would need rework of VCD single thread, + // or flag we pass-through to next eval() iteration break; case VDumpCtlType::LIMIT: // $dumplimit currently ignored From fd656f6cc1f2f2448e892f86d1d0b745348e8fa2 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 3 Mar 2020 19:19:50 -0500 Subject: [PATCH 31/50] Fix clang asserted missing lock on m_dumping. --- src/V3EmitC.cpp | 11 ++++++----- src/V3EmitCSyms.cpp | 6 +++++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index ffe1bab79..d5e4f9b66 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -2156,7 +2156,7 @@ void EmitCImp::emitDestructorImp(AstNodeModule* modp) { // Call via function in __Trace.cpp as this .cpp file does not have trace header if (v3Global.needTraceDumper()) { puts("#ifdef VM_TRACE\n"); - puts("if (VL_UNLIKELY(__VlSymsp->__Vm_dumperp)) _traceDumpClose();\n"); + puts("if (VL_UNLIKELY(__VlSymsp->__Vm_dumping)) _traceDumpClose();\n"); puts("#endif // VM_TRACE\n"); } } @@ -2368,7 +2368,7 @@ void EmitCImp::emitWrapEval(AstNodeModule* modp) { putsDecoration("// Tracing\n"); // SystemC's eval loop deals with calling trace, not us if (v3Global.needTraceDumper() && !optSystemC()) { - puts("if (VL_UNLIKELY(vlSymsp->__Vm_dumperp)) _traceDump();\n"); + puts("if (VL_UNLIKELY(vlSymsp->__Vm_dumping)) _traceDump();\n"); } puts("#endif // VM_TRACE\n"); } @@ -2443,7 +2443,7 @@ void EmitCImp::emitWrapEval(AstNodeModule* modp) { puts(EmitCBaseVisitor::symTopAssign()+"\n"); putsDecoration("// Tracing\n"); // SystemC's eval loop deals with calling trace, not us - puts("if (VL_UNLIKELY(vlSymsp->__Vm_dumperp)) _traceDump();\n"); + puts("if (VL_UNLIKELY(vlSymsp->__Vm_dumping)) _traceDump();\n"); puts("#endif // VM_TRACE\n"); puts("}\n"); } @@ -3083,20 +3083,21 @@ class EmitCTrace : EmitCStmts { if (v3Global.needTraceDumper()) { puts("void " + topClassName() + "::_traceDumpOpen() {\n"); + puts( "VerilatedLockGuard lock(__VlSymsp->__Vm_dumperMutex);\n"); puts( "if (VL_UNLIKELY(!__VlSymsp->__Vm_dumperp)) {\n"); - puts( "VerilatedLockGuard lock(__VlSymsp->__Vm_dumperMutex);\n"); puts( "__VlSymsp->__Vm_dumperp = new " + v3Global.opt.traceClassLang() + "();\n"); puts( "const char* cp = vl_dumpctl_filenamep();\n"); puts( "trace(__VlSymsp->__Vm_dumperp, 0, 0);\n"); puts( "__VlSymsp->__Vm_dumperp->open(vl_dumpctl_filenamep());\n"); puts( "__VlSymsp->__Vm_dumperp->changeThread();\n"); + puts( "__VlSymsp->__Vm_dumping = true;\n"); puts( "}\n"); puts("}\n"); splitSizeInc(10); puts("void " + topClassName() + "::_traceDumpClose() {\n"); - // Caller checked for __Vm_dumperp non-NULL puts( "VerilatedLockGuard lock(__VlSymsp->__Vm_dumperMutex);\n"); + puts( "__VlSymsp->__Vm_dumping = false;\n"); puts( "delete __VlSymsp->__Vm_dumperp; __VlSymsp->__Vm_dumperp = NULL;\n"); puts("}\n"); splitSizeInc(10); diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 8533060a2..69dbc8ad4 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -420,6 +420,7 @@ void EmitCSyms::emitSymHdr() { if (v3Global.needTraceDumper()) { // __Vm_dumperp is local, otherwise we wouldn't know what design's eval() // should call a global dumpperp + puts("bool __Vm_dumping; // Dumping is active\n"); puts("VerilatedMutex __Vm_dumperMutex; // Protect __Vm_dumperp\n"); puts(v3Global.opt.traceClassLang() + "* __Vm_dumperp VL_GUARDED_BY(__Vm_dumperMutex); /// Trace class for $dump*\n"); @@ -590,7 +591,10 @@ void EmitCSyms::emitSymImp() { puts(symClassName()+"::"+symClassName()+"("+topClassName()+"* topp, const char* namep)\n"); puts(" // Setup locals\n"); puts(" : __Vm_namep(namep)\n"); // No leak, as gets destroyed when the top is destroyed - if (v3Global.needTraceDumper()) puts(" , __Vm_dumperp(NULL)\n"); + if (v3Global.needTraceDumper()) { + puts(" , __Vm_dumping(false)\n"); + puts(" , __Vm_dumperp(NULL)\n"); + } if (v3Global.opt.trace()) puts(" , __Vm_activity(false)\n"); puts(" , __Vm_didInit(false)\n"); puts(" // Setup submodule names\n"); From dab1cb610ab3e63e46ea95c3cc81e2030b64f30f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 5 Mar 2020 18:12:10 -0500 Subject: [PATCH 32/50] Tests: Allow iv to run SystemVerilog tests --- test_regress/driver.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 1ffa65862..b2560964f 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -565,7 +565,7 @@ sub new { ghdl_run_flags => [], # IV iv => 0, - iv_flags => [split(/\s+/,"+define+iverilog -o $self->{obj_dir}/simiv")], + iv_flags => [split(/\s+/,"+define+iverilog -g2012 -o $self->{obj_dir}/simiv")], iv_flags2 => [], # Overridden in some sim files iv_pli => 0, # need to use pli iv_run_flags => [], From c108f5def98ad6791a051d792a8452ffd0d61d85 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 5 Mar 2020 19:09:58 -0500 Subject: [PATCH 33/50] Commentary, Closes #2177. --- bin/verilator | 37 ++++++++++++++++++++++++++-- examples/make_tracing_c/sim_main.cpp | 31 +++++++++++------------ examples/make_tracing_c/sub.v | 17 ------------- examples/make_tracing_c/top.v | 2 -- 4 files changed, 50 insertions(+), 37 deletions(-) diff --git a/bin/verilator b/bin/verilator index 1714ed230..57ae1c283 100755 --- a/bin/verilator +++ b/bin/verilator @@ -1936,6 +1936,39 @@ when your source changes it will automatically run all of these steps. See the examples directory in the distribution. +=head1 EVALUATION LOOP + +When using SystemC, when Verilator is evaluated is managed by the SystemC +kernel, and for the most part can be ignored. When using C++, the user +must call eval(), or eval_step() and eval_end_step(). + +1. When there is a single design instantiated at the C++ level that need to +evaluate, just call designp->eval(). + +2. When there are multiple designs instantiated each at the C++ level that +need to evaluate, call first_designp->eval_step() then ->eval_step() on all +other designs. Then call ->eval_end_step() on the first design then all +other designs. If there is only a single design, you would call +eval_step() then eval_end_step(); in fact eval() described above is just a +wrapper which calls these two functions. + +When eval() is called Verilator looks for changes in clock signals and +evaluates related sequential always blocks, such as computing always_ff @ +(posedge...) outputs. Then Verilator evaluates combinatorial logic. + +Note combinatorial logic is not computed before sequential always blocks +are computed (for speed reasons). Therefore it is best to set any non-clock +inputs up with a separate eval() call before changing clocks(). + +Alternatively, if all always_ff statements use only the posedge of clocks, +or all inputs go directly to always_ff statements, as is typical, then you +can change non-clock inputs on the negative edge of the input clock, which +will be faster as there will be fewer eval() calls. + +For more information on evaluation, see docs/internals.adoc in the +distribution. + + =head1 BENCHMARKING & OPTIMIZATION For best performance, run Verilator with the "-O3 --x-assign fast @@ -2212,7 +2245,7 @@ example: Note signals are read and written as member variables of the lower module. You call the eval() method to evaluate the model. When the simulation is complete call the final() method to wrap up any SystemVerilog final blocks, -and complete any assertions. +and complete any assertions. See L. =head1 CONNECTING TO SYSTEMC @@ -5335,7 +5368,7 @@ L, L, L, L, L which is the source for this document, -and internals.txt in the distribution. +and docs/internals.adoc in the distribution. =cut diff --git a/examples/make_tracing_c/sim_main.cpp b/examples/make_tracing_c/sim_main.cpp index 1e75819f4..527ff105b 100644 --- a/examples/make_tracing_c/sim_main.cpp +++ b/examples/make_tracing_c/sim_main.cpp @@ -46,7 +46,6 @@ int main(int argc, char** argv, char** env) { // Set some inputs top->reset_l = !0; - top->fastclk = 0; top->clk = 0; top->in_small = 1; top->in_quad = 0x1234; @@ -58,22 +57,22 @@ int main(int argc, char** argv, char** env) { while (!Verilated::gotFinish()) { main_time++; // Time passes... - // Toggle clocks and such - top->fastclk = !top->fastclk; - if ((main_time % 10) == 3) { - top->clk = 1; - } - if ((main_time % 10) == 8) { - top->clk = 0; - } - if (main_time > 1 && main_time < 10) { - top->reset_l = !1; // Assert reset - } else { - top->reset_l = !0; // Deassert reset - } + // Toggle a fast (time/2 period) clock + top->clk = !top->clk; - // Assign some other inputs - top->in_quad += 0x12; + // Toggle control signals on an edge that doesn't correspond + // to where the controls are sampled; in this example we do + // this only on a negedge of clk, because we know + // reset is not sampled there. + if (!top->clk) { + if (main_time > 1 && main_time < 10) { + top->reset_l = !1; // Assert reset + } else { + top->reset_l = !0; // Deassert reset + } + // Assign some other inputs + top->in_quad += 0x12; + } // Evaluate model // (If you have multiple models being simulated in the same diff --git a/examples/make_tracing_c/sub.v b/examples/make_tracing_c/sub.v index e50d43d51..553d85921 100644 --- a/examples/make_tracing_c/sub.v +++ b/examples/make_tracing_c/sub.v @@ -7,25 +7,10 @@ module sub ( input clk, - input fastclk, input reset_l ); // Example counter/flop - reg [31:0] count_f; - always_ff @ (posedge fastclk) begin - if (!reset_l) begin - /*AUTORESET*/ - // Beginning of autoreset for uninitialized flops - count_f <= 32'h0; - // End of automatics - end - else begin - count_f <= count_f + 1; - end - end - - // Another example flop reg [31:0] count_c; always_ff @ (posedge clk) begin if (!reset_l) begin @@ -37,8 +22,6 @@ module sub else begin count_c <= count_c + 1; if (count_c >= 3) begin - $display("[%0t] fastclk is %0d times faster than clk\n", - $time, count_f/count_c); // This write is a magic value the Makefile uses to make sure the // test completes successfully. $write("*-* All Finished *-*\n"); diff --git a/examples/make_tracing_c/top.v b/examples/make_tracing_c/top.v index 0dc22d9cc..ac537c68f 100644 --- a/examples/make_tracing_c/top.v +++ b/examples/make_tracing_c/top.v @@ -11,7 +11,6 @@ module top ( // Declare some signals so we can see how I/O works input clk, - input fastclk, input reset_l, output wire [1:0] out_small, @@ -31,7 +30,6 @@ module top sub sub (/*AUTOINST*/ // Inputs .clk (clk), - .fastclk (fastclk), .reset_l (reset_l)); // Print some stuff as an example From 75ecad591ad250946a91cd3cdc7292416be58806 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 5 Mar 2020 21:49:25 -0500 Subject: [PATCH 34/50] Implement $displayb/o/h, $writeb/o/h, etc, Closes #1637. --- Changes | 2 ++ src/V3AstNodes.h | 35 +++++++++++++--------- src/V3Width.cpp | 2 +- src/verilog.l | 30 ++++++++++--------- src/verilog.y | 43 ++++++++++++++++++++++++++-- test_regress/t/t_assert_comp_bad.out | 2 +- test_regress/t/t_display.out | 8 ++++-- test_regress/t/t_display.v | 6 ++++ test_regress/t/t_display_merge.out | 4 +-- test_regress/t/t_sys_file_basic.out | 6 ++++ test_regress/t/t_sys_file_basic.pl | 5 +--- test_regress/t/t_sys_file_basic.v | 8 ++++++ 12 files changed, 111 insertions(+), 40 deletions(-) create mode 100644 test_regress/t/t_sys_file_basic.out diff --git a/Changes b/Changes index b949dba1e..1495898e0 100644 --- a/Changes +++ b/Changes @@ -15,6 +15,8 @@ The contributors that suggested a given feature are shown in []. Thanks! *** Fix genblk naming with directly nested generate blocks, #2176. [Alexander Grobman] +**** Implement $displayb/o/h, $writeb/o/h, etc, #1637. + **** Use gcc -Os in examples instead of -O2 for better average performance. **** Fix undeclared VL_SHIFTR_WWQ, #2114. [Alex Solomatnikov] diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 7365d6430..b7ab752a8 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -2956,17 +2956,21 @@ public: class AstSFormatF : public AstNode { // Convert format to string, generally under an AstDisplay or AstSFormat // Also used as "real" function for /*verilator sformat*/ functions - string m_text; - bool m_hidden; // Under display, etc - bool m_hasFormat; // Has format code + string m_text; + bool m_hidden; // Under display, etc + bool m_hasFormat; // Has format code + char m_missingArgChar; // Format code when argument without format, 'h'/'o'/'b' public: class NoFormat {}; - AstSFormatF(FileLine* fl, const string& text, bool hidden, AstNode* exprsp) - : ASTGEN_SUPER(fl), m_text(text), m_hidden(hidden), m_hasFormat(true) { + AstSFormatF(FileLine* fl, const string& text, bool hidden, AstNode* exprsp, + char missingArgChar = 'd') + : ASTGEN_SUPER(fl) + , m_text(text), m_hidden(hidden), m_hasFormat(true), m_missingArgChar(missingArgChar) { dtypeSetString(); addNOp1p(exprsp); addNOp2p(NULL); } - AstSFormatF(FileLine* fl, NoFormat, AstNode* exprsp) - : ASTGEN_SUPER(fl), m_text(""), m_hidden(true), m_hasFormat(false) { + AstSFormatF(FileLine* fl, NoFormat, AstNode* exprsp, char missingArgChar = 'd') + : ASTGEN_SUPER(fl) + , m_text(""), m_hidden(true), m_hasFormat(false), m_missingArgChar(missingArgChar) { dtypeSetString(); addNOp1p(exprsp); addNOp2p(NULL); } ASTNODE_NODE_FUNCS(SFormatF) @@ -2988,6 +2992,7 @@ public: bool hidden() const { return m_hidden; } void hasFormat(bool flag) { m_hasFormat = flag; } bool hasFormat() const { return m_hasFormat; } + char missingArgChar() const { return m_missingArgChar; } }; class AstDisplay : public AstNodeStmt { @@ -2995,18 +3000,19 @@ class AstDisplay : public AstNodeStmt { // Children: file which must be a varref // Children: SFORMATF to generate print string private: - AstDisplayType m_displayType; + AstDisplayType m_displayType; public: AstDisplay(FileLine* fl, AstDisplayType dispType, const string& text, AstNode* filep, - AstNode* exprsp) + AstNode* exprsp, char missingArgChar = 'd') : ASTGEN_SUPER(fl) { - setOp1p(new AstSFormatF(fl, text, true, exprsp)); + setOp1p(new AstSFormatF(fl, text, true, exprsp, missingArgChar)); setNOp3p(filep); m_displayType = dispType; } - AstDisplay(FileLine* fl, AstDisplayType dispType, AstNode* filep, AstNode* exprsp) + AstDisplay(FileLine* fl, AstDisplayType dispType, AstNode* filep, AstNode* exprsp, + char missingArgChar = 'd') : ASTGEN_SUPER(fl) { - setOp1p(new AstSFormatF(fl, AstSFormatF::NoFormat(), exprsp)); + setOp1p(new AstSFormatF(fl, AstSFormatF::NoFormat(), exprsp, missingArgChar)); setNOp3p(filep); m_displayType = dispType; } @@ -3092,9 +3098,10 @@ class AstSFormat : public AstNodeStmt { // Children: string to load // Children: SFORMATF to generate print string public: - AstSFormat(FileLine* fl, AstNode* lhsp, const string& text, AstNode* exprsp) + AstSFormat(FileLine* fl, AstNode* lhsp, const string& text, AstNode* exprsp, + char missingArgChar = 'd') : ASTGEN_SUPER(fl) { - setOp1p(new AstSFormatF(fl, text, true, exprsp)); + setOp1p(new AstSFormatF(fl, text, true, exprsp, missingArgChar)); setOp3p(lhsp); } ASTNODE_NODE_FUNCS(SFormat) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index dc4152b46..0f886eea2 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2819,7 +2819,7 @@ private: } else if (argp && argp->isString()) { ch = '@'; } else { - ch = 'h'; + ch = nodep->missingArgChar(); } if (argp) argp = argp->nextp(); break; diff --git a/src/verilog.l b/src/verilog.l index 33b791946..2ebd3694e 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -197,6 +197,9 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$cos" { FL; return yD_COS; } "$cosh" { FL; return yD_COSH; } "$display" { FL; return yD_DISPLAY; } + "$displayb" { FL; return yD_DISPLAYB; } + "$displayh" { FL; return yD_DISPLAYH; } + "$displayo" { FL; return yD_DISPLAYO; } "$dumpall" { FL; return yD_DUMPALL; } "$dumpfile" { FL; return yD_DUMPFILE; } "$dumpflush" { FL; return yD_DUMPFLUSH; } @@ -213,6 +216,9 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$exp" { FL; return yD_EXP; } "$fclose" { FL; return yD_FCLOSE; } "$fdisplay" { FL; return yD_FDISPLAY; } + "$fdisplayb" { FL; return yD_FDISPLAYB; } + "$fdisplayh" { FL; return yD_FDISPLAYH; } + "$fdisplayo" { FL; return yD_FDISPLAYO; } "$feof" { FL; return yD_FEOF; } "$fflush" { FL; return yD_FFLUSH; } "$fgetc" { FL; return yD_FGETC; } @@ -227,6 +233,9 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$ftell" { FL; return yD_FTELL; } "$fullskew" { FL; return yaTIMINGSPEC; } "$fwrite" { FL; return yD_FWRITE; } + "$fwriteb" { FL; return yD_FWRITEB; } + "$fwriteh" { FL; return yD_FWRITEH; } + "$fwriteo" { FL; return yD_FWRITEO; } "$hold" { FL; return yaTIMINGSPEC; } "$hypot" { FL; return yD_HYPOT; } "$itor" { FL; return yD_ITOR; } @@ -245,9 +254,9 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$removal" { FL; return yaTIMINGSPEC; } "$rewind" { FL; return yD_REWIND; } "$rtoi" { FL; return yD_RTOI; } + "$sampled" { FL; return yD_SAMPLED; } "$setup" { FL; return yaTIMINGSPEC; } "$setuphold" { FL; return yaTIMINGSPEC; } - "$sampled" { FL; return yD_SAMPLED; } "$sformat" { FL; return yD_SFORMAT; } "$sformatf" { FL; return yD_SFORMATF; } "$shortrealtobits" { FL; return yD_SHORTREALTOBITS; } @@ -259,6 +268,9 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$stime" { FL; return yD_STIME; } "$stop" { FL; return yD_STOP; } "$swrite" { FL; return yD_SWRITE; } + "$swriteb" { FL; return yD_SWRITEB; } + "$swriteh" { FL; return yD_SWRITEH; } + "$swriteo" { FL; return yD_SWRITEO; } "$system" { FL; return yD_SYSTEM; } "$tan" { FL; return yD_TAN; } "$tanh" { FL; return yD_TANH; } @@ -270,6 +282,9 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$value$plusargs" { FL; return yD_VALUEPLUSARGS; } "$width" { FL; return yaTIMINGSPEC; } "$write" { FL; return yD_WRITE; } + "$writeb" { FL; return yD_WRITEB; } + "$writeh" { FL; return yD_WRITEH; } + "$writeo" { FL; return yD_WRITEO; } "$writememh" { FL; return yD_WRITEMEMH; } /* Keywords */ "always" { FL; return yALWAYS; } @@ -374,19 +389,6 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "wor" { FL; return yWOR; } "xnor" { FL; return yXNOR; } "xor" { FL; return yXOR; } - /* Special errors */ - "$displayb" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $display with %%b format instead: %s", yytext); } - "$displayh" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $display with %%x format instead: %s", yytext); } - "$displayo" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $display with %%o format instead: %s", yytext); } - "$fdisplayb" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fdisplay with %%b format instead: %s", yytext); } - "$fdisplayh" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fdisplay with %%x format instead: %s", yytext); } - "$fdisplayo" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fdisplay with %%o format instead: %s", yytext); } - "$fwriteb" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fwrite with %%b format instead: %s", yytext); } - "$fwriteh" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fwrite with %%x format instead: %s", yytext); } - "$fwriteo" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fwrite with %%o format instead: %s", yytext); } - "$writeb" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $write with %%b format instead: %s", yytext); } - "$writeh" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $write with %%x format instead: %s", yytext); } - "$writeo" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $write with %%o format instead: %s", yytext); } } /* Verilog 2001 */ diff --git a/src/verilog.y b/src/verilog.y index 8ad3f5fb9..70c6288e0 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -553,6 +553,9 @@ class AstSenTree; %token yD_COUNTONES "$countones" %token yD_DIMENSIONS "$dimensions" %token yD_DISPLAY "$display" +%token yD_DISPLAYB "$displayb" +%token yD_DISPLAYH "$displayh" +%token yD_DISPLAYO "$displayo" %token yD_DUMPALL "$dumpall" %token yD_DUMPFILE "$dumpfile" %token yD_DUMPFLUSH "$dumpflush" @@ -566,6 +569,9 @@ class AstSenTree; %token yD_FATAL "$fatal" %token yD_FCLOSE "$fclose" %token yD_FDISPLAY "$fdisplay" +%token yD_FDISPLAYB "$fdisplayb" +%token yD_FDISPLAYH "$fdisplayh" +%token yD_FDISPLAYO "$fdisplayo" %token yD_FEOF "$feof" %token yD_FFLUSH "$fflush" %token yD_FGETC "$fgetc" @@ -579,6 +585,9 @@ class AstSenTree; %token yD_FSEEK "$fseek" %token yD_FTELL "$ftell" %token yD_FWRITE "$fwrite" +%token yD_FWRITEB "$fwriteb" +%token yD_FWRITEH "$fwriteh" +%token yD_FWRITEO "$fwriteo" %token yD_HIGH "$high" %token yD_HYPOT "$hypot" %token yD_INCREMENT "$increment" @@ -614,6 +623,9 @@ class AstSenTree; %token yD_STIME "$stime" %token yD_STOP "$stop" %token yD_SWRITE "$swrite" +%token yD_SWRITEB "$swriteb" +%token yD_SWRITEH "$swriteh" +%token yD_SWRITEO "$swriteo" %token yD_SYSTEM "$system" %token yD_TAN "$tan" %token yD_TANH "$tanh" @@ -627,7 +639,10 @@ class AstSenTree; %token yD_VALUEPLUSARGS "$value$plusargs" %token yD_WARNING "$warning" %token yD_WRITE "$write" +%token yD_WRITEB "$writeb" +%token yD_WRITEH "$writeh" %token yD_WRITEMEMH "$writememh" +%token yD_WRITEO "$writeo" %token yVL_CLOCK "/*verilator sc_clock*/" %token yVL_CLOCKER "/*verilator clocker*/" @@ -3195,16 +3210,40 @@ system_t_call: // IEEE: system_tf_call (as task) | yD_STOP parenE { $$ = new AstStop($1, false); } | yD_STOP '(' expr ')' { $$ = new AstStop($1, false); DEL($3); } // - | yD_SFORMAT '(' expr ',' str commaEListE ')' { $$ = new AstSFormat($1,$3,*$5,$6); } - | yD_SWRITE '(' expr ',' str commaEListE ')' { $$ = new AstSFormat($1,$3,*$5,$6); } + | yD_SFORMAT '(' expr ',' str commaEListE ')' { $$ = new AstSFormat($1, $3, *$5, $6); } + | yD_SWRITE '(' expr ',' str commaEListE ')' { $$ = new AstSFormat($1, $3, *$5, $6); } + | yD_SWRITEB '(' expr ',' str commaEListE ')' { $$ = new AstSFormat($1, $3, *$5, $6, 'b'); } + | yD_SWRITEH '(' expr ',' str commaEListE ')' { $$ = new AstSFormat($1, $3, *$5, $6, 'h'); } + | yD_SWRITEO '(' expr ',' str commaEListE ')' { $$ = new AstSFormat($1, $3, *$5, $6, 'o'); } // | yD_DISPLAY parenE { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, NULL, NULL); } | yD_DISPLAY '(' exprList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, NULL, $3); } + | yD_DISPLAYB parenE { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, NULL, NULL, 'b'); } + | yD_DISPLAYB '(' exprList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, NULL, $3, 'b'); } + | yD_DISPLAYH parenE { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, NULL, NULL, 'h'); } + | yD_DISPLAYH '(' exprList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, NULL, $3, 'h'); } + | yD_DISPLAYO parenE { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, NULL, NULL, 'o'); } + | yD_DISPLAYO '(' exprList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, NULL, $3, 'o'); } | yD_WRITE parenE { $$ = NULL; } // NOP | yD_WRITE '(' exprList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, NULL, $3); } + | yD_WRITEB parenE { $$ = NULL; } // NOP + | yD_WRITEB '(' exprList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, NULL, $3, 'b'); } + | yD_WRITEH parenE { $$ = NULL; } // NOP + | yD_WRITEH '(' exprList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, NULL, $3, 'h'); } + | yD_WRITEO parenE { $$ = NULL; } // NOP + | yD_WRITEO '(' exprList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, NULL, $3, 'o'); } | yD_FDISPLAY '(' expr ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, NULL); } | yD_FDISPLAY '(' expr ',' exprListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, $5); } + | yD_FDISPLAYB '(' expr ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, NULL, 'b'); } + | yD_FDISPLAYB '(' expr ',' exprListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, $5, 'b'); } + | yD_FDISPLAYH '(' expr ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, NULL, 'h'); } + | yD_FDISPLAYH '(' expr ',' exprListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, $5, 'h'); } + | yD_FDISPLAYO '(' expr ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, NULL, 'o'); } + | yD_FDISPLAYO '(' expr ',' exprListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, $5, 'o'); } | yD_FWRITE '(' expr ',' exprListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, $3, $5); } + | yD_FWRITEB '(' expr ',' exprListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, $3, $5, 'b'); } + | yD_FWRITEO '(' expr ',' exprListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, $3, $5, 'h'); } + | yD_FWRITEH '(' expr ',' exprListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, $3, $5, 'o'); } | yD_INFO parenE { $$ = new AstDisplay($1,AstDisplayType::DT_INFO, NULL, NULL); } | yD_INFO '(' exprList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_INFO, NULL, $3); } | yD_WARNING parenE { $$ = new AstDisplay($1,AstDisplayType::DT_WARNING, NULL, NULL); } diff --git a/test_regress/t/t_assert_comp_bad.out b/test_regress/t/t_assert_comp_bad.out index ec27ed155..a3d3be7a7 100644 --- a/test_regress/t/t_assert_comp_bad.out +++ b/test_regress/t/t_assert_comp_bad.out @@ -7,7 +7,7 @@ $warning("User compile-time warning"); ^~~~~~~~ ... Use "/* verilator lint_off USERWARN */" and lint_on around source to disable this message. -%Warning-USERWARN: t/t_assert_comp_bad.v:11: 00000001 +%Warning-USERWARN: t/t_assert_comp_bad.v:11: 1 : ... In instance t $warning(1); ^~~~~~~~ diff --git a/test_regress/t/t_display.out b/test_regress/t/t_display.out index 289022a90..7102f4108 100644 --- a/test_regress/t/t_display.out +++ b/test_regress/t/t_display.out @@ -43,11 +43,15 @@ [0] %s=! %s= what! %s= hmmm!1234 [0] %6s=: !: %6s=: what!: %6s=: hmmm!1234: [0] %8s=: sv-str: +d: 12 12 +h: 00c 00c +o: 014 014 +b: 000001100 000001100 [0] hello, from a very long string. Percent %s are literally substituted in. hello, from a concatenated string. hello, from a concatenated format string [0]. -extra argument: 0000000000000000 -0000000000000000: pre argument +extra argument: 0 + 0: pre argument [0] Embedded <#013> return [0] Embedded multiline diff --git a/test_regress/t/t_display.v b/test_regress/t/t_display.v index 90b80c6eb..12bc6db5f 100644 --- a/test_regress/t/t_display.v +++ b/test_regress/t/t_display.v @@ -132,6 +132,12 @@ module t; $display("[%0t] %%8s=:%8s:", $time, svs); + // Displays without format, must use default + $write("d: "); $write(nine); $write(" "); $display(nine); + $writeh("h: "); $writeh(nine); $writeh(" "); $displayh(nine); + $writeo("o: "); $writeo(nine); $writeo(" "); $displayo(nine); + $writeb("b: "); $writeb(nine); $writeb(" "); $displayb(nine); + $display("[%0t] %s%s%s", $time, "hel", "lo, fr", "om a very long string. Percent %s are literally substituted in."); $display("hel", "lo, fr", "om a concatenated string."); diff --git a/test_regress/t/t_display_merge.out b/test_regress/t/t_display_merge.out index 5d290cba7..7ab198f50 100644 --- a/test_regress/t/t_display_merge.out +++ b/test_regress/t/t_display_merge.out @@ -8,12 +8,12 @@ f t2=0 post t3=0 - t4=0 t5=00000000000000000 + t4=0 t5=0 0 m t=0 t2=0 t3=0 t4=0 t5=0 t=0 t2=0 t3=0 t4=0 t5=0 mm -f a=top.t b=top.t pre t=0 t2=0 post t3=0 t4=0 t5=00000000000000000m t=0 t2=0 t3=0 t4=0 t5=0 t=0 t2=0 t3=0 t4=0 t5=0mm +f a=top.t b=top.t pre t=0 t2=0 post t3=0 t4=0 t5=0 0m t=0 t2=0 t3=0 t4=0 t5=0 t=0 t2=0 t3=0 t4=0 t5=0mm *-* All Finished *-* diff --git a/test_regress/t/t_sys_file_basic.out b/test_regress/t/t_sys_file_basic.out new file mode 100644 index 000000000..bd5e9f664 --- /dev/null +++ b/test_regress/t/t_sys_file_basic.out @@ -0,0 +1,6 @@ +[0] hello v=12345667 +[0] Hello2 +d: 12 12 +h: 00000000014 0000000c +o: 0000000c 00000000014 +b: 00000000000000000000000000001100 00000000000000000000000000001100 diff --git a/test_regress/t/t_sys_file_basic.pl b/test_regress/t/t_sys_file_basic.pl index 1c167efd4..5e4c3a3ba 100755 --- a/test_regress/t/t_sys_file_basic.pl +++ b/test_regress/t/t_sys_file_basic.pl @@ -21,10 +21,7 @@ execute( check_finished => 1, ); -file_grep("$Self->{obj_dir}/t_sys_file_basic_test.log", -qr/\[0\] hello v=12345667 -\[0\] Hello2 -/); +files_identical("$Self->{obj_dir}/t_sys_file_basic_test.log", $Self->{golden_filename}); ok(1); 1; diff --git a/test_regress/t/t_sys_file_basic.v b/test_regress/t/t_sys_file_basic.v index d0bb007c4..60ed787bb 100644 --- a/test_regress/t/t_sys_file_basic.v +++ b/test_regress/t/t_sys_file_basic.v @@ -19,6 +19,7 @@ module t; reg [16*8:1] letterz; real r; string s; + integer i; reg [7:0] v_a,v_b,v_c,v_d; reg [31:0] v_worda; @@ -51,6 +52,13 @@ module t; $fdisplay(file, "[%0t] hello v=%x", $time, 32'h12345667); $fwrite(file, "[%0t] %s\n", $time, "Hello2"); + + i = 12; + $fwrite(file, "d: "); $fwrite(file, i); $fwrite(file, " "); $fdisplay(file, i); + $fwriteh(file, "h: "); $fwriteh(file, i); $fwriteh(file, " "); $fdisplayh(file, i); + $fwriteo(file, "o: "); $fwriteo(file, i); $fwriteo(file, " "); $fdisplayo(file, i); + $fwriteb(file, "b: "); $fwriteb(file, i); $fwriteb(file, " "); $fdisplayb(file, i); + $fflush(file); $fclose(file); From 135cbcd79a727ca6cb1dd378418bc999e3c88231 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 5 Mar 2020 22:33:31 -0500 Subject: [PATCH 35/50] Internals: Move 'new' unsupported forward from parse into Ast. --- src/V3AstNodes.h | 50 ++++++++++++++++++++++++++-- src/V3EmitCInlines.cpp | 4 +++ src/V3Width.cpp | 13 +++++++- src/verilog.y | 15 ++++----- test_regress/t/t_class_unsup_bad.out | 3 -- 5 files changed, 70 insertions(+), 15 deletions(-) diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index b7ab752a8..65ef1bcd7 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -3938,22 +3938,66 @@ public: }; class AstNew : public AstNodeMath { + // New as constructor + // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it // Parents: math|stmt // Children: varref|arraysel, math public: - explicit AstNew(FileLine* fl) + AstNew(FileLine* fl, AstNode* argsp) : ASTGEN_SUPER(fl) { dtypep(NULL); // V3Width will resolve + addNOp2p(argsp); } ASTNODE_NODE_FUNCS(New) - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { - V3ERROR_NA; /* How can from be a const? */ } virtual V3Hash sameHash() const { return V3Hash(); } virtual string emitVerilog() { return "new"; } virtual string emitC() { V3ERROR_NA; return ""; } virtual bool cleanOut() const { return true; } virtual bool same(const AstNode* samep) const { return true; } virtual int instrCount() const { return widthInstrs(); } + AstNode* argsp() const { return op2p(); } +}; + +class AstNewCopy : public AstNodeMath { + // New as shallow copy + // Parents: math|stmt + // Children: varref|arraysel, math +public: + AstNewCopy(FileLine* fl, AstNode* rhsp) + : ASTGEN_SUPER(fl) { + dtypeFrom(rhsp); // otherwise V3Width will resolve + setNOp1p(rhsp); + } + ASTNODE_NODE_FUNCS(NewCopy) + virtual V3Hash sameHash() const { return V3Hash(); } + virtual string emitVerilog() { return "new"; } + virtual string emitC() { V3ERROR_NA; return ""; } + virtual bool cleanOut() const { return true; } + virtual bool same(const AstNode* samep) const { return true; } + virtual int instrCount() const { return widthInstrs(); } + AstNode* rhsp() const { return op1p(); } +}; + +class AstNewDynamic : public AstNodeMath { + // New for dynamic array + // Parents: math|stmt + // Children: varref|arraysel, math +public: + AstNewDynamic(FileLine* fl, AstNode* sizep, AstNode* rhsp) + : ASTGEN_SUPER(fl) { + dtypeFrom(rhsp); // otherwise V3Width will resolve + setNOp1p(sizep); + setNOp2p(rhsp); + } + ASTNODE_NODE_FUNCS(NewDynamic) + virtual V3Hash sameHash() const { return V3Hash(); } + virtual string emitVerilog() { return "new"; } + virtual string emitC() { V3ERROR_NA; return ""; } + virtual bool cleanOut() const { return true; } + virtual bool same(const AstNode* samep) const { return true; } + virtual int instrCount() const { return widthInstrs(); } + AstNode* sizep() const { return sizep(); } + AstNode* rhsp() const { return op2p(); } }; class AstPragma : public AstNode { diff --git a/src/V3EmitCInlines.cpp b/src/V3EmitCInlines.cpp index 39a78e140..9cd64af07 100644 --- a/src/V3EmitCInlines.cpp +++ b/src/V3EmitCInlines.cpp @@ -62,6 +62,10 @@ class EmitCInlines : EmitCBaseVisitor { v3Global.needHeavy(true); iterateChildren(nodep); } + virtual void visit(AstNew* nodep) VL_OVERRIDE { + if (v3Global.opt.savable()) v3error("Unsupported: --savable with dynamic new"); + iterateChildren(nodep); + } virtual void visit(AstAtoN* nodep) VL_OVERRIDE { v3Global.needHeavy(true); iterateChildren(nodep); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 0f886eea2..497bc928c 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2288,13 +2288,24 @@ private: virtual void visit(AstNew* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; - userIterateChildren(nodep, WidthVP(SELF, BOTH).p()); AstClassRefDType* refp = VN_CAST(m_vup->dtypeNullp(), ClassRefDType); if (!refp) { // e.g. int a = new; nodep->v3error("new() not expected in this context"); return; } nodep->dtypep(refp); + if (nodep->argsp()) { + nodep->v3error("Unsupported: new with arguments"); + userIterateChildren(nodep, WidthVP(SELF, BOTH).p()); + } + } + virtual void visit(AstNewCopy* nodep) VL_OVERRIDE { + if (nodep->didWidthAndSet()) return; + nodep->v3error("Unsupported: new-as-copy"); + } + virtual void visit(AstNewDynamic* nodep) VL_OVERRIDE { + if (nodep->didWidthAndSet()) return; + nodep->v3error("Unsupported: Dynamic array new"); } virtual void visit(AstPattern* nodep) VL_OVERRIDE { diff --git a/src/verilog.y b/src/verilog.y index 70c6288e0..1a4d5cb00 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -2903,15 +2903,14 @@ finc_or_dec_expression: // ==IEEE: inc_or_dec_expression class_new: // ==IEEE: class_new // // Special precence so (...) doesn't match expr - yNEW__ETC { $$ = new AstNew($1); } - | yNEW__ETC expr { $$ = new AstNew($1); BBUNSUP($1, "Unsupported: new with expression"); } - // // Grammer abiguity; we assume "new (x)" the () are a argument, not expr - | yNEW__PAREN '(' list_of_argumentsE ')' { $$ = new AstNew($1); BBUNSUP($1, "Unsupported: new with arguments"); } + yNEW__ETC { $$ = new AstNew($1, NULL); } + | yNEW__ETC expr { $$ = new AstNewCopy($1, $2); } + | yNEW__PAREN '(' list_of_argumentsE ')' { $$ = new AstNew($1, $3); } ; dynamic_array_new: // ==IEEE: dynamic_array_new - yNEW__ETC '[' expr ']' { $$ = new AstNew($1); BBUNSUP($1, "Unsupported: Dynamic array new"); } - | yNEW__ETC '[' expr ']' '(' expr ')' { $$ = new AstNew($1); BBUNSUP($1, "Unsupported: Dynamic array new"); } + yNEW__ETC '[' expr ']' { $$ = new AstNewDynamic($1, $3, NULL); } + | yNEW__ETC '[' expr ']' '(' expr ')' { $$ = new AstNewDynamic($1, $3, $6); } ; //************************************************ @@ -5579,8 +5578,8 @@ class_method: // ==IEEE: class_method class_item_qualifier: // IEEE: class_item_qualifier minus ySTATIC // // IMPORTANT: yPROTECTED | yLOCAL is in a lex rule - yPROTECTED { $$ = NULL; } // Ignoring protected until implemented - | yLOCAL__ETC { $$ = NULL; BBUNSUP($1, "Unsupported: 'local' class item"); } + yPROTECTED { $$ = NULL; } // Ignoring protected until warning implemented + | yLOCAL__ETC { $$ = NULL; } // Ignoring local until warning implemented | ySTATIC__ETC { $$ = NULL; BBUNSUP($1, "Unsupported: 'static' class item"); } ; diff --git a/test_regress/t/t_class_unsup_bad.out b/test_regress/t/t_class_unsup_bad.out index 7d5a2eb29..db3c6788c 100644 --- a/test_regress/t/t_class_unsup_bad.out +++ b/test_regress/t/t_class_unsup_bad.out @@ -10,9 +10,6 @@ class C #(parameter P=1); %Error: t/t_class_unsup_bad.v:13: Unsupported: class parameters localparam LOCPAR = 10; ^ -%Error: t/t_class_unsup_bad.v:16: Unsupported: 'local' class item - local int loc; - ^~~~~ %Error: t/t_class_unsup_bad.v:24: Unsupported: virtual class member qualifier virtual function void func_virtual; endfunction ^~~~~~~ From 29923b78fd1ee0b1357a045ecee502ec05fde5b6 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 5 Mar 2020 23:28:41 -0500 Subject: [PATCH 36/50] Internals: Use VL_TO_STRING instead of to_string. --- src/V3Width.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 497bc928c..30f6f9027 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2796,8 +2796,10 @@ private: newFormat += "%@"; AstNRelinker handle; argp->unlinkFrBack(&handle); - AstCMethodHard* newp = new AstCMethodHard( - nodep->fileline(), argp, "to_string", NULL); + AstCMath* newp = new AstCMath( + nodep->fileline(), "VL_TO_STRING(", 0, true); + newp->addBodysp(argp); + newp->addBodysp(new AstText(nodep->fileline(), ")")); newp->dtypeSetString(); newp->pure(true); newp->protect(false); From e673875b3b99bf37f39869e99b7815fee3e19831 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 6 Mar 2020 07:31:56 -0500 Subject: [PATCH 37/50] Fix clang warning, last commit. --- src/V3AstNodes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 65ef1bcd7..7eec8a8a0 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -3996,7 +3996,7 @@ public: virtual bool cleanOut() const { return true; } virtual bool same(const AstNode* samep) const { return true; } virtual int instrCount() const { return widthInstrs(); } - AstNode* sizep() const { return sizep(); } + AstNode* sizep() const { return op1p(); } AstNode* rhsp() const { return op2p(); } }; From 8054fc47ea8f9660029b4e1ec9a34ac95ef5dd21 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 7 Mar 2020 08:24:57 -0500 Subject: [PATCH 38/50] Internals: Refectoring. No functional change intended. --- src/V3Width.cpp | 57 +++++++++++++++++-------------------------------- 1 file changed, 19 insertions(+), 38 deletions(-) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 30f6f9027..69c0c32b6 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2457,18 +2457,7 @@ private: if (patp) { // Determine initial values patp->dtypep(memp); - userIterate(patp, WidthVP(memp, BOTH).p()); // See visit(AstPatMember* - - // Convert to concat for now - AstNode* valuep = patp->lhssp()->unlinkFrBack(); - if (VN_IS(valuep, Const)) { - // Forming a AstConcat will cause problems with - // unsized (uncommitted sized) constants - if (AstNode* newccp = WidthCommitVisitor::newIfConstCommitSize(VN_CAST(valuep, Const))) { - VL_DO_DANGLING(pushDeletep(valuep), valuep); - valuep = newccp; - } - } + AstNode* valuep = patternMemberValueIterate(patp); if (!newp) newp = valuep; else { AstConcat* concatp = new AstConcat(patp->fileline(), newp, valuep); @@ -2511,18 +2500,7 @@ private: if (patp) { // Don't want the RHS an array patp->dtypep(arrayp->subDTypep()); - // Determine values - might be another InitArray - userIterate(patp, WidthVP(patp->dtypep(), BOTH).p()); // See visit(AstPatMember* - // Convert to InitArray or constify immediately - AstNode* valuep = patp->lhssp()->unlinkFrBack(); - if (VN_IS(valuep, Const)) { - // Forming a AstConcat will cause problems with - // unsized (uncommitted sized) constants - if (AstNode* newp = WidthCommitVisitor::newIfConstCommitSize(VN_CAST(valuep, Const))) { - VL_DO_DANGLING(pushDeletep(valuep), valuep); - valuep = newp; - } - } + AstNode* valuep = patternMemberValueIterate(patp); if (VN_IS(arrayp, UnpackArrayDType)) { if (!newp) { AstInitArray* newap @@ -2575,21 +2553,8 @@ private: if (patp) { // Determine initial values vdtypep = nodep->findLogicBoolDType(); - // Don't want the RHS an array patp->dtypep(vdtypep); - // Determine values - might be another InitArray - userIterate(patp, WidthVP(patp->dtypep(), BOTH).p()); - // Convert to InitArray or constify immediately - AstNode* valuep = patp->lhssp()->unlinkFrBack(); - if (VN_IS(valuep, Const)) { - // Forming a AstConcat will cause problems with - // unsized (uncommitted sized) constants - if (AstNode* newccp - = WidthCommitVisitor::newIfConstCommitSize(VN_CAST(valuep, Const))) { - VL_DO_DANGLING(pushDeletep(valuep), valuep); - valuep = newccp; - } - } + AstNode* valuep = patternMemberValueIterate(patp); { // Packed. Convert to concat for now. if (!newp) newp = valuep; else { @@ -2609,6 +2574,22 @@ private: //if (debug()>=9) newp->dumpTree("-apat-out: "); VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present } + AstNode* patternMemberValueIterate(AstPatMember* patp) { + // Determine values - might be another InitArray + userIterate(patp, WidthVP(patp->dtypep(), BOTH).p()); + // Convert to InitArray or constify immediately + AstNode* valuep = patp->lhssp()->unlinkFrBack(); + if (VN_IS(valuep, Const)) { + // Forming a AstConcat will cause problems with + // unsized (uncommitted sized) constants + if (AstNode* newp = WidthCommitVisitor::newIfConstCommitSize(VN_CAST(valuep, Const))) { + VL_DO_DANGLING(pushDeletep(valuep), valuep); + valuep = newp; + } + } + return valuep; + } + virtual void visit(AstPatMember* nodep) VL_OVERRIDE { AstNodeDType* vdtypep = m_vup->dtypeNullp(); UASSERT_OBJ(vdtypep, nodep, "Pattern member type not assigned by AstPattern visitor"); From e70cba77e601402735733fbd816f32c884a9f67c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 7 Mar 2020 10:24:27 -0500 Subject: [PATCH 39/50] Add support for dynamic arrays, #379. --- Changes | 2 + include/verilated_heavy.h | 20 +++- src/V3AstNodes.cpp | 18 +++ src/V3AstNodes.h | 50 ++++++++ src/V3Clean.cpp | 1 + src/V3EmitC.cpp | 3 + src/V3EmitCInlines.cpp | 4 + src/V3Width.cpp | 104 +++++++++++++++-- src/V3WidthSel.cpp | 11 ++ test_regress/t/t_dpi_openreg_bad.out | 9 -- test_regress/t/t_dpi_openreg_bad.v | 20 ---- test_regress/t/t_dynarray.pl | 20 ++++ test_regress/t/t_dynarray.v | 108 ++++++++++++++++++ test_regress/t/t_dynarray_bad.out | 6 + ...t_dpi_openreg_bad.pl => t_dynarray_bad.pl} | 4 +- test_regress/t/t_dynarray_bad.v | 17 +++ 16 files changed, 358 insertions(+), 39 deletions(-) delete mode 100644 test_regress/t/t_dpi_openreg_bad.out delete mode 100644 test_regress/t/t_dpi_openreg_bad.v create mode 100755 test_regress/t/t_dynarray.pl create mode 100644 test_regress/t/t_dynarray.v create mode 100644 test_regress/t/t_dynarray_bad.out rename test_regress/t/{t_dpi_openreg_bad.pl => t_dynarray_bad.pl} (81%) create mode 100644 test_regress/t/t_dynarray_bad.v diff --git a/Changes b/Changes index 1495898e0..4c0ace434 100644 --- a/Changes +++ b/Changes @@ -9,6 +9,8 @@ The contributors that suggested a given feature are shown in []. Thanks! ** Add support for $dumpfile and $dumpvars, #2126. [Alexander Grobman] +** Add support for dynamic arrays, #379. + *** Add +verilator+noassert flag to disable assertion checking. [Tobias Wölfel] *** Add check for assertOn for asserts, #2162. [Tobias Wölfel] diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index ef9f2b8bc..432c847d4 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -245,11 +245,12 @@ void VL_WRITEMEM_N(bool hex, int bits, const std::string& filename, } //=================================================================== -// Verilog queue container +// Verilog queue and dynamic array container // There are no multithreaded locks on this; the base variable must // be protected by other means // // Bound here is the maximum size() allowed, e.g. 1 + SystemVerilog bound +// For dynamic arrays it is always zero template class VlQueue { private: // TYPES @@ -279,6 +280,21 @@ public: void clear() { m_deque.clear(); } void erase(size_t index) { if (VL_LIKELY(index < m_deque.size())) m_deque.erase(index); } + // Dynamic array new[] becomes a renew() + void renew(size_t size) { + clear(); + m_deque.resize(size, atDefault()); + } + // Dynamic array new[]() becomes a renew_copy() + void renew_copy(size_t size, const VlQueue& rhs) { + if (size == 0) { + clear(); + } else { + *this = rhs; + m_deque.resize(size, atDefault()); + } + } + // function void q.push_front(value) void push_front(const T_Value& value) { m_deque.push_front(value); @@ -304,6 +320,7 @@ public: // because we need to be able to insert only when the value is set T_Value& at(size_t index) { static T_Value s_throwAway; + // Needs to work for dynamic arrays, so does not use T_MaxSize if (VL_UNLIKELY(index >= m_deque.size())) { s_throwAway = atDefault(); return s_throwAway; @@ -313,6 +330,7 @@ public: // Accessing. Verilog: v = assoc[index] const T_Value& at(size_t index) const { static T_Value s_throwAway; + // Needs to work for dynamic arrays, so does not use T_MaxSize if (VL_UNLIKELY(index >= m_deque.size())) return atDefault(); else return m_deque[index]; } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 127026a30..89e6de50e 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -278,6 +278,17 @@ AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDT VlArgTypeRecursed info; info.m_oprefix = out; return info; + } else if (const AstDynArrayDType* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) { + VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true); + string out = "VlQueue<"; + out += sub.m_oprefix; + if (!sub.m_osuffix.empty() || !sub.m_oref.empty()) { + out += " " + sub.m_osuffix + sub.m_oref; + } + out += "> "; + VlArgTypeRecursed info; + info.m_oprefix = out; + return info; } else if (const AstQueueDType* adtypep = VN_CAST_CONST(dtypep, QueueDType)) { VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true); VlArgTypeRecursed info; @@ -1168,6 +1179,13 @@ void AstAssocArrayDType::dumpSmall(std::ostream& str) const { string AstAssocArrayDType::prettyDTypeName() const { return subDTypep()->prettyDTypeName() + "[" + keyDTypep()->prettyDTypeName() + "]"; } +void AstDynArrayDType::dumpSmall(std::ostream& str) const { + this->AstNodeDType::dumpSmall(str); + str<<"[]"; +} +string AstDynArrayDType::prettyDTypeName() const { + return subDTypep()->prettyDTypeName() + "[]"; +} void AstQueueDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); str<<"[queue]"; diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 7eec8a8a0..c4c55a1e3 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -451,6 +451,56 @@ public: virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); } }; +class AstDynArrayDType : public AstNodeDType { + // Dynamic array data type, ie "[]" + // Children: DTYPE (moved to refDTypep() in V3Width) +private: + AstNodeDType* m_refDTypep; // Elements of this type (after widthing) +public: + AstDynArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) + : ASTGEN_SUPER(fl) { + childDTypep(dtp); // Only for parser + refDTypep(NULL); + dtypep(NULL); // V3Width will resolve + } + AstDynArrayDType(FileLine* fl, AstNodeDType* dtp) + : ASTGEN_SUPER(fl) { + refDTypep(dtp); + dtypep(NULL); // V3Width will resolve + } + ASTNODE_NODE_FUNCS(DynArrayDType) + virtual const char* broken() const { + BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) + || (!m_refDTypep && childDTypep()))); + return NULL; } + virtual void cloneRelink() { + if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); } } + virtual bool same(const AstNode* samep) const { + const AstAssocArrayDType* asamep = static_cast(samep); + return subDTypep() == asamep->subDTypep(); } + virtual bool similarDType(AstNodeDType* samep) const { + const AstAssocArrayDType* asamep = static_cast(samep); + return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); + } + virtual string prettyDTypeName() const; + virtual void dumpSmall(std::ostream& str) const; + virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); } + AstNodeDType* getChildDTypep() const { return childDTypep(); } + AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } // op1 = Range of variable + void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } + virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); } + void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } + virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; } + virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); } + // METHODS + virtual AstBasicDType* basicp() const { return NULL; } // (Slow) recurse down to find basic data type + virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; } + virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); } + virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); } +}; + class AstPackArrayDType : public AstNodeArrayDType { // Packed array data type, ie "some_dtype [2:0] var_name" // Children: DTYPE (moved to refDTypep() in V3Width) diff --git a/src/V3Clean.cpp b/src/V3Clean.cpp index 6581ec37e..8416378d4 100644 --- a/src/V3Clean.cpp +++ b/src/V3Clean.cpp @@ -88,6 +88,7 @@ private: if (!nodep->user2() && nodep->hasDType()) { if (VN_IS(nodep, Var) || VN_IS(nodep, NodeDType) // Don't want to change variable widths! || VN_IS(nodep->dtypep()->skipRefp(), AssocArrayDType) // Or arrays + || VN_IS(nodep->dtypep()->skipRefp(), DynArrayDType) || VN_IS(nodep->dtypep()->skipRefp(), ClassRefDType) || VN_IS(nodep->dtypep()->skipRefp(), QueueDType) || VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType) diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index d5e4f9b66..59c521fc5 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -1503,6 +1503,9 @@ class EmitCImp : EmitCStmts { return emitVarResetRecurse(varp, adtypep->subDTypep(), depth+1, ".atDefault()" + cvtarray); } + else if (AstDynArrayDType* adtypep = VN_CAST(dtypep, DynArrayDType)) { + return emitVarResetRecurse(varp, adtypep->subDTypep(), depth+1, ".atDefault()"); + } else if (AstQueueDType* adtypep = VN_CAST(dtypep, QueueDType)) { return emitVarResetRecurse(varp, adtypep->subDTypep(), depth+1, ".atDefault()"); } diff --git a/src/V3EmitCInlines.cpp b/src/V3EmitCInlines.cpp index 9cd64af07..5d60724af 100644 --- a/src/V3EmitCInlines.cpp +++ b/src/V3EmitCInlines.cpp @@ -50,6 +50,10 @@ class EmitCInlines : EmitCBaseVisitor { v3Global.needHeavy(true); iterateChildren(nodep); } + virtual void visit(AstDynArrayDType* nodep) VL_OVERRIDE { + v3Global.needHeavy(true); + iterateChildren(nodep); + } virtual void visit(AstQueueDType* nodep) VL_OVERRIDE { v3Global.needHeavy(true); iterateChildren(nodep); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 69c0c32b6..8283ce30c 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -457,7 +457,7 @@ private: if (m_vup->prelim()) { AstNodeDType* vdtypep = m_vup->dtypeNullp(); if (vdtypep && (VN_IS(vdtypep, AssocArrayDType) - || VN_IS(vdtypep, AssocArrayDType) + || VN_IS(vdtypep, DynArrayDType) || VN_IS(vdtypep, QueueDType))) { nodep->v3error("Unsupported: Concatenation to form " << vdtypep->prettyDTypeNameQ() << "data type"); @@ -536,7 +536,9 @@ private: if (m_vup->prelim()) { AstNodeDType* vdtypep = m_vup->dtypeNullp(); if (vdtypep - && (VN_IS(vdtypep, AssocArrayDType) || VN_IS(vdtypep, QueueDType) + && (VN_IS(vdtypep, AssocArrayDType) + || VN_IS(vdtypep, DynArrayDType) + || VN_IS(vdtypep, QueueDType) || VN_IS(vdtypep, UnpackArrayDType))) { nodep->v3error("Unsupported: Replication to form " << vdtypep->prettyDTypeNameQ() << " data type"); @@ -1219,6 +1221,14 @@ private: nodep->dtypep(nodep); // The array itself, not subDtype UINFO(4,"dtWidthed "<didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed + if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep)); + // Iterate into subDTypep() to resolve that type and update pointer. + nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep())); + nodep->dtypep(nodep); // The array itself, not subDtype + UINFO(4,"dtWidthed "<didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep)); @@ -1445,9 +1455,13 @@ private: if (nodep->childDTypep()) nodep->dtypep(moveChildDTypeEdit(nodep)); nodep->dtypep(iterateEditDTypep(nodep, nodep->dtypep())); UASSERT_OBJ(nodep->dtypep(), nodep, "No dtype determined for var"); - if (VN_IS(nodep->dtypeSkipRefp(), UnsizedArrayDType)) { + if (AstUnsizedArrayDType* unsizedp = VN_CAST(nodep->dtypeSkipRefp(), UnsizedArrayDType)) { if (!(m_ftaskp && m_ftaskp->dpiImport())) { - nodep->v3error("Unsized/open arrays ('[]') are only supported in DPI imports"); + UINFO(9, "Unsized becomes dynamic array " << nodep << endl); + AstDynArrayDType* newp + = new AstDynArrayDType(unsizedp->fileline(), unsizedp->subDTypep()); + nodep->dtypep(newp); + v3Global.rootp()->typeTablep()->addTypesp(newp); } } else if (nodep->isIO() && !(VN_IS(nodep->dtypeSkipRefp(), BasicDType) @@ -1778,6 +1792,7 @@ private: if (memberSelStruct(nodep, adtypep)) return; } else if (VN_IS(fromDtp, EnumDType) || VN_IS(fromDtp, AssocArrayDType) + || VN_IS(fromDtp, DynArrayDType) || VN_IS(fromDtp, QueueDType) || VN_IS(fromDtp, BasicDType)) { // Method call on enum without following parenthesis, e.g. "ENUM.next" @@ -1849,6 +1864,9 @@ private: else if (AstAssocArrayDType* adtypep = VN_CAST(fromDtp, AssocArrayDType)) { methodCallAssoc(nodep, adtypep); } + else if (AstDynArrayDType* adtypep = VN_CAST(fromDtp, DynArrayDType)) { + methodCallDyn(nodep, adtypep); + } else if (AstQueueDType* adtypep = VN_CAST(fromDtp, QueueDType)) { methodCallQueue(nodep, adtypep); } @@ -2059,6 +2077,41 @@ private: if (lvalue) varrefp->lvalue(true); } } + void methodCallDyn(AstMethodCall* nodep, AstDynArrayDType* adtypep) { + AstCMethodHard* newp = NULL; + if (nodep->name() == "at") { // Created internally for [] + methodOkArguments(nodep, 1, 1); + methodCallLValue(nodep, nodep->fromp(), true); + newp = new AstCMethodHard(nodep->fileline(), + nodep->fromp()->unlinkFrBack(), + "at", NULL); + newp->dtypeFrom(adtypep->subDTypep()); + newp->protect(false); + newp->didWidth(true); + } else if (nodep->name() == "size") { + methodOkArguments(nodep, 0, 0); + newp = new AstCMethodHard(nodep->fileline(), + nodep->fromp()->unlinkFrBack(), + "size", NULL); + newp->dtypeSetSigned32(); + newp->didWidth(true); + newp->protect(false); + } else if (nodep->name() == "delete") { // function void delete() + methodOkArguments(nodep, 0, 0); + methodCallLValue(nodep, nodep->fromp(), true); + newp = new AstCMethodHard(nodep->fileline(), + nodep->fromp()->unlinkFrBack(), + "clear", NULL); + newp->makeStatement(); + } else { + nodep->v3error("Unsupported/unknown built-in dynamic array method " + << nodep->prettyNameQ()); + } + if (newp) { + newp->didWidth(true); + nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + } + } void methodCallQueue(AstMethodCall* nodep, AstQueueDType* adtypep) { AstCMethodHard* newp = NULL; if (nodep->name() == "at") { // Created internally for [] @@ -2305,7 +2358,26 @@ private: } virtual void visit(AstNewDynamic* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; - nodep->v3error("Unsupported: Dynamic array new"); + AstDynArrayDType* adtypep = VN_CAST(m_vup->dtypeNullp(), DynArrayDType); + if (!adtypep) { // e.g. int a = new; + if (adtypep) UINFO(1, "Got adtypep " << adtypep << endl); + nodep->v3error("dynamic new() not expected in this context (data type must be dynamic array)"); + return; + } + // The AstNodeAssign visitor will be soon be replacing this node, make sure it gets it + if (!VN_IS(nodep->backp(), NodeAssign)) { + if (adtypep) UINFO(1, "Got backp " << nodep->backp() << endl); + nodep->v3error("dynamic new() not expected in this context (expected under an assign)"); + return; + } + nodep->dtypep(adtypep); + if (m_vup && m_vup->prelim()) { + iterateCheckSigned32(nodep, "new() size", nodep->sizep(), BOTH); + } + if (nodep->rhsp()) { + iterateCheckTyped(nodep, "Dynamic array new RHS", nodep->rhsp(), adtypep->subDTypep(), + BOTH); + } } virtual void visit(AstPattern* nodep) VL_OVERRIDE { @@ -2727,6 +2799,23 @@ private: iterateCheckAssign(nodep, "Assign RHS", nodep->rhsp(), FINAL, lhsDTypep); //if (debug()) nodep->dumpTree(cout, " AssignOut: "); } + if (AstNewDynamic* dynp = VN_CAST(nodep->rhsp(), NewDynamic)) { + UINFO(9, "= new[] -> .resize(): " << nodep); + AstCMethodHard* newp; + if (!dynp->rhsp()) { + newp = new AstCMethodHard(nodep->fileline(), nodep->lhsp()->unlinkFrBack(), + "renew", dynp->sizep()->unlinkFrBack()); + } else { + newp = new AstCMethodHard(nodep->fileline(), nodep->lhsp()->unlinkFrBack(), + "renew_copy", dynp->sizep()->unlinkFrBack()); + newp->addPinsp(dynp->rhsp()->unlinkFrBack()); + } + newp->didWidth(true); + newp->protect(false); + newp->makeStatement(); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } } virtual void visit(AstSFormatF* nodep) VL_OVERRIDE { @@ -2772,6 +2861,7 @@ private: added = true; newFormat += "%g"; } else if (VN_IS(dtypep, AssocArrayDType) + || VN_IS(dtypep, DynArrayDType) || VN_IS(dtypep, QueueDType)) { added = true; newFormat += "%@"; @@ -4225,8 +4315,8 @@ private: AstNode* checkCvtUS(AstNode* nodep) { if (nodep && nodep->isDouble()) { - nodep->v3error("Expected integral (non-real) input to " - <backp()->prettyTypeName()); + nodep->v3error("Expected integral (non-" << nodep->dtypep()->prettyDTypeName() + << ") input to " << nodep->backp()->prettyTypeName()); nodep = spliceCvtS(nodep, true); } return nodep; diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp index ae3e4946d..d2ddff0bc 100644 --- a/src/V3WidthSel.cpp +++ b/src/V3WidthSel.cpp @@ -93,6 +93,8 @@ private: } else if (VN_IS(ddtypep, AssocArrayDType)) { } + else if (VN_IS(ddtypep, DynArrayDType)) { + } else if (VN_IS(ddtypep, QueueDType)) { } else if (const AstNodeUOrStructDType* adtypep = VN_CAST(ddtypep, NodeUOrStructDType)) { @@ -260,6 +262,15 @@ private: if (debug()>=9) newp->dumpTree(cout, "--SELBTn: "); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } + else if (AstDynArrayDType* adtypep = VN_CAST(ddtypep, DynArrayDType)) { + // SELBIT(array, index) -> CMETHODCALL(queue, "at", index) + AstNode* subp = rhsp; + AstCMethodHard* newp = new AstCMethodHard(nodep->fileline(), + fromp, "at", subp); + newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference + if (debug()>=9) newp->dumpTree(cout, "--SELBTq: "); + nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else if (AstQueueDType* adtypep = VN_CAST(ddtypep, QueueDType)) { // SELBIT(array, index) -> CMETHODCALL(queue, "at", index) AstNode* subp = rhsp; diff --git a/test_regress/t/t_dpi_openreg_bad.out b/test_regress/t/t_dpi_openreg_bad.out deleted file mode 100644 index 12ffed236..000000000 --- a/test_regress/t/t_dpi_openreg_bad.out +++ /dev/null @@ -1,9 +0,0 @@ -%Error: t/t_dpi_openreg_bad.v:13: Unsized/open arrays ('[]') are only supported in DPI imports - : ... In instance t - reg a []; - ^ -%Error: t/t_dpi_openreg_bad.v:14: Unsized/open arrays ('[]') are only supported in DPI imports - : ... In instance t - input b []; - ^ -%Error: Exiting due to diff --git a/test_regress/t/t_dpi_openreg_bad.v b/test_regress/t/t_dpi_openreg_bad.v deleted file mode 100644 index f2b5375e0..000000000 --- a/test_regress/t/t_dpi_openreg_bad.v +++ /dev/null @@ -1,20 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// Copyright 2009 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. - -module t (/*AUTOARG*/ - // Inputs - b - ); - - reg a []; - input b []; - - initial begin - $stop; - end - -endmodule diff --git a/test_regress/t/t_dynarray.pl b/test_regress/t/t_dynarray.pl new file mode 100755 index 000000000..6b3b15be5 --- /dev/null +++ b/test_regress/t/t_dynarray.pl @@ -0,0 +1,20 @@ +#!/usr/bin/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. + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_dynarray.v b/test_regress/t/t_dynarray.v new file mode 100644 index 000000000..146ad0be2 --- /dev/null +++ b/test_regress/t/t_dynarray.v @@ -0,0 +1,108 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2020 by Wilson Snyder. + +`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*/ + // Inputs + clk + ); + input clk; + + integer cyc=0; + + integer i; + string v; + + // verilator lint_off UNUSED + integer unused[]; + // verilator lint_on UNUSED + + typedef bit [7:0] byte_t; + byte_t a[]; + byte_t b[]; + + always @ (posedge clk) begin + cyc <= cyc + 1; + begin + `checkh(a.size, 0); + v = $sformatf("%p", a); `checks(v, "'{} "); + + a = new [3]; + `checkh(a.size, 3); + a[0] = 10; + a[1] = 11; + a[2] = 12; + `checkh(a[0], 10); + `checkh(a[1], 11); + `checkh(a[2], 12); + v = $sformatf("%p", a); `checks(v, "'{'ha, 'hb, 'hc} "); + a.delete; + `checkh(a.size, 0); + + a = new [2]; +`ifdef verilator // Unsupported pattern assignment + a[0] = 15; a[1] = 16; +`else + a = '{15, 16}; +`endif + `checkh(a.size, 2); + `checkh(a[0], 15); + `checkh(a[1], 16) + +`ifdef verilator // Unsupported pattern assignment + a = new [1]; + a[0] = 17; +`else + a = '{17}; +`endif + `checkh(a.size, 1); // IEEE says resizes to smallest that fits pattern + `checkh(a[0], 17); + + a = new[2]; + a[0] = 5; + a[1] = 6; + `checkh(a[0], 5); + `checkh(a[1], 6); + a = new[2]; + `checkh(a[0], 0); + `checkh(a[1], 0); + + a[0] = 5; + a[1] = 6; + `checkh(a[0], 5); + `checkh(a[1], 6); + + b = new [4](a); + `checkh(b.size, 4); + `checkh(b[0], 5); + `checkh(b[1], 6); + `checkh(b[2], 0); + `checkh(b[3], 0); + + a = b; + `checkh(a.size, 4); + `checkh(a[0], 5); + `checkh(a[1], 6); + `checkh(a[2], 0); + `checkh(a[3], 0); + + a = new [0]; + `checkh(a.size, 0); + b = new [4](a); + `checkh(b.size, 4); + `checkh(b[0], 0); + `checkh(b[1], 0); + `checkh(b[2], 0); + `checkh(b[4], 0); + end + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_dynarray_bad.out b/test_regress/t/t_dynarray_bad.out new file mode 100644 index 000000000..c323f3ca2 --- /dev/null +++ b/test_regress/t/t_dynarray_bad.out @@ -0,0 +1,6 @@ +%Warning-WIDTH: t/t_dynarray_bad.v:14: Operator NEWDYNAMIC expects 32 bits on the new() size, but new() size's VARREF 's' generates 64 bits. + : ... In instance t + a = new [s]; + ^~~ + ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. +%Error: Internal Error: ../V3Number.cpp:#: Number operation called with non-logic (double or string) argument: '"str"" diff --git a/test_regress/t/t_dpi_openreg_bad.pl b/test_regress/t/t_dynarray_bad.pl similarity index 81% rename from test_regress/t/t_dpi_openreg_bad.pl rename to test_regress/t/t_dynarray_bad.pl index 57ecc0da2..4689d6999 100755 --- a/test_regress/t/t_dpi_openreg_bad.pl +++ b/test_regress/t/t_dynarray_bad.pl @@ -2,7 +2,7 @@ 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 +# 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. @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(linter => 1); lint( - fails => $Self->{vlt_all}, + fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_dynarray_bad.v b/test_regress/t/t_dynarray_bad.v new file mode 100644 index 000000000..2516a6deb --- /dev/null +++ b/test_regress/t/t_dynarray_bad.v @@ -0,0 +1,17 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2020 by Wilson Snyder. + +module t (/*AUTOARG*/); + + integer a[]; + + string s; + + initial begin + s = "str"; + a = new [s]; // Bad + end + +endmodule From 2d52f525c57f8c7d6170c993b24e123241415f4d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 7 Mar 2020 10:51:06 -0500 Subject: [PATCH 40/50] Add --structs-packed for forward compatibility, #1541. --- Changes | 2 ++ bin/verilator | 7 +++++++ src/V3Options.cpp | 2 ++ src/V3Options.h | 2 ++ src/V3Width.cpp | 3 +++ 5 files changed, 16 insertions(+) diff --git a/Changes b/Changes index 4c0ace434..671649dd1 100644 --- a/Changes +++ b/Changes @@ -15,6 +15,8 @@ The contributors that suggested a given feature are shown in []. Thanks! *** Add check for assertOn for asserts, #2162. [Tobias Wölfel] +*** Add --structs-packed for forward compatibility. + *** Fix genblk naming with directly nested generate blocks, #2176. [Alexander Grobman] **** Implement $displayb/o/h, $writeb/o/h, etc, #1637. diff --git a/bin/verilator b/bin/verilator index 57ae1c283..b321db9e7 100755 --- a/bin/verilator +++ b/bin/verilator @@ -1344,6 +1344,13 @@ Creates more detailed statistics, including a list of all the variables by size (plain --stats just gives a count). See --stats, which is implied by this. +=item --structs-packed + +Converts all unpacked structures to packed structures and issues a UNPACKED +warning. Currently this is the default and --no-structs-packed will not +work. Specifying this option allows for forward compatibility when a +future version of Verilator no longer always packs unpacked structures. + =item -sv Specifies SystemVerilog language features should be enabled; equivalent to diff --git a/src/V3Options.cpp b/src/V3Options.cpp index eb56d87b2..724fc37e4 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -786,6 +786,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char else if ( onoffb(sw, "-skip-identical", bflag/*ref*/)) { m_skipIdentical = bflag; } else if ( onoff (sw, "-stats", flag/*ref*/)) { m_stats = flag; } else if ( onoff (sw, "-stats-vars", flag/*ref*/)) { m_statsVars = flag; m_stats |= flag; } + else if ( onoff (sw, "-structs-unpacked", flag/*ref*/)) { m_structsPacked = flag; } else if (!strcmp(sw, "-sv")) { m_defaultLanguage = V3LangCode::L1800_2005; } else if ( onoff (sw, "-threads-coarsen", flag/*ref*/)) { m_threadsCoarsen = flag; } // Undocumented, debug else if ( onoff (sw, "-trace", flag/*ref*/)) { m_trace = flag; } @@ -1489,6 +1490,7 @@ V3Options::V3Options() { m_savable = false; m_stats = false; m_statsVars = false; + m_structsPacked = true; m_systemC = false; m_threads = 0; m_threadsDpiPure = true; diff --git a/src/V3Options.h b/src/V3Options.h index f89ab5a45..339349fdc 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -184,6 +184,7 @@ class V3Options { bool m_relativeIncludes; // main switch: --relative-includes bool m_reportUnoptflat; // main switch: --report-unoptflat bool m_savable; // main switch: --savable + bool m_structsPacked; // main switch: --structs-packed bool m_systemC; // main switch: --sc: System C instead of simple C++ bool m_stats; // main switch: --stats bool m_statsVars; // main switch: --stats-vars @@ -322,6 +323,7 @@ class V3Options { bool savable() const { return m_savable; } bool stats() const { return m_stats; } bool statsVars() const { return m_statsVars; } + bool structsPacked() const { return m_structsPacked; } bool assertOn() const { return m_assert; } // assertOn as __FILE__ may be defined bool autoflush() const { return m_autoflush; } bool bboxSys() const { return m_bboxSys; } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 8283ce30c..485dbd7e0 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1745,6 +1745,9 @@ private: //if (debug()>=9) nodep->dumpTree("-class-in--"); if (!nodep->packed()) { nodep->v3warn(UNPACKED, "Unsupported: Unpacked struct/union"); + if (!v3Global.opt.structsPacked()) { + nodep->v3warn(UNPACKED, "Unsupported: --no-structs-packed"); + } } userIterateChildren(nodep, NULL); // First size all members nodep->repairMemberCache(); From 961ac49c5ce1ab33376b538fbfaac4b4b2042d1a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 7 Mar 2020 11:00:57 -0500 Subject: [PATCH 41/50] Internals: Merge parse type from classes branch. No functional change intended. --- src/verilog.y | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/verilog.y b/src/verilog.y index 1a4d5cb00..c7ba7f6b0 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -5470,7 +5470,7 @@ ps_id_etc: // package_scope + general id package_scopeIdFollowsE id { } ; -ps_type: // IEEE: ps_parameter_identifier | ps_type_identifier +ps_type: // IEEE: ps_parameter_identifier | ps_type_identifier // Even though we looked up the type and have a AstNode* to it, // we can't fully resolve it because it may have been just a forward definition. package_scopeIdFollowsE idRefDType { $$ = $2; $2->packagep($1); } @@ -5479,7 +5479,7 @@ ps_type: // IEEE: ps_parameter_identifier | ps_type_identifier //=== Below rules assume special scoping per above -class_typeWithoutId: // as with class_typeWithoutId but allow yaID__aTYPE +class_typeWithoutId: // as with class_typeWithoutId but allow yaID__aTYPE // // and we thus don't need to resolve it in specified package package_scopeIdFollowsE class_typeOneList { $$ = $2; $2->packagep($1); } ; From 808c958d42614bc42536f0434d6192652982e2ae Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 7 Mar 2020 12:52:11 -0500 Subject: [PATCH 42/50] Internals: Add AstNodeCCall and other items towards classes. --- src/V3Ast.h | 71 ++++++++++++++++++++++++---- src/V3AstNodes.cpp | 43 ++++++++++++----- src/V3AstNodes.h | 108 ++++++++++++++++++------------------------- src/V3Branch.cpp | 2 +- src/V3Clean.cpp | 2 +- src/V3Dead.cpp | 10 ++++ src/V3DepthBlock.cpp | 2 +- src/V3Descope.cpp | 2 +- src/V3EmitC.cpp | 10 +++- src/V3GenClk.cpp | 2 +- src/V3Inline.cpp | 3 +- src/V3InstrCount.cpp | 2 +- src/V3Life.cpp | 2 +- src/V3LifePost.cpp | 4 +- src/V3Partition.cpp | 2 +- src/V3Scope.cpp | 2 +- src/V3Stats.cpp | 2 +- src/V3Task.cpp | 10 +++- 18 files changed, 181 insertions(+), 98 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index f877e4056..851c4c898 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -55,6 +55,12 @@ typedef std::set MTaskIdSet; // Set of mtaskIds for Var sorting do { \ if (VL_UNCOVERABLE(test)) return #test; \ } while (0) +// For broken() function, return error string if a base of this class has a match +#define BROKEN_BASE_RTN(test) \ + do { \ + const char* reasonp = (test); \ + if (VL_UNCOVERABLE(reasonp)) return reasonp; \ + } while (0) // (V)erilator (N)ode is: True if AstNode is of a a given AstType #define VN_IS(nodep,nodetypename) (AstNode::privateIs(nodep)) @@ -2230,6 +2236,54 @@ public: //###################################################################### // Tasks/functions common handling +class AstNodeCCall : public AstNodeStmt { + // A call of a C++ function, perhaps a AstCFunc or perhaps globally named + // Functions are not statements, while tasks are. AstNodeStmt needs isStatement() to deal. + AstCFunc* m_funcp; + string m_hiername; + string m_argTypes; +public: + AstNodeCCall(AstType t, FileLine* fl, AstCFunc* funcp, AstNode* argsp = NULL) + : AstNodeStmt(t, fl, true) + , m_funcp(funcp) { + addNOp2p(argsp); + } + // Replacement form for V3Combine + // Note this removes old attachments from the oldp + AstNodeCCall(AstType t, AstNodeCCall* oldp, AstCFunc* funcp) + : AstNodeStmt(t, oldp->fileline(), true) + , m_funcp(funcp) { + m_funcp = funcp; + m_hiername = oldp->hiername(); + m_argTypes = oldp->argTypes(); + if (oldp->argsp()) addNOp2p(oldp->argsp()->unlinkFrBackWithNext()); + } + ASTNODE_BASE_FUNCS(NodeCCall) + virtual void dump(std::ostream& str=std::cout) const; + virtual void cloneRelink(); + virtual const char* broken() const; + virtual int instrCount() const { return instrCountCall(); } + virtual V3Hash sameHash() const { return V3Hash(funcp()); } + virtual bool same(const AstNode* samep) const { + const AstNodeCCall* asamep = static_cast(samep); + return (funcp() == asamep->funcp() && argTypes() == asamep->argTypes()); + } + AstNode* exprsp() const { return op2p(); } // op2 = expressions to print + virtual bool isGateOptimizable() const { return false; } + virtual bool isPredictOptimizable() const { return false; } + virtual bool isPure() const; + virtual bool isOutputter() const { return !isPure(); } + AstCFunc* funcp() const { return m_funcp; } + string hiername() const { return m_hiername; } + void hiername(const string& hn) { m_hiername = hn; } + string hiernameProtect() const; + void argTypes(const string& str) { m_argTypes = str; } + string argTypes() const { return m_argTypes; } + // op1p reserved for AstCMethodCall + AstNode* argsp() const { return op2p(); } + void addArgsp(AstNode* nodep) { addOp2p(nodep); } +}; + class AstNodeFTask : public AstNode { private: string m_name; // Name of task @@ -2311,12 +2365,12 @@ public: AstNodeFTaskRef(AstType t, FileLine* fl, bool statement, AstNode* namep, AstNode* pinsp) : AstNodeStmt(t, fl, statement) , m_taskp(NULL), m_packagep(NULL) { - setOp1p(namep); addNOp2p(pinsp); + setOp1p(namep); addNOp3p(pinsp); } AstNodeFTaskRef(AstType t, FileLine* fl, bool statement, const string& name, AstNode* pinsp) : AstNodeStmt(t, fl, statement) , m_taskp(NULL), m_name(name), m_packagep(NULL) { - addNOp2p(pinsp); + addNOp3p(pinsp); } ASTNODE_BASE_FUNCS(NodeFTaskRef) virtual const char* broken() const { BROKEN_RTN(m_taskp && !m_taskp->brokeExists()); return NULL; } @@ -2338,12 +2392,13 @@ public: void packagep(AstPackage* nodep) { m_packagep = nodep; } // op1 = namep AstNode* namep() const { return op1p(); } - // op2 = Pin interconnection list - AstNode* pinsp() const { return op2p(); } - void addPinsp(AstNode* nodep) { addOp2p(nodep); } - // op3 = scope tracking - AstScopeName* scopeNamep() const { return VN_CAST(op3p(), ScopeName); } - void scopeNamep(AstNode* nodep) { setNOp3p(nodep); } + // op2 = reserved for AstMethodCall + // op3 = Pin interconnection list + AstNode* pinsp() const { return op3p(); } + void addPinsp(AstNode* nodep) { addOp3p(nodep); } + // op4 = scope tracking + AstScopeName* scopeNamep() const { return VN_CAST(op4p(), ScopeName); } + void scopeNamep(AstNode* nodep) { setNOp4p(nodep); } }; class AstNodeModule : public AstNode { diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 89e6de50e..9f57d2ba3 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -26,6 +26,7 @@ #include "V3Global.h" #include "V3Graph.h" #include "V3PartitionGraph.h" // Just for mtask dumping +#include "V3EmitCBase.h" #include #include @@ -88,6 +89,27 @@ const char* AstNodeUOrStructDType::broken() const { return NULL; } +void AstNodeCCall::dump(std::ostream& str) const { + this->AstNode::dump(str); + if (funcp()) { + str << " " << funcp()->name() << " => "; + funcp()->dump(str); + } else { + str << " " << name(); + } +} +void AstNodeCCall::cloneRelink() { + if (m_funcp && m_funcp->clonep()) { m_funcp = m_funcp->clonep(); } +} +const char* AstNodeCCall::broken() const { + BROKEN_RTN(m_funcp && !m_funcp->brokeExists()); + return NULL; +} +bool AstNodeCCall::isPure() const { return funcp()->pure(); } +string AstNodeCCall::hiernameProtect() const { + return VIdProtect::protectWordsIf(hiername(), protect()); +} + void AstNodeCond::numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, const V3Number& ths) { if (lhs.isNeqZero()) out.opAssign(rhs); else out.opAssign(ths); @@ -679,10 +701,6 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep) { ///< What is the base variabl return nodep; } -string AstCCall::hiernameProtect() const { - return VIdProtect::protectWordsIf(hiername(), protect()); -} - const char* AstScope::broken() const { BROKEN_RTN(m_aboveScopep && !m_aboveScopep->brokeExists()); BROKEN_RTN(m_aboveCellp && !m_aboveCellp->brokeExists()); @@ -1024,6 +1042,16 @@ void AstMemberSel::dump(std::ostream& str) const { if (varp()) { varp()->dump(str); } else { str << "%Error:UNLINKED"; } } +void AstMethodCall::dump(std::ostream& str) const { + this->AstNode::dump(str); + if (isStatement()) str << " [STMT]"; + str << " -> "; + if (taskp()) { + taskp()->dump(str); + } else { + str << " -> UNLINKED"; + } +} void AstModportFTaskRef::dump(std::ostream& str) const { this->AstNode::dump(str); if (isExport()) str<<" EXPORT"; @@ -1343,13 +1371,6 @@ void AstCFile::dump(std::ostream& str) const { if (source()) str<<" [SRC]"; if (slow()) str<<" [SLOW]"; } -void AstCCall::dump(std::ostream& str) const { - this->AstNode::dump(str); - if (funcp()) { - str<<" "<name()<<" => "; - funcp()->dump(str); - } -} void AstCFunc::dump(std::ostream& str) const { this->AstNode::dump(str); if (slow()) str<<" [SLOW]"; diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index c4c55a1e3..c060added 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -1408,31 +1408,33 @@ public: void declRange(const VNumRange& flag) { m_declRange = flag; } }; -class AstMethodCall : public AstNode { +class AstMethodCall : public AstNodeFTaskRef { // A reference to a member task (or function) - // We do not support generic member calls yet, so this is only enough to - // make built-in methods work -private: - string m_name; // Name of method + // PARENTS: stmt/math + // Not all calls are statments vs math. AstNodeStmt needs isStatement() to deal. + // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it public: - AstMethodCall(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name, AstNode* pinsp) - : ASTGEN_SUPER(fl), m_name(name) { - setOp1p(fromp); + AstMethodCall(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name, + AstNode* pinsp) + : ASTGEN_SUPER(fl, false, name, pinsp) { + setOp2p(fromp); dtypep(NULL); // V3Width will resolve - addNOp2p(pinsp); } AstMethodCall(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp) - : ASTGEN_SUPER(fl), m_name(name) { - setOp1p(fromp); - addNOp2p(pinsp); + : ASTGEN_SUPER(fl, false, name, pinsp) { + setOp2p(fromp); } ASTNODE_NODE_FUNCS(MethodCall) - virtual string name() const { return m_name; } // * = Var name - virtual void name(const string& name) { m_name = name; } - AstNode* fromp() const { return op1p(); } // op1 = Extracting what (NULL=TBD during parsing) - void fromp(AstNode* nodep) { setOp1p(nodep); } - AstNode* pinsp() const { return op2p(); } // op2 = Pin interconnection list - void addPinsp(AstNode* nodep) { addOp2p(nodep); } + virtual const char* broken() const { + BROKEN_BASE_RTN(AstNodeFTaskRef::broken()); + BROKEN_RTN(!fromp()); + return NULL; + } + virtual void dump(std::ostream& str) const; + virtual bool hasDType() const { return true; } + void makeStatement() { statement(true); dtypeSetVoid(); } + AstNode* fromp() const { return op2p(); } // op2 = Extracting what (NULL=TBD during parsing) + void fromp(AstNode* nodep) { setOp2p(nodep); } }; class AstCMethodHard : public AstNodeStmt { @@ -3995,7 +3997,6 @@ class AstNew : public AstNodeMath { public: AstNew(FileLine* fl, AstNode* argsp) : ASTGEN_SUPER(fl) { - dtypep(NULL); // V3Width will resolve addNOp2p(argsp); } ASTNODE_NODE_FUNCS(New) @@ -6881,54 +6882,37 @@ public: bool emptyBody() const { return argsp()==NULL && initsp()==NULL && stmtsp()==NULL && finalsp()==NULL; } }; -class AstCCall : public AstNodeStmt { +class AstCCall : public AstNodeCCall { // C++ function call // Parents: Anything above a statement // Children: Args to the function -private: - AstCFunc* m_funcp; - string m_hiername; - string m_argTypes; public: - AstCCall(FileLine* fl, AstCFunc* funcp, AstNode* argsp=NULL) - : ASTGEN_SUPER(fl) { - m_funcp = funcp; - addNOp1p(argsp); - } - AstCCall(AstCCall* oldp, AstCFunc* funcp) // Replacement form for V3Combine - // Note this removes old attachments from the oldp - : ASTGEN_SUPER(oldp->fileline()) { - m_funcp = funcp; - m_hiername = oldp->hiername(); - m_argTypes = oldp->argTypes(); - if (oldp->argsp()) addNOp1p(oldp->argsp()->unlinkFrBackWithNext()); - } + AstCCall(FileLine* fl, AstCFunc* funcp, AstNode* argsp = NULL) + : ASTGEN_SUPER(fl, funcp, argsp) {} + // Replacement form for V3Combine + // Note this removes old attachments from the oldp + AstCCall(AstCCall* oldp, AstCFunc* funcp) + : ASTGEN_SUPER(oldp, funcp) {} ASTNODE_NODE_FUNCS(CCall) - virtual void dump(std::ostream& str=std::cout) const; - virtual void cloneRelink() { if (m_funcp && m_funcp->clonep()) { - m_funcp = m_funcp->clonep(); - }} - virtual const char* broken() const { BROKEN_RTN(m_funcp && !m_funcp->brokeExists()); return NULL; } - virtual int instrCount() const { return instrCountCall(); } - virtual V3Hash sameHash() const { return V3Hash(funcp()); } - virtual bool same(const AstNode* samep) const { - const AstCCall* asamep = static_cast(samep); - return (funcp() == asamep->funcp() - && argTypes() == asamep->argTypes()); } - AstNode* exprsp() const { return op1p(); } // op1 = expressions to print - virtual bool isGateOptimizable() const { return false; } - virtual bool isPredictOptimizable() const { return false; } - virtual bool isPure() const { return funcp()->pure(); } - virtual bool isOutputter() const { return !(funcp()->pure()); } - AstCFunc* funcp() const { return m_funcp; } - string hiername() const { return m_hiername; } - void hiername(const string& hn) { m_hiername = hn; } - string hiernameProtect() const; - void argTypes(const string& str) { m_argTypes = str; } - string argTypes() const { return m_argTypes; } - // - AstNode* argsp() const { return op1p(); } - void addArgsp(AstNode* nodep) { addOp1p(nodep); } +}; + +class AstCMethodCall : public AstNodeCCall { + // C++ method call + // Parents: Anything above a statement + // Children: Args to the function +public: + AstCMethodCall(FileLine* fl, AstNode* fromp, AstCFunc* funcp, AstNode* argsp = NULL) + : ASTGEN_SUPER(fl, funcp, argsp) { + setOp1p(fromp); + } + ASTNODE_NODE_FUNCS(CMethodCall) + virtual const char* broken() const { + BROKEN_BASE_RTN(AstNodeCCall::broken()); + BROKEN_RTN(!fromp()); + return NULL; + } + AstNode* fromp() const { return op1p(); } // op1 = Extracting what (NULL=TBD during parsing) + void fromp(AstNode* nodep) { setOp1p(nodep); } }; class AstCReturn : public AstNodeStmt { diff --git a/src/V3Branch.cpp b/src/V3Branch.cpp index 8533d475f..ff713d124 100644 --- a/src/V3Branch.cpp +++ b/src/V3Branch.cpp @@ -96,7 +96,7 @@ private: m_likely = lastLikely; m_unlikely = lastUnlikely; } - virtual void visit(AstCCall* nodep) VL_OVERRIDE { + virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE { checkUnlikely(nodep); nodep->funcp()->user1Inc(); iterateChildren(nodep); diff --git a/src/V3Clean.cpp b/src/V3Clean.cpp index 8416378d4..16463090a 100644 --- a/src/V3Clean.cpp +++ b/src/V3Clean.cpp @@ -281,7 +281,7 @@ private: iterateChildren(nodep); ensureCleanAndNext(nodep->bodysp()); } - virtual void visit(AstCCall* nodep) VL_OVERRIDE { + virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE { iterateChildren(nodep); ensureCleanAndNext(nodep->argsp()); setClean(nodep, true); diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index e864f2af3..a98ff7bfb 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -188,6 +188,10 @@ private: else nodep->packagep()->user1Inc(); } } + virtual void visit(AstMethodCall* nodep) VL_OVERRIDE { + iterateChildren(nodep); + checkAll(nodep); + } virtual void visit(AstRefDType* nodep) VL_OVERRIDE { iterateChildren(nodep); checkDType(nodep); @@ -211,6 +215,12 @@ private: } checkAll(nodep); } + virtual void visit(AstMemberSel* nodep) VL_OVERRIDE { + iterateChildren(nodep); + if (nodep->varp()) nodep->varp()->user1Inc(); + if (nodep->fromp()->dtypep()) nodep->fromp()->dtypep()->user1Inc(); // classref + checkAll(nodep); + } virtual void visit(AstModport* nodep) VL_OVERRIDE { iterateChildren(nodep); if (m_elimCells) { diff --git a/src/V3DepthBlock.cpp b/src/V3DepthBlock.cpp index f924703e0..6ddb7e774 100644 --- a/src/V3DepthBlock.cpp +++ b/src/V3DepthBlock.cpp @@ -96,7 +96,7 @@ private: void visitStmt(AstNodeStmt* nodep) { m_depth++; if (m_depth > v3Global.opt.compLimitBlocks() - && !VN_IS(nodep, CCall)) { // Already done + && !VN_IS(nodep, NodeCCall)) { // Already done UINFO(4, "DeepBlocks "<backp(); // Only for debug if (debug()>=9) backp->dumpTree(cout, "- pre : "); diff --git a/src/V3Descope.cpp b/src/V3Descope.cpp index f48a27ce5..4f0ca0aad 100644 --- a/src/V3Descope.cpp +++ b/src/V3Descope.cpp @@ -259,7 +259,7 @@ private: nodep->hierThis(hierThis); nodep->varScopep(NULL); } - virtual void visit(AstCCall* nodep) VL_OVERRIDE { + virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE { // UINFO(9," "<hiernameProtect()); + virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE { + if (AstCMethodCall* ccallp = VN_CAST(nodep, CMethodCall)) { + // make this a Ast type for future opt + iterate(ccallp->fromp()); + putbs("->"); + } else { + puts(nodep->hiernameProtect()); + } puts(nodep->funcp()->nameProtect()); puts("("); puts(nodep->argTypes()); diff --git a/src/V3GenClk.cpp b/src/V3GenClk.cpp index 34573f9f1..eda3e027c 100644 --- a/src/V3GenClk.cpp +++ b/src/V3GenClk.cpp @@ -168,7 +168,7 @@ private: iterateChildren(nodep); } } - virtual void visit(AstCCall* nodep) VL_OVERRIDE { + virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE { iterateChildren(nodep); if (!nodep->funcp()->entryPoint()) { // Enter the function and trace it diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index dd32eda44..364b3ec77 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -150,7 +150,8 @@ private: } virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE { // Cleanup link until V3LinkDot can correct it - if (!nodep->packagep()) nodep->taskp(NULL); + // MethodCalls not currently supported by inliner, so keep linked + if (!nodep->packagep() && !VN_IS(nodep, MethodCall)) nodep->taskp(NULL); iterateChildren(nodep); } virtual void visit(AstAlways* nodep) VL_OVERRIDE { diff --git a/src/V3InstrCount.cpp b/src/V3InstrCount.cpp index f0d26cd16..94c54c3d7 100644 --- a/src/V3InstrCount.cpp +++ b/src/V3InstrCount.cpp @@ -236,7 +236,7 @@ private: markCost(nodep); UASSERT_OBJ(nodep == m_startNodep, nodep, "Multiple actives, or not start node"); } - virtual void visit(AstCCall* nodep) VL_OVERRIDE { + virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE { VisitBase vb(this, nodep); iterateChildren(nodep); m_tracingCall = true; diff --git a/src/V3Life.cpp b/src/V3Life.cpp index 44d86ab18..e02164178 100644 --- a/src/V3Life.cpp +++ b/src/V3Life.cpp @@ -410,7 +410,7 @@ private: bodyLifep->lifeToAbove(); VL_DO_DANGLING(delete bodyLifep, bodyLifep); } - virtual void visit(AstCCall* nodep) VL_OVERRIDE { + virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE { //UINFO(4," CCALL "<isTop()) iterateChildren(nodep); } - virtual void visit(AstCCall* nodep) VL_OVERRIDE { + virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE { iterateChildren(nodep); if (!nodep->funcp()->entryPoint()) { // Enter the function and trace it @@ -319,7 +319,7 @@ private: // Only track the top scopes, not lower level functions if (nodep->isTop()) iterateChildren(nodep); } - virtual void visit(AstCCall* nodep) VL_OVERRIDE { + virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE { iterateChildren(nodep); if (!nodep->funcp()->entryPoint()) { // Enter the function and trace it diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index f742fdad2..b8ae1f469 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -1777,7 +1777,7 @@ private: } iterateChildren(nodep); } - virtual void visit(AstCCall* nodep) VL_OVERRIDE { + virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE { iterateChildren(nodep); // Enter the function and trace it m_tracingCall = true; diff --git a/src/V3Scope.cpp b/src/V3Scope.cpp index 315394e48..f2f7e0d87 100644 --- a/src/V3Scope.cpp +++ b/src/V3Scope.cpp @@ -386,7 +386,7 @@ private: UASSERT_OBJ(newp, nodep, "No clone for package function"); nodep->taskp(newp); UINFO(9," New pkg-taskref "<taskp(NULL); UINFO(9," New pkg-taskref "<funcp()->entryPoint()) { diff --git a/src/V3Task.cpp b/src/V3Task.cpp index ac9d669c2..8ced44164 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -190,6 +190,7 @@ private: m_assignwp = NULL; } virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE { + // Includes handling AstMethodCall if (m_assignwp) { // Wire assigns must become always statements to deal with insertion // of multiple statements. Perhaps someday make all wassigns into always's? @@ -487,7 +488,12 @@ private: // AstNode* beginp = new AstComment(refp->fileline(), string("Function: ")+refp->name(), true); - AstCCall* ccallp = new AstCCall(refp->fileline(), cfuncp, NULL); + AstNodeCCall* ccallp; + if (AstMethodCall* mrefp = VN_CAST(refp, MethodCall)) { + ccallp = new AstCMethodCall(refp->fileline(), mrefp->fromp()->unlinkFrBack(), cfuncp); + } else { + ccallp = new AstCCall(refp->fileline(), cfuncp); + } beginp->addNext(ccallp); // Convert complicated outputs to temp signals @@ -1174,7 +1180,7 @@ private: } // Replace the ref AstNode* visitp = NULL; - if (VN_IS(nodep, FuncRef)) { + if (!nodep->isStatement()) { UASSERT_OBJ(nodep->taskp()->isFunction(), nodep, "func reference to non-function"); AstVarRef* outrefp = new AstVarRef(nodep->fileline(), outvscp, false); nodep->replaceWith(outrefp); From 6f49f802b11bcaef6156157666106f76690b13ee Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 7 Mar 2020 16:59:46 -0500 Subject: [PATCH 43/50] Tests: Add fst_identical. --- test_regress/driver.pl | 11 ++++++++++- test_regress/t/t_interface_ref_trace_fst.pl | 3 +-- test_regress/t/t_trace_array_fst.pl | 3 +-- test_regress/t/t_trace_complex_fst.pl | 3 +-- test_regress/t/t_trace_complex_fst_thread.pl | 3 +-- test_regress/t/t_trace_complex_params_fst.pl | 3 +-- test_regress/t/t_trace_complex_structs_fst.pl | 3 +-- test_regress/t/t_trace_fst.pl | 3 +-- test_regress/t/t_trace_packed_struct_fst.pl | 3 +-- test_regress/t/t_trace_two_dumpfst_cc.pl | 3 +-- test_regress/t/t_trace_two_hdrfst_cc.pl | 3 +-- test_regress/t/t_trace_two_portfst_cc.pl | 3 +-- 12 files changed, 21 insertions(+), 23 deletions(-) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index b2560964f..1cb2c5536 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -2075,11 +2075,20 @@ sub fst2vcd { if (!$out || $out !~ /Usage:/) { $self->skip("No fst2vcd installed\n"); return 1; } $cmd = qq{fst2vcd -e "$fn1" -o "$fn2"}; - print "\t$cmd\n" if $::Debug; + print "\t$cmd\n"; # Always print to help debug race cases $out = `$cmd`; return 1; } +sub fst_identical { + my $self = (ref $_[0]? shift : $Self); + my $fn1 = shift; + my $fn2 = shift; + my $tmp = $fn1.".vcd"; + fst2vcd($fn1, $tmp); + return vcd_identical($tmp, $fn2); +} + sub _vcd_read { my $self = (ref $_[0]? shift : $Self); my $filename = shift; diff --git a/test_regress/t/t_interface_ref_trace_fst.pl b/test_regress/t/t_interface_ref_trace_fst.pl index 4f96ba39e..b94b6c15c 100755 --- a/test_regress/t/t_interface_ref_trace_fst.pl +++ b/test_regress/t/t_interface_ref_trace_fst.pl @@ -19,8 +19,7 @@ execute( check_finished => 1, ); -fst2vcd($Self->trace_filename, "$Self->{obj_dir}/simx-fst2vcd.vcd"); -vcd_identical("$Self->{obj_dir}/simx-fst2vcd.vcd", $Self->{golden_filename}); +fst_identical($Self->trace_filename, $Self->{golden_filename}); ok(1); 1; diff --git a/test_regress/t/t_trace_array_fst.pl b/test_regress/t/t_trace_array_fst.pl index ac5674592..71df415e7 100755 --- a/test_regress/t/t_trace_array_fst.pl +++ b/test_regress/t/t_trace_array_fst.pl @@ -19,8 +19,7 @@ execute( check_finished => 1, ); -fst2vcd($Self->trace_filename, "$Self->{obj_dir}/simx-fst2vcd.vcd"); -vcd_identical("$Self->{obj_dir}/simx-fst2vcd.vcd", $Self->{golden_filename}); +fst_identical($Self->trace_filename, $Self->{golden_filename}); ok(1); 1; diff --git a/test_regress/t/t_trace_complex_fst.pl b/test_regress/t/t_trace_complex_fst.pl index 5539602ff..f44a661c8 100755 --- a/test_regress/t/t_trace_complex_fst.pl +++ b/test_regress/t/t_trace_complex_fst.pl @@ -19,8 +19,7 @@ execute( check_finished => 1, ); -fst2vcd($Self->trace_filename, "$Self->{obj_dir}/simx-fst2vcd.vcd"); -vcd_identical("$Self->{obj_dir}/simx-fst2vcd.vcd", $Self->{golden_filename}); +fst_identical($Self->trace_filename, $Self->{golden_filename}); ok(1); 1; diff --git a/test_regress/t/t_trace_complex_fst_thread.pl b/test_regress/t/t_trace_complex_fst_thread.pl index 9430e48fb..f52f24b8a 100755 --- a/test_regress/t/t_trace_complex_fst_thread.pl +++ b/test_regress/t/t_trace_complex_fst_thread.pl @@ -20,8 +20,7 @@ execute( check_finished => 1, ); -fst2vcd($Self->trace_filename, "$Self->{obj_dir}/simx-fst2vcd.vcd"); -vcd_identical("$Self->{obj_dir}/simx-fst2vcd.vcd", $Self->{golden_filename}); +fst_identical($Self->trace_filename, $Self->{golden_filename}); ok(1); 1; diff --git a/test_regress/t/t_trace_complex_params_fst.pl b/test_regress/t/t_trace_complex_params_fst.pl index cd2aa2f9d..436680ea9 100755 --- a/test_regress/t/t_trace_complex_params_fst.pl +++ b/test_regress/t/t_trace_complex_params_fst.pl @@ -19,8 +19,7 @@ execute( check_finished => 1, ); -fst2vcd($Self->trace_filename, "$Self->{obj_dir}/simx-fst2vcd.vcd"); -vcd_identical("$Self->{obj_dir}/simx-fst2vcd.vcd", $Self->{golden_filename}); +fst_identical($Self->trace_filename, $Self->{golden_filename}); ok(1); 1; diff --git a/test_regress/t/t_trace_complex_structs_fst.pl b/test_regress/t/t_trace_complex_structs_fst.pl index 60f80c1cd..3a6b98aa1 100755 --- a/test_regress/t/t_trace_complex_structs_fst.pl +++ b/test_regress/t/t_trace_complex_structs_fst.pl @@ -19,8 +19,7 @@ execute( check_finished => 1, ); -fst2vcd($Self->trace_filename, "$Self->{obj_dir}/simx-fst2vcd.vcd"); -vcd_identical("$Self->{obj_dir}/simx-fst2vcd.vcd", $Self->{golden_filename}); +fst_identical($Self->trace_filename, $Self->{golden_filename}); ok(1); 1; diff --git a/test_regress/t/t_trace_fst.pl b/test_regress/t/t_trace_fst.pl index 54dde9646..5a10032c3 100755 --- a/test_regress/t/t_trace_fst.pl +++ b/test_regress/t/t_trace_fst.pl @@ -14,8 +14,7 @@ execute( check_finished => 1, ); -fst2vcd($Self->trace_filename, "$Self->{obj_dir}/simx-fst2vcd.vcd"); -vcd_identical("$Self->{obj_dir}/simx-fst2vcd.vcd", $Self->{golden_filename}); +fst_identical($Self->trace_filename, $Self->{golden_filename}); ok(1); 1; diff --git a/test_regress/t/t_trace_packed_struct_fst.pl b/test_regress/t/t_trace_packed_struct_fst.pl index c9ad3c203..259774eea 100755 --- a/test_regress/t/t_trace_packed_struct_fst.pl +++ b/test_regress/t/t_trace_packed_struct_fst.pl @@ -19,8 +19,7 @@ execute( check_finished => 1, ); -fst2vcd($Self->trace_filename, "$Self->{obj_dir}/simx-fst2vcd.vcd"); -vcd_identical("$Self->{obj_dir}/simx-fst2vcd.vcd", $Self->{golden_filename}); +fst_identical($Self->trace_filename, $Self->{golden_filename}); ok(1); 1; diff --git a/test_regress/t/t_trace_two_dumpfst_cc.pl b/test_regress/t/t_trace_two_dumpfst_cc.pl index f19d777c0..87ce59a99 100755 --- a/test_regress/t/t_trace_two_dumpfst_cc.pl +++ b/test_regress/t/t_trace_two_dumpfst_cc.pl @@ -34,8 +34,7 @@ execute( ); if ($Self->{vlt_all}) { - fst2vcd($Self->trace_filename, "$Self->{obj_dir}/simx-fst2vcd.vcd"); - vcd_identical("$Self->{obj_dir}/simx-fst2vcd.vcd", $Self->{golden_filename}); + fst_identical($Self->trace_filename, $Self->{golden_filename}); } ok(1); diff --git a/test_regress/t/t_trace_two_hdrfst_cc.pl b/test_regress/t/t_trace_two_hdrfst_cc.pl index 514eca86d..ec1cd5937 100755 --- a/test_regress/t/t_trace_two_hdrfst_cc.pl +++ b/test_regress/t/t_trace_two_hdrfst_cc.pl @@ -34,8 +34,7 @@ execute( ); if ($Self->{vlt_all}) { - fst2vcd($Self->trace_filename, "$Self->{obj_dir}/simx-fst2vcd.vcd"); - vcd_identical("$Self->{obj_dir}/simx-fst2vcd.vcd", $Self->{golden_filename}); + fst_identical($Self->trace_filename, $Self->{golden_filename}); } ok(1); diff --git a/test_regress/t/t_trace_two_portfst_cc.pl b/test_regress/t/t_trace_two_portfst_cc.pl index cb21e0f34..ce9131110 100755 --- a/test_regress/t/t_trace_two_portfst_cc.pl +++ b/test_regress/t/t_trace_two_portfst_cc.pl @@ -34,8 +34,7 @@ execute( ); if ($Self->{vlt_all}) { - fst2vcd($Self->trace_filename, "$Self->{obj_dir}/simx-fst2vcd.vcd"); - vcd_identical("$Self->{obj_dir}/simx-fst2vcd.vcd", $Self->{golden_filename}); + fst_identical($Self->trace_filename, $Self->{golden_filename}); } ok(1); From 6c6d70a5e516f3e47aa9bff3ba2fdda1390ae94a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 7 Mar 2020 18:39:58 -0500 Subject: [PATCH 44/50] Fix FST when multi-model tracing. --- include/verilated_fst_c.cpp | 25 +++++-- include/verilated_fst_c.h | 18 +++-- include/verilated_vcd_c.cpp | 7 +- test_regress/t/t_trace_two_cc.cpp | 13 +++- test_regress/t/t_trace_two_dump_cc.out | 85 +++++++++++----------- test_regress/t/t_trace_two_dumpfst_cc.out | 48 ++++++------ test_regress/t/t_trace_two_hdrfst_cc.out | Bin 2097 -> 1896 bytes test_regress/t/t_trace_two_port_cc.out | 85 +++++++++++----------- test_regress/t/t_trace_two_portfst_cc.out | 48 ++++++------ 9 files changed, 183 insertions(+), 146 deletions(-) diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp index 5eb69fe04..926a19384 100644 --- a/include/verilated_fst_c.cpp +++ b/include/verilated_fst_c.cpp @@ -77,10 +77,11 @@ protected: // VerilatedFst VerilatedFst::VerilatedFst(void* fst) - : m_fst(fst), - m_fullDump(true), - m_scopeEscape('.') { - m_valueStrBuffer.reserve(64+1); // Need enough room for quad + : m_fst(fst) + , m_fullDump(true) + , m_nextCode(1) + , m_scopeEscape('.') { + m_valueStrBuffer.reserve(64 + 1); // Need enough room for quad } void VerilatedFst::open(const char* filename) VL_MT_UNSAFE { @@ -91,10 +92,12 @@ void VerilatedFst::open(const char* filename) VL_MT_UNSAFE { fstWriterSetParallelMode(m_fst, 1); #endif m_curScope.clear(); + m_nextCode = 1; for (vluint32_t ent = 0; ent< m_callbacks.size(); ++ent) { VerilatedFstCallInfo* cip = m_callbacks[ent]; - cip->m_code = 1; + cip->m_code = m_nextCode; + // Initialize; callbacks will call decl* which update m_nextCode (cip->m_initcb)(this, cip->m_userthis, cip->m_code); } @@ -121,9 +124,15 @@ void VerilatedFst::declDTypeEnum(int dtypenum, const char* name, vluint32_t elem m_local2fstdtype[dtypenum] = enumNum; } -void VerilatedFst::declSymbol(vluint32_t code, const char* name, - int dtypenum, fstVarDir vardir, fstVarType vartype, - bool array, int arraynum, vluint32_t len) { +void VerilatedFst::declSymbol(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, + fstVarType vartype, bool array, int arraynum, vluint32_t len, + vluint32_t bits) { + + // Make sure deduplicate tracking increments for future declarations + int codesNeeded = 1 + int(bits / 32); + //Not supported: if (tri) codesNeeded *= 2; // Space in change array for __en signals + m_nextCode = std::max(m_nextCode, code + codesNeeded); + std::pair p = m_code2symbol.insert(std::make_pair(code, static_cast(NULL))); std::istringstream nameiss(name); diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index d9c0c6281..9f2f6c9d6 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -50,6 +50,7 @@ private: void* m_fst; VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread bool m_fullDump; + vluint32_t m_nextCode; ///< Next code number to assign char m_scopeEscape; std::string m_module; CallbackVec m_callbacks; ///< Routines to perform dumping @@ -60,7 +61,7 @@ private: VL_UNCOPYABLE(VerilatedFst); void declSymbol(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, fstVarType vartype, - bool array, int arraynum, vluint32_t len); + bool array, int arraynum, vluint32_t len, vluint32_t bits); // helpers std::vector m_valueStrBuffer; public: @@ -105,32 +106,35 @@ public: void declBit(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, fstVarType vartype, bool array, int arraynum) { - declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1); + declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1, 1); } void declBus(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, fstVarType vartype, bool array, int arraynum, int msb, int lsb) { - declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1); + declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1, + msb - lsb + 1); } void declDouble(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, fstVarType vartype, bool array, int arraynum) { - declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 2); + declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 2, 64); } void declFloat(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, fstVarType vartype, bool array, int arraynum) { - declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1); + declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1, 32); } void declQuad(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, fstVarType vartype, bool array, int arraynum, int msb, int lsb) { - declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1); + declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1, + msb - lsb + 1); } void declArray(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, fstVarType vartype, bool array, int arraynum, int msb, int lsb) { - declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1); + declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1, + msb - lsb + 1); } /// Inside dumping routines, dump one signal if it has changed diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index c9406686a..49f4d69f9 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -239,6 +239,7 @@ void VerilatedVcd::makeNameMap() { for (vluint32_t ent = 0; ent < m_callbacks.size(); ent++) { VerilatedVcdCallInfo* cip = m_callbacks[ent]; cip->m_code = m_nextCode; + // Initialize; callbacks will call decl* which update m_nextCode (cip->m_initcb)(this, cip->m_userthis, cip->m_code); } @@ -535,12 +536,12 @@ void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep, if (!code) { VL_FATAL_MT(__FILE__, __LINE__, "", "Internal: internal trace problem, code 0 is illegal"); } - int bits = ((msb>lsb)?(msb-lsb):(lsb-msb))+1; - int codesNeeded = 1+int(bits/32); + int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1; + int codesNeeded = 1 + int(bits / 32); if (tri) codesNeeded *= 2; // Space in change array for __en signals // Make sure array is large enough - m_nextCode = std::max(m_nextCode, code+codesNeeded); + m_nextCode = std::max(m_nextCode, code + codesNeeded); if (m_sigs.capacity() <= m_nextCode) { m_sigs.reserve(m_nextCode*2); // Power-of-2 allocation speeds things up } diff --git a/test_regress/t/t_trace_two_cc.cpp b/test_regress/t/t_trace_two_cc.cpp index 3eb7c0baa..2a4455ac5 100644 --- a/test_regress/t/t_trace_two_cc.cpp +++ b/test_regress/t/t_trace_two_cc.cpp @@ -36,10 +36,6 @@ int main(int argc, char** argv, char** env) { srand48(5); ap = new VM_PREFIX("topa"); bp = new Vt_trace_two_b("topb"); - ap->eval_step(); - bp->eval_step(); - ap->eval_end_step(); - bp->eval_end_step(); #ifdef TEST_HDR_TRACE Verilated::traceEverOn(true); @@ -54,8 +50,16 @@ int main(int argc, char** argv, char** env) { bp->trace(tfp, 99); tfp->open(VL_STRINGIFY(TEST_OBJ_DIR) "/simx.vcd"); # endif +#endif + +#ifdef TEST_HDR_TRACE + ap->eval_step(); + bp->eval_step(); + ap->eval_end_step(); + bp->eval_end_step(); if (tfp) tfp->dump(main_time); #endif + { ap->clk = false; ap->clk = false; @@ -78,6 +82,7 @@ int main(int argc, char** argv, char** env) { } ap->final(); bp->final(); + #ifdef TEST_HDR_TRACE if (tfp) tfp->close(); #endif diff --git a/test_regress/t/t_trace_two_dump_cc.out b/test_regress/t/t_trace_two_dump_cc.out index 466b4c432..3ed0dcca5 100644 --- a/test_regress/t/t_trace_two_dump_cc.out +++ b/test_regress/t/t_trace_two_dump_cc.out @@ -1,5 +1,5 @@ $version Generated by VerilatedVcd $end -$date Sun Mar 1 20:48:56 2020 +$date Sat Mar 7 18:39:02 2020 $end $timescale 1ns $end @@ -17,86 +17,89 @@ $timescale 1ns $end $enddefinitions $end -#0 +#10 b00000000000000000000000000000001 # b00000000000000000000000000000000 + -03 +13 b00000000000000000000000000000001 ; -#0 -#10 #10 +#15 +#15 +03 +#20 +#20 b00000000000000000000000000000010 # b00000000000000000000000000000011 + 13 -#15 -#15 +#25 +#25 03 -#20 -#20 +#30 +#30 b00000000000000000000000000000011 # b00000000000000000000000000000100 + 13 -#25 -#25 +#35 +#35 03 -#30 -#30 +#40 +#40 b00000000000000000000000000000100 # b00000000000000000000000000000101 + 13 -#35 -#35 +#45 +#45 03 -#40 -#40 +#50 +#50 b00000000000000000000000000000101 # b00000000000000000000000000000110 + 13 -#45 -#45 +#55 +#55 03 -#50 -#50 +#60 +#60 b00000000000000000000000000000110 # b00000000000000000000000000000111 + 13 -#55 -#55 +#65 +#65 03 -#60 -#60 +#70 +#70 b00000000000000000000000000000111 # b00000000000000000000000000001000 + 13 -#65 -#65 +#75 +#75 03 -#70 -#70 +#80 +#80 b00000000000000000000000000001000 # b00000000000000000000000000001001 + 13 -#75 -#75 +#85 +#85 03 -#80 -#80 +#90 +#90 b00000000000000000000000000001001 # b00000000000000000000000000001010 + 13 -#85 -#85 +#95 +#95 03 -#90 -#90 +#100 +#100 b00000000000000000000000000001010 # b00000000000000000000000000001011 + 13 -#95 -#95 +#105 +#105 03 -#100 -#100 +#110 +#110 b00000000000000000000000000001011 # b00000000000000000000000000001100 + 13 diff --git a/test_regress/t/t_trace_two_dumpfst_cc.out b/test_regress/t/t_trace_two_dumpfst_cc.out index 9141e9a39..1ec523a92 100755 --- a/test_regress/t/t_trace_two_dumpfst_cc.out +++ b/test_regress/t/t_trace_two_dumpfst_cc.out @@ -1,5 +1,5 @@ $date - Sun Mar 1 21:31:56 2020 + Sat Mar 7 18:39:05 2020 $end $version @@ -21,63 +21,69 @@ $upscope $end $upscope $end $enddefinitions $end $dumpvars -#0 -0! +1! +b00000000000000000000000000000001 " +b00000000000000000000000000000000 # +b00000000000000000000000000000001 $ #10 1! -b00000000000000000000000000000011 # -b00000000000000000000000000000010 " #15 0! #20 1! -b00000000000000000000000000000011 " -b00000000000000000000000000000100 # +b00000000000000000000000000000011 # +b00000000000000000000000000000010 " #25 0! #30 1! -b00000000000000000000000000000101 # -b00000000000000000000000000000100 " +b00000000000000000000000000000011 " +b00000000000000000000000000000100 # #35 0! #40 1! -b00000000000000000000000000000101 " -b00000000000000000000000000000110 # +b00000000000000000000000000000101 # +b00000000000000000000000000000100 " #45 0! #50 1! -b00000000000000000000000000000111 # -b00000000000000000000000000000110 " +b00000000000000000000000000000101 " +b00000000000000000000000000000110 # #55 0! #60 1! -b00000000000000000000000000000111 " -b00000000000000000000000000001000 # +b00000000000000000000000000000111 # +b00000000000000000000000000000110 " #65 0! #70 1! -b00000000000000000000000000001001 # -b00000000000000000000000000001000 " +b00000000000000000000000000000111 " +b00000000000000000000000000001000 # #75 0! #80 1! -b00000000000000000000000000001001 " -b00000000000000000000000000001010 # +b00000000000000000000000000001001 # +b00000000000000000000000000001000 " #85 0! #90 1! -b00000000000000000000000000001011 # -b00000000000000000000000000001010 " +b00000000000000000000000000001001 " +b00000000000000000000000000001010 # #95 0! #100 1! +b00000000000000000000000000001011 # +b00000000000000000000000000001010 " +#105 +0! +#110 +1! b00000000000000000000000000001011 " b00000000000000000000000000001100 # diff --git a/test_regress/t/t_trace_two_hdrfst_cc.out b/test_regress/t/t_trace_two_hdrfst_cc.out index a7289d36eacaf3a8b413ea09f4599659c18f2aee..52aefd9ccc1480fb894b1b2f12b92a25c27e00fe 100755 GIT binary patch literal 1896 zcmbu8!BT@T5Qfj@DYgZ*UYvxMLi-M$Jb3I-hz?^5Op@yO_WodC+Nx|FxfTBGx8H6W z7MauH>M?WlkQt(cRJx9mb(~TpBPm3vt3rft+SszL#MQHPPo{L*_z$k!Ynx{~)KHc6 zFKu2on)Y>Z*lBWglaa3i!h2~nDVk8ed-bnR03WEUtNBQjQu*bsheYpm%sjl{Bib7{^oc2+wb!2 zVWYDhEf+K+^QV#A{cj|=LWO=VtJ2{PSx+tw`vyH(Atz!h#~(#gHX|uuGm1hXuP=z* zuo+3W!bqBNK_%%<1WF=&uMk%(UMb!LRi{EtP&jVq2d4mkR@BBjW|%0?4O7W>m}odc z!$CA4<~;(R=B&Dsyhux$ieNq<7CmCzqOHwZU`U+>?z;#U10wDbu!wn!3)Z2!bp-K% zSoR3Ug5L!O literal 2097 zcmb`HKX2497{;^K1E1l&I_+#Hx$B>W4W>?j7*Dyxhoa_^$WDrw`Y9ONwKIa1p&y`C zH^k7b5)u*;h^h+{YTr1ixr$;3!K(~+$(!f*K9BAAXd9%dsBk7l*oe%$+sdzxA3u0=`Yw9??dQJdUA_JB=;JfbgHUUIdk@L_e`jT-VP7idjHVt{a^O}pB@?id_?e~eB1_x7sb=r-E$vEfgK^U=SKHvDAMw))2<(*7rgzcGl9?>YTzZJcqg>$7b}x?%X6!}+MK57@yM zo3_J$xBi=kzcrBWUVl6ydjFs4`f8hzZW%tNHsk|<;`#${t?Ro@+#Ue(a3kLUTedVx diff --git a/test_regress/t/t_trace_two_port_cc.out b/test_regress/t/t_trace_two_port_cc.out index dd2f3213c..cbe559eb8 100644 --- a/test_regress/t/t_trace_two_port_cc.out +++ b/test_regress/t/t_trace_two_port_cc.out @@ -1,5 +1,5 @@ $version Generated by VerilatedVcd $end -$date Sun Mar 1 21:32:13 2020 +$date Sat Mar 7 18:38:11 2020 $end $timescale 1ns $end @@ -17,86 +17,89 @@ $timescale 1ns $end $enddefinitions $end -#0 +#10 b00000000000000000000000000000001 # b00000000000000000000000000000000 + -03 +13 b00000000000000000000000000000001 ; -#0 -#10 #10 +#15 +#15 +03 +#20 +#20 b00000000000000000000000000000010 # b00000000000000000000000000000011 + 13 -#15 -#15 +#25 +#25 03 -#20 -#20 +#30 +#30 b00000000000000000000000000000011 # b00000000000000000000000000000100 + 13 -#25 -#25 +#35 +#35 03 -#30 -#30 +#40 +#40 b00000000000000000000000000000100 # b00000000000000000000000000000101 + 13 -#35 -#35 +#45 +#45 03 -#40 -#40 +#50 +#50 b00000000000000000000000000000101 # b00000000000000000000000000000110 + 13 -#45 -#45 +#55 +#55 03 -#50 -#50 +#60 +#60 b00000000000000000000000000000110 # b00000000000000000000000000000111 + 13 -#55 -#55 +#65 +#65 03 -#60 -#60 +#70 +#70 b00000000000000000000000000000111 # b00000000000000000000000000001000 + 13 -#65 -#65 +#75 +#75 03 -#70 -#70 +#80 +#80 b00000000000000000000000000001000 # b00000000000000000000000000001001 + 13 -#75 -#75 +#85 +#85 03 -#80 -#80 +#90 +#90 b00000000000000000000000000001001 # b00000000000000000000000000001010 + 13 -#85 -#85 +#95 +#95 03 -#90 -#90 +#100 +#100 b00000000000000000000000000001010 # b00000000000000000000000000001011 + 13 -#95 -#95 +#105 +#105 03 -#100 -#100 +#110 +#110 b00000000000000000000000000001011 # b00000000000000000000000000001100 + 13 diff --git a/test_regress/t/t_trace_two_portfst_cc.out b/test_regress/t/t_trace_two_portfst_cc.out index ec99d954e..39390199f 100755 --- a/test_regress/t/t_trace_two_portfst_cc.out +++ b/test_regress/t/t_trace_two_portfst_cc.out @@ -1,5 +1,5 @@ $date - Sun Mar 1 21:32:04 2020 + Sat Mar 7 18:37:58 2020 $end $version @@ -21,63 +21,69 @@ $upscope $end $upscope $end $enddefinitions $end $dumpvars -#0 -0! +1! +b00000000000000000000000000000001 " +b00000000000000000000000000000000 # +b00000000000000000000000000000001 $ #10 1! -b00000000000000000000000000000011 # -b00000000000000000000000000000010 " #15 0! #20 1! -b00000000000000000000000000000011 " -b00000000000000000000000000000100 # +b00000000000000000000000000000011 # +b00000000000000000000000000000010 " #25 0! #30 1! -b00000000000000000000000000000101 # -b00000000000000000000000000000100 " +b00000000000000000000000000000011 " +b00000000000000000000000000000100 # #35 0! #40 1! -b00000000000000000000000000000101 " -b00000000000000000000000000000110 # +b00000000000000000000000000000101 # +b00000000000000000000000000000100 " #45 0! #50 1! -b00000000000000000000000000000111 # -b00000000000000000000000000000110 " +b00000000000000000000000000000101 " +b00000000000000000000000000000110 # #55 0! #60 1! -b00000000000000000000000000000111 " -b00000000000000000000000000001000 # +b00000000000000000000000000000111 # +b00000000000000000000000000000110 " #65 0! #70 1! -b00000000000000000000000000001001 # -b00000000000000000000000000001000 " +b00000000000000000000000000000111 " +b00000000000000000000000000001000 # #75 0! #80 1! -b00000000000000000000000000001001 " -b00000000000000000000000000001010 # +b00000000000000000000000000001001 # +b00000000000000000000000000001000 " #85 0! #90 1! -b00000000000000000000000000001011 # -b00000000000000000000000000001010 " +b00000000000000000000000000001001 " +b00000000000000000000000000001010 # #95 0! #100 1! +b00000000000000000000000000001011 # +b00000000000000000000000000001010 " +#105 +0! +#110 +1! b00000000000000000000000000001011 " b00000000000000000000000000001100 # From 6d73237b270b29b0d89887f331093c4de82d29fe Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 7 Mar 2020 19:24:05 -0500 Subject: [PATCH 45/50] Travis: Don't cpan test to save time. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 71442d049..b9e719b11 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ cache: before_install: # Perl modules needed for testing - - yes yes | sudo cpan -fi Unix::Processors Parallel::Forker Bit::Vector + - yes yes | sudo cpan -fTi Unix::Processors Parallel::Forker Bit::Vector - sudo apt-get install gdb gtkwave - sudo apt-get install libgoogle-perftools-dev before_script: From bd42e31b2a9b187221b5748d711bc9dfe68a5ad8 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 7 Mar 2020 20:08:41 -0500 Subject: [PATCH 46/50] Tests: For travis, skip Bit::Vector and show intall dates. --- .travis.yml | 6 +++++- ci/build_vcddiff.sh | 3 +++ ci/build_verilator.sh | 3 +++ ci/test.sh | 3 +++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b9e719b11..4dccd03aa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,10 +24,14 @@ cache: - $VERILATOR_CACHE before_install: + - date # Perl modules needed for testing - - yes yes | sudo cpan -fTi Unix::Processors Parallel::Forker Bit::Vector +# Not listing Bit::Vector as slow to install, and only skips one test + - yes yes | sudo cpan -fi Unix::Processors Parallel::Forker + - date - sudo apt-get install gdb gtkwave - sudo apt-get install libgoogle-perftools-dev + - date before_script: - bash -x ci/build_vcddiff.sh - bash -x ci/build_verilator.sh diff --git a/ci/build_vcddiff.sh b/ci/build_vcddiff.sh index 9a0e8b6da..18ee74e68 100755 --- a/ci/build_vcddiff.sh +++ b/ci/build_vcddiff.sh @@ -6,6 +6,7 @@ # Lesser General Public License Version 3 or the Perl Artistic License # Version 2.0. set -e +date # NB: it would be better to add this via a PPA @@ -16,3 +17,5 @@ VCDDIFF_DIR=${TMP_DIR}/vcddiff git -C "${VCDDIFF_DIR}" checkout 5112f88b7ba8818dce9dfb72619e64a1fc19542c make -C "${VCDDIFF_DIR}" sudo cp "${VCDDIFF_DIR}/vcddiff" /usr/local/bin + +date diff --git a/ci/build_verilator.sh b/ci/build_verilator.sh index cd1d7d558..7766453ac 100755 --- a/ci/build_verilator.sh +++ b/ci/build_verilator.sh @@ -15,6 +15,7 @@ # process or add Verilator as a Git submodule. Verilator tarballs can # not be used as the script relies on Git revisions for caching. set -e +date if [ -z "${VERILATOR_NUM_JOBS}" ]; then VERILATOR_NUM_JOBS=$(nproc) @@ -62,3 +63,5 @@ else autoconf && ./configure ${VERILATOR_CONFIG_FLAGS} cp ${VERILATOR_CACHE}/* bin fi + +date diff --git a/ci/test.sh b/ci/test.sh index 6b72bc5cb..2170510ca 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -6,6 +6,7 @@ # Lesser General Public License Version 3 or the Perl Artistic License # Version 2.0. set -e +date export DRIVER_FLAGS='-j 0 --quiet --rerun' @@ -24,3 +25,5 @@ case $1 in exit -1 ;; esac + +date From e2dec043a0df6c2e4b07ec404bae7a1a10afe2cc Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 7 Mar 2020 21:01:36 -0500 Subject: [PATCH 47/50] Tests: Backout part of previous commit. --- .travis.yml | 3 --- ci/build_vcddiff.sh | 3 --- ci/build_verilator.sh | 3 --- ci/test.sh | 3 --- 4 files changed, 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4dccd03aa..372eebe05 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,14 +24,11 @@ cache: - $VERILATOR_CACHE before_install: - - date # Perl modules needed for testing # Not listing Bit::Vector as slow to install, and only skips one test - yes yes | sudo cpan -fi Unix::Processors Parallel::Forker - - date - sudo apt-get install gdb gtkwave - sudo apt-get install libgoogle-perftools-dev - - date before_script: - bash -x ci/build_vcddiff.sh - bash -x ci/build_verilator.sh diff --git a/ci/build_vcddiff.sh b/ci/build_vcddiff.sh index 18ee74e68..9a0e8b6da 100755 --- a/ci/build_vcddiff.sh +++ b/ci/build_vcddiff.sh @@ -6,7 +6,6 @@ # Lesser General Public License Version 3 or the Perl Artistic License # Version 2.0. set -e -date # NB: it would be better to add this via a PPA @@ -17,5 +16,3 @@ VCDDIFF_DIR=${TMP_DIR}/vcddiff git -C "${VCDDIFF_DIR}" checkout 5112f88b7ba8818dce9dfb72619e64a1fc19542c make -C "${VCDDIFF_DIR}" sudo cp "${VCDDIFF_DIR}/vcddiff" /usr/local/bin - -date diff --git a/ci/build_verilator.sh b/ci/build_verilator.sh index 7766453ac..cd1d7d558 100755 --- a/ci/build_verilator.sh +++ b/ci/build_verilator.sh @@ -15,7 +15,6 @@ # process or add Verilator as a Git submodule. Verilator tarballs can # not be used as the script relies on Git revisions for caching. set -e -date if [ -z "${VERILATOR_NUM_JOBS}" ]; then VERILATOR_NUM_JOBS=$(nproc) @@ -63,5 +62,3 @@ else autoconf && ./configure ${VERILATOR_CONFIG_FLAGS} cp ${VERILATOR_CACHE}/* bin fi - -date diff --git a/ci/test.sh b/ci/test.sh index 2170510ca..6b72bc5cb 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -6,7 +6,6 @@ # Lesser General Public License Version 3 or the Perl Artistic License # Version 2.0. set -e -date export DRIVER_FLAGS='-j 0 --quiet --rerun' @@ -25,5 +24,3 @@ case $1 in exit -1 ;; esac - -date From 328fef81900f536482457b57b3301c4c86a857fa Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 7 Mar 2020 21:38:44 -0500 Subject: [PATCH 48/50] Tests: Add driver --hashset for Travis. --- .travis.yml | 9 +++++++-- ci/test.sh | 6 ++++++ test_regress/Makefile | 3 ++- test_regress/driver.pl | 28 ++++++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 372eebe05..dd59d6f58 100644 --- a/.travis.yml +++ b/.travis.yml @@ -59,9 +59,14 @@ jobs: script: ci/test.sh vlt - if: type != cron stage: test - name: Vltmt test + name: Vltmt set 0 test compiler: gcc - script: ci/test.sh vltmt + script: ci/test.sh vltmt0 + - if: type != cron + stage: test + name: Vltmt set 1 test + compiler: gcc + script: ci/test.sh vltmt1 # Cron builds try different OS/compiler combinations - if: type = cron stage: "Build Verilator" diff --git a/ci/test.sh b/ci/test.sh index 6b72bc5cb..c39769723 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -19,6 +19,12 @@ case $1 in vltmt) make -C test_regress SCENARIOS=--vltmt ;; + vltmt0) + make -C test_regress SCENARIOS=--vltmt HASHSET=--hashset=0/2 + ;; + vltmt1) + make -C test_regress SCENARIOS=--vltmt HASHSET=--hashset=1/2 + ;; *) echo "Usage: test.sh (dist|vlt|vltmt)" exit -1 diff --git a/test_regress/Makefile b/test_regress/Makefile index 82fff4a4d..e105ee9af 100644 --- a/test_regress/Makefile +++ b/test_regress/Makefile @@ -43,10 +43,11 @@ endif ###################################################################### SCENARIOS ?= --vlt --vltmt --dist +DRIVER_HASHSET ?= .PHONY: test test: - $(PERL) driver.pl $(DRIVER_FLAGS) $(SCENARIOS) + $(PERL) driver.pl $(DRIVER_FLAGS) $(SCENARIOS) $(DRIVER_HASHSET) ###################################################################### diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 1cb2c5536..1d967ba8c 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -66,6 +66,7 @@ my $opt_gdb; my $opt_rr; my $opt_gdbbt; my $opt_gdbsim; +my $opt_hashset; my $opt_jobs = 1; my $opt_optimize; my $opt_quiet; @@ -90,6 +91,7 @@ if (! GetOptions( "gdbbt!" => \$opt_gdbbt, "gdbsim!" => \$opt_gdbsim, "golden!" => sub { $ENV{HARNESS_UPDATE_GOLDEN} = 1; }, + "hashset=s" => \$opt_hashset, "help" => \&usage, "j=i" => \$opt_jobs, "optimize:s" => \$opt_optimize, @@ -141,6 +143,8 @@ if ($#opt_tests<0) { # Run everything push @opt_tests, sort(glob("${dir}/t_*.pl")); } } +@opt_tests = _calc_hashset(@opt_tests) if $opt_hashset; + if ($#opt_tests>=2 && $opt_jobs>=2) { # Without this tests such as t_debug_sigsegv_bt_bad.pl will occasionally # block on input and cause a SIGSTOP, then a "fg" was needed to resume testing. @@ -261,6 +265,25 @@ sub calc_jobs { return $ok + 1; } +sub _calc_hashset { + my @in = @_; + return @in if !$opt_hashset; + $opt_hashset =~ m!^(\d+)/(\d+)$! + or die "%Error: Need number/number format for --hashset: $opt_hashset\n"; + my ($set, $nsets) = ($1, $2); + my @new; + foreach my $t (@opt_tests) { + my $checksum = do { + local $/; + unpack("%32W*", $t); + }; + if ($set == ($checksum % $nsets)) { + push @new, $t; + } + } + return @new; +} + ####################################################################### ####################################################################### ####################################################################### @@ -2503,6 +2526,11 @@ Run Verilator generated executable under the debugger. Update golden files, equivalent to setting HARNESS_UPDATE_GOLDEN=1. +=item --hashset I/I + +Split tests based on a hash of the test names into I and run only +tests in set number I (0..I-1). + =item --help Displays this message and program version and exits. From 1c1319079b1b4b9352f5b8bf009517e2b7338844 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 7 Mar 2020 22:02:03 -0500 Subject: [PATCH 49/50] Tests: Add driver --hashset for Travis. --- ci/test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/test.sh b/ci/test.sh index c39769723..361a198d7 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -20,10 +20,10 @@ case $1 in make -C test_regress SCENARIOS=--vltmt ;; vltmt0) - make -C test_regress SCENARIOS=--vltmt HASHSET=--hashset=0/2 + make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2 ;; vltmt1) - make -C test_regress SCENARIOS=--vltmt HASHSET=--hashset=1/2 + make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2 ;; *) echo "Usage: test.sh (dist|vlt|vltmt)" From 95c4b6aaba789593d16a3b59ec6385e4478310b5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 8 Mar 2020 08:38:53 -0400 Subject: [PATCH 50/50] Version bump --- Changes | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Changes b/Changes index 671649dd1..a83afa729 100644 --- a/Changes +++ b/Changes @@ -3,7 +3,7 @@ Revision history for Verilator The contributors that suggested a given feature are shown in []. Thanks! -* Verilator 4.029 devel +* Verilator 4.030 2020-03-08 ** Add split_var metacomment to assist UNOPTFLAT fixes, #2066. [Yutetsu TAKATSUKASA] diff --git a/configure.ac b/configure.ac index 51bb7b2a0..c3d87cbd1 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[4.029 devel], +AC_INIT([Verilator],[4.030 2020-03-08], [https://verilator.org], [verilator],[https://verilator.org]) # When releasing, also update header of Changes file