'Merge from master for release.'
This commit is contained in:
commit
e69c380205
12
.travis.yml
12
.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"
|
||||
|
|
|
|||
25
Changes
25
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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ endif::[]
|
|||
^.^| *Welcome to Verilator, the fastest free Verilog HDL simulator.*
|
||||
+++ <br/> +++ • Accepts synthesizable Verilog or SystemVerilog
|
||||
+++ <br/> +++ • Performs lint code-quality checks
|
||||
+++ <br/> +++ • Compiles into multithreaded {cpp}, SystemC, or (soon) {cpp}-under-Python
|
||||
+++ <br/> +++ • Compiles into multithreaded {cpp}, or SystemC
|
||||
+++ <br/> +++ • 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
|
||||
|
|
|
|||
219
bin/verilator
219
bin/verilator
|
|
@ -421,6 +421,7 @@ more information.
|
|||
+verilator+prof+threads+window+I<value> Set profile duration
|
||||
+verilator+rand+reset+I<value> Set random reset technique
|
||||
+verilator+seed+I<value> 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<sformat> 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 <text...>*/
|
||||
|
||||
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<split_var> 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<split_var> 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<split_var>.
|
||||
|
||||
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<examples/make_tracing_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<examples/make_tracing_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<verilator_coverage>, L<verilator_gantt>, L<verilator_profcfunc>, L<make>,
|
|||
|
||||
L<verilator --help> which is the source for this document,
|
||||
|
||||
and internals.txt in the distribution.
|
||||
and docs/internals.adoc in the distribution.
|
||||
|
||||
=cut
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <verilated_vcd_c.h>
|
||||
#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");
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -1602,6 +1602,25 @@ IData VL_ATOI_N(const std::string& str, int base) VL_PURE {
|
|||
return static_cast<IData>(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<QData>(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<QData>(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, "",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Code2SymbolType::iterator, bool> p
|
||||
= m_code2symbol.insert(std::make_pair(code, static_cast<fstHandle>(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);
|
||||
|
|
|
|||
|
|
@ -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<char> 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?
|
||||
|
|
|
|||
|
|
@ -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 T_Value, size_t T_MaxSize = 0> 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<T_Value,T_MaxSize>& 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
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@ class VerilatedVcdSingleton {
|
|||
private:
|
||||
typedef std::vector<VerilatedVcd*> 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:
|
||||
|
|
|
|||
|
|
@ -103,9 +103,9 @@ private:
|
|||
typedef std::vector<VerilatedVcdSig> SigVec;
|
||||
SigVec m_sigs; ///< Pointer to signal information
|
||||
typedef std::vector<VerilatedVcdCallInfo*> CallbackVec;
|
||||
CallbackVec m_callbacks; ///< Routines to perform dumping
|
||||
CallbackVec m_callbacks; ///< Routines to perform dumping
|
||||
typedef std::map<std::string,std::string> 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?
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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 <stdint.h>
|
||||
|
|
@ -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 <inttypes.h> // Solaris
|
||||
# include <stdint.h> // Linux and most flavors
|
||||
# include <sys/types.h> // __WORDSIZE
|
||||
|
|
|
|||
|
|
@ -233,6 +233,7 @@ RAW_OBJS = \
|
|||
V3Slice.o \
|
||||
V3Split.o \
|
||||
V3SplitAs.o \
|
||||
V3SplitVar.o \
|
||||
V3Stats.o \
|
||||
V3StatsReport.o \
|
||||
V3String.o \
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
102
src/V3Ast.h
102
src/V3Ast.h
|
|
@ -55,6 +55,12 @@ typedef std::set<int> 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<Ast ## nodetypename>(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<en>(_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<const AstNodeCCall*>(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 {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "V3Global.h"
|
||||
#include "V3Graph.h"
|
||||
#include "V3PartitionGraph.h" // Just for mtask dumping
|
||||
#include "V3EmitCBase.h"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <iomanip>
|
||||
|
|
@ -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<<" "<<funcp()->name()<<" => ";
|
||||
funcp()->dump(str);
|
||||
}
|
||||
}
|
||||
void AstCFunc::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (slow()) str<<" [SLOW]";
|
||||
|
|
|
|||
298
src/V3AstNodes.h
298
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<const AstAssocArrayDType*>(samep);
|
||||
return subDTypep() == asamep->subDTypep(); }
|
||||
virtual bool similarDType(AstNodeDType* samep) const {
|
||||
const AstAssocArrayDType* asamep = static_cast<const AstAssocArrayDType*>(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<const AstCCall*>(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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 "<<m_depth<<" "<<nodep<<endl);
|
||||
AstNode* backp = nodep->backp(); // Only for debug
|
||||
if (debug()>=9) backp->dumpTree(cout, "- pre : ");
|
||||
|
|
|
|||
|
|
@ -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," "<<nodep<<endl);
|
||||
iterateChildren(nodep);
|
||||
// Convert the hierch name
|
||||
|
|
|
|||
156
src/V3EmitC.cpp
156
src/V3EmitC.cpp
|
|
@ -307,8 +307,14 @@ public:
|
|||
puts(".data()"); // Access returned std::array as C array
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCCall* nodep) VL_OVERRIDE {
|
||||
puts(nodep->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("
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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 = ',';
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 "<<nodep<<endl);
|
||||
iterateChildren(nodep);
|
||||
// Enter the function and trace it
|
||||
|
|
|
|||
|
|
@ -72,7 +72,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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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," "<<nodep<<endl);
|
||||
// Rename "genblk"s to include a number
|
||||
|
|
@ -909,9 +898,6 @@ class LinkDotFindVisitor : public AstNVisitor {
|
|||
++m_beginNum;
|
||||
nodep->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"<<cvtToHex(m_curSymp)<<endl);
|
||||
if (nodep->name() != "") {
|
||||
m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
|
||||
UINFO(5," cur=se"<<cvtToHex(m_curSymp)<<endl);
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_ds.m_dotSymp = m_curSymp = oldCurSymp;
|
||||
|
|
|
|||
|
|
@ -305,6 +305,16 @@ private:
|
|||
m_varp->attrSFormat(true);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_SPLIT_VAR) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
if (!VN_IS(m_modp, Module)) {
|
||||
m_varp->v3warn(SPLITVAR, m_varp->prettyNameQ() << " has split_var metacomment, "
|
||||
"but will not be split because it is not declared in a module.");
|
||||
} else {
|
||||
m_varp->attrSplitVar(true);
|
||||
}
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_SC_BV) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
m_varp->attrScBv(true);
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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<<V3Error::msgPrefix()
|
||||
<<" Widest candidate vars to split:"<<endl;
|
||||
std::cerr << V3Error::warnMore() << "... Widest candidate vars to split:" << endl;
|
||||
std::stable_sort(m_unoptflatVars.begin(), m_unoptflatVars.end(), OrderVarWidthCmp());
|
||||
vl_unordered_set<const AstVar*> 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<<V3Error::msgPrefix()<<" "
|
||||
<<varp->fileline()<<" "<<varp->prettyName()<<std::dec
|
||||
<<", width "<<varp->width()<<", fanout "
|
||||
<<vsvertexp->fanout()<<endl;
|
||||
const bool canSplit = V3SplitVar::canSplitVar(varp);
|
||||
std::cerr << V3Error::warnMore() << " " << varp->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<<V3Error::msgPrefix()
|
||||
<<" Most fanned out candidate vars to split:"<<endl;
|
||||
std::cerr << V3Error::warnMore()
|
||||
<< "... Most fanned out candidate vars to split:" << endl;
|
||||
std::stable_sort(m_unoptflatVars.begin(), m_unoptflatVars.end(),
|
||||
OrderVarFanoutCmp());
|
||||
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<<V3Error::msgPrefix()<<" "
|
||||
<<varp->fileline()<<" "<<varp->prettyName()
|
||||
<<", width "<<std::dec<<varp->width()
|
||||
<<", fanout "<<vsvertexp->fanout()<<endl;
|
||||
const bool canSplit = V3SplitVar::canSplitVar(varp);
|
||||
std::cerr << V3Error::warnMore() << " " << varp->fileline() << " "
|
||||
<< varp->prettyName() << ", width " << std::dec << varp->width()
|
||||
<< ", fanout " << vsvertexp->fanout();
|
||||
if (canSplit) {
|
||||
std::cerr << ", can split_var";
|
||||
canSplitList.insert(varp);
|
||||
}
|
||||
std::cerr<<endl;
|
||||
}
|
||||
if (!canSplitList.empty()) {
|
||||
std::cerr << V3Error::warnMore()
|
||||
<< "... Suggest add /*verilator split_var*/ to appropriate variables above."
|
||||
<< std::endl;
|
||||
}
|
||||
V3Stats::addStat("Order, SplitVar, candidates", canSplitList.size());
|
||||
m_unoptflatVars.clear();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -431,20 +431,6 @@ private:
|
|||
}
|
||||
|
||||
// Generate Statements
|
||||
virtual void visit(AstGenerate* nodep) VL_OVERRIDE {
|
||||
if (debug()>=9) nodep->dumpTree(cout, "-genin: ");
|
||||
iterateChildren(nodep);
|
||||
// After expanding the generate, all statements under it can be moved
|
||||
// up, and the generate block deleted as it's not relevant
|
||||
if (AstNode* stmtsp = nodep->stmtsp()) {
|
||||
stmtsp->unlinkFrBackWithNext();
|
||||
nodep->replaceWith(stmtsp);
|
||||
if (debug()>=9) stmtsp->dumpTree(cout, "-genout: ");
|
||||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstGenIf* nodep) VL_OVERRIDE {
|
||||
UINFO(9," GENIF "<<nodep<<endl);
|
||||
iterateAndNextNull(nodep->condp());
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -353,7 +353,8 @@ class ProtectVisitor : public AstNVisitor {
|
|||
nodep->v3error("Unsupported: unpacked arrays with protect-lib on "<<nodep->prettyNameQ());
|
||||
}
|
||||
if (nodep->direction() == VDirection::INPUT) {
|
||||
if (nodep->isUsedClock()) {
|
||||
if (nodep->isUsedClock()
|
||||
|| nodep->attrClocker() == VVarAttrClocker::CLOCKER_YES) {
|
||||
handleClock(nodep);
|
||||
} else {
|
||||
handleDataInput(nodep);
|
||||
|
|
|
|||
|
|
@ -386,7 +386,7 @@ private:
|
|||
UASSERT_OBJ(newp, nodep, "No clone for package function");
|
||||
nodep->taskp(newp);
|
||||
UINFO(9," New pkg-taskref "<<nodep<<endl);
|
||||
} else {
|
||||
} else if (!VN_IS(nodep, MethodCall)) {
|
||||
nodep->taskp(NULL);
|
||||
UINFO(9," New pkg-taskref "<<nodep<<endl);
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,39 @@
|
|||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Break variables into separate words to avoid UNOPTFLAT
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2020 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef _V3SPLITVAR_H_
|
||||
#define _V3SPLITVAR_H_ 1
|
||||
|
||||
//============================================================================
|
||||
|
||||
class AstNetlist;
|
||||
class AstVar;
|
||||
|
||||
class V3SplitVar {
|
||||
public:
|
||||
// Split variables marked with split_var metacomment.
|
||||
static void splitVariable(AstNetlist* nodep);
|
||||
|
||||
// Return true if the variable can be split.
|
||||
// This check is not perfect.
|
||||
static bool canSplitVar(const AstVar* varp);
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
|
@ -177,7 +177,7 @@ private:
|
|||
// While's we assume evaluate once.
|
||||
//virtual void visit(AstWhile* nodep) VL_OVERRIDE {
|
||||
|
||||
virtual void visit(AstCCall* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
|
||||
allNodes(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
if (m_fast && !nodep->funcp()->entryPoint()) {
|
||||
|
|
|
|||
|
|
@ -190,6 +190,7 @@ private:
|
|||
m_assignwp = NULL;
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
|
||||
// Includes handling AstMethodCall
|
||||
if (m_assignwp) {
|
||||
// Wire assigns must become always statements to deal with insertion
|
||||
// of multiple statements. Perhaps someday make all wassigns into always's?
|
||||
|
|
@ -487,7 +488,12 @@ private:
|
|||
//
|
||||
AstNode* beginp = new AstComment(refp->fileline(),
|
||||
string("Function: ")+refp->name(), true);
|
||||
AstCCall* ccallp = new AstCCall(refp->fileline(), cfuncp, NULL);
|
||||
AstNodeCCall* ccallp;
|
||||
if (AstMethodCall* mrefp = VN_CAST(refp, MethodCall)) {
|
||||
ccallp = new AstCMethodCall(refp->fileline(), mrefp->fromp()->unlinkFrBack(), cfuncp);
|
||||
} else {
|
||||
ccallp = new AstCCall(refp->fileline(), cfuncp);
|
||||
}
|
||||
beginp->addNext(ccallp);
|
||||
|
||||
// Convert complicated outputs to temp signals
|
||||
|
|
@ -1174,7 +1180,7 @@ private:
|
|||
}
|
||||
// Replace the ref
|
||||
AstNode* visitp = NULL;
|
||||
if (VN_IS(nodep, FuncRef)) {
|
||||
if (!nodep->isStatement()) {
|
||||
UASSERT_OBJ(nodep->taskp()->isFunction(), nodep, "func reference to non-function");
|
||||
AstVarRef* outrefp = new AstVarRef(nodep->fileline(), outvscp, false);
|
||||
nodep->replaceWith(outrefp);
|
||||
|
|
|
|||
188
src/V3Width.cpp
188
src/V3Width.cpp
|
|
@ -457,7 +457,7 @@ private:
|
|||
if (m_vup->prelim()) {
|
||||
AstNodeDType* vdtypep = m_vup->dtypeNullp();
|
||||
if (vdtypep && (VN_IS(vdtypep, AssocArrayDType)
|
||||
|| VN_IS(vdtypep, AssocArrayDType)
|
||||
|| VN_IS(vdtypep, DynArrayDType)
|
||||
|| VN_IS(vdtypep, QueueDType))) {
|
||||
nodep->v3error("Unsupported: Concatenation to form "
|
||||
<< vdtypep->prettyDTypeNameQ() << "data type");
|
||||
|
|
@ -536,7 +536,9 @@ private:
|
|||
if (m_vup->prelim()) {
|
||||
AstNodeDType* vdtypep = m_vup->dtypeNullp();
|
||||
if (vdtypep
|
||||
&& (VN_IS(vdtypep, AssocArrayDType) || VN_IS(vdtypep, QueueDType)
|
||||
&& (VN_IS(vdtypep, AssocArrayDType)
|
||||
|| VN_IS(vdtypep, DynArrayDType)
|
||||
|| VN_IS(vdtypep, QueueDType)
|
||||
|| VN_IS(vdtypep, UnpackArrayDType))) {
|
||||
nodep->v3error("Unsupported: Replication to form " << vdtypep->prettyDTypeNameQ()
|
||||
<< " data type");
|
||||
|
|
@ -1219,6 +1221,14 @@ private:
|
|||
nodep->dtypep(nodep); // The array itself, not subDtype
|
||||
UINFO(4,"dtWidthed "<<nodep<<endl);
|
||||
}
|
||||
virtual void visit(AstDynArrayDType* nodep) VL_OVERRIDE {
|
||||
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
|
||||
if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep));
|
||||
// Iterate into subDTypep() to resolve that type and update pointer.
|
||||
nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep()));
|
||||
nodep->dtypep(nodep); // The array itself, not subDtype
|
||||
UINFO(4,"dtWidthed "<<nodep<<endl);
|
||||
}
|
||||
virtual void visit(AstQueueDType* nodep) VL_OVERRIDE {
|
||||
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
|
||||
if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep));
|
||||
|
|
@ -1445,9 +1455,13 @@ private:
|
|||
if (nodep->childDTypep()) nodep->dtypep(moveChildDTypeEdit(nodep));
|
||||
nodep->dtypep(iterateEditDTypep(nodep, nodep->dtypep()));
|
||||
UASSERT_OBJ(nodep->dtypep(), nodep, "No dtype determined for var");
|
||||
if (VN_IS(nodep->dtypeSkipRefp(), UnsizedArrayDType)) {
|
||||
if (AstUnsizedArrayDType* unsizedp = VN_CAST(nodep->dtypeSkipRefp(), UnsizedArrayDType)) {
|
||||
if (!(m_ftaskp && m_ftaskp->dpiImport())) {
|
||||
nodep->v3error("Unsized/open arrays ('[]') are only supported in DPI imports");
|
||||
UINFO(9, "Unsized becomes dynamic array " << nodep << endl);
|
||||
AstDynArrayDType* newp
|
||||
= new AstDynArrayDType(unsizedp->fileline(), unsizedp->subDTypep());
|
||||
nodep->dtypep(newp);
|
||||
v3Global.rootp()->typeTablep()->addTypesp(newp);
|
||||
}
|
||||
}
|
||||
else if (nodep->isIO() && !(VN_IS(nodep->dtypeSkipRefp(), BasicDType)
|
||||
|
|
@ -1731,6 +1745,9 @@ private:
|
|||
//if (debug()>=9) nodep->dumpTree("-class-in--");
|
||||
if (!nodep->packed()) {
|
||||
nodep->v3warn(UNPACKED, "Unsupported: Unpacked struct/union");
|
||||
if (!v3Global.opt.structsPacked()) {
|
||||
nodep->v3warn(UNPACKED, "Unsupported: --no-structs-packed");
|
||||
}
|
||||
}
|
||||
userIterateChildren(nodep, NULL); // First size all members
|
||||
nodep->repairMemberCache();
|
||||
|
|
@ -1778,6 +1795,7 @@ private:
|
|||
if (memberSelStruct(nodep, adtypep)) return;
|
||||
} else if (VN_IS(fromDtp, EnumDType)
|
||||
|| VN_IS(fromDtp, AssocArrayDType)
|
||||
|| VN_IS(fromDtp, DynArrayDType)
|
||||
|| VN_IS(fromDtp, QueueDType)
|
||||
|| VN_IS(fromDtp, BasicDType)) {
|
||||
// Method call on enum without following parenthesis, e.g. "ENUM.next"
|
||||
|
|
@ -1849,6 +1867,9 @@ private:
|
|||
else if (AstAssocArrayDType* adtypep = VN_CAST(fromDtp, AssocArrayDType)) {
|
||||
methodCallAssoc(nodep, adtypep);
|
||||
}
|
||||
else if (AstDynArrayDType* adtypep = VN_CAST(fromDtp, DynArrayDType)) {
|
||||
methodCallDyn(nodep, adtypep);
|
||||
}
|
||||
else if (AstQueueDType* adtypep = VN_CAST(fromDtp, QueueDType)) {
|
||||
methodCallQueue(nodep, adtypep);
|
||||
}
|
||||
|
|
@ -2059,6 +2080,41 @@ private:
|
|||
if (lvalue) varrefp->lvalue(true);
|
||||
}
|
||||
}
|
||||
void methodCallDyn(AstMethodCall* nodep, AstDynArrayDType* adtypep) {
|
||||
AstCMethodHard* newp = NULL;
|
||||
if (nodep->name() == "at") { // Created internally for []
|
||||
methodOkArguments(nodep, 1, 1);
|
||||
methodCallLValue(nodep, nodep->fromp(), true);
|
||||
newp = new AstCMethodHard(nodep->fileline(),
|
||||
nodep->fromp()->unlinkFrBack(),
|
||||
"at", NULL);
|
||||
newp->dtypeFrom(adtypep->subDTypep());
|
||||
newp->protect(false);
|
||||
newp->didWidth(true);
|
||||
} else if (nodep->name() == "size") {
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
newp = new AstCMethodHard(nodep->fileline(),
|
||||
nodep->fromp()->unlinkFrBack(),
|
||||
"size", NULL);
|
||||
newp->dtypeSetSigned32();
|
||||
newp->didWidth(true);
|
||||
newp->protect(false);
|
||||
} else if (nodep->name() == "delete") { // function void delete()
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
methodCallLValue(nodep, nodep->fromp(), true);
|
||||
newp = new AstCMethodHard(nodep->fileline(),
|
||||
nodep->fromp()->unlinkFrBack(),
|
||||
"clear", NULL);
|
||||
newp->makeStatement();
|
||||
} else {
|
||||
nodep->v3error("Unsupported/unknown built-in dynamic array method "
|
||||
<< nodep->prettyNameQ());
|
||||
}
|
||||
if (newp) {
|
||||
newp->didWidth(true);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
void methodCallQueue(AstMethodCall* nodep, AstQueueDType* adtypep) {
|
||||
AstCMethodHard* newp = NULL;
|
||||
if (nodep->name() == "at") { // Created internally for []
|
||||
|
|
@ -2288,13 +2344,43 @@ private:
|
|||
|
||||
virtual void visit(AstNew* nodep) VL_OVERRIDE {
|
||||
if (nodep->didWidthAndSet()) return;
|
||||
userIterateChildren(nodep, WidthVP(SELF, BOTH).p());
|
||||
AstClassRefDType* refp = VN_CAST(m_vup->dtypeNullp(), ClassRefDType);
|
||||
if (!refp) { // e.g. int a = new;
|
||||
nodep->v3error("new() not expected in this context");
|
||||
return;
|
||||
}
|
||||
nodep->dtypep(refp);
|
||||
if (nodep->argsp()) {
|
||||
nodep->v3error("Unsupported: new with arguments");
|
||||
userIterateChildren(nodep, WidthVP(SELF, BOTH).p());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNewCopy* nodep) VL_OVERRIDE {
|
||||
if (nodep->didWidthAndSet()) return;
|
||||
nodep->v3error("Unsupported: new-as-copy");
|
||||
}
|
||||
virtual void visit(AstNewDynamic* nodep) VL_OVERRIDE {
|
||||
if (nodep->didWidthAndSet()) return;
|
||||
AstDynArrayDType* adtypep = VN_CAST(m_vup->dtypeNullp(), DynArrayDType);
|
||||
if (!adtypep) { // e.g. int a = new;
|
||||
if (adtypep) UINFO(1, "Got adtypep " << adtypep << endl);
|
||||
nodep->v3error("dynamic new() not expected in this context (data type must be dynamic array)");
|
||||
return;
|
||||
}
|
||||
// The AstNodeAssign visitor will be soon be replacing this node, make sure it gets it
|
||||
if (!VN_IS(nodep->backp(), NodeAssign)) {
|
||||
if (adtypep) UINFO(1, "Got backp " << nodep->backp() << endl);
|
||||
nodep->v3error("dynamic new() not expected in this context (expected under an assign)");
|
||||
return;
|
||||
}
|
||||
nodep->dtypep(adtypep);
|
||||
if (m_vup && m_vup->prelim()) {
|
||||
iterateCheckSigned32(nodep, "new() size", nodep->sizep(), BOTH);
|
||||
}
|
||||
if (nodep->rhsp()) {
|
||||
iterateCheckTyped(nodep, "Dynamic array new RHS", nodep->rhsp(), adtypep->subDTypep(),
|
||||
BOTH);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstPattern* nodep) VL_OVERRIDE {
|
||||
|
|
@ -2446,18 +2532,7 @@ private:
|
|||
if (patp) {
|
||||
// Determine initial values
|
||||
patp->dtypep(memp);
|
||||
userIterate(patp, WidthVP(memp, BOTH).p()); // See visit(AstPatMember*
|
||||
|
||||
// Convert to concat for now
|
||||
AstNode* valuep = patp->lhssp()->unlinkFrBack();
|
||||
if (VN_IS(valuep, Const)) {
|
||||
// Forming a AstConcat will cause problems with
|
||||
// unsized (uncommitted sized) constants
|
||||
if (AstNode* newccp = WidthCommitVisitor::newIfConstCommitSize(VN_CAST(valuep, Const))) {
|
||||
VL_DO_DANGLING(pushDeletep(valuep), valuep);
|
||||
valuep = newccp;
|
||||
}
|
||||
}
|
||||
AstNode* valuep = patternMemberValueIterate(patp);
|
||||
if (!newp) newp = valuep;
|
||||
else {
|
||||
AstConcat* concatp = new AstConcat(patp->fileline(), newp, valuep);
|
||||
|
|
@ -2500,18 +2575,7 @@ private:
|
|||
if (patp) {
|
||||
// Don't want the RHS an array
|
||||
patp->dtypep(arrayp->subDTypep());
|
||||
// Determine values - might be another InitArray
|
||||
userIterate(patp, WidthVP(patp->dtypep(), BOTH).p()); // See visit(AstPatMember*
|
||||
// Convert to InitArray or constify immediately
|
||||
AstNode* valuep = patp->lhssp()->unlinkFrBack();
|
||||
if (VN_IS(valuep, Const)) {
|
||||
// Forming a AstConcat will cause problems with
|
||||
// unsized (uncommitted sized) constants
|
||||
if (AstNode* newp = WidthCommitVisitor::newIfConstCommitSize(VN_CAST(valuep, Const))) {
|
||||
VL_DO_DANGLING(pushDeletep(valuep), valuep);
|
||||
valuep = newp;
|
||||
}
|
||||
}
|
||||
AstNode* valuep = patternMemberValueIterate(patp);
|
||||
if (VN_IS(arrayp, UnpackArrayDType)) {
|
||||
if (!newp) {
|
||||
AstInitArray* newap
|
||||
|
|
@ -2564,21 +2628,8 @@ private:
|
|||
if (patp) {
|
||||
// Determine initial values
|
||||
vdtypep = nodep->findLogicBoolDType();
|
||||
// Don't want the RHS an array
|
||||
patp->dtypep(vdtypep);
|
||||
// Determine values - might be another InitArray
|
||||
userIterate(patp, WidthVP(patp->dtypep(), BOTH).p());
|
||||
// Convert to InitArray or constify immediately
|
||||
AstNode* valuep = patp->lhssp()->unlinkFrBack();
|
||||
if (VN_IS(valuep, Const)) {
|
||||
// Forming a AstConcat will cause problems with
|
||||
// unsized (uncommitted sized) constants
|
||||
if (AstNode* newccp
|
||||
= WidthCommitVisitor::newIfConstCommitSize(VN_CAST(valuep, Const))) {
|
||||
VL_DO_DANGLING(pushDeletep(valuep), valuep);
|
||||
valuep = newccp;
|
||||
}
|
||||
}
|
||||
AstNode* valuep = patternMemberValueIterate(patp);
|
||||
{ // Packed. Convert to concat for now.
|
||||
if (!newp) newp = valuep;
|
||||
else {
|
||||
|
|
@ -2598,6 +2649,22 @@ private:
|
|||
//if (debug()>=9) newp->dumpTree("-apat-out: ");
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present
|
||||
}
|
||||
AstNode* patternMemberValueIterate(AstPatMember* patp) {
|
||||
// Determine values - might be another InitArray
|
||||
userIterate(patp, WidthVP(patp->dtypep(), BOTH).p());
|
||||
// Convert to InitArray or constify immediately
|
||||
AstNode* valuep = patp->lhssp()->unlinkFrBack();
|
||||
if (VN_IS(valuep, Const)) {
|
||||
// Forming a AstConcat will cause problems with
|
||||
// unsized (uncommitted sized) constants
|
||||
if (AstNode* newp = WidthCommitVisitor::newIfConstCommitSize(VN_CAST(valuep, Const))) {
|
||||
VL_DO_DANGLING(pushDeletep(valuep), valuep);
|
||||
valuep = newp;
|
||||
}
|
||||
}
|
||||
return valuep;
|
||||
}
|
||||
|
||||
virtual void visit(AstPatMember* nodep) VL_OVERRIDE {
|
||||
AstNodeDType* vdtypep = m_vup->dtypeNullp();
|
||||
UASSERT_OBJ(vdtypep, nodep, "Pattern member type not assigned by AstPattern visitor");
|
||||
|
|
@ -2735,6 +2802,23 @@ private:
|
|||
iterateCheckAssign(nodep, "Assign RHS", nodep->rhsp(), FINAL, lhsDTypep);
|
||||
//if (debug()) nodep->dumpTree(cout, " AssignOut: ");
|
||||
}
|
||||
if (AstNewDynamic* dynp = VN_CAST(nodep->rhsp(), NewDynamic)) {
|
||||
UINFO(9, "= new[] -> .resize(): " << nodep);
|
||||
AstCMethodHard* newp;
|
||||
if (!dynp->rhsp()) {
|
||||
newp = new AstCMethodHard(nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
|
||||
"renew", dynp->sizep()->unlinkFrBack());
|
||||
} else {
|
||||
newp = new AstCMethodHard(nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
|
||||
"renew_copy", dynp->sizep()->unlinkFrBack());
|
||||
newp->addPinsp(dynp->rhsp()->unlinkFrBack());
|
||||
}
|
||||
newp->didWidth(true);
|
||||
newp->protect(false);
|
||||
newp->makeStatement();
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstSFormatF* nodep) VL_OVERRIDE {
|
||||
|
|
@ -2780,13 +2864,16 @@ private:
|
|||
added = true;
|
||||
newFormat += "%g";
|
||||
} else if (VN_IS(dtypep, AssocArrayDType)
|
||||
|| VN_IS(dtypep, DynArrayDType)
|
||||
|| VN_IS(dtypep, QueueDType)) {
|
||||
added = true;
|
||||
newFormat += "%@";
|
||||
AstNRelinker handle;
|
||||
argp->unlinkFrBack(&handle);
|
||||
AstCMethodHard* newp = new AstCMethodHard(
|
||||
nodep->fileline(), argp, "to_string", NULL);
|
||||
AstCMath* newp = new AstCMath(
|
||||
nodep->fileline(), "VL_TO_STRING(", 0, true);
|
||||
newp->addBodysp(argp);
|
||||
newp->addBodysp(new AstText(nodep->fileline(), ")"));
|
||||
newp->dtypeSetString();
|
||||
newp->pure(true);
|
||||
newp->protect(false);
|
||||
|
|
@ -2819,7 +2906,7 @@ private:
|
|||
} else if (argp && argp->isString()) {
|
||||
ch = '@';
|
||||
} else {
|
||||
ch = 'h';
|
||||
ch = nodep->missingArgChar();
|
||||
}
|
||||
if (argp) argp = argp->nextp();
|
||||
break;
|
||||
|
|
@ -2872,6 +2959,11 @@ private:
|
|||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstDumpCtl* nodep) VL_OVERRIDE {
|
||||
assertAtStatement(nodep);
|
||||
// Just let all arguments seek their natural sizes
|
||||
userIterateChildren(nodep, WidthVP(SELF, BOTH).p());
|
||||
}
|
||||
virtual void visit(AstFOpen* nodep) VL_OVERRIDE {
|
||||
// Although a system function in IEEE, here a statement which sets the file pointer (MCD)
|
||||
assertAtStatement(nodep);
|
||||
|
|
@ -4226,8 +4318,8 @@ private:
|
|||
|
||||
AstNode* checkCvtUS(AstNode* nodep) {
|
||||
if (nodep && nodep->isDouble()) {
|
||||
nodep->v3error("Expected integral (non-real) input to "
|
||||
<<nodep->backp()->prettyTypeName());
|
||||
nodep->v3error("Expected integral (non-" << nodep->dtypep()->prettyDTypeName()
|
||||
<< ") input to " << nodep->backp()->prettyTypeName());
|
||||
nodep = spliceCvtS(nodep, true);
|
||||
}
|
||||
return nodep;
|
||||
|
|
|
|||
|
|
@ -93,6 +93,8 @@ private:
|
|||
}
|
||||
else if (VN_IS(ddtypep, AssocArrayDType)) {
|
||||
}
|
||||
else if (VN_IS(ddtypep, DynArrayDType)) {
|
||||
}
|
||||
else if (VN_IS(ddtypep, QueueDType)) {
|
||||
}
|
||||
else if (const AstNodeUOrStructDType* adtypep = VN_CAST(ddtypep, NodeUOrStructDType)) {
|
||||
|
|
@ -260,6 +262,15 @@ private:
|
|||
if (debug()>=9) newp->dumpTree(cout, "--SELBTn: ");
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
else if (AstDynArrayDType* adtypep = VN_CAST(ddtypep, DynArrayDType)) {
|
||||
// SELBIT(array, index) -> CMETHODCALL(queue, "at", index)
|
||||
AstNode* subp = rhsp;
|
||||
AstCMethodHard* newp = new AstCMethodHard(nodep->fileline(),
|
||||
fromp, "at", subp);
|
||||
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference
|
||||
if (debug()>=9) newp->dumpTree(cout, "--SELBTq: ");
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
else if (AstQueueDType* adtypep = VN_CAST(ddtypep, QueueDType)) {
|
||||
// SELBIT(array, index) -> CMETHODCALL(queue, "at", index)
|
||||
AstNode* subp = rhsp;
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@
|
|||
#include "V3Slice.h"
|
||||
#include "V3Split.h"
|
||||
#include "V3SplitAs.h"
|
||||
#include "V3SplitVar.h"
|
||||
#include "V3Stats.h"
|
||||
#include "V3String.h"
|
||||
#include "V3Subst.h"
|
||||
|
|
@ -175,12 +176,14 @@ static void process() {
|
|||
V3Const::constifyAllLint(v3Global.rootp());
|
||||
|
||||
if (!v3Global.opt.xmlOnly()) {
|
||||
// Split packed variables into multiple pieces to resolve UNOPTFLAT.
|
||||
// should be after constifyAllLint() which flattens to 1D bit vector
|
||||
V3SplitVar::splitVariable(v3Global.rootp());
|
||||
|
||||
// Remove cell arrays (must be between V3Width and scoping)
|
||||
V3Inst::dearrayAll(v3Global.rootp());
|
||||
V3LinkDot::linkDotArrayed(v3Global.rootp());
|
||||
}
|
||||
|
||||
if (!v3Global.opt.xmlOnly()) {
|
||||
// Task inlining & pushing BEGINs names to variables/cells
|
||||
// Begin processing must be after Param, before module inlining
|
||||
V3Begin::debeginAll(v3Global.rootp()); // Flatten cell names, before inliner
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ my $Opt_DistTitle = $ARGV[0] or die "%Error: No disttitle specified,";
|
|||
my $Opt_DistDate = $ARGV[1] or die "%Error: No distdate specified,";
|
||||
|
||||
my $header =
|
||||
("\\usepackage[left=1.7in,right=1.7in,top=1.3in,bottom=1.3in]{geometry}\n"
|
||||
("\\usepackage[left=1.0in,right=1.0in,top=1.0in,bottom=1.0in]{geometry}\n"
|
||||
."\\usepackage[pdftex,bookmarks=true,bookmarksnumbered=true,hypertexnames=false,breaklinks=true,colorlinks=true,linkcolor=blue]{hyperref}\n"
|
||||
."\\usepackage{fancyhdr} \\pagestyle{fancy}\n"
|
||||
."\\usepackage{graphicx}\n"
|
||||
|
|
|
|||
|
|
@ -197,9 +197,28 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
|||
"$cos" { FL; return yD_COS; }
|
||||
"$cosh" { FL; return yD_COSH; }
|
||||
"$display" { FL; return yD_DISPLAY; }
|
||||
"$displayb" { FL; return yD_DISPLAYB; }
|
||||
"$displayh" { FL; return yD_DISPLAYH; }
|
||||
"$displayo" { FL; return yD_DISPLAYO; }
|
||||
"$dumpall" { FL; return yD_DUMPALL; }
|
||||
"$dumpfile" { FL; return yD_DUMPFILE; }
|
||||
"$dumpflush" { FL; return yD_DUMPFLUSH; }
|
||||
"$dumplimit" { FL; return yD_DUMPLIMIT; }
|
||||
"$dumpoff" { FL; return yD_DUMPOFF; }
|
||||
"$dumpon" { FL; return yD_DUMPON; }
|
||||
"$dumpports" { FL; return yD_DUMPPORTS; }
|
||||
"$dumpportsall" { FL; return yD_DUMPALL; }
|
||||
"$dumpportsflush" { FL; return yD_DUMPFLUSH; }
|
||||
"$dumpportslimit" { FL; return yD_DUMPLIMIT; }
|
||||
"$dumpportsoff" { FL; return yD_DUMPOFF; }
|
||||
"$dumpportson" { FL; return yD_DUMPON; }
|
||||
"$dumpvars" { FL; return yD_DUMPVARS; }
|
||||
"$exp" { FL; return yD_EXP; }
|
||||
"$fclose" { FL; return yD_FCLOSE; }
|
||||
"$fdisplay" { FL; return yD_FDISPLAY; }
|
||||
"$fdisplayb" { FL; return yD_FDISPLAYB; }
|
||||
"$fdisplayh" { FL; return yD_FDISPLAYH; }
|
||||
"$fdisplayo" { FL; return yD_FDISPLAYO; }
|
||||
"$feof" { FL; return yD_FEOF; }
|
||||
"$fflush" { FL; return yD_FFLUSH; }
|
||||
"$fgetc" { FL; return yD_FGETC; }
|
||||
|
|
@ -208,12 +227,15 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
|||
"$floor" { FL; return yD_FLOOR; }
|
||||
"$fopen" { FL; return yD_FOPEN; }
|
||||
"$fread" { FL; return yD_FREAD; }
|
||||
"$frewind" { FL; return yD_FREWIND; }
|
||||
"$fscanf" { FL; return yD_FSCANF; }
|
||||
"$fseek" { FL; return yD_FSEEK; }
|
||||
"$ftell" { FL; return yD_FTELL; }
|
||||
"$frewind" { FL; return yD_FREWIND; }
|
||||
"$fullskew" { FL; return yaTIMINGSPEC; }
|
||||
"$fwrite" { FL; return yD_FWRITE; }
|
||||
"$fwriteb" { FL; return yD_FWRITEB; }
|
||||
"$fwriteh" { FL; return yD_FWRITEH; }
|
||||
"$fwriteo" { FL; return yD_FWRITEO; }
|
||||
"$hold" { FL; return yaTIMINGSPEC; }
|
||||
"$hypot" { FL; return yD_HYPOT; }
|
||||
"$itor" { FL; return yD_ITOR; }
|
||||
|
|
@ -232,9 +254,9 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
|||
"$removal" { FL; return yaTIMINGSPEC; }
|
||||
"$rewind" { FL; return yD_REWIND; }
|
||||
"$rtoi" { FL; return yD_RTOI; }
|
||||
"$sampled" { FL; return yD_SAMPLED; }
|
||||
"$setup" { FL; return yaTIMINGSPEC; }
|
||||
"$setuphold" { FL; return yaTIMINGSPEC; }
|
||||
"$sampled" { FL; return yD_SAMPLED; }
|
||||
"$sformat" { FL; return yD_SFORMAT; }
|
||||
"$sformatf" { FL; return yD_SFORMATF; }
|
||||
"$shortrealtobits" { FL; return yD_SHORTREALTOBITS; }
|
||||
|
|
@ -246,6 +268,9 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
|||
"$stime" { FL; return yD_STIME; }
|
||||
"$stop" { FL; return yD_STOP; }
|
||||
"$swrite" { FL; return yD_SWRITE; }
|
||||
"$swriteb" { FL; return yD_SWRITEB; }
|
||||
"$swriteh" { FL; return yD_SWRITEH; }
|
||||
"$swriteo" { FL; return yD_SWRITEO; }
|
||||
"$system" { FL; return yD_SYSTEM; }
|
||||
"$tan" { FL; return yD_TAN; }
|
||||
"$tanh" { FL; return yD_TANH; }
|
||||
|
|
@ -257,6 +282,9 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
|||
"$value$plusargs" { FL; return yD_VALUEPLUSARGS; }
|
||||
"$width" { FL; return yaTIMINGSPEC; }
|
||||
"$write" { FL; return yD_WRITE; }
|
||||
"$writeb" { FL; return yD_WRITEB; }
|
||||
"$writeh" { FL; return yD_WRITEH; }
|
||||
"$writeo" { FL; return yD_WRITEO; }
|
||||
"$writememh" { FL; return yD_WRITEMEMH; }
|
||||
/* Keywords */
|
||||
"always" { FL; return yALWAYS; }
|
||||
|
|
@ -361,19 +389,6 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
|||
"wor" { FL; return yWOR; }
|
||||
"xnor" { FL; return yXNOR; }
|
||||
"xor" { FL; return yXOR; }
|
||||
/* Special errors */
|
||||
"$displayb" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $display with %%b format instead: %s", yytext); }
|
||||
"$displayh" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $display with %%x format instead: %s", yytext); }
|
||||
"$displayo" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $display with %%o format instead: %s", yytext); }
|
||||
"$fdisplayb" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fdisplay with %%b format instead: %s", yytext); }
|
||||
"$fdisplayh" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fdisplay with %%x format instead: %s", yytext); }
|
||||
"$fdisplayo" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fdisplay with %%o format instead: %s", yytext); }
|
||||
"$fwriteb" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fwrite with %%b format instead: %s", yytext); }
|
||||
"$fwriteh" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fwrite with %%x format instead: %s", yytext); }
|
||||
"$fwriteo" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fwrite with %%o format instead: %s", yytext); }
|
||||
"$writeb" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $write with %%b format instead: %s", yytext); }
|
||||
"$writeh" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $write with %%x format instead: %s", yytext); }
|
||||
"$writeo" { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $write with %%o format instead: %s", yytext); }
|
||||
}
|
||||
|
||||
/* Verilog 2001 */
|
||||
|
|
@ -704,6 +719,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
|||
"/*verilator public_flat_rd*/" { FL; return yVL_PUBLIC_FLAT_RD; }
|
||||
"/*verilator public_flat_rw*/" { FL; return yVL_PUBLIC_FLAT_RW; } // The @(edge) is converted by the preproc
|
||||
"/*verilator public_module*/" { FL; return yVL_PUBLIC_MODULE; }
|
||||
"/*verilator split_var*/" { FL; return yVL_SPLIT_VAR; }
|
||||
"/*verilator sc_clock*/" { FL; return yVL_CLOCK; }
|
||||
"/*verilator clocker*/" { FL; return yVL_CLOCKER; }
|
||||
"/*verilator no_clocker*/" { FL; return yVL_NO_CLOCKER; }
|
||||
|
|
|
|||
125
src/verilog.y
125
src/verilog.y
|
|
@ -553,11 +553,25 @@ class AstSenTree;
|
|||
%token<fl> yD_COUNTONES "$countones"
|
||||
%token<fl> yD_DIMENSIONS "$dimensions"
|
||||
%token<fl> yD_DISPLAY "$display"
|
||||
%token<fl> yD_DISPLAYB "$displayb"
|
||||
%token<fl> yD_DISPLAYH "$displayh"
|
||||
%token<fl> yD_DISPLAYO "$displayo"
|
||||
%token<fl> yD_DUMPALL "$dumpall"
|
||||
%token<fl> yD_DUMPFILE "$dumpfile"
|
||||
%token<fl> yD_DUMPFLUSH "$dumpflush"
|
||||
%token<fl> yD_DUMPLIMIT "$dumplimit"
|
||||
%token<fl> yD_DUMPOFF "$dumpoff"
|
||||
%token<fl> yD_DUMPON "$dumpon"
|
||||
%token<fl> yD_DUMPPORTS "$dumpports"
|
||||
%token<fl> yD_DUMPVARS "$dumpvars"
|
||||
%token<fl> yD_ERROR "$error"
|
||||
%token<fl> yD_EXP "$exp"
|
||||
%token<fl> yD_FATAL "$fatal"
|
||||
%token<fl> yD_FCLOSE "$fclose"
|
||||
%token<fl> yD_FDISPLAY "$fdisplay"
|
||||
%token<fl> yD_FDISPLAYB "$fdisplayb"
|
||||
%token<fl> yD_FDISPLAYH "$fdisplayh"
|
||||
%token<fl> yD_FDISPLAYO "$fdisplayo"
|
||||
%token<fl> yD_FEOF "$feof"
|
||||
%token<fl> yD_FFLUSH "$fflush"
|
||||
%token<fl> yD_FGETC "$fgetc"
|
||||
|
|
@ -571,6 +585,9 @@ class AstSenTree;
|
|||
%token<fl> yD_FSEEK "$fseek"
|
||||
%token<fl> yD_FTELL "$ftell"
|
||||
%token<fl> yD_FWRITE "$fwrite"
|
||||
%token<fl> yD_FWRITEB "$fwriteb"
|
||||
%token<fl> yD_FWRITEH "$fwriteh"
|
||||
%token<fl> yD_FWRITEO "$fwriteo"
|
||||
%token<fl> yD_HIGH "$high"
|
||||
%token<fl> yD_HYPOT "$hypot"
|
||||
%token<fl> yD_INCREMENT "$increment"
|
||||
|
|
@ -606,6 +623,9 @@ class AstSenTree;
|
|||
%token<fl> yD_STIME "$stime"
|
||||
%token<fl> yD_STOP "$stop"
|
||||
%token<fl> yD_SWRITE "$swrite"
|
||||
%token<fl> yD_SWRITEB "$swriteb"
|
||||
%token<fl> yD_SWRITEH "$swriteh"
|
||||
%token<fl> yD_SWRITEO "$swriteo"
|
||||
%token<fl> yD_SYSTEM "$system"
|
||||
%token<fl> yD_TAN "$tan"
|
||||
%token<fl> yD_TANH "$tanh"
|
||||
|
|
@ -619,7 +639,10 @@ class AstSenTree;
|
|||
%token<fl> yD_VALUEPLUSARGS "$value$plusargs"
|
||||
%token<fl> yD_WARNING "$warning"
|
||||
%token<fl> yD_WRITE "$write"
|
||||
%token<fl> yD_WRITEB "$writeb"
|
||||
%token<fl> yD_WRITEH "$writeh"
|
||||
%token<fl> yD_WRITEMEMH "$writememh"
|
||||
%token<fl> yD_WRITEO "$writeo"
|
||||
|
||||
%token<fl> yVL_CLOCK "/*verilator sc_clock*/"
|
||||
%token<fl> yVL_CLOCKER "/*verilator clocker*/"
|
||||
|
|
@ -639,6 +662,7 @@ class AstSenTree;
|
|||
%token<fl> yVL_PUBLIC_FLAT_RD "/*verilator public_flat_rd*/"
|
||||
%token<fl> yVL_PUBLIC_FLAT_RW "/*verilator public_flat_rw*/"
|
||||
%token<fl> yVL_PUBLIC_MODULE "/*verilator public_module*/"
|
||||
%token<fl> yVL_SPLIT_VAR "/*verilator split_var*/"
|
||||
|
||||
%token<fl> yP_TICK "'"
|
||||
%token<fl> yP_TICKBRA "'{"
|
||||
|
|
@ -1155,7 +1179,7 @@ interface_item<nodep>: // IEEE: interface_item + non_port_interface_item
|
|||
;
|
||||
|
||||
interface_generate_region<nodep>: // ==IEEE: generate_region
|
||||
yGENERATE interface_itemList yENDGENERATE { $$ = new AstGenerate($1, $2); }
|
||||
yGENERATE interface_itemList yENDGENERATE { $$ = $2; }
|
||||
| yGENERATE yENDGENERATE { $$ = NULL; }
|
||||
;
|
||||
|
||||
|
|
@ -2035,7 +2059,7 @@ bind_instantiation<nodep>: // ==IEEE: bind_instantiation
|
|||
// different, so we copy all rules for checkers.
|
||||
|
||||
generate_region<nodep>: // ==IEEE: generate_region
|
||||
yGENERATE ~c~genItemList yENDGENERATE { $$ = new AstGenerate($1, $2); }
|
||||
yGENERATE ~c~genItemList yENDGENERATE { $$ = $2; }
|
||||
| yGENERATE yENDGENERATE { $$ = NULL; }
|
||||
;
|
||||
|
||||
|
|
@ -2043,20 +2067,22 @@ generate_region<nodep>: // ==IEEE: generate_region
|
|||
//UNSUP BISONPRE_COPY(generate_region,{s/~c~/c_/g}) // {copied}
|
||||
//UNSUP ;
|
||||
|
||||
generate_block_or_null<nodep>: // IEEE: generate_block_or_null
|
||||
generate_block_or_null<nodep>: // IEEE: generate_block_or_null (called from gencase/genif/genfor)
|
||||
// ';' // is included in
|
||||
// // IEEE: generate_block
|
||||
// // Must always return a BEGIN node, or NULL - see GenFor construction
|
||||
generate_item { $$ = $1 ? (new AstBegin($1->fileline(),"genblk",$1,true)) : NULL; }
|
||||
generate_item { $$ = $1 ? (new AstBegin($1->fileline(),"",$1,true,true)) : NULL; }
|
||||
| genItemBegin { $$ = $1; }
|
||||
;
|
||||
|
||||
genItemBegin<nodep>: // IEEE: part of generate_block
|
||||
yBEGIN ~c~genItemList yEND { $$ = new AstBegin($1,"genblk",$2,true); }
|
||||
yBEGIN ~c~genItemList yEND { $$ = new AstBegin($1,"",$2,true,false); }
|
||||
| yBEGIN yEND { $$ = NULL; }
|
||||
| id ':' yBEGIN ~c~genItemList yEND endLabelE { $$ = new AstBegin($<fl>1,*$1,$4,true); GRAMMARP->endLabel($<fl>6,*$1,$6); }
|
||||
| id ':' yBEGIN ~c~genItemList yEND endLabelE
|
||||
{ $$ = new AstBegin($<fl>1,*$1,$4,true,false); GRAMMARP->endLabel($<fl>6,*$1,$6); }
|
||||
| id ':' yBEGIN yEND endLabelE { $$ = NULL; GRAMMARP->endLabel($<fl>5,*$1,$5); }
|
||||
| yBEGIN ':' idAny ~c~ genItemList yEND endLabelE { $$ = new AstBegin($<fl>3,*$3,$4,true); GRAMMARP->endLabel($<fl>6,*$3,$6); }
|
||||
| yBEGIN ':' idAny ~c~genItemList yEND endLabelE
|
||||
{ $$ = new AstBegin($<fl>3,*$3,$4,true,false); GRAMMARP->endLabel($<fl>6,*$3,$6); }
|
||||
| yBEGIN ':' idAny yEND endLabelE { $$ = NULL; GRAMMARP->endLabel($<fl>5,*$3,$5); }
|
||||
;
|
||||
|
||||
|
|
@ -2114,11 +2140,11 @@ loop_generate_construct<nodep>: // ==IEEE: loop_generate_construct
|
|||
{ // Convert BEGIN(...) to BEGIN(GENFOR(...)), as we need the BEGIN to hide the local genvar
|
||||
AstBegin* lowerBegp = VN_CAST($9, Begin);
|
||||
UASSERT_OBJ(!($9 && !lowerBegp), $9, "Child of GENFOR should have been begin");
|
||||
if (!lowerBegp) lowerBegp = new AstBegin($1,"genblk",NULL,true); // Empty body
|
||||
if (!lowerBegp) lowerBegp = new AstBegin($1, "genblk", NULL, true, true); // Empty body
|
||||
AstNode* lowerNoBegp = lowerBegp->stmtsp();
|
||||
if (lowerNoBegp) lowerNoBegp->unlinkFrBackWithNext();
|
||||
//
|
||||
AstBegin* blkp = new AstBegin($1,lowerBegp->name(),NULL,true);
|
||||
AstBegin* blkp = new AstBegin($1, lowerBegp->name(), NULL, true, true);
|
||||
// V3LinkDot detects BEGIN(GENFOR(...)) as a special case
|
||||
AstNode* initp = $3; AstNode* varp = $3;
|
||||
if (VN_IS(varp, Var)) { // Genvar
|
||||
|
|
@ -2280,6 +2306,7 @@ sigAttr<nodep>:
|
|||
| yVL_ISOLATE_ASSIGNMENTS { $$ = new AstAttrOf($1,AstAttrType::VAR_ISOLATE_ASSIGNMENTS); }
|
||||
| yVL_SC_BV { $$ = new AstAttrOf($1,AstAttrType::VAR_SC_BV); }
|
||||
| yVL_SFORMAT { $$ = new AstAttrOf($1,AstAttrType::VAR_SFORMAT); }
|
||||
| yVL_SPLIT_VAR { $$ = new AstAttrOf($1,AstAttrType::VAR_SPLIT_VAR); }
|
||||
;
|
||||
|
||||
rangeListE<rangep>: // IEEE: [{packed_dimension}]
|
||||
|
|
@ -2791,10 +2818,10 @@ statement_item<nodep>: // IEEE: statement_item
|
|||
|
||||
statementFor<beginp>: // IEEE: part of statement
|
||||
yFOR '(' for_initialization expr ';' for_stepE ')' stmtBlock
|
||||
{ $$ = new AstBegin($1,"",$3);
|
||||
{ $$ = new AstBegin($1, "", $3, false, true);
|
||||
$$->addStmtsp(new AstWhile($1, $4,$8,$6)); }
|
||||
| yFOR '(' for_initialization ';' for_stepE ')' stmtBlock
|
||||
{ $$ = new AstBegin($1,"",$3);
|
||||
{ $$ = new AstBegin($1, "", $3, false, true);
|
||||
$$->addStmtsp(new AstWhile($1, new AstConst($1,AstConst::LogicTrue()),$7,$5)); }
|
||||
;
|
||||
|
||||
|
|
@ -2876,15 +2903,14 @@ finc_or_dec_expression<nodep>: // ==IEEE: inc_or_dec_expression
|
|||
|
||||
class_new<nodep>: // ==IEEE: class_new
|
||||
// // Special precence so (...) doesn't match expr
|
||||
yNEW__ETC { $$ = new AstNew($1); }
|
||||
| yNEW__ETC expr { $$ = new AstNew($1); BBUNSUP($1, "Unsupported: new with expression"); }
|
||||
// // Grammer abiguity; we assume "new (x)" the () are a argument, not expr
|
||||
| yNEW__PAREN '(' list_of_argumentsE ')' { $$ = new AstNew($1); BBUNSUP($1, "Unsupported: new with arguments"); }
|
||||
yNEW__ETC { $$ = new AstNew($1, NULL); }
|
||||
| yNEW__ETC expr { $$ = new AstNewCopy($1, $2); }
|
||||
| yNEW__PAREN '(' list_of_argumentsE ')' { $$ = new AstNew($1, $3); }
|
||||
;
|
||||
|
||||
dynamic_array_new<nodep>: // ==IEEE: dynamic_array_new
|
||||
yNEW__ETC '[' expr ']' { $$ = new AstNew($1); BBUNSUP($1, "Unsupported: Dynamic array new"); }
|
||||
| yNEW__ETC '[' expr ']' '(' expr ')' { $$ = new AstNew($1); BBUNSUP($1, "Unsupported: Dynamic array new"); }
|
||||
yNEW__ETC '[' expr ']' { $$ = new AstNewDynamic($1, $3, NULL); }
|
||||
| yNEW__ETC '[' expr ']' '(' expr ')' { $$ = new AstNewDynamic($1, $3, $6); }
|
||||
;
|
||||
|
||||
//************************************************
|
||||
|
|
@ -3150,8 +3176,30 @@ system_t_call<nodep>: // IEEE: system_tf_call (as task)
|
|||
| yaD_DPI '(' exprList ')' { $$ = new AstTaskRef($<fl>1, *$1, $3);
|
||||
GRAMMARP->argWrapList(VN_CAST($$, TaskRef)); }
|
||||
//
|
||||
| yD_DUMPPORTS '(' idDotted ',' expr ')' { $$ = new AstDumpCtl($<fl>1, VDumpCtlType::FILE, $5); DEL($3);
|
||||
$$->addNext(new AstDumpCtl($<fl>1, VDumpCtlType::VARS,
|
||||
new AstConst($<fl>1, 1))); }
|
||||
| yD_DUMPPORTS '(' ',' expr ')' { $$ = new AstDumpCtl($<fl>1, VDumpCtlType::FILE, $4);
|
||||
$$->addNext(new AstDumpCtl($<fl>1, VDumpCtlType::VARS,
|
||||
new AstConst($<fl>1, 1))); }
|
||||
| yD_DUMPFILE '(' expr ')' { $$ = new AstDumpCtl($<fl>1, VDumpCtlType::FILE, $3); }
|
||||
| yD_DUMPVARS parenE { $$ = new AstDumpCtl($<fl>1, VDumpCtlType::VARS,
|
||||
new AstConst($<fl>1, 0)); }
|
||||
| yD_DUMPVARS '(' expr ')' { $$ = new AstDumpCtl($<fl>1, VDumpCtlType::VARS, $3); }
|
||||
| yD_DUMPVARS '(' expr ',' idDotted ')' { $$ = new AstDumpCtl($<fl>1, VDumpCtlType::VARS, $3); DEL($5); }
|
||||
| yD_DUMPALL parenE { $$ = new AstDumpCtl($<fl>1, VDumpCtlType::ALL); }
|
||||
| yD_DUMPALL '(' expr ')' { $$ = new AstDumpCtl($<fl>1, VDumpCtlType::ALL); DEL($3); }
|
||||
| yD_DUMPFLUSH parenE { $$ = new AstDumpCtl($<fl>1, VDumpCtlType::FLUSH); }
|
||||
| yD_DUMPFLUSH '(' expr ')' { $$ = new AstDumpCtl($<fl>1, VDumpCtlType::FLUSH); DEL($3); }
|
||||
| yD_DUMPLIMIT '(' expr ')' { $$ = new AstDumpCtl($<fl>1, VDumpCtlType::LIMIT, $3); }
|
||||
| yD_DUMPLIMIT '(' expr ',' expr ')' { $$ = new AstDumpCtl($<fl>1, VDumpCtlType::LIMIT, $3); DEL($5); }
|
||||
| yD_DUMPOFF parenE { $$ = new AstDumpCtl($<fl>1, VDumpCtlType::OFF); }
|
||||
| yD_DUMPOFF '(' expr ')' { $$ = new AstDumpCtl($<fl>1, VDumpCtlType::OFF); DEL($3); }
|
||||
| yD_DUMPON parenE { $$ = new AstDumpCtl($<fl>1, VDumpCtlType::ON); }
|
||||
| yD_DUMPON '(' expr ')' { $$ = new AstDumpCtl($<fl>1, VDumpCtlType::ON); DEL($3); }
|
||||
//
|
||||
| yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? NULL : new AstUCStmt($1,$3)); }
|
||||
| yD_SYSTEM '(' expr ')' { $$ = new AstSystemT($1, $3); }
|
||||
| yD_SYSTEM '(' expr ')' { $$ = new AstSystemT($1, $3); }
|
||||
//
|
||||
| yD_FCLOSE '(' idClassSel ')' { $$ = new AstFClose($1, $3); }
|
||||
| yD_FFLUSH parenE { $$ = NULL; BBUNSUP($1, "Unsupported: $fflush of all handles does not map to C++."); }
|
||||
|
|
@ -3161,16 +3209,40 @@ system_t_call<nodep>: // IEEE: system_tf_call (as task)
|
|||
| yD_STOP parenE { $$ = new AstStop($1, false); }
|
||||
| yD_STOP '(' expr ')' { $$ = new AstStop($1, false); DEL($3); }
|
||||
//
|
||||
| yD_SFORMAT '(' expr ',' str commaEListE ')' { $$ = new AstSFormat($1,$3,*$5,$6); }
|
||||
| yD_SWRITE '(' expr ',' str commaEListE ')' { $$ = new AstSFormat($1,$3,*$5,$6); }
|
||||
| yD_SFORMAT '(' expr ',' str commaEListE ')' { $$ = new AstSFormat($1, $3, *$5, $6); }
|
||||
| yD_SWRITE '(' expr ',' str commaEListE ')' { $$ = new AstSFormat($1, $3, *$5, $6); }
|
||||
| yD_SWRITEB '(' expr ',' str commaEListE ')' { $$ = new AstSFormat($1, $3, *$5, $6, 'b'); }
|
||||
| yD_SWRITEH '(' expr ',' str commaEListE ')' { $$ = new AstSFormat($1, $3, *$5, $6, 'h'); }
|
||||
| yD_SWRITEO '(' expr ',' str commaEListE ')' { $$ = new AstSFormat($1, $3, *$5, $6, 'o'); }
|
||||
//
|
||||
| yD_DISPLAY parenE { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, NULL, NULL); }
|
||||
| yD_DISPLAY '(' exprList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, NULL, $3); }
|
||||
| yD_DISPLAYB parenE { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, NULL, NULL, 'b'); }
|
||||
| yD_DISPLAYB '(' exprList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, NULL, $3, 'b'); }
|
||||
| yD_DISPLAYH parenE { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, NULL, NULL, 'h'); }
|
||||
| yD_DISPLAYH '(' exprList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, NULL, $3, 'h'); }
|
||||
| yD_DISPLAYO parenE { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, NULL, NULL, 'o'); }
|
||||
| yD_DISPLAYO '(' exprList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, NULL, $3, 'o'); }
|
||||
| yD_WRITE parenE { $$ = NULL; } // NOP
|
||||
| yD_WRITE '(' exprList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, NULL, $3); }
|
||||
| yD_WRITEB parenE { $$ = NULL; } // NOP
|
||||
| yD_WRITEB '(' exprList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, NULL, $3, 'b'); }
|
||||
| yD_WRITEH parenE { $$ = NULL; } // NOP
|
||||
| yD_WRITEH '(' exprList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, NULL, $3, 'h'); }
|
||||
| yD_WRITEO parenE { $$ = NULL; } // NOP
|
||||
| yD_WRITEO '(' exprList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, NULL, $3, 'o'); }
|
||||
| yD_FDISPLAY '(' expr ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, NULL); }
|
||||
| yD_FDISPLAY '(' expr ',' exprListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, $5); }
|
||||
| yD_FDISPLAYB '(' expr ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, NULL, 'b'); }
|
||||
| yD_FDISPLAYB '(' expr ',' exprListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, $5, 'b'); }
|
||||
| yD_FDISPLAYH '(' expr ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, NULL, 'h'); }
|
||||
| yD_FDISPLAYH '(' expr ',' exprListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, $5, 'h'); }
|
||||
| yD_FDISPLAYO '(' expr ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, NULL, 'o'); }
|
||||
| yD_FDISPLAYO '(' expr ',' exprListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, $5, 'o'); }
|
||||
| yD_FWRITE '(' expr ',' exprListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, $3, $5); }
|
||||
| yD_FWRITEB '(' expr ',' exprListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, $3, $5, 'b'); }
|
||||
| yD_FWRITEO '(' expr ',' exprListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, $3, $5, 'h'); }
|
||||
| yD_FWRITEH '(' expr ',' exprListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, $3, $5, 'o'); }
|
||||
| yD_INFO parenE { $$ = new AstDisplay($1,AstDisplayType::DT_INFO, NULL, NULL); }
|
||||
| yD_INFO '(' exprList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_INFO, NULL, $3); }
|
||||
| yD_WARNING parenE { $$ = new AstDisplay($1,AstDisplayType::DT_WARNING, NULL, NULL); }
|
||||
|
|
@ -4471,7 +4543,7 @@ assertion_item<nodep>: // ==IEEE: assertion_item
|
|||
deferred_immediate_assertion_item<nodep>: // ==IEEE: deferred_immediate_assertion_item
|
||||
deferred_immediate_assertion_statement { $$ = $1; }
|
||||
| id/*block_identifier*/ ':' deferred_immediate_assertion_statement
|
||||
{ $$ = new AstBegin($<fl>1, *$1, $3); }
|
||||
{ $$ = new AstBegin($<fl>1, *$1, $3, false, true); }
|
||||
;
|
||||
|
||||
procedural_assertion_statement<nodep>: // ==IEEE: procedural_assertion_statement
|
||||
|
|
@ -4526,7 +4598,8 @@ deferred_immediate_assertion_statement<nodep>: // ==IEEE: deferred_immediate_ass
|
|||
|
||||
concurrent_assertion_item<nodep>: // IEEE: concurrent_assertion_item
|
||||
concurrent_assertion_statement { $$ = $1; }
|
||||
| id/*block_identifier*/ ':' concurrent_assertion_statement { $$ = new AstBegin($<fl>1, *$1, $3); }
|
||||
| id/*block_identifier*/ ':' concurrent_assertion_statement
|
||||
{ $$ = new AstBegin($<fl>1, *$1, $3, false, true); }
|
||||
// // IEEE: checker_instantiation
|
||||
// // identical to module_instantiation; see etcInst
|
||||
;
|
||||
|
|
@ -5397,7 +5470,7 @@ ps_id_etc: // package_scope + general id
|
|||
package_scopeIdFollowsE id { }
|
||||
;
|
||||
|
||||
ps_type<dtypep>: // IEEE: ps_parameter_identifier | ps_type_identifier
|
||||
ps_type<refdtypep>: // IEEE: ps_parameter_identifier | ps_type_identifier
|
||||
// Even though we looked up the type and have a AstNode* to it,
|
||||
// we can't fully resolve it because it may have been just a forward definition.
|
||||
package_scopeIdFollowsE idRefDType { $$ = $2; $2->packagep($1); }
|
||||
|
|
@ -5406,7 +5479,7 @@ ps_type<dtypep>: // IEEE: ps_parameter_identifier | ps_type_identifier
|
|||
|
||||
//=== Below rules assume special scoping per above
|
||||
|
||||
class_typeWithoutId<nodep>: // as with class_typeWithoutId but allow yaID__aTYPE
|
||||
class_typeWithoutId<refdtypep>: // as with class_typeWithoutId but allow yaID__aTYPE
|
||||
// // and we thus don't need to resolve it in specified package
|
||||
package_scopeIdFollowsE class_typeOneList { $$ = $2; $2->packagep($1); }
|
||||
;
|
||||
|
|
@ -5505,8 +5578,8 @@ class_method<nodep>: // ==IEEE: class_method
|
|||
|
||||
class_item_qualifier<nodep>: // IEEE: class_item_qualifier minus ySTATIC
|
||||
// // IMPORTANT: yPROTECTED | yLOCAL is in a lex rule
|
||||
yPROTECTED { $$ = NULL; } // Ignoring protected until implemented
|
||||
| yLOCAL__ETC { $$ = NULL; BBUNSUP($1, "Unsupported: 'local' class item"); }
|
||||
yPROTECTED { $$ = NULL; } // Ignoring protected until warning implemented
|
||||
| yLOCAL__ETC { $$ = NULL; } // Ignoring local until warning implemented
|
||||
| ySTATIC__ETC { $$ = NULL; BBUNSUP($1, "Unsupported: 'static' class item"); }
|
||||
;
|
||||
|
||||
|
|
|
|||
|
|
@ -43,10 +43,11 @@ endif
|
|||
######################################################################
|
||||
|
||||
SCENARIOS ?= --vlt --vltmt --dist
|
||||
DRIVER_HASHSET ?=
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
$(PERL) driver.pl $(DRIVER_FLAGS) $(SCENARIOS)
|
||||
$(PERL) driver.pl $(DRIVER_FLAGS) $(SCENARIOS) $(DRIVER_HASHSET)
|
||||
|
||||
######################################################################
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ my $opt_gdb;
|
|||
my $opt_rr;
|
||||
my $opt_gdbbt;
|
||||
my $opt_gdbsim;
|
||||
my $opt_hashset;
|
||||
my $opt_jobs = 1;
|
||||
my $opt_optimize;
|
||||
my $opt_quiet;
|
||||
|
|
@ -90,6 +91,7 @@ if (! GetOptions(
|
|||
"gdbbt!" => \$opt_gdbbt,
|
||||
"gdbsim!" => \$opt_gdbsim,
|
||||
"golden!" => sub { $ENV{HARNESS_UPDATE_GOLDEN} = 1; },
|
||||
"hashset=s" => \$opt_hashset,
|
||||
"help" => \&usage,
|
||||
"j=i" => \$opt_jobs,
|
||||
"optimize:s" => \$opt_optimize,
|
||||
|
|
@ -141,6 +143,8 @@ if ($#opt_tests<0) { # Run everything
|
|||
push @opt_tests, sort(glob("${dir}/t_*.pl"));
|
||||
}
|
||||
}
|
||||
@opt_tests = _calc_hashset(@opt_tests) if $opt_hashset;
|
||||
|
||||
if ($#opt_tests>=2 && $opt_jobs>=2) {
|
||||
# Without this tests such as t_debug_sigsegv_bt_bad.pl will occasionally
|
||||
# block on input and cause a SIGSTOP, then a "fg" was needed to resume testing.
|
||||
|
|
@ -261,6 +265,25 @@ sub calc_jobs {
|
|||
return $ok + 1;
|
||||
}
|
||||
|
||||
sub _calc_hashset {
|
||||
my @in = @_;
|
||||
return @in if !$opt_hashset;
|
||||
$opt_hashset =~ m!^(\d+)/(\d+)$!
|
||||
or die "%Error: Need number/number format for --hashset: $opt_hashset\n";
|
||||
my ($set, $nsets) = ($1, $2);
|
||||
my @new;
|
||||
foreach my $t (@opt_tests) {
|
||||
my $checksum = do {
|
||||
local $/;
|
||||
unpack("%32W*", $t);
|
||||
};
|
||||
if ($set == ($checksum % $nsets)) {
|
||||
push @new, $t;
|
||||
}
|
||||
}
|
||||
return @new;
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
#######################################################################
|
||||
#######################################################################
|
||||
|
|
@ -565,7 +588,7 @@ sub new {
|
|||
ghdl_run_flags => [],
|
||||
# IV
|
||||
iv => 0,
|
||||
iv_flags => [split(/\s+/,"+define+iverilog -o $self->{obj_dir}/simiv")],
|
||||
iv_flags => [split(/\s+/,"+define+iverilog -g2012 -o $self->{obj_dir}/simiv")],
|
||||
iv_flags2 => [], # Overridden in some sim files
|
||||
iv_pli => 0, # need to use pli
|
||||
iv_run_flags => [],
|
||||
|
|
@ -1048,7 +1071,7 @@ sub compile {
|
|||
"-DTEST_VERBOSE=\"".($self->{verbose} ? 1 : 0)."\"",
|
||||
"-DTEST_SYSTEMC=\"" .($self->sc ? 1 : 0). "\"",
|
||||
"-DCMAKE_PREFIX_PATH=\"".(($ENV{SYSTEMC_INCLUDE}||$ENV{SYSTEMC}||'')."/..\""),
|
||||
"-DTEST_OPT_FAST=\"" . ($param{benchmark}?"-O2":"") . "\"",
|
||||
"-DTEST_OPT_FAST=\"" . ($param{benchmark} ? "-Os" : "") . "\"",
|
||||
"-DTEST_VERILATION=\"" . $::Opt_Verilation . "\"",
|
||||
]);
|
||||
return 1 if $self->errors || $self->skips || $self->unsupporteds;
|
||||
|
|
@ -1066,7 +1089,7 @@ sub compile {
|
|||
"TEST_OBJ_DIR=$self->{obj_dir}",
|
||||
"CPPFLAGS_DRIVER=-D".uc($self->{name}),
|
||||
($self->{verbose} ? "CPPFLAGS_DRIVER2=-DTEST_VERBOSE=1":""),
|
||||
($param{benchmark}?"OPT_FAST=-O2":""),
|
||||
($param{benchmark} ? "OPT_FAST=-Os" : ""),
|
||||
"$self->{VM_PREFIX}", # bypass default rule, as we don't need archive
|
||||
($param{make_flags}||""),
|
||||
]);
|
||||
|
|
@ -1724,7 +1747,7 @@ sub _make_main {
|
|||
}
|
||||
$fh->print("\n");
|
||||
|
||||
print $fh " delete topp; topp=NULL;\n";
|
||||
print $fh " VL_DO_DANGLING(delete topp, topp);\n";
|
||||
print $fh " exit(0L);\n";
|
||||
print $fh "}\n";
|
||||
$fh->close();
|
||||
|
|
@ -1742,7 +1765,7 @@ sub _print_advance_time {
|
|||
|
||||
if ($self->sc) {
|
||||
print $fh "#if (SYSTEMC_VERSION>=20070314)\n";
|
||||
print $fh " sc_start(${time},SC_NS);\n";
|
||||
print $fh " sc_start(${time}, SC_NS);\n";
|
||||
print $fh "#else\n";
|
||||
print $fh " sc_start(${time});\n";
|
||||
print $fh "#endif\n";
|
||||
|
|
@ -2075,11 +2098,20 @@ sub fst2vcd {
|
|||
if (!$out || $out !~ /Usage:/) { $self->skip("No fst2vcd installed\n"); return 1; }
|
||||
|
||||
$cmd = qq{fst2vcd -e "$fn1" -o "$fn2"};
|
||||
print "\t$cmd\n" if $::Debug;
|
||||
print "\t$cmd\n"; # Always print to help debug race cases
|
||||
$out = `$cmd`;
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub fst_identical {
|
||||
my $self = (ref $_[0]? shift : $Self);
|
||||
my $fn1 = shift;
|
||||
my $fn2 = shift;
|
||||
my $tmp = $fn1.".vcd";
|
||||
fst2vcd($fn1, $tmp);
|
||||
return vcd_identical($tmp, $fn2);
|
||||
}
|
||||
|
||||
sub _vcd_read {
|
||||
my $self = (ref $_[0]? shift : $Self);
|
||||
my $filename = shift;
|
||||
|
|
@ -2494,6 +2526,11 @@ Run Verilator generated executable under the debugger.
|
|||
|
||||
Update golden files, equivalent to setting HARNESS_UPDATE_GOLDEN=1.
|
||||
|
||||
=item --hashset I<set>/I<numsets>
|
||||
|
||||
Split tests based on a hash of the test names into I<numsets> and run only
|
||||
tests in set number I<set> (0..I<numsets>-1).
|
||||
|
||||
=item --help
|
||||
|
||||
Displays this message and program version and exits.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
$warning("User compile-time warning");
|
||||
^~~~~~~~
|
||||
... Use "/* verilator lint_off USERWARN */" and lint_on around source to disable this message.
|
||||
%Warning-USERWARN: t/t_assert_comp_bad.v:11: 00000001
|
||||
%Warning-USERWARN: t/t_assert_comp_bad.v:11: 1
|
||||
: ... In instance t
|
||||
$warning(1);
|
||||
^~~~~~~~
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
top_filename("t/t_assert_on.v");
|
||||
|
||||
compile();
|
||||
|
||||
execute();
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
top_filename("t/t_assert_on.v");
|
||||
|
||||
compile(
|
||||
verilator_flags2 => ['--assert'],
|
||||
nc_flags2 => ['+assert'],
|
||||
);
|
||||
|
||||
execute(
|
||||
fails => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
scenarios(vlt => 1);
|
||||
|
||||
top_filename("t/t_assert_on.v");
|
||||
|
||||
compile(
|
||||
verilator_flags2 => ["--assert"],
|
||||
);
|
||||
|
||||
execute(
|
||||
all_run_flags => ["+verilator+noassert"],
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
scenarios(vlt => 1);
|
||||
|
||||
top_filename("t/t_assert_on.v");
|
||||
|
||||
compile(
|
||||
verilator_flags2 => ["--assert"],
|
||||
);
|
||||
|
||||
execute(
|
||||
fails => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2007 by Wilson Snyder.
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
|
||||
input clk;
|
||||
|
||||
always @ (posedge clk) begin
|
||||
assert (0);
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -10,9 +10,6 @@ class C #(parameter P=1);
|
|||
%Error: t/t_class_unsup_bad.v:13: Unsupported: class parameters
|
||||
localparam LOCPAR = 10;
|
||||
^
|
||||
%Error: t/t_class_unsup_bad.v:16: Unsupported: 'local' class item
|
||||
local int loc;
|
||||
^~~~~
|
||||
%Error: t/t_class_unsup_bad.v:24: Unsupported: virtual class member qualifier
|
||||
virtual function void func_virtual; endfunction
|
||||
^~~~~~~
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
#include <verilated.h>
|
||||
#include VM_PREFIX_INCLUDE
|
||||
|
||||
unsigned int main_time = false;
|
||||
unsigned int main_time = 0;
|
||||
|
||||
double sc_time_stamp() { return main_time; }
|
||||
|
||||
|
|
|
|||
|
|
@ -43,11 +43,15 @@
|
|||
[0] %s=! %s= what! %s= hmmm!1234
|
||||
[0] %6s=: !: %6s=: what!: %6s=: hmmm!1234:
|
||||
[0] %8s=: sv-str:
|
||||
d: 12 12
|
||||
h: 00c 00c
|
||||
o: 014 014
|
||||
b: 000001100 000001100
|
||||
[0] hello, from a very long string. Percent %s are literally substituted in.
|
||||
hello, from a concatenated string.
|
||||
hello, from a concatenated format string [0].
|
||||
extra argument: 0000000000000000
|
||||
0000000000000000: pre argument
|
||||
extra argument: 0
|
||||
0: pre argument
|
||||
[0] Embedded <#013> return
|
||||
[0] Embedded
|
||||
multiline
|
||||
|
|
|
|||
|
|
@ -132,6 +132,12 @@ module t;
|
|||
$display("[%0t] %%8s=:%8s:", $time,
|
||||
svs);
|
||||
|
||||
// Displays without format, must use default
|
||||
$write("d: "); $write(nine); $write(" "); $display(nine);
|
||||
$writeh("h: "); $writeh(nine); $writeh(" "); $displayh(nine);
|
||||
$writeo("o: "); $writeo(nine); $writeo(" "); $displayo(nine);
|
||||
$writeb("b: "); $writeb(nine); $writeb(" "); $displayb(nine);
|
||||
|
||||
$display("[%0t] %s%s%s", $time,
|
||||
"hel", "lo, fr", "om a very long string. Percent %s are literally substituted in.");
|
||||
$display("hel", "lo, fr", "om a concatenated string.");
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ f
|
|||
t2=0
|
||||
post
|
||||
t3=0
|
||||
t4=0 t5=00000000000000000
|
||||
t4=0 t5=0 0
|
||||
m
|
||||
t=0 t2=0 t3=0 t4=0 t5=0
|
||||
t=0 t2=0 t3=0 t4=0 t5=0
|
||||
mm
|
||||
|
||||
f a=top.t b=top.t pre t=0 t2=0 post t3=0 t4=0 t5=00000000000000000m t=0 t2=0 t3=0 t4=0 t5=0 t=0 t2=0 t3=0 t4=0 t5=0mm
|
||||
f a=top.t b=top.t pre t=0 t2=0 post t3=0 t4=0 t5=0 0m t=0 t2=0 t3=0 t4=0 t5=0 t=0 t2=0 t3=0 t4=0 t5=0mm
|
||||
|
||||
*-* All Finished *-*
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
%Error: t/t_dpi_openreg_bad.v:13: Unsized/open arrays ('[]') are only supported in DPI imports
|
||||
: ... In instance t
|
||||
reg a [];
|
||||
^
|
||||
%Error: t/t_dpi_openreg_bad.v:14: Unsized/open arrays ('[]') are only supported in DPI imports
|
||||
: ... In instance t
|
||||
input b [];
|
||||
^
|
||||
%Error: Exiting due to
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// Copyright 2009 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
b
|
||||
);
|
||||
|
||||
reg a [];
|
||||
input b [];
|
||||
|
||||
initial begin
|
||||
$stop;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -114,7 +114,7 @@ void mon_eval() {
|
|||
|
||||
//======================================================================
|
||||
|
||||
unsigned int main_time = false;
|
||||
unsigned int main_time = 0;
|
||||
|
||||
double sc_time_stamp() { return main_time; }
|
||||
int main(int argc, char** argv, char** env) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2019 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2020 by Wilson Snyder.
|
||||
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
integer cyc=0;
|
||||
|
||||
integer i;
|
||||
string v;
|
||||
|
||||
// verilator lint_off UNUSED
|
||||
integer unused[];
|
||||
// verilator lint_on UNUSED
|
||||
|
||||
typedef bit [7:0] byte_t;
|
||||
byte_t a[];
|
||||
byte_t b[];
|
||||
|
||||
always @ (posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
begin
|
||||
`checkh(a.size, 0);
|
||||
v = $sformatf("%p", a); `checks(v, "'{} ");
|
||||
|
||||
a = new [3];
|
||||
`checkh(a.size, 3);
|
||||
a[0] = 10;
|
||||
a[1] = 11;
|
||||
a[2] = 12;
|
||||
`checkh(a[0], 10);
|
||||
`checkh(a[1], 11);
|
||||
`checkh(a[2], 12);
|
||||
v = $sformatf("%p", a); `checks(v, "'{'ha, 'hb, 'hc} ");
|
||||
a.delete;
|
||||
`checkh(a.size, 0);
|
||||
|
||||
a = new [2];
|
||||
`ifdef verilator // Unsupported pattern assignment
|
||||
a[0] = 15; a[1] = 16;
|
||||
`else
|
||||
a = '{15, 16};
|
||||
`endif
|
||||
`checkh(a.size, 2);
|
||||
`checkh(a[0], 15);
|
||||
`checkh(a[1], 16)
|
||||
|
||||
`ifdef verilator // Unsupported pattern assignment
|
||||
a = new [1];
|
||||
a[0] = 17;
|
||||
`else
|
||||
a = '{17};
|
||||
`endif
|
||||
`checkh(a.size, 1); // IEEE says resizes to smallest that fits pattern
|
||||
`checkh(a[0], 17);
|
||||
|
||||
a = new[2];
|
||||
a[0] = 5;
|
||||
a[1] = 6;
|
||||
`checkh(a[0], 5);
|
||||
`checkh(a[1], 6);
|
||||
a = new[2];
|
||||
`checkh(a[0], 0);
|
||||
`checkh(a[1], 0);
|
||||
|
||||
a[0] = 5;
|
||||
a[1] = 6;
|
||||
`checkh(a[0], 5);
|
||||
`checkh(a[1], 6);
|
||||
|
||||
b = new [4](a);
|
||||
`checkh(b.size, 4);
|
||||
`checkh(b[0], 5);
|
||||
`checkh(b[1], 6);
|
||||
`checkh(b[2], 0);
|
||||
`checkh(b[3], 0);
|
||||
|
||||
a = b;
|
||||
`checkh(a.size, 4);
|
||||
`checkh(a[0], 5);
|
||||
`checkh(a[1], 6);
|
||||
`checkh(a[2], 0);
|
||||
`checkh(a[3], 0);
|
||||
|
||||
a = new [0];
|
||||
`checkh(a.size, 0);
|
||||
b = new [4](a);
|
||||
`checkh(b.size, 4);
|
||||
`checkh(b[0], 0);
|
||||
`checkh(b[1], 0);
|
||||
`checkh(b[2], 0);
|
||||
`checkh(b[4], 0);
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
%Warning-WIDTH: t/t_dynarray_bad.v:14: Operator NEWDYNAMIC expects 32 bits on the new() size, but new() size's VARREF 's' generates 64 bits.
|
||||
: ... In instance t
|
||||
a = new [s];
|
||||
^~~
|
||||
... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message.
|
||||
%Error: Internal Error: ../V3Number.cpp:#: Number operation called with non-logic (double or string) argument: '"str""
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2019 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
scenarios(linter => 1);
|
||||
|
||||
lint(
|
||||
fails => 1,
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2020 by Wilson Snyder.
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
|
||||
integer a[];
|
||||
|
||||
string s;
|
||||
|
||||
initial begin
|
||||
s = "str";
|
||||
a = new [s]; // Bad
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -7,6 +7,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
|||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
|
|
@ -14,15 +15,18 @@ compile(
|
|||
verilator_make_cmake => 1,
|
||||
);
|
||||
|
||||
system("cmake --version");
|
||||
if ($? != 0) {
|
||||
skip("cmake is not installed");
|
||||
} else {
|
||||
my $cmakecache = $Self->{obj_dir}."/CMakeCache.txt";
|
||||
if (! -e $cmakecache) {
|
||||
error("$cmakecache does not exist.")
|
||||
}
|
||||
|
||||
my $cmakecache = $Self->{obj_dir}."/CMakeCache.txt";
|
||||
if (! -e $cmakecache) {
|
||||
error("$cmakecache does not exist")
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
}
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
010: exp=top.t.show0 got=top.t.show0
|
||||
014: exp=top.t.genblk1.show1 got=top.t.genblk1.show1
|
||||
018: exp=top.t.genblk2.show2 got=top.t.genblk2.show2
|
||||
023: exp=top.t.genblk3.genblk1.show3 got=top.t.genblk3.genblk1.show3
|
||||
029: exp=top.t.x1.x3.show4 got=top.t.x1.x3.show4
|
||||
*-* All Finished *-*
|
||||
|
|
@ -7,10 +7,12 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
|||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
scenarios(linter => 1);
|
||||
scenarios(simulator => 1);
|
||||
|
||||
lint(
|
||||
fails => $Self->{vlt_all},
|
||||
compile(
|
||||
);
|
||||
|
||||
execute(
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk, reset_l
|
||||
);
|
||||
|
||||
input clk;
|
||||
input reset_l;
|
||||
|
||||
generate
|
||||
show #(`__LINE__, "top.t.show0") show0();
|
||||
|
||||
if (0) ;
|
||||
else if (0) ;
|
||||
else if (1) show #(`__LINE__, "top.t.genblk1.show1") show1();
|
||||
|
||||
if (0) begin end
|
||||
else if (0) begin end
|
||||
else if (1) begin show #(`__LINE__, "top.t.genblk2.show2") show2(); end
|
||||
|
||||
if (0) ;
|
||||
else begin
|
||||
if (0) begin end
|
||||
else if (1) begin show #(`__LINE__, "top.t.genblk3.genblk1.show3") show3(); end
|
||||
end
|
||||
|
||||
if (0) ;
|
||||
else begin : x1
|
||||
if (0) begin : x2 end
|
||||
else if (1) begin : x3 show #(`__LINE__, "top.t.x1.x3.show4") show4(); end
|
||||
end
|
||||
endgenerate
|
||||
|
||||
int cyc;
|
||||
|
||||
always @ (posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
if (cyc == 99) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
end
|
||||
endmodule
|
||||
|
||||
module show #(parameter LINE=0, parameter string EXPT) ();
|
||||
always @ (posedge t.clk) begin
|
||||
if (t.cyc == LINE) begin
|
||||
$display("%03d: exp=%s got=%m", LINE, EXPT);
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue