Compare commits

...
48 Commits
Author SHA1 Message Date
Wilson Snyder 89a0632ecc Version bump 2022-03-12 13:09:08 -05:00
Wilson Snyder dcc05db7f1 Commentary: Changes updated. 2022-03-12 11:34:04 -05:00
Drew Ranck 90fb2e5487 Fix ++/-- tree fix in case statements (#3346) (#3349). 2022-03-12 11:24:32 -05:00
Wilson Snyder b5ce7d5982 Add VERILATOR_VERSION_INTEGER for determining API (#3343). 2022-03-12 11:17:39 -05:00
Wilson Snyder f211616a4c Fix missing debug, and code cleanup in V3LinkInc. 2022-03-11 07:34:11 -05:00
Chuxuan Wang a9cb9bac21 Commentary in docs/guide/connecting.rst (#3345) 2022-03-09 03:57:55 -05:00
Wilson Snyder ae005434e4 Fix $fscanf etc to return -1 on EOF (#3313). 2022-03-07 17:44:16 -05:00
Wilson Snyder ef87d057fc Fix $fscanf etc to return -1 on EOF (#3113). 2022-03-07 17:43:33 -05:00
github action 181b9a5795 Apply 'make format' 2022-03-06 22:17:42 +00:00
Wilson Snyder 9baf9c55c2 Commentary 2022-03-06 17:16:41 -05:00
Yutetsu TAKATSUKASA e29132377e Fix driver.pl when expected value is 0 (#3339)
* Tests: use defined() to accept $expvalue==0

* Tests: Update expected stats of t_cast_huge in --vltmt mode
2022-03-06 14:43:28 +09:00
Yutetsu TAKATSUKASA 999751c422 Count non-empty always blocks in V3Split (#3337)
"Optimizations, Split always" in stats now means the number of newly added always.
Co-authored-by: Wilson Snyder <[email protected]>
2022-03-06 12:56:34 +09:00
Wilson Snyder 22656d6fdd Fix Vdeeptemp error with --threads and --compiler clang (#3338). 2022-03-05 20:17:36 -05:00
Wilson Snyder ef0c5fd772 Fix unnamedblk error on foreach (#3321). 2022-03-05 17:05:22 -05:00
Wilson Snyder 90c61c79d6 Fix unnamedblk error on foreach (#3321). 2022-03-05 17:04:52 -05:00
Wilson Snyder 4ba3bff87f Fix class stringification on wide arrays (#3312). 2022-03-05 16:32:30 -05:00
Wilson Snyder c3dd6f5344 Fix public function arguments that are arrayed (#3316). 2022-03-05 16:19:53 -05:00
Wilson Snyder 321880f5a6 Add trace dumpvars() call for selective runtime tracing (#3322). 2022-03-05 15:44:32 -05:00
Geza Lore 3737d209f6 Keep recursive module list topologically (#3324).
Fixes (#3324).
2022-03-05 15:04:13 +00:00
Todd Strader 29c4b0a141 Fix cast to array types (#3333) 2022-03-03 07:48:04 -05:00
Wilson Snyder 956f64c6ba Fix compile error with --trace-fst --sc (#3332). 2022-03-02 07:26:26 -05:00
Larry Doolittle c2d18d8ae4 Commentary: More minor spelling fixes in docs/guide/*.rst (#3331) 2022-03-01 22:07:12 -05:00
Geza Lore 5b9806ae6d Improve V3Combine
- Always use a fast function to replace a slow one if available
- Iterate to fixed point (i.e.: if combining made more functions
identical, combine those too). This will be more useful in the future.
- Use only single, const traversal
2022-02-27 20:40:58 +00:00
Geza Lore 665fa140a8 V3Combine: Fix crash if CCall in expression position 2022-02-27 12:52:40 +00:00
Yutetsu TAKATSUKASA 32f843a214 Internals: Don't show "Split always" statistics twice. (Split and Reorder were shown). (#3328) 2022-02-27 20:33:54 +09:00
Larry Doolittle 72a3c756ad Commentary: Minor spelling fixes in docs/guide/*.rst (#3327) 2022-02-27 10:01:44 +00:00
github action 47069dfe52 Apply 'make format' 2022-02-27 07:53:05 +00:00
HungMingWu 43a84d7ad8 Internals: Fix VL_RESTORER behavior on passing a lvalue reference (#3326)
Signed-off-by: HungMingWu <[email protected]>
2022-02-27 07:52:11 +00:00
Jamie Iles b6ca2a42f2 Fix FST traces to include vector range (#3296) (#3297) 2022-02-26 12:52:24 -05:00
Wilson Snyder e52a4ac74f Fix $readmem file not found to be warning not error (#3310). 2022-02-19 10:04:12 -05:00
Geza Lore decfa6bd7a V3Order: Use unique ordinals per function name
This helps diffing generated code after reordering output, otherwise no
functional change.
2022-02-16 18:36:40 +00:00
Geza Lore 8931bd37e2 Cleanup V3Changed and V3GenClk 2022-02-16 18:09:19 +00:00
Geza Lore 4b79d23d00 Replace SenTreeSet with generic collection
Introduce VNRef that can be used to wrap AstNode keys in STL
collections, resulting in equality comparisons rather than identity
comparisons. This can then replace the SenTreeSet data-structure.
2022-02-16 18:09:19 +00:00
github action 77fe7c426e Apply 'make format' 2022-02-16 05:11:38 +00:00
Raynard Qiao 331c2244fc Fixed signed number operation (#3294) (#3308) 2022-02-16 00:10:34 -05:00
Wilson Snyder 5a3eab634a Suppress WIDTH warning on negate using carry bit (#3295). [Peter Monsson] 2022-02-13 15:28:07 -05:00
Wilson Snyder 77e68acf54 Suppress WIDTH warning on negate using carry bit (#2395). [Peter Monsson] 2022-02-13 15:27:31 -05:00
Wilson Snyder 7a355d448a Fix skipping public enum values with four-state values (#3303). 2022-02-10 19:27:28 -05:00
Wilson Snyder 3b7ad1820d GTKWave header updates from upstream. 2022-02-09 21:56:22 -05:00
Wilson Snyder d3b63b2653 Fix error if file not found 2022-02-09 21:56:22 -05:00
Wilson Snyder 046896e60a Commentary 2022-02-09 21:56:22 -05:00
Geza Lore fb9119ff49 Rename AstCFunc attribute for clarity.
'formCallTree' -> 'isFinal'. No functional change.
2022-01-28 16:18:50 +00:00
Guokai Chen 818aaa8b89 Fix macOS arm64 build by excluding x86 only cpuid header (#3285) (#3291)
Signed-off-by: Guokai Chen <[email protected]>
2022-01-23 09:15:09 -05:00
Geza Lore 26bdfc3474 Commentary 2022-01-21 05:53:42 +00:00
Wilson Snyder 0e91d8a10e Internal: Rename for clarity. No functional change. 2022-01-19 19:14:09 -05:00
Wilson Snyder 434c3c3ef3 Removed the deprecated "fl" attribute in XML output; use "loc" attribute instead. 2022-01-17 16:22:07 -05:00
Wilson Snyder 21e05c43dd Removed the deprecated lint_off flag -msg; use -rule instead. 2022-01-17 16:04:06 -05:00
Wilson Snyder 0e154b35ef devel release 2022-01-17 15:54:31 -05:00
161 changed files with 8613 additions and 6856 deletions
+28
View File
@@ -8,6 +8,34 @@ The changes in each Verilator version are described below. The
contributors that suggested a given feature are shown in []. Thanks!
Verilator 4.220 2022-03-12
==========================
**Minor:**
* Removed the deprecated lint_off flag -msg; use -rule instead.
* Removed the deprecated "fl" attribute in XML output; use "loc" attribute instead.
* Suppress WIDTH warning on negate using carry bit (#3295). [Peter Monsson]
* Add trace dumpvars() call for selective runtime tracing (#3322). [Shunyao CAD]
* Add VERILATOR_VERSION_INTEGER for determining API (#3343). [Larry Doolittle]
* Improve various V3Combine algorithm details (#3328). [Yutetsu TAKATSUKASA]
* Improve various V3Order algorithm details. [Geza Lore]
* Fix macOS arm64 build (#3285) (#3291). [Guokai Chen]
* Fix signed number operation (#3294) (#3308). [Raynard Qiao]
* Fix FST traces to include vector range (#3296) (#3297). [Jamie Iles]
* Fix skipping public enum values with four-state values (#3303).
* Fix $readmem file not found to be warning not error (#3310). [Alexander Grobman]
* Fix class stringification on wide arrays (#3312). [Iru Cai]
* Fix $fscanf etc to return -1 on EOF (#3313). [Jose Tejada]
* Fix public function arguments that are arrayed (#3316). [pawel256]
* Fix unnamedblk error on foreach (#3321). [Aliaksei Chapyzhenka]
* Fix crash in recursive module inlining (#3324). [Larry Doolittle]
* Fix VL_RESTORER behavior on passing a lvalue reference (#3326). [HungMingWu]
* Fix compile error with --trace-fst --sc (#3332). [leavinel]
* Fix cast to array types (#3333). [Todd Strader]
* Fix Vdeeptemp error with --threads and --compiler clang (#3338). [Per Karlsson]
Verilator 4.218 2022-01-17
==========================
+2 -2
View File
@@ -38,10 +38,10 @@ def diff_dir(a, b):
anyfile = False
for base in sorted(files.keys()):
if (not 'a' in files[base]) or (not 'b' in files[base]):
continue
a = files[base]['a']
b = files[base]['b']
if not a or not b:
continue
print("=" * 70)
print("= %s <-> %s" % (a, b))
diff_file(a, b)
+3 -1
View File
@@ -7,7 +7,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[4.218 2022-01-17],
AC_INIT([Verilator],[4.220 2022-03-12],
[https://verilator.org],
[verilator],[https://verilator.org])
# When releasing, also update header of Changes file
@@ -22,6 +22,8 @@ AC_MSG_RESULT([configuring for $PACKAGE_STRING])
PACKAGE_VERSION_NUMBER=`AS_ECHO("$PACKAGE_VERSION") | sed 's/ .*//g'`
AC_SUBST(PACKAGE_VERSION_NUMBER)
AC_DEFINE_UNQUOTED([PACKAGE_VERSION_NUMBER_STRING],["$PACKAGE_VERSION_NUMBER"],[Package version as a number])
VERILATOR_VERSION_INTEGER=`AS_ECHO("$PACKAGE_VERSION") | [sed 's/\([0-9]\)\.\([0-9][0-9][0-9]\) .*/\1\2000/g']`
AC_SUBST(VERILATOR_VERSION_INTEGER)
# Ignore automake flags passed by Ubuntu builds
AC_ARG_ENABLE([dependency-tracking],
+6
View File
@@ -10,6 +10,7 @@ Alex Chadwick
Ameya Vikram Singh
Andreas Kuster
Chris Randall
Chuxuan Wang
Conor McCullough
Dan Petrisko
Daniel Bates
@@ -17,6 +18,7 @@ David Horton
David Metz
David Stanford
David Turner
Drew Ranck
Drew Taussig
Driss Hafdi
Edgar E. Iglesias
@@ -28,6 +30,7 @@ Geza Lore
Gianfranco Costamagna
Glen Gibb
Graham Rushton
Guokai Chen
Harald Heckmann
Howard Su
Huang Rui
@@ -40,6 +43,7 @@ James Hanlon
James Hutchinson
James Pallister
Jamey Hicks
Jamie Iles
Jan Van Winkel
Jean Berniolles
Jeremy Bennett
@@ -55,6 +59,7 @@ Keith Colbert
Kevin Kiningham
Krzysztof Bieganski
Kuba Ober
Larry Doolittle
Ludwig Rogiers
Lukasz Dalek
Maarten De Braekeleer
@@ -83,6 +88,7 @@ Pieter Kapsenberg
Piotr Binkowski
Qingyao Sun
Rafal Kapuscik
Raynard Qiao
Richard Myers
Rupert Swarbrick
Samuel Riedel
+1 -1
View File
@@ -422,7 +422,7 @@ accesses the above signal "readme" would be:
.. code-block:: bash
cat >sim_main.cpp <<'<<EOF'
cat >sim_main.cpp <<'EOF'
#include "Vour.h"
#include "verilated.h"
#include "verilated_vpi.h" // Required to get definitions
+1 -9
View File
@@ -16,14 +16,6 @@ Verilated_heavy.h
"verilated.h". Verilated_heavy.h is planned for removal no sooner than
July 2022.
Configuration File -msg
The :vlopt:`lint_off` "-msg" option has been replaced with the "-rule"
option. "-msg" is planned for removal no sooner than January 2021.
XML locations
The XML "fl" attribute has been replaced with the "loc" attribute. "fl"
is planned for removal no sooner than January 2021.
Option `--cdc`
The experimental `--cdc` option is believed to be generally unused and is
planned for removeal no sooner than January 2023.
planned for removal no sooner than January 2023.
+2 -2
View File
@@ -884,7 +884,7 @@ Summary:
Using DPI imports/exports is allowed and generally relatively safe in
terms of information disclosed, which is limited to the DPI function
prototyptes. Use of the VPI is not recommended as many design details
prototypes. Use of the VPI is not recommended as many design details
may be exposed, and an INSECURE warning will be issued.
.. option:: --protect-lib <name>
@@ -1514,7 +1514,7 @@ The grammar of configuration commands is as follows:
.. option:: no_clocker -module "<modulename>" [-function "<funcname>"] -var "<signame>"
Indicates that the signal is used as clock or not. This information is
used by Verilator to mark the signal and any derrived signals as
used by Verilator to mark the signal and any derived signals as
clocker. See :vlopt:`--clk`.
Same as :option:`/*verilator&32;clocker*/` metacomment.
+1 -1
View File
@@ -67,7 +67,7 @@ which have low coverage are written to the output directory.
Specifies if the coverage point does not include the count number of
coverage hits, then the coverage point will be considered above the
threashold, and the coverage report will put a "%" to indicate the coverage
threshold, and the coverage report will put a "%" to indicate the coverage
is not sufficient. Defaults to 10.
.. option:: --help
+1 -1
View File
@@ -13,7 +13,7 @@ For an overview of use of verilator_gantt, see :ref:`Profiling`.
Gantt Chart VCD
---------------
Verilated_gnatt creates a value change dump (VCD) format dump file which
Verilated_gantt creates a value change dump (VCD) format dump file which
may be viewed in a waveform viewer (e.g. C<GTKWave>):
.. figure:: figures/fig_gantt_min.png
+1 -1
View File
@@ -185,7 +185,7 @@ or "`ifdef`"'s may break other tools.
.. option:: /*verilator&32;no_clocker*/
Specifies that the signal is used as clock or not. This information is
used by Verilator to mark the signal and any derrived signals as
used by Verilator to mark the signal and any derived signals as
clocker. See :vlopt:`--clk`.
Same as :option:`clocker` and :option:`no_clocker` in configuration
+5 -4
View File
@@ -37,15 +37,15 @@ Does Verilator run under Windows?
Yes, ideally run Ubuntu under Windows Subsystem for Linux (WSL2).
Alternatively use Cygwin, though this tends to be slower and is not
regurally tested. Verilated output also compiles under Microsoft Visual
C++, but this is also not regurally tested.
regularly tested. Verilated output also compiles under Microsoft Visual
C++, but this is also not regularly tested.
Can you provide binaries?
"""""""""""""""""""""""""
You can install Verilator via the system package manager (apt, yum, etc.)
on many Linux distributions, including Debian, Ubuntu, SuSE, RedHat, and
on many Linux distributions, including Debian, Ubuntu, SuSE, Red Hat, and
others. These packages are provided by the Linux distributions and
generally will lag the version of the mainline Verilator repository. If no
binary package is available for your distribution, how about you set one
@@ -134,7 +134,8 @@ B. Or, for finer-grained control, or C++ files with multiple Verilated
...
Verilated::traceEverOn(true);
VerilatedVcdC* tfp = new VerilatedVcdC;
topp->trace(tfp, 99); // Trace 99 levels of hierarchy
topp->trace(tfp, 99); // Trace 99 levels of hierarchy (or see below)
// tfp->dumpvars(1, "t"); // trace 1 level under "t"
tfp->open("obj_dir/t_trace_ena_cc/simx.vcd");
...
while (contextp->time() < sim_time && !contextp->gotFinish()) {
+1 -1
View File
@@ -157,7 +157,7 @@ The Verilated executable may produce the following:
* - profile.vlt
- -profile data file for :ref:`Thread PGO`
* - profile_threads.dat
- -profile-threads data file for :command:`verilator_gnatt`
- -profile-threads data file for :command:`verilator_gantt`
Verilator_gantt may produce the following:
+1 -1
View File
@@ -77,7 +77,7 @@ OS Requirements
---------------
Verilator is developed and has primary testing on Ubuntu, with additional
testing on FreeBSD and Apple OS-X. Versions have also built on Redhat
testing on FreeBSD and Apple OS-X. Versions have also built on Red Hat
Linux, and other flavors of GNU/Linux-ish platforms. Verilator also works
on Windows Subsystem for Linux (WSL2), Windows under Cygwin, and Windows
under MinGW (gcc -mno-cygwin). Verilated output (not Verilator itself)
+3 -3
View File
@@ -136,7 +136,7 @@ ___05F (5F is the hex code of an underscore.)
Bind
----
sVerilator only supports bind to a target module name, not to an
Verilator only supports bind to a target module name, not to an
instance path.
@@ -340,7 +340,7 @@ Force statement
---------------
Verilator supports the procedural `force` (and corresponding `release`)
statement. The behaviour of the `force` statement however does not entirely
statement. The behavior of the `force` statement however does not entirely
comply with the IEEE 1800 SystemVerilog standard. According to the standard,
when a procedural statement of the form `force a = b;` is executed, the
simulation should behave as if from that point onwards, a continuous
@@ -350,7 +350,7 @@ More specifically: the value of `a` should be updated, whenever the value of
Verilator instead evaluates the current value of `b` at the time the `force`
statement is executed, and forces `a` to that value, without updating it
until a new `force` or `release` statement is encountered that applies to
`a`. This non-standard behaviour is nevertheless consistent with some other
`a`. This non-standard behavior is nevertheless consistent with some other
simulators.
+1 -1
View File
@@ -68,7 +68,7 @@ multi-core SoC.
Verilator is run in hierarchical mode on the whole SoC. Verilator will
make two models, one for the CPU hierarchy block, and one for the SoC. The
Verialted code for the SoC will automatically call the CPU Verilated model.
Verilated code for the SoC will automatically call the CPU Verilated model.
The current hierarchical Verilation is based on :vlopt:`--lib-create`. Each
hierarchy block is Verilated into a library. User modules of the hierarchy
+5 -5
View File
@@ -447,7 +447,7 @@ List Of Warnings
p0();
endmodule
Other tools with similar warnings: Veriable's forbid_defparam_rule.
Other tools with similar warnings: Verible's forbid_defparam_rule.
.. option:: DEPRECATED
@@ -518,7 +518,7 @@ List Of Warnings
Another way DIDNOTCONVERGE may occur is if # delays are used to generate
clocks. Verilator ignores the delays and gives an :option:`ASSIGNDLY`
or :option:`STMTDLY` warning. If these were suppressed, due to the
absense of the delay, the code may now oscillate.
absence of the delay, the code may now oscillate.
Finally, rare, more difficult cases can be debugged like a C++ program;
either enter :command:`gdb` and use its tracing facilities, or edit the
@@ -528,7 +528,7 @@ List Of Warnings
.. option:: ENDCAPSULATED
Warns that a class member is declared is local or protected, but is
being accessed from outside that class (if local) or a derrived class
being accessed from outside that class (if local) or a derived class
(if protected).
Ignoring this warning will only suppress the lint check, it will
@@ -924,7 +924,7 @@ List Of Warnings
simulate correctly.
Other tools with similar warnings: Icarus Verilog's portbind, "warning:
Instantiating module ... with dangling impot port (...)". Slang's
Instantiating module ... with dangling input port (...)". Slang's
unconnected-port, "port '...' has no connection".
@@ -1217,7 +1217,7 @@ List Of Warnings
used to cause some important action at a later time, it might be an
important difference.
Some possible work arounds:
Some possible workarounds:
* Move the delayed statement into the C++ wrapper file, where the
stimulus and clock generation can be done in C++.
+1 -1
View File
@@ -1183,7 +1183,7 @@ Verilator ideally would support all of IEEE, and has the goal to get close
to full support. However the following IEEE sections and features are not
anticipated to be ever implemented for the reasons indicated.
IEEE 1800-2017 3.3 recursive modules
IEEE 1800-2017 3.3 modules within modules
Little/no tool support, and arguably not a good practice.
IEEE 1800-2017 6.12 "shortreal"
Little/no tool support, and easily simply promoted to real.
-3
View File
@@ -46,9 +46,6 @@ The XML document consists of 4 sections within the top level
hierarchy. Each instance is represented with the ``<cell>`` element
with the following attributes:
- ``fl`` (deprecated): The file id and line number where the module
was instanced. Use ``loc`` instead.
- ``loc``: The file id, first line number, last line number, first
column number and last column number of the identifier where the
module was instanced, separated by commas.
+6 -3
View File
@@ -140,6 +140,10 @@ void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint3
#include <sys/sysctl.h>
#endif
#if defined(FST_MACOSX) || defined(__MINGW32__) || defined(__OpenBSD__) || defined(__FreeBSD__)
#define FST_UNBUFFERED_IO
#endif
#ifdef __GNUC__
/* Boolean expression more often true than false */
#define FST_LIKELY(x) __builtin_expect(!!(x), 1)
@@ -4577,12 +4581,11 @@ if(sectype == FST_BL_ZWRAPPER)
if(!fcomp) { tmpfile_close(&fcomp, &xc->f_nam); return(0); }
}
#if defined(FST_MACOSX)
#if defined(FST_UNBUFFERED_IO)
setvbuf(fcomp, (char *)NULL, _IONBF, 0); /* keeps gzip from acting weird in tandem with fopen */
#endif
#ifdef __MINGW32__
setvbuf(fcomp, (char *)NULL, _IONBF, 0); /* keeps gzip from acting weird in tandem with fopen */
xc->filename_unpacked = hf;
#else
if(hf)
@@ -4880,7 +4883,7 @@ if((!nam)||(!(xc->f=fopen(nam, "rb"))))
char *hf = (char *)calloc(1, flen + 6);
int rc;
#if defined(__MINGW32__) || defined(FST_MACOSX)
#if defined(FST_UNBUFFERED_IO)
setvbuf(xc->f, (char *)NULL, _IONBF, 0); /* keeps gzip from acting weird in tandem with fopen */
#endif
+2 -2
View File
@@ -1497,7 +1497,7 @@ void VL_FWRITEF(IData fpi, const char* formatp, ...) VL_MT_SAFE {
IData VL_FSCANF_IX(IData fpi, const char* formatp, ...) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles
FILE* const fp = VL_CVT_I_FP(fpi);
if (VL_UNLIKELY(!fp)) return 0;
if (VL_UNLIKELY(!fp)) return ~0U; // -1
va_list ap;
va_start(ap, formatp);
@@ -1844,7 +1844,7 @@ VlReadMem::VlReadMem(bool hex, int bits, const std::string& filename, QData star
m_fp = std::fopen(filename.c_str(), "r");
if (VL_UNLIKELY(!m_fp)) {
// We don't report the Verilog source filename as it slow to have to pass it down
VL_FATAL_MT(filename.c_str(), 0, "", "$readmem file not found");
VL_WARN_MT(filename.c_str(), 0, "", "$readmem file not found");
// cppcheck-suppress resourceLeak // m_fp is nullptr - bug in cppcheck
return;
}
+2
View File
@@ -33,6 +33,7 @@
// clang-format off
#include "verilatedos.h"
#include "verilated_config.h"
#if VM_SC
# include "verilated_sc.h" // Get SYSTEMC_VERSION and time declarations
#endif
@@ -86,6 +87,7 @@ class VerilatedCovContext;
class VerilatedEvalMsgQueue;
class VerilatedFst;
class VerilatedFstC;
class VerilatedFstSc;
class VerilatedScope;
class VerilatedScopeNameMap;
class VerilatedVar;
+6 -1
View File
@@ -20,6 +20,11 @@
// Autoconf substitutes this with the strings from AC_INIT.
#define VERILATOR_PRODUCT "@PACKAGE_NAME@"
/// Verilator version name, e.g. "1.000 2000-01-01"
/// Verilator version name, e.g. "1.002 2000-01-01"
// Autoconf substitutes this with the strings from AC_INIT.
#define VERILATOR_VERSION "@PACKAGE_VERSION@"
/// Verilator version number as integer
/// As major * 100000 + minor * 1000, e.g. 1002000 == 1.002
// Autoconf substitutes this with the strings from AC_INIT.
#define VERILATOR_VERSION_INTEGER @VERILATOR_VERSION_INTEGER@
+16 -8
View File
@@ -122,7 +122,7 @@ void VerilatedFst::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
// convert m_code2symbol into an array for fast lookup
if (!m_symbolp) {
m_symbolp = new fstHandle[nextCode()];
m_symbolp = new fstHandle[nextCode()]{0};
for (const auto& i : m_code2symbol) m_symbolp[i.first] = i.second;
}
m_code2symbol.clear();
@@ -158,10 +158,12 @@ void VerilatedFst::declDTypeEnum(int dtypenum, const char* name, vluint32_t elem
}
void VerilatedFst::declare(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
fstVarType vartype, bool array, int arraynum, bool bussed, int msb,
int lsb) {
const int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1;
VerilatedTrace<VerilatedFst>::declCode(code, bits, false);
const bool enabled = VerilatedTrace<VerilatedFst>::declCode(code, name, bits, false);
if (!enabled) return;
std::string nameasstr = namePrefix() + name;
std::istringstream nameiss{nameasstr};
@@ -205,6 +207,7 @@ void VerilatedFst::declare(vluint32_t code, const char* name, int dtypenum, fstV
std::stringstream name_ss;
name_ss << symbol_name;
if (array) name_ss << "[" << arraynum << "]";
if (bussed) name_ss << " [" << msb << ":" << lsb << "]";
std::string name_str = name_ss.str();
if (dtypenum > 0) {
@@ -223,23 +226,23 @@ void VerilatedFst::declare(vluint32_t code, const char* name, int dtypenum, fstV
void VerilatedFst::declBit(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum) {
declare(code, name, dtypenum, vardir, vartype, array, arraynum, 0, 0);
declare(code, name, dtypenum, vardir, vartype, array, arraynum, false, 0, 0);
}
void VerilatedFst::declBus(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
declare(code, name, dtypenum, vardir, vartype, array, arraynum, msb, lsb);
declare(code, name, dtypenum, vardir, vartype, array, arraynum, true, msb, lsb);
}
void VerilatedFst::declQuad(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
declare(code, name, dtypenum, vardir, vartype, array, arraynum, msb, lsb);
declare(code, name, dtypenum, vardir, vartype, array, arraynum, true, msb, lsb);
}
void VerilatedFst::declArray(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
declare(code, name, dtypenum, vardir, vartype, array, arraynum, msb, lsb);
declare(code, name, dtypenum, vardir, vartype, array, arraynum, true, msb, lsb);
}
void VerilatedFst::declDouble(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum) {
declare(code, name, dtypenum, vardir, vartype, array, arraynum, 63, 0);
declare(code, name, dtypenum, vardir, vartype, array, arraynum, false, 63, 0);
}
// Note: emit* are only ever called from one place (full* in
@@ -248,12 +251,14 @@ void VerilatedFst::declDouble(vluint32_t code, const char* name, int dtypenum, f
VL_ATTR_ALWINLINE
void VerilatedFst::emitBit(vluint32_t code, CData newval) {
VL_DEBUG_IFDEF(assert(m_symbolp[code]););
fstWriterEmitValueChange(m_fst, m_symbolp[code], newval ? "1" : "0");
}
VL_ATTR_ALWINLINE
void VerilatedFst::emitCData(vluint32_t code, CData newval, int bits) {
char buf[VL_BYTESIZE];
VL_DEBUG_IFDEF(assert(m_symbolp[code]););
cvtCDataToStr(buf, newval << (VL_BYTESIZE - bits));
fstWriterEmitValueChange(m_fst, m_symbolp[code], buf);
}
@@ -261,6 +266,7 @@ void VerilatedFst::emitCData(vluint32_t code, CData newval, int bits) {
VL_ATTR_ALWINLINE
void VerilatedFst::emitSData(vluint32_t code, SData newval, int bits) {
char buf[VL_SHORTSIZE];
VL_DEBUG_IFDEF(assert(m_symbolp[code]););
cvtSDataToStr(buf, newval << (VL_SHORTSIZE - bits));
fstWriterEmitValueChange(m_fst, m_symbolp[code], buf);
}
@@ -268,6 +274,7 @@ void VerilatedFst::emitSData(vluint32_t code, SData newval, int bits) {
VL_ATTR_ALWINLINE
void VerilatedFst::emitIData(vluint32_t code, IData newval, int bits) {
char buf[VL_IDATASIZE];
VL_DEBUG_IFDEF(assert(m_symbolp[code]););
cvtIDataToStr(buf, newval << (VL_IDATASIZE - bits));
fstWriterEmitValueChange(m_fst, m_symbolp[code], buf);
}
@@ -275,6 +282,7 @@ void VerilatedFst::emitIData(vluint32_t code, IData newval, int bits) {
VL_ATTR_ALWINLINE
void VerilatedFst::emitQData(vluint32_t code, QData newval, int bits) {
char buf[VL_QUADSIZE];
VL_DEBUG_IFDEF(assert(m_symbolp[code]););
cvtQDataToStr(buf, newval << (VL_QUADSIZE - bits));
fstWriterEmitValueChange(m_fst, m_symbolp[code], buf);
}
+7 -1
View File
@@ -54,7 +54,7 @@ private:
// CONSTRUCTORS
VL_UNCOPYABLE(VerilatedFst);
void declare(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
fstVarType vartype, bool array, int arraynum, bool bussed, int msb, int lsb);
protected:
//=========================================================================
@@ -121,6 +121,7 @@ template <> void VerilatedTrace<VerilatedFst>::set_time_unit(const char* unitp);
template <> void VerilatedTrace<VerilatedFst>::set_time_unit(const std::string& unit);
template <> void VerilatedTrace<VerilatedFst>::set_time_resolution(const char* unitp);
template <> void VerilatedTrace<VerilatedFst>::set_time_resolution(const std::string& unit);
template <> void VerilatedTrace<VerilatedFst>::dumpvars(int level, const std::string& hier);
#endif
//=============================================================================
@@ -178,6 +179,11 @@ public:
void set_time_resolution(const std::string& unit) VL_MT_SAFE {
m_sptrace.set_time_resolution(unit);
}
// Set variables to dump, using $dumpvars format
// If level = 0, dump everything and hier is then ignored
void dumpvars(int level, const std::string& hier) VL_MT_SAFE {
m_sptrace.dumpvars(level, hier);
}
// Internal class access
inline VerilatedFst* spTrace() { return &m_sptrace; }
+7 -5
View File
@@ -162,10 +162,6 @@ extern const char* vl_mc_scan_plusargs(const char* prefixp); // PLIish
// Base macros
// Return true if data[bit] set; not 0/1 return, but 0/non-zero return.
#define VL_BITISSET_I(data, bit) ((data) & (VL_UL(1) << VL_BITBIT_I(bit)))
#define VL_BITISSET_Q(data, bit) ((data) & (1ULL << VL_BITBIT_Q(bit)))
#define VL_BITISSET_E(data, bit) ((data) & (VL_EUL(1) << VL_BITBIT_E(bit)))
#define VL_BITISSET_W(data, bit) ((data)[VL_BITWORD_E(bit)] & (VL_EUL(1) << VL_BITBIT_E(bit)))
#define VL_BITISSETLIMIT_W(data, width, bit) (((bit) < (width)) && VL_BITISSET_W(data, bit))
// Shift appropriate word by bit. Does not account for wrapping between two words
@@ -343,13 +339,19 @@ double vl_time_multiplier(int scale) VL_PURE;
vluint64_t vl_time_pow10(int n) VL_PURE;
#ifdef VL_DEBUG
/// Evaluate statement if Verilated::debug() enabled
/// Evaluate statement if VL_DEBUG defined
# define VL_DEBUG_IFDEF(stmt) \
do { \
stmt \
} while (false)
/// Evaluate statement if VL_DEBUG defined and Verilated::debug() enabled
# define VL_DEBUG_IF(stmt) \
do { \
if (VL_UNLIKELY(Verilated::debug())) {stmt} \
} while (false)
#else
// We intentionally do not compile the stmt to improve compile speed
# define VL_DEBUG_IFDEF(stmt) do {} while (false)
# define VL_DEBUG_IF(stmt) do {} while (false)
#endif
+2 -2
View File
@@ -316,14 +316,14 @@ public: // But only for verilated*.cpp
IData fdSeek(IData fdi, IData offset, IData origin) VL_MT_SAFE_EXCLUDES(m_fdMutex) {
const VerilatedLockGuard lock{m_fdMutex};
const VerilatedFpList fdlist = fdToFpList(fdi);
if (VL_UNLIKELY(fdlist.size() != 1)) return 0;
if (VL_UNLIKELY(fdlist.size() != 1)) return ~0U; // -1
return static_cast<IData>(
std::fseek(*fdlist.begin(), static_cast<long>(offset), static_cast<int>(origin)));
}
IData fdTell(IData fdi) VL_MT_SAFE_EXCLUDES(m_fdMutex) {
const VerilatedLockGuard lock{m_fdMutex};
const VerilatedFpList fdlist = fdToFpList(fdi);
if (VL_UNLIKELY(fdlist.size() != 1)) return 0;
if (VL_UNLIKELY(fdlist.size() != 1)) return ~0U; // -1
return static_cast<IData>(std::ftell(*fdlist.begin()));
}
void fdWrite(IData fdi, const std::string& output) VL_MT_SAFE_EXCLUDES(m_fdMutex) {
+2 -2
View File
@@ -43,7 +43,7 @@
#if defined(__linux)
# include <sched.h> // For sched_getcpu()
#endif
#if defined(__APPLE__)
#if defined(__APPLE__) && !defined(__arm64__)
# include <cpuid.h> // For __cpuid_count()
#endif
// clang-format on
@@ -168,7 +168,7 @@ public:
static int getcpu() { // Return current executing CPU
#if defined(__linux)
return sched_getcpu();
#elif defined(__APPLE__)
#elif defined(__APPLE__) && !defined(__arm64__)
vluint32_t info[4];
__cpuid_count(1, 0, info[0], info[1], info[2], info[3]);
// info[1] is EBX, bits 24-31 are APIC ID
+15 -12
View File
@@ -27,6 +27,7 @@
#include "verilated.h"
#include "verilated_trace_defs.h"
#include <bitset>
#include <memory>
#include <string>
#include <vector>
@@ -142,7 +143,9 @@ private:
};
vluint32_t* m_sigs_oldvalp; // Old value store
EData* m_sigs_enabledp; // Bit vector of enabled codes (nullptr = all on)
vluint64_t m_timeLastDump; // Last time we did a dump
std::vector<bool> m_sigs_enabledVec; // Staging for m_sigs_enabledp
std::vector<CallbackRecord> m_initCbs; // Routines to initialize traciong
std::vector<CallbackRecord> m_fullCbs; // Routines to perform full dump
std::vector<CallbackRecord> m_chgCbs; // Routines to perform incremental dump
@@ -152,6 +155,7 @@ private:
vluint32_t m_numSignals; // Number of distinct signals
vluint32_t m_maxBits; // Number of bits in the widest signal
std::vector<std::string> m_namePrefixStack{""}; // Path prefixes to add to signal names
std::vector<std::pair<int, std::string>> m_dumpvars; // dumpvar() entries
char m_scopeEscape;
double m_timeRes; // Time resolution (ns/ms etc)
double m_timeUnit; // Time units (ns/ms etc)
@@ -171,27 +175,22 @@ private:
#ifdef VL_TRACE_THREADED
// Number of total trace buffers that have been allocated
vluint32_t m_numTraceBuffers;
// Size of trace buffers
size_t m_traceBufferSize;
// Buffers handed to worker for processing
VerilatedThreadQueue<vluint32_t*> m_buffersToWorker;
// Buffers returned from worker after processing
VerilatedThreadQueue<vluint32_t*> m_buffersFromWorker;
// Write pointer into current buffer
vluint32_t* m_traceBufferWritep;
// End of trace buffer
vluint32_t* m_traceBufferEndp;
// The worker thread itself
std::unique_ptr<std::thread> m_workerThread;
// Get a new trace buffer that can be populated. May block if none available
vluint32_t* getTraceBuffer();
// Write pointer into current buffer
vluint32_t* m_traceBufferWritep;
// End of trace buffer
vluint32_t* m_traceBufferEndp;
// The worker thread itself
std::unique_ptr<std::thread> m_workerThread;
// The function executed by the worker thread
void workerThreadMain();
@@ -223,7 +222,8 @@ protected:
void traceInit() VL_MT_UNSAFE;
void declCode(vluint32_t code, vluint32_t bits, bool tri);
// Declare new signal and return true if enabled
bool declCode(vluint32_t code, const char* namep, vluint32_t bits, bool tri);
// Is this an escape?
bool isScopeEscape(char c) { return std::isspace(c) || c == m_scopeEscape; }
@@ -259,6 +259,9 @@ public:
// Set time resolution (s/ms, defaults to ns)
void set_time_resolution(const char* unitp) VL_MT_SAFE;
void set_time_resolution(const std::string& unit) VL_MT_SAFE;
// Set variables to dump, using $dumpvars format
// If level = 0, dump everything and hier is then ignored
void dumpvars(int level, const std::string& hier) VL_MT_SAFE;
// Call
void dump(vluint64_t timeui) VL_MT_SAFE_EXCLUDES(m_mutex);
+90 -14
View File
@@ -282,6 +282,7 @@ template <> void VerilatedTrace<VL_DERIVED_T>::onExit(void* selfp) {
template <>
VerilatedTrace<VL_DERIVED_T>::VerilatedTrace()
: m_sigs_oldvalp{nullptr}
, m_sigs_enabledp{nullptr}
, m_timeLastDump{0}
, m_fullDump{true}
, m_nextCode{0}
@@ -302,6 +303,7 @@ VerilatedTrace<VL_DERIVED_T>::VerilatedTrace()
template <> VerilatedTrace<VL_DERIVED_T>::~VerilatedTrace() {
if (m_sigs_oldvalp) VL_DO_CLEAR(delete[] m_sigs_oldvalp, m_sigs_oldvalp = nullptr);
if (m_sigs_enabledp) VL_DO_CLEAR(delete[] m_sigs_enabledp, m_sigs_enabledp = nullptr);
Verilated::removeFlushCb(VerilatedTrace<VL_DERIVED_T>::onFlush, this);
Verilated::removeExitCb(VerilatedTrace<VL_DERIVED_T>::onExit, this);
#ifdef VL_TRACE_THREADED
@@ -320,9 +322,10 @@ template <> void VerilatedTrace<VL_DERIVED_T>::traceInit() VL_MT_UNSAFE {
m_nextCode = 1;
m_numSignals = 0;
m_maxBits = 0;
m_sigs_enabledVec.clear();
// Call all initialize callbacks, which will:
// - Call decl* for each signal
// - Call decl* for each signal (these eventually call ::declCode)
// - Store the base code
for (vluint32_t i = 0; i < m_initCbs.size(); ++i) {
const CallbackRecord& cbr = m_initCbs[i];
@@ -338,6 +341,23 @@ template <> void VerilatedTrace<VL_DERIVED_T>::traceInit() VL_MT_UNSAFE {
// holding previous signal values.
if (!m_sigs_oldvalp) m_sigs_oldvalp = new vluint32_t[nextCode()];
// Apply enables
if (m_sigs_enabledp) VL_DO_CLEAR(delete[] m_sigs_enabledp, m_sigs_enabledp = nullptr);
if (!m_sigs_enabledVec.empty()) {
// Else if was empty, m_sigs_enabledp = nullptr to short circuit tests
// But it isn't, so alloc one bit for each code to indicate enablement
// We don't want to still use m_signs_enabledVec as std::vector<bool> is not
// guarenteed to be fast
m_sigs_enabledp = new vluint32_t[1 + VL_WORDS_I(nextCode())]{0};
m_sigs_enabledVec.reserve(nextCode());
for (size_t code = 0; code < nextCode(); ++code) {
if (m_sigs_enabledVec[code]) {
m_sigs_enabledp[VL_BITWORD_I(code)] |= 1U << VL_BITBIT_I(code);
}
}
m_sigs_enabledVec.clear();
}
// Set callback so flush/abort will flush this file
Verilated::addFlushCb(VerilatedTrace<VL_DERIVED_T>::onFlush, this);
Verilated::addExitCb(VerilatedTrace<VL_DERIVED_T>::onExit, this);
@@ -356,10 +376,38 @@ template <> void VerilatedTrace<VL_DERIVED_T>::traceInit() VL_MT_UNSAFE {
}
template <>
void VerilatedTrace<VL_DERIVED_T>::declCode(vluint32_t code, vluint32_t bits, bool tri) {
bool VerilatedTrace<VL_DERIVED_T>::declCode(vluint32_t code, const char* namep, vluint32_t bits,
bool tri) {
if (VL_UNCOVERABLE(!code)) {
VL_FATAL_MT(__FILE__, __LINE__, "", "Internal: internal trace problem, code 0 is illegal");
}
// To keep it simple, this is O(enables * signals), but we expect few enables
std::string declName = namePrefix() + namep;
bool enabled = false;
if (m_dumpvars.empty()) enabled = true;
for (const auto& item : m_dumpvars) {
const int dumpvarsLevel = item.first;
const char* dvp = item.second.c_str();
const char* np = declName.c_str();
while (*dvp && *dvp == *np) {
++dvp;
++np;
}
if (*dvp) continue; // Didn't match dumpvar item
if (*np && *np != ' ') continue; // e.g. "t" isn't a match for "top"
int levels = 0;
while (*np) {
if (*np++ == ' ') ++levels;
}
if (levels > dumpvarsLevel) continue; // Too deep
// We only need to set first code word if it's a multicode signal
// as that's all we'll check for later
if (m_sigs_enabledVec.size() <= code) m_sigs_enabledVec.resize((code + 1024) * 2);
m_sigs_enabledVec[code] = true;
enabled = true;
break;
}
// Note: The tri-state flag is not used by Verilator, but is here for
// compatibility with some foreign code.
int codesNeeded = VL_WORDS_I(bits);
@@ -367,6 +415,7 @@ void VerilatedTrace<VL_DERIVED_T>::declCode(vluint32_t code, vluint32_t bits, bo
m_nextCode = std::max(m_nextCode, code + codesNeeded);
++m_numSignals;
m_maxBits = std::max(m_maxBits, bits);
return enabled;
}
//=========================================================================
@@ -392,6 +441,19 @@ template <>
void VerilatedTrace<VL_DERIVED_T>::set_time_resolution(const std::string& unit) VL_MT_SAFE {
set_time_resolution(unit.c_str());
}
template <>
void VerilatedTrace<VL_DERIVED_T>::dumpvars(int level, const std::string& hier) VL_MT_SAFE {
if (level == 0) {
m_dumpvars.clear(); // empty = everything on
} else {
// Convert Verilog . separators to trace space separators
std::string hierSpaced = hier;
for (auto& i : hierSpaced) {
if (i == '.') i = ' ';
}
m_dumpvars.push_back(std::make_pair(level, hierSpaced));
}
}
template <>
void VerilatedTrace<VL_DERIVED_T>::dump(vluint64_t timeui) VL_MT_SAFE_EXCLUDES(m_mutex) {
@@ -523,44 +585,58 @@ template <> void VerilatedTrace<VL_DERIVED_T>::popNamePrefix(unsigned count) {
// the emit* functions can be inlined for performance.
template <> void VerilatedTrace<VL_DERIVED_T>::fullBit(vluint32_t* oldp, CData newval) {
*oldp = newval;
self()->emitBit(oldp - m_sigs_oldvalp, newval);
const uint32_t code = oldp - m_sigs_oldvalp;
*oldp = newval; // Still copy even if not tracing so chg doesn't call full
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
self()->emitBit(code, newval);
}
template <>
void VerilatedTrace<VL_DERIVED_T>::fullCData(vluint32_t* oldp, CData newval, int bits) {
*oldp = newval;
self()->emitCData(oldp - m_sigs_oldvalp, newval, bits);
const uint32_t code = oldp - m_sigs_oldvalp;
*oldp = newval; // Still copy even if not tracing so chg doesn't call full
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
self()->emitCData(code, newval, bits);
}
template <>
void VerilatedTrace<VL_DERIVED_T>::fullSData(vluint32_t* oldp, SData newval, int bits) {
*oldp = newval;
self()->emitSData(oldp - m_sigs_oldvalp, newval, bits);
const uint32_t code = oldp - m_sigs_oldvalp;
*oldp = newval; // Still copy even if not tracing so chg doesn't call full
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
self()->emitSData(code, newval, bits);
}
template <>
void VerilatedTrace<VL_DERIVED_T>::fullIData(vluint32_t* oldp, IData newval, int bits) {
*oldp = newval;
self()->emitIData(oldp - m_sigs_oldvalp, newval, bits);
const uint32_t code = oldp - m_sigs_oldvalp;
*oldp = newval; // Still copy even if not tracing so chg doesn't call full
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
self()->emitIData(code, newval, bits);
}
template <>
void VerilatedTrace<VL_DERIVED_T>::fullQData(vluint32_t* oldp, QData newval, int bits) {
const uint32_t code = oldp - m_sigs_oldvalp;
*reinterpret_cast<QData*>(oldp) = newval;
self()->emitQData(oldp - m_sigs_oldvalp, newval, bits);
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
self()->emitQData(code, newval, bits);
}
template <>
void VerilatedTrace<VL_DERIVED_T>::fullWData(vluint32_t* oldp, const WData* newvalp, int bits) {
const uint32_t code = oldp - m_sigs_oldvalp;
for (int i = 0; i < VL_WORDS_I(bits); ++i) oldp[i] = newvalp[i];
self()->emitWData(oldp - m_sigs_oldvalp, newvalp, bits);
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
self()->emitWData(code, newvalp, bits);
}
template <> void VerilatedTrace<VL_DERIVED_T>::fullDouble(vluint32_t* oldp, double newval) {
// cppcheck-suppress invalidPointerCast
const uint32_t code = oldp - m_sigs_oldvalp;
*reinterpret_cast<double*>(oldp) = newval;
self()->emitDouble(oldp - m_sigs_oldvalp, newval);
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
// cppcheck-suppress invalidPointerCast
self()->emitDouble(code, newval);
}
//=========================================================================
+4 -1
View File
@@ -463,7 +463,7 @@ void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep,
int arraynum, bool tri, bool bussed, int msb, int lsb) {
const int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1;
VerilatedTrace<VerilatedVcd>::declCode(code, bits, tri);
const bool enabled = VerilatedTrace<VerilatedVcd>::declCode(code, name, bits, tri);
if (m_suffixes.size() <= nextCode() * VL_TRACE_SUFFIX_ENTRY_SIZE) {
m_suffixes.resize(nextCode() * VL_TRACE_SUFFIX_ENTRY_SIZE * 2, 0);
@@ -472,6 +472,8 @@ void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep,
// Make sure write buffer is large enough (one character per bit), plus header
bufferResize(bits + 1024);
if (!enabled) return;
// Split name into basename
// Spaces and tabs aren't legal in VCD signal names, so:
// Space separates each level of scope
@@ -606,6 +608,7 @@ static inline void VerilatedVcdCCopyAndAppendNewLine(char* writep, const char* s
void VerilatedVcd::finishLine(vluint32_t code, char* writep) {
const char* const suffixp = m_suffixes.data() + code * VL_TRACE_SUFFIX_ENTRY_SIZE;
VL_DEBUG_IFDEF(assert(suffixp[0]););
VerilatedVcdCCopyAndAppendNewLine(writep, suffixp);
// Now write back the write pointer incremented by the actual size of the
+6
View File
@@ -328,6 +328,7 @@ template <> void VerilatedTrace<VerilatedVcd>::set_time_unit(const char* unitp);
template <> void VerilatedTrace<VerilatedVcd>::set_time_unit(const std::string& unit);
template <> void VerilatedTrace<VerilatedVcd>::set_time_resolution(const char* unitp);
template <> void VerilatedTrace<VerilatedVcd>::set_time_resolution(const std::string& unit);
template <> void VerilatedTrace<VerilatedVcd>::dumpvars(int level, const std::string& hier);
#endif // DOXYGEN
//=============================================================================
@@ -392,6 +393,11 @@ public:
void set_time_resolution(const std::string& unit) VL_MT_SAFE {
m_sptrace.set_time_resolution(unit);
}
// Set variables to dump, using $dumpvars format
// If level = 0, dump everything and hier is then ignored
void dumpvars(int level, const std::string& hier) VL_MT_SAFE {
m_sptrace.dumpvars(level, hier);
}
// Internal class access
inline VerilatedVcd* spTrace() { return &m_sptrace; }
+6
View File
@@ -414,6 +414,12 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read()
#define VL_BITBIT_Q(bit) ((bit) & VL_SIZEBITS_Q) ///< Bit number for a bit in a quad
#define VL_BITBIT_E(bit) ((bit) & VL_SIZEBITS_E) ///< Bit number for a bit in a EData
// Return true if data[bit] set; not 0/1 return, but 0/non-zero return.
#define VL_BITISSET_I(data, bit) ((data) & (VL_UL(1) << VL_BITBIT_I(bit)))
#define VL_BITISSET_Q(data, bit) ((data) & (1ULL << VL_BITBIT_Q(bit)))
#define VL_BITISSET_E(data, bit) ((data) & (VL_EUL(1) << VL_BITBIT_E(bit)))
#define VL_BITISSET_W(data, bit) ((data)[VL_BITWORD_E(bit)] & (VL_EUL(1) << VL_BITBIT_E(bit)))
//=========================================================================
// Floating point
// #defines, to avoid requiring math.h on all compile runs
+14 -27
View File
@@ -32,9 +32,7 @@
#include "V3Global.h"
#include "V3Active.h"
#include "V3Ast.h"
#include "V3EmitCBase.h"
#include "V3Const.h"
#include "V3SenTree.h" // for SenTreeSet
#include "V3Graph.h"
#include <unordered_map>
@@ -211,9 +209,8 @@ private:
AstActive* m_iActivep = nullptr; // For current scope, the IActive we're building
AstActive* m_cActivep = nullptr; // For current scope, the SActive(combo) we're building
SenTreeSet m_activeSens; // Sen lists for each active we've made
using ActiveMap = std::unordered_map<AstSenTree*, AstActive*>;
ActiveMap m_activeMap; // Map sentree to active, for folding.
// Map from AstSenTree (equivalence) to the corresponding AstActive created.
std::unordered_map<VNRef<AstSenTree>, AstActive*> m_activeMap;
// METHODS
void addActive(AstActive* nodep) {
@@ -225,7 +222,6 @@ private:
m_scopep = nodep;
m_iActivep = nullptr;
m_cActivep = nullptr;
m_activeSens.clear();
m_activeMap.clear();
iterateChildren(nodep);
// Don't clear scopep, the namer persists beyond this visit
@@ -259,29 +255,20 @@ public:
}
return m_iActivep;
}
// Return an AstActive that is sensitive to a SenTree equivalent to the given sentreep.
AstActive* getActive(FileLine* fl, AstSenTree* sensesp) {
// Return a sentree in this scope that matches given sense list.
AstActive* activep = nullptr;
AstSenTree* const activeSenp = m_activeSens.find(sensesp);
if (activeSenp) {
const auto it = m_activeMap.find(activeSenp);
UASSERT(it != m_activeMap.end(), "Corrupt active map");
activep = it->second;
}
auto it = m_activeMap.find(*sensesp);
// If found matching AstActive, return it
if (it != m_activeMap.end()) return it->second;
// Not found, form a new one
if (!activep) {
AstSenTree* const newsenp = sensesp->cloneTree(false);
activep = new AstActive(fl, "sequent", newsenp);
activep->sensesStorep(activep->sensesp());
UINFO(8, " New ACTIVE " << activep << endl);
// Form the sensitivity list
addActive(activep);
m_activeMap[newsenp] = activep;
m_activeSens.add(newsenp);
// Note actives may have also been added above in the Active visitor
}
// No such AstActive yet, creat it, and add to map.
AstSenTree* const newsenp = sensesp->cloneTree(false);
AstActive* const activep = new AstActive(fl, "sequent", newsenp);
activep->sensesStorep(activep->sensesp());
addActive(activep);
m_activeMap.emplace(*newsenp, activep);
return activep;
}
@@ -476,7 +463,7 @@ private:
m_scopeFinalp = new AstCFunc(
nodep->fileline(), "_final_" + m_namer.scopep()->nameDotless(), m_namer.scopep());
m_scopeFinalp->dontCombine(true);
m_scopeFinalp->formCallTree(true);
m_scopeFinalp->isFinal(true);
m_scopeFinalp->isStatic(false);
m_scopeFinalp->isLoose(true);
m_scopeFinalp->slow(true);
+47 -2
View File
@@ -2025,12 +2025,15 @@ public:
#include "V3Ast__gen_impl.h" // From ./astgen
// Specializations of privateMayBeUnder
template <> inline bool AstNode::mayBeUnder<AstCell>(const AstNode* nodep) {
template <> inline bool AstNode::privateMayBeUnder<AstCell>(const AstNode* nodep) {
return !VN_IS(nodep, NodeStmt) && !VN_IS(nodep, NodeMath);
}
template <> inline bool AstNode::mayBeUnder<AstNodeAssign>(const AstNode* nodep) {
template <> inline bool AstNode::privateMayBeUnder<AstNodeAssign>(const AstNode* nodep) {
return !VN_IS(nodep, NodeMath);
}
template <> inline bool AstNode::privateMayBeUnder<AstVarScope>(const AstNode* nodep) {
return !VN_IS(nodep, NodeStmt) && !VN_IS(nodep, NodeMath);
}
inline std::ostream& operator<<(std::ostream& os, const AstNode* rhs) {
if (!rhs) {
@@ -2043,6 +2046,47 @@ inline std::ostream& operator<<(std::ostream& os, const AstNode* rhs) {
inline void VNRelinker::relink(AstNode* newp) { newp->AstNode::relink(this); }
//######################################################################
// VNRef is std::reference_wrapper that can only hold AstNode subtypes
template <typename T_Node> //
class VNRef final : public std::reference_wrapper<T_Node> {
static_assert(std::is_base_of<AstNode, T_Node>::value,
"Type parameter 'T_Node' must be a subtype of AstNode");
public:
template <typename U>
VNRef(U&& x)
: std::reference_wrapper<T_Node>{x} {}
VNRef(const VNRef& other) noexcept
: std::reference_wrapper<T_Node>{other} {}
};
static_assert(sizeof(VNRef<AstNode>) == sizeof(std::reference_wrapper<AstNode>),
"VNRef should not contain extra members");
// Specializations of std::hash and std::equal_to for VNRef. This in turn
// enables us to use for example std::unordered_set<VNRef<AstNode>> for
// sets using equality (AstNode::sameTree) rather than identity comparisons,
// without having to copy nodes into the collections.
// Forward declaration to avoid including V3Hasher.h which needs V3Ast.h (this file).
size_t V3HasherUncachedHash(AstNode&);
// Specialization of std::hash for VNRef
template <typename T_Node> //
struct std::hash<VNRef<T_Node>> final {
size_t operator()(VNRef<T_Node> r) const { return V3HasherUncachedHash(r); }
};
// Specialization of std::equal_to for VNRef
template <typename T_Node> //
struct std::equal_to<VNRef<T_Node>> final {
size_t operator()(VNRef<T_Node> ra, VNRef<T_Node> rb) const {
return ra.get().sameTree(&(rb.get()));
}
};
//######################################################################
//=== AstNode* : Derived generic node types
@@ -2833,6 +2877,7 @@ public:
virtual bool isPure() const override;
virtual bool isOutputter() const override { return !isPure(); }
AstCFunc* funcp() const { return m_funcp; }
void funcp(AstCFunc* funcp) { m_funcp = funcp; }
void argTypes(const string& str) { m_argTypes = str; }
string argTypes() const { return m_argTypes; }
// op1p reserved for AstCMethodCall
+25 -17
View File
@@ -454,25 +454,33 @@ string AstVar::cPubArgType(bool named, bool forReturn) const {
if (forReturn) named = false;
string arg;
if (isWide() && isReadOnly()) arg += "const ";
if (widthMin() == 1) {
arg += "bool";
} else if (widthMin() <= VL_IDATASIZE) {
arg += "uint32_t";
} else if (widthMin() <= VL_QUADSIZE) {
arg += "vluint64_t";
} else {
arg += "uint32_t"; // []'s added later
}
if (isWide()) {
if (forReturn) {
v3warn(E_UNSUPPORTED, "Unsupported: Public functions with >64 bit outputs; "
"make an output of a public task instead");
const bool isRef = !forReturn && (isWritable() || direction().isRefOrConstRef());
if (VN_IS(dtypeSkipRefp(), BasicDType) && !dtypeSkipRefp()->isDouble()
&& !dtypeSkipRefp()->isString()) {
// Backward compatible type declaration
if (widthMin() == 1) {
arg += "bool";
} else if (widthMin() <= VL_IDATASIZE) {
arg += "uint32_t";
} else if (widthMin() <= VL_QUADSIZE) {
arg += "vluint64_t";
} else {
arg += "uint32_t"; // []'s added later
}
if (isWide()) {
if (forReturn) {
v3warn(E_UNSUPPORTED, "Unsupported: Public functions with >64 bit outputs; "
"make an output of a public task instead");
}
arg += " (& " + name();
arg += ")[" + cvtToStr(widthWords()) + "]";
} else {
if (isRef) arg += "&";
if (named) arg += " " + name();
}
arg += " (& " + name();
arg += ")[" + cvtToStr(widthWords()) + "]";
} else {
if (!forReturn && (isWritable() || direction().isRefOrConstRef())) arg += "&";
if (named) arg += " " + name();
// Newer internal-compatible types
arg += dtypep()->cType((named ? name() : string{}), true, isRef);
}
return arg;
}
+12 -5
View File
@@ -8874,7 +8874,7 @@ private:
bool m_isTrace : 1; // Function is related to tracing
bool m_dontCombine : 1; // V3Combine shouldn't compare this func tree, it's special
bool m_declPrivate : 1; // Declare it private
bool m_formCallTree : 1; // Make a global function to call entire tree of functions
bool m_isFinal : 1; // This is a function corresponding to a SystemVerilog 'final' block
bool m_slow : 1; // Slow routine, called once or just at init time
bool m_funcPublic : 1; // From user public task/function
bool m_isConstructor : 1; // Is C class constructor
@@ -8903,7 +8903,7 @@ public:
m_isTrace = false;
m_dontCombine = false;
m_declPrivate = false;
m_formCallTree = false;
m_isFinal = false;
m_slow = false;
m_funcPublic = false;
m_isConstructor = false;
@@ -8956,13 +8956,13 @@ public:
AstScope* scopep() const { return m_scopep; }
void scopep(AstScope* nodep) { m_scopep = nodep; }
string rtnTypeVoid() const { return ((m_rtnType == "") ? "void" : m_rtnType); }
bool dontCombine() const { return m_dontCombine || isTrace(); }
bool dontCombine() const { return m_dontCombine || isTrace() || entryPoint(); }
void dontCombine(bool flag) { m_dontCombine = flag; }
bool dontInline() const { return dontCombine() || slow() || funcPublic(); }
bool declPrivate() const { return m_declPrivate; }
void declPrivate(bool flag) { m_declPrivate = flag; }
bool formCallTree() const { return m_formCallTree; }
void formCallTree(bool flag) { m_formCallTree = flag; }
bool isFinal() const { return m_isFinal; }
void isFinal(bool flag) { m_isFinal = flag; }
bool slow() const { return m_slow; }
void slow(bool flag) { m_slow = flag; }
bool funcPublic() const { return m_funcPublic; }
@@ -9185,6 +9185,13 @@ public:
}
AstNode* stmtsp() const { return op1p(); }
void addStmtsp(AstNode* nodep) { addOp1p(nodep); }
void addStmtsFirstp(AstNode* nodep) {
if (stmtsp()) {
stmtsp()->addHereThisAsNext(nodep);
} else {
addStmtsp(nodep);
}
}
ExecMTask* execMTaskp() const { return m_execMTaskp; }
void execMTaskp(ExecMTask* execMTaskp) { m_execMTaskp = execMTaskp; }
virtual void dump(std::ostream& str = std::cout) const override;
+27 -79
View File
@@ -117,8 +117,8 @@ public:
class ChangedInsertVisitor final : public VNVisitor {
private:
// STATE
ChangedState* m_statep = nullptr; // Shared state across visitors
AstVarScope* m_vscp = nullptr; // Original (non-change) variable we're change-detecting
ChangedState& m_state; // Shared state across visitors
AstVarScope* const m_vscp; // Original (non-change) variable we're change-detecting
AstVarScope* m_newvscp = nullptr; // New (change detect) variable we're change-detecting
AstNode* m_varEqnp = nullptr; // Original var's equation to get var value
AstNode* m_newLvEqnp = nullptr; // New var's equation to read value
@@ -126,34 +126,32 @@ private:
uint32_t m_detects = 0; // # detects created
// CONSTANTS
enum MiscConsts {
DETECTARRAY_MAX_INDEXES = 256 // How many indexes before error
// Ok to increase this, but may result in much slower model
};
// How many indexes before error. Ok to increase this, but may result in much slower model
static constexpr uint32_t DETECTARRAY_MAX_INDEXES = 256;
void newChangeDet() {
if (++m_detects > DETECTARRAY_MAX_INDEXES) {
m_vscp->v3warn(E_DETECTARRAY,
"Unsupported: Can't detect more than "
<< cvtToStr(DETECTARRAY_MAX_INDEXES)
<< DETECTARRAY_MAX_INDEXES
<< " array indexes (probably with UNOPTFLAT warning suppressed): "
<< m_vscp->prettyName() << '\n'
<< m_vscp->warnMore()
<< "... Could recompile with DETECTARRAY_MAX_INDEXES increased");
return;
}
m_statep->maybeCreateChgFuncp();
m_state.maybeCreateChgFuncp();
AstChangeDet* const changep = new AstChangeDet{
m_vscp->fileline(), m_varEqnp->cloneTree(true), m_newRvEqnp->cloneTree(true)};
m_statep->m_chgFuncp->addStmtsp(changep);
m_state.m_chgFuncp->addStmtsp(changep);
AstAssign* const initp = new AstAssign{m_vscp->fileline(), m_newLvEqnp->cloneTree(true),
m_varEqnp->cloneTree(true)};
m_statep->m_chgFuncp->addFinalsp(initp);
m_state.m_chgFuncp->addFinalsp(initp);
// Later code will expand words which adds to GCC compile time,
// so add penalty based on word width also
m_statep->m_numStmts += initp->nodeCount() + m_varEqnp->widthWords();
m_state.m_numStmts += initp->nodeCount() + m_varEqnp->widthWords();
}
virtual void visit(AstBasicDType*) override { //
@@ -202,13 +200,13 @@ private:
public:
// CONSTRUCTORS
ChangedInsertVisitor(AstVarScope* vscp, ChangedState* statep) {
ChangedInsertVisitor(AstVarScope* vscp, ChangedState& state)
: m_state{state}
, m_vscp{vscp} {
// DPI export trigger should never need change detect. See similar assertions in V3Order
// (OrderVisitor::nodeMarkCircular), and V3GenClk (GenClkRenameVisitor::genInpClk).
UASSERT_OBJ(vscp != v3Global.rootp()->dpiExportTriggerp(), vscp,
"DPI export trigger should not need change detect");
m_statep = statep;
m_vscp = vscp;
{
AstVar* const varp = m_vscp->varp();
const string newvarname{"__Vchglast__" + m_vscp->scopep()->nameDotless() + "__"
@@ -219,9 +217,9 @@ public:
// CHANGEDET(VARREF(_last), VARREF(var))
AstVar* const newvarp
= new AstVar{varp->fileline(), VVarType::MODULETEMP, newvarname, varp};
m_statep->m_topModp->addStmtp(newvarp);
m_newvscp = new AstVarScope{m_vscp->fileline(), m_statep->m_scopetopp, newvarp};
m_statep->m_scopetopp->addVarp(m_newvscp);
m_state.m_topModp->addStmtp(newvarp);
m_newvscp = new AstVarScope{m_vscp->fileline(), m_state.m_scopetopp, newvarp};
m_state.m_scopetopp->addVarp(m_newvscp);
m_varEqnp = new AstVarRef{m_vscp->fileline(), m_vscp, VAccess::READ};
m_newLvEqnp = new AstVarRef{m_vscp->fileline(), m_newvscp, VAccess::WRITE};
@@ -236,72 +234,22 @@ public:
VL_UNCOPYABLE(ChangedInsertVisitor);
};
//######################################################################
// Changed state, as a visitor of each AstNode
class ChangedVisitor final : public VNVisitor {
private:
// NODE STATE
// Entire netlist:
// AstVarScope::user1() -> bool. True indicates processed
const VNUser1InUse m_inuser1;
// STATE
ChangedState* const m_statep; // Shared state across visitors
// METHODS
VL_DEBUG_FUNC; // Declare debug()
void genChangeDet(AstVarScope* vscp) {
vscp->v3warn(IMPERFECTSCH, "Imperfect scheduling of variable: " << vscp->prettyNameQ());
{ ChangedInsertVisitor{vscp, m_statep}; }
}
// VISITORS
virtual void visit(AstNodeModule* nodep) override {
UINFO(4, " MOD " << nodep << endl);
if (nodep->isTop()) m_statep->m_topModp = nodep;
iterateChildren(nodep);
}
virtual void visit(AstTopScope* nodep) override {
UINFO(4, " TS " << nodep << endl);
// Clearing
AstNode::user1ClearTree();
// Prep for if make change detection function
AstScope* const scopep = nodep->scopep();
UASSERT_OBJ(scopep, nodep, "No scope found on top level, perhaps you have no statements?");
m_statep->m_scopetopp = scopep;
iterateChildren(nodep);
}
virtual void visit(AstVarScope* nodep) override {
if (nodep->isCircular()) {
UINFO(8, " CIRC " << nodep << endl);
if (!nodep->user1SetOnce()) genChangeDet(nodep);
}
}
//--------------------
virtual void visit(AstNodeMath*) override {} // Accelerate
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
ChangedVisitor(AstNetlist* nodep, ChangedState* statep)
: m_statep{statep} {
iterate(nodep);
}
virtual ~ChangedVisitor() override = default;
};
//######################################################################
// Changed class functions
void V3Changed::changedAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{
ChangedState state;
ChangedVisitor{nodep, &state};
} // Destruct before checking
ChangedState state;
state.m_scopetopp = nodep->topScopep()->scopep();
state.m_topModp = nodep->topModulep();
nodep->foreach<AstVarScope>([&state](AstVarScope* vscp) {
if (vscp->isCircular()) {
vscp->v3warn(IMPERFECTSCH,
"Imperfect scheduling of variable: " << vscp->prettyNameQ());
ChangedInsertVisitor{vscp, state};
}
});
V3Global::dumpCheckGlobalTree("changed", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
+2 -2
View File
@@ -322,8 +322,8 @@ private:
virtual void visit(AstCFunc* nodep) override {
iterateChildren(nodep);
// Link to global function
if (nodep->formCallTree()) {
UINFO(4, " formCallTree " << nodep << endl);
if (nodep->isFinal()) {
UINFO(4, " isFinal " << nodep << endl);
AstCCall* const callp = new AstCCall(nodep->fileline(), nodep);
m_finalFuncp->addStmtsp(callp);
}
+165 -157
View File
@@ -27,195 +27,203 @@
#include "V3DupFinder.h"
#include "V3Stats.h"
#include "V3Ast.h"
#include "V3AstUserAllocator.h"
#include <algorithm>
#include <map>
#include <list>
#include <vector>
//######################################################################
class CombBaseVisitor VL_NOT_FINAL : public VNVisitor {
protected:
// STATE
// METHODS
virtual ~CombBaseVisitor() override = default;
VL_DEBUG_FUNC; // Declare debug()
};
//######################################################################
// Combine replacement function
class CombCallVisitor final : CombBaseVisitor {
// Find all CCALLS of each CFUNC, so that we can later rename them
private:
class CombineVisitor final : VNVisitor {
// NODE STATE
std::multimap<AstCFunc*, AstCCall*> m_callMmap; // Associative array of {function}{call}
// METHODS
public:
void replaceFunc(AstCFunc* oldfuncp, AstCFunc* newfuncp) {
if (oldfuncp == newfuncp) return;
if (newfuncp) {
UINFO(4, " Replace " << oldfuncp << " -WITH-> " << newfuncp << endl);
} else {
UINFO(4, " Remove " << oldfuncp << endl);
}
// Note: m_callMmap modified in loop, so not using equal_range.
for (auto it = m_callMmap.find(oldfuncp); it != m_callMmap.end();
it = m_callMmap.find(oldfuncp)) {
AstCCall* const oldp = it->second;
UINFO(4, " Called " << oldp << endl);
UASSERT_OBJ(oldp->funcp() == oldfuncp, oldp,
"Call list broken, points to call w/different func");
if (newfuncp) {
// Replace call to oldfuncp with call to newfuncp
AstNode* const argsp
= oldp->argsp() ? oldp->argsp()->unlinkFrBackWithNext() : nullptr;
AstCCall* const newp = new AstCCall(oldp->fileline(), newfuncp, argsp);
newp->selfPointer(oldp->selfPointer());
newp->argTypes(oldp->argTypes());
addCall(newp); // Fix the table, in case the newfuncp itself gets replaced
oldp->replaceWith(newp);
} else {
// Just deleting empty function
oldp->unlinkFrBack();
}
VL_DO_DANGLING(pushDeletep(oldp), oldp);
m_callMmap.erase(it); // Fix the table, This call has been replaced
}
}
// METHODS
void addCall(AstCCall* nodep) { m_callMmap.emplace(nodep->funcp(), nodep); }
// AstNodeModule::user1() List of AstCFuncs in this module (via m_cfuncs)
// AstCFunc::user1() List of AstCCalls to this function (via m_callSites)
// AstCFunc::user2() bool: Already replaced (in 'process')
// AstCFunc::user3() bool: Marks functions earlier in iteration order (in 'combinePass')
// *::user4() Used by V3Hasher
const VNUser1InUse m_user1InUse;
private:
// VISITORS
virtual void visit(AstCCall* nodep) override {
if (nodep->funcp()->dontCombine()) return;
addCall(nodep);
}
// LCOV_EXCL_START
virtual void visit(AstAddrOfCFunc* nodep) override {
// We cannot yet handle references via AstAddrOfCFunc, but currently those are
// only used in tracing functions, which are not combined. Blow up in case this changes.
if (nodep->funcp()->dontCombine()) return;
nodep->v3fatalSrc(
"Don't know how to combine functions that are referenced via AstAddrOfCFunc");
}
// LCOV_EXCL_END
// Speed things up
virtual void visit(AstNodeAssign*) override {}
virtual void visit(AstNodeMath*) override {}
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
CombCallVisitor() = default;
virtual ~CombCallVisitor() override = default;
void main(AstNetlist* nodep) { iterate(nodep); }
};
//######################################################################
// Combine state, as a visitor of each AstNode
class CombineVisitor final : CombBaseVisitor {
private:
// NODE STATE
// Entire netlist:
const VNUser3InUse m_user3InUse; // Marks replaced AstCFuncs
// VNUser4InUse part of V3Hasher in V3DupFinder
// TYPES
using funcit_t = std::list<AstCFunc*>::iterator;
struct CFuncs {
std::list<AstCFunc*> m_fast;
std::list<AstCFunc*> m_slow;
};
// STATE
AstUser1Allocator<AstNodeModule, CFuncs> m_cfuncs; // AstCFuncs under module
AstUser1Allocator<AstCFunc, std::vector<AstCCall*>> m_callSites; // Call sites of the AstCFunc
AstNodeModule* m_modp = nullptr; // Current module
const V3Hasher m_hasher; // For hashing
VDouble0 m_cfuncsCombined; // Statistic tracking
CombCallVisitor m_call; // Tracking of function call users
V3DupFinder m_dupFinder; // Duplicate finder for CFuncs in module
// METHODS
void walkEmptyFuncs() {
for (const auto& itr : m_dupFinder) {
AstCFunc* const oldfuncp = VN_AS(itr.second, CFunc);
UASSERT_OBJ(oldfuncp, itr.second, "Not a CFunc in hash");
if (!oldfuncp->emptyBody()) continue;
UASSERT_OBJ(!oldfuncp->dontCombine(), oldfuncp,
"dontCombine function should not be in hash");
VL_DEBUG_FUNC; // Declare debug()
// Remove calls to empty function
UASSERT_OBJ(!oldfuncp->user3(), oldfuncp, "Should not be processed yet");
UINFO(5, " Drop empty CFunc " << itr.first << " " << oldfuncp << endl);
oldfuncp->user3SetOnce(); // Mark replaced
m_call.replaceFunc(oldfuncp, nullptr);
oldfuncp->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(oldfuncp), oldfuncp);
void removeEmptyFunctions(std::list<AstCFunc*>& funcps) {
for (funcit_t it = funcps.begin(), nit; it != funcps.end(); it = nit) {
AstCFunc* const funcp = *it;
nit = it;
++nit;
if (funcp->emptyBody()) {
// Delete call sites
for (AstCCall* const callp : m_callSites(funcp)) {
VL_DO_DANGLING(callp->unlinkFrBack()->deleteTree(), callp);
}
m_callSites(funcp).clear();
// Remove from list
funcps.erase(it);
// Delete function
VL_DO_DANGLING(funcp->unlinkFrBack()->deleteTree(), funcp);
}
}
}
void walkDupFuncs() {
// Do non-slow first as then favors naming functions based on fast name
for (const bool slow : {false, true}) {
for (auto newIt = m_dupFinder.begin(); newIt != m_dupFinder.end(); ++newIt) {
AstCFunc* const newfuncp = VN_AS(newIt->second, CFunc);
UASSERT_OBJ(newfuncp, newIt->second, "Not a CFunc in hash");
if (newfuncp->user3()) continue; // Already replaced
if (newfuncp->slow() != slow) continue;
auto oldIt = newIt;
++oldIt; // Skip over current position
for (; oldIt != m_dupFinder.end(); ++oldIt) {
AstCFunc* const oldfuncp = VN_AS(oldIt->second, CFunc);
UASSERT_OBJ(oldfuncp, oldIt->second, "Not a CFunc in hash");
UASSERT_OBJ(newfuncp != oldfuncp, newfuncp,
"Same function hashed multiple times");
if (newIt->first != oldIt->first) break; // Iterate over same hashes only
if (oldfuncp->user3()) continue; // Already replaced
if (!newfuncp->sameTree(oldfuncp)) continue; // Different functions
// One pass of combining. Returns true if did replacement.
bool combinePass(std::list<AstCFunc*>& funcps, V3DupFinder& dupFinder) {
const VNUser3InUse user3InUse;
// Replace calls to oldfuncp with calls to newfuncp
UINFO(5, " Replace CFunc " << newIt->first << " " << newfuncp << endl);
UINFO(5, " with " << oldIt->first << " " << oldfuncp << endl);
++m_cfuncsCombined;
oldfuncp->user3SetOnce(); // Mark replaced
m_call.replaceFunc(oldfuncp, newfuncp);
oldfuncp->unlinkFrBack();
// Replacement may promote a slow routine to fast path
if (!oldfuncp->slow()) newfuncp->slow(false);
VL_DO_DANGLING(pushDeletep(oldfuncp), oldfuncp);
bool replaced = false;
// Replace all identical functions with the first function in the list
for (funcit_t it = funcps.begin(), nit; it != funcps.end(); it = nit) {
AstCFunc* const funcp = *it;
nit = it;
++nit;
// Remove functions already replaced in the previous iteration
if (funcp->user2()) {
funcps.erase(it);
VL_DO_DANGLING(funcp->unlinkFrBack()->deleteTree(), funcp);
continue;
}
while (true) {
auto dit = dupFinder.findDuplicate(funcp);
if (dit == dupFinder.end()) break;
AstCFunc* oldp = VN_AS(dit->second, CFunc);
AstCFunc* newp = funcp;
UASSERT_OBJ(!oldp->user2(), oldp, "Should have been removed from dupFinder");
// Swap them, if the duplicate is earlier in the list of functions. This is
// necessary because replacing a call site in a later function might have made that
// function equivalent to an earlier function, but we want the first equivalent
// function in the list to be the canonical one.
if (oldp->user3()) std::swap(oldp, newp);
// Something is being replaced
UINFO(9, "Replacing " << oldp << endl);
UINFO(9, " with " << newp << endl);
++m_cfuncsCombined;
replaced = true;
// Mark as replaced
oldp->user2(true);
// Redirect the calls
for (AstCCall* const callp : m_callSites(oldp)) {
// For sanity check only
const V3Hash oldHash = m_hasher(callp);
// Redirect the call
callp->funcp(newp);
// When redirecting a call to an equivalent function, we do not need to re-hash
// the caller, because the hash of the two calls must be the same, and hence
// the hash of the caller should not change.
UASSERT_OBJ(oldHash == m_hasher.rehash(callp), callp, "Hash changed");
}
// Erase the replaced duplicate
UASSERT_OBJ(dupFinder.erase(oldp) == 1, oldp, "Replaced node not in dupFinder");
// If we just replaced the function we are iterating (because there was an
// equivalent earlier in the list), then move on, as this is on longer a candidate
if (oldp == funcp) break;
}
// Mark as function earlier in list of functions.
funcp->user3(true);
}
return replaced;
}
void process(AstNetlist* netlistp) {
// First, remove empty functions. We need to do this separately, because removing
// calls can change the hashes of the callers.
for (AstNodeModule* modulep = netlistp->modulesp(); modulep;
modulep = VN_AS(modulep->nextp(), NodeModule)) {
removeEmptyFunctions(m_cfuncs(modulep).m_fast);
removeEmptyFunctions(m_cfuncs(modulep).m_slow);
}
// Combine functions within each module
for (AstNodeModule* modulep = netlistp->modulesp(); modulep;
modulep = VN_AS(modulep->nextp(), NodeModule)) {
// Put fast functions first, so they are preferred over slow functions
auto funcps = std::move(m_cfuncs(modulep).m_fast);
funcps.splice(funcps.end(), m_cfuncs(modulep).m_slow);
V3DupFinder dupFinder{m_hasher};
// First, hash all functions
for (AstCFunc* const funcp : funcps) dupFinder.insert(funcp);
// Iterate to fixed point
{
const VNUser2InUse user2InUse;
while (combinePass(funcps, dupFinder)) {}
}
}
}
// VISITORS
virtual void visit(AstNetlist* nodep) override {
m_call.main(nodep); // Track all call sites of each function
iterateChildren(nodep);
// Gather functions and references
iterateChildrenConst(nodep);
// Combine functions
process(nodep);
}
virtual void visit(AstNodeModule* nodep) override {
UINFO(4, " MOD " << nodep << endl);
m_dupFinder.clear();
// Compute hash of all CFuncs in the module
iterateChildren(nodep);
if (debug() >= 9) m_dupFinder.dumpFilePrefixed("combine");
// Walk the hashes removing empty functions
walkEmptyFuncs();
// Walk the hashes looking for duplicate functions
walkDupFuncs();
UASSERT_OBJ(!m_modp, nodep, "Should not nest");
m_modp = nodep;
iterateChildrenConst(nodep);
m_modp = nullptr;
}
virtual void visit(AstCFunc* nodep) override {
iterateChildrenConst(nodep);
if (nodep->dontCombine()) return;
// Hash the entire function
m_dupFinder.insert(nodep);
auto& coll = nodep->slow() ? m_cfuncs(m_modp).m_slow : m_cfuncs(m_modp).m_fast;
coll.emplace_back(nodep);
}
virtual void visit(AstCCall* nodep) override {
iterateChildrenConst(nodep);
AstCFunc* const funcp = nodep->funcp();
if (funcp->dontCombine()) return;
m_callSites(funcp).emplace_back(nodep);
}
virtual void visit(AstAddrOfCFunc* nodep) override {
iterateChildrenConst(nodep);
if (nodep->funcp()->dontCombine()) return;
// LCOV_EXCL_START
// We cannot yet handle references via AstAddrOfCFunc, but currently those are
// only used in tracing functions, which are not combined. Blow up in case this changes.
nodep->v3fatalSrc(
"Don't know how to combine functions that are referenced via AstAddrOfCFunc");
// LCOV_EXCL_END
}
//--------------------
// Default: Just iterate
virtual void visit(AstVar*) override {} // Accelerate
virtual void visit(AstNodeStmt* nodep) override {} // Accelerate
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
virtual void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
public:
// CONSTRUCTORS
explicit CombineVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~CombineVisitor() override {
V3Stats::addStat("Optimizations, Combined CFuncs", m_cfuncsCombined);
}
~CombineVisitor() { V3Stats::addStat("Optimizations, Combined CFuncs", m_cfuncsCombined); }
public:
static void apply(AstNetlist* netlistp) { CombineVisitor{netlistp}; }
};
//######################################################################
@@ -223,6 +231,6 @@ public:
void V3Combine::combineAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CombineVisitor{nodep}; } // Destruct before checking
CombineVisitor::apply(nodep);
V3Global::dumpCheckGlobalTree("combine", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
+1 -1
View File
@@ -71,7 +71,7 @@ static void makeToStringMiddle(AstClass* nodep) {
comma = ", ";
stmt += itemp->origNameProtect();
stmt += ":\" + ";
if (itemp->isWide()) {
if (VN_IS(itemp->dtypep()->skipRefp(), BasicDType) && itemp->isWide()) {
stmt += "VL_TO_STRING_W(";
stmt += cvtToStr(itemp->widthWords());
stmt += ", ";
+22 -2
View File
@@ -41,6 +41,7 @@ private:
// STATE
AstCFunc* m_cfuncp = nullptr; // Current block
AstMTaskBody* m_mtaskbodyp = nullptr; // Current mtaskbody
AstNode* m_stmtp = nullptr; // Current statement
int m_depth = 0; // How deep in an expression
int m_maxdepth = 0; // Maximum depth in an expression
@@ -54,8 +55,13 @@ private:
// if (debug() >= 9) nodep->dumpTree(cout, "deep:");
AstVar* const varp = new AstVar{nodep->fileline(), VVarType::STMTTEMP,
m_tempNames.get(nodep), nodep->dtypep()};
UASSERT_OBJ(m_cfuncp, nodep, "Deep expression not under a function");
m_cfuncp->addInitsp(varp);
if (m_cfuncp) {
m_cfuncp->addInitsp(varp);
} else if (m_mtaskbodyp) {
m_mtaskbodyp->addStmtsFirstp(varp);
} else {
nodep->v3fatalSrc("Deep expression not under a function");
}
// Replace node tree with reference to var
AstVarRef* const newp = new AstVarRef{nodep->fileline(), varp, VAccess::READ};
nodep->replaceWith(newp);
@@ -71,14 +77,28 @@ private:
// VISITORS
virtual void visit(AstCFunc* nodep) override {
VL_RESTORER(m_cfuncp);
VL_RESTORER(m_mtaskbodyp);
{
m_cfuncp = nodep;
m_mtaskbodyp = nullptr;
m_depth = 0;
m_maxdepth = 0;
m_tempNames.reset();
iterateChildren(nodep);
}
}
virtual void visit(AstMTaskBody* nodep) override {
VL_RESTORER(m_cfuncp);
VL_RESTORER(m_mtaskbodyp);
{
m_cfuncp = nullptr;
m_mtaskbodyp = nodep;
m_depth = 0;
m_maxdepth = 0;
// We don't reset the names, as must share across tasks
iterateChildren(nodep);
}
}
void visitStmt(AstNodeStmt* nodep) {
VL_RESTORER(m_stmtp);
{
+12 -1
View File
@@ -30,6 +30,17 @@
//######################################################################
// V3DupFinder class functions
V3DupFinder::size_type V3DupFinder::erase(AstNode* nodep) {
const auto& er = equal_range(m_hasher(nodep));
for (iterator it = er.first; it != er.second; ++it) {
if (nodep == it->second) {
erase(it);
return 1;
}
}
return 0;
}
V3DupFinder::iterator V3DupFinder::findDuplicate(AstNode* nodep, V3DupFinderUserSame* checkp) {
const auto& er = equal_range(m_hasher(nodep));
for (iterator it = er.first; it != er.second; ++it) {
@@ -37,7 +48,7 @@ V3DupFinder::iterator V3DupFinder::findDuplicate(AstNode* nodep, V3DupFinderUser
if (nodep == node2p) continue; // Same node is not a duplicate
if (checkp && !checkp->isSame(nodep, node2p)) continue; // User says it is not a duplicate
if (!nodep->sameTree(node2p)) continue; // Not the same trees
// Found duplicate!
// Found duplicate
return it;
}
return end();
+16 -3
View File
@@ -28,6 +28,7 @@
#include "V3Hasher.h"
#include <map>
#include <memory>
//============================================================================
@@ -43,12 +44,20 @@ class V3DupFinder final : private std::multimap<V3Hash, AstNode*> {
using Super = std::multimap<V3Hash, AstNode*>;
// MEMBERS
const V3Hasher m_hasher;
const V3Hasher* const m_hasherp; // Pointer to owned hasher
const V3Hasher& m_hasher; // Reference to hasher
public:
// CONSTRUCTORS
V3DupFinder(){};
~V3DupFinder() = default;
V3DupFinder()
: m_hasherp{new V3Hasher}
, m_hasher{*m_hasherp} {}
V3DupFinder(const V3Hasher& hasher)
: m_hasherp{nullptr}
, m_hasher{hasher} {}
~V3DupFinder() {
if (m_hasherp) delete m_hasherp;
}
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@@ -63,10 +72,14 @@ public:
using Super::end;
using Super::erase;
using Super::iterator;
using Super::size_type;
// Insert node into data structure
iterator insert(AstNode* nodep) { return emplace(m_hasher(nodep), nodep); }
// Erase node from data structure
size_type erase(AstNode* nodep);
// Return duplicate, if one was inserted, with optional user check for sameness
iterator findDuplicate(AstNode* nodep, V3DupFinderUserSame* checkp = nullptr);
+6
View File
@@ -192,6 +192,12 @@ class EmitCHeader final : public EmitCConstInit {
puts("enum " + tdefp->name() + " {\n");
for (const AstEnumItem* itemp = edtypep->itemsp(); itemp;
itemp = VN_AS(itemp->nextp(), EnumItem)) {
if (const AstConst* const constp = VN_CAST(itemp->valuep(), Const)) {
if (constp->num().isFourState()) {
puts("// " + itemp->nameProtect() + " is four-state\n");
continue;
}
}
puts(itemp->nameProtect());
puts(" = ");
iterate(itemp->valuep());
+4 -5
View File
@@ -61,7 +61,7 @@ class EmitXmlFileVisitor final : public VNVisitor {
void outputTag(AstNode* nodep, const string& tagin) {
string tag = tagin;
if (tag == "") tag = VString::downcase(nodep->typeName());
puts("<" + tag + " " + nodep->fileline()->xml());
puts("<" + tag);
puts(" " + nodep->fileline()->xmlDetailedLocation());
if (VN_IS(nodep, NodeDType)) {
puts(" id=");
@@ -386,8 +386,7 @@ private:
if (nodep->level() >= 0
&& nodep->level() <= 2) { // ==2 because we don't add wrapper when in XML mode
m_os << "<cells>\n";
m_os << "<cell " << nodep->fileline()->xml() << " "
<< nodep->fileline()->xmlDetailedLocation() //
m_os << "<cell " << nodep->fileline()->xmlDetailedLocation() //
<< " name=\"" << nodep->prettyName() << "\""
<< " submodname=\"" << nodep->prettyName() << "\""
<< " hier=\"" << nodep->prettyName() << "\"";
@@ -405,8 +404,8 @@ private:
virtual void visit(AstCell* nodep) override {
if (nodep->modp()->dead()) return;
if (!m_hasChildren) m_os << ">\n";
m_os << "<cell " << nodep->fileline()->xml() << " "
<< nodep->fileline()->xmlDetailedLocation() << " name=\"" << nodep->name() << "\""
m_os << "<cell " << nodep->fileline()->xmlDetailedLocation() << " name=\"" << nodep->name()
<< "\""
<< " submodname=\"" << nodep->modName() << "\""
<< " hier=\"" << m_hier + nodep->name() << "\"";
const std::string hier = m_hier;
-1
View File
@@ -200,7 +200,6 @@ public:
string filebasenameNoExt() const;
string firstColumnLetters() const;
string profileFuncname() const;
string xml() const { return "fl=\"" + filenameLetters() + cvtToStr(lastLineno()) + "\""; }
string xmlDetailedLocation() const;
string lineDirectiveStrg(int enterExit) const;
+9 -21
View File
@@ -53,9 +53,7 @@ private:
// METHODS
AstVarScope* genInpClk(AstVarScope* vscp) {
if (vscp->user2p()) {
return VN_AS(vscp->user2p(), VarScope);
} else {
if (!vscp->user2p()) {
// In order to create a __VinpClk* for a signal, it needs to be marked circular.
// The DPI export trigger is never marked circular by V3Order (see comments in
// OrderVisitor::nodeMarkCircular). The only other place where one might mark
@@ -86,22 +84,15 @@ private:
m_scopetopp->addFinalClkp(asninitp);
//
vscp->user2p(newvscp);
return newvscp;
}
return VN_AS(vscp->user2p(), VarScope);
}
// VISITORS
virtual void visit(AstTopScope* nodep) override {
AstNode::user2ClearTree(); // user2p() used on entire tree
iterateChildren(nodep);
}
//----
virtual void visit(AstVarRef* nodep) override {
// Consumption/generation of a variable,
AstVarScope* const vscp = nodep->varScopep();
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
if (m_activep && !nodep->user3()) {
nodep->user3(true);
if (m_activep && !nodep->user3SetOnce()) {
AstVarScope* const vscp = nodep->varScopep();
if (vscp->isCircular()) {
UINFO(8, " VarActReplace " << nodep << endl);
// Replace with the new variable
@@ -115,10 +106,8 @@ private:
}
virtual void visit(AstActive* nodep) override {
m_activep = nodep;
UASSERT_OBJ(nodep->sensesp(), nodep, "Unlinked");
iterate(nodep->sensesp());
m_activep = nullptr;
iterateChildren(nodep);
}
//-----
@@ -141,7 +130,6 @@ private:
// NODE STATE
// Cleared on top scope
// AstVarScope::user() -> bool. Set when the var has been used as clock
const VNUser1InUse m_inuser1;
// STATE
bool m_tracingCall = false; // Iterating into a call to a cfunc
@@ -151,13 +139,13 @@ private:
// VISITORS
virtual void visit(AstTopScope* nodep) override {
AstNode::user1ClearTree(); // user1p() used on entire tree
iterateChildren(nodep);
{
// Make the new clock signals and replace any activate references
// See rename, it does some AstNode::userClearTree()'s
GenClkRenameVisitor{nodep, m_topModp};
const VNUser1InUse user1InUse;
iterateChildren(nodep);
}
// Make the new clock signals and replace any activate references
// See rename, it does some AstNode::userClearTree()'s
GenClkRenameVisitor{nodep, m_topModp};
}
virtual void visit(AstNodeModule* nodep) override {
// Only track the top scopes, not lower level functions
+2 -1
View File
@@ -43,7 +43,8 @@ class V3HierBlockPlan;
/// end-of-stope.
// Object must be named, or it will not persist until end-of-scope.
// Constructor needs () or GCC 4.8 false warning.
#define VL_RESTORER(var) const VRestorer<decltype(var)> restorer_##var(var);
#define VL_RESTORER(var) \
const VRestorer<typename std::decay<decltype(var)>::type> restorer_##var(var);
// Object used by VL_RESTORER. This object must be an auto variable, not
// allocated on the heap or otherwise.
+14
View File
@@ -516,7 +516,21 @@ V3Hash V3Hasher::operator()(AstNode* nodep) const {
return V3Hash(nodep->user4());
}
V3Hash V3Hasher::rehash(AstNode* nodep) const {
nodep->user4(0);
HasherVisitor{nodep};
return V3Hash(nodep->user4());
}
V3Hash V3Hasher::uncachedHash(const AstNode* nodep) {
const HasherVisitor visitor{nodep, HasherVisitor::Uncached{}};
return visitor.finalHash();
}
//######################################################################
// This is used by the std::hash specialization for VNRef.
// Declared separately to avoid a circular header dependency.
size_t V3HasherUncachedHash(AstNode& node) {
return static_cast<size_t>(V3Hasher::uncachedHash(&node).value());
}
+3
View File
@@ -45,6 +45,9 @@ public:
// Compute hash of node. This method caches the hash in the node's user4().
V3Hash operator()(AstNode* nodep) const;
// Re-compute hash of this node, discarding cached value, but used cached hash of children.
V3Hash rehash(AstNode* nodep) const;
// Compute hash of node, without caching in user4.
static V3Hash uncachedHash(const AstNode* nodep);
};
+6 -6
View File
@@ -320,7 +320,7 @@ private:
if (!nodep->exprp()) return; // No-connect
if (m_cellRangep) {
UINFO(4, " PIN " << nodep << endl);
const int pinwidth = nodep->modVarp()->width();
const int modwidth = nodep->modVarp()->width();
const int expwidth = nodep->exprp()->width();
const std::pair<uint32_t, uint32_t> pinDim
= nodep->modVarp()->dtypep()->dimensions(false);
@@ -328,7 +328,7 @@ private:
= nodep->exprp()->dtypep()->dimensions(false);
UINFO(4, " PINVAR " << nodep->modVarp() << endl);
UINFO(4, " EXP " << nodep->exprp() << endl);
UINFO(4, " pinwidth ew=" << expwidth << " pw=" << pinwidth << " ed=" << expDim.first
UINFO(4, " modwidth ew=" << expwidth << " pw=" << modwidth << " ed=" << expDim.first
<< "," << expDim.second << " pd=" << pinDim.first << ","
<< pinDim.second << endl);
if (expDim.first == pinDim.first && expDim.second == pinDim.second + 1) {
@@ -341,11 +341,11 @@ private:
AstNode* exprp = nodep->exprp()->unlinkFrBack();
exprp = new AstArraySel(exprp->fileline(), exprp, arraySelNum);
nodep->exprp(exprp);
} else if (expwidth == pinwidth) {
} else if (expwidth == modwidth) {
// NOP: Arrayed instants: widths match so connect to each instance
} else if (expwidth == pinwidth * m_cellRangep->elementsConst()) {
} else if (expwidth == modwidth * m_cellRangep->elementsConst()) {
// Arrayed instants: one bit for each of the instants (each
// assign is 1 pinwidth wide)
// assign is 1 modwidth wide)
if (m_cellRangep->littleEndian()) {
nodep->exprp()->v3warn(LITENDIAN, "Little endian instance range connecting to "
"vector: left < right of instance range: ["
@@ -362,7 +362,7 @@ private:
"with output connections to non-wires.");
// Note spec allows more complicated matches such as slices and such
}
exprp = new AstSel(exprp->fileline(), exprp, pinwidth * m_instSelNum, pinwidth);
exprp = new AstSel(exprp->fileline(), exprp, modwidth * m_instSelNum, modwidth);
nodep->exprp(exprp);
} else {
nodep->v3fatalSrc("Width mismatch; V3Width should have errored out.");
+5 -1
View File
@@ -942,7 +942,7 @@ class LinkDotFindVisitor final : public VNVisitor {
// places such as tasks, where "task ...; begin ... end"
// are common.
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
if (VN_IS(stmtp, Var)) {
if (VN_IS(stmtp, Var) || VN_IS(stmtp, Foreach)) {
++m_modBlockNum;
nodep->name("unnamedblk" + cvtToStr(m_modBlockNum));
break;
@@ -1092,6 +1092,10 @@ class LinkDotFindVisitor final : public VNVisitor {
} else {
findvarp->combineType(nodep);
findvarp->fileline()->modifyStateInherit(nodep->fileline());
if (nodep->getChildDTypep()->numeric().isSigned()
&& !findvarp->getChildDTypep()->numeric().isSigned()) {
findvarp->getChildDTypep()->numeric(VSigning(true));
}
AstBasicDType* const bdtypep
= VN_CAST(findvarp->childDTypep(), BasicDType);
if (bdtypep && bdtypep->implicit()) {
+16 -3
View File
@@ -62,6 +62,9 @@ private:
AstNode* m_insStmtp = nullptr; // Where to insert statement
bool m_unsupportedHere = false; // Used to detect where it's not supported yet
// METHODS
VL_DEBUG_FUNC; // Declare debug()
void insertBeforeStmt(AstNode* nodep, AstNode* newp) {
// Return node that must be visited, if any
// See also AstNode::addBeforeStmt; this predates that function
@@ -86,7 +89,7 @@ private:
// VISITORS
virtual void visit(AstNodeModule* nodep) override {
// Reset increments count
VL_RESTORER(m_modIncrementsNum);
m_modIncrementsNum = 0;
iterateChildren(nodep);
}
@@ -131,6 +134,16 @@ private:
iterateAndNextNull(nodep->elsesp());
m_insStmtp = nullptr;
}
virtual void visit(AstCaseItem* nodep) override {
m_insMode = IM_BEFORE;
{
VL_RESTORER(m_unsupportedHere);
m_unsupportedHere = true;
iterateAndNextNull(nodep->condsp());
}
m_insStmtp = nullptr; // Next thing should be new statement
iterateAndNextNull(nodep->bodysp());
}
virtual void visit(AstNodeFor* nodep) override { // LCOV_EXCL_LINE
nodep->v3fatalSrc(
"For statements should have been converted to while statements in V3Begin.cpp");
@@ -146,10 +159,10 @@ private:
m_insStmtp = nullptr; // Next thing should be new statement
}
void unsupported_visit(AstNode* nodep) {
VL_RESTORER(m_unsupportedHere);
m_unsupportedHere = true;
UINFO(9, "Marking unsupported " << nodep << endl);
iterateChildren(nodep);
m_unsupportedHere = false;
}
virtual void visit(AstLogAnd* nodep) override { unsupported_visit(nodep); }
virtual void visit(AstLogOr* nodep) override { unsupported_visit(nodep); }
@@ -262,5 +275,5 @@ public:
void V3LinkInc::linkIncrements(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ LinkIncVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("linkInc", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
V3Global::dumpCheckGlobalTree("linkinc", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
+4 -1
View File
@@ -1170,7 +1170,10 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
case 'l': m_oLife = flag; break;
case 'm': m_oAssemble = flag; break;
// n
case 'o': m_oConstBitOpTree = flag; break; // Can remove ~2022-01 when stable
case 'o':
m_oConstBitOpTree = flag;
break; // Can remove ~2022-01 when stable
// o will be used as an escape for a second character of optimization disables
case 'p':
m_public = !flag;
break; // With -Op so flag=0, we want public on so few optimizations done
+27 -12
View File
@@ -535,6 +535,22 @@ class OrderBuildVisitor final : public VNVisitor {
}
}
// Roles of vertices:
// VarVertexType::STD: Data dependencies for combinational logic and delayed
// assignment updates (AssignPost).
// VarVertexType::POST: Ensures all sequential blocks reading a signal do so before
// any combinational or delayed assignments update that signal.
// VarVertexType::PORD: Ensures a _d = _q AssignPre is the first write of a _d,
// before any sequential blocks write to that _d.
// VarVertexType::PRE: This is an optimization. Try to ensure that a _d = _q
// AssignPre is the last read of a _q, after all reads of that
// _q by sequential logic. Note: The model is still correct if we
// cannot satisfy this due to other constraints. If this ordering
// is possible, then combined with the PORD constraint we get
// that all writes to _d are after all reads of a _q, which then
// allows us to eliminate the _d completely and assign to the _q
// directly (this is what V3LifePost does).
// Variable is produced
if (gen) {
// Update VarUsage
@@ -1038,8 +1054,8 @@ public:
class OrderProcess final : VNDeleter {
// NODE STATE
// AstNodeModule::user3 -> int: Number of AstCFuncs created under this module
// AstNode::user4 -> Used by V3Const::constifyExpensiveEdit
// AstNode::user3 -> Used by loop reporting
// AstNode::user4 -> Used by V3Const::constifyExpensiveEdit
const VNUser3InUse user3InUse;
// STATE
@@ -1057,6 +1073,7 @@ class OrderProcess final : VNDeleter {
friend class OrderMoveDomScope;
V3List<OrderMoveDomScope*> m_pomReadyDomScope; // List of ready domain/scope pairs, by loopId
std::vector<OrderVarStdVertex*> m_unoptflatVars; // Vector of variables in UNOPTFLAT loop
std::map<std::pair<AstNodeModule*, std::string>, unsigned> m_funcNums; // Function ordinals
// STATS
std::array<VDouble0, OrderVEdgeType::_ENUM_END> m_statCut; // Count of each edge type cut
@@ -1099,16 +1116,14 @@ class OrderProcess final : VNDeleter {
string cfuncName(AstNodeModule* modp, AstSenTree* domainp, AstScope* scopep,
AstNode* forWhatp) {
modp->user3Inc();
const int funcnum = modp->user3();
string name = (domainp->hasCombo()
? "_combo"
: (domainp->hasInitial()
? "_initial"
: (domainp->hasSettle()
? "_settle"
: (domainp->isMulti() ? "_multiclk" : "_sequent"))));
name = name + "__" + scopep->nameDotless() + "__" + cvtToStr(funcnum);
string name = domainp->hasCombo() ? "_combo"
: domainp->hasInitial() ? "_initial"
: domainp->hasSettle() ? "_settle"
: domainp->isMulti() ? "_multiclk"
: "_sequent";
name = name + "__" + scopep->nameDotless();
const unsigned funcnum = m_funcNums.emplace(std::make_pair(modp, name), 0).first->second++;
name = name + "__" + cvtToStr(funcnum);
if (v3Global.opt.profCFuncs()) {
name += "__PROF__" + forWhatp->fileline()->profileFuncname();
}
+7 -2
View File
@@ -554,10 +554,15 @@ class ParamProcessor final {
cellp->v3error("Exceeded maximum --module-recursion-depth of "
<< v3Global.opt.moduleRecursionDepth());
}
// Keep tree sorted by level
// Keep tree sorted by level. Append to end of sub-list at the same level. This is
// important because due to the way recursive modules are handled, different
// parametrizations of the same recursive module end up with the same level (which in
// itself is a bit unfortunate). Nevertheless, as a later parametrization must not be above
// an earlier parametrization of a recursive module, it is sufficient to add to the end of
// the sub-list to keep the modules topologically sorted.
AstNodeModule* insertp = srcModp;
while (VN_IS(insertp->nextp(), NodeModule)
&& VN_AS(insertp->nextp(), NodeModule)->level() < newmodp->level()) {
&& VN_AS(insertp->nextp(), NodeModule)->level() <= newmodp->level()) {
insertp = VN_AS(insertp->nextp(), NodeModule);
}
insertp->addNextHere(newmodp);
+14 -53
View File
@@ -31,51 +31,11 @@
// Collect SenTrees under the entire scope
// And provide functions to find/add a new one
class SenTreeSet final {
// Hash table of sensitive blocks.
private:
// TYPES
struct HashSenTree {
size_t operator()(const AstSenTree* kp) const {
return V3Hasher::uncachedHash(kp).value();
}
};
struct EqSenTree {
bool operator()(const AstSenTree* ap, const AstSenTree* bp) const {
return ap->sameTree(bp);
}
};
// MEMBERS
using Set = std::unordered_set<AstSenTree*, HashSenTree, EqSenTree>;
Set m_trees; // Set of sensitive blocks, for folding.
public:
// CONSTRUCTORS
SenTreeSet() = default;
// METHODS
void add(AstSenTree* nodep) { m_trees.insert(nodep); }
AstSenTree* find(AstSenTree* likep) {
AstSenTree* resultp = nullptr;
const auto it = m_trees.find(likep);
if (it != m_trees.end()) resultp = *it;
return resultp;
}
void clear() { m_trees.clear(); }
private:
VL_UNCOPYABLE(SenTreeSet);
};
class SenTreeFinder final {
private:
// STATE
AstTopScope* const m_topScopep; // Top scope to add global SenTrees to
SenTreeSet m_trees; // Set of global SenTrees
std::unordered_set<VNRef<AstSenTree>> m_trees; // Set of global SenTrees
VL_UNCOPYABLE(SenTreeFinder);
@@ -87,25 +47,26 @@ public:
explicit SenTreeFinder(AstNetlist* netlistp)
: m_topScopep{netlistp->topScopep()} {
// Gather existing global SenTrees
for (AstNode* nodep = m_topScopep->senTreesp(); nodep; nodep = nodep->nextp()) {
m_trees.add(VN_AS(nodep, SenTree));
for (AstSenTree* senTreep = m_topScopep->senTreesp(); senTreep;
senTreep = VN_AS(senTreep->nextp(), SenTree)) {
m_trees.emplace(*senTreep);
}
}
// METHODS
// Return a global AstSenTree that matches given SenTree.
// Return a global AstSenTree equivalent to the given senTreep.
// If no such global AstSenTree exists create one and add it to the stored AstTopScope.
AstSenTree* getSenTree(AstSenTree* senTreep) {
AstSenTree* treep = m_trees.find(senTreep);
if (!treep) {
// Not found, form a new one
treep = senTreep->cloneTree(false);
m_topScopep->addSenTreep(treep);
UINFO(8, " New SENTREE " << treep << endl);
m_trees.add(treep);
}
return treep;
auto it = m_trees.find(*senTreep);
// If match found, return it.
if (it != m_trees.end()) return &(*it).get();
// Not found, create a new one
AstSenTree* const newSenTreep = senTreep->cloneTree(false);
m_topScopep->addSenTreep(newSenTreep);
m_trees.emplace(*newSenTreep);
return newSenTreep;
}
// Return the global combinational AstSenTree.
+53 -18
View File
@@ -254,14 +254,11 @@ protected:
SplitPliVertex* m_pliVertexp; // Element specifying PLI ordering
V3Graph m_graph; // Scoreboard of var usages/dependencies
bool m_inDly; // Inside ASSIGNDLY
VDouble0 m_statSplits; // Statistic tracking
// CONSTRUCTORS
public:
SplitReorderBaseVisitor() { scoreboardClear(); }
virtual ~SplitReorderBaseVisitor() override {
V3Stats::addStat("Optimizations, Split always", m_statSplits);
}
virtual ~SplitReorderBaseVisitor() override = default;
// METHODS
protected:
@@ -794,21 +791,55 @@ private:
};
class RemovePlaceholdersVisitor final : public VNVisitor {
std::unordered_set<AstNode*> m_removeSet; // placeholders to be removed
public:
explicit RemovePlaceholdersVisitor(AstNode* nodep) {
iterate(nodep);
for (AstNode* np : m_removeSet) {
np->unlinkFrBack(); // Without next
VL_DO_DANGLING(np->deleteTree(), np);
// MEMBERS
bool m_isPure = true;
int m_emptyAlways = 0;
// CONSTRUCTORS
RemovePlaceholdersVisitor() = default;
virtual ~RemovePlaceholdersVisitor() override = default;
// VISITORS
virtual void visit(AstSplitPlaceholder* nodep) override { pushDeletep(nodep->unlinkFrBack()); }
virtual void visit(AstNodeIf* nodep) override {
VL_RESTORER(m_isPure);
m_isPure = true;
iterateChildren(nodep);
if (!nodep->ifsp() && !nodep->elsesp() && m_isPure) pushDeletep(nodep->unlinkFrBack());
}
virtual void visit(AstAlways* nodep) override {
VL_RESTORER(m_isPure);
m_isPure = true;
iterateChildren(nodep);
if (m_isPure) {
bool emptyOrCommentOnly = true;
for (AstNode* bodysp = nodep->bodysp(); bodysp; bodysp = bodysp->nextp()) {
// If this always block contains only AstComment, remove here.
// V3Gate will remove anyway.
if (!VN_IS(bodysp, Comment)) {
emptyOrCommentOnly = false;
break;
}
}
if (emptyOrCommentOnly) {
pushDeletep(nodep->unlinkFrBack());
++m_emptyAlways;
}
}
}
virtual ~RemovePlaceholdersVisitor() override = default;
virtual void visit(AstSplitPlaceholder* nodep) override { m_removeSet.insert(nodep); }
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
virtual void visit(AstNode* nodep) override {
m_isPure &= nodep->isPure();
iterateChildren(nodep); // must visit regardless of m_isPure to remove placeholders
}
private:
VL_UNCOPYABLE(RemovePlaceholdersVisitor);
public:
static int exec(AstAlways* nodep) {
RemovePlaceholdersVisitor visitor;
visitor.iterate(nodep);
return visitor.m_emptyAlways;
}
};
class SplitVisitor final : public SplitReorderBaseVisitor {
@@ -820,6 +851,7 @@ private:
// AstNodeIf* whose condition we're currently visiting
const AstNode* m_curIfConditional = nullptr;
VDouble0 m_statSplits; // Statistic tracking
// CONSTRUCTORS
public:
@@ -834,14 +866,17 @@ public:
for (AlwaysVec::iterator addme = it->second.begin(); addme != it->second.end();
++addme) {
origp->addNextHere(*addme);
RemovePlaceholdersVisitor{*addme};
const int numRemoved = RemovePlaceholdersVisitor::exec(*addme);
m_statSplits -= numRemoved;
}
origp->unlinkFrBack(); // Without next
VL_DO_DANGLING(origp->deleteTree(), origp);
}
}
virtual ~SplitVisitor() override = default;
virtual ~SplitVisitor() override {
V3Stats::addStat("Optimizations, Split always", m_statSplits);
}
// METHODS
protected:
@@ -944,7 +979,7 @@ protected:
// Counting original always blocks rather than newly-split
// always blocks makes it a little easier to use this stat to
// check the result of the t_alw_split test:
++m_statSplits;
m_statSplits += ifColor.colors().size() - 1; // -1 for the original always
// Visit through the original always block one more time,
// and emit the split always blocks into m_replaceBlocks:
+29 -12
View File
@@ -4403,26 +4403,26 @@ private:
modDTypep = modDTypep->skipRefp();
conDTypep = conDTypep->skipRefp();
AstNodeDType* subDTypep = modDTypep;
const int pinwidth = modDTypep->width();
const int modwidth = modDTypep->width();
const int conwidth = conDTypep->width();
if (conDTypep == modDTypep // If match, we're golden
|| similarDTypeRecurse(conDTypep, modDTypep)) {
userIterateAndNext(nodep->exprp(), WidthVP(subDTypep, FINAL).p());
} else if (m_cellp->rangep()) {
const int numInsts = m_cellp->rangep()->elementsConst();
if (conwidth == pinwidth) {
if (conwidth == modwidth) {
// Arrayed instants: widths match so connect to each instance
subDTypep = conDTypep; // = same expr dtype
} else if (conwidth == numInsts * pinwidth) {
} else if (conwidth == numInsts * modwidth) {
// Arrayed instants: one bit for each of the instants (each
// assign is 1 pinwidth wide)
// assign is 1 modwidth wide)
subDTypep = conDTypep; // = same expr dtype (but numInst*pin_dtype)
} else {
// Must be a error according to spec
// (Because we need to know if to connect to one or all instants)
nodep->v3error(ucfirst(nodep->prettyOperatorName())
<< " as part of a module instance array"
<< " requires " << pinwidth << " or " << pinwidth * numInsts
<< " requires " << modwidth << " or " << modwidth * numInsts
<< " bits, but connection's "
<< nodep->exprp()->prettyTypeName() << " generates " << conwidth
<< " bits. (IEEE 1800-2017 23.3.3)");
@@ -4438,12 +4438,12 @@ private:
<< " data type but connection is "
<< conDTypep->prettyDTypeNameQ() << " data type.");
} else if (nodep->modVarp()->isTristate()) {
if (pinwidth != conwidth) {
if (modwidth != conwidth) {
// Ideally should call pinReconnectSimple which would tolerate this
// then have a conversion warning
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: " << ucfirst(nodep->prettyOperatorName())
<< " to inout signal requires " << pinwidth
<< " to inout signal requires " << modwidth
<< " bits, but connection's "
<< nodep->exprp()->prettyTypeName()
<< " generates " << conwidth << " bits.");
@@ -4524,9 +4524,9 @@ private:
// Very much like like an pin
const AstNodeDType* const conDTypep = nodep->exprp()->dtypep();
const int numInsts = nodep->rangep()->elementsConst();
const int pinwidth = numInsts;
const int modwidth = numInsts;
const int conwidth = conDTypep->width();
if (conwidth == 1 && pinwidth > 1) { // Multiple connections
if (conwidth == 1 && modwidth > 1) { // Multiple connections
AstNodeDType* const subDTypep = nodep->findLogicDType(1, 1, conDTypep->numeric());
userIterateAndNext(nodep->exprp(), WidthVP(subDTypep, FINAL).p());
AstNode* const newp = new AstReplicate(nodep->fileline(),
@@ -5049,7 +5049,7 @@ private:
void visit_negate_not(AstNodeUniop* nodep, bool real_ok) {
// CALLER: (real_ok=false) Not
// CALLER: (real_ok=true) Negate
// CALLER: (real_ok=true) Negate - allow real numbers
// Signed: From lhs
// IEEE-2012 Table 11-21:
// Widths: out width = lhs width
@@ -5076,7 +5076,14 @@ private:
AstNodeDType* const expDTypep = m_vup->dtypeOverridep(nodep->dtypep());
nodep->dtypep(expDTypep); // Propagate expression type to negation
AstNodeDType* const subDTypep = expDTypep;
iterateCheck(nodep, "LHS", nodep->lhsp(), CONTEXT, FINAL, subDTypep, EXTEND_EXP);
// Some warning suppressions
bool lhsWarn = true;
if (VN_IS(nodep, Negate)) {
// Warn if user wants extra bit from carry
if (subDTypep->widthMin() == (nodep->lhsp()->widthMin() + 1)) lhsWarn = false;
}
iterateCheck(nodep, "LHS", nodep->lhsp(), CONTEXT, FINAL, subDTypep, EXTEND_EXP,
lhsWarn);
}
}
@@ -6292,8 +6299,18 @@ private:
const bool fromNumericable = VN_IS(fromBaseDtp, BasicDType)
|| VN_IS(fromBaseDtp, EnumDType)
|| VN_IS(fromBaseDtp, NodeUOrStructDType);
const AstNodeDType* toBaseDtp = toDtp;
while (const AstPackArrayDType* const packp = VN_CAST(toBaseDtp, PackArrayDType)) {
toBaseDtp = packp->subDTypep();
while (const AstRefDType* const refp = VN_CAST(toBaseDtp, RefDType)) {
toBaseDtp = refp->refDTypep();
}
}
const bool toNumericable
= VN_IS(toBaseDtp, BasicDType) || VN_IS(toBaseDtp, NodeUOrStructDType);
// UNSUP unpacked struct/unions (treated like BasicDType)
if (VN_IS(toDtp, BasicDType) || VN_IS(toDtp, NodeUOrStructDType)) {
if (toNumericable) {
if (fromNumericable) return COMPATIBLE;
} else if (VN_IS(toDtp, EnumDType)) {
if (VN_IS(fromBaseDtp, EnumDType) && toDtp->sameTree(fromDtp)) return ENUM_IMPLICIT;
-1
View File
@@ -142,7 +142,6 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
-?"-match" { FL; return yVLT_D_MATCH; }
-?"-model" { FL; return yVLT_D_MODEL; }
-?"-module" { FL; return yVLT_D_MODULE; }
-?"-msg" { FL; return yVLT_D_MSG; }
-?"-mtask" { FL; return yVLT_D_MTASK; }
-?"-rule" { FL; return yVLT_D_RULE; }
-?"-task" { FL; return yVLT_D_TASK; }
-9
View File
@@ -370,7 +370,6 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
%token<fl> yVLT_D_MATCH "--match"
%token<fl> yVLT_D_MODEL "--model"
%token<fl> yVLT_D_MODULE "--module"
%token<fl> yVLT_D_MSG "--msg"
%token<fl> yVLT_D_MTASK "--mtask"
%token<fl> yVLT_D_RULE "--rule"
%token<fl> yVLT_D_TASK "--task"
@@ -6436,10 +6435,6 @@ vltOffFront<errcodeen>:
yVLT_COVERAGE_OFF { $$ = V3ErrorCode::I_COVERAGE; }
| yVLT_TRACING_OFF { $$ = V3ErrorCode::I_TRACING; }
| yVLT_LINT_OFF { $$ = V3ErrorCode::I_LINT; }
| yVLT_LINT_OFF yVLT_D_MSG idAny
{ $$ = V3ErrorCode((*$3).c_str());
if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown Error Code: " << *$3); }
$2->v3warn(DEPRECATED, "Deprecated -msg in configuration files, use -rule instead."); }
| yVLT_LINT_OFF yVLT_D_RULE idAny
{ $$ = V3ErrorCode((*$3).c_str());
if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown Error Code: " << *$3); } }
@@ -6449,10 +6444,6 @@ vltOnFront<errcodeen>:
yVLT_COVERAGE_ON { $$ = V3ErrorCode::I_COVERAGE; }
| yVLT_TRACING_ON { $$ = V3ErrorCode::I_TRACING; }
| yVLT_LINT_ON { $$ = V3ErrorCode::I_LINT; }
| yVLT_LINT_ON yVLT_D_MSG idAny
{ $$ = V3ErrorCode((*$3).c_str());
if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown Error Code: " << *$3); }
$2->v3warn(DEPRECATED, "Deprecated -msg in configuration files, use -rule instead."); }
| yVLT_LINT_ON yVLT_D_RULE idAny
{ $$ = V3ErrorCode((*$3).c_str());
if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown Error Code: " << *$3); } }
+1 -1
View File
@@ -2434,7 +2434,7 @@ sub file_grep {
return if ($contents eq "_Already_Errored_");
if ($contents !~ /$regexp/) {
$self->error("File_grep: $filename: Regexp not found: $regexp\n");
} elsif ($expvalue && $expvalue ne $1) {
} elsif (defined($expvalue) && $expvalue ne $1) {
$self->error("File_grep: $filename: Got='$1' Expected='$expvalue' in regexp: $regexp\n");
}
}
+18 -5
View File
@@ -47,11 +47,21 @@ module t (/*AUTOARG*/
f_split_1 = m_din;
end
reg [15:0] l_split_1, l_split_2;
always @ (posedge clk) begin
l_split_2 <= l_split_1;
l_split_1 <= l_split_2 | m_din;
end
function logic[15:0] sideeffect_func(logic [15:0] v);
/*verilator no_inline_task */
$display(" sideeffect_func() is called %t", $time);
return ~v;
endfunction
reg [15:0] m_split_1 = 0;
reg [15:0] m_split_2 = 0;
always @(posedge clk) begin
if (sideeffect_func(m_split_1) != 16'b0) begin
m_split_1 <= m_din;
end else begin
m_split_2 <= m_din;
end
end
reg [15:0] z_split_1, z_split_2;
always @ (posedge clk) begin
@@ -104,6 +114,7 @@ module t (/*AUTOARG*/
if (!(c_split_1==16'h0112 && c_split_2==16'hfeed)) $stop;
if (!(e_split_1==16'hfeed && e_split_2==16'hfeed)) $stop;
if (!(f_split_1==16'hfeed && f_split_2==16'hfeed)) $stop;
if (!(m_split_1==16'hfeed && m_split_2==16'h0000)) $stop;
if (!(z_split_1==16'h0112 && z_split_2==16'h0112)) $stop;
end
if (cyc==5) begin
@@ -113,6 +124,7 @@ module t (/*AUTOARG*/
// Two valid orderings, as we don't know which posedge clk gets evaled first
if (!(e_split_1==16'hfeed && e_split_2==16'hfeed) && !(e_split_1==16'he11e && e_split_2==16'he11e)) $stop;
if (!(f_split_1==16'hfeed && f_split_2==16'hfeed) && !(f_split_1==16'he11e && f_split_2==16'hfeed)) $stop;
if (!(m_split_1==16'hfeed && m_split_2==16'h0000)) $stop;
if (!(z_split_1==16'h0112 && z_split_2==16'h0112)) $stop;
end
if (cyc==6) begin
@@ -122,6 +134,7 @@ module t (/*AUTOARG*/
// Two valid orderings, as we don't know which posedge clk gets evaled first
if (!(e_split_1==16'he11e && e_split_2==16'he11e) && !(e_split_1==16'he22e && e_split_2==16'he22e)) $stop;
if (!(f_split_1==16'he11e && f_split_2==16'hfeed) && !(f_split_1==16'he22e && f_split_2==16'he11e)) $stop;
if (!(m_split_1==16'he11e && m_split_2==16'h0000)) $stop;
if (!(z_split_1==16'h1ee1 && z_split_2==16'h0112)) $stop;
end
if (cyc==7) begin
+1 -1
View File
@@ -15,7 +15,7 @@ compile(
);
if ($Self->{vlt_all}) {
file_grep($Self->{stats}, qr/Optimizations, Split always\s+(\d+)/i, 3);
file_grep($Self->{stats}, qr/Optimizations, Split always\s+(\d+)/i, 4);
}
execute(
+6
View File
@@ -50,6 +50,12 @@ module t (/*AUTOARG*/
end
end
reg [15:0] l_split_1, l_split_2;
always @ (posedge clk) begin
l_split_2 <= l_split_1;
l_split_1 <= l_split_2 | m_din;
end
// (The checker block is an exception, it won't split.)
always @ (posedge clk) begin
if (cyc!=0) begin
+1 -1
View File
@@ -16,7 +16,7 @@ compile(
);
if ($Self->{vlt_all}) {
file_grep($Self->{stats}, qr/Optimizations, Split always\s+(\d+)/i, 0);
file_grep($Self->{stats}, qr/Optimizations, Split always\s+(\d+)/i, 12);
}
execute(
+1 -1
View File
@@ -15,7 +15,7 @@ compile(
);
if ($Self->{vlt_all}) {
file_grep($Self->{stats}, qr/Optimizations, Split always\s+(\d+)/i, 0);
file_grep($Self->{stats}, qr/Optimizations, Split always\s+(\d+)/i, 5);
}
execute(
+1 -2
View File
@@ -16,8 +16,7 @@ compile(
if ($Self->{vlt_all}) {
file_grep($Self->{stats}, qr/Optimizations, Tables created\s+(\d+)/i, 10);
file_grep($Self->{stats}, qr/Optimizations, Combined CFuncs\s+(\d+)/i,
($Self->{vltmt} ? 0 : 8));
file_grep($Self->{stats}, qr/Optimizations, Combined CFuncs\s+(\d+)/i, 8);
}
execute(
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(simulator => 1);
compile(
verilator_flags2 => ["--trace --Os -x-assign 0"],
);
execute(
check_finished => 1,
);
ok(1);
1;
+156
View File
@@ -0,0 +1,156 @@
module t
(/*AUTOARG*/
// Inputs
clk
);
input clk;
int cyc = 0;
logic [1:0] case_sel;
always @ (posedge clk) begin : main
cyc <= cyc + 1;
case_sel <= 2'($urandom);
if (cyc > 100) begin
$write("*-* All Finished *-*\n");
$finish();
end
end
// -------------------------
// Simple case-stmt with ++/--
logic [3:0] count_d;
logic [3:0] count_q = '0;
logic [3:0] want_count_d;
logic [3:0] want_count_q = '0;
always_ff @(posedge clk) begin : flops
count_q <= count_d;
want_count_q <= want_count_d;
end
always @(posedge clk) begin : simple_check
if (cyc > 0) begin
if (count_q !== want_count_q) begin
$error("%m: Checks cyc=%0d, count_q (%0d) !== want_count_q (%0d)",
cyc, count_q, want_count_q);
$stop; // don't finish to fail the test.
end
end
end
always_comb begin : update_golden_counts
want_count_d = want_count_q;
if (case_sel == 2'b10)
want_count_d++;
else if (case_sel == 2'b01)
want_count_d--;
end
// Make sure the ++ and -- operators are handled correctly in case stmts.
// Test for https://github.com/verilator/verilator/issues/3346
always_comb begin : update_counts
count_d = count_q;
case (case_sel)
2'b10: count_d++;
2'b01: count_d--;
default : ;
endcase // case (case_sel)
end
// -------------------------
// FSM with ++/--
// A more elaborate case statement, with if-else, for loops, etc
// to confirm that ++/-- is handled by V3LinkInc.cpp
logic [3:0] state_d, state_q;
initial state_q = '0;
logic [3:0] state_counter_d, state_counter_q;
always_ff @(posedge clk) begin
state_q <= state_d;
state_counter_q <= state_counter_d;
end
always_comb begin : update_state
state_d = state_q;
state_counter_d = state_counter_q;
case (state_q)
// state 0, no begin/end, goes to state 1
4'd0: state_d = 4'd1;
// state 1, clears state_counter_d, goes to state 2
4'd1: begin
state_d = 4'd2;
state_counter_d = '0;
end
// state 2, wait until state_counter_d increments to 4.
4'd2: begin
state_counter_d++;
if (state_counter_q == 4) begin
state_d = 4'd3;
end
end
// state 3, decrements state_counter_d from 5 to 0.
4'd3: begin
state_counter_d--;
if (state_counter_q == 1) begin
state_d = 4'd4;
end
end
4'd4: begin
// add 4 with for-loop and ++.
for (int unsigned i = 0; i < 4; i++) begin
state_counter_d++;
end
if (state_counter_q == 12) begin
state_counter_d = '0;
state_d = 4'd5;
end
end
4'd5: begin
// add 8 with a while loop and go to state 6.
while (state_counter_d <= 7) begin
state_counter_d++;
end
if (state_counter_d == 8) begin
state_d = 4'd15;
end
end
4'd15 : begin
// success, stay here.
state_counter_d = 4'd7; // pick and hold some success number.
end
default: ;
endcase // case (state_q)
end // block: state
always @(posedge clk) begin : simple_state_check
//$display("%m: debug, cyc=%0d, state_q=%0d, state_counter_q=%0d",
// cyc, state_q, state_counter_q);
if (cyc >= 90) begin
// the above FSM should finish before 90 cycles.
// Make sure we made it to state 4'd15.
if (state_q !== 4'd15 ||
state_counter_q !== 4'd7) begin
$error("%m: EOT checks, cyc=%0d, state_q=%0d (want 15), state_counter_q=%0d (want 7)",
cyc, state_q, state_counter_q);
$stop; // don't finish to fail the test.
end
end
end
endmodule : t
+17
View File
@@ -15,6 +15,7 @@ module t;
typedef logic [3:0] mc_t;
typedef mc_t tocast_t;
typedef logic [2:0] [7:0] two_dee_t;
typedef struct packed {
logic [15:0] data;
@@ -42,6 +43,8 @@ module t;
logic [15:0] allones = 16'hffff;
parameter FOUR = 4;
localparam two_dee_t two_dee = two_dee_t'(32'habcdef);
// bug925
localparam [6:0] RESULT = 7'((6*9+92)%96);
@@ -63,6 +66,9 @@ module t;
logic [32:0] b33 = {32'(0), one};
logic [31:0] b32 = {31'(0), one};
logic [31:0] thirty_two_bits;
two_dee_t two_dee_sig;
initial begin
if (logic8bit != 8'h12) $stop;
if (4'shf > 4'sh0) $stop;
@@ -107,6 +113,17 @@ module t;
if (b33 != 33'b1) $stop;
if (b32 != 32'b1) $stop;
if (two_dee[0] != 8'hef) $stop;
if (two_dee[1] != 8'hcd) $stop;
if (two_dee[2] != 8'hab) $stop;
thirty_two_bits = 32'h123456;
two_dee_sig = two_dee_t'(thirty_two_bits);
if (two_dee_sig[0] != 8'h56) $stop;
if (two_dee_sig[1] != 8'h34) $stop;
if (two_dee_sig[2] != 8'h12) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
+2 -2
View File
@@ -1,4 +1,4 @@
''{b:'h1, i:'h2a, carray4:'{'h11, 'h22, 'h33, 'h44} , name:"object_name"}'
''{b:'h1, i:'h2a, carray4:'{'h911, 'h922, 'h933, 'h944} , name:"object_name"}'
''{b:'h1, i:'h2a, carray4:'{'h11, 'h22, 'h33, 'h44} , cwide:'{'h0, 'h0} , name:"object_name"}'
''{b:'h1, i:'h2a, carray4:'{'h911, 'h922, 'h933, 'h944} , cwide:'{'h0, 'h0} , name:"object_name"}'
DEBUG: object_name (@0) message
*-* All Finished *-*
+1
View File
@@ -15,6 +15,7 @@ class Cls;
bit b;
int i;
bit [15:0] carray4 [4];
bit [64:0] cwide[2];
string name;
task debug();
$display("DEBUG: %s (@%0t) %s", this.name, $realtime, "message");
+3 -3
View File
@@ -17,9 +17,9 @@ compile(
);
if ($Self->{vlt_all}) {
file_grep("$out_filename", qr/\<var fl="d74" loc=".*?" name="clk0" .*dir="input" .*vartype="logic" origName="clk0" clocker="true" public="true"\/\>/i);
file_grep("$out_filename", qr/\<var fl="d75" loc=".*?" name="clk1" .*dir="input" .*vartype="logic" origName="clk1" clocker="true" public="true"\/\>/i);
file_grep("$out_filename", qr/\<var fl="d76" loc=".*?" name="clk2" .*dir="input" .*vartype="logic" origName="clk2" clocker="true" public="true"\/\>/i);
file_grep("$out_filename", qr/\<var loc="d,74,.*?" name="clk0" .*dir="input" .*vartype="logic" origName="clk0" clocker="true" public="true"\/\>/i);
file_grep("$out_filename", qr/\<var loc="d,75,.*?" name="clk1" .*dir="input" .*vartype="logic" origName="clk1" clocker="true" public="true"\/\>/i);
file_grep("$out_filename", qr/\<var loc="d,76,.*?" name="clk2" .*dir="input" .*vartype="logic" origName="clk2" clocker="true" public="true"\/\>/i);
}
execute(
+4 -4
View File
@@ -18,10 +18,10 @@ compile(
);
if ($Self->{vlt_all}) {
file_grep("$out_filename", qr/\<var fl="e78" loc=".*?" name="clk0" .*dir="input" .*vartype="logic" origName="clk0" clocker="true" public="true"\/\>/i);
file_grep("$out_filename", qr/\<var fl="e79" loc=".*?" name="clk1" .*dir="input" .*vartype="logic" origName="clk1" clocker="true" public="true"\/\>/i);
file_grep("$out_filename", qr/\<var fl="e80" loc=".*?" name="clk2" .*dir="input" .*vartype="logic" origName="clk2" clocker="true" public="true"\/\>/i);
file_grep("$out_filename", qr/\<var fl="e82" loc=".*?" name="data_in" .*dir="input" .*vartype="logic" origName="data_in" clocker="false" public="true"\/\>/i);
file_grep("$out_filename", qr/\<var loc="e,78,.*?" name="clk0" .*dir="input" .*vartype="logic" origName="clk0" clocker="true" public="true"\/\>/i);
file_grep("$out_filename", qr/\<var loc="e,79,.*?" name="clk1" .*dir="input" .*vartype="logic" origName="clk1" clocker="true" public="true"\/\>/i);
file_grep("$out_filename", qr/\<var loc="e,80,.*?" name="clk2" .*dir="input" .*vartype="logic" origName="clk2" clocker="true" public="true"\/\>/i);
file_grep("$out_filename", qr/\<var loc="e,82,.*?" name="data_in" .*dir="input" .*vartype="logic" origName="data_in" clocker="false" public="true"\/\>/i);
}
execute(
+1 -1
View File
@@ -17,7 +17,7 @@ compile(
);
if ($Self->{vlt_all}) {
file_grep("$out_filename", qr/\<var fl="e44" loc=".*?" name="t.f0.clock_gate.clken_latched" dtype_id="1" vartype="logic" origName="clken_latched" clock_enable="true" latched="true"\/\>/i);
file_grep("$out_filename", qr/\<var loc="e,44,.*?" name="t.f0.clock_gate.clken_latched" dtype_id="1" vartype="logic" origName="clken_latched" clock_enable="true" latched="true"\/\>/i);
file_grep($Self->{stats}, qr/Optimizations, Gate sigs deduped\s+(\d+)/i, 4);
}
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2022 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(vltmt => 1); # Note issue shows up with --threads
compile(
verilator_flags2 => ['--compiler clang --threads 2 -Wno-UNOPTTHREADS'],
);
ok(1);
1;
+83
View File
@@ -0,0 +1,83 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2022 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
module t(/*AUTOARG*/
// Outputs
out,
// Inputs
clk_0, clk_1, clk_2, clk_3, clk_4, clk_5, clk_6, clk_7, clk_8, clk_9, clk_10,
clk_11, clk_12, clk_13, clk_14, clk_15, clk_16, clk_17, clk_18, clk_19,
rstn_0, rstn_1, rstn_2, rstn_3, rstn_4, rstn_5, rstn_6, rstn_7, rstn_8,
rstn_9, rstn_10, rstn_11, rstn_12, rstn_13, rstn_14, rstn_15, rstn_16,
rstn_17, rstn_18, rstn_19
);
input clk_0;
input clk_1;
input clk_2;
input clk_3;
input clk_4;
input clk_5;
input clk_6;
input clk_7;
input clk_8;
input clk_9;
input clk_10;
input clk_11;
input clk_12;
input clk_13;
input clk_14;
input clk_15;
input clk_16;
input clk_17;
input clk_18;
input clk_19;
input rstn_0;
input rstn_1;
input rstn_2;
input rstn_3;
input rstn_4;
input rstn_5;
input rstn_6;
input rstn_7;
input rstn_8;
input rstn_9;
input rstn_10;
input rstn_11;
input rstn_12;
input rstn_13;
input rstn_14;
input rstn_15;
input rstn_16;
input rstn_17;
input rstn_18;
input rstn_19;
// verilator lint_off MULTIDRIVEN
output reg out [0:29-1];
always_ff @(posedge clk_0, negedge rstn_0) if ((rstn_0 == 0)) out[0] <= 0;
always_ff @(posedge clk_1, negedge rstn_1) if ((rstn_1 == 0)) out[1] <= 0;
always_ff @(posedge clk_2, negedge rstn_2) if ((rstn_2 == 0)) out[2] <= 0;
always_ff @(posedge clk_3, negedge rstn_3) if ((rstn_3 == 0)) out[3] <= 0;
always_ff @(posedge clk_4, negedge rstn_4) if ((rstn_4 == 0)) out[4] <= 0;
always_ff @(posedge clk_5, negedge rstn_5) if ((rstn_5 == 0)) out[5] <= 0;
always_ff @(posedge clk_6, negedge rstn_6) if ((rstn_6 == 0)) out[6] <= 0;
always_ff @(posedge clk_7, negedge rstn_7) if ((rstn_7 == 0)) out[7] <= 0;
always_ff @(posedge clk_8, negedge rstn_8) if ((rstn_8 == 0)) out[8] <= 0;
always_ff @(posedge clk_9, negedge rstn_9) if ((rstn_9 == 0)) out[9] <= 0;
always_ff @(posedge clk_10, negedge rstn_10) if ((rstn_10 == 0)) out[10] <= 0;
always_ff @(posedge clk_11, negedge rstn_11) if ((rstn_11 == 0)) out[11] <= 0;
always_ff @(posedge clk_12, negedge rstn_12) if ((rstn_12 == 0)) out[12] <= 0;
always_ff @(posedge clk_13, negedge rstn_13) if ((rstn_13 == 0)) out[13] <= 0;
always_ff @(posedge clk_14, negedge rstn_14) if ((rstn_14 == 0)) out[14] <= 0;
always_ff @(posedge clk_15, negedge rstn_15) if ((rstn_15 == 0)) out[15] <= 0;
always_ff @(posedge clk_16, negedge rstn_16) if ((rstn_16 == 0)) out[16] <= 0;
always_ff @(posedge clk_17, negedge rstn_17) if ((rstn_17 == 0)) out[17] <= 0;
always_ff @(posedge clk_18, negedge rstn_18) if ((rstn_18 == 0)) out[18] <= 0;
always_ff @(posedge clk_19, negedge rstn_19) if ((rstn_19 == 0)) out[19] <= 0;
endmodule
+4 -4
View File
@@ -18,10 +18,10 @@ compile(
);
if ($Self->{vlt_all}) {
file_grep("$out_filename", qr/\<var fl="d56" loc=".*?" name="formatted" dtype_id="\d+" dir="input" vartype="string" origName="formatted" sformat="true"\/\>/i);
file_grep("$out_filename", qr/\<var fl="d77" loc=".*?" name="t.sub.in" dtype_id="\d+" vartype="int" origName="in" public="true" public_flat_rd="true"\/\>/i);
file_grep("$out_filename", qr/\<var fl="d78" loc=".*?" name="t.sub.fr_a" dtype_id="\d+" vartype="int" origName="fr_a" public="true" public_flat_rd="true" public_flat_rw="true"\/\>/i);
file_grep("$out_filename", qr/\<var fl="d79" loc=".*?" name="t.sub.fr_b" dtype_id="\d+" vartype="int" origName="fr_b" public="true" public_flat_rd="true" public_flat_rw="true"\/\>/i);
file_grep("$out_filename", qr/\<var loc="d,56,.*?" name="formatted" dtype_id="\d+" dir="input" vartype="string" origName="formatted" sformat="true"\/\>/i);
file_grep("$out_filename", qr/\<var loc="d,77,.*?" name="t.sub.in" dtype_id="\d+" vartype="int" origName="in" public="true" public_flat_rd="true"\/\>/i);
file_grep("$out_filename", qr/\<var loc="d,78,.*?" name="t.sub.fr_a" dtype_id="\d+" vartype="int" origName="fr_a" public="true" public_flat_rd="true" public_flat_rw="true"\/\>/i);
file_grep("$out_filename", qr/\<var loc="d,79,.*?" name="t.sub.fr_b" dtype_id="\d+" vartype="int" origName="fr_b" public="true" public_flat_rd="true" public_flat_rw="true"\/\>/i);
}
execute(
+4 -4
View File
@@ -20,10 +20,10 @@ compile(
);
if ($Self->{vlt_all}) {
file_grep("$out_filename", qr/\<var fl="e58" loc=".*?" name="formatted" dtype_id="\d+" dir="input" vartype="string" origName="formatted" sformat="true"\/\>/i);
file_grep("$out_filename", qr/\<var fl="e81" loc=".*?" name="t.sub.in" dtype_id="\d+" vartype="int" origName="in" public="true" public_flat_rd="true"\/\>/i);
file_grep("$out_filename", qr/\<var fl="e82" loc=".*?" name="t.sub.fr_a" dtype_id="\d+" vartype="int" origName="fr_a" public="true" public_flat_rd="true" public_flat_rw="true"\/\>/i);
file_grep("$out_filename", qr/\<var fl="e83" loc=".*?" name="t.sub.fr_b" dtype_id="\d+" vartype="int" origName="fr_b" public="true" public_flat_rd="true" public_flat_rw="true"\/\>/i);
file_grep("$out_filename", qr/\<var loc="e,58,.*?" name="formatted" dtype_id="\d+" dir="input" vartype="string" origName="formatted" sformat="true"\/\>/i);
file_grep("$out_filename", qr/\<var loc="e,81,.*?" name="t.sub.in" dtype_id="\d+" vartype="int" origName="in" public="true" public_flat_rd="true"\/\>/i);
file_grep("$out_filename", qr/\<var loc="e,82,.*?" name="t.sub.fr_a" dtype_id="\d+" vartype="int" origName="fr_a" public="true" public_flat_rd="true" public_flat_rw="true"\/\>/i);
file_grep("$out_filename", qr/\<var loc="e,83,.*?" name="t.sub.fr_b" dtype_id="\d+" vartype="int" origName="fr_b" public="true" public_flat_rd="true" public_flat_rw="true"\/\>/i);
}
execute(
+3
View File
@@ -8,6 +8,9 @@ package p3;
typedef enum logic [2:0] {
ZERO = 3'b0,
ONE = 3'b1 } e3_t /*verilator public*/;
typedef enum logic [2:0] {
TWO = 3'd2,
XES = 3'b?1? } has_x_t /*verilator public*/;
endpackage
package p62;
+1 -1
View File
@@ -1,5 +1,5 @@
%Error: t/t_force_bad_rw.v:14:20: Unsupported: Signals used via read-write reference cannot be forced
: ... In instance t.unnamedblk1.index
: ... In instance t.unnamedblk1.unnamedblk1.index
14 | foreach (ass[index]) begin
| ^~~~~
%Error: Exiting due to
+21
View File
@@ -0,0 +1,21 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2022 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(simulator => 1);
compile(
);
execute(
check_finished => 1,
);
ok(1);
1;
+28
View File
@@ -0,0 +1,28 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2022 by Pawel Jewstafjew ([email protected]).
// SPDX-License-Identifier: CC0-1.0
interface Iface (input bit [31:0] regs [1]);
initial begin
string instance_path = $sformatf("%m");
$display("Iface path %s\n", instance_path);
$write("*-* All Finished *-*\n");
$finish;
end
bit [0:0] ppp;
always_comb begin
// Ok:
//for (int index = 1 ; index < 2 ; ++index) begin
foreach (regs[index]) begin
ppp[index] = 1;
end
end
endinterface
module top (input bit [31:0] regs [1]);
Iface t1(.regs(regs));
endmodule
+4 -4
View File
@@ -18,10 +18,10 @@ compile(
);
if ($Self->{vlt_all}) {
file_grep("$out_filename", qr/\<module fl="d84" loc=".*?" name="ma" origName="ma" public="true"\>/i);
file_grep("$out_filename", qr/\<module fl="d99" loc=".*?" name="mb" origName="mb" public="true"\>/i);
file_grep("$out_filename", qr/\<module fl="d127" loc=".*?" name="mc" origName="mc" public="true"\>/i);
file_grep("$out_filename", qr/\<module fl="d127" loc=".*?" name="mc__PB1" origName="mc" public="true"\>/i);
file_grep("$out_filename", qr/\<module loc="d,84,.*?" name="ma" origName="ma" public="true"\>/i);
file_grep("$out_filename", qr/\<module loc="d,99,.*?" name="mb" origName="mb" public="true"\>/i);
file_grep("$out_filename", qr/\<module loc="d,127,.*?" name="mc" origName="mc" public="true"\>/i);
file_grep("$out_filename", qr/\<module loc="d,127,.*?" name="mc__PB1" origName="mc" public="true"\>/i);
}
execute(
+4 -4
View File
@@ -18,10 +18,10 @@ compile(
);
if ($Self->{vlt_all}) {
file_grep("$out_filename", qr/\<module fl="e84" loc=".*?" name="ma" origName="ma" public="true"\>/i);
file_grep("$out_filename", qr/\<module fl="e99" loc=".*?" name="mb" origName="mb" public="true"\>/i);
file_grep("$out_filename", qr/\<module fl="e127" loc=".*?" name="mc" origName="mc" public="true"\>/i);
file_grep("$out_filename", qr/\<module fl="e127" loc=".*?" name="mc__PB1" origName="mc" public="true"\>/i);
file_grep("$out_filename", qr/\<module loc="e,84,.*?" name="ma" origName="ma" public="true"\>/i);
file_grep("$out_filename", qr/\<module loc="e,99,.*?" name="mb" origName="mb" public="true"\>/i);
file_grep("$out_filename", qr/\<module loc="e,127,.*?" name="mc" origName="mc" public="true"\>/i);
file_grep("$out_filename", qr/\<module loc="e,127,.*?" name="mc__PB1" origName="mc" public="true"\>/i);
}
execute(
+2 -2
View File
@@ -18,8 +18,8 @@ compile(
);
if ($Self->{vlt_all}) {
file_grep("$out_filename", qr/\<instance fl="d87" loc=".*?" name="t.ma0.mb0" defName="mb" origName="mb0"\/\>/i);
file_grep("$out_filename", qr/\<module fl="d99" loc=".*?" name="mb" origName="mb"\>/i);
file_grep("$out_filename", qr/\<instance loc="d,87,.*?" name="t.ma0.mb0" defName="mb" origName="mb0"\/\>/i);
file_grep("$out_filename", qr/\<module loc="d,99,.*?" name="mb" origName="mb"\>/i);
}
execute(
+2 -2
View File
@@ -18,8 +18,8 @@ compile(
);
if ($Self->{vlt_all}) {
file_grep("$out_filename", qr/\<instance fl="e87" loc=".*?" name="t.ma0.mb0" defName="mb" origName="mb0"\/\>/i);
file_grep("$out_filename", qr/\<module fl="e99" loc=".*?" name="mb" origName="mb"\>/i);
file_grep("$out_filename", qr/\<instance loc="e,87,.*?" name="t.ma0.mb0" defName="mb" origName="mb0"\/\>/i);
file_grep("$out_filename", qr/\<module loc="e,99,.*?" name="mb" origName="mb"\>/i);
}
execute(
+7
View File
@@ -32,6 +32,13 @@ module t (clk);
$write("Hello in publicTop\n");
endtask
task test_task(input [19:0] in [2], output [19:0] out [2]);
// Issue 3316
// verilator public
out[0] = in[1];
out[1] = in[0];
endtask
endmodule
module tpub (
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(simulator => 1);
compile(
verilator_flags2 => ["--Os -x-assign 0"],
);
execute(
check_finished => 1,
);
ok(1);
1;
+55
View File
@@ -0,0 +1,55 @@
module t
(/*AUTOARG*/
// Inputs
clk
);
input clk;
int cyc = 0;
always @ (posedge clk) begin : main
cyc <= cyc + 1;
if (cyc > 100) begin
$write("*-* All Finished *-*\n");
$finish();
end
end
logic [3:0] count_d;
logic [3:0] count_q = '0;
logic [3:0] want_count_d;
logic [3:0] want_count_q = '0;
always_ff @(posedge clk) begin : flops
count_q <= count_d;
want_count_q <= want_count_d;
end
always @(posedge clk) begin : simple_check
if (cyc > 0) begin
if (count_q !== want_count_q) begin
$error("%m: cyc=%0d, count_q (%0d) !== want_count_q (%0d)",
cyc, count_q, want_count_q);
$stop; // don't finish to fail the test.
end
end
end
always_comb begin : update_golden_counts
want_count_d = want_count_q;
want_count_d += 1'b1;
end
// make sure an implicit void cast on n++ works as expected.
always_comb begin : update_counts
count_d = count_q;
count_d++;
end
endmodule
+6 -6
View File
@@ -18,12 +18,12 @@ compile(
);
if ($Self->{vlt_all}) {
file_grep("$out_filename", qr/\<module fl="e56" loc=".*?" name="l1" origName="l1"\>/i);
file_grep("$out_filename", qr/\<module fl="e62" loc=".*?" name="l2" origName="l2"\>/i);
file_grep("$out_filename", qr/\<module fl="e69" loc=".*?" name="l3" origName="l3"\>/i);
file_grep("$out_filename", qr/\<module fl="e76" loc=".*?" name="l4" origName="l4"\>/i);
file_grep("$out_filename", qr/\<module fl="e83" loc=".*?" name="l5__P2" origName="l5"\>/i);
file_grep("$out_filename", qr/\<module fl="e83" loc=".*?" name="l5__P1" origName="l5"\>/i);
file_grep("$out_filename", qr/\<module loc="e,56,.*?" name="l1" origName="l1"\>/i);
file_grep("$out_filename", qr/\<module loc="e,62,.*?" name="l2" origName="l2"\>/i);
file_grep("$out_filename", qr/\<module loc="e,69,.*?" name="l3" origName="l3"\>/i);
file_grep("$out_filename", qr/\<module loc="e,76,.*?" name="l4" origName="l4"\>/i);
file_grep("$out_filename", qr/\<module loc="e,83,.*?" name="l5__P2" origName="l5"\>/i);
file_grep("$out_filename", qr/\<module loc="e,83,.*?" name="l5__P1" origName="l5"\>/i);
}
execute(
+3 -3
View File
@@ -18,9 +18,9 @@ compile(
);
if ($Self->{vlt_all}) {
file_grep("$out_filename", qr/\<var fl="e70" loc=".*?" name="t.u.u0.u0.z1" dtype_id="\d+" vartype="logic" origName="z1"\/\>/i);
file_grep("$out_filename", qr/\<var fl="e70" loc=".*?" name="t.u.u0.u1.z1" dtype_id="\d+" vartype="logic" origName="z1"\/\>/i);
file_grep("$out_filename", qr/\<var fl="e70" loc=".*?" name="t.u.u1.u0.z0" dtype_id="\d+" vartype="logic" origName="z0"\/\>/i);
file_grep("$out_filename", qr/\<var loc="e,70,.*?" name="t.u.u0.u0.z1" dtype_id="\d+" vartype="logic" origName="z1"\/\>/i);
file_grep("$out_filename", qr/\<var loc="e,70,.*?" name="t.u.u0.u1.z1" dtype_id="\d+" vartype="logic" origName="z1"\/\>/i);
file_grep("$out_filename", qr/\<var loc="e,70,.*?" name="t.u.u1.u0.z0" dtype_id="\d+" vartype="logic" origName="z0"\/\>/i);
}
execute(
+3 -3
View File
@@ -19,9 +19,9 @@ compile(
);
if ($Self->{vlt_all}) {
file_grep("$out_filename", qr/\<var fl="e70" loc=".*?" name="u.u0.u0.z0" dtype_id="\d+" vartype="logic" origName="z0" public="true" public_flat_rd="true" public_flat_rw="true"\/\>/i);
file_grep("$out_filename", qr/\<var fl="e85" loc=".*?" name="u.u0.u0.u0.u0.z1" dtype_id="\d+" vartype="logic" origName="z1" public="true" public_flat_rd="true" public_flat_rw="true"\/\>/i);
file_grep("$out_filename", qr/\<var fl="e83" loc=".*?" name="u.u0.u1.u0.u0.z" dtype_id="\d+" vartype="logic" origName="z" public="true" public_flat_rd="true" public_flat_rw="true"\/\>/i);
file_grep("$out_filename", qr/\<var loc="e,70,.*?" name="u.u0.u0.z0" dtype_id="\d+" vartype="logic" origName="z0" public="true" public_flat_rd="true" public_flat_rw="true"\/\>/i);
file_grep("$out_filename", qr/\<var loc="e,85,.*?" name="u.u0.u0.u0.u0.z1" dtype_id="\d+" vartype="logic" origName="z1" public="true" public_flat_rd="true" public_flat_rw="true"\/\>/i);
file_grep("$out_filename", qr/\<var loc="e,83,.*?" name="u.u0.u1.u0.u0.z" dtype_id="\d+" vartype="logic" origName="z" public="true" public_flat_rd="true" public_flat_rw="true"\/\>/i);
}
execute(
File diff suppressed because it is too large Load Diff
+166 -174
View File
@@ -1,5 +1,5 @@
$date
Thu Apr 1 14:51:24 2021
Tue Feb 22 23:55:19 2022
$end
$version
@@ -11,220 +11,212 @@ $end
$scope module top $end
$scope module t $end
$var wire 1 ! clk $end
$var integer 32 " cyc $end
$scope interface intf_1 $end
$var integer 32 " cyc [31:0] $end
$scope module a $end
$scope module ac1 $end
$scope interface intf_for_check $end
$var wire 1 ! clk $end
$var wire 32 " cyc $end
$var integer 32 # value $end
$var wire 32 " cyc [31:0] $end
$var integer 32 # value [31:0] $end
$scope struct the_struct $end
$var logic 32 $ val100 $end
$var logic 32 % val200 $end
$var logic 32 $ val100 [31:0] $end
$var logic 32 % val200 [31:0] $end
$upscope $end
$upscope $end
$scope module s1 $end
$upscope $end
$scope module ac2 $end
$scope interface intf_for_check $end
$var wire 1 ! clk $end
$var wire 32 " cyc [31:0] $end
$var integer 32 & value [31:0] $end
$scope struct the_struct $end
$var logic 32 ' val100 [31:0] $end
$var logic 32 ( val200 [31:0] $end
$upscope $end
$upscope $end
$upscope $end
$scope module ac3 $end
$scope interface intf_for_check $end
$var wire 1 ! clk $end
$var wire 32 " cyc [31:0] $end
$var integer 32 ) value [31:0] $end
$scope struct the_struct $end
$var logic 32 * val100 [31:0] $end
$var logic 32 + val200 [31:0] $end
$upscope $end
$upscope $end
$upscope $end
$scope module as3 $end
$scope interface intf_for_struct $end
$var wire 1 ! clk $end
$var wire 32 " cyc $end
$var integer 32 # value $end
$var wire 32 " cyc [31:0] $end
$var integer 32 ) value [31:0] $end
$scope struct the_struct $end
$var logic 32 $ val100 $end
$var logic 32 % val200 $end
$var logic 32 * val100 [31:0] $end
$var logic 32 + val200 [31:0] $end
$upscope $end
$upscope $end
$upscope $end
$scope interface intf_in_sub_all $end
$var wire 1 ! clk $end
$var wire 32 " cyc [31:0] $end
$var integer 32 ) value [31:0] $end
$scope struct the_struct $end
$var logic 32 * val100 [31:0] $end
$var logic 32 + val200 [31:0] $end
$upscope $end
$upscope $end
$scope interface intf_one $end
$var wire 1 ! clk $end
$var wire 32 " cyc [31:0] $end
$var integer 32 # value [31:0] $end
$scope struct the_struct $end
$var logic 32 $ val100 [31:0] $end
$var logic 32 % val200 [31:0] $end
$upscope $end
$upscope $end
$scope interface intf_two $end
$var wire 1 ! clk $end
$var wire 32 " cyc [31:0] $end
$var integer 32 & value [31:0] $end
$scope struct the_struct $end
$var logic 32 ' val100 [31:0] $end
$var logic 32 ( val200 [31:0] $end
$upscope $end
$upscope $end
$upscope $end
$scope module abcdefghijklmnopqrstuvwxyz $end
$scope module ac1 $end
$scope interface intf_for_check $end
$var wire 1 ! clk $end
$var wire 32 " cyc [31:0] $end
$var integer 32 & value [31:0] $end
$scope struct the_struct $end
$var logic 32 ' val100 [31:0] $end
$var logic 32 ( val200 [31:0] $end
$upscope $end
$upscope $end
$upscope $end
$scope module ac2 $end
$scope interface intf_for_check $end
$var wire 1 ! clk $end
$var wire 32 " cyc [31:0] $end
$var integer 32 # value [31:0] $end
$scope struct the_struct $end
$var logic 32 $ val100 [31:0] $end
$var logic 32 % val200 [31:0] $end
$upscope $end
$upscope $end
$upscope $end
$scope module ac3 $end
$scope interface intf_for_check $end
$var wire 1 ! clk $end
$var wire 32 " cyc [31:0] $end
$var integer 32 , value [31:0] $end
$scope struct the_struct $end
$var logic 32 - val100 [31:0] $end
$var logic 32 . val200 [31:0] $end
$upscope $end
$upscope $end
$upscope $end
$scope module as3 $end
$scope interface intf_for_struct $end
$var wire 1 ! clk $end
$var wire 32 " cyc [31:0] $end
$var integer 32 , value [31:0] $end
$scope struct the_struct $end
$var logic 32 - val100 [31:0] $end
$var logic 32 . val200 [31:0] $end
$upscope $end
$upscope $end
$upscope $end
$scope interface intf_in_sub_all $end
$var wire 1 ! clk $end
$var wire 32 " cyc [31:0] $end
$var integer 32 , value [31:0] $end
$scope struct the_struct $end
$var logic 32 - val100 [31:0] $end
$var logic 32 . val200 [31:0] $end
$upscope $end
$upscope $end
$scope interface intf_one $end
$var wire 1 ! clk $end
$var wire 32 " cyc [31:0] $end
$var integer 32 & value [31:0] $end
$scope struct the_struct $end
$var logic 32 ' val100 [31:0] $end
$var logic 32 ( val200 [31:0] $end
$upscope $end
$upscope $end
$scope interface intf_two $end
$var wire 1 ! clk $end
$var wire 32 " cyc [31:0] $end
$var integer 32 # value [31:0] $end
$scope struct the_struct $end
$var logic 32 $ val100 [31:0] $end
$var logic 32 % val200 [31:0] $end
$upscope $end
$upscope $end
$upscope $end
$scope module c1 $end
$scope interface intf_for_check $end
$var wire 1 ! clk $end
$var wire 32 " cyc $end
$var integer 32 # value $end
$var wire 32 " cyc [31:0] $end
$var integer 32 # value [31:0] $end
$scope struct the_struct $end
$var logic 32 $ val100 $end
$var logic 32 % val200 $end
$upscope $end
$upscope $end
$upscope $end
$scope module a $end
$scope interface intf_one $end
$var wire 1 ! clk $end
$var wire 32 " cyc $end
$var integer 32 # value $end
$scope struct the_struct $end
$var logic 32 $ val100 $end
$var logic 32 % val200 $end
$upscope $end
$upscope $end
$scope module ac1 $end
$scope interface intf_for_check $end
$var wire 1 ! clk $end
$var wire 32 " cyc $end
$var integer 32 # value $end
$scope struct the_struct $end
$var logic 32 $ val100 $end
$var logic 32 % val200 $end
$upscope $end
$upscope $end
$upscope $end
$upscope $end
$scope module abcdefghijklmnopqrstuvwxyz $end
$scope interface intf_two $end
$var wire 1 ! clk $end
$var wire 32 " cyc $end
$var integer 32 # value $end
$scope struct the_struct $end
$var logic 32 $ val100 $end
$var logic 32 % val200 $end
$upscope $end
$upscope $end
$scope module ac2 $end
$scope interface intf_for_check $end
$var wire 1 ! clk $end
$var wire 32 " cyc $end
$var integer 32 # value $end
$scope struct the_struct $end
$var logic 32 $ val100 $end
$var logic 32 % val200 $end
$upscope $end
$upscope $end
$upscope $end
$upscope $end
$scope interface intf_2 $end
$var wire 1 ! clk $end
$var wire 32 " cyc $end
$var integer 32 & value $end
$scope struct the_struct $end
$var logic 32 ' val100 $end
$var logic 32 ( val200 $end
$upscope $end
$upscope $end
$scope module s2 $end
$scope interface intf_for_struct $end
$var wire 1 ! clk $end
$var wire 32 " cyc $end
$var integer 32 & value $end
$scope struct the_struct $end
$var logic 32 ' val100 $end
$var logic 32 ( val200 $end
$var logic 32 $ val100 [31:0] $end
$var logic 32 % val200 [31:0] $end
$upscope $end
$upscope $end
$upscope $end
$scope module c2 $end
$scope interface intf_for_check $end
$var wire 1 ! clk $end
$var wire 32 " cyc $end
$var integer 32 & value $end
$var wire 32 " cyc [31:0] $end
$var integer 32 & value [31:0] $end
$scope struct the_struct $end
$var logic 32 ' val100 $end
$var logic 32 ( val200 $end
$var logic 32 ' val100 [31:0] $end
$var logic 32 ( val200 [31:0] $end
$upscope $end
$upscope $end
$upscope $end
$scope module a $end
$scope interface intf_two $end
$scope interface intf_1 $end
$var wire 1 ! clk $end
$var wire 32 " cyc $end
$var integer 32 & value $end
$var wire 32 " cyc [31:0] $end
$var integer 32 # value [31:0] $end
$scope struct the_struct $end
$var logic 32 ' val100 $end
$var logic 32 ( val200 $end
$var logic 32 $ val100 [31:0] $end
$var logic 32 % val200 [31:0] $end
$upscope $end
$upscope $end
$scope module ac2 $end
$scope interface intf_for_check $end
$scope interface intf_2 $end
$var wire 1 ! clk $end
$var wire 32 " cyc $end
$var integer 32 & value $end
$var wire 32 " cyc [31:0] $end
$var integer 32 & value [31:0] $end
$scope struct the_struct $end
$var logic 32 ' val100 $end
$var logic 32 ( val200 $end
$var logic 32 ' val100 [31:0] $end
$var logic 32 ( val200 [31:0] $end
$upscope $end
$upscope $end
$upscope $end
$upscope $end
$scope module abcdefghijklmnopqrstuvwxyz $end
$scope interface intf_one $end
$var wire 1 ! clk $end
$var wire 32 " cyc $end
$var integer 32 & value $end
$scope struct the_struct $end
$var logic 32 ' val100 $end
$var logic 32 ( val200 $end
$upscope $end
$upscope $end
$scope module ac1 $end
$scope interface intf_for_check $end
$var wire 1 ! clk $end
$var wire 32 " cyc $end
$var integer 32 & value $end
$scope struct the_struct $end
$var logic 32 ' val100 $end
$var logic 32 ( val200 $end
$upscope $end
$upscope $end
$upscope $end
$upscope $end
$scope module a $end
$scope interface intf_in_sub_all $end
$var wire 1 ! clk $end
$var wire 32 " cyc $end
$var integer 32 ) value $end
$scope struct the_struct $end
$var logic 32 * val100 $end
$var logic 32 + val200 $end
$upscope $end
$upscope $end
$scope module as3 $end
$scope module s1 $end
$scope interface intf_for_struct $end
$var wire 1 ! clk $end
$var wire 32 " cyc $end
$var integer 32 ) value $end
$var wire 32 " cyc [31:0] $end
$var integer 32 # value [31:0] $end
$scope struct the_struct $end
$var logic 32 * val100 $end
$var logic 32 + val200 $end
$var logic 32 $ val100 [31:0] $end
$var logic 32 % val200 [31:0] $end
$upscope $end
$upscope $end
$upscope $end
$scope module ac3 $end
$scope interface intf_for_check $end
$var wire 1 ! clk $end
$var wire 32 " cyc $end
$var integer 32 ) value $end
$scope struct the_struct $end
$var logic 32 * val100 $end
$var logic 32 + val200 $end
$upscope $end
$upscope $end
$upscope $end
$upscope $end
$scope module abcdefghijklmnopqrstuvwxyz $end
$scope interface intf_in_sub_all $end
$var wire 1 ! clk $end
$var wire 32 " cyc $end
$var integer 32 , value $end
$scope struct the_struct $end
$var logic 32 - val100 $end
$var logic 32 . val200 $end
$upscope $end
$upscope $end
$scope module as3 $end
$scope module s2 $end
$scope interface intf_for_struct $end
$var wire 1 ! clk $end
$var wire 32 " cyc $end
$var integer 32 , value $end
$var wire 32 " cyc [31:0] $end
$var integer 32 & value [31:0] $end
$scope struct the_struct $end
$var logic 32 - val100 $end
$var logic 32 . val200 $end
$upscope $end
$upscope $end
$upscope $end
$scope module ac3 $end
$scope interface intf_for_check $end
$var wire 1 ! clk $end
$var wire 32 " cyc $end
$var integer 32 , value $end
$scope struct the_struct $end
$var logic 32 - val100 $end
$var logic 32 . val200 $end
$upscope $end
$var logic 32 ' val100 [31:0] $end
$var logic 32 ( val200 [31:0] $end
$upscope $end
$upscope $end
$upscope $end
+2 -2
View File
@@ -1,11 +1,11 @@
%Warning-UNUSED: t/t_lint_once_bad.v:19:14: Signal is not driven, nor used: 'unus1'
: ... In instance t.sub3
: ... In instance t.sub1
19 | reg [A:0] unus1; reg [A:0] unus2;
| ^~~~~
... For warning description see https://verilator.org/warn/UNUSED?v=latest
... Use "/* verilator lint_off UNUSED */" and lint_on around source to disable this message.
%Warning-UNUSED: t/t_lint_once_bad.v:19:34: Signal is not driven, nor used: 'unus2'
: ... In instance t.sub3
: ... In instance t.sub1
19 | reg [A:0] unus1; reg [A:0] unus2;
| ^~~~~
%Error: Exiting due to
+1 -1
View File
@@ -1,5 +1,5 @@
%Warning-WIDTH: t/t_lint_repeat_bad.v:18:17: Operator ASSIGNW expects 1 bits on the Assign RHS, but Assign RHS's VARREF 'a' generates 2 bits.
: ... In instance t.sub2
: ... In instance t.sub3
18 | wire [0:0] b = a;
| ^
... For warning description see https://verilator.org/warn/WIDTH?v=latest

Some files were not shown because too many files have changed in this diff Show More