'Merge from master for release.'

This commit is contained in:
Wilson Snyder 2020-06-06 07:49:57 -04:00
commit 369ce6af2c
1677 changed files with 16506 additions and 6920 deletions

View File

@ -3,3 +3,4 @@ exclude_paths:
- '.github/**'
- 'ci/build_verilator.sh'
- 'include/vltstd/**'
- 'nodist/fastcov.py'

View File

@ -8,176 +8,107 @@
version: ~> 1.0
os: linux
language: cpp
cache: ccache
env:
global:
- VERILATOR_CACHE=$HOME/verilator_cache
- VERILATOR_ROOT=$PWD
- VERILATOR_NUM_JOBS=$(echo `nproc` + 1 | bc)
- VERILATOR_CONFIG_FLAGS="--enable-maintainer-mode --enable-longtests"
- VERILATOR_AUTHOR_SITE=1
cache:
directories:
- $VERILATOR_CACHE
- $HOME/.ccache
before_install:
# Perl modules needed for testing
# Not listing Bit::Vector as slow to install, and only skips one test
- touch temp.cpp ; g++ -E -dM -c temp.cpp | sort ; rm -rf temp.cpp
- yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
- sudo apt-get install gdb gtkwave
- sudo apt-get install libgoogle-perftools-dev
before_script:
- bash -x ci/build_vcddiff.sh
- bash -x ci/build_verilator.sh
after_script:
- ccache -s
env:
global:
- VERILATOR_ROOT=$TRAVIS_BUILD_DIR
# The list and order of build stages
stages:
- "Build Verilator"
- test
- build # Build Verilator
- test # Run tests
# Dump info about the environment for debugging
before_install:
# To dump the script that Travis itself is executing, add 'cat $0' here
- cd "$TRAVIS_BUILD_DIR" # Skipping the git clone in later stages requires this
- export CCACHE_MAXSIZE=$(ci/travis-ccache-size.bash) # Set here after the 'cd'
- env | sort
- ls -lA .
- ls -lA bin
- g++ -E -dM -c -x c++ /dev/null | sort
- clang++ -E -dM -c -x c++ /dev/null | sort
# Install all dependencies
install:
- ./ci/travis-install.bash
before_script:
# ccache maintenance
- ./ci/travis-ccache-maint.bash
# On Focal, set the SystemC installation location
- |
if [ "$TRAVIS_DIST" = "focal" ]; then
export SYSTEMC_INCLUDE=/usr/include
export SYSTEMC_LIBDIR=/usr/lib/x86_64-linux-gnu
fi
before_cache:
- ccache -s -z
# All jobs run the same script
script: ./ci/travis-script.bash
# Enumerate all the jobs
jobs:
include:
- if: type != cron
stage: "Build Verilator"
name: Build Verilator
compiler: gcc
script: echo "Done building Verilator"
# Non-cron build will just run on whatever linux flavor we get
- if: type != cron
stage: test
name: Dist test
compiler: gcc
script: ci/test.sh dist
- if: type != cron
stage: test
name: Vlt test
compiler: gcc
script: ci/test.sh vlt
- if: type != cron
stage: test
name: Vltmt set 0 test
compiler: gcc
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"
name: Build xenial gcc Verilator
os: linux
dist: xenial
compiler: gcc
script: echo "Done building Verilator"
- if: type = cron
stage: test
name: Xenial gcc dist test
os: linux
dist: xenial
compiler: gcc
script: ci/test.sh dist
- if: type = cron
stage: test
name: Xenial gcc vlt test
os: linux
dist: xenial
compiler: gcc
script: ci/test.sh vlt
- if: type = cron
stage: test
name: Xenial gcc vltmt test
os: linux
dist: xenial
compiler: gcc
script: ci/test.sh vltmt
- if: type = cron
stage: "Build Verilator"
name: Build xenial clang Verilator
os: linux
dist: xenial
compiler: clang
script: echo "Done building Verilator"
- if: type = cron
stage: test
name: Xenial clang dist test
os: linux
dist: xenial
compiler: clang
script: ci/test.sh dist
- if: type = cron
stage: test
name: Xenial clang vlt test
os: linux
dist: xenial
compiler: clang
script: ci/test.sh vlt
- if: type = cron
stage: test
name: Xenial clang vltmt test
os: linux
dist: xenial
compiler: clang
script: ci/test.sh vltmt
# - if: type = cron
# stage: "Build Verilator"
# name: Build OSX gcc Verilator
# os: osx
# compiler: gcc
# script: echo "Done building Verilator"
# - if: type = cron
# stage: test
# name: OSX gcc dist test
# os: osx
# compiler: gcc
# script: ci/test.sh dist
# - if: type = cron
# stage: test
# name: OSX gcc vlt test
# os: osx
# compiler: gcc
# script: ci/test.sh vlt
# - if: type = cron
# stage: test
# name: OSX gcc vltmt test
# os: osx
# compiler: gcc
# script: ci/test.sh vltmt
- if: type = cron
stage: "Build Verilator"
name: Build trusty gcc Verilator
os: linux
dist: trusty
compiler: gcc
script: echo "Done building Verilator"
- if: type = cron
stage: test
name: Trusty gcc dist test
os: linux
dist: trusty
compiler: gcc
script: ci/test.sh dist
- if: type = cron
stage: test
name: Trusty gcc vlt test
os: linux
dist: trusty
compiler: gcc
script: ci/test.sh vlt
- if: type = cron
stage: test
os: linux
dist: trusty
name: Trusty gcc vltmt test
compiler: gcc
script: ci/test.sh vltmt
############################################################################
# Jobs in the 'build' stage
############################################################################
# GCC builds
- {stage: build, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {create: {name: trusty-gcc, paths: .}}}
- {stage: build, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {create: {name: xenial-gcc, paths: .}}}
- {stage: build, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {create: {name: bionic-gcc, paths: .}}}
- {stage: build, os: linux, dist: focal, compiler: gcc, workspaces: {create: {name: focal-gcc, paths: .}}}
# Clang builds
- {stage: build, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {create: {name: xenial-clang, paths: .}}}
- {stage: build, os: linux, dist: focal, compiler: clang, workspaces: {create: {name: focal-clang, paths: .}}}
# Coverage build
- {stage: build, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {create: {name: coverage, paths: .}}, env: COVERAGE=1}
############################################################################
# Jobs in the 'test' stage
############################################################################
# GCC tests
- {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
- {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
- {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
- {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
# Clang tests
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=dist-vlt-0}
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=dist-vlt-1}
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=vltmt-0}
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=vltmt-1}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=dist-vlt-0}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=dist-vlt-1}
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=vltmt-0}
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=vltmt-1}
# Coverage tests
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-dist}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-0}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-1}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-2}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-3}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-0}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-1}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-2}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-3}
notifications:
email:

1780
Changes

File diff suppressed because it is too large Load Diff

View File

@ -45,6 +45,7 @@ src/Makefile$
src/Makefile_obj$
include/verilated.mk$
test_regress/.gdbinit$
codecov.yml
config.cache$
config.status$
verilator\.log

View File

@ -5,6 +5,7 @@ ifdef::env-github[]
image:https://img.shields.io/badge/License-LGPL%20v3-blue.svg[license LGPLv3,link=https://www.gnu.org/licenses/lgpl-3.0]
image:https://img.shields.io/badge/License-Artistic%202.0-0298c3.svg[license Artistic-2.0,link=https://opensource.org/licenses/Artistic-2.0]
image:https://api.codacy.com/project/badge/Grade/fa78caa433c84a4ab9049c43e9debc6f[Code Quality,link=https://www.codacy.com/gh/verilator/verilator]
image:https://codecov.io/gh/verilator/verilator/branch/master/graph/badge.svg[Coverage,link=https://codecov.io/gh/verilator/verilator]
image:https://travis-ci.com/verilator/verilator.svg?branch=master[Build Status (Travis CI),link=https://travis-ci.com/verilator/verilator]
endif::[]
@ -20,9 +21,9 @@ endif::[]
== Welcome to Verilator
[cols="a,a",indent=0,frame="none"]
[cols="a,a",indent=0,frame="none",grid="rows"]
|===
^.^| *Welcome to Verilator, the fastest Verilog HDL simulator.*
^.^| *Welcome to Verilator, the fastest Verilog/SystemVerilog simulator.*
+++ <br/> +++ &bullet; Accepts synthesizable Verilog or SystemVerilog
+++ <br/> +++ &bullet; Performs lint code-quality checks
+++ <br/> +++ &bullet; Compiles into multithreaded {cpp}, or SystemC
@ -73,15 +74,15 @@ replacement for NC-Verilog, VCS or another commercial Verilog simulator, or
if you are looking for a behavioral Verilog simulator e.g. for a quick
class project (we recommend http://iverilog.icarus.com[Icarus Verilog] for
this.) However, if you are looking for a path to migrate SystemVerilog to
{cpp} or SystemC, and your team is comfortable writing just a
touch of {cpp} code, Verilator is the tool for you.
{cpp} or SystemC, or your team is comfortable writing just a touch of {cpp}
code, Verilator is the tool for you.
== Performance
Verilator does not simply convert Verilog HDL to {cpp} or SystemC. Rather,
Verilator compiles your code into a much faster optimized and optionally
thread-partitioned model, which is in turn wrapped inside a
{cpp}/SystemC/{cpp}-under-Python module. The results are a compiled
{cpp}/SystemC 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
@ -112,9 +113,11 @@ For more information:
* https://verilator.org/verilator_doc.html[Verilator manual (HTML)],
or https://verilator.org/verilator_doc.pdf[Verilator manual (PDF)]
* https://github.com/verilator/verilator-announce[Subscribe to verilator announcements]
* https://verilator.org/forum[Verilator forum]
* https://verilator.org/issues[Verilator Issues]
* https://verilator.org/issues[Verilator issues]
== Support

View File

@ -300,6 +300,7 @@ detailed descriptions in L</"VERILATION ARGUMENTS"> for more information.
--dump-tree Enable dumping .tree files
--dump-treei <level> Enable dumping .tree files at a level
--dump-treei-<srcfile> <level> Enable dumping .tree file at a source file at a level
--dump-tree-addrids Use short identifiers instead of addresses
-E Preprocess, but do not compile
--error-limit <value> Abort after this number of errors
--exe Link to create executable
@ -399,6 +400,7 @@ detailed descriptions in L</"VERILATION ARGUMENTS"> for more information.
+verilog2001ext+<ext> Synonym for +1364-2001ext+<ext>
--version Displays program version and exits
--vpi Enable VPI compiles
--waiver-output <filename> Create a waiver file based on the linter warnings
-Wall Enable all style warnings
-Werror-<message> Convert warnings to errors
-Wfuture-<message> Disable unknown message warnings
@ -811,6 +813,14 @@ file to the specified tree dumping level (e.g. C<--dump-treei-V3Order 9>).
Level 0 disbles dumps and is equivalent to "--no-dump-tree". Level 9
enables dumping of every stage.
=item --dump-tree-addrids
Rarely needed - for developer use. Replace AST node addresses with short
identifiers in tree dumps to enhance readability. Each unique pointer value
is mapped to a unique identifier, but note that this is not necessarily
unique per node instance as an address might get reused by a newly allocated
node after a node with the same address has been dumped then freed.
=item -E
Preprocess the source code, but do not compile, as with 'gcc -E'. Output
@ -881,7 +891,10 @@ octal (0..) or binary (0b..) notation.
=item Double literals
Double literals must contain a dot (.) and/or an exponent (e).
Double literals must be one of the following styles:
- contains a dot (.) (e.g. 1.23)
- contains an expornent (e/E) (e.g. 12e3)
- contains p/P for hexadecimal floating point in C99 (e.g. 0x123.ABCp1)
=item Strings
@ -1119,17 +1132,15 @@ developers.
Enables splitting the output .cpp files into multiple outputs. When a C++
file exceeds the specified number of operations, a new file will be created
at the next function boundary. In addition, any infrequently executed
"cold" routines will be placed into __Slow files. This accelerates
compilation by as optimization can be disabled on the routines in __Slow,
and the remaining files can be compiled on parallel machines. Using
--output-split should have only a trivial impact on performance. On one
design --output-split 20000 resulted in splitting into approximately
one-minute-compile chunks.
at the next function boundary. In addition, if the total output code size
exceeds the specified value, VM_PARALLEL_BUILDS will be set to 1 by default
in the generated make files, making parallel compilation possible. Using
--output-split should have only a trivial impact on model performance. But
can greatly improve C++ compilation speed. The use of I<ccache> (set for you
if present at configure time) is also more effective with this option.
Typically when using this, make with VM_PARALLEL_BUILDS=1 (set for you if
using the default makefiles), and use I<ccache> (set for you if present at
configure time).
This option is on by default with a value of 20000. To disable, pass with a
value of 0.
=item --output-split-cfuncs I<statements>
@ -1141,10 +1152,14 @@ worse with decreasing split values. Note that this option is stronger than
--output-split in the sense that --output-split will not split inside a
function.
Defaults to the value of --output-split, unless explicitly specified.
=item --output-split-ctrace I<statements>
Enables splitting trace functions in the output .cpp files into
multiple functions. Defaults to same setting as --output-split-cfuncs.
Similar to --output-split-cfuncs, enables splitting trace functions in the
output .cpp files into multiple functions.
Defaults to the value of --output-split, unless explicitly specified.
=item -P
@ -1451,7 +1466,7 @@ good value.
Sets default timescale, timeunit and timeprecision for when `timescale does
not occur in sources. Default is "1ps/1ps" (to match SystemC). This is
overriden by C<--timescale-override>.
overridden by C<--timescale-override>.
=item --timescale-override I<timeunit>/I<timeprecision>
@ -1539,7 +1554,7 @@ larger trace files.
=item --trace-threads I<threads>
Enable waveform tracing using separate threads. This is typically faster in
simulation runtime but uses more total compute. This option is independend of,
simulation runtime but uses more total compute. This option is independent of,
and works with, both C<--trace> and C<--trace-fst>. Different trace formats can
take advantage of more trace threads to varying degrees. Currently VCD tracing
can utilize at most --trace-threads 1, and FST tracing can utilize at most
@ -1601,6 +1616,17 @@ Displays program version and exits.
Enable use of VPI and linking against the verilated_vpi.cpp files.
=item --waiver-output <filename>
Generate a waiver file which contains all waiver statements to suppress the
warnings emitted during this Verilator run. This is in particular useful as
a starting point for solving linter warnings or suppressing them
systematically.
The generated file is in the Verilator Configuration format, see
L</"CONFIGURATION FILES">, and can directly be consumed by Verilator. The
standard file extension is .vlt.
=item -Wall
Enable all code style warnings, including code style warnings that are
@ -2001,7 +2027,7 @@ depending on the operating system.
# Might be needed if SystemC 2.3.0
export SYSTEMC_CXX_FLAGS=-pthread
g++ -L$SYSTEMC_LIBDIR ../sc_main.o Vour__ALL*.o verilated.o \
g++ -L$SYSTEMC_LIBDIR ../sc_main.o Vour__ALL.a verilated.o \
-o Vour -lsystemc
And now we run it
@ -2054,11 +2080,11 @@ distribution.
=head1 BENCHMARKING & OPTIMIZATION
For best performance, run Verilator with the "-O3 --x-assign fast
--x-initial fast --noassert" flags. The -O3 flag will require longer
compile times, and "--x-assign fast --x-initial fast" may increase the risk
of reset bugs in trade for performance; see the above documentation for
these flags.
For best performance, run Verilator with the "-O3 --x-assign fast --x-initial
fast --noassert" flags. The -O3 flag will require longer time to run
Verilator, and "--x-assign fast --x-initial fast" may increase the risk of
reset bugs in trade for performance; see the above documentation for these
flags.
If using Verilated multithreaded, use C<numactl> to ensure you are using
non-conflicting hardware resources. See L</"MULTITHREADING">.
@ -2070,49 +2096,69 @@ simple change to a clock latch used to gate clocks and gained a 60%
performance improvement.
Beyond that, the performance of a Verilated model depends mostly on your
C++ compiler and size of your CPU's caches.
C++ compiler and size of your CPU's caches. Experience shows that large models
are often limited by the size of the instruction cache, and as such reducing
code size if possible can be beneficial.
By default, the lib/verilated.mk file has optimization turned off. This is
for the benefit of new users, as it improves compile times at the cost of
simulation runtimes. To add optimization as the default, set one of three variables,
OPT, OPT_FAST, or OPT_SLOW lib/verilated.mk. Or, use the -CFLAGS and/or
-LDFLAGS option on the verilator command line to pass the flags directly to
the compiler or linker. Or, just for one run, pass them on the command
line to make:
The supplied $VERILATOR_ROOT/include/verilated.mk file uses the OPT, OPT_FAST,
OPT_SLOW and OPT_GLOBAL variables to control optimization. You can set these
when compiling the output of Verilator with Make, for example:
make OPT_FAST="-Os -march=native -fno-stack-protector" -f Vour.mk Vour__ALL.a
make OPT_FAST="-Os -march=native" -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="-Os
-march=native", 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 "-O2" or "-O3" may help, but gcc compile times
may be excessive under O3 on even medium sized designs.
OPT_FAST specifies optimization flags for those parts of the model that are on
the fast path. This is mostly code that is executed every cycle. OPT_SLOW
applies to slow-path code, which executes rarely, often only once at the
beginning or end of simulation. Note that OPT_SLOW is ignored if
VM_PARALLEL_BUILDS is not 1, in which case all generated code will be compiled
in a single compilation unit using OPT_FAST. See also the C<--output-split>
option. The OPT_GLOBAL variable applies to common code in the run-time library
used by verilated models (shipped in $VERILATOR_ROOT/include). Additional C++
files passed on the verilator command line use OPT_FAST. The OPT variable
applies to all compilation units in addition to the specific OPT_* variables
described above.
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.)
You can also use the -CFLAGS and/or -LDFLAGS options on the verilator command
line to pass flags directly to the compiler or linker.
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.
The default values of the OPT_* variables are chosen to yield good simulation
speed with reasonable C++ compilation times. To this end, OPT_FAST is set to
"-Os" by default. Higher optimization such as "-O2" or "-O3" may help (though
often they provide only a very small performance benefit), but compile times
may be excessively large even with medium sized designs. Compilation times can
be improved at the expense of simulation speed by reducing optimization, for
example with OPT_FAST="-O0". Often good simulation speed can be achieved with
OPT_FAST="-O1 -fstrict-aliasing" but with improved compilation times. Files
controlled by OPT_SLOW have little effect on performance and therefore OPT_SLOW
is empty by default (equivalent to "-O0") for improved compilation speed. In
common use-cases there should be little benefit in changing OPT_SLOW.
OPT_GLOBAL is set to "-Os" by default and there should rarely be a need to
change it. As the run-time library is small in comparison to a lot of verilated
models, disabling optimization on the run-time library should not have a
serious effect on overall compilation time, but may have detrimental effect on
simulation speed, especially with tracing. In addition to the above, for best
results use OPT="-march=native", the latest Clang compiler (about 10% faster
than GCC), and link statically.
If you will be running many simulations on a single compile, investigate
feedback driven compilation. With GCC, using -fprofile-arcs, then
Generally the answer to which optimization level gives the best user experience
depends on the use case and some experimentation can pay dividends. For a
speedy debug cycle during development, especially on large designs where C++
compilation speed can dominate, consider using lower optimization to get to an
executable faster. For throughput oriented use cases, for example regressions,
it is usually worth spending extra compilation time to reduce total CPU time.
If you will be running many simulations on a single model, you can investigate
profile guided optimization. With GCC, using -fprofile-arcs, then
-fbranch-probabilities will yield another 15% or so.
Modern compilers also support link-time optimization (LTO), which can help
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.
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.
Unfortunately, using the optimizer with SystemC files can result in compilation
taking several minutes. (The SystemC libraries have many little inlined
functions that drive the compiler nuts.)
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
@ -2184,8 +2230,7 @@ After running Make, the C++ compiler may produce the following:
{mod_prefix}{misc}.o // Intermediate objects
{prefix} // Final executable (w/--exe argument)
{prefix}__ALL.a // Library of all Verilated objects
{prefix}__ALLfast.cpp // Include of hot code for single compile
{prefix}__ALLslow.cpp // Include of slow code for single compile
{prefix}__ALL.cpp // Include of all code for single compile
{prefix}{misc}.d // Intermediate dependencies
{prefix}{misc}.o // Intermediate objects
@ -2653,7 +2698,7 @@ Verilator and add the generated C++ sources to the target specified.
verilate(target SOURCES source ... [TOP_MODULE top] [PREFIX name]
[TRACE] [TRACE_FST] [SYSTEMC] [COVERAGE]
[INCLUDE_DIRS dir ...] [OPT_SLOW ...] [OPT_FAST ...]
[DIRECTORY dir] [VERILATOR_ARGS ...])
[OPT_GLOBAL ..] [DIRECTORY dir] [VERILATOR_ARGS ...])
Lowercase and ... should be replaced with arguments, the uppercase parts
delimit the arguments and can be passed in any order, or left out entirely
@ -2744,6 +2789,11 @@ optimization level to improve compile times with large designs.
Optional. Set compiler flags for the fast path.
=item OPT_GLOBAL
Optional. Set compiler flags for the common run-time library used by verilated
models.
=item DIRECTORY
Optional. Set the verilator output directory. It is preferable to use the
@ -2769,8 +2819,7 @@ underneath NC:
cd obj_dir
ncsc_run \
sc_main.cpp \
Vour__ALLfast.cpp \
Vour__ALLslow.cpp \
Vour__ALL.cpp \
verilated.cpp
For larger designs you'll want to automate this using makefiles, which pull
@ -3076,7 +3125,7 @@ information.
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.
recommended by Verilator itself, see UNOPTFLAT.
Same as /*verilator split_var*/, see L</"LANGUAGE EXTENSIONS"> for more
information.
@ -3101,11 +3150,11 @@ uwire keyword.
=head2 SystemVerilog 2005 (IEEE 1800-2005) Support
Verilator supports ==? and !=? operators, ++ and -- in some contexts,
$bits, $countones, $error, $fatal, $info, $isunknown, $onehot, $onehot0,
$unit, $warning, always_comb, always_ff, always_latch, bit, byte, chandle,
const, do-while, enum, export, final, import, int, interface, logic,
longint, modport, package, program, shortint, struct, time, typedef, union,
var, void, priority case/if, and unique case/if.
$bits, $countbits, $countones, $error, $fatal, $info, $isunknown, $onehot,
$onehot0, $unit, $warning, always_comb, always_ff, always_latch, bit, byte,
chandle, const, do-while, enum, export, final, import, int, interface,
logic, longint, modport, package, program, shortint, struct, time, typedef,
union, var, void, priority case/if, and unique case/if.
It also supports .name and .* interconnection.
@ -3571,7 +3620,7 @@ for more information.
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
Typically the variables to attach this to are recommended by Verilator
itself, see UNOPTFLAT below.
For example, Verilator will internally convert a variable with the
@ -3620,29 +3669,24 @@ declared.
=head1 LANGUAGE LIMITATIONS
There are some limitations and lack of features relative to a commercial
simulator, by intent. User beware.
It is strongly recommended you use a lint tool before running this program.
Verilator isn't designed to easily uncover common mistakes that a lint
program will find for you.
There are some limitations and lack of features relative to the major
closed-source simulators, by intent.
=head2 Synthesis Subset
Verilator supports only the Synthesis subset with a few minor additions
such as $stop, $finish and $display. That is, you cannot use hierarchical
references, events or similar features of the Verilog language. It also
simulates as Synopsys's Design Compiler would; namely a block of the form:
Verilator supports the Synthesis subset with other verification constructs
being added over time. Verilator also simulates events as Synopsys's Design
Compiler would; namely given a block of the form:
always @ (x) y = x & z;
This will recompute y when there is even a potential for change in x or a
change in z, that is when the flops computing x or z evaluate (which is
what Design Compiler will synthesize.) A compliant simulator would only
calculate y if x changes. Use Verilog-Mode's /*AS*/ or Verilog 2001's
always @* to reduce missing activity items. Avoid putting $displays in
combo blocks, as they may print multiple times when not desired, even on
compliant simulators as event ordering is not specified.
calculate y if x changes. We recommend using always_comb to make the code
run the same everywhere. Also avoid putting $displays in combo blocks, as
they may print multiple times when not desired, even on compliant
simulators as event ordering is not specified.
=head2 Signal Naming
@ -3659,9 +3703,9 @@ path.
=head2 Class
Verilator class support is very limited and in active development.
Verilator supports members, and methods. Verilator doe not support class
static members, class extend, or class parameters.
Verilator class support is limited but in active development. Verilator
supports members, and methods. Verilator doe not support class static
members, class extend, or class parameters.
=head2 Dotted cross-hierarchy references
@ -3675,18 +3719,9 @@ specified in the Verilog standard; arrayed instances are named
{cellName}[{instanceNumber}] in Verilog, which becomes
{cellname}__BRA__{instanceNumber}__KET__ inside the generated C++ code.
Verilator creates numbered "genblk" when a begin: name is not specified
around a block inside a generate statement. These numbers may differ
between other simulators, but the Verilog specification does not allow
users to use these names, so it should not matter.
If you are having trouble determining where a dotted path goes wrong, note
that Verilator will print a list of known scopes to help your debugging.
=head2 Floating Point
Short floating point (shortreal) numbers are converted to real.
=head2 Latches
Verilator is optimized for edge sensitive (flop based) designs. It will
@ -3788,12 +3823,6 @@ primary inputs to the model, or wires directly attached to primary inputs.
For proper behavior clock enables may also need the /*verilator
clock_enable*/ attribute.
=head2 Ranges must be big-bit-endian
Bit ranges must be numbered with the MSB being numbered greater or the same
as the LSB. Little-bit-endian buses [0:15] are not supported as they
aren't easily made compatible with C++.
=head2 Gate Primitives
The 2-state gate primitives (and, buf, nand, nor, not, or, xnor, xor) are
@ -3802,7 +3831,8 @@ primitives are not supported. Tables are not supported.
=head2 Specify blocks
All specify blocks and timing checks are ignored.
All specify blocks and timing checks are ignored. All min:typ:max delays
use the typical value.
=head2 Array Initialization
@ -3831,7 +3861,6 @@ coverage section.
Verilator does not support SEREs yet. All assertion and coverage
statements must be simple expressions that complete in one cycle.
(Arguably SEREs are much of the point, but one must start somewhere.)
=head2 Encrypted Verilog
@ -3908,41 +3937,26 @@ Interfaces and modports, including with generated data types are supported.
Generate blocks around modports are not supported, nor are virtual
interfaces nor unnamed interfaces.
=item priority if, unique if
=item shortreal
Priority and unique if's are treated as normal ifs and not asserted to be
full nor unique.
Short floating point (shortreal) numbers are converted to real. Most other
simulators either do not support float, or convert likewise.
=item specify specparam
All specify blocks and timing checks are ignored.
=item string
String is supported only to the point that they can be assigned,
concatenated, compared, and passed to DPI imports. Standard method calls
on strings are not supported.
=item timeunit, timeprecision
All timing control statements are ignored.
=item uwire
Verilator does not perform warning checking on uwires, it treats the uwire
keyword as if it were the normal wire keyword.
=item $bits, $countones, $error, $fatal, $finish, $info, $isunknown,
$onehot, $onehot0, $readmemb, $readmemh, $signed, $stime, $stop, $time,
$unsigned, $warning.
=item $bits, $countbits, $countones, $error, $fatal, $finish, $info,
$isunknown, $onehot, $onehot0, $readmemb, $readmemh, $signed, $stime, $stop,
$time, $unsigned, $warning.
Generally 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
@ -3980,6 +3994,11 @@ $setup, $setuphold, $skew, $timeskew, $width
All specify blocks and timing checks are ignored.
=item $monitor, $strobe
Monitor and strobe are not supported, convert to always_comb $display or
similar.
=item $random
$random does not support the optional argument to set the seed. Use the
@ -4049,7 +4068,7 @@ the source line directly above.
Warns that an always_comb block has a variable which is set after it is
used. This may cause simulation-synthesis mismatches, as not all
commercial simulators allow this ordering.
simulators allow this ordering.
always_comb begin
a = b;
@ -4797,7 +4816,10 @@ correctly.
Warns that unpacked structs and unions are not supported.
Ignoring this warning will make Verilator treat the structure as packed,
which may make Verilator simulations differ from other simulators.
which may make Verilator simulations differ from other simulators. This
downgrading may also result what would normally be a legal unpacked
struct/array inside an unpacked struct/array becomming an illegal unpacked
struct/array inside a packed struct/array.
=item UNSIGNED
@ -4975,14 +4997,14 @@ Note people sometimes request binaries when they are having problems with
their C++ compiler. Alas, binaries won't help this, as in the end a fully
working C++ compiler is required to compile the output of Verilator.
=item How can it be faster than (name-the-commercial-simulator)?
=item How can it be faster than (name-a-big-3-closed-source-simulator)?
Generally, the implied part is of the question is "... with all of the
manpower they can put into developing it."
Most commercial simulators have to be Verilog compliant, meaning event
driven. This prevents them from being able to reorder blocks and make
netlist-style optimizations, which are where most of the gains come from.
Most simulators have to be Verilog compliant, meaning event driven. This
prevents them from being able to reorder blocks and make netlist-style
optimizations, which are where most of the gains come from.
Non-compliance shouldn't be scary. Your synthesis program isn't compliant,
so your simulator shouldn't have to be -- and Verilator is closer to the
@ -5021,8 +5043,8 @@ simulator in order to optimize it. If it takes more than a minute or so
(and you're not using --debug since debug is disk bound), see if your
machine is paging; most likely you need to run it on a machine with more
memory. Verilator is a full 64-bit application and may use more than 4GB,
but about 1GB is the maximum typically needed, and very large commercial
designs have topped 16GB.
but about 1GB is the maximum typically needed, and very large designs have
topped 16GB.
=item How do I generate waveforms (traces) in C++?
@ -5125,10 +5147,10 @@ format instead.
=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)
programs, or any of the many commercial offerings;
FST is supported by GTKWave only.
Verilator makes standard VCD (Value Change Dump) and FST files. VCD files
are viewable with the public domain GTKWave (recommended) or Dinotrace
(legacy) programs, or any of the many closed-source offerings; FST is
supported by GTKWave only.
=item How do I reduce the size of large waveform (trace) files?
@ -5168,6 +5190,10 @@ For an example, after running 'make test' in the Verilator distribution,
see the examples/make_tracing_c/logs directory. Grep for lines starting
with '%' to see what lines Verilator believes need more coverage.
Info files can be written by verilator_coverage for import to C<lcov>.
This enables use of C<genhtml> for HTML reports and importing reports to
sites such as L<https://codecov.io>.
=item Where is the translate_off command? (How do I ignore a construct?)
Translate on/off pragmas are generally a bad idea, as it's easy to have
@ -5240,10 +5266,15 @@ test_regress/t/t_extend_class files show an example of how to do this.
=item How do I get faster build times?
When running make pass the make variable VM_PARALLEL_BUILDS=1 so that
builds occur in parallel.
builds occur in parallel. Note this is now set by default if an output
file was large enough to be split due to the --output-split option.
Use a recent compiler. Newer compilers tend do be faster, with the
now relatively old GCC 3.0 to 3.3 being horrible.
Verilator emits any infrequently executed "cold" routines into separate
__Slow.cpp files. This can accelerate compilation as optimization can be
disabled on these routines. See the OPT_FAST and OPT_SLOW make variables
and the BENCHMARKING & OPTIMIZATION section of the manual.
Use a recent compiler. Newer compilers tend to be faster.
Compile in parallel on many machines and use caching; see the web for the
ccache, distcc and icecream packages. ccache will skip GCC runs between
@ -5365,7 +5396,7 @@ outputs. Now, the following should fail:
cd test_regress
t/t_BUG.pl # Run on Verilator
t/t_BUG.pl --debug # Run on Verilator, passing --debug to Verilator
t/t_BUG.pl --vcs # Run on a commercial simulator
t/t_BUG.pl --vcs # Run on VCS simulator
t/t_BUG.pl --nc|--iv|--ghdl # Likewise on other simulators
The test driver accepts a number of options, many of which mirror the main
@ -5408,7 +5439,7 @@ In 2018, Verilator 4.000 was released with multithreaded support.
Currently, various language features and performance enhancements are added
as the need arises. Verilator is now about 3x faster than in 2002, and is
faster than many popular commercial simulators.
faster than most (if not every) other simulator.
=head1 AUTHORS
@ -5424,83 +5455,92 @@ Major concepts by Paul Wasson, Duane Galbi, John Coiner and Jie Xu.
Many people have provided ideas and other assistance with Verilator.
The major corporate sponsors of Verilator, by providing significant
contributions of time or funds include include Atmel Corporation, Cavium
Verilator is receiving major development support from the CHIPS Alliance.
Previous major corporate sponsors of Verilator, by providing significant
contributions of time or funds included include Atmel Corporation, Cavium
Inc., Compaq Corporation, Digital Equipment Corporation, Embecosm Ltd.,
Hicamp Systems, Intel Corporation, Mindspeed Technologies Inc., MicroTune
Inc., picoChip Designs Ltd., Sun Microsystems Inc., Nauticus Networks Inc.,
and SiCortex Inc.
The people who have contributed major functionality are Byron Bradley,
Jeremy Bennett, Lane Brooks, John Coiner, Duane Galbi, Todd Strader, Paul
Wasson, Jie Xu, and Wilson Snyder. Major testers included Jeff Dutton,
Jonathon Donaldson, Ralf Karge, David Hewson, Iztok Jeras, Wim Michiels,
Alex Solomatnikov, Sebastien Van Cauwenberghe, Gene Weber, and Clifford
Wolf.
Jeremy Bennett, Lane Brooks, John Coiner, Duane Galbi, Geza Lore, Todd
Strader, Stefan Wallentowitz, Paul Wasson, Jie Xu, and Wilson Snyder.
Major testers included Jeff Dutton, Jonathon Donaldson, Ralf Karge, David
Hewson, Iztok Jeras, Wim Michiels, Alex Solomatnikov, Sebastien Van
Cauwenberghe, Gene Weber, and Clifford Wolf.
Some of the people who have provided ideas and feedback for Verilator
Some of the people who have provided ideas, and feedback for Verilator
include: David Addison, Tariq B. Ahmad, Nikana Anastasiadis, Hans Van
Antwerpen, Vasu Arasanipalai, Jens Arm, Sharad Bagri, Matthew Ballance,
Andrew Bardsley, Matthew Barr, Geoff Barrett, Julius Baxter, Jeremy
Bennett, Michael Berman, Victor Besyakov, David Binderman, Piotr Binkowski,
Johan Bjork, David Black, Tymoteusz Blazejczyk, Daniel Bone, Gregg
Bouchard, Christopher Boumenot, Nick Bowler, Byron Bradley, Bryan Brady,
Maarten De Braekeleer, Charlie Brej, J Briquet, Lane Brooks, John Brownlee,
Jeff Bush, Lawrence Butcher, Tony Bybell, Ted Campbell, Chris Candler,
Lauren Carlson, Donal Casey, Sebastien Van Cauwenberghe, Alex Chadwick,
Terry Chen, Yi-Chung Chen, Enzo Chi, Robert A. Clark, Allan Cochrane, John
Coiner, Gianfranco Costamagna, George Cuan, Joe DErrico, Lukasz Dalek,
Laurens van Dam, Gunter Dannoritzer, Ashutosh Das, Bernard Deadman, John
Demme, Mike Denio, John Deroo, Philip Derrick, John Dickol, Ruben Diez,
Danny Ding, Jacko Dirks, Ivan Djordjevic, Jonathon Donaldson, Leendert van
Doorn, Sebastian Dressler, Alex Duller, Jeff Dutton, Tomas Dzetkulic,
Usuario Eda, Charles Eddleston, Chandan Egbert, Joe Eiler, Ahmed
El-Mahmoudy, Trevor Elbourne, Robert Farrell, Eugen Fekete, Fabrizio
Ferrandi, Udi Finkelstein, Brian Flachs, Andrea Foletto, Bob Fredieu, Duane
Galbi, Benjamin Gartner, Christian Gelinek, Peter Gerst, Glen Gibb, Shankar
Giri, Dan Gisselquist, Sam Gladstone, Amir Gonnen, Chitlesh Goorah, Sergi
Granell, Al Grant, Xuan Guo, Driss Hafdi, Neil Hamilton, Oyvind Harboe,
Bennett, Michael Berman, Victor Besyakov, Moinak Bhattacharyya, David
Binderman, Piotr Binkowski, Johan Bjork, David Black, Tymoteusz Blazejczyk,
Daniel Bone, Gregg Bouchard, Christopher Boumenot, Nick Bowler, Byron
Bradley, Bryan Brady, Maarten De Braekeleer, Charlie Brej, J Briquet, Lane
Brooks, John Brownlee, Jeff Bush, Lawrence Butcher, Tony Bybell, Ted
Campbell, Chris Candler, Lauren Carlson, Donal Casey, Sebastien Van
Cauwenberghe, Alex Chadwick, Terry Chen, Yi-Chung Chen, Enzo Chi, Robert
A. Clark, Allan Cochrane, John Coiner, Gianfranco Costamagna, Sean Cross,
George Cuan, Joe DErrico, Lukasz Dalek, Laurens van Dam, Gunter
Dannoritzer, Ashutosh Das, Bernard Deadman, John Demme, Mike Denio, John
Deroo, Philip Derrick, John Dickol, Ruben Diez, Danny Ding, Jacko Dirks,
Ivan Djordjevic, Jonathon Donaldson, Leendert van Doorn, Sebastian
Dressler, Alex Duller, Jeff Dutton, Tomas Dzetkulic, Usuario Eda, Charles
Eddleston, Chandan Egbert, Joe Eiler, Ahmed El-Mahmoudy, Trevor Elbourne,
Mats Engstrom, Robert Farrell, Eugen Fekete, Fabrizio Ferrandi, Udi
Finkelstein, Brian Flachs, Andrea Foletto, Bob Fredieu, Duane Galbi,
Benjamin Gartner, Christian Gelinek, Peter Gerst, Glen Gibb, Michael
Gielda, Shankar Giri, Dan Gisselquist, Petr Gladkikh, Sam Gladstone, Amir
Gonnen, Chitlesh Goorah, Kai Gossner, Sergi Granell, Al Grant, Alexander
Grobman, Xuan Guo, Driss Hafdi, Neil Hamilton, James Hanlon, Oyvind Harboe,
Jannis Harder, Junji Hashimoto, Thomas Hawkins, Mitch Hayenga, Robert
Henry, David Hewson, Jamey Hicks, Joel Holdsworth, Andrew Holme, Hiroki
Honda, Alex Hornung, David Horton, Jae Hossell, Alan Hunter, James
Hutchinson, Jamie Iles, Ben Jackson, Shareef Jalloq, Krzysztof Jankowski,
HyungKi Jeong, Iztok Jeras, James Johnson, Christophe Joly, Franck Jullien,
James Jung, Mike Kagen, Arthur Kahlich, Kaalia Kahn, Guy-Armand Kamendje,
Vasu Kandadi, Kanad Kanhere, Patricio Kaplan, Pieter Kapsenberg, Ralf
Karge, Dan Katz, Sol Katzman, Jonathan Kimmitt, Olof Kindgren, Kevin
Kiningham, Dan Kirkham, Sobhan Klnv, Gernot Koch, Soon Koh, Steve Kolecki,
Brett Koonce, Will Korteland, Wojciech Koszek, Varun Koyyalagunta, David
Kravitz, Roland Kruse, Sergey Kvachonok, Ed Lander, Steve Lang, Stephane
Laurent, Walter Lavino, Christian Leber, Larry Lee, Igor Lesik, John Li,
Eivind Liland, Yu Sheng Lin, Charlie Lind, Andrew Ling, Paul Liu, Derek
Lockhart, Jake Longo, Arthur Low, Stefan Ludwig, Dan Lussier, Fred Ma,
Duraid Madina, Affe Mao, Julien Margetts, Mark Marshall, Alfonso Martinez,
Yves Mathieu, Patrick Maupin, Jason McMullan, Elliot Mednick, Wim Michiels,
Miodrag Milanovic, Wai Sum Mong, Peter Monsson, Sean Moore, Dennis
Muhlestein, John Murphy, Matt Myers, Richard Myers, Dimitris Nalbantis,
Peter Nelson, Bob Newgard, Cong Van Nguyen, Paul Nitza, Yossi Nivin, Pete
Nixon, Lisa Noack, Mark Nodine, Andreas Olofsson, Aleksander Osman, James
Pallister, Brad Parker, Dan Petrisko, Maciej Piechotka, David Pierce,
Dominic Plunkett, David Poole, Mike Popoloski, Roman Popov, Rich Porter,
Niranjan Prabhu, Usha Priyadharshini, Mark Jackson Pulver, Prateek Puri,
Marshal Qiao, Danilo Ramos, Chris Randall, Anton Rapp, Josh Redford, Odd
Magne Reitan, Frederic Requin, Frederick Requin, Alberto Del Rio, Eric
Rippey, Oleg Rodionov, Paul Rolfe, Arjen Roodselaar, Tobias Rosenkranz, Jan
Egil Ruud, Denis Rystsov, John Sanguinetti, Galen Seitz, Salman Sheikh, Hao
Shi, Mike Shinkarovsky, Rafael Shirakawa, Jeffrey Short, Anderson Ignacio
Da Silva, Rodney Sinclair, Steven Slatter, Brian Small, Garrett Smith,
Wilson Snyder, Stan Sokorac, Alex Solomatnikov, Wei Song, Art Stamness,
John Stevenson, Patrick Stewart, Rob Stoddard, Todd Strader, John Stroebel,
Sven Stucki, Howard Su, Emerson Suguimoto, Gene Sullivan, Renga
Sundararajan, Rupert Swarbrick, Yutetsu Takatsukasa, Peter Tengstrand,
Wesley Terpstra, Rui Terra, Stefan Thiede, Gary Thomas, Ian Thompson, Kevin
Thompson, Mike Thyer, Hans Tichelaar, Viktor Tomov, Steve Tong, Michael
Tresidder, Neil Turton, Bogdan Vukobratovic, Holger Waechtler, Philipp
Wagner, Stefan Wallentowitz, Shawn Wang, Paul Wasson, Greg Waters, Thomas
Watts, Eugene Weber, David Welch, Thomas J Whatson, Leon Wildman, Gerald
Williams, Trevor Williams, Jeff Winston, Joshua Wise, Clifford Wolf, Johan
Wouters, Junyi Xi, Ding Xiaoliang, Jie Xu, Mandy Xu, Luke Yang, and Amir
Yazdanbakhsh.
Henry, Stephen Henry, David Hewson, Jamey Hicks, Joel Holdsworth, Andrew
Holme, Hiroki Honda, Alex Hornung, David Horton, Peter Horvath, Jae
Hossell, Alan Hunter, James Hutchinson, Jamie Iles, Ben Jackson, Shareef
Jalloq, Krzysztof Jankowski, HyungKi Jeong, Iztok Jeras, James Johnson,
Christophe Joly, Franck Jullien, James Jung, Mike Kagen, Arthur Kahlich,
Kaalia Kahn, Guy-Armand Kamendje, Vasu Kandadi, Kanad Kanhere, Patricio
Kaplan, Pieter Kapsenberg, Ralf Karge, Dan Katz, Sol Katzman, Ian Kennedy,
Jonathan Kimmitt, Olof Kindgren, Kevin Kiningham, Dan Kirkham, Sobhan Klnv,
Gernot Koch, Soon Koh, Nathan Kohagen, Steve Kolecki, Brett Koonce, Will
Korteland, Wojciech Koszek, Varun Koyyalagunta, David Kravitz, Roland
Kruse, Sergey Kvachonok, Charles Eric LaForest, Ed Lander, Steve Lang,
Stephane Laurent, Walter Lavino, Christian Leber, Larry Lee, Igor Lesik,
John Li, Eivind Liland, Yu Sheng Lin, Charlie Lind, Andrew Ling, Jiuyang
Liu, Paul Liu, Derek Lockhart, Jake Longo, Geza Lore, Arthur Low, Stefan
Ludwig, Dan Lussier, Fred Ma, Duraid Madina, Affe Mao, Julien Margetts,
Mark Marshall, Alfonso Martinez, Yves Mathieu, Patrick Maupin, Jason
McMullan, Elliot Mednick, Wim Michiels, Miodrag Milanovic, Wai Sum Mong,
Peter Monsson, Sean Moore, Dennis Muhlestein, John Murphy, Matt Myers,
Nathan Myers, Richard Myers, Dimitris Nalbantis, Peter Nelson, Bob Newgard,
Cong Van Nguyen, Paul Nitza, Yossi Nivin, Pete Nixon, Lisa Noack, Mark
Nodine, Kuba Ober, Andreas Olofsson, Aleksander Osman, James Pallister,
Vassilis Papaefstathiou, Brad Parker, Dan Petrisko, Maciej Piechotka, David
Pierce, Dominic Plunkett, David Poole, Mike Popoloski, Roman Popov, Rich
Porter, Niranjan Prabhu, Usha Priyadharshini, Mark Jackson Pulver, Prateek
Puri, Marshal Qiao, Danilo Ramos, Chris Randall, Anton Rapp, Josh Redford,
Odd Magne Reitan, Frederic Requin, Frederick Requin, Dustin Richmond,
Alberto Del Rio, Eric Rippey, Oleg Rodionov, Ludwig Rogiers, Paul Rolfe,
Arjen Roodselaar, Tobias Rosenkranz, Huang Rui, Jan Egil Ruud, Denis
Rystsov, John Sanguinetti, Galen Seitz, Salman Sheikh, Hao Shi, Mike
Shinkarovsky, Rafael Shirakawa, Jeffrey Short, Anderson Ignacio Da Silva,
Rodney Sinclair, Steven Slatter, Brian Small, Garrett Smith, Tim Snyder,
Maciej Sobkowski, Stan Sokorac, Alex Solomatnikov, Wei Song, Art Stamness,
David Stanford, John Stevenson, Pete Stevenson, Patrick Stewart, Rob
Stoddard, Todd Strader, John Stroebel, Sven Stucki, Howard Su, Emerson
Suguimoto, Gene Sullivan, Qingyao Sun, Renga Sundararajan, Rupert
Swarbrick, Yutetsu Takatsukasa, Peter Tengstrand, Wesley Terpstra, Rui
Terra, Stefan Thiede, Gary Thomas, Ian Thompson, Kevin Thompson, Mike
Thyer, Hans Tichelaar, Viktor Tomov, Steve Tong, Michael Tresidder, Neil
Turton, Srini Vemuri, Yuri Victorovich, Bogdan Vukobratovic, Holger
Waechtler, Philipp Wagner, Stefan Wallentowitz, Shawn Wang, Paul Wasson,
Greg Waters, Thomas Watts, Eugene Weber, David Welch, Thomas J Whatson,
Marco Widmer, Leon Wildman, Daniel Wilkerson, Gerald Williams, Trevor
Williams, Jan Van Winkel, Jeff Winston, Joshua Wise, Clifford Wolf, Tobias
Wolfel, Johan Wouters, Junyi Xi, Ding Xiaoliang, Jie Xu, Mandy Xu,
Takatsukasa Y, Luke Yang, and Amir Yazdanbakhsh.
Thanks to them, and all those we've missed including above, or wished to
remain anonymous.

View File

@ -156,6 +156,8 @@ verilator_coverage - Verilator coverage analyzer
verilator_coverage -write merged.dat -read <datafiles>...
verilator_coverage -write-info merged.info -read <datafiles>...
Verilator_coverage processes Verilator coverage reports.
With --anotate, it reads the specified data file and generates annotated
@ -224,8 +226,20 @@ Displays program version and exits.
=item --write I<filename>
Specifies the aggregate coverage results, summed across all the files,
should be written to the given filename. This is useful in scripts to
combine many sequential runs into one master coverage file.
should be written to the given filename in verilator_coverage data format.
This is useful in scripts to combine many sequential runs into one master
coverage file.
=item --write-info I<filename.info>
Specifies the aggregate coverage results, summed across all the files,
should be written to the given filename in C<lcov> .info format.
This may be used to use C<lcov> to aggregate or generate reports.
The info format loses data compared to the Verilator coverage data format;
the info will all forms of coverage converted to line style coverage, and
if there are multiple coverage points on a single line, the minimum
coverage across those points will be used to report coverage of the line.
=back
@ -277,7 +291,7 @@ Wilson Snyder <wsnyder@wsnyder.org>
=head1 SEE ALSO
C<verilator>
C<verilator>, C<lcov>
L<verilator_coverage --help> which is the source for this document.

View File

@ -1,19 +0,0 @@
#!/bin/bash
# DESCRIPTION: Verilator: Build script for vcddiff
#
# Copyright 2019 by Todd Strader. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
set -e
# NB: it would be better to add this via a PPA
TMP_DIR=$(mktemp -d)
git -C "${TMP_DIR}" clone https://github.com/veripool/vcddiff
VCDDIFF_DIR=${TMP_DIR}/vcddiff
git -C "${VCDDIFF_DIR}" checkout 5112f88b7ba8818dce9dfb72619e64a1fc19542c
make -C "${VCDDIFF_DIR}"
sudo cp "${VCDDIFF_DIR}/vcddiff" /usr/local/bin

View File

@ -1,65 +0,0 @@
#!/bin/bash
# DESCRIPTION: Verilator: Travis CI build script
#
# Copyright 2019 by Todd Strader. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
#
# This script builds and caches the Verilator binaries for Travis CI
# (and possibly other CI platforms). The Verilator CI system uses this
# script, but other CI systems that depend on Verilator may also use
# the script.
# see: https://github.com/verilator/verilator_ext_tests/blob/master/.travis.yml
# To use this script, either checkout Verilator as part of the CI build
# process or add Verilator as a Git submodule. Verilator tarballs can
# not be used as the script relies on Git revisions for caching.
set -e
if [ -z "${VERILATOR_NUM_JOBS}" ]; then
VERILATOR_NUM_JOBS=$(nproc)
fi
# Caching would be simpler if we installed without VERILATOR_ROOT, but
# it's needed for driver.pl outside of the repo
if [ -z "${VERILATOR_ROOT}" ]; then
echo "VERILATOR_ROOT not set"
exit -1
fi
if [ -z "${VERILATOR_CACHE}" ]; then
echo "VERILATOR_CACHE not set"
exit -1
fi
VERILATOR_REV=$(cd "${VERILATOR_ROOT}" && git rev-parse HEAD)
echo "Found Verilator rev ${VERILATOR_REV}"
CACHED_REV_FILE=${VERILATOR_CACHE}/.rev.txt
if [[ ! -f "${CACHED_REV_FILE}" || \
$(< "${CACHED_REV_FILE}") != "${VERILATOR_REV}" ]]; then
echo "Building Verilator"
# Unsure why Travis monkies with the capitalization of the stage name, but it does
if [[ -n ${TRAVIS_BUILD_STAGE_NAME} && \
${TRAVIS_BUILD_STAGE_NAME} != "Build verilator" ]]; then
echo "WARNING: Building Verilator in Travis build stage other than \"Build verilator\": ${TRAVIS_BUILD_STAGE_NAME}"
fi
cd "${VERILATOR_ROOT}"
autoconf && ./configure ${VERILATOR_CONFIG_FLAGS} && make -j ${VERILATOR_NUM_JOBS}
# Copy the Verilator build artifacts
mkdir -p "${VERILATOR_CACHE}"
rm -rf ${VERILATOR_CACHE}/*
cp bin/*bin* "${VERILATOR_CACHE}"
# Remember the Git revision
echo "${VERILATOR_REV}" > "${CACHED_REV_FILE}"
else
echo "Using cached Verilator"
cd "${VERILATOR_ROOT}"
# Create include/verilated_config.h and maybe other things
autoconf && ./configure ${VERILATOR_CONFIG_FLAGS}
cp ${VERILATOR_CACHE}/* bin
fi

View File

@ -6,44 +6,40 @@
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
FROM ubuntu:18.04
FROM ubuntu:20.04
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive \
apt-get install --no-install-recommends -y \
autoconf=2.69-11 \
bc=1.07.1-2 \
bison=2:3.0.4.dfsg-1build1 \
build-essential=12.4ubuntu1 \
ca-certificates=20180409 \
cmake=3.10.2-1ubuntu2.18.04.1 \
flex=2.6.4-6 \
gdb=8.1-0ubuntu3.2 \
gcc-6=6.5.0-2ubuntu1~18.04 \
gcc-5=5.5.0-12ubuntu1 \
gcc-4.8=4.8.5-4ubuntu8 \
git=1:2.17.1-1ubuntu0.5 \
gtkwave=3.3.86-1 \
g++-6=6.5.0-2ubuntu1~18.04 \
g++-5=5.5.0-12ubuntu1 \
g++-4.8=4.8.5-4ubuntu8 \
libfl2=2.6.4-6 \
libfl-dev=2.6.4-6 \
numactl=2.0.11-2.1ubuntu0.1 \
perl=5.26.1-6ubuntu0.3 \
python3=3.6.7-1~18.04 \
wget=1.19.4-1ubuntu2.2 \
zlibc=0.9k-4.3 \
zlib1g=1:1.2.11.dfsg-0ubuntu2 \
zlib1g-dev=1:1.2.11.dfsg-0ubuntu2 \
autoconf \
bc \
bison \
build-essential \
ca-certificates \
ccache \
clang \
cmake \
flex \
gdb \
git \
gtkwave \
libfl2 \
libfl-dev \
libgoogle-perftools-dev \
libsystemc \
libsystemc-dev \
numactl \
perl \
python3 \
wget \
zlibc \
zlib1g \
zlib1g-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /tmp
COPY build-systemc.sh /tmp/
RUN ./build-systemc.sh
RUN cpan install -fi Unix::Processors Parallel::Forker Bit::Vector
RUN git clone https://github.com/veripool/vcddiff.git && \
@ -55,4 +51,6 @@ COPY build.sh /tmp/build.sh
ENV VERILATOR_AUTHOR_SITE=1
WORKDIR /work
ENTRYPOINT [ "/tmp/build.sh" ]

View File

@ -5,7 +5,7 @@ build. It uses the following parameters:
* Source repository (default: https://github.com/verilator/verilator)
* Source revision (default: master)
* GCC version (4.8.5, 5.5.0, 6.5.0, 7.4.0, default: 7.4.0)
* Compiler (GCC 9.3.0, clang 10.0.0, default: 9.3.0)
The container is published as `verilator/verilator-buildenv` on
https://hub.docker.com/repository/docker/verilator/verilator-buildenv[docker hub].
@ -20,13 +20,13 @@ To also run tests:
To change the compiler:
docker run -ti -e CC=gcc-4.8 -e CXX=g++-4.8 verilator/verilator-buildenv test
docker run -ti -e CC=clang-10 -e CXX=clang++-10 verilator/verilator-buildenv test
The tests that involve gdb are not working due to security restrictions.
To run those too:
....
docker run -ti -v ${PWD}:/tmp/repo -e REPO=/tmp/repo -e REV=`git rev-parse --short HEAD` -e CC=gcc-4.8 -e CXX=g++-4.8 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined verilator/verilator-buildenv test
docker run -ti -e CC=clang-10 -e CXX=clang++-10 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined verilator/verilator-buildenv test
....
Rather then building using a remote git repository you may prefer to use a

View File

@ -1,30 +0,0 @@
#!/bin/bash -e
# DESCRIPTION: Build SystemC in Ubuntu 18.04 with different g++/gcc
#
# Copyright 2020 by Stefan Wallentowitz. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
build_variant () {
version=$($1 --version | grep gcc | awk '{print $4}')
mkdir "/usr/local/systemc-2.3.3-gcc$version"
mkdir build
cd build
../configure --prefix="/usr/local/systemc-2.3.3-gcc$version" CC="$1" CXX="$2" LD="$2"
make -j
make install
cd ..
rm -r build
}
wget https://www.accellera.org/images/downloads/standards/systemc/systemc-2.3.3.tar.gz
tar -xzf systemc-2.3.3.tar.gz
cd systemc-2.3.3
build_variant gcc g++
build_variant gcc-6 g++-6
build_variant gcc-5 g++-5
build_variant gcc-4.8 g++-4.8
cd ..
rm -r systemc-2.3.3*

View File

@ -12,12 +12,6 @@
: "${CC:=gcc}"
: "${CXX:=g++}"
GCCVERSION=$(${CC} --version | grep gcc | awk '{print $4}')
export SYSTEMC_INCLUDE="/usr/local/systemc-2.3.3-gcc${GCCVERSION}/include"
export SYSTEMC_LIBDIR="/usr/local/systemc-2.3.3-gcc${GCCVERSION}/lib-linux64"
export LD_LIBRARY_PATH=${SYSTEMC_LIBDIR}
SRCS=$PWD/verilator
git clone "$REPO" "$SRCS"

View File

@ -6,19 +6,20 @@
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
FROM ubuntu:18.04
FROM ubuntu:20.04
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive \
&& apt-get install --no-install-recommends -y \
autoconf=2.69-11 \
bc=1.07.1-2 \
bison=2:3.0.4.dfsg-1build1 \
build-essential=12.4ubuntu1 \
ca-certificates=20180409 \
autoconf \
bc \
bison \
build-essential \
ca-certificates \
ccache \
flex=2.6.4-6 \
flex \
git \
libfl-dev=2.6.4-6 \
libfl-dev \
libgoogle-perftools-dev \
perl \
python3 \

View File

@ -1,34 +0,0 @@
#!/bin/bash
# DESCRIPTION: Verilator: Travis CI test script
#
# Copyright 2019 by Todd Strader. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
set -e
export DRIVER_FLAGS='-j 0 --quiet --rerun'
case $1 in
dist)
make -C test_regress SCENARIOS=--dist
;;
vlt)
make -C test_regress SCENARIOS=--vlt
;;
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
;;
esac

29
ci/travis-ccache-maint.bash Executable file
View File

@ -0,0 +1,29 @@
#!/usr/bin/env bash
# DESCRIPTION: Verilator: Travis CI ccache maintenance
#
# Copyright 2020 by Geza Lore. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
#
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
################################################################################
# This script is run in 'before_script', once ccache has been set up.
################################################################################
set -e
set -x
# Show version
ccache --version
# Flush ccache if requested in commit message
COMMIT="${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT}"
if git log --format=%B -n 1 "$COMMIT" | grep -q -i '\[travis\s\+ccache\s\+clear\]'; then
echo "Flushing ccache due to commit message"
ccache -C
fi
# Dump stats, then zero stats
ccache -s -z

37
ci/travis-ccache-size.bash Executable file
View File

@ -0,0 +1,37 @@
#!/usr/bin/env bash
# DESCRIPTION: Verilator: Travis CI ccache sizer
#
# Copyright 2020 by Geza Lore. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
#
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
################################################################################
# This script computes the size of the ccache to be used for a job. We want the
# ccache to be just big enough to be able to hold a whole build so a re-build
# of the same does not miss in the cache due to capacity, but we don't want the
# ccache too big as pulling it down from the network takes time, and it is
# unlikely objects from much earlier builds would be useful.
################################################################################
fatal() {
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
}
if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then
if [ "$COVERAGE" == 1 ]; then
echo "1024M"
else
echo "768M"
fi
elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
if [[ $TESTS == coverage-* ]]; then
echo "1536M"
else
echo "256M"
fi
else
fatal "Unknown build stage: '$TRAVIS_BUILD_STAGE_NAME'"
fi

72
ci/travis-install.bash Executable file
View File

@ -0,0 +1,72 @@
#!/usr/bin/env bash
# DESCRIPTION: Verilator: Travis CI dependency install script
#
# Copyright 2020 by Geza Lore. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
#
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
################################################################################
# This script runs in the 'install' phase of all jobs, in all stages. We try to
# minimize the time spent in this by selectively installing only the components
# required by the particular build stage.
################################################################################
# Note that Travis runs "apt-get update" when "apt-get install" is used in the
# .travis.yml file directly, but since we invoke it via this script, we need to
# run it manually where requried, otherwise some packages cannot be found.
set -e
set -x
fatal() {
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
}
install-vcddiff() {
TMP_DIR="$(mktemp -d)"
git clone https://github.com/veripool/vcddiff "$TMP_DIR"
git -C "${TMP_DIR}" checkout 5112f88b7ba8818dce9dfb72619e64a1fc19542c
make -C "${TMP_DIR}"
sudo cp "${TMP_DIR}/vcddiff" /usr/local/bin
}
if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then
##############################################################################
# Dependencies of jobs in the 'build' stage, i.e.: packages required to
# build Verilator
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
time sudo apt-get update
sudo apt-get install libfl-dev
sudo apt-get install libgoogle-perftools-dev
if [ "$COVERAGE" = 1 ]; then
yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
fi
else
fatal "Unknown os: '$TRAVIS_OS_NAME'"
fi
elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
##############################################################################
# Dependencies of jobs in the 'test' stage, i.e.: packages required to
# run the tests
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
sudo apt-get update
sudo apt-get install gdb gtkwave lcov
if [ "$TRAVIS_DIST" = "focal" ]; then
sudo apt-get install libsystemc-dev
fi
yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
# Not listing Bit::Vector as slow to install, and only skips one test
install-vcddiff
else
fatal "Unknown os: '$TRAVIS_OS_NAME'"
fi
else
##############################################################################
# Unknown build stage
fatal "Unknown build stage: '$TRAVIS_BUILD_STAGE_NAME'"
fi

101
ci/travis-script.bash Executable file
View File

@ -0,0 +1,101 @@
#!/usr/bin/env bash
# DESCRIPTION: Verilator: Travis CI main job script
#
# Copyright 2020 by Geza Lore. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
#
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
################################################################################
# This is the main script executed in the 'script' phase by all jobs. We use a
# single script to keep the .travis.yml spec simple. We pass job parameters via
# environment variables using 'env' keys. Having different 'env' keys in jobs
# ensures they use different Travis build caches.
################################################################################
set -e
set -x
fatal() {
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
}
if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then
##############################################################################
# Build verilator
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
if [ "$COVERAGE" != 1 ]; then
autoconf
./configure --enable-longtests --enable-ccwarn
make -j $(nproc)
else
nodist/code_coverage --stages 1-2
fi
else
fatal "Unknown os: '$TRAVIS_OS_NAME'"
fi
elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
##############################################################################
# Run tests
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
# Run the specified test
case $TESTS in
dist-vlt-0)
make -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=0/2
;;
dist-vlt-1)
make -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=1/2
;;
vltmt-0)
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2
;;
vltmt-1)
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2
;;
coverage-dist)
nodist/code_coverage --stages 3- --scenarios=--dist
;;
coverage-vlt-0)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=0/4
;;
coverage-vlt-1)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=1/4
;;
coverage-vlt-2)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=2/4
;;
coverage-vlt-3)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=3/4
;;
coverage-vltmt-0)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=0/4
;;
coverage-vltmt-1)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=1/4
;;
coverage-vltmt-2)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=2/4
;;
coverage-vltmt-3)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=3/4
;;
*)
fatal "Unknown test: $TESTS"
;;
esac
# Upload coverage data to codecov.io
if [[ $TESTS == coverage-* ]]; then
bash <(curl -s https://codecov.io/bash) -f nodist/obj_dir/coverage/app_total.info
fi
else
fatal "Unknown os: '$TRAVIS_OS_NAME'"
fi
else
##############################################################################
# Unknown build stage
fatal "Unknown build stage: '$TRAVIS_BUILD_STAGE_NAME'"
fi

38
codecov.yml Normal file
View File

@ -0,0 +1,38 @@
# DESCRIPTION: codecov.io config
#
# Copyright 2020-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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
####################
# Validate:
# curl --data-binary @codecov.yml https://codecov.io/validate
codecov:
require_ci_to_pass: no
coverage:
precision: 2
round: down
range: "70...100"
ignore:
- "ci"
- "docs"
- "examples"
- "include/gtkwave"
- "include/vltstd"
- "test_regress"
parsers:
gcov:
branch_detection:
conditional: yes
loop: yes
method: no
macro: no
comment:
layout: "reach,diff,flags,tree"
behavior: default
require_changes: yes

View File

@ -7,7 +7,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[4.034 2020-05-03],
AC_INIT([Verilator],[4.036 2020-06-06],
[https://verilator.org],
[verilator],[https://verilator.org])
# When releasing, also update header of Changes file
@ -16,7 +16,10 @@ AC_INIT([Verilator],[4.034 2020-05-03],
AC_CONFIG_HEADER(src/config_build.h)
AC_CONFIG_FILES(Makefile docs/Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h verilator.pc verilator-config.cmake verilator-config-version.cmake)
# Version
AC_MSG_RESULT([configuring for $PACKAGE_STRING])
PACKAGE_VERSION_NUMBER=`AS_ECHO("$PACKAGE_VERSION") | sed 's/ .*//g'`
AC_SUBST(PACKAGE_VERSION_NUMBER)
# Ignore automake flags passed by Ubuntu builds
AC_ARG_ENABLE([dependency-tracking],
@ -416,6 +419,7 @@ AC_LINK_IFELSE(
CFG_WITH_THREADED=$_my_result
AC_SUBST(CFG_WITH_THREADED)
AC_MSG_RESULT($CFG_WITH_THREADED)
CXXFLAGS="$ACO_SAVE_CXXFLAGS"
# Check compiler flag
if test "$CFG_WITH_THREADED" = "no" ; then
@ -438,6 +442,20 @@ AC_CHECK_MEMBER([struct stat.st_mtim.tv_nsec],
[AC_DEFINE([HAVE_STAT_NSEC],[1],[Defined if struct stat has st_mtim.tv_nsec])],
[], [#include <sys/stat.h>])
# HAVE_SYSTEMC
# - If found the default search path has it, so support is always enabled.
# - If not found or not system-wide, user can set SYSTEMC_INCLUDE.
# AC_CHECK_HEADERS seems to not locate on Travis-CI but include does work.
AC_MSG_CHECKING([whether SystemC is found (in system path)])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([[#include <systemc.h>
]],[])],
[_my_result=yes
AC_DEFINE([HAVE_SYSTEMC_H],[1],[Defined if have systemc.h])],
[_my_result=no])
AC_MSG_RESULT($_my_result)
AC_SUBST(HAVE_SYSTEMC_H)
# Checks for system services
# Other install directories

View File

@ -6,15 +6,22 @@ Please see the Verilator manual for 200+ additional contributors. Thanks to all.
Ahmed El-Mahmoudy
Alex Chadwick
Chris Randall
Dan Petrisko
David Horton
David Stanford
Driss Hafdi
Eric Rippey
Garrett Smith
Geza Lore
Gianfranco Costamagna
Glen Gibb
Howard Su
Huang Rui
Iztok Jeras
James Hanlon
James Hutchinson
Jamey Hicks
Jan Van Winkel
Jeremy Bennett
John Coiner
John Demme
@ -22,11 +29,13 @@ Julien Margetts
Kanad Kanhere
Kevin Kiningham
Kuba Ober
Ludwig Rogiers
Lukasz Dalek
Maarten De Braekeleer
Maciej Sobkowski
Marco Widmer
Matthew Ballance
Michael Killough
Mike Popoloski
Nathan Kohagen
Nathan Myers
@ -39,11 +48,19 @@ Qingyao Sun
Richard Myers
Sean Cross
Sebastien Van Cauwenberghe
Sergi Granell
Stefan Wallentowitz
Stephen Henry
Tim Snyder
Tobias Rosenkranz
Tobias Wölfel
Todd Strader
Tomasz Gorochowik
Tymoteusz Blazejczyk
Vassilis Papaefstathiou
Veripool API Bot
Wilson Snyder
Yossi Nivin
Yuri Victorovich
Yutetsu TAKATSUKASA
Yves Mathieu

View File

@ -80,8 +80,7 @@ MSVC++.
To build or run Verilator you need these standard packages:
sudo apt-get install perl python3
sudo apt-get install make
sudo apt-get install perl python3 make
sudo apt-get install g++ # Alternatively, clang
sudo apt-get install libgz # Non-Ubuntu (ignore if gives error)
sudo apt-get install libfl2 libfl-dev zlibc zlib1g zlib1g-dev # Ubuntu only (ignore if gives error)
@ -95,12 +94,11 @@ good performance:
To build Verilator you will need to install these packages; these do not
need to be present to run Verilator:
sudo apt-get install git
sudo apt-get install autoconf flex bison
sudo apt-get install git autoconf flex bison
Those developing Verilator itself may also want these (see internals.adoc):
sudo apt-get install gdb asciidoctor graphviz cmake clang-format
sudo apt-get install gdb asciidoctor graphviz cmake clang clang-format gprof lcov
cpan install Pod::Perldoc
cpan install Unix::Processors
cpan install Parallel::Forker
@ -266,10 +264,9 @@ set in your environment; it is built into the executable.
== Announcements
To get notified of new releases, login to
https://www.veripool.org[Veripool], and click the "watch" button near the
top right under https://www.veripool.org/projects/verilator/news[Verilator
News].
To get notified of new releases, go to
https://github.com/verilator/verilator-announce[Verilator announcement
repository] and follow the instructions there.
== Directory Structure

View File

@ -786,10 +786,10 @@ better viewers let us know; ZGRViewer isn't great for large graphs.
Tree files are dumps of the AST Tree and are produced between every major
algorithmic stage. An example:
NETLIST 0x90fb00 <e1> {a0}
1: MODULE 0x912b20 <e8822> {a8} top L2 [P]
*1:2: VAR 0x91a780 <e74#> {a22} @dt=0xa2e640(w32) out_wide [O] WIRE
1:2:1: BASICDTYPE 0xa2e640 <e2149> {e24} @dt=this(sw32) integer kwd=integer range=[31:0]
NETLIST 0x90fb00 <e1> {a0ah}
1: MODULE 0x912b20 <e8822> {a8ah} top L2 [P]
*1:2: VAR 0x91a780 <e74#> {a22ah} @dt=0xa2e640(w32) out_wide [O] WIRE
1:2:1: BASICDTYPE 0xa2e640 <e2149> {e24ah} @dt=this(sw32) integer kwd=integer range=[31:0]
The following summarizes the above example dump, with more detail on each
field in the section below.
@ -807,8 +807,9 @@ the `MODULE`, which in turn is the `op1p` pointer under the `NETLIST`
| `<e74>` | means the 74th edit to the netlist was the last modification to
this node.
| `{a22}` | indicates this node is related to line 22 in the source filename
"a", where "a" is the first file read, "z" the 26th, and "aa" the 27th.
| `{a22ah}` | indicates this node is related to the source filename "a",
where "a" is the first file read, "z" the 26th, and "aa" the 27th. Then
line 22 in that file, then column 8 (aa=0, az=25, ba=26, ...).
| `@dt=0x...` | indicates the address of the data type this node contains.
@ -849,7 +850,10 @@ correspond directly to Verilog entities (for example `MODULE` and
Address of the node::
A hexadecimal address of the node in memory. Useful for examining with the
debugger.
debugger. If the actual address values are not important, then using the
`--dump-tree-addrids` option will convert address values to short identifiers
of the form `([A-Z]*)`, which is hopefully easier for the reader to cross
reference throughout the dump.
Last edit number::
@ -996,6 +1000,24 @@ function in `src/verilator.cpp`.
To get your pass to build you'll need to add its binary filename to the
list in `src/Makefile_obj.in` and reconfigure.
=== "Never" features
Verilator ideally would support all of IEEE, and has the goal to get close
to full support. However the following IEEE sections and features are not
anticipated to be ever implemented for the reasons indicated.
[horizontal]
IEEE 1800-2017 3.3 recursive modules:: Little/no tool support, and arguably not a good practice.
IEEE 1800-2017 6.12 "shortreal":: Little/no tool support, and easily simply promoted to real.
IEEE 1800-2017 11.11 Min, typ, max:: No SDF support so will always use typical.
IEEE 1800-2017 11.12 "let":: Little/no tool support, makes difficult to implement parsers.
IEEE 1800-2017 20.15 Probabilistic functions:: Little industry use.
IEEE 1800-2017 20.16 Stochastic analysis:: Little industry use.
IEEE 1800-2017 20.17 PLA modeling:: Little industry use and outdated technology.
IEEE 1800-2017 31 Timing checks:: No longer relevant with static timing analysis tools.
IEEE 1800-2017 32 SDF annotation:: No longer relevant with static timing analysis tools.
IEEE 1800-2017 33 Config:: Little/no tool support or industry use.
== Distribution
Copyright 2008-2020 by Wilson Snyder. Verilator is free software; you can

View File

@ -5,11 +5,9 @@
# This is an example cmake script to build a verilog to systemc project
# using cmake and verilator.
#
# 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# This file ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################

View File

@ -6,11 +6,9 @@
# This makefile is here for testing the examples and should
# generally not be added to a CMake project.
#
# 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# This file ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################

View File

@ -5,11 +5,9 @@
# This is an example cmake script to build a verilog to SystemC project
# using CMake and Verilator.
#
# 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# This file ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################

View File

@ -6,11 +6,9 @@
# This makefile is here for testing the examples and should
# generally not be added to a CMake project.
#
# 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# This file ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################

View File

@ -5,11 +5,9 @@
# This is an example cmake script to build a verilog to systemc project
# using cmake and verilator.
#
# 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# This file ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################

View File

@ -6,11 +6,9 @@
# This makefile is here for testing the examples and should
# generally not be added to a CMake project.
#
# 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# This file ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################

View File

@ -5,11 +5,9 @@
# This is an example cmake script to build a verilog to systemc project
# using cmake and verilator.
#
# 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# This file ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################

View File

@ -6,11 +6,9 @@
# This makefile is here for testing the examples and should
# generally not be added to a CMake project.
#
# 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# This file ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################

View File

@ -5,11 +5,9 @@
# This is an example cmake script to build a verilog to SystemC project
# using CMake and Verilator.
#
# 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# This file ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################

View File

@ -6,11 +6,9 @@
# This makefile is here for testing the examples and should
# generally not be added to a CMake project.
#
# 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# This file ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################

View File

@ -5,11 +5,9 @@
# This calls the object directory makefile. That allows the objects to
# be placed in the "current directory" which simplifies the Makefile.
#
# 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# This file ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################
# Check for sanity to avoid later confusion

View File

@ -19,7 +19,7 @@ int main(int argc, char** argv, char** env) {
// e.g. examples/c_tracing.
// Prevent unused variable warnings
if (0 && argc && argv && env) {}
if (false && argc && argv && env) {}
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
Vtop* top = new Vtop;

View File

@ -5,11 +5,9 @@
# This calls the object directory makefile. That allows the objects to
# be placed in the "current directory" which simplifies the Makefile.
#
# 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# This file ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################
# Check for sanity to avoid later confusion

View File

@ -23,7 +23,7 @@ int sc_main(int argc, char* argv[]) {
// e.g. examples/c_tracing.
// Prevent unused variable warnings
if (0 && argc && argv) {}
if (false && argc && argv) {}
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
Vtop* top = new Vtop("top");

View File

@ -5,11 +5,9 @@
# This calls the object directory makefiles. That allows the objects to
# be placed in the "current directory" which simplifies the Makefile.
#
# 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# This file ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################
# Check for sanity to avoid later confusion

View File

@ -20,7 +20,7 @@ vluint64_t main_time = 0;
double sc_time_stamp() { return main_time; }
int main(int argc, char** argv, char** env) {
if (0 && argc && argv && env) {}
if (false && argc && argv && env) {}
Verilated::debug(0);
Verilated::randReset(2);

View File

@ -5,11 +5,9 @@
# This calls the object directory makefile. That allows the objects to
# be placed in the "current directory" which simplifies the Makefile.
#
# 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# This file ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################
# Check for sanity to avoid later confusion

View File

@ -5,11 +5,9 @@
#
# This is executed in the object directory, and called by ../Makefile
#
# 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# This file ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
#######################################################################

View File

@ -22,7 +22,7 @@ int main(int argc, char** argv, char** env) {
// This is a more complicated example, please also see the simpler examples/make_hello_c.
// Prevent unused variable warnings
if (0 && argc && argv && env) {}
if (false && argc && argv && env) {}
// Set debug level, 0 is off, 9 is highest presently used
// May be overridden by commandArgs

View File

@ -5,11 +5,9 @@
# This calls the object directory makefile. That allows the objects to
# be placed in the "current directory" which simplifies the Makefile.
#
# 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# This file ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################
# Check for sanity to avoid later confusion

View File

@ -5,11 +5,9 @@
#
# This is executed in the object directory, and called by ../Makefile
#
# 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# This file ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
#######################################################################
@ -39,8 +37,8 @@ endif
# If you build your own rules from scratch, note you need to include
# SystemC as follows (Vtop.mk file includes verilated.mk with these
# already).
# CPPFLAGS += $(SYSTEMC_CXX_FLAGS) -I$(SYSTEMC_INCLUDE)
# LDFLAGS += $(SYSTEMC_CXX_FLAGS) -L$(SYSTEMC_LIBDIR)
# CPPFLAGS += $(SYSTEMC_CXX_FLAGS) $(addprefix -I, $(SYSTEMC_INCLUDE))
# LDFLAGS += $(SYSTEMC_CXX_FLAGS) $(addprefix -L, $(SYSTEMC_LIBDIR))
# See the benchmarking section of bin/verilator.
# Support class optimizations. This includes the tracing and symbol table.

View File

@ -24,7 +24,7 @@ int sc_main(int argc, char* argv[]) {
// This is a more complicated example, please also see the simpler examples/make_hello_c.
// Prevent unused variable warnings
if (0 && argc && argv) {}
if (false && argc && argv) {}
// Set debug level, 0 is off, 9 is highest presently used
// May be overridden by commandArgs

View File

@ -2,11 +2,9 @@
#
# DESCRIPTION: Verilator Example: XML tests
#
# 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# This file ONLY is placed under the Creative Commons Public Domain, for
# any use, without warranty, 2020 by Wilson Snyder.
# SPDX-License-Identifier: CC0-1.0
#
######################################################################

View File

@ -29,7 +29,7 @@
#include <algorithm>
#include <cctype>
#include <cerrno>
#include <tgmath.h>
#include <sstream>
#include <sys/stat.h> // mkdir
// clang-format off
@ -77,7 +77,7 @@ VerilatedImp VerilatedImp::s_s;
#ifndef VL_USER_FINISH ///< Define this to override this function
void vl_finish(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE {
if (0 && hier) {}
if (false && hier) {}
VL_PRINTF( // Not VL_PRINTF_MT, already on main thread
"- %s:%d: Verilog $finish\n", filename, linenum);
if (Verilated::gotFinish()) {
@ -100,7 +100,7 @@ void vl_stop(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE {
#ifndef VL_USER_FATAL ///< Define this to override this function
void vl_fatal(const char* filename, int linenum, const char* hier, const char* msg) VL_MT_UNSAFE {
if (0 && hier) {}
if (false && hier) {}
Verilated::gotFinish(true);
if (filename && filename[0]) {
// Not VL_PRINTF_MT, already on main thread
@ -215,7 +215,7 @@ void VL_DBG_MSGF(const char* formatp, ...) VL_MT_SAFE {
// Using VL_PRINTF not VL_PRINTF_MT so that we can call VL_DBG_MSGF
// from within the guts of the thread execution machinery (and it goes
// to the screen and not into the queues we're debugging)
VL_PRINTF("-V{t%d,%" VL_PRI64 "u}%s", VL_THREAD_ID(), _vl_dbg_sequence_number(), out.c_str());
VL_PRINTF("-V{t%u,%" VL_PRI64 "u}%s", VL_THREAD_ID(), _vl_dbg_sequence_number(), out.c_str());
}
#ifdef VL_THREADED
@ -243,8 +243,8 @@ Verilated::Serialized::Serialized() {
s_errorLimit = 1;
s_randReset = 0;
s_randSeed = 0;
s_timeunit = -VL_TIME_UNIT; // Initial value until overriden by _Vconfigure
s_timeprecision = -VL_TIME_PRECISION; // Initial value until overriden by _Vconfigure
s_timeunit = VL_TIME_UNIT; // Initial value until overriden by _Vconfigure
s_timeprecision = VL_TIME_PRECISION; // Initial value until overriden by _Vconfigure
}
Verilated::NonSerialized::NonSerialized() {
@ -283,7 +283,7 @@ vluint64_t vl_rand64() VL_MT_SAFE {
if (VL_UNLIKELY(!t_seeded)) {
t_seeded = true;
{
VerilatedLockGuard lock(s_mutex);
const VerilatedLockGuard lock(s_mutex);
if (Verilated::randSeed() != 0) {
t_state[0] = ((static_cast<vluint64_t>(Verilated::randSeed()) << 32)
^ (static_cast<vluint64_t>(Verilated::randSeed())));
@ -311,7 +311,8 @@ vluint64_t vl_rand64() VL_MT_SAFE {
IData VL_RANDOM_I(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_I(obits); }
QData VL_RANDOM_Q(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_Q(obits); }
// VL_RANDOM_W currently unused as $random always 32 bits
// VL_RANDOM_W currently unused as $random always 32 bits, left for backwards compatibility
// LCOV_EXCL_START
WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE {
for (int i = 0; i < VL_WORDS_I(obits); ++i) {
if (i < (VL_WORDS_I(obits) - 1)) {
@ -322,6 +323,7 @@ WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE {
}
return outwp;
}
// LCOV_EXCL_STOP
IData VL_RAND_RESET_I(int obits) VL_MT_SAFE {
if (Verilated::randReset() == 0) return 0;
@ -334,7 +336,7 @@ IData VL_RAND_RESET_I(int obits) VL_MT_SAFE {
}
QData VL_RAND_RESET_Q(int obits) VL_MT_SAFE {
if (Verilated::randReset() == 0) return 0;
QData data = VL_ULL(~0);
QData data = ~0ULL;
if (Verilated::randReset() != 1) { // if 2, randomize
data = VL_RANDOM_Q(obits);
}
@ -391,7 +393,7 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp,
if (vw == 1) { // Single divisor word breaks rest of algorithm
vluint64_t k = 0;
for (int j = uw - 1; j >= 0; --j) {
vluint64_t unw64 = ((k << VL_ULL(32)) + static_cast<vluint64_t>(lwp[j]));
vluint64_t unw64 = ((k << 32ULL) + static_cast<vluint64_t>(lwp[j]));
owp[j] = unw64 / static_cast<vluint64_t>(rwp[0]);
k = unw64 - static_cast<vluint64_t>(owp[j]) * static_cast<vluint64_t>(rwp[0]);
}
@ -433,26 +435,25 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp,
// Main loop
for (int j = uw - vw; j >= 0; --j) {
// Estimate
vluint64_t unw64 = (static_cast<vluint64_t>(un[j + vw]) << VL_ULL(32)
vluint64_t unw64 = (static_cast<vluint64_t>(un[j + vw]) << 32ULL
| static_cast<vluint64_t>(un[j + vw - 1]));
vluint64_t qhat = unw64 / static_cast<vluint64_t>(vn[vw - 1]);
vluint64_t rhat = unw64 - qhat * static_cast<vluint64_t>(vn[vw - 1]);
again:
if (qhat >= VL_ULL(0x100000000)
|| ((qhat * vn[vw - 2]) > ((rhat << VL_ULL(32)) + un[j + vw - 2]))) {
if (qhat >= 0x100000000ULL || ((qhat * vn[vw - 2]) > ((rhat << 32ULL) + un[j + vw - 2]))) {
qhat = qhat - 1;
rhat = rhat + vn[vw - 1];
if (rhat < VL_ULL(0x100000000)) goto again;
if (rhat < 0x100000000ULL) goto again;
}
vlsint64_t t = 0; // Must be signed
vluint64_t k = 0;
for (int i = 0; i < vw; ++i) {
vluint64_t p = qhat * vn[i]; // Multiply by estimate
t = un[i + j] - k - (p & VL_ULL(0xFFFFFFFF)); // Subtract
t = un[i + j] - k - (p & 0xFFFFFFFFULL); // Subtract
un[i + j] = t;
k = (p >> VL_ULL(32)) - (t >> VL_ULL(32));
k = (p >> 32ULL) - (t >> 32ULL);
}
t = un[j + vw] - k;
un[j + vw] = t;
@ -465,7 +466,7 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp,
for (int i = 0; i < vw; ++i) {
t = static_cast<vluint64_t>(un[i + j]) + static_cast<vluint64_t>(vn[i]) + k;
un[i + j] = t;
k = t >> VL_ULL(32);
k = t >> 32ULL;
}
un[j + vw] = un[j + vw] + k;
}
@ -516,7 +517,7 @@ QData VL_POW_QQW(int, int, int rbits, QData lhs, WDataInP rwp) VL_MT_SAFE {
// Skip check for rhs == 0, as short-circuit doesn't save time
if (VL_UNLIKELY(lhs == 0)) return 0;
QData power = lhs;
QData out = VL_ULL(1);
QData out = 1ULL;
for (int bit = 0; bit < rbits; ++bit) {
if (bit > 0) power = power * power;
if (VL_BITISSET_W(rwp, bit)) out *= power;
@ -630,7 +631,7 @@ std::string _vl_vsformat_time(char* tmp, double ld, bool left, size_t width) {
QData fracDiv = static_cast<QData>(vl_time_multiplier(fracDigits));
QData whole = static_cast<QData>(scaled) / fracDiv;
QData fraction = static_cast<QData>(scaled) % fracDiv;
int digits;
int digits = 0;
if (!fracDigits) {
digits = sprintf(tmp, "%" VL_PRI64 "u%s", whole, suffix.c_str());
} else {
@ -678,7 +679,16 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
inPct = false;
char fmt = pos[0];
switch (fmt) {
case '0' ... '9':
case '0': // FALLTHRU
case '1': // FALLTHRU
case '2': // FALLTHRU
case '3': // FALLTHRU
case '4': // FALLTHRU
case '5': // FALLTHRU
case '6': // FALLTHRU
case '7': // FALLTHRU
case '8': // FALLTHRU
case '9':
inPct = true; // Get more digits
widthSet = true;
width = width * 10 + (fmt - '0');
@ -721,20 +731,14 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
const int lbits = va_arg(ap, int);
double d = va_arg(ap, double);
if (lbits) {} // UNUSED - always 64
switch (fmt) {
case '^': { // Realtime
if (fmt == '^') { // Realtime
if (!widthSet) width = VerilatedImp::timeFormatWidth();
output += _vl_vsformat_time(tmp, d, left, width);
break;
}
default: {
} else {
std::string fmt(pctp, pos - pctp + 1);
sprintf(tmp, fmt.c_str(), d);
output += tmp;
break;
} //
break;
} // switch
}
break;
}
default: {
@ -742,7 +746,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
const int lbits = va_arg(ap, int);
QData ld = 0;
WData qlwp[VL_WQ_WORDS_E];
WDataInP lwp;
WDataInP lwp = NULL;
if (lbits <= VL_QUADSIZE) {
ld = _VL_VA_ARG_Q(ap, lbits);
VL_SET_WQ(qlwp, ld);
@ -758,7 +762,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
switch (fmt) {
case 'c': {
IData charval = ld & 0xff;
output += charval;
output += static_cast<char>(charval);
break;
}
case 's': {
@ -774,7 +778,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
break;
}
case 'd': { // Signed decimal
int digits;
int digits = 0;
std::string append;
if (lbits <= VL_QUADSIZE) {
digits = sprintf(tmp, "%" VL_PRI64 "d",
@ -803,7 +807,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
break;
}
case '#': { // Unsigned decimal
int digits;
int digits = 0;
std::string append;
if (lbits <= VL_QUADSIZE) {
digits = sprintf(tmp, "%" VL_PRI64 "u", ld);
@ -838,30 +842,28 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
// Octal numbers may span more than one wide word,
// so we need to grab each bit separately and check for overrun
// Octal is rare, so we'll do it a slow simple way
output += ('0' + ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 0)) ? 1 : 0)
+ ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 1)) ? 2 : 0)
+ ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 2)) ? 4 : 0));
output += static_cast<char>(
'0' + ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 0)) ? 1 : 0)
+ ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 1)) ? 2 : 0)
+ ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 2)) ? 4 : 0));
}
break;
case 'u': // Packed 2-state
output.reserve(output.size() + 4 * VL_WORDS_I(lbits));
for (int i = 0; i < VL_WORDS_I(lbits); ++i) {
output += static_cast<char>((lwp[i]) & 0xff);
output += static_cast<char>((lwp[i] >> 8) & 0xff);
output += static_cast<char>((lwp[i] >> 16) & 0xff);
output += static_cast<char>((lwp[i] >> 24) & 0xff);
}
break;
case 'z': // Packed 4-state
output.reserve(output.size() + 8 * VL_WORDS_I(lbits));
for (int i = 0; i < VL_WORDS_I(lbits); ++i) {
output += static_cast<char>((lwp[i]) & 0xff);
output += static_cast<char>((lwp[i] >> 8) & 0xff);
output += static_cast<char>((lwp[i] >> 16) & 0xff);
output += static_cast<char>((lwp[i] >> 24) & 0xff);
output += "\0\0\0\0"; // No tristate
case 'u':
case 'z': { // Packed 4-state
const bool is_4_state = (fmt == 'z');
output.reserve(output.size() + ((is_4_state ? 2 : 1) * VL_WORDS_I(lbits)));
int bytes_to_go = VL_BYTES_I(lbits);
int bit = 0;
while (bytes_to_go > 0) {
const int wr_bytes = std::min(4, bytes_to_go);
for (int byte = 0; byte < wr_bytes; byte++, bit += 8)
output += static_cast<char>(VL_BITRSHIFT_W(lwp, bit) & 0xff);
output.append(4 - wr_bytes, static_cast<char>(0));
if (is_4_state) output.append(4, static_cast<char>(0));
bytes_to_go -= wr_bytes;
}
break;
}
case 'v': // Strength; assume always strong
for (lsb = lbits - 1; lsb >= 0; --lsb) {
if (VL_BITRSHIFT_W(lwp, lsb) & 1) {
@ -891,7 +893,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
static inline bool _vl_vsss_eof(FILE* fp, int floc) VL_MT_SAFE {
if (fp) {
return feof(fp) ? 1 : 0; // 1:0 to prevent MSVC++ warning
return feof(fp) ? true : false; // true : false to prevent MSVC++ warning
} else {
return floc < 0;
}
@ -929,8 +931,8 @@ static inline void _vl_vsss_skipspace(FILE* fp, int& floc, WDataInP fromp,
_vl_vsss_advance(fp, floc);
}
}
static inline void _vl_vsss_read(FILE* fp, int& floc, WDataInP fromp, const std::string& fstr,
char* tmpp, const char* acceptp) VL_MT_SAFE {
static inline void _vl_vsss_read_str(FILE* fp, int& floc, WDataInP fromp, const std::string& fstr,
char* tmpp, const char* acceptp) VL_MT_SAFE {
// Read into tmp, consisting of characters from acceptp list
char* cp = tmpp;
while (true) {
@ -944,6 +946,19 @@ static inline void _vl_vsss_read(FILE* fp, int& floc, WDataInP fromp, const std:
*cp++ = '\0';
// VL_DBG_MSGF(" _read got='"<<tmpp<<"'\n");
}
static inline char* _vl_vsss_read_bin(FILE* fp, int& floc, WDataInP fromp, const std::string& fstr,
char* beginp, std::size_t n, bool inhibit = false) {
// Variant of _vl_vsss_read_str using the same underlying I/O functions but optimized
// specifically for block reads of N bytes (read operations are not demarcated by
// whitespace). In the fp case, except descriptor to have been opened in binary mode.
while (n-- > 0) {
const int c = _vl_vsss_peek(fp, floc, fromp, fstr);
if (c == EOF) return NULL;
if (!inhibit) *beginp++ = c;
_vl_vsss_advance(fp, floc);
}
return beginp;
}
static inline void _vl_vsss_setbit(WDataOutP owp, int obits, int lsb, int nbits,
IData ld) VL_MT_SAFE {
for (; nbits && lsb < obits; nbits--, lsb++, ld >>= 1) {
@ -992,12 +1007,14 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
int floc = fbits - 1;
IData got = 0;
bool inPct = false;
bool inIgnore = false;
const char* pos = formatp;
for (; *pos && !_vl_vsss_eof(fp, floc); ++pos) {
// VL_DBG_MSGF("_vlscan fmt='"<<pos[0]<<"' floc="<<floc<<" file='"<<_vl_vsss_peek(fp, floc,
// fromp, fstr)<<"'"<<endl);
if (!inPct && pos[0] == '%') {
inPct = true;
inIgnore = false;
} else if (!inPct && isspace(pos[0])) { // Format spaces
while (isspace(pos[1])) pos++;
_vl_vsss_skipspace(fp, floc, fromp, fstr);
@ -1017,12 +1034,16 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
_vl_vsss_advance(fp, floc);
break;
}
case '*':
inPct = true;
inIgnore = true;
break;
default: {
// Deal with all read-and-scan somethings
// Note LSBs are preserved if there's an overflow
const int obits = va_arg(ap, int);
const int obits = inIgnore ? 0 : va_arg(ap, int);
WData qowp[VL_WQ_WORDS_E];
VL_SET_WQ(qowp, VL_ULL(0));
VL_SET_WQ(qowp, 0ULL);
WDataOutP owp = qowp;
if (obits > VL_QUADSIZE) owp = va_arg(ap, WDataOutP);
for (int i = 0; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
@ -1036,7 +1057,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
}
case 's': {
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read(fp, floc, fromp, fstr, tmp, NULL);
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, NULL);
if (!tmp[0]) goto done;
int lpos = (static_cast<int>(strlen(tmp))) - 1;
int lsb = 0;
@ -1048,9 +1069,9 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
}
case 'd': { // Signed decimal
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read(fp, floc, fromp, fstr, tmp, "0123456789+-xXzZ?_");
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "0123456789+-xXzZ?_");
if (!tmp[0]) goto done;
vlsint64_t ld;
vlsint64_t ld = 0;
sscanf(tmp, "%30" VL_PRI64 "d", &ld);
VL_SET_WQ(owp, ld);
break;
@ -1059,7 +1080,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
case 'e':
case 'g': { // Real number
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read(fp, floc, fromp, fstr, tmp, "+-.0123456789eE");
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "+-.0123456789eE");
if (!tmp[0]) goto done;
// cppcheck-suppress unusedStructMember // It's used
union {
@ -1073,43 +1094,71 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
case 't': // FALLTHRU // Time
case '#': { // Unsigned decimal
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read(fp, floc, fromp, fstr, tmp, "0123456789+-xXzZ?_");
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "0123456789+-xXzZ?_");
if (!tmp[0]) goto done;
QData ld;
QData ld = 0;
sscanf(tmp, "%30" VL_PRI64 "u", &ld);
VL_SET_WQ(owp, ld);
break;
}
case 'b': {
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read(fp, floc, fromp, fstr, tmp, "01xXzZ?_");
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "01xXzZ?_");
if (!tmp[0]) goto done;
_vl_vsss_based(owp, obits, 1, tmp, 0, strlen(tmp));
break;
}
case 'o': {
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read(fp, floc, fromp, fstr, tmp, "01234567xXzZ?_");
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "01234567xXzZ?_");
if (!tmp[0]) goto done;
_vl_vsss_based(owp, obits, 3, tmp, 0, strlen(tmp));
break;
}
case 'x': {
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read(fp, floc, fromp, fstr, tmp, "0123456789abcdefABCDEFxXzZ?_");
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "0123456789abcdefABCDEFxXzZ?_");
if (!tmp[0]) goto done;
_vl_vsss_based(owp, obits, 4, tmp, 0, strlen(tmp));
break;
}
case 'u': {
// Read packed 2-value binary data
const int bytes = VL_BYTES_I(obits);
char* out = reinterpret_cast<char*>(owp);
if (!_vl_vsss_read_bin(fp, floc, fromp, fstr, out, bytes)) goto done;
const int last = bytes % 4;
if (last != 0
&& !_vl_vsss_read_bin(fp, floc, fromp, fstr, out, 4 - last, true))
goto done;
break;
}
case 'z': {
// Read packed 4-value binary data
char* out = reinterpret_cast<char*>(owp);
int bytes = VL_BYTES_I(obits);
while (bytes > 0) {
const int abytes = std::min(4, bytes);
// aval (4B) read {0, 1} state
out = _vl_vsss_read_bin(fp, floc, fromp, fstr, out, abytes);
if (!out) goto done;
// bval (4B) disregard {X, Z} state and align to new 8B boundary.
out = _vl_vsss_read_bin(fp, floc, fromp, fstr, out, 8 - abytes, true);
if (!out) goto done;
bytes -= abytes;
}
break;
}
default:
std::string msg = std::string("Unknown _vl_vsscanf code: ") + pos[0];
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
break;
} // switch
got++;
if (!inIgnore) ++got;
// Reload data if non-wide (if wide, we put it in the right place directly)
if (obits <= VL_BYTESIZE) {
if (obits == 0) { // Due to inIgnore
} else if (obits <= VL_BYTESIZE) {
CData* p = va_arg(ap, CData*);
*p = owp[0];
} else if (obits <= VL_SHORTSIZE) {
@ -1133,7 +1182,10 @@ done:
//===========================================================================
// File I/O
FILE* VL_CVT_I_FP(IData lhs) VL_MT_SAFE { return VerilatedImp::fdToFp(lhs); }
FILE* VL_CVT_I_FP(IData lhs) VL_MT_SAFE {
// Expected non-MCD case; returns null on MCD descriptors.
return VerilatedImp::fdToFp(lhs);
}
void _VL_VINT_TO_STRING(int obits, char* destoutp, WDataInP sourcep) VL_MT_SAFE {
// See also VL_DATA_TO_STRING_NW
@ -1159,7 +1211,7 @@ void _VL_STRING_TO_VINT(int obits, void* destp, size_t srclen, const char* srcp)
size_t bytes = VL_BYTES_I(obits);
char* op = reinterpret_cast<char*>(destp);
if (srclen > bytes) srclen = bytes; // Don't overflow destination
size_t i;
size_t i = 0;
for (i = 0; i < srclen; ++i) { *op++ = srcp[srclen - 1 - i]; }
for (; i < bytes; ++i) { *op++ = 0; }
}
@ -1201,38 +1253,21 @@ IData VL_FERROR_IN(IData, std::string& outputr) VL_MT_SAFE {
return ret;
}
IData VL_FOPEN_NI(const std::string& filename, IData mode) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles
char modez[5];
EData modee = mode;
_VL_VINT_TO_STRING(VL_IDATASIZE, modez, &modee);
return VL_FOPEN_S(filename.c_str(), modez);
IData VL_FOPEN_NN(const std::string& filename, const std::string& mode) {
return VerilatedImp::fdNew(filename.c_str(), mode.c_str());
}
IData VL_FOPEN_QI(QData filename, IData mode) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles
WData fnw[VL_WQ_WORDS_E];
VL_SET_WQ(fnw, filename);
return VL_FOPEN_WI(VL_WQ_WORDS_E, fnw, mode);
}
IData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles
char filenamez[VL_TO_STRING_MAX_WORDS * VL_EDATASIZE + 1];
_VL_VINT_TO_STRING(fnwords * VL_EDATASIZE, filenamez, filenamep);
EData modee = mode;
char modez[5];
_VL_VINT_TO_STRING(4 * sizeof(char), modez, &modee);
return VL_FOPEN_S(filenamez, modez);
}
IData VL_FOPEN_S(const char* filenamep, const char* modep) VL_MT_SAFE {
return VerilatedImp::fdNew(fopen(filenamep, modep));
IData VL_FOPEN_MCD_N(const std::string& filename) VL_MT_SAFE {
return VerilatedImp::fdNewMcd(filename.c_str());
}
void VL_FFLUSH_I(IData fdi) VL_MT_SAFE { VerilatedImp::fdFlush(fdi); }
IData VL_FSEEK_I(IData fdi, IData offset, IData origin) VL_MT_SAFE {
return VerilatedImp::fdSeek(fdi, offset, origin);
}
IData VL_FTELL_I(IData fdi) VL_MT_SAFE { return VerilatedImp::fdTell(fdi); }
void VL_FCLOSE_I(IData fdi) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles
FILE* fp = VL_CVT_I_FP(fdi);
if (VL_UNLIKELY(!fp)) return;
fclose(fp);
VerilatedImp::fdDelete(fdi);
VerilatedImp::fdClose(fdi);
}
void VL_FFLUSH_ALL() VL_MT_SAFE { fflush(stdout); }
@ -1327,15 +1362,13 @@ void VL_FWRITEF(IData fpi, const char* formatp, ...) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles
static VL_THREAD_LOCAL std::string output; // static only for speed
output = "";
FILE* fp = VL_CVT_I_FP(fpi);
if (VL_UNLIKELY(!fp)) return;
va_list ap;
va_start(ap, formatp);
_vl_vsformat(output, formatp, ap);
va_end(ap);
fputs(output.c_str(), fp);
VerilatedImp::fdWrite(fpi, output);
}
IData VL_FSCANF_IX(IData fpi, const char* formatp, ...) VL_MT_SAFE {
@ -1484,36 +1517,38 @@ IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_M
VL_ZERO_RESET_W(rbits, rwp);
switch (tolower(fmt)) {
case 'd':
vlsint64_t lld;
case 'd': {
vlsint64_t lld = 0;
sscanf(dp, "%30" VL_PRI64 "d", &lld);
VL_SET_WQ(rwp, lld);
break;
}
case 'b': _vl_vsss_based(rwp, rbits, 1, dp, 0, strlen(dp)); break;
case 'o': _vl_vsss_based(rwp, rbits, 3, dp, 0, strlen(dp)); break;
case 'h': // FALLTHRU
case 'x': _vl_vsss_based(rwp, rbits, 4, dp, 0, strlen(dp)); break;
case 's': // string/no conversion
case 's': { // string/no conversion
for (int i = 0, lsb = 0, posp = static_cast<int>(strlen(dp)) - 1; i < rbits && posp >= 0;
--posp) {
_vl_vsss_setbit(rwp, rbits, lsb, 8, dp[posp]);
lsb += 8;
}
break;
}
case 'e': {
double temp = 0.f;
double temp = 0.F;
sscanf(dp, "%le", &temp);
VL_SET_WQ(rwp, VL_CVT_Q_D(temp));
break;
}
case 'f': {
double temp = 0.f;
double temp = 0.F;
sscanf(dp, "%lf", &temp);
VL_SET_WQ(rwp, VL_CVT_Q_D(temp));
break;
}
case 'g': {
double temp = 0.f;
double temp = 0.F;
sscanf(dp, "%lg", &temp);
VL_SET_WQ(rwp, VL_CVT_Q_D(temp));
break;
@ -1761,7 +1796,7 @@ bool VlReadMem::get(QData& addrr, std::string& valuer) {
m_addr = (m_addr << 4) + value;
} else {
indata = true;
valuer += c;
valuer += static_cast<char>(c);
// printf(" Value width=%d @%x = %c\n", width, m_addr, c);
if (VL_UNLIKELY(value > 1 && !m_hex)) {
VL_FATAL_MT(m_filename.c_str(), m_linenum, "",
@ -1775,7 +1810,7 @@ bool VlReadMem::get(QData& addrr, std::string& valuer) {
lastc = c;
}
if (VL_UNLIKELY(m_end != ~VL_ULL(0) && m_addr <= m_end)) {
if (VL_UNLIKELY(m_end != ~0ULL && m_addr <= m_end)) {
VL_FATAL_MT(m_filename.c_str(), m_linenum, "",
"$readmem file ended before specified final address (IEEE 2017 21.4)");
}
@ -1783,7 +1818,7 @@ bool VlReadMem::get(QData& addrr, std::string& valuer) {
return false; // EOF
}
void VlReadMem::setData(void* valuep, const std::string& rhs) {
QData shift = m_hex ? VL_ULL(4) : VL_ULL(1);
QData shift = m_hex ? 4ULL : 1ULL;
bool innum = false;
// Shift value in
for (std::string::const_iterator it = rhs.begin(); it != rhs.end(); ++it) {
@ -1906,7 +1941,7 @@ void VL_READMEM_N(bool hex, // Hex format, else binary
VlReadMem rmem(hex, bits, filename, start, end);
if (VL_UNLIKELY(!rmem.isOpen())) return;
while (true) {
QData addr;
QData addr = 0;
std::string value;
if (rmem.get(addr /*ref*/, value /*ref*/)) {
if (VL_UNLIKELY(addr < static_cast<QData>(array_lsb)
@ -2006,50 +2041,55 @@ int VL_TIME_STR_CONVERT(const char* strp) {
}
static const char* vl_time_str(int scale) {
static const char* const names[]
= {"1s", "100ms", "10ms", "1ms", "100us", "10us", "1us", "100ns",
"10ns", "1ns", "100ps", "10ps", "1ps", "100fs", "10fs", "1fs"};
if (scale < 0) scale = -scale;
if (VL_UNLIKELY(scale > 15)) scale = 0;
return names[scale];
= {"100s", "10s", "1s", "100ms", "10ms", "1ms", "100us", "10us", "1us",
"100ns", "10ns", "1ns", "100ps", "10ps", "1ps", "100fs", "10fs", "1fs"};
if (VL_UNLIKELY(scale > 2 || scale < -15)) scale = 0;
return names[2 - scale];
}
double vl_time_multiplier(int scale) {
// Return timescale multipler -15 to +15
// Return timescale multipler -18 to +18
// For speed, this does not check for illegal values
static double pow10[] = {1.0,
10.0,
100.0,
1000.0,
10000.0,
100000.0,
1000000.0,
10000000.0,
100000000.0,
1000000000.0,
10000000000.0,
100000000000.0,
1000000000000.0,
10000000000000.0,
100000000000000.0,
1000000000000000.0};
static double neg10[] = {1.0,
0.1,
0.01,
0.001,
0.0001,
0.00001,
0.000001,
0.0000001,
0.00000001,
0.000000001,
0.0000000001,
0.00000000001,
0.000000000001,
0.0000000000001,
0.00000000000001,
0.000000000000001};
if (scale < 0) {
static const double neg10[] = {1.0,
0.1,
0.01,
0.001,
0.0001,
0.00001,
0.000001,
0.0000001,
0.00000001,
0.000000001,
0.0000000001,
0.00000000001,
0.000000000001,
0.0000000000001,
0.00000000000001,
0.000000000000001,
0.0000000000000001,
0.00000000000000001,
0.000000000000000001};
return neg10[-scale];
} else {
static const double pow10[] = {1.0,
10.0,
100.0,
1000.0,
10000.0,
100000.0,
1000000.0,
10000000.0,
100000000.0,
1000000000.0,
10000000000.0,
100000000000.0,
1000000000000.0,
10000000000000.0,
100000000000000.0,
1000000000000000.0,
10000000000000000.0,
100000000000000000.0,
1000000000000000000.0};
return pow10[scale];
}
}
@ -2085,7 +2125,7 @@ Verilated::ThreadLocal::ThreadLocal()
Verilated::ThreadLocal::~ThreadLocal() {}
void Verilated::debug(int level) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
s_s.s_debug = level;
if (level) {
#ifdef VL_DEBUG
@ -2099,49 +2139,49 @@ void Verilated::debug(int level) VL_MT_SAFE {
}
}
void Verilated::randReset(int val) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
s_s.s_randReset = val;
}
void Verilated::randSeed(int val) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
s_s.s_randSeed = val;
}
void Verilated::calcUnusedSigs(bool flag) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
s_s.s_calcUnusedSigs = flag;
}
void Verilated::errorCount(int val) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
s_s.s_errorCount = val;
}
void Verilated::errorCountInc() VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
++s_s.s_errorCount;
}
void Verilated::errorLimit(int val) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
s_s.s_errorLimit = val;
}
void Verilated::gotFinish(bool flag) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
s_s.s_gotFinish = flag;
}
void Verilated::assertOn(bool flag) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
s_s.s_assertOn = flag;
}
void Verilated::fatalOnVpiError(bool flag) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
s_s.s_fatalOnVpiError = flag;
}
void Verilated::timeunit(int value) VL_MT_SAFE {
if (value < 0) value = -value; // Stored as 0..15
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
s_s.s_timeunit = value;
}
void Verilated::timeprecision(int value) VL_MT_SAFE {
if (value < 0) value = -value; // Stored as 0..15
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
s_s.s_timeprecision = value;
#ifdef SYSTEMC_VERSION
sc_time sc_res = sc_get_time_resolution();
@ -2172,15 +2212,15 @@ void Verilated::timeprecision(int value) VL_MT_SAFE {
#endif
}
void Verilated::profThreadsStart(vluint64_t flag) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
s_ns.s_profThreadsStart = flag;
}
void Verilated::profThreadsWindow(vluint64_t flag) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
s_ns.s_profThreadsWindow = flag;
}
void Verilated::profThreadsFilenamep(const char* flagp) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
if (s_ns.s_profThreadsFilenamep) free(const_cast<char*>(s_ns.s_profThreadsFilenamep));
s_ns.s_profThreadsFilenamep = strdup(flagp);
}
@ -2203,7 +2243,7 @@ const char* Verilated::catName(const char* n1, const char* n2, const char* delim
}
void Verilated::flushCb(VerilatedVoidCb cb) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
if (s_flushCb == cb) { // Ok - don't duplicate
} else if (!s_flushCb) {
s_flushCb = cb;
@ -2214,18 +2254,22 @@ void Verilated::flushCb(VerilatedVoidCb cb) VL_MT_SAFE {
}
}
// When running internal code coverage (gcc --coverage, as opposed to
// verilator --coverage), dump coverage data to properly cover failing
// tests.
void Verilated::flushCall() VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
if (s_flushCb) (*s_flushCb)();
fflush(stderr);
fflush(stdout);
VL_GCOV_FLUSH();
}
const char* Verilated::productName() VL_PURE { return VERILATOR_PRODUCT; }
const char* Verilated::productVersion() VL_PURE { return VERILATOR_VERSION; }
void Verilated::commandArgs(int argc, const char** argv) VL_MT_SAFE {
VerilatedLockGuard lock(s_args.m_argMutex);
const VerilatedLockGuard lock(s_args.m_argMutex);
s_args.argc = argc;
s_args.argv = argv;
VerilatedImp::commandArgs(argc, argv);
@ -2301,11 +2345,11 @@ void Verilated::endOfEvalGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
// VerilatedImp:: Methods
std::string VerilatedImp::timeFormatSuffix() VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_sergMutex);
const VerilatedLockGuard lock(s_s.m_sergMutex);
return s_s.m_serg.m_timeFormatSuffix;
}
void VerilatedImp::timeFormatSuffix(const std::string& value) VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_sergMutex);
const VerilatedLockGuard lock(s_s.m_sergMutex);
s_s.m_serg.m_timeFormatSuffix = value;
}
void VerilatedImp::timeFormatUnits(int value) VL_MT_SAFE { s_s.m_ser.m_timeFormatUnits = value; }
@ -2315,7 +2359,7 @@ void VerilatedImp::timeFormatPrecision(int value) VL_MT_SAFE {
void VerilatedImp::timeFormatWidth(int value) VL_MT_SAFE { s_s.m_ser.m_timeFormatWidth = value; }
void VerilatedImp::internalsDump() VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_argMutex);
const VerilatedLockGuard lock(s_s.m_argMutex);
VL_PRINTF_MT("internalsDump:\n");
versionDump();
VL_PRINTF_MT(" Argv:");
@ -2332,12 +2376,12 @@ void VerilatedImp::versionDump() VL_MT_SAFE {
}
void VerilatedImp::commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) {
VerilatedLockGuard lock(s_s.m_argMutex);
const VerilatedLockGuard lock(s_s.m_argMutex);
s_s.m_argVec.clear(); // Always clear
commandArgsAddGuts(argc, argv);
}
void VerilatedImp::commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) {
VerilatedLockGuard lock(s_s.m_argMutex);
const VerilatedLockGuard lock(s_s.m_argMutex);
commandArgsAddGuts(argc, argv);
}
void VerilatedImp::commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.m_argMutex) {
@ -2444,12 +2488,12 @@ vluint32_t VerilatedVarProps::entSize() const {
size_t VerilatedVarProps::totalSize() const {
size_t size = entSize();
for (int dim = 0; dim <= dims(); ++dim) size *= m_unpacked[dim].elements();
for (int udim = 0; udim <= udims(); ++udim) size *= m_unpacked[udim].elements();
return size;
}
void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const {
if (VL_UNLIKELY(dim <= 0 || dim > m_udims || dim > 3)) return NULL;
if (VL_UNLIKELY(dim <= 0 || dim > udims())) return NULL;
if (VL_UNLIKELY(indx < low(dim) || indx > high(dim))) return NULL;
int indxAdj = indx - low(dim);
vluint8_t* bytep = reinterpret_cast<vluint8_t*>(datap);
@ -2470,6 +2514,7 @@ VerilatedScope::VerilatedScope() {
m_funcnumMax = 0;
m_symsp = NULL;
m_varsp = NULL;
m_timeunit = 0;
m_type = SCOPE_OTHER;
}
@ -2484,7 +2529,7 @@ VerilatedScope::~VerilatedScope() {
void VerilatedScope::configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp,
const char* identifier, vlsint8_t timeunit,
const Type type) VL_MT_UNSAFE {
const Type& type) VL_MT_UNSAFE {
// Slowpath - called once/scope at construction
// We don't want the space and reference-count access overhead of strings.
m_symsp = symsp;
@ -2538,7 +2583,7 @@ void VerilatedScope::varInsert(int finalize, const char* namep, void* datap,
if (i == 0) {
var.m_packed.m_left = msb;
var.m_packed.m_right = lsb;
} else if (i >= 1 && i <= 3) {
} else if (i >= 1 && i <= var.udims()) {
var.m_unpacked[i - 1].m_left = msb;
var.m_unpacked[i - 1].m_right = lsb;
} else {

View File

@ -337,7 +337,7 @@ public: // But internals only - called from VerilatedModule's
VerilatedScope();
~VerilatedScope();
void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp,
const char* identifier, vlsint8_t timeunit, const Type type) VL_MT_UNSAFE;
const char* identifier, vlsint8_t timeunit, const Type& type) VL_MT_UNSAFE;
void exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE;
void varInsert(int finalize, const char* namep, void* datap, VerilatedVarType vltype,
int vlflags, int dims, ...) VL_MT_UNSAFE;
@ -365,7 +365,7 @@ public: // But internals only - called from VerilatedModule's
class VerilatedHierarchy {
public:
void add(VerilatedScope* fromp, VerilatedScope* top);
static void add(VerilatedScope* fromp, VerilatedScope* top);
};
//===========================================================================
@ -386,8 +386,8 @@ class Verilated {
bool s_assertOn; ///< Assertions are enabled
bool s_fatalOnVpiError; ///< Stop on vpi error/unsupported
// Slow path
unsigned s_timeunit : 4; ///< Time unit as 0..15
unsigned s_timeprecision : 4; ///< Time precision as 0..15
vlsint8_t s_timeunit; ///< Time unit as 0..15
vlsint8_t s_timeprecision; ///< Time precision as 0..15
int s_errorCount; ///< Number of errors
int s_errorLimit; ///< Stop on error number
int s_randReset; ///< Random reset: 0=all 0s, 1=all 1s, 2=random
@ -673,13 +673,9 @@ extern WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP r
/// File I/O
extern IData VL_FGETS_IXI(int obits, void* destp, IData fpi);
extern IData VL_FOPEN_S(const char* filenamep, const char* modep);
extern IData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode);
extern IData VL_FOPEN_QI(QData filename, IData mode);
inline IData VL_FOPEN_II(IData filename, IData mode) VL_MT_SAFE {
return VL_FOPEN_QI(filename, mode);
}
extern void VL_FFLUSH_I(IData fdi);
extern IData VL_FSEEK_I(IData fdi, IData offset, IData origin);
extern IData VL_FTELL_I(IData fdi);
extern void VL_FCLOSE_I(IData fdi);
extern IData VL_FREAD_I(int width, int array_lsb, int array_size, void* memp, IData fpi,
@ -711,7 +707,7 @@ extern const char* vl_mc_scan_plusargs(const char* prefixp); // PLIish
/// Return true if data[bit] set; not 0/1 return, but 0/non-zero return.
#define VL_BITISSET_I(data, bit) ((data) & (VL_UL(1) << VL_BITBIT_I(bit)))
#define VL_BITISSET_Q(data, bit) ((data) & (VL_ULL(1) << VL_BITBIT_Q(bit)))
#define VL_BITISSET_Q(data, bit) ((data) & (1ULL << VL_BITBIT_Q(bit)))
#define VL_BITISSET_E(data, bit) ((data) & (VL_EUL(1) << VL_BITBIT_E(bit)))
#define VL_BITISSET_W(data, bit) ((data)[VL_BITWORD_E(bit)] & (VL_EUL(1) << VL_BITBIT_E(bit)))
#define VL_BITISSETLIMIT_W(data, width, bit) (((bit) < (width)) && VL_BITISSET_W(data, bit))
@ -722,22 +718,22 @@ extern const char* vl_mc_scan_plusargs(const char* prefixp); // PLIish
/// Create two 32-bit words from quadword
/// WData is always at least 2 words; does not clean upper bits
#define VL_SET_WQ(owp, data) \
{ \
do { \
(owp)[0] = static_cast<IData>(data); \
(owp)[1] = static_cast<IData>((data) >> VL_EDATASIZE); \
}
} while (false)
#define VL_SET_WI(owp, data) \
{ \
do { \
(owp)[0] = static_cast<IData>(data); \
(owp)[1] = 0; \
}
} while (false)
#define VL_SET_QW(lwp) \
((static_cast<QData>((lwp)[0])) \
| (static_cast<QData>((lwp)[1]) << (static_cast<QData>(VL_EDATASIZE))))
#define _VL_SET_QII(ld, rd) ((static_cast<QData>(ld) << VL_ULL(32)) | static_cast<QData>(rd))
#define _VL_SET_QII(ld, rd) ((static_cast<QData>(ld) << 32ULL) | static_cast<QData>(rd))
/// Return FILE* from IData
extern FILE* VL_CVT_I_FP(IData lhs);
extern FILE* VL_CVT_I_FP(IData lhs) VL_MT_SAFE;
// clang-format off
// Use a union to avoid cast-to-different-size warnings
@ -780,7 +776,7 @@ static inline IData VL_RTOI_I_D(double lhs) VL_PURE {
// Sign extend such that if MSB set, we get ffff_ffff, else 0s
// (Requires clean input)
#define VL_SIGN_I(nbits, lhs) ((lhs) >> VL_BITBIT_I((nbits)-VL_UL(1)))
#define VL_SIGN_Q(nbits, lhs) ((lhs) >> VL_BITBIT_Q((nbits)-VL_ULL(1)))
#define VL_SIGN_Q(nbits, lhs) ((lhs) >> VL_BITBIT_Q((nbits)-1ULL))
#define VL_SIGN_E(nbits, lhs) ((lhs) >> VL_BITBIT_E((nbits)-VL_EUL(1)))
#define VL_SIGN_W(nbits, rwp) \
((rwp)[VL_BITWORD_E((nbits)-VL_EUL(1))] >> VL_BITBIT_E((nbits)-VL_EUL(1)))
@ -792,7 +788,7 @@ static inline IData VL_EXTENDSIGN_I(int lbits, IData lhs) VL_PURE {
return (-((lhs) & (VL_UL(1) << (lbits - 1))));
}
static inline QData VL_EXTENDSIGN_Q(int lbits, QData lhs) VL_PURE {
return (-((lhs) & (VL_ULL(1) << (lbits - 1))));
return (-((lhs) & (1ULL << (lbits - 1))));
}
// Debugging prints
@ -930,8 +926,7 @@ static inline void VL_ASSIGNBIT_II(int, int bit, IData& lhsr, IData rhs) VL_PURE
lhsr = ((lhsr & ~(VL_UL(1) << VL_BITBIT_I(bit))) | (rhs << VL_BITBIT_I(bit)));
}
static inline void VL_ASSIGNBIT_QI(int, int bit, QData& lhsr, QData rhs) VL_PURE {
lhsr = ((lhsr & ~(VL_ULL(1) << VL_BITBIT_Q(bit)))
| (static_cast<QData>(rhs) << VL_BITBIT_Q(bit)));
lhsr = ((lhsr & ~(1ULL << VL_BITBIT_Q(bit))) | (static_cast<QData>(rhs) << VL_BITBIT_Q(bit)));
}
static inline void VL_ASSIGNBIT_WI(int, int bit, WDataOutP owp, IData rhs) VL_MT_SAFE {
EData orig = owp[VL_BITWORD_E(bit)];
@ -949,7 +944,7 @@ static inline void VL_ASSIGNBIT_IO(int, int bit, IData& lhsr, IData) VL_PURE {
lhsr = (lhsr | (VL_UL(1) << VL_BITBIT_I(bit)));
}
static inline void VL_ASSIGNBIT_QO(int, int bit, QData& lhsr, IData) VL_PURE {
lhsr = (lhsr | (VL_ULL(1) << VL_BITBIT_Q(bit)));
lhsr = (lhsr | (1ULL << VL_BITBIT_Q(bit)));
}
static inline void VL_ASSIGNBIT_WO(int, int bit, WDataOutP owp, IData) VL_MT_SAFE {
EData orig = owp[VL_BITWORD_E(bit)];
@ -1217,6 +1212,36 @@ static inline IData VL_COUNTONES_W(int words, WDataInP lwp) VL_MT_SAFE {
return r;
}
// EMIT_RULE: VL_COUNTBITS_II: oclean = false; lhs clean
static inline IData VL_COUNTBITS_I(int lbits, IData lhs, IData ctrl0, IData ctrl1,
IData ctrl2) VL_PURE {
int ctrlSum = (ctrl0 & 0x1) + (ctrl1 & 0x1) + (ctrl2 & 0x1);
if (ctrlSum == 3) {
return VL_COUNTONES_I(lhs);
} else if (ctrlSum == 0) {
IData mask = (lbits == 32) ? -1 : ((1 << lbits) - 1);
return VL_COUNTONES_I(~lhs & mask);
} else {
return (lbits == 32) ? 32 : lbits;
}
}
static inline IData VL_COUNTBITS_Q(int lbits, QData lhs, IData ctrl0, IData ctrl1,
IData ctrl2) VL_PURE {
return VL_COUNTBITS_I(32, static_cast<IData>(lhs), ctrl0, ctrl1, ctrl2)
+ VL_COUNTBITS_I(lbits - 32, static_cast<IData>(lhs >> 32), ctrl0, ctrl1, ctrl2);
}
#define VL_COUNTBITS_E VL_COUNTBITS_I
static inline IData VL_COUNTBITS_W(int lbits, int words, WDataInP lwp, IData ctrl0, IData ctrl1,
IData ctrl2) VL_MT_SAFE {
EData r = 0;
IData wordLbits = 32;
for (int i = 0; i < words; ++i) {
if (i == words - 1) { wordLbits = lbits % 32; }
r += VL_COUNTBITS_E(wordLbits, lwp[i], ctrl0, ctrl1, ctrl2);
}
return r;
}
static inline IData VL_ONEHOT_I(IData lhs) VL_PURE {
return (((lhs & (lhs - 1)) == 0) & (lhs != 0));
}
@ -1261,7 +1286,7 @@ static inline IData VL_CLOG2_Q(QData lhs) VL_PURE {
if (VL_UNLIKELY(!lhs)) return 0;
lhs--;
int shifts = 0;
for (; lhs != 0; ++shifts) lhs = lhs >> VL_ULL(1);
for (; lhs != 0; ++shifts) lhs = lhs >> 1ULL;
return shifts;
}
static inline IData VL_CLOG2_W(int words, WDataInP lwp) VL_MT_SAFE {
@ -1459,8 +1484,8 @@ static inline WDataOutP VL_ADD_W(int words, WDataOutP owp, WDataInP lwp, WDataIn
QData carry = 0;
for (int i = 0; i < words; ++i) {
carry = carry + static_cast<QData>(lwp[i]) + static_cast<QData>(rwp[i]);
owp[i] = (carry & VL_ULL(0xffffffff));
carry = (carry >> VL_ULL(32)) & VL_ULL(0xffffffff);
owp[i] = (carry & 0xffffffffULL);
carry = (carry >> 32ULL) & 0xffffffffULL;
}
// Last output word is dirty
return owp;
@ -1472,8 +1497,8 @@ static inline WDataOutP VL_SUB_W(int words, WDataOutP owp, WDataInP lwp, WDataIn
carry = (carry + static_cast<QData>(lwp[i])
+ static_cast<QData>(static_cast<IData>(~rwp[i])));
if (i == 0) ++carry; // Negation of rwp
owp[i] = (carry & VL_ULL(0xffffffff));
carry = (carry >> VL_ULL(32)) & VL_ULL(0xffffffff);
owp[i] = (carry & 0xffffffffULL);
carry = (carry >> 32ULL) & 0xffffffffULL;
}
// Last output word is dirty
return owp;
@ -1486,8 +1511,8 @@ static inline WDataOutP VL_MUL_W(int words, WDataOutP owp, WDataInP lwp, WDataIn
QData mul = static_cast<QData>(lwp[lword]) * static_cast<QData>(rwp[rword]);
for (int qword = lword + rword; qword < words; ++qword) {
mul += static_cast<QData>(owp[qword]);
owp[qword] = (mul & VL_ULL(0xffffffff));
mul = (mul >> VL_ULL(32)) & VL_ULL(0xffffffff);
owp[qword] = (mul & 0xffffffffULL);
mul = (mul >> 32ULL) & 0xffffffffULL;
}
}
}
@ -1535,8 +1560,8 @@ static inline WDataOutP VL_MULS_WWW(int, int lbits, int, WDataOutP owp, WDataInP
for (int i = 0; i < words; ++i) {
carry = carry + static_cast<QData>(static_cast<IData>(~owp[i]));
if (i == 0) ++carry; // Negation of temp2
owp[i] = (carry & VL_ULL(0xffffffff));
carry = (carry >> VL_ULL(32)) & VL_ULL(0xffffffff);
owp[i] = (carry & 0xffffffffULL);
carry = (carry >> 32ULL) & 0xffffffffULL;
}
// Not needed: owp[words-1] |= 1<<VL_BITBIT_E(lbits-1); // Set sign bit
}
@ -1627,7 +1652,7 @@ static inline IData VL_POW_III(int, int, int rbits, IData lhs, IData rhs) VL_PUR
IData out = 1;
for (int i = 0; i < rbits; ++i) {
if (i > 0) power = power * power;
if (rhs & (VL_ULL(1) << i)) out *= power;
if (rhs & (1ULL << i)) out *= power;
}
return out;
}
@ -1635,10 +1660,10 @@ static inline QData VL_POW_QQQ(int, int, int rbits, QData lhs, QData rhs) VL_PUR
if (VL_UNLIKELY(rhs == 0)) return 1;
if (VL_UNLIKELY(lhs == 0)) return 0;
QData power = lhs;
QData out = VL_ULL(1);
QData out = 1ULL;
for (int i = 0; i < rbits; ++i) {
if (i > 0) power = power * power;
if (rhs & (VL_ULL(1) << i)) out *= power;
if (rhs & (1ULL << i)) out *= power;
}
return out;
}
@ -1884,7 +1909,8 @@ static inline IData VL_STREAML_FAST_III(int, int lbits, int, IData ld, IData rd_
case 1: ret = ((ret >> 2) & VL_UL(0x33333333)) | ((ret & VL_UL(0x33333333)) << 2); // FALLTHRU
case 2: ret = ((ret >> 4) & VL_UL(0x0f0f0f0f)) | ((ret & VL_UL(0x0f0f0f0f)) << 4); // FALLTHRU
case 3: ret = ((ret >> 8) & VL_UL(0x00ff00ff)) | ((ret & VL_UL(0x00ff00ff)) << 8); // FALLTHRU
case 4: ret = ((ret >> 16) | (ret << 16));
case 4: ret = ((ret >> 16) | (ret << 16)); // FALLTHRU
default:;
}
return ret >> (VL_IDATASIZE - lbits);
}
@ -1896,25 +1922,26 @@ static inline QData VL_STREAML_FAST_QQI(int, int lbits, int, QData ld, IData rd_
vluint32_t lbitsFloor = lbits & ~VL_MASK_I(rd_log2);
vluint32_t lbitsRem = lbits - lbitsFloor;
QData msbMask = VL_MASK_Q(lbitsRem) << lbitsFloor;
ret = (ret & ~msbMask) | ((ret & msbMask) << ((VL_ULL(1) << rd_log2) - lbitsRem));
ret = (ret & ~msbMask) | ((ret & msbMask) << ((1ULL << rd_log2) - lbitsRem));
}
switch (rd_log2) {
case 0:
ret = (((ret >> 1) & VL_ULL(0x5555555555555555))
| ((ret & VL_ULL(0x5555555555555555)) << 1)); // FALLTHRU
ret = (((ret >> 1) & 0x5555555555555555ULL)
| ((ret & 0x5555555555555555ULL) << 1)); // FALLTHRU
case 1:
ret = (((ret >> 2) & VL_ULL(0x3333333333333333))
| ((ret & VL_ULL(0x3333333333333333)) << 2)); // FALLTHRU
ret = (((ret >> 2) & 0x3333333333333333ULL)
| ((ret & 0x3333333333333333ULL) << 2)); // FALLTHRU
case 2:
ret = (((ret >> 4) & VL_ULL(0x0f0f0f0f0f0f0f0f))
| ((ret & VL_ULL(0x0f0f0f0f0f0f0f0f)) << 4)); // FALLTHRU
ret = (((ret >> 4) & 0x0f0f0f0f0f0f0f0fULL)
| ((ret & 0x0f0f0f0f0f0f0f0fULL) << 4)); // FALLTHRU
case 3:
ret = (((ret >> 8) & VL_ULL(0x00ff00ff00ff00ff))
| ((ret & VL_ULL(0x00ff00ff00ff00ff)) << 8)); // FALLTHRU
ret = (((ret >> 8) & 0x00ff00ff00ff00ffULL)
| ((ret & 0x00ff00ff00ff00ffULL) << 8)); // FALLTHRU
case 4:
ret = (((ret >> 16) & VL_ULL(0x0000ffff0000ffff))
| ((ret & VL_ULL(0x0000ffff0000ffff)) << 16)); // FALLTHRU
case 5: ret = ((ret >> 32) | (ret << 32));
ret = (((ret >> 16) & 0x0000ffff0000ffffULL)
| ((ret & 0x0000ffff0000ffffULL) << 16)); // FALLTHRU
case 5: ret = ((ret >> 32) | (ret << 32)); // FALLTHRU
default:;
}
return ret >> (VL_QUADSIZE - lbits);
}
@ -2358,14 +2385,14 @@ static inline WDataOutP VL_SEL_WWII(int obits, int lbits, int, int, WDataOutP ow
/// Return QData from double (numeric)
// EMIT_RULE: VL_RTOIROUND_Q_D: oclean=dirty; lclean==clean/real
static inline QData VL_RTOIROUND_Q_D(int bits, double lhs) VL_PURE {
static inline QData VL_RTOIROUND_Q_D(int, double lhs) VL_PURE {
// IEEE format: [63]=sign [62:52]=exp+1023 [51:0]=mantissa
// This does not need to support subnormals as they are sub-integral
lhs = VL_ROUND(lhs);
if (lhs == 0.0) return 0;
QData q = VL_CVT_Q_D(lhs);
int lsb = static_cast<int>((q >> VL_ULL(52)) & VL_MASK_Q(11)) - 1023 - 52;
vluint64_t mantissa = (q & VL_MASK_Q(52)) | (VL_ULL(1) << 52);
int lsb = static_cast<int>((q >> 52ULL) & VL_MASK_Q(11)) - 1023 - 52;
vluint64_t mantissa = (q & VL_MASK_Q(52)) | (1ULL << 52);
vluint64_t out = 0;
if (lsb < 0) {
out = mantissa >> -lsb;
@ -2385,8 +2412,8 @@ static inline WDataOutP VL_RTOIROUND_W_D(int obits, WDataOutP owp, double lhs) V
VL_ZERO_W(obits, owp);
if (lhs == 0.0) return owp;
QData q = VL_CVT_Q_D(lhs);
int lsb = static_cast<int>((q >> VL_ULL(52)) & VL_MASK_Q(11)) - 1023 - 52;
vluint64_t mantissa = (q & VL_MASK_Q(52)) | (VL_ULL(1) << 52);
int lsb = static_cast<int>((q >> 52ULL) & VL_MASK_Q(11)) - 1023 - 52;
vluint64_t mantissa = (q & VL_MASK_Q(52)) | (1ULL << 52);
if (lsb < 0) {
VL_SET_WQ(owp, mantissa >> -lsb);
} else if (lsb < obits) {

View File

@ -84,27 +84,29 @@ CPPFLAGS += $(VM_USER_CFLAGS)
LDFLAGS += $(VM_USER_LDFLAGS)
LDLIBS += $(VM_USER_LDLIBS)
# See the benchmarking section of bin/verilator.
# Support class optimizations. This includes the tracing and symbol table.
# 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 = -Os -fstrict-aliasing
#OPT_FAST = -O
#OPT_FAST =
######################################################################
# Optimization control.
#######################################################################
##### Aggregates
# See also the BENCHMARKING & OPTIMIZATION section of the manual.
VM_CLASSES += $(VM_CLASSES_FAST) $(VM_CLASSES_SLOW)
VM_SUPPORT += $(VM_SUPPORT_FAST) $(VM_SUPPORT_SLOW)
# Optimization flags for non performance-critical/rarely executed code.
# No optimization by default, which improves compilation speed.
OPT_SLOW =
# Optimization for performance critical/hot code. Most time is spent in these
# routines. Optimizing by default for improved execution speed.
OPT_FAST = -Os
# Optimization applied to the common run-time library used by verilated models.
# For compatibility this is called OPT_GLOBAL even though it only applies to
# files in the run-time library. Normally there should be no need for the user
# to change this as the library is small, but can have significant speed impact.
OPT_GLOBAL = -Os
#######################################################################
##### SystemC builds
ifeq ($(VM_SC),1)
CPPFLAGS += $(SYSTEMC_CXX_FLAGS) -I$(SYSTEMC_INCLUDE)
LDFLAGS += $(SYSTEMC_CXX_FLAGS) -L$(SYSTEMC_LIBDIR)
CPPFLAGS += $(SYSTEMC_CXX_FLAGS) $(addprefix -I, $(SYSTEMC_INCLUDE))
LDFLAGS += $(SYSTEMC_CXX_FLAGS) $(addprefix -L, $(SYSTEMC_LIBDIR))
SC_LIBS = -lsystemc
ifneq ($(wildcard $(SYSTEMC_LIBDIR)/*numeric_bit*),)
# Systemc 1.2.1beta
@ -163,35 +165,39 @@ ifneq ($(VK_LIBS_THREADED),0)
endif
#######################################################################
##### Stub
### Aggregates
preproc:
VM_FAST += $(VM_CLASSES_FAST) $(VM_SUPPORT_FAST)
VM_SLOW += $(VM_CLASSES_SLOW) $(VM_SUPPORT_SLOW)
#######################################################################
# Overall Objects Linking
### Overall Objects Linking
VK_CLASSES_FAST_CPP = $(addsuffix .cpp, $(VM_CLASSES_FAST))
VK_CLASSES_SLOW_CPP = $(addsuffix .cpp, $(VM_CLASSES_SLOW))
VK_SUPPORT_FAST_CPP = $(addsuffix .cpp, $(VM_SUPPORT_FAST))
VK_SUPPORT_SLOW_CPP = $(addsuffix .cpp, $(VM_SUPPORT_SLOW))
VK_FAST_OBJS = $(addsuffix .o, $(VM_FAST))
VK_SLOW_OBJS = $(addsuffix .o, $(VM_SLOW))
VK_USER_OBJS = $(addsuffix .o, $(VM_USER_CLASSES))
# Note VM_GLOBAL_FAST and VM_GLOBAL_SLOW holds the files required from the
# run-time library. In practice everything is actually in VM_GLOBAL_FAST,
# but keeping the distinction for compatibility for now.
VK_GLOBAL_OBJS = $(addsuffix .o, $(VM_GLOBAL_FAST) $(VM_GLOBAL_SLOW))
ifneq ($(VM_PARALLEL_BUILDS),1)
# Fast building, all .cpp's in one fell swoop
# This saves about 5 sec per module, but can be slower if only a little changes
VK_OBJS += $(VM_PREFIX)__ALLfast.o $(VM_PREFIX)__ALLslow.o
all_cpp: $(VM_PREFIX)__ALLfast.cpp $(VM_PREFIX)__ALLslow.cpp
$(VM_PREFIX)__ALLfast.cpp: $(VK_CLASSES_FAST_CPP) $(VK_SUPPORT_FAST_CPP)
$(VERILATOR_INCLUDER) -DVL_INCLUDE_OPT=include $^ > $@
$(VM_PREFIX)__ALLslow.cpp: $(VK_CLASSES_SLOW_CPP) $(VK_SUPPORT_SLOW_CPP)
# Fast build for small designs: All .cpp files in one fell swoop. This
# saves total compute, but can be slower if only a little changes. It is
# also a lot slower for medium to large designs when the speed of the C
# compiler dominates, which in this mode is not parallelizable.
VK_OBJS += $(VM_PREFIX)__ALL.o
$(VM_PREFIX)__ALL.cpp: $(addsuffix .cpp, $(VM_FAST) $(VM_SLOW))
$(VERILATOR_INCLUDER) -DVL_INCLUDE_OPT=include $^ > $@
all_cpp: $(VM_PREFIX)__ALL.cpp
else
#Slow way of building... Each .cpp file by itself
VK_OBJS += $(addsuffix .o, $(VM_CLASSES) $(VM_SUPPORT))
# Parallel build: Each .cpp file by itself. This can be somewhat slower for
# very small designs and examples, but is a lot faster for large designs.
VK_OBJS += $(VK_FAST_OBJS) $(VK_SLOW_OBJS)
endif
$(VM_PREFIX)__ALL.a: $(VK_OBJS)
@ -202,19 +208,16 @@ $(VM_PREFIX)__ALL.a: $(VK_OBJS)
### Compile rules
ifneq ($(VM_DEFAULT_RULES),0)
$(VM_PREFIX)__ALLfast.o: $(VM_PREFIX)__ALLfast.cpp
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $<
$(VM_PREFIX)__ALLslow.o: $(VM_PREFIX)__ALLslow.cpp
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_SLOW) -c -o $@ $<
# VM_GLOBAL_FAST files including verilated.o use this rule
# Anything not in $(VK_SLOW_OBJS) or $(VK_GLOBAL_OBJS), including verilated.o
# and user files passed on the Verilator command line use this rule.
%.o: %.cpp
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $<
%__Slow.o: %__Slow.cpp
$(VK_SLOW_OBJS): %.o: %.cpp
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_SLOW) -c -o $@ $<
$(VK_GLOBAL_OBJS): %.o: %.cpp
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_GLOBAL) -c -o $@ $<
endif
#Default rule embedded in make:

View File

@ -94,7 +94,6 @@ private:
typedef std::map<int, std::string> IndexValueMap;
typedef std::deque<VerilatedCovImpItem*> ItemList;
private:
// MEMBERS
VerilatedMutex m_mutex; ///< Protects all members
ValueIndexMap m_valueIndexes VL_GUARDED_BY(m_mutex); ///< Unique arbitrary value for values
@ -250,12 +249,12 @@ public:
// PUBLIC METHODS
void clear() VL_EXCLUDES(m_mutex) {
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
clearGuts();
}
void clearNonMatch(const char* matchp) VL_EXCLUDES(m_mutex) {
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
if (matchp && matchp[0]) {
ItemList newlist;
for (ItemList::iterator it = m_items.begin(); it != m_items.end(); ++it) {
@ -271,7 +270,7 @@ public:
}
void zero() VL_EXCLUDES(m_mutex) {
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
for (ItemList::const_iterator it = m_items.begin(); it != m_items.end(); ++it) {
(*it)->zero();
}
@ -279,17 +278,17 @@ public:
// We assume there's always call to i/f/p in that order
void inserti(VerilatedCovImpItem* itemp) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
assert(!m_insertp);
m_insertp = itemp;
}
void insertf(const char* filenamep, int lineno) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
m_insertFilenamep = filenamep;
m_insertLineno = lineno;
}
void insertp(const char* ckeyps[MAX_KEYS], const char* valps[MAX_KEYS]) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
assert(m_insertp);
// First two key/vals are filename
ckeyps[0] = "filename";
@ -332,10 +331,10 @@ public:
m_insertp->m_keys[addKeynum] = valueIndex(key);
m_insertp->m_vals[addKeynum] = valueIndex(val);
addKeynum++;
if (!legalKey(key)) {
if (VL_UNCOVERABLE(!legalKey(key))) {
std::string msg
= ("%Error: Coverage keys of one character, or letter+digit are illegal: "
+ key);
+ key); // LCOV_EXCL_LINE
VL_FATAL_MT("", 0, "", msg.c_str());
}
}
@ -347,7 +346,7 @@ public:
void write(const char* filename) VL_EXCLUDES(m_mutex) {
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
#ifndef VM_COVERAGE
VL_FATAL_MT("", 0, "", "%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
#endif
@ -475,11 +474,11 @@ void VerilatedCov::_insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8)
}
// Backward compatibility for Verilator
void VerilatedCov::_insertp(A(0), A(1), K(2), int val2, K(3), int val3, K(4),
const std::string& val4, A(5), A(6)) VL_MT_SAFE {
const std::string& val4, A(5), A(6), A(7)) VL_MT_SAFE {
std::string val2str = vlCovCvtToStr(val2);
std::string val3str = vlCovCvtToStr(val3);
_insertp(C(0), C(1), key2, val2str.c_str(), key3, val3str.c_str(), key4, val4.c_str(), C(5),
C(6), N(7), N(8), N(9), N(10), N(11), N(12), N(13), N(14), N(15), N(16), N(17), N(18),
C(6), C(7), N(8), N(9), N(10), N(11), N(12), N(13), N(14), N(15), N(16), N(17), N(18),
N(19), N(20), N(21), N(22), N(23), N(24), N(25), N(26), N(27), N(28), N(29));
}
#undef A

View File

@ -121,7 +121,7 @@ public:
D(22), D(23), D(24), D(25), D(26), D(27), D(28), D(29));
// Backward compatibility for Verilator
static void _insertp(A(0), A(1), K(2), int val2, K(3), int val3, K(4), const std::string& val4,
A(5), A(6));
A(5), A(6), A(7));
#undef K
#undef A

View File

@ -38,6 +38,7 @@ VLCOVGEN_ITEM("name=>'filename', short=>'f', group=>1, default=>undef, descr
VLCOVGEN_ITEM("name=>'groupdesc', short=>'d', group=>1, default=>'', descr=>'Description of the covergroup this item belongs to'")
VLCOVGEN_ITEM("name=>'groupname', short=>'g', group=>1, default=>'', descr=>'Group name of the covergroup this item belongs to'")
VLCOVGEN_ITEM("name=>'groupcmt', short=>'O', group=>1, default=>'', ")
VLCOVGEN_ITEM("name=>'linescov', short=>'S', group=>1, default=>'', descr=>'List of comma-separated lines covered'")
VLCOVGEN_ITEM("name=>'per_instance',short=>'P', group=>1, default=>0, descr=>'True if every hierarchy is independently counted; otherwise all hierarchies will be combined into a single count'")
VLCOVGEN_ITEM("name=>'row0_name', short=>'R0', group=>1, default=>undef, descr=>'The row title for the header line of this row'")
VLCOVGEN_ITEM("name=>'row1_name', short=>'R1', group=>1, default=>undef, ")
@ -80,6 +81,7 @@ VLCOVGEN_ITEM("name=>'weight', short=>'w', group=>0, default=>undef, descr
#define VL_CIK_HIER "h"
#define VL_CIK_LIMIT "L"
#define VL_CIK_LINENO "l"
#define VL_CIK_LINESCOV "S"
#define VL_CIK_PER_INSTANCE "P"
#define VL_CIK_ROW0 "r0"
#define VL_CIK_ROW0_NAME "R0"
@ -121,6 +123,7 @@ public:
if (key == "hier") return VL_CIK_HIER;
if (key == "limit") return VL_CIK_LIMIT;
if (key == "lineno") return VL_CIK_LINENO;
if (key == "linescov") return VL_CIK_LINESCOV;
if (key == "per_instance") return VL_CIK_PER_INSTANCE;
if (key == "row0") return VL_CIK_ROW0;
if (key == "row0_name") return VL_CIK_ROW0_NAME;

View File

@ -47,7 +47,7 @@
// Function requires a "context" in the import declaration
#define _VL_SVDPI_CONTEXT_WARN() \
_VL_SVDPI_WARN("%%Warning: DPI C Function called by Verilog DPI import with missing " \
"'context' keyword.\n");
"'context' keyword.\n")
//======================================================================
//======================================================================
@ -416,7 +416,7 @@ static svBit _vl_svGetBitArrElem(const svOpenArrayHandle s, int nargs, int indx1
case VLVT_UINT16: return (*(reinterpret_cast<SData*>(datap)) >> lsb) & 1;
case VLVT_UINT32: return (*(reinterpret_cast<IData*>(datap)) >> lsb) & 1;
case VLVT_UINT64:
return (*(reinterpret_cast<QData*>(datap)) >> static_cast<QData>(lsb)) & VL_ULL(1);
return (*(reinterpret_cast<QData*>(datap)) >> static_cast<QData>(lsb)) & 1ULL;
case VLVT_WDATA: {
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
return VL_BITRSHIFT_W(wdatap, lsb) & 1;

View File

@ -36,17 +36,12 @@
#include "gtkwave/lz4.c"
#include <algorithm>
#include <cerrno>
#include <ctime>
#include <fcntl.h>
#include <iterator>
#include <sstream>
#include <sys/stat.h>
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
# include <io.h>
#else
# include <stdint.h>
# include <unistd.h>
#endif
@ -132,15 +127,17 @@ 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,
vluint32_t bits) {
void VerilatedFst::declare(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
const int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1;
VerilatedTrace<VerilatedFst>::declCode(code, bits, false);
std::pair<Code2SymbolType::iterator, bool> p
= m_code2symbol.insert(std::make_pair(code, static_cast<fstHandle>(NULL)));
std::istringstream nameiss(name);
std::istream_iterator<std::string> beg(nameiss), end;
std::istream_iterator<std::string> beg(nameiss);
std::istream_iterator<std::string> end;
std::list<std::string> tokens(beg, end); // Split name
std::string symbol_name(tokens.back());
tokens.pop_back(); // Remove symbol name from hierarchy
@ -178,39 +175,32 @@ void VerilatedFst::declSymbol(vluint32_t code, const char* name, int dtypenum, f
fstWriterEmitEnumTableRef(m_fst, enumNum);
}
if (p.second) { // New
p.first->second = fstWriterCreateVar(m_fst, vartype, vardir, len, name_str.c_str(), 0);
p.first->second = fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), 0);
assert(p.first->second);
} else { // Alias
fstWriterCreateVar(m_fst, vartype, vardir, len, name_str.c_str(), p.first->second);
fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), p.first->second);
}
}
void VerilatedFst::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, 1);
declare(code, name, dtypenum, vardir, vartype, array, arraynum, 0, 0);
}
void VerilatedFst::declBus(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
msb - lsb + 1);
declare(code, name, dtypenum, vardir, vartype, array, arraynum, msb, lsb);
}
void VerilatedFst::declQuad(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
msb - lsb + 1);
declare(code, name, dtypenum, vardir, vartype, array, arraynum, msb, lsb);
}
void VerilatedFst::declArray(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
msb - lsb + 1);
}
void VerilatedFst::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, 32);
declare(code, name, dtypenum, vardir, vartype, array, arraynum, msb, lsb);
}
void VerilatedFst::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, 64);
declare(code, name, dtypenum, vardir, vartype, array, arraynum, 63, 0);
}
// Note: emit* are only ever called from one place (full* in
@ -266,11 +256,6 @@ void VerilatedFst::emitWData(vluint32_t code, const WData* newvalp, int bits) {
fstWriterEmitValueChange(m_fst, m_symbolp[code], m_strbuf);
}
VL_ATTR_ALWINLINE
void VerilatedFst::emitFloat(vluint32_t code, float newval) {
fstWriterEmitValueChange(m_fst, m_symbolp[code], &newval);
}
VL_ATTR_ALWINLINE
void VerilatedFst::emitDouble(vluint32_t code, double newval) {
fstWriterEmitValueChange(m_fst, m_symbolp[code], &newval);

View File

@ -55,8 +55,8 @@ private:
// CONSTRUCTORS
VL_UNCOPYABLE(VerilatedFst);
void declSymbol(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, vluint32_t len, vluint32_t bits);
void declare(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
protected:
//=========================================================================
@ -77,7 +77,6 @@ protected:
inline void emitIData(vluint32_t code, IData newval, int bits);
inline void emitQData(vluint32_t code, QData newval, int bits);
inline void emitWData(vluint32_t code, const WData* newvalp, int bits);
inline void emitFloat(vluint32_t code, float newval);
inline void emitDouble(vluint32_t code, double newval);
public:
@ -112,8 +111,6 @@ public:
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
void declArray(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
void declFloat(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum);
void declDouble(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum);
};

View File

@ -427,7 +427,8 @@ extern std::string VL_TOLOWER_NN(const std::string& ld);
extern std::string VL_TOUPPER_NN(const std::string& ld);
extern IData VL_FERROR_IN(IData fpi, std::string& outputr) VL_MT_SAFE;
extern IData VL_FOPEN_NI(const std::string& filename, IData mode) VL_MT_SAFE;
extern IData VL_FOPEN_NN(const std::string& filename, const std::string& mode) VL_MT_SAFE;
extern IData VL_FOPEN_MCD_N(const std::string& filename) VL_MT_SAFE;
extern void VL_READMEM_N(bool hex, int bits, QData depth, int array_lsb,
const std::string& filename, void* memp, QData start,
QData end) VL_MT_SAFE;

View File

@ -32,6 +32,7 @@
#include <deque>
#include <set>
#include <vector>
#include <numeric>
#ifdef VL_THREADED
# include <functional>
# include <queue>
@ -95,7 +96,7 @@ public:
// METHODS
//// Add message to queue (called by producer)
void post(const VerilatedMsg& msg) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard lock(m_mutex);
const VerilatedLockGuard lock(m_mutex);
m_queue.insert(msg); // Pass by value to copy the message into queue
++m_depth;
}
@ -168,6 +169,24 @@ public:
};
#endif // VL_THREADED
// FILE* list constructed from a file-descriptor
class VerilatedFpList {
FILE* m_fp[31];
std::size_t m_sz;
public:
typedef FILE* const* const_iterator;
explicit VerilatedFpList()
: m_sz(0) {}
const_iterator begin() const { return m_fp; }
const_iterator end() const { return m_fp + m_sz; }
std::size_t size() const { return m_sz; }
std::size_t capacity() const { return 31; }
void push_back(FILE* fd) {
if (VL_LIKELY(size() < capacity())) m_fp[m_sz++] = fd;
}
};
//======================================================================
// VerilatedImp
@ -229,17 +248,21 @@ protected:
VerilatedMutex m_fdMutex; ///< Protect m_fdps, m_fdFree
std::vector<FILE*> m_fdps VL_GUARDED_BY(m_fdMutex); ///< File descriptors
/// List of free descriptors (SLOW - FOPEN/CLOSE only)
std::deque<IData> m_fdFree VL_GUARDED_BY(m_fdMutex);
std::vector<IData> m_fdFree VL_GUARDED_BY(m_fdMutex);
// List of free descriptors in the MCT region [4, 32)
std::vector<IData> m_fdFreeMct VL_GUARDED_BY(m_fdMutex);
public: // But only for verilated*.cpp
// CONSTRUCTORS
VerilatedImp()
: m_argVecLoaded(false)
, m_exportNext(0) {
m_fdps.resize(3);
m_fdps[0] = stdin;
m_fdps[1] = stdout;
m_fdps[2] = stderr;
s_s.m_fdps.resize(31);
std::fill(s_s.m_fdps.begin(), s_s.m_fdps.end(), (FILE*)0);
s_s.m_fdFreeMct.resize(30);
for (std::size_t i = 0, id = 1; i < s_s.m_fdFreeMct.size(); ++i, ++id) {
s_s.m_fdFreeMct[i] = id;
}
}
~VerilatedImp() {}
@ -256,7 +279,7 @@ public:
static void commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex);
static void commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex);
static std::string argPlusMatch(const char* prefixp) VL_EXCLUDES(s_s.m_argMutex) {
VerilatedLockGuard lock(s_s.m_argMutex);
const VerilatedLockGuard lock(s_s.m_argMutex);
// Note prefixp does not include the leading "+"
size_t len = strlen(prefixp);
if (VL_UNLIKELY(!s_s.m_argVecLoaded)) {
@ -285,7 +308,7 @@ public:
// There's often many more scopes than userdata's and thus having a ~48byte
// per map overhead * N scopes would take much more space and cache thrashing.
static inline void userInsert(const void* scopep, void* userKey, void* userData) VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_userMapMutex);
const VerilatedLockGuard lock(s_s.m_userMapMutex);
UserMap::iterator it = s_s.m_userMap.find(std::make_pair(scopep, userKey));
if (it != s_s.m_userMap.end()) {
it->second = userData;
@ -294,7 +317,7 @@ public:
}
}
static inline void* userFind(const void* scopep, void* userKey) VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_userMapMutex);
const VerilatedLockGuard lock(s_s.m_userMapMutex);
UserMap::const_iterator it = s_s.m_userMap.find(std::make_pair(scopep, userKey));
if (VL_UNLIKELY(it == s_s.m_userMap.end())) return NULL;
return it->second;
@ -304,7 +327,7 @@ private:
/// Symbol table destruction cleans up the entries for each scope.
static void userEraseScope(const VerilatedScope* scopep) VL_MT_SAFE {
// Slow ok - called once/scope on destruction, so we simply iterate.
VerilatedLockGuard lock(s_s.m_userMapMutex);
const VerilatedLockGuard lock(s_s.m_userMapMutex);
for (UserMap::iterator it = s_s.m_userMap.begin(); it != s_s.m_userMap.end();) {
if (it->first.first == scopep) {
s_s.m_userMap.erase(it++);
@ -314,7 +337,7 @@ private:
}
}
static void userDump() VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_userMapMutex); // Avoid it changing in middle of dump
const VerilatedLockGuard lock(s_s.m_userMapMutex); // Avoid it changing in middle of dump
bool first = true;
for (UserMap::const_iterator it = s_s.m_userMap.begin(); it != s_s.m_userMap.end(); ++it) {
if (first) {
@ -330,14 +353,14 @@ public: // But only for verilated*.cpp
// METHODS - scope name
static void scopeInsert(const VerilatedScope* scopep) VL_MT_SAFE {
// Slow ok - called once/scope at construction
VerilatedLockGuard lock(s_s.m_nameMutex);
const VerilatedLockGuard lock(s_s.m_nameMutex);
VerilatedScopeNameMap::iterator it = s_s.m_nameMap.find(scopep->name());
if (it == s_s.m_nameMap.end()) {
s_s.m_nameMap.insert(it, std::make_pair(scopep->name(), scopep));
}
}
static inline const VerilatedScope* scopeFind(const char* namep) VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_nameMutex);
const VerilatedLockGuard lock(s_s.m_nameMutex);
// If too slow, can assume this is only VL_MT_SAFE_POSINIT
VerilatedScopeNameMap::const_iterator it = s_s.m_nameMap.find(namep);
if (VL_UNLIKELY(it == s_s.m_nameMap.end())) return NULL;
@ -345,13 +368,13 @@ public: // But only for verilated*.cpp
}
static void scopeErase(const VerilatedScope* scopep) VL_MT_SAFE {
// Slow ok - called once/scope at destruction
VerilatedLockGuard lock(s_s.m_nameMutex);
const VerilatedLockGuard lock(s_s.m_nameMutex);
userEraseScope(scopep);
VerilatedScopeNameMap::iterator it = s_s.m_nameMap.find(scopep->name());
if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it);
}
static void scopesDump() VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_nameMutex);
const VerilatedLockGuard lock(s_s.m_nameMutex);
VL_PRINTF_MT(" scopesDump:\n");
for (VerilatedScopeNameMap::const_iterator it = s_s.m_nameMap.begin();
it != s_s.m_nameMap.end(); ++it) {
@ -369,7 +392,7 @@ public: // But only for verilated*.cpp
// METHODS - hierarchy
static void hierarchyAdd(const VerilatedScope* fromp, const VerilatedScope* top) VL_MT_SAFE {
// Slow ok - called at construction for VPI accessible elements
VerilatedLockGuard lock(s_s.m_hierMapMutex);
const VerilatedLockGuard lock(s_s.m_hierMapMutex);
s_s.m_hierMap[fromp].push_back(top);
}
static const VerilatedHierarchyMap* hierarchyMap() VL_MT_SAFE_POSTINIT {
@ -388,7 +411,7 @@ public: // But only for verilated*.cpp
// miss at the cost of a multiply, and all lookups move to slowpath.
static int exportInsert(const char* namep) VL_MT_SAFE {
// Slow ok - called once/function at creation
VerilatedLockGuard lock(s_s.m_exportMutex);
const VerilatedLockGuard lock(s_s.m_exportMutex);
ExportNameMap::iterator it = s_s.m_exportMap.find(namep);
if (it == s_s.m_exportMap.end()) {
s_s.m_exportMap.insert(it, std::make_pair(namep, s_s.m_exportNext++));
@ -398,7 +421,7 @@ public: // But only for verilated*.cpp
}
}
static int exportFind(const char* namep) VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_exportMutex);
const VerilatedLockGuard lock(s_s.m_exportMutex);
ExportNameMap::const_iterator it = s_s.m_exportMap.find(namep);
if (VL_LIKELY(it != s_s.m_exportMap.end())) return it->second;
std::string msg = (std::string("%Error: Testbench C called ") + namep
@ -408,7 +431,7 @@ public: // But only for verilated*.cpp
}
static const char* exportName(int funcnum) VL_MT_SAFE {
// Slowpath; find name for given export; errors only so no map to reverse-map it
VerilatedLockGuard lock(s_s.m_exportMutex);
const VerilatedLockGuard lock(s_s.m_exportMutex);
for (ExportNameMap::const_iterator it = s_s.m_exportMap.begin();
it != s_s.m_exportMap.end(); ++it) {
if (it->second == funcnum) return it->first;
@ -416,7 +439,7 @@ public: // But only for verilated*.cpp
return "*UNKNOWN*";
}
static void exportsDump() VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_exportMutex);
const VerilatedLockGuard lock(s_s.m_exportMutex);
bool first = true;
for (ExportNameMap::const_iterator it = s_s.m_exportMap.begin();
it != s_s.m_exportMap.end(); ++it) {
@ -448,16 +471,29 @@ public: // But only for verilated*.cpp
public: // But only for verilated*.cpp
// METHODS - file IO
static IData fdNew(FILE* fp) VL_MT_SAFE {
static IData fdNewMcd(const char* filenamep) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_fdMutex);
if (s_s.m_fdFreeMct.empty()) return 0;
IData idx = s_s.m_fdFreeMct.back();
s_s.m_fdFreeMct.pop_back();
s_s.m_fdps[idx] = fopen(filenamep, "w");
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return 0;
return (1 << idx);
}
static IData fdNew(const char* filenamep, const char* modep) VL_MT_SAFE {
FILE* fp = fopen(filenamep, modep);
if (VL_UNLIKELY(!fp)) return 0;
// Bit 31 indicates it's a descriptor not a MCD
VerilatedLockGuard lock(s_s.m_fdMutex);
const VerilatedLockGuard lock(s_s.m_fdMutex);
if (s_s.m_fdFree.empty()) {
// Need to create more space in m_fdps and m_fdFree
size_t start = s_s.m_fdps.size();
s_s.m_fdps.resize(start * 2);
for (size_t i = start; i < start * 2; ++i) {
s_s.m_fdFree.push_back(static_cast<IData>(i));
const size_t start = std::max(31ul + 1ul + 3ul, s_s.m_fdps.size());
const size_t excess = 10;
s_s.m_fdps.resize(start + excess);
std::fill(s_s.m_fdps.begin() + start, s_s.m_fdps.end(), (FILE*)0);
s_s.m_fdFree.resize(excess);
for (std::size_t i = 0, id = start; i < s_s.m_fdFree.size(); ++i, ++id) {
s_s.m_fdFree[i] = id;
}
}
IData idx = s_s.m_fdFree.back();
@ -465,19 +501,83 @@ public: // But only for verilated*.cpp
s_s.m_fdps[idx] = fp;
return (idx | (1UL << 31)); // bit 31 indicates not MCD
}
static void fdDelete(IData fdi) VL_MT_SAFE {
IData idx = VL_MASK_I(31) & fdi;
VerilatedLockGuard lock(s_s.m_fdMutex);
if (VL_UNLIKELY(!(fdi & (VL_ULL(1) << 31)) || idx >= s_s.m_fdps.size())) return;
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free
s_s.m_fdps[idx] = NULL;
s_s.m_fdFree.push_back(idx);
static void fdFlush(IData fdi) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_fdMutex);
const VerilatedFpList fdlist = fdToFpList(fdi);
for (VerilatedFpList::const_iterator it = fdlist.begin(); it != fdlist.end(); ++it) {
fflush(*it);
}
}
static IData fdSeek(IData fdi, IData offset, IData origin) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_fdMutex);
const VerilatedFpList fdlist = fdToFpList(fdi);
if (VL_UNLIKELY(fdlist.size() != 1)) return 0;
return static_cast<IData>(
fseek(*fdlist.begin(), static_cast<long>(offset), static_cast<int>(origin)));
}
static IData fdTell(IData fdi) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_fdMutex);
const VerilatedFpList fdlist = fdToFpList(fdi);
if (VL_UNLIKELY(fdlist.size() != 1)) return 0;
return static_cast<IData>(ftell(*fdlist.begin()));
}
static void fdWrite(IData fdi, const std::string& output) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_fdMutex);
const VerilatedFpList fdlist = fdToFpList(fdi);
for (VerilatedFpList::const_iterator it = fdlist.begin(); it != fdlist.end(); ++it) {
if (VL_UNLIKELY(!*it)) continue;
fwrite(output.c_str(), 1, output.size(), *it);
}
}
static void fdClose(IData fdi) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_fdMutex);
if ((fdi & (1 << 31)) != 0) {
// Non-MCD case
IData idx = VL_MASK_I(31) & fdi;
if (VL_UNLIKELY(idx >= s_s.m_fdps.size())) return;
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free
fclose(s_s.m_fdps[idx]);
s_s.m_fdps[idx] = (FILE*)0;
s_s.m_fdFree.push_back(idx);
} else {
// MCD case
for (int i = 0; (fdi != 0) && (i < 31); i++, fdi >>= 1) {
if (fdi & VL_MASK_I(1)) {
fclose(s_s.m_fdps[i]);
s_s.m_fdps[i] = NULL;
s_s.m_fdFreeMct.push_back(i);
}
}
}
}
static inline FILE* fdToFp(IData fdi) VL_MT_SAFE {
IData idx = VL_MASK_I(31) & fdi;
VerilatedLockGuard lock(s_s.m_fdMutex); // This might get slow, if it does we can cache it
if (VL_UNLIKELY(!(fdi & (VL_ULL(1) << 31)) || idx >= s_s.m_fdps.size())) return NULL;
return s_s.m_fdps[idx];
const VerilatedLockGuard lock(s_s.m_fdMutex);
const VerilatedFpList fdlist = fdToFpList(fdi);
if (VL_UNLIKELY(fdlist.size() != 1)) return NULL;
return *fdlist.begin();
}
private:
static inline VerilatedFpList fdToFpList(IData fdi) VL_REQUIRES(s_s.m_fdMutex) {
VerilatedFpList fp;
if ((fdi & (1 << 31)) != 0) {
// Non-MCD case
const IData idx = fdi & VL_MASK_I(31);
switch (idx) {
case 0: fp.push_back(stdin); break;
case 1: fp.push_back(stdout); break;
case 2: fp.push_back(stderr); break;
default:
if (VL_LIKELY(idx < s_s.m_fdps.size())) fp.push_back(s_s.m_fdps[idx]);
break;
}
} else {
// MCD Case
for (int i = 0; (fdi != 0) && (i < fp.capacity()); ++i, fdi >>= 1) {
if (fdi & VL_MASK_I(1)) fp.push_back(s_s.m_fdps[i]);
}
}
return fp;
}
};

View File

@ -123,8 +123,8 @@ void VerilatedSave::open(const char* filenamep) VL_MT_UNSAFE_ONE {
if (isOpen()) return;
VL_DEBUG_IF(VL_DBG_MSGF("- save: opening save file %s\n", filenamep););
if (filenamep[0] == '|') {
assert(0); // Not supported yet.
if (VL_UNCOVERABLE(filenamep[0] == '|')) {
assert(0); // LCOV_EXCL_LINE // Not supported yet.
} else {
// cppcheck-suppress duplicateExpression
m_fd = ::open(filenamep,
@ -146,8 +146,8 @@ void VerilatedRestore::open(const char* filenamep) VL_MT_UNSAFE_ONE {
if (isOpen()) return;
VL_DEBUG_IF(VL_DBG_MSGF("- restore: opening restore file %s\n", filenamep););
if (filenamep[0] == '|') {
assert(0); // Not supported yet.
if (VL_UNCOVERABLE(filenamep[0] == '|')) {
assert(0); // LCOV_EXCL_LINE // Not supported yet.
} else {
// cppcheck-suppress duplicateExpression
m_fd = ::open(filenamep, O_CREAT | O_RDONLY | O_LARGEFILE | O_CLOEXEC, 0666);
@ -194,13 +194,15 @@ void VerilatedSave::flush() VL_MT_UNSAFE_ONE {
ssize_t got = ::write(m_fd, wp, remaining);
if (got > 0) {
wp += got;
} else if (got < 0) {
if (errno != EAGAIN && errno != EINTR) {
} else if (VL_UNCOVERABLE(got < 0)) {
if (VL_UNCOVERABLE(errno != EAGAIN && errno != EINTR)) {
// LCOV_EXCL_START
// write failed, presume error (perhaps out of disk space)
std::string msg = std::string(__FUNCTION__) + ": " + strerror(errno);
VL_FATAL_MT("", 0, "", msg.c_str());
close();
break;
// LCOV_EXCL_STOP
}
}
}
@ -223,13 +225,15 @@ void VerilatedRestore::fill() VL_MT_UNSAFE_ONE {
ssize_t got = ::read(m_fd, m_endp, remaining);
if (got > 0) {
m_endp += got;
} else if (got < 0) {
if (errno != EAGAIN && errno != EINTR) {
} else if (VL_UNCOVERABLE(got < 0)) {
if (VL_UNCOVERABLE(errno != EAGAIN && errno != EINTR)) {
// LCOV_EXCL_START
// write failed, presume error (perhaps out of disk space)
std::string msg = std::string(__FUNCTION__) + ": " + strerror(errno);
VL_FATAL_MT("", 0, "", msg.c_str());
close();
break;
// LCOV_EXCL_STOP
}
} else { // got==0, EOF
// Fill buffer from here to end with NULLs so reader's don't

View File

@ -29,6 +29,8 @@
#include "verilatedos.h"
#include <vector>
//===========================================================================
/// Verilator range
/// Thread safety: Assume is constructed only with model, then any number of readers
@ -78,7 +80,14 @@ class VerilatedVarProps {
const int m_pdims; // Packed dimensions
const int m_udims; // Unpacked dimensions
VerilatedRange m_packed; // Packed array range
VerilatedRange m_unpacked[3]; // Unpacked array range
std::vector<VerilatedRange> m_unpacked; // Unpacked array ranges
void initUnpacked(const int* ulims) {
for (int i = 0; i < m_udims; ++i) {
const int left = ulims ? ulims[2 * i + 0] : 0;
const int right = ulims ? ulims[2 * i + 1] : 0;
m_unpacked.push_back(VerilatedRange(left, right));
}
}
// CONSTRUCTORS
protected:
friend class VerilatedScope;
@ -87,7 +96,9 @@ protected:
, m_vltype(vltype)
, m_vlflags(vlflags)
, m_pdims(pdims)
, m_udims(udims) {}
, m_udims(udims) {
initUnpacked(NULL);
}
public:
class Unpacked {};
@ -98,34 +109,13 @@ public:
, m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(0)
, m_udims(0) {}
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int u0l, int u0r)
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int udims, const int* ulims)
: m_magic(MAGIC)
, m_vltype(vltype)
, m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(0)
, m_udims(1) {
m_unpacked[0].init(u0l, u0r);
}
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int u0l, int u0r, int u1l,
int u1r)
: m_magic(MAGIC)
, m_vltype(vltype)
, m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(0)
, m_udims(2) {
m_unpacked[0].init(u0l, u0r);
m_unpacked[1].init(u1l, u1r);
}
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int u0l, int u0r, int u1l,
int u1r, int u2l, int u2r)
: m_magic(MAGIC)
, m_vltype(vltype)
, m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(0)
, m_udims(3) {
m_unpacked[0].init(u0l, u0r);
m_unpacked[1].init(u1l, u1r);
m_unpacked[2].init(u2l, u2r);
, m_udims(udims) {
initUnpacked(ulims);
}
// With packed
class Packed {};
@ -137,37 +127,14 @@ public:
, m_udims(0)
, m_packed(pl, pr) {}
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked,
int u0l, int u0r)
int udims, const int* ulims)
: m_magic(MAGIC)
, m_vltype(vltype)
, m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(1)
, m_udims(1)
, m_udims(udims)
, m_packed(pl, pr) {
m_unpacked[0].init(u0l, u0r);
}
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked,
int u0l, int u0r, int u1l, int u1r)
: m_magic(MAGIC)
, m_vltype(vltype)
, m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(1)
, m_udims(2)
, m_packed(pl, pr) {
m_unpacked[0].init(u0l, u0r);
m_unpacked[1].init(u1l, u1r);
}
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked,
int u0l, int u0r, int u1l, int u1r, int u2l, int u2r)
: m_magic(MAGIC)
, m_vltype(vltype)
, m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(1)
, m_udims(3)
, m_packed(pl, pr) {
m_unpacked[0].init(u0l, u0r);
m_unpacked[1].init(u1l, u1r);
m_unpacked[2].init(u2l, u2r);
initUnpacked(ulims);
}
public:
@ -189,27 +156,29 @@ public:
// DPI accessors
int left(int dim) const {
return dim == 0 ? m_packed.left()
: VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].left() : 0;
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].left() : 0;
}
int right(int dim) const {
return dim == 0 ? m_packed.right()
: VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].right() : 0;
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].right() : 0;
}
int low(int dim) const {
return dim == 0 ? m_packed.low()
: VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].low() : 0;
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].low() : 0;
}
int high(int dim) const {
return dim == 0 ? m_packed.high()
: VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].high() : 0;
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].high() : 0;
}
int increment(int dim) const {
return dim == 0 ? m_packed.increment()
: VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].increment() : 0;
return dim == 0
? m_packed.increment()
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].increment() : 0;
}
int elements(int dim) const {
return dim == 0 ? m_packed.elements()
: VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].elements() : 0;
return dim == 0
? m_packed.elements()
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].elements() : 0;
}
/// Total size in bytes (note DPI limited to 4GB)
size_t totalSize() const;

View File

@ -120,13 +120,13 @@ void VlThreadPool::setupProfilingClientThread() {
// try not to malloc while collecting profiling.
t_profilep->reserve(4096);
{
VerilatedLockGuard lk(m_mutex);
const VerilatedLockGuard lk(m_mutex);
m_allProfiles.insert(t_profilep);
}
}
void VlThreadPool::profileAppendAll(const VlProfileRec& rec) {
VerilatedLockGuard lk(m_mutex);
const VerilatedLockGuard lk(m_mutex);
for (ProfileSet::iterator it = m_allProfiles.begin(); it != m_allProfiles.end(); ++it) {
// Every thread's profile trace gets a copy of rec.
(*it)->emplace_back(rec);
@ -134,7 +134,7 @@ void VlThreadPool::profileAppendAll(const VlProfileRec& rec) {
}
void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed) {
VerilatedLockGuard lk(m_mutex);
const VerilatedLockGuard lk(m_mutex);
VL_DEBUG_IF(VL_DBG_MSGF("+prof+threads writing to '%s'\n", filenamep););
FILE* fp = fopen(filenamep, "w");

View File

@ -234,7 +234,7 @@ public:
inline void addTask(VlExecFnp fnp, bool evenCycle, VlThrSymTab sym) {
bool notify;
{
VerilatedLockGuard lk(m_mutex);
const VerilatedLockGuard lk(m_mutex);
m_ready.emplace_back(fnp, evenCycle, sym);
m_ready_size.fetch_add(1, std::memory_order_relaxed);
notify = m_waiting;

View File

@ -40,7 +40,7 @@
// Threaded tracing
// A simple synchronized first in first out queue
template <class T> class VerilatedThreadQueue {
template <class T> class VerilatedThreadQueue { // LCOV_EXCL_LINE // lcov bug
private:
VerilatedMutex m_mutex; // Protects m_queue
std::condition_variable_any m_cv;
@ -73,7 +73,7 @@ public:
// Non blocking get
bool tryGet(T& result) {
VerilatedLockGuard lockGuard(m_mutex);
const VerilatedLockGuard lockGuard(m_mutex);
if (m_queue.empty()) { return false; }
result = m_queue.front();
m_queue.pop_front();
@ -95,7 +95,6 @@ public:
CHG_IDATA = 0x4,
CHG_QDATA = 0x5,
CHG_WDATA = 0x6,
CHG_FLOAT = 0x7,
CHG_DOUBLE = 0x8,
// TODO: full..
TIME_CHANGE = 0xd,
@ -105,8 +104,6 @@ public:
};
#endif
class VerilatedTraceCallInfo;
//=============================================================================
// VerilatedTrace
@ -114,13 +111,38 @@ class VerilatedTraceCallInfo;
// implementations in the format specific derived class, which must be passed
// as the type parameter T_Derived
template <class T_Derived> class VerilatedTrace {
private:
public:
//=========================================================================
// Generic tracing internals
typedef void (*initCb_t)(void*, T_Derived*, uint32_t); // Type of init callbacks
typedef void (*dumpCb_t)(void*, T_Derived*); // Type of all but init callbacks
private:
struct CallbackRecord {
// Note: would make these fields const, but some old STL implementations
// (the one in Ubuntu 14.04 with GCC 4.8.4 in particular) use the
// assignment operator on inserting into collections, so they don't work
// with const fields...
union {
initCb_t m_initCb; // The callback function
dumpCb_t m_dumpCb; // The callback function
};
void* m_userp; // The user pointer to pass to the callback (the symbol table)
CallbackRecord(initCb_t cb, void* userp)
: m_initCb(cb)
, m_userp(userp) {}
CallbackRecord(dumpCb_t cb, void* userp)
: m_dumpCb(cb)
, m_userp(userp) {}
};
vluint32_t* m_sigs_oldvalp; ///< Old value store
vluint64_t m_timeLastDump; ///< Last time we did a dump
std::vector<VerilatedTraceCallInfo*> m_callbacks; ///< Routines to perform dumping
std::vector<CallbackRecord> m_initCbs; ///< Routines to initialize traciong
std::vector<CallbackRecord> m_fullCbs; ///< Routines to perform full dump
std::vector<CallbackRecord> m_chgCbs; ///< Routines to perform incremental dump
std::vector<CallbackRecord> m_cleanupCbs; ///< Routines to call at the end of dump
bool m_fullDump; ///< Whether a full dump is required on the next call to 'dump'
vluint32_t m_nextCode; ///< Next code number to assign
vluint32_t m_numSignals; ///< Number of distinct signals
@ -130,6 +152,8 @@ private:
double m_timeRes; ///< Time resolution (ns/ms etc)
double m_timeUnit; ///< Time units (ns/ms etc)
void addCallbackRecord(std::vector<CallbackRecord>& cbVec, CallbackRecord& cbRec);
// Equivalent to 'this' but is of the sub-type 'T_Derived*'. Use 'self()->'
// to access duck-typed functions to avoid a virtual function call.
T_Derived* self() { return static_cast<T_Derived*>(this); }
@ -209,8 +233,8 @@ protected:
// These hooks are called before a full or change based dump is produced.
// The return value indicates whether to proceed with the dump.
virtual bool preFullDump() { return true; }
virtual bool preChangeDump() { return true; }
virtual bool preFullDump() = 0;
virtual bool preChangeDump() = 0;
public:
//=========================================================================
@ -232,13 +256,13 @@ public:
//=========================================================================
// Non-hot path internal interface to Verilator generated code
typedef void (*callback_t)(T_Derived* tracep, void* userthis, vluint32_t code);
void addInitCb(initCb_t cb, void* userp) VL_MT_UNSAFE_ONE;
void addFullCb(dumpCb_t cb, void* userp) VL_MT_UNSAFE_ONE;
void addChgCb(dumpCb_t cb, void* userp) VL_MT_UNSAFE_ONE;
void addCleanupCb(dumpCb_t cb, void* userp) VL_MT_UNSAFE_ONE;
void changeThread() { m_assertOne.changeThread(); }
void addCallback(callback_t initcb, callback_t fullcb, callback_t changecb,
void* userthis) VL_MT_UNSAFE_ONE;
void module(const std::string& name) VL_MT_UNSAFE_ONE {
m_assertOne.check();
m_moduleName = name;
@ -261,7 +285,6 @@ public:
// duck-typed void emitIData(vluint32_t code, IData newval, int bits) = 0;
// duck-typed void emitQData(vluint32_t code, QData newval, int bits) = 0;
// duck-typed void emitWData(vluint32_t code, const WData* newvalp, int bits) = 0;
// duck-typed void emitFloat(vluint32_t code, float newval) = 0;
// duck-typed void emitDouble(vluint32_t code, double newval) = 0;
vluint32_t* oldp(vluint32_t code) { return m_sigs_oldvalp + code; }
@ -273,7 +296,6 @@ public:
void fullIData(vluint32_t* oldp, IData newval, int bits);
void fullQData(vluint32_t* oldp, QData newval, int bits);
void fullWData(vluint32_t* oldp, const WData* newvalp, int bits);
void fullFloat(vluint32_t* oldp, float newval);
void fullDouble(vluint32_t* oldp, double newval);
#ifdef VL_TRACE_THREADED
@ -319,14 +341,6 @@ public:
for (int i = 0; i < (bits + 31) / 32; ++i) { *m_traceBufferWritep++ = newvalp[i]; }
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp););
}
inline void chgFloat(vluint32_t code, float newval) {
m_traceBufferWritep[0] = VerilatedTraceCommand::CHG_FLOAT;
m_traceBufferWritep[1] = code;
// cppcheck-suppress invalidPointerCast
*reinterpret_cast<float*>(m_traceBufferWritep + 2) = newval;
m_traceBufferWritep += 3;
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp););
}
inline void chgDouble(vluint32_t code, double newval) {
m_traceBufferWritep[0] = VerilatedTraceCommand::CHG_DOUBLE;
m_traceBufferWritep[1] = code;
@ -374,10 +388,6 @@ public:
}
}
}
inline void CHG(Float)(vluint32_t* oldp, float newval) {
// cppcheck-suppress invalidPointerCast
if (VL_UNLIKELY(*reinterpret_cast<float*>(oldp) != newval)) fullFloat(oldp, newval);
}
inline void CHG(Double)(vluint32_t* oldp, double newval) {
// cppcheck-suppress invalidPointerCast
if (VL_UNLIKELY(*reinterpret_cast<double*>(oldp) != newval)) fullDouble(oldp, newval);

View File

@ -39,7 +39,7 @@
// Static utility functions
static double timescaleToDouble(const char* unitp) {
char* endp;
char* endp = NULL;
double value = strtod(unitp, &endp);
// On error so we allow just "ns" to return 1e-9.
if (value == 0.0 && endp == unitp) value = 1;
@ -73,31 +73,6 @@ static std::string doubleToTimescale(double value) {
return valuestr; // Gets converted to string, so no ref to stack
}
//=============================================================================
// Internal callback routines for each module being traced.
// Each module that wishes to be traced registers a set of callbacks stored in
// this class. When the trace file is being constructed, this class provides
// the callback routines to be executed.
class VerilatedTraceCallInfo {
public: // This is in .cpp file so is not widely visible
typedef VerilatedTrace<VL_DERIVED_T>::callback_t callback_t;
callback_t m_initcb; ///< Initialization Callback function
callback_t m_fullcb; ///< Full Dumping Callback function
callback_t m_changecb; ///< Incremental Dumping Callback function
void* m_userthis; ///< User data pointer for callback
vluint32_t m_code; ///< Starting code number (set later by traceInit)
// CONSTRUCTORS
VerilatedTraceCallInfo(callback_t icb, callback_t fcb, callback_t changecb, void* ut)
: m_initcb(icb)
, m_fullcb(fcb)
, m_changecb(changecb)
, m_userthis(ut)
, m_code(1) {}
~VerilatedTraceCallInfo() {}
};
#ifdef VL_TRACE_THREADED
//=========================================================================
// Buffer management
@ -196,11 +171,6 @@ template <> void VerilatedTrace<VL_DERIVED_T>::workerThreadMain() {
chgWDataImpl(oldp, readp, top);
readp += VL_WORDS_I(top);
continue;
case VerilatedTraceCommand::CHG_FLOAT:
VL_TRACE_THREAD_DEBUG("Command CHG_FLOAT " << top);
chgFloatImpl(oldp, *reinterpret_cast<const float*>(readp));
readp += 1;
continue;
case VerilatedTraceCommand::CHG_DOUBLE:
VL_TRACE_THREAD_DEBUG("Command CHG_DOUBLE " << top);
chgDoubleImpl(oldp, *reinterpret_cast<const double*>(readp));
@ -224,13 +194,14 @@ template <> void VerilatedTrace<VL_DERIVED_T>::workerThreadMain() {
shutdown = true;
break;
//===
// Unknown command
default:
//===
// Unknown command
default: { // LCOV_EXCL_START
VL_TRACE_THREAD_DEBUG("Command UNKNOWN");
VL_PRINTF_MT("Trace command: 0x%08x\n", cmd);
VL_FATAL_MT(__FILE__, __LINE__, "", "Unknown trace command");
break;
} // LCOV_EXCL_STOP
}
// The above switch will execute 'continue' when necessary,
@ -311,10 +282,6 @@ VerilatedTrace<VL_DERIVED_T>::VerilatedTrace()
template <> VerilatedTrace<VL_DERIVED_T>::~VerilatedTrace() {
if (m_sigs_oldvalp) VL_DO_CLEAR(delete[] m_sigs_oldvalp, m_sigs_oldvalp = NULL);
while (!m_callbacks.empty()) {
delete m_callbacks.back();
m_callbacks.pop_back();
}
#ifdef VL_TRACE_THREADED
close();
#endif
@ -334,11 +301,12 @@ template <> void VerilatedTrace<VL_DERIVED_T>::traceInit() VL_MT_UNSAFE {
m_numSignals = 0;
m_maxBits = 0;
// Call all initialize callbacks, which will call decl* for each signal.
for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) {
VerilatedTraceCallInfo* cip = m_callbacks[ent];
cip->m_code = nextCode();
(cip->m_initcb)(self(), cip->m_userthis, cip->m_code);
// Call all initialize callbacks, which will:
// - Call decl* for each signal
// - Store the base code
for (vluint32_t i = 0; i < m_initCbs.size(); ++i) {
const CallbackRecord& cbr = m_initCbs[i];
cbr.m_initCb(cbr.m_userp, self(), nextCode());
}
if (expectedCodes && nextCode() != expectedCodes) {
@ -409,12 +377,12 @@ template <> void VerilatedTrace<VL_DERIVED_T>::set_time_resolution(const std::st
template <> void VerilatedTrace<VL_DERIVED_T>::dump(vluint64_t timeui) {
m_assertOne.check();
if (VL_UNLIKELY(m_timeLastDump && timeui <= m_timeLastDump)) {
if (VL_UNCOVERABLE(m_timeLastDump && timeui <= m_timeLastDump)) { // LCOV_EXCL_START
VL_PRINTF_MT("%%Warning: previous dump at t=%" VL_PRI64 "u, requesting t=%" VL_PRI64
"u, dump call ignored\n",
m_timeLastDump, timeui);
return;
}
} // LCOV_EXCL_STOP
m_timeLastDump = timeui;
Verilated::quiesce();
@ -452,17 +420,22 @@ template <> void VerilatedTrace<VL_DERIVED_T>::dump(vluint64_t timeui) {
// Run the callbacks
if (VL_UNLIKELY(m_fullDump)) {
m_fullDump = false; // No more need for next dump to be full
for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) {
VerilatedTraceCallInfo* cip = m_callbacks[ent];
(cip->m_fullcb)(self(), cip->m_userthis, cip->m_code);
for (vluint32_t i = 0; i < m_fullCbs.size(); ++i) {
const CallbackRecord& cbr = m_fullCbs[i];
cbr.m_dumpCb(cbr.m_userp, self());
}
} else {
for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) {
VerilatedTraceCallInfo* cip = m_callbacks[ent];
(cip->m_changecb)(self(), cip->m_userthis, cip->m_code);
for (vluint32_t i = 0; i < m_chgCbs.size(); ++i) {
const CallbackRecord& cbr = m_chgCbs[i];
cbr.m_dumpCb(cbr.m_userp, self());
}
}
for (vluint32_t i = 0; i < m_cleanupCbs.size(); ++i) {
const CallbackRecord& cbr = m_cleanupCbs[i];
cbr.m_dumpCb(cbr.m_userp, self());
}
#ifdef VL_TRACE_THREADED
if (VL_LIKELY(bufferp)) {
// Mark end of the trace buffer we just filled
@ -481,17 +454,32 @@ template <> void VerilatedTrace<VL_DERIVED_T>::dump(vluint64_t timeui) {
// Non-hot path internal interface to Verilator generated code
template <>
void VerilatedTrace<VL_DERIVED_T>::addCallback(callback_t initcb, callback_t fullcb,
callback_t changecb,
void* userthis) VL_MT_UNSAFE_ONE {
void VerilatedTrace<VL_DERIVED_T>::addCallbackRecord(std::vector<CallbackRecord>& cbVec,
CallbackRecord& cbRec) {
m_assertOne.check();
if (VL_UNLIKELY(timeLastDump() != 0)) {
if (VL_UNCOVERABLE(timeLastDump() != 0)) { // LCOV_EXCL_START
std::string msg = (std::string("Internal: ") + __FILE__ + "::" + __FUNCTION__
+ " called with already open file");
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
}
VerilatedTraceCallInfo* cip = new VerilatedTraceCallInfo(initcb, fullcb, changecb, userthis);
m_callbacks.push_back(cip);
} // LCOV_EXCL_STOP
cbVec.push_back(cbRec);
}
template <> void VerilatedTrace<VL_DERIVED_T>::addInitCb(initCb_t cb, void* userp) {
CallbackRecord cbr(cb, userp);
addCallbackRecord(m_initCbs, cbr);
}
template <> void VerilatedTrace<VL_DERIVED_T>::addFullCb(dumpCb_t cb, void* userp) {
CallbackRecord cbr(cb, userp);
addCallbackRecord(m_fullCbs, cbr);
}
template <> void VerilatedTrace<VL_DERIVED_T>::addChgCb(dumpCb_t cb, void* userp) {
CallbackRecord cbr(cb, userp);
addCallbackRecord(m_chgCbs, cbr);
}
template <> void VerilatedTrace<VL_DERIVED_T>::addCleanupCb(dumpCb_t cb, void* userp) {
CallbackRecord cbr(cb, userp);
addCallbackRecord(m_cleanupCbs, cbr);
}
//=========================================================================
@ -537,12 +525,6 @@ void VerilatedTrace<VL_DERIVED_T>::fullWData(vluint32_t* oldp, const WData* newv
self()->emitWData(oldp - m_sigs_oldvalp, newvalp, bits);
}
template <> void VerilatedTrace<VL_DERIVED_T>::fullFloat(vluint32_t* oldp, float newval) {
// cppcheck-suppress invalidPointerCast
*reinterpret_cast<float*>(oldp) = newval;
self()->emitFloat(oldp - m_sigs_oldvalp, newval);
}
template <> void VerilatedTrace<VL_DERIVED_T>::fullDouble(vluint32_t* oldp, double newval) {
// cppcheck-suppress invalidPointerCast
*reinterpret_cast<double*>(oldp) = newval;

View File

@ -31,8 +31,8 @@
//
//*************************************************************************
#ifndef _V3_UNORDERED_SET_MAP_H_
#define _V3_UNORDERED_SET_MAP_H_
#ifndef _VERILATED_UNORDERED_SET_MAP_H_
#define _VERILATED_UNORDERED_SET_MAP_H_
#include "verilatedos.h"
@ -55,6 +55,12 @@ inline size_t vl_hash_bytes(const void* vbufp, size_t nbytes) {
return hash;
}
template <> inline size_t vl_hash<int>::operator()(const int& k) const { return k; }
template <> inline bool vl_equal_to<int>::operator()(const int& a, const int& b) const {
return a == b;
}
template <> inline size_t vl_hash<unsigned int>::operator()(const unsigned int& k) const {
return k;
}
@ -225,8 +231,7 @@ public:
return end();
}
const_iterator end() const {
return iterator(VL_ULL(0xFFFFFFFFFFFFFFFF), const_cast<Bucket&>(m_emptyBucket).begin(),
this);
return iterator(0xFFFFFFFFFFFFFFFFULL, const_cast<Bucket&>(m_emptyBucket).begin(), this);
}
bool empty() const { return m_numElements == 0; }
@ -249,8 +254,7 @@ public:
// function further. This permits the use of very fast client
// hash funcs (like just returning the int or pointer value as
// is!) and tolerates crappy client hash functions pretty well.
size_t mult
= hashVal * ((sizeof(size_t) == 8) ? VL_ULL(11400714819323198485) : 2654435769lu);
size_t mult = hashVal * ((sizeof(size_t) == 8) ? 11400714819323198485ULL : 2654435769lu);
size_t result = (mult >> (((sizeof(size_t) == 8) ? 64 : 32) - log2Buckets));
return result;
}
@ -339,7 +343,7 @@ public:
}
private:
size_t numBuckets() const { return (VL_ULL(1) << m_log2Buckets); }
size_t numBuckets() const { return (1ULL << m_log2Buckets); }
Bucket* getBucket(size_t idx) {
initBuckets();
@ -372,7 +376,7 @@ private:
new_log2Buckets = m_log2Buckets - 2;
}
size_t new_num_buckets = VL_ULL(1) << new_log2Buckets;
size_t new_num_buckets = 1ULL << new_log2Buckets;
Bucket* new_bucketsp = new Bucket[new_num_buckets];
for (size_t i = 0; i < numBuckets(); i++) {

View File

@ -27,7 +27,6 @@
#include <cerrno>
#include <ctime>
#include <fcntl.h>
#include <sys/stat.h>
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
# include <io.h>
@ -35,8 +34,6 @@
# include <unistd.h>
#endif
#include "verilated_intrinsics.h"
// SPDIFF_ON
#ifndef O_LARGEFILE // For example on WIN32
@ -88,11 +85,11 @@ private:
public:
static void pushVcd(VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
VerilatedLockGuard lock(singleton().s_vcdMutex);
const VerilatedLockGuard lock(singleton().s_vcdMutex);
singleton().s_vcdVecp.push_back(vcdp);
}
static void removeVcd(const VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
VerilatedLockGuard lock(singleton().s_vcdMutex);
const VerilatedLockGuard lock(singleton().s_vcdMutex);
VcdVec::iterator pos
= find(singleton().s_vcdVecp.begin(), singleton().s_vcdVecp.end(), vcdp);
if (pos != singleton().s_vcdVecp.end()) { singleton().s_vcdVecp.erase(pos); }
@ -101,7 +98,7 @@ public:
// Thread safety: Although this function is protected by a mutex so
// perhaps in the future we can allow tracing in separate threads,
// vcdp->flush() assumes call from single thread
VerilatedLockGuard lock(singleton().s_vcdMutex);
const VerilatedLockGuard lock(singleton().s_vcdMutex);
for (VcdVec::const_iterator it = singleton().s_vcdVecp.begin();
it != singleton().s_vcdVecp.end(); ++it) {
VerilatedVcd* vcdp = *it;
@ -203,8 +200,8 @@ void VerilatedVcd::openNext(bool incFilename) {
}
m_filename = name;
}
if (m_filename[0] == '|') {
assert(0); // Not supported yet.
if (VL_UNCOVERABLE(m_filename[0] == '|')) {
assert(0); // LCOV_EXCL_LINE // Not supported yet.
} else {
// cppcheck-suppress duplicateExpression
if (!m_filep->open(m_filename)) {
@ -358,13 +355,15 @@ void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE {
if (got > 0) {
wp += got;
m_wroteBytes += got;
} else if (got < 0) {
if (errno != EAGAIN && errno != EINTR) {
} else if (VL_UNCOVERABLE(got < 0)) {
if (VL_UNCOVERABLE(errno != EAGAIN && errno != EINTR)) {
// LCOV_EXCL_START
// write failed, presume error (perhaps out of disk space)
std::string msg = std::string("VerilatedVcd::bufferFlush: ") + strerror(errno);
VL_FATAL_MT("", 0, "", msg.c_str());
closeErr();
break;
// LCOV_EXCL_STOP
}
}
}
@ -583,9 +582,6 @@ void VerilatedVcd::declArray(vluint32_t code, const char* name, bool array, int
int lsb) {
declare(code, name, "wire", array, arraynum, false, true, msb, lsb);
}
void VerilatedVcd::declFloat(vluint32_t code, const char* name, bool array, int arraynum) {
declare(code, name, "real", array, arraynum, false, false, 31, 0);
}
void VerilatedVcd::declDouble(vluint32_t code, const char* name, bool array, int arraynum) {
declare(code, name, "real", array, arraynum, false, false, 63, 0);
}
@ -699,15 +695,6 @@ void VerilatedVcd::emitWData(vluint32_t code, const WData* newvalp, int bits) {
finishLine(code, wp);
}
VL_ATTR_ALWINLINE
void VerilatedVcd::emitFloat(vluint32_t code, float newval) {
char* wp = m_writep;
// Buffer can't overflow before sprintf; we sized during declaration
sprintf(wp, "r%.16g", static_cast<double>(newval));
wp += strlen(wp);
finishLine(code, wp);
}
VL_ATTR_ALWINLINE
void VerilatedVcd::emitDouble(vluint32_t code, double newval) {
char* wp = m_writep;
@ -742,7 +729,7 @@ void VerilatedVcd::fullQuad(vluint32_t code, const vluint64_t newval, int bits)
(*(reinterpret_cast<vluint64_t*>(oldp(code)))) = newval;
*m_writep++ = 'b';
for (int bit = bits - 1; bit >= 0; --bit) {
*m_writep++ = ((newval & (VL_ULL(1) << bit)) ? '1' : '0');
*m_writep++ = ((newval & (1ULL << bit)) ? '1' : '0');
}
*m_writep++ = ' ';
m_writep = writeCode(m_writep, code);
@ -764,7 +751,7 @@ void VerilatedVcd::fullArray(vluint32_t code, const vluint64_t* newval, int bits
for (int word = 0; word < (((bits - 1) / 64) + 1); ++word) { oldp(code)[word] = newval[word]; }
*m_writep++ = 'b';
for (int bit = bits - 1; bit >= 0; --bit) {
*m_writep++ = ((newval[(bit / 64)] & (VL_ULL(1) << (bit & 0x3f))) ? '1' : '0');
*m_writep++ = ((newval[(bit / 64)] & (1ULL << (bit & 0x3f))) ? '1' : '0');
}
*m_writep++ = ' ';
m_writep = writeCode(m_writep, code);
@ -792,14 +779,13 @@ void VerilatedVcd::fullTriBus(vluint32_t code, const vluint32_t newval, const vl
*m_writep++ = '\n';
bufferCheck();
}
void VerilatedVcd::fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri,
void VerilatedVcd::fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint64_t newtri,
int bits) {
(*(reinterpret_cast<vluint64_t*>(oldp(code)))) = newval;
(*(reinterpret_cast<vluint64_t*>(oldp(code + 1)))) = newtri;
*m_writep++ = 'b';
for (int bit = bits - 1; bit >= 0; --bit) {
*m_writep++
= "01zz"[((newval >> bit) & VL_ULL(1)) | (((newtri >> bit) & VL_ULL(1)) << VL_ULL(1))];
*m_writep++ = "01zz"[((newval >> bit) & 1ULL) | (((newtri >> bit) & 1ULL) << 1ULL)];
}
*m_writep++ = ' ';
m_writep = writeCode(m_writep, code);
@ -834,33 +820,6 @@ void VerilatedVcd::fullDouble(vluint32_t code, const double newval) {
*m_writep++ = '\n';
bufferCheck();
}
void VerilatedVcd::fullFloat(vluint32_t code, const float newval) {
// cppcheck-suppress invalidPointerCast
(*(reinterpret_cast<float*>(oldp(code)))) = newval;
// Buffer can't overflow before sprintf; we sized during declaration
sprintf(m_writep, "r%.16g", static_cast<double>(newval));
m_writep += strlen(m_writep);
*m_writep++ = ' ';
m_writep = writeCode(m_writep, code);
*m_writep++ = '\n';
bufferCheck();
}
void VerilatedVcd::fullBitX(vluint32_t code) {
*m_writep++ = 'x';
m_writep = writeCode(m_writep, code);
*m_writep++ = '\n';
bufferCheck();
}
void VerilatedVcd::fullBusX(vluint32_t code, int bits) {
*m_writep++ = 'b';
for (int bit = bits - 1; bit >= 0; --bit) *m_writep++ = 'x';
*m_writep++ = ' ';
m_writep = writeCode(m_writep, code);
*m_writep++ = '\n';
bufferCheck();
}
void VerilatedVcd::fullQuadX(vluint32_t code, int bits) { fullBusX(code, bits); }
void VerilatedVcd::fullArrayX(vluint32_t code, int bits) { fullBusX(code, bits); }
#endif // VL_TRACE_VCD_OLD_API
@ -873,8 +832,6 @@ void VerilatedVcd::flush_all() VL_MT_UNSAFE_ONE { VerilatedVcdSingleton::flush_a
//======================================================================
//======================================================================
// clang-format off
#ifdef VERILATED_VCD_TEST
#include <iostream>
@ -882,34 +839,39 @@ vluint32_t v1, v2, s1, s2[3];
vluint32_t tri96[3];
vluint32_t tri96__tri[3];
vluint64_t quad96[2];
vluint64_t tquad;
vluint64_t tquad__tri;
vluint8_t ch;
vluint64_t timestamp = 1;
double doub = 0;
double doub = 0.0;
float flo = 0.0f;
void vcdInit(VerilatedVcd* vcdp, void* userthis, vluint32_t code) {
void vcdInit(void*, VerilatedVcd* vcdp, vluint32_t) {
vcdp->scopeEscape('.');
vcdp->module("top");
vcdp->declBus(0x2, "v1",-1,5,1);
vcdp->declBus(0x3, "v2",-1,6,0);
vcdp->module("top.sub1");
vcdp->declBit(0x4, "s1",-1);
vcdp->declBit(0x5, "ch",-1);
vcdp->module("top.sub2");
vcdp->declArray(0x6, "s2",-1, 40,3);
/**/ vcdp->declBus(0x2, "v1", -1, 0, 5, 1);
/**/ vcdp->declBus(0x3, "v2", -1, 0, 6, 1);
/**/ vcdp->module("top.sub1");
/***/ vcdp->declBit(0x4, "s1", -1, 0);
/***/ vcdp->declBit(0x5, "ch", -1, 0);
/**/ vcdp->module("top.sub2");
/***/ vcdp->declArray(0x6, "s2", -1, 0, 40, 3);
// Note need to add 3 for next code.
vcdp->module("top2");
vcdp->declBus(0x2, "t2v1",-1,4,1);
vcdp->declTriBit(0x10, "io1",-1);
vcdp->declTriBus(0x12, "io5",-1,4,0);
vcdp->declTriArray(0x16, "io96",-1,95,0);
// Note need to add 6 for next code.
vcdp->declDouble(0x1c, "doub",-1);
// Note need to add 2 for next code.
vcdp->declArray(0x1e, "q2",-1,95,0);
// Note need to add 4 for next code.
/**/ vcdp->declBus(0x2, "t2v1", -1, 0, 4, 1);
/**/ vcdp->declTriBit(0x10, "io1", -1, 0);
/**/ vcdp->declTriBus(0x12, "io5", -1, 0, 4, 0);
/**/ vcdp->declTriArray(0x16, "io96", -1, 0, 95, 0);
/**/ // Note need to add 6 for next code.
/**/ vcdp->declDouble(0x1c, "doub", -1, 0);
/**/ // Note need to add 2 for next code.
/**/ vcdp->declArray(0x20, "q2", -1, 0, 95, 0);
/**/ // Note need to add 4 for next code.
/**/ vcdp->declTriQuad(0x24, "tq", -1, 0, 63, 0);
/**/ // Note need to add 4 for next code.
}
void vcdFull(VerilatedVcd* vcdp, void* userthis, vluint32_t code) {
void vcdFull(void*, VerilatedVcd* vcdp) {
vcdp->fullBus(0x2, v1, 5);
vcdp->fullBus(0x3, v2, 7);
vcdp->fullBit(0x4, s1);
@ -919,10 +881,11 @@ void vcdFull(VerilatedVcd* vcdp, void* userthis, vluint32_t code) {
vcdp->fullTriBus(0x12, tri96[0] & 0x1f, tri96__tri[0] & 0x1f, 5);
vcdp->fullTriArray(0x16, tri96, tri96__tri, 96);
vcdp->fullDouble(0x1c, doub);
vcdp->fullArray(0x1e, &quad96[0], 96);
vcdp->fullArray(0x20, &quad96[0], 96);
vcdp->fullTriQuad(0x24, tquad, tquad__tri, 64);
}
void vcdChange(VerilatedVcd* vcdp, void* userthis, vluint32_t code) {
void vcdChange(void*, VerilatedVcd* vcdp) {
vcdp->chgBus(0x2, v1, 5);
vcdp->chgBus(0x3, v2, 7);
vcdp->chgBit(0x4, s1);
@ -932,12 +895,12 @@ void vcdChange(VerilatedVcd* vcdp, void* userthis, vluint32_t code) {
vcdp->chgTriBus(0x12, tri96[0] & 0x1f, tri96__tri[0] & 0x1f, 5);
vcdp->chgTriArray(0x16, tri96, tri96__tri, 96);
vcdp->chgDouble(0x1c, doub);
vcdp->chgArray(0x1e, &quad96[0], 96);
vcdp->chgArray(0x20, &quad96[0], 96);
vcdp->chgTriQuad(0x24, tquad, tquad__tri, 64);
}
main() {
std::cout << "test: O_LARGEFILE=" << O_LARGEFILE << std::endl;
// clang-format off
void vcdTestMain(const char* filenamep) {
v1 = v2 = s1 = 0;
s2[0] = s2[1] = s2[2] = 0;
tri96[2] = tri96[1] = tri96[0] = 0;
@ -945,43 +908,52 @@ main() {
quad96[1] = quad96[0] = 0;
ch = 0;
doub = 0;
tquad = tquad__tri = 0;
{
VerilatedVcdC* vcdp = new VerilatedVcdC;
vcdp->spTrace()->addCallback(&vcdInit, &vcdFull, &vcdChange, 0);
vcdp->open("test.vcd");
vcdp->evcd(true);
vcdp->spTrace()->addInitCb(&vcdInit, 0);
vcdp->spTrace()->addFullCb(&vcdFull, 0);
vcdp->spTrace()->addChgCb(&vcdChange, 0);
vcdp->open(filenamep);
// Dumping
vcdp->dump(timestamp++);
vcdp->dump(++timestamp);
v1 = 0xfff;
tri96[2] = 4; tri96[1] = 2; tri96[0] = 1;
tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = ~0; // Still tri
quad96[1] = 0xffffffff; quad96[0] = 0;
doub = 1.5;
vcdp->dump(timestamp++);
flo = 1.4f;
vcdp->dump(++timestamp);
v2 = 0x1;
s2[1] = 2;
tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = 0; // enable w/o data change
quad96[1] = 0; quad96[0] = ~0;
doub = -1.66e13;
vcdp->dump(timestamp++);
flo = 0.123f;
tquad = 0x00ff00ff00ff00ffULL;
tquad__tri = 0x0000fffff0000ffffULL;
vcdp->dump(++timestamp);
ch = 2;
tri96[2] = ~4; tri96[1] = ~2; tri96[0] = ~1;
doub = -3.33e-13;
vcdp->dump(timestamp++);
vcdp->dump(timestamp++);
vcdp->dump(++timestamp);
vcdp->dump(++timestamp);
# ifdef VERILATED_VCD_TEST_64BIT
vluint64_t bytesPerDump = VL_ULL(15);
for (vluint64_t i = 0; i < ((VL_ULL(1) << 32) / bytesPerDump); i++) {
vluint64_t bytesPerDump = 15ULL;
for (vluint64_t i = 0; i < ((1ULL << 32) / bytesPerDump); i++) {
v1 = i;
vcdp->dump(timestamp++);
vcdp->dump(++timestamp);
}
# endif
vcdp->close();
}
}
#endif
// clang-format on
//********************************************************************
// ;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"
// ;compile-command: "v4make test_regress/t/t_trace_c_api.pl"
//
// Local Variables:
// End:

View File

@ -130,7 +130,6 @@ protected:
inline void emitIData(vluint32_t code, IData newval, int bits);
inline void emitQData(vluint32_t code, QData newval, int bits);
inline void emitWData(vluint32_t code, const WData* newvalp, int bits);
inline void emitFloat(vluint32_t code, float newval);
inline void emitDouble(vluint32_t code, double newval);
public:
@ -163,7 +162,6 @@ public:
void declBus(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
void declQuad(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
void declArray(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
void declFloat(vluint32_t code, const char* name, bool array, int arraynum);
void declDouble(vluint32_t code, const char* name, bool array, int arraynum);
#ifdef VL_TRACE_VCD_OLD_API
@ -195,7 +193,6 @@ public:
void fullWData(vluint32_t* oldp, const WData* newvalp, int bits) {
fullArray(oldp - this->oldp(0), newvalp, bits);
}
void fullFloat(vluint32_t* oldp, float newval) { fullFloat(oldp - this->oldp(0), newval); }
void fullDouble(vluint32_t* oldp, double newval) { fullDouble(oldp - this->oldp(0), newval); }
inline void chgBit(vluint32_t* oldp, CData newval) { chgBit(oldp - this->oldp(0), newval); }
@ -214,9 +211,6 @@ public:
inline void chgWData(vluint32_t* oldp, const WData* newvalp, int bits) {
chgArray(oldp - this->oldp(0), newvalp, bits);
}
inline void chgFloat(vluint32_t* oldp, float newval) {
chgFloat(oldp - this->oldp(0), newval);
}
inline void chgDouble(vluint32_t* oldp, double newval) {
chgDouble(oldp - this->oldp(0), newval);
}
@ -230,20 +224,10 @@ public:
void fullArray(vluint32_t code, const vluint64_t* newvalp, int bits);
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);
void fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint64_t newtri, int bits);
void fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip,
int bits);
void fullDouble(vluint32_t code, const double newval);
void fullFloat(vluint32_t code, const float newval);
/// Inside dumping routines, dump one signal as unknowns
/// Presently this code doesn't change the oldval vector.
/// Thus this is for special standalone applications that after calling
/// fullBitX, must when then value goes non-X call fullBit.
void fullBitX(vluint32_t code);
void fullBusX(vluint32_t code, int bits);
void fullQuadX(vluint32_t code, int bits);
void fullArrayX(vluint32_t code, int bits);
/// Inside dumping routines, dump one signal if it has changed.
/// We do want to inline these to avoid calls when the value did not change.
@ -262,7 +246,7 @@ public:
inline void chgQuad(vluint32_t code, const vluint64_t newval, int bits) {
vluint64_t diff = (*(reinterpret_cast<vluint64_t*>(oldp(code)))) ^ newval;
if (VL_UNLIKELY(diff)) {
if (VL_UNLIKELY(bits == 64 || (diff & ((VL_ULL(1) << bits) - 1)))) {
if (VL_UNLIKELY(bits == 64 || (diff & ((1ULL << bits) - 1)))) {
fullQuad(code, newval, bits);
}
}
@ -303,12 +287,12 @@ public:
}
}
}
inline void chgTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri,
inline void chgTriQuad(vluint32_t code, const vluint64_t newval, const vluint64_t newtri,
int bits) {
vluint64_t diff = (((*(reinterpret_cast<vluint64_t*>(oldp(code)))) ^ newval)
| ((*(reinterpret_cast<vluint64_t*>(oldp(code + 1)))) ^ newtri));
if (VL_UNLIKELY(diff)) {
if (VL_UNLIKELY(bits == 64 || (diff & ((VL_ULL(1) << bits) - 1)))) {
if (VL_UNLIKELY(bits == 64 || (diff & ((1ULL << bits) - 1)))) {
fullTriQuad(code, newval, newtri, bits);
}
}
@ -329,15 +313,9 @@ public:
fullDouble(code, newval);
}
}
inline void chgFloat(vluint32_t code, const float newval) {
// cppcheck-suppress invalidPointerCast
if (VL_UNLIKELY((*(reinterpret_cast<float*>(oldp(code)))) != newval)) {
fullFloat(code, newval);
}
}
protected:
// METHODS
// Old/standalone API only
void evcd(bool flag) { m_evcd = flag; }
#endif // VL_TRACE_VCD_OLD_API
};
@ -405,6 +383,15 @@ public:
/// Internal class access
inline VerilatedVcd* spTrace() { return &m_sptrace; }
#ifdef VL_TRACE_VCD_OLD_API
//=========================================================================
// Note: These are only for testing for backward compatibility with foreign
// code and is not used by Verilator. Do not use these as there is no
// guarantee of functionality.
/// Use evcd format
void evcd(bool flag) VL_MT_UNSAFE_ONE { m_sptrace.evcd(flag); }
#endif
};
#endif // guard

View File

@ -77,7 +77,7 @@ private:
virtual void set_time_unit(int exponent10_seconds) {} // deprecated
#endif
#if defined(NC_SYSTEMC) || (SYSTEMC_VERSION >= 20111100)
virtual void set_time_unit(double v, sc_time_unit tu) {}
virtual void set_time_unit(double v, sc_time_unit tu) {} // LCOV_EXCL_LINE
#endif
//--------------------------------------------------

View File

@ -30,7 +30,6 @@
#include <list>
#include <map>
#include <set>
#include <sstream>
//======================================================================
// Internal constants
@ -50,7 +49,7 @@
// Not supported yet
#define _VL_VPI_UNIMP() \
_VL_VPI_ERROR(__FILE__, __LINE__, Verilated::catName("Unsupported VPI function: ", VL_FUNC));
(_VL_VPI_ERROR(__FILE__, __LINE__, Verilated::catName("Unsupported VPI function: ", VL_FUNC)))
//======================================================================
// Implementation
@ -136,7 +135,7 @@ public:
static inline VerilatedVpioConst* castp(vpiHandle h) {
return dynamic_cast<VerilatedVpioConst*>(reinterpret_cast<VerilatedVpio*>(h));
}
virtual vluint32_t type() const { return vpiUndefined; }
virtual vluint32_t type() const { return vpiConstant; }
vlsint32_t num() const { return m_num; }
};
@ -377,8 +376,8 @@ struct VerilatedVpiTimedCbsCmp {
/// Ordering sets keyed by time, then callback descriptor
bool operator()(const std::pair<QData, VerilatedVpioCb*>& a,
const std::pair<QData, VerilatedVpioCb*>& b) const {
if (a.first < b.first) return 1;
if (a.first > b.first) return 0;
if (a.first < b.first) return true;
if (a.first > b.first) return false;
return a.second < b.second;
}
};
@ -450,7 +449,7 @@ public:
static QData cbNextDeadline() {
VpioTimedCbs::const_iterator it = s_s.m_timedCbs.begin();
if (VL_LIKELY(it != s_s.m_timedCbs.end())) return it->first;
return ~VL_ULL(0); // maxquad
return ~0ULL; // maxquad
}
static bool callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE {
VpioCbList& cbObjList = s_s.m_cbObjLists[reason];
@ -624,7 +623,7 @@ const char* VerilatedVpiError::strFromVpiVal(PLI_INT32 vpiVal) VL_MT_SAFE {
"vpiRawFourStateVal",
};
// clang-format on
if (vpiVal < 0) return names[0];
if (VL_UNCOVERABLE(vpiVal < 0)) return names[0];
return names[(vpiVal <= vpiRawFourStateVal) ? vpiVal : 0];
}
const char* VerilatedVpiError::strFromVpiObjType(PLI_INT32 vpiVal) VL_MT_SAFE {
@ -768,7 +767,7 @@ const char* VerilatedVpiError::strFromVpiObjType(PLI_INT32 vpiVal) VL_MT_SAFE {
"vpiGenVar"
};
// clang-format on
if (vpiVal < 0) return names[0];
if (VL_UNCOVERABLE(vpiVal < 0)) return names[0];
return names[(vpiVal <= vpiGenVar) ? vpiVal : 0];
}
const char* VerilatedVpiError::strFromVpiMethod(PLI_INT32 vpiVal) VL_MT_SAFE {
@ -851,7 +850,7 @@ const char* VerilatedVpiError::strFromVpiCallbackReason(PLI_INT32 vpiVal) VL_MT_
"cbAtEndOfSimTime"
};
// clang-format on
if (vpiVal < 0) return names[0];
if (VL_UNCOVERABLE(vpiVal < 0)) return names[0];
return names[(vpiVal <= cbAtEndOfSimTime) ? vpiVal : 0];
}
@ -940,7 +939,7 @@ const char* VerilatedVpiError::strFromVpiProp(PLI_INT32 vpiVal) VL_MT_SAFE {
}
#define CHECK_RESULT_CSTR(got, exp) \
if (strcmp((got), (exp))) { \
if (0 != strcmp((got), (exp))) { \
std::string msg \
= std::string("%Error: ") + "GOT = '" + got + "'" + " EXP = '" + exp + "'"; \
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str()); \
@ -1026,7 +1025,7 @@ vpiHandle vpi_register_cb(p_cb_data cb_data_p) {
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported callback type %s", VL_FUNC,
VerilatedVpiError::strFromVpiCallbackReason(cb_data_p->reason));
return NULL;
};
}
}
PLI_INT32 vpi_remove_cb(vpiHandle object) {
@ -1135,16 +1134,30 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
_VL_VPI_ERROR_RESET();
switch (type) {
case vpiLeftRange: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (VL_UNLIKELY(!vop->rangep())) return 0;
return (new VerilatedVpioConst(vop->rangep()->left()))->castVpiHandle();
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return 0;
return (new VerilatedVpioConst(vop->rangep()->left()))->castVpiHandle();
} else if (VerilatedVpioRange* vop = VerilatedVpioRange::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return 0;
return (new VerilatedVpioConst(vop->rangep()->left()))->castVpiHandle();
}
_VL_VPI_WARNING(__FILE__, __LINE__,
"%s: Unsupported vpiHandle (%p) for type %s, nothing will be returned",
VL_FUNC, object, VerilatedVpiError::strFromVpiMethod(type));
return 0;
}
case vpiRightRange: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (VL_UNLIKELY(!vop->rangep())) return 0;
return (new VerilatedVpioConst(vop->rangep()->right()))->castVpiHandle();
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return 0;
return (new VerilatedVpioConst(vop->rangep()->right()))->castVpiHandle();
} else if (VerilatedVpioRange* vop = VerilatedVpioRange::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return 0;
return (new VerilatedVpioConst(vop->rangep()->right()))->castVpiHandle();
}
_VL_VPI_WARNING(__FILE__, __LINE__,
"%s: Unsupported vpiHandle (%p) for type %s, nothing will be returned",
VL_FUNC, object, VerilatedVpiError::strFromVpiMethod(type));
return 0;
}
case vpiIndex: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
@ -1361,7 +1374,7 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
}
case VLVT_UINT64: {
QData data = *(reinterpret_cast<QData*>(vop->varDatap()));
out[1].aval = static_cast<IData>(data >> VL_ULL(32));
out[1].aval = static_cast<IData>(data >> 32ULL);
out[1].bval = 0;
out[0].aval = static_cast<IData>(data);
out[0].bval = 0;
@ -1600,8 +1613,8 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
return;
}
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format %s", VL_FUNC,
VerilatedVpiError::strFromVpiVal(value_p->format));
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported vpiHandle (%p)", VL_FUNC, object);
}
vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p, p_vpi_time /*time_p*/,
@ -1907,6 +1920,7 @@ void vpi_put_value_array(vpiHandle /*object*/, p_vpi_arrayvalue /*arrayvalue_p*/
void vpi_get_time(vpiHandle object, p_vpi_time time_p) {
VerilatedVpiImp::assertOneCheck();
_VL_VPI_ERROR_RESET();
// cppcheck-suppress nullPointer
if (VL_UNLIKELY(!time_p)) {
_VL_VPI_WARNING(__FILE__, __LINE__, "Ignoring vpi_get_time with NULL value pointer");
@ -1937,7 +1951,7 @@ void vpi_get_time(vpiHandle object, p_vpi_time time_p) {
PLI_UINT32 vpi_mcd_open(PLI_BYTE8* filenamep) {
VerilatedVpiImp::assertOneCheck();
_VL_VPI_ERROR_RESET();
return VL_FOPEN_S(filenamep, "wb");
return VL_FOPEN_NN(filenamep, "wb");
}
PLI_UINT32 vpi_mcd_close(PLI_UINT32 mcd) {
@ -2072,17 +2086,19 @@ PLI_INT32 vpi_control(PLI_INT32 operation, ...) {
_VL_VPI_ERROR_RESET();
switch (operation) {
case vpiFinish: {
VL_FINISH_MT(__FILE__, __LINE__, "*VPI*");
VL_FINISH_MT("", 0, "*VPI*");
return 1;
}
case vpiStop: {
VL_STOP_MT(__FILE__, __LINE__, "*VPI*");
return 1;
VL_STOP_MT("", 0, "*VPI*");
return 1; // LCOV_EXCL_LINE
}
default: {
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, ignoring", VL_FUNC,
VerilatedVpiError::strFromVpiProp(operation));
return 0;
}
}
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, ignoring", VL_FUNC,
VerilatedVpiError::strFromVpiProp(operation));
return 0;
}
vpiHandle vpi_handle_by_multi_index(vpiHandle /*obj*/, PLI_INT32 /*num_index*/,

View File

@ -144,30 +144,23 @@
#define VL_MT_UNSAFE_ONE ///< Comment tag that function is not threadsafe when VL_THREADED,
///< protected to make sure single-caller
#ifdef _MSC_VER
# define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant
// Was "(c##ui64)". C++11 has standardized on ULL, and MSVC now supports this.
// We propose to no longer require using this macro no sooner than June 2020.
// File an issue ASAP if this breaks anything.
#else
# define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant
#endif
#define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant (deprecated)
// This is not necessarily the same as #UL, depending on what the IData typedef is.
#define VL_UL(c) (static_cast<IData>(c##UL)) ///< Add appropriate suffix to 32-bit constant
#if defined(VL_CPPCHECK) || defined(__clang_analyzer__)
#if defined(VL_CPPCHECK) || defined(__clang_analyzer__) || __cplusplus < 201103L
# define VL_DANGLING(var)
#else
///< After e.g. delete, set variable to NULL to indicate must not use later
/// After e.g. delete, set variable to NULL to indicate must not use later
# define VL_DANGLING(var) \
do { \
(var) = NULL; \
*const_cast<const void**>(reinterpret_cast<const void* const*>(&var)) = NULL; \
} while (false)
#endif
///< Perform an e.g. delete, then set variable to NULL to indicate must not use later.
///< Unlike VL_DO_CLEAR the setting of the variable is only for debug reasons.
/// Perform an e.g. delete, then set variable to NULL to indicate must not use later.
/// Unlike VL_DO_CLEAR the setting of the variable is only for debug reasons.
#define VL_DO_DANGLING(stmt, var) \
do { \
do { \
@ -176,7 +169,7 @@
VL_DANGLING(var); \
} while (false)
///< Perform an e.g. delete, then set variable to NULL as a requirement
/// Perform an e.g. delete, then set variable to NULL as a requirement
#define VL_DO_CLEAR(stmt, stmt2) \
do { \
do { \
@ -224,6 +217,20 @@
# define VL_INLINE_OPT ///< "inline" if compiling all objects in single compiler run
#endif
//=========================================================================
// Internal coverage
#ifdef VL_GCOV
extern "C" {
void __gcov_flush(); // gcc sources gcc/gcov-io.h has the prototype
}
/// Flush internal code coverage data before e.g. abort()
# define VL_GCOV_FLUSH() \
__gcov_flush()
#else
# define VL_GCOV_FLUSH()
#endif
//=========================================================================
// Warning disabled
@ -401,7 +408,7 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
#define VL_MASK_I(nbits) (((nbits) & VL_SIZEBITS_I) ? ((1U << ((nbits) & VL_SIZEBITS_I)) - 1) : ~0)
/// Mask for quads with 1's where relevant bits are (0=all bits)
#define VL_MASK_Q(nbits) \
(((nbits) & VL_SIZEBITS_Q) ? ((VL_ULL(1) << ((nbits) & VL_SIZEBITS_Q)) - VL_ULL(1)) : VL_ULL(~0))
(((nbits) & VL_SIZEBITS_Q) ? ((1ULL << ((nbits) & VL_SIZEBITS_Q)) - 1ULL) : ~0ULL)
/// Mask for EData with 1's where relevant bits are (0=all bits)
#define VL_MASK_E(nbits) VL_MASK_I(nbits)
#define VL_EUL(n) VL_UL(n) ///< Make constant number EData sized

View File

@ -1,58 +0,0 @@
#!/usr/bin/env perl
######################################################################
#
# Copyright 2007-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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
#
######################################################################
# DESCRIPTION: Debugging of bison output
use warnings;
use strict;
my $Debug;
my %declared;
my %used;
my $body = 0;
my $rule = "";
my $lineno = 0;
foreach my $line (<STDIN>) {
$lineno++;
chomp $line;
$line =~ s!//.*$!!g;
$line =~ s!\s+! !g;
next if $line eq '';
if ($line =~ m!^\%\%!) {
$body++;
} elsif ($body == 1) {
$rule .= $line;
if ($line =~ m!^\s*;\s*$!) {
#print "Rule: $rule\n";
($rule =~ /^([a-zA-Z0-9_]+)(<\S+>)?:(.*)$/) or die "%Error: No rule name: $1\n";
my $rulename = $1; my $preaction = $3;
$declared{$rulename} = $lineno;
$preaction =~ s/\{[^\}]*\}/ /g;
#print "RULEN $rulename PA $preaction\n" if $Debug;
$rule = '';
foreach my $ref (split /\s+/, $preaction) {
next if $ref !~ /^[a-zA-Z]/;
next if $ref eq $rulename;
if (!$used{$ref} && $declared{$ref}) {
print " %Warning: $lineno: $ref used by $rulename after declaration\n";
}
$used{$ref} = $lineno;
print " ref $ref\n" if $Debug;
}
}
}
}
# Local Variables:
# compile-command: "./bisonreader < ../src/verilog.y"
# End:

View File

@ -6,30 +6,71 @@ use warnings;
use Cwd;
use File::Copy qw(cp);
use File::Path qw(mkpath);
use File::Spec;
use FindBin qw($RealBin);
use Getopt::Long;
use Parallel::Forker;
use Unix::Processors;
use IO::File;
use Pod::Usage;
use strict;
use vars qw($Debug);
our $Opt_Stop = 1;
our $Opt_Fastcov = 1;
our $Exclude_Branch_Regexp;
our $Exclude_Line_Regexp;
our $Remove_Gcda_Regexp;
our @Remove_Sources;
our @Source_Globs;
our $Fork = new Parallel::Forker(use_sig_child => 1, poll_interval => 10*1000);
$Fork->max_proc(Unix::Processors->new->max_online * 1.5);
$SIG{CHLD} = sub { Parallel::Forker::sig_child($Fork); };
$SIG{TERM} = sub { $Fork->kill_tree_all('TERM') if $Fork && $Fork->in_parent; die "Quitting...\n"; };
#======================================================================
# main
our $Opt_Stage = 0;
our $Opt_Hashset;
our $opt_stages = '';
our $Opt_Scenarios;
our %Opt_Stages;
our @Opt_Tests;
autoflush STDOUT 1;
autoflush STDERR 1;
Getopt::Long::config("no_auto_abbrev");
if (! GetOptions(
"debug" => sub { $Debug = 1; },
"hashset=s" => \$Opt_Hashset, # driver.pl hashset
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
"stage=i" => \$Opt_Stage,
"fastcov!" => \$Opt_Fastcov, # use fastcov, not documented, for debug
"scenarios=s" => \$Opt_Scenarios, # driver.pl scenarios
"stage=s" => \$opt_stages, # starting stage number
"stages=s" => \$opt_stages, # starting stage number
"stop!" => \$Opt_Stop, # stop/do not stop on error in tests
"test=s@" => \@Opt_Tests, # test name
)) {
die "%Error: Bad usage, try 'install_test --help'\n";
die "%Error: Bad usage, try 'code_coverage --help'\n";
}
{
my $start = 0;
my $end = 99;
if ($opt_stages && $opt_stages =~ /^(\d+)$/) {
$start = $end = $1;
} elsif ($opt_stages && $opt_stages =~ /^(\d+)-(\d+$)$/) {
$start = $1; $end = $2;
} elsif ($opt_stages && $opt_stages =~ /^-(\d+$)$/) {
$end = $1;
} elsif ($opt_stages && $opt_stages =~ /^(\d+)-$/) {
$start = $1;
} elsif ($opt_stages) {
die "%Error: --stages not understood: $opt_stages,";
}
for (my $n = $start; $n <= $end; ++$n) { $Opt_Stages{$n} = 1; }
}
test();
@ -41,97 +82,238 @@ sub test {
-r "nodist/code_coverage.dat" or die "%Error: Run from the top of the verilator kit,";
require "./nodist/code_coverage.dat";
if ($Opt_Stage <= 0) {
print "Stage 0: configure (coverage on)\n";
run("make distclean");
run("./configure --enable-longtests CXX='g++ --coverage'");
run("make -k");
if ($Opt_Stages{1}) {
travis_fold_start("configure");
print "Stage 1: configure (coverage on)\n";
run("make distclean || true");
run("autoconf");
# Exceptions can pollute the branch coverage data
run("./configure --enable-longtests CXX='g++ --coverage -fno-exceptions -DVL_GCOV'");
travis_fold_end();
}
if ($Opt_Stages{2}) {
travis_fold_start("build");
print "Stage 2: build\n";
my $nproc = Unix::Processors->new->max_online;
run("make -k -j $nproc VERILATOR_NO_OPT_BUILD=1");
# The optimized versions will not collect good coverage, overwrite them
run("cp bin/verilator_bin_dbg bin/verilator_bin");
run("cp bin/verilator_coverage_bin_dbg bin/verilator_coverage_bin");
travis_fold_end();
}
if ($Opt_Stage <= 1) {
print "Stage 1: make examples (with coverage on)\n";
run("make examples");
run("make test_regress");
if ($Opt_Stages{3}) {
travis_fold_start("test");
print "Stage 3: make tests (with coverage on)\n";
if ($#Opt_Tests < 0) {
run("make examples VERILATOR_NO_OPT_BUILD=1")
if !$Opt_Scenarios || $Opt_Scenarios =~ /dist/i;
run("make test_regress VERILATOR_NO_OPT_BUILD=1"
. ($Opt_Scenarios ? " SCENARIOS='".$Opt_Scenarios."'" : "")
. ($Opt_Hashset ? " DRIVER_HASHSET='--hashset=".$Opt_Hashset."'" : "")
. ($Opt_Stop ? '' : ' || true'));
} else {
foreach my $test (@Opt_Tests) {
if (! -f $test && -f "test_regress/t/${test}") {
$test = "test_regress/t/${test}";
}
run($test);
}
}
travis_fold_end();
}
my $cc_dir = "nodist/obj_dir/coverage";
if ($Opt_Stage <= 2) {
print "Stage 2: Create info files under $cc_dir\n";
if ($Opt_Stages{4}) {
travis_fold_start("gcno");
print "Stage 4: Create gcno files under $cc_dir\n";
mkpath($cc_dir);
mkpath("$cc_dir/info");
my $dats = `find . -print | grep .gcda`;
my %dats;
foreach my $dat (split '\n', $dats) {
$dats{$dat} = 1;
}
foreach my $dat (sort keys %dats) {
(my $gcno = $dat) =~ s!\.gcda$!.gcno!;
if ($dat =~ /$Remove_Gcda_Regexp/) {
# Remove .gcda/.gcno for files we don't care about before we slowly
# read them
unlink $dat;
unlink $gcno;
delete $dats{$dat};
next;
}
}
$dats = `find . -print | grep .gcno`;
my %gcnos;
foreach my $gcno (split '\n', $dats) {
(my $gbase = $gcno) =~ s!.*/!!;
$gcnos{$gbase} = File::Spec->rel2abs($gcno);
}
# We need a matching .gcno for every .gcda, try to find a matching file elsewhere
foreach my $dat (sort keys %dats) {
(my $gcno = $dat) =~ s!\.gcda$!.gcno!;
(my $gbase = $gcno) =~ s!.*/!!;
if (!-r $gcno) {
if ($gcnos{$gbase}) {
symlink($gcnos{$gbase}, $gcno)
or die "%Error: can't ln -s $gcnos{$gbase} $gcno,";
} else {
warn "MISSING .gcno for a .gcda: $gcno\n";
}
}
}
travis_fold_end();
}
if ($Opt_Stages{5} && $Opt_Fastcov) {
travis_fold_start("fastcov");
# Must run in root directory to find all files
mkpath($cc_dir);
#run("${RealBin}/fastcov.py -b -c src/obj_dbg -X".
# " --exclude /usr --exclude test_regress"
# ." -o ${cc_dir}/app_total.json");
run("${RealBin}/fastcov.py -b -c src/obj_dbg -X --lcov".
" --exclude /usr --exclude test_regress"
." -o ${cc_dir}/app_total.info");
travis_fold_end();
}
if ($Opt_Stages{5} && !$Opt_Fastcov) {
travis_fold_start("infos");
print "Stage 5: make infos\n";
my $dats = `find . -print | grep .gcda`;
my %dirs;
foreach my $dat (split '\n', $dats) {
$dat =~ s!/[^/]+$!!;
$dirs{$dat} = 1;
(my $dir = $dat) =~ s!/[^/]+$!!;
$dirs{$dir} = 1;
}
foreach my $dir (sort keys %dirs) {
(my $outname = $dir) =~ s![^a-zA-Z0-9]+!_!g;
run("cd $cc_dir/info ; lcov -c -d ../../../../$dir -o app_test_${outname}.info");
$Fork->schedule(run_on_start => sub {
# .info may be empty, so ignore errors (unfortunately)
run("cd $cc_dir/info ; lcov -c -d ../../../../$dir --exclude /usr -o app_test_${outname}.info || true");
})->run;
}
$Fork->wait_all;
travis_fold_end();
}
if ($Opt_Stage <= 3) {
# lcov doesn't have a control file to override single lines, so replicate the sources
print "Stage 3: Clone sources under $cc_dir\n";
if ($Opt_Stages{6}) {
travis_fold_start("clone");
# No control file to override single lines, so replicate the sources
# Also lets us see the insertion markers in the HTML source res
print "Stage 6: Clone sources under $cc_dir\n";
clone_sources($cc_dir);
travis_fold_end();
}
if ($Opt_Stage <= 4) {
print "Stage 4: Copy .gcno files\n";
if ($Opt_Stages{8} && !$Opt_Fastcov) {
travis_fold_start("copy");
print "Stage 8: Copy .gcno files\n";
my $dats = `find . -print | grep .gcno`;
foreach my $dat (split '\n', $dats) {
foreach my $dat (sort (split '\n', $dats)) {
next if $dat =~ /$cc_dir/;
my $outdat = $cc_dir."/".$dat;
#print "cp $dat, $outdat);\n";
cp($dat, $outdat);
}
travis_fold_end();
}
if ($Opt_Stage <= 5) {
print "Stage 5: Combine data files\n";
run("cd $cc_dir ; lcov -c -i -d src/obj_dbg -o app_base.info");
run("cd $cc_dir ; lcov -a app_base.info -o app_total.info");
my $infos = `cd $cc_dir ; find info -print | grep .info`;
my $comb = "";
my @infos = (split /\n/, $infos);
foreach my $info (@infos) {
$comb .= " -a $info";
# Need to batch them to avoid overrunning shell command length limit
if (length($comb) > 10000 || $info eq $infos[$#infos]) {
run("cd $cc_dir ; lcov -a app_total.info $comb -o app_total.info");
$comb = "";
if ($Opt_Stages{10} && !$Opt_Fastcov) {
travis_fold_start("combine");
print "Stage 10: Combine data files\n";
{
run("cd $cc_dir ; lcov -c -i -d src/obj_dbg -o app_base.info");
run("cd $cc_dir ; lcov -a app_base.info -o app_total.info");
my $infos = `cd $cc_dir ; find info -print | grep .info`;
my $comb = "";
my @infos = (sort (split /\n/, $infos));
foreach my $info (@infos) {
$comb .= " -a $info";
# Need to batch them to avoid overrunning shell command length limit
if (length($comb) > 10000 || $info eq $infos[$#infos]) {
# .info may be empty, so ignore errors (unfortunately)
run("cd $cc_dir ; lcov -a app_total.info $comb -o app_total.info || true");
$comb = "";
}
}
}
travis_fold_end();
}
if ($Opt_Stage <= 6) {
print "Stage 6: Filter processed source files\n";
my $cmd = '';
foreach my $glob (@Remove_Sources) {
$cmd .= " '$glob'";
if ($Opt_Stages{11}) {
travis_fold_start("dirs");
print "Stage 11: Cleanup paths\n";
if ($Opt_Fastcov) {
cleanup_abs_paths_info($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info");
#cleanup_abs_paths_json($cc_dir, "$cc_dir/app_total.json", "$cc_dir/app_total.json");
} else {
cleanup_abs_paths_info($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info");
}
run("cd $cc_dir ; lcov --remove app_total.info $cmd -o app_total.info");
travis_fold_end();
}
if ($Opt_Stage <= 7) {
print "Stage 7: Create HTML\n";
cleanup_abs_paths($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info");
run("cd $cc_dir ; genhtml app_total.info --demangle-cpp"
if ($Opt_Stages{12}) {
travis_fold_start("filter");
print "Stage 12: Filter processed source files\n";
my $inc = '';
foreach my $glob (@Source_Globs) {
foreach my $infile (glob $glob) {
$inc .= " '$infile'";
}
}
my $exc = '';
foreach my $glob (@Remove_Sources) {
# Fastcov does exact match not globbing at present
# Lcov requires whole path match so needs the glob
$glob =~ s!^\*!! if $Opt_Fastcov;
$glob =~ s!\*$!! if $Opt_Fastcov;
$exc .= " '$glob'";
}
if ($Opt_Fastcov) {
$inc = "--include ".$inc if $inc ne '';
$exc = "--exclude ".$exc if $exc ne '';
run("cd $cc_dir ; ${RealBin}/fastcov.py -C app_total.info ${inc} ${exc} -x --lcov -o app_total_f.info");
} else {
run("cd $cc_dir ; lcov --remove app_total.info $exc -o app_total_f.info");
}
travis_fold_end();
}
if ($Opt_Stages{17}) {
travis_fold_start("report");
print "Stage 17: Create HTML\n";
run("cd $cc_dir ; genhtml app_total_f.info --demangle-cpp"
." --rc lcov_branch_coverage=1 --rc genhtml_hi_limit=100 --output-directory html");
travis_fold_end();
}
if ($Opt_Stage <= 9) {
if ($Opt_Stages{18}) {
travis_fold_start("upload");
print "Stage 18: Upload\n";
my $cmd = "bash <(curl -s https://codecov.io/bash) -f $cc_dir/app_total.info";
print "print: Not running: export CODECOV_TOKEN=<hidden>\n";
print "print: Not running: $cmd\n";
travis_fold_end();
}
if ($Opt_Stages{19}) {
print "*-* All Finished *-*\n";
print "\n";
print "* See report in ${cc_dir}/html/index.html\n";
print "* Remember to make distclean && ./configure before working on non-coverage\n";
}
}
sub clone_sources {
my $cc_dir = shift;
my $excluded_lines = 0;
my $excluded_br_lines = 0;
foreach my $glob (@Source_Globs) {
foreach my $infile (glob $glob) {
$infile !~ m!^/!
@ -145,21 +327,35 @@ sub clone_sources {
while (defined(my $line = $fh->getline)) {
$lineno++;
chomp $line;
if ($line !~ m!// LCOV_EXCL_LINE!
&& $line =~ /$Exclude_Line_Regexp/) {
$line .= " //code_coverage: // LCOV_EXCL_LINE";
if ($line =~ /LCOV_EXCL_LINE/) {
$line .= " LCOV_EXCL_BR_LINE";
}
elsif ($line =~ /LCOV_EXCL_START/) {
$line .= " LCOV_EXCL_BR_START";
}
elsif ($line =~ /LCOV_EXCL_STOP/) {
$line .= " LCOV_EXCL_BR_STOP";
}
elsif ($line =~ /$Exclude_Line_Regexp/) {
$line .= " //code_coverage: // LCOV_EXCL_LINE LCOV_EXCL_BR_LINE";
$excluded_lines++;
$excluded_br_lines++;
#print "$infile:$lineno: $line";
}
elsif ($line =~ /$Exclude_Branch_Regexp/) {
$line .= " //code_coverage: // LCOV_EXCL_BR_LINE";
$excluded_br_lines++;
#print "$infile:$lineno: $line";
} else {
}
$ofh->print("$line\n");
}
}
}
print "Source code lines automatically LCOV_EXCL_LINE'ed: $excluded_lines\n";
print "Number of source lines automatically LCOV_EXCL_LINE'ed: $excluded_lines\n";
print "Number of source lines automatically LCOV_EXCL_BR_LINE'ed: $excluded_br_lines\n";
}
sub cleanup_abs_paths {
sub cleanup_abs_paths_info {
my $cc_dir = shift;
my $infile = shift;
my $outfile = shift;
@ -178,18 +374,41 @@ sub cleanup_abs_paths {
$ofh->print(@lines);
}
sub cleanup_abs_paths_json {
my $cc_dir = shift;
my $infile = shift;
my $outfile = shift;
# Handcrafted cleanup, alternative would be to deserialize/serialize JSON
# But JSON::Parse not installed by default
# JSON::PP more likely to be installed, but slower
my $fh = IO::File->new("<$infile") or die "%Error: $! $infile,";
my @lines;
while (defined(my $line = $fh->getline)) {
$line =~ s!"$ENV{VERILATOR_ROOT}/!"!g;
$line =~ s!"$cc_dir/!"!g;
$line =~ s!obj_dbg/verilog.y$!verilog.y!g;
push @lines, $line;
}
my $ofh = IO::File->new(">$outfile") or die "%Error: $! $outfile,";
$ofh->print(@lines);
}
#######################################################################
# .dat file callbacks
sub exclude_branch_regexp {
$Exclude_Branch_Regexp = shift;
}
sub exclude_line_regexp {
$Exclude_Line_Regexp = shift;
}
sub remove_gcda_regexp {
$Remove_Gcda_Regexp = shift;
}
sub remove_source {
my @srcs = @_;
push @Remove_Sources, @srcs;
}
sub source_globs {
my @dirs = @_;
push @Source_Globs, @dirs;
@ -206,6 +425,15 @@ sub run {
($status == 0) or die "%Error: Command Failed $command, $status, stopped";
}
our $_Travis_Action;
sub travis_fold_start {
$_Travis_Action = shift;
print "travis_fold:start:$_Travis_Action\n";
}
sub travis_fold_end {
print "travis_fold:end:$_Travis_Action\n";
}
#######################################################################
__END__
@ -231,13 +459,30 @@ This will rebuild the current object files.
=over 4
=item --hashset I<hashset>
Pass test hashset onto driver.pl test harness.
=item --help
Displays this message and program version and exits.
=item -stage I<stage>
=item --scenarios I<scenarios>
Runs a specific stage (see the script).
Pass test scenarios onto driver.pl test harness.
=item --stages I<stage>
Runs a specific stage or range of stages (see the script).
=item --no-stop
Do not stop collecting data if tests fail.
=item --test I<test_regress_test_name>
Instead of normal regressions, run the specified test. May be specified
multiple times for multiple tests.
=back

View File

@ -21,7 +21,8 @@ source_globs("src/*.cpp",
"include/*/*.c",
);
remove_source("/usr/include/*");
# Note *'s are removed when using fastcov
remove_source("/usr/*");
remove_source("*/include/sysc/*");
remove_source("*/V3ClkGater.cpp");
remove_source("*/V3ClkGater.h");
@ -37,7 +38,21 @@ remove_source("*include/gtkwave/*");
remove_source("*test_regress/*");
remove_source("*examples/*");
# Remove collected coverage on each little test main file
# Would just be removed with remove_source in later step
remove_gcda_regexp(qr!test_regress/.*/(Vt_|Vtop_).*\.gcda!);
exclude_line_regexp(qr/(\bv3fatalSrc\b|\bVL_UNCOVERABLE\b)/);
# Exclude line entirely, also excludes from function and branch coverage
exclude_line_regexp(qr/(\bv3fatalSrc\b
|\bfatalSrc\b
|\bVL_UNCOVERABLE\b
|\bVL_FATAL
|\bUASSERT
|\bERROR_RSVD_WORD
|\bV3ERROR_NA
|\bUINFO\b)/x);
# Exclude for branch coverage only
exclude_branch_regexp(qr/(\bdebug\(\))/x);
1;

744
nodist/fastcov.py Executable file
View File

@ -0,0 +1,744 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
# Copyright 2018-present, Bryan Gillespie
"""
Author: Bryan Gillespie
https://github.com/RPGillespie6/fastcov
A massively parallel gcov wrapper for generating intermediate coverage formats fast
The goal of fastcov is to generate code coverage intermediate formats as fast as possible,
even for large projects with hundreds of gcda objects. The intermediate formats may then be
consumed by a report generator such as lcov's genhtml, or a dedicated frontend such as coveralls.
Sample Usage:
$ cd build_dir
$ ./fastcov.py --zerocounters
$ <run unit tests>
$ ./fastcov.py --exclude /usr/include test/ --lcov -o report.info
$ genhtml -o code_coverage report.info
"""
import re
import os
import sys
import glob
import json
import time
import logging
import argparse
import threading
import subprocess
import multiprocessing
FASTCOV_VERSION = (1,7)
MINIMUM_PYTHON = (3,5)
MINIMUM_GCOV = (9,0,0)
# Interesting metrics
START_TIME = time.monotonic()
GCOVS_TOTAL = 0
GCOVS_SKIPPED = 0
# For when things go wrong...
# Start error codes at 3 because 1-2 are special
# See https://stackoverflow.com/a/1535733/2516916
EXIT_CODE = 0
EXIT_CODES = {
"gcov_version": 3,
"python_version": 4,
"unsupported_coverage_format": 5,
"excl_not_found": 6,
}
# Disable all logging in case developers are using this as a module
logging.disable(level=logging.CRITICAL)
class FastcovFormatter(logging.Formatter):
def format(self, record):
record.levelname = record.levelname.lower()
log_message = super(FastcovFormatter, self).format(record)
return "[{:.3f}s] {}".format(stopwatch(), log_message)
def chunks(l, n):
"""Yield successive n-sized chunks from l."""
for i in range(0, len(l), n):
yield l[i:i + n]
def setExitCode(key):
global EXIT_CODE
EXIT_CODE = EXIT_CODES[key]
def incrementCounters(total, skipped):
global GCOVS_TOTAL
global GCOVS_SKIPPED
GCOVS_TOTAL += total
GCOVS_SKIPPED += skipped
def stopwatch():
"""Return number of seconds since last time this was called."""
global START_TIME
end_time = time.monotonic()
delta = end_time - START_TIME
START_TIME = end_time
return delta
def parseVersionFromLine(version_str):
"""Given a string containing a dotted integer version, parse out integers and return as tuple."""
version = re.search(r'(\d+\.\d+\.\d+)', version_str)
if not version:
return (0,0,0)
return tuple(map(int, version.group(1).split(".")))
def getGcovVersion(gcov):
p = subprocess.Popen([gcov, "-v"], stdout=subprocess.PIPE)
output = p.communicate()[0].decode('UTF-8')
p.wait()
return parseVersionFromLine(output.split("\n")[0])
def removeFiles(files):
for file in files:
os.remove(file)
def getFilteredCoverageFiles(coverage_files, exclude):
def excludeGcda(gcda):
for ex in exclude:
if ex in gcda:
logging.debug("Omitting %s due to '--exclude-gcda %s'", gcda, ex)
return False
return True
return list(filter(excludeGcda, coverage_files))
def findCoverageFiles(cwd, coverage_files, use_gcno):
coverage_type = "user provided"
if not coverage_files:
coverage_type = "gcno" if use_gcno else "gcda"
coverage_files = glob.glob(os.path.join(os.path.abspath(cwd), "**/*." + coverage_type), recursive=True)
logging.info("Found {} coverage files ({})".format(len(coverage_files), coverage_type))
logging.debug("Coverage files found:\n %s", "\n ".join(coverage_files))
return coverage_files
def gcovWorker(data_q, metrics_q, args, chunk, gcov_filter_options):
base_report = {"sources": {}}
gcovs_total = 0
gcovs_skipped = 0
gcov_args = "-it"
if args.branchcoverage or args.xbranchcoverage:
gcov_args += "b"
p = subprocess.Popen([args.gcov, gcov_args] + chunk, cwd=args.cdirectory, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
for line in iter(p.stdout.readline, b''):
intermediate_json = json.loads(line.decode(sys.stdout.encoding))
intermediate_json_files = processGcovs(args.cdirectory, intermediate_json["files"], gcov_filter_options)
for f in intermediate_json_files:
distillSource(f, base_report["sources"], args.test_name, args.xbranchcoverage)
gcovs_total += len(intermediate_json["files"])
gcovs_skipped += len(intermediate_json["files"]) - len(intermediate_json_files)
p.wait()
data_q.put(base_report)
metrics_q.put((gcovs_total, gcovs_skipped))
def processGcdas(args, coverage_files, gcov_filter_options):
chunk_size = max(args.minimum_chunk, int(len(coverage_files) / args.jobs) + 1)
processes = []
data_q = multiprocessing.Queue()
metrics_q = multiprocessing.Queue()
for chunk in chunks(coverage_files, chunk_size):
p = multiprocessing.Process(target=gcovWorker, args=(data_q, metrics_q, args, chunk, gcov_filter_options))
processes.append(p)
p.start()
logging.info("Spawned {} gcov processes, each processing at most {} coverage files".format(len(processes), chunk_size))
fastcov_jsons = []
for p in processes:
fastcov_jsons.append(data_q.get())
incrementCounters(*metrics_q.get())
for p in processes:
p.join()
base_fastcov = fastcov_jsons.pop()
for fj in fastcov_jsons:
combineReports(base_fastcov, fj)
return base_fastcov
def shouldFilterSource(source, gcov_filter_options):
"""Returns true if the provided source file should be filtered due to CLI options, otherwise returns false."""
# If explicit sources were passed, check for match
if gcov_filter_options["sources"]:
if source not in gcov_filter_options["sources"]:
logging.debug("Filtering coverage for '%s' due to option '--source-files'", source)
return True
# Check exclude filter
for ex in gcov_filter_options["exclude"]:
if ex in source:
logging.debug("Filtering coverage for '%s' due to option '--exclude %s'", source, ex)
return True
# Check include filter
if gcov_filter_options["include"]:
included = False
for inc in gcov_filter_options["include"]:
if inc in source:
included = True
break
if not included:
logging.debug("Filtering coverage for '%s' due to option '--include %s'", source, " ".join(gcov_filter_options["include"]))
return True
return False
def filterFastcov(fastcov_json, args):
logging.info("Performing filtering operations (if applicable)")
gcov_filter_options = getGcovFilterOptions(args)
for source in list(fastcov_json["sources"].keys()):
if shouldFilterSource(source, gcov_filter_options):
del fastcov_json["sources"][source]
def processGcov(cwd, gcov, files, gcov_filter_options):
# Add absolute path
gcov["file_abs"] = os.path.abspath(os.path.join(cwd, gcov["file"]))
if shouldFilterSource(gcov["file_abs"], gcov_filter_options):
return
files.append(gcov)
logging.debug("Accepted coverage for '%s'", gcov["file_abs"])
def processGcovs(cwd, gcov_files, gcov_filter_options):
files = []
for gcov in gcov_files:
processGcov(cwd, gcov, files, gcov_filter_options)
return files
def dumpBranchCoverageToLcovInfo(f, branches):
branch_miss = 0
branch_found = 0
brda = []
for line_num, branch_counts in branches.items():
for i, count in enumerate(branch_counts):
# Branch (<line number>, <block number>, <branch number>, <taken>)
brda.append((line_num, int(i/2), i, count))
branch_miss += int(count == 0)
branch_found += 1
for v in sorted(brda):
f.write("BRDA:{},{},{},{}\n".format(*v))
f.write("BRF:{}\n".format(branch_found)) # Branches Found
f.write("BRH:{}\n".format(branch_found - branch_miss)) # Branches Hit
def dumpToLcovInfo(fastcov_json, output):
with open(output, "w") as f:
sources = fastcov_json["sources"]
for sf in sorted(sources.keys()):
for tn in sorted(sources[sf].keys()):
data = sources[sf][tn]
f.write("TN:{}\n".format(tn)) #Test Name - used mainly in conjuction with genhtml --show-details
f.write("SF:{}\n".format(sf)) #Source File
fn_miss = 0
fn = []
fnda = []
for function, fdata in data["functions"].items():
fn.append((fdata["start_line"], function)) # Function Start Line
fnda.append((fdata["execution_count"], function)) # Function Hits
fn_miss += int(fdata["execution_count"] == 0)
# NOTE: lcov sorts FN, but not FNDA.
for v in sorted(fn):
f.write("FN:{},{}\n".format(*v))
for v in sorted(fnda):
f.write("FNDA:{},{}\n".format(*v))
f.write("FNF:{}\n".format(len(data["functions"]))) #Functions Found
f.write("FNH:{}\n".format((len(data["functions"]) - fn_miss))) #Functions Hit
if data["branches"]:
dumpBranchCoverageToLcovInfo(f, data["branches"])
line_miss = 0
da = []
for line_num, count in data["lines"].items():
da.append((line_num, count))
line_miss += int(count == 0)
for v in sorted(da):
f.write("DA:{},{}\n".format(*v)) # Line
f.write("LF:{}\n".format(len(data["lines"]))) #Lines Found
f.write("LH:{}\n".format((len(data["lines"]) - line_miss))) #Lines Hit
f.write("end_of_record\n")
def getSourceLines(source, fallback_encodings=[]):
"""Return a list of lines from the provided source, trying to decode with fallback encodings if the default fails."""
default_encoding = sys.getdefaultencoding()
for encoding in [default_encoding] + fallback_encodings:
try:
with open(source, encoding=encoding) as f:
return f.readlines()
except UnicodeDecodeError:
pass
logging.warning("Could not decode '{}' with {} or fallback encodings ({}); ignoring errors".format(source, default_encoding, ",".join(fallback_encodings)))
with open(source, errors="ignore") as f:
return f.readlines()
def exclProcessSource(fastcov_sources, source, exclude_branches_sw, include_branches_sw, fallback_encodings):
start_line = 0
end_line = 0
# Start enumeration at line 1 because the first line of the file is line 1 not 0
for i, line in enumerate(getSourceLines(source, fallback_encodings), 1):
# Cycle through test names (likely only 1)
for test_name in fastcov_sources[source]:
fastcov_data = fastcov_sources[source][test_name]
# Build line to function dict so can quickly delete by line number
line_to_func = {}
for f in fastcov_data["functions"].keys():
l = fastcov_data["functions"][f]["start_line"]
if l not in line_to_func:
line_to_func[l] = set()
line_to_func[l].add(f)
if i in fastcov_data["branches"]:
del_exclude_br = exclude_branches_sw and any(line.lstrip().startswith(e) for e in exclude_branches_sw)
del_include_br = include_branches_sw and all(not line.lstrip().startswith(e) for e in include_branches_sw)
if del_exclude_br or del_include_br:
del fastcov_data["branches"][i]
if "LCOV_EXCL" not in line:
continue
if "LCOV_EXCL_LINE" in line:
for key in ["lines", "branches"]:
if i in fastcov_data[key]:
del fastcov_data[key][i]
if i in line_to_func:
for key in line_to_func[i]:
if key in fastcov_data["functions"]:
del fastcov_data["functions"][key]
elif "LCOV_EXCL_START" in line:
start_line = i
elif "LCOV_EXCL_STOP" in line:
end_line = i
if not start_line:
end_line = 0
continue
for key in ["lines", "branches"]:
for line_num in list(fastcov_data[key].keys()):
if start_line <= line_num <= end_line:
del fastcov_data[key][line_num]
for line_num in range(start_line, end_line):
if line_num in line_to_func:
for key in line_to_func[line_num]:
if key in fastcov_data["functions"]:
del fastcov_data["functions"][key]
start_line = end_line = 0
elif "LCOV_EXCL_BR_LINE" in line:
if i in fastcov_data["branches"]:
del fastcov_data["branches"][i]
def exclMarkerWorker(fastcov_sources, chunk, exclude_branches_sw, include_branches_sw, fallback_encodings):
for source in chunk:
try:
exclProcessSource(fastcov_sources, source, exclude_branches_sw, include_branches_sw, fallback_encodings)
except FileNotFoundError:
logging.error("Could not find '%s' to scan for exclusion markers...", source)
setExitCode("excl_not_found") # Set exit code because of error
def scanExclusionMarkers(fastcov_json, jobs, exclude_branches_sw, include_branches_sw, min_chunk_size, fallback_encodings):
chunk_size = max(min_chunk_size, int(len(fastcov_json["sources"]) / jobs) + 1)
threads = []
for chunk in chunks(list(fastcov_json["sources"].keys()), chunk_size):
t = threading.Thread(target=exclMarkerWorker, args=(fastcov_json["sources"], chunk, exclude_branches_sw, include_branches_sw, fallback_encodings))
threads.append(t)
t.start()
logging.info("Spawned {} threads each scanning at most {} source files".format(len(threads), chunk_size))
for t in threads:
t.join()
def distillFunction(function_raw, functions):
function_name = function_raw["name"]
# NOTE: need to explicitly cast all counts coming from gcov to int - this is because gcov's json library
# will pass as scientific notation (i.e. 12+e45)
start_line = int(function_raw["start_line"])
execution_count = int(function_raw["execution_count"])
if function_name not in functions:
functions[function_name] = {
"start_line": start_line,
"execution_count": execution_count
}
else:
functions[function_name]["execution_count"] += execution_count
def emptyBranchSet(branch1, branch2):
return (branch1["count"] == 0 and branch2["count"] == 0)
def matchingBranchSet(branch1, branch2):
return (branch1["count"] == branch2["count"])
def filterExceptionalBranches(branches):
filtered_branches = []
exception_branch = False
for i in range(0, len(branches), 2):
if i+1 >= len(branches):
filtered_branches.append(branches[i])
break
# Filter exceptional branch noise
if branches[i+1]["throw"]:
exception_branch = True
continue
# Filter initializer list noise
if exception_branch and emptyBranchSet(branches[i], branches[i+1]) and len(filtered_branches) >= 2 and matchingBranchSet(filtered_branches[-1], filtered_branches[-2]):
return []
filtered_branches.append(branches[i])
filtered_branches.append(branches[i+1])
return filtered_branches
def distillLine(line_raw, lines, branches, include_exceptional_branches):
line_number = int(line_raw["line_number"])
count = int(line_raw["count"])
if line_number not in lines:
lines[line_number] = count
else:
lines[line_number] += count
# Filter out exceptional branches by default unless requested otherwise
if not include_exceptional_branches:
line_raw["branches"] = filterExceptionalBranches(line_raw["branches"])
# Increment all branch counts
for i, branch in enumerate(line_raw["branches"]):
if line_number not in branches:
branches[line_number] = []
blen = len(branches[line_number])
glen = len(line_raw["branches"])
if blen < glen:
branches[line_number] += [0] * (glen - blen)
branches[line_number][i] += int(branch["count"])
def distillSource(source_raw, sources, test_name, include_exceptional_branches):
source_name = source_raw["file_abs"]
if source_name not in sources:
sources[source_name] = {
test_name: {
"functions": {},
"branches": {},
"lines": {}
}
}
for function in source_raw["functions"]:
distillFunction(function, sources[source_name][test_name]["functions"])
for line in source_raw["lines"]:
distillLine(line, sources[source_name][test_name]["lines"], sources[source_name][test_name]["branches"], include_exceptional_branches)
def dumpToJson(intermediate, output):
with open(output, "w") as f:
json.dump(intermediate, f)
def getGcovFilterOptions(args):
return {
"sources": set([os.path.abspath(s) for s in args.sources]), #Make paths absolute, use set for fast lookups
"include": args.includepost,
"exclude": args.excludepost,
}
def addDicts(dict1, dict2):
"""Add dicts together by value. i.e. addDicts({"a":1,"b":0}, {"a":2}) == {"a":3,"b":0}."""
result = {k:v for k,v in dict1.items()}
for k,v in dict2.items():
if k in result:
result[k] += v
else:
result[k] = v
return result
def addLists(list1, list2):
"""Add lists together by value. i.e. addLists([1,1], [2,2]) == [3,3]."""
# Find big list and small list
blist, slist = list(list2), list(list1)
if len(list1) > len(list2):
blist, slist = slist, blist
# Overlay small list onto big list
for i, b in enumerate(slist):
blist[i] += b
return blist
def combineReports(base, overlay):
for source, scov in overlay["sources"].items():
# Combine Source Coverage
if source not in base["sources"]:
base["sources"][source] = scov
continue
for test_name, tcov in scov.items():
# Combine Source Test Name Coverage
if test_name not in base["sources"][source]:
base["sources"][source][test_name] = tcov
continue
# Drill down and create convenience variable
base_data = base["sources"][source][test_name]
# Combine Line Coverage
base_data["lines"] = addDicts(base_data["lines"], tcov["lines"])
# Combine Branch Coverage
for branch, cov in tcov["branches"].items():
if branch not in base_data["branches"]:
base_data["branches"][branch] = cov
else:
base_data["branches"][branch] = addLists(base_data["branches"][branch], cov)
# Combine Function Coverage
for function, cov in tcov["functions"].items():
if function not in base_data["functions"]:
base_data["functions"][function] = cov
else:
base_data["functions"][function]["execution_count"] += cov["execution_count"]
def parseInfo(path):
"""Parse an lcov .info file into fastcov json."""
fastcov_json = {
"sources": {}
}
with open(path) as f:
for line in f:
if line.startswith("TN:"):
current_test_name = line[3:].strip()
elif line.startswith("SF:"):
current_sf = line[3:].strip()
fastcov_json["sources"][current_sf] = {
current_test_name: {
"functions": {},
"branches": {},
"lines": {},
}
}
current_data = fastcov_json["sources"][current_sf][current_test_name]
elif line.startswith("FN:"):
line_num, function_name = line[3:].strip().split(",")
current_data["functions"][function_name] = {}
current_data["functions"][function_name]["start_line"] = int(line_num)
elif line.startswith("FNDA:"):
count, function_name = line[5:].strip().split(",")
current_data["functions"][function_name]["execution_count"] = int(count)
elif line.startswith("DA:"):
line_num, count = line[3:].strip().split(",")
current_data["lines"][line_num] = int(count)
elif line.startswith("BRDA:"):
branch_tokens = line[5:].strip().split(",")
line_num, count = branch_tokens[0], branch_tokens[-1]
if line_num not in current_data["branches"]:
current_data["branches"][line_num] = []
current_data["branches"][line_num].append(int(count))
return fastcov_json
def convertKeysToInt(report):
for source in report["sources"].keys():
for test_name in report["sources"][source].keys():
report_data = report["sources"][source][test_name]
report_data["lines"] = {int(k):v for k,v in report_data["lines"].items()}
report_data["branches"] = {int(k):v for k,v in report_data["branches"].items()}
def parseAndCombine(paths):
base_report = {}
for path in paths:
if path.endswith(".json"):
with open(path) as f:
report = json.load(f)
elif path.endswith(".info"):
report = parseInfo(path)
else:
logging.error("Currently only fastcov .json and lcov .info supported for combine operations, aborting due to %s...\n", path)
sys.exit(EXIT_CODES["unsupported_coverage_format"])
# In order for sorting to work later when we serialize,
# make sure integer keys are int
convertKeysToInt(report)
if not base_report:
base_report = report
logging.info("Setting {} as base report".format(path))
else:
combineReports(base_report, report)
logging.info("Adding {} to base report".format(path))
return base_report
def getCombineCoverage(args):
logging.info("Performing combine operation")
fastcov_json = parseAndCombine(args.combine)
filterFastcov(fastcov_json, args)
return fastcov_json
def getGcovCoverage(args):
# Need at least python 3.5 because of use of recursive glob
checkPythonVersion(sys.version_info[0:2])
# Need at least gcov 9.0.0 because that's when gcov JSON and stdout streaming was introduced
checkGcovVersion(getGcovVersion(args.gcov))
# Get list of gcda files to process
coverage_files = findCoverageFiles(args.directory, args.coverage_files, args.use_gcno)
# If gcda/gcno filtering is enabled, filter them out now
if args.excludepre:
coverage_files = getFilteredCoverageFiles(coverage_files, args.excludepre)
logging.info("Found {} coverage files after filtering".format(len(coverage_files)))
# We "zero" the "counters" by simply deleting all gcda files
if args.zerocounters:
removeFiles(coverage_files)
logging.info("Removed {} .gcda files".format(len(coverage_files)))
sys.exit()
# Fire up one gcov per cpu and start processing gcdas
gcov_filter_options = getGcovFilterOptions(args)
fastcov_json = processGcdas(args, coverage_files, gcov_filter_options)
# Summarize processing results
logging.info("Processed {} .gcov files ({} total, {} skipped)".format(GCOVS_TOTAL - GCOVS_SKIPPED, GCOVS_TOTAL, GCOVS_SKIPPED))
logging.debug("Final report will contain coverage for the following %d source files:\n %s", len(fastcov_json["sources"]), "\n ".join(fastcov_json["sources"]))
return fastcov_json
def dumpFile(fastcov_json, args):
if args.lcov:
dumpToLcovInfo(fastcov_json, args.output)
logging.info("Created lcov info file '{}'".format(args.output))
else:
dumpToJson(fastcov_json, args.output)
logging.info("Created fastcov json file '{}'".format(args.output))
def tupleToDotted(tup):
return ".".join(map(str, tup))
def parseArgs():
parser = argparse.ArgumentParser(description='A parallel gcov wrapper for fast coverage report generation')
parser.add_argument('-z', '--zerocounters', dest='zerocounters', action="store_true", help='Recursively delete all gcda files')
# Enable Branch Coverage
parser.add_argument('-b', '--branch-coverage', dest='branchcoverage', action="store_true", help='Include only the most useful branches in the coverage report.')
parser.add_argument('-B', '--exceptional-branch-coverage', dest='xbranchcoverage', action="store_true", help='Include ALL branches in the coverage report (including potentially noisy exceptional branches).')
parser.add_argument('-A', '--exclude-br-lines-starting-with', dest='exclude_branches_sw', nargs="+", metavar='', default=[], help='Exclude branches from lines starting with one of the provided strings (i.e. assert, return, etc.)')
parser.add_argument('-a', '--include-br-lines-starting-with', dest='include_branches_sw', nargs="+", metavar='', default=[], help='Include only branches from lines starting with one of the provided strings (i.e. if, else, while, etc.)')
parser.add_argument('-X', '--skip-exclusion-markers', dest='skip_exclusion_markers', action="store_true", help='Skip reading source files to search for lcov exclusion markers (such as "LCOV_EXCL_LINE")')
parser.add_argument('-x', '--scan-exclusion-markers', dest='scan_exclusion_markers', action="store_true", help='(Combine operations) Force reading source files to search for lcov exclusion markers (such as "LCOV_EXCL_LINE")')
# Capture untested file coverage as well via gcno
parser.add_argument('-n', '--process-gcno', dest='use_gcno', action="store_true", help='Process both gcno and gcda coverage files. This option is useful for capturing untested files in the coverage report.')
# Filtering Options
parser.add_argument('-s', '--source-files', dest='sources', nargs="+", metavar='', default=[], help='Filter: Specify exactly which source files should be included in the final report. Paths must be either absolute or relative to current directory.')
parser.add_argument('-e', '--exclude', dest='excludepost', nargs="+", metavar='', default=[], help='Filter: Exclude source files from final report if they contain one of the provided substrings (i.e. /usr/include test/, etc.)')
parser.add_argument('-i', '--include', dest='includepost', nargs="+", metavar='', default=[], help='Filter: Only include source files in final report that contain one of the provided substrings (i.e. src/ etc.)')
parser.add_argument('-f', '--gcda-files', dest='coverage_files', nargs="+", metavar='', default=[], help='Filter: Specify exactly which gcda or gcno files should be processed. Note that specifying gcno causes both gcno and gcda to be processed.')
parser.add_argument('-E', '--exclude-gcda', dest='excludepre', nargs="+", metavar='', default=[], help='Filter: Exclude gcda or gcno files from being processed via simple find matching (not regex)')
parser.add_argument('-g', '--gcov', dest='gcov', default='gcov', help='Which gcov binary to use')
parser.add_argument('-d', '--search-directory', dest='directory', default=".", help='Base directory to recursively search for gcda files (default: .)')
parser.add_argument('-c', '--compiler-directory', dest='cdirectory', default=".", help='Base directory compiler was invoked from (default: .) \
This needs to be set if invoking fastcov from somewhere other than the base compiler directory.')
parser.add_argument('-j', '--jobs', dest='jobs', type=int, default=multiprocessing.cpu_count(), help='Number of parallel gcov to spawn (default: {}).'.format(multiprocessing.cpu_count()))
parser.add_argument('-m', '--minimum-chunk-size', dest='minimum_chunk', type=int, default=5, help='Minimum number of files a thread should process (default: 5). \
If you have only 4 gcda files but they are monstrously huge, you could change this value to a 1 so that each thread will only process 1 gcda. Otherwise fastcov will spawn only 1 thread to process all of them.')
parser.add_argument('-F', '--fallback-encodings', dest='fallback_encodings', nargs="+", metavar='', default=[], help='List of encodings to try if opening a source file with the default fails (i.e. latin1, etc.). This option is not usually needed.')
parser.add_argument('-l', '--lcov', dest='lcov', action="store_true", help='Output in lcov info format instead of fastcov json')
parser.add_argument('-o', '--output', dest='output', default="coverage.json", help='Name of output file (default: coverage.json)')
parser.add_argument('-q', '--quiet', dest='quiet', action="store_true", help='Suppress output to stdout')
parser.add_argument('-t', '--test-name', dest='test_name', default="", help='Specify a test name for the coverage. Equivalent to lcov\'s `-t`.')
parser.add_argument('-C', '--add-tracefile', dest='combine', nargs="+", help='Combine multiple coverage files into one. If this flag is specified, fastcov will do a combine operation instead invoking gcov. Equivalent to lcov\'s `-a`.')
parser.add_argument('-V', '--verbose', dest="verbose", action="store_true", help="Print more detailed information about what fastcov is doing")
parser.add_argument('-v', '--version', action="version", version='%(prog)s {version}'.format(version=__version__), help="Show program's version number and exit")
args = parser.parse_args()
return args
def checkPythonVersion(version):
"""Exit if the provided python version is less than the supported version."""
if version < MINIMUM_PYTHON:
sys.stderr.write("Minimum python version {} required, found {}\n".format(tupleToDotted(MINIMUM_PYTHON), tupleToDotted(version)))
sys.exit(EXIT_CODES["python_version"])
def checkGcovVersion(version):
"""Exit if the provided gcov version is less than the supported version."""
if version < MINIMUM_GCOV:
sys.stderr.write("Minimum gcov version {} required, found {}\n".format(tupleToDotted(MINIMUM_GCOV), tupleToDotted(version)))
sys.exit(EXIT_CODES["gcov_version"])
def setupLogging(quiet, verbose):
handler = logging.StreamHandler()
handler.setFormatter(FastcovFormatter("[%(levelname)s]: %(message)s"))
root = logging.getLogger()
root.setLevel(logging.INFO)
root.addHandler(handler)
if not quiet:
logging.disable(level=logging.NOTSET) # Re-enable logging
if verbose:
root.setLevel(logging.DEBUG)
def main():
args = parseArgs()
# Setup logging
setupLogging(args.quiet, args.verbose)
# Get report from appropriate source
if args.combine:
fastcov_json = getCombineCoverage(args)
skip_exclusion_markers = not args.scan_exclusion_markers
else:
fastcov_json = getGcovCoverage(args)
skip_exclusion_markers = args.skip_exclusion_markers
# Scan for exclusion markers
if not skip_exclusion_markers:
scanExclusionMarkers(fastcov_json, args.jobs, args.exclude_branches_sw, args.include_branches_sw, args.minimum_chunk, args.fallback_encodings)
logging.info("Scanned {} source files for exclusion markers".format(len(fastcov_json["sources"])))
# Dump to desired file format
dumpFile(fastcov_json, args)
# If there was an error along the way, but we still completed the pipeline...
if EXIT_CODE:
sys.exit(EXIT_CODE)
# Set package version... it's way down here so that we can call tupleToDotted
__version__ = tupleToDotted(FASTCOV_VERSION)
if __name__ == '__main__':
main()

View File

@ -1,257 +0,0 @@
#!/usr/bin/env perl
# See copyright, etc in below POD section.
######################################################################
use warnings;
use Getopt::Long;
#use Data::Dumper; $Data::Dumper::Indent=1; $Data::Dumper::Sortkeys=1; #Debug
use IO::File;
use IO::Dir;
use Pod::Usage;
use strict;
use vars qw($Debug);
our $VERSION = '0.001';
our $Opt_Widen = 1;
#======================================================================
# main
autoflush STDOUT 1;
autoflush STDERR 1;
Getopt::Long::config("no_auto_abbrev");
if (! GetOptions (
"debug" => sub { $Debug = 1; },
"help" => sub { print "Version $VERSION\n";
pod2usage(-verbose=>2, -exitval => 0,
output=>\*STDOUT, -noperldoc=>1); },
"narrow!" => sub { $Opt_Widen = 0; },
"version" => sub { print "Version $VERSION\n"; exit(0); },
"widen!" => sub { $Opt_Widen = 1; }, # Default, undocumented
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
)) {
die "%Error: Bad usage, try 'git_untabify --help'\n";
}
read_patch();
#######################################################################
sub read_patch {
my $filename = undef;
my $lineno = 0;
my $hunk = 0;
my $editlines = {};
while (defined(my $line = <STDIN>)) {
chomp $line;
if ($line =~ m!^\+\+\+ b/(.*)!) {
find_edits($editlines);
edit_file($filename, $editlines);
$filename = $1;
$lineno = 0;
$editlines = {};
print "FILE $filename\n" if $Debug;
}
elsif ($line =~ m!^@@ -?[0-9]+,?[0-9]* \+?([0-9]+)!) {
$lineno = $1 - 1;
++$hunk;
print " LINE $1 $line" if $Debug;
}
elsif ($line =~ m!^ !) {
++$lineno;
$editlines->{$lineno} = {line => $line,
hunk => $hunk,
user_edit => 0, };
}
elsif ($line =~ m!^\+!) {
++$lineno;
print " $lineno: $line" if $Debug;
$editlines->{$lineno} = {line => $line,
hunk => $hunk,
user_edit => 1, };
}
}
find_edits($editlines);
edit_file($filename, $editlines);
}
sub find_edits {
my $editlines = shift;
# Expand edit regions so if have edited line, non-edited line, edited
# line, we will tab expand the middle ones.
my %hunk_firstlines;
foreach my $lineno (sort {$a <=> $b} keys %$editlines) {
my $hunk = $editlines->{$lineno}{hunk};
$hunk_firstlines{$hunk} ||= $lineno if $editlines->{$lineno}{user_edit};
}
my %hunk_lastlines;
foreach my $lineno (sort {$b <=> $a} keys %$editlines) {
my $hunk = $editlines->{$lineno}{hunk};
$hunk_lastlines{$hunk} ||= $lineno if $editlines->{$lineno}{user_edit};
}
if ($Opt_Widen) {
# Expand to include }'s that finish basic block
foreach my $hunk (keys %hunk_lastlines) {
while (my $lineno = $hunk_lastlines{$hunk}) {
++$lineno;
if (($editlines->{$lineno}{line} || "")
=~ /^[+ ]\s+}[ \t};]*$/) {
$hunk_lastlines{$hunk} = $lineno;
} else {
last;
}
}
}
# Expand to always untabify at least 3 lines (so that future diff will
# have non-tabs within a edit hunk distance
foreach my $hunk (keys %hunk_firstlines) {
if ($hunk_firstlines{$hunk} == $hunk_lastlines{$hunk}) {
--$hunk_firstlines{$hunk};
++$hunk_lastlines{$hunk};
}
elsif ($hunk_firstlines{$hunk}+1 == $hunk_lastlines{$hunk}) {
++$hunk_lastlines{$hunk};
}
}
}
foreach my $lineno (sort {$a <=> $b} keys %$editlines) {
if (($editlines->{$lineno}{line}||"") =~ /\t/) {
my $hunk = $editlines->{$lineno}{hunk};
if ($hunk_firstlines{$hunk} <= $lineno && $hunk_lastlines{$hunk} >= $lineno) {
$editlines->{$lineno}{editit} = 1;
}
}
}
}
sub edit_file {
my $filename = shift;
my $editlines = shift;
my @editits;
foreach my $lineno (sort {$a <=> $b} keys %$editlines) {
push @editits, $lineno if $editlines->{$lineno}{editit};
}
return if $#editits < 0;
if (ignore($filename)) {
print "%Warning: Ignoring $filename\n";
return;
}
print "Edit $filename ",join(",",@editits),"\n";
my $lineno = 0;
my @out;
{
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename\n";
while (defined(my $line = $fh->getline)) {
++$lineno;
if ($editlines->{$lineno}{editit}) {
print $line;
push @out, untabify($line);
} else {
push @out, $line;
}
}
$fh->close;
}
{
my $fh = IO::File->new(">${filename}.untab") or die "%Error: $! ${filename}.untab,";
$fh->print(join('',@out));
$fh->close;
my ($dev,$ino,$mode) = stat($filename);
chmod $mode, "${filename}.untab";
}
rename("${filename}.untab", $filename) or die "%Error: $! ${filename}.untab,";
}
sub ignore {
my $filename = shift;
return 1 if ($filename =~ /(Makefile|\.mk)/);
return 1 if ($filename =~ /\.(y|l|out|vcd)$/);
return 1 if ($filename =~ /gtkwave/);
#
return 0 if ($filename =~ /\.(sv|v|vh|svh|h|vc|cpp|pl)$/);
return 0;
}
sub untabify {
my $line = shift;
my $out = "";
my $col = 0;
foreach my $c (split //, $line) {
if ($c eq "\t") {
my $destcol = int(($col+8)/8)*8;
while ($col < $destcol) { ++$col; $out .= " "; }
} else {
$out .= $c;
$col++;
}
}
return $out;
}
#######################################################################
__END__
=pod
=head1 NAME
git_untabify - Pipe a git diff report and untabify differences
=head1 SYNOPSIS
git diff a..b | git_untabify
=head1 DESCRIPTION
Take a patch file, and edit the files in the destination patch list to
untabify the related patch lines.
=head1 ARGUMENTS
=over 4
=item --help
Displays this message and program version and exits.
=item --narrow
Only edit lines which the user edited.
If not provided, also edit other lines within at least a 3 line area around
the edit, and between any edits within the same hunk.
=item --version
Displays program version and exits.
=back
=head1 DISTRIBUTION
Copyright 2005-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.
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
=head1 AUTHORS
Wilson Snyder <wsnyder@wsnyder.org>
=head1 SEE ALSO
=cut
######################################################################
### Local Variables:
### compile-command: "./git_untabify "
### End:

View File

@ -84,7 +84,7 @@ maintainer-copy::
clean mostlyclean distclean maintainer-clean::
-rm -rf obj_* *.log *.dmp *.vpd core
-rm -f *.o *.d perlxsi.c *_gen_*
-rm -f *__gen*
-rm -f *__gen* obj_*
-rm -f .objcache*
distclean maintainer-clean::

View File

@ -211,11 +211,13 @@ RAW_OBJS = \
V3LinkCells.o \
V3LinkDot.o \
V3LinkJump.o \
V3LinkInc.o \
V3LinkLValue.o \
V3LinkLevel.o \
V3LinkParse.o \
V3LinkResolve.o \
V3Localize.o \
V3MergeCond.o \
V3Name.o \
V3Number.o \
V3Options.o \
@ -246,6 +248,7 @@ RAW_OBJS = \
V3Undriven.o \
V3Unknown.o \
V3Unroll.o \
V3Waiver.o \
V3Width.o \
V3WidthSel.o \
@ -287,21 +290,21 @@ V3Number_test: V3Number_test.o
$(PERL) $(ASTGEN) -I$(srcdir) $*.cpp
%.o: %.cpp
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $<
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@
%.o: %.c
$(OBJCACHE) ${CC} ${CFLAGS} ${CPPFLAGSWALL} -c $<
$(OBJCACHE) ${CC} ${CFLAGS} ${CPPFLAGSWALL} -c $< -o $@
V3ParseLex.o: V3ParseLex.cpp V3Lexer.yy.cpp V3ParseBison.c
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $<
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
V3ParseGrammar.o: V3ParseGrammar.cpp V3ParseBison.c
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $<
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
V3ParseImp.o: V3ParseImp.cpp V3ParseBison.c
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $<
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $<
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
#### Generated files

View File

@ -50,7 +50,6 @@ protected:
class ActiveNamer : public ActiveBaseVisitor {
private:
typedef std::map<string, AstActive*> ActiveNameMap;
// STATE
AstScope* m_scopep; // Current scope to add statement to
AstActive* m_iActivep; // For current scope, the IActive we're building

View File

@ -89,7 +89,7 @@ private:
}
// Move the SENTREE for each active up to the global level.
// This way we'll easily see what clock domains are identical
AstSenTree* wantp = m_finder.getSenTree(nodep->fileline(), sensesp);
AstSenTree* wantp = m_finder.getSenTree(sensesp);
UINFO(4, " lookdone\n");
if (wantp != sensesp) {
// Move the active's contents to the other active
@ -108,7 +108,7 @@ private:
// No need to do statements under it, they're already moved.
// iterateChildren(nodep);
}
virtual void visit(AstInitial* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
virtual void visit(AstNodeProcedure* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
@ -117,15 +117,9 @@ private:
virtual void visit(AstAssignW* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstAlways* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstFinal* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been deleted");
}
//--------------------
virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate
virtual void visit(AstVarScope*) VL_OVERRIDE {} // Accelerate

View File

@ -23,9 +23,6 @@
#include "V3GraphDfa.h"
#include "V3Stats.h"
#include <cstdarg>
#include <iomanip>
//######################################################################
// Assert class functions

View File

@ -23,9 +23,6 @@
#include "V3Global.h"
#include "V3AssertPre.h"
#include <cstdarg>
#include <iomanip>
//######################################################################
// Assert class functions

View File

@ -23,7 +23,6 @@
#include "V3Broken.h"
#include "V3String.h"
#include <cstdarg>
#include <iomanip>
#include <memory>
@ -727,7 +726,7 @@ void AstNode::deleteNode() {
this->m_op4p = reinterpret_cast<AstNode*>(0x1);
if (
#if !defined(VL_DEBUG) || defined(VL_LEAK_CHECKS)
1
true
#else
!v3Global.opt.debugLeak()
#endif
@ -1129,6 +1128,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
*logsp << "No changes since last dump!\n";
} else {
dumpTree(*logsp);
editCountSetLast(); // Next dump can indicate start from here
}
}
}
@ -1139,13 +1139,11 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
// set by other steps if it is called in the middle of other operations
if (AstNetlist* netp = VN_CAST(this, Netlist)) V3Broken::brokenAll(netp);
}
// Next dump can indicate start from here
editCountSetLast();
}
void AstNode::v3errorEndFatal(std::ostringstream& str) const {
v3errorEnd(str);
assert(0);
assert(0); // LCOV_EXCL_LINE
VL_UNREACHABLE
}
@ -1154,10 +1152,10 @@ string AstNode::locationStr() const {
const AstNode* backp = this;
int itmax = 10000; // Max iterations before giving up on location search
while (backp) {
if (--itmax < 0) {
if (VL_UNCOVERABLE(--itmax < 0)) {
// Likely some circular back link, and V3Ast is trying to report a low-level error
UINFO(1, "Ran out of iterations finding locationStr on " << backp << endl);
return "";
return ""; // LCOV_EXCL_LINE
}
const AstScope* scopep;
if ((scopep = VN_CAST_CONST(backp, Scope))) {

View File

@ -193,12 +193,14 @@ class AstCFuncType {
public:
enum en {
FT_NORMAL,
TRACE_REGISTER,
TRACE_INIT,
TRACE_INIT_SUB,
TRACE_FULL,
TRACE_FULL_SUB,
TRACE_CHANGE,
TRACE_CHANGE_SUB
TRACE_CHANGE_SUB,
TRACE_CLEANUP
};
enum en m_e;
inline AstCFuncType()
@ -210,10 +212,7 @@ public:
: m_e(static_cast<en>(_e)) {}
operator en() const { return m_e; }
// METHODS
bool isTrace() const {
return (m_e == TRACE_INIT || m_e == TRACE_INIT_SUB || m_e == TRACE_FULL
|| m_e == TRACE_FULL_SUB || m_e == TRACE_CHANGE || m_e == TRACE_CHANGE_SUB);
}
bool isTrace() const { return m_e != FT_NORMAL; }
};
inline bool operator==(const AstCFuncType& lhs, const AstCFuncType& rhs) {
return lhs.m_e == rhs.m_e;
@ -258,7 +257,7 @@ public:
case ET_HIGHEDGE: return ET_LOWEDGE;
case ET_LOWEDGE: return ET_HIGHEDGE;
default: UASSERT_STATIC(0, "Inverting bad edgeType()");
};
}
return VEdgeType::ET_ILLEGAL;
}
const char* ascii() const {
@ -1081,9 +1080,6 @@ public:
// - Also used to allow parameter passing up/down iterate calls
class WidthVP;
class LinkVP;
class OrderBlockNU;
class OrderVarNU;
class V3GraphVertex;
class VSymEnt;
@ -1104,15 +1100,11 @@ public:
explicit VNUser(void* p) { m_u.up = p; }
~VNUser() {}
// Casters
WidthVP* c() { return ((WidthVP*)m_u.up); }
LinkVP* toLinkVP() { return ((LinkVP*)m_u.up); }
VSymEnt* toSymEnt() { return ((VSymEnt*)m_u.up); }
AstNode* toNodep() { return ((AstNode*)m_u.up); }
OrderBlockNU* toOrderBlock() { return ((OrderBlockNU*)m_u.up); }
OrderVarNU* toOrderVar() { return ((OrderVarNU*)m_u.up); }
V3GraphVertex* toGraphVertex() { return ((V3GraphVertex*)m_u.up); }
inline int toInt() { return m_u.ui; }
static inline VNUser fromZero() { return VNUser(0); }
WidthVP* c() const { return reinterpret_cast<WidthVP*>(m_u.up); }
VSymEnt* toSymEnt() const { return reinterpret_cast<VSymEnt*>(m_u.up); }
AstNode* toNodep() const { return reinterpret_cast<AstNode*>(m_u.up); }
V3GraphVertex* toGraphVertex() const { return reinterpret_cast<V3GraphVertex*>(m_u.up); }
int toInt() const { return m_u.ui; }
static inline VNUser fromInt(int i) { return VNUser(i); }
};
@ -1318,7 +1310,7 @@ public:
class FullValue {}; // for creator type-overload selection
explicit V3Hash(Illegal) { m_both = 0; }
// Saving and restoring inside a userp
explicit V3Hash(VNUser u) { m_both = u.toInt(); }
explicit V3Hash(const VNUser& u) { m_both = u.toInt(); }
V3Hash operator+=(const V3Hash& rh) {
setBoth(depth() + rh.depth(), (hshval() * 31 + rh.hshval()));
return *this;
@ -1355,12 +1347,12 @@ public:
// Prefetch a node.
// The if() makes it faster, even though prefetch won't fault on null pointers
#define ASTNODE_PREFETCH(nodep) \
{ \
do { \
if (nodep) { \
VL_PREFETCH_RD(&((nodep)->m_nextp)); \
VL_PREFETCH_RD(&((nodep)->m_iterpp)); \
} \
}
} while (false)
class AstNode {
// v ASTNODE_PREFETCH depends on below ordering of members
@ -1508,6 +1500,7 @@ public:
}
bool brokeExists() const;
bool brokeExistsAbove() const;
bool brokeExistsBelow() const;
// CONSTRUCTORS
virtual ~AstNode() {}
@ -1788,20 +1781,22 @@ public:
static void dumpTreeFileGdb(const char* filenamep = NULL);
// METHODS - queries
// Else a $display, etc, that must be ordered with other displays
virtual bool isPure() const { return true; }
// Changes control flow, disable some optimizations
virtual bool isBrancher() const { return false; }
// Else a AstTime etc that can't be pushed out
virtual bool isGateOptimizable() const { return true; }
// GateDedupable is a slightly larger superset of GateOptimzable (eg, AstNodeIf)
virtual bool isGateDedupable() const { return isGateOptimizable(); }
// Else a AstTime etc that can't be substituted out
virtual bool isSubstOptimizable() const { return true; }
// Else a AstTime etc which output can't be predicted from input
virtual bool isPredictOptimizable() const { return true; }
// Needs verilated_heavy.h (uses std::string or some others)
virtual bool isHeavy() const { return false; }
// Else creates output or exits, etc, not unconsumed
virtual bool isOutputter() const { return false; }
// Else a AstTime etc which output can't be predicted from input
virtual bool isPredictOptimizable() const { return true; }
// Else a $display, etc, that must be ordered with other displays
virtual bool isPure() const { return true; }
// Else a AstTime etc that can't be substituted out
virtual bool isSubstOptimizable() const { return true; }
// isUnlikely handles $stop or similar statement which means an above IF
// statement is unlikely to be taken
virtual bool isUnlikely() const { return false; }
@ -1998,6 +1993,43 @@ public:
virtual bool same(const AstNode*) const { return true; }
};
class AstNodeQuadop : public AstNodeMath {
// Quaternary math
public:
AstNodeQuadop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths, AstNode* fhs)
: AstNodeMath(t, fl) {
setOp1p(lhs);
setOp2p(rhs);
setOp3p(ths);
setOp4p(fhs);
}
ASTNODE_BASE_FUNCS(NodeQuadop)
AstNode* lhsp() const { return op1p(); }
AstNode* rhsp() const { return op2p(); }
AstNode* thsp() const { return op3p(); }
AstNode* fhsp() const { return op4p(); }
void lhsp(AstNode* nodep) { return setOp1p(nodep); }
void rhsp(AstNode* nodep) { return setOp2p(nodep); }
void thsp(AstNode* nodep) { return setOp3p(nodep); }
void fhsp(AstNode* nodep) { return setOp4p(nodep); }
// METHODS
// Set out to evaluation of a AstConst'ed
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths, const V3Number& fhs)
= 0;
virtual bool cleanLhs() const = 0; // True if LHS must have extra upper bits zero
virtual bool cleanRhs() const = 0; // True if RHS must have extra upper bits zero
virtual bool cleanThs() const = 0; // True if THS must have extra upper bits zero
virtual bool cleanFhs() const = 0; // True if THS must have extra upper bits zero
virtual bool sizeMattersLhs() const = 0; // True if output result depends on lhs size
virtual bool sizeMattersRhs() const = 0; // True if output result depends on rhs size
virtual bool sizeMattersThs() const = 0; // True if output result depends on ths size
virtual bool sizeMattersFhs() const = 0; // True if output result depends on ths size
virtual int instrCount() const { return widthInstrs(); }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode*) const { return true; }
};
class AstNodeBiCom : public AstNodeBiop {
// Binary math with commutative properties
public:
@ -2090,6 +2122,20 @@ public:
virtual bool same(const AstNode*) const { return true; }
};
class AstNodeProcedure : public AstNode {
// IEEE procedure: initial, final, always
public:
AstNodeProcedure(AstType t, FileLine* fl, AstNode* bodysp)
: AstNode(t, fl) {
addNOp2p(bodysp);
}
ASTNODE_BASE_FUNCS(NodeProcedure)
// METHODS
AstNode* bodysp() const { return op2p(); } // op2 = Statements to evaluate
void addStmtp(AstNode* nodep) { addOp2p(nodep); }
bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); }
};
class AstNodeStmt : public AstNode {
// Statement -- anything that's directly under a function
bool m_statement; // Really a statement (e.g. not a function with return)
@ -2323,9 +2369,8 @@ public:
virtual AstNodeDType* skipRefToEnump() const = 0;
// (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
virtual int widthAlignBytes() const = 0;
virtual int
// (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
widthTotalBytes() const = 0;
virtual int widthTotalBytes() const = 0;
virtual bool maybePointedTo() const { return true; }
// Iff has a non-null refDTypep(), as generic node function
virtual AstNodeDType* virtRefDTypep() const { return NULL; }
@ -2429,9 +2474,8 @@ public:
} // op1 = AstMember list
void addMembersp(AstNode* nodep) { addNOp1p(nodep); }
bool packed() const { return m_packed; }
bool packedUnsup() const {
return true;
} // packed() but as don't support unpacked, presently all structs
// packed() but as don't support unpacked, presently all structs
static bool packedUnsup() { return true; }
void isFourstate(bool flag) { m_isFourstate = flag; }
virtual bool isFourstate() const { return m_isFourstate; }
void clearCache() { m_members.clear(); }
@ -2440,7 +2484,7 @@ public:
MemberNameMap::const_iterator it = m_members.find(name);
return (it == m_members.end()) ? NULL : it->second;
}
int lsb() const { return 0; }
static int lsb() { return 0; }
int msb() const { return dtypep()->width() - 1; } // Packed classes look like arrays
VNumRange declRange() const { return VNumRange(msb(), lsb(), false); }
};
@ -2482,10 +2526,8 @@ public:
virtual V3Hash sameHash() const {
return V3Hash(V3Hash(m_refDTypep), V3Hash(msb()), V3Hash(lsb()));
}
AstNodeDType* getChildDTypep() const { return childDTypep(); }
AstNodeDType* childDTypep() const {
return VN_CAST(op1p(), NodeDType);
} // op1 = Range of variable
virtual AstNodeDType* getChildDTypep() const { return childDTypep(); }
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); }
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
@ -2680,11 +2722,13 @@ private:
string m_dotted; // Dotted part of scope the name()ed task/func is under or ""
string m_inlinedDots; // Dotted hierarchy flattened out
AstNodeModule* m_packagep; // Package hierarchy
bool m_pli; // Pli system call ($name)
public:
AstNodeFTaskRef(AstType t, FileLine* fl, bool statement, AstNode* namep, AstNode* pinsp)
: AstNodeStmt(t, fl, statement)
, m_taskp(NULL)
, m_packagep(NULL) {
, m_packagep(NULL)
, m_pli(false) {
setOp1p(namep);
addNOp3p(pinsp);
}
@ -2692,7 +2736,8 @@ public:
: AstNodeStmt(t, fl, statement)
, m_taskp(NULL)
, m_name(name)
, m_packagep(NULL) {
, m_packagep(NULL)
, m_pli(false) {
addNOp3p(pinsp);
}
ASTNODE_BASE_FUNCS(NodeFTaskRef)
@ -2716,6 +2761,8 @@ public:
void dotted(const string& name) { m_dotted = name; }
AstNodeModule* packagep() const { return m_packagep; }
void packagep(AstNodeModule* nodep) { m_packagep = nodep; }
bool pli() const { return m_pli; }
void pli(bool flag) { m_pli = flag; }
// op1 = namep
AstNode* namep() const { return op1p(); }
// op2 = reserved for AstMethodCall

View File

@ -24,7 +24,6 @@
#include "V3PartitionGraph.h" // Just for mtask dumping
#include "V3EmitCBase.h"
#include <cstdarg>
#include <iomanip>
#include <vector>
@ -282,16 +281,16 @@ string AstVar::verilogKwd() const {
class AstVar::VlArgTypeRecursed {
public:
string m_oref; // To output, reference part before name, "&"
string m_osuffix; // To output, suffixed after name, "[3]"
string m_oprefix; // To output, prefixed before name, "Foo_t"
void clear() {
m_oref.clear();
m_osuffix.clear();
m_oprefix.clear();
}
string refParen(const string& name) {
return m_oref.empty() ? name : "(" + m_oref + " " + name + ")";
bool m_isRef; // Is it a reference?
string m_type; // The base type, e.g.: "Foo_t"s
string m_dims; // Array dimensions, e.g.: "[3][2][1]"
string render(const string& name) {
string out;
out += m_type;
out += " ";
out += m_isRef ? "(&" + name + ")" : name;
out += m_dims;
return out;
}
};
@ -301,126 +300,86 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string&
string ostatic;
if (isStatic() && namespc.empty()) ostatic = "static ";
VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep(), false);
VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep());
string oname;
if (named) {
oname += " ";
if (!namespc.empty()) oname += namespc + "::";
oname += VIdProtect::protectIf(name(), protect());
}
return ostatic + info.m_oprefix + info.refParen(oname) + info.m_osuffix;
return ostatic + info.render(oname);
}
AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep,
bool arrayed) const {
bool compound) const {
VlArgTypeRecursed info;
info.m_isRef
= isDpiOpenArray() || (forFunc && (isWritable() || direction().isRefOrConstRef()));
dtypep = dtypep->skipRefp();
if (const AstAssocArrayDType* adtypep = VN_CAST_CONST(dtypep, AssocArrayDType)) {
VlArgTypeRecursed key = vlArgTypeRecurse(forFunc, adtypep->keyDTypep(), true);
VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true);
string out = "VlAssocArray<";
out += key.m_oprefix;
if (!key.m_osuffix.empty() || !key.m_oref.empty()) {
out += " " + key.m_osuffix + key.m_oref;
}
out += ", ";
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;
const VlArgTypeRecursed key = vlArgTypeRecurse(false, adtypep->keyDTypep(), true);
const VlArgTypeRecursed val = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">";
} 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;
const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
info.m_type = "VlQueue<" + sub.m_type + ">";
} else if (const AstQueueDType* adtypep = VN_CAST_CONST(dtypep, QueueDType)) {
VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true);
VlArgTypeRecursed info;
string out = "VlQueue<" + sub.m_oprefix;
if (!sub.m_osuffix.empty() || !sub.m_oref.empty()) {
out += " " + sub.m_osuffix + sub.m_oref;
}
const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
info.m_type = "VlQueue<" + sub.m_type;
// + 1 below as VlQueue uses 0 to mean unlimited, 1 to mean size() max is 1
if (adtypep->boundp()) out += ", " + cvtToStr(adtypep->boundConst() + 1);
out += "> ";
info.m_oprefix = out;
return info;
if (adtypep->boundp()) info.m_type += ", " + cvtToStr(adtypep->boundConst() + 1);
info.m_type += ">";
} else if (const AstClassRefDType* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) {
VlArgTypeRecursed info;
info.m_oprefix = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
return info;
info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
} else if (const AstUnpackArrayDType* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) {
VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), arrayed);
info.m_osuffix = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + info.m_osuffix;
return info;
} else if (const AstBasicDType* bdtypep = dtypep->basicp()) {
string otype;
string oarray;
bool strtype = bdtypep->keyword() == AstBasicDTypeKwd::STRING;
string bitvec;
if (!bdtypep->isOpaque() && !v3Global.opt.protectIds()) {
// We don't print msb()/lsb() as multidim packed would require recursion,
// and may confuse users as C++ data is stored always with bit 0 used
bitvec += "/*" + cvtToStr(dtypep->width() - 1) + ":0*/";
if (compound) {
v3fatalSrc("Dynamic arrays or queues with unpacked elements are not yet supported");
}
if ((forFunc && isReadOnly()) || bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR
|| bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR)
otype += "const ";
const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), compound);
info.m_type = sub.m_type;
info.m_dims = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + sub.m_dims;
} else if (const AstBasicDType* bdtypep = dtypep->basicp()) {
// We don't print msb()/lsb() as multidim packed would require recursion,
// and may confuse users as C++ data is stored always with bit 0 used
const string bitvec = (!bdtypep->isOpaque() && !v3Global.opt.protectIds())
? "/*" + cvtToStr(dtypep->width() - 1) + ":0*/"
: "";
if (bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) {
otype += "char*";
info.m_type = "const char*";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) {
otype += "VerilatedScope*";
info.m_type = "const VerilatedScope*";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::DOUBLE) {
otype += "double";
info.m_type = "double";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::FLOAT) {
otype += "float";
} else if (strtype) {
otype += "std::string";
info.m_type = "float";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::STRING) {
info.m_type = "std::string";
} else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width
otype += "CData" + bitvec;
info.m_type = "CData" + bitvec;
} else if (dtypep->widthMin() <= 16) {
otype += "SData" + bitvec;
info.m_type = "SData" + bitvec;
} else if (dtypep->widthMin() <= VL_IDATASIZE) {
otype += "IData" + bitvec;
info.m_type = "IData" + bitvec;
} else if (dtypep->isQuad()) {
otype += "QData" + bitvec;
info.m_type = "QData" + bitvec;
} else if (dtypep->isWide()) {
if (arrayed) {
otype += "VlWide<" + cvtToStr(dtypep->widthWords()) + "> ";
if (compound) {
info.m_type = "VlWide<" + cvtToStr(dtypep->widthWords()) + "> ";
} else {
otype += "WData" + bitvec; // []'s added later
oarray += "[" + cvtToStr(dtypep->widthWords()) + "]";
info.m_type += "WData" + bitvec; // []'s added later
info.m_dims = "[" + cvtToStr(dtypep->widthWords()) + "]";
}
}
string oref;
if (isDpiOpenArray()
|| (forFunc
&& (isWritable() || direction() == VDirection::REF
|| direction() == VDirection::CONSTREF || (strtype && isNonOutput())))) {
oref = "&";
}
VlArgTypeRecursed info;
info.m_oprefix = otype;
info.m_osuffix = oarray;
info.m_oref = oref;
// UINFO(9, "vlArgRec "<<"oprefix="<<info.m_oprefix<<" osuffix="<<info.m_osuffix
// <<" oref="<<info.m_oref<<" "<<dtypep);
return info;
} else {
v3fatalSrc("Unknown data type in var type emitter: " << dtypep->prettyName());
}
UASSERT_OBJ(!compound || info.m_dims.empty(), this, "Declaring C array inside compound type");
if (forFunc && isReadOnly() && info.m_isRef) { info.m_type = "const " + info.m_type; }
return info;
}
string AstVar::vlEnumType() const {
@ -472,29 +431,52 @@ string AstVar::vlEnumDir() const {
return out;
}
string AstVar::vlPropInit() const {
string AstVar::vlPropDecl(string propName) const {
string out;
out = vlEnumType(); // VLVT_UINT32 etc
out += ", " + vlEnumDir(); // VLVD_IN etc
if (AstBasicDType* bdtypep = basicp()) {
out += ", VerilatedVarProps::Packed()";
out += ", " + cvtToStr(bdtypep->left()) + ", " + cvtToStr(bdtypep->right());
}
bool first = true;
for (AstNodeDType* dtp = dtypep(); dtp;) {
std::vector<int> ulims; // Unpacked dimension limits
for (const AstNodeDType* dtp = dtypep(); dtp;) {
dtp = dtp->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
if (AstNodeArrayDType* adtypep = VN_CAST(dtp, NodeArrayDType)) {
if (first) {
out += ", VerilatedVarProps::Unpacked()";
first = false;
}
out += ", " + cvtToStr(adtypep->declRange().left()) + ", "
+ cvtToStr(adtypep->declRange().right());
if (const AstNodeArrayDType* const adtypep = VN_CAST_CONST(dtp, NodeArrayDType)) {
ulims.push_back(adtypep->declRange().left());
ulims.push_back(adtypep->declRange().right());
dtp = adtypep->subDTypep();
} else {
break; // AstBasicDType - nothing below
}
}
if (!ulims.empty()) {
out += "static const int " + propName + "__ulims[";
out += cvtToStr(ulims.size());
out += "] = {";
std::vector<int>::const_iterator it = ulims.begin();
out += cvtToStr(*it);
while (++it != ulims.end()) {
out += ", ";
out += cvtToStr(*it);
}
out += "};\n";
}
out += "static const VerilatedVarProps ";
out += propName;
out += "(";
out += vlEnumType(); // VLVT_UINT32 etc
out += ", " + vlEnumDir(); // VLVD_IN etc
if (const AstBasicDType* const bdtypep = basicp()) {
out += ", VerilatedVarProps::Packed()";
out += ", " + cvtToStr(bdtypep->left());
out += ", " + cvtToStr(bdtypep->right());
}
if (!ulims.empty()) {
out += ", VerilatedVarProps::Unpacked()";
out += ", " + cvtToStr(ulims.size() / 2);
out += ", " + propName + "__ulims";
}
out += ");\n";
return out;
}
@ -746,6 +728,14 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep) {
return nodep;
}
const char* AstJumpBlock::broken() const {
BROKEN_RTN(!labelp()->brokeExistsBelow());
return NULL;
}
void AstJumpBlock::cloneRelink() {
if (m_labelp->clonep()) m_labelp = m_labelp->clonep();
}
const char* AstScope::broken() const {
BROKEN_RTN(m_aboveScopep && !m_aboveScopep->brokeExists());
BROKEN_RTN(m_aboveCellp && !m_aboveCellp->brokeExists());
@ -753,7 +743,6 @@ const char* AstScope::broken() const {
BROKEN_RTN(m_modp && !m_modp->brokeExists());
return NULL;
}
void AstScope::cloneRelink() {
if (m_aboveScopep && m_aboveScopep->clonep()) m_aboveScopep->clonep();
if (m_aboveCellp && m_aboveCellp->clonep()) m_aboveCellp->clonep();
@ -761,7 +750,6 @@ void AstScope::cloneRelink() {
static_cast<AstNode*>(m_modp)->clonep();
}
}
string AstScope::nameDotless() const {
string out = shortName();
string::size_type pos;
@ -780,7 +768,6 @@ string AstScopeName::scopePrettyNameFormatter(AstText* scopeTextp) const {
if (out.substr(0, 1) == ".") out.replace(0, 1, "");
return AstNode::prettyName(out);
}
string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const {
string out;
for (AstText* textp = scopeTextp; textp; textp = VN_CAST(textp->nextp(), Text)) {
@ -977,27 +964,37 @@ void AstWhile::addNextStmt(AstNode* newp, AstNode* belowp) {
//======================================================================
// Per-type Debugging
// Render node address for dumps. By default this is just the address
// printed as hex, but with --dump-tree-addrids we map addresses to short
// strings with a bijection to aid human readability. Observe that this might
// not actually be a unique identifier as the address can get reused after a
// node has been freed.
static std::string nodeAddr(const AstNode* nodep) {
return v3Global.opt.dumpTreeAddrids() ? v3Global.ptrToId(nodep) : cvtToHex(nodep);
}
void AstNode::dump(std::ostream& str) const {
str << typeName() << " "
<< cvtToHex(this)
//<<" "<<cvtToHex(this)->m_backp
<< nodeAddr(this)
//<< " " << nodeAddr(m_backp)
<< " <e" << std::dec << editCount() << ((editCount() >= editCountLast()) ? "#>" : ">")
<< " {" << fileline()->filenameLetters() << std::dec << fileline()->lastLineno() << "}";
if (user1p()) str << " u1=" << cvtToHex(user1p());
if (user2p()) str << " u2=" << cvtToHex(user2p());
if (user3p()) str << " u3=" << cvtToHex(user3p());
if (user4p()) str << " u4=" << cvtToHex(user4p());
if (user5p()) str << " u5=" << cvtToHex(user5p());
<< " {" << fileline()->filenameLetters() << std::dec << fileline()->lastLineno()
<< fileline()->firstColumnLetters() << "}";
if (user1p()) str << " u1=" << nodeAddr(user1p());
if (user2p()) str << " u2=" << nodeAddr(user2p());
if (user3p()) str << " u3=" << nodeAddr(user3p());
if (user4p()) str << " u4=" << nodeAddr(user4p());
if (user5p()) str << " u5=" << nodeAddr(user5p());
if (hasDType()) {
// Final @ so less likely to by accident read it as a nodep
if (dtypep() == this) {
str << " @dt=this@";
} else {
str << " @dt=" << cvtToHex(dtypep()) << "@";
str << " @dt=" << nodeAddr(dtypep()) << "@";
}
if (AstNodeDType* dtp = dtypep()) { dtp->dumpSmall(str); }
} else { // V3Broken will throw an error
if (dtypep()) str << " %Error-dtype-exp=null,got=" << cvtToHex(dtypep());
if (dtypep()) str << " %Error-dtype-exp=null,got=" << nodeAddr(dtypep());
}
if (name() != "") {
if (VN_IS(this, Const)) {
@ -1142,6 +1139,15 @@ void AstJumpGo::dump(std::ostream& str) const {
str << "%Error:UNLINKED";
}
}
void AstJumpLabel::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " -> ";
if (blockp()) {
blockp()->dump(str);
} else {
str << "%Error:UNLINKED";
}
}
void AstMemberSel::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " -> ";
@ -1218,12 +1224,16 @@ void AstRange::dump(std::ostream& str) const {
}
void AstRefDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str);
if (defp()) {
if (typedefp() || subDTypep()) {
static bool s_recursing = false;
if (!s_recursing) { // Prevent infinite dump if circular typedefs
s_recursing = true;
str << " -> ";
defp()->dump(str);
if (typedefp()) {
typedefp()->dump(str);
} else if (subDTypep()) {
subDTypep()->dump(str);
}
s_recursing = false;
}
} else {
@ -1239,7 +1249,7 @@ void AstNodeDType::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (generic()) str << " [GENERIC]";
if (AstNodeDType* dtp = virtRefDTypep()) {
str << " refdt=" << cvtToHex(dtp);
str << " refdt=" << nodeAddr(dtp);
dtp->dumpSmall(str);
}
}
@ -1384,7 +1394,7 @@ void AstVarScope::dump(std::ostream& str) const {
}
void AstVarXRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (packagep()) { str << " pkg=" << cvtToHex(packagep()); }
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
if (lvalue()) {
str << " [LV] => ";
} else {
@ -1402,7 +1412,7 @@ void AstVarXRef::dump(std::ostream& str) const {
}
void AstVarRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (packagep()) { str << " pkg=" << cvtToHex(packagep()); }
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
if (lvalue()) {
str << " [LV] => ";
} else {
@ -1454,7 +1464,7 @@ void AstParseRef::dump(std::ostream& str) const {
}
void AstPackageRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (packagep()) { str << " pkg=" << cvtToHex(packagep()); }
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
str << " -> ";
if (packagep()) {
packagep()->dump(str);
@ -1462,7 +1472,10 @@ void AstPackageRef::dump(std::ostream& str) const {
str << "UNLINKED";
}
}
void AstDot::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstDot::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (colon()) str << "[::]";
}
void AstActive::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " => ";
@ -1474,7 +1487,7 @@ void AstActive::dump(std::ostream& str) const {
}
void AstNodeFTaskRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (packagep()) { str << " pkg=" << cvtToHex(packagep()); }
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
str << " -> ";
if (dotted() != "") { str << ".=" << dotted() << " "; }
if (taskp()) {
@ -1506,6 +1519,8 @@ void AstBegin::dump(std::ostream& str) const {
}
void AstCoverDecl::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (!page().empty()) str << " page=" << page();
if (!linescov().empty()) str << " lc=" << linescov();
if (this->dataDeclNullp()) {
str << " -> ";
this->dataDeclNullp()->dump(str);

View File

@ -319,6 +319,7 @@ public:
, m_packagep(NULL) {}
ASTNODE_NODE_FUNCS(Class)
virtual string verilogKwd() const { return "class"; }
virtual bool isHeavy() const { return true; }
virtual bool maybePointedTo() const { return true; }
virtual void dump(std::ostream& str) const;
virtual const char* broken() const {
@ -345,19 +346,18 @@ public:
};
class AstClassExtends : public AstNode {
// Children: AstClassRefDType during early parse, then moves to dtype
// Children: List of AstParseRef for packages/classes
// during early parse, then moves to dtype
public:
AstClassExtends(FileLine* fl, AstNodeDType* dtp)
AstClassExtends(FileLine* fl, AstNode* classOrPkgsp)
: ASTGEN_SUPER(fl) {
childDTypep(dtp); // Only for parser
setNOp1p(classOrPkgsp); // Only for parser
}
ASTNODE_NODE_FUNCS(ClassExtends)
virtual string verilogKwd() const { return "extends"; }
virtual bool hasDType() const { return true; }
AstNodeDType* getChildDTypep() const { return childDTypep(); }
// op1 = Type assigning to
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
AstNodeDType* classOrPkgsp() const { return VN_CAST(op1p(), NodeDType); }
void classOrPkgsp(AstNodeDType* nodep) { setOp1p(nodep); }
AstClass* classp() const; // Class being extended (after link)
};
@ -541,6 +541,7 @@ public:
virtual string prettyDTypeName() const;
virtual void dumpSmall(std::ostream& str) const;
virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); }
virtual bool isHeavy() const { return true; }
AstNodeDType* getChildDTypep() const { return childDTypep(); }
// op1 = Range of variable
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
@ -603,6 +604,7 @@ public:
virtual string prettyDTypeName() const;
virtual void dumpSmall(std::ostream& str) const;
virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); }
virtual bool isHeavy() const { return true; }
AstNodeDType* getChildDTypep() const { return childDTypep(); }
// op1 = Range of variable
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
@ -815,6 +817,7 @@ public:
BROKEN_RTN(dtypep() != this);
return NULL;
}
virtual bool isHeavy() const { return keyword() == AstBasicDTypeKwd::STRING; }
AstRange* rangep() const { return VN_CAST(op1p(), Range); } // op1 = Range of variable
void rangep(AstRange* nodep) { setNOp1p(nodep); }
void setSignedState(const VSigning& signst) {
@ -832,8 +835,8 @@ public:
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
// (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
virtual int widthAlignBytes() const;
virtual int
widthTotalBytes() const; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
// (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
virtual int widthTotalBytes() const;
virtual bool isFourstate() const { return keyword().isFourstate(); }
AstBasicDTypeKwd keyword() const { // Avoid using - use isSomething accessors instead
return m.m_keyword;
@ -855,9 +858,8 @@ public:
bool isDpiPrimitive() const { // DPI uses a primitive type
return !isDpiBitVec() && !isDpiLogicVec();
}
const VNumRange& nrange() const {
return m.m_nrange;
} // Generally the msb/lsb/etc funcs should be used instead
// Generally the msb/lsb/etc funcs should be used instead
const VNumRange& nrange() const { return m.m_nrange; }
int msb() const { return (rangep() ? rangep()->msbConst() : m.m_nrange.hi()); }
int lsb() const { return (rangep() ? rangep()->lsbConst() : m.m_nrange.lo()); }
int left() const { return littleEndian() ? lsb() : msb(); } // How to show a declaration
@ -1067,6 +1069,7 @@ public:
virtual void dumpSmall(std::ostream& str) const;
virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); }
virtual string prettyDTypeName() const;
virtual bool isHeavy() const { return true; }
AstNodeDType* getChildDTypep() const { return childDTypep(); }
// op1 = Range of variable
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
@ -1095,25 +1098,24 @@ public:
class AstRefDType : public AstNodeDType {
private:
// Pre-Width must reference the Typeref, not what it points to, as some child
// types like AstBracketArrayType will disappear and can't lose the handle
AstTypedef* m_typedefp; // referenced type
// Post-width typedefs are removed and point to type directly
AstNodeDType* m_refDTypep; // data type pointed to, BELOW the AstTypedef
string m_name; // Name of an AstTypedef
AstNodeModule* m_packagep; // Package hierarchy
public:
AstRefDType(FileLine* fl, const string& name)
: ASTGEN_SUPER(fl)
, m_typedefp(NULL)
, m_refDTypep(NULL)
, m_name(name)
, m_packagep(NULL) {}
AstRefDType(FileLine* fl, AstNodeDType* defp)
: ASTGEN_SUPER(fl)
, m_refDTypep(defp)
, m_packagep(NULL) {
dtypeFrom(defp->dtypep());
widthFromSub(subDTypep());
}
class FlagTypeOfExpr {}; // type(expr) for parser only
AstRefDType(FileLine* fl, FlagTypeOfExpr, AstNode* typeofp)
: ASTGEN_SUPER(fl)
, m_typedefp(NULL)
, m_refDTypep(NULL)
, m_packagep(NULL) {
setOp2p(typeofp);
@ -1121,47 +1123,53 @@ public:
ASTNODE_NODE_FUNCS(RefDType)
// METHODS
virtual const char* broken() const {
BROKEN_RTN(m_typedefp && !m_typedefp->brokeExists());
BROKEN_RTN(m_refDTypep && !m_refDTypep->brokeExists());
return NULL;
}
virtual void cloneRelink() {
if (m_typedefp && m_typedefp->clonep()) { m_typedefp = m_typedefp->clonep(); }
if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); }
}
virtual bool same(const AstNode* samep) const {
const AstRefDType* asamep = static_cast<const AstRefDType*>(samep);
return (m_refDTypep == asamep->m_refDTypep && m_name == asamep->m_name
&& m_packagep == asamep->m_packagep);
return (m_typedefp == asamep->m_typedefp && m_refDTypep == asamep->m_refDTypep
&& m_name == asamep->m_name && m_packagep == asamep->m_packagep);
}
virtual bool similarDType(AstNodeDType* samep) const {
return skipRefp()->similarDType(samep->skipRefp());
}
virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_refDTypep), V3Hash(m_packagep)); }
virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_typedefp), V3Hash(m_packagep)); }
virtual void dump(std::ostream& str = std::cout) const;
virtual string name() const { return m_name; }
virtual string prettyDTypeName() const {
return subDTypep() ? subDTypep()->name() : prettyName();
}
virtual AstBasicDType* basicp() const { return subDTypep() ? subDTypep()->basicp() : NULL; }
AstNodeDType* subDTypep() const {
if (typedefp()) return typedefp()->subDTypep();
return refDTypep(); // Maybe NULL
}
virtual AstNodeDType* skipRefp() const {
// Skip past both the Ref and the Typedef
if (defp()) {
return defp()->skipRefp();
if (subDTypep()) {
return subDTypep()->skipRefp();
} else {
v3fatalSrc("Typedef not linked");
return NULL;
}
}
virtual AstNodeDType* skipRefToConstp() const {
if (defp()) {
return defp()->skipRefToConstp();
if (subDTypep()) {
return subDTypep()->skipRefToConstp();
} else {
v3fatalSrc("Typedef not linked");
return NULL;
}
}
virtual AstNodeDType* skipRefToEnump() const {
if (defp()) {
return defp()->skipRefToEnump();
if (subDTypep()) {
return subDTypep()->skipRefToEnump();
} else {
v3fatalSrc("Typedef not linked");
return NULL;
@ -1171,15 +1179,13 @@ public:
virtual int widthTotalBytes() const { return dtypeSkipRefp()->widthTotalBytes(); }
void name(const string& flag) { m_name = flag; }
// op1 = Range of variable
AstNodeDType* dtypeSkipRefp() const { return defp()->skipRefp(); }
AstNodeDType* defp() const {
return m_refDTypep;
} // Code backward compatibility name for refDTypep
AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); }
AstTypedef* typedefp() const { return m_typedefp; }
void typedefp(AstTypedef* nodep) { m_typedefp = nodep; }
AstNodeDType* refDTypep() const { return m_refDTypep; }
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
virtual AstNodeDType* virtRefDTypep() const { return refDTypep(); }
virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); }
virtual AstNodeDType* subDTypep() const { return m_refDTypep; }
AstNodeModule* packagep() const { return m_packagep; }
void packagep(AstNodeModule* nodep) { m_packagep = nodep; }
AstNode* typeofp() const { return op2p(); }
@ -1902,11 +1908,11 @@ public:
VDirection declDirection() const { return m_declDirection; }
void varType(AstVarType type) { m_varType = type; }
void varType2Out() {
m_tristate = 0;
m_tristate = false;
m_direction = VDirection::OUTPUT;
}
void varType2In() {
m_tristate = 0;
m_tristate = false;
m_direction = VDirection::INPUT;
}
AstBasicDTypeKwd declKwd() const { return m_declKwd; }
@ -1918,7 +1924,7 @@ public:
string vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc = "") const;
string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc
string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc
string vlPropInit() const; // Return VerilatorVarProps initializer
string vlPropDecl(string propName) const; // Return VerilatorVarProps declaration
void combineType(AstVarType type);
AstNodeDType* getChildDTypep() const { return childDTypep(); }
// op1 = Range of variable
@ -2078,7 +2084,7 @@ public:
private:
class VlArgTypeRecursed;
VlArgTypeRecursed vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep,
bool arrayed) const;
bool compound = false) const;
};
class AstDefParam : public AstNode {
@ -2867,9 +2873,11 @@ public:
class AstDot : public AstNode {
// A dot separating paths in an AstVarXRef, AstFuncRef or AstTaskRef
// These are eliminated in the link stage
bool m_colon; // Is a "::" instead of a "." (lhs must be package/class)
public:
AstDot(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
: ASTGEN_SUPER(fl) {
AstDot(FileLine* fl, bool colon, AstNode* lhsp, AstNode* rhsp)
: ASTGEN_SUPER(fl)
, m_colon(colon) {
setOp1p(lhsp);
setOp2p(rhsp);
}
@ -2877,23 +2885,28 @@ public:
// For parser, make only if non-null package
static AstNode* newIfPkg(FileLine* fl, AstPackage* packagep, AstNode* rhsp) {
if (!packagep) return rhsp;
return new AstDot(fl, new AstPackageRef(fl, packagep), rhsp);
return new AstDot(fl, true, new AstPackageRef(fl, packagep), rhsp);
}
virtual void dump(std::ostream& str) const;
virtual string emitVerilog() { V3ERROR_NA_RETURN(""); }
virtual string emitC() { V3ERROR_NA_RETURN(""); }
AstNode* lhsp() const { return op1p(); }
AstNode* rhsp() const { return op2p(); }
bool colon() const { return m_colon; }
};
class AstUnbounded : public AstNode {
class AstUnbounded : public AstNodeMath {
// A $ in the parser, used for unbounded and queues
// Due to where is used, treated as Signed32
public:
explicit AstUnbounded(FileLine* fl)
: ASTGEN_SUPER(fl) {}
: ASTGEN_SUPER(fl) {
dtypeSetSigned32();
}
ASTNODE_NODE_FUNCS(Unbounded)
virtual string emitVerilog() { return "$"; }
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const { return true; }
};
//######################################################################
@ -3076,25 +3089,34 @@ public:
bool hasCombo() const; // Includes a COMBO SenItem
};
class AstAlways : public AstNode {
class AstFinal : public AstNodeProcedure {
public:
AstFinal(FileLine* fl, AstNode* bodysp)
: ASTGEN_SUPER(fl, bodysp) {}
ASTNODE_NODE_FUNCS(Final)
};
class AstInitial : public AstNodeProcedure {
public:
AstInitial(FileLine* fl, AstNode* bodysp)
: ASTGEN_SUPER(fl, bodysp) {}
ASTNODE_NODE_FUNCS(Initial)
};
class AstAlways : public AstNodeProcedure {
VAlwaysKwd m_keyword;
public:
AstAlways(FileLine* fl, VAlwaysKwd keyword, AstSenTree* sensesp, AstNode* bodysp)
: ASTGEN_SUPER(fl)
: ASTGEN_SUPER(fl, bodysp)
, m_keyword(keyword) {
addNOp1p(sensesp);
addNOp2p(bodysp);
}
ASTNODE_NODE_FUNCS(Always)
//
virtual void dump(std::ostream& str) const;
AstSenTree* sensesp() const { return VN_CAST(op1p(), SenTree); } // op1 = Sensitivity list
AstNode* bodysp() const { return op2p(); } // op2 = Statements to evaluate
void addStmtp(AstNode* nodep) { addOp2p(nodep); }
VAlwaysKwd keyword() const { return m_keyword; }
// Special accessors
bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); }
};
class AstAlwaysPublic : public AstNodeStmt {
@ -3300,14 +3322,17 @@ private:
string m_page;
string m_text;
string m_hier;
int m_column;
string m_linescov;
int m_offset; // Offset column numbers to uniq-ify IFs
int m_binNum; // Set by V3EmitCSyms to tell final V3Emit what to increment
public:
AstCoverDecl(FileLine* fl, int column, const string& page, const string& comment)
AstCoverDecl(FileLine* fl, const string& page, const string& comment, const string& linescov,
int offset)
: ASTGEN_SUPER(fl) {
m_text = comment;
m_page = page;
m_column = column;
m_text = comment;
m_linescov = linescov;
m_offset = offset;
m_binNum = 0;
m_dataDeclp = NULL;
}
@ -3325,10 +3350,11 @@ public:
virtual void dump(std::ostream& str) const;
virtual int instrCount() const { return 1 + 2 * instrCountLd(); }
virtual bool maybePointedTo() const { return true; }
int column() const { return m_column; }
void binNum(int flag) { m_binNum = flag; }
int binNum() const { return m_binNum; }
int offset() const { return m_offset; }
const string& comment() const { return m_text; } // text to insert in code
const string& linescov() const { return m_linescov; }
const string& page() const { return m_page; }
const string& hier() const { return m_hier; }
void hier(const string& flag) { m_hier = flag; }
@ -3336,8 +3362,8 @@ public:
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const {
const AstCoverDecl* asamep = static_cast<const AstCoverDecl*>(samep);
return (fileline() == asamep->fileline() && hier() == asamep->hier()
&& comment() == asamep->comment() && column() == asamep->column());
return (fileline() == asamep->fileline() && linescov() == asamep->linescov()
&& hier() == asamep->hier() && comment() == asamep->comment());
}
virtual bool isPredictOptimizable() const { return false; }
void dataDeclp(AstCoverDecl* nodep) { m_dataDeclp = nodep; }
@ -3626,6 +3652,7 @@ public:
virtual string emitVerilog() { return "%f" + verilogKwd() + "(%l)"; }
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual bool isGateOptimizable() const { return false; }
virtual bool isHeavy() const { return true; }
virtual bool isPredictOptimizable() const { return false; }
virtual bool isOutputter() const { return true; }
virtual bool cleanOut() const { return true; }
@ -3777,6 +3804,7 @@ public:
ASTNODE_NODE_FUNCS(FOpen)
virtual string verilogKwd() const { return "$fopen"; }
virtual bool isGateOptimizable() const { return false; }
virtual bool isHeavy() const { return true; }
virtual bool isPredictOptimizable() const { return false; }
virtual bool isPure() const { return false; }
virtual bool isOutputter() const { return true; }
@ -3788,6 +3816,28 @@ public:
AstNode* modep() const { return op3p(); }
};
class AstFOpenMcd : public AstNodeStmt {
// Although a system function in IEEE, here a statement which sets the file pointer (MCD)
public:
AstFOpenMcd(FileLine* fl, AstNode* filep, AstNode* filenamep)
: ASTGEN_SUPER(fl) {
setOp1p(filep);
setOp2p(filenamep);
}
ASTNODE_NODE_FUNCS(FOpenMcd)
virtual string verilogKwd() const { return "$fopen"; }
virtual bool isGateOptimizable() const { return false; }
virtual bool isHeavy() const { return true; }
virtual bool isPredictOptimizable() const { return false; }
virtual bool isPure() const { return false; }
virtual bool isOutputter() const { return true; }
virtual bool isUnlikely() const { return true; }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const { return true; }
AstNode* filep() const { return op1p(); }
AstNode* filenamep() const { return op2p(); }
};
class AstFFlush : public AstNodeStmt {
// Parents: stmtlist
// Children: file which must be a varref
@ -4009,6 +4059,7 @@ public:
setNOp4p(msbp);
}
virtual bool isGateOptimizable() const { return false; }
virtual bool isHeavy() const { return true; }
virtual bool isPredictOptimizable() const { return false; }
virtual bool isPure() const { return false; }
virtual bool isOutputter() const { return true; }
@ -4099,6 +4150,7 @@ public:
virtual string emitVerilog() { return "%f$value$plusargs(%l, %k%r)"; }
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual bool isGateOptimizable() const { return false; }
virtual bool isHeavy() const { return true; }
virtual bool isPredictOptimizable() const { return false; }
virtual bool cleanOut() const { return true; }
virtual V3Hash sameHash() const { return V3Hash(); }
@ -4283,44 +4335,81 @@ public:
void priorityPragma(bool flag) { m_priorityPragma = flag; }
};
class AstJumpLabel : public AstNodeStmt {
// Jump point declaration
// Separate from AstJumpGo; as a declaration can't be deleted
class AstJumpBlock : public AstNodeStmt {
// Block of code including a JumpGo and JumpLabel
// Parents: {statement list}
// Children: {statement list, with JumpGo below}
// Children: {statement list, with JumpGo and JumpLabel below}
private:
AstJumpLabel* m_labelp; // [After V3Jump] Pointer to declaration
int m_labelNum; // Set by V3EmitCSyms to tell final V3Emit what to increment
public:
AstJumpLabel(FileLine* fl, AstNode* stmtsp)
// After construction must call ->labelp to associate with appropriate label
AstJumpBlock(FileLine* fl, AstNode* stmtsp)
: ASTGEN_SUPER(fl)
, m_labelNum(0) {
addNOp1p(stmtsp);
}
virtual const char* broken() const;
virtual void cloneRelink();
ASTNODE_NODE_FUNCS(JumpBlock)
virtual int instrCount() const { return 0; }
ASTNODE_NODE_FUNCS(JumpLabel)
virtual bool maybePointedTo() const { return true; }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const { return true; }
// op1 = Statements
AstNode* stmtsp() const { return op1p(); } // op1 = List of statements
void addStmtsp(AstNode* nodep) { addNOp1p(nodep); }
AstNode* endStmtsp() const { return op2p(); } // op1 = List of end-of-block
void addEndStmtsp(AstNode* nodep) { addNOp2p(nodep); }
int labelNum() const { return m_labelNum; }
void labelNum(int flag) { m_labelNum = flag; }
AstJumpLabel* labelp() const { return m_labelp; }
void labelp(AstJumpLabel* labelp) { m_labelp = labelp; }
};
class AstJumpLabel : public AstNodeStmt {
// Jump point declaration
// Parents: {statement list with JumpBlock above}
// Children: none
private:
AstJumpBlock* m_blockp; // [After V3Jump] Pointer to declaration
public:
AstJumpLabel(FileLine* fl, AstJumpBlock* blockp)
: ASTGEN_SUPER(fl)
, m_blockp(blockp) {}
ASTNODE_NODE_FUNCS(JumpLabel)
virtual bool maybePointedTo() const { return true; }
virtual const char* broken() const {
BROKEN_RTN(!blockp()->brokeExistsAbove());
BROKEN_RTN(blockp()->labelp() != this);
return NULL;
}
virtual void cloneRelink() {
if (m_blockp->clonep()) m_blockp = m_blockp->clonep();
}
virtual void dump(std::ostream& str) const;
virtual int instrCount() const { return 0; }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const {
return blockp() == static_cast<const AstJumpLabel*>(samep)->blockp();
}
AstJumpBlock* blockp() const { return m_blockp; }
};
class AstJumpGo : public AstNodeStmt {
// Jump point; branch up to the JumpLabel
// Parents: {statement list}
// Jump point; branch down to a JumpLabel
// No support for backward jumps at present
// Parents: {statement list with JumpBlock above}
// Children: none
private:
AstJumpLabel* m_labelp; // [After V3Jump] Pointer to declaration
public:
AstJumpGo(FileLine* fl, AstJumpLabel* labelp)
: ASTGEN_SUPER(fl) {
m_labelp = labelp;
}
ASTNODE_NODE_FUNCS(JumpGo)
: ASTGEN_SUPER(fl)
, m_labelp(labelp) {}
ASTNODE_NODE_FUNCS(JumpGo);
virtual const char* broken() const {
BROKEN_RTN(!labelp()->brokeExistsAbove());
BROKEN_RTN(!labelp()->brokeExistsBelow());
return NULL;
}
virtual void cloneRelink() {
@ -4330,7 +4419,6 @@ public:
virtual int instrCount() const { return instrCountBranch(); }
virtual V3Hash sameHash() const { return V3Hash(labelp()); }
virtual bool same(const AstNode* samep) const {
// Also same if identical tree structure all the way down, but hard to detect
return labelp() == static_cast<const AstJumpGo*>(samep)->labelp();
}
virtual bool isGateOptimizable() const { return false; }
@ -4433,28 +4521,6 @@ public:
void joinType(const VJoinType& flag) { m_joinType = flag; }
};
class AstInitial : public AstNode {
public:
AstInitial(FileLine* fl, AstNode* bodysp)
: ASTGEN_SUPER(fl) {
addNOp1p(bodysp);
}
ASTNODE_NODE_FUNCS(Initial)
AstNode* bodysp() const { return op1p(); } // op1 = Expressions to evaluate
// Special accessors
bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); }
};
class AstFinal : public AstNode {
public:
AstFinal(FileLine* fl, AstNode* bodysp)
: ASTGEN_SUPER(fl) {
addNOp1p(bodysp);
}
ASTNODE_NODE_FUNCS(Final)
AstNode* bodysp() const { return op1p(); } // op1 = Expressions to evaluate
};
class AstInside : public AstNodeMath {
public:
AstInside(FileLine* fl, AstNode* exprp, AstNode* itemsp)
@ -4761,35 +4827,36 @@ class AstTraceDecl : public AstNodeStmt {
// Trace point declaration
// Separate from AstTraceInc; as a declaration can't be deleted
// Parents: {statement list}
// Children: none
// Children: expression being traced
private:
string m_showname; // Name of variable
uint32_t m_code; // Trace identifier code; converted to ASCII by trace routines
VNumRange m_bitRange; // Property of var the trace details
VNumRange m_arrayRange; // Property of var the trace details
uint32_t m_codeInc; // Code increment
AstVarType m_varType; // Type of variable (for localparam vs. param)
AstBasicDTypeKwd m_declKwd; // Keyword at declaration time
VDirection m_declDirection; // Declared direction input/output etc
bool m_isScoped; // Uses run-time scope (for interfaces)
const string m_showname; // Name of variable
const VNumRange m_bitRange; // Property of var the trace details
const VNumRange m_arrayRange; // Property of var the trace details
const uint32_t m_codeInc; // Code increment
const AstVarType m_varType; // Type of variable (for localparam vs. param)
const AstBasicDTypeKwd m_declKwd; // Keyword at declaration time
const VDirection m_declDirection; // Declared direction input/output etc
const bool m_isScoped; // Uses run-time scope (for interfaces)
public:
AstTraceDecl(FileLine* fl, const string& showname,
AstVar* varp, // For input/output state etc
AstNode* valuep, const VNumRange& bitRange, const VNumRange& arrayRange,
bool isScoped)
: ASTGEN_SUPER(fl)
, m_code(0)
, m_showname(showname)
, m_bitRange(bitRange)
, m_arrayRange(arrayRange)
, m_codeInc(
((arrayRange.ranged() ? arrayRange.elements() : 1) * valuep->dtypep()->widthWords()
* (VL_EDATASIZE / 32))) // A code is always 32-bits
, m_varType(varp->varType())
, m_declKwd(varp->declKwd())
, m_declDirection(varp->declDirection())
, m_isScoped(isScoped) {
dtypeFrom(valuep);
m_code = 0;
m_codeInc
= ((arrayRange.ranged() ? arrayRange.elements() : 1) * valuep->dtypep()->widthWords()
* (VL_EDATASIZE / (8 * sizeof(uint32_t)))); // A code is always 32-bits
m_varType = varp->varType();
m_declKwd = varp->declKwd();
m_declDirection = varp->declDirection();
addNOp1p(valuep);
}
virtual int instrCount() const { return 100; } // Large...
ASTNODE_NODE_FUNCS(TraceDecl)
@ -4808,20 +4875,25 @@ public:
AstBasicDTypeKwd declKwd() const { return m_declKwd; }
VDirection declDirection() const { return m_declDirection; }
bool isScoped() const { return m_isScoped; }
AstNode* valuep() const { return op1p(); }
};
class AstTraceInc : public AstNodeStmt {
// Trace point; incremental change detect and dump
// Trace point dump
// Parents: {statement list}
// Children: incremental value
// Children: op1: things to emit before this node,
// op2: expression being traced (from decl)
private:
AstTraceDecl* m_declp; // [After V3Trace] Pointer to declaration
AstTraceDecl* m_declp; // Pointer to declaration
const bool m_full; // Is this a full vs incremental dump
public:
AstTraceInc(FileLine* fl, AstTraceDecl* declp, AstNode* valuep)
: ASTGEN_SUPER(fl) {
AstTraceInc(FileLine* fl, AstTraceDecl* declp, bool full)
: ASTGEN_SUPER(fl)
, m_declp(declp)
, m_full(full) {
dtypeFrom(declp);
m_declp = declp;
addNOp2p(valuep);
addOp2p(declp->valuep()->cloneTree(true));
}
ASTNODE_NODE_FUNCS(TraceInc)
virtual const char* broken() const {
@ -4843,13 +4915,11 @@ public:
virtual bool isOutputter() const { return true; }
// but isPure() true
// op1 = Statements before the value
AstNode* precondsp() const {
return op1p();
} // op1 = prepare statements for condition (exec every loop)
AstNode* precondsp() const { return op1p(); }
void addPrecondsp(AstNode* newp) { addOp1p(newp); }
// op2 = Value to trace
AstTraceDecl* declp() const { return m_declp; } // Where defined
AstNode* valuep() const { return op2p(); }
AstTraceDecl* declp() const { return m_declp; }
bool full() const { return m_full; }
};
class AstActive : public AstNode {
@ -5397,6 +5467,33 @@ public:
virtual bool sizeMattersLhs() const { return false; }
virtual int instrCount() const { return widthInstrs() * 16; }
};
class AstCountBits : public AstNodeQuadop {
// Number of bits set in vector
public:
AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p)
: ASTGEN_SUPER(fl, exprp, ctrl1p, ctrl1p->cloneTree(false), ctrl1p->cloneTree(false)) {}
AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p, AstNode* ctrl2p)
: ASTGEN_SUPER(fl, exprp, ctrl1p, ctrl2p, ctrl2p->cloneTree(false)) {}
AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p, AstNode* ctrl2p, AstNode* ctrl3p)
: ASTGEN_SUPER(fl, exprp, ctrl1p, ctrl2p, ctrl3p) {}
ASTNODE_NODE_FUNCS(CountBits)
virtual void numberOperate(V3Number& out, const V3Number& expr, const V3Number& ctrl1,
const V3Number& ctrl2, const V3Number& ctrl3) {
out.opCountBits(expr, ctrl1, ctrl2, ctrl3);
}
virtual string emitVerilog() { return "%f$countbits(%l, %r, %f, %o)"; }
virtual string emitC() { return ""; }
virtual bool cleanOut() const { return false; }
virtual bool cleanLhs() const { return true; }
virtual bool cleanRhs() const { return true; }
virtual bool cleanThs() const { return true; }
virtual bool cleanFhs() const { return true; }
virtual bool sizeMattersLhs() const { return false; }
virtual bool sizeMattersRhs() const { return false; }
virtual bool sizeMattersThs() const { return false; }
virtual bool sizeMattersFhs() const { return false; }
virtual int instrCount() const { return widthInstrs() * 16; }
};
class AstCountOnes : public AstNodeUniop {
// Number of bits set in vector
public:
@ -5426,6 +5523,24 @@ public:
virtual bool cleanLhs() const { return false; }
virtual bool sizeMattersLhs() const { return false; }
};
class AstIsUnbounded : public AstNodeUniop {
// True if is unmbounded ($)
public:
AstIsUnbounded(FileLine* fl, AstNode* lhsp)
: ASTGEN_SUPER(fl, lhsp) {
dtypeSetLogicBool();
}
ASTNODE_NODE_FUNCS(IsUnbounded)
virtual void numberOperate(V3Number& out, const V3Number&) {
// Any constant isn't unbounded
out.setZero();
}
virtual string emitVerilog() { return "%f$isunbounded(%l)"; }
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const { return false; }
virtual bool cleanLhs() const { return false; }
virtual bool sizeMattersLhs() const { return false; }
};
class AstOneHot : public AstNodeUniop {
// True if only single bit set in vector
public:
@ -5967,6 +6082,7 @@ public:
virtual bool cleanOut() const { return true; }
virtual bool cleanLhs() const { return true; }
virtual bool sizeMattersLhs() const { return false; }
virtual bool isHeavy() const { return true; }
FmtType format() const { return m_fmt; }
};
@ -7133,6 +7249,106 @@ public:
virtual int instrCount() const { return widthInstrs() * instrCountMul() * 10; }
virtual bool signedFlavor() const { return true; }
};
class AstPreAdd : public AstNodeTriop {
// Pre-increment/add
// Parents: MATH
// Children: lhsp: AstConst (1) as currently support only ++ not +=
// Children: rhsp: tree with AstVarRef that is value to read before operation
// Children: thsp: tree with AstVarRef LValue that is stored after operation
public:
AstPreAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp)
: ASTGEN_SUPER(fl, lhsp, rhsp, thsp) {}
ASTNODE_NODE_FUNCS(PreAdd)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths) {
V3ERROR_NA; // Need to modify lhs
}
virtual string emitVerilog() { return "%k(++%r)"; }
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const { return false; }
virtual bool cleanLhs() const { return false; }
virtual bool cleanRhs() const { return false; }
virtual bool cleanThs() const { return false; }
virtual bool sizeMattersLhs() const { return true; }
virtual bool sizeMattersRhs() const { return true; }
virtual bool sizeMattersThs() const { return true; }
};
class AstPreSub : public AstNodeTriop {
// Pre-decrement/subtract
// Parents: MATH
// Children: lhsp: AstConst (1) as currently support only -- not -=
// Children: rhsp: tree with AstVarRef that is value to read before operation
// Children: thsp: tree with AstVarRef LValue that is stored after operation
public:
AstPreSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp)
: ASTGEN_SUPER(fl, lhsp, rhsp, thsp) {}
ASTNODE_NODE_FUNCS(PreSub)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths) {
V3ERROR_NA; // Need to modify lhs
}
virtual string emitVerilog() { return "%k(--%r)"; }
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const { return false; }
virtual bool cleanLhs() const { return false; }
virtual bool cleanRhs() const { return false; }
virtual bool cleanThs() const { return false; }
virtual bool sizeMattersLhs() const { return true; }
virtual bool sizeMattersRhs() const { return true; }
virtual bool sizeMattersThs() const { return true; }
};
class AstPostAdd : public AstNodeTriop {
// Post-increment/add
// Parents: MATH
// Children: lhsp: AstConst (1) as currently support only ++ not +=
// Children: rhsp: tree with AstVarRef that is value to read before operation
// Children: thsp: tree with AstVarRef LValue that is stored after operation
public:
AstPostAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp)
: ASTGEN_SUPER(fl, lhsp, rhsp, thsp) {}
ASTNODE_NODE_FUNCS(PostAdd)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths) {
V3ERROR_NA; // Need to modify lhs
}
virtual string emitVerilog() { return "%k(%r++)"; }
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const { return false; }
virtual bool cleanLhs() const { return false; }
virtual bool cleanRhs() const { return false; }
virtual bool cleanThs() const { return false; }
virtual bool sizeMattersLhs() const { return true; }
virtual bool sizeMattersRhs() const { return true; }
virtual bool sizeMattersThs() const { return true; }
};
class AstPostSub : public AstNodeTriop {
// Post-decrement/subtract
// Parents: MATH
// Children: lhsp: AstConst (1) as currently support only -- not -=
// Children: rhsp: tree with AstVarRef that is value to read before operation
// Children: thsp: tree with AstVarRef LValue that is stored after operation
public:
AstPostSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp)
: ASTGEN_SUPER(fl, lhsp, rhsp, thsp) {}
ASTNODE_NODE_FUNCS(PostSub)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths) {
V3ERROR_NA; // Need to modify lhs
}
virtual string emitVerilog() { return "%k(%r--)"; }
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const { return false; }
virtual bool cleanLhs() const { return false; }
virtual bool cleanRhs() const { return false; }
virtual bool cleanThs() const { return false; }
virtual bool sizeMattersLhs() const { return true; }
virtual bool sizeMattersRhs() const { return true; }
virtual bool sizeMattersThs() const { return true; }
};
class AstEqCase : public AstNodeBiCom {
public:
AstEqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
@ -7500,6 +7716,7 @@ public:
virtual bool sizeMattersLhs() const { return false; }
virtual bool sizeMattersRhs() const { return false; }
virtual bool sizeMattersThs() const { return false; }
virtual bool isHeavy() const { return true; }
};
class AstGetcN : public AstNodeBiop {
@ -7525,6 +7742,7 @@ public:
virtual bool cleanRhs() const { return true; }
virtual bool sizeMattersLhs() const { return false; }
virtual bool sizeMattersRhs() const { return false; }
virtual bool isHeavy() const { return true; }
};
class AstGetcRefN : public AstNodeBiop {
@ -7543,13 +7761,14 @@ public:
V3ERROR_NA;
}
virtual string emitVerilog() { return "%k%l[%r]"; }
virtual string emitC() { V3ERROR_NA; }
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual string emitSimpleOperator() { return ""; }
virtual bool cleanOut() const { return true; }
virtual bool cleanLhs() const { return true; }
virtual bool cleanRhs() const { return true; }
virtual bool sizeMattersLhs() const { return false; }
virtual bool sizeMattersRhs() const { return false; }
virtual bool isHeavy() const { return true; }
};
class AstSubstrN : public AstNodeTriop {
@ -7575,6 +7794,7 @@ public:
virtual bool sizeMattersLhs() const { return false; }
virtual bool sizeMattersRhs() const { return false; }
virtual bool sizeMattersThs() const { return false; }
virtual bool isHeavy() const { return true; }
};
class AstCompareNN : public AstNodeBiop {
@ -7607,6 +7827,7 @@ public:
virtual bool cleanRhs() const { return true; }
virtual bool sizeMattersLhs() const { return false; }
virtual bool sizeMattersRhs() const { return false; }
virtual bool isHeavy() const { return true; }
};
class AstPast : public AstNodeMath {
@ -7675,11 +7896,10 @@ public:
virtual bool cleanOut() const { V3ERROR_NA_RETURN(""); }
virtual int instrCount() const { return widthInstrs(); }
AstNodeDType* getChildDTypep() const { return childDTypep(); }
AstNodeDType* childDTypep() const {
return VN_CAST(op1p(), NodeDType);
} // op1 = Type assigning to
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
// op1 = Type assigning to
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
AstNode* itemsp() const { return op2p(); } // op2 = AstPatReplicate, AstPatMember, etc
};
class AstPatMember : public AstNodeMath {

View File

@ -30,12 +30,9 @@
#include "V3Global.h"
#include "V3Begin.h"
#include "V3Inst.h"
#include "V3Ast.h"
#include <algorithm>
#include <cstdarg>
#include <vector>
//######################################################################

View File

@ -30,7 +30,6 @@
#include "V3Branch.h"
#include "V3Ast.h"
#include <cstdarg>
#include <map>
//######################################################################

View File

@ -32,7 +32,6 @@
#include "V3AstConstOnly.h"
#include <algorithm>
#include <cstdarg>
#include VL_INCLUDE_UNORDERED_MAP
//######################################################################
@ -131,6 +130,14 @@ public:
if (!(iter->second & FLAG_LINKABLE)) return false;
return true;
}
static bool okIfAbove(const AstNode* nodep) {
// Must be linked to and below current node
if (!okIfLinkedTo(nodep)) return false;
NodeMap::iterator iter = s_nodes.find(nodep);
if (iter == s_nodes.end()) return false;
if ((iter->second & FLAG_UNDER_NOW)) return false;
return true;
}
static bool okIfBelow(const AstNode* nodep) {
// Must be linked to and below current node
if (!okIfLinkedTo(nodep)) return false;
@ -142,19 +149,22 @@ public:
static void prepForTree() {
#ifndef VL_LEAK_CHECKS
s_nodes.clear();
#endif
#else
for (NodeMap::iterator it = s_nodes.begin(); it != s_nodes.end(); ++it) {
it->second &= ~FLAG_IN_TREE;
it->second &= ~FLAG_LINKABLE;
}
#endif
}
static void doneWithTree() {
for (int backs = 0; backs < 2;
backs++) { // Those with backp() are probably under one leaking without
for (NodeMap::iterator it = s_nodes.begin(); it != s_nodes.end(); ++it) {
if ((it->second & FLAG_ALLOCATED) && !(it->second & FLAG_IN_TREE)
&& !(it->second & FLAG_LEAKED)
&& (it->first->backp() ? backs == 1 : backs == 0)) {
// LCOV_EXCL_START
if (VL_UNCOVERABLE((it->second & FLAG_ALLOCATED) && !(it->second & FLAG_IN_TREE)
&& !(it->second & FLAG_LEAKED)
&& (it->first->backp() ? backs == 1 : backs == 0))) {
// Use only AstNode::dump instead of the virtual one, as there
// may be varp() and other cross links that are bad.
if (v3Global.opt.debugCheck()) {
@ -173,6 +183,7 @@ public:
}
it->second |= FLAG_LEAKED;
}
// LCOV_EXCL_STOP
}
}
}
@ -193,6 +204,10 @@ bool AstNode::brokeExistsAbove() const {
// Called by node->broken() routines to do table lookup
return BrokenTable::okIfBelow(this);
}
bool AstNode::brokeExistsBelow() const {
// Called by node->broken() routines to do table lookup
return BrokenTable::okIfAbove(this);
}
//######################################################################

View File

@ -32,10 +32,7 @@
#include "V3CCtors.h"
#include <algorithm>
#include <cmath>
#include <cstdarg>
#include <map>
#include <vector>
class V3CCtorsVisitor {
private:
@ -49,7 +46,6 @@ private:
int m_funcNum; // Function number being built
public:
AstCFunc* builtFuncp() const { return m_tlFuncp; }
void add(AstNode* nodep) {
if (v3Global.opt.outputSplitCFuncs() && v3Global.opt.outputSplitCFuncs() < m_numStmts) {
m_funcp = NULL;
@ -146,13 +142,11 @@ void V3CCtors::cctorsAll() {
modp = VN_CAST(modp->nextp(), NodeModule)) {
// Process each module in turn
{
AstCFunc* varResetFuncp;
V3CCtorsVisitor var_reset(
modp, "_ctor_var_reset",
(VN_IS(modp, Class) ? EmitCBaseVisitor::symClassVar() : ""),
(VN_IS(modp, Class) ? "vlSymsp" : ""),
(VN_IS(modp, Class) ? "if (false && vlSymsp) {} // Prevent unused\n" : ""));
varResetFuncp = var_reset.builtFuncp();
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
if (AstVar* varp = VN_CAST(np, Var)) {

View File

@ -218,7 +218,7 @@ public:
//######################################################################
// Class class functions
void V3CUse::cUseAll(AstNetlist* nodep) {
void V3CUse::cUseAll() {
UINFO(2, __FUNCTION__ << ": " << endl);
// Call visitor separately for each module, so visitor state is cleared
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp;

View File

@ -27,7 +27,7 @@
class V3CUse {
public:
static void cUseAll(AstNetlist* nodep);
static void cUseAll();
};
#endif // Guard

View File

@ -43,7 +43,6 @@
#include "V3Stats.h"
#include <algorithm>
#include <cstdarg>
#define CASE_OVERLAP_WIDTH 16 // Maximum width we can check for overlaps in
#define CASE_BARF 999999 // Magic width when non-constant
@ -96,7 +95,7 @@ private:
} else if (VN_IS(m_caseExprp, Case)
&& (VN_CAST(m_caseExprp, Case)->casez()
|| VN_CAST(m_caseExprp, Case)->caseInside())) {
if (nodep->num().isUnknown()) {
if (nodep->num().isAnyX()) {
nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, "
"(perhaps intended ?/z in constant)");
}
@ -281,13 +280,13 @@ private:
// IF(msb-1, 01, 00))
AstNode* cexprp = nodep->exprp()->unlinkFrBack();
if (debug() >= 9) {
if (debug() >= 9) { // LCOV_EXCL_START
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) {
if (AstNode* itemp = m_valueItem[i]) {
UINFO(9, "Value " << std::hex << i << " " << itemp << endl);
}
}
}
} // LCOV_EXCL_STOP
// Handle any assertions
replaceCaseParallel(nodep, m_caseNoOverlapsAllCovered);
@ -460,7 +459,7 @@ private:
// Xs in case or casez are impossible due to two state simulations
if (casep->casex()) {
} else if (casep->casez() || casep->caseInside()) {
if (itemp->num().isUnknown()) return true;
if (itemp->num().isAnyX()) return true;
} else {
if (itemp->num().isFourState()) return true;
}

View File

@ -45,7 +45,6 @@
#include "V3Ast.h"
#include <algorithm>
#include <cstdarg>
//######################################################################
// Cast state, as a visitor of each AstNode
@ -128,6 +127,15 @@ private:
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
if (nodep->sizeMattersThs()) ensureCast(nodep->thsp());
}
virtual void visit(AstNodeQuadop* nodep) VL_OVERRIDE {
iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1() | nodep->thsp()->user1()
| nodep->fhsp()->user1());
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
if (nodep->sizeMattersThs()) ensureCast(nodep->thsp());
if (nodep->sizeMattersFhs()) ensureCast(nodep->fhsp());
}
virtual void visit(AstCCast* nodep) VL_OVERRIDE {
iterateChildren(nodep);
ensureLower32Cast(nodep);

View File

@ -33,12 +33,9 @@
#include "V3File.h"
#include <algorithm>
#include <cstdarg>
#include <deque>
#include <iomanip>
#include <list>
#include <memory>
#include <vector>
#define CDC_WEIGHT_ASYNC 0x1000 // Weight for edges that feed async logic
@ -258,7 +255,7 @@ private:
iterateChildren(nodep);
m_logicVertexp = NULL;
if (0 && debug() >= 9) {
if (false && debug() >= 9) {
UINFO(9, "Trace Logic:\n");
nodep->dumpTree(cout, "-log1: ");
}
@ -298,7 +295,7 @@ private:
static bool told_file = false;
nodep->v3warnCode(code, msg);
if (!told_file) {
told_file = 1;
told_file = true;
std::cerr << V3Error::msgPrefix() << " See details in " << m_ofFilename << endl;
}
*m_ofp << "%Warning-" << code.ascii() << ": " << nodep->fileline() << " " << msg << endl;
@ -732,7 +729,7 @@ private:
// Ignores
virtual void visit(AstInitial*) VL_OVERRIDE {}
virtual void visit(AstTraceInc*) VL_OVERRIDE {}
virtual void visit(AstTraceDecl*) VL_OVERRIDE {}
virtual void visit(AstCoverToggle*) VL_OVERRIDE {}
virtual void visit(AstNodeDType*) VL_OVERRIDE {}

View File

@ -35,8 +35,6 @@
#include "V3EmitCBase.h"
#include <algorithm>
#include <cstdarg>
#include <set>
//######################################################################

View File

@ -31,7 +31,6 @@
#include "V3Ast.h"
#include <algorithm>
#include <cstdarg>
//######################################################################
// Clean state, as a visitor of each AstNode
@ -160,6 +159,15 @@ private:
if (nodep->cleanThs()) ensureClean(nodep->thsp());
// no setClean.. must do it in each user routine.
}
void operandQuadop(AstNodeQuadop* nodep) {
iterateChildren(nodep);
computeCppWidth(nodep);
if (nodep->cleanLhs()) { ensureClean(nodep->lhsp()); }
if (nodep->cleanRhs()) { ensureClean(nodep->rhsp()); }
if (nodep->cleanThs()) { ensureClean(nodep->thsp()); }
if (nodep->cleanFhs()) { ensureClean(nodep->fhsp()); }
// no setClean.. must do it in each user routine.
}
// VISITORS
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
@ -192,6 +200,10 @@ private:
operandBiop(nodep);
setClean(nodep, isClean(nodep->lhsp()) && isClean(nodep->rhsp()));
}
virtual void visit(AstNodeQuadop* nodep) VL_OVERRIDE {
operandQuadop(nodep);
setClean(nodep, nodep->cleanOut());
}
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {
iterateChildren(nodep);
computeCppWidth(nodep);

View File

@ -36,7 +36,6 @@
#include "V3EmitCBase.h"
#include <algorithm>
#include <cstdarg>
//######################################################################
// Clock state, as a visitor of each AstNode
@ -48,9 +47,6 @@ private:
// AstVarScope::user1p() -> AstVarScope*. Temporary signal that was created.
AstUser1InUse m_inuser1;
// TYPES
enum { DOUBLE_OR_RATE = 10 }; // How many | per ||, Determined experimentally as best
// STATE
AstNodeModule* m_modp; // Current module
AstTopScope* m_topScopep; // Current top scope

View File

@ -40,7 +40,6 @@
#include "V3Ast.h"
#include <algorithm>
#include <cstdarg>
#include <map>
#include <vector>
@ -57,15 +56,6 @@ protected:
// METHODS
virtual ~CombBaseVisitor() {}
VL_DEBUG_FUNC; // Declare debug()
//***** optimization levels
static bool emptyFunctionDeletion() { return true; }
static bool duplicateFunctionCombine() { return true; }
// Note this is disabled, it still needed work
// Also repair it for DPI functions; when make __common need to ensure proper
// flags get inherited from the old to new AstCFunc, and that AstText doesn't
// get split between functions causing the text to have a dangling reference.
bool statementCombine() { return false; } // duplicateFunctionCombine();
};
//######################################################################
@ -86,11 +76,10 @@ public:
} else {
UINFO(4, " Remove " << oldfuncp << endl);
}
std::pair<CallMmap::iterator, CallMmap::iterator> eqrange
= m_callMmap.equal_range(oldfuncp);
for (CallMmap::iterator nextit = eqrange.first; nextit != eqrange.second;) {
CallMmap::iterator eqit = nextit++;
AstCCall* callp = eqit->second;
// Note: m_callMmap modified in loop, so not using equal_range.
for (CallMmap::iterator it = m_callMmap.find(oldfuncp); it != m_callMmap.end();
it = m_callMmap.find(oldfuncp)) {
AstCCall* callp = it->second;
if (!callp->user3()) { // !already done
UINFO(4, " Called " << callp << endl);
UASSERT_OBJ(callp->funcp() == oldfuncp, callp,
@ -105,8 +94,13 @@ public:
}
callp->user3(true); // Dead now
VL_DO_DANGLING(pushDeletep(callp), callp);
m_callMmap.erase(eqit); // Fix the table
}
// It is safe to unconditionally remove this entry here as the above
// 'if' would never be entered again for this entry (we set user3).
// The only other place where m_callMmap is looked up is deleteCall
// below, but that is only ever called straight after an addCall
// of the node being deleted, so it won't miss this entry.
m_callMmap.erase(it); // Fix the table
}
}
// METHODS
@ -182,7 +176,6 @@ private:
CombineState m_state; // Major state
AstNodeModule* m_modp; // Current module
AstCFunc* m_funcp; // Current function
V3Hash m_lowerHash; // Hash of the statement we're building
CombCallVisitor m_call; // Tracking of function call users
int m_modNFuncs; // Number of functions made
AstNode* m_walkLast1p; // Final node that is the same in duplicate list
@ -195,6 +188,7 @@ private:
m_hashed.hashAndInsert(nodep);
// UINFO(9, " stmthash " << hex << nodep->user4() << " " << nodep << endl);
}
#ifdef VL_COMBINE_STATEMENTS
void hashFunctions(AstCFunc* nodep) {
// Compute hash of all statement trees in the function
CombineState oldState = m_state;
@ -204,6 +198,7 @@ private:
}
m_state = oldState;
}
#endif
void walkEmptyFuncs() {
for (V3Hashed::iterator it = m_hashed.begin(); it != m_hashed.end(); ++it) {
AstNode* node1p = it->second;
@ -251,6 +246,8 @@ private:
oldfuncp->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(oldfuncp), oldfuncp);
}
#ifdef VL_COMBINE_STATEMENTS
void replaceOnlyCallFunc(AstCCall* nodep) {
if (AstCFunc* oldfuncp = VN_CAST(nodep->backp(), CFunc)) {
// oldfuncp->dumpTree(cout, "MAYDEL: ");
@ -343,7 +340,7 @@ private:
// Grab statement bodies
AstNRelinker relink1Handle;
AstNRelinker relink2Handle;
for (AstNode *nextp, *walkp = node1p; 1; walkp = nextp) {
for (AstNode *nextp, *walkp = node1p; true; walkp = nextp) {
nextp = walkp->nextp();
if (walkp == node1p) {
walkp->unlinkFrBack(&relink1Handle);
@ -353,7 +350,7 @@ private:
}
if (walkp == last1p) break;
}
for (AstNode *nextp, *walkp = node2p; 1; walkp = nextp) {
for (AstNode *nextp, *walkp = node2p; true; walkp = nextp) {
nextp = walkp->nextp();
if (walkp == node2p) {
walkp->unlinkFrBack(&relink2Handle);
@ -381,6 +378,7 @@ private:
VL_DO_DANGLING(replaceOnlyCallFunc(call1p), call1p);
VL_DO_DANGLING(replaceOnlyCallFunc(call2p), call2p);
}
#endif
// VISITORS
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
@ -404,15 +402,21 @@ private:
m_state = STATE_IDLE;
if (debug() >= 9) m_hashed.dumpFilePrefixed("combine");
// Walk the hashes removing empty functions
if (emptyFunctionDeletion()) walkEmptyFuncs();
walkEmptyFuncs();
// Walk the hashes looking for duplicate functions
if (duplicateFunctionCombine()) walkDupFuncs();
walkDupFuncs();
// Walk the statements looking for large replicated code sections
if (statementCombine()) {
// Note this is disabled, it still needed work
// Also repair it for DPI functions; when make __common need to ensure proper
// flags get inherited from the old to new AstCFunc, and that AstText doesn't
// get split between functions causing the text to have a dangling reference.
#ifdef VL_COMBINE_STATEMENTS
{
m_state = STATE_DUP;
iterateChildren(nodep);
m_state = STATE_IDLE;
}
#endif
m_modp = NULL;
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
@ -420,9 +424,12 @@ private:
if (!nodep->dontCombine()) {
if (m_state == STATE_HASH) {
hashStatement(nodep); // Hash the entire function - it might be identical
} else if (m_state == STATE_DUP) {
}
#ifdef VL_COMBINE_STATEMENTS
else if (m_state == STATE_DUP) {
iterateChildren(nodep);
}
#endif
}
m_funcp = NULL;
}
@ -433,9 +440,12 @@ private:
}
if (m_state == STATE_HASH && m_funcp) {
hashStatement(nodep);
} else if (m_state == STATE_DUP && m_funcp) {
}
#ifdef VL_COMBINE_STATEMENTS
else if (m_state == STATE_DUP && m_funcp) {
walkDupCodeStart(nodep);
}
#endif
}
//--------------------

View File

@ -335,7 +335,7 @@ public:
// UINFO(9, " Hit " << *m_lastIt << endl);
filelinep->warnOn(m_lastIgnore.it->m_code, m_lastIgnore.it->m_on);
}
if (0 && debug() >= 9) {
if (false && debug() >= 9) {
for (IgnLines::const_iterator it = m_lastIgnore.it; it != m_ignLines.end(); ++it) {
UINFO(9, " NXT " << *it << endl);
}

View File

@ -43,7 +43,7 @@ public:
static void applyModule(AstNodeModule* modulep);
static void applyFTask(AstNodeModule* modulep, AstNodeFTask* ftaskp);
static void applyVarAttr(AstNodeModule* modulep, AstNodeFTask* ftaskp, AstVar* varp);
static bool waive(FileLine* filelinep, V3ErrorCode code, const string& match);
static bool waive(FileLine* filelinep, V3ErrorCode code, const string& message);
};
#endif // Guard

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