mirror of
https://github.com/verilator/verilator.git
synced 2026-10-06 10:03:44 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04c0fc8aa7 | ||
|
|
1d8955fea5 | ||
|
|
48740a0dba | ||
|
|
4a404bd92e | ||
|
|
ff41701ddc | ||
|
|
2590c9c4a6 | ||
|
|
c5d61da5d2 | ||
|
|
5a622fd9db | ||
|
|
c83b1478e1 | ||
|
|
3243651c63 | ||
|
|
8d61cd9029 | ||
|
|
7fe49de420 | ||
|
|
a433096d5a | ||
|
|
b88e1e6970 | ||
|
|
79f228b04f | ||
|
|
d7cc1e6844 | ||
|
|
42312101b5 | ||
|
|
329f5b712a | ||
|
|
6ddd92c0a1 | ||
|
|
277dee109c | ||
|
|
ef71576825 | ||
|
|
c3271aa891 | ||
|
|
1cf17b5e78 | ||
|
|
2b6353b36e | ||
|
|
8b647f0977 | ||
|
|
4c31c5fab5 | ||
|
|
6ce878cb0d | ||
|
|
a67ba04c37 | ||
|
|
ae448e5ef9 | ||
|
|
a57826b125 | ||
|
|
656c460605 | ||
|
|
95534fa5c5 | ||
|
|
611e8b10c6 | ||
|
|
047852eb08 | ||
|
|
6318a08056 | ||
|
|
b60a92eed3 | ||
|
|
fe306a36b8 | ||
|
|
18870f8b62 | ||
|
|
9712ceedd7 | ||
|
|
2e32387e5c | ||
|
|
b66877c9df | ||
|
|
74a6f94e2b | ||
|
|
35fc8b7259 | ||
|
|
e591afd101 | ||
|
|
a41cdf4cfb | ||
|
|
ef72c42aa7 | ||
|
|
fbc814b54a | ||
|
|
4cfa3f879a | ||
|
|
4a8c7e869f | ||
|
|
a4a1c7a384 | ||
|
|
460315128b | ||
|
|
8ddafb4d9f | ||
|
|
ebda8f866c | ||
|
|
5ee4595aa8 | ||
|
|
5089ac6119 | ||
|
|
3f66f846cd | ||
|
|
279f21bb5b | ||
|
|
773ed97504 | ||
|
|
b6d4899d3f | ||
|
|
9d48ff7745 | ||
|
|
c4aab57c62 | ||
|
|
e8f27be200 | ||
|
|
15f0f967b3 | ||
|
|
cbafff8a71 | ||
|
|
41e362b580 | ||
|
|
622f59ad65 | ||
|
|
c5da38206e | ||
|
|
d737266f64 | ||
|
|
978c35995a | ||
|
|
2af7f2fa18 | ||
|
|
373c9090d3 | ||
|
|
723d407a87 | ||
|
|
dc90e6c3c3 | ||
|
|
68a2ed6776 | ||
|
|
7f32d4dc45 | ||
|
|
7b683fe258 | ||
|
|
72858175a2 | ||
|
|
9d7086067c | ||
|
|
5bb1da88ed | ||
|
|
9969a60b34 | ||
|
|
72402fa91e | ||
|
|
8255f3f9fe | ||
|
|
8957f77793 | ||
|
|
7187b82d1d | ||
|
|
1a92a58720 | ||
|
|
2351f9b9ad | ||
|
|
abc3c216f8 | ||
|
|
f1afa667d7 | ||
|
|
76d0671952 | ||
|
|
424769c32b | ||
|
|
f7249ad23a | ||
|
|
613d76c578 | ||
|
|
50662751fe | ||
|
|
c9e59e767a | ||
|
|
a7432bdea7 | ||
|
|
9ffad7f0db | ||
|
|
3097d5e093 | ||
|
|
cff4b5a5ee | ||
|
|
eda46e3949 | ||
|
|
71651718d4 | ||
|
|
da0cb44954 | ||
|
|
57621a93ad | ||
|
|
6a882f9dc6 | ||
|
|
c18b0eb122 | ||
|
|
3c28a66acf | ||
|
|
5c11de1663 | ||
|
|
72ea6bf414 | ||
|
|
101314a572 | ||
|
|
01f3e81a36 | ||
|
|
3cb3b6c400 | ||
|
|
8f58b58853 | ||
|
|
b66826169d | ||
|
|
d2a7376f14 | ||
|
|
c9e8a1cb4d | ||
|
|
8170f6f03f | ||
|
|
0abf88823f | ||
|
|
accf5a9a17 | ||
|
|
c64c81b7a3 | ||
|
|
7834028842 | ||
|
|
1e0d5eb238 | ||
|
|
b5460bd867 | ||
|
|
53cde90c8f | ||
|
|
d20a4db773 | ||
|
|
0f7677480f | ||
|
|
ba3930777a | ||
|
|
9c054a5774 | ||
|
|
cef0105dfc | ||
|
|
4773a1e77c | ||
|
|
ed4c7038b4 | ||
|
|
c4f31d3bb6 | ||
|
|
dc25e9b949 | ||
|
|
1f52b01b2c | ||
|
|
d5fc0fca41 | ||
|
|
212aa332dd | ||
|
|
17e7da77f0 | ||
|
|
201f0d3f5f | ||
|
|
7d0b3b300a | ||
|
|
0b55e205f7 | ||
|
|
9c0c6439cc | ||
|
|
d33d0301f8 | ||
|
|
6fd7f45cef | ||
|
|
57a937df03 | ||
|
|
ffd461dcf8 | ||
|
|
f77058774e | ||
|
|
1d0a726437 | ||
|
|
29bcbb0417 | ||
|
|
2d11c2cbb3 | ||
|
|
2edbcce032 | ||
|
|
35a53d9adb | ||
|
|
2885c2ce97 | ||
|
|
900c023bb5 | ||
|
|
12b95f6b93 | ||
|
|
85de3048a5 | ||
|
|
c1a9fe07e9 | ||
|
|
1a0da2e4ec | ||
|
|
38d11ecabe | ||
|
|
148762364b | ||
|
|
68d7596adf | ||
|
|
f005b7fd87 | ||
|
|
68ed683681 | ||
|
|
61e41595a2 | ||
|
|
484b574cef | ||
|
|
29695adf70 | ||
|
|
fac43811fd | ||
|
|
15f63d12d5 | ||
|
|
ba7b3fd60f | ||
|
|
897b9ccfe2 | ||
|
|
b97e1aa9fe | ||
|
|
d4a631446b | ||
|
|
a2cc053c6f | ||
|
|
8998ffc4e5 | ||
|
|
ca162716c6 | ||
|
|
629dd16714 | ||
|
|
12b903caf4 | ||
|
|
f9a0cf0cff | ||
|
|
070bcddf5a | ||
|
|
feb1e2bd48 | ||
|
|
6e7ee23644 | ||
|
|
c00cc18d37 | ||
|
|
a7e17a8855 | ||
|
|
60fa1db731 | ||
|
|
ac09ad3ffd | ||
|
|
27953e26b6 | ||
|
|
9375d9f603 | ||
|
|
72bd91c7f1 | ||
|
|
8850ca962e | ||
|
|
7fd590f855 | ||
|
|
5f7ae1fbce | ||
|
|
b56a25e89c | ||
|
|
4f32b093e6 | ||
|
|
6a54fb6f96 | ||
|
|
546ccd56c4 | ||
|
|
ca77a93214 | ||
|
|
ee1b20e1cd | ||
|
|
aa86e0bbc0 | ||
|
|
b6b3482010 | ||
|
|
05aecd2c0b | ||
|
|
6ab3d8f3ed | ||
|
|
0fcc7f2987 | ||
|
|
7d7e67b49b | ||
|
|
a41ea180fa | ||
|
|
98889b3f4e | ||
|
|
83fbfa8c71 | ||
|
|
a57262d6e7 | ||
|
|
fe708f045a | ||
|
|
8afcd67a1f | ||
|
|
16e258eb4c | ||
|
|
d6fbbddac9 |
@@ -3,3 +3,4 @@ exclude_paths:
|
|||||||
- '.github/**'
|
- '.github/**'
|
||||||
- 'ci/build_verilator.sh'
|
- 'ci/build_verilator.sh'
|
||||||
- 'include/vltstd/**'
|
- 'include/vltstd/**'
|
||||||
|
- 'nodist/fastcov.py'
|
||||||
|
|||||||
+91
-160
@@ -8,176 +8,107 @@
|
|||||||
|
|
||||||
version: ~> 1.0
|
version: ~> 1.0
|
||||||
|
|
||||||
os: linux
|
|
||||||
language: cpp
|
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:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
- $VERILATOR_CACHE
|
- $HOME/.ccache
|
||||||
|
|
||||||
before_install:
|
env:
|
||||||
# Perl modules needed for testing
|
global:
|
||||||
# Not listing Bit::Vector as slow to install, and only skips one test
|
- VERILATOR_ROOT=$TRAVIS_BUILD_DIR
|
||||||
- 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
|
|
||||||
|
|
||||||
|
# The list and order of build stages
|
||||||
stages:
|
stages:
|
||||||
- "Build Verilator"
|
- build # Build Verilator
|
||||||
- test
|
- 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:
|
jobs:
|
||||||
include:
|
include:
|
||||||
- if: type != cron
|
############################################################################
|
||||||
stage: "Build Verilator"
|
# Jobs in the 'build' stage
|
||||||
name: Build Verilator
|
############################################################################
|
||||||
compiler: gcc
|
# GCC builds
|
||||||
script: echo "Done building Verilator"
|
- {stage: build, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {create: {name: trusty-gcc, paths: .}}}
|
||||||
# Non-cron build will just run on whatever linux flavor we get
|
- {stage: build, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {create: {name: xenial-gcc, paths: .}}}
|
||||||
- if: type != cron
|
- {stage: build, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {create: {name: bionic-gcc, paths: .}}}
|
||||||
stage: test
|
- {stage: build, os: linux, dist: focal, compiler: gcc, workspaces: {create: {name: focal-gcc, paths: .}}}
|
||||||
name: Dist test
|
# Clang builds
|
||||||
compiler: gcc
|
- {stage: build, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {create: {name: xenial-clang, paths: .}}}
|
||||||
script: ci/test.sh dist
|
- {stage: build, os: linux, dist: focal, compiler: clang, workspaces: {create: {name: focal-clang, paths: .}}}
|
||||||
- if: type != cron
|
# Coverage build
|
||||||
stage: test
|
- {stage: build, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {create: {name: coverage, paths: .}}, env: COVERAGE=1}
|
||||||
name: Vlt test
|
############################################################################
|
||||||
compiler: gcc
|
# Jobs in the 'test' stage
|
||||||
script: ci/test.sh vlt
|
############################################################################
|
||||||
- if: type != cron
|
# GCC tests
|
||||||
stage: test
|
- {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||||
name: Vltmt set 0 test
|
- {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||||
compiler: gcc
|
- {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||||
script: ci/test.sh vltmt0
|
- {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||||
- if: type != cron
|
- {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
|
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||||
name: Vltmt set 1 test
|
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||||
compiler: gcc
|
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||||
script: ci/test.sh vltmt1
|
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||||
# Cron builds try different OS/compiler combinations
|
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||||
- if: type = cron
|
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||||
stage: "Build Verilator"
|
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||||
name: Build xenial gcc Verilator
|
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||||
os: linux
|
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||||
dist: xenial
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||||
compiler: gcc
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||||
script: echo "Done building Verilator"
|
# Clang tests
|
||||||
- if: type = cron
|
- {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
|
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||||
name: Xenial gcc dist test
|
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||||
os: linux
|
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||||
dist: xenial
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||||
compiler: gcc
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||||
script: ci/test.sh dist
|
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||||
- if: type = cron
|
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||||
stage: test
|
# Coverage tests
|
||||||
name: Xenial gcc vlt test
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-dist}
|
||||||
os: linux
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-0}
|
||||||
dist: xenial
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-1}
|
||||||
compiler: gcc
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-2}
|
||||||
script: ci/test.sh vlt
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-3}
|
||||||
- if: type = cron
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-0}
|
||||||
stage: test
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-1}
|
||||||
name: Xenial gcc vltmt test
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-2}
|
||||||
os: linux
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-3}
|
||||||
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
|
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
email:
|
email:
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ src/Makefile$
|
|||||||
src/Makefile_obj$
|
src/Makefile_obj$
|
||||||
include/verilated.mk$
|
include/verilated.mk$
|
||||||
test_regress/.gdbinit$
|
test_regress/.gdbinit$
|
||||||
|
codecov.yml
|
||||||
config.cache$
|
config.cache$
|
||||||
config.status$
|
config.status$
|
||||||
verilator\.log
|
verilator\.log
|
||||||
|
|||||||
+9
-6
@@ -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-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://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://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]
|
image:https://travis-ci.com/verilator/verilator.svg?branch=master[Build Status (Travis CI),link=https://travis-ci.com/verilator/verilator]
|
||||||
endif::[]
|
endif::[]
|
||||||
|
|
||||||
@@ -20,9 +21,9 @@ endif::[]
|
|||||||
|
|
||||||
== Welcome to Verilator
|
== 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/> +++ • Accepts synthesizable Verilog or SystemVerilog
|
||||||
+++ <br/> +++ • Performs lint code-quality checks
|
+++ <br/> +++ • Performs lint code-quality checks
|
||||||
+++ <br/> +++ • Compiles into multithreaded {cpp}, or SystemC
|
+++ <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
|
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
|
class project (we recommend http://iverilog.icarus.com[Icarus Verilog] for
|
||||||
this.) However, if you are looking for a path to migrate SystemVerilog to
|
this.) However, if you are looking for a path to migrate SystemVerilog to
|
||||||
{cpp} or SystemC, and your team is comfortable writing just a
|
{cpp} or SystemC, or your team is comfortable writing just a touch of {cpp}
|
||||||
touch of {cpp} code, Verilator is the tool for you.
|
code, Verilator is the tool for you.
|
||||||
|
|
||||||
== Performance
|
== Performance
|
||||||
|
|
||||||
Verilator does not simply convert Verilog HDL to {cpp} or SystemC. Rather,
|
Verilator does not simply convert Verilog HDL to {cpp} or SystemC. Rather,
|
||||||
Verilator compiles your code into a much faster optimized and optionally
|
Verilator compiles your code into a much faster optimized and optionally
|
||||||
thread-partitioned model, which is in turn wrapped inside a
|
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
|
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
|
standalone SystemC, and on a single thread is about 100 times faster than
|
||||||
interpreted Verilog simulators such as http://iverilog.icarus.com[Icarus
|
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)],
|
* https://verilator.org/verilator_doc.html[Verilator manual (HTML)],
|
||||||
or https://verilator.org/verilator_doc.pdf[Verilator manual (PDF)]
|
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/forum[Verilator forum]
|
||||||
|
|
||||||
* https://verilator.org/issues[Verilator Issues]
|
* https://verilator.org/issues[Verilator issues]
|
||||||
|
|
||||||
== Support
|
== Support
|
||||||
|
|
||||||
|
|||||||
+244
-204
@@ -300,6 +300,7 @@ detailed descriptions in L</"VERILATION ARGUMENTS"> for more information.
|
|||||||
--dump-tree Enable dumping .tree files
|
--dump-tree Enable dumping .tree files
|
||||||
--dump-treei <level> Enable dumping .tree files at a level
|
--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-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
|
-E Preprocess, but do not compile
|
||||||
--error-limit <value> Abort after this number of errors
|
--error-limit <value> Abort after this number of errors
|
||||||
--exe Link to create executable
|
--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>
|
+verilog2001ext+<ext> Synonym for +1364-2001ext+<ext>
|
||||||
--version Displays program version and exits
|
--version Displays program version and exits
|
||||||
--vpi Enable VPI compiles
|
--vpi Enable VPI compiles
|
||||||
|
--waiver-output <filename> Create a waiver file based on the linter warnings
|
||||||
-Wall Enable all style warnings
|
-Wall Enable all style warnings
|
||||||
-Werror-<message> Convert warnings to errors
|
-Werror-<message> Convert warnings to errors
|
||||||
-Wfuture-<message> Disable unknown message warnings
|
-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
|
Level 0 disbles dumps and is equivalent to "--no-dump-tree". Level 9
|
||||||
enables dumping of every stage.
|
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
|
=item -E
|
||||||
|
|
||||||
Preprocess the source code, but do not compile, as with 'gcc -E'. Output
|
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
|
=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
|
=item Strings
|
||||||
|
|
||||||
@@ -1119,17 +1132,15 @@ developers.
|
|||||||
|
|
||||||
Enables splitting the output .cpp files into multiple outputs. When a C++
|
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
|
file exceeds the specified number of operations, a new file will be created
|
||||||
at the next function boundary. In addition, any infrequently executed
|
at the next function boundary. In addition, if the total output code size
|
||||||
"cold" routines will be placed into __Slow files. This accelerates
|
exceeds the specified value, VM_PARALLEL_BUILDS will be set to 1 by default
|
||||||
compilation by as optimization can be disabled on the routines in __Slow,
|
in the generated make files, making parallel compilation possible. Using
|
||||||
and the remaining files can be compiled on parallel machines. Using
|
--output-split should have only a trivial impact on model performance. But
|
||||||
--output-split should have only a trivial impact on performance. On one
|
can greatly improve C++ compilation speed. The use of I<ccache> (set for you
|
||||||
design --output-split 20000 resulted in splitting into approximately
|
if present at configure time) is also more effective with this option.
|
||||||
one-minute-compile chunks.
|
|
||||||
|
|
||||||
Typically when using this, make with VM_PARALLEL_BUILDS=1 (set for you if
|
This option is on by default with a value of 20000. To disable, pass with a
|
||||||
using the default makefiles), and use I<ccache> (set for you if present at
|
value of 0.
|
||||||
configure time).
|
|
||||||
|
|
||||||
=item --output-split-cfuncs I<statements>
|
=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
|
--output-split in the sense that --output-split will not split inside a
|
||||||
function.
|
function.
|
||||||
|
|
||||||
|
Defaults to the value of --output-split, unless explicitly specified.
|
||||||
|
|
||||||
=item --output-split-ctrace I<statements>
|
=item --output-split-ctrace I<statements>
|
||||||
|
|
||||||
Enables splitting trace functions in the output .cpp files into
|
Similar to --output-split-cfuncs, enables splitting trace functions in the
|
||||||
multiple functions. Defaults to same setting as --output-split-cfuncs.
|
output .cpp files into multiple functions.
|
||||||
|
|
||||||
|
Defaults to the value of --output-split, unless explicitly specified.
|
||||||
|
|
||||||
=item -P
|
=item -P
|
||||||
|
|
||||||
@@ -1451,7 +1466,7 @@ good value.
|
|||||||
|
|
||||||
Sets default timescale, timeunit and timeprecision for when `timescale does
|
Sets default timescale, timeunit and timeprecision for when `timescale does
|
||||||
not occur in sources. Default is "1ps/1ps" (to match SystemC). This is
|
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>
|
=item --timescale-override I<timeunit>/I<timeprecision>
|
||||||
|
|
||||||
@@ -1539,7 +1554,7 @@ larger trace files.
|
|||||||
=item --trace-threads I<threads>
|
=item --trace-threads I<threads>
|
||||||
|
|
||||||
Enable waveform tracing using separate threads. This is typically faster in
|
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
|
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
|
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
|
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.
|
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
|
=item -Wall
|
||||||
|
|
||||||
Enable all code style warnings, including code style warnings that are
|
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
|
# Might be needed if SystemC 2.3.0
|
||||||
export SYSTEMC_CXX_FLAGS=-pthread
|
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
|
-o Vour -lsystemc
|
||||||
|
|
||||||
And now we run it
|
And now we run it
|
||||||
@@ -2054,11 +2080,11 @@ distribution.
|
|||||||
|
|
||||||
=head1 BENCHMARKING & OPTIMIZATION
|
=head1 BENCHMARKING & OPTIMIZATION
|
||||||
|
|
||||||
For best performance, run Verilator with the "-O3 --x-assign fast
|
For best performance, run Verilator with the "-O3 --x-assign fast --x-initial
|
||||||
--x-initial fast --noassert" flags. The -O3 flag will require longer
|
fast --noassert" flags. The -O3 flag will require longer time to run
|
||||||
compile times, and "--x-assign fast --x-initial fast" may increase the risk
|
Verilator, and "--x-assign fast --x-initial fast" may increase the risk of
|
||||||
of reset bugs in trade for performance; see the above documentation for
|
reset bugs in trade for performance; see the above documentation for these
|
||||||
these flags.
|
flags.
|
||||||
|
|
||||||
If using Verilated multithreaded, use C<numactl> to ensure you are using
|
If using Verilated multithreaded, use C<numactl> to ensure you are using
|
||||||
non-conflicting hardware resources. See L</"MULTITHREADING">.
|
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.
|
performance improvement.
|
||||||
|
|
||||||
Beyond that, the performance of a Verilated model depends mostly on your
|
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
|
The supplied $VERILATOR_ROOT/include/verilated.mk file uses the OPT, OPT_FAST,
|
||||||
for the benefit of new users, as it improves compile times at the cost of
|
OPT_SLOW and OPT_GLOBAL variables to control optimization. You can set these
|
||||||
simulation runtimes. To add optimization as the default, set one of three variables,
|
when compiling the output of Verilator with Make, for example:
|
||||||
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:
|
|
||||||
|
|
||||||
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
|
OPT_FAST specifies optimization flags for those parts of the model that are on
|
||||||
fast path, mostly code that is executed every cycle. OPT_SLOW specifies
|
the fast path. This is mostly code that is executed every cycle. OPT_SLOW
|
||||||
optimizations for slow-path files (plus tracing), which execute only
|
applies to slow-path code, which executes rarely, often only once at the
|
||||||
rarely, yet take a long time to compile with optimization on. OPT
|
beginning or end of simulation. Note that OPT_SLOW is ignored if
|
||||||
specifies overall optimization and affects all compiles, including those
|
VM_PARALLEL_BUILDS is not 1, in which case all generated code will be compiled
|
||||||
OPT_FAST and OPT_SLOW control. For best results, use OPT="-Os
|
in a single compilation unit using OPT_FAST. See also the C<--output-split>
|
||||||
-march=native", and link with "-static". Nearly the same results can be
|
option. The OPT_GLOBAL variable applies to common code in the run-time library
|
||||||
had with much better compile times with OPT_FAST="-O1 -fstrict-aliasing".
|
used by verilated models (shipped in $VERILATOR_ROOT/include). Additional C++
|
||||||
Higher optimization such as "-O2" or "-O3" may help, but gcc compile times
|
files passed on the verilator command line use OPT_FAST. The OPT variable
|
||||||
may be excessive under O3 on even medium sized designs.
|
applies to all compilation units in addition to the specific OPT_* variables
|
||||||
|
described above.
|
||||||
|
|
||||||
Unfortunately, using the optimizer with SystemC files can result in
|
You can also use the -CFLAGS and/or -LDFLAGS options on the verilator command
|
||||||
compiles taking several minutes. (The SystemC libraries have many little
|
line to pass flags directly to the compiler or linker.
|
||||||
inlined functions that drive the compiler nuts.)
|
|
||||||
|
|
||||||
For best results, use the latest clang compiler (about 10% faster than
|
The default values of the OPT_* variables are chosen to yield good simulation
|
||||||
GCC). Note the now fairly old GCC 3.2 and earlier have optimization bugs
|
speed with reasonable C++ compilation times. To this end, OPT_FAST is set to
|
||||||
around pointer aliasing detection, which can result in 2x performance
|
"-Os" by default. Higher optimization such as "-O2" or "-O3" may help (though
|
||||||
losses.
|
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
|
Generally the answer to which optimization level gives the best user experience
|
||||||
feedback driven compilation. With GCC, using -fprofile-arcs, then
|
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.
|
-fbranch-probabilities will yield another 15% or so.
|
||||||
|
|
||||||
Modern compilers also support link-time optimization (LTO), which can help
|
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
|
especially if you link in DPI code. To enable LTO on GCC, pass "-flto" in both
|
||||||
both compilation and link. Note LTO may cause excessive compile times on
|
compilation and link. Note LTO may cause excessive compile times on large
|
||||||
large designs.
|
designs.
|
||||||
|
|
||||||
Using profile driven compiler optimization, with feedback from a real
|
Unfortunately, using the optimizer with SystemC files can result in compilation
|
||||||
design, can yield up to30% improvements.
|
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
|
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
|
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
|
{mod_prefix}{misc}.o // Intermediate objects
|
||||||
{prefix} // Final executable (w/--exe argument)
|
{prefix} // Final executable (w/--exe argument)
|
||||||
{prefix}__ALL.a // Library of all Verilated objects
|
{prefix}__ALL.a // Library of all Verilated objects
|
||||||
{prefix}__ALLfast.cpp // Include of hot code for single compile
|
{prefix}__ALL.cpp // Include of all code for single compile
|
||||||
{prefix}__ALLslow.cpp // Include of slow code for single compile
|
|
||||||
{prefix}{misc}.d // Intermediate dependencies
|
{prefix}{misc}.d // Intermediate dependencies
|
||||||
{prefix}{misc}.o // Intermediate objects
|
{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]
|
verilate(target SOURCES source ... [TOP_MODULE top] [PREFIX name]
|
||||||
[TRACE] [TRACE_FST] [SYSTEMC] [COVERAGE]
|
[TRACE] [TRACE_FST] [SYSTEMC] [COVERAGE]
|
||||||
[INCLUDE_DIRS dir ...] [OPT_SLOW ...] [OPT_FAST ...]
|
[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
|
Lowercase and ... should be replaced with arguments, the uppercase parts
|
||||||
delimit the arguments and can be passed in any order, or left out entirely
|
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.
|
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
|
=item DIRECTORY
|
||||||
|
|
||||||
Optional. Set the verilator output directory. It is preferable to use the
|
Optional. Set the verilator output directory. It is preferable to use the
|
||||||
@@ -2769,8 +2819,7 @@ underneath NC:
|
|||||||
cd obj_dir
|
cd obj_dir
|
||||||
ncsc_run \
|
ncsc_run \
|
||||||
sc_main.cpp \
|
sc_main.cpp \
|
||||||
Vour__ALLfast.cpp \
|
Vour__ALL.cpp \
|
||||||
Vour__ALLslow.cpp \
|
|
||||||
verilated.cpp
|
verilated.cpp
|
||||||
|
|
||||||
For larger designs you'll want to automate this using makefiles, which pull
|
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
|
Break the variable into multiple pieces typically to resolve UNOPTFLAT
|
||||||
performance issues. Typically the variables to attach this to are
|
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
|
Same as /*verilator split_var*/, see L</"LANGUAGE EXTENSIONS"> for more
|
||||||
information.
|
information.
|
||||||
@@ -3101,11 +3150,11 @@ uwire keyword.
|
|||||||
=head2 SystemVerilog 2005 (IEEE 1800-2005) Support
|
=head2 SystemVerilog 2005 (IEEE 1800-2005) Support
|
||||||
|
|
||||||
Verilator supports ==? and !=? operators, ++ and -- in some contexts,
|
Verilator supports ==? and !=? operators, ++ and -- in some contexts,
|
||||||
$bits, $countones, $error, $fatal, $info, $isunknown, $onehot, $onehot0,
|
$bits, $countbits, $countones, $error, $fatal, $info, $isunknown, $onehot,
|
||||||
$unit, $warning, always_comb, always_ff, always_latch, bit, byte, chandle,
|
$onehot0, $unit, $warning, always_comb, always_ff, always_latch, bit, byte,
|
||||||
const, do-while, enum, export, final, import, int, interface, logic,
|
chandle, const, do-while, enum, export, final, import, int, interface,
|
||||||
longint, modport, package, program, shortint, struct, time, typedef, union,
|
logic, longint, modport, package, program, shortint, struct, time, typedef,
|
||||||
var, void, priority case/if, and unique case/if.
|
union, var, void, priority case/if, and unique case/if.
|
||||||
|
|
||||||
It also supports .name and .* interconnection.
|
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
|
Attached to a variable or a net declaration to break the variable into
|
||||||
multiple pieces typically to resolve UNOPTFLAT performance issues.
|
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.
|
itself, see UNOPTFLAT below.
|
||||||
|
|
||||||
For example, Verilator will internally convert a variable with the
|
For example, Verilator will internally convert a variable with the
|
||||||
@@ -3620,29 +3669,24 @@ declared.
|
|||||||
|
|
||||||
=head1 LANGUAGE LIMITATIONS
|
=head1 LANGUAGE LIMITATIONS
|
||||||
|
|
||||||
There are some limitations and lack of features relative to a commercial
|
There are some limitations and lack of features relative to the major
|
||||||
simulator, by intent. User beware.
|
closed-source simulators, by intent.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
=head2 Synthesis Subset
|
=head2 Synthesis Subset
|
||||||
|
|
||||||
Verilator supports only the Synthesis subset with a few minor additions
|
Verilator supports the Synthesis subset with other verification constructs
|
||||||
such as $stop, $finish and $display. That is, you cannot use hierarchical
|
being added over time. Verilator also simulates events as Synopsys's Design
|
||||||
references, events or similar features of the Verilog language. It also
|
Compiler would; namely given a block of the form:
|
||||||
simulates as Synopsys's Design Compiler would; namely a block of the form:
|
|
||||||
|
|
||||||
always @ (x) y = x & z;
|
always @ (x) y = x & z;
|
||||||
|
|
||||||
This will recompute y when there is even a potential for change in x or a
|
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
|
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
|
what Design Compiler will synthesize.) A compliant simulator would only
|
||||||
calculate y if x changes. Use Verilog-Mode's /*AS*/ or Verilog 2001's
|
calculate y if x changes. We recommend using always_comb to make the code
|
||||||
always @* to reduce missing activity items. Avoid putting $displays in
|
run the same everywhere. Also avoid putting $displays in combo blocks, as
|
||||||
combo blocks, as they may print multiple times when not desired, even on
|
they may print multiple times when not desired, even on compliant
|
||||||
compliant simulators as event ordering is not specified.
|
simulators as event ordering is not specified.
|
||||||
|
|
||||||
=head2 Signal Naming
|
=head2 Signal Naming
|
||||||
|
|
||||||
@@ -3659,9 +3703,9 @@ path.
|
|||||||
|
|
||||||
=head2 Class
|
=head2 Class
|
||||||
|
|
||||||
Verilator class support is very limited and in active development.
|
Verilator class support is limited but in active development. Verilator
|
||||||
Verilator supports members, and methods. Verilator doe not support class
|
supports members, and methods. Verilator doe not support class static
|
||||||
static members, class extend, or class parameters.
|
members, class extend, or class parameters.
|
||||||
|
|
||||||
=head2 Dotted cross-hierarchy references
|
=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}[{instanceNumber}] in Verilog, which becomes
|
||||||
{cellname}__BRA__{instanceNumber}__KET__ inside the generated C++ code.
|
{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
|
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.
|
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
|
=head2 Latches
|
||||||
|
|
||||||
Verilator is optimized for edge sensitive (flop based) designs. It will
|
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
|
For proper behavior clock enables may also need the /*verilator
|
||||||
clock_enable*/ attribute.
|
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
|
=head2 Gate Primitives
|
||||||
|
|
||||||
The 2-state gate primitives (and, buf, nand, nor, not, or, xnor, xor) are
|
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
|
=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
|
=head2 Array Initialization
|
||||||
|
|
||||||
@@ -3831,7 +3861,6 @@ coverage section.
|
|||||||
|
|
||||||
Verilator does not support SEREs yet. All assertion and coverage
|
Verilator does not support SEREs yet. All assertion and coverage
|
||||||
statements must be simple expressions that complete in one cycle.
|
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
|
=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
|
Generate blocks around modports are not supported, nor are virtual
|
||||||
interfaces nor unnamed interfaces.
|
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
|
Short floating point (shortreal) numbers are converted to real. Most other
|
||||||
full nor unique.
|
simulators either do not support float, or convert likewise.
|
||||||
|
|
||||||
=item specify specparam
|
=item specify specparam
|
||||||
|
|
||||||
All specify blocks and timing checks are ignored.
|
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
|
=item uwire
|
||||||
|
|
||||||
Verilator does not perform warning checking on uwires, it treats the uwire
|
Verilator does not perform warning checking on uwires, it treats the uwire
|
||||||
keyword as if it were the normal wire keyword.
|
keyword as if it were the normal wire keyword.
|
||||||
|
|
||||||
=item $bits, $countones, $error, $fatal, $finish, $info, $isunknown,
|
=item $bits, $countbits, $countones, $error, $fatal, $finish, $info,
|
||||||
$onehot, $onehot0, $readmemb, $readmemh, $signed, $stime, $stop, $time,
|
$isunknown, $onehot, $onehot0, $readmemb, $readmemh, $signed, $stime, $stop,
|
||||||
$unsigned, $warning.
|
$time, $unsigned, $warning.
|
||||||
|
|
||||||
Generally supported.
|
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
|
=item $dump/$dumpports and related
|
||||||
|
|
||||||
$dumpfile or $dumpports will create a VCD or FST file (which is based on
|
$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.
|
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
|
=item $random
|
||||||
|
|
||||||
$random does not support the optional argument to set the seed. Use the
|
$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
|
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
|
used. This may cause simulation-synthesis mismatches, as not all
|
||||||
commercial simulators allow this ordering.
|
simulators allow this ordering.
|
||||||
|
|
||||||
always_comb begin
|
always_comb begin
|
||||||
a = b;
|
a = b;
|
||||||
@@ -4797,7 +4816,10 @@ correctly.
|
|||||||
Warns that unpacked structs and unions are not supported.
|
Warns that unpacked structs and unions are not supported.
|
||||||
|
|
||||||
Ignoring this warning will make Verilator treat the structure as packed,
|
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
|
=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
|
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.
|
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
|
Generally, the implied part is of the question is "... with all of the
|
||||||
manpower they can put into developing it."
|
manpower they can put into developing it."
|
||||||
|
|
||||||
Most commercial simulators have to be Verilog compliant, meaning event
|
Most simulators have to be Verilog compliant, meaning event driven. This
|
||||||
driven. This prevents them from being able to reorder blocks and make
|
prevents them from being able to reorder blocks and make netlist-style
|
||||||
netlist-style optimizations, which are where most of the gains come from.
|
optimizations, which are where most of the gains come from.
|
||||||
|
|
||||||
Non-compliance shouldn't be scary. Your synthesis program isn't compliant,
|
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
|
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
|
(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
|
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,
|
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
|
but about 1GB is the maximum typically needed, and very large designs have
|
||||||
designs have topped 16GB.
|
topped 16GB.
|
||||||
|
|
||||||
=item How do I generate waveforms (traces) in C++?
|
=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)?
|
=item How do I view waveforms (aka dumps or traces)?
|
||||||
|
|
||||||
Verilator makes standard VCD (Value Change Dump) and FST files. VCD files are viewable
|
Verilator makes standard VCD (Value Change Dump) and FST files. VCD files
|
||||||
with the public domain GTKWave (recommended) or Dinotrace (legacy)
|
are viewable with the public domain GTKWave (recommended) or Dinotrace
|
||||||
programs, or any of the many commercial offerings;
|
(legacy) programs, or any of the many closed-source offerings; FST is
|
||||||
FST is supported by GTKWave only.
|
supported by GTKWave only.
|
||||||
|
|
||||||
=item How do I reduce the size of large waveform (trace) files?
|
=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
|
see the examples/make_tracing_c/logs directory. Grep for lines starting
|
||||||
with '%' to see what lines Verilator believes need more coverage.
|
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?)
|
=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
|
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?
|
=item How do I get faster build times?
|
||||||
|
|
||||||
When running make pass the make variable VM_PARALLEL_BUILDS=1 so that
|
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
|
Verilator emits any infrequently executed "cold" routines into separate
|
||||||
now relatively old GCC 3.0 to 3.3 being horrible.
|
__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
|
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
|
ccache, distcc and icecream packages. ccache will skip GCC runs between
|
||||||
@@ -5365,7 +5396,7 @@ outputs. Now, the following should fail:
|
|||||||
cd test_regress
|
cd test_regress
|
||||||
t/t_BUG.pl # Run on Verilator
|
t/t_BUG.pl # Run on Verilator
|
||||||
t/t_BUG.pl --debug # Run on Verilator, passing --debug to 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
|
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
|
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
|
Currently, various language features and performance enhancements are added
|
||||||
as the need arises. Verilator is now about 3x faster than in 2002, and is
|
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
|
=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.
|
Many people have provided ideas and other assistance with Verilator.
|
||||||
|
|
||||||
The major corporate sponsors of Verilator, by providing significant
|
Verilator is receiving major development support from the CHIPS Alliance.
|
||||||
contributions of time or funds include include Atmel Corporation, Cavium
|
|
||||||
|
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.,
|
Inc., Compaq Corporation, Digital Equipment Corporation, Embecosm Ltd.,
|
||||||
Hicamp Systems, Intel Corporation, Mindspeed Technologies Inc., MicroTune
|
Hicamp Systems, Intel Corporation, Mindspeed Technologies Inc., MicroTune
|
||||||
Inc., picoChip Designs Ltd., Sun Microsystems Inc., Nauticus Networks Inc.,
|
Inc., picoChip Designs Ltd., Sun Microsystems Inc., Nauticus Networks Inc.,
|
||||||
and SiCortex Inc.
|
and SiCortex Inc.
|
||||||
|
|
||||||
The people who have contributed major functionality are Byron Bradley,
|
The people who have contributed major functionality are Byron Bradley,
|
||||||
Jeremy Bennett, Lane Brooks, John Coiner, Duane Galbi, Todd Strader, Paul
|
Jeremy Bennett, Lane Brooks, John Coiner, Duane Galbi, Geza Lore, Todd
|
||||||
Wasson, Jie Xu, and Wilson Snyder. Major testers included Jeff Dutton,
|
Strader, Stefan Wallentowitz, Paul Wasson, Jie Xu, and Wilson Snyder.
|
||||||
Jonathon Donaldson, Ralf Karge, David Hewson, Iztok Jeras, Wim Michiels,
|
Major testers included Jeff Dutton, Jonathon Donaldson, Ralf Karge, David
|
||||||
Alex Solomatnikov, Sebastien Van Cauwenberghe, Gene Weber, and Clifford
|
Hewson, Iztok Jeras, Wim Michiels, Alex Solomatnikov, Sebastien Van
|
||||||
Wolf.
|
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
|
include: David Addison, Tariq B. Ahmad, Nikana Anastasiadis, Hans Van
|
||||||
Antwerpen, Vasu Arasanipalai, Jens Arm, Sharad Bagri, Matthew Ballance,
|
Antwerpen, Vasu Arasanipalai, Jens Arm, Sharad Bagri, Matthew Ballance,
|
||||||
Andrew Bardsley, Matthew Barr, Geoff Barrett, Julius Baxter, Jeremy
|
Andrew Bardsley, Matthew Barr, Geoff Barrett, Julius Baxter, Jeremy
|
||||||
Bennett, Michael Berman, Victor Besyakov, David Binderman, Piotr Binkowski,
|
Bennett, Michael Berman, Victor Besyakov, Moinak Bhattacharyya, David
|
||||||
Johan Bjork, David Black, Tymoteusz Blazejczyk, Daniel Bone, Gregg
|
Binderman, Piotr Binkowski, Johan Bjork, David Black, Tymoteusz Blazejczyk,
|
||||||
Bouchard, Christopher Boumenot, Nick Bowler, Byron Bradley, Bryan Brady,
|
Daniel Bone, Gregg Bouchard, Christopher Boumenot, Nick Bowler, Byron
|
||||||
Maarten De Braekeleer, Charlie Brej, J Briquet, Lane Brooks, John Brownlee,
|
Bradley, Bryan Brady, Maarten De Braekeleer, Charlie Brej, J Briquet, Lane
|
||||||
Jeff Bush, Lawrence Butcher, Tony Bybell, Ted Campbell, Chris Candler,
|
Brooks, John Brownlee, Jeff Bush, Lawrence Butcher, Tony Bybell, Ted
|
||||||
Lauren Carlson, Donal Casey, Sebastien Van Cauwenberghe, Alex Chadwick,
|
Campbell, Chris Candler, Lauren Carlson, Donal Casey, Sebastien Van
|
||||||
Terry Chen, Yi-Chung Chen, Enzo Chi, Robert A. Clark, Allan Cochrane, John
|
Cauwenberghe, Alex Chadwick, Terry Chen, Yi-Chung Chen, Enzo Chi, Robert
|
||||||
Coiner, Gianfranco Costamagna, George Cuan, Joe DErrico, Lukasz Dalek,
|
A. Clark, Allan Cochrane, John Coiner, Gianfranco Costamagna, Sean Cross,
|
||||||
Laurens van Dam, Gunter Dannoritzer, Ashutosh Das, Bernard Deadman, John
|
George Cuan, Joe DErrico, Lukasz Dalek, Laurens van Dam, Gunter
|
||||||
Demme, Mike Denio, John Deroo, Philip Derrick, John Dickol, Ruben Diez,
|
Dannoritzer, Ashutosh Das, Bernard Deadman, John Demme, Mike Denio, John
|
||||||
Danny Ding, Jacko Dirks, Ivan Djordjevic, Jonathon Donaldson, Leendert van
|
Deroo, Philip Derrick, John Dickol, Ruben Diez, Danny Ding, Jacko Dirks,
|
||||||
Doorn, Sebastian Dressler, Alex Duller, Jeff Dutton, Tomas Dzetkulic,
|
Ivan Djordjevic, Jonathon Donaldson, Leendert van Doorn, Sebastian
|
||||||
Usuario Eda, Charles Eddleston, Chandan Egbert, Joe Eiler, Ahmed
|
Dressler, Alex Duller, Jeff Dutton, Tomas Dzetkulic, Usuario Eda, Charles
|
||||||
El-Mahmoudy, Trevor Elbourne, Robert Farrell, Eugen Fekete, Fabrizio
|
Eddleston, Chandan Egbert, Joe Eiler, Ahmed El-Mahmoudy, Trevor Elbourne,
|
||||||
Ferrandi, Udi Finkelstein, Brian Flachs, Andrea Foletto, Bob Fredieu, Duane
|
Mats Engstrom, Robert Farrell, Eugen Fekete, Fabrizio Ferrandi, Udi
|
||||||
Galbi, Benjamin Gartner, Christian Gelinek, Peter Gerst, Glen Gibb, Shankar
|
Finkelstein, Brian Flachs, Andrea Foletto, Bob Fredieu, Duane Galbi,
|
||||||
Giri, Dan Gisselquist, Sam Gladstone, Amir Gonnen, Chitlesh Goorah, Sergi
|
Benjamin Gartner, Christian Gelinek, Peter Gerst, Glen Gibb, Michael
|
||||||
Granell, Al Grant, Xuan Guo, Driss Hafdi, Neil Hamilton, Oyvind Harboe,
|
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
|
Jannis Harder, Junji Hashimoto, Thomas Hawkins, Mitch Hayenga, Robert
|
||||||
Henry, David Hewson, Jamey Hicks, Joel Holdsworth, Andrew Holme, Hiroki
|
Henry, Stephen Henry, David Hewson, Jamey Hicks, Joel Holdsworth, Andrew
|
||||||
Honda, Alex Hornung, David Horton, Jae Hossell, Alan Hunter, James
|
Holme, Hiroki Honda, Alex Hornung, David Horton, Peter Horvath, Jae
|
||||||
Hutchinson, Jamie Iles, Ben Jackson, Shareef Jalloq, Krzysztof Jankowski,
|
Hossell, Alan Hunter, James Hutchinson, Jamie Iles, Ben Jackson, Shareef
|
||||||
HyungKi Jeong, Iztok Jeras, James Johnson, Christophe Joly, Franck Jullien,
|
Jalloq, Krzysztof Jankowski, HyungKi Jeong, Iztok Jeras, James Johnson,
|
||||||
James Jung, Mike Kagen, Arthur Kahlich, Kaalia Kahn, Guy-Armand Kamendje,
|
Christophe Joly, Franck Jullien, James Jung, Mike Kagen, Arthur Kahlich,
|
||||||
Vasu Kandadi, Kanad Kanhere, Patricio Kaplan, Pieter Kapsenberg, Ralf
|
Kaalia Kahn, Guy-Armand Kamendje, Vasu Kandadi, Kanad Kanhere, Patricio
|
||||||
Karge, Dan Katz, Sol Katzman, Jonathan Kimmitt, Olof Kindgren, Kevin
|
Kaplan, Pieter Kapsenberg, Ralf Karge, Dan Katz, Sol Katzman, Ian Kennedy,
|
||||||
Kiningham, Dan Kirkham, Sobhan Klnv, Gernot Koch, Soon Koh, Steve Kolecki,
|
Jonathan Kimmitt, Olof Kindgren, Kevin Kiningham, Dan Kirkham, Sobhan Klnv,
|
||||||
Brett Koonce, Will Korteland, Wojciech Koszek, Varun Koyyalagunta, David
|
Gernot Koch, Soon Koh, Nathan Kohagen, Steve Kolecki, Brett Koonce, Will
|
||||||
Kravitz, Roland Kruse, Sergey Kvachonok, Ed Lander, Steve Lang, Stephane
|
Korteland, Wojciech Koszek, Varun Koyyalagunta, David Kravitz, Roland
|
||||||
Laurent, Walter Lavino, Christian Leber, Larry Lee, Igor Lesik, John Li,
|
Kruse, Sergey Kvachonok, Charles Eric LaForest, Ed Lander, Steve Lang,
|
||||||
Eivind Liland, Yu Sheng Lin, Charlie Lind, Andrew Ling, Paul Liu, Derek
|
Stephane Laurent, Walter Lavino, Christian Leber, Larry Lee, Igor Lesik,
|
||||||
Lockhart, Jake Longo, Arthur Low, Stefan Ludwig, Dan Lussier, Fred Ma,
|
John Li, Eivind Liland, Yu Sheng Lin, Charlie Lind, Andrew Ling, Jiuyang
|
||||||
Duraid Madina, Affe Mao, Julien Margetts, Mark Marshall, Alfonso Martinez,
|
Liu, Paul Liu, Derek Lockhart, Jake Longo, Geza Lore, Arthur Low, Stefan
|
||||||
Yves Mathieu, Patrick Maupin, Jason McMullan, Elliot Mednick, Wim Michiels,
|
Ludwig, Dan Lussier, Fred Ma, Duraid Madina, Affe Mao, Julien Margetts,
|
||||||
Miodrag Milanovic, Wai Sum Mong, Peter Monsson, Sean Moore, Dennis
|
Mark Marshall, Alfonso Martinez, Yves Mathieu, Patrick Maupin, Jason
|
||||||
Muhlestein, John Murphy, Matt Myers, Richard Myers, Dimitris Nalbantis,
|
McMullan, Elliot Mednick, Wim Michiels, Miodrag Milanovic, Wai Sum Mong,
|
||||||
Peter Nelson, Bob Newgard, Cong Van Nguyen, Paul Nitza, Yossi Nivin, Pete
|
Peter Monsson, Sean Moore, Dennis Muhlestein, John Murphy, Matt Myers,
|
||||||
Nixon, Lisa Noack, Mark Nodine, Andreas Olofsson, Aleksander Osman, James
|
Nathan Myers, Richard Myers, Dimitris Nalbantis, Peter Nelson, Bob Newgard,
|
||||||
Pallister, Brad Parker, Dan Petrisko, Maciej Piechotka, David Pierce,
|
Cong Van Nguyen, Paul Nitza, Yossi Nivin, Pete Nixon, Lisa Noack, Mark
|
||||||
Dominic Plunkett, David Poole, Mike Popoloski, Roman Popov, Rich Porter,
|
Nodine, Kuba Ober, Andreas Olofsson, Aleksander Osman, James Pallister,
|
||||||
Niranjan Prabhu, Usha Priyadharshini, Mark Jackson Pulver, Prateek Puri,
|
Vassilis Papaefstathiou, Brad Parker, Dan Petrisko, Maciej Piechotka, David
|
||||||
Marshal Qiao, Danilo Ramos, Chris Randall, Anton Rapp, Josh Redford, Odd
|
Pierce, Dominic Plunkett, David Poole, Mike Popoloski, Roman Popov, Rich
|
||||||
Magne Reitan, Frederic Requin, Frederick Requin, Alberto Del Rio, Eric
|
Porter, Niranjan Prabhu, Usha Priyadharshini, Mark Jackson Pulver, Prateek
|
||||||
Rippey, Oleg Rodionov, Paul Rolfe, Arjen Roodselaar, Tobias Rosenkranz, Jan
|
Puri, Marshal Qiao, Danilo Ramos, Chris Randall, Anton Rapp, Josh Redford,
|
||||||
Egil Ruud, Denis Rystsov, John Sanguinetti, Galen Seitz, Salman Sheikh, Hao
|
Odd Magne Reitan, Frederic Requin, Frederick Requin, Dustin Richmond,
|
||||||
Shi, Mike Shinkarovsky, Rafael Shirakawa, Jeffrey Short, Anderson Ignacio
|
Alberto Del Rio, Eric Rippey, Oleg Rodionov, Ludwig Rogiers, Paul Rolfe,
|
||||||
Da Silva, Rodney Sinclair, Steven Slatter, Brian Small, Garrett Smith,
|
Arjen Roodselaar, Tobias Rosenkranz, Huang Rui, Jan Egil Ruud, Denis
|
||||||
Wilson Snyder, Stan Sokorac, Alex Solomatnikov, Wei Song, Art Stamness,
|
Rystsov, John Sanguinetti, Galen Seitz, Salman Sheikh, Hao Shi, Mike
|
||||||
John Stevenson, Patrick Stewart, Rob Stoddard, Todd Strader, John Stroebel,
|
Shinkarovsky, Rafael Shirakawa, Jeffrey Short, Anderson Ignacio Da Silva,
|
||||||
Sven Stucki, Howard Su, Emerson Suguimoto, Gene Sullivan, Renga
|
Rodney Sinclair, Steven Slatter, Brian Small, Garrett Smith, Tim Snyder,
|
||||||
Sundararajan, Rupert Swarbrick, Yutetsu Takatsukasa, Peter Tengstrand,
|
Maciej Sobkowski, Stan Sokorac, Alex Solomatnikov, Wei Song, Art Stamness,
|
||||||
Wesley Terpstra, Rui Terra, Stefan Thiede, Gary Thomas, Ian Thompson, Kevin
|
David Stanford, John Stevenson, Pete Stevenson, Patrick Stewart, Rob
|
||||||
Thompson, Mike Thyer, Hans Tichelaar, Viktor Tomov, Steve Tong, Michael
|
Stoddard, Todd Strader, John Stroebel, Sven Stucki, Howard Su, Emerson
|
||||||
Tresidder, Neil Turton, Bogdan Vukobratovic, Holger Waechtler, Philipp
|
Suguimoto, Gene Sullivan, Qingyao Sun, Renga Sundararajan, Rupert
|
||||||
Wagner, Stefan Wallentowitz, Shawn Wang, Paul Wasson, Greg Waters, Thomas
|
Swarbrick, Yutetsu Takatsukasa, Peter Tengstrand, Wesley Terpstra, Rui
|
||||||
Watts, Eugene Weber, David Welch, Thomas J Whatson, Leon Wildman, Gerald
|
Terra, Stefan Thiede, Gary Thomas, Ian Thompson, Kevin Thompson, Mike
|
||||||
Williams, Trevor Williams, Jeff Winston, Joshua Wise, Clifford Wolf, Johan
|
Thyer, Hans Tichelaar, Viktor Tomov, Steve Tong, Michael Tresidder, Neil
|
||||||
Wouters, Junyi Xi, Ding Xiaoliang, Jie Xu, Mandy Xu, Luke Yang, and Amir
|
Turton, Srini Vemuri, Yuri Victorovich, Bogdan Vukobratovic, Holger
|
||||||
Yazdanbakhsh.
|
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
|
Thanks to them, and all those we've missed including above, or wished to
|
||||||
remain anonymous.
|
remain anonymous.
|
||||||
|
|||||||
+17
-3
@@ -156,6 +156,8 @@ verilator_coverage - Verilator coverage analyzer
|
|||||||
|
|
||||||
verilator_coverage -write merged.dat -read <datafiles>...
|
verilator_coverage -write merged.dat -read <datafiles>...
|
||||||
|
|
||||||
|
verilator_coverage -write-info merged.info -read <datafiles>...
|
||||||
|
|
||||||
Verilator_coverage processes Verilator coverage reports.
|
Verilator_coverage processes Verilator coverage reports.
|
||||||
|
|
||||||
With --anotate, it reads the specified data file and generates annotated
|
With --anotate, it reads the specified data file and generates annotated
|
||||||
@@ -224,8 +226,20 @@ Displays program version and exits.
|
|||||||
=item --write I<filename>
|
=item --write I<filename>
|
||||||
|
|
||||||
Specifies the aggregate coverage results, summed across all the files,
|
Specifies the aggregate coverage results, summed across all the files,
|
||||||
should be written to the given filename. This is useful in scripts to
|
should be written to the given filename in verilator_coverage data format.
|
||||||
combine many sequential runs into one master coverage file.
|
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
|
=back
|
||||||
|
|
||||||
@@ -277,7 +291,7 @@ Wilson Snyder <[email protected]>
|
|||||||
|
|
||||||
=head1 SEE ALSO
|
=head1 SEE ALSO
|
||||||
|
|
||||||
C<verilator>
|
C<verilator>, C<lcov>
|
||||||
|
|
||||||
L<verilator_coverage --help> which is the source for this document.
|
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.
|
# Version 2.0.
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-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 \
|
RUN apt-get update \
|
||||||
&& DEBIAN_FRONTEND=noninteractive \
|
&& DEBIAN_FRONTEND=noninteractive \
|
||||||
apt-get install --no-install-recommends -y \
|
apt-get install --no-install-recommends -y \
|
||||||
autoconf=2.69-11 \
|
autoconf \
|
||||||
bc=1.07.1-2 \
|
bc \
|
||||||
bison=2:3.0.4.dfsg-1build1 \
|
bison \
|
||||||
build-essential=12.4ubuntu1 \
|
build-essential \
|
||||||
ca-certificates=20180409 \
|
ca-certificates \
|
||||||
cmake=3.10.2-1ubuntu2.18.04.1 \
|
ccache \
|
||||||
flex=2.6.4-6 \
|
clang \
|
||||||
gdb=8.1-0ubuntu3.2 \
|
cmake \
|
||||||
gcc-6=6.5.0-2ubuntu1~18.04 \
|
flex \
|
||||||
gcc-5=5.5.0-12ubuntu1 \
|
gdb \
|
||||||
gcc-4.8=4.8.5-4ubuntu8 \
|
git \
|
||||||
git=1:2.17.1-1ubuntu0.5 \
|
gtkwave \
|
||||||
gtkwave=3.3.86-1 \
|
libfl2 \
|
||||||
g++-6=6.5.0-2ubuntu1~18.04 \
|
libfl-dev \
|
||||||
g++-5=5.5.0-12ubuntu1 \
|
libgoogle-perftools-dev \
|
||||||
g++-4.8=4.8.5-4ubuntu8 \
|
libsystemc \
|
||||||
libfl2=2.6.4-6 \
|
libsystemc-dev \
|
||||||
libfl-dev=2.6.4-6 \
|
numactl \
|
||||||
numactl=2.0.11-2.1ubuntu0.1 \
|
perl \
|
||||||
perl=5.26.1-6ubuntu0.3 \
|
python3 \
|
||||||
python3=3.6.7-1~18.04 \
|
wget \
|
||||||
wget=1.19.4-1ubuntu2.2 \
|
zlibc \
|
||||||
zlibc=0.9k-4.3 \
|
zlib1g \
|
||||||
zlib1g=1:1.2.11.dfsg-0ubuntu2 \
|
zlib1g-dev \
|
||||||
zlib1g-dev=1:1.2.11.dfsg-0ubuntu2 \
|
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
WORKDIR /tmp
|
WORKDIR /tmp
|
||||||
|
|
||||||
COPY build-systemc.sh /tmp/
|
|
||||||
RUN ./build-systemc.sh
|
|
||||||
|
|
||||||
RUN cpan install -fi Unix::Processors Parallel::Forker Bit::Vector
|
RUN cpan install -fi Unix::Processors Parallel::Forker Bit::Vector
|
||||||
|
|
||||||
RUN git clone https://github.com/veripool/vcddiff.git && \
|
RUN git clone https://github.com/veripool/vcddiff.git && \
|
||||||
@@ -55,4 +51,6 @@ COPY build.sh /tmp/build.sh
|
|||||||
|
|
||||||
ENV VERILATOR_AUTHOR_SITE=1
|
ENV VERILATOR_AUTHOR_SITE=1
|
||||||
|
|
||||||
|
WORKDIR /work
|
||||||
|
|
||||||
ENTRYPOINT [ "/tmp/build.sh" ]
|
ENTRYPOINT [ "/tmp/build.sh" ]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ build. It uses the following parameters:
|
|||||||
|
|
||||||
* Source repository (default: https://github.com/verilator/verilator)
|
* Source repository (default: https://github.com/verilator/verilator)
|
||||||
* Source revision (default: master)
|
* 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
|
The container is published as `verilator/verilator-buildenv` on
|
||||||
https://hub.docker.com/repository/docker/verilator/verilator-buildenv[docker hub].
|
https://hub.docker.com/repository/docker/verilator/verilator-buildenv[docker hub].
|
||||||
@@ -20,13 +20,13 @@ To also run tests:
|
|||||||
|
|
||||||
To change the compiler:
|
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.
|
The tests that involve gdb are not working due to security restrictions.
|
||||||
To run those too:
|
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
|
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}"
|
: "${CC:=gcc}"
|
||||||
: "${CXX:=g++}"
|
: "${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
|
SRCS=$PWD/verilator
|
||||||
|
|
||||||
git clone "$REPO" "$SRCS"
|
git clone "$REPO" "$SRCS"
|
||||||
|
|||||||
@@ -6,19 +6,20 @@
|
|||||||
# Version 2.0.
|
# Version 2.0.
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-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 \
|
RUN apt-get update \
|
||||||
|
&& DEBIAN_FRONTEND=noninteractive \
|
||||||
&& apt-get install --no-install-recommends -y \
|
&& apt-get install --no-install-recommends -y \
|
||||||
autoconf=2.69-11 \
|
autoconf \
|
||||||
bc=1.07.1-2 \
|
bc \
|
||||||
bison=2:3.0.4.dfsg-1build1 \
|
bison \
|
||||||
build-essential=12.4ubuntu1 \
|
build-essential \
|
||||||
ca-certificates=20180409 \
|
ca-certificates \
|
||||||
ccache \
|
ccache \
|
||||||
flex=2.6.4-6 \
|
flex \
|
||||||
git \
|
git \
|
||||||
libfl-dev=2.6.4-6 \
|
libfl-dev \
|
||||||
libgoogle-perftools-dev \
|
libgoogle-perftools-dev \
|
||||||
perl \
|
perl \
|
||||||
python3 \
|
python3 \
|
||||||
|
|||||||
-34
@@ -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
|
|
||||||
Executable
+29
@@ -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
|
||||||
Executable
+37
@@ -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
|
||||||
Executable
+72
@@ -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
|
||||||
Executable
+101
@@ -0,0 +1,101 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# DESCRIPTION: Verilator: Travis CI main job script
|
||||||
|
#
|
||||||
|
# Copyright 2020 by Geza Lore. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# This is the main script executed in the 'script' phase by all jobs. We use a
|
||||||
|
# single script to keep the .travis.yml spec simple. We pass job parameters via
|
||||||
|
# environment variables using 'env' keys. Having different 'env' keys in jobs
|
||||||
|
# ensures they use different Travis build caches.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
|
||||||
|
fatal() {
|
||||||
|
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then
|
||||||
|
##############################################################################
|
||||||
|
# Build verilator
|
||||||
|
|
||||||
|
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||||
|
if [ "$COVERAGE" != 1 ]; then
|
||||||
|
autoconf
|
||||||
|
./configure --enable-longtests --enable-ccwarn
|
||||||
|
make -j $(nproc)
|
||||||
|
else
|
||||||
|
nodist/code_coverage --stages 1-2
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
fatal "Unknown os: '$TRAVIS_OS_NAME'"
|
||||||
|
fi
|
||||||
|
elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
|
||||||
|
##############################################################################
|
||||||
|
# Run tests
|
||||||
|
|
||||||
|
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||||
|
# Run the specified test
|
||||||
|
case $TESTS in
|
||||||
|
dist-vlt-0)
|
||||||
|
make -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=0/2
|
||||||
|
;;
|
||||||
|
dist-vlt-1)
|
||||||
|
make -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=1/2
|
||||||
|
;;
|
||||||
|
vltmt-0)
|
||||||
|
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2
|
||||||
|
;;
|
||||||
|
vltmt-1)
|
||||||
|
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2
|
||||||
|
;;
|
||||||
|
coverage-dist)
|
||||||
|
nodist/code_coverage --stages 3- --scenarios=--dist
|
||||||
|
;;
|
||||||
|
coverage-vlt-0)
|
||||||
|
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=0/4
|
||||||
|
;;
|
||||||
|
coverage-vlt-1)
|
||||||
|
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=1/4
|
||||||
|
;;
|
||||||
|
coverage-vlt-2)
|
||||||
|
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=2/4
|
||||||
|
;;
|
||||||
|
coverage-vlt-3)
|
||||||
|
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=3/4
|
||||||
|
;;
|
||||||
|
coverage-vltmt-0)
|
||||||
|
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=0/4
|
||||||
|
;;
|
||||||
|
coverage-vltmt-1)
|
||||||
|
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=1/4
|
||||||
|
;;
|
||||||
|
coverage-vltmt-2)
|
||||||
|
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=2/4
|
||||||
|
;;
|
||||||
|
coverage-vltmt-3)
|
||||||
|
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=3/4
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
fatal "Unknown test: $TESTS"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
# Upload coverage data to codecov.io
|
||||||
|
if [[ $TESTS == coverage-* ]]; then
|
||||||
|
bash <(curl -s https://codecov.io/bash) -f nodist/obj_dir/coverage/app_total.info
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
fatal "Unknown os: '$TRAVIS_OS_NAME'"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
##############################################################################
|
||||||
|
# Unknown build stage
|
||||||
|
fatal "Unknown build stage: '$TRAVIS_BUILD_STAGE_NAME'"
|
||||||
|
fi
|
||||||
+38
@@ -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
|
||||||
+19
-1
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||||
#AC_INIT([Verilator],[#.### devel])
|
#AC_INIT([Verilator],[#.### devel])
|
||||||
AC_INIT([Verilator],[4.034 2020-05-03],
|
AC_INIT([Verilator],[4.036 2020-06-06],
|
||||||
[https://verilator.org],
|
[https://verilator.org],
|
||||||
[verilator],[https://verilator.org])
|
[verilator],[https://verilator.org])
|
||||||
# When releasing, also update header of Changes file
|
# 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_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)
|
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])
|
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
|
# Ignore automake flags passed by Ubuntu builds
|
||||||
AC_ARG_ENABLE([dependency-tracking],
|
AC_ARG_ENABLE([dependency-tracking],
|
||||||
@@ -416,6 +419,7 @@ AC_LINK_IFELSE(
|
|||||||
CFG_WITH_THREADED=$_my_result
|
CFG_WITH_THREADED=$_my_result
|
||||||
AC_SUBST(CFG_WITH_THREADED)
|
AC_SUBST(CFG_WITH_THREADED)
|
||||||
AC_MSG_RESULT($CFG_WITH_THREADED)
|
AC_MSG_RESULT($CFG_WITH_THREADED)
|
||||||
|
CXXFLAGS="$ACO_SAVE_CXXFLAGS"
|
||||||
|
|
||||||
# Check compiler flag
|
# Check compiler flag
|
||||||
if test "$CFG_WITH_THREADED" = "no" ; then
|
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])],
|
[AC_DEFINE([HAVE_STAT_NSEC],[1],[Defined if struct stat has st_mtim.tv_nsec])],
|
||||||
[], [#include <sys/stat.h>])
|
[], [#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
|
# Checks for system services
|
||||||
|
|
||||||
# Other install directories
|
# Other install directories
|
||||||
|
|||||||
@@ -6,15 +6,22 @@ Please see the Verilator manual for 200+ additional contributors. Thanks to all.
|
|||||||
Ahmed El-Mahmoudy
|
Ahmed El-Mahmoudy
|
||||||
Alex Chadwick
|
Alex Chadwick
|
||||||
Chris Randall
|
Chris Randall
|
||||||
|
Dan Petrisko
|
||||||
|
David Horton
|
||||||
David Stanford
|
David Stanford
|
||||||
Driss Hafdi
|
Driss Hafdi
|
||||||
Eric Rippey
|
Eric Rippey
|
||||||
Garrett Smith
|
Garrett Smith
|
||||||
Geza Lore
|
Geza Lore
|
||||||
Gianfranco Costamagna
|
Gianfranco Costamagna
|
||||||
|
Glen Gibb
|
||||||
Howard Su
|
Howard Su
|
||||||
|
Huang Rui
|
||||||
Iztok Jeras
|
Iztok Jeras
|
||||||
James Hanlon
|
James Hanlon
|
||||||
|
James Hutchinson
|
||||||
|
Jamey Hicks
|
||||||
|
Jan Van Winkel
|
||||||
Jeremy Bennett
|
Jeremy Bennett
|
||||||
John Coiner
|
John Coiner
|
||||||
John Demme
|
John Demme
|
||||||
@@ -22,11 +29,13 @@ Julien Margetts
|
|||||||
Kanad Kanhere
|
Kanad Kanhere
|
||||||
Kevin Kiningham
|
Kevin Kiningham
|
||||||
Kuba Ober
|
Kuba Ober
|
||||||
|
Ludwig Rogiers
|
||||||
Lukasz Dalek
|
Lukasz Dalek
|
||||||
Maarten De Braekeleer
|
Maarten De Braekeleer
|
||||||
Maciej Sobkowski
|
Maciej Sobkowski
|
||||||
Marco Widmer
|
Marco Widmer
|
||||||
Matthew Ballance
|
Matthew Ballance
|
||||||
|
Michael Killough
|
||||||
Mike Popoloski
|
Mike Popoloski
|
||||||
Nathan Kohagen
|
Nathan Kohagen
|
||||||
Nathan Myers
|
Nathan Myers
|
||||||
@@ -39,11 +48,19 @@ Qingyao Sun
|
|||||||
Richard Myers
|
Richard Myers
|
||||||
Sean Cross
|
Sean Cross
|
||||||
Sebastien Van Cauwenberghe
|
Sebastien Van Cauwenberghe
|
||||||
|
Sergi Granell
|
||||||
Stefan Wallentowitz
|
Stefan Wallentowitz
|
||||||
|
Stephen Henry
|
||||||
|
Tim Snyder
|
||||||
Tobias Rosenkranz
|
Tobias Rosenkranz
|
||||||
Tobias Wölfel
|
Tobias Wölfel
|
||||||
Todd Strader
|
Todd Strader
|
||||||
|
Tomasz Gorochowik
|
||||||
|
Tymoteusz Blazejczyk
|
||||||
|
Vassilis Papaefstathiou
|
||||||
Veripool API Bot
|
Veripool API Bot
|
||||||
Wilson Snyder
|
Wilson Snyder
|
||||||
|
Yossi Nivin
|
||||||
|
Yuri Victorovich
|
||||||
Yutetsu TAKATSUKASA
|
Yutetsu TAKATSUKASA
|
||||||
Yves Mathieu
|
Yves Mathieu
|
||||||
|
|||||||
+6
-9
@@ -80,8 +80,7 @@ MSVC++.
|
|||||||
|
|
||||||
To build or run Verilator you need these standard packages:
|
To build or run Verilator you need these standard packages:
|
||||||
|
|
||||||
sudo apt-get install perl python3
|
sudo apt-get install perl python3 make
|
||||||
sudo apt-get install make
|
|
||||||
sudo apt-get install g++ # Alternatively, clang
|
sudo apt-get install g++ # Alternatively, clang
|
||||||
sudo apt-get install libgz # Non-Ubuntu (ignore if gives error)
|
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)
|
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
|
To build Verilator you will need to install these packages; these do not
|
||||||
need to be present to run Verilator:
|
need to be present to run Verilator:
|
||||||
|
|
||||||
sudo apt-get install git
|
sudo apt-get install git autoconf flex bison
|
||||||
sudo apt-get install autoconf flex bison
|
|
||||||
|
|
||||||
Those developing Verilator itself may also want these (see internals.adoc):
|
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 Pod::Perldoc
|
||||||
cpan install Unix::Processors
|
cpan install Unix::Processors
|
||||||
cpan install Parallel::Forker
|
cpan install Parallel::Forker
|
||||||
@@ -266,10 +264,9 @@ set in your environment; it is built into the executable.
|
|||||||
|
|
||||||
== Announcements
|
== Announcements
|
||||||
|
|
||||||
To get notified of new releases, login to
|
To get notified of new releases, go to
|
||||||
https://www.veripool.org[Veripool], and click the "watch" button near the
|
https://github.com/verilator/verilator-announce[Verilator announcement
|
||||||
top right under https://www.veripool.org/projects/verilator/news[Verilator
|
repository] and follow the instructions there.
|
||||||
News].
|
|
||||||
|
|
||||||
== Directory Structure
|
== Directory Structure
|
||||||
|
|
||||||
|
|||||||
+29
-7
@@ -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
|
Tree files are dumps of the AST Tree and are produced between every major
|
||||||
algorithmic stage. An example:
|
algorithmic stage. An example:
|
||||||
|
|
||||||
NETLIST 0x90fb00 <e1> {a0}
|
NETLIST 0x90fb00 <e1> {a0ah}
|
||||||
1: MODULE 0x912b20 <e8822> {a8} top L2 [P]
|
1: MODULE 0x912b20 <e8822> {a8ah} top L2 [P]
|
||||||
*1:2: VAR 0x91a780 <e74#> {a22} @dt=0xa2e640(w32) out_wide [O] WIRE
|
*1:2: VAR 0x91a780 <e74#> {a22ah} @dt=0xa2e640(w32) out_wide [O] WIRE
|
||||||
1:2:1: BASICDTYPE 0xa2e640 <e2149> {e24} @dt=this(sw32) integer kwd=integer range=[31:0]
|
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
|
The following summarizes the above example dump, with more detail on each
|
||||||
field in the section below.
|
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
|
| `<e74>` | means the 74th edit to the netlist was the last modification to
|
||||||
this node.
|
this node.
|
||||||
|
|
||||||
| `{a22}` | indicates this node is related to line 22 in the source filename
|
| `{a22ah}` | indicates this node is related to the source filename "a",
|
||||||
"a", where "a" is the first file read, "z" the 26th, and "aa" the 27th.
|
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.
|
| `@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::
|
Address of the node::
|
||||||
|
|
||||||
A hexadecimal address of the node in memory. Useful for examining with the
|
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::
|
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
|
To get your pass to build you'll need to add its binary filename to the
|
||||||
list in `src/Makefile_obj.in` and reconfigure.
|
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
|
== Distribution
|
||||||
|
|
||||||
Copyright 2008-2020 by Wilson Snyder. Verilator is free software; you can
|
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
|
# This is an example cmake script to build a verilog to systemc project
|
||||||
# using cmake and verilator.
|
# using cmake and verilator.
|
||||||
#
|
#
|
||||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
# This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
# can redistribute it and/or modify it under the terms of either the GNU
|
# any use, without warranty, 2020 by Wilson Snyder.
|
||||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
# Version 2.0.
|
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,9 @@
|
|||||||
# This makefile is here for testing the examples and should
|
# This makefile is here for testing the examples and should
|
||||||
# generally not be added to a CMake project.
|
# generally not be added to a CMake project.
|
||||||
#
|
#
|
||||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
# This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
# can redistribute it and/or modify it under the terms of either the GNU
|
# any use, without warranty, 2020 by Wilson Snyder.
|
||||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
# Version 2.0.
|
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,9 @@
|
|||||||
# This is an example cmake script to build a verilog to SystemC project
|
# This is an example cmake script to build a verilog to SystemC project
|
||||||
# using CMake and Verilator.
|
# using CMake and Verilator.
|
||||||
#
|
#
|
||||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
# This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
# can redistribute it and/or modify it under the terms of either the GNU
|
# any use, without warranty, 2020 by Wilson Snyder.
|
||||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
# Version 2.0.
|
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,9 @@
|
|||||||
# This makefile is here for testing the examples and should
|
# This makefile is here for testing the examples and should
|
||||||
# generally not be added to a CMake project.
|
# generally not be added to a CMake project.
|
||||||
#
|
#
|
||||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
# This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
# can redistribute it and/or modify it under the terms of either the GNU
|
# any use, without warranty, 2020 by Wilson Snyder.
|
||||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
# Version 2.0.
|
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,9 @@
|
|||||||
# This is an example cmake script to build a verilog to systemc project
|
# This is an example cmake script to build a verilog to systemc project
|
||||||
# using cmake and verilator.
|
# using cmake and verilator.
|
||||||
#
|
#
|
||||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
# This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
# can redistribute it and/or modify it under the terms of either the GNU
|
# any use, without warranty, 2020 by Wilson Snyder.
|
||||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
# Version 2.0.
|
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,9 @@
|
|||||||
# This makefile is here for testing the examples and should
|
# This makefile is here for testing the examples and should
|
||||||
# generally not be added to a CMake project.
|
# generally not be added to a CMake project.
|
||||||
#
|
#
|
||||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
# This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
# can redistribute it and/or modify it under the terms of either the GNU
|
# any use, without warranty, 2020 by Wilson Snyder.
|
||||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
# Version 2.0.
|
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,9 @@
|
|||||||
# This is an example cmake script to build a verilog to systemc project
|
# This is an example cmake script to build a verilog to systemc project
|
||||||
# using cmake and verilator.
|
# using cmake and verilator.
|
||||||
#
|
#
|
||||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
# This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
# can redistribute it and/or modify it under the terms of either the GNU
|
# any use, without warranty, 2020 by Wilson Snyder.
|
||||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
# Version 2.0.
|
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,9 @@
|
|||||||
# This makefile is here for testing the examples and should
|
# This makefile is here for testing the examples and should
|
||||||
# generally not be added to a CMake project.
|
# generally not be added to a CMake project.
|
||||||
#
|
#
|
||||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
# This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
# can redistribute it and/or modify it under the terms of either the GNU
|
# any use, without warranty, 2020 by Wilson Snyder.
|
||||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
# Version 2.0.
|
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,9 @@
|
|||||||
# This is an example cmake script to build a verilog to SystemC project
|
# This is an example cmake script to build a verilog to SystemC project
|
||||||
# using CMake and Verilator.
|
# using CMake and Verilator.
|
||||||
#
|
#
|
||||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
# This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
# can redistribute it and/or modify it under the terms of either the GNU
|
# any use, without warranty, 2020 by Wilson Snyder.
|
||||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
# Version 2.0.
|
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,9 @@
|
|||||||
# This makefile is here for testing the examples and should
|
# This makefile is here for testing the examples and should
|
||||||
# generally not be added to a CMake project.
|
# generally not be added to a CMake project.
|
||||||
#
|
#
|
||||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
# This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
# can redistribute it and/or modify it under the terms of either the GNU
|
# any use, without warranty, 2020 by Wilson Snyder.
|
||||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
# Version 2.0.
|
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,9 @@
|
|||||||
# This calls the object directory makefile. That allows the objects to
|
# This calls the object directory makefile. That allows the objects to
|
||||||
# be placed in the "current directory" which simplifies the Makefile.
|
# be placed in the "current directory" which simplifies the Makefile.
|
||||||
#
|
#
|
||||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
# This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
# can redistribute it and/or modify it under the terms of either the GNU
|
# any use, without warranty, 2020 by Wilson Snyder.
|
||||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
# Version 2.0.
|
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
# Check for sanity to avoid later confusion
|
# Check for sanity to avoid later confusion
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ int main(int argc, char** argv, char** env) {
|
|||||||
// e.g. examples/c_tracing.
|
// e.g. examples/c_tracing.
|
||||||
|
|
||||||
// Prevent unused variable warnings
|
// 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"
|
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
|
||||||
Vtop* top = new Vtop;
|
Vtop* top = new Vtop;
|
||||||
|
|||||||
@@ -5,11 +5,9 @@
|
|||||||
# This calls the object directory makefile. That allows the objects to
|
# This calls the object directory makefile. That allows the objects to
|
||||||
# be placed in the "current directory" which simplifies the Makefile.
|
# be placed in the "current directory" which simplifies the Makefile.
|
||||||
#
|
#
|
||||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
# This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
# can redistribute it and/or modify it under the terms of either the GNU
|
# any use, without warranty, 2020 by Wilson Snyder.
|
||||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
# Version 2.0.
|
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
# Check for sanity to avoid later confusion
|
# Check for sanity to avoid later confusion
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ int sc_main(int argc, char* argv[]) {
|
|||||||
// e.g. examples/c_tracing.
|
// e.g. examples/c_tracing.
|
||||||
|
|
||||||
// Prevent unused variable warnings
|
// Prevent unused variable warnings
|
||||||
if (0 && argc && argv) {}
|
if (false && argc && argv) {}
|
||||||
|
|
||||||
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
|
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
|
||||||
Vtop* top = new Vtop("top");
|
Vtop* top = new Vtop("top");
|
||||||
|
|||||||
@@ -5,11 +5,9 @@
|
|||||||
# This calls the object directory makefiles. That allows the objects to
|
# This calls the object directory makefiles. That allows the objects to
|
||||||
# be placed in the "current directory" which simplifies the Makefile.
|
# be placed in the "current directory" which simplifies the Makefile.
|
||||||
#
|
#
|
||||||
# Copyright 2019 by Wilson Snyder. This program is free software; you
|
# This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
# can redistribute it and/or modify it under the terms of either the GNU
|
# any use, without warranty, 2020 by Wilson Snyder.
|
||||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
# Version 2.0.
|
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
# Check for sanity to avoid later confusion
|
# Check for sanity to avoid later confusion
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ vluint64_t main_time = 0;
|
|||||||
double sc_time_stamp() { return main_time; }
|
double sc_time_stamp() { return main_time; }
|
||||||
|
|
||||||
int main(int argc, char** argv, char** env) {
|
int main(int argc, char** argv, char** env) {
|
||||||
if (0 && argc && argv && env) {}
|
if (false && argc && argv && env) {}
|
||||||
|
|
||||||
Verilated::debug(0);
|
Verilated::debug(0);
|
||||||
Verilated::randReset(2);
|
Verilated::randReset(2);
|
||||||
|
|||||||
@@ -5,11 +5,9 @@
|
|||||||
# This calls the object directory makefile. That allows the objects to
|
# This calls the object directory makefile. That allows the objects to
|
||||||
# be placed in the "current directory" which simplifies the Makefile.
|
# be placed in the "current directory" which simplifies the Makefile.
|
||||||
#
|
#
|
||||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
# This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
# can redistribute it and/or modify it under the terms of either the GNU
|
# any use, without warranty, 2020 by Wilson Snyder.
|
||||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
# Version 2.0.
|
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
# Check for sanity to avoid later confusion
|
# Check for sanity to avoid later confusion
|
||||||
|
|||||||
@@ -5,11 +5,9 @@
|
|||||||
#
|
#
|
||||||
# This is executed in the object directory, and called by ../Makefile
|
# This is executed in the object directory, and called by ../Makefile
|
||||||
#
|
#
|
||||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
# This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
# can redistribute it and/or modify it under the terms of either the GNU
|
# any use, without warranty, 2020 by Wilson Snyder.
|
||||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
# Version 2.0.
|
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.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.
|
// This is a more complicated example, please also see the simpler examples/make_hello_c.
|
||||||
|
|
||||||
// Prevent unused variable warnings
|
// 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
|
// Set debug level, 0 is off, 9 is highest presently used
|
||||||
// May be overridden by commandArgs
|
// May be overridden by commandArgs
|
||||||
|
|||||||
@@ -5,11 +5,9 @@
|
|||||||
# This calls the object directory makefile. That allows the objects to
|
# This calls the object directory makefile. That allows the objects to
|
||||||
# be placed in the "current directory" which simplifies the Makefile.
|
# be placed in the "current directory" which simplifies the Makefile.
|
||||||
#
|
#
|
||||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
# This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
# can redistribute it and/or modify it under the terms of either the GNU
|
# any use, without warranty, 2020 by Wilson Snyder.
|
||||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
# Version 2.0.
|
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
# Check for sanity to avoid later confusion
|
# Check for sanity to avoid later confusion
|
||||||
|
|||||||
@@ -5,11 +5,9 @@
|
|||||||
#
|
#
|
||||||
# This is executed in the object directory, and called by ../Makefile
|
# This is executed in the object directory, and called by ../Makefile
|
||||||
#
|
#
|
||||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
# This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
# can redistribute it and/or modify it under the terms of either the GNU
|
# any use, without warranty, 2020 by Wilson Snyder.
|
||||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
# Version 2.0.
|
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
||||||
#
|
#
|
||||||
#######################################################################
|
#######################################################################
|
||||||
|
|
||||||
@@ -39,8 +37,8 @@ endif
|
|||||||
# If you build your own rules from scratch, note you need to include
|
# If you build your own rules from scratch, note you need to include
|
||||||
# SystemC as follows (Vtop.mk file includes verilated.mk with these
|
# SystemC as follows (Vtop.mk file includes verilated.mk with these
|
||||||
# already).
|
# already).
|
||||||
# CPPFLAGS += $(SYSTEMC_CXX_FLAGS) -I$(SYSTEMC_INCLUDE)
|
# CPPFLAGS += $(SYSTEMC_CXX_FLAGS) $(addprefix -I, $(SYSTEMC_INCLUDE))
|
||||||
# LDFLAGS += $(SYSTEMC_CXX_FLAGS) -L$(SYSTEMC_LIBDIR)
|
# LDFLAGS += $(SYSTEMC_CXX_FLAGS) $(addprefix -L, $(SYSTEMC_LIBDIR))
|
||||||
|
|
||||||
# See the benchmarking section of bin/verilator.
|
# See the benchmarking section of bin/verilator.
|
||||||
# Support class optimizations. This includes the tracing and symbol table.
|
# 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.
|
// This is a more complicated example, please also see the simpler examples/make_hello_c.
|
||||||
|
|
||||||
// Prevent unused variable warnings
|
// Prevent unused variable warnings
|
||||||
if (0 && argc && argv) {}
|
if (false && argc && argv) {}
|
||||||
|
|
||||||
// Set debug level, 0 is off, 9 is highest presently used
|
// Set debug level, 0 is off, 9 is highest presently used
|
||||||
// May be overridden by commandArgs
|
// May be overridden by commandArgs
|
||||||
|
|||||||
@@ -2,11 +2,9 @@
|
|||||||
#
|
#
|
||||||
# DESCRIPTION: Verilator Example: XML tests
|
# DESCRIPTION: Verilator Example: XML tests
|
||||||
#
|
#
|
||||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
# This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
# can redistribute it and/or modify it under the terms of either the GNU
|
# any use, without warranty, 2020 by Wilson Snyder.
|
||||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
# Version 2.0.
|
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
|
|||||||
+221
-176
@@ -29,7 +29,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <tgmath.h>
|
#include <sstream>
|
||||||
#include <sys/stat.h> // mkdir
|
#include <sys/stat.h> // mkdir
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
@@ -77,7 +77,7 @@ VerilatedImp VerilatedImp::s_s;
|
|||||||
|
|
||||||
#ifndef VL_USER_FINISH ///< Define this to override this function
|
#ifndef VL_USER_FINISH ///< Define this to override this function
|
||||||
void vl_finish(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE {
|
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
|
VL_PRINTF( // Not VL_PRINTF_MT, already on main thread
|
||||||
"- %s:%d: Verilog $finish\n", filename, linenum);
|
"- %s:%d: Verilog $finish\n", filename, linenum);
|
||||||
if (Verilated::gotFinish()) {
|
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
|
#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 {
|
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);
|
Verilated::gotFinish(true);
|
||||||
if (filename && filename[0]) {
|
if (filename && filename[0]) {
|
||||||
// Not VL_PRINTF_MT, already on main thread
|
// 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
|
// 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
|
// from within the guts of the thread execution machinery (and it goes
|
||||||
// to the screen and not into the queues we're debugging)
|
// 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
|
#ifdef VL_THREADED
|
||||||
@@ -243,8 +243,8 @@ Verilated::Serialized::Serialized() {
|
|||||||
s_errorLimit = 1;
|
s_errorLimit = 1;
|
||||||
s_randReset = 0;
|
s_randReset = 0;
|
||||||
s_randSeed = 0;
|
s_randSeed = 0;
|
||||||
s_timeunit = -VL_TIME_UNIT; // 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
|
s_timeprecision = VL_TIME_PRECISION; // Initial value until overriden by _Vconfigure
|
||||||
}
|
}
|
||||||
|
|
||||||
Verilated::NonSerialized::NonSerialized() {
|
Verilated::NonSerialized::NonSerialized() {
|
||||||
@@ -283,7 +283,7 @@ vluint64_t vl_rand64() VL_MT_SAFE {
|
|||||||
if (VL_UNLIKELY(!t_seeded)) {
|
if (VL_UNLIKELY(!t_seeded)) {
|
||||||
t_seeded = true;
|
t_seeded = true;
|
||||||
{
|
{
|
||||||
VerilatedLockGuard lock(s_mutex);
|
const VerilatedLockGuard lock(s_mutex);
|
||||||
if (Verilated::randSeed() != 0) {
|
if (Verilated::randSeed() != 0) {
|
||||||
t_state[0] = ((static_cast<vluint64_t>(Verilated::randSeed()) << 32)
|
t_state[0] = ((static_cast<vluint64_t>(Verilated::randSeed()) << 32)
|
||||||
^ (static_cast<vluint64_t>(Verilated::randSeed())));
|
^ (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); }
|
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); }
|
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 {
|
WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||||
for (int i = 0; i < VL_WORDS_I(obits); ++i) {
|
for (int i = 0; i < VL_WORDS_I(obits); ++i) {
|
||||||
if (i < (VL_WORDS_I(obits) - 1)) {
|
if (i < (VL_WORDS_I(obits) - 1)) {
|
||||||
@@ -322,6 +323,7 @@ WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE {
|
|||||||
}
|
}
|
||||||
return outwp;
|
return outwp;
|
||||||
}
|
}
|
||||||
|
// LCOV_EXCL_STOP
|
||||||
|
|
||||||
IData VL_RAND_RESET_I(int obits) VL_MT_SAFE {
|
IData VL_RAND_RESET_I(int obits) VL_MT_SAFE {
|
||||||
if (Verilated::randReset() == 0) return 0;
|
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 {
|
QData VL_RAND_RESET_Q(int obits) VL_MT_SAFE {
|
||||||
if (Verilated::randReset() == 0) return 0;
|
if (Verilated::randReset() == 0) return 0;
|
||||||
QData data = VL_ULL(~0);
|
QData data = ~0ULL;
|
||||||
if (Verilated::randReset() != 1) { // if 2, randomize
|
if (Verilated::randReset() != 1) { // if 2, randomize
|
||||||
data = VL_RANDOM_Q(obits);
|
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
|
if (vw == 1) { // Single divisor word breaks rest of algorithm
|
||||||
vluint64_t k = 0;
|
vluint64_t k = 0;
|
||||||
for (int j = uw - 1; j >= 0; --j) {
|
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]);
|
owp[j] = unw64 / static_cast<vluint64_t>(rwp[0]);
|
||||||
k = unw64 - static_cast<vluint64_t>(owp[j]) * 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
|
// Main loop
|
||||||
for (int j = uw - vw; j >= 0; --j) {
|
for (int j = uw - vw; j >= 0; --j) {
|
||||||
// Estimate
|
// 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]));
|
| static_cast<vluint64_t>(un[j + vw - 1]));
|
||||||
vluint64_t qhat = unw64 / static_cast<vluint64_t>(vn[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]);
|
vluint64_t rhat = unw64 - qhat * static_cast<vluint64_t>(vn[vw - 1]);
|
||||||
|
|
||||||
again:
|
again:
|
||||||
if (qhat >= VL_ULL(0x100000000)
|
if (qhat >= 0x100000000ULL || ((qhat * vn[vw - 2]) > ((rhat << 32ULL) + un[j + vw - 2]))) {
|
||||||
|| ((qhat * vn[vw - 2]) > ((rhat << VL_ULL(32)) + un[j + vw - 2]))) {
|
|
||||||
qhat = qhat - 1;
|
qhat = qhat - 1;
|
||||||
rhat = rhat + vn[vw - 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
|
vlsint64_t t = 0; // Must be signed
|
||||||
vluint64_t k = 0;
|
vluint64_t k = 0;
|
||||||
for (int i = 0; i < vw; ++i) {
|
for (int i = 0; i < vw; ++i) {
|
||||||
vluint64_t p = qhat * vn[i]; // Multiply by estimate
|
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;
|
un[i + j] = t;
|
||||||
k = (p >> VL_ULL(32)) - (t >> VL_ULL(32));
|
k = (p >> 32ULL) - (t >> 32ULL);
|
||||||
}
|
}
|
||||||
t = un[j + vw] - k;
|
t = un[j + vw] - k;
|
||||||
un[j + vw] = t;
|
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) {
|
for (int i = 0; i < vw; ++i) {
|
||||||
t = static_cast<vluint64_t>(un[i + j]) + static_cast<vluint64_t>(vn[i]) + k;
|
t = static_cast<vluint64_t>(un[i + j]) + static_cast<vluint64_t>(vn[i]) + k;
|
||||||
un[i + j] = t;
|
un[i + j] = t;
|
||||||
k = t >> VL_ULL(32);
|
k = t >> 32ULL;
|
||||||
}
|
}
|
||||||
un[j + vw] = un[j + vw] + k;
|
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
|
// Skip check for rhs == 0, as short-circuit doesn't save time
|
||||||
if (VL_UNLIKELY(lhs == 0)) return 0;
|
if (VL_UNLIKELY(lhs == 0)) return 0;
|
||||||
QData power = lhs;
|
QData power = lhs;
|
||||||
QData out = VL_ULL(1);
|
QData out = 1ULL;
|
||||||
for (int bit = 0; bit < rbits; ++bit) {
|
for (int bit = 0; bit < rbits; ++bit) {
|
||||||
if (bit > 0) power = power * power;
|
if (bit > 0) power = power * power;
|
||||||
if (VL_BITISSET_W(rwp, bit)) out *= 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 fracDiv = static_cast<QData>(vl_time_multiplier(fracDigits));
|
||||||
QData whole = static_cast<QData>(scaled) / fracDiv;
|
QData whole = static_cast<QData>(scaled) / fracDiv;
|
||||||
QData fraction = static_cast<QData>(scaled) % fracDiv;
|
QData fraction = static_cast<QData>(scaled) % fracDiv;
|
||||||
int digits;
|
int digits = 0;
|
||||||
if (!fracDigits) {
|
if (!fracDigits) {
|
||||||
digits = sprintf(tmp, "%" VL_PRI64 "u%s", whole, suffix.c_str());
|
digits = sprintf(tmp, "%" VL_PRI64 "u%s", whole, suffix.c_str());
|
||||||
} else {
|
} else {
|
||||||
@@ -678,7 +679,16 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
|||||||
inPct = false;
|
inPct = false;
|
||||||
char fmt = pos[0];
|
char fmt = pos[0];
|
||||||
switch (fmt) {
|
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
|
inPct = true; // Get more digits
|
||||||
widthSet = true;
|
widthSet = true;
|
||||||
width = width * 10 + (fmt - '0');
|
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);
|
const int lbits = va_arg(ap, int);
|
||||||
double d = va_arg(ap, double);
|
double d = va_arg(ap, double);
|
||||||
if (lbits) {} // UNUSED - always 64
|
if (lbits) {} // UNUSED - always 64
|
||||||
switch (fmt) {
|
if (fmt == '^') { // Realtime
|
||||||
case '^': { // Realtime
|
|
||||||
if (!widthSet) width = VerilatedImp::timeFormatWidth();
|
if (!widthSet) width = VerilatedImp::timeFormatWidth();
|
||||||
output += _vl_vsformat_time(tmp, d, left, width);
|
output += _vl_vsformat_time(tmp, d, left, width);
|
||||||
break;
|
} else {
|
||||||
}
|
|
||||||
default: {
|
|
||||||
std::string fmt(pctp, pos - pctp + 1);
|
std::string fmt(pctp, pos - pctp + 1);
|
||||||
sprintf(tmp, fmt.c_str(), d);
|
sprintf(tmp, fmt.c_str(), d);
|
||||||
output += tmp;
|
output += tmp;
|
||||||
break;
|
}
|
||||||
} //
|
|
||||||
break;
|
|
||||||
} // switch
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
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);
|
const int lbits = va_arg(ap, int);
|
||||||
QData ld = 0;
|
QData ld = 0;
|
||||||
WData qlwp[VL_WQ_WORDS_E];
|
WData qlwp[VL_WQ_WORDS_E];
|
||||||
WDataInP lwp;
|
WDataInP lwp = NULL;
|
||||||
if (lbits <= VL_QUADSIZE) {
|
if (lbits <= VL_QUADSIZE) {
|
||||||
ld = _VL_VA_ARG_Q(ap, lbits);
|
ld = _VL_VA_ARG_Q(ap, lbits);
|
||||||
VL_SET_WQ(qlwp, ld);
|
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) {
|
switch (fmt) {
|
||||||
case 'c': {
|
case 'c': {
|
||||||
IData charval = ld & 0xff;
|
IData charval = ld & 0xff;
|
||||||
output += charval;
|
output += static_cast<char>(charval);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 's': {
|
case 's': {
|
||||||
@@ -774,7 +778,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'd': { // Signed decimal
|
case 'd': { // Signed decimal
|
||||||
int digits;
|
int digits = 0;
|
||||||
std::string append;
|
std::string append;
|
||||||
if (lbits <= VL_QUADSIZE) {
|
if (lbits <= VL_QUADSIZE) {
|
||||||
digits = sprintf(tmp, "%" VL_PRI64 "d",
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case '#': { // Unsigned decimal
|
case '#': { // Unsigned decimal
|
||||||
int digits;
|
int digits = 0;
|
||||||
std::string append;
|
std::string append;
|
||||||
if (lbits <= VL_QUADSIZE) {
|
if (lbits <= VL_QUADSIZE) {
|
||||||
digits = sprintf(tmp, "%" VL_PRI64 "u", ld);
|
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,
|
// Octal numbers may span more than one wide word,
|
||||||
// so we need to grab each bit separately and check for overrun
|
// so we need to grab each bit separately and check for overrun
|
||||||
// Octal is rare, so we'll do it a slow simple way
|
// Octal is rare, so we'll do it a slow simple way
|
||||||
output += ('0' + ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 0)) ? 1 : 0)
|
output += static_cast<char>(
|
||||||
+ ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 1)) ? 2 : 0)
|
'0' + ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 0)) ? 1 : 0)
|
||||||
+ ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 2)) ? 4 : 0));
|
+ ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 1)) ? 2 : 0)
|
||||||
|
+ ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 2)) ? 4 : 0));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'u': // Packed 2-state
|
case 'u':
|
||||||
output.reserve(output.size() + 4 * VL_WORDS_I(lbits));
|
case 'z': { // Packed 4-state
|
||||||
for (int i = 0; i < VL_WORDS_I(lbits); ++i) {
|
const bool is_4_state = (fmt == 'z');
|
||||||
output += static_cast<char>((lwp[i]) & 0xff);
|
output.reserve(output.size() + ((is_4_state ? 2 : 1) * VL_WORDS_I(lbits)));
|
||||||
output += static_cast<char>((lwp[i] >> 8) & 0xff);
|
int bytes_to_go = VL_BYTES_I(lbits);
|
||||||
output += static_cast<char>((lwp[i] >> 16) & 0xff);
|
int bit = 0;
|
||||||
output += static_cast<char>((lwp[i] >> 24) & 0xff);
|
while (bytes_to_go > 0) {
|
||||||
}
|
const int wr_bytes = std::min(4, bytes_to_go);
|
||||||
break;
|
for (int byte = 0; byte < wr_bytes; byte++, bit += 8)
|
||||||
case 'z': // Packed 4-state
|
output += static_cast<char>(VL_BITRSHIFT_W(lwp, bit) & 0xff);
|
||||||
output.reserve(output.size() + 8 * VL_WORDS_I(lbits));
|
output.append(4 - wr_bytes, static_cast<char>(0));
|
||||||
for (int i = 0; i < VL_WORDS_I(lbits); ++i) {
|
if (is_4_state) output.append(4, static_cast<char>(0));
|
||||||
output += static_cast<char>((lwp[i]) & 0xff);
|
bytes_to_go -= wr_bytes;
|
||||||
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
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 'v': // Strength; assume always strong
|
case 'v': // Strength; assume always strong
|
||||||
for (lsb = lbits - 1; lsb >= 0; --lsb) {
|
for (lsb = lbits - 1; lsb >= 0; --lsb) {
|
||||||
if (VL_BITRSHIFT_W(lwp, lsb) & 1) {
|
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 {
|
static inline bool _vl_vsss_eof(FILE* fp, int floc) VL_MT_SAFE {
|
||||||
if (fp) {
|
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 {
|
} else {
|
||||||
return floc < 0;
|
return floc < 0;
|
||||||
}
|
}
|
||||||
@@ -929,8 +931,8 @@ static inline void _vl_vsss_skipspace(FILE* fp, int& floc, WDataInP fromp,
|
|||||||
_vl_vsss_advance(fp, floc);
|
_vl_vsss_advance(fp, floc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static inline void _vl_vsss_read(FILE* fp, int& floc, WDataInP fromp, const std::string& fstr,
|
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 {
|
char* tmpp, const char* acceptp) VL_MT_SAFE {
|
||||||
// Read into tmp, consisting of characters from acceptp list
|
// Read into tmp, consisting of characters from acceptp list
|
||||||
char* cp = tmpp;
|
char* cp = tmpp;
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -944,6 +946,19 @@ static inline void _vl_vsss_read(FILE* fp, int& floc, WDataInP fromp, const std:
|
|||||||
*cp++ = '\0';
|
*cp++ = '\0';
|
||||||
// VL_DBG_MSGF(" _read got='"<<tmpp<<"'\n");
|
// 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,
|
static inline void _vl_vsss_setbit(WDataOutP owp, int obits, int lsb, int nbits,
|
||||||
IData ld) VL_MT_SAFE {
|
IData ld) VL_MT_SAFE {
|
||||||
for (; nbits && lsb < obits; nbits--, lsb++, ld >>= 1) {
|
for (; nbits && lsb < obits; nbits--, lsb++, ld >>= 1) {
|
||||||
@@ -992,12 +1007,14 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
|||||||
int floc = fbits - 1;
|
int floc = fbits - 1;
|
||||||
IData got = 0;
|
IData got = 0;
|
||||||
bool inPct = false;
|
bool inPct = false;
|
||||||
|
bool inIgnore = false;
|
||||||
const char* pos = formatp;
|
const char* pos = formatp;
|
||||||
for (; *pos && !_vl_vsss_eof(fp, floc); ++pos) {
|
for (; *pos && !_vl_vsss_eof(fp, floc); ++pos) {
|
||||||
// VL_DBG_MSGF("_vlscan fmt='"<<pos[0]<<"' floc="<<floc<<" file='"<<_vl_vsss_peek(fp, floc,
|
// VL_DBG_MSGF("_vlscan fmt='"<<pos[0]<<"' floc="<<floc<<" file='"<<_vl_vsss_peek(fp, floc,
|
||||||
// fromp, fstr)<<"'"<<endl);
|
// fromp, fstr)<<"'"<<endl);
|
||||||
if (!inPct && pos[0] == '%') {
|
if (!inPct && pos[0] == '%') {
|
||||||
inPct = true;
|
inPct = true;
|
||||||
|
inIgnore = false;
|
||||||
} else if (!inPct && isspace(pos[0])) { // Format spaces
|
} else if (!inPct && isspace(pos[0])) { // Format spaces
|
||||||
while (isspace(pos[1])) pos++;
|
while (isspace(pos[1])) pos++;
|
||||||
_vl_vsss_skipspace(fp, floc, fromp, fstr);
|
_vl_vsss_skipspace(fp, floc, fromp, fstr);
|
||||||
@@ -1017,12 +1034,16 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
|||||||
_vl_vsss_advance(fp, floc);
|
_vl_vsss_advance(fp, floc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case '*':
|
||||||
|
inPct = true;
|
||||||
|
inIgnore = true;
|
||||||
|
break;
|
||||||
default: {
|
default: {
|
||||||
// Deal with all read-and-scan somethings
|
// Deal with all read-and-scan somethings
|
||||||
// Note LSBs are preserved if there's an overflow
|
// 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];
|
WData qowp[VL_WQ_WORDS_E];
|
||||||
VL_SET_WQ(qowp, VL_ULL(0));
|
VL_SET_WQ(qowp, 0ULL);
|
||||||
WDataOutP owp = qowp;
|
WDataOutP owp = qowp;
|
||||||
if (obits > VL_QUADSIZE) owp = va_arg(ap, WDataOutP);
|
if (obits > VL_QUADSIZE) owp = va_arg(ap, WDataOutP);
|
||||||
for (int i = 0; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
|
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': {
|
case 's': {
|
||||||
_vl_vsss_skipspace(fp, floc, fromp, fstr);
|
_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;
|
if (!tmp[0]) goto done;
|
||||||
int lpos = (static_cast<int>(strlen(tmp))) - 1;
|
int lpos = (static_cast<int>(strlen(tmp))) - 1;
|
||||||
int lsb = 0;
|
int lsb = 0;
|
||||||
@@ -1048,9 +1069,9 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
|||||||
}
|
}
|
||||||
case 'd': { // Signed decimal
|
case 'd': { // Signed decimal
|
||||||
_vl_vsss_skipspace(fp, floc, fromp, fstr);
|
_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;
|
if (!tmp[0]) goto done;
|
||||||
vlsint64_t ld;
|
vlsint64_t ld = 0;
|
||||||
sscanf(tmp, "%30" VL_PRI64 "d", &ld);
|
sscanf(tmp, "%30" VL_PRI64 "d", &ld);
|
||||||
VL_SET_WQ(owp, ld);
|
VL_SET_WQ(owp, ld);
|
||||||
break;
|
break;
|
||||||
@@ -1059,7 +1080,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
|||||||
case 'e':
|
case 'e':
|
||||||
case 'g': { // Real number
|
case 'g': { // Real number
|
||||||
_vl_vsss_skipspace(fp, floc, fromp, fstr);
|
_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;
|
if (!tmp[0]) goto done;
|
||||||
// cppcheck-suppress unusedStructMember // It's used
|
// cppcheck-suppress unusedStructMember // It's used
|
||||||
union {
|
union {
|
||||||
@@ -1073,43 +1094,71 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
|||||||
case 't': // FALLTHRU // Time
|
case 't': // FALLTHRU // Time
|
||||||
case '#': { // Unsigned decimal
|
case '#': { // Unsigned decimal
|
||||||
_vl_vsss_skipspace(fp, floc, fromp, fstr);
|
_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;
|
if (!tmp[0]) goto done;
|
||||||
QData ld;
|
QData ld = 0;
|
||||||
sscanf(tmp, "%30" VL_PRI64 "u", &ld);
|
sscanf(tmp, "%30" VL_PRI64 "u", &ld);
|
||||||
VL_SET_WQ(owp, ld);
|
VL_SET_WQ(owp, ld);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'b': {
|
case 'b': {
|
||||||
_vl_vsss_skipspace(fp, floc, fromp, fstr);
|
_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;
|
if (!tmp[0]) goto done;
|
||||||
_vl_vsss_based(owp, obits, 1, tmp, 0, strlen(tmp));
|
_vl_vsss_based(owp, obits, 1, tmp, 0, strlen(tmp));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'o': {
|
case 'o': {
|
||||||
_vl_vsss_skipspace(fp, floc, fromp, fstr);
|
_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;
|
if (!tmp[0]) goto done;
|
||||||
_vl_vsss_based(owp, obits, 3, tmp, 0, strlen(tmp));
|
_vl_vsss_based(owp, obits, 3, tmp, 0, strlen(tmp));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'x': {
|
case 'x': {
|
||||||
_vl_vsss_skipspace(fp, floc, fromp, fstr);
|
_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;
|
if (!tmp[0]) goto done;
|
||||||
_vl_vsss_based(owp, obits, 4, tmp, 0, strlen(tmp));
|
_vl_vsss_based(owp, obits, 4, tmp, 0, strlen(tmp));
|
||||||
break;
|
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:
|
default:
|
||||||
std::string msg = std::string("Unknown _vl_vsscanf code: ") + pos[0];
|
std::string msg = std::string("Unknown _vl_vsscanf code: ") + pos[0];
|
||||||
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
|
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
|
||||||
break;
|
break;
|
||||||
} // switch
|
} // switch
|
||||||
|
|
||||||
got++;
|
if (!inIgnore) ++got;
|
||||||
// Reload data if non-wide (if wide, we put it in the right place directly)
|
// 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*);
|
CData* p = va_arg(ap, CData*);
|
||||||
*p = owp[0];
|
*p = owp[0];
|
||||||
} else if (obits <= VL_SHORTSIZE) {
|
} else if (obits <= VL_SHORTSIZE) {
|
||||||
@@ -1133,7 +1182,10 @@ done:
|
|||||||
//===========================================================================
|
//===========================================================================
|
||||||
// File I/O
|
// 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 {
|
void _VL_VINT_TO_STRING(int obits, char* destoutp, WDataInP sourcep) VL_MT_SAFE {
|
||||||
// See also VL_DATA_TO_STRING_NW
|
// 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);
|
size_t bytes = VL_BYTES_I(obits);
|
||||||
char* op = reinterpret_cast<char*>(destp);
|
char* op = reinterpret_cast<char*>(destp);
|
||||||
if (srclen > bytes) srclen = bytes; // Don't overflow destination
|
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 = 0; i < srclen; ++i) { *op++ = srcp[srclen - 1 - i]; }
|
||||||
for (; i < bytes; ++i) { *op++ = 0; }
|
for (; i < bytes; ++i) { *op++ = 0; }
|
||||||
}
|
}
|
||||||
@@ -1201,38 +1253,21 @@ IData VL_FERROR_IN(IData, std::string& outputr) VL_MT_SAFE {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
IData VL_FOPEN_NI(const std::string& filename, IData mode) VL_MT_SAFE {
|
IData VL_FOPEN_NN(const std::string& filename, const std::string& mode) {
|
||||||
// While threadsafe, each thread can only access different file handles
|
return VerilatedImp::fdNew(filename.c_str(), mode.c_str());
|
||||||
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_QI(QData filename, IData mode) VL_MT_SAFE {
|
IData VL_FOPEN_MCD_N(const std::string& filename) VL_MT_SAFE {
|
||||||
// While threadsafe, each thread can only access different file handles
|
return VerilatedImp::fdNewMcd(filename.c_str());
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
void VL_FCLOSE_I(IData fdi) VL_MT_SAFE {
|
||||||
// While threadsafe, each thread can only access different file handles
|
// While threadsafe, each thread can only access different file handles
|
||||||
FILE* fp = VL_CVT_I_FP(fdi);
|
VerilatedImp::fdClose(fdi);
|
||||||
if (VL_UNLIKELY(!fp)) return;
|
|
||||||
fclose(fp);
|
|
||||||
VerilatedImp::fdDelete(fdi);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VL_FFLUSH_ALL() VL_MT_SAFE { fflush(stdout); }
|
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
|
// While threadsafe, each thread can only access different file handles
|
||||||
static VL_THREAD_LOCAL std::string output; // static only for speed
|
static VL_THREAD_LOCAL std::string output; // static only for speed
|
||||||
output = "";
|
output = "";
|
||||||
FILE* fp = VL_CVT_I_FP(fpi);
|
|
||||||
if (VL_UNLIKELY(!fp)) return;
|
|
||||||
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, formatp);
|
va_start(ap, formatp);
|
||||||
_vl_vsformat(output, formatp, ap);
|
_vl_vsformat(output, formatp, ap);
|
||||||
va_end(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 {
|
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);
|
VL_ZERO_RESET_W(rbits, rwp);
|
||||||
switch (tolower(fmt)) {
|
switch (tolower(fmt)) {
|
||||||
case 'd':
|
case 'd': {
|
||||||
vlsint64_t lld;
|
vlsint64_t lld = 0;
|
||||||
sscanf(dp, "%30" VL_PRI64 "d", &lld);
|
sscanf(dp, "%30" VL_PRI64 "d", &lld);
|
||||||
VL_SET_WQ(rwp, lld);
|
VL_SET_WQ(rwp, lld);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 'b': _vl_vsss_based(rwp, rbits, 1, dp, 0, strlen(dp)); 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 'o': _vl_vsss_based(rwp, rbits, 3, dp, 0, strlen(dp)); break;
|
||||||
case 'h': // FALLTHRU
|
case 'h': // FALLTHRU
|
||||||
case 'x': _vl_vsss_based(rwp, rbits, 4, dp, 0, strlen(dp)); break;
|
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;
|
for (int i = 0, lsb = 0, posp = static_cast<int>(strlen(dp)) - 1; i < rbits && posp >= 0;
|
||||||
--posp) {
|
--posp) {
|
||||||
_vl_vsss_setbit(rwp, rbits, lsb, 8, dp[posp]);
|
_vl_vsss_setbit(rwp, rbits, lsb, 8, dp[posp]);
|
||||||
lsb += 8;
|
lsb += 8;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 'e': {
|
case 'e': {
|
||||||
double temp = 0.f;
|
double temp = 0.F;
|
||||||
sscanf(dp, "%le", &temp);
|
sscanf(dp, "%le", &temp);
|
||||||
VL_SET_WQ(rwp, VL_CVT_Q_D(temp));
|
VL_SET_WQ(rwp, VL_CVT_Q_D(temp));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'f': {
|
case 'f': {
|
||||||
double temp = 0.f;
|
double temp = 0.F;
|
||||||
sscanf(dp, "%lf", &temp);
|
sscanf(dp, "%lf", &temp);
|
||||||
VL_SET_WQ(rwp, VL_CVT_Q_D(temp));
|
VL_SET_WQ(rwp, VL_CVT_Q_D(temp));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'g': {
|
case 'g': {
|
||||||
double temp = 0.f;
|
double temp = 0.F;
|
||||||
sscanf(dp, "%lg", &temp);
|
sscanf(dp, "%lg", &temp);
|
||||||
VL_SET_WQ(rwp, VL_CVT_Q_D(temp));
|
VL_SET_WQ(rwp, VL_CVT_Q_D(temp));
|
||||||
break;
|
break;
|
||||||
@@ -1761,7 +1796,7 @@ bool VlReadMem::get(QData& addrr, std::string& valuer) {
|
|||||||
m_addr = (m_addr << 4) + value;
|
m_addr = (m_addr << 4) + value;
|
||||||
} else {
|
} else {
|
||||||
indata = true;
|
indata = true;
|
||||||
valuer += c;
|
valuer += static_cast<char>(c);
|
||||||
// printf(" Value width=%d @%x = %c\n", width, m_addr, c);
|
// printf(" Value width=%d @%x = %c\n", width, m_addr, c);
|
||||||
if (VL_UNLIKELY(value > 1 && !m_hex)) {
|
if (VL_UNLIKELY(value > 1 && !m_hex)) {
|
||||||
VL_FATAL_MT(m_filename.c_str(), m_linenum, "",
|
VL_FATAL_MT(m_filename.c_str(), m_linenum, "",
|
||||||
@@ -1775,7 +1810,7 @@ bool VlReadMem::get(QData& addrr, std::string& valuer) {
|
|||||||
lastc = c;
|
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, "",
|
VL_FATAL_MT(m_filename.c_str(), m_linenum, "",
|
||||||
"$readmem file ended before specified final address (IEEE 2017 21.4)");
|
"$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
|
return false; // EOF
|
||||||
}
|
}
|
||||||
void VlReadMem::setData(void* valuep, const std::string& rhs) {
|
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;
|
bool innum = false;
|
||||||
// Shift value in
|
// Shift value in
|
||||||
for (std::string::const_iterator it = rhs.begin(); it != rhs.end(); ++it) {
|
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);
|
VlReadMem rmem(hex, bits, filename, start, end);
|
||||||
if (VL_UNLIKELY(!rmem.isOpen())) return;
|
if (VL_UNLIKELY(!rmem.isOpen())) return;
|
||||||
while (true) {
|
while (true) {
|
||||||
QData addr;
|
QData addr = 0;
|
||||||
std::string value;
|
std::string value;
|
||||||
if (rmem.get(addr /*ref*/, value /*ref*/)) {
|
if (rmem.get(addr /*ref*/, value /*ref*/)) {
|
||||||
if (VL_UNLIKELY(addr < static_cast<QData>(array_lsb)
|
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* vl_time_str(int scale) {
|
||||||
static const char* const names[]
|
static const char* const names[]
|
||||||
= {"1s", "100ms", "10ms", "1ms", "100us", "10us", "1us", "100ns",
|
= {"100s", "10s", "1s", "100ms", "10ms", "1ms", "100us", "10us", "1us",
|
||||||
"10ns", "1ns", "100ps", "10ps", "1ps", "100fs", "10fs", "1fs"};
|
"100ns", "10ns", "1ns", "100ps", "10ps", "1ps", "100fs", "10fs", "1fs"};
|
||||||
if (scale < 0) scale = -scale;
|
if (VL_UNLIKELY(scale > 2 || scale < -15)) scale = 0;
|
||||||
if (VL_UNLIKELY(scale > 15)) scale = 0;
|
return names[2 - scale];
|
||||||
return names[scale];
|
|
||||||
}
|
}
|
||||||
double vl_time_multiplier(int 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
|
// 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) {
|
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];
|
return neg10[-scale];
|
||||||
} else {
|
} 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];
|
return pow10[scale];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2085,7 +2125,7 @@ Verilated::ThreadLocal::ThreadLocal()
|
|||||||
Verilated::ThreadLocal::~ThreadLocal() {}
|
Verilated::ThreadLocal::~ThreadLocal() {}
|
||||||
|
|
||||||
void Verilated::debug(int level) VL_MT_SAFE {
|
void Verilated::debug(int level) VL_MT_SAFE {
|
||||||
VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
s_s.s_debug = level;
|
s_s.s_debug = level;
|
||||||
if (level) {
|
if (level) {
|
||||||
#ifdef VL_DEBUG
|
#ifdef VL_DEBUG
|
||||||
@@ -2099,49 +2139,49 @@ void Verilated::debug(int level) VL_MT_SAFE {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
void Verilated::randReset(int val) 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;
|
s_s.s_randReset = val;
|
||||||
}
|
}
|
||||||
void Verilated::randSeed(int val) VL_MT_SAFE {
|
void Verilated::randSeed(int val) VL_MT_SAFE {
|
||||||
VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
s_s.s_randSeed = val;
|
s_s.s_randSeed = val;
|
||||||
}
|
}
|
||||||
void Verilated::calcUnusedSigs(bool flag) VL_MT_SAFE {
|
void Verilated::calcUnusedSigs(bool flag) VL_MT_SAFE {
|
||||||
VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
s_s.s_calcUnusedSigs = flag;
|
s_s.s_calcUnusedSigs = flag;
|
||||||
}
|
}
|
||||||
void Verilated::errorCount(int val) VL_MT_SAFE {
|
void Verilated::errorCount(int val) VL_MT_SAFE {
|
||||||
VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
s_s.s_errorCount = val;
|
s_s.s_errorCount = val;
|
||||||
}
|
}
|
||||||
void Verilated::errorCountInc() VL_MT_SAFE {
|
void Verilated::errorCountInc() VL_MT_SAFE {
|
||||||
VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
++s_s.s_errorCount;
|
++s_s.s_errorCount;
|
||||||
}
|
}
|
||||||
void Verilated::errorLimit(int val) VL_MT_SAFE {
|
void Verilated::errorLimit(int val) VL_MT_SAFE {
|
||||||
VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
s_s.s_errorLimit = val;
|
s_s.s_errorLimit = val;
|
||||||
}
|
}
|
||||||
void Verilated::gotFinish(bool flag) VL_MT_SAFE {
|
void Verilated::gotFinish(bool flag) VL_MT_SAFE {
|
||||||
VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
s_s.s_gotFinish = flag;
|
s_s.s_gotFinish = flag;
|
||||||
}
|
}
|
||||||
void Verilated::assertOn(bool flag) VL_MT_SAFE {
|
void Verilated::assertOn(bool flag) VL_MT_SAFE {
|
||||||
VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
s_s.s_assertOn = flag;
|
s_s.s_assertOn = flag;
|
||||||
}
|
}
|
||||||
void Verilated::fatalOnVpiError(bool flag) VL_MT_SAFE {
|
void Verilated::fatalOnVpiError(bool flag) VL_MT_SAFE {
|
||||||
VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
s_s.s_fatalOnVpiError = flag;
|
s_s.s_fatalOnVpiError = flag;
|
||||||
}
|
}
|
||||||
void Verilated::timeunit(int value) VL_MT_SAFE {
|
void Verilated::timeunit(int value) VL_MT_SAFE {
|
||||||
if (value < 0) value = -value; // Stored as 0..15
|
if (value < 0) value = -value; // Stored as 0..15
|
||||||
VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
s_s.s_timeunit = value;
|
s_s.s_timeunit = value;
|
||||||
}
|
}
|
||||||
void Verilated::timeprecision(int value) VL_MT_SAFE {
|
void Verilated::timeprecision(int value) VL_MT_SAFE {
|
||||||
if (value < 0) value = -value; // Stored as 0..15
|
if (value < 0) value = -value; // Stored as 0..15
|
||||||
VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
s_s.s_timeprecision = value;
|
s_s.s_timeprecision = value;
|
||||||
#ifdef SYSTEMC_VERSION
|
#ifdef SYSTEMC_VERSION
|
||||||
sc_time sc_res = sc_get_time_resolution();
|
sc_time sc_res = sc_get_time_resolution();
|
||||||
@@ -2172,15 +2212,15 @@ void Verilated::timeprecision(int value) VL_MT_SAFE {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
void Verilated::profThreadsStart(vluint64_t flag) VL_MT_SAFE {
|
void Verilated::profThreadsStart(vluint64_t flag) VL_MT_SAFE {
|
||||||
VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
s_ns.s_profThreadsStart = flag;
|
s_ns.s_profThreadsStart = flag;
|
||||||
}
|
}
|
||||||
void Verilated::profThreadsWindow(vluint64_t flag) VL_MT_SAFE {
|
void Verilated::profThreadsWindow(vluint64_t flag) VL_MT_SAFE {
|
||||||
VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
s_ns.s_profThreadsWindow = flag;
|
s_ns.s_profThreadsWindow = flag;
|
||||||
}
|
}
|
||||||
void Verilated::profThreadsFilenamep(const char* flagp) VL_MT_SAFE {
|
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));
|
if (s_ns.s_profThreadsFilenamep) free(const_cast<char*>(s_ns.s_profThreadsFilenamep));
|
||||||
s_ns.s_profThreadsFilenamep = strdup(flagp);
|
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 {
|
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
|
if (s_flushCb == cb) { // Ok - don't duplicate
|
||||||
} else if (!s_flushCb) {
|
} else if (!s_flushCb) {
|
||||||
s_flushCb = cb;
|
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 {
|
void Verilated::flushCall() VL_MT_SAFE {
|
||||||
VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
if (s_flushCb) (*s_flushCb)();
|
if (s_flushCb) (*s_flushCb)();
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
VL_GCOV_FLUSH();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* Verilated::productName() VL_PURE { return VERILATOR_PRODUCT; }
|
const char* Verilated::productName() VL_PURE { return VERILATOR_PRODUCT; }
|
||||||
const char* Verilated::productVersion() VL_PURE { return VERILATOR_VERSION; }
|
const char* Verilated::productVersion() VL_PURE { return VERILATOR_VERSION; }
|
||||||
|
|
||||||
void Verilated::commandArgs(int argc, const char** argv) VL_MT_SAFE {
|
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.argc = argc;
|
||||||
s_args.argv = argv;
|
s_args.argv = argv;
|
||||||
VerilatedImp::commandArgs(argc, argv);
|
VerilatedImp::commandArgs(argc, argv);
|
||||||
@@ -2301,11 +2345,11 @@ void Verilated::endOfEvalGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
|
|||||||
// VerilatedImp:: Methods
|
// VerilatedImp:: Methods
|
||||||
|
|
||||||
std::string VerilatedImp::timeFormatSuffix() VL_MT_SAFE {
|
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;
|
return s_s.m_serg.m_timeFormatSuffix;
|
||||||
}
|
}
|
||||||
void VerilatedImp::timeFormatSuffix(const std::string& value) VL_MT_SAFE {
|
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;
|
s_s.m_serg.m_timeFormatSuffix = value;
|
||||||
}
|
}
|
||||||
void VerilatedImp::timeFormatUnits(int value) VL_MT_SAFE { s_s.m_ser.m_timeFormatUnits = 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::timeFormatWidth(int value) VL_MT_SAFE { s_s.m_ser.m_timeFormatWidth = value; }
|
||||||
|
|
||||||
void VerilatedImp::internalsDump() VL_MT_SAFE {
|
void VerilatedImp::internalsDump() VL_MT_SAFE {
|
||||||
VerilatedLockGuard lock(s_s.m_argMutex);
|
const VerilatedLockGuard lock(s_s.m_argMutex);
|
||||||
VL_PRINTF_MT("internalsDump:\n");
|
VL_PRINTF_MT("internalsDump:\n");
|
||||||
versionDump();
|
versionDump();
|
||||||
VL_PRINTF_MT(" Argv:");
|
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) {
|
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
|
s_s.m_argVec.clear(); // Always clear
|
||||||
commandArgsAddGuts(argc, argv);
|
commandArgsAddGuts(argc, argv);
|
||||||
}
|
}
|
||||||
void VerilatedImp::commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) {
|
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);
|
commandArgsAddGuts(argc, argv);
|
||||||
}
|
}
|
||||||
void VerilatedImp::commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.m_argMutex) {
|
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 VerilatedVarProps::totalSize() const {
|
||||||
size_t size = entSize();
|
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;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const {
|
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;
|
if (VL_UNLIKELY(indx < low(dim) || indx > high(dim))) return NULL;
|
||||||
int indxAdj = indx - low(dim);
|
int indxAdj = indx - low(dim);
|
||||||
vluint8_t* bytep = reinterpret_cast<vluint8_t*>(datap);
|
vluint8_t* bytep = reinterpret_cast<vluint8_t*>(datap);
|
||||||
@@ -2470,6 +2514,7 @@ VerilatedScope::VerilatedScope() {
|
|||||||
m_funcnumMax = 0;
|
m_funcnumMax = 0;
|
||||||
m_symsp = NULL;
|
m_symsp = NULL;
|
||||||
m_varsp = NULL;
|
m_varsp = NULL;
|
||||||
|
m_timeunit = 0;
|
||||||
m_type = SCOPE_OTHER;
|
m_type = SCOPE_OTHER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2484,7 +2529,7 @@ VerilatedScope::~VerilatedScope() {
|
|||||||
|
|
||||||
void VerilatedScope::configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp,
|
void VerilatedScope::configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp,
|
||||||
const char* identifier, vlsint8_t timeunit,
|
const char* identifier, vlsint8_t timeunit,
|
||||||
const Type type) VL_MT_UNSAFE {
|
const Type& type) VL_MT_UNSAFE {
|
||||||
// Slowpath - called once/scope at construction
|
// Slowpath - called once/scope at construction
|
||||||
// We don't want the space and reference-count access overhead of strings.
|
// We don't want the space and reference-count access overhead of strings.
|
||||||
m_symsp = symsp;
|
m_symsp = symsp;
|
||||||
@@ -2538,7 +2583,7 @@ void VerilatedScope::varInsert(int finalize, const char* namep, void* datap,
|
|||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
var.m_packed.m_left = msb;
|
var.m_packed.m_left = msb;
|
||||||
var.m_packed.m_right = lsb;
|
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_left = msb;
|
||||||
var.m_unpacked[i - 1].m_right = lsb;
|
var.m_unpacked[i - 1].m_right = lsb;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+80
-53
@@ -337,7 +337,7 @@ public: // But internals only - called from VerilatedModule's
|
|||||||
VerilatedScope();
|
VerilatedScope();
|
||||||
~VerilatedScope();
|
~VerilatedScope();
|
||||||
void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp,
|
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 exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE;
|
||||||
void varInsert(int finalize, const char* namep, void* datap, VerilatedVarType vltype,
|
void varInsert(int finalize, const char* namep, void* datap, VerilatedVarType vltype,
|
||||||
int vlflags, int dims, ...) VL_MT_UNSAFE;
|
int vlflags, int dims, ...) VL_MT_UNSAFE;
|
||||||
@@ -365,7 +365,7 @@ public: // But internals only - called from VerilatedModule's
|
|||||||
|
|
||||||
class VerilatedHierarchy {
|
class VerilatedHierarchy {
|
||||||
public:
|
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_assertOn; ///< Assertions are enabled
|
||||||
bool s_fatalOnVpiError; ///< Stop on vpi error/unsupported
|
bool s_fatalOnVpiError; ///< Stop on vpi error/unsupported
|
||||||
// Slow path
|
// Slow path
|
||||||
unsigned s_timeunit : 4; ///< Time unit as 0..15
|
vlsint8_t s_timeunit; ///< Time unit as 0..15
|
||||||
unsigned s_timeprecision : 4; ///< Time precision as 0..15
|
vlsint8_t s_timeprecision; ///< Time precision as 0..15
|
||||||
int s_errorCount; ///< Number of errors
|
int s_errorCount; ///< Number of errors
|
||||||
int s_errorLimit; ///< Stop on error number
|
int s_errorLimit; ///< Stop on error number
|
||||||
int s_randReset; ///< Random reset: 0=all 0s, 1=all 1s, 2=random
|
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
|
/// File I/O
|
||||||
extern IData VL_FGETS_IXI(int obits, void* destp, IData fpi);
|
extern IData VL_FGETS_IXI(int obits, void* destp, IData fpi);
|
||||||
|
|
||||||
extern IData VL_FOPEN_S(const char* filenamep, const char* modep);
|
extern void VL_FFLUSH_I(IData fdi);
|
||||||
extern IData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode);
|
extern IData VL_FSEEK_I(IData fdi, IData offset, IData origin);
|
||||||
extern IData VL_FOPEN_QI(QData filename, IData mode);
|
extern IData VL_FTELL_I(IData fdi);
|
||||||
inline IData VL_FOPEN_II(IData filename, IData mode) VL_MT_SAFE {
|
|
||||||
return VL_FOPEN_QI(filename, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void VL_FCLOSE_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,
|
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.
|
/// 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_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_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_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))
|
#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
|
/// Create two 32-bit words from quadword
|
||||||
/// WData is always at least 2 words; does not clean upper bits
|
/// WData is always at least 2 words; does not clean upper bits
|
||||||
#define VL_SET_WQ(owp, data) \
|
#define VL_SET_WQ(owp, data) \
|
||||||
{ \
|
do { \
|
||||||
(owp)[0] = static_cast<IData>(data); \
|
(owp)[0] = static_cast<IData>(data); \
|
||||||
(owp)[1] = static_cast<IData>((data) >> VL_EDATASIZE); \
|
(owp)[1] = static_cast<IData>((data) >> VL_EDATASIZE); \
|
||||||
}
|
} while (false)
|
||||||
#define VL_SET_WI(owp, data) \
|
#define VL_SET_WI(owp, data) \
|
||||||
{ \
|
do { \
|
||||||
(owp)[0] = static_cast<IData>(data); \
|
(owp)[0] = static_cast<IData>(data); \
|
||||||
(owp)[1] = 0; \
|
(owp)[1] = 0; \
|
||||||
}
|
} while (false)
|
||||||
#define VL_SET_QW(lwp) \
|
#define VL_SET_QW(lwp) \
|
||||||
((static_cast<QData>((lwp)[0])) \
|
((static_cast<QData>((lwp)[0])) \
|
||||||
| (static_cast<QData>((lwp)[1]) << (static_cast<QData>(VL_EDATASIZE))))
|
| (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
|
/// 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
|
// clang-format off
|
||||||
// Use a union to avoid cast-to-different-size warnings
|
// 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
|
// Sign extend such that if MSB set, we get ffff_ffff, else 0s
|
||||||
// (Requires clean input)
|
// (Requires clean input)
|
||||||
#define VL_SIGN_I(nbits, lhs) ((lhs) >> VL_BITBIT_I((nbits)-VL_UL(1)))
|
#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_E(nbits, lhs) ((lhs) >> VL_BITBIT_E((nbits)-VL_EUL(1)))
|
||||||
#define VL_SIGN_W(nbits, rwp) \
|
#define VL_SIGN_W(nbits, rwp) \
|
||||||
((rwp)[VL_BITWORD_E((nbits)-VL_EUL(1))] >> VL_BITBIT_E((nbits)-VL_EUL(1)))
|
((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))));
|
return (-((lhs) & (VL_UL(1) << (lbits - 1))));
|
||||||
}
|
}
|
||||||
static inline QData VL_EXTENDSIGN_Q(int lbits, QData lhs) VL_PURE {
|
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
|
// 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)));
|
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 {
|
static inline void VL_ASSIGNBIT_QI(int, int bit, QData& lhsr, QData rhs) VL_PURE {
|
||||||
lhsr = ((lhsr & ~(VL_ULL(1) << VL_BITBIT_Q(bit)))
|
lhsr = ((lhsr & ~(1ULL << VL_BITBIT_Q(bit))) | (static_cast<QData>(rhs) << 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 {
|
static inline void VL_ASSIGNBIT_WI(int, int bit, WDataOutP owp, IData rhs) VL_MT_SAFE {
|
||||||
EData orig = owp[VL_BITWORD_E(bit)];
|
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)));
|
lhsr = (lhsr | (VL_UL(1) << VL_BITBIT_I(bit)));
|
||||||
}
|
}
|
||||||
static inline void VL_ASSIGNBIT_QO(int, int bit, QData& lhsr, IData) VL_PURE {
|
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 {
|
static inline void VL_ASSIGNBIT_WO(int, int bit, WDataOutP owp, IData) VL_MT_SAFE {
|
||||||
EData orig = owp[VL_BITWORD_E(bit)];
|
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;
|
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 {
|
static inline IData VL_ONEHOT_I(IData lhs) VL_PURE {
|
||||||
return (((lhs & (lhs - 1)) == 0) & (lhs != 0));
|
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;
|
if (VL_UNLIKELY(!lhs)) return 0;
|
||||||
lhs--;
|
lhs--;
|
||||||
int shifts = 0;
|
int shifts = 0;
|
||||||
for (; lhs != 0; ++shifts) lhs = lhs >> VL_ULL(1);
|
for (; lhs != 0; ++shifts) lhs = lhs >> 1ULL;
|
||||||
return shifts;
|
return shifts;
|
||||||
}
|
}
|
||||||
static inline IData VL_CLOG2_W(int words, WDataInP lwp) VL_MT_SAFE {
|
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;
|
QData carry = 0;
|
||||||
for (int i = 0; i < words; ++i) {
|
for (int i = 0; i < words; ++i) {
|
||||||
carry = carry + static_cast<QData>(lwp[i]) + static_cast<QData>(rwp[i]);
|
carry = carry + static_cast<QData>(lwp[i]) + static_cast<QData>(rwp[i]);
|
||||||
owp[i] = (carry & VL_ULL(0xffffffff));
|
owp[i] = (carry & 0xffffffffULL);
|
||||||
carry = (carry >> VL_ULL(32)) & VL_ULL(0xffffffff);
|
carry = (carry >> 32ULL) & 0xffffffffULL;
|
||||||
}
|
}
|
||||||
// Last output word is dirty
|
// Last output word is dirty
|
||||||
return owp;
|
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])
|
carry = (carry + static_cast<QData>(lwp[i])
|
||||||
+ static_cast<QData>(static_cast<IData>(~rwp[i])));
|
+ static_cast<QData>(static_cast<IData>(~rwp[i])));
|
||||||
if (i == 0) ++carry; // Negation of rwp
|
if (i == 0) ++carry; // Negation of rwp
|
||||||
owp[i] = (carry & VL_ULL(0xffffffff));
|
owp[i] = (carry & 0xffffffffULL);
|
||||||
carry = (carry >> VL_ULL(32)) & VL_ULL(0xffffffff);
|
carry = (carry >> 32ULL) & 0xffffffffULL;
|
||||||
}
|
}
|
||||||
// Last output word is dirty
|
// Last output word is dirty
|
||||||
return owp;
|
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]);
|
QData mul = static_cast<QData>(lwp[lword]) * static_cast<QData>(rwp[rword]);
|
||||||
for (int qword = lword + rword; qword < words; ++qword) {
|
for (int qword = lword + rword; qword < words; ++qword) {
|
||||||
mul += static_cast<QData>(owp[qword]);
|
mul += static_cast<QData>(owp[qword]);
|
||||||
owp[qword] = (mul & VL_ULL(0xffffffff));
|
owp[qword] = (mul & 0xffffffffULL);
|
||||||
mul = (mul >> VL_ULL(32)) & VL_ULL(0xffffffff);
|
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) {
|
for (int i = 0; i < words; ++i) {
|
||||||
carry = carry + static_cast<QData>(static_cast<IData>(~owp[i]));
|
carry = carry + static_cast<QData>(static_cast<IData>(~owp[i]));
|
||||||
if (i == 0) ++carry; // Negation of temp2
|
if (i == 0) ++carry; // Negation of temp2
|
||||||
owp[i] = (carry & VL_ULL(0xffffffff));
|
owp[i] = (carry & 0xffffffffULL);
|
||||||
carry = (carry >> VL_ULL(32)) & VL_ULL(0xffffffff);
|
carry = (carry >> 32ULL) & 0xffffffffULL;
|
||||||
}
|
}
|
||||||
// Not needed: owp[words-1] |= 1<<VL_BITBIT_E(lbits-1); // Set sign bit
|
// 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;
|
IData out = 1;
|
||||||
for (int i = 0; i < rbits; ++i) {
|
for (int i = 0; i < rbits; ++i) {
|
||||||
if (i > 0) power = power * power;
|
if (i > 0) power = power * power;
|
||||||
if (rhs & (VL_ULL(1) << i)) out *= power;
|
if (rhs & (1ULL << i)) out *= power;
|
||||||
}
|
}
|
||||||
return out;
|
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(rhs == 0)) return 1;
|
||||||
if (VL_UNLIKELY(lhs == 0)) return 0;
|
if (VL_UNLIKELY(lhs == 0)) return 0;
|
||||||
QData power = lhs;
|
QData power = lhs;
|
||||||
QData out = VL_ULL(1);
|
QData out = 1ULL;
|
||||||
for (int i = 0; i < rbits; ++i) {
|
for (int i = 0; i < rbits; ++i) {
|
||||||
if (i > 0) power = power * power;
|
if (i > 0) power = power * power;
|
||||||
if (rhs & (VL_ULL(1) << i)) out *= power;
|
if (rhs & (1ULL << i)) out *= power;
|
||||||
}
|
}
|
||||||
return out;
|
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 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 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 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);
|
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 lbitsFloor = lbits & ~VL_MASK_I(rd_log2);
|
||||||
vluint32_t lbitsRem = lbits - lbitsFloor;
|
vluint32_t lbitsRem = lbits - lbitsFloor;
|
||||||
QData msbMask = VL_MASK_Q(lbitsRem) << 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) {
|
switch (rd_log2) {
|
||||||
case 0:
|
case 0:
|
||||||
ret = (((ret >> 1) & VL_ULL(0x5555555555555555))
|
ret = (((ret >> 1) & 0x5555555555555555ULL)
|
||||||
| ((ret & VL_ULL(0x5555555555555555)) << 1)); // FALLTHRU
|
| ((ret & 0x5555555555555555ULL) << 1)); // FALLTHRU
|
||||||
case 1:
|
case 1:
|
||||||
ret = (((ret >> 2) & VL_ULL(0x3333333333333333))
|
ret = (((ret >> 2) & 0x3333333333333333ULL)
|
||||||
| ((ret & VL_ULL(0x3333333333333333)) << 2)); // FALLTHRU
|
| ((ret & 0x3333333333333333ULL) << 2)); // FALLTHRU
|
||||||
case 2:
|
case 2:
|
||||||
ret = (((ret >> 4) & VL_ULL(0x0f0f0f0f0f0f0f0f))
|
ret = (((ret >> 4) & 0x0f0f0f0f0f0f0f0fULL)
|
||||||
| ((ret & VL_ULL(0x0f0f0f0f0f0f0f0f)) << 4)); // FALLTHRU
|
| ((ret & 0x0f0f0f0f0f0f0f0fULL) << 4)); // FALLTHRU
|
||||||
case 3:
|
case 3:
|
||||||
ret = (((ret >> 8) & VL_ULL(0x00ff00ff00ff00ff))
|
ret = (((ret >> 8) & 0x00ff00ff00ff00ffULL)
|
||||||
| ((ret & VL_ULL(0x00ff00ff00ff00ff)) << 8)); // FALLTHRU
|
| ((ret & 0x00ff00ff00ff00ffULL) << 8)); // FALLTHRU
|
||||||
case 4:
|
case 4:
|
||||||
ret = (((ret >> 16) & VL_ULL(0x0000ffff0000ffff))
|
ret = (((ret >> 16) & 0x0000ffff0000ffffULL)
|
||||||
| ((ret & VL_ULL(0x0000ffff0000ffff)) << 16)); // FALLTHRU
|
| ((ret & 0x0000ffff0000ffffULL) << 16)); // FALLTHRU
|
||||||
case 5: ret = ((ret >> 32) | (ret << 32));
|
case 5: ret = ((ret >> 32) | (ret << 32)); // FALLTHRU
|
||||||
|
default:;
|
||||||
}
|
}
|
||||||
return ret >> (VL_QUADSIZE - lbits);
|
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)
|
/// Return QData from double (numeric)
|
||||||
// EMIT_RULE: VL_RTOIROUND_Q_D: oclean=dirty; lclean==clean/real
|
// 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
|
// IEEE format: [63]=sign [62:52]=exp+1023 [51:0]=mantissa
|
||||||
// This does not need to support subnormals as they are sub-integral
|
// This does not need to support subnormals as they are sub-integral
|
||||||
lhs = VL_ROUND(lhs);
|
lhs = VL_ROUND(lhs);
|
||||||
if (lhs == 0.0) return 0;
|
if (lhs == 0.0) return 0;
|
||||||
QData q = VL_CVT_Q_D(lhs);
|
QData q = VL_CVT_Q_D(lhs);
|
||||||
int lsb = static_cast<int>((q >> VL_ULL(52)) & VL_MASK_Q(11)) - 1023 - 52;
|
int lsb = static_cast<int>((q >> 52ULL) & VL_MASK_Q(11)) - 1023 - 52;
|
||||||
vluint64_t mantissa = (q & VL_MASK_Q(52)) | (VL_ULL(1) << 52);
|
vluint64_t mantissa = (q & VL_MASK_Q(52)) | (1ULL << 52);
|
||||||
vluint64_t out = 0;
|
vluint64_t out = 0;
|
||||||
if (lsb < 0) {
|
if (lsb < 0) {
|
||||||
out = mantissa >> -lsb;
|
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);
|
VL_ZERO_W(obits, owp);
|
||||||
if (lhs == 0.0) return owp;
|
if (lhs == 0.0) return owp;
|
||||||
QData q = VL_CVT_Q_D(lhs);
|
QData q = VL_CVT_Q_D(lhs);
|
||||||
int lsb = static_cast<int>((q >> VL_ULL(52)) & VL_MASK_Q(11)) - 1023 - 52;
|
int lsb = static_cast<int>((q >> 52ULL) & VL_MASK_Q(11)) - 1023 - 52;
|
||||||
vluint64_t mantissa = (q & VL_MASK_Q(52)) | (VL_ULL(1) << 52);
|
vluint64_t mantissa = (q & VL_MASK_Q(52)) | (1ULL << 52);
|
||||||
if (lsb < 0) {
|
if (lsb < 0) {
|
||||||
VL_SET_WQ(owp, mantissa >> -lsb);
|
VL_SET_WQ(owp, mantissa >> -lsb);
|
||||||
} else if (lsb < obits) {
|
} else if (lsb < obits) {
|
||||||
|
|||||||
+42
-39
@@ -84,27 +84,29 @@ CPPFLAGS += $(VM_USER_CFLAGS)
|
|||||||
LDFLAGS += $(VM_USER_LDFLAGS)
|
LDFLAGS += $(VM_USER_LDFLAGS)
|
||||||
LDLIBS += $(VM_USER_LDLIBS)
|
LDLIBS += $(VM_USER_LDLIBS)
|
||||||
|
|
||||||
# See the benchmarking section of bin/verilator.
|
######################################################################
|
||||||
# Support class optimizations. This includes the tracing and symbol table.
|
# Optimization control.
|
||||||
# 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 =
|
|
||||||
|
|
||||||
#######################################################################
|
# See also the BENCHMARKING & OPTIMIZATION section of the manual.
|
||||||
##### Aggregates
|
|
||||||
|
|
||||||
VM_CLASSES += $(VM_CLASSES_FAST) $(VM_CLASSES_SLOW)
|
# Optimization flags for non performance-critical/rarely executed code.
|
||||||
VM_SUPPORT += $(VM_SUPPORT_FAST) $(VM_SUPPORT_SLOW)
|
# 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
|
##### SystemC builds
|
||||||
|
|
||||||
ifeq ($(VM_SC),1)
|
ifeq ($(VM_SC),1)
|
||||||
CPPFLAGS += $(SYSTEMC_CXX_FLAGS) -I$(SYSTEMC_INCLUDE)
|
CPPFLAGS += $(SYSTEMC_CXX_FLAGS) $(addprefix -I, $(SYSTEMC_INCLUDE))
|
||||||
LDFLAGS += $(SYSTEMC_CXX_FLAGS) -L$(SYSTEMC_LIBDIR)
|
LDFLAGS += $(SYSTEMC_CXX_FLAGS) $(addprefix -L, $(SYSTEMC_LIBDIR))
|
||||||
SC_LIBS = -lsystemc
|
SC_LIBS = -lsystemc
|
||||||
ifneq ($(wildcard $(SYSTEMC_LIBDIR)/*numeric_bit*),)
|
ifneq ($(wildcard $(SYSTEMC_LIBDIR)/*numeric_bit*),)
|
||||||
# Systemc 1.2.1beta
|
# Systemc 1.2.1beta
|
||||||
@@ -163,35 +165,39 @@ ifneq ($(VK_LIBS_THREADED),0)
|
|||||||
endif
|
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_FAST_OBJS = $(addsuffix .o, $(VM_FAST))
|
||||||
VK_CLASSES_SLOW_CPP = $(addsuffix .cpp, $(VM_CLASSES_SLOW))
|
VK_SLOW_OBJS = $(addsuffix .o, $(VM_SLOW))
|
||||||
|
|
||||||
VK_SUPPORT_FAST_CPP = $(addsuffix .cpp, $(VM_SUPPORT_FAST))
|
|
||||||
VK_SUPPORT_SLOW_CPP = $(addsuffix .cpp, $(VM_SUPPORT_SLOW))
|
|
||||||
|
|
||||||
VK_USER_OBJS = $(addsuffix .o, $(VM_USER_CLASSES))
|
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))
|
VK_GLOBAL_OBJS = $(addsuffix .o, $(VM_GLOBAL_FAST) $(VM_GLOBAL_SLOW))
|
||||||
|
|
||||||
ifneq ($(VM_PARALLEL_BUILDS),1)
|
ifneq ($(VM_PARALLEL_BUILDS),1)
|
||||||
# Fast building, all .cpp's in one fell swoop
|
# Fast build for small designs: All .cpp files in one fell swoop. This
|
||||||
# This saves about 5 sec per module, but can be slower if only a little changes
|
# saves total compute, but can be slower if only a little changes. It is
|
||||||
VK_OBJS += $(VM_PREFIX)__ALLfast.o $(VM_PREFIX)__ALLslow.o
|
# also a lot slower for medium to large designs when the speed of the C
|
||||||
all_cpp: $(VM_PREFIX)__ALLfast.cpp $(VM_PREFIX)__ALLslow.cpp
|
# compiler dominates, which in this mode is not parallelizable.
|
||||||
$(VM_PREFIX)__ALLfast.cpp: $(VK_CLASSES_FAST_CPP) $(VK_SUPPORT_FAST_CPP)
|
|
||||||
$(VERILATOR_INCLUDER) -DVL_INCLUDE_OPT=include $^ > $@
|
VK_OBJS += $(VM_PREFIX)__ALL.o
|
||||||
$(VM_PREFIX)__ALLslow.cpp: $(VK_CLASSES_SLOW_CPP) $(VK_SUPPORT_SLOW_CPP)
|
$(VM_PREFIX)__ALL.cpp: $(addsuffix .cpp, $(VM_FAST) $(VM_SLOW))
|
||||||
$(VERILATOR_INCLUDER) -DVL_INCLUDE_OPT=include $^ > $@
|
$(VERILATOR_INCLUDER) -DVL_INCLUDE_OPT=include $^ > $@
|
||||||
|
all_cpp: $(VM_PREFIX)__ALL.cpp
|
||||||
else
|
else
|
||||||
#Slow way of building... Each .cpp file by itself
|
# Parallel build: Each .cpp file by itself. This can be somewhat slower for
|
||||||
VK_OBJS += $(addsuffix .o, $(VM_CLASSES) $(VM_SUPPORT))
|
# very small designs and examples, but is a lot faster for large designs.
|
||||||
|
|
||||||
|
VK_OBJS += $(VK_FAST_OBJS) $(VK_SLOW_OBJS)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
$(VM_PREFIX)__ALL.a: $(VK_OBJS)
|
$(VM_PREFIX)__ALL.a: $(VK_OBJS)
|
||||||
@@ -202,19 +208,16 @@ $(VM_PREFIX)__ALL.a: $(VK_OBJS)
|
|||||||
### Compile rules
|
### Compile rules
|
||||||
|
|
||||||
ifneq ($(VM_DEFAULT_RULES),0)
|
ifneq ($(VM_DEFAULT_RULES),0)
|
||||||
$(VM_PREFIX)__ALLfast.o: $(VM_PREFIX)__ALLfast.cpp
|
# Anything not in $(VK_SLOW_OBJS) or $(VK_GLOBAL_OBJS), including verilated.o
|
||||||
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $<
|
# and user files passed on the Verilator command line use this rule.
|
||||||
|
|
||||||
$(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
|
|
||||||
%.o: %.cpp
|
%.o: %.cpp
|
||||||
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $<
|
$(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 $@ $<
|
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_SLOW) -c -o $@ $<
|
||||||
|
|
||||||
|
$(VK_GLOBAL_OBJS): %.o: %.cpp
|
||||||
|
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_GLOBAL) -c -o $@ $<
|
||||||
endif
|
endif
|
||||||
|
|
||||||
#Default rule embedded in make:
|
#Default rule embedded in make:
|
||||||
|
|||||||
+11
-12
@@ -94,7 +94,6 @@ private:
|
|||||||
typedef std::map<int, std::string> IndexValueMap;
|
typedef std::map<int, std::string> IndexValueMap;
|
||||||
typedef std::deque<VerilatedCovImpItem*> ItemList;
|
typedef std::deque<VerilatedCovImpItem*> ItemList;
|
||||||
|
|
||||||
private:
|
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
VerilatedMutex m_mutex; ///< Protects all members
|
VerilatedMutex m_mutex; ///< Protects all members
|
||||||
ValueIndexMap m_valueIndexes VL_GUARDED_BY(m_mutex); ///< Unique arbitrary value for values
|
ValueIndexMap m_valueIndexes VL_GUARDED_BY(m_mutex); ///< Unique arbitrary value for values
|
||||||
@@ -250,12 +249,12 @@ public:
|
|||||||
// PUBLIC METHODS
|
// PUBLIC METHODS
|
||||||
void clear() VL_EXCLUDES(m_mutex) {
|
void clear() VL_EXCLUDES(m_mutex) {
|
||||||
Verilated::quiesce();
|
Verilated::quiesce();
|
||||||
VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
clearGuts();
|
clearGuts();
|
||||||
}
|
}
|
||||||
void clearNonMatch(const char* matchp) VL_EXCLUDES(m_mutex) {
|
void clearNonMatch(const char* matchp) VL_EXCLUDES(m_mutex) {
|
||||||
Verilated::quiesce();
|
Verilated::quiesce();
|
||||||
VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
if (matchp && matchp[0]) {
|
if (matchp && matchp[0]) {
|
||||||
ItemList newlist;
|
ItemList newlist;
|
||||||
for (ItemList::iterator it = m_items.begin(); it != m_items.end(); ++it) {
|
for (ItemList::iterator it = m_items.begin(); it != m_items.end(); ++it) {
|
||||||
@@ -271,7 +270,7 @@ public:
|
|||||||
}
|
}
|
||||||
void zero() VL_EXCLUDES(m_mutex) {
|
void zero() VL_EXCLUDES(m_mutex) {
|
||||||
Verilated::quiesce();
|
Verilated::quiesce();
|
||||||
VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
for (ItemList::const_iterator it = m_items.begin(); it != m_items.end(); ++it) {
|
for (ItemList::const_iterator it = m_items.begin(); it != m_items.end(); ++it) {
|
||||||
(*it)->zero();
|
(*it)->zero();
|
||||||
}
|
}
|
||||||
@@ -279,17 +278,17 @@ public:
|
|||||||
|
|
||||||
// We assume there's always call to i/f/p in that order
|
// We assume there's always call to i/f/p in that order
|
||||||
void inserti(VerilatedCovImpItem* itemp) VL_EXCLUDES(m_mutex) {
|
void inserti(VerilatedCovImpItem* itemp) VL_EXCLUDES(m_mutex) {
|
||||||
VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
assert(!m_insertp);
|
assert(!m_insertp);
|
||||||
m_insertp = itemp;
|
m_insertp = itemp;
|
||||||
}
|
}
|
||||||
void insertf(const char* filenamep, int lineno) VL_EXCLUDES(m_mutex) {
|
void insertf(const char* filenamep, int lineno) VL_EXCLUDES(m_mutex) {
|
||||||
VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
m_insertFilenamep = filenamep;
|
m_insertFilenamep = filenamep;
|
||||||
m_insertLineno = lineno;
|
m_insertLineno = lineno;
|
||||||
}
|
}
|
||||||
void insertp(const char* ckeyps[MAX_KEYS], const char* valps[MAX_KEYS]) VL_EXCLUDES(m_mutex) {
|
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);
|
assert(m_insertp);
|
||||||
// First two key/vals are filename
|
// First two key/vals are filename
|
||||||
ckeyps[0] = "filename";
|
ckeyps[0] = "filename";
|
||||||
@@ -332,10 +331,10 @@ public:
|
|||||||
m_insertp->m_keys[addKeynum] = valueIndex(key);
|
m_insertp->m_keys[addKeynum] = valueIndex(key);
|
||||||
m_insertp->m_vals[addKeynum] = valueIndex(val);
|
m_insertp->m_vals[addKeynum] = valueIndex(val);
|
||||||
addKeynum++;
|
addKeynum++;
|
||||||
if (!legalKey(key)) {
|
if (VL_UNCOVERABLE(!legalKey(key))) {
|
||||||
std::string msg
|
std::string msg
|
||||||
= ("%Error: Coverage keys of one character, or letter+digit are illegal: "
|
= ("%Error: Coverage keys of one character, or letter+digit are illegal: "
|
||||||
+ key);
|
+ key); // LCOV_EXCL_LINE
|
||||||
VL_FATAL_MT("", 0, "", msg.c_str());
|
VL_FATAL_MT("", 0, "", msg.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -347,7 +346,7 @@ public:
|
|||||||
|
|
||||||
void write(const char* filename) VL_EXCLUDES(m_mutex) {
|
void write(const char* filename) VL_EXCLUDES(m_mutex) {
|
||||||
Verilated::quiesce();
|
Verilated::quiesce();
|
||||||
VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
#ifndef VM_COVERAGE
|
#ifndef VM_COVERAGE
|
||||||
VL_FATAL_MT("", 0, "", "%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
|
VL_FATAL_MT("", 0, "", "%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
|
||||||
#endif
|
#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
|
// Backward compatibility for Verilator
|
||||||
void VerilatedCov::_insertp(A(0), A(1), K(2), int val2, K(3), int val3, K(4),
|
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 val2str = vlCovCvtToStr(val2);
|
||||||
std::string val3str = vlCovCvtToStr(val3);
|
std::string val3str = vlCovCvtToStr(val3);
|
||||||
_insertp(C(0), C(1), key2, val2str.c_str(), key3, val3str.c_str(), key4, val4.c_str(), C(5),
|
_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));
|
N(19), N(20), N(21), N(22), N(23), N(24), N(25), N(26), N(27), N(28), N(29));
|
||||||
}
|
}
|
||||||
#undef A
|
#undef A
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ public:
|
|||||||
D(22), D(23), D(24), D(25), D(26), D(27), D(28), D(29));
|
D(22), D(23), D(24), D(25), D(26), D(27), D(28), D(29));
|
||||||
// Backward compatibility for Verilator
|
// 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,
|
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 K
|
||||||
#undef A
|
#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=>'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=>'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=>'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=>'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=>'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, ")
|
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_HIER "h"
|
||||||
#define VL_CIK_LIMIT "L"
|
#define VL_CIK_LIMIT "L"
|
||||||
#define VL_CIK_LINENO "l"
|
#define VL_CIK_LINENO "l"
|
||||||
|
#define VL_CIK_LINESCOV "S"
|
||||||
#define VL_CIK_PER_INSTANCE "P"
|
#define VL_CIK_PER_INSTANCE "P"
|
||||||
#define VL_CIK_ROW0 "r0"
|
#define VL_CIK_ROW0 "r0"
|
||||||
#define VL_CIK_ROW0_NAME "R0"
|
#define VL_CIK_ROW0_NAME "R0"
|
||||||
@@ -121,6 +123,7 @@ public:
|
|||||||
if (key == "hier") return VL_CIK_HIER;
|
if (key == "hier") return VL_CIK_HIER;
|
||||||
if (key == "limit") return VL_CIK_LIMIT;
|
if (key == "limit") return VL_CIK_LIMIT;
|
||||||
if (key == "lineno") return VL_CIK_LINENO;
|
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 == "per_instance") return VL_CIK_PER_INSTANCE;
|
||||||
if (key == "row0") return VL_CIK_ROW0;
|
if (key == "row0") return VL_CIK_ROW0;
|
||||||
if (key == "row0_name") return VL_CIK_ROW0_NAME;
|
if (key == "row0_name") return VL_CIK_ROW0_NAME;
|
||||||
|
|||||||
@@ -47,7 +47,7 @@
|
|||||||
// Function requires a "context" in the import declaration
|
// Function requires a "context" in the import declaration
|
||||||
#define _VL_SVDPI_CONTEXT_WARN() \
|
#define _VL_SVDPI_CONTEXT_WARN() \
|
||||||
_VL_SVDPI_WARN("%%Warning: DPI C Function called by Verilog DPI import with missing " \
|
_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_UINT16: return (*(reinterpret_cast<SData*>(datap)) >> lsb) & 1;
|
||||||
case VLVT_UINT32: return (*(reinterpret_cast<IData*>(datap)) >> lsb) & 1;
|
case VLVT_UINT32: return (*(reinterpret_cast<IData*>(datap)) >> lsb) & 1;
|
||||||
case VLVT_UINT64:
|
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: {
|
case VLVT_WDATA: {
|
||||||
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
||||||
return VL_BITRSHIFT_W(wdatap, lsb) & 1;
|
return VL_BITRSHIFT_W(wdatap, lsb) & 1;
|
||||||
|
|||||||
+13
-28
@@ -36,17 +36,12 @@
|
|||||||
#include "gtkwave/lz4.c"
|
#include "gtkwave/lz4.c"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cerrno>
|
|
||||||
#include <ctime>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
|
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
|
||||||
# include <io.h>
|
# include <io.h>
|
||||||
#else
|
#else
|
||||||
# include <stdint.h>
|
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -132,15 +127,17 @@ void VerilatedFst::declDTypeEnum(int dtypenum, const char* name, vluint32_t elem
|
|||||||
m_local2fstdtype[dtypenum] = enumNum;
|
m_local2fstdtype[dtypenum] = enumNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VerilatedFst::declSymbol(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
void VerilatedFst::declare(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||||
fstVarType vartype, bool array, int arraynum, vluint32_t len,
|
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
|
||||||
vluint32_t bits) {
|
const int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1;
|
||||||
|
|
||||||
VerilatedTrace<VerilatedFst>::declCode(code, bits, false);
|
VerilatedTrace<VerilatedFst>::declCode(code, bits, false);
|
||||||
|
|
||||||
std::pair<Code2SymbolType::iterator, bool> p
|
std::pair<Code2SymbolType::iterator, bool> p
|
||||||
= m_code2symbol.insert(std::make_pair(code, static_cast<fstHandle>(NULL)));
|
= m_code2symbol.insert(std::make_pair(code, static_cast<fstHandle>(NULL)));
|
||||||
std::istringstream nameiss(name);
|
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::list<std::string> tokens(beg, end); // Split name
|
||||||
std::string symbol_name(tokens.back());
|
std::string symbol_name(tokens.back());
|
||||||
tokens.pop_back(); // Remove symbol name from hierarchy
|
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);
|
fstWriterEmitEnumTableRef(m_fst, enumNum);
|
||||||
}
|
}
|
||||||
if (p.second) { // New
|
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);
|
assert(p.first->second);
|
||||||
} else { // Alias
|
} 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,
|
void VerilatedFst::declBit(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||||
fstVarType vartype, bool array, int arraynum) {
|
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,
|
void VerilatedFst::declBus(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||||
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
|
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
|
||||||
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
|
declare(code, name, dtypenum, vardir, vartype, array, arraynum, msb, lsb);
|
||||||
msb - lsb + 1);
|
|
||||||
}
|
}
|
||||||
void VerilatedFst::declQuad(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
void VerilatedFst::declQuad(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||||
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
|
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
|
||||||
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
|
declare(code, name, dtypenum, vardir, vartype, array, arraynum, msb, lsb);
|
||||||
msb - lsb + 1);
|
|
||||||
}
|
}
|
||||||
void VerilatedFst::declArray(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
void VerilatedFst::declArray(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||||
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
|
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
|
||||||
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
|
declare(code, name, dtypenum, vardir, vartype, array, arraynum, msb, lsb);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
void VerilatedFst::declDouble(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
void VerilatedFst::declDouble(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||||
fstVarType vartype, bool array, int arraynum) {
|
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
|
// 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);
|
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
|
VL_ATTR_ALWINLINE
|
||||||
void VerilatedFst::emitDouble(vluint32_t code, double newval) {
|
void VerilatedFst::emitDouble(vluint32_t code, double newval) {
|
||||||
fstWriterEmitValueChange(m_fst, m_symbolp[code], &newval);
|
fstWriterEmitValueChange(m_fst, m_symbolp[code], &newval);
|
||||||
|
|||||||
@@ -55,8 +55,8 @@ private:
|
|||||||
|
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VL_UNCOPYABLE(VerilatedFst);
|
VL_UNCOPYABLE(VerilatedFst);
|
||||||
void declSymbol(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
void declare(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||||
fstVarType vartype, bool array, int arraynum, vluint32_t len, vluint32_t bits);
|
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
@@ -77,7 +77,6 @@ protected:
|
|||||||
inline void emitIData(vluint32_t code, IData newval, int bits);
|
inline void emitIData(vluint32_t code, IData newval, int bits);
|
||||||
inline void emitQData(vluint32_t code, QData 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 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);
|
inline void emitDouble(vluint32_t code, double newval);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -112,8 +111,6 @@ public:
|
|||||||
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
|
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
|
||||||
void declArray(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
void declArray(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||||
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
|
fstVarType vartype, bool array, int arraynum, 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,
|
void declDouble(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||||
fstVarType vartype, bool array, int arraynum);
|
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 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_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,
|
extern void VL_READMEM_N(bool hex, int bits, QData depth, int array_lsb,
|
||||||
const std::string& filename, void* memp, QData start,
|
const std::string& filename, void* memp, QData start,
|
||||||
QData end) VL_MT_SAFE;
|
QData end) VL_MT_SAFE;
|
||||||
|
|||||||
+137
-37
@@ -32,6 +32,7 @@
|
|||||||
#include <deque>
|
#include <deque>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <numeric>
|
||||||
#ifdef VL_THREADED
|
#ifdef VL_THREADED
|
||||||
# include <functional>
|
# include <functional>
|
||||||
# include <queue>
|
# include <queue>
|
||||||
@@ -95,7 +96,7 @@ public:
|
|||||||
// METHODS
|
// METHODS
|
||||||
//// Add message to queue (called by producer)
|
//// Add message to queue (called by producer)
|
||||||
void post(const VerilatedMsg& msg) VL_EXCLUDES(m_mutex) {
|
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_queue.insert(msg); // Pass by value to copy the message into queue
|
||||||
++m_depth;
|
++m_depth;
|
||||||
}
|
}
|
||||||
@@ -168,6 +169,24 @@ public:
|
|||||||
};
|
};
|
||||||
#endif // VL_THREADED
|
#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
|
// VerilatedImp
|
||||||
|
|
||||||
@@ -229,17 +248,21 @@ protected:
|
|||||||
VerilatedMutex m_fdMutex; ///< Protect m_fdps, m_fdFree
|
VerilatedMutex m_fdMutex; ///< Protect m_fdps, m_fdFree
|
||||||
std::vector<FILE*> m_fdps VL_GUARDED_BY(m_fdMutex); ///< File descriptors
|
std::vector<FILE*> m_fdps VL_GUARDED_BY(m_fdMutex); ///< File descriptors
|
||||||
/// List of free descriptors (SLOW - FOPEN/CLOSE only)
|
/// 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
|
public: // But only for verilated*.cpp
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VerilatedImp()
|
VerilatedImp()
|
||||||
: m_argVecLoaded(false)
|
: m_argVecLoaded(false)
|
||||||
, m_exportNext(0) {
|
, m_exportNext(0) {
|
||||||
m_fdps.resize(3);
|
s_s.m_fdps.resize(31);
|
||||||
m_fdps[0] = stdin;
|
std::fill(s_s.m_fdps.begin(), s_s.m_fdps.end(), (FILE*)0);
|
||||||
m_fdps[1] = stdout;
|
s_s.m_fdFreeMct.resize(30);
|
||||||
m_fdps[2] = stderr;
|
for (std::size_t i = 0, id = 1; i < s_s.m_fdFreeMct.size(); ++i, ++id) {
|
||||||
|
s_s.m_fdFreeMct[i] = id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
~VerilatedImp() {}
|
~VerilatedImp() {}
|
||||||
|
|
||||||
@@ -256,7 +279,7 @@ public:
|
|||||||
static void commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex);
|
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 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) {
|
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 "+"
|
// Note prefixp does not include the leading "+"
|
||||||
size_t len = strlen(prefixp);
|
size_t len = strlen(prefixp);
|
||||||
if (VL_UNLIKELY(!s_s.m_argVecLoaded)) {
|
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
|
// 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.
|
// 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 {
|
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));
|
UserMap::iterator it = s_s.m_userMap.find(std::make_pair(scopep, userKey));
|
||||||
if (it != s_s.m_userMap.end()) {
|
if (it != s_s.m_userMap.end()) {
|
||||||
it->second = userData;
|
it->second = userData;
|
||||||
@@ -294,7 +317,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
static inline void* userFind(const void* scopep, void* userKey) VL_MT_SAFE {
|
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));
|
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;
|
if (VL_UNLIKELY(it == s_s.m_userMap.end())) return NULL;
|
||||||
return it->second;
|
return it->second;
|
||||||
@@ -304,7 +327,7 @@ private:
|
|||||||
/// Symbol table destruction cleans up the entries for each scope.
|
/// Symbol table destruction cleans up the entries for each scope.
|
||||||
static void userEraseScope(const VerilatedScope* scopep) VL_MT_SAFE {
|
static void userEraseScope(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||||
// Slow ok - called once/scope on destruction, so we simply iterate.
|
// 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();) {
|
for (UserMap::iterator it = s_s.m_userMap.begin(); it != s_s.m_userMap.end();) {
|
||||||
if (it->first.first == scopep) {
|
if (it->first.first == scopep) {
|
||||||
s_s.m_userMap.erase(it++);
|
s_s.m_userMap.erase(it++);
|
||||||
@@ -314,7 +337,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
static void userDump() VL_MT_SAFE {
|
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;
|
bool first = true;
|
||||||
for (UserMap::const_iterator it = s_s.m_userMap.begin(); it != s_s.m_userMap.end(); ++it) {
|
for (UserMap::const_iterator it = s_s.m_userMap.begin(); it != s_s.m_userMap.end(); ++it) {
|
||||||
if (first) {
|
if (first) {
|
||||||
@@ -330,14 +353,14 @@ public: // But only for verilated*.cpp
|
|||||||
// METHODS - scope name
|
// METHODS - scope name
|
||||||
static void scopeInsert(const VerilatedScope* scopep) VL_MT_SAFE {
|
static void scopeInsert(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||||
// Slow ok - called once/scope at construction
|
// 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());
|
VerilatedScopeNameMap::iterator it = s_s.m_nameMap.find(scopep->name());
|
||||||
if (it == s_s.m_nameMap.end()) {
|
if (it == s_s.m_nameMap.end()) {
|
||||||
s_s.m_nameMap.insert(it, std::make_pair(scopep->name(), scopep));
|
s_s.m_nameMap.insert(it, std::make_pair(scopep->name(), scopep));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static inline const VerilatedScope* scopeFind(const char* namep) VL_MT_SAFE {
|
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
|
// If too slow, can assume this is only VL_MT_SAFE_POSINIT
|
||||||
VerilatedScopeNameMap::const_iterator it = s_s.m_nameMap.find(namep);
|
VerilatedScopeNameMap::const_iterator it = s_s.m_nameMap.find(namep);
|
||||||
if (VL_UNLIKELY(it == s_s.m_nameMap.end())) return NULL;
|
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 {
|
static void scopeErase(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||||
// Slow ok - called once/scope at destruction
|
// Slow ok - called once/scope at destruction
|
||||||
VerilatedLockGuard lock(s_s.m_nameMutex);
|
const VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||||
userEraseScope(scopep);
|
userEraseScope(scopep);
|
||||||
VerilatedScopeNameMap::iterator it = s_s.m_nameMap.find(scopep->name());
|
VerilatedScopeNameMap::iterator it = s_s.m_nameMap.find(scopep->name());
|
||||||
if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it);
|
if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it);
|
||||||
}
|
}
|
||||||
static void scopesDump() VL_MT_SAFE {
|
static void scopesDump() VL_MT_SAFE {
|
||||||
VerilatedLockGuard lock(s_s.m_nameMutex);
|
const VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||||
VL_PRINTF_MT(" scopesDump:\n");
|
VL_PRINTF_MT(" scopesDump:\n");
|
||||||
for (VerilatedScopeNameMap::const_iterator it = s_s.m_nameMap.begin();
|
for (VerilatedScopeNameMap::const_iterator it = s_s.m_nameMap.begin();
|
||||||
it != s_s.m_nameMap.end(); ++it) {
|
it != s_s.m_nameMap.end(); ++it) {
|
||||||
@@ -369,7 +392,7 @@ public: // But only for verilated*.cpp
|
|||||||
// METHODS - hierarchy
|
// METHODS - hierarchy
|
||||||
static void hierarchyAdd(const VerilatedScope* fromp, const VerilatedScope* top) VL_MT_SAFE {
|
static void hierarchyAdd(const VerilatedScope* fromp, const VerilatedScope* top) VL_MT_SAFE {
|
||||||
// Slow ok - called at construction for VPI accessible elements
|
// 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);
|
s_s.m_hierMap[fromp].push_back(top);
|
||||||
}
|
}
|
||||||
static const VerilatedHierarchyMap* hierarchyMap() VL_MT_SAFE_POSTINIT {
|
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.
|
// miss at the cost of a multiply, and all lookups move to slowpath.
|
||||||
static int exportInsert(const char* namep) VL_MT_SAFE {
|
static int exportInsert(const char* namep) VL_MT_SAFE {
|
||||||
// Slow ok - called once/function at creation
|
// 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);
|
ExportNameMap::iterator it = s_s.m_exportMap.find(namep);
|
||||||
if (it == s_s.m_exportMap.end()) {
|
if (it == s_s.m_exportMap.end()) {
|
||||||
s_s.m_exportMap.insert(it, std::make_pair(namep, s_s.m_exportNext++));
|
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 {
|
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);
|
ExportNameMap::const_iterator it = s_s.m_exportMap.find(namep);
|
||||||
if (VL_LIKELY(it != s_s.m_exportMap.end())) return it->second;
|
if (VL_LIKELY(it != s_s.m_exportMap.end())) return it->second;
|
||||||
std::string msg = (std::string("%Error: Testbench C called ") + namep
|
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 {
|
static const char* exportName(int funcnum) VL_MT_SAFE {
|
||||||
// Slowpath; find name for given export; errors only so no map to reverse-map it
|
// 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();
|
for (ExportNameMap::const_iterator it = s_s.m_exportMap.begin();
|
||||||
it != s_s.m_exportMap.end(); ++it) {
|
it != s_s.m_exportMap.end(); ++it) {
|
||||||
if (it->second == funcnum) return it->first;
|
if (it->second == funcnum) return it->first;
|
||||||
@@ -416,7 +439,7 @@ public: // But only for verilated*.cpp
|
|||||||
return "*UNKNOWN*";
|
return "*UNKNOWN*";
|
||||||
}
|
}
|
||||||
static void exportsDump() VL_MT_SAFE {
|
static void exportsDump() VL_MT_SAFE {
|
||||||
VerilatedLockGuard lock(s_s.m_exportMutex);
|
const VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (ExportNameMap::const_iterator it = s_s.m_exportMap.begin();
|
for (ExportNameMap::const_iterator it = s_s.m_exportMap.begin();
|
||||||
it != s_s.m_exportMap.end(); ++it) {
|
it != s_s.m_exportMap.end(); ++it) {
|
||||||
@@ -448,16 +471,29 @@ public: // But only for verilated*.cpp
|
|||||||
|
|
||||||
public: // But only for verilated*.cpp
|
public: // But only for verilated*.cpp
|
||||||
// METHODS - file IO
|
// 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;
|
if (VL_UNLIKELY(!fp)) return 0;
|
||||||
// Bit 31 indicates it's a descriptor not a MCD
|
// 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()) {
|
if (s_s.m_fdFree.empty()) {
|
||||||
// Need to create more space in m_fdps and m_fdFree
|
// Need to create more space in m_fdps and m_fdFree
|
||||||
size_t start = s_s.m_fdps.size();
|
const size_t start = std::max(31ul + 1ul + 3ul, s_s.m_fdps.size());
|
||||||
s_s.m_fdps.resize(start * 2);
|
const size_t excess = 10;
|
||||||
for (size_t i = start; i < start * 2; ++i) {
|
s_s.m_fdps.resize(start + excess);
|
||||||
s_s.m_fdFree.push_back(static_cast<IData>(i));
|
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();
|
IData idx = s_s.m_fdFree.back();
|
||||||
@@ -465,19 +501,83 @@ public: // But only for verilated*.cpp
|
|||||||
s_s.m_fdps[idx] = fp;
|
s_s.m_fdps[idx] = fp;
|
||||||
return (idx | (1UL << 31)); // bit 31 indicates not MCD
|
return (idx | (1UL << 31)); // bit 31 indicates not MCD
|
||||||
}
|
}
|
||||||
static void fdDelete(IData fdi) VL_MT_SAFE {
|
static void fdFlush(IData fdi) VL_MT_SAFE {
|
||||||
IData idx = VL_MASK_I(31) & fdi;
|
const VerilatedLockGuard lock(s_s.m_fdMutex);
|
||||||
VerilatedLockGuard lock(s_s.m_fdMutex);
|
const VerilatedFpList fdlist = fdToFpList(fdi);
|
||||||
if (VL_UNLIKELY(!(fdi & (VL_ULL(1) << 31)) || idx >= s_s.m_fdps.size())) return;
|
for (VerilatedFpList::const_iterator it = fdlist.begin(); it != fdlist.end(); ++it) {
|
||||||
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free
|
fflush(*it);
|
||||||
s_s.m_fdps[idx] = NULL;
|
}
|
||||||
s_s.m_fdFree.push_back(idx);
|
}
|
||||||
|
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 {
|
static inline FILE* fdToFp(IData fdi) VL_MT_SAFE {
|
||||||
IData idx = VL_MASK_I(31) & fdi;
|
const VerilatedLockGuard lock(s_s.m_fdMutex);
|
||||||
VerilatedLockGuard lock(s_s.m_fdMutex); // This might get slow, if it does we can cache it
|
const VerilatedFpList fdlist = fdToFpList(fdi);
|
||||||
if (VL_UNLIKELY(!(fdi & (VL_ULL(1) << 31)) || idx >= s_s.m_fdps.size())) return NULL;
|
if (VL_UNLIKELY(fdlist.size() != 1)) return NULL;
|
||||||
return s_s.m_fdps[idx];
|
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;
|
if (isOpen()) return;
|
||||||
VL_DEBUG_IF(VL_DBG_MSGF("- save: opening save file %s\n", filenamep););
|
VL_DEBUG_IF(VL_DBG_MSGF("- save: opening save file %s\n", filenamep););
|
||||||
|
|
||||||
if (filenamep[0] == '|') {
|
if (VL_UNCOVERABLE(filenamep[0] == '|')) {
|
||||||
assert(0); // Not supported yet.
|
assert(0); // LCOV_EXCL_LINE // Not supported yet.
|
||||||
} else {
|
} else {
|
||||||
// cppcheck-suppress duplicateExpression
|
// cppcheck-suppress duplicateExpression
|
||||||
m_fd = ::open(filenamep,
|
m_fd = ::open(filenamep,
|
||||||
@@ -146,8 +146,8 @@ void VerilatedRestore::open(const char* filenamep) VL_MT_UNSAFE_ONE {
|
|||||||
if (isOpen()) return;
|
if (isOpen()) return;
|
||||||
VL_DEBUG_IF(VL_DBG_MSGF("- restore: opening restore file %s\n", filenamep););
|
VL_DEBUG_IF(VL_DBG_MSGF("- restore: opening restore file %s\n", filenamep););
|
||||||
|
|
||||||
if (filenamep[0] == '|') {
|
if (VL_UNCOVERABLE(filenamep[0] == '|')) {
|
||||||
assert(0); // Not supported yet.
|
assert(0); // LCOV_EXCL_LINE // Not supported yet.
|
||||||
} else {
|
} else {
|
||||||
// cppcheck-suppress duplicateExpression
|
// cppcheck-suppress duplicateExpression
|
||||||
m_fd = ::open(filenamep, O_CREAT | O_RDONLY | O_LARGEFILE | O_CLOEXEC, 0666);
|
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);
|
ssize_t got = ::write(m_fd, wp, remaining);
|
||||||
if (got > 0) {
|
if (got > 0) {
|
||||||
wp += got;
|
wp += got;
|
||||||
} else if (got < 0) {
|
} else if (VL_UNCOVERABLE(got < 0)) {
|
||||||
if (errno != EAGAIN && errno != EINTR) {
|
if (VL_UNCOVERABLE(errno != EAGAIN && errno != EINTR)) {
|
||||||
|
// LCOV_EXCL_START
|
||||||
// write failed, presume error (perhaps out of disk space)
|
// write failed, presume error (perhaps out of disk space)
|
||||||
std::string msg = std::string(__FUNCTION__) + ": " + strerror(errno);
|
std::string msg = std::string(__FUNCTION__) + ": " + strerror(errno);
|
||||||
VL_FATAL_MT("", 0, "", msg.c_str());
|
VL_FATAL_MT("", 0, "", msg.c_str());
|
||||||
close();
|
close();
|
||||||
break;
|
break;
|
||||||
|
// LCOV_EXCL_STOP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -223,13 +225,15 @@ void VerilatedRestore::fill() VL_MT_UNSAFE_ONE {
|
|||||||
ssize_t got = ::read(m_fd, m_endp, remaining);
|
ssize_t got = ::read(m_fd, m_endp, remaining);
|
||||||
if (got > 0) {
|
if (got > 0) {
|
||||||
m_endp += got;
|
m_endp += got;
|
||||||
} else if (got < 0) {
|
} else if (VL_UNCOVERABLE(got < 0)) {
|
||||||
if (errno != EAGAIN && errno != EINTR) {
|
if (VL_UNCOVERABLE(errno != EAGAIN && errno != EINTR)) {
|
||||||
|
// LCOV_EXCL_START
|
||||||
// write failed, presume error (perhaps out of disk space)
|
// write failed, presume error (perhaps out of disk space)
|
||||||
std::string msg = std::string(__FUNCTION__) + ": " + strerror(errno);
|
std::string msg = std::string(__FUNCTION__) + ": " + strerror(errno);
|
||||||
VL_FATAL_MT("", 0, "", msg.c_str());
|
VL_FATAL_MT("", 0, "", msg.c_str());
|
||||||
close();
|
close();
|
||||||
break;
|
break;
|
||||||
|
// LCOV_EXCL_STOP
|
||||||
}
|
}
|
||||||
} else { // got==0, EOF
|
} else { // got==0, EOF
|
||||||
// Fill buffer from here to end with NULLs so reader's don't
|
// Fill buffer from here to end with NULLs so reader's don't
|
||||||
|
|||||||
@@ -29,6 +29,8 @@
|
|||||||
|
|
||||||
#include "verilatedos.h"
|
#include "verilatedos.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
/// Verilator range
|
/// Verilator range
|
||||||
/// Thread safety: Assume is constructed only with model, then any number of readers
|
/// 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_pdims; // Packed dimensions
|
||||||
const int m_udims; // Unpacked dimensions
|
const int m_udims; // Unpacked dimensions
|
||||||
VerilatedRange m_packed; // Packed array range
|
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
|
// CONSTRUCTORS
|
||||||
protected:
|
protected:
|
||||||
friend class VerilatedScope;
|
friend class VerilatedScope;
|
||||||
@@ -87,7 +96,9 @@ protected:
|
|||||||
, m_vltype(vltype)
|
, m_vltype(vltype)
|
||||||
, m_vlflags(vlflags)
|
, m_vlflags(vlflags)
|
||||||
, m_pdims(pdims)
|
, m_pdims(pdims)
|
||||||
, m_udims(udims) {}
|
, m_udims(udims) {
|
||||||
|
initUnpacked(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class Unpacked {};
|
class Unpacked {};
|
||||||
@@ -98,34 +109,13 @@ public:
|
|||||||
, m_vlflags(VerilatedVarFlags(vlflags))
|
, m_vlflags(VerilatedVarFlags(vlflags))
|
||||||
, m_pdims(0)
|
, m_pdims(0)
|
||||||
, m_udims(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_magic(MAGIC)
|
||||||
, m_vltype(vltype)
|
, m_vltype(vltype)
|
||||||
, m_vlflags(VerilatedVarFlags(vlflags))
|
, m_vlflags(VerilatedVarFlags(vlflags))
|
||||||
, m_pdims(0)
|
, m_pdims(0)
|
||||||
, m_udims(1) {
|
, m_udims(udims) {
|
||||||
m_unpacked[0].init(u0l, u0r);
|
initUnpacked(ulims);
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
// With packed
|
// With packed
|
||||||
class Packed {};
|
class Packed {};
|
||||||
@@ -137,37 +127,14 @@ public:
|
|||||||
, m_udims(0)
|
, m_udims(0)
|
||||||
, m_packed(pl, pr) {}
|
, m_packed(pl, pr) {}
|
||||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked,
|
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked,
|
||||||
int u0l, int u0r)
|
int udims, const int* ulims)
|
||||||
: m_magic(MAGIC)
|
: m_magic(MAGIC)
|
||||||
, m_vltype(vltype)
|
, m_vltype(vltype)
|
||||||
, m_vlflags(VerilatedVarFlags(vlflags))
|
, m_vlflags(VerilatedVarFlags(vlflags))
|
||||||
, m_pdims(1)
|
, m_pdims(1)
|
||||||
, m_udims(1)
|
, m_udims(udims)
|
||||||
, m_packed(pl, pr) {
|
, m_packed(pl, pr) {
|
||||||
m_unpacked[0].init(u0l, u0r);
|
initUnpacked(ulims);
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -189,27 +156,29 @@ public:
|
|||||||
// DPI accessors
|
// DPI accessors
|
||||||
int left(int dim) const {
|
int left(int dim) const {
|
||||||
return dim == 0 ? m_packed.left()
|
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 {
|
int right(int dim) const {
|
||||||
return dim == 0 ? m_packed.right()
|
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 {
|
int low(int dim) const {
|
||||||
return dim == 0 ? m_packed.low()
|
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 {
|
int high(int dim) const {
|
||||||
return dim == 0 ? m_packed.high()
|
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 {
|
int increment(int dim) const {
|
||||||
return dim == 0 ? m_packed.increment()
|
return dim == 0
|
||||||
: VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].increment() : 0;
|
? m_packed.increment()
|
||||||
|
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].increment() : 0;
|
||||||
}
|
}
|
||||||
int elements(int dim) const {
|
int elements(int dim) const {
|
||||||
return dim == 0 ? m_packed.elements()
|
return dim == 0
|
||||||
: VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].elements() : 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)
|
/// Total size in bytes (note DPI limited to 4GB)
|
||||||
size_t totalSize() const;
|
size_t totalSize() const;
|
||||||
|
|||||||
@@ -120,13 +120,13 @@ void VlThreadPool::setupProfilingClientThread() {
|
|||||||
// try not to malloc while collecting profiling.
|
// try not to malloc while collecting profiling.
|
||||||
t_profilep->reserve(4096);
|
t_profilep->reserve(4096);
|
||||||
{
|
{
|
||||||
VerilatedLockGuard lk(m_mutex);
|
const VerilatedLockGuard lk(m_mutex);
|
||||||
m_allProfiles.insert(t_profilep);
|
m_allProfiles.insert(t_profilep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VlThreadPool::profileAppendAll(const VlProfileRec& rec) {
|
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) {
|
for (ProfileSet::iterator it = m_allProfiles.begin(); it != m_allProfiles.end(); ++it) {
|
||||||
// Every thread's profile trace gets a copy of rec.
|
// Every thread's profile trace gets a copy of rec.
|
||||||
(*it)->emplace_back(rec);
|
(*it)->emplace_back(rec);
|
||||||
@@ -134,7 +134,7 @@ void VlThreadPool::profileAppendAll(const VlProfileRec& rec) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed) {
|
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););
|
VL_DEBUG_IF(VL_DBG_MSGF("+prof+threads writing to '%s'\n", filenamep););
|
||||||
|
|
||||||
FILE* fp = fopen(filenamep, "w");
|
FILE* fp = fopen(filenamep, "w");
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ public:
|
|||||||
inline void addTask(VlExecFnp fnp, bool evenCycle, VlThrSymTab sym) {
|
inline void addTask(VlExecFnp fnp, bool evenCycle, VlThrSymTab sym) {
|
||||||
bool notify;
|
bool notify;
|
||||||
{
|
{
|
||||||
VerilatedLockGuard lk(m_mutex);
|
const VerilatedLockGuard lk(m_mutex);
|
||||||
m_ready.emplace_back(fnp, evenCycle, sym);
|
m_ready.emplace_back(fnp, evenCycle, sym);
|
||||||
m_ready_size.fetch_add(1, std::memory_order_relaxed);
|
m_ready_size.fetch_add(1, std::memory_order_relaxed);
|
||||||
notify = m_waiting;
|
notify = m_waiting;
|
||||||
|
|||||||
+37
-27
@@ -40,7 +40,7 @@
|
|||||||
// Threaded tracing
|
// Threaded tracing
|
||||||
|
|
||||||
// A simple synchronized first in first out queue
|
// A simple synchronized first in first out queue
|
||||||
template <class T> class VerilatedThreadQueue {
|
template <class T> class VerilatedThreadQueue { // LCOV_EXCL_LINE // lcov bug
|
||||||
private:
|
private:
|
||||||
VerilatedMutex m_mutex; // Protects m_queue
|
VerilatedMutex m_mutex; // Protects m_queue
|
||||||
std::condition_variable_any m_cv;
|
std::condition_variable_any m_cv;
|
||||||
@@ -73,7 +73,7 @@ public:
|
|||||||
|
|
||||||
// Non blocking get
|
// Non blocking get
|
||||||
bool tryGet(T& result) {
|
bool tryGet(T& result) {
|
||||||
VerilatedLockGuard lockGuard(m_mutex);
|
const VerilatedLockGuard lockGuard(m_mutex);
|
||||||
if (m_queue.empty()) { return false; }
|
if (m_queue.empty()) { return false; }
|
||||||
result = m_queue.front();
|
result = m_queue.front();
|
||||||
m_queue.pop_front();
|
m_queue.pop_front();
|
||||||
@@ -95,7 +95,6 @@ public:
|
|||||||
CHG_IDATA = 0x4,
|
CHG_IDATA = 0x4,
|
||||||
CHG_QDATA = 0x5,
|
CHG_QDATA = 0x5,
|
||||||
CHG_WDATA = 0x6,
|
CHG_WDATA = 0x6,
|
||||||
CHG_FLOAT = 0x7,
|
|
||||||
CHG_DOUBLE = 0x8,
|
CHG_DOUBLE = 0x8,
|
||||||
// TODO: full..
|
// TODO: full..
|
||||||
TIME_CHANGE = 0xd,
|
TIME_CHANGE = 0xd,
|
||||||
@@ -105,8 +104,6 @@ public:
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class VerilatedTraceCallInfo;
|
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// VerilatedTrace
|
// VerilatedTrace
|
||||||
|
|
||||||
@@ -114,13 +111,38 @@ class VerilatedTraceCallInfo;
|
|||||||
// implementations in the format specific derived class, which must be passed
|
// implementations in the format specific derived class, which must be passed
|
||||||
// as the type parameter T_Derived
|
// as the type parameter T_Derived
|
||||||
template <class T_Derived> class VerilatedTrace {
|
template <class T_Derived> class VerilatedTrace {
|
||||||
private:
|
public:
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
// Generic tracing internals
|
// 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
|
vluint32_t* m_sigs_oldvalp; ///< Old value store
|
||||||
vluint64_t m_timeLastDump; ///< Last time we did a dump
|
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'
|
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_nextCode; ///< Next code number to assign
|
||||||
vluint32_t m_numSignals; ///< Number of distinct signals
|
vluint32_t m_numSignals; ///< Number of distinct signals
|
||||||
@@ -130,6 +152,8 @@ private:
|
|||||||
double m_timeRes; ///< Time resolution (ns/ms etc)
|
double m_timeRes; ///< Time resolution (ns/ms etc)
|
||||||
double m_timeUnit; ///< Time units (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()->'
|
// Equivalent to 'this' but is of the sub-type 'T_Derived*'. Use 'self()->'
|
||||||
// to access duck-typed functions to avoid a virtual function call.
|
// to access duck-typed functions to avoid a virtual function call.
|
||||||
T_Derived* self() { return static_cast<T_Derived*>(this); }
|
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.
|
// These hooks are called before a full or change based dump is produced.
|
||||||
// The return value indicates whether to proceed with the dump.
|
// The return value indicates whether to proceed with the dump.
|
||||||
virtual bool preFullDump() { return true; }
|
virtual bool preFullDump() = 0;
|
||||||
virtual bool preChangeDump() { return true; }
|
virtual bool preChangeDump() = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
@@ -232,13 +256,13 @@ public:
|
|||||||
//=========================================================================
|
//=========================================================================
|
||||||
// Non-hot path internal interface to Verilator generated code
|
// 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 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 {
|
void module(const std::string& name) VL_MT_UNSAFE_ONE {
|
||||||
m_assertOne.check();
|
m_assertOne.check();
|
||||||
m_moduleName = name;
|
m_moduleName = name;
|
||||||
@@ -261,7 +285,6 @@ public:
|
|||||||
// duck-typed void emitIData(vluint32_t code, IData newval, int bits) = 0;
|
// 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 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 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;
|
// duck-typed void emitDouble(vluint32_t code, double newval) = 0;
|
||||||
|
|
||||||
vluint32_t* oldp(vluint32_t code) { return m_sigs_oldvalp + code; }
|
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 fullIData(vluint32_t* oldp, IData newval, int bits);
|
||||||
void fullQData(vluint32_t* oldp, QData newval, int bits);
|
void fullQData(vluint32_t* oldp, QData newval, int bits);
|
||||||
void fullWData(vluint32_t* oldp, const WData* newvalp, 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);
|
void fullDouble(vluint32_t* oldp, double newval);
|
||||||
|
|
||||||
#ifdef VL_TRACE_THREADED
|
#ifdef VL_TRACE_THREADED
|
||||||
@@ -319,14 +341,6 @@ public:
|
|||||||
for (int i = 0; i < (bits + 31) / 32; ++i) { *m_traceBufferWritep++ = newvalp[i]; }
|
for (int i = 0; i < (bits + 31) / 32; ++i) { *m_traceBufferWritep++ = newvalp[i]; }
|
||||||
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp););
|
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) {
|
inline void chgDouble(vluint32_t code, double newval) {
|
||||||
m_traceBufferWritep[0] = VerilatedTraceCommand::CHG_DOUBLE;
|
m_traceBufferWritep[0] = VerilatedTraceCommand::CHG_DOUBLE;
|
||||||
m_traceBufferWritep[1] = code;
|
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) {
|
inline void CHG(Double)(vluint32_t* oldp, double newval) {
|
||||||
// cppcheck-suppress invalidPointerCast
|
// cppcheck-suppress invalidPointerCast
|
||||||
if (VL_UNLIKELY(*reinterpret_cast<double*>(oldp) != newval)) fullDouble(oldp, newval);
|
if (VL_UNLIKELY(*reinterpret_cast<double*>(oldp) != newval)) fullDouble(oldp, newval);
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
// Static utility functions
|
// Static utility functions
|
||||||
|
|
||||||
static double timescaleToDouble(const char* unitp) {
|
static double timescaleToDouble(const char* unitp) {
|
||||||
char* endp;
|
char* endp = NULL;
|
||||||
double value = strtod(unitp, &endp);
|
double value = strtod(unitp, &endp);
|
||||||
// On error so we allow just "ns" to return 1e-9.
|
// On error so we allow just "ns" to return 1e-9.
|
||||||
if (value == 0.0 && endp == unitp) value = 1;
|
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
|
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
|
#ifdef VL_TRACE_THREADED
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
// Buffer management
|
// Buffer management
|
||||||
@@ -196,11 +171,6 @@ template <> void VerilatedTrace<VL_DERIVED_T>::workerThreadMain() {
|
|||||||
chgWDataImpl(oldp, readp, top);
|
chgWDataImpl(oldp, readp, top);
|
||||||
readp += VL_WORDS_I(top);
|
readp += VL_WORDS_I(top);
|
||||||
continue;
|
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:
|
case VerilatedTraceCommand::CHG_DOUBLE:
|
||||||
VL_TRACE_THREAD_DEBUG("Command CHG_DOUBLE " << top);
|
VL_TRACE_THREAD_DEBUG("Command CHG_DOUBLE " << top);
|
||||||
chgDoubleImpl(oldp, *reinterpret_cast<const double*>(readp));
|
chgDoubleImpl(oldp, *reinterpret_cast<const double*>(readp));
|
||||||
@@ -224,13 +194,14 @@ template <> void VerilatedTrace<VL_DERIVED_T>::workerThreadMain() {
|
|||||||
shutdown = true;
|
shutdown = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//===
|
//===
|
||||||
// Unknown command
|
// Unknown command
|
||||||
default:
|
default: { // LCOV_EXCL_START
|
||||||
VL_TRACE_THREAD_DEBUG("Command UNKNOWN");
|
VL_TRACE_THREAD_DEBUG("Command UNKNOWN");
|
||||||
VL_PRINTF_MT("Trace command: 0x%08x\n", cmd);
|
VL_PRINTF_MT("Trace command: 0x%08x\n", cmd);
|
||||||
VL_FATAL_MT(__FILE__, __LINE__, "", "Unknown trace command");
|
VL_FATAL_MT(__FILE__, __LINE__, "", "Unknown trace command");
|
||||||
break;
|
break;
|
||||||
|
} // LCOV_EXCL_STOP
|
||||||
}
|
}
|
||||||
|
|
||||||
// The above switch will execute 'continue' when necessary,
|
// The above switch will execute 'continue' when necessary,
|
||||||
@@ -311,10 +282,6 @@ VerilatedTrace<VL_DERIVED_T>::VerilatedTrace()
|
|||||||
|
|
||||||
template <> 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);
|
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
|
#ifdef VL_TRACE_THREADED
|
||||||
close();
|
close();
|
||||||
#endif
|
#endif
|
||||||
@@ -334,11 +301,12 @@ template <> void VerilatedTrace<VL_DERIVED_T>::traceInit() VL_MT_UNSAFE {
|
|||||||
m_numSignals = 0;
|
m_numSignals = 0;
|
||||||
m_maxBits = 0;
|
m_maxBits = 0;
|
||||||
|
|
||||||
// Call all initialize callbacks, which will call decl* for each signal.
|
// Call all initialize callbacks, which will:
|
||||||
for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) {
|
// - Call decl* for each signal
|
||||||
VerilatedTraceCallInfo* cip = m_callbacks[ent];
|
// - Store the base code
|
||||||
cip->m_code = nextCode();
|
for (vluint32_t i = 0; i < m_initCbs.size(); ++i) {
|
||||||
(cip->m_initcb)(self(), cip->m_userthis, cip->m_code);
|
const CallbackRecord& cbr = m_initCbs[i];
|
||||||
|
cbr.m_initCb(cbr.m_userp, self(), nextCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expectedCodes && nextCode() != expectedCodes) {
|
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) {
|
template <> void VerilatedTrace<VL_DERIVED_T>::dump(vluint64_t timeui) {
|
||||||
m_assertOne.check();
|
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
|
VL_PRINTF_MT("%%Warning: previous dump at t=%" VL_PRI64 "u, requesting t=%" VL_PRI64
|
||||||
"u, dump call ignored\n",
|
"u, dump call ignored\n",
|
||||||
m_timeLastDump, timeui);
|
m_timeLastDump, timeui);
|
||||||
return;
|
return;
|
||||||
}
|
} // LCOV_EXCL_STOP
|
||||||
m_timeLastDump = timeui;
|
m_timeLastDump = timeui;
|
||||||
|
|
||||||
Verilated::quiesce();
|
Verilated::quiesce();
|
||||||
@@ -452,17 +420,22 @@ template <> void VerilatedTrace<VL_DERIVED_T>::dump(vluint64_t timeui) {
|
|||||||
// Run the callbacks
|
// Run the callbacks
|
||||||
if (VL_UNLIKELY(m_fullDump)) {
|
if (VL_UNLIKELY(m_fullDump)) {
|
||||||
m_fullDump = false; // No more need for next dump to be full
|
m_fullDump = false; // No more need for next dump to be full
|
||||||
for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) {
|
for (vluint32_t i = 0; i < m_fullCbs.size(); ++i) {
|
||||||
VerilatedTraceCallInfo* cip = m_callbacks[ent];
|
const CallbackRecord& cbr = m_fullCbs[i];
|
||||||
(cip->m_fullcb)(self(), cip->m_userthis, cip->m_code);
|
cbr.m_dumpCb(cbr.m_userp, self());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) {
|
for (vluint32_t i = 0; i < m_chgCbs.size(); ++i) {
|
||||||
VerilatedTraceCallInfo* cip = m_callbacks[ent];
|
const CallbackRecord& cbr = m_chgCbs[i];
|
||||||
(cip->m_changecb)(self(), cip->m_userthis, cip->m_code);
|
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
|
#ifdef VL_TRACE_THREADED
|
||||||
if (VL_LIKELY(bufferp)) {
|
if (VL_LIKELY(bufferp)) {
|
||||||
// Mark end of the trace buffer we just filled
|
// 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
|
// Non-hot path internal interface to Verilator generated code
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void VerilatedTrace<VL_DERIVED_T>::addCallback(callback_t initcb, callback_t fullcb,
|
void VerilatedTrace<VL_DERIVED_T>::addCallbackRecord(std::vector<CallbackRecord>& cbVec,
|
||||||
callback_t changecb,
|
CallbackRecord& cbRec) {
|
||||||
void* userthis) VL_MT_UNSAFE_ONE {
|
|
||||||
m_assertOne.check();
|
m_assertOne.check();
|
||||||
if (VL_UNLIKELY(timeLastDump() != 0)) {
|
if (VL_UNCOVERABLE(timeLastDump() != 0)) { // LCOV_EXCL_START
|
||||||
std::string msg = (std::string("Internal: ") + __FILE__ + "::" + __FUNCTION__
|
std::string msg = (std::string("Internal: ") + __FILE__ + "::" + __FUNCTION__
|
||||||
+ " called with already open file");
|
+ " called with already open file");
|
||||||
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
|
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
|
||||||
}
|
} // LCOV_EXCL_STOP
|
||||||
VerilatedTraceCallInfo* cip = new VerilatedTraceCallInfo(initcb, fullcb, changecb, userthis);
|
cbVec.push_back(cbRec);
|
||||||
m_callbacks.push_back(cip);
|
}
|
||||||
|
|
||||||
|
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);
|
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) {
|
template <> void VerilatedTrace<VL_DERIVED_T>::fullDouble(vluint32_t* oldp, double newval) {
|
||||||
// cppcheck-suppress invalidPointerCast
|
// cppcheck-suppress invalidPointerCast
|
||||||
*reinterpret_cast<double*>(oldp) = newval;
|
*reinterpret_cast<double*>(oldp) = newval;
|
||||||
|
|||||||
@@ -31,8 +31,8 @@
|
|||||||
//
|
//
|
||||||
//*************************************************************************
|
//*************************************************************************
|
||||||
|
|
||||||
#ifndef _V3_UNORDERED_SET_MAP_H_
|
#ifndef _VERILATED_UNORDERED_SET_MAP_H_
|
||||||
#define _V3_UNORDERED_SET_MAP_H_
|
#define _VERILATED_UNORDERED_SET_MAP_H_
|
||||||
|
|
||||||
#include "verilatedos.h"
|
#include "verilatedos.h"
|
||||||
|
|
||||||
@@ -55,6 +55,12 @@ inline size_t vl_hash_bytes(const void* vbufp, size_t nbytes) {
|
|||||||
return hash;
|
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 {
|
template <> inline size_t vl_hash<unsigned int>::operator()(const unsigned int& k) const {
|
||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
@@ -225,8 +231,7 @@ public:
|
|||||||
return end();
|
return end();
|
||||||
}
|
}
|
||||||
const_iterator end() const {
|
const_iterator end() const {
|
||||||
return iterator(VL_ULL(0xFFFFFFFFFFFFFFFF), const_cast<Bucket&>(m_emptyBucket).begin(),
|
return iterator(0xFFFFFFFFFFFFFFFFULL, const_cast<Bucket&>(m_emptyBucket).begin(), this);
|
||||||
this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const { return m_numElements == 0; }
|
bool empty() const { return m_numElements == 0; }
|
||||||
@@ -249,8 +254,7 @@ public:
|
|||||||
// function further. This permits the use of very fast client
|
// function further. This permits the use of very fast client
|
||||||
// hash funcs (like just returning the int or pointer value as
|
// hash funcs (like just returning the int or pointer value as
|
||||||
// is!) and tolerates crappy client hash functions pretty well.
|
// is!) and tolerates crappy client hash functions pretty well.
|
||||||
size_t mult
|
size_t mult = hashVal * ((sizeof(size_t) == 8) ? 11400714819323198485ULL : 2654435769lu);
|
||||||
= hashVal * ((sizeof(size_t) == 8) ? VL_ULL(11400714819323198485) : 2654435769lu);
|
|
||||||
size_t result = (mult >> (((sizeof(size_t) == 8) ? 64 : 32) - log2Buckets));
|
size_t result = (mult >> (((sizeof(size_t) == 8) ? 64 : 32) - log2Buckets));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -339,7 +343,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t numBuckets() const { return (VL_ULL(1) << m_log2Buckets); }
|
size_t numBuckets() const { return (1ULL << m_log2Buckets); }
|
||||||
|
|
||||||
Bucket* getBucket(size_t idx) {
|
Bucket* getBucket(size_t idx) {
|
||||||
initBuckets();
|
initBuckets();
|
||||||
@@ -372,7 +376,7 @@ private:
|
|||||||
new_log2Buckets = m_log2Buckets - 2;
|
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];
|
Bucket* new_bucketsp = new Bucket[new_num_buckets];
|
||||||
|
|
||||||
for (size_t i = 0; i < numBuckets(); i++) {
|
for (size_t i = 0; i < numBuckets(); i++) {
|
||||||
|
|||||||
+64
-92
@@ -27,7 +27,6 @@
|
|||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
|
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
|
||||||
# include <io.h>
|
# include <io.h>
|
||||||
@@ -35,8 +34,6 @@
|
|||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "verilated_intrinsics.h"
|
|
||||||
|
|
||||||
// SPDIFF_ON
|
// SPDIFF_ON
|
||||||
|
|
||||||
#ifndef O_LARGEFILE // For example on WIN32
|
#ifndef O_LARGEFILE // For example on WIN32
|
||||||
@@ -88,11 +85,11 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
static void pushVcd(VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
|
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);
|
singleton().s_vcdVecp.push_back(vcdp);
|
||||||
}
|
}
|
||||||
static void removeVcd(const VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
|
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
|
VcdVec::iterator pos
|
||||||
= find(singleton().s_vcdVecp.begin(), singleton().s_vcdVecp.end(), vcdp);
|
= find(singleton().s_vcdVecp.begin(), singleton().s_vcdVecp.end(), vcdp);
|
||||||
if (pos != singleton().s_vcdVecp.end()) { singleton().s_vcdVecp.erase(pos); }
|
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
|
// Thread safety: Although this function is protected by a mutex so
|
||||||
// perhaps in the future we can allow tracing in separate threads,
|
// perhaps in the future we can allow tracing in separate threads,
|
||||||
// vcdp->flush() assumes call from single thread
|
// 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();
|
for (VcdVec::const_iterator it = singleton().s_vcdVecp.begin();
|
||||||
it != singleton().s_vcdVecp.end(); ++it) {
|
it != singleton().s_vcdVecp.end(); ++it) {
|
||||||
VerilatedVcd* vcdp = *it;
|
VerilatedVcd* vcdp = *it;
|
||||||
@@ -203,8 +200,8 @@ void VerilatedVcd::openNext(bool incFilename) {
|
|||||||
}
|
}
|
||||||
m_filename = name;
|
m_filename = name;
|
||||||
}
|
}
|
||||||
if (m_filename[0] == '|') {
|
if (VL_UNCOVERABLE(m_filename[0] == '|')) {
|
||||||
assert(0); // Not supported yet.
|
assert(0); // LCOV_EXCL_LINE // Not supported yet.
|
||||||
} else {
|
} else {
|
||||||
// cppcheck-suppress duplicateExpression
|
// cppcheck-suppress duplicateExpression
|
||||||
if (!m_filep->open(m_filename)) {
|
if (!m_filep->open(m_filename)) {
|
||||||
@@ -358,13 +355,15 @@ void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE {
|
|||||||
if (got > 0) {
|
if (got > 0) {
|
||||||
wp += got;
|
wp += got;
|
||||||
m_wroteBytes += got;
|
m_wroteBytes += got;
|
||||||
} else if (got < 0) {
|
} else if (VL_UNCOVERABLE(got < 0)) {
|
||||||
if (errno != EAGAIN && errno != EINTR) {
|
if (VL_UNCOVERABLE(errno != EAGAIN && errno != EINTR)) {
|
||||||
|
// LCOV_EXCL_START
|
||||||
// write failed, presume error (perhaps out of disk space)
|
// write failed, presume error (perhaps out of disk space)
|
||||||
std::string msg = std::string("VerilatedVcd::bufferFlush: ") + strerror(errno);
|
std::string msg = std::string("VerilatedVcd::bufferFlush: ") + strerror(errno);
|
||||||
VL_FATAL_MT("", 0, "", msg.c_str());
|
VL_FATAL_MT("", 0, "", msg.c_str());
|
||||||
closeErr();
|
closeErr();
|
||||||
break;
|
break;
|
||||||
|
// LCOV_EXCL_STOP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -583,9 +582,6 @@ void VerilatedVcd::declArray(vluint32_t code, const char* name, bool array, int
|
|||||||
int lsb) {
|
int lsb) {
|
||||||
declare(code, name, "wire", array, arraynum, false, true, msb, 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) {
|
void VerilatedVcd::declDouble(vluint32_t code, const char* name, bool array, int arraynum) {
|
||||||
declare(code, name, "real", array, arraynum, false, false, 63, 0);
|
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);
|
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
|
VL_ATTR_ALWINLINE
|
||||||
void VerilatedVcd::emitDouble(vluint32_t code, double newval) {
|
void VerilatedVcd::emitDouble(vluint32_t code, double newval) {
|
||||||
char* wp = m_writep;
|
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;
|
(*(reinterpret_cast<vluint64_t*>(oldp(code)))) = newval;
|
||||||
*m_writep++ = 'b';
|
*m_writep++ = 'b';
|
||||||
for (int bit = bits - 1; bit >= 0; --bit) {
|
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++ = ' ';
|
||||||
m_writep = writeCode(m_writep, code);
|
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]; }
|
for (int word = 0; word < (((bits - 1) / 64) + 1); ++word) { oldp(code)[word] = newval[word]; }
|
||||||
*m_writep++ = 'b';
|
*m_writep++ = 'b';
|
||||||
for (int bit = bits - 1; bit >= 0; --bit) {
|
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++ = ' ';
|
||||||
m_writep = writeCode(m_writep, code);
|
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';
|
*m_writep++ = '\n';
|
||||||
bufferCheck();
|
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) {
|
int bits) {
|
||||||
(*(reinterpret_cast<vluint64_t*>(oldp(code)))) = newval;
|
(*(reinterpret_cast<vluint64_t*>(oldp(code)))) = newval;
|
||||||
(*(reinterpret_cast<vluint64_t*>(oldp(code + 1)))) = newtri;
|
(*(reinterpret_cast<vluint64_t*>(oldp(code + 1)))) = newtri;
|
||||||
*m_writep++ = 'b';
|
*m_writep++ = 'b';
|
||||||
for (int bit = bits - 1; bit >= 0; --bit) {
|
for (int bit = bits - 1; bit >= 0; --bit) {
|
||||||
*m_writep++
|
*m_writep++ = "01zz"[((newval >> bit) & 1ULL) | (((newtri >> bit) & 1ULL) << 1ULL)];
|
||||||
= "01zz"[((newval >> bit) & VL_ULL(1)) | (((newtri >> bit) & VL_ULL(1)) << VL_ULL(1))];
|
|
||||||
}
|
}
|
||||||
*m_writep++ = ' ';
|
*m_writep++ = ' ';
|
||||||
m_writep = writeCode(m_writep, code);
|
m_writep = writeCode(m_writep, code);
|
||||||
@@ -834,33 +820,6 @@ void VerilatedVcd::fullDouble(vluint32_t code, const double newval) {
|
|||||||
*m_writep++ = '\n';
|
*m_writep++ = '\n';
|
||||||
bufferCheck();
|
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
|
#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
|
#ifdef VERILATED_VCD_TEST
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
@@ -882,34 +839,39 @@ vluint32_t v1, v2, s1, s2[3];
|
|||||||
vluint32_t tri96[3];
|
vluint32_t tri96[3];
|
||||||
vluint32_t tri96__tri[3];
|
vluint32_t tri96__tri[3];
|
||||||
vluint64_t quad96[2];
|
vluint64_t quad96[2];
|
||||||
|
vluint64_t tquad;
|
||||||
|
vluint64_t tquad__tri;
|
||||||
vluint8_t ch;
|
vluint8_t ch;
|
||||||
vluint64_t timestamp = 1;
|
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->scopeEscape('.');
|
||||||
vcdp->module("top");
|
vcdp->module("top");
|
||||||
vcdp->declBus(0x2, "v1",-1,5,1);
|
/**/ vcdp->declBus(0x2, "v1", -1, 0, 5, 1);
|
||||||
vcdp->declBus(0x3, "v2",-1,6,0);
|
/**/ vcdp->declBus(0x3, "v2", -1, 0, 6, 1);
|
||||||
vcdp->module("top.sub1");
|
/**/ vcdp->module("top.sub1");
|
||||||
vcdp->declBit(0x4, "s1",-1);
|
/***/ vcdp->declBit(0x4, "s1", -1, 0);
|
||||||
vcdp->declBit(0x5, "ch",-1);
|
/***/ vcdp->declBit(0x5, "ch", -1, 0);
|
||||||
vcdp->module("top.sub2");
|
/**/ vcdp->module("top.sub2");
|
||||||
vcdp->declArray(0x6, "s2",-1, 40,3);
|
/***/ vcdp->declArray(0x6, "s2", -1, 0, 40, 3);
|
||||||
// Note need to add 3 for next code.
|
// Note need to add 3 for next code.
|
||||||
vcdp->module("top2");
|
vcdp->module("top2");
|
||||||
vcdp->declBus(0x2, "t2v1",-1,4,1);
|
/**/ vcdp->declBus(0x2, "t2v1", -1, 0, 4, 1);
|
||||||
vcdp->declTriBit(0x10, "io1",-1);
|
/**/ vcdp->declTriBit(0x10, "io1", -1, 0);
|
||||||
vcdp->declTriBus(0x12, "io5",-1,4,0);
|
/**/ vcdp->declTriBus(0x12, "io5", -1, 0, 4, 0);
|
||||||
vcdp->declTriArray(0x16, "io96",-1,95,0);
|
/**/ vcdp->declTriArray(0x16, "io96", -1, 0, 95, 0);
|
||||||
// Note need to add 6 for next code.
|
/**/ // Note need to add 6 for next code.
|
||||||
vcdp->declDouble(0x1c, "doub",-1);
|
/**/ vcdp->declDouble(0x1c, "doub", -1, 0);
|
||||||
// Note need to add 2 for next code.
|
/**/ // Note need to add 2 for next code.
|
||||||
vcdp->declArray(0x1e, "q2",-1,95,0);
|
/**/ vcdp->declArray(0x20, "q2", -1, 0, 95, 0);
|
||||||
// Note need to add 4 for next code.
|
/**/ // 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(0x2, v1, 5);
|
||||||
vcdp->fullBus(0x3, v2, 7);
|
vcdp->fullBus(0x3, v2, 7);
|
||||||
vcdp->fullBit(0x4, s1);
|
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->fullTriBus(0x12, tri96[0] & 0x1f, tri96__tri[0] & 0x1f, 5);
|
||||||
vcdp->fullTriArray(0x16, tri96, tri96__tri, 96);
|
vcdp->fullTriArray(0x16, tri96, tri96__tri, 96);
|
||||||
vcdp->fullDouble(0x1c, doub);
|
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(0x2, v1, 5);
|
||||||
vcdp->chgBus(0x3, v2, 7);
|
vcdp->chgBus(0x3, v2, 7);
|
||||||
vcdp->chgBit(0x4, s1);
|
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->chgTriBus(0x12, tri96[0] & 0x1f, tri96__tri[0] & 0x1f, 5);
|
||||||
vcdp->chgTriArray(0x16, tri96, tri96__tri, 96);
|
vcdp->chgTriArray(0x16, tri96, tri96__tri, 96);
|
||||||
vcdp->chgDouble(0x1c, doub);
|
vcdp->chgDouble(0x1c, doub);
|
||||||
vcdp->chgArray(0x1e, &quad96[0], 96);
|
vcdp->chgArray(0x20, &quad96[0], 96);
|
||||||
|
vcdp->chgTriQuad(0x24, tquad, tquad__tri, 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
// clang-format off
|
||||||
std::cout << "test: O_LARGEFILE=" << O_LARGEFILE << std::endl;
|
void vcdTestMain(const char* filenamep) {
|
||||||
|
|
||||||
v1 = v2 = s1 = 0;
|
v1 = v2 = s1 = 0;
|
||||||
s2[0] = s2[1] = s2[2] = 0;
|
s2[0] = s2[1] = s2[2] = 0;
|
||||||
tri96[2] = tri96[1] = tri96[0] = 0;
|
tri96[2] = tri96[1] = tri96[0] = 0;
|
||||||
@@ -945,43 +908,52 @@ main() {
|
|||||||
quad96[1] = quad96[0] = 0;
|
quad96[1] = quad96[0] = 0;
|
||||||
ch = 0;
|
ch = 0;
|
||||||
doub = 0;
|
doub = 0;
|
||||||
|
tquad = tquad__tri = 0;
|
||||||
{
|
{
|
||||||
VerilatedVcdC* vcdp = new VerilatedVcdC;
|
VerilatedVcdC* vcdp = new VerilatedVcdC;
|
||||||
vcdp->spTrace()->addCallback(&vcdInit, &vcdFull, &vcdChange, 0);
|
vcdp->evcd(true);
|
||||||
vcdp->open("test.vcd");
|
vcdp->spTrace()->addInitCb(&vcdInit, 0);
|
||||||
|
vcdp->spTrace()->addFullCb(&vcdFull, 0);
|
||||||
|
vcdp->spTrace()->addChgCb(&vcdChange, 0);
|
||||||
|
vcdp->open(filenamep);
|
||||||
// Dumping
|
// Dumping
|
||||||
vcdp->dump(timestamp++);
|
vcdp->dump(++timestamp);
|
||||||
v1 = 0xfff;
|
v1 = 0xfff;
|
||||||
tri96[2] = 4; tri96[1] = 2; tri96[0] = 1;
|
tri96[2] = 4; tri96[1] = 2; tri96[0] = 1;
|
||||||
tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = ~0; // Still tri
|
tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = ~0; // Still tri
|
||||||
quad96[1] = 0xffffffff; quad96[0] = 0;
|
quad96[1] = 0xffffffff; quad96[0] = 0;
|
||||||
doub = 1.5;
|
doub = 1.5;
|
||||||
vcdp->dump(timestamp++);
|
flo = 1.4f;
|
||||||
|
vcdp->dump(++timestamp);
|
||||||
v2 = 0x1;
|
v2 = 0x1;
|
||||||
s2[1] = 2;
|
s2[1] = 2;
|
||||||
tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = 0; // enable w/o data change
|
tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = 0; // enable w/o data change
|
||||||
quad96[1] = 0; quad96[0] = ~0;
|
quad96[1] = 0; quad96[0] = ~0;
|
||||||
doub = -1.66e13;
|
doub = -1.66e13;
|
||||||
vcdp->dump(timestamp++);
|
flo = 0.123f;
|
||||||
|
tquad = 0x00ff00ff00ff00ffULL;
|
||||||
|
tquad__tri = 0x0000fffff0000ffffULL;
|
||||||
|
vcdp->dump(++timestamp);
|
||||||
ch = 2;
|
ch = 2;
|
||||||
tri96[2] = ~4; tri96[1] = ~2; tri96[0] = ~1;
|
tri96[2] = ~4; tri96[1] = ~2; tri96[0] = ~1;
|
||||||
doub = -3.33e-13;
|
doub = -3.33e-13;
|
||||||
vcdp->dump(timestamp++);
|
vcdp->dump(++timestamp);
|
||||||
vcdp->dump(timestamp++);
|
vcdp->dump(++timestamp);
|
||||||
# ifdef VERILATED_VCD_TEST_64BIT
|
# ifdef VERILATED_VCD_TEST_64BIT
|
||||||
vluint64_t bytesPerDump = VL_ULL(15);
|
vluint64_t bytesPerDump = 15ULL;
|
||||||
for (vluint64_t i = 0; i < ((VL_ULL(1) << 32) / bytesPerDump); i++) {
|
for (vluint64_t i = 0; i < ((1ULL << 32) / bytesPerDump); i++) {
|
||||||
v1 = i;
|
v1 = i;
|
||||||
vcdp->dump(timestamp++);
|
vcdp->dump(++timestamp);
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
vcdp->close();
|
vcdp->close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#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:
|
// Local Variables:
|
||||||
// End:
|
// End:
|
||||||
|
|||||||
+14
-27
@@ -130,7 +130,6 @@ protected:
|
|||||||
inline void emitIData(vluint32_t code, IData newval, int bits);
|
inline void emitIData(vluint32_t code, IData newval, int bits);
|
||||||
inline void emitQData(vluint32_t code, QData 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 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);
|
inline void emitDouble(vluint32_t code, double newval);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -163,7 +162,6 @@ public:
|
|||||||
void declBus(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
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 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 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);
|
void declDouble(vluint32_t code, const char* name, bool array, int arraynum);
|
||||||
|
|
||||||
#ifdef VL_TRACE_VCD_OLD_API
|
#ifdef VL_TRACE_VCD_OLD_API
|
||||||
@@ -195,7 +193,6 @@ public:
|
|||||||
void fullWData(vluint32_t* oldp, const WData* newvalp, int bits) {
|
void fullWData(vluint32_t* oldp, const WData* newvalp, int bits) {
|
||||||
fullArray(oldp - this->oldp(0), newvalp, 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); }
|
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); }
|
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) {
|
inline void chgWData(vluint32_t* oldp, const WData* newvalp, int bits) {
|
||||||
chgArray(oldp - this->oldp(0), newvalp, 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) {
|
inline void chgDouble(vluint32_t* oldp, double newval) {
|
||||||
chgDouble(oldp - this->oldp(0), newval);
|
chgDouble(oldp - this->oldp(0), newval);
|
||||||
}
|
}
|
||||||
@@ -230,20 +224,10 @@ public:
|
|||||||
void fullArray(vluint32_t code, const vluint64_t* newvalp, int bits);
|
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 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 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,
|
void fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip,
|
||||||
int bits);
|
int bits);
|
||||||
void fullDouble(vluint32_t code, const double newval);
|
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.
|
/// 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.
|
/// 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) {
|
inline void chgQuad(vluint32_t code, const vluint64_t newval, int bits) {
|
||||||
vluint64_t diff = (*(reinterpret_cast<vluint64_t*>(oldp(code)))) ^ newval;
|
vluint64_t diff = (*(reinterpret_cast<vluint64_t*>(oldp(code)))) ^ newval;
|
||||||
if (VL_UNLIKELY(diff)) {
|
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);
|
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) {
|
int bits) {
|
||||||
vluint64_t diff = (((*(reinterpret_cast<vluint64_t*>(oldp(code)))) ^ newval)
|
vluint64_t diff = (((*(reinterpret_cast<vluint64_t*>(oldp(code)))) ^ newval)
|
||||||
| ((*(reinterpret_cast<vluint64_t*>(oldp(code + 1)))) ^ newtri));
|
| ((*(reinterpret_cast<vluint64_t*>(oldp(code + 1)))) ^ newtri));
|
||||||
if (VL_UNLIKELY(diff)) {
|
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);
|
fullTriQuad(code, newval, newtri, bits);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -329,15 +313,9 @@ public:
|
|||||||
fullDouble(code, newval);
|
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
|
// METHODS
|
||||||
|
// Old/standalone API only
|
||||||
void evcd(bool flag) { m_evcd = flag; }
|
void evcd(bool flag) { m_evcd = flag; }
|
||||||
#endif // VL_TRACE_VCD_OLD_API
|
#endif // VL_TRACE_VCD_OLD_API
|
||||||
};
|
};
|
||||||
@@ -405,6 +383,15 @@ public:
|
|||||||
|
|
||||||
/// Internal class access
|
/// Internal class access
|
||||||
inline VerilatedVcd* spTrace() { return &m_sptrace; }
|
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
|
#endif // guard
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ private:
|
|||||||
virtual void set_time_unit(int exponent10_seconds) {} // deprecated
|
virtual void set_time_unit(int exponent10_seconds) {} // deprecated
|
||||||
#endif
|
#endif
|
||||||
#if defined(NC_SYSTEMC) || (SYSTEMC_VERSION >= 20111100)
|
#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
|
#endif
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
+45
-29
@@ -30,7 +30,6 @@
|
|||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// Internal constants
|
// Internal constants
|
||||||
@@ -50,7 +49,7 @@
|
|||||||
|
|
||||||
// Not supported yet
|
// Not supported yet
|
||||||
#define _VL_VPI_UNIMP() \
|
#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
|
// Implementation
|
||||||
@@ -136,7 +135,7 @@ public:
|
|||||||
static inline VerilatedVpioConst* castp(vpiHandle h) {
|
static inline VerilatedVpioConst* castp(vpiHandle h) {
|
||||||
return dynamic_cast<VerilatedVpioConst*>(reinterpret_cast<VerilatedVpio*>(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; }
|
vlsint32_t num() const { return m_num; }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -377,8 +376,8 @@ struct VerilatedVpiTimedCbsCmp {
|
|||||||
/// Ordering sets keyed by time, then callback descriptor
|
/// Ordering sets keyed by time, then callback descriptor
|
||||||
bool operator()(const std::pair<QData, VerilatedVpioCb*>& a,
|
bool operator()(const std::pair<QData, VerilatedVpioCb*>& a,
|
||||||
const std::pair<QData, VerilatedVpioCb*>& b) const {
|
const std::pair<QData, VerilatedVpioCb*>& b) const {
|
||||||
if (a.first < b.first) return 1;
|
if (a.first < b.first) return true;
|
||||||
if (a.first > b.first) return 0;
|
if (a.first > b.first) return false;
|
||||||
return a.second < b.second;
|
return a.second < b.second;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -450,7 +449,7 @@ public:
|
|||||||
static QData cbNextDeadline() {
|
static QData cbNextDeadline() {
|
||||||
VpioTimedCbs::const_iterator it = s_s.m_timedCbs.begin();
|
VpioTimedCbs::const_iterator it = s_s.m_timedCbs.begin();
|
||||||
if (VL_LIKELY(it != s_s.m_timedCbs.end())) return it->first;
|
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 {
|
static bool callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE {
|
||||||
VpioCbList& cbObjList = s_s.m_cbObjLists[reason];
|
VpioCbList& cbObjList = s_s.m_cbObjLists[reason];
|
||||||
@@ -624,7 +623,7 @@ const char* VerilatedVpiError::strFromVpiVal(PLI_INT32 vpiVal) VL_MT_SAFE {
|
|||||||
"vpiRawFourStateVal",
|
"vpiRawFourStateVal",
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
if (vpiVal < 0) return names[0];
|
if (VL_UNCOVERABLE(vpiVal < 0)) return names[0];
|
||||||
return names[(vpiVal <= vpiRawFourStateVal) ? vpiVal : 0];
|
return names[(vpiVal <= vpiRawFourStateVal) ? vpiVal : 0];
|
||||||
}
|
}
|
||||||
const char* VerilatedVpiError::strFromVpiObjType(PLI_INT32 vpiVal) VL_MT_SAFE {
|
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"
|
"vpiGenVar"
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
if (vpiVal < 0) return names[0];
|
if (VL_UNCOVERABLE(vpiVal < 0)) return names[0];
|
||||||
return names[(vpiVal <= vpiGenVar) ? vpiVal : 0];
|
return names[(vpiVal <= vpiGenVar) ? vpiVal : 0];
|
||||||
}
|
}
|
||||||
const char* VerilatedVpiError::strFromVpiMethod(PLI_INT32 vpiVal) VL_MT_SAFE {
|
const char* VerilatedVpiError::strFromVpiMethod(PLI_INT32 vpiVal) VL_MT_SAFE {
|
||||||
@@ -851,7 +850,7 @@ const char* VerilatedVpiError::strFromVpiCallbackReason(PLI_INT32 vpiVal) VL_MT_
|
|||||||
"cbAtEndOfSimTime"
|
"cbAtEndOfSimTime"
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
if (vpiVal < 0) return names[0];
|
if (VL_UNCOVERABLE(vpiVal < 0)) return names[0];
|
||||||
return names[(vpiVal <= cbAtEndOfSimTime) ? vpiVal : 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) \
|
#define CHECK_RESULT_CSTR(got, exp) \
|
||||||
if (strcmp((got), (exp))) { \
|
if (0 != strcmp((got), (exp))) { \
|
||||||
std::string msg \
|
std::string msg \
|
||||||
= std::string("%Error: ") + "GOT = '" + got + "'" + " EXP = '" + exp + "'"; \
|
= std::string("%Error: ") + "GOT = '" + got + "'" + " EXP = '" + exp + "'"; \
|
||||||
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str()); \
|
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,
|
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported callback type %s", VL_FUNC,
|
||||||
VerilatedVpiError::strFromVpiCallbackReason(cb_data_p->reason));
|
VerilatedVpiError::strFromVpiCallbackReason(cb_data_p->reason));
|
||||||
return NULL;
|
return NULL;
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PLI_INT32 vpi_remove_cb(vpiHandle object) {
|
PLI_INT32 vpi_remove_cb(vpiHandle object) {
|
||||||
@@ -1135,16 +1134,30 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
|
|||||||
_VL_VPI_ERROR_RESET();
|
_VL_VPI_ERROR_RESET();
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case vpiLeftRange: {
|
case vpiLeftRange: {
|
||||||
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
|
||||||
if (VL_UNLIKELY(!vop)) return 0;
|
if (VL_UNLIKELY(!vop->rangep())) return 0;
|
||||||
if (VL_UNLIKELY(!vop->rangep())) return 0;
|
return (new VerilatedVpioConst(vop->rangep()->left()))->castVpiHandle();
|
||||||
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: {
|
case vpiRightRange: {
|
||||||
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
|
||||||
if (VL_UNLIKELY(!vop)) return 0;
|
if (VL_UNLIKELY(!vop->rangep())) return 0;
|
||||||
if (VL_UNLIKELY(!vop->rangep())) return 0;
|
return (new VerilatedVpioConst(vop->rangep()->right()))->castVpiHandle();
|
||||||
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: {
|
case vpiIndex: {
|
||||||
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
||||||
@@ -1361,7 +1374,7 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
|
|||||||
}
|
}
|
||||||
case VLVT_UINT64: {
|
case VLVT_UINT64: {
|
||||||
QData data = *(reinterpret_cast<QData*>(vop->varDatap()));
|
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[1].bval = 0;
|
||||||
out[0].aval = static_cast<IData>(data);
|
out[0].aval = static_cast<IData>(data);
|
||||||
out[0].bval = 0;
|
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());
|
VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
||||||
return;
|
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*/,
|
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) {
|
void vpi_get_time(vpiHandle object, p_vpi_time time_p) {
|
||||||
VerilatedVpiImp::assertOneCheck();
|
VerilatedVpiImp::assertOneCheck();
|
||||||
|
_VL_VPI_ERROR_RESET();
|
||||||
// cppcheck-suppress nullPointer
|
// cppcheck-suppress nullPointer
|
||||||
if (VL_UNLIKELY(!time_p)) {
|
if (VL_UNLIKELY(!time_p)) {
|
||||||
_VL_VPI_WARNING(__FILE__, __LINE__, "Ignoring vpi_get_time with NULL value pointer");
|
_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) {
|
PLI_UINT32 vpi_mcd_open(PLI_BYTE8* filenamep) {
|
||||||
VerilatedVpiImp::assertOneCheck();
|
VerilatedVpiImp::assertOneCheck();
|
||||||
_VL_VPI_ERROR_RESET();
|
_VL_VPI_ERROR_RESET();
|
||||||
return VL_FOPEN_S(filenamep, "wb");
|
return VL_FOPEN_NN(filenamep, "wb");
|
||||||
}
|
}
|
||||||
|
|
||||||
PLI_UINT32 vpi_mcd_close(PLI_UINT32 mcd) {
|
PLI_UINT32 vpi_mcd_close(PLI_UINT32 mcd) {
|
||||||
@@ -2072,17 +2086,19 @@ PLI_INT32 vpi_control(PLI_INT32 operation, ...) {
|
|||||||
_VL_VPI_ERROR_RESET();
|
_VL_VPI_ERROR_RESET();
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case vpiFinish: {
|
case vpiFinish: {
|
||||||
VL_FINISH_MT(__FILE__, __LINE__, "*VPI*");
|
VL_FINISH_MT("", 0, "*VPI*");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
case vpiStop: {
|
case vpiStop: {
|
||||||
VL_STOP_MT(__FILE__, __LINE__, "*VPI*");
|
VL_STOP_MT("", 0, "*VPI*");
|
||||||
return 1;
|
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*/,
|
vpiHandle vpi_handle_by_multi_index(vpiHandle /*obj*/, PLI_INT32 /*num_index*/,
|
||||||
|
|||||||
+22
-15
@@ -144,30 +144,23 @@
|
|||||||
#define VL_MT_UNSAFE_ONE ///< Comment tag that function is not threadsafe when VL_THREADED,
|
#define VL_MT_UNSAFE_ONE ///< Comment tag that function is not threadsafe when VL_THREADED,
|
||||||
///< protected to make sure single-caller
|
///< protected to make sure single-caller
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant (deprecated)
|
||||||
# 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
|
|
||||||
|
|
||||||
// This is not necessarily the same as #UL, depending on what the IData typedef is.
|
// 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
|
#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)
|
# define VL_DANGLING(var)
|
||||||
#else
|
#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) \
|
# define VL_DANGLING(var) \
|
||||||
do { \
|
do { \
|
||||||
(var) = NULL; \
|
*const_cast<const void**>(reinterpret_cast<const void* const*>(&var)) = NULL; \
|
||||||
} while (false)
|
} while (false)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
///< Perform an e.g. delete, then set variable to NULL to indicate must not use later.
|
/// 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.
|
/// Unlike VL_DO_CLEAR the setting of the variable is only for debug reasons.
|
||||||
#define VL_DO_DANGLING(stmt, var) \
|
#define VL_DO_DANGLING(stmt, var) \
|
||||||
do { \
|
do { \
|
||||||
do { \
|
do { \
|
||||||
@@ -176,7 +169,7 @@
|
|||||||
VL_DANGLING(var); \
|
VL_DANGLING(var); \
|
||||||
} while (false)
|
} 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) \
|
#define VL_DO_CLEAR(stmt, stmt2) \
|
||||||
do { \
|
do { \
|
||||||
do { \
|
do { \
|
||||||
@@ -224,6 +217,20 @@
|
|||||||
# define VL_INLINE_OPT ///< "inline" if compiling all objects in single compiler run
|
# define VL_INLINE_OPT ///< "inline" if compiling all objects in single compiler run
|
||||||
#endif
|
#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
|
// 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)
|
#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)
|
/// Mask for quads with 1's where relevant bits are (0=all bits)
|
||||||
#define VL_MASK_Q(nbits) \
|
#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)
|
/// Mask for EData with 1's where relevant bits are (0=all bits)
|
||||||
#define VL_MASK_E(nbits) VL_MASK_I(nbits)
|
#define VL_MASK_E(nbits) VL_MASK_I(nbits)
|
||||||
#define VL_EUL(n) VL_UL(n) ///< Make constant number EData sized
|
#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:
|
|
||||||
+302
-57
@@ -6,30 +6,71 @@ use warnings;
|
|||||||
use Cwd;
|
use Cwd;
|
||||||
use File::Copy qw(cp);
|
use File::Copy qw(cp);
|
||||||
use File::Path qw(mkpath);
|
use File::Path qw(mkpath);
|
||||||
|
use File::Spec;
|
||||||
|
use FindBin qw($RealBin);
|
||||||
use Getopt::Long;
|
use Getopt::Long;
|
||||||
|
use Parallel::Forker;
|
||||||
|
use Unix::Processors;
|
||||||
use IO::File;
|
use IO::File;
|
||||||
use Pod::Usage;
|
use Pod::Usage;
|
||||||
use strict;
|
use strict;
|
||||||
use vars qw($Debug);
|
use vars qw($Debug);
|
||||||
|
|
||||||
|
our $Opt_Stop = 1;
|
||||||
|
our $Opt_Fastcov = 1;
|
||||||
|
our $Exclude_Branch_Regexp;
|
||||||
our $Exclude_Line_Regexp;
|
our $Exclude_Line_Regexp;
|
||||||
|
our $Remove_Gcda_Regexp;
|
||||||
|
|
||||||
our @Remove_Sources;
|
our @Remove_Sources;
|
||||||
our @Source_Globs;
|
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
|
# main
|
||||||
|
|
||||||
our $Opt_Stage = 0;
|
our $Opt_Hashset;
|
||||||
|
our $opt_stages = '';
|
||||||
|
our $Opt_Scenarios;
|
||||||
|
our %Opt_Stages;
|
||||||
|
our @Opt_Tests;
|
||||||
|
|
||||||
autoflush STDOUT 1;
|
autoflush STDOUT 1;
|
||||||
autoflush STDERR 1;
|
autoflush STDERR 1;
|
||||||
Getopt::Long::config("no_auto_abbrev");
|
Getopt::Long::config("no_auto_abbrev");
|
||||||
if (! GetOptions(
|
if (! GetOptions(
|
||||||
"debug" => sub { $Debug = 1; },
|
"debug" => sub { $Debug = 1; },
|
||||||
|
"hashset=s" => \$Opt_Hashset, # driver.pl hashset
|
||||||
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
|
"<>" => 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();
|
test();
|
||||||
@@ -41,97 +82,238 @@ sub test {
|
|||||||
-r "nodist/code_coverage.dat" or die "%Error: Run from the top of the verilator kit,";
|
-r "nodist/code_coverage.dat" or die "%Error: Run from the top of the verilator kit,";
|
||||||
require "./nodist/code_coverage.dat";
|
require "./nodist/code_coverage.dat";
|
||||||
|
|
||||||
if ($Opt_Stage <= 0) {
|
if ($Opt_Stages{1}) {
|
||||||
print "Stage 0: configure (coverage on)\n";
|
travis_fold_start("configure");
|
||||||
run("make distclean");
|
print "Stage 1: configure (coverage on)\n";
|
||||||
run("./configure --enable-longtests CXX='g++ --coverage'");
|
run("make distclean || true");
|
||||||
run("make -k");
|
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
|
# The optimized versions will not collect good coverage, overwrite them
|
||||||
run("cp bin/verilator_bin_dbg bin/verilator_bin");
|
run("cp bin/verilator_bin_dbg bin/verilator_bin");
|
||||||
run("cp bin/verilator_coverage_bin_dbg bin/verilator_coverage_bin");
|
run("cp bin/verilator_coverage_bin_dbg bin/verilator_coverage_bin");
|
||||||
|
travis_fold_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($Opt_Stage <= 1) {
|
if ($Opt_Stages{3}) {
|
||||||
print "Stage 1: make examples (with coverage on)\n";
|
travis_fold_start("test");
|
||||||
run("make examples");
|
print "Stage 3: make tests (with coverage on)\n";
|
||||||
run("make test_regress");
|
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";
|
my $cc_dir = "nodist/obj_dir/coverage";
|
||||||
if ($Opt_Stage <= 2) {
|
if ($Opt_Stages{4}) {
|
||||||
print "Stage 2: Create info files under $cc_dir\n";
|
travis_fold_start("gcno");
|
||||||
|
print "Stage 4: Create gcno files under $cc_dir\n";
|
||||||
mkpath($cc_dir);
|
mkpath($cc_dir);
|
||||||
mkpath("$cc_dir/info");
|
mkpath("$cc_dir/info");
|
||||||
my $dats = `find . -print | grep .gcda`;
|
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;
|
my %dirs;
|
||||||
foreach my $dat (split '\n', $dats) {
|
foreach my $dat (split '\n', $dats) {
|
||||||
$dat =~ s!/[^/]+$!!;
|
(my $dir = $dat) =~ s!/[^/]+$!!;
|
||||||
$dirs{$dat} = 1;
|
$dirs{$dir} = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach my $dir (sort keys %dirs) {
|
foreach my $dir (sort keys %dirs) {
|
||||||
(my $outname = $dir) =~ s![^a-zA-Z0-9]+!_!g;
|
(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) {
|
if ($Opt_Stages{6}) {
|
||||||
# lcov doesn't have a control file to override single lines, so replicate the sources
|
travis_fold_start("clone");
|
||||||
print "Stage 3: Clone sources under $cc_dir\n";
|
# 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);
|
clone_sources($cc_dir);
|
||||||
|
travis_fold_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($Opt_Stage <= 4) {
|
if ($Opt_Stages{8} && !$Opt_Fastcov) {
|
||||||
print "Stage 4: Copy .gcno files\n";
|
travis_fold_start("copy");
|
||||||
|
print "Stage 8: Copy .gcno files\n";
|
||||||
my $dats = `find . -print | grep .gcno`;
|
my $dats = `find . -print | grep .gcno`;
|
||||||
foreach my $dat (split '\n', $dats) {
|
foreach my $dat (sort (split '\n', $dats)) {
|
||||||
next if $dat =~ /$cc_dir/;
|
next if $dat =~ /$cc_dir/;
|
||||||
my $outdat = $cc_dir."/".$dat;
|
my $outdat = $cc_dir."/".$dat;
|
||||||
#print "cp $dat, $outdat);\n";
|
#print "cp $dat, $outdat);\n";
|
||||||
cp($dat, $outdat);
|
cp($dat, $outdat);
|
||||||
}
|
}
|
||||||
|
travis_fold_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($Opt_Stage <= 5) {
|
if ($Opt_Stages{10} && !$Opt_Fastcov) {
|
||||||
print "Stage 5: Combine data files\n";
|
travis_fold_start("combine");
|
||||||
run("cd $cc_dir ; lcov -c -i -d src/obj_dbg -o app_base.info");
|
print "Stage 10: Combine data files\n";
|
||||||
run("cd $cc_dir ; lcov -a app_base.info -o app_total.info");
|
{
|
||||||
my $infos = `cd $cc_dir ; find info -print | grep .info`;
|
run("cd $cc_dir ; lcov -c -i -d src/obj_dbg -o app_base.info");
|
||||||
my $comb = "";
|
run("cd $cc_dir ; lcov -a app_base.info -o app_total.info");
|
||||||
my @infos = (split /\n/, $infos);
|
my $infos = `cd $cc_dir ; find info -print | grep .info`;
|
||||||
foreach my $info (@infos) {
|
my $comb = "";
|
||||||
$comb .= " -a $info";
|
my @infos = (sort (split /\n/, $infos));
|
||||||
# Need to batch them to avoid overrunning shell command length limit
|
foreach my $info (@infos) {
|
||||||
if (length($comb) > 10000 || $info eq $infos[$#infos]) {
|
$comb .= " -a $info";
|
||||||
run("cd $cc_dir ; lcov -a app_total.info $comb -o app_total.info");
|
# Need to batch them to avoid overrunning shell command length limit
|
||||||
$comb = "";
|
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) {
|
if ($Opt_Stages{11}) {
|
||||||
print "Stage 6: Filter processed source files\n";
|
travis_fold_start("dirs");
|
||||||
my $cmd = '';
|
print "Stage 11: Cleanup paths\n";
|
||||||
foreach my $glob (@Remove_Sources) {
|
if ($Opt_Fastcov) {
|
||||||
$cmd .= " '$glob'";
|
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) {
|
if ($Opt_Stages{12}) {
|
||||||
print "Stage 7: Create HTML\n";
|
travis_fold_start("filter");
|
||||||
cleanup_abs_paths($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info");
|
print "Stage 12: Filter processed source files\n";
|
||||||
run("cd $cc_dir ; genhtml app_total.info --demangle-cpp"
|
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");
|
." --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 "*-* 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 {
|
sub clone_sources {
|
||||||
my $cc_dir = shift;
|
my $cc_dir = shift;
|
||||||
my $excluded_lines = 0;
|
my $excluded_lines = 0;
|
||||||
|
my $excluded_br_lines = 0;
|
||||||
foreach my $glob (@Source_Globs) {
|
foreach my $glob (@Source_Globs) {
|
||||||
foreach my $infile (glob $glob) {
|
foreach my $infile (glob $glob) {
|
||||||
$infile !~ m!^/!
|
$infile !~ m!^/!
|
||||||
@@ -145,21 +327,35 @@ sub clone_sources {
|
|||||||
while (defined(my $line = $fh->getline)) {
|
while (defined(my $line = $fh->getline)) {
|
||||||
$lineno++;
|
$lineno++;
|
||||||
chomp $line;
|
chomp $line;
|
||||||
if ($line !~ m!// LCOV_EXCL_LINE!
|
if ($line =~ /LCOV_EXCL_LINE/) {
|
||||||
&& $line =~ /$Exclude_Line_Regexp/) {
|
$line .= " LCOV_EXCL_BR_LINE";
|
||||||
$line .= " //code_coverage: // LCOV_EXCL_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_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";
|
#print "$infile:$lineno: $line";
|
||||||
} else {
|
|
||||||
}
|
}
|
||||||
$ofh->print("$line\n");
|
$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 $cc_dir = shift;
|
||||||
my $infile = shift;
|
my $infile = shift;
|
||||||
my $outfile = shift;
|
my $outfile = shift;
|
||||||
@@ -178,18 +374,41 @@ sub cleanup_abs_paths {
|
|||||||
$ofh->print(@lines);
|
$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
|
# .dat file callbacks
|
||||||
|
|
||||||
|
sub exclude_branch_regexp {
|
||||||
|
$Exclude_Branch_Regexp = shift;
|
||||||
|
}
|
||||||
sub exclude_line_regexp {
|
sub exclude_line_regexp {
|
||||||
$Exclude_Line_Regexp = shift;
|
$Exclude_Line_Regexp = shift;
|
||||||
}
|
}
|
||||||
|
sub remove_gcda_regexp {
|
||||||
|
$Remove_Gcda_Regexp = shift;
|
||||||
|
}
|
||||||
sub remove_source {
|
sub remove_source {
|
||||||
my @srcs = @_;
|
my @srcs = @_;
|
||||||
push @Remove_Sources, @srcs;
|
push @Remove_Sources, @srcs;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub source_globs {
|
sub source_globs {
|
||||||
my @dirs = @_;
|
my @dirs = @_;
|
||||||
push @Source_Globs, @dirs;
|
push @Source_Globs, @dirs;
|
||||||
@@ -206,6 +425,15 @@ sub run {
|
|||||||
($status == 0) or die "%Error: Command Failed $command, $status, stopped";
|
($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__
|
__END__
|
||||||
|
|
||||||
@@ -231,13 +459,30 @@ This will rebuild the current object files.
|
|||||||
|
|
||||||
=over 4
|
=over 4
|
||||||
|
|
||||||
|
=item --hashset I<hashset>
|
||||||
|
|
||||||
|
Pass test hashset onto driver.pl test harness.
|
||||||
|
|
||||||
=item --help
|
=item --help
|
||||||
|
|
||||||
Displays this message and program version and exits.
|
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
|
=back
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ source_globs("src/*.cpp",
|
|||||||
"include/*/*.c",
|
"include/*/*.c",
|
||||||
);
|
);
|
||||||
|
|
||||||
remove_source("/usr/include/*");
|
# Note *'s are removed when using fastcov
|
||||||
|
remove_source("/usr/*");
|
||||||
remove_source("*/include/sysc/*");
|
remove_source("*/include/sysc/*");
|
||||||
remove_source("*/V3ClkGater.cpp");
|
remove_source("*/V3ClkGater.cpp");
|
||||||
remove_source("*/V3ClkGater.h");
|
remove_source("*/V3ClkGater.h");
|
||||||
@@ -37,7 +38,21 @@ remove_source("*include/gtkwave/*");
|
|||||||
remove_source("*test_regress/*");
|
remove_source("*test_regress/*");
|
||||||
remove_source("*examples/*");
|
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;
|
1;
|
||||||
|
|||||||
Executable
+744
@@ -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 <[email protected]>
|
|
||||||
|
|
||||||
=head1 SEE ALSO
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
### Local Variables:
|
|
||||||
### compile-command: "./git_untabify "
|
|
||||||
### End:
|
|
||||||
+1
-1
@@ -84,7 +84,7 @@ maintainer-copy::
|
|||||||
clean mostlyclean distclean maintainer-clean::
|
clean mostlyclean distclean maintainer-clean::
|
||||||
-rm -rf obj_* *.log *.dmp *.vpd core
|
-rm -rf obj_* *.log *.dmp *.vpd core
|
||||||
-rm -f *.o *.d perlxsi.c *_gen_*
|
-rm -f *.o *.d perlxsi.c *_gen_*
|
||||||
-rm -f *__gen*
|
-rm -f *__gen* obj_*
|
||||||
-rm -f .objcache*
|
-rm -f .objcache*
|
||||||
|
|
||||||
distclean maintainer-clean::
|
distclean maintainer-clean::
|
||||||
|
|||||||
+9
-6
@@ -211,11 +211,13 @@ RAW_OBJS = \
|
|||||||
V3LinkCells.o \
|
V3LinkCells.o \
|
||||||
V3LinkDot.o \
|
V3LinkDot.o \
|
||||||
V3LinkJump.o \
|
V3LinkJump.o \
|
||||||
|
V3LinkInc.o \
|
||||||
V3LinkLValue.o \
|
V3LinkLValue.o \
|
||||||
V3LinkLevel.o \
|
V3LinkLevel.o \
|
||||||
V3LinkParse.o \
|
V3LinkParse.o \
|
||||||
V3LinkResolve.o \
|
V3LinkResolve.o \
|
||||||
V3Localize.o \
|
V3Localize.o \
|
||||||
|
V3MergeCond.o \
|
||||||
V3Name.o \
|
V3Name.o \
|
||||||
V3Number.o \
|
V3Number.o \
|
||||||
V3Options.o \
|
V3Options.o \
|
||||||
@@ -246,6 +248,7 @@ RAW_OBJS = \
|
|||||||
V3Undriven.o \
|
V3Undriven.o \
|
||||||
V3Unknown.o \
|
V3Unknown.o \
|
||||||
V3Unroll.o \
|
V3Unroll.o \
|
||||||
|
V3Waiver.o \
|
||||||
V3Width.o \
|
V3Width.o \
|
||||||
V3WidthSel.o \
|
V3WidthSel.o \
|
||||||
|
|
||||||
@@ -287,21 +290,21 @@ V3Number_test: V3Number_test.o
|
|||||||
$(PERL) $(ASTGEN) -I$(srcdir) $*.cpp
|
$(PERL) $(ASTGEN) -I$(srcdir) $*.cpp
|
||||||
|
|
||||||
%.o: %.cpp
|
%.o: %.cpp
|
||||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $<
|
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
$(OBJCACHE) ${CC} ${CFLAGS} ${CPPFLAGSWALL} -c $<
|
$(OBJCACHE) ${CC} ${CFLAGS} ${CPPFLAGSWALL} -c $< -o $@
|
||||||
|
|
||||||
V3ParseLex.o: V3ParseLex.cpp V3Lexer.yy.cpp V3ParseBison.c
|
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
|
V3ParseGrammar.o: V3ParseGrammar.cpp V3ParseBison.c
|
||||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $<
|
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
|
||||||
|
|
||||||
V3ParseImp.o: V3ParseImp.cpp V3ParseBison.c
|
V3ParseImp.o: V3ParseImp.cpp V3ParseBison.c
|
||||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $<
|
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
|
||||||
|
|
||||||
V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp
|
V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp
|
||||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $<
|
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
|
||||||
|
|
||||||
#### Generated files
|
#### Generated files
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ protected:
|
|||||||
|
|
||||||
class ActiveNamer : public ActiveBaseVisitor {
|
class ActiveNamer : public ActiveBaseVisitor {
|
||||||
private:
|
private:
|
||||||
typedef std::map<string, AstActive*> ActiveNameMap;
|
|
||||||
// STATE
|
// STATE
|
||||||
AstScope* m_scopep; // Current scope to add statement to
|
AstScope* m_scopep; // Current scope to add statement to
|
||||||
AstActive* m_iActivep; // For current scope, the IActive we're building
|
AstActive* m_iActivep; // For current scope, the IActive we're building
|
||||||
|
|||||||
+2
-8
@@ -89,7 +89,7 @@ private:
|
|||||||
}
|
}
|
||||||
// Move the SENTREE for each active up to the global level.
|
// Move the SENTREE for each active up to the global level.
|
||||||
// This way we'll easily see what clock domains are identical
|
// 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");
|
UINFO(4, " lookdone\n");
|
||||||
if (wantp != sensesp) {
|
if (wantp != sensesp) {
|
||||||
// Move the active's contents to the other active
|
// 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.
|
// No need to do statements under it, they're already moved.
|
||||||
// iterateChildren(nodep);
|
// 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");
|
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||||
}
|
}
|
||||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
|
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
|
virtual void visit(AstAssignW* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
|
||||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
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
|
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
|
||||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
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(AstNodeMath*) VL_OVERRIDE {} // Accelerate
|
||||||
virtual void visit(AstVarScope*) VL_OVERRIDE {} // Accelerate
|
virtual void visit(AstVarScope*) VL_OVERRIDE {} // Accelerate
|
||||||
|
|||||||
@@ -23,9 +23,6 @@
|
|||||||
#include "V3GraphDfa.h"
|
#include "V3GraphDfa.h"
|
||||||
#include "V3Stats.h"
|
#include "V3Stats.h"
|
||||||
|
|
||||||
#include <cstdarg>
|
|
||||||
#include <iomanip>
|
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// Assert class functions
|
// Assert class functions
|
||||||
|
|
||||||
|
|||||||
@@ -23,9 +23,6 @@
|
|||||||
#include "V3Global.h"
|
#include "V3Global.h"
|
||||||
#include "V3AssertPre.h"
|
#include "V3AssertPre.h"
|
||||||
|
|
||||||
#include <cstdarg>
|
|
||||||
#include <iomanip>
|
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// Assert class functions
|
// Assert class functions
|
||||||
|
|
||||||
|
|||||||
+5
-7
@@ -23,7 +23,6 @@
|
|||||||
#include "V3Broken.h"
|
#include "V3Broken.h"
|
||||||
#include "V3String.h"
|
#include "V3String.h"
|
||||||
|
|
||||||
#include <cstdarg>
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@@ -727,7 +726,7 @@ void AstNode::deleteNode() {
|
|||||||
this->m_op4p = reinterpret_cast<AstNode*>(0x1);
|
this->m_op4p = reinterpret_cast<AstNode*>(0x1);
|
||||||
if (
|
if (
|
||||||
#if !defined(VL_DEBUG) || defined(VL_LEAK_CHECKS)
|
#if !defined(VL_DEBUG) || defined(VL_LEAK_CHECKS)
|
||||||
1
|
true
|
||||||
#else
|
#else
|
||||||
!v3Global.opt.debugLeak()
|
!v3Global.opt.debugLeak()
|
||||||
#endif
|
#endif
|
||||||
@@ -1129,6 +1128,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
|
|||||||
*logsp << "No changes since last dump!\n";
|
*logsp << "No changes since last dump!\n";
|
||||||
} else {
|
} else {
|
||||||
dumpTree(*logsp);
|
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
|
// set by other steps if it is called in the middle of other operations
|
||||||
if (AstNetlist* netp = VN_CAST(this, Netlist)) V3Broken::brokenAll(netp);
|
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 {
|
void AstNode::v3errorEndFatal(std::ostringstream& str) const {
|
||||||
v3errorEnd(str);
|
v3errorEnd(str);
|
||||||
assert(0);
|
assert(0); // LCOV_EXCL_LINE
|
||||||
VL_UNREACHABLE
|
VL_UNREACHABLE
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1154,10 +1152,10 @@ string AstNode::locationStr() const {
|
|||||||
const AstNode* backp = this;
|
const AstNode* backp = this;
|
||||||
int itmax = 10000; // Max iterations before giving up on location search
|
int itmax = 10000; // Max iterations before giving up on location search
|
||||||
while (backp) {
|
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
|
// 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);
|
UINFO(1, "Ran out of iterations finding locationStr on " << backp << endl);
|
||||||
return "";
|
return ""; // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
const AstScope* scopep;
|
const AstScope* scopep;
|
||||||
if ((scopep = VN_CAST_CONST(backp, Scope))) {
|
if ((scopep = VN_CAST_CONST(backp, Scope))) {
|
||||||
|
|||||||
+86
-39
@@ -193,12 +193,14 @@ class AstCFuncType {
|
|||||||
public:
|
public:
|
||||||
enum en {
|
enum en {
|
||||||
FT_NORMAL,
|
FT_NORMAL,
|
||||||
|
TRACE_REGISTER,
|
||||||
TRACE_INIT,
|
TRACE_INIT,
|
||||||
TRACE_INIT_SUB,
|
TRACE_INIT_SUB,
|
||||||
TRACE_FULL,
|
TRACE_FULL,
|
||||||
TRACE_FULL_SUB,
|
TRACE_FULL_SUB,
|
||||||
TRACE_CHANGE,
|
TRACE_CHANGE,
|
||||||
TRACE_CHANGE_SUB
|
TRACE_CHANGE_SUB,
|
||||||
|
TRACE_CLEANUP
|
||||||
};
|
};
|
||||||
enum en m_e;
|
enum en m_e;
|
||||||
inline AstCFuncType()
|
inline AstCFuncType()
|
||||||
@@ -210,10 +212,7 @@ public:
|
|||||||
: m_e(static_cast<en>(_e)) {}
|
: m_e(static_cast<en>(_e)) {}
|
||||||
operator en() const { return m_e; }
|
operator en() const { return m_e; }
|
||||||
// METHODS
|
// METHODS
|
||||||
bool isTrace() const {
|
bool isTrace() const { return m_e != FT_NORMAL; }
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
inline bool operator==(const AstCFuncType& lhs, const AstCFuncType& rhs) {
|
inline bool operator==(const AstCFuncType& lhs, const AstCFuncType& rhs) {
|
||||||
return lhs.m_e == rhs.m_e;
|
return lhs.m_e == rhs.m_e;
|
||||||
@@ -258,7 +257,7 @@ public:
|
|||||||
case ET_HIGHEDGE: return ET_LOWEDGE;
|
case ET_HIGHEDGE: return ET_LOWEDGE;
|
||||||
case ET_LOWEDGE: return ET_HIGHEDGE;
|
case ET_LOWEDGE: return ET_HIGHEDGE;
|
||||||
default: UASSERT_STATIC(0, "Inverting bad edgeType()");
|
default: UASSERT_STATIC(0, "Inverting bad edgeType()");
|
||||||
};
|
}
|
||||||
return VEdgeType::ET_ILLEGAL;
|
return VEdgeType::ET_ILLEGAL;
|
||||||
}
|
}
|
||||||
const char* ascii() const {
|
const char* ascii() const {
|
||||||
@@ -1081,9 +1080,6 @@ public:
|
|||||||
// - Also used to allow parameter passing up/down iterate calls
|
// - Also used to allow parameter passing up/down iterate calls
|
||||||
|
|
||||||
class WidthVP;
|
class WidthVP;
|
||||||
class LinkVP;
|
|
||||||
class OrderBlockNU;
|
|
||||||
class OrderVarNU;
|
|
||||||
class V3GraphVertex;
|
class V3GraphVertex;
|
||||||
class VSymEnt;
|
class VSymEnt;
|
||||||
|
|
||||||
@@ -1104,15 +1100,11 @@ public:
|
|||||||
explicit VNUser(void* p) { m_u.up = p; }
|
explicit VNUser(void* p) { m_u.up = p; }
|
||||||
~VNUser() {}
|
~VNUser() {}
|
||||||
// Casters
|
// Casters
|
||||||
WidthVP* c() { return ((WidthVP*)m_u.up); }
|
WidthVP* c() const { return reinterpret_cast<WidthVP*>(m_u.up); }
|
||||||
LinkVP* toLinkVP() { return ((LinkVP*)m_u.up); }
|
VSymEnt* toSymEnt() const { return reinterpret_cast<VSymEnt*>(m_u.up); }
|
||||||
VSymEnt* toSymEnt() { return ((VSymEnt*)m_u.up); }
|
AstNode* toNodep() const { return reinterpret_cast<AstNode*>(m_u.up); }
|
||||||
AstNode* toNodep() { return ((AstNode*)m_u.up); }
|
V3GraphVertex* toGraphVertex() const { return reinterpret_cast<V3GraphVertex*>(m_u.up); }
|
||||||
OrderBlockNU* toOrderBlock() { return ((OrderBlockNU*)m_u.up); }
|
int toInt() const { return m_u.ui; }
|
||||||
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); }
|
|
||||||
static inline VNUser fromInt(int i) { return VNUser(i); }
|
static inline VNUser fromInt(int i) { return VNUser(i); }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1318,7 +1310,7 @@ public:
|
|||||||
class FullValue {}; // for creator type-overload selection
|
class FullValue {}; // for creator type-overload selection
|
||||||
explicit V3Hash(Illegal) { m_both = 0; }
|
explicit V3Hash(Illegal) { m_both = 0; }
|
||||||
// Saving and restoring inside a userp
|
// 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) {
|
V3Hash operator+=(const V3Hash& rh) {
|
||||||
setBoth(depth() + rh.depth(), (hshval() * 31 + rh.hshval()));
|
setBoth(depth() + rh.depth(), (hshval() * 31 + rh.hshval()));
|
||||||
return *this;
|
return *this;
|
||||||
@@ -1355,12 +1347,12 @@ public:
|
|||||||
// Prefetch a node.
|
// Prefetch a node.
|
||||||
// The if() makes it faster, even though prefetch won't fault on null pointers
|
// The if() makes it faster, even though prefetch won't fault on null pointers
|
||||||
#define ASTNODE_PREFETCH(nodep) \
|
#define ASTNODE_PREFETCH(nodep) \
|
||||||
{ \
|
do { \
|
||||||
if (nodep) { \
|
if (nodep) { \
|
||||||
VL_PREFETCH_RD(&((nodep)->m_nextp)); \
|
VL_PREFETCH_RD(&((nodep)->m_nextp)); \
|
||||||
VL_PREFETCH_RD(&((nodep)->m_iterpp)); \
|
VL_PREFETCH_RD(&((nodep)->m_iterpp)); \
|
||||||
} \
|
} \
|
||||||
}
|
} while (false)
|
||||||
|
|
||||||
class AstNode {
|
class AstNode {
|
||||||
// v ASTNODE_PREFETCH depends on below ordering of members
|
// v ASTNODE_PREFETCH depends on below ordering of members
|
||||||
@@ -1508,6 +1500,7 @@ public:
|
|||||||
}
|
}
|
||||||
bool brokeExists() const;
|
bool brokeExists() const;
|
||||||
bool brokeExistsAbove() const;
|
bool brokeExistsAbove() const;
|
||||||
|
bool brokeExistsBelow() const;
|
||||||
|
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
virtual ~AstNode() {}
|
virtual ~AstNode() {}
|
||||||
@@ -1788,20 +1781,22 @@ public:
|
|||||||
static void dumpTreeFileGdb(const char* filenamep = NULL);
|
static void dumpTreeFileGdb(const char* filenamep = NULL);
|
||||||
|
|
||||||
// METHODS - queries
|
// 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
|
// Changes control flow, disable some optimizations
|
||||||
virtual bool isBrancher() const { return false; }
|
virtual bool isBrancher() const { return false; }
|
||||||
// Else a AstTime etc that can't be pushed out
|
// Else a AstTime etc that can't be pushed out
|
||||||
virtual bool isGateOptimizable() const { return true; }
|
virtual bool isGateOptimizable() const { return true; }
|
||||||
// GateDedupable is a slightly larger superset of GateOptimzable (eg, AstNodeIf)
|
// GateDedupable is a slightly larger superset of GateOptimzable (eg, AstNodeIf)
|
||||||
virtual bool isGateDedupable() const { return isGateOptimizable(); }
|
virtual bool isGateDedupable() const { return isGateOptimizable(); }
|
||||||
// Else a AstTime etc that can't be substituted out
|
// Needs verilated_heavy.h (uses std::string or some others)
|
||||||
virtual bool isSubstOptimizable() const { return true; }
|
virtual bool isHeavy() const { return false; }
|
||||||
// Else a AstTime etc which output can't be predicted from input
|
|
||||||
virtual bool isPredictOptimizable() const { return true; }
|
|
||||||
// Else creates output or exits, etc, not unconsumed
|
// Else creates output or exits, etc, not unconsumed
|
||||||
virtual bool isOutputter() const { return false; }
|
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
|
// isUnlikely handles $stop or similar statement which means an above IF
|
||||||
// statement is unlikely to be taken
|
// statement is unlikely to be taken
|
||||||
virtual bool isUnlikely() const { return false; }
|
virtual bool isUnlikely() const { return false; }
|
||||||
@@ -1998,6 +1993,43 @@ public:
|
|||||||
virtual bool same(const AstNode*) const { return true; }
|
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 {
|
class AstNodeBiCom : public AstNodeBiop {
|
||||||
// Binary math with commutative properties
|
// Binary math with commutative properties
|
||||||
public:
|
public:
|
||||||
@@ -2090,6 +2122,20 @@ public:
|
|||||||
virtual bool same(const AstNode*) const { return true; }
|
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 {
|
class AstNodeStmt : public AstNode {
|
||||||
// Statement -- anything that's directly under a function
|
// Statement -- anything that's directly under a function
|
||||||
bool m_statement; // Really a statement (e.g. not a function with return)
|
bool m_statement; // Really a statement (e.g. not a function with return)
|
||||||
@@ -2323,9 +2369,8 @@ public:
|
|||||||
virtual AstNodeDType* skipRefToEnump() const = 0;
|
virtual AstNodeDType* skipRefToEnump() const = 0;
|
||||||
// (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
|
// (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
|
||||||
virtual int widthAlignBytes() const = 0;
|
virtual int widthAlignBytes() const = 0;
|
||||||
virtual int
|
|
||||||
// (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
|
// (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; }
|
virtual bool maybePointedTo() const { return true; }
|
||||||
// Iff has a non-null refDTypep(), as generic node function
|
// Iff has a non-null refDTypep(), as generic node function
|
||||||
virtual AstNodeDType* virtRefDTypep() const { return NULL; }
|
virtual AstNodeDType* virtRefDTypep() const { return NULL; }
|
||||||
@@ -2429,9 +2474,8 @@ public:
|
|||||||
} // op1 = AstMember list
|
} // op1 = AstMember list
|
||||||
void addMembersp(AstNode* nodep) { addNOp1p(nodep); }
|
void addMembersp(AstNode* nodep) { addNOp1p(nodep); }
|
||||||
bool packed() const { return m_packed; }
|
bool packed() const { return m_packed; }
|
||||||
bool packedUnsup() const {
|
// packed() but as don't support unpacked, presently all structs
|
||||||
return true;
|
static bool packedUnsup() { return true; }
|
||||||
} // packed() but as don't support unpacked, presently all structs
|
|
||||||
void isFourstate(bool flag) { m_isFourstate = flag; }
|
void isFourstate(bool flag) { m_isFourstate = flag; }
|
||||||
virtual bool isFourstate() const { return m_isFourstate; }
|
virtual bool isFourstate() const { return m_isFourstate; }
|
||||||
void clearCache() { m_members.clear(); }
|
void clearCache() { m_members.clear(); }
|
||||||
@@ -2440,7 +2484,7 @@ public:
|
|||||||
MemberNameMap::const_iterator it = m_members.find(name);
|
MemberNameMap::const_iterator it = m_members.find(name);
|
||||||
return (it == m_members.end()) ? NULL : it->second;
|
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
|
int msb() const { return dtypep()->width() - 1; } // Packed classes look like arrays
|
||||||
VNumRange declRange() const { return VNumRange(msb(), lsb(), false); }
|
VNumRange declRange() const { return VNumRange(msb(), lsb(), false); }
|
||||||
};
|
};
|
||||||
@@ -2482,10 +2526,8 @@ public:
|
|||||||
virtual V3Hash sameHash() const {
|
virtual V3Hash sameHash() const {
|
||||||
return V3Hash(V3Hash(m_refDTypep), V3Hash(msb()), V3Hash(lsb()));
|
return V3Hash(V3Hash(m_refDTypep), V3Hash(msb()), V3Hash(lsb()));
|
||||||
}
|
}
|
||||||
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
virtual AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
||||||
AstNodeDType* childDTypep() const {
|
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
|
||||||
return VN_CAST(op1p(), NodeDType);
|
|
||||||
} // op1 = Range of variable
|
|
||||||
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
||||||
virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); }
|
virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); }
|
||||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
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_dotted; // Dotted part of scope the name()ed task/func is under or ""
|
||||||
string m_inlinedDots; // Dotted hierarchy flattened out
|
string m_inlinedDots; // Dotted hierarchy flattened out
|
||||||
AstNodeModule* m_packagep; // Package hierarchy
|
AstNodeModule* m_packagep; // Package hierarchy
|
||||||
|
bool m_pli; // Pli system call ($name)
|
||||||
public:
|
public:
|
||||||
AstNodeFTaskRef(AstType t, FileLine* fl, bool statement, AstNode* namep, AstNode* pinsp)
|
AstNodeFTaskRef(AstType t, FileLine* fl, bool statement, AstNode* namep, AstNode* pinsp)
|
||||||
: AstNodeStmt(t, fl, statement)
|
: AstNodeStmt(t, fl, statement)
|
||||||
, m_taskp(NULL)
|
, m_taskp(NULL)
|
||||||
, m_packagep(NULL) {
|
, m_packagep(NULL)
|
||||||
|
, m_pli(false) {
|
||||||
setOp1p(namep);
|
setOp1p(namep);
|
||||||
addNOp3p(pinsp);
|
addNOp3p(pinsp);
|
||||||
}
|
}
|
||||||
@@ -2692,7 +2736,8 @@ public:
|
|||||||
: AstNodeStmt(t, fl, statement)
|
: AstNodeStmt(t, fl, statement)
|
||||||
, m_taskp(NULL)
|
, m_taskp(NULL)
|
||||||
, m_name(name)
|
, m_name(name)
|
||||||
, m_packagep(NULL) {
|
, m_packagep(NULL)
|
||||||
|
, m_pli(false) {
|
||||||
addNOp3p(pinsp);
|
addNOp3p(pinsp);
|
||||||
}
|
}
|
||||||
ASTNODE_BASE_FUNCS(NodeFTaskRef)
|
ASTNODE_BASE_FUNCS(NodeFTaskRef)
|
||||||
@@ -2716,6 +2761,8 @@ public:
|
|||||||
void dotted(const string& name) { m_dotted = name; }
|
void dotted(const string& name) { m_dotted = name; }
|
||||||
AstNodeModule* packagep() const { return m_packagep; }
|
AstNodeModule* packagep() const { return m_packagep; }
|
||||||
void packagep(AstNodeModule* nodep) { m_packagep = nodep; }
|
void packagep(AstNodeModule* nodep) { m_packagep = nodep; }
|
||||||
|
bool pli() const { return m_pli; }
|
||||||
|
void pli(bool flag) { m_pli = flag; }
|
||||||
// op1 = namep
|
// op1 = namep
|
||||||
AstNode* namep() const { return op1p(); }
|
AstNode* namep() const { return op1p(); }
|
||||||
// op2 = reserved for AstMethodCall
|
// op2 = reserved for AstMethodCall
|
||||||
|
|||||||
+151
-136
@@ -24,7 +24,6 @@
|
|||||||
#include "V3PartitionGraph.h" // Just for mtask dumping
|
#include "V3PartitionGraph.h" // Just for mtask dumping
|
||||||
#include "V3EmitCBase.h"
|
#include "V3EmitCBase.h"
|
||||||
|
|
||||||
#include <cstdarg>
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -282,16 +281,16 @@ string AstVar::verilogKwd() const {
|
|||||||
|
|
||||||
class AstVar::VlArgTypeRecursed {
|
class AstVar::VlArgTypeRecursed {
|
||||||
public:
|
public:
|
||||||
string m_oref; // To output, reference part before name, "&"
|
bool m_isRef; // Is it a reference?
|
||||||
string m_osuffix; // To output, suffixed after name, "[3]"
|
string m_type; // The base type, e.g.: "Foo_t"s
|
||||||
string m_oprefix; // To output, prefixed before name, "Foo_t"
|
string m_dims; // Array dimensions, e.g.: "[3][2][1]"
|
||||||
void clear() {
|
string render(const string& name) {
|
||||||
m_oref.clear();
|
string out;
|
||||||
m_osuffix.clear();
|
out += m_type;
|
||||||
m_oprefix.clear();
|
out += " ";
|
||||||
}
|
out += m_isRef ? "(&" + name + ")" : name;
|
||||||
string refParen(const string& name) {
|
out += m_dims;
|
||||||
return m_oref.empty() ? name : "(" + m_oref + " " + name + ")";
|
return out;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -301,126 +300,86 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string&
|
|||||||
string ostatic;
|
string ostatic;
|
||||||
if (isStatic() && namespc.empty()) ostatic = "static ";
|
if (isStatic() && namespc.empty()) ostatic = "static ";
|
||||||
|
|
||||||
VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep(), false);
|
VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep());
|
||||||
|
|
||||||
string oname;
|
string oname;
|
||||||
if (named) {
|
if (named) {
|
||||||
oname += " ";
|
|
||||||
if (!namespc.empty()) oname += namespc + "::";
|
if (!namespc.empty()) oname += namespc + "::";
|
||||||
oname += VIdProtect::protectIf(name(), protect());
|
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,
|
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();
|
dtypep = dtypep->skipRefp();
|
||||||
if (const AstAssocArrayDType* adtypep = VN_CAST_CONST(dtypep, AssocArrayDType)) {
|
if (const AstAssocArrayDType* adtypep = VN_CAST_CONST(dtypep, AssocArrayDType)) {
|
||||||
VlArgTypeRecursed key = vlArgTypeRecurse(forFunc, adtypep->keyDTypep(), true);
|
const VlArgTypeRecursed key = vlArgTypeRecurse(false, adtypep->keyDTypep(), true);
|
||||||
VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true);
|
const VlArgTypeRecursed val = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
|
||||||
string out = "VlAssocArray<";
|
info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">";
|
||||||
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;
|
|
||||||
} else if (const AstDynArrayDType* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) {
|
} else if (const AstDynArrayDType* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) {
|
||||||
VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true);
|
const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
|
||||||
string out = "VlQueue<";
|
info.m_type = "VlQueue<" + sub.m_type + ">";
|
||||||
out += sub.m_oprefix;
|
|
||||||
if (!sub.m_osuffix.empty() || !sub.m_oref.empty()) {
|
|
||||||
out += " " + sub.m_osuffix + sub.m_oref;
|
|
||||||
}
|
|
||||||
out += "> ";
|
|
||||||
VlArgTypeRecursed info;
|
|
||||||
info.m_oprefix = out;
|
|
||||||
return info;
|
|
||||||
} else if (const AstQueueDType* adtypep = VN_CAST_CONST(dtypep, QueueDType)) {
|
} else if (const AstQueueDType* adtypep = VN_CAST_CONST(dtypep, QueueDType)) {
|
||||||
VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true);
|
const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
|
||||||
VlArgTypeRecursed info;
|
info.m_type = "VlQueue<" + sub.m_type;
|
||||||
string out = "VlQueue<" + sub.m_oprefix;
|
|
||||||
if (!sub.m_osuffix.empty() || !sub.m_oref.empty()) {
|
|
||||||
out += " " + sub.m_osuffix + sub.m_oref;
|
|
||||||
}
|
|
||||||
// + 1 below as VlQueue uses 0 to mean unlimited, 1 to mean size() max is 1
|
// + 1 below as VlQueue uses 0 to mean unlimited, 1 to mean size() max is 1
|
||||||
if (adtypep->boundp()) out += ", " + cvtToStr(adtypep->boundConst() + 1);
|
if (adtypep->boundp()) info.m_type += ", " + cvtToStr(adtypep->boundConst() + 1);
|
||||||
out += "> ";
|
info.m_type += ">";
|
||||||
info.m_oprefix = out;
|
|
||||||
return info;
|
|
||||||
} else if (const AstClassRefDType* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) {
|
} else if (const AstClassRefDType* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) {
|
||||||
VlArgTypeRecursed info;
|
info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
|
||||||
info.m_oprefix = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
|
|
||||||
return info;
|
|
||||||
} else if (const AstUnpackArrayDType* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) {
|
} else if (const AstUnpackArrayDType* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) {
|
||||||
VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), arrayed);
|
if (compound) {
|
||||||
info.m_osuffix = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + info.m_osuffix;
|
v3fatalSrc("Dynamic arrays or queues with unpacked elements are not yet supported");
|
||||||
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 ((forFunc && isReadOnly()) || bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR
|
const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), compound);
|
||||||
|| bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR)
|
info.m_type = sub.m_type;
|
||||||
otype += "const ";
|
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) {
|
if (bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) {
|
||||||
otype += "char*";
|
info.m_type = "const char*";
|
||||||
} else if (bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) {
|
} else if (bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) {
|
||||||
otype += "VerilatedScope*";
|
info.m_type = "const VerilatedScope*";
|
||||||
} else if (bdtypep->keyword() == AstBasicDTypeKwd::DOUBLE) {
|
} else if (bdtypep->keyword() == AstBasicDTypeKwd::DOUBLE) {
|
||||||
otype += "double";
|
info.m_type = "double";
|
||||||
} else if (bdtypep->keyword() == AstBasicDTypeKwd::FLOAT) {
|
} else if (bdtypep->keyword() == AstBasicDTypeKwd::FLOAT) {
|
||||||
otype += "float";
|
info.m_type = "float";
|
||||||
} else if (strtype) {
|
} else if (bdtypep->keyword() == AstBasicDTypeKwd::STRING) {
|
||||||
otype += "std::string";
|
info.m_type = "std::string";
|
||||||
} else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width
|
} else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width
|
||||||
otype += "CData" + bitvec;
|
info.m_type = "CData" + bitvec;
|
||||||
} else if (dtypep->widthMin() <= 16) {
|
} else if (dtypep->widthMin() <= 16) {
|
||||||
otype += "SData" + bitvec;
|
info.m_type = "SData" + bitvec;
|
||||||
} else if (dtypep->widthMin() <= VL_IDATASIZE) {
|
} else if (dtypep->widthMin() <= VL_IDATASIZE) {
|
||||||
otype += "IData" + bitvec;
|
info.m_type = "IData" + bitvec;
|
||||||
} else if (dtypep->isQuad()) {
|
} else if (dtypep->isQuad()) {
|
||||||
otype += "QData" + bitvec;
|
info.m_type = "QData" + bitvec;
|
||||||
} else if (dtypep->isWide()) {
|
} else if (dtypep->isWide()) {
|
||||||
if (arrayed) {
|
if (compound) {
|
||||||
otype += "VlWide<" + cvtToStr(dtypep->widthWords()) + "> ";
|
info.m_type = "VlWide<" + cvtToStr(dtypep->widthWords()) + "> ";
|
||||||
} else {
|
} else {
|
||||||
otype += "WData" + bitvec; // []'s added later
|
info.m_type += "WData" + bitvec; // []'s added later
|
||||||
oarray += "[" + cvtToStr(dtypep->widthWords()) + "]";
|
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 {
|
} else {
|
||||||
v3fatalSrc("Unknown data type in var type emitter: " << dtypep->prettyName());
|
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 {
|
string AstVar::vlEnumType() const {
|
||||||
@@ -472,29 +431,52 @@ string AstVar::vlEnumDir() const {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
string AstVar::vlPropInit() const {
|
string AstVar::vlPropDecl(string propName) const {
|
||||||
string out;
|
string out;
|
||||||
out = vlEnumType(); // VLVT_UINT32 etc
|
|
||||||
out += ", " + vlEnumDir(); // VLVD_IN etc
|
std::vector<int> ulims; // Unpacked dimension limits
|
||||||
if (AstBasicDType* bdtypep = basicp()) {
|
for (const AstNodeDType* dtp = dtypep(); dtp;) {
|
||||||
out += ", VerilatedVarProps::Packed()";
|
|
||||||
out += ", " + cvtToStr(bdtypep->left()) + ", " + cvtToStr(bdtypep->right());
|
|
||||||
}
|
|
||||||
bool first = true;
|
|
||||||
for (AstNodeDType* dtp = dtypep(); dtp;) {
|
|
||||||
dtp = dtp->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
dtp = dtp->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
||||||
if (AstNodeArrayDType* adtypep = VN_CAST(dtp, NodeArrayDType)) {
|
if (const AstNodeArrayDType* const adtypep = VN_CAST_CONST(dtp, NodeArrayDType)) {
|
||||||
if (first) {
|
ulims.push_back(adtypep->declRange().left());
|
||||||
out += ", VerilatedVarProps::Unpacked()";
|
ulims.push_back(adtypep->declRange().right());
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
out += ", " + cvtToStr(adtypep->declRange().left()) + ", "
|
|
||||||
+ cvtToStr(adtypep->declRange().right());
|
|
||||||
dtp = adtypep->subDTypep();
|
dtp = adtypep->subDTypep();
|
||||||
} else {
|
} else {
|
||||||
break; // AstBasicDType - nothing below
|
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;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -746,6 +728,14 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep) {
|
|||||||
return 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 {
|
const char* AstScope::broken() const {
|
||||||
BROKEN_RTN(m_aboveScopep && !m_aboveScopep->brokeExists());
|
BROKEN_RTN(m_aboveScopep && !m_aboveScopep->brokeExists());
|
||||||
BROKEN_RTN(m_aboveCellp && !m_aboveCellp->brokeExists());
|
BROKEN_RTN(m_aboveCellp && !m_aboveCellp->brokeExists());
|
||||||
@@ -753,7 +743,6 @@ const char* AstScope::broken() const {
|
|||||||
BROKEN_RTN(m_modp && !m_modp->brokeExists());
|
BROKEN_RTN(m_modp && !m_modp->brokeExists());
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AstScope::cloneRelink() {
|
void AstScope::cloneRelink() {
|
||||||
if (m_aboveScopep && m_aboveScopep->clonep()) m_aboveScopep->clonep();
|
if (m_aboveScopep && m_aboveScopep->clonep()) m_aboveScopep->clonep();
|
||||||
if (m_aboveCellp && m_aboveCellp->clonep()) m_aboveCellp->clonep();
|
if (m_aboveCellp && m_aboveCellp->clonep()) m_aboveCellp->clonep();
|
||||||
@@ -761,7 +750,6 @@ void AstScope::cloneRelink() {
|
|||||||
static_cast<AstNode*>(m_modp)->clonep();
|
static_cast<AstNode*>(m_modp)->clonep();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string AstScope::nameDotless() const {
|
string AstScope::nameDotless() const {
|
||||||
string out = shortName();
|
string out = shortName();
|
||||||
string::size_type pos;
|
string::size_type pos;
|
||||||
@@ -780,7 +768,6 @@ string AstScopeName::scopePrettyNameFormatter(AstText* scopeTextp) const {
|
|||||||
if (out.substr(0, 1) == ".") out.replace(0, 1, "");
|
if (out.substr(0, 1) == ".") out.replace(0, 1, "");
|
||||||
return AstNode::prettyName(out);
|
return AstNode::prettyName(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const {
|
string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const {
|
||||||
string out;
|
string out;
|
||||||
for (AstText* textp = scopeTextp; textp; textp = VN_CAST(textp->nextp(), Text)) {
|
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
|
// 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 {
|
void AstNode::dump(std::ostream& str) const {
|
||||||
str << typeName() << " "
|
str << typeName() << " "
|
||||||
<< cvtToHex(this)
|
<< nodeAddr(this)
|
||||||
//<<" "<<cvtToHex(this)->m_backp
|
//<< " " << nodeAddr(m_backp)
|
||||||
<< " <e" << std::dec << editCount() << ((editCount() >= editCountLast()) ? "#>" : ">")
|
<< " <e" << std::dec << editCount() << ((editCount() >= editCountLast()) ? "#>" : ">")
|
||||||
<< " {" << fileline()->filenameLetters() << std::dec << fileline()->lastLineno() << "}";
|
<< " {" << fileline()->filenameLetters() << std::dec << fileline()->lastLineno()
|
||||||
if (user1p()) str << " u1=" << cvtToHex(user1p());
|
<< fileline()->firstColumnLetters() << "}";
|
||||||
if (user2p()) str << " u2=" << cvtToHex(user2p());
|
if (user1p()) str << " u1=" << nodeAddr(user1p());
|
||||||
if (user3p()) str << " u3=" << cvtToHex(user3p());
|
if (user2p()) str << " u2=" << nodeAddr(user2p());
|
||||||
if (user4p()) str << " u4=" << cvtToHex(user4p());
|
if (user3p()) str << " u3=" << nodeAddr(user3p());
|
||||||
if (user5p()) str << " u5=" << cvtToHex(user5p());
|
if (user4p()) str << " u4=" << nodeAddr(user4p());
|
||||||
|
if (user5p()) str << " u5=" << nodeAddr(user5p());
|
||||||
if (hasDType()) {
|
if (hasDType()) {
|
||||||
// Final @ so less likely to by accident read it as a nodep
|
// Final @ so less likely to by accident read it as a nodep
|
||||||
if (dtypep() == this) {
|
if (dtypep() == this) {
|
||||||
str << " @dt=this@";
|
str << " @dt=this@";
|
||||||
} else {
|
} else {
|
||||||
str << " @dt=" << cvtToHex(dtypep()) << "@";
|
str << " @dt=" << nodeAddr(dtypep()) << "@";
|
||||||
}
|
}
|
||||||
if (AstNodeDType* dtp = dtypep()) { dtp->dumpSmall(str); }
|
if (AstNodeDType* dtp = dtypep()) { dtp->dumpSmall(str); }
|
||||||
} else { // V3Broken will throw an error
|
} 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 (name() != "") {
|
||||||
if (VN_IS(this, Const)) {
|
if (VN_IS(this, Const)) {
|
||||||
@@ -1142,6 +1139,15 @@ void AstJumpGo::dump(std::ostream& str) const {
|
|||||||
str << "%Error:UNLINKED";
|
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 {
|
void AstMemberSel::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
str << " -> ";
|
str << " -> ";
|
||||||
@@ -1218,12 +1224,16 @@ void AstRange::dump(std::ostream& str) const {
|
|||||||
}
|
}
|
||||||
void AstRefDType::dump(std::ostream& str) const {
|
void AstRefDType::dump(std::ostream& str) const {
|
||||||
this->AstNodeDType::dump(str);
|
this->AstNodeDType::dump(str);
|
||||||
if (defp()) {
|
if (typedefp() || subDTypep()) {
|
||||||
static bool s_recursing = false;
|
static bool s_recursing = false;
|
||||||
if (!s_recursing) { // Prevent infinite dump if circular typedefs
|
if (!s_recursing) { // Prevent infinite dump if circular typedefs
|
||||||
s_recursing = true;
|
s_recursing = true;
|
||||||
str << " -> ";
|
str << " -> ";
|
||||||
defp()->dump(str);
|
if (typedefp()) {
|
||||||
|
typedefp()->dump(str);
|
||||||
|
} else if (subDTypep()) {
|
||||||
|
subDTypep()->dump(str);
|
||||||
|
}
|
||||||
s_recursing = false;
|
s_recursing = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1239,7 +1249,7 @@ void AstNodeDType::dump(std::ostream& str) const {
|
|||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
if (generic()) str << " [GENERIC]";
|
if (generic()) str << " [GENERIC]";
|
||||||
if (AstNodeDType* dtp = virtRefDTypep()) {
|
if (AstNodeDType* dtp = virtRefDTypep()) {
|
||||||
str << " refdt=" << cvtToHex(dtp);
|
str << " refdt=" << nodeAddr(dtp);
|
||||||
dtp->dumpSmall(str);
|
dtp->dumpSmall(str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1384,7 +1394,7 @@ void AstVarScope::dump(std::ostream& str) const {
|
|||||||
}
|
}
|
||||||
void AstVarXRef::dump(std::ostream& str) const {
|
void AstVarXRef::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
if (packagep()) { str << " pkg=" << cvtToHex(packagep()); }
|
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
|
||||||
if (lvalue()) {
|
if (lvalue()) {
|
||||||
str << " [LV] => ";
|
str << " [LV] => ";
|
||||||
} else {
|
} else {
|
||||||
@@ -1402,7 +1412,7 @@ void AstVarXRef::dump(std::ostream& str) const {
|
|||||||
}
|
}
|
||||||
void AstVarRef::dump(std::ostream& str) const {
|
void AstVarRef::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
if (packagep()) { str << " pkg=" << cvtToHex(packagep()); }
|
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
|
||||||
if (lvalue()) {
|
if (lvalue()) {
|
||||||
str << " [LV] => ";
|
str << " [LV] => ";
|
||||||
} else {
|
} else {
|
||||||
@@ -1454,7 +1464,7 @@ void AstParseRef::dump(std::ostream& str) const {
|
|||||||
}
|
}
|
||||||
void AstPackageRef::dump(std::ostream& str) const {
|
void AstPackageRef::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
if (packagep()) { str << " pkg=" << cvtToHex(packagep()); }
|
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
|
||||||
str << " -> ";
|
str << " -> ";
|
||||||
if (packagep()) {
|
if (packagep()) {
|
||||||
packagep()->dump(str);
|
packagep()->dump(str);
|
||||||
@@ -1462,7 +1472,10 @@ void AstPackageRef::dump(std::ostream& str) const {
|
|||||||
str << "UNLINKED";
|
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 {
|
void AstActive::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
str << " => ";
|
str << " => ";
|
||||||
@@ -1474,7 +1487,7 @@ void AstActive::dump(std::ostream& str) const {
|
|||||||
}
|
}
|
||||||
void AstNodeFTaskRef::dump(std::ostream& str) const {
|
void AstNodeFTaskRef::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
if (packagep()) { str << " pkg=" << cvtToHex(packagep()); }
|
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
|
||||||
str << " -> ";
|
str << " -> ";
|
||||||
if (dotted() != "") { str << ".=" << dotted() << " "; }
|
if (dotted() != "") { str << ".=" << dotted() << " "; }
|
||||||
if (taskp()) {
|
if (taskp()) {
|
||||||
@@ -1506,6 +1519,8 @@ void AstBegin::dump(std::ostream& str) const {
|
|||||||
}
|
}
|
||||||
void AstCoverDecl::dump(std::ostream& str) const {
|
void AstCoverDecl::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
|
if (!page().empty()) str << " page=" << page();
|
||||||
|
if (!linescov().empty()) str << " lc=" << linescov();
|
||||||
if (this->dataDeclNullp()) {
|
if (this->dataDeclNullp()) {
|
||||||
str << " -> ";
|
str << " -> ";
|
||||||
this->dataDeclNullp()->dump(str);
|
this->dataDeclNullp()->dump(str);
|
||||||
|
|||||||
+345
-125
@@ -319,6 +319,7 @@ public:
|
|||||||
, m_packagep(NULL) {}
|
, m_packagep(NULL) {}
|
||||||
ASTNODE_NODE_FUNCS(Class)
|
ASTNODE_NODE_FUNCS(Class)
|
||||||
virtual string verilogKwd() const { return "class"; }
|
virtual string verilogKwd() const { return "class"; }
|
||||||
|
virtual bool isHeavy() const { return true; }
|
||||||
virtual bool maybePointedTo() const { return true; }
|
virtual bool maybePointedTo() const { return true; }
|
||||||
virtual void dump(std::ostream& str) const;
|
virtual void dump(std::ostream& str) const;
|
||||||
virtual const char* broken() const {
|
virtual const char* broken() const {
|
||||||
@@ -345,19 +346,18 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class AstClassExtends : public AstNode {
|
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:
|
public:
|
||||||
AstClassExtends(FileLine* fl, AstNodeDType* dtp)
|
AstClassExtends(FileLine* fl, AstNode* classOrPkgsp)
|
||||||
: ASTGEN_SUPER(fl) {
|
: ASTGEN_SUPER(fl) {
|
||||||
childDTypep(dtp); // Only for parser
|
setNOp1p(classOrPkgsp); // Only for parser
|
||||||
}
|
}
|
||||||
ASTNODE_NODE_FUNCS(ClassExtends)
|
ASTNODE_NODE_FUNCS(ClassExtends)
|
||||||
virtual string verilogKwd() const { return "extends"; }
|
virtual string verilogKwd() const { return "extends"; }
|
||||||
virtual bool hasDType() const { return true; }
|
virtual bool hasDType() const { return true; }
|
||||||
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
AstNodeDType* classOrPkgsp() const { return VN_CAST(op1p(), NodeDType); }
|
||||||
// op1 = Type assigning to
|
void classOrPkgsp(AstNodeDType* nodep) { setOp1p(nodep); }
|
||||||
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
|
|
||||||
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
|
||||||
AstClass* classp() const; // Class being extended (after link)
|
AstClass* classp() const; // Class being extended (after link)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -541,6 +541,7 @@ public:
|
|||||||
virtual string prettyDTypeName() const;
|
virtual string prettyDTypeName() const;
|
||||||
virtual void dumpSmall(std::ostream& str) const;
|
virtual void dumpSmall(std::ostream& str) const;
|
||||||
virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); }
|
virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); }
|
||||||
|
virtual bool isHeavy() const { return true; }
|
||||||
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
||||||
// op1 = Range of variable
|
// op1 = Range of variable
|
||||||
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
|
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
|
||||||
@@ -603,6 +604,7 @@ public:
|
|||||||
virtual string prettyDTypeName() const;
|
virtual string prettyDTypeName() const;
|
||||||
virtual void dumpSmall(std::ostream& str) const;
|
virtual void dumpSmall(std::ostream& str) const;
|
||||||
virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); }
|
virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); }
|
||||||
|
virtual bool isHeavy() const { return true; }
|
||||||
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
||||||
// op1 = Range of variable
|
// op1 = Range of variable
|
||||||
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
|
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
|
||||||
@@ -815,6 +817,7 @@ public:
|
|||||||
BROKEN_RTN(dtypep() != this);
|
BROKEN_RTN(dtypep() != this);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
virtual bool isHeavy() const { return keyword() == AstBasicDTypeKwd::STRING; }
|
||||||
AstRange* rangep() const { return VN_CAST(op1p(), Range); } // op1 = Range of variable
|
AstRange* rangep() const { return VN_CAST(op1p(), Range); } // op1 = Range of variable
|
||||||
void rangep(AstRange* nodep) { setNOp1p(nodep); }
|
void rangep(AstRange* nodep) { setNOp1p(nodep); }
|
||||||
void setSignedState(const VSigning& signst) {
|
void setSignedState(const VSigning& signst) {
|
||||||
@@ -832,8 +835,8 @@ public:
|
|||||||
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
|
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
|
||||||
// (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
|
// (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
|
||||||
virtual int widthAlignBytes() const;
|
virtual int widthAlignBytes() const;
|
||||||
virtual int
|
// (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
|
||||||
widthTotalBytes() const; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
|
virtual int widthTotalBytes() const;
|
||||||
virtual bool isFourstate() const { return keyword().isFourstate(); }
|
virtual bool isFourstate() const { return keyword().isFourstate(); }
|
||||||
AstBasicDTypeKwd keyword() const { // Avoid using - use isSomething accessors instead
|
AstBasicDTypeKwd keyword() const { // Avoid using - use isSomething accessors instead
|
||||||
return m.m_keyword;
|
return m.m_keyword;
|
||||||
@@ -855,9 +858,8 @@ public:
|
|||||||
bool isDpiPrimitive() const { // DPI uses a primitive type
|
bool isDpiPrimitive() const { // DPI uses a primitive type
|
||||||
return !isDpiBitVec() && !isDpiLogicVec();
|
return !isDpiBitVec() && !isDpiLogicVec();
|
||||||
}
|
}
|
||||||
const VNumRange& nrange() const {
|
// Generally the msb/lsb/etc funcs should be used instead
|
||||||
return m.m_nrange;
|
const VNumRange& nrange() const { return m.m_nrange; }
|
||||||
} // Generally the msb/lsb/etc funcs should be used instead
|
|
||||||
int msb() const { return (rangep() ? rangep()->msbConst() : m.m_nrange.hi()); }
|
int msb() const { return (rangep() ? rangep()->msbConst() : m.m_nrange.hi()); }
|
||||||
int lsb() const { return (rangep() ? rangep()->lsbConst() : m.m_nrange.lo()); }
|
int lsb() const { return (rangep() ? rangep()->lsbConst() : m.m_nrange.lo()); }
|
||||||
int left() const { return littleEndian() ? lsb() : msb(); } // How to show a declaration
|
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 void dumpSmall(std::ostream& str) const;
|
||||||
virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); }
|
virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); }
|
||||||
virtual string prettyDTypeName() const;
|
virtual string prettyDTypeName() const;
|
||||||
|
virtual bool isHeavy() const { return true; }
|
||||||
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
||||||
// op1 = Range of variable
|
// op1 = Range of variable
|
||||||
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
|
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
|
||||||
@@ -1095,25 +1098,24 @@ public:
|
|||||||
|
|
||||||
class AstRefDType : public AstNodeDType {
|
class AstRefDType : public AstNodeDType {
|
||||||
private:
|
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
|
AstNodeDType* m_refDTypep; // data type pointed to, BELOW the AstTypedef
|
||||||
string m_name; // Name of an AstTypedef
|
string m_name; // Name of an AstTypedef
|
||||||
AstNodeModule* m_packagep; // Package hierarchy
|
AstNodeModule* m_packagep; // Package hierarchy
|
||||||
public:
|
public:
|
||||||
AstRefDType(FileLine* fl, const string& name)
|
AstRefDType(FileLine* fl, const string& name)
|
||||||
: ASTGEN_SUPER(fl)
|
: ASTGEN_SUPER(fl)
|
||||||
|
, m_typedefp(NULL)
|
||||||
, m_refDTypep(NULL)
|
, m_refDTypep(NULL)
|
||||||
, m_name(name)
|
, m_name(name)
|
||||||
, m_packagep(NULL) {}
|
, 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
|
class FlagTypeOfExpr {}; // type(expr) for parser only
|
||||||
AstRefDType(FileLine* fl, FlagTypeOfExpr, AstNode* typeofp)
|
AstRefDType(FileLine* fl, FlagTypeOfExpr, AstNode* typeofp)
|
||||||
: ASTGEN_SUPER(fl)
|
: ASTGEN_SUPER(fl)
|
||||||
|
, m_typedefp(NULL)
|
||||||
, m_refDTypep(NULL)
|
, m_refDTypep(NULL)
|
||||||
, m_packagep(NULL) {
|
, m_packagep(NULL) {
|
||||||
setOp2p(typeofp);
|
setOp2p(typeofp);
|
||||||
@@ -1121,47 +1123,53 @@ public:
|
|||||||
ASTNODE_NODE_FUNCS(RefDType)
|
ASTNODE_NODE_FUNCS(RefDType)
|
||||||
// METHODS
|
// METHODS
|
||||||
virtual const char* broken() const {
|
virtual const char* broken() const {
|
||||||
|
BROKEN_RTN(m_typedefp && !m_typedefp->brokeExists());
|
||||||
BROKEN_RTN(m_refDTypep && !m_refDTypep->brokeExists());
|
BROKEN_RTN(m_refDTypep && !m_refDTypep->brokeExists());
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
virtual void cloneRelink() {
|
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(); }
|
if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); }
|
||||||
}
|
}
|
||||||
virtual bool same(const AstNode* samep) const {
|
virtual bool same(const AstNode* samep) const {
|
||||||
const AstRefDType* asamep = static_cast<const AstRefDType*>(samep);
|
const AstRefDType* asamep = static_cast<const AstRefDType*>(samep);
|
||||||
return (m_refDTypep == asamep->m_refDTypep && m_name == asamep->m_name
|
return (m_typedefp == asamep->m_typedefp && m_refDTypep == asamep->m_refDTypep
|
||||||
&& m_packagep == asamep->m_packagep);
|
&& m_name == asamep->m_name && m_packagep == asamep->m_packagep);
|
||||||
}
|
}
|
||||||
virtual bool similarDType(AstNodeDType* samep) const {
|
virtual bool similarDType(AstNodeDType* samep) const {
|
||||||
return skipRefp()->similarDType(samep->skipRefp());
|
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 void dump(std::ostream& str = std::cout) const;
|
||||||
virtual string name() const { return m_name; }
|
virtual string name() const { return m_name; }
|
||||||
virtual string prettyDTypeName() const {
|
virtual string prettyDTypeName() const {
|
||||||
return subDTypep() ? subDTypep()->name() : prettyName();
|
return subDTypep() ? subDTypep()->name() : prettyName();
|
||||||
}
|
}
|
||||||
virtual AstBasicDType* basicp() const { return subDTypep() ? subDTypep()->basicp() : NULL; }
|
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 {
|
virtual AstNodeDType* skipRefp() const {
|
||||||
// Skip past both the Ref and the Typedef
|
// Skip past both the Ref and the Typedef
|
||||||
if (defp()) {
|
if (subDTypep()) {
|
||||||
return defp()->skipRefp();
|
return subDTypep()->skipRefp();
|
||||||
} else {
|
} else {
|
||||||
v3fatalSrc("Typedef not linked");
|
v3fatalSrc("Typedef not linked");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual AstNodeDType* skipRefToConstp() const {
|
virtual AstNodeDType* skipRefToConstp() const {
|
||||||
if (defp()) {
|
if (subDTypep()) {
|
||||||
return defp()->skipRefToConstp();
|
return subDTypep()->skipRefToConstp();
|
||||||
} else {
|
} else {
|
||||||
v3fatalSrc("Typedef not linked");
|
v3fatalSrc("Typedef not linked");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual AstNodeDType* skipRefToEnump() const {
|
virtual AstNodeDType* skipRefToEnump() const {
|
||||||
if (defp()) {
|
if (subDTypep()) {
|
||||||
return defp()->skipRefToEnump();
|
return subDTypep()->skipRefToEnump();
|
||||||
} else {
|
} else {
|
||||||
v3fatalSrc("Typedef not linked");
|
v3fatalSrc("Typedef not linked");
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1171,15 +1179,13 @@ public:
|
|||||||
virtual int widthTotalBytes() const { return dtypeSkipRefp()->widthTotalBytes(); }
|
virtual int widthTotalBytes() const { return dtypeSkipRefp()->widthTotalBytes(); }
|
||||||
void name(const string& flag) { m_name = flag; }
|
void name(const string& flag) { m_name = flag; }
|
||||||
// op1 = Range of variable
|
// op1 = Range of variable
|
||||||
AstNodeDType* dtypeSkipRefp() const { return defp()->skipRefp(); }
|
AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); }
|
||||||
AstNodeDType* defp() const {
|
AstTypedef* typedefp() const { return m_typedefp; }
|
||||||
return m_refDTypep;
|
void typedefp(AstTypedef* nodep) { m_typedefp = nodep; }
|
||||||
} // Code backward compatibility name for refDTypep
|
|
||||||
AstNodeDType* refDTypep() const { return m_refDTypep; }
|
AstNodeDType* refDTypep() const { return m_refDTypep; }
|
||||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||||
virtual AstNodeDType* virtRefDTypep() const { return refDTypep(); }
|
virtual AstNodeDType* virtRefDTypep() const { return refDTypep(); }
|
||||||
virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); }
|
virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); }
|
||||||
virtual AstNodeDType* subDTypep() const { return m_refDTypep; }
|
|
||||||
AstNodeModule* packagep() const { return m_packagep; }
|
AstNodeModule* packagep() const { return m_packagep; }
|
||||||
void packagep(AstNodeModule* nodep) { m_packagep = nodep; }
|
void packagep(AstNodeModule* nodep) { m_packagep = nodep; }
|
||||||
AstNode* typeofp() const { return op2p(); }
|
AstNode* typeofp() const { return op2p(); }
|
||||||
@@ -1902,11 +1908,11 @@ public:
|
|||||||
VDirection declDirection() const { return m_declDirection; }
|
VDirection declDirection() const { return m_declDirection; }
|
||||||
void varType(AstVarType type) { m_varType = type; }
|
void varType(AstVarType type) { m_varType = type; }
|
||||||
void varType2Out() {
|
void varType2Out() {
|
||||||
m_tristate = 0;
|
m_tristate = false;
|
||||||
m_direction = VDirection::OUTPUT;
|
m_direction = VDirection::OUTPUT;
|
||||||
}
|
}
|
||||||
void varType2In() {
|
void varType2In() {
|
||||||
m_tristate = 0;
|
m_tristate = false;
|
||||||
m_direction = VDirection::INPUT;
|
m_direction = VDirection::INPUT;
|
||||||
}
|
}
|
||||||
AstBasicDTypeKwd declKwd() const { return m_declKwd; }
|
AstBasicDTypeKwd declKwd() const { return m_declKwd; }
|
||||||
@@ -1918,7 +1924,7 @@ public:
|
|||||||
string vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc = "") const;
|
string vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc = "") const;
|
||||||
string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc
|
string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc
|
||||||
string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, 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);
|
void combineType(AstVarType type);
|
||||||
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
||||||
// op1 = Range of variable
|
// op1 = Range of variable
|
||||||
@@ -2078,7 +2084,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
class VlArgTypeRecursed;
|
class VlArgTypeRecursed;
|
||||||
VlArgTypeRecursed vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep,
|
VlArgTypeRecursed vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep,
|
||||||
bool arrayed) const;
|
bool compound = false) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AstDefParam : public AstNode {
|
class AstDefParam : public AstNode {
|
||||||
@@ -2867,9 +2873,11 @@ public:
|
|||||||
class AstDot : public AstNode {
|
class AstDot : public AstNode {
|
||||||
// A dot separating paths in an AstVarXRef, AstFuncRef or AstTaskRef
|
// A dot separating paths in an AstVarXRef, AstFuncRef or AstTaskRef
|
||||||
// These are eliminated in the link stage
|
// These are eliminated in the link stage
|
||||||
|
bool m_colon; // Is a "::" instead of a "." (lhs must be package/class)
|
||||||
public:
|
public:
|
||||||
AstDot(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
AstDot(FileLine* fl, bool colon, AstNode* lhsp, AstNode* rhsp)
|
||||||
: ASTGEN_SUPER(fl) {
|
: ASTGEN_SUPER(fl)
|
||||||
|
, m_colon(colon) {
|
||||||
setOp1p(lhsp);
|
setOp1p(lhsp);
|
||||||
setOp2p(rhsp);
|
setOp2p(rhsp);
|
||||||
}
|
}
|
||||||
@@ -2877,23 +2885,28 @@ public:
|
|||||||
// For parser, make only if non-null package
|
// For parser, make only if non-null package
|
||||||
static AstNode* newIfPkg(FileLine* fl, AstPackage* packagep, AstNode* rhsp) {
|
static AstNode* newIfPkg(FileLine* fl, AstPackage* packagep, AstNode* rhsp) {
|
||||||
if (!packagep) return 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 void dump(std::ostream& str) const;
|
||||||
virtual string emitVerilog() { V3ERROR_NA_RETURN(""); }
|
virtual string emitVerilog() { V3ERROR_NA_RETURN(""); }
|
||||||
virtual string emitC() { V3ERROR_NA_RETURN(""); }
|
virtual string emitC() { V3ERROR_NA_RETURN(""); }
|
||||||
AstNode* lhsp() const { return op1p(); }
|
AstNode* lhsp() const { return op1p(); }
|
||||||
AstNode* rhsp() const { return op2p(); }
|
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
|
// A $ in the parser, used for unbounded and queues
|
||||||
|
// Due to where is used, treated as Signed32
|
||||||
public:
|
public:
|
||||||
explicit AstUnbounded(FileLine* fl)
|
explicit AstUnbounded(FileLine* fl)
|
||||||
: ASTGEN_SUPER(fl) {}
|
: ASTGEN_SUPER(fl) {
|
||||||
|
dtypeSetSigned32();
|
||||||
|
}
|
||||||
ASTNODE_NODE_FUNCS(Unbounded)
|
ASTNODE_NODE_FUNCS(Unbounded)
|
||||||
virtual string emitVerilog() { return "$"; }
|
virtual string emitVerilog() { return "$"; }
|
||||||
virtual string emitC() { V3ERROR_NA_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
|
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;
|
VAlwaysKwd m_keyword;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AstAlways(FileLine* fl, VAlwaysKwd keyword, AstSenTree* sensesp, AstNode* bodysp)
|
AstAlways(FileLine* fl, VAlwaysKwd keyword, AstSenTree* sensesp, AstNode* bodysp)
|
||||||
: ASTGEN_SUPER(fl)
|
: ASTGEN_SUPER(fl, bodysp)
|
||||||
, m_keyword(keyword) {
|
, m_keyword(keyword) {
|
||||||
addNOp1p(sensesp);
|
addNOp1p(sensesp);
|
||||||
addNOp2p(bodysp);
|
|
||||||
}
|
}
|
||||||
ASTNODE_NODE_FUNCS(Always)
|
ASTNODE_NODE_FUNCS(Always)
|
||||||
//
|
//
|
||||||
virtual void dump(std::ostream& str) const;
|
virtual void dump(std::ostream& str) const;
|
||||||
AstSenTree* sensesp() const { return VN_CAST(op1p(), SenTree); } // op1 = Sensitivity list
|
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; }
|
VAlwaysKwd keyword() const { return m_keyword; }
|
||||||
// Special accessors
|
|
||||||
bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class AstAlwaysPublic : public AstNodeStmt {
|
class AstAlwaysPublic : public AstNodeStmt {
|
||||||
@@ -3300,14 +3322,17 @@ private:
|
|||||||
string m_page;
|
string m_page;
|
||||||
string m_text;
|
string m_text;
|
||||||
string m_hier;
|
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
|
int m_binNum; // Set by V3EmitCSyms to tell final V3Emit what to increment
|
||||||
public:
|
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) {
|
: ASTGEN_SUPER(fl) {
|
||||||
m_text = comment;
|
|
||||||
m_page = page;
|
m_page = page;
|
||||||
m_column = column;
|
m_text = comment;
|
||||||
|
m_linescov = linescov;
|
||||||
|
m_offset = offset;
|
||||||
m_binNum = 0;
|
m_binNum = 0;
|
||||||
m_dataDeclp = NULL;
|
m_dataDeclp = NULL;
|
||||||
}
|
}
|
||||||
@@ -3325,10 +3350,11 @@ public:
|
|||||||
virtual void dump(std::ostream& str) const;
|
virtual void dump(std::ostream& str) const;
|
||||||
virtual int instrCount() const { return 1 + 2 * instrCountLd(); }
|
virtual int instrCount() const { return 1 + 2 * instrCountLd(); }
|
||||||
virtual bool maybePointedTo() const { return true; }
|
virtual bool maybePointedTo() const { return true; }
|
||||||
int column() const { return m_column; }
|
|
||||||
void binNum(int flag) { m_binNum = flag; }
|
void binNum(int flag) { m_binNum = flag; }
|
||||||
int binNum() const { return m_binNum; }
|
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& 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& page() const { return m_page; }
|
||||||
const string& hier() const { return m_hier; }
|
const string& hier() const { return m_hier; }
|
||||||
void hier(const string& flag) { m_hier = flag; }
|
void hier(const string& flag) { m_hier = flag; }
|
||||||
@@ -3336,8 +3362,8 @@ public:
|
|||||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||||
virtual bool same(const AstNode* samep) const {
|
virtual bool same(const AstNode* samep) const {
|
||||||
const AstCoverDecl* asamep = static_cast<const AstCoverDecl*>(samep);
|
const AstCoverDecl* asamep = static_cast<const AstCoverDecl*>(samep);
|
||||||
return (fileline() == asamep->fileline() && hier() == asamep->hier()
|
return (fileline() == asamep->fileline() && linescov() == asamep->linescov()
|
||||||
&& comment() == asamep->comment() && column() == asamep->column());
|
&& hier() == asamep->hier() && comment() == asamep->comment());
|
||||||
}
|
}
|
||||||
virtual bool isPredictOptimizable() const { return false; }
|
virtual bool isPredictOptimizable() const { return false; }
|
||||||
void dataDeclp(AstCoverDecl* nodep) { m_dataDeclp = nodep; }
|
void dataDeclp(AstCoverDecl* nodep) { m_dataDeclp = nodep; }
|
||||||
@@ -3626,6 +3652,7 @@ public:
|
|||||||
virtual string emitVerilog() { return "%f" + verilogKwd() + "(%l)"; }
|
virtual string emitVerilog() { return "%f" + verilogKwd() + "(%l)"; }
|
||||||
virtual string emitC() { V3ERROR_NA_RETURN(""); }
|
virtual string emitC() { V3ERROR_NA_RETURN(""); }
|
||||||
virtual bool isGateOptimizable() const { return false; }
|
virtual bool isGateOptimizable() const { return false; }
|
||||||
|
virtual bool isHeavy() const { return true; }
|
||||||
virtual bool isPredictOptimizable() const { return false; }
|
virtual bool isPredictOptimizable() const { return false; }
|
||||||
virtual bool isOutputter() const { return true; }
|
virtual bool isOutputter() const { return true; }
|
||||||
virtual bool cleanOut() const { return true; }
|
virtual bool cleanOut() const { return true; }
|
||||||
@@ -3777,6 +3804,7 @@ public:
|
|||||||
ASTNODE_NODE_FUNCS(FOpen)
|
ASTNODE_NODE_FUNCS(FOpen)
|
||||||
virtual string verilogKwd() const { return "$fopen"; }
|
virtual string verilogKwd() const { return "$fopen"; }
|
||||||
virtual bool isGateOptimizable() const { return false; }
|
virtual bool isGateOptimizable() const { return false; }
|
||||||
|
virtual bool isHeavy() const { return true; }
|
||||||
virtual bool isPredictOptimizable() const { return false; }
|
virtual bool isPredictOptimizable() const { return false; }
|
||||||
virtual bool isPure() const { return false; }
|
virtual bool isPure() const { return false; }
|
||||||
virtual bool isOutputter() const { return true; }
|
virtual bool isOutputter() const { return true; }
|
||||||
@@ -3788,6 +3816,28 @@ public:
|
|||||||
AstNode* modep() const { return op3p(); }
|
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 {
|
class AstFFlush : public AstNodeStmt {
|
||||||
// Parents: stmtlist
|
// Parents: stmtlist
|
||||||
// Children: file which must be a varref
|
// Children: file which must be a varref
|
||||||
@@ -4009,6 +4059,7 @@ public:
|
|||||||
setNOp4p(msbp);
|
setNOp4p(msbp);
|
||||||
}
|
}
|
||||||
virtual bool isGateOptimizable() const { return false; }
|
virtual bool isGateOptimizable() const { return false; }
|
||||||
|
virtual bool isHeavy() const { return true; }
|
||||||
virtual bool isPredictOptimizable() const { return false; }
|
virtual bool isPredictOptimizable() const { return false; }
|
||||||
virtual bool isPure() const { return false; }
|
virtual bool isPure() const { return false; }
|
||||||
virtual bool isOutputter() const { return true; }
|
virtual bool isOutputter() const { return true; }
|
||||||
@@ -4099,6 +4150,7 @@ public:
|
|||||||
virtual string emitVerilog() { return "%f$value$plusargs(%l, %k%r)"; }
|
virtual string emitVerilog() { return "%f$value$plusargs(%l, %k%r)"; }
|
||||||
virtual string emitC() { V3ERROR_NA_RETURN(""); }
|
virtual string emitC() { V3ERROR_NA_RETURN(""); }
|
||||||
virtual bool isGateOptimizable() const { return false; }
|
virtual bool isGateOptimizable() const { return false; }
|
||||||
|
virtual bool isHeavy() const { return true; }
|
||||||
virtual bool isPredictOptimizable() const { return false; }
|
virtual bool isPredictOptimizable() const { return false; }
|
||||||
virtual bool cleanOut() const { return true; }
|
virtual bool cleanOut() const { return true; }
|
||||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||||
@@ -4283,44 +4335,81 @@ public:
|
|||||||
void priorityPragma(bool flag) { m_priorityPragma = flag; }
|
void priorityPragma(bool flag) { m_priorityPragma = flag; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class AstJumpLabel : public AstNodeStmt {
|
class AstJumpBlock : public AstNodeStmt {
|
||||||
// Jump point declaration
|
// Block of code including a JumpGo and JumpLabel
|
||||||
// Separate from AstJumpGo; as a declaration can't be deleted
|
|
||||||
// Parents: {statement list}
|
// Parents: {statement list}
|
||||||
// Children: {statement list, with JumpGo below}
|
// Children: {statement list, with JumpGo and JumpLabel below}
|
||||||
private:
|
private:
|
||||||
|
AstJumpLabel* m_labelp; // [After V3Jump] Pointer to declaration
|
||||||
int m_labelNum; // Set by V3EmitCSyms to tell final V3Emit what to increment
|
int m_labelNum; // Set by V3EmitCSyms to tell final V3Emit what to increment
|
||||||
public:
|
public:
|
||||||
AstJumpLabel(FileLine* fl, AstNode* stmtsp)
|
// After construction must call ->labelp to associate with appropriate label
|
||||||
|
AstJumpBlock(FileLine* fl, AstNode* stmtsp)
|
||||||
: ASTGEN_SUPER(fl)
|
: ASTGEN_SUPER(fl)
|
||||||
, m_labelNum(0) {
|
, m_labelNum(0) {
|
||||||
addNOp1p(stmtsp);
|
addNOp1p(stmtsp);
|
||||||
}
|
}
|
||||||
|
virtual const char* broken() const;
|
||||||
|
virtual void cloneRelink();
|
||||||
|
ASTNODE_NODE_FUNCS(JumpBlock)
|
||||||
virtual int instrCount() const { return 0; }
|
virtual int instrCount() const { return 0; }
|
||||||
ASTNODE_NODE_FUNCS(JumpLabel)
|
|
||||||
virtual bool maybePointedTo() const { return true; }
|
virtual bool maybePointedTo() const { return true; }
|
||||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||||
virtual bool same(const AstNode* samep) const { return true; }
|
virtual bool same(const AstNode* samep) const { return true; }
|
||||||
// op1 = Statements
|
// op1 = Statements
|
||||||
AstNode* stmtsp() const { return op1p(); } // op1 = List of statements
|
AstNode* stmtsp() const { return op1p(); } // op1 = List of statements
|
||||||
void addStmtsp(AstNode* nodep) { addNOp1p(nodep); }
|
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; }
|
int labelNum() const { return m_labelNum; }
|
||||||
void labelNum(int flag) { m_labelNum = flag; }
|
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 {
|
class AstJumpGo : public AstNodeStmt {
|
||||||
// Jump point; branch up to the JumpLabel
|
// Jump point; branch down to a JumpLabel
|
||||||
// Parents: {statement list}
|
// No support for backward jumps at present
|
||||||
|
// Parents: {statement list with JumpBlock above}
|
||||||
|
// Children: none
|
||||||
private:
|
private:
|
||||||
AstJumpLabel* m_labelp; // [After V3Jump] Pointer to declaration
|
AstJumpLabel* m_labelp; // [After V3Jump] Pointer to declaration
|
||||||
public:
|
public:
|
||||||
AstJumpGo(FileLine* fl, AstJumpLabel* labelp)
|
AstJumpGo(FileLine* fl, AstJumpLabel* labelp)
|
||||||
: ASTGEN_SUPER(fl) {
|
: ASTGEN_SUPER(fl)
|
||||||
m_labelp = labelp;
|
, m_labelp(labelp) {}
|
||||||
}
|
ASTNODE_NODE_FUNCS(JumpGo);
|
||||||
ASTNODE_NODE_FUNCS(JumpGo)
|
|
||||||
virtual const char* broken() const {
|
virtual const char* broken() const {
|
||||||
BROKEN_RTN(!labelp()->brokeExistsAbove());
|
BROKEN_RTN(!labelp()->brokeExistsBelow());
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
virtual void cloneRelink() {
|
virtual void cloneRelink() {
|
||||||
@@ -4330,7 +4419,6 @@ public:
|
|||||||
virtual int instrCount() const { return instrCountBranch(); }
|
virtual int instrCount() const { return instrCountBranch(); }
|
||||||
virtual V3Hash sameHash() const { return V3Hash(labelp()); }
|
virtual V3Hash sameHash() const { return V3Hash(labelp()); }
|
||||||
virtual bool same(const AstNode* samep) const {
|
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();
|
return labelp() == static_cast<const AstJumpGo*>(samep)->labelp();
|
||||||
}
|
}
|
||||||
virtual bool isGateOptimizable() const { return false; }
|
virtual bool isGateOptimizable() const { return false; }
|
||||||
@@ -4433,28 +4521,6 @@ public:
|
|||||||
void joinType(const VJoinType& flag) { m_joinType = flag; }
|
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 {
|
class AstInside : public AstNodeMath {
|
||||||
public:
|
public:
|
||||||
AstInside(FileLine* fl, AstNode* exprp, AstNode* itemsp)
|
AstInside(FileLine* fl, AstNode* exprp, AstNode* itemsp)
|
||||||
@@ -4761,35 +4827,36 @@ class AstTraceDecl : public AstNodeStmt {
|
|||||||
// Trace point declaration
|
// Trace point declaration
|
||||||
// Separate from AstTraceInc; as a declaration can't be deleted
|
// Separate from AstTraceInc; as a declaration can't be deleted
|
||||||
// Parents: {statement list}
|
// Parents: {statement list}
|
||||||
// Children: none
|
// Children: expression being traced
|
||||||
private:
|
private:
|
||||||
string m_showname; // Name of variable
|
|
||||||
uint32_t m_code; // Trace identifier code; converted to ASCII by trace routines
|
uint32_t m_code; // Trace identifier code; converted to ASCII by trace routines
|
||||||
VNumRange m_bitRange; // Property of var the trace details
|
const string m_showname; // Name of variable
|
||||||
VNumRange m_arrayRange; // Property of var the trace details
|
const VNumRange m_bitRange; // Property of var the trace details
|
||||||
uint32_t m_codeInc; // Code increment
|
const VNumRange m_arrayRange; // Property of var the trace details
|
||||||
AstVarType m_varType; // Type of variable (for localparam vs. param)
|
const uint32_t m_codeInc; // Code increment
|
||||||
AstBasicDTypeKwd m_declKwd; // Keyword at declaration time
|
const AstVarType m_varType; // Type of variable (for localparam vs. param)
|
||||||
VDirection m_declDirection; // Declared direction input/output etc
|
const AstBasicDTypeKwd m_declKwd; // Keyword at declaration time
|
||||||
bool m_isScoped; // Uses run-time scope (for interfaces)
|
const VDirection m_declDirection; // Declared direction input/output etc
|
||||||
|
const bool m_isScoped; // Uses run-time scope (for interfaces)
|
||||||
public:
|
public:
|
||||||
AstTraceDecl(FileLine* fl, const string& showname,
|
AstTraceDecl(FileLine* fl, const string& showname,
|
||||||
AstVar* varp, // For input/output state etc
|
AstVar* varp, // For input/output state etc
|
||||||
AstNode* valuep, const VNumRange& bitRange, const VNumRange& arrayRange,
|
AstNode* valuep, const VNumRange& bitRange, const VNumRange& arrayRange,
|
||||||
bool isScoped)
|
bool isScoped)
|
||||||
: ASTGEN_SUPER(fl)
|
: ASTGEN_SUPER(fl)
|
||||||
|
, m_code(0)
|
||||||
, m_showname(showname)
|
, m_showname(showname)
|
||||||
, m_bitRange(bitRange)
|
, m_bitRange(bitRange)
|
||||||
, m_arrayRange(arrayRange)
|
, 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) {
|
, m_isScoped(isScoped) {
|
||||||
dtypeFrom(valuep);
|
dtypeFrom(valuep);
|
||||||
m_code = 0;
|
addNOp1p(valuep);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
virtual int instrCount() const { return 100; } // Large...
|
virtual int instrCount() const { return 100; } // Large...
|
||||||
ASTNODE_NODE_FUNCS(TraceDecl)
|
ASTNODE_NODE_FUNCS(TraceDecl)
|
||||||
@@ -4808,20 +4875,25 @@ public:
|
|||||||
AstBasicDTypeKwd declKwd() const { return m_declKwd; }
|
AstBasicDTypeKwd declKwd() const { return m_declKwd; }
|
||||||
VDirection declDirection() const { return m_declDirection; }
|
VDirection declDirection() const { return m_declDirection; }
|
||||||
bool isScoped() const { return m_isScoped; }
|
bool isScoped() const { return m_isScoped; }
|
||||||
|
AstNode* valuep() const { return op1p(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class AstTraceInc : public AstNodeStmt {
|
class AstTraceInc : public AstNodeStmt {
|
||||||
// Trace point; incremental change detect and dump
|
// Trace point dump
|
||||||
// Parents: {statement list}
|
// Parents: {statement list}
|
||||||
// Children: incremental value
|
// Children: op1: things to emit before this node,
|
||||||
|
// op2: expression being traced (from decl)
|
||||||
|
|
||||||
private:
|
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:
|
public:
|
||||||
AstTraceInc(FileLine* fl, AstTraceDecl* declp, AstNode* valuep)
|
AstTraceInc(FileLine* fl, AstTraceDecl* declp, bool full)
|
||||||
: ASTGEN_SUPER(fl) {
|
: ASTGEN_SUPER(fl)
|
||||||
|
, m_declp(declp)
|
||||||
|
, m_full(full) {
|
||||||
dtypeFrom(declp);
|
dtypeFrom(declp);
|
||||||
m_declp = declp;
|
addOp2p(declp->valuep()->cloneTree(true));
|
||||||
addNOp2p(valuep);
|
|
||||||
}
|
}
|
||||||
ASTNODE_NODE_FUNCS(TraceInc)
|
ASTNODE_NODE_FUNCS(TraceInc)
|
||||||
virtual const char* broken() const {
|
virtual const char* broken() const {
|
||||||
@@ -4843,13 +4915,11 @@ public:
|
|||||||
virtual bool isOutputter() const { return true; }
|
virtual bool isOutputter() const { return true; }
|
||||||
// but isPure() true
|
// but isPure() true
|
||||||
// op1 = Statements before the value
|
// op1 = Statements before the value
|
||||||
AstNode* precondsp() const {
|
AstNode* precondsp() const { return op1p(); }
|
||||||
return op1p();
|
|
||||||
} // op1 = prepare statements for condition (exec every loop)
|
|
||||||
void addPrecondsp(AstNode* newp) { addOp1p(newp); }
|
void addPrecondsp(AstNode* newp) { addOp1p(newp); }
|
||||||
// op2 = Value to trace
|
|
||||||
AstTraceDecl* declp() const { return m_declp; } // Where defined
|
|
||||||
AstNode* valuep() const { return op2p(); }
|
AstNode* valuep() const { return op2p(); }
|
||||||
|
AstTraceDecl* declp() const { return m_declp; }
|
||||||
|
bool full() const { return m_full; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class AstActive : public AstNode {
|
class AstActive : public AstNode {
|
||||||
@@ -5397,6 +5467,33 @@ public:
|
|||||||
virtual bool sizeMattersLhs() const { return false; }
|
virtual bool sizeMattersLhs() const { return false; }
|
||||||
virtual int instrCount() const { return widthInstrs() * 16; }
|
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 {
|
class AstCountOnes : public AstNodeUniop {
|
||||||
// Number of bits set in vector
|
// Number of bits set in vector
|
||||||
public:
|
public:
|
||||||
@@ -5426,6 +5523,24 @@ public:
|
|||||||
virtual bool cleanLhs() const { return false; }
|
virtual bool cleanLhs() const { return false; }
|
||||||
virtual bool sizeMattersLhs() 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 {
|
class AstOneHot : public AstNodeUniop {
|
||||||
// True if only single bit set in vector
|
// True if only single bit set in vector
|
||||||
public:
|
public:
|
||||||
@@ -5967,6 +6082,7 @@ public:
|
|||||||
virtual bool cleanOut() const { return true; }
|
virtual bool cleanOut() const { return true; }
|
||||||
virtual bool cleanLhs() const { return true; }
|
virtual bool cleanLhs() const { return true; }
|
||||||
virtual bool sizeMattersLhs() const { return false; }
|
virtual bool sizeMattersLhs() const { return false; }
|
||||||
|
virtual bool isHeavy() const { return true; }
|
||||||
FmtType format() const { return m_fmt; }
|
FmtType format() const { return m_fmt; }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -7133,6 +7249,106 @@ public:
|
|||||||
virtual int instrCount() const { return widthInstrs() * instrCountMul() * 10; }
|
virtual int instrCount() const { return widthInstrs() * instrCountMul() * 10; }
|
||||||
virtual bool signedFlavor() const { return true; }
|
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 {
|
class AstEqCase : public AstNodeBiCom {
|
||||||
public:
|
public:
|
||||||
AstEqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
AstEqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
||||||
@@ -7500,6 +7716,7 @@ public:
|
|||||||
virtual bool sizeMattersLhs() const { return false; }
|
virtual bool sizeMattersLhs() const { return false; }
|
||||||
virtual bool sizeMattersRhs() const { return false; }
|
virtual bool sizeMattersRhs() const { return false; }
|
||||||
virtual bool sizeMattersThs() const { return false; }
|
virtual bool sizeMattersThs() const { return false; }
|
||||||
|
virtual bool isHeavy() const { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class AstGetcN : public AstNodeBiop {
|
class AstGetcN : public AstNodeBiop {
|
||||||
@@ -7525,6 +7742,7 @@ public:
|
|||||||
virtual bool cleanRhs() const { return true; }
|
virtual bool cleanRhs() const { return true; }
|
||||||
virtual bool sizeMattersLhs() const { return false; }
|
virtual bool sizeMattersLhs() const { return false; }
|
||||||
virtual bool sizeMattersRhs() const { return false; }
|
virtual bool sizeMattersRhs() const { return false; }
|
||||||
|
virtual bool isHeavy() const { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class AstGetcRefN : public AstNodeBiop {
|
class AstGetcRefN : public AstNodeBiop {
|
||||||
@@ -7543,13 +7761,14 @@ public:
|
|||||||
V3ERROR_NA;
|
V3ERROR_NA;
|
||||||
}
|
}
|
||||||
virtual string emitVerilog() { return "%k%l[%r]"; }
|
virtual string emitVerilog() { return "%k%l[%r]"; }
|
||||||
virtual string emitC() { V3ERROR_NA; }
|
virtual string emitC() { V3ERROR_NA_RETURN(""); }
|
||||||
virtual string emitSimpleOperator() { return ""; }
|
virtual string emitSimpleOperator() { return ""; }
|
||||||
virtual bool cleanOut() const { return true; }
|
virtual bool cleanOut() const { return true; }
|
||||||
virtual bool cleanLhs() const { return true; }
|
virtual bool cleanLhs() const { return true; }
|
||||||
virtual bool cleanRhs() const { return true; }
|
virtual bool cleanRhs() const { return true; }
|
||||||
virtual bool sizeMattersLhs() const { return false; }
|
virtual bool sizeMattersLhs() const { return false; }
|
||||||
virtual bool sizeMattersRhs() const { return false; }
|
virtual bool sizeMattersRhs() const { return false; }
|
||||||
|
virtual bool isHeavy() const { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class AstSubstrN : public AstNodeTriop {
|
class AstSubstrN : public AstNodeTriop {
|
||||||
@@ -7575,6 +7794,7 @@ public:
|
|||||||
virtual bool sizeMattersLhs() const { return false; }
|
virtual bool sizeMattersLhs() const { return false; }
|
||||||
virtual bool sizeMattersRhs() const { return false; }
|
virtual bool sizeMattersRhs() const { return false; }
|
||||||
virtual bool sizeMattersThs() const { return false; }
|
virtual bool sizeMattersThs() const { return false; }
|
||||||
|
virtual bool isHeavy() const { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class AstCompareNN : public AstNodeBiop {
|
class AstCompareNN : public AstNodeBiop {
|
||||||
@@ -7607,6 +7827,7 @@ public:
|
|||||||
virtual bool cleanRhs() const { return true; }
|
virtual bool cleanRhs() const { return true; }
|
||||||
virtual bool sizeMattersLhs() const { return false; }
|
virtual bool sizeMattersLhs() const { return false; }
|
||||||
virtual bool sizeMattersRhs() const { return false; }
|
virtual bool sizeMattersRhs() const { return false; }
|
||||||
|
virtual bool isHeavy() const { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class AstPast : public AstNodeMath {
|
class AstPast : public AstNodeMath {
|
||||||
@@ -7675,11 +7896,10 @@ public:
|
|||||||
virtual bool cleanOut() const { V3ERROR_NA_RETURN(""); }
|
virtual bool cleanOut() const { V3ERROR_NA_RETURN(""); }
|
||||||
virtual int instrCount() const { return widthInstrs(); }
|
virtual int instrCount() const { return widthInstrs(); }
|
||||||
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
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(); }
|
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
|
AstNode* itemsp() const { return op2p(); } // op2 = AstPatReplicate, AstPatMember, etc
|
||||||
};
|
};
|
||||||
class AstPatMember : public AstNodeMath {
|
class AstPatMember : public AstNodeMath {
|
||||||
|
|||||||
@@ -30,12 +30,9 @@
|
|||||||
|
|
||||||
#include "V3Global.h"
|
#include "V3Global.h"
|
||||||
#include "V3Begin.h"
|
#include "V3Begin.h"
|
||||||
#include "V3Inst.h"
|
|
||||||
#include "V3Ast.h"
|
#include "V3Ast.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdarg>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,6 @@
|
|||||||
#include "V3Branch.h"
|
#include "V3Branch.h"
|
||||||
#include "V3Ast.h"
|
#include "V3Ast.h"
|
||||||
|
|
||||||
#include <cstdarg>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|||||||
+20
-5
@@ -32,7 +32,6 @@
|
|||||||
#include "V3AstConstOnly.h"
|
#include "V3AstConstOnly.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdarg>
|
|
||||||
#include VL_INCLUDE_UNORDERED_MAP
|
#include VL_INCLUDE_UNORDERED_MAP
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
@@ -131,6 +130,14 @@ public:
|
|||||||
if (!(iter->second & FLAG_LINKABLE)) return false;
|
if (!(iter->second & FLAG_LINKABLE)) return false;
|
||||||
return true;
|
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) {
|
static bool okIfBelow(const AstNode* nodep) {
|
||||||
// Must be linked to and below current node
|
// Must be linked to and below current node
|
||||||
if (!okIfLinkedTo(nodep)) return false;
|
if (!okIfLinkedTo(nodep)) return false;
|
||||||
@@ -142,19 +149,22 @@ public:
|
|||||||
static void prepForTree() {
|
static void prepForTree() {
|
||||||
#ifndef VL_LEAK_CHECKS
|
#ifndef VL_LEAK_CHECKS
|
||||||
s_nodes.clear();
|
s_nodes.clear();
|
||||||
#endif
|
#else
|
||||||
for (NodeMap::iterator it = s_nodes.begin(); it != s_nodes.end(); ++it) {
|
for (NodeMap::iterator it = s_nodes.begin(); it != s_nodes.end(); ++it) {
|
||||||
it->second &= ~FLAG_IN_TREE;
|
it->second &= ~FLAG_IN_TREE;
|
||||||
it->second &= ~FLAG_LINKABLE;
|
it->second &= ~FLAG_LINKABLE;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
static void doneWithTree() {
|
static void doneWithTree() {
|
||||||
for (int backs = 0; backs < 2;
|
for (int backs = 0; backs < 2;
|
||||||
backs++) { // Those with backp() are probably under one leaking without
|
backs++) { // Those with backp() are probably under one leaking without
|
||||||
for (NodeMap::iterator it = s_nodes.begin(); it != s_nodes.end(); ++it) {
|
for (NodeMap::iterator it = s_nodes.begin(); it != s_nodes.end(); ++it) {
|
||||||
if ((it->second & FLAG_ALLOCATED) && !(it->second & FLAG_IN_TREE)
|
// LCOV_EXCL_START
|
||||||
&& !(it->second & FLAG_LEAKED)
|
if (VL_UNCOVERABLE((it->second & FLAG_ALLOCATED) && !(it->second & FLAG_IN_TREE)
|
||||||
&& (it->first->backp() ? backs == 1 : backs == 0)) {
|
&& !(it->second & FLAG_LEAKED)
|
||||||
|
&& (it->first->backp() ? backs == 1 : backs == 0))) {
|
||||||
|
|
||||||
// Use only AstNode::dump instead of the virtual one, as there
|
// Use only AstNode::dump instead of the virtual one, as there
|
||||||
// may be varp() and other cross links that are bad.
|
// may be varp() and other cross links that are bad.
|
||||||
if (v3Global.opt.debugCheck()) {
|
if (v3Global.opt.debugCheck()) {
|
||||||
@@ -173,6 +183,7 @@ public:
|
|||||||
}
|
}
|
||||||
it->second |= FLAG_LEAKED;
|
it->second |= FLAG_LEAKED;
|
||||||
}
|
}
|
||||||
|
// LCOV_EXCL_STOP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,6 +204,10 @@ bool AstNode::brokeExistsAbove() const {
|
|||||||
// Called by node->broken() routines to do table lookup
|
// Called by node->broken() routines to do table lookup
|
||||||
return BrokenTable::okIfBelow(this);
|
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 "V3CCtors.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
|
||||||
#include <cstdarg>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
class V3CCtorsVisitor {
|
class V3CCtorsVisitor {
|
||||||
private:
|
private:
|
||||||
@@ -49,7 +46,6 @@ private:
|
|||||||
int m_funcNum; // Function number being built
|
int m_funcNum; // Function number being built
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AstCFunc* builtFuncp() const { return m_tlFuncp; }
|
|
||||||
void add(AstNode* nodep) {
|
void add(AstNode* nodep) {
|
||||||
if (v3Global.opt.outputSplitCFuncs() && v3Global.opt.outputSplitCFuncs() < m_numStmts) {
|
if (v3Global.opt.outputSplitCFuncs() && v3Global.opt.outputSplitCFuncs() < m_numStmts) {
|
||||||
m_funcp = NULL;
|
m_funcp = NULL;
|
||||||
@@ -146,13 +142,11 @@ void V3CCtors::cctorsAll() {
|
|||||||
modp = VN_CAST(modp->nextp(), NodeModule)) {
|
modp = VN_CAST(modp->nextp(), NodeModule)) {
|
||||||
// Process each module in turn
|
// Process each module in turn
|
||||||
{
|
{
|
||||||
AstCFunc* varResetFuncp;
|
|
||||||
V3CCtorsVisitor var_reset(
|
V3CCtorsVisitor var_reset(
|
||||||
modp, "_ctor_var_reset",
|
modp, "_ctor_var_reset",
|
||||||
(VN_IS(modp, Class) ? EmitCBaseVisitor::symClassVar() : ""),
|
(VN_IS(modp, Class) ? EmitCBaseVisitor::symClassVar() : ""),
|
||||||
(VN_IS(modp, Class) ? "vlSymsp" : ""),
|
(VN_IS(modp, Class) ? "vlSymsp" : ""),
|
||||||
(VN_IS(modp, Class) ? "if (false && vlSymsp) {} // Prevent unused\n" : ""));
|
(VN_IS(modp, Class) ? "if (false && vlSymsp) {} // Prevent unused\n" : ""));
|
||||||
varResetFuncp = var_reset.builtFuncp();
|
|
||||||
|
|
||||||
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
|
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
|
||||||
if (AstVar* varp = VN_CAST(np, Var)) {
|
if (AstVar* varp = VN_CAST(np, Var)) {
|
||||||
|
|||||||
+1
-1
@@ -218,7 +218,7 @@ public:
|
|||||||
//######################################################################
|
//######################################################################
|
||||||
// Class class functions
|
// Class class functions
|
||||||
|
|
||||||
void V3CUse::cUseAll(AstNetlist* nodep) {
|
void V3CUse::cUseAll() {
|
||||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||||
// Call visitor separately for each module, so visitor state is cleared
|
// Call visitor separately for each module, so visitor state is cleared
|
||||||
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp;
|
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp;
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
class V3CUse {
|
class V3CUse {
|
||||||
public:
|
public:
|
||||||
static void cUseAll(AstNetlist* nodep);
|
static void cUseAll();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // Guard
|
#endif // Guard
|
||||||
|
|||||||
+4
-5
@@ -43,7 +43,6 @@
|
|||||||
#include "V3Stats.h"
|
#include "V3Stats.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdarg>
|
|
||||||
|
|
||||||
#define CASE_OVERLAP_WIDTH 16 // Maximum width we can check for overlaps in
|
#define CASE_OVERLAP_WIDTH 16 // Maximum width we can check for overlaps in
|
||||||
#define CASE_BARF 999999 // Magic width when non-constant
|
#define CASE_BARF 999999 // Magic width when non-constant
|
||||||
@@ -96,7 +95,7 @@ private:
|
|||||||
} else if (VN_IS(m_caseExprp, Case)
|
} else if (VN_IS(m_caseExprp, Case)
|
||||||
&& (VN_CAST(m_caseExprp, Case)->casez()
|
&& (VN_CAST(m_caseExprp, Case)->casez()
|
||||||
|| VN_CAST(m_caseExprp, Case)->caseInside())) {
|
|| VN_CAST(m_caseExprp, Case)->caseInside())) {
|
||||||
if (nodep->num().isUnknown()) {
|
if (nodep->num().isAnyX()) {
|
||||||
nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, "
|
nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, "
|
||||||
"(perhaps intended ?/z in constant)");
|
"(perhaps intended ?/z in constant)");
|
||||||
}
|
}
|
||||||
@@ -281,13 +280,13 @@ private:
|
|||||||
// IF(msb-1, 01, 00))
|
// IF(msb-1, 01, 00))
|
||||||
AstNode* cexprp = nodep->exprp()->unlinkFrBack();
|
AstNode* cexprp = nodep->exprp()->unlinkFrBack();
|
||||||
|
|
||||||
if (debug() >= 9) {
|
if (debug() >= 9) { // LCOV_EXCL_START
|
||||||
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) {
|
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) {
|
||||||
if (AstNode* itemp = m_valueItem[i]) {
|
if (AstNode* itemp = m_valueItem[i]) {
|
||||||
UINFO(9, "Value " << std::hex << i << " " << itemp << endl);
|
UINFO(9, "Value " << std::hex << i << " " << itemp << endl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // LCOV_EXCL_STOP
|
||||||
|
|
||||||
// Handle any assertions
|
// Handle any assertions
|
||||||
replaceCaseParallel(nodep, m_caseNoOverlapsAllCovered);
|
replaceCaseParallel(nodep, m_caseNoOverlapsAllCovered);
|
||||||
@@ -460,7 +459,7 @@ private:
|
|||||||
// Xs in case or casez are impossible due to two state simulations
|
// Xs in case or casez are impossible due to two state simulations
|
||||||
if (casep->casex()) {
|
if (casep->casex()) {
|
||||||
} else if (casep->casez() || casep->caseInside()) {
|
} else if (casep->casez() || casep->caseInside()) {
|
||||||
if (itemp->num().isUnknown()) return true;
|
if (itemp->num().isAnyX()) return true;
|
||||||
} else {
|
} else {
|
||||||
if (itemp->num().isFourState()) return true;
|
if (itemp->num().isFourState()) return true;
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-1
@@ -45,7 +45,6 @@
|
|||||||
#include "V3Ast.h"
|
#include "V3Ast.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdarg>
|
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// Cast state, as a visitor of each AstNode
|
// Cast state, as a visitor of each AstNode
|
||||||
@@ -128,6 +127,15 @@ private:
|
|||||||
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
|
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
|
||||||
if (nodep->sizeMattersThs()) ensureCast(nodep->thsp());
|
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 {
|
virtual void visit(AstCCast* nodep) VL_OVERRIDE {
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
ensureLower32Cast(nodep);
|
ensureLower32Cast(nodep);
|
||||||
|
|||||||
+3
-6
@@ -33,12 +33,9 @@
|
|||||||
#include "V3File.h"
|
#include "V3File.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdarg>
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <list>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#define CDC_WEIGHT_ASYNC 0x1000 // Weight for edges that feed async logic
|
#define CDC_WEIGHT_ASYNC 0x1000 // Weight for edges that feed async logic
|
||||||
|
|
||||||
@@ -258,7 +255,7 @@ private:
|
|||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
m_logicVertexp = NULL;
|
m_logicVertexp = NULL;
|
||||||
|
|
||||||
if (0 && debug() >= 9) {
|
if (false && debug() >= 9) {
|
||||||
UINFO(9, "Trace Logic:\n");
|
UINFO(9, "Trace Logic:\n");
|
||||||
nodep->dumpTree(cout, "-log1: ");
|
nodep->dumpTree(cout, "-log1: ");
|
||||||
}
|
}
|
||||||
@@ -298,7 +295,7 @@ private:
|
|||||||
static bool told_file = false;
|
static bool told_file = false;
|
||||||
nodep->v3warnCode(code, msg);
|
nodep->v3warnCode(code, msg);
|
||||||
if (!told_file) {
|
if (!told_file) {
|
||||||
told_file = 1;
|
told_file = true;
|
||||||
std::cerr << V3Error::msgPrefix() << " See details in " << m_ofFilename << endl;
|
std::cerr << V3Error::msgPrefix() << " See details in " << m_ofFilename << endl;
|
||||||
}
|
}
|
||||||
*m_ofp << "%Warning-" << code.ascii() << ": " << nodep->fileline() << " " << msg << endl;
|
*m_ofp << "%Warning-" << code.ascii() << ": " << nodep->fileline() << " " << msg << endl;
|
||||||
@@ -732,7 +729,7 @@ private:
|
|||||||
|
|
||||||
// Ignores
|
// Ignores
|
||||||
virtual void visit(AstInitial*) VL_OVERRIDE {}
|
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(AstCoverToggle*) VL_OVERRIDE {}
|
||||||
virtual void visit(AstNodeDType*) VL_OVERRIDE {}
|
virtual void visit(AstNodeDType*) VL_OVERRIDE {}
|
||||||
|
|
||||||
|
|||||||
@@ -35,8 +35,6 @@
|
|||||||
#include "V3EmitCBase.h"
|
#include "V3EmitCBase.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdarg>
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|
||||||
|
|||||||
+13
-1
@@ -31,7 +31,6 @@
|
|||||||
#include "V3Ast.h"
|
#include "V3Ast.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdarg>
|
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// Clean state, as a visitor of each AstNode
|
// Clean state, as a visitor of each AstNode
|
||||||
@@ -160,6 +159,15 @@ private:
|
|||||||
if (nodep->cleanThs()) ensureClean(nodep->thsp());
|
if (nodep->cleanThs()) ensureClean(nodep->thsp());
|
||||||
// no setClean.. must do it in each user routine.
|
// 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
|
// VISITORS
|
||||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||||
@@ -192,6 +200,10 @@ private:
|
|||||||
operandBiop(nodep);
|
operandBiop(nodep);
|
||||||
setClean(nodep, isClean(nodep->lhsp()) && isClean(nodep->rhsp()));
|
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 {
|
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
computeCppWidth(nodep);
|
computeCppWidth(nodep);
|
||||||
|
|||||||
@@ -36,7 +36,6 @@
|
|||||||
#include "V3EmitCBase.h"
|
#include "V3EmitCBase.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdarg>
|
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// Clock state, as a visitor of each AstNode
|
// Clock state, as a visitor of each AstNode
|
||||||
@@ -48,9 +47,6 @@ private:
|
|||||||
// AstVarScope::user1p() -> AstVarScope*. Temporary signal that was created.
|
// AstVarScope::user1p() -> AstVarScope*. Temporary signal that was created.
|
||||||
AstUser1InUse m_inuser1;
|
AstUser1InUse m_inuser1;
|
||||||
|
|
||||||
// TYPES
|
|
||||||
enum { DOUBLE_OR_RATE = 10 }; // How many | per ||, Determined experimentally as best
|
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
AstNodeModule* m_modp; // Current module
|
AstNodeModule* m_modp; // Current module
|
||||||
AstTopScope* m_topScopep; // Current top scope
|
AstTopScope* m_topScopep; // Current top scope
|
||||||
|
|||||||
+34
-24
@@ -40,7 +40,6 @@
|
|||||||
#include "V3Ast.h"
|
#include "V3Ast.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdarg>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -57,15 +56,6 @@ protected:
|
|||||||
// METHODS
|
// METHODS
|
||||||
virtual ~CombBaseVisitor() {}
|
virtual ~CombBaseVisitor() {}
|
||||||
VL_DEBUG_FUNC; // Declare debug()
|
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 {
|
} else {
|
||||||
UINFO(4, " Remove " << oldfuncp << endl);
|
UINFO(4, " Remove " << oldfuncp << endl);
|
||||||
}
|
}
|
||||||
std::pair<CallMmap::iterator, CallMmap::iterator> eqrange
|
// Note: m_callMmap modified in loop, so not using equal_range.
|
||||||
= m_callMmap.equal_range(oldfuncp);
|
for (CallMmap::iterator it = m_callMmap.find(oldfuncp); it != m_callMmap.end();
|
||||||
for (CallMmap::iterator nextit = eqrange.first; nextit != eqrange.second;) {
|
it = m_callMmap.find(oldfuncp)) {
|
||||||
CallMmap::iterator eqit = nextit++;
|
AstCCall* callp = it->second;
|
||||||
AstCCall* callp = eqit->second;
|
|
||||||
if (!callp->user3()) { // !already done
|
if (!callp->user3()) { // !already done
|
||||||
UINFO(4, " Called " << callp << endl);
|
UINFO(4, " Called " << callp << endl);
|
||||||
UASSERT_OBJ(callp->funcp() == oldfuncp, callp,
|
UASSERT_OBJ(callp->funcp() == oldfuncp, callp,
|
||||||
@@ -105,8 +94,13 @@ public:
|
|||||||
}
|
}
|
||||||
callp->user3(true); // Dead now
|
callp->user3(true); // Dead now
|
||||||
VL_DO_DANGLING(pushDeletep(callp), callp);
|
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
|
// METHODS
|
||||||
@@ -182,7 +176,6 @@ private:
|
|||||||
CombineState m_state; // Major state
|
CombineState m_state; // Major state
|
||||||
AstNodeModule* m_modp; // Current module
|
AstNodeModule* m_modp; // Current module
|
||||||
AstCFunc* m_funcp; // Current function
|
AstCFunc* m_funcp; // Current function
|
||||||
V3Hash m_lowerHash; // Hash of the statement we're building
|
|
||||||
CombCallVisitor m_call; // Tracking of function call users
|
CombCallVisitor m_call; // Tracking of function call users
|
||||||
int m_modNFuncs; // Number of functions made
|
int m_modNFuncs; // Number of functions made
|
||||||
AstNode* m_walkLast1p; // Final node that is the same in duplicate list
|
AstNode* m_walkLast1p; // Final node that is the same in duplicate list
|
||||||
@@ -195,6 +188,7 @@ private:
|
|||||||
m_hashed.hashAndInsert(nodep);
|
m_hashed.hashAndInsert(nodep);
|
||||||
// UINFO(9, " stmthash " << hex << nodep->user4() << " " << nodep << endl);
|
// UINFO(9, " stmthash " << hex << nodep->user4() << " " << nodep << endl);
|
||||||
}
|
}
|
||||||
|
#ifdef VL_COMBINE_STATEMENTS
|
||||||
void hashFunctions(AstCFunc* nodep) {
|
void hashFunctions(AstCFunc* nodep) {
|
||||||
// Compute hash of all statement trees in the function
|
// Compute hash of all statement trees in the function
|
||||||
CombineState oldState = m_state;
|
CombineState oldState = m_state;
|
||||||
@@ -204,6 +198,7 @@ private:
|
|||||||
}
|
}
|
||||||
m_state = oldState;
|
m_state = oldState;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
void walkEmptyFuncs() {
|
void walkEmptyFuncs() {
|
||||||
for (V3Hashed::iterator it = m_hashed.begin(); it != m_hashed.end(); ++it) {
|
for (V3Hashed::iterator it = m_hashed.begin(); it != m_hashed.end(); ++it) {
|
||||||
AstNode* node1p = it->second;
|
AstNode* node1p = it->second;
|
||||||
@@ -251,6 +246,8 @@ private:
|
|||||||
oldfuncp->unlinkFrBack();
|
oldfuncp->unlinkFrBack();
|
||||||
VL_DO_DANGLING(pushDeletep(oldfuncp), oldfuncp);
|
VL_DO_DANGLING(pushDeletep(oldfuncp), oldfuncp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef VL_COMBINE_STATEMENTS
|
||||||
void replaceOnlyCallFunc(AstCCall* nodep) {
|
void replaceOnlyCallFunc(AstCCall* nodep) {
|
||||||
if (AstCFunc* oldfuncp = VN_CAST(nodep->backp(), CFunc)) {
|
if (AstCFunc* oldfuncp = VN_CAST(nodep->backp(), CFunc)) {
|
||||||
// oldfuncp->dumpTree(cout, "MAYDEL: ");
|
// oldfuncp->dumpTree(cout, "MAYDEL: ");
|
||||||
@@ -343,7 +340,7 @@ private:
|
|||||||
// Grab statement bodies
|
// Grab statement bodies
|
||||||
AstNRelinker relink1Handle;
|
AstNRelinker relink1Handle;
|
||||||
AstNRelinker relink2Handle;
|
AstNRelinker relink2Handle;
|
||||||
for (AstNode *nextp, *walkp = node1p; 1; walkp = nextp) {
|
for (AstNode *nextp, *walkp = node1p; true; walkp = nextp) {
|
||||||
nextp = walkp->nextp();
|
nextp = walkp->nextp();
|
||||||
if (walkp == node1p) {
|
if (walkp == node1p) {
|
||||||
walkp->unlinkFrBack(&relink1Handle);
|
walkp->unlinkFrBack(&relink1Handle);
|
||||||
@@ -353,7 +350,7 @@ private:
|
|||||||
}
|
}
|
||||||
if (walkp == last1p) break;
|
if (walkp == last1p) break;
|
||||||
}
|
}
|
||||||
for (AstNode *nextp, *walkp = node2p; 1; walkp = nextp) {
|
for (AstNode *nextp, *walkp = node2p; true; walkp = nextp) {
|
||||||
nextp = walkp->nextp();
|
nextp = walkp->nextp();
|
||||||
if (walkp == node2p) {
|
if (walkp == node2p) {
|
||||||
walkp->unlinkFrBack(&relink2Handle);
|
walkp->unlinkFrBack(&relink2Handle);
|
||||||
@@ -381,6 +378,7 @@ private:
|
|||||||
VL_DO_DANGLING(replaceOnlyCallFunc(call1p), call1p);
|
VL_DO_DANGLING(replaceOnlyCallFunc(call1p), call1p);
|
||||||
VL_DO_DANGLING(replaceOnlyCallFunc(call2p), call2p);
|
VL_DO_DANGLING(replaceOnlyCallFunc(call2p), call2p);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||||
@@ -404,15 +402,21 @@ private:
|
|||||||
m_state = STATE_IDLE;
|
m_state = STATE_IDLE;
|
||||||
if (debug() >= 9) m_hashed.dumpFilePrefixed("combine");
|
if (debug() >= 9) m_hashed.dumpFilePrefixed("combine");
|
||||||
// Walk the hashes removing empty functions
|
// Walk the hashes removing empty functions
|
||||||
if (emptyFunctionDeletion()) walkEmptyFuncs();
|
walkEmptyFuncs();
|
||||||
// Walk the hashes looking for duplicate functions
|
// Walk the hashes looking for duplicate functions
|
||||||
if (duplicateFunctionCombine()) walkDupFuncs();
|
walkDupFuncs();
|
||||||
// Walk the statements looking for large replicated code sections
|
// 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;
|
m_state = STATE_DUP;
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
m_state = STATE_IDLE;
|
m_state = STATE_IDLE;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
m_modp = NULL;
|
m_modp = NULL;
|
||||||
}
|
}
|
||||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||||
@@ -420,9 +424,12 @@ private:
|
|||||||
if (!nodep->dontCombine()) {
|
if (!nodep->dontCombine()) {
|
||||||
if (m_state == STATE_HASH) {
|
if (m_state == STATE_HASH) {
|
||||||
hashStatement(nodep); // Hash the entire function - it might be identical
|
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);
|
iterateChildren(nodep);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
m_funcp = NULL;
|
m_funcp = NULL;
|
||||||
}
|
}
|
||||||
@@ -433,9 +440,12 @@ private:
|
|||||||
}
|
}
|
||||||
if (m_state == STATE_HASH && m_funcp) {
|
if (m_state == STATE_HASH && m_funcp) {
|
||||||
hashStatement(nodep);
|
hashStatement(nodep);
|
||||||
} else if (m_state == STATE_DUP && m_funcp) {
|
}
|
||||||
|
#ifdef VL_COMBINE_STATEMENTS
|
||||||
|
else if (m_state == STATE_DUP && m_funcp) {
|
||||||
walkDupCodeStart(nodep);
|
walkDupCodeStart(nodep);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------
|
//--------------------
|
||||||
|
|||||||
+1
-1
@@ -335,7 +335,7 @@ public:
|
|||||||
// UINFO(9, " Hit " << *m_lastIt << endl);
|
// UINFO(9, " Hit " << *m_lastIt << endl);
|
||||||
filelinep->warnOn(m_lastIgnore.it->m_code, m_lastIgnore.it->m_on);
|
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) {
|
for (IgnLines::const_iterator it = m_lastIgnore.it; it != m_ignLines.end(); ++it) {
|
||||||
UINFO(9, " NXT " << *it << endl);
|
UINFO(9, " NXT " << *it << endl);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -43,7 +43,7 @@ public:
|
|||||||
static void applyModule(AstNodeModule* modulep);
|
static void applyModule(AstNodeModule* modulep);
|
||||||
static void applyFTask(AstNodeModule* modulep, AstNodeFTask* ftaskp);
|
static void applyFTask(AstNodeModule* modulep, AstNodeFTask* ftaskp);
|
||||||
static void applyVarAttr(AstNodeModule* modulep, AstNodeFTask* ftaskp, AstVar* varp);
|
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
|
#endif // Guard
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user