'Merge from master for release.'
This commit is contained in:
commit
369ce6af2c
|
|
@ -3,3 +3,4 @@ exclude_paths:
|
|||
- '.github/**'
|
||||
- 'ci/build_verilator.sh'
|
||||
- 'include/vltstd/**'
|
||||
- 'nodist/fastcov.py'
|
||||
|
|
|
|||
251
.travis.yml
251
.travis.yml
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ src/Makefile$
|
|||
src/Makefile_obj$
|
||||
include/verilated.mk$
|
||||
test_regress/.gdbinit$
|
||||
codecov.yml
|
||||
config.cache$
|
||||
config.status$
|
||||
verilator\.log
|
||||
|
|
|
|||
15
README.adoc
15
README.adoc
|
|
@ -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/> +++ • Accepts synthesizable Verilog or SystemVerilog
|
||||
+++ <br/> +++ • Performs lint code-quality checks
|
||||
+++ <br/> +++ • 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
|
||||
|
||||
|
|
|
|||
448
bin/verilator
448
bin/verilator
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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" ]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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*
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
34
ci/test.sh
34
ci/test.sh
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
20
configure.ac
20
configure.ac
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
#
|
||||
######################################################################
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
#
|
||||
######################################################################
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
#
|
||||
######################################################################
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
#
|
||||
######################################################################
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
#
|
||||
######################################################################
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
#
|
||||
######################################################################
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
#
|
||||
######################################################################
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
#
|
||||
######################################################################
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
#
|
||||
######################################################################
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
#
|
||||
######################################################################
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
#
|
||||
#######################################################################
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
#
|
||||
######################################################################
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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++) {
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
//--------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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*/,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -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:
|
||||
|
|
@ -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::
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -23,9 +23,6 @@
|
|||
#include "V3GraphDfa.h"
|
||||
#include "V3Stats.h"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <iomanip>
|
||||
|
||||
//######################################################################
|
||||
// Assert class functions
|
||||
|
||||
|
|
|
|||
|
|
@ -23,9 +23,6 @@
|
|||
#include "V3Global.h"
|
||||
#include "V3AssertPre.h"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <iomanip>
|
||||
|
||||
//######################################################################
|
||||
// Assert class functions
|
||||
|
||||
|
|
|
|||
|
|
@ -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))) {
|
||||
|
|
|
|||
125
src/V3Ast.h
125
src/V3Ast.h
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
470
src/V3AstNodes.h
470
src/V3AstNodes.h
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -30,12 +30,9 @@
|
|||
|
||||
#include "V3Global.h"
|
||||
#include "V3Begin.h"
|
||||
#include "V3Inst.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdarg>
|
||||
#include <vector>
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@
|
|||
#include "V3Branch.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <map>
|
||||
|
||||
//######################################################################
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
class V3CUse {
|
||||
public:
|
||||
static void cUseAll(AstNetlist* nodep);
|
||||
static void cUseAll();
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 {}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,8 +35,6 @@
|
|||
#include "V3EmitCBase.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdarg>
|
||||
#include <set>
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
//--------------------
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue