diff --git a/.travis.yml b/.travis.yml
index 71442d049..dd59d6f58 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -25,7 +25,8 @@ cache:
before_install:
# Perl modules needed for testing
- - yes yes | sudo cpan -fi Unix::Processors Parallel::Forker Bit::Vector
+# Not listing Bit::Vector as slow to install, and only skips one test
+ - yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
- sudo apt-get install gdb gtkwave
- sudo apt-get install libgoogle-perftools-dev
before_script:
@@ -58,9 +59,14 @@ jobs:
script: ci/test.sh vlt
- if: type != cron
stage: test
- name: Vltmt test
+ name: Vltmt set 0 test
compiler: gcc
- script: ci/test.sh vltmt
+ script: ci/test.sh vltmt0
+ - if: type != cron
+ stage: test
+ name: Vltmt set 1 test
+ compiler: gcc
+ script: ci/test.sh vltmt1
# Cron builds try different OS/compiler combinations
- if: type = cron
stage: "Build Verilator"
diff --git a/Changes b/Changes
index 647c2dbf9..a83afa729 100644
--- a/Changes
+++ b/Changes
@@ -3,6 +3,29 @@ Revision history for Verilator
The contributors that suggested a given feature are shown in []. Thanks!
+* Verilator 4.030 2020-03-08
+
+** Add split_var metacomment to assist UNOPTFLAT fixes, #2066. [Yutetsu TAKATSUKASA]
+
+** Add support for $dumpfile and $dumpvars, #2126. [Alexander Grobman]
+
+** Add support for dynamic arrays, #379.
+
+*** Add +verilator+noassert flag to disable assertion checking. [Tobias Wölfel]
+
+*** Add check for assertOn for asserts, #2162. [Tobias Wölfel]
+
+*** Add --structs-packed for forward compatibility.
+
+*** Fix genblk naming with directly nested generate blocks, #2176. [Alexander Grobman]
+
+**** Implement $displayb/o/h, $writeb/o/h, etc, #1637.
+
+**** Use gcc -Os in examples instead of -O2 for better average performance.
+
+**** Fix undeclared VL_SHIFTR_WWQ, #2114. [Alex Solomatnikov]
+
+
* Verilator 4.028 2020-02-08
** Support attributes (public, isolate_assignments, etc.) in configuration files.
@@ -45,6 +68,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
**** Fix OpenSolaris issues, #2154. [brancoliticus]
+**** Fix gated clocks under --protect-lib, #2169. [Todd Strader]
+
* Verilator 4.026 2020-01-11
diff --git a/Makefile.in b/Makefile.in
index d79d0b2ff..6f7441743 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -208,12 +208,6 @@ EXAMPLES_FIRST = \
EXAMPLES = $(EXAMPLES_FIRST) $(filter-out $(EXAMPLES_FIRST), $(sort $(wildcard examples/*)))
-ifeq ($(OBJCACHE_JOBS),)
-ifneq ($(OBJCACHE_HOSTS),)
-export OBJCACHE_JOBS := -j $(shell objcache --jobs "$(OBJCACHE_HOSTS)")
-endif
-endif
-
# See uninstall also - don't put wildcards in this variable, it might uninstall other stuff
VL_INST_MAN_FILES = verilator.1 verilator_coverage.1 verilator_gantt.1 verilator_profcfunc.1
diff --git a/README.adoc b/README.adoc
index 395302e64..3e2eb528b 100644
--- a/README.adoc
+++ b/README.adoc
@@ -25,7 +25,7 @@ endif::[]
^.^| *Welcome to Verilator, the fastest free Verilog HDL simulator.*
+++
+++ • Accepts synthesizable Verilog or SystemVerilog
+++
+++ • Performs lint code-quality checks
-+++
+++ • Compiles into multithreaded {cpp}, SystemC, or (soon) {cpp}-under-Python
++++
+++ • Compiles into multithreaded {cpp}, or SystemC
+++
+++ • Creates XML to front-end your own tools
<.^|image:https://www.veripool.org/img/verilator_256_200_min.png[Logo,256,200]
@@ -81,7 +81,7 @@ touch of {cpp} code, Verilator is the tool for you.
Verilator does not simply convert Verilog HDL to {cpp} or SystemC. Rather
than only translate, Verilator compiles your code into a much faster
optimized and optionally thread-partitioned model, which is in turn wrapped
-inside a {cpp}/SystemC/Python module. The results are a compiled Verilog
+inside a {cpp}/SystemC/{cpp}-under-Python module. The results are a compiled Verilog
model that executes even on a single-thread over 10x faster than standalone
SystemC, and on a single thread is about 100 times faster than interpreted
Verilog simulators such as http://iverilog.icarus.com[Icarus
diff --git a/bin/verilator b/bin/verilator
index ab3061e22..b321db9e7 100755
--- a/bin/verilator
+++ b/bin/verilator
@@ -421,6 +421,7 @@ more information.
+verilator+prof+threads+window+I Set profile duration
+verilator+rand+reset+I Set random reset technique
+verilator+seed+I Set random seed
+ +verilator+noassert Disable assert checking
+verilator+V Verbose version and config
+verilator+version Show version and exit
@@ -1343,6 +1344,13 @@ Creates more detailed statistics, including a list of all the variables by
size (plain --stats just gives a count). See --stats, which is implied by
this.
+=item --structs-packed
+
+Converts all unpacked structures to packed structures and issues a UNPACKED
+warning. Currently this is the default and --no-structs-packed will not
+work. Specifying this option allows for forward compatibility when a
+future version of Verilator no longer always packs unpacked structures.
+
=item -sv
Specifies SystemVerilog language features should be enabled; equivalent to
@@ -1773,6 +1781,11 @@ For $random and "-x-initial unique", set the simulation runtime random seed
value. If zero or not specified picks a value from the system random
number generator.
+=item +verilator+noassert
+
+Disable assert checking per runtime argument. This is the same as calling
+"Verilated::assertOn(false)" in the model.
+
=item +verilator+V
Shows the verbose version, including configuration information.
@@ -1900,13 +1913,13 @@ Now we run Verilator on our little example.
We then can compile it
- cd obj_dir
- make -j -f Vour.mk Vour__ALL.a
- make -j -f Vour.mk ../sc_main.o verilated.o
+ make -j -C obj_dir -f Vour.mk Vour__ALL.a
+ make -j -C obj_dir -f Vour.mk ../sc_main.o verilated.o
And link with SystemC. Note your path to the libraries may vary,
depending on the operating system.
+ cd obj_dir
export SYSTEMC_LIBDIR=/path/to/where/libsystemc.a/exists
export LD_LIBRARY_PATH=$SYSTEMC_LIBDIR:$LD_LIBRARY_PATH
# Might be needed if SystemC 2.3.0
@@ -1930,6 +1943,39 @@ when your source changes it will automatically run all of these steps. See
the examples directory in the distribution.
+=head1 EVALUATION LOOP
+
+When using SystemC, when Verilator is evaluated is managed by the SystemC
+kernel, and for the most part can be ignored. When using C++, the user
+must call eval(), or eval_step() and eval_end_step().
+
+1. When there is a single design instantiated at the C++ level that need to
+evaluate, just call designp->eval().
+
+2. When there are multiple designs instantiated each at the C++ level that
+need to evaluate, call first_designp->eval_step() then ->eval_step() on all
+other designs. Then call ->eval_end_step() on the first design then all
+other designs. If there is only a single design, you would call
+eval_step() then eval_end_step(); in fact eval() described above is just a
+wrapper which calls these two functions.
+
+When eval() is called Verilator looks for changes in clock signals and
+evaluates related sequential always blocks, such as computing always_ff @
+(posedge...) outputs. Then Verilator evaluates combinatorial logic.
+
+Note combinatorial logic is not computed before sequential always blocks
+are computed (for speed reasons). Therefore it is best to set any non-clock
+inputs up with a separate eval() call before changing clocks().
+
+Alternatively, if all always_ff statements use only the posedge of clocks,
+or all inputs go directly to always_ff statements, as is typical, then you
+can change non-clock inputs on the negative edge of the input clock, which
+will be faster as there will be fewer eval() calls.
+
+For more information on evaluation, see docs/internals.adoc in the
+distribution.
+
+
=head1 BENCHMARKING & OPTIMIZATION
For best performance, run Verilator with the "-O3 --x-assign fast
@@ -1958,27 +2004,27 @@ OPT, OPT_FAST, or OPT_SLOW lib/verilated.mk. Or, use the -CFLAGS and/or
the compiler or linker. Or, just for one run, pass them on the command
line to make:
- make OPT_FAST="-O2 -fno-stack-protector" -f Vour.mk Vour__ALL.a
+ make OPT_FAST="-Os -fno-stack-protector" -f Vour.mk Vour__ALL.a
OPT_FAST specifies optimizations for those programs that are part of the
fast path, mostly code that is executed every cycle. OPT_SLOW specifies
optimizations for slow-path files (plus tracing), which execute only
rarely, yet take a long time to compile with optimization on. OPT
specifies overall optimization and affects all compiles, including those
-OPT_FAST and OPT_SLOW control. For best results, use OPT="-O2", and link
+OPT_FAST and OPT_SLOW control. For best results, use OPT="-Os", and link
with "-static". Nearly the same results can be had with much better
compile times with OPT_FAST="-O1 -fstrict-aliasing". Higher optimization
-such as "-O3" may help, but gcc compile times may be excessive under O3 on
-even medium sized designs. Alternatively, some larger designs report
-better performance using "-Os".
+such as "-O2" or "-O3" may help, but gcc compile times may be excessive
+under O3 on even medium sized designs.
Unfortunately, using the optimizer with SystemC files can result in
compiles taking several minutes. (The SystemC libraries have many little
inlined functions that drive the compiler nuts.)
-For best results, use GCC 3.3 or newer. GCC 3.2 and earlier have
-optimization bugs around pointer aliasing detection, which can result in 2x
-performance losses.
+For best results, use the latest clang compiler (about 10% faster than
+GCC). Note the now fairly old GCC 3.2 and earlier have optimization bugs
+around pointer aliasing detection, which can result in 2x performance
+losses.
If you will be running many simulations on a single compile, investigate
feedback driven compilation. With GCC, using -fprofile-arcs, then
@@ -1989,6 +2035,9 @@ especially if you link in DPI code. To enable LTO on GCC, pass "-flto" in
both compilation and link. Note LTO may cause excessive compile times on
large designs.
+Using profile driven compiler optimization, with feedback from a real
+design, can yield up to30% improvements.
+
If you are using your own makefiles, you may want to compile the Verilated
code with -DVL_INLINE_OPT=inline. This will inline functions, however this
requires that all cpp files be compiled in a single compiler run.
@@ -1999,7 +2048,7 @@ either oprofile or gprof to see where in the C++ code the time is spent.
Run the gprof output through verilator_profcfunc and it will tell you what
Verilog line numbers on which most of the time is being spent.
-When done, please let the author know the results. I like to keep tabs on
+When done, please let the author know the results. We like to keep tabs on
how Verilator compares, and may be able to suggest additional improvements.
@@ -2074,7 +2123,7 @@ After running Make, the C++ compiler may produce the following:
A generic Linux/OS variable specifying what directories have shared object
(.so) files. This path should include SystemC and any other shared objects
-needed at simultion runtime.
+needed at simulation runtime.
=item OBJCACHE
@@ -2203,7 +2252,7 @@ example:
Note signals are read and written as member variables of the lower module.
You call the eval() method to evaluate the model. When the simulation is
complete call the final() method to wrap up any SystemVerilog final blocks,
-and complete any assertions.
+and complete any assertions. See L"EVALUATION LOOP">.
=head1 CONNECTING TO SYSTEMC
@@ -3411,6 +3460,33 @@ behavior. See the test_regress/t/t_dpi_display.v file for an example.
Same as C in configuration files, see L"CONFIGURATION FILES">
for more information.
+=item /*verilator split_var*/
+
+Attached to a variable or a net declaration to break the variable into
+multiple pieces typically to resolve UNOPTFLAT performance issues.
+Typically the variables to attach this to are recommeded by Verilator
+itself, see UNOPTFLAT below.
+
+For example, Verilator will internally convert a variable with the
+metacomment such as:
+
+ logic [7:0] x [0:1] /*verilator split_var*/;
+
+To:
+
+ logic [7:0] x__BRA__0__KET__ /*verilator split_var*/;
+ logic [7:0] x__BRA__1__KET__ /*verilator split_var*/;
+
+Note that the generated packed variables retain the split_var metacomment
+because they may be split into further smaller pieces accorting to the
+access patterns.
+
+This only supports unpacked arrays, packed arrays, and packed structs of
+integer types (reg, logic, bit, byte, int...); otherwise if a split was
+requested but cannot occur a SPLITVAR warning is issued. Splitting large
+arrays may slow donw the Verilation speed, so use this only on variables
+that require it.
+
=item /*verilator tag */
Attached after a variable or structure member to indicate opaque (to
@@ -3746,17 +3822,29 @@ $unsigned, $warning.
Generally supported.
-=item $display, $write, $fdisplay, $fwrite, $swrite
-
-$display and friends must have a constant format string as the first
-argument (as with C's printf). The rare usage which lists variables
-standalone without a format is not supported.
-
=item $displayb, $displayh, $displayo, $writeb, $writeh, $writeo, etc
The sized display functions are rarely used and so not supported. Replace
them with a $write with the appropriate format specifier.
+=item $dump/$dumpports and related
+
+$dumpfile or $dumpports will create a VCD or FST file (which is based on
+the --trace argument given when the model was Verilated). This will take
+effect starting at the next eval() call. If you have multiple Verilated
+designs under the same C model, then this will dump signals only from the
+design containing the $dumpvar.
+
+$dumpvars and $dumpports module identifier is ignored; the traced instances
+will always start at the top of the design. The levels argument is also
+ignored, use tracing_on/tracing_off pragmas instead.
+
+$dumpportson/$dumpportsoff/$dumpportsall/$dumpportslimit filename argument
+is ignored, only a single trace file may be active at once.
+
+$dumpall/$dumpportsall, $dumpon/$dumpportson, $dumpoff/$dumpportsoff, and
+$dumplimit/$dumpportlimit are currently ignored.
+
=item $finish, $stop
The rarely used optional parameter to $finish and $stop is ignored.
@@ -4374,6 +4462,29 @@ Ignoring this warning may make Verilator simulations differ from other
simulators, if the increased precision of real affects your model or DPI
calls.
+=item SPLITVAR
+
+Warns that a variable with a C metacomment was not split.
+Some possible reasons for this are:
+
+* The datatype of the variable is not supported for splitting. (e.g. is a
+real).
+
+* The access pattern of the variable can not be determined
+statically. (e.g. is accessed as a memory).
+
+* The index of the array exceeds the array size.
+
+* The variable is accessed from outside using dotted reference.
+(e.g. top.instance0.variable0 = 1).
+
+* The variable is not declared in a module, but in a package or an
+interface.
+
+* The variable is a parameter, localparam, genvar, or queue.
+
+* The variable is tirstate or bidirectional. (e.g. inout or ref).
+
=item STMTDLY
Warns that you have a statement with a delayed time in front of it, for
@@ -4505,6 +4616,11 @@ being generated from an always statement that consumed high bits of the
same bus processed by another series of always blocks. The fix is the
same; split it into two separate signals generated from each block.
+Another way to resolve this warning is to add a C metacomment
+described above. This will cause the variable to be split internally,
+potentially resolving the conflict. If you run with --report-unoptflat
+Verilator will suggest possible candidates for C.
+
The UNOPTFLAT warning may also be due to clock enables, identified from the
reported path going through a clock gating cell. To fix these, use the
clock_enable meta comment described above.
@@ -4771,19 +4887,20 @@ designs have topped 16GB.
See the next question for tracing in SystemC mode.
-Add the --trace switch to Verilator, and in your top level C code, call
-Verilated::traceEverOn(true). Then create a VerilatedVcdC object, and
-in your main loop call "trace_object->dump(time)" every time step, and
-finally call "trace_object->close()". For an example, see below and the
-examples/make_tracing_c/sim_main.cpp file of the distribution.
+A. Add the --trace switch to Verilator, and in your top level C code, call
+Verilated::traceEverOn(true). Then you may use $dumpfile and $dumpvars to
+enable traces, same as with any Verilog simulator. See
+C.
-You also need to compile verilated_vcd_c.cpp and add it to your link,
-preferably by adding the dependencies in $(VK_GLOBAL_OBJS) to your
-Makefile's link rule. This is done for you if using the Verilator --exe
-flag.
-
-Note you can also call ->trace on multiple Verilated objects with the same
-trace file if you want all data to land in the same output file.
+B. Or, for finer-grained control, or C++ files with multiple Verilated
+modules you may also create the trace purely from C++. Create a
+VerilatedVcdC object, and in your main loop call "trace_object->dump(time)"
+every time step, and finally call "trace_object->close()". You also need
+to compile verilated_vcd_c.cpp and add it to your link, preferably by
+adding the dependencies in $(VK_GLOBAL_OBJS) to your Makefile's link rule.
+This is done for you if using the Verilator --exe flag. Note you can also
+call ->trace on multiple Verilated objects with the same trace file if you
+want all data to land in the same output file.
#include "verilated_vcd_c.h"
...
@@ -4803,11 +4920,17 @@ trace file if you want all data to land in the same output file.
=item How do I generate waveforms (traces) in SystemC?
-Add the --trace switch to Verilator, and in your top level C sc_main code,
-include verilated_vcd_sc.h. Then call Verilated::traceEverOn(true). Then
-create a VerilatedVcdSc object as you would create a normal SystemC trace
-file. For an example, see the call to VerilatedVcdSc in the
-examples/make_tracing_sc/sc_main.cpp file of the distribution, and below.
+A. Add the --trace switch to Verilator, and in your top level sc_main, call
+Verilated::traceEverOn(true). Then you may use $dumpfile and $dumpvars to
+enable traces, same as with any Verilog simulator, see the non-SystemC
+example in C. This will trace only the module
+containing the $dumpvar.
+
+B. Or, you may create a trace purely from SystemC, which may trace all
+Verilated designs in the SystemC model. Create a VerilatedVcdSc object as
+you would create a normal SystemC trace file. For an example, see the call
+to VerilatedVcdSc in the examples/make_tracing_sc/sc_main.cpp file of the
+distribution, and below.
Alternatively you may use the C++ trace mechanism described in the previous
question, however the timescale and timeprecision will not inherited from
@@ -4837,23 +4960,23 @@ trace file if you want all data to land in the same output file.
=item How do I generate FST waveforms (traces) in C++?
-FST a format by GTKWave.
-This version provides a basic FST support.
-To dump FST format, add the --trace-fst switch to Verilator and change the include
-path in the testbench to:
+FST a format by GTKWave. This version provides a basic FST support. To
+dump FST format, add the --trace-fst switch to Verilator and either A. use
+$dumpfile/$dumpvars in Verilog as described in the VCD example above, or
+B. in C++ change the include described in the VCD example above:
#include "verilated_fst_c.h"
VerilatedFstC* tfp = new VerilatedFstC;
-Note that currently supporting both FST and VCD in a single simulation is impossible,
-but such requirement could be rare.
+Note that currently supporting both FST and VCD in a single simulation is
+impossible, but such requirement should be rare.
-=item How do I generate FST waveforms (traces) in SystemC?
+=item How do I generate FST waveforms (aka dumps or traces) in SystemC?
The FST library from GTKWave does not currently support SystemC; use VCD
format instead.
-=item How do I view waveforms (traces)?
+=item How do I view waveforms (aka dumps or traces)?
Verilator makes standard VCD (Value Change Dump) and FST files. VCD files are viewable
with the public domain GTKWave (recommended) or Dinotrace (legacy)
@@ -5241,6 +5364,10 @@ redistribute it and/or modify the Verilator internals under the terms of
either the GNU Lesser General Public License Version 3 or the Perl Artistic
License Version 2.0.
+All Verilog and C++/SystemC code quoted within this documentation file are
+released into the Public Domain. Many example files and test files are
+likewise released into the Public Domain as described in the files
+themselves.
=head1 SEE ALSO
@@ -5248,7 +5375,7 @@ L, L, L, L,
L which is the source for this document,
-and internals.txt in the distribution.
+and docs/internals.adoc in the distribution.
=cut
diff --git a/bin/verilator_gantt b/bin/verilator_gantt
index 252b98c9a..574d01567 100755
--- a/bin/verilator_gantt
+++ b/bin/verilator_gantt
@@ -123,13 +123,13 @@ sub report {
}
my $nthreads = scalar keys %Threads;
- $Global{cpus}{cpu_time} = {};
+ $Global{cpus} = {};
foreach my $thread (keys %Threads) {
# Make potentially multiple characters per column
foreach my $start (keys %{$Threads{$thread}}) {
my $cpu = $Threads{$thread}{$start}{cpu};
my $elapsed = $Threads{$thread}{$start}{end} - $start;
- $Global{cpus}{cpu_time}{$cpu} += $elapsed;
+ $Global{cpus}{$cpu}{cpu_time} += $elapsed;
}
}
diff --git a/ci/test.sh b/ci/test.sh
index 6b72bc5cb..361a198d7 100755
--- a/ci/test.sh
+++ b/ci/test.sh
@@ -19,6 +19,12 @@ case $1 in
vltmt)
make -C test_regress SCENARIOS=--vltmt
;;
+ vltmt0)
+ make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2
+ ;;
+ vltmt1)
+ make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2
+ ;;
*)
echo "Usage: test.sh (dist|vlt|vltmt)"
exit -1
diff --git a/configure.ac b/configure.ac
index 69591d834..c3d87cbd1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -6,7 +6,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
-AC_INIT([Verilator],[4.028 2020-02-06],
+AC_INIT([Verilator],[4.030 2020-03-08],
[https://verilator.org],
[verilator],[https://verilator.org])
# When releasing, also update header of Changes file
diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS
index 34ac03ccf..8c6c42276 100644
--- a/docs/CONTRIBUTORS
+++ b/docs/CONTRIBUTORS
@@ -33,7 +33,9 @@ Richard Myers
Sebastien Van Cauwenberghe
Stefan Wallentowitz
Tobias Rosenkranz
+Tobias Wölfel
Todd Strader
Wilson Snyder
Yutetsu TAKATSUKASA
Yves Mathieu
+David Stanford
diff --git a/docs/install.adoc b/docs/install.adoc
index d71f8d6e8..09a74c516 100644
--- a/docs/install.adoc
+++ b/docs/install.adoc
@@ -98,9 +98,11 @@ Additionally, to build or run Verilator you need these standard packages:
Those developing Verilator may also want these (see internals.adoc):
- sudo apt-get install gdb asciidoctor graphviz
+ sudo apt-get install gdb asciidoctor graphviz cmake
cpan install Pod::Perldoc
cpan install Unix::Processors
+ cpan install Parallel::Forker
+ cpan install Bit::Vector
==== Install SystemC
diff --git a/docs/internals.adoc b/docs/internals.adoc
index a7e155200..55d5e407a 100644
--- a/docs/internals.adoc
+++ b/docs/internals.adoc
@@ -625,13 +625,17 @@ with e.g. "sudo cpan install Parallel::Forker".
* vcddiff to find differences in VCD outputs. See the readme at
https://github.com/veripool/vcddiff
+* Cmake for build paths that use it.
+
+* Bit::Vector to test vgen.pl
+
=== Controlling the Test Driver
Test drivers are written in PERL. All invoke the main test driver script,
which can provide detailed help on all the features available when writing
a test driver.
- test_regress/t/driver.pl --help
+ test_regress/driver.pl --help
For convenience, a summary of the most commonly used features is provided
here. All drivers require a call to `compile` subroutine to compile the
@@ -716,6 +720,13 @@ respectively 16,384 and 4,096. The method of doing this is system
dependent, but on Fedora Linux it would require editing the
`/etc/security/limits.conf` file as root.
+=== Manual Test Execution
+
+A specific regression test can be executed manually. To start the "EXAMPLE"
+test, run the following command.
+
+ test_regress/t/t_EXAMPLE.pl
+
=== Continuous Integration
Verilator has a https://travis-ci.com/verilator/verilator[Travis CI environment]
diff --git a/examples/cmake_tracing_c/CMakeLists.txt b/examples/cmake_tracing_c/CMakeLists.txt
index ab5236b3c..d26932609 100644
--- a/examples/cmake_tracing_c/CMakeLists.txt
+++ b/examples/cmake_tracing_c/CMakeLists.txt
@@ -34,5 +34,5 @@ add_executable(example ../make_tracing_c/sim_main.cpp)
# Add the Verilated circuit to the target
verilate(example COVERAGE TRACE
INCLUDE_DIRS "../make_tracing_c"
- VERILATOR_ARGS -f ../make_tracing_c/input.vc -O2 -x-assign 0
+ VERILATOR_ARGS -f ../make_tracing_c/input.vc -Os -x-assign 0
SOURCES ../make_tracing_c/top.v)
diff --git a/examples/cmake_tracing_sc/CMakeLists.txt b/examples/cmake_tracing_sc/CMakeLists.txt
index f2490eb6c..20a55c06e 100644
--- a/examples/cmake_tracing_sc/CMakeLists.txt
+++ b/examples/cmake_tracing_sc/CMakeLists.txt
@@ -41,7 +41,7 @@ add_executable(example ../make_tracing_sc/sc_main.cpp)
# Add the Verilated circuit to the target
verilate(example SYSTEMC COVERAGE TRACE
INCLUDE_DIRS "../make_tracing_sc"
- VERILATOR_ARGS -f ../make_tracing_sc/input.vc -O2 -x-assign 0
+ VERILATOR_ARGS -f ../make_tracing_sc/input.vc -Os -x-assign 0
SOURCES ../make_tracing_sc/top.v)
verilator_link_systemc(example)
diff --git a/examples/make_protect_lib/Makefile b/examples/make_protect_lib/Makefile
index 0f9f2e1a3..b2e33a283 100644
--- a/examples/make_protect_lib/Makefile
+++ b/examples/make_protect_lib/Makefile
@@ -34,7 +34,7 @@ VERILATOR_FLAGS =
# Generate C++
VERILATOR_FLAGS += -cc
# Optimize
-VERILATOR_FLAGS += -O2 -x-assign 0
+VERILATOR_FLAGS += -Os -x-assign 0
# Warn abount lint issues; may not want this on less solid designs
VERILATOR_FLAGS += -Wall
# Make waveforms
diff --git a/examples/make_tracing_c/Makefile b/examples/make_tracing_c/Makefile
index f5a3b497e..a6acdc445 100644
--- a/examples/make_tracing_c/Makefile
+++ b/examples/make_tracing_c/Makefile
@@ -38,7 +38,7 @@ VERILATOR_FLAGS += -cc --exe
# Generate makefile dependencies (not shown as complicates the Makefile)
#VERILATOR_FLAGS += -MMD
# Optimize
-VERILATOR_FLAGS += -O2 -x-assign 0
+VERILATOR_FLAGS += -Os -x-assign 0
# Warn abount lint issues; may not want this on less solid designs
VERILATOR_FLAGS += -Wall
# Make waveforms
diff --git a/examples/make_tracing_c/Makefile_obj b/examples/make_tracing_c/Makefile_obj
index c3eb5291d..6d07eb427 100644
--- a/examples/make_tracing_c/Makefile_obj
+++ b/examples/make_tracing_c/Makefile_obj
@@ -38,7 +38,7 @@ endif
# SystemC takes minutes to optimize, thus it is off by default.
OPT_SLOW =
# Fast path optimizations. Most time is spent in these classes.
-OPT_FAST = -O2 -fstrict-aliasing
+OPT_FAST = -Os -fstrict-aliasing
#OPT_FAST = -O
#OPT_FAST =
diff --git a/examples/make_tracing_c/sim_main.cpp b/examples/make_tracing_c/sim_main.cpp
index c8003611e..527ff105b 100644
--- a/examples/make_tracing_c/sim_main.cpp
+++ b/examples/make_tracing_c/sim_main.cpp
@@ -10,11 +10,6 @@
// Include model header, generated from Verilating "top.v"
#include "Vtop.h"
-// If "verilator --trace" is used, include the tracing class
-#if VM_TRACE
-# include
-#endif
-
// Current simulation time (64-bit unsigned)
vluint64_t main_time = 0;
// Called by $time in Verilog
@@ -36,31 +31,21 @@ int main(int argc, char** argv, char** env) {
// May be overridden by commandArgs
Verilated::randReset(2);
+ // Verilator must compute traced signals
+ Verilated::traceEverOn(true);
+
// Pass arguments so Verilated code can see them, e.g. $value$plusargs
// This needs to be called before you create any model
Verilated::commandArgs(argc, argv);
+ // Create logs/ directory in case we have traces to put under it
+ Verilated::mkdir("logs");
+
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
Vtop* top = new Vtop; // Or use a const unique_ptr, or the VL_UNIQUE_PTR wrapper
-#if VM_TRACE
- // If verilator was invoked with --trace argument,
- // and if at run time passed the +trace argument, turn on tracing
- VerilatedVcdC* tfp = NULL;
- const char* flag = Verilated::commandArgsPlusMatch("trace");
- if (flag && 0==strcmp(flag, "+trace")) {
- Verilated::traceEverOn(true); // Verilator must compute traced signals
- VL_PRINTF("Enabling waves into logs/vlt_dump.vcd...\n");
- tfp = new VerilatedVcdC;
- top->trace(tfp, 99); // Trace 99 levels of hierarchy
- Verilated::mkdir("logs");
- tfp->open("logs/vlt_dump.vcd"); // Open the dump file
- }
-#endif
-
// Set some inputs
top->reset_l = !0;
- top->fastclk = 0;
top->clk = 0;
top->in_small = 1;
top->in_quad = 0x1234;
@@ -72,31 +57,29 @@ int main(int argc, char** argv, char** env) {
while (!Verilated::gotFinish()) {
main_time++; // Time passes...
- // Toggle clocks and such
- top->fastclk = !top->fastclk;
- if ((main_time % 10) == 3) {
- top->clk = 1;
- }
- if ((main_time % 10) == 8) {
- top->clk = 0;
- }
- if (main_time > 1 && main_time < 10) {
- top->reset_l = !1; // Assert reset
- } else {
- top->reset_l = !0; // Deassert reset
- }
+ // Toggle a fast (time/2 period) clock
+ top->clk = !top->clk;
- // Assign some other inputs
- top->in_quad += 0x12;
+ // Toggle control signals on an edge that doesn't correspond
+ // to where the controls are sampled; in this example we do
+ // this only on a negedge of clk, because we know
+ // reset is not sampled there.
+ if (!top->clk) {
+ if (main_time > 1 && main_time < 10) {
+ top->reset_l = !1; // Assert reset
+ } else {
+ top->reset_l = !0; // Deassert reset
+ }
+ // Assign some other inputs
+ top->in_quad += 0x12;
+ }
// Evaluate model
+ // (If you have multiple models being simulated in the same
+ // timestep then instead of eval(), call eval_step() on each, then
+ // eval_end_step() on each.)
top->eval();
-#if VM_TRACE
- // Dump trace data for this cycle
- if (tfp) tfp->dump(main_time);
-#endif
-
// Read outputs
VL_PRINTF("[%" VL_PRI64 "d] clk=%x rstl=%x iquad=%" VL_PRI64 "x"
" -> oquad=%" VL_PRI64"x owide=%x_%08x_%08x\n",
@@ -107,11 +90,6 @@ int main(int argc, char** argv, char** env) {
// Final model cleanup
top->final();
- // Close trace if opened
-#if VM_TRACE
- if (tfp) { tfp->close(); tfp = NULL; }
-#endif
-
// Coverage analysis (since test passed)
#if VM_COVERAGE
Verilated::mkdir("logs");
diff --git a/examples/make_tracing_c/sub.v b/examples/make_tracing_c/sub.v
index e50d43d51..553d85921 100644
--- a/examples/make_tracing_c/sub.v
+++ b/examples/make_tracing_c/sub.v
@@ -7,25 +7,10 @@
module sub
(
input clk,
- input fastclk,
input reset_l
);
// Example counter/flop
- reg [31:0] count_f;
- always_ff @ (posedge fastclk) begin
- if (!reset_l) begin
- /*AUTORESET*/
- // Beginning of autoreset for uninitialized flops
- count_f <= 32'h0;
- // End of automatics
- end
- else begin
- count_f <= count_f + 1;
- end
- end
-
- // Another example flop
reg [31:0] count_c;
always_ff @ (posedge clk) begin
if (!reset_l) begin
@@ -37,8 +22,6 @@ module sub
else begin
count_c <= count_c + 1;
if (count_c >= 3) begin
- $display("[%0t] fastclk is %0d times faster than clk\n",
- $time, count_f/count_c);
// This write is a magic value the Makefile uses to make sure the
// test completes successfully.
$write("*-* All Finished *-*\n");
diff --git a/examples/make_tracing_c/top.v b/examples/make_tracing_c/top.v
index beae05605..ac537c68f 100644
--- a/examples/make_tracing_c/top.v
+++ b/examples/make_tracing_c/top.v
@@ -11,7 +11,6 @@ module top
(
// Declare some signals so we can see how I/O works
input clk,
- input fastclk,
input reset_l,
output wire [1:0] out_small,
@@ -31,11 +30,15 @@ module top
sub sub (/*AUTOINST*/
// Inputs
.clk (clk),
- .fastclk (fastclk),
.reset_l (reset_l));
// Print some stuff as an example
initial begin
+ if ($test$plusargs("trace") != 0) begin
+ $display("[%0t] Tracing to logs/vlt_dump.vcd...\n", $time);
+ $dumpfile("logs/vlt_dump.vcd");
+ $dumpvars();
+ end
$display("[%0t] Model running...\n", $time);
end
diff --git a/examples/make_tracing_sc/Makefile b/examples/make_tracing_sc/Makefile
index e70053c53..ded101604 100644
--- a/examples/make_tracing_sc/Makefile
+++ b/examples/make_tracing_sc/Makefile
@@ -38,7 +38,7 @@ VERILATOR_FLAGS += -sc --exe
# Generate makefile dependencies (not shown as complicates the Makefile)
#VERILATOR_FLAGS += -MMD
# Optimize
-VERILATOR_FLAGS += -O2 -x-assign 0
+VERILATOR_FLAGS += -Os -x-assign 0
# Warn abount lint issues; may not want this on less solid designs
VERILATOR_FLAGS += -Wall
# Make waveforms
diff --git a/examples/make_tracing_sc/Makefile_obj b/examples/make_tracing_sc/Makefile_obj
index 7c52ba627..03ffe389b 100644
--- a/examples/make_tracing_sc/Makefile_obj
+++ b/examples/make_tracing_sc/Makefile_obj
@@ -46,7 +46,7 @@ endif
# SystemC takes minutes to optimize, thus it is off by default.
OPT_SLOW =
# Fast path optimizations. Most time is spent in these classes.
-OPT_FAST = -O2 -fstrict-aliasing
+OPT_FAST = -Os -fstrict-aliasing
#OPT_FAST = -O
#OPT_FAST =
diff --git a/examples/make_tracing_sc/sc_main.cpp b/examples/make_tracing_sc/sc_main.cpp
index b2d704aec..381d321bf 100644
--- a/examples/make_tracing_sc/sc_main.cpp
+++ b/examples/make_tracing_sc/sc_main.cpp
@@ -37,6 +37,9 @@ int sc_main(int argc, char* argv[]) {
// This needs to be called before you create any model
Verilated::commandArgs(argc, argv);
+ // Create logs/ directory in case we have traces to put under it
+ Verilated::mkdir("logs");
+
// General logfile
ios::sync_with_stdio();
diff --git a/include/verilated.cpp b/include/verilated.cpp
index e740066a9..c242b5ab5 100644
--- a/include/verilated.cpp
+++ b/include/verilated.cpp
@@ -1602,6 +1602,25 @@ IData VL_ATOI_N(const std::string& str, int base) VL_PURE {
return static_cast(v);
}
+//===========================================================================
+// Dumping
+
+const char* vl_dumpctl_filenamep(bool setit, const std::string& filename) VL_MT_SAFE {
+ // This function performs both accessing and setting so it's easy to make an in-function static
+ static VL_THREAD_LOCAL std::string t_filename;
+ if (setit) {
+ t_filename = filename;
+ } else {
+ static VL_THREAD_LOCAL bool t_warned = false;
+ if (VL_UNLIKELY(t_filename.empty() && !t_warned)) {
+ t_warned = true;
+ VL_PRINTF_MT("%%Warning: $dumpvar ignored as not proceeded by $dumpfile\n");
+ return "";
+ }
+ }
+ return t_filename.c_str();
+}
+
//===========================================================================
// Readmem/writemem
@@ -1832,7 +1851,7 @@ void VL_READMEM_N(bool hex, // Hex format, else binary
QData end // Last row address to read
) VL_MT_SAFE {
QData addr_max = array_lsb + depth - 1;
- if (start < array_lsb) start = array_lsb;
+ if (start < static_cast(array_lsb)) start = array_lsb;
QData addr_end = end;
if (addr_end > addr_max) addr_end = addr_max;
@@ -1883,7 +1902,7 @@ void VL_WRITEMEM_N(bool hex, // Hex format, else binary
QData end // Last address to write, or ~0 when not specified
) VL_MT_SAFE {
QData addr_max = array_lsb + depth - 1;
- if (start < array_lsb) start = array_lsb;
+ if (start < static_cast(array_lsb)) start = array_lsb;
if (end > addr_max) end = addr_max;
VlWriteMem wmem(hex, bits, filename, start, end);
@@ -2199,6 +2218,9 @@ void VerilatedImp::commandArgVl(const std::string& arg) {
else if (commandArgVlValue(arg, "+verilator+seed+", value/*ref*/)) {
Verilated::randSeed(atoi(value.c_str()));
}
+ else if (arg == "+verilator+noassert") {
+ Verilated::assertOn(false);
+ }
else if (arg == "+verilator+V") {
versionDump(); // Someday more info too
VL_FATAL_MT("COMMAND_LINE", 0, "",
diff --git a/include/verilated.h b/include/verilated.h
index 3c0b0f9d4..90aa9ff53 100644
--- a/include/verilated.h
+++ b/include/verilated.h
@@ -83,6 +83,7 @@ class VerilatedVar;
class VerilatedVarNameMap;
class VerilatedVcd;
class VerilatedVcdC;
+class VerilatedVcdSc;
class VerilatedFst;
class VerilatedFstC;
@@ -200,13 +201,19 @@ public:
/// Check that the current thread ID is the same as the construction thread ID
void check() VL_MT_UNSAFE_ONE {
if (VL_UNCOVERABLE(m_threadid != VL_THREAD_ID())) {
- fatal_different(); // LCOV_EXCL_LINE
+ if (m_threadid == 0) {
+ m_threadid = VL_THREAD_ID();
+ } else {
+ fatal_different(); // LCOV_EXCL_LINE
+ }
}
}
+ void changeThread() { m_threadid = 0; } // Allow intentional change-of-thread
static void fatal_different() VL_MT_SAFE;
#else // !VL_THREADED || !VL_DEBUG
public:
void check() {}
+ void changeThread() {}
#endif
};
@@ -2013,6 +2020,12 @@ static inline WDataOutP VL_SHIFTR_WWW(int obits, int lbits, int rbits,
}
return VL_SHIFTR_WWI(obits, lbits, 32, owp, lwp, rwp[0]);
}
+static inline WDataOutP VL_SHIFTR_WWQ(int obits, int lbits, int rbits,
+ WDataOutP owp, WDataInP lwp, QData rd) VL_MT_SAFE {
+ WData rwp[VL_WQ_WORDS_E]; VL_SET_WQ(rwp, rd);
+ return VL_SHIFTR_WWW(obits, lbits, rbits, owp, lwp, rwp);
+}
+
static inline IData VL_SHIFTR_IIW(int obits, int, int rbits, IData lhs, WDataInP rwp) VL_MT_SAFE {
for (int i = 1; i < VL_WORDS_I(rbits); ++i) {
if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more
@@ -2098,6 +2111,11 @@ static inline WDataOutP VL_SHIFTRS_WWW(int obits, int lbits, int rbits,
}
return VL_SHIFTRS_WWI(obits, lbits, 32, owp, lwp, rwp[0]);
}
+static inline WDataOutP VL_SHIFTRS_WWQ(int obits, int lbits, int rbits,
+ WDataOutP owp, WDataInP lwp, QData rd) VL_MT_SAFE {
+ WData rwp[VL_WQ_WORDS_E]; VL_SET_WQ(rwp, rd);
+ return VL_SHIFTRS_WWW(obits, lbits, rbits, owp, lwp, rwp);
+}
static inline IData VL_SHIFTRS_IIW(int obits, int lbits, int rbits,
IData lhs, WDataInP rwp) VL_MT_SAFE {
EData overshift = 0; // Huge shift 1>>32 or more
diff --git a/include/verilated.mk.in b/include/verilated.mk.in
index e64de5e97..b00b58272 100644
--- a/include/verilated.mk.in
+++ b/include/verilated.mk.in
@@ -86,7 +86,7 @@ LDLIBS += $(VM_USER_LDLIBS)
# SystemC takes minutes to optimize, thus it is off by default.
#OPT_SLOW =
# Fast path optimizations. Most time is spent in these classes.
-#OPT_FAST = -O2 -fstrict-aliasing
+#OPT_FAST = -Os -fstrict-aliasing
#OPT_FAST = -O
#OPT_FAST =
diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp
index 2e2533cbc..926a19384 100644
--- a/include/verilated_fst_c.cpp
+++ b/include/verilated_fst_c.cpp
@@ -64,9 +64,12 @@ protected:
vluint32_t m_code; ///< Starting code number
// CONSTRUCTORS
VerilatedFstCallInfo(VerilatedFstCallback_t icb, VerilatedFstCallback_t fcb,
- VerilatedFstCallback_t changecb,
- void* ut, vluint32_t code)
- : m_initcb(icb), m_fullcb(fcb), m_changecb(changecb), m_userthis(ut), m_code(code) {}
+ VerilatedFstCallback_t changecb, void* ut)
+ : m_initcb(icb)
+ , m_fullcb(fcb)
+ , m_changecb(changecb)
+ , m_userthis(ut)
+ , m_code(1) {}
~VerilatedFstCallInfo() {}
};
@@ -74,10 +77,11 @@ protected:
// VerilatedFst
VerilatedFst::VerilatedFst(void* fst)
- : m_fst(fst),
- m_fullDump(true),
- m_scopeEscape('.') {
- m_valueStrBuffer.reserve(64+1); // Need enough room for quad
+ : m_fst(fst)
+ , m_fullDump(true)
+ , m_nextCode(1)
+ , m_scopeEscape('.') {
+ m_valueStrBuffer.reserve(64 + 1); // Need enough room for quad
}
void VerilatedFst::open(const char* filename) VL_MT_UNSAFE {
@@ -88,10 +92,12 @@ void VerilatedFst::open(const char* filename) VL_MT_UNSAFE {
fstWriterSetParallelMode(m_fst, 1);
#endif
m_curScope.clear();
+ m_nextCode = 1;
for (vluint32_t ent = 0; ent< m_callbacks.size(); ++ent) {
VerilatedFstCallInfo* cip = m_callbacks[ent];
- cip->m_code = 1;
+ cip->m_code = m_nextCode;
+ // Initialize; callbacks will call decl* which update m_nextCode
(cip->m_initcb)(this, cip->m_userthis, cip->m_code);
}
@@ -118,9 +124,15 @@ void VerilatedFst::declDTypeEnum(int dtypenum, const char* name, vluint32_t elem
m_local2fstdtype[dtypenum] = enumNum;
}
-void VerilatedFst::declSymbol(vluint32_t code, const char* name,
- int dtypenum, fstVarDir vardir, fstVarType vartype,
- bool array, int arraynum, vluint32_t len) {
+void VerilatedFst::declSymbol(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
+ fstVarType vartype, bool array, int arraynum, vluint32_t len,
+ vluint32_t bits) {
+
+ // Make sure deduplicate tracking increments for future declarations
+ int codesNeeded = 1 + int(bits / 32);
+ //Not supported: if (tri) codesNeeded *= 2; // Space in change array for __en signals
+ m_nextCode = std::max(m_nextCode, code + codesNeeded);
+
std::pair p
= m_code2symbol.insert(std::make_pair(code, static_cast(NULL)));
std::istringstream nameiss(name);
@@ -173,17 +185,16 @@ void VerilatedFst::declSymbol(vluint32_t code, const char* name,
//=============================================================================
// Callbacks
-void VerilatedFst::addCallback(
- VerilatedFstCallback_t initcb, VerilatedFstCallback_t fullcb,
- VerilatedFstCallback_t changecb, void* userthis) VL_MT_UNSAFE_ONE {
+void VerilatedFst::addCallback(VerilatedFstCallback_t initcb, VerilatedFstCallback_t fullcb,
+ VerilatedFstCallback_t changecb, void* userthis) VL_MT_UNSAFE_ONE {
m_assertOne.check();
if (VL_UNLIKELY(isOpen())) {
- std::string msg = (std::string("Internal: ")+__FILE__+"::"+__FUNCTION__
- +" called with already open file");
+ std::string msg = (std::string("Internal: ") + __FILE__ + "::" + __FUNCTION__
+ + " called with already open file");
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
}
- VerilatedFstCallInfo* vci = new VerilatedFstCallInfo(initcb, fullcb, changecb, userthis, 1);
- m_callbacks.push_back(vci);
+ VerilatedFstCallInfo* cip = new VerilatedFstCallInfo(initcb, fullcb, changecb, userthis);
+ m_callbacks.push_back(cip);
}
//=============================================================================
@@ -192,7 +203,7 @@ void VerilatedFst::addCallback(
void VerilatedFst::dump(vluint64_t timeui) {
if (!isOpen()) return;
if (VL_UNLIKELY(m_fullDump)) {
- m_fullDump = false; // No need for more full dumps
+ m_fullDump = false; // No more need for next dump to be full
for (vluint32_t ent = 0; ent< m_callbacks.size(); ++ent) {
VerilatedFstCallInfo* cip = m_callbacks[ent];
(cip->m_fullcb)(this, cip->m_userthis, cip->m_code);
diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h
index eda522554..9f2f6c9d6 100644
--- a/include/verilated_fst_c.h
+++ b/include/verilated_fst_c.h
@@ -50,6 +50,7 @@ private:
void* m_fst;
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
bool m_fullDump;
+ vluint32_t m_nextCode; ///< Next code number to assign
char m_scopeEscape;
std::string m_module;
CallbackVec m_callbacks; ///< Routines to perform dumping
@@ -60,12 +61,13 @@ private:
VL_UNCOPYABLE(VerilatedFst);
void declSymbol(vluint32_t code, const char* name,
int dtypenum, fstVarDir vardir, fstVarType vartype,
- bool array, int arraynum, vluint32_t len);
+ bool array, int arraynum, vluint32_t len, vluint32_t bits);
// helpers
std::vector m_valueStrBuffer;
public:
explicit VerilatedFst(void* fst=NULL);
~VerilatedFst() { if (m_fst == NULL) { fstWriterClose(m_fst); } }
+ void changeThread() { m_assertOne.changeThread(); }
bool isOpen() const { return m_fst != NULL; }
void open(const char* filename) VL_MT_UNSAFE;
void flush() VL_MT_UNSAFE { fstWriterFlushContext(m_fst); }
@@ -104,32 +106,35 @@ public:
void declBit(vluint32_t code, const char* name,
int dtypenum, fstVarDir vardir, fstVarType vartype,
bool array, int arraynum) {
- declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1);
+ declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1, 1);
}
void declBus(vluint32_t code, const char* name,
int dtypenum, fstVarDir vardir, fstVarType vartype,
bool array, int arraynum, int msb, int lsb) {
- declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1);
+ declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
+ msb - lsb + 1);
}
void declDouble(vluint32_t code, const char* name,
int dtypenum, fstVarDir vardir, fstVarType vartype,
bool array, int arraynum) {
- declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 2);
+ declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 2, 64);
}
void declFloat(vluint32_t code, const char* name,
int dtypenum, fstVarDir vardir, fstVarType vartype,
bool array, int arraynum) {
- declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1);
+ declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1, 32);
}
void declQuad(vluint32_t code, const char* name,
int dtypenum, fstVarDir vardir, fstVarType vartype,
bool array, int arraynum, int msb, int lsb) {
- declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1);
+ declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
+ msb - lsb + 1);
}
void declArray(vluint32_t code, const char* name,
int dtypenum, fstVarDir vardir, fstVarType vartype,
bool array, int arraynum, int msb, int lsb) {
- declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1);
+ declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
+ msb - lsb + 1);
}
/// Inside dumping routines, dump one signal if it has changed
@@ -167,10 +172,10 @@ public:
void fullArray(vluint32_t code, const vluint32_t* newval, int bits) {
chgArray(code, newval, bits); }
- void declTriBit (vluint32_t code, const char* name, int arraynum);
- void declTriBus (vluint32_t code, const char* name, int arraynum, int msb, int lsb);
- void declTriQuad (vluint32_t code, const char* name, int arraynum, int msb, int lsb);
- void declTriArray (vluint32_t code, const char* name, int arraynum, int msb, int lsb);
+ void declTriBit(vluint32_t code, const char* name, int arraynum);
+ void declTriBus(vluint32_t code, const char* name, int arraynum, int msb, int lsb);
+ void declTriQuad(vluint32_t code, const char* name, int arraynum, int msb, int lsb);
+ void declTriArray(vluint32_t code, const char* name, int arraynum, int msb, int lsb);
void fullTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri);
void fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits);
void fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits);
@@ -198,7 +203,9 @@ class VerilatedFstC {
VL_UNCOPYABLE(VerilatedFstC);
public:
explicit VerilatedFstC(void* filep=NULL) : m_sptrace(filep) {}
- ~VerilatedFstC() {}
+ ~VerilatedFstC() { close(); }
+ /// Routines can only be called from one thread; allow next call from different thread
+ void changeThread() { spTrace()->changeThread(); }
public:
// ACCESSORS
/// Is file open?
diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h
index c04ee3214..432c847d4 100644
--- a/include/verilated_heavy.h
+++ b/include/verilated_heavy.h
@@ -245,11 +245,12 @@ void VL_WRITEMEM_N(bool hex, int bits, const std::string& filename,
}
//===================================================================
-// Verilog queue container
+// Verilog queue and dynamic array container
// There are no multithreaded locks on this; the base variable must
// be protected by other means
//
// Bound here is the maximum size() allowed, e.g. 1 + SystemVerilog bound
+// For dynamic arrays it is always zero
template class VlQueue {
private:
// TYPES
@@ -279,6 +280,21 @@ public:
void clear() { m_deque.clear(); }
void erase(size_t index) { if (VL_LIKELY(index < m_deque.size())) m_deque.erase(index); }
+ // Dynamic array new[] becomes a renew()
+ void renew(size_t size) {
+ clear();
+ m_deque.resize(size, atDefault());
+ }
+ // Dynamic array new[]() becomes a renew_copy()
+ void renew_copy(size_t size, const VlQueue& rhs) {
+ if (size == 0) {
+ clear();
+ } else {
+ *this = rhs;
+ m_deque.resize(size, atDefault());
+ }
+ }
+
// function void q.push_front(value)
void push_front(const T_Value& value) {
m_deque.push_front(value);
@@ -304,6 +320,7 @@ public:
// because we need to be able to insert only when the value is set
T_Value& at(size_t index) {
static T_Value s_throwAway;
+ // Needs to work for dynamic arrays, so does not use T_MaxSize
if (VL_UNLIKELY(index >= m_deque.size())) {
s_throwAway = atDefault();
return s_throwAway;
@@ -313,6 +330,7 @@ public:
// Accessing. Verilog: v = assoc[index]
const T_Value& at(size_t index) const {
static T_Value s_throwAway;
+ // Needs to work for dynamic arrays, so does not use T_MaxSize
if (VL_UNLIKELY(index >= m_deque.size())) return atDefault();
else return m_deque[index];
}
@@ -441,4 +459,10 @@ inline IData VL_CMP_NN(const std::string& lhs, const std::string& rhs, bool igno
extern IData VL_ATOI_N(const std::string& str, int base) VL_PURE;
+//======================================================================
+// Dumping
+
+extern const char* vl_dumpctl_filenamep(bool setit = false,
+ const std::string& filename = "") VL_MT_SAFE;
+
#endif // Guard
diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp
index 42b930f05..49f4d69f9 100644
--- a/include/verilated_vcd_c.cpp
+++ b/include/verilated_vcd_c.cpp
@@ -57,8 +57,8 @@ class VerilatedVcdSingleton {
private:
typedef std::vector VcdVec;
struct Singleton {
- VerilatedMutex s_vcdMutex; ///< Protect the singleton
- VcdVec s_vcdVecp VL_GUARDED_BY(s_vcdMutex); ///< List of all created traces
+ VerilatedMutex s_vcdMutex; ///< Protect the singleton
+ VcdVec s_vcdVecp VL_GUARDED_BY(s_vcdMutex); ///< List of all created traces
};
static Singleton& singleton() { static Singleton s; return s; }
public:
@@ -96,16 +96,19 @@ public:
class VerilatedVcdCallInfo {
protected:
friend class VerilatedVcd;
- VerilatedVcdCallback_t m_initcb; ///< Initialization Callback function
- VerilatedVcdCallback_t m_fullcb; ///< Full Dumping Callback function
- VerilatedVcdCallback_t m_changecb; ///< Incremental Dumping Callback function
- void* m_userthis; ///< Fake "this" for caller
- vluint32_t m_code; ///< Starting code number
+ VerilatedVcdCallback_t m_initcb; ///< Initialization Callback function
+ VerilatedVcdCallback_t m_fullcb; ///< Full Dumping Callback function
+ VerilatedVcdCallback_t m_changecb; ///< Incremental Dumping Callback function
+ void* m_userthis; ///< Fake "this" for caller
+ vluint32_t m_code; ///< Starting code number (set later by traceInit)
// CONSTRUCTORS
VerilatedVcdCallInfo(VerilatedVcdCallback_t icb, VerilatedVcdCallback_t fcb,
- VerilatedVcdCallback_t changecb,
- void* ut, vluint32_t code)
- : m_initcb(icb), m_fullcb(fcb), m_changecb(changecb), m_userthis(ut), m_code(code) {}
+ VerilatedVcdCallback_t changecb, void* ut)
+ : m_initcb(icb)
+ , m_fullcb(fcb)
+ , m_changecb(changecb)
+ , m_userthis(ut)
+ , m_code(1) {}
~VerilatedVcdCallInfo() {}
};
@@ -116,7 +119,7 @@ protected:
bool VerilatedVcdFile::open(const std::string& name) VL_MT_UNSAFE {
m_fd = ::open(name.c_str(), O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE|O_NONBLOCK|O_CLOEXEC, 0666);
- return (m_fd>=0);
+ return m_fd >= 0;
}
void VerilatedVcdFile::close() VL_MT_UNSAFE {
@@ -133,7 +136,10 @@ ssize_t VerilatedVcdFile::write(const char* bufp, ssize_t len) VL_MT_UNSAFE {
// Opening/Closing
VerilatedVcd::VerilatedVcd(VerilatedVcdFile* filep)
- : m_isOpen(false), m_rolloverMB(0), m_modDepth(0), m_nextCode(1) {
+ : m_isOpen(false)
+ , m_rolloverMB(0)
+ , m_modDepth(0)
+ , m_nextCode(1) {
// Not in header to avoid link issue if header is included without this .cpp file
m_fileNewed = (filep == NULL);
m_filep = m_fileNewed ? new VerilatedVcdFile : filep;
@@ -153,7 +159,7 @@ VerilatedVcd::VerilatedVcd(VerilatedVcdFile* filep)
void VerilatedVcd::open(const char* filename) {
m_assertOne.check();
- if (isOpen()) return;
+ if (isOpen() || !filename || !*filename) return;
// Set member variables
m_filename = filename;
@@ -230,9 +236,10 @@ void VerilatedVcd::makeNameMap() {
deleteNameMap();
m_nextCode = 1;
m_namemapp = new NameMap;
- for (vluint32_t ent = 0; ent< m_callbacks.size(); ent++) {
+ for (vluint32_t ent = 0; ent < m_callbacks.size(); ent++) {
VerilatedVcdCallInfo* cip = m_callbacks[ent];
cip->m_code = m_nextCode;
+ // Initialize; callbacks will call decl* which update m_nextCode
(cip->m_initcb)(this, cip->m_userthis, cip->m_code);
}
@@ -513,7 +520,7 @@ void VerilatedVcd::dumpHeader() {
printIndent(-1);
printStr("$enddefinitions $end\n\n\n");
- assert(m_modDepth==0);
+ assert(m_modDepth == 0);
// Reclaim storage
deleteNameMap();
@@ -529,12 +536,12 @@ void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep,
if (!code) { VL_FATAL_MT(__FILE__, __LINE__, "",
"Internal: internal trace problem, code 0 is illegal"); }
- int bits = ((msb>lsb)?(msb-lsb):(lsb-msb))+1;
- int codesNeeded = 1+int(bits/32);
+ int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1;
+ int codesNeeded = 1 + int(bits / 32);
if (tri) codesNeeded *= 2; // Space in change array for __en signals
// Make sure array is large enough
- m_nextCode = std::max(m_nextCode, code+codesNeeded);
+ m_nextCode = std::max(m_nextCode, code + codesNeeded);
if (m_sigs.capacity() <= m_nextCode) {
m_sigs.reserve(m_nextCode*2); // Power-of-2 allocation speeds things up
}
@@ -658,19 +665,16 @@ void VerilatedVcd::fullFloat(vluint32_t code, const float newval) {
//=============================================================================
// Callbacks
-void VerilatedVcd::addCallback(
- VerilatedVcdCallback_t initcb, VerilatedVcdCallback_t fullcb, VerilatedVcdCallback_t changecb,
- void* userthis) VL_MT_UNSAFE_ONE
-{
+void VerilatedVcd::addCallback(VerilatedVcdCallback_t initcb, VerilatedVcdCallback_t fullcb,
+ VerilatedVcdCallback_t changecb, void* userthis) VL_MT_UNSAFE_ONE {
m_assertOne.check();
if (VL_UNLIKELY(isOpen())) {
- std::string msg = std::string("Internal: ")+__FILE__+"::"+__FUNCTION__
- +" called with already open file";
+ std::string msg = std::string("Internal: ") + __FILE__ + "::" + __FUNCTION__
+ + " called with already open file";
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
}
- VerilatedVcdCallInfo* vci
- = new VerilatedVcdCallInfo(initcb, fullcb, changecb, userthis, m_nextCode);
- m_callbacks.push_back(vci);
+ VerilatedVcdCallInfo* cip = new VerilatedVcdCallInfo(initcb, fullcb, changecb, userthis);
+ m_callbacks.push_back(cip);
}
//=============================================================================
@@ -680,7 +684,7 @@ void VerilatedVcd::dumpFull(vluint64_t timeui) {
m_assertOne.check();
dumpPrep(timeui);
Verilated::quiesce();
- for (vluint32_t ent = 0; ent< m_callbacks.size(); ent++) {
+ for (vluint32_t ent = 0; ent < m_callbacks.size(); ent++) {
VerilatedVcdCallInfo* cip = m_callbacks[ent];
(cip->m_fullcb)(this, cip->m_userthis, cip->m_code);
}
@@ -690,7 +694,7 @@ void VerilatedVcd::dump(vluint64_t timeui) {
m_assertOne.check();
if (!isOpen()) return;
if (VL_UNLIKELY(m_fullDump)) {
- m_fullDump = false; // No need for more full dumps
+ m_fullDump = false; // No more need for next dump to be full
dumpFull(timeui);
return;
}
@@ -700,7 +704,7 @@ void VerilatedVcd::dump(vluint64_t timeui) {
}
dumpPrep(timeui);
Verilated::quiesce();
- for (vluint32_t ent = 0; ent< m_callbacks.size(); ++ent) {
+ for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) {
VerilatedVcdCallInfo* cip = m_callbacks[ent];
(cip->m_changecb)(this, cip->m_userthis, cip->m_code);
}
@@ -829,6 +833,7 @@ main() {
#endif
//********************************************************************
+// ;compile-command: "mkdir -p ../test_dir && cd ../test_dir && c++ -DVERILATED_VCD_TEST ../include/verilated_vcd_c.cpp -o verilated_vcd_c && ./verilated_vcd_c && cat test.vcd"
+//
// Local Variables:
-// compile-command: "mkdir -p ../test_dir && cd ../test_dir && c++ -DVERILATED_VCD_TEST ../include/verilated_vcd_c.cpp -o verilated_vcd_c && ./verilated_vcd_c && cat test.vcd"
// End:
diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h
index 835af7b71..f0a5bcb9f 100644
--- a/include/verilated_vcd_c.h
+++ b/include/verilated_vcd_c.h
@@ -103,9 +103,9 @@ private:
typedef std::vector SigVec;
SigVec m_sigs; ///< Pointer to signal information
typedef std::vector CallbackVec;
- CallbackVec m_callbacks; ///< Routines to perform dumping
+ CallbackVec m_callbacks; ///< Routines to perform dumping
typedef std::map NameMap;
- NameMap* m_namemapp; ///< List of names for the header
+ NameMap* m_namemapp; ///< List of names for the header
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
@@ -159,6 +159,8 @@ private:
public:
explicit VerilatedVcd(VerilatedVcdFile* filep = NULL);
~VerilatedVcd();
+ /// Routines can only be called from one thread; allow next call from different thread
+ void changeThread() { m_assertOne.changeThread(); }
// ACCESSORS
/// Set size in megabytes after which new file should be created
@@ -445,7 +447,9 @@ class VerilatedVcdC {
public:
explicit VerilatedVcdC(VerilatedVcdFile* filep = NULL)
: m_sptrace(filep) {}
- ~VerilatedVcdC() {}
+ ~VerilatedVcdC() { close(); }
+ /// Routines can only be called from one thread; allow next call from different thread
+ void changeThread() { spTrace()->changeThread(); }
public:
// ACCESSORS
/// Is file open?
diff --git a/include/verilated_vcd_sc.h b/include/verilated_vcd_sc.h
index f5ab1efe1..48c961c8d 100644
--- a/include/verilated_vcd_sc.h
+++ b/include/verilated_vcd_sc.h
@@ -62,7 +62,7 @@ public:
spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
# endif
}
- virtual ~VerilatedVcdSc() {}
+ virtual ~VerilatedVcdSc() { close(); }
// METHODS
/// Called by SystemC simulate()
diff --git a/include/verilatedos.h b/include/verilatedos.h
index 1db5ad3e1..cc3bdd3b3 100644
--- a/include/verilatedos.h
+++ b/include/verilatedos.h
@@ -223,9 +223,12 @@
#ifdef __MINGW32__
# define __USE_MINGW_ANSI_STDIO 1 // Force old MinGW (GCC 5 and older) to use C99 formats
-# define __STDC_FORMAT_MACROS 1 // Otherwise MinGW doesn't get PRId64 for fstapi.c
#endif
+// The inttypes supplied with some GCC & MINGW32 versions requires STDC_FORMAT_MACROS
+// to be declared in order to get the PRIxx macros used by fstapi.c
+#define __STDC_FORMAT_MACROS
+
#if defined(__CYGWIN__)
# include
@@ -273,10 +276,6 @@ typedef signed __int32 ssize_t; ///< signed size_t; returned fro
#else // Linux or compliant Unix flavors, -m64
-// The inttypes supplied with some GCC versions requires STDC_FORMAT_MACROS
-// to be declared in order to get the PRIxx macros used by fstapi.c
-#define __STDC_FORMAT_MACROS
-
# include // Solaris
# include // Linux and most flavors
# include // __WORDSIZE
diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in
index f847288bb..4f677b61c 100644
--- a/src/Makefile_obj.in
+++ b/src/Makefile_obj.in
@@ -233,6 +233,7 @@ RAW_OBJS = \
V3Slice.o \
V3Split.o \
V3SplitAs.o \
+ V3SplitVar.o \
V3Stats.o \
V3StatsReport.o \
V3String.o \
diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp
index 6e593c339..ffd983921 100644
--- a/src/V3Assert.cpp
+++ b/src/V3Assert.cpp
@@ -150,7 +150,7 @@ private:
// It's more LIKELY that we'll take the NULL if clause
// than the sim-killing else clause:
ifp->branchPred(VBranchPred::BP_LIKELY);
- bodysp = ifp;
+ bodysp = newIfAssertOn(ifp);
} else {
nodep->v3fatalSrc("Unknown node type");
}
diff --git a/src/V3Ast.h b/src/V3Ast.h
index 2f8c2857b..851c4c898 100644
--- a/src/V3Ast.h
+++ b/src/V3Ast.h
@@ -55,6 +55,12 @@ typedef std::set MTaskIdSet; // Set of mtaskIds for Var sorting
do { \
if (VL_UNCOVERABLE(test)) return #test; \
} while (0)
+// For broken() function, return error string if a base of this class has a match
+#define BROKEN_BASE_RTN(test) \
+ do { \
+ const char* reasonp = (test); \
+ if (VL_UNCOVERABLE(reasonp)) return reasonp; \
+ } while (0)
// (V)erilator (N)ode is: True if AstNode is of a a given AstType
#define VN_IS(nodep,nodetypename) (AstNode::privateIs(nodep))
@@ -326,7 +332,8 @@ public:
VAR_SC_BV, // V3LinkParse moves to AstVar::attrScBv
VAR_SFORMAT, // V3LinkParse moves to AstVar::attrSFormat
VAR_CLOCKER, // V3LinkParse moves to AstVar::attrClocker
- VAR_NO_CLOCKER // V3LinkParse moves to AstVar::attrClocker
+ VAR_NO_CLOCKER, // V3LinkParse moves to AstVar::attrClocker
+ VAR_SPLIT_VAR // V3LinkParse moves to AstVar::attrSplitVar
};
enum en m_e;
const char* ascii() const {
@@ -342,7 +349,7 @@ public:
"VAR_BASE", "VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC",
"VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD", "VAR_PUBLIC_FLAT_RW",
"VAR_ISOLATE_ASSIGNMENTS", "VAR_SC_BV", "VAR_SFORMAT", "VAR_CLOCKER",
- "VAR_NO_CLOCKER"
+ "VAR_NO_CLOCKER", "VAR_SPLIT_VAR"
};
return names[m_e];
}
@@ -814,6 +821,32 @@ inline bool operator==(AstDisplayType::en lhs, const AstDisplayType& rhs) {
//######################################################################
+class VDumpCtlType {
+public:
+ enum en { FILE, VARS, ALL, FLUSH, LIMIT, OFF, ON };
+ enum en m_e;
+ inline VDumpCtlType()
+ : m_e(ON) {}
+ // cppcheck-suppress noExplicitConstructor
+ inline VDumpCtlType(en _e)
+ : m_e(_e) {}
+ explicit inline VDumpCtlType(int _e)
+ : m_e(static_cast(_e)) {}
+ operator en() const { return m_e; }
+ const char* ascii() const {
+ static const char* const names[] = {"$dumpfile", "$dumpvars", "$dumpall", "$dumpflush",
+ "$dumplimit", "$dumpoff", "$dumpon"};
+ return names[m_e];
+ }
+};
+inline bool operator==(const VDumpCtlType& lhs, const VDumpCtlType& rhs) {
+ return lhs.m_e == rhs.m_e;
+}
+inline bool operator==(const VDumpCtlType& lhs, VDumpCtlType::en rhs) { return lhs.m_e == rhs; }
+inline bool operator==(VDumpCtlType::en lhs, const VDumpCtlType& rhs) { return lhs == rhs.m_e; }
+
+//######################################################################
+
class VParseRefExp {
public:
enum en {
@@ -2203,6 +2236,54 @@ public:
//######################################################################
// Tasks/functions common handling
+class AstNodeCCall : public AstNodeStmt {
+ // A call of a C++ function, perhaps a AstCFunc or perhaps globally named
+ // Functions are not statements, while tasks are. AstNodeStmt needs isStatement() to deal.
+ AstCFunc* m_funcp;
+ string m_hiername;
+ string m_argTypes;
+public:
+ AstNodeCCall(AstType t, FileLine* fl, AstCFunc* funcp, AstNode* argsp = NULL)
+ : AstNodeStmt(t, fl, true)
+ , m_funcp(funcp) {
+ addNOp2p(argsp);
+ }
+ // Replacement form for V3Combine
+ // Note this removes old attachments from the oldp
+ AstNodeCCall(AstType t, AstNodeCCall* oldp, AstCFunc* funcp)
+ : AstNodeStmt(t, oldp->fileline(), true)
+ , m_funcp(funcp) {
+ m_funcp = funcp;
+ m_hiername = oldp->hiername();
+ m_argTypes = oldp->argTypes();
+ if (oldp->argsp()) addNOp2p(oldp->argsp()->unlinkFrBackWithNext());
+ }
+ ASTNODE_BASE_FUNCS(NodeCCall)
+ virtual void dump(std::ostream& str=std::cout) const;
+ virtual void cloneRelink();
+ virtual const char* broken() const;
+ virtual int instrCount() const { return instrCountCall(); }
+ virtual V3Hash sameHash() const { return V3Hash(funcp()); }
+ virtual bool same(const AstNode* samep) const {
+ const AstNodeCCall* asamep = static_cast(samep);
+ return (funcp() == asamep->funcp() && argTypes() == asamep->argTypes());
+ }
+ AstNode* exprsp() const { return op2p(); } // op2 = expressions to print
+ virtual bool isGateOptimizable() const { return false; }
+ virtual bool isPredictOptimizable() const { return false; }
+ virtual bool isPure() const;
+ virtual bool isOutputter() const { return !isPure(); }
+ AstCFunc* funcp() const { return m_funcp; }
+ string hiername() const { return m_hiername; }
+ void hiername(const string& hn) { m_hiername = hn; }
+ string hiernameProtect() const;
+ void argTypes(const string& str) { m_argTypes = str; }
+ string argTypes() const { return m_argTypes; }
+ // op1p reserved for AstCMethodCall
+ AstNode* argsp() const { return op2p(); }
+ void addArgsp(AstNode* nodep) { addOp2p(nodep); }
+};
+
class AstNodeFTask : public AstNode {
private:
string m_name; // Name of task
@@ -2284,12 +2365,12 @@ public:
AstNodeFTaskRef(AstType t, FileLine* fl, bool statement, AstNode* namep, AstNode* pinsp)
: AstNodeStmt(t, fl, statement)
, m_taskp(NULL), m_packagep(NULL) {
- setOp1p(namep); addNOp2p(pinsp);
+ setOp1p(namep); addNOp3p(pinsp);
}
AstNodeFTaskRef(AstType t, FileLine* fl, bool statement, const string& name, AstNode* pinsp)
: AstNodeStmt(t, fl, statement)
, m_taskp(NULL), m_name(name), m_packagep(NULL) {
- addNOp2p(pinsp);
+ addNOp3p(pinsp);
}
ASTNODE_BASE_FUNCS(NodeFTaskRef)
virtual const char* broken() const { BROKEN_RTN(m_taskp && !m_taskp->brokeExists()); return NULL; }
@@ -2311,12 +2392,13 @@ public:
void packagep(AstPackage* nodep) { m_packagep = nodep; }
// op1 = namep
AstNode* namep() const { return op1p(); }
- // op2 = Pin interconnection list
- AstNode* pinsp() const { return op2p(); }
- void addPinsp(AstNode* nodep) { addOp2p(nodep); }
- // op3 = scope tracking
- AstScopeName* scopeNamep() const { return VN_CAST(op3p(), ScopeName); }
- void scopeNamep(AstNode* nodep) { setNOp3p(nodep); }
+ // op2 = reserved for AstMethodCall
+ // op3 = Pin interconnection list
+ AstNode* pinsp() const { return op3p(); }
+ void addPinsp(AstNode* nodep) { addOp3p(nodep); }
+ // op4 = scope tracking
+ AstScopeName* scopeNamep() const { return VN_CAST(op4p(), ScopeName); }
+ void scopeNamep(AstNode* nodep) { setNOp4p(nodep); }
};
class AstNodeModule : public AstNode {
diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp
index 835758651..9f57d2ba3 100644
--- a/src/V3AstNodes.cpp
+++ b/src/V3AstNodes.cpp
@@ -26,6 +26,7 @@
#include "V3Global.h"
#include "V3Graph.h"
#include "V3PartitionGraph.h" // Just for mtask dumping
+#include "V3EmitCBase.h"
#include
#include
@@ -88,6 +89,27 @@ const char* AstNodeUOrStructDType::broken() const {
return NULL;
}
+void AstNodeCCall::dump(std::ostream& str) const {
+ this->AstNode::dump(str);
+ if (funcp()) {
+ str << " " << funcp()->name() << " => ";
+ funcp()->dump(str);
+ } else {
+ str << " " << name();
+ }
+}
+void AstNodeCCall::cloneRelink() {
+ if (m_funcp && m_funcp->clonep()) { m_funcp = m_funcp->clonep(); }
+}
+const char* AstNodeCCall::broken() const {
+ BROKEN_RTN(m_funcp && !m_funcp->brokeExists());
+ return NULL;
+}
+bool AstNodeCCall::isPure() const { return funcp()->pure(); }
+string AstNodeCCall::hiernameProtect() const {
+ return VIdProtect::protectWordsIf(hiername(), protect());
+}
+
void AstNodeCond::numberOperate(V3Number& out, const V3Number& lhs,
const V3Number& rhs, const V3Number& ths) {
if (lhs.isNeqZero()) out.opAssign(rhs); else out.opAssign(ths);
@@ -278,6 +300,17 @@ AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDT
VlArgTypeRecursed info;
info.m_oprefix = out;
return info;
+ } else if (const AstDynArrayDType* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) {
+ VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true);
+ string out = "VlQueue<";
+ out += sub.m_oprefix;
+ if (!sub.m_osuffix.empty() || !sub.m_oref.empty()) {
+ out += " " + sub.m_osuffix + sub.m_oref;
+ }
+ out += "> ";
+ VlArgTypeRecursed info;
+ info.m_oprefix = out;
+ return info;
} else if (const AstQueueDType* adtypep = VN_CAST_CONST(dtypep, QueueDType)) {
VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true);
VlArgTypeRecursed info;
@@ -668,10 +701,6 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep) { ///< What is the base variabl
return nodep;
}
-string AstCCall::hiernameProtect() const {
- return VIdProtect::protectWordsIf(hiername(), protect());
-}
-
const char* AstScope::broken() const {
BROKEN_RTN(m_aboveScopep && !m_aboveScopep->brokeExists());
BROKEN_RTN(m_aboveCellp && !m_aboveCellp->brokeExists());
@@ -1013,6 +1042,16 @@ void AstMemberSel::dump(std::ostream& str) const {
if (varp()) { varp()->dump(str); }
else { str << "%Error:UNLINKED"; }
}
+void AstMethodCall::dump(std::ostream& str) const {
+ this->AstNode::dump(str);
+ if (isStatement()) str << " [STMT]";
+ str << " -> ";
+ if (taskp()) {
+ taskp()->dump(str);
+ } else {
+ str << " -> UNLINKED";
+ }
+}
void AstModportFTaskRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isExport()) str<<" EXPORT";
@@ -1168,6 +1207,13 @@ void AstAssocArrayDType::dumpSmall(std::ostream& str) const {
string AstAssocArrayDType::prettyDTypeName() const {
return subDTypep()->prettyDTypeName() + "[" + keyDTypep()->prettyDTypeName() + "]";
}
+void AstDynArrayDType::dumpSmall(std::ostream& str) const {
+ this->AstNodeDType::dumpSmall(str);
+ str<<"[]";
+}
+string AstDynArrayDType::prettyDTypeName() const {
+ return subDTypep()->prettyDTypeName() + "[]";
+}
void AstQueueDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str<<"[queue]";
@@ -1282,6 +1328,7 @@ void AstBegin::dump(std::ostream& str) const {
if (unnamed()) str<<" [UNNAMED]";
if (generate()) str<<" [GEN]";
if (genforp()) str<<" [GENFOR]";
+ if (implied()) str<<" [IMPLIED]";
}
void AstCoverDecl::dump(std::ostream& str) const {
this->AstNode::dump(str);
@@ -1324,13 +1371,6 @@ void AstCFile::dump(std::ostream& str) const {
if (source()) str<<" [SRC]";
if (slow()) str<<" [SLOW]";
}
-void AstCCall::dump(std::ostream& str) const {
- this->AstNode::dump(str);
- if (funcp()) {
- str<<" "<name()<<" => ";
- funcp()->dump(str);
- }
-}
void AstCFunc::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (slow()) str<<" [SLOW]";
diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h
index dcba2822f..c060added 100644
--- a/src/V3AstNodes.h
+++ b/src/V3AstNodes.h
@@ -451,6 +451,56 @@ public:
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
};
+class AstDynArrayDType : public AstNodeDType {
+ // Dynamic array data type, ie "[]"
+ // Children: DTYPE (moved to refDTypep() in V3Width)
+private:
+ AstNodeDType* m_refDTypep; // Elements of this type (after widthing)
+public:
+ AstDynArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp)
+ : ASTGEN_SUPER(fl) {
+ childDTypep(dtp); // Only for parser
+ refDTypep(NULL);
+ dtypep(NULL); // V3Width will resolve
+ }
+ AstDynArrayDType(FileLine* fl, AstNodeDType* dtp)
+ : ASTGEN_SUPER(fl) {
+ refDTypep(dtp);
+ dtypep(NULL); // V3Width will resolve
+ }
+ ASTNODE_NODE_FUNCS(DynArrayDType)
+ virtual const char* broken() const {
+ BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
+ || (!m_refDTypep && childDTypep())));
+ return NULL; }
+ virtual void cloneRelink() {
+ if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); } }
+ virtual bool same(const AstNode* samep) const {
+ const AstAssocArrayDType* asamep = static_cast(samep);
+ return subDTypep() == asamep->subDTypep(); }
+ virtual bool similarDType(AstNodeDType* samep) const {
+ const AstAssocArrayDType* asamep = static_cast(samep);
+ return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
+ }
+ virtual string prettyDTypeName() const;
+ virtual void dumpSmall(std::ostream& str) const;
+ virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); }
+ AstNodeDType* getChildDTypep() const { return childDTypep(); }
+ AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } // op1 = Range of variable
+ void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
+ virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); }
+ void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
+ virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; }
+ virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); }
+ // METHODS
+ virtual AstBasicDType* basicp() const { return NULL; } // (Slow) recurse down to find basic data type
+ virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
+ virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
+ virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
+ virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); }
+ virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
+};
+
class AstPackArrayDType : public AstNodeArrayDType {
// Packed array data type, ie "some_dtype [2:0] var_name"
// Children: DTYPE (moved to refDTypep() in V3Width)
@@ -1358,31 +1408,33 @@ public:
void declRange(const VNumRange& flag) { m_declRange = flag; }
};
-class AstMethodCall : public AstNode {
+class AstMethodCall : public AstNodeFTaskRef {
// A reference to a member task (or function)
- // We do not support generic member calls yet, so this is only enough to
- // make built-in methods work
-private:
- string m_name; // Name of method
+ // PARENTS: stmt/math
+ // Not all calls are statments vs math. AstNodeStmt needs isStatement() to deal.
+ // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it
public:
- AstMethodCall(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name, AstNode* pinsp)
- : ASTGEN_SUPER(fl), m_name(name) {
- setOp1p(fromp);
+ AstMethodCall(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name,
+ AstNode* pinsp)
+ : ASTGEN_SUPER(fl, false, name, pinsp) {
+ setOp2p(fromp);
dtypep(NULL); // V3Width will resolve
- addNOp2p(pinsp);
}
AstMethodCall(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp)
- : ASTGEN_SUPER(fl), m_name(name) {
- setOp1p(fromp);
- addNOp2p(pinsp);
+ : ASTGEN_SUPER(fl, false, name, pinsp) {
+ setOp2p(fromp);
}
ASTNODE_NODE_FUNCS(MethodCall)
- virtual string name() const { return m_name; } // * = Var name
- virtual void name(const string& name) { m_name = name; }
- AstNode* fromp() const { return op1p(); } // op1 = Extracting what (NULL=TBD during parsing)
- void fromp(AstNode* nodep) { setOp1p(nodep); }
- AstNode* pinsp() const { return op2p(); } // op2 = Pin interconnection list
- void addPinsp(AstNode* nodep) { addOp2p(nodep); }
+ virtual const char* broken() const {
+ BROKEN_BASE_RTN(AstNodeFTaskRef::broken());
+ BROKEN_RTN(!fromp());
+ return NULL;
+ }
+ virtual void dump(std::ostream& str) const;
+ virtual bool hasDType() const { return true; }
+ void makeStatement() { statement(true); dtypeSetVoid(); }
+ AstNode* fromp() const { return op2p(); } // op2 = Extracting what (NULL=TBD during parsing)
+ void fromp(AstNode* nodep) { setOp2p(nodep); }
};
class AstCMethodHard : public AstNodeStmt {
@@ -1456,6 +1508,7 @@ private:
bool m_attrScBv:1; // User force bit vector attribute
bool m_attrIsolateAssign:1;// User isolate_assignments attribute
bool m_attrSFormat:1;// User sformat attribute
+ bool m_attrSplitVar:1; // declared with split_var metacomment
bool m_fileDescr:1; // File descriptor
bool m_isConst:1; // Table contains constant data
bool m_isStatic:1; // Static variable
@@ -1478,7 +1531,7 @@ private:
m_sigUserRdPublic = false; m_sigUserRWPublic = false;
m_funcLocal = false; m_funcReturn = false;
m_attrClockEn = false; m_attrScBv = false;
- m_attrIsolateAssign = false; m_attrSFormat = false;
+ m_attrIsolateAssign = false; m_attrSFormat = false; m_attrSplitVar = false;
m_fileDescr = false; m_isConst = false;
m_isStatic = false; m_isPulldown = false; m_isPullup = false;
m_isIfaceParent = false; m_isDpiOpenArray = false;
@@ -1582,6 +1635,7 @@ public:
void attrScBv(bool flag) { m_attrScBv = flag; }
void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; }
void attrSFormat(bool flag) { m_attrSFormat = flag; }
+ void attrSplitVar(bool flag) { m_attrSplitVar = flag; }
void usedClock(bool flag) { m_usedClock = flag; }
void usedParam(bool flag) { m_usedParam = flag; }
void usedLoopIdx(bool flag) { m_usedLoopIdx = flag; }
@@ -1658,6 +1712,7 @@ public:
bool attrFileDescr() const { return m_fileDescr; }
bool attrScClocked() const { return m_scClocked; }
bool attrSFormat() const { return m_attrSFormat; }
+ bool attrSplitVar() const { return m_attrSplitVar; }
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
VVarAttrClocker attrClocker() const { return m_attrClocker; }
virtual string verilogKwd() const;
@@ -2332,21 +2387,6 @@ public:
//######################################################################
-class AstGenerate : public AstNode {
- // A Generate/end block
- // Parents: MODULE
- // Children: modItems
-public:
- AstGenerate(FileLine* fl, AstNode* stmtsp)
- : ASTGEN_SUPER(fl) {
- addNOp1p(stmtsp);
- }
- ASTNODE_NODE_FUNCS(Generate)
- // op1 = Statements
- AstNode* stmtsp() const { return op1p(); } // op1 = List of statements
- void addStmtp(AstNode* nodep) { addOp1p(nodep); }
-};
-
class AstParseRef : public AstNode {
// A reference to a variable, function or task
// We don't know which at parse time due to bison constraints
@@ -2968,17 +3008,21 @@ public:
class AstSFormatF : public AstNode {
// Convert format to string, generally under an AstDisplay or AstSFormat
// Also used as "real" function for /*verilator sformat*/ functions
- string m_text;
- bool m_hidden; // Under display, etc
- bool m_hasFormat; // Has format code
+ string m_text;
+ bool m_hidden; // Under display, etc
+ bool m_hasFormat; // Has format code
+ char m_missingArgChar; // Format code when argument without format, 'h'/'o'/'b'
public:
class NoFormat {};
- AstSFormatF(FileLine* fl, const string& text, bool hidden, AstNode* exprsp)
- : ASTGEN_SUPER(fl), m_text(text), m_hidden(hidden), m_hasFormat(true) {
+ AstSFormatF(FileLine* fl, const string& text, bool hidden, AstNode* exprsp,
+ char missingArgChar = 'd')
+ : ASTGEN_SUPER(fl)
+ , m_text(text), m_hidden(hidden), m_hasFormat(true), m_missingArgChar(missingArgChar) {
dtypeSetString();
addNOp1p(exprsp); addNOp2p(NULL); }
- AstSFormatF(FileLine* fl, NoFormat, AstNode* exprsp)
- : ASTGEN_SUPER(fl), m_text(""), m_hidden(true), m_hasFormat(false) {
+ AstSFormatF(FileLine* fl, NoFormat, AstNode* exprsp, char missingArgChar = 'd')
+ : ASTGEN_SUPER(fl)
+ , m_text(""), m_hidden(true), m_hasFormat(false), m_missingArgChar(missingArgChar) {
dtypeSetString();
addNOp1p(exprsp); addNOp2p(NULL); }
ASTNODE_NODE_FUNCS(SFormatF)
@@ -3000,6 +3044,7 @@ public:
bool hidden() const { return m_hidden; }
void hasFormat(bool flag) { m_hasFormat = flag; }
bool hasFormat() const { return m_hasFormat; }
+ char missingArgChar() const { return m_missingArgChar; }
};
class AstDisplay : public AstNodeStmt {
@@ -3007,18 +3052,19 @@ class AstDisplay : public AstNodeStmt {
// Children: file which must be a varref
// Children: SFORMATF to generate print string
private:
- AstDisplayType m_displayType;
+ AstDisplayType m_displayType;
public:
AstDisplay(FileLine* fl, AstDisplayType dispType, const string& text, AstNode* filep,
- AstNode* exprsp)
+ AstNode* exprsp, char missingArgChar = 'd')
: ASTGEN_SUPER(fl) {
- setOp1p(new AstSFormatF(fl, text, true, exprsp));
+ setOp1p(new AstSFormatF(fl, text, true, exprsp, missingArgChar));
setNOp3p(filep);
m_displayType = dispType;
}
- AstDisplay(FileLine* fl, AstDisplayType dispType, AstNode* filep, AstNode* exprsp)
+ AstDisplay(FileLine* fl, AstDisplayType dispType, AstNode* filep, AstNode* exprsp,
+ char missingArgChar = 'd')
: ASTGEN_SUPER(fl) {
- setOp1p(new AstSFormatF(fl, AstSFormatF::NoFormat(), exprsp));
+ setOp1p(new AstSFormatF(fl, AstSFormatF::NoFormat(), exprsp, missingArgChar));
setNOp3p(filep);
m_displayType = dispType;
}
@@ -3045,6 +3091,31 @@ public:
void filep(AstNodeVarRef* nodep) { setNOp3p(nodep); }
};
+class AstDumpCtl : public AstNodeStmt {
+ // $dumpon etc
+ // Parents: expr
+ // Child: expr based on type of control statement
+ VDumpCtlType m_ctlType; // Type of operation
+public:
+ AstDumpCtl(FileLine* fl, VDumpCtlType ctlType, AstNode* exprp = NULL)
+ : ASTGEN_SUPER(fl), m_ctlType(ctlType) {
+ setNOp1p(exprp);
+ }
+ ASTNODE_NODE_FUNCS(DumpCtl)
+ virtual string verilogKwd() const { return ctlType().ascii(); }
+ virtual string emitVerilog() { return "%f" + verilogKwd() + "(%l)"; }
+ virtual string emitC() { V3ERROR_NA; return ""; }
+ virtual bool isGateOptimizable() const { return false; }
+ virtual bool isPredictOptimizable() const { return false; }
+ virtual bool isOutputter() const { return true; }
+ virtual bool cleanOut() const { return true; }
+ virtual V3Hash sameHash() const { return V3Hash(); }
+ virtual bool same(const AstNode* samep) const { return true; }
+ VDumpCtlType ctlType() const { return m_ctlType; }
+ AstNode* exprp() const { return op1p(); } // op2 = Expressions to output
+ void exprp(AstNode* nodep) { setOp1p(nodep); }
+};
+
class AstElabDisplay : public AstNode {
// Parents: stmtlist
// Children: SFORMATF to generate print string
@@ -3079,9 +3150,10 @@ class AstSFormat : public AstNodeStmt {
// Children: string to load
// Children: SFORMATF to generate print string
public:
- AstSFormat(FileLine* fl, AstNode* lhsp, const string& text, AstNode* exprsp)
+ AstSFormat(FileLine* fl, AstNode* lhsp, const string& text, AstNode* exprsp,
+ char missingArgChar = 'd')
: ASTGEN_SUPER(fl) {
- setOp1p(new AstSFormatF(fl, text, true, exprsp));
+ setOp1p(new AstSFormatF(fl, text, true, exprsp, missingArgChar));
setOp3p(lhsp);
}
ASTNODE_NODE_FUNCS(SFormat)
@@ -3751,16 +3823,19 @@ class AstBegin : public AstNode {
// Children: statements
private:
string m_name; // Name of block
- bool m_unnamed; // Originally unnamed
+ bool m_unnamed; // Originally unnamed (name change does not affect this)
bool m_generate; // Underneath a generate
+ bool m_implied; // Not inserted by user
public:
// Node that simply puts name into the output stream
- AstBegin(FileLine* fl, const string& name, AstNode* stmtsp, bool generate=false)
+ AstBegin(FileLine* fl, const string& name, AstNode* stmtsp, bool generate = false,
+ bool implied = false)
: ASTGEN_SUPER(fl)
, m_name(name) {
addNOp1p(stmtsp);
- m_unnamed = (name=="");
+ m_unnamed = (name == "");
m_generate = generate;
+ m_implied = implied;
}
ASTNODE_NODE_FUNCS(Begin)
virtual void dump(std::ostream& str) const;
@@ -3775,6 +3850,7 @@ public:
bool unnamed() const { return m_unnamed; }
void generate(bool flag) { m_generate = flag; }
bool generate() const { return m_generate; }
+ bool implied() const { return m_implied; }
};
class AstInitial : public AstNode {
@@ -3914,22 +3990,65 @@ public:
};
class AstNew : public AstNodeMath {
+ // New as constructor
+ // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it
// Parents: math|stmt
// Children: varref|arraysel, math
public:
- explicit AstNew(FileLine* fl)
+ AstNew(FileLine* fl, AstNode* argsp)
: ASTGEN_SUPER(fl) {
- dtypep(NULL); // V3Width will resolve
+ addNOp2p(argsp);
}
ASTNODE_NODE_FUNCS(New)
- virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) {
- V3ERROR_NA; /* How can from be a const? */ }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual string emitVerilog() { return "new"; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual bool cleanOut() const { return true; }
virtual bool same(const AstNode* samep) const { return true; }
virtual int instrCount() const { return widthInstrs(); }
+ AstNode* argsp() const { return op2p(); }
+};
+
+class AstNewCopy : public AstNodeMath {
+ // New as shallow copy
+ // Parents: math|stmt
+ // Children: varref|arraysel, math
+public:
+ AstNewCopy(FileLine* fl, AstNode* rhsp)
+ : ASTGEN_SUPER(fl) {
+ dtypeFrom(rhsp); // otherwise V3Width will resolve
+ setNOp1p(rhsp);
+ }
+ ASTNODE_NODE_FUNCS(NewCopy)
+ virtual V3Hash sameHash() const { return V3Hash(); }
+ virtual string emitVerilog() { return "new"; }
+ virtual string emitC() { V3ERROR_NA; return ""; }
+ virtual bool cleanOut() const { return true; }
+ virtual bool same(const AstNode* samep) const { return true; }
+ virtual int instrCount() const { return widthInstrs(); }
+ AstNode* rhsp() const { return op1p(); }
+};
+
+class AstNewDynamic : public AstNodeMath {
+ // New for dynamic array
+ // Parents: math|stmt
+ // Children: varref|arraysel, math
+public:
+ AstNewDynamic(FileLine* fl, AstNode* sizep, AstNode* rhsp)
+ : ASTGEN_SUPER(fl) {
+ dtypeFrom(rhsp); // otherwise V3Width will resolve
+ setNOp1p(sizep);
+ setNOp2p(rhsp);
+ }
+ ASTNODE_NODE_FUNCS(NewDynamic)
+ virtual V3Hash sameHash() const { return V3Hash(); }
+ virtual string emitVerilog() { return "new"; }
+ virtual string emitC() { V3ERROR_NA; return ""; }
+ virtual bool cleanOut() const { return true; }
+ virtual bool same(const AstNode* samep) const { return true; }
+ virtual int instrCount() const { return widthInstrs(); }
+ AstNode* sizep() const { return op1p(); }
+ AstNode* rhsp() const { return op2p(); }
};
class AstPragma : public AstNode {
@@ -6763,54 +6882,37 @@ public:
bool emptyBody() const { return argsp()==NULL && initsp()==NULL && stmtsp()==NULL && finalsp()==NULL; }
};
-class AstCCall : public AstNodeStmt {
+class AstCCall : public AstNodeCCall {
// C++ function call
// Parents: Anything above a statement
// Children: Args to the function
-private:
- AstCFunc* m_funcp;
- string m_hiername;
- string m_argTypes;
public:
- AstCCall(FileLine* fl, AstCFunc* funcp, AstNode* argsp=NULL)
- : ASTGEN_SUPER(fl) {
- m_funcp = funcp;
- addNOp1p(argsp);
- }
- AstCCall(AstCCall* oldp, AstCFunc* funcp) // Replacement form for V3Combine
- // Note this removes old attachments from the oldp
- : ASTGEN_SUPER(oldp->fileline()) {
- m_funcp = funcp;
- m_hiername = oldp->hiername();
- m_argTypes = oldp->argTypes();
- if (oldp->argsp()) addNOp1p(oldp->argsp()->unlinkFrBackWithNext());
- }
+ AstCCall(FileLine* fl, AstCFunc* funcp, AstNode* argsp = NULL)
+ : ASTGEN_SUPER(fl, funcp, argsp) {}
+ // Replacement form for V3Combine
+ // Note this removes old attachments from the oldp
+ AstCCall(AstCCall* oldp, AstCFunc* funcp)
+ : ASTGEN_SUPER(oldp, funcp) {}
ASTNODE_NODE_FUNCS(CCall)
- virtual void dump(std::ostream& str=std::cout) const;
- virtual void cloneRelink() { if (m_funcp && m_funcp->clonep()) {
- m_funcp = m_funcp->clonep();
- }}
- virtual const char* broken() const { BROKEN_RTN(m_funcp && !m_funcp->brokeExists()); return NULL; }
- virtual int instrCount() const { return instrCountCall(); }
- virtual V3Hash sameHash() const { return V3Hash(funcp()); }
- virtual bool same(const AstNode* samep) const {
- const AstCCall* asamep = static_cast(samep);
- return (funcp() == asamep->funcp()
- && argTypes() == asamep->argTypes()); }
- AstNode* exprsp() const { return op1p(); } // op1 = expressions to print
- virtual bool isGateOptimizable() const { return false; }
- virtual bool isPredictOptimizable() const { return false; }
- virtual bool isPure() const { return funcp()->pure(); }
- virtual bool isOutputter() const { return !(funcp()->pure()); }
- AstCFunc* funcp() const { return m_funcp; }
- string hiername() const { return m_hiername; }
- void hiername(const string& hn) { m_hiername = hn; }
- string hiernameProtect() const;
- void argTypes(const string& str) { m_argTypes = str; }
- string argTypes() const { return m_argTypes; }
- //
- AstNode* argsp() const { return op1p(); }
- void addArgsp(AstNode* nodep) { addOp1p(nodep); }
+};
+
+class AstCMethodCall : public AstNodeCCall {
+ // C++ method call
+ // Parents: Anything above a statement
+ // Children: Args to the function
+public:
+ AstCMethodCall(FileLine* fl, AstNode* fromp, AstCFunc* funcp, AstNode* argsp = NULL)
+ : ASTGEN_SUPER(fl, funcp, argsp) {
+ setOp1p(fromp);
+ }
+ ASTNODE_NODE_FUNCS(CMethodCall)
+ virtual const char* broken() const {
+ BROKEN_BASE_RTN(AstNodeCCall::broken());
+ BROKEN_RTN(!fromp());
+ return NULL;
+ }
+ AstNode* fromp() const { return op1p(); } // op1 = Extracting what (NULL=TBD during parsing)
+ void fromp(AstNode* nodep) { setOp1p(nodep); }
};
class AstCReturn : public AstNodeStmt {
diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp
index 2cb65de2e..77650f7a4 100644
--- a/src/V3Begin.cpp
+++ b/src/V3Begin.cpp
@@ -125,7 +125,7 @@ private:
while ((pos=dottedname.find("__DOT__")) != string::npos) {
string ident = dottedname.substr(0, pos);
dottedname = dottedname.substr(pos+strlen("__DOT__"));
- if (!nodep->unnamed()) {
+ if (nodep->name() != "") {
if (m_namedScope=="") m_namedScope = ident;
else m_namedScope = m_namedScope + "__DOT__"+ident;
}
diff --git a/src/V3Branch.cpp b/src/V3Branch.cpp
index 8533d475f..ff713d124 100644
--- a/src/V3Branch.cpp
+++ b/src/V3Branch.cpp
@@ -96,7 +96,7 @@ private:
m_likely = lastLikely;
m_unlikely = lastUnlikely;
}
- virtual void visit(AstCCall* nodep) VL_OVERRIDE {
+ virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
checkUnlikely(nodep);
nodep->funcp()->user1Inc();
iterateChildren(nodep);
diff --git a/src/V3Clean.cpp b/src/V3Clean.cpp
index 6581ec37e..16463090a 100644
--- a/src/V3Clean.cpp
+++ b/src/V3Clean.cpp
@@ -88,6 +88,7 @@ private:
if (!nodep->user2() && nodep->hasDType()) {
if (VN_IS(nodep, Var) || VN_IS(nodep, NodeDType) // Don't want to change variable widths!
|| VN_IS(nodep->dtypep()->skipRefp(), AssocArrayDType) // Or arrays
+ || VN_IS(nodep->dtypep()->skipRefp(), DynArrayDType)
|| VN_IS(nodep->dtypep()->skipRefp(), ClassRefDType)
|| VN_IS(nodep->dtypep()->skipRefp(), QueueDType)
|| VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType)
@@ -280,7 +281,7 @@ private:
iterateChildren(nodep);
ensureCleanAndNext(nodep->bodysp());
}
- virtual void visit(AstCCall* nodep) VL_OVERRIDE {
+ virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
iterateChildren(nodep);
ensureCleanAndNext(nodep->argsp());
setClean(nodep, true);
diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp
index e864f2af3..a98ff7bfb 100644
--- a/src/V3Dead.cpp
+++ b/src/V3Dead.cpp
@@ -188,6 +188,10 @@ private:
else nodep->packagep()->user1Inc();
}
}
+ virtual void visit(AstMethodCall* nodep) VL_OVERRIDE {
+ iterateChildren(nodep);
+ checkAll(nodep);
+ }
virtual void visit(AstRefDType* nodep) VL_OVERRIDE {
iterateChildren(nodep);
checkDType(nodep);
@@ -211,6 +215,12 @@ private:
}
checkAll(nodep);
}
+ virtual void visit(AstMemberSel* nodep) VL_OVERRIDE {
+ iterateChildren(nodep);
+ if (nodep->varp()) nodep->varp()->user1Inc();
+ if (nodep->fromp()->dtypep()) nodep->fromp()->dtypep()->user1Inc(); // classref
+ checkAll(nodep);
+ }
virtual void visit(AstModport* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (m_elimCells) {
diff --git a/src/V3DepthBlock.cpp b/src/V3DepthBlock.cpp
index f924703e0..6ddb7e774 100644
--- a/src/V3DepthBlock.cpp
+++ b/src/V3DepthBlock.cpp
@@ -96,7 +96,7 @@ private:
void visitStmt(AstNodeStmt* nodep) {
m_depth++;
if (m_depth > v3Global.opt.compLimitBlocks()
- && !VN_IS(nodep, CCall)) { // Already done
+ && !VN_IS(nodep, NodeCCall)) { // Already done
UINFO(4, "DeepBlocks "<backp(); // Only for debug
if (debug()>=9) backp->dumpTree(cout, "- pre : ");
diff --git a/src/V3Descope.cpp b/src/V3Descope.cpp
index f48a27ce5..4f0ca0aad 100644
--- a/src/V3Descope.cpp
+++ b/src/V3Descope.cpp
@@ -259,7 +259,7 @@ private:
nodep->hierThis(hierThis);
nodep->varScopep(NULL);
}
- virtual void visit(AstCCall* nodep) VL_OVERRIDE {
+ virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
// UINFO(9," "<hiernameProtect());
+ virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
+ if (AstCMethodCall* ccallp = VN_CAST(nodep, CMethodCall)) {
+ // make this a Ast type for future opt
+ iterate(ccallp->fromp());
+ putbs("->");
+ } else {
+ puts(nodep->hiernameProtect());
+ }
puts(nodep->funcp()->nameProtect());
puts("(");
puts(nodep->argTypes());
@@ -402,6 +408,45 @@ public:
if (nodep->addNewline()) text += "\n";
displayNode(nodep, nodep->fmtp()->scopeNamep(), text, nodep->fmtp()->exprsp(), false);
}
+ virtual void visit(AstDumpCtl* nodep) VL_OVERRIDE {
+ switch (nodep->ctlType()) {
+ case VDumpCtlType::FILE:
+ puts("vl_dumpctl_filenamep(true, ");
+ emitCvtPackStr(nodep->exprp());
+ puts(");\n");
+ break;
+ case VDumpCtlType::VARS:
+ // We ignore number of levels to dump in exprp()
+ if (v3Global.opt.trace()) {
+ puts("vlSymsp->TOPp->_traceDumpOpen();\n");
+ } else {
+ puts("VL_PRINTF_MT(\"-Info: ");
+ puts(protect(nodep->fileline()->filename()));
+ puts(":");
+ puts(cvtToStr(nodep->fileline()->lineno()));
+ puts(": $dumpvar ignored, as Verilated without --trace");
+ puts("\\n\");\n");
+ }
+ break;
+ case VDumpCtlType::ALL:
+ // $dumpall currently ignored
+ break;
+ case VDumpCtlType::FLUSH:
+ // $dumpall currently ignored; would need rework of VCD single thread,
+ // or flag we pass-through to next eval() iteration
+ break;
+ case VDumpCtlType::LIMIT:
+ // $dumplimit currently ignored
+ break;
+ case VDumpCtlType::OFF:
+ // Currently ignored as both Vcd and Fst do not support them, as would need "X" dump
+ break;
+ case VDumpCtlType::ON:
+ // Currently ignored as $dumpoff is also ignored
+ break;
+ default: nodep->v3fatalSrc("Bad case, unexpected " << nodep->ctlType().ascii());
+ }
+ }
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
// For use under AstCCalls for dpiImports. ScopeNames under
// displays are handled in AstDisplay
@@ -1464,6 +1509,9 @@ class EmitCImp : EmitCStmts {
return emitVarResetRecurse(varp, adtypep->subDTypep(), depth+1,
".atDefault()" + cvtarray);
}
+ else if (AstDynArrayDType* adtypep = VN_CAST(dtypep, DynArrayDType)) {
+ return emitVarResetRecurse(varp, adtypep->subDTypep(), depth+1, ".atDefault()");
+ }
else if (AstQueueDType* adtypep = VN_CAST(dtypep, QueueDType)) {
return emitVarResetRecurse(varp, adtypep->subDTypep(), depth+1, ".atDefault()");
}
@@ -2110,8 +2158,16 @@ void EmitCImp::emitCoverageImp(AstNodeModule* modp) {
void EmitCImp::emitDestructorImp(AstNodeModule* modp) {
puts("\n");
puts(prefixNameProtect(modp) + "::~" + prefixNameProtect(modp) + "() {\n");
- if (modp->isTop() && v3Global.opt.mtasks()) {
- puts("delete __Vm_threadPoolp; __Vm_threadPoolp = NULL;\n");
+ if (modp->isTop()) {
+ if (v3Global.opt.mtasks()) {
+ puts("delete __Vm_threadPoolp; __Vm_threadPoolp = NULL;\n");
+ }
+ // Call via function in __Trace.cpp as this .cpp file does not have trace header
+ if (v3Global.needTraceDumper()) {
+ puts("#ifdef VM_TRACE\n");
+ puts("if (VL_UNLIKELY(__VlSymsp->__Vm_dumping)) _traceDumpClose();\n");
+ puts("#endif // VM_TRACE\n");
+ }
}
emitTextSection(AstType::atScDtor);
if (modp->isTop()) puts("delete __VlSymsp; __VlSymsp=NULL;\n");
@@ -2304,7 +2360,7 @@ void EmitCImp::emitSettleLoop(const std::string& eval_call, bool initial) {
}
void EmitCImp::emitWrapEval(AstNodeModule* modp) {
- puts("\nvoid " + prefixNameProtect(modp) + "::eval() {\n");
+ puts("\nvoid " + prefixNameProtect(modp) + "::eval_step() {\n");
puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+++++TOP Evaluate " + prefixNameProtect(modp)
+ "::eval\\n\"); );\n");
puts(EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp; // Setup global symbol table\n");
@@ -2316,6 +2372,15 @@ void EmitCImp::emitWrapEval(AstNodeModule* modp) {
putsDecoration("// Initialize\n");
puts("if (VL_UNLIKELY(!vlSymsp->__Vm_didInit)) "
+protect("_eval_initial_loop")+"(vlSymsp);\n");
+ if (v3Global.opt.trace()) {
+ puts("#ifdef VM_TRACE\n");
+ putsDecoration("// Tracing\n");
+ // SystemC's eval loop deals with calling trace, not us
+ if (v3Global.needTraceDumper() && !optSystemC()) {
+ puts("if (VL_UNLIKELY(vlSymsp->__Vm_dumping)) _traceDump();\n");
+ }
+ puts("#endif // VM_TRACE\n");
+ }
if (v3Global.opt.inhibitSim()) {
puts("if (VL_UNLIKELY(__Vm_inhibitSim)) return;\n");
}
@@ -2377,6 +2442,21 @@ void EmitCImp::emitWrapEval(AstNodeModule* modp) {
puts("}\n");
splitSizeInc(10);
+ //
+ if (v3Global.needTraceDumper() && !optSystemC()) {
+ puts("\nvoid " + prefixNameProtect(modp) + "::eval_end_step() {\n");
+ puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+eval_end_step " + prefixNameProtect(modp)
+ + "::eval_end_step\\n\"); );\n");
+ puts("#ifdef VM_TRACE\n");
+ puts(EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp; // Setup global symbol table\n");
+ puts(EmitCBaseVisitor::symTopAssign()+"\n");
+ putsDecoration("// Tracing\n");
+ // SystemC's eval loop deals with calling trace, not us
+ puts("if (VL_UNLIKELY(vlSymsp->__Vm_dumping)) _traceDump();\n");
+ puts("#endif // VM_TRACE\n");
+ puts("}\n");
+ }
+
//
puts("\nvoid " + prefixNameProtect(modp) + "::" + protect("_eval_initial_loop") + "("
+ EmitCBaseVisitor::symClassVar() + ") {\n");
@@ -2693,11 +2773,11 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
ofp()->putsPrivate(!modp->isTop()); // private: unless top
puts(symClassName()+"* __VlSymsp; // Symbol table\n");
ofp()->putsPrivate(false); // public:
- if (modp->isTop() && v3Global.opt.inhibitSim()) {
- puts("bool __Vm_inhibitSim; ///< Set true to disable evaluation of module\n");
- }
- if (modp->isTop() && v3Global.opt.mtasks()) {
- emitMTaskState();
+ if (modp->isTop()) {
+ if (v3Global.opt.inhibitSim()) {
+ puts("bool __Vm_inhibitSim; ///< Set true to disable evaluation of module\n");
+ }
+ if (v3Global.opt.mtasks()) emitMTaskState();
}
emitCoverageDecl(modp); // may flip public/private
@@ -2775,14 +2855,26 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
if (modp->isTop()) {
puts("\n// API METHODS\n");
+ string callEvalEndStep
+ = (v3Global.needTraceDumper() && !optSystemC()) ? "eval_end_step(); " : "";
if (optSystemC()) ofp()->putsPrivate(true); ///< eval() is invoked by our sensitive() calls.
- else puts("/// Evaluate the model. Application must call when inputs change.\n");
- puts("void eval();\n");
+ if (!optSystemC()) puts("/// Evaluate the model. Application must call when inputs change.\n");
+ puts("void eval() { eval_step(); " + callEvalEndStep + "}\n");
+ if (!optSystemC()) puts("/// Evaluate when calling multiple units/models per time step.\n");
+ puts("void eval_step();\n");
+ if (!optSystemC()) {
+ puts("/// Evaluate at end of a timestep for tracing, when using eval_step().\n");
+ puts("/// Application must call after all eval() and before time changes.\n");
+ puts("void eval_end_step()");
+ if (callEvalEndStep == "") puts(" {}\n");
+ else puts(";\n");
+ }
ofp()->putsPrivate(false); // public:
if (!optSystemC()) puts("/// Simulation complete, run final blocks. Application must call on completion.\n");
puts("void final();\n");
if (v3Global.opt.inhibitSim()) {
- puts("void inhibitSim(bool flag) { __Vm_inhibitSim=flag; } ///< Set true to disable evaluation of module\n");
+ puts("/// Disable evaluation of module (e.g. turn off)\n");
+ puts("void inhibitSim(bool flag) { __Vm_inhibitSim = flag; }\n");
}
}
@@ -2791,6 +2883,9 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
ofp()->putsPrivate(true); // private:
puts("static void "+protect("_eval_initial_loop")
+"("+EmitCBaseVisitor::symClassVar()+");\n");
+ if (v3Global.needTraceDumper() && !optSystemC()) puts("void _traceDump();");
+ if (v3Global.needTraceDumper()) puts("void _traceDumpOpen();");
+ if (v3Global.needTraceDumper()) puts("void _traceDumpClose();");
}
if (!VN_IS(modp, Class)) {
@@ -2978,14 +3073,45 @@ class EmitCTrace : EmitCStmts {
void emitTraceHeader() {
// Includes
- puts("#include \""+v3Global.opt.traceSourceName()+"_c.h\"\n");
- puts("#include \""+ symClassName() +".h\"\n");
+ puts("#include \"" + v3Global.opt.traceSourceLang() + ".h\"\n");
+ puts("#include \"" + symClassName() + ".h\"\n");
puts("\n");
}
void emitTraceSlow() {
puts("\n//======================\n\n");
+ if (v3Global.needTraceDumper() && !optSystemC()) {
+ puts("void " + topClassName() + "::_traceDump() {\n");
+ // Caller checked for __Vm_dumperp non-NULL
+ puts( "VerilatedLockGuard lock(__VlSymsp->__Vm_dumperMutex);\n");
+ puts( "__VlSymsp->__Vm_dumperp->dump(VL_TIME_Q());\n");
+ puts("}\n");
+ splitSizeInc(10);
+ }
+
+ if (v3Global.needTraceDumper()) {
+ puts("void " + topClassName() + "::_traceDumpOpen() {\n");
+ puts( "VerilatedLockGuard lock(__VlSymsp->__Vm_dumperMutex);\n");
+ puts( "if (VL_UNLIKELY(!__VlSymsp->__Vm_dumperp)) {\n");
+ puts( "__VlSymsp->__Vm_dumperp = new " + v3Global.opt.traceClassLang() + "();\n");
+ puts( "const char* cp = vl_dumpctl_filenamep();\n");
+ puts( "trace(__VlSymsp->__Vm_dumperp, 0, 0);\n");
+ puts( "__VlSymsp->__Vm_dumperp->open(vl_dumpctl_filenamep());\n");
+ puts( "__VlSymsp->__Vm_dumperp->changeThread();\n");
+ puts( "__VlSymsp->__Vm_dumping = true;\n");
+ puts( "}\n");
+ puts("}\n");
+ splitSizeInc(10);
+
+ puts("void " + topClassName() + "::_traceDumpClose() {\n");
+ puts( "VerilatedLockGuard lock(__VlSymsp->__Vm_dumperMutex);\n");
+ puts( "__VlSymsp->__Vm_dumping = false;\n");
+ puts( "delete __VlSymsp->__Vm_dumperp; __VlSymsp->__Vm_dumperp = NULL;\n");
+ puts("}\n");
+ splitSizeInc(10);
+ }
+
puts("void "+topClassName()+"::trace(");
puts(v3Global.opt.traceClassBase()+"C* tfp, int, int) {\n");
puts( "tfp->spTrace()->addCallback("
diff --git a/src/V3EmitCInlines.cpp b/src/V3EmitCInlines.cpp
index 0090b880a..5d60724af 100644
--- a/src/V3EmitCInlines.cpp
+++ b/src/V3EmitCInlines.cpp
@@ -50,6 +50,10 @@ class EmitCInlines : EmitCBaseVisitor {
v3Global.needHeavy(true);
iterateChildren(nodep);
}
+ virtual void visit(AstDynArrayDType* nodep) VL_OVERRIDE {
+ v3Global.needHeavy(true);
+ iterateChildren(nodep);
+ }
virtual void visit(AstQueueDType* nodep) VL_OVERRIDE {
v3Global.needHeavy(true);
iterateChildren(nodep);
@@ -62,10 +66,19 @@ class EmitCInlines : EmitCBaseVisitor {
v3Global.needHeavy(true);
iterateChildren(nodep);
}
+ virtual void visit(AstNew* nodep) VL_OVERRIDE {
+ if (v3Global.opt.savable()) v3error("Unsupported: --savable with dynamic new");
+ iterateChildren(nodep);
+ }
virtual void visit(AstAtoN* nodep) VL_OVERRIDE {
v3Global.needHeavy(true);
iterateChildren(nodep);
}
+ virtual void visit(AstDumpCtl* nodep) VL_OVERRIDE {
+ if (v3Global.opt.trace()) v3Global.needTraceDumper(true);
+ v3Global.needHeavy(true);
+ iterateChildren(nodep);
+ }
virtual void visit(AstPutcN* nodep) VL_OVERRIDE {
v3Global.needHeavy(true);
iterateChildren(nodep);
diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp
index 4d2a2a79d..2de114211 100644
--- a/src/V3EmitCMake.cpp
+++ b/src/V3EmitCMake.cpp
@@ -160,13 +160,13 @@ class CMakeEmitter {
}
if (v3Global.opt.trace()) {
global.push_back("${VERILATOR_ROOT}/include/"
- + v3Global.opt.traceSourceName()+"_c.cpp");
+ + v3Global.opt.traceSourceBase() + "_c.cpp");
if (v3Global.opt.systemC()) {
if (v3Global.opt.traceFormat() != TraceFormat::VCD) {
v3error("Unsupported: This trace format is not supported in SystemC, use VCD format.");
}
global.push_back("${VERILATOR_ROOT}/include/"
- + v3Global.opt.traceSourceName()+"_sc.cpp");
+ + v3Global.opt.traceSourceLang() + ".cpp");
}
}
if (v3Global.opt.mtasks()) {
diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp
index 6cdc1c635..69dbc8ad4 100644
--- a/src/V3EmitCSyms.cpp
+++ b/src/V3EmitCSyms.cpp
@@ -417,6 +417,14 @@ void EmitCSyms::emitSymHdr() {
puts("\n// LOCAL STATE\n");
puts("const char* __Vm_namep;\n"); // Must be before subcells, as constructor order needed before _vlCoverInsert.
+ if (v3Global.needTraceDumper()) {
+ // __Vm_dumperp is local, otherwise we wouldn't know what design's eval()
+ // should call a global dumpperp
+ puts("bool __Vm_dumping; // Dumping is active\n");
+ puts("VerilatedMutex __Vm_dumperMutex; // Protect __Vm_dumperp\n");
+ puts(v3Global.opt.traceClassLang()
+ + "* __Vm_dumperp VL_GUARDED_BY(__Vm_dumperMutex); /// Trace class for $dump*\n");
+ }
if (v3Global.opt.trace()) {
puts("bool __Vm_activity; ///< Used by trace routines to determine change occurred\n");
}
@@ -582,10 +590,12 @@ void EmitCSyms::emitSymImp() {
puts("\n// FUNCTIONS\n");
puts(symClassName()+"::"+symClassName()+"("+topClassName()+"* topp, const char* namep)\n");
puts(" // Setup locals\n");
- puts(" : __Vm_namep(namep)\n"); // No leak, as we get destroyed when the top is destroyed
- if (v3Global.opt.trace()) {
- puts(" , __Vm_activity(false)\n");
+ puts(" : __Vm_namep(namep)\n"); // No leak, as gets destroyed when the top is destroyed
+ if (v3Global.needTraceDumper()) {
+ puts(" , __Vm_dumping(false)\n");
+ puts(" , __Vm_dumperp(NULL)\n");
}
+ if (v3Global.opt.trace()) puts(" , __Vm_activity(false)\n");
puts(" , __Vm_didInit(false)\n");
puts(" // Setup submodule names\n");
char comma = ',';
diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp
index 284e02bc4..c8a83ce2a 100644
--- a/src/V3EmitMk.cpp
+++ b/src/V3EmitMk.cpp
@@ -85,12 +85,12 @@ public:
putMakeClassEntry(of, "verilated_cov.cpp");
}
if (v3Global.opt.trace()) {
- putMakeClassEntry(of, v3Global.opt.traceSourceName()+"_c.cpp");
+ putMakeClassEntry(of, v3Global.opt.traceSourceBase() + "_c.cpp");
if (v3Global.opt.systemC()) {
if (v3Global.opt.traceFormat() != TraceFormat::VCD) {
v3error("Unsupported: This trace format is not supported in SystemC, use VCD format.");
} else {
- putMakeClassEntry(of, v3Global.opt.traceSourceName()+"_sc.cpp");
+ putMakeClassEntry(of, v3Global.opt.traceSourceLang() + ".cpp");
}
}
}
diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp
index a07f6d477..afa57b8cf 100644
--- a/src/V3EmitV.cpp
+++ b/src/V3EmitV.cpp
@@ -76,7 +76,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
- if (nodep->unnamed()) {
+ if (nodep->name() == "") {
putbs("begin\n");
} else {
putbs("begin : "+nodep->name()+"\n");
@@ -84,11 +84,6 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
iterateChildren(nodep);
puts("end\n");
}
- virtual void visit(AstGenerate* nodep) VL_OVERRIDE {
- putfs(nodep, "generate\n");
- iterateChildren(nodep);
- putqs(nodep, "end\n");
- }
virtual void visit(AstFinal* nodep) VL_OVERRIDE {
putfs(nodep, "final begin\n");
iterateChildren(nodep);
diff --git a/src/V3Error.h b/src/V3Error.h
index b6adb3681..79e8c49ae 100644
--- a/src/V3Error.h
+++ b/src/V3Error.h
@@ -102,6 +102,7 @@ public:
REDEFMACRO, // Redefining existing define macro
SELRANGE, // Selection index out of range
SHORTREAL, // Shortreal not supported
+ SPLITVAR, // Cannot split the variable
STMTDLY, // Delayed statement
SYMRSVDWORD, // Symbol is Reserved Word
SYNCASYNCNET, // Mixed sync + async reset
@@ -153,7 +154,7 @@ public:
"MULTIDRIVEN", "MULTITOP",
"PINMISSING", "PINNOCONNECT", "PINCONNECTEMPTY", "PROCASSWIRE",
"REALCVT", "REDEFMACRO",
- "SELRANGE", "SHORTREAL", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET",
+ "SELRANGE", "SHORTREAL", "SPLITVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET",
"TICKCOUNT",
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS",
"UNPACKED", "UNSIGNED", "UNUSED",
diff --git a/src/V3GenClk.cpp b/src/V3GenClk.cpp
index 34573f9f1..eda3e027c 100644
--- a/src/V3GenClk.cpp
+++ b/src/V3GenClk.cpp
@@ -168,7 +168,7 @@ private:
iterateChildren(nodep);
}
}
- virtual void visit(AstCCall* nodep) VL_OVERRIDE {
+ virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (!nodep->funcp()->entryPoint()) {
// Enter the function and trace it
diff --git a/src/V3Global.h b/src/V3Global.h
index 0011df4ff..da20b88cd 100644
--- a/src/V3Global.h
+++ b/src/V3Global.h
@@ -71,15 +71,16 @@ inline bool operator==(VWidthMinUsage::en lhs, const VWidthMinUsage& rhs) {
class V3Global {
// Globals
- AstNetlist* m_rootp; // Root of entire netlist
- VWidthMinUsage m_widthMinUsage; // What AstNode::widthMin() is used for
+ AstNetlist* m_rootp; // Root of entire netlist
+ VWidthMinUsage m_widthMinUsage; // What AstNode::widthMin() is used for
- int m_debugFileNumber; // Number to append to debug files created
- bool m_assertDTypesResolved; // Tree should have dtypep()'s
- bool m_constRemoveXs; // Const needs to strip any Xs
- bool m_needHInlines; // Need __Inlines file
- bool m_needHeavy; // Need verilated_heavy.h include
- bool m_dpi; // Need __Dpi include files
+ int m_debugFileNumber; // Number to append to debug files created
+ bool m_assertDTypesResolved; // Tree should have dtypep()'s
+ bool m_constRemoveXs; // Const needs to strip any Xs
+ bool m_needTraceDumper; // Need __Vm_dumperp in symbols
+ bool m_needHInlines; // Need __Inlines file
+ bool m_needHeavy; // Need verilated_heavy.h include
+ bool m_dpi; // Need __Dpi include files
public:
// Options
@@ -92,6 +93,7 @@ public:
m_widthMinUsage = VWidthMinUsage::LINT_WIDTH;
m_assertDTypesResolved = false;
m_constRemoveXs = false;
+ m_needTraceDumper = false;
m_needHInlines = false;
m_needHeavy = false;
m_dpi = false;
@@ -119,10 +121,12 @@ public:
char digits[100]; sprintf(digits, "%03d", m_debugFileNumber);
return opt.makeDir()+"/"+opt.prefix()+"_"+digits+"_"+nameComment;
}
+ bool needTraceDumper() const { return m_needTraceDumper; }
+ void needTraceDumper(bool flag) { m_needTraceDumper = flag; }
bool needHInlines() const { return m_needHInlines; }
- void needHInlines(bool flag) { m_needHInlines=flag; }
+ void needHInlines(bool flag) { m_needHInlines = flag; }
bool needHeavy() const { return m_needHeavy; }
- void needHeavy(bool flag) { m_needHeavy=flag; }
+ void needHeavy(bool flag) { m_needHeavy = flag; }
bool dpi() const { return m_dpi; }
void dpi(bool flag) { m_dpi = flag; }
};
diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp
index dd32eda44..364b3ec77 100644
--- a/src/V3Inline.cpp
+++ b/src/V3Inline.cpp
@@ -150,7 +150,8 @@ private:
}
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
// Cleanup link until V3LinkDot can correct it
- if (!nodep->packagep()) nodep->taskp(NULL);
+ // MethodCalls not currently supported by inliner, so keep linked
+ if (!nodep->packagep() && !VN_IS(nodep, MethodCall)) nodep->taskp(NULL);
iterateChildren(nodep);
}
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
diff --git a/src/V3InstrCount.cpp b/src/V3InstrCount.cpp
index f0d26cd16..94c54c3d7 100644
--- a/src/V3InstrCount.cpp
+++ b/src/V3InstrCount.cpp
@@ -236,7 +236,7 @@ private:
markCost(nodep);
UASSERT_OBJ(nodep == m_startNodep, nodep, "Multiple actives, or not start node");
}
- virtual void visit(AstCCall* nodep) VL_OVERRIDE {
+ virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
VisitBase vb(this, nodep);
iterateChildren(nodep);
m_tracingCall = true;
diff --git a/src/V3Life.cpp b/src/V3Life.cpp
index 44d86ab18..e02164178 100644
--- a/src/V3Life.cpp
+++ b/src/V3Life.cpp
@@ -410,7 +410,7 @@ private:
bodyLifep->lifeToAbove();
VL_DO_DANGLING(delete bodyLifep, bodyLifep);
}
- virtual void visit(AstCCall* nodep) VL_OVERRIDE {
+ virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
//UINFO(4," CCALL "<isTop()) iterateChildren(nodep);
}
- virtual void visit(AstCCall* nodep) VL_OVERRIDE {
+ virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (!nodep->funcp()->entryPoint()) {
// Enter the function and trace it
@@ -319,7 +319,7 @@ private:
// Only track the top scopes, not lower level functions
if (nodep->isTop()) iterateChildren(nodep);
}
- virtual void visit(AstCCall* nodep) VL_OVERRIDE {
+ virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (!nodep->funcp()->entryPoint()) {
// Enter the function and trace it
diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp
index c7a045d1d..ccc9aa8d3 100644
--- a/src/V3LinkDot.cpp
+++ b/src/V3LinkDot.cpp
@@ -683,7 +683,6 @@ class LinkDotFindVisitor : public AstNVisitor {
string m_scope; // Scope text
AstBegin* m_beginp; // Current Begin/end block
AstNodeFTask* m_ftaskp; // Current function/task
- bool m_inGenerate; // Inside a generate
bool m_inRecursion; // Inside a recursive module
int m_paramNum; // Parameter number, for position based connection
int m_beginNum; // Begin block number, 0=none seen
@@ -891,16 +890,6 @@ class LinkDotFindVisitor : public AstNVisitor {
nodep->user1p(m_curSymp);
iterateChildren(nodep);
}
- virtual void visit(AstGenerate* nodep) VL_OVERRIDE {
- // Begin: ... blocks often replicate under genif/genfor, so simply
- // suppress duplicate checks. See t_gen_forif.v for an example.
- bool lastInGen = m_inGenerate;
- {
- m_inGenerate = true;
- iterateChildren(nodep);
- }
- m_inGenerate = lastInGen;
- }
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
UINFO(5," "<name(nodep->name()+cvtToStr(m_beginNum));
}
- // Just for loop index, make special name. The [00] is so it will "dearray" to same
- // name as after we expand the GENFOR
- if (nodep->genforp()) nodep->name(nodep->name());
}
// All blocks are numbered in the standard, IE we start with "genblk1" even if only one.
if (nodep->name()=="" && nodep->unnamed()) {
@@ -928,20 +914,24 @@ class LinkDotFindVisitor : public AstNVisitor {
}
}
}
- int oldNum = m_beginNum;
- AstBegin* oldbegin = m_beginp;
- VSymEnt* oldCurSymp = m_curSymp;
- {
- m_beginNum = 0;
- m_beginp = nodep;
- m_curSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_packagep);
- m_curSymp->fallbackp(oldCurSymp);
- // Iterate
+ if (nodep->name() == "") {
iterateChildren(nodep);
+ } else {
+ int oldNum = m_beginNum;
+ AstBegin* oldbegin = m_beginp;
+ VSymEnt* oldCurSymp = m_curSymp;
+ {
+ m_beginNum = 0;
+ m_beginp = nodep;
+ m_curSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_packagep);
+ m_curSymp->fallbackp(oldCurSymp);
+ // Iterate
+ iterateChildren(nodep);
+ }
+ m_curSymp = oldCurSymp;
+ m_beginp = oldbegin;
+ m_beginNum = oldNum;
}
- m_curSymp = oldCurSymp;
- m_beginp = oldbegin;
- m_beginNum = oldNum;
}
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
// NodeTask: Remember its name for later resolution
@@ -1202,7 +1192,6 @@ public:
m_statep = statep;
m_beginp = NULL;
m_ftaskp = NULL;
- m_inGenerate = false;
m_inRecursion = false;
m_paramNum = 0;
m_beginNum = 0;
@@ -2068,6 +2057,12 @@ private:
AstVarXRef* refp = new AstVarXRef(nodep->fileline(), nodep->name(),
m_ds.m_dotText, false); // lvalue'ness computed later
refp->varp(varp);
+ if (varp->attrSplitVar()) {
+ refp->v3warn(SPLITVAR, varp->prettyNameQ()
+ << " has split_var metacomment but will not be split because"
+ << " it is accessed from another module via a dot.");
+ varp->attrSplitVar(false);
+ }
m_ds.m_dotText = "";
if (m_ds.m_unresolved && m_ds.m_unlinkedScope) {
string dotted = refp->dotted();
@@ -2464,8 +2459,10 @@ private:
checkNoDot(nodep);
VSymEnt* oldCurSymp = m_curSymp;
{
- m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
- UINFO(5," cur=se"<name() != "") {
+ m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
+ UINFO(5," cur=se"<attrSFormat(true);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
+ else if (nodep->attrType() == AstAttrType::VAR_SPLIT_VAR) {
+ UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
+ if (!VN_IS(m_modp, Module)) {
+ m_varp->v3warn(SPLITVAR, m_varp->prettyNameQ() << " has split_var metacomment, "
+ "but will not be split because it is not declared in a module.");
+ } else {
+ m_varp->attrSplitVar(true);
+ }
+ VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
+ }
else if (nodep->attrType() == AstAttrType::VAR_SC_BV) {
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
m_varp->attrScBv(true);
@@ -435,7 +445,7 @@ private:
new AstConst(fl, 1),
new AstConst(fl, -1))));
stmtsp->addNext(new AstWhile(fl, condp, newp, incp));
- newp = new AstBegin(nodep->fileline(), "", stmtsp);
+ newp = new AstBegin(nodep->fileline(), "", stmtsp, false, true);
dimension--;
}
//newp->dumpTree(cout, "-foreach-new:");
@@ -488,6 +498,21 @@ private:
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
V3Config::applyCoverageBlock(m_modp, nodep);
cleanFileline(nodep);
+ AstNode* backp = nodep->backp();
+ // IEEE says directly nested item is not a new block
+ bool nestedIf = (nodep->implied() // User didn't provide begin/end
+ && (VN_IS(nodep->stmtsp(), GenIf)
+ || VN_IS(nodep->stmtsp(), GenCase)) // Has an if/case
+ && !nodep->stmtsp()->nextp()); // Has only one item
+ // It's not FOR(BEGIN(...)) but we earlier changed it to BEGIN(FOR(...))
+ if (nodep->genforp() && nodep->name() == "") {
+ nodep->name("genblk");
+ }
+ else if (nodep->generate() && nodep->name() == ""
+ && (VN_IS(backp, CaseItem) || VN_IS(backp, GenIf))
+ && !nestedIf) {
+ nodep->name("genblk");
+ }
iterateChildren(nodep);
}
virtual void visit(AstCase* nodep) VL_OVERRIDE {
diff --git a/src/V3Options.cpp b/src/V3Options.cpp
index eb56d87b2..724fc37e4 100644
--- a/src/V3Options.cpp
+++ b/src/V3Options.cpp
@@ -786,6 +786,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
else if ( onoffb(sw, "-skip-identical", bflag/*ref*/)) { m_skipIdentical = bflag; }
else if ( onoff (sw, "-stats", flag/*ref*/)) { m_stats = flag; }
else if ( onoff (sw, "-stats-vars", flag/*ref*/)) { m_statsVars = flag; m_stats |= flag; }
+ else if ( onoff (sw, "-structs-unpacked", flag/*ref*/)) { m_structsPacked = flag; }
else if (!strcmp(sw, "-sv")) { m_defaultLanguage = V3LangCode::L1800_2005; }
else if ( onoff (sw, "-threads-coarsen", flag/*ref*/)) { m_threadsCoarsen = flag; } // Undocumented, debug
else if ( onoff (sw, "-trace", flag/*ref*/)) { m_trace = flag; }
@@ -1489,6 +1490,7 @@ V3Options::V3Options() {
m_savable = false;
m_stats = false;
m_statsVars = false;
+ m_structsPacked = true;
m_systemC = false;
m_threads = 0;
m_threadsDpiPure = true;
diff --git a/src/V3Options.h b/src/V3Options.h
index dac7c3402..339349fdc 100644
--- a/src/V3Options.h
+++ b/src/V3Options.h
@@ -184,6 +184,7 @@ class V3Options {
bool m_relativeIncludes; // main switch: --relative-includes
bool m_reportUnoptflat; // main switch: --report-unoptflat
bool m_savable; // main switch: --savable
+ bool m_structsPacked; // main switch: --structs-packed
bool m_systemC; // main switch: --sc: System C instead of simple C++
bool m_stats; // main switch: --stats
bool m_statsVars; // main switch: --stats-vars
@@ -322,6 +323,7 @@ class V3Options {
bool savable() const { return m_savable; }
bool stats() const { return m_stats; }
bool statsVars() const { return m_statsVars; }
+ bool structsPacked() const { return m_structsPacked; }
bool assertOn() const { return m_assert; } // assertOn as __FILE__ may be defined
bool autoflush() const { return m_autoflush; }
bool bboxSys() const { return m_bboxSys; }
@@ -467,7 +469,11 @@ class V3Options {
bool oTable() const { return m_oTable; }
string traceClassBase() const { return m_traceFormat.classBase(); }
- string traceSourceName() const { return m_traceFormat.sourceName(); }
+ string traceClassLang() const { return m_traceFormat.classBase() + (systemC() ? "Sc" : "C"); }
+ string traceSourceBase() const { return m_traceFormat.sourceName(); }
+ string traceSourceLang() const {
+ return m_traceFormat.sourceName() + (systemC() ? "_sc" : "_c");
+ }
// METHODS (from main)
static string version();
diff --git a/src/V3Order.cpp b/src/V3Order.cpp
index 703b93b51..1644f14c8 100644
--- a/src/V3Order.cpp
+++ b/src/V3Order.cpp
@@ -91,6 +91,7 @@
#include "V3Partition.h"
#include "V3PartitionGraph.h"
#include "V3SenTree.h"
+#include "V3SplitVar.h"
#include "V3Stats.h"
#include "V3Order.h"
@@ -892,32 +893,48 @@ private:
m_graph.userClearVertices();
// May be very large vector, so only report the "most important"
// elements. Up to 10 of the widest
- std::cerr< canSplitList;
int lim = m_unoptflatVars.size() < 10 ? m_unoptflatVars.size() : 10;
for (int i = 0; i < lim; i++) {
OrderVarStdVertex* vsvertexp = m_unoptflatVars[i];
AstVar* varp = vsvertexp->varScp()->varp();
- std::cerr<fileline()<<" "<prettyName()<width()<<", fanout "
- <fanout()<fileline() << " "
+ << varp->prettyName() << std::dec << ", width " << varp->width()
+ << ", fanout " << vsvertexp->fanout();
+ if (canSplit) {
+ std::cerr <<", can split_var";
+ canSplitList.insert(varp);
+ }
+ std::cerr << std::endl;
}
// Up to 10 of the most fanned out
- std::cerr<varScp()->varp();
- std::cerr<fileline()<<" "<prettyName()
- <<", width "<width()
- <<", fanout "<fanout()<fileline() << " "
+ << varp->prettyName() << ", width " << std::dec << varp->width()
+ << ", fanout " << vsvertexp->fanout();
+ if (canSplit) {
+ std::cerr << ", can split_var";
+ canSplitList.insert(varp);
+ }
+ std::cerr<=9) nodep->dumpTree(cout, "-genin: ");
- iterateChildren(nodep);
- // After expanding the generate, all statements under it can be moved
- // up, and the generate block deleted as it's not relevant
- if (AstNode* stmtsp = nodep->stmtsp()) {
- stmtsp->unlinkFrBackWithNext();
- nodep->replaceWith(stmtsp);
- if (debug()>=9) stmtsp->dumpTree(cout, "-genout: ");
- } else {
- nodep->unlinkFrBack();
- }
- VL_DO_DANGLING(nodep->deleteTree(), nodep);
- }
virtual void visit(AstGenIf* nodep) VL_OVERRIDE {
UINFO(9," GENIF "<condp());
diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp
index f742fdad2..b8ae1f469 100644
--- a/src/V3Partition.cpp
+++ b/src/V3Partition.cpp
@@ -1777,7 +1777,7 @@ private:
}
iterateChildren(nodep);
}
- virtual void visit(AstCCall* nodep) VL_OVERRIDE {
+ virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
iterateChildren(nodep);
// Enter the function and trace it
m_tracingCall = true;
diff --git a/src/V3ProtectLib.cpp b/src/V3ProtectLib.cpp
index b44edf500..6e64d7563 100644
--- a/src/V3ProtectLib.cpp
+++ b/src/V3ProtectLib.cpp
@@ -353,7 +353,8 @@ class ProtectVisitor : public AstNVisitor {
nodep->v3error("Unsupported: unpacked arrays with protect-lib on "<prettyNameQ());
}
if (nodep->direction() == VDirection::INPUT) {
- if (nodep->isUsedClock()) {
+ if (nodep->isUsedClock()
+ || nodep->attrClocker() == VVarAttrClocker::CLOCKER_YES) {
handleClock(nodep);
} else {
handleDataInput(nodep);
diff --git a/src/V3Scope.cpp b/src/V3Scope.cpp
index 315394e48..f2f7e0d87 100644
--- a/src/V3Scope.cpp
+++ b/src/V3Scope.cpp
@@ -386,7 +386,7 @@ private:
UASSERT_OBJ(newp, nodep, "No clone for package function");
nodep->taskp(newp);
UINFO(9," New pkg-taskref "<taskp(NULL);
UINFO(9," New pkg-taskref "< // sort
+#include