mirror of
https://github.com/verilator/verilator.git
synced 2026-10-06 01:54:01 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0cd4a57ad9 | ||
|
|
1bd1e21a69 | ||
|
|
7e7447812c | ||
|
|
af3ab13012 | ||
|
|
b35b5aacfa | ||
|
|
9c01665078 | ||
|
|
a500140f1d | ||
|
|
dced49a804 | ||
|
|
f8a67b2fe8 | ||
|
|
8cdecd5668 | ||
|
|
75d255a3bf | ||
|
|
0674267333 | ||
|
|
1632160fb1 | ||
|
|
e609328ebb | ||
|
|
8291ef6537 | ||
|
|
30600bf1a3 | ||
|
|
b968f57711 | ||
|
|
ee7b399bf5 | ||
|
|
50c28fa9d3 | ||
|
|
a17f51eac0 | ||
|
|
cc50126ad3 | ||
|
|
9d1a39a5e4 | ||
|
|
82cc1a319f | ||
|
|
2fd23458ce | ||
|
|
271fa5fe3c | ||
|
|
04c96694e6 | ||
|
|
e7bd44561c | ||
|
|
4d5e448664 | ||
|
|
236c2141e3 | ||
|
|
788fe3dc27 | ||
|
|
a2abd361db | ||
|
|
09806d7576 | ||
|
|
a2aa678278 | ||
|
|
0b09636c58 | ||
|
|
af197f2ceb | ||
|
|
748c818ccb | ||
|
|
ad55564905 | ||
|
|
ad2cb45a14 | ||
|
|
277fd9197f | ||
|
|
61ff7039b4 | ||
|
|
7342cf278a | ||
|
|
958654909f | ||
|
|
d9be86d69a | ||
|
|
378d947702 | ||
|
|
98b5417e04 | ||
|
|
0af971292e | ||
|
|
43a2fa080a | ||
|
|
0cdc2e038c | ||
|
|
d4a411db6c | ||
|
|
8d367dc8a3 | ||
|
|
5a4cc333fb | ||
|
|
f13fd4478c | ||
|
|
23e4a0f784 | ||
|
|
aa595d40de | ||
|
|
fa828ac9ba | ||
|
|
b1495f0742 | ||
|
|
8006b5479c | ||
|
|
19c2906a64 | ||
|
|
c367b671b6 | ||
|
|
35226d5e1a | ||
|
|
fac89c5d62 | ||
|
|
f40f0464e2 | ||
|
|
262ed9c03a | ||
|
|
a7edf13d62 | ||
|
|
6e57076726 | ||
|
|
cef56c6fca | ||
|
|
91f30af01f | ||
|
|
3c8953fec2 | ||
|
|
6de78d58fa | ||
|
|
d42f9c095b | ||
|
|
46e10173f8 | ||
|
|
d84c7df38f | ||
|
|
6e2d8df9e5 | ||
|
|
e2b40195b4 | ||
|
|
541f983dba | ||
|
|
5658cd3394 | ||
|
|
3963a50aef | ||
|
|
47f040a5fd | ||
|
|
7b7a2e99e3 | ||
|
|
25397e7612 | ||
|
|
4984d19ae9 | ||
|
|
305448ea86 | ||
|
|
4a1d18f0e9 | ||
|
|
30482f3eea | ||
|
|
b469feb44b | ||
|
|
466fd56d18 | ||
|
|
1aaf3f3424 | ||
|
|
b5e4917405 | ||
|
|
140671300c | ||
|
|
820a4dbbdd | ||
|
|
53d8ccd149 | ||
|
|
418b36ea71 | ||
|
|
05e51d0d18 | ||
|
|
575c565e77 | ||
|
|
01255082a6 | ||
|
|
0098e67e59 | ||
|
|
3798a472b5 | ||
|
|
0e322e2e85 | ||
|
|
5cd5c05c05 | ||
|
|
933e796cc2 | ||
|
|
ae701e014d | ||
|
|
3a0b8c8870 | ||
|
|
dea0e6793f | ||
|
|
4862916f39 | ||
|
|
870ec27b73 | ||
|
|
a21947d887 | ||
|
|
893dee3434 | ||
|
|
f083805ab5 | ||
|
|
7067afde5d | ||
|
|
1eaec2aa8a | ||
|
|
da01810d98 | ||
|
|
4c7d5a1dc0 | ||
|
|
d15e3d93c4 | ||
|
|
aae2bf872c | ||
|
|
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'
|
||||||
|
|||||||
+121
-160
@@ -8,176 +8,137 @@
|
|||||||
|
|
||||||
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
|
||||||
|
# Don't produce core dumps (esp. on FreeBSD)
|
||||||
|
- ulimit -c 0
|
||||||
|
# On Focal, set the SystemC installation location
|
||||||
|
- |
|
||||||
|
if [ "$TRAVIS_DIST" = "focal" ] && [ "$M32" != "1" ]; then
|
||||||
|
export SYSTEMC_INCLUDE=/usr/include
|
||||||
|
export SYSTEMC_LIBDIR=/usr/lib/x86_64-linux-gnu
|
||||||
|
fi
|
||||||
|
# Override compiler for M32
|
||||||
|
- |
|
||||||
|
if [ "$M32" = "1" ]; then
|
||||||
|
export CC="$CC -m32"
|
||||||
|
export CXX="$CXX -m32"
|
||||||
|
unset M32 # verilated.mk actually references $(M32) so unset
|
||||||
|
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
|
# 32-bit build
|
||||||
compiler: gcc
|
- {stage: build, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {create: {name: focal-gcc-m32, paths: .}}, env: M32=1}
|
||||||
script: ci/test.sh vlt
|
# OS X build
|
||||||
- if: type != cron
|
- {stage: build, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {create: {name: osx-xcode11.6, paths: .}}}
|
||||||
stage: test
|
# FreeBSD build
|
||||||
name: Vltmt set 0 test
|
- {stage: build, if: type = cron, os: freebsd, compiler: clang, workspaces: {create: {name: freebsd, paths: .}}}
|
||||||
compiler: gcc
|
############################################################################
|
||||||
script: ci/test.sh vltmt0
|
# Jobs in the 'test' stage
|
||||||
- if: type != cron
|
############################################################################
|
||||||
stage: test
|
# GCC tests
|
||||||
name: Vltmt set 1 test
|
- {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||||
compiler: gcc
|
- {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||||
script: ci/test.sh vltmt1
|
- {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||||
# Cron builds try different OS/compiler combinations
|
- {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: "Build Verilator"
|
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||||
name: Build xenial gcc Verilator
|
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||||
os: linux
|
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||||
dist: xenial
|
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||||
compiler: gcc
|
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||||
script: echo "Done building Verilator"
|
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||||
- if: type = cron
|
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||||
stage: test
|
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||||
name: Xenial gcc dist test
|
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||||
os: linux
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||||
dist: xenial
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||||
compiler: gcc
|
# Clang tests
|
||||||
script: ci/test.sh dist
|
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||||
- 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-1}
|
||||||
stage: test
|
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||||
name: Xenial gcc vlt test
|
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||||
os: linux
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||||
dist: xenial
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||||
compiler: gcc
|
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||||
script: ci/test.sh vlt
|
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||||
- if: type = cron
|
# Coverage tests
|
||||||
stage: test
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-dist}
|
||||||
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-vlt-0}
|
||||||
os: linux
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-1}
|
||||||
dist: xenial
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-2}
|
||||||
compiler: gcc
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-3}
|
||||||
script: ci/test.sh vltmt
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-0}
|
||||||
- if: type = cron
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-1}
|
||||||
stage: "Build Verilator"
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-2}
|
||||||
name: Build xenial clang Verilator
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-3}
|
||||||
os: linux
|
# 32-bit tests
|
||||||
dist: xenial
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=dist-vlt-0]}
|
||||||
compiler: clang
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=dist-vlt-1]}
|
||||||
script: echo "Done building Verilator"
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=vltmt-0]}
|
||||||
- if: type = cron
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=vltmt-1]}
|
||||||
stage: test
|
# OS X tests
|
||||||
name: Xenial clang dist test
|
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||||
os: linux
|
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||||
dist: xenial
|
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||||
compiler: clang
|
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||||
script: ci/test.sh dist
|
# FreeBSD tests
|
||||||
- if: type = cron
|
- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||||
stage: test
|
- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||||
name: Xenial clang vlt test
|
- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||||
os: linux
|
- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||||
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
|
||||||
|
|||||||
+4
-1
@@ -425,6 +425,9 @@ CPPCHECK_CPP = $(wildcard \
|
|||||||
CPPCHECK_H = $(wildcard \
|
CPPCHECK_H = $(wildcard \
|
||||||
$(srcdir)/include/*.h \
|
$(srcdir)/include/*.h \
|
||||||
$(srcdir)/src/*.h )
|
$(srcdir)/src/*.h )
|
||||||
|
CPPCHECK_YL = $(wildcard \
|
||||||
|
$(srcdir)/src/*.y \
|
||||||
|
$(srcdir)/src/*.l )
|
||||||
CPPCHECK = src/cppcheck_filtered
|
CPPCHECK = src/cppcheck_filtered
|
||||||
CPPCHECK_FLAGS = --enable=all --inline-suppr \
|
CPPCHECK_FLAGS = --enable=all --inline-suppr \
|
||||||
--suppress=unusedScopedObject --suppress=cstyleCast --suppress=useInitializationList \
|
--suppress=unusedScopedObject --suppress=cstyleCast --suppress=useInitializationList \
|
||||||
@@ -462,7 +465,7 @@ CLANGFORMAT_FLAGS = -i
|
|||||||
clang-format:
|
clang-format:
|
||||||
@$(CLANGFORMAT) --version | egrep 10.0 > /dev/null \
|
@$(CLANGFORMAT) --version | egrep 10.0 > /dev/null \
|
||||||
|| echo "*** You are not using clang-format 10.0, indents may differ from master's ***"
|
|| echo "*** You are not using clang-format 10.0, indents may differ from master's ***"
|
||||||
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CPPCHECK_CPP) $(CPPCHECK_H)
|
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL)
|
||||||
|
|
||||||
ftp: info
|
ftp: info
|
||||||
|
|
||||||
|
|||||||
+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
|
||||||
|
|
||||||
|
|||||||
+627
-578
File diff suppressed because it is too large
Load Diff
+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
+104
@@ -0,0 +1,104 @@
|
|||||||
|
#!/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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||||
|
MAKE=make
|
||||||
|
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||||
|
MAKE=make
|
||||||
|
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
|
||||||
|
MAKE=gmake
|
||||||
|
else
|
||||||
|
fatal "Unknown os: '$TRAVIS_OS_NAME'"
|
||||||
|
fi
|
||||||
|
|
||||||
|
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
|
||||||
|
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
|
||||||
|
if [ "$M32" = 1 ]; then
|
||||||
|
sudo apt-get install gcc-multilib g++-multilib
|
||||||
|
fi
|
||||||
|
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||||
|
brew update
|
||||||
|
brew install ccache perl gperftools
|
||||||
|
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
|
||||||
|
sudo pkg install -y autoconf bison ccache gmake perl5
|
||||||
|
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
|
||||||
|
if [ "$M32" = 1 ]; then
|
||||||
|
sudo apt-get install lib32z1-dev gcc-multilib g++-multilib
|
||||||
|
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
|
||||||
|
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||||
|
brew update
|
||||||
|
# brew cask install gtkwave # fst2vcd hangs at launch, so don't bother
|
||||||
|
brew install ccache perl
|
||||||
|
yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
|
||||||
|
install-vcddiff
|
||||||
|
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
|
||||||
|
# fst2vcd fails with "Could not open '<input file>', exiting."
|
||||||
|
sudo pkg install -y ccache gmake perl5 python3
|
||||||
|
yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
|
||||||
|
install-vcddiff
|
||||||
|
else
|
||||||
|
fatal "Unknown os: '$TRAVIS_OS_NAME'"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
##############################################################################
|
||||||
|
# Unknown build stage
|
||||||
|
fatal "Unknown build stage: '$TRAVIS_BUILD_STAGE_NAME'"
|
||||||
|
fi
|
||||||
Executable
+134
@@ -0,0 +1,134 @@
|
|||||||
|
#!/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_OS_NAME" = "linux" ]; then
|
||||||
|
export MAKE=make
|
||||||
|
NPROC=$(nproc)
|
||||||
|
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||||
|
export MAKE=make
|
||||||
|
NPROC=$(sysctl -n hw.logicalcpu)
|
||||||
|
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
|
||||||
|
export MAKE=gmake
|
||||||
|
NPROC=$(sysctl -n hw.ncpu)
|
||||||
|
else
|
||||||
|
fatal "Unknown os: '$TRAVIS_OS_NAME'"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then
|
||||||
|
##############################################################################
|
||||||
|
# Build verilator
|
||||||
|
|
||||||
|
if [ "$COVERAGE" != 1 ]; then
|
||||||
|
autoconf
|
||||||
|
./configure --enable-longtests --enable-ccwarn
|
||||||
|
"$MAKE" -j "$NPROC"
|
||||||
|
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||||
|
file bin/verilator_bin
|
||||||
|
file bin/verilator_bin_dbg
|
||||||
|
md5 bin/verilator_bin
|
||||||
|
md5 bin/verilator_bin_dbg
|
||||||
|
stat bin/verilator_bin
|
||||||
|
stat bin/verilator_bin_dbg
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
nodist/code_coverage --stages 1-2
|
||||||
|
fi
|
||||||
|
elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
|
||||||
|
##############################################################################
|
||||||
|
# Run tests
|
||||||
|
|
||||||
|
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||||
|
export VERILATOR_TEST_NO_GDB=1 # Pain to get GDB to work on OS X
|
||||||
|
export VERILATOR_TEST_NO_GPROF=1 # Apple Clang has no -pg
|
||||||
|
# export PATH="/Applications/gtkwave.app/Contents/Resources/bin:$PATH" # fst2vcd
|
||||||
|
file bin/verilator_bin
|
||||||
|
file bin/verilator_bin_dbg
|
||||||
|
md5 bin/verilator_bin
|
||||||
|
md5 bin/verilator_bin_dbg
|
||||||
|
stat bin/verilator_bin
|
||||||
|
stat bin/verilator_bin_dbg
|
||||||
|
# For some reason, the dbg exe is corrupted by this point ('file' reports
|
||||||
|
# it as data rather than a Mach-O). Unclear if this is an OS X issue or
|
||||||
|
# one for Travis. Remove the file and re-link...
|
||||||
|
rm bin/verilator_bin_dbg
|
||||||
|
"$MAKE" -j "$NPROC"
|
||||||
|
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
|
||||||
|
export VERILATOR_TEST_NO_GDB=1 # Disable for now, ideally should run
|
||||||
|
export VERILATOR_TEST_NO_GPROF=1 # gprof is a bit different on FreeBSD, disable
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 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
|
||||||
|
##############################################################################
|
||||||
|
# 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
|
||||||
+42
-15
@@ -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.038 2020-07-11],
|
||||||
[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],
|
||||||
@@ -111,25 +114,25 @@ AC_MSG_RESULT($CFG_WITH_LONGTESTS)
|
|||||||
|
|
||||||
# CFG_WITH_PREC11
|
# CFG_WITH_PREC11
|
||||||
AC_MSG_CHECKING(whether allow pre-C++11)
|
AC_MSG_CHECKING(whether allow pre-C++11)
|
||||||
AC_ARG_ENABLE([prec11],
|
AC_ARG_ENABLE([prec11-final],
|
||||||
[AS_HELP_STRING([--enable-prec11],
|
[AS_HELP_STRING([--enable-prec11-final],
|
||||||
[enable pre-C++11 compilers for Verilator binary
|
[enable pre-C++11 compilers for Verilator binary
|
||||||
and Verilated makefiles])],
|
and Verilated makefiles])],
|
||||||
[case "${enableval}" in
|
[case "${enableval}" in
|
||||||
yes) CFG_WITH_PREC11=yes ;;
|
yes) CFG_WITH_PREC11=yes ;;
|
||||||
no) CFG_WITH_PREC11=no ;;
|
no) CFG_WITH_PREC11=no ;;
|
||||||
*) AC_MSG_ERROR([bad value ${enableval} for --enable-prec11]) ;;
|
*) AC_MSG_ERROR([bad value ${enableval} for --enable-prec11-final]) ;;
|
||||||
esac],
|
esac],
|
||||||
[CFG_WITH_PREC11=no;]
|
[CFG_WITH_PREC11=no;]
|
||||||
)
|
)
|
||||||
AC_SUBST(CFG_WITH_PREC11)
|
AC_SUBST(CFG_WITH_PREC11)
|
||||||
AC_MSG_RESULT($CFG_WITH_PREC11)
|
AC_MSG_RESULT($CFG_WITH_PREC11)
|
||||||
|
|
||||||
# Compiler flags
|
# Compiler flags (ensure they are not empty to avoid configure defaults)
|
||||||
CFLAGS+=" -I${includedir}"
|
CFLAGS+=" "
|
||||||
CPPFLAGS+=" -I${includedir}"
|
CPPFLAGS+=" "
|
||||||
CXXFLAGS+=" -I${includedir}"
|
CXXFLAGS+=" "
|
||||||
LDFLAGS+=" -L${libdir}"
|
LDFLAGS+=" "
|
||||||
|
|
||||||
# Checks for programs.
|
# Checks for programs.
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
@@ -150,14 +153,20 @@ AC_PATH_PROG(PERL,perl)
|
|||||||
if test "x$PERL" = "x" ; then
|
if test "x$PERL" = "x" ; then
|
||||||
AC_MSG_ERROR([Cannot find "perl" in your PATH, please install it])
|
AC_MSG_ERROR([Cannot find "perl" in your PATH, please install it])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AC_PATH_PROG(LEX,flex)
|
AC_PATH_PROG(LEX,flex)
|
||||||
if test "x$LEX" = "x" ; then
|
if test "x$LEX" = "x" ; then
|
||||||
AC_MSG_ERROR([Cannot find "flex" in your PATH, please install it])
|
AC_MSG_ERROR([Cannot find "flex" in your PATH, please install it])
|
||||||
fi
|
fi
|
||||||
|
flex_version=$($LEX --version | head -1)
|
||||||
|
AC_MSG_RESULT([$LEX --version = $flex_version])
|
||||||
|
|
||||||
AC_PATH_PROG(YACC,bison)
|
AC_PATH_PROG(YACC,bison)
|
||||||
if test "x$YACC" = "x" ; then
|
if test "x$YACC" = "x" ; then
|
||||||
AC_MSG_ERROR([Cannot find "bison" in your PATH, please install it])
|
AC_MSG_ERROR([Cannot find "bison" in your PATH, please install it])
|
||||||
fi
|
fi
|
||||||
|
bison_version=$($YACC --version | head -1)
|
||||||
|
AC_MSG_RESULT([$YACC --version = $bison_version])
|
||||||
|
|
||||||
AC_CHECK_PROG(OBJCACHE,ccache,ccache)
|
AC_CHECK_PROG(OBJCACHE,ccache,ccache)
|
||||||
if test "x$OBJCACHE" != "x" ; then
|
if test "x$OBJCACHE" != "x" ; then
|
||||||
@@ -416,6 +425,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
|
||||||
@@ -423,12 +433,11 @@ if test "$CFG_WITH_THREADED" = "no" ; then
|
|||||||
AC_MSG_NOTICE([[]])
|
AC_MSG_NOTICE([[]])
|
||||||
AC_MSG_ERROR([[the $CXX compiler appears to not support C++11.
|
AC_MSG_ERROR([[the $CXX compiler appears to not support C++11.
|
||||||
|
|
||||||
Verilator plans to require a C++11 or newer compiler in a future release,
|
Verilator will require a C++11 or newer compiler for all releases starting
|
||||||
unless sufficient people report problems. Therefore, if you do not have a
|
September 2020. Please investigate a C++11 build environment now so you
|
||||||
C++11 compiler, please post a message to
|
will be ready. Until then you may rerun configure with the
|
||||||
https://www.veripool.org/boards/3/topics/2580-Verilator-Requiring-C-11-compiler
|
--enable-prec11-final argument to enable reduced functionality with such
|
||||||
indicating your OS and when you think C++11 might be ok, and then rerun
|
older compilers. Thanks.]])
|
||||||
configure with the --enable-prec11 argument. Thanks.]])
|
|
||||||
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -438,6 +447,24 @@ 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)])
|
||||||
|
ACO_SAVE_LIBS="$LIBS"
|
||||||
|
LIBS="$LIBS -lsystemc"
|
||||||
|
AC_LINK_IFELSE(
|
||||||
|
[AC_LANG_PROGRAM([[#include <systemc.h>
|
||||||
|
extern "C" int sc_main(int argc, char* argv[]) {}
|
||||||
|
]],[[sc_version()]])],
|
||||||
|
[_my_result=yes
|
||||||
|
AC_DEFINE([HAVE_SYSTEMC],[1],[Defined if have SystemC library])],
|
||||||
|
[_my_result=no])
|
||||||
|
AC_MSG_RESULT($_my_result)
|
||||||
|
LIBS="$ACO_SAVE_LIBS"
|
||||||
|
AC_SUBST(HAVE_SYSTEMC)
|
||||||
|
|
||||||
# Checks for system services
|
# Checks for system services
|
||||||
|
|
||||||
# Other install directories
|
# Other install directories
|
||||||
|
|||||||
@@ -6,15 +6,25 @@ 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
|
||||||
|
Conor McCullough
|
||||||
|
Dan Petrisko
|
||||||
|
David Horton
|
||||||
David Stanford
|
David Stanford
|
||||||
Driss Hafdi
|
Driss Hafdi
|
||||||
Eric Rippey
|
Eric Rippey
|
||||||
|
Fan Shupei
|
||||||
Garrett Smith
|
Garrett Smith
|
||||||
Geza Lore
|
Geza Lore
|
||||||
Gianfranco Costamagna
|
Gianfranco Costamagna
|
||||||
|
Glen Gibb
|
||||||
|
Harald Heckmann
|
||||||
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 +32,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 +51,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
|
||||||
|
|||||||
+9
-12
@@ -39,7 +39,7 @@ brief:
|
|||||||
#sudo apt-get install libfl2 # Ubuntu only (ignore if gives error)
|
#sudo apt-get install libfl2 # Ubuntu only (ignore if gives error)
|
||||||
#sudo apt-get install libfl-dev # Ubuntu only (ignore if gives error)
|
#sudo apt-get install libfl-dev # Ubuntu only (ignore if gives error)
|
||||||
|
|
||||||
git clone https://git.veripool.org/git/verilator # Only first time
|
git clone https://github.com/verilator/verilator # Only first time
|
||||||
## Note the URL above is not a page you can see with a browser, it's for git only
|
## Note the URL above is not a page you can see with a browser, it's for git only
|
||||||
|
|
||||||
# Every time you need to build:
|
# Every time you need to build:
|
||||||
@@ -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)
|
||||||
@@ -90,17 +89,16 @@ To build or run the following are optional but should be installed for
|
|||||||
good performance:
|
good performance:
|
||||||
|
|
||||||
sudo apt-get install ccache # If present at build, needed for run
|
sudo apt-get install ccache # If present at build, needed for run
|
||||||
sudo apt-get install libgoogle-perftools-dev numactl
|
sudo apt-get install libgoogle-perftools-dev numactl perl-doc
|
||||||
|
|
||||||
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
|
||||||
@@ -130,7 +128,7 @@ Downloads]; we presume you know how to use it, and is not described here.)
|
|||||||
|
|
||||||
Get the sources from the repository: (You need do this only once, ever.)
|
Get the sources from the repository: (You need do this only once, ever.)
|
||||||
|
|
||||||
git clone https://git.veripool.org/git/verilator # Only first time
|
git clone https://github.com/verilator/verilator # Only first time
|
||||||
## Note the URL above is not a page you can see with a browser, it's for git only
|
## Note the URL above is not a page you can see with a browser, it's for git only
|
||||||
|
|
||||||
Enter the checkout and determine what version/branch to use:
|
Enter the checkout and determine what version/branch to use:
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
+32
-9
@@ -777,19 +777,20 @@ output, for example:
|
|||||||
You can then print a.ps. You may prefer gif format, which doesn't get
|
You can then print a.ps. You may prefer gif format, which doesn't get
|
||||||
scaled so can be more useful with large graphs.
|
scaled so can be more useful with large graphs.
|
||||||
|
|
||||||
For dynamic graph viewing consider
|
For interactive graph viewing consider
|
||||||
|
https://github.com/jrfonseca/xdot.py[xdot] or
|
||||||
http://zvtm.sourceforge.net/zgrviewer.html[ZGRViewer]. If you know of
|
http://zvtm.sourceforge.net/zgrviewer.html[ZGRViewer]. If you know of
|
||||||
better viewers let us know; ZGRViewer isn't great for large graphs.
|
better viewers (especially for large graphs) please let us know.
|
||||||
|
|
||||||
=== .tree Output
|
=== .tree Output
|
||||||
|
|
||||||
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 +808,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 +851,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 +1001,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
|
||||||
@@ -70,7 +68,7 @@ run:
|
|||||||
@echo " library (libverilated_secret.a) generated from the previous"
|
@echo " library (libverilated_secret.a) generated from the previous"
|
||||||
@echo " step"
|
@echo " step"
|
||||||
@echo "---------------------------------------------------------------"
|
@echo "---------------------------------------------------------------"
|
||||||
$(VERILATOR) $(TOP_VERILATOR_FLAGS) --exe -LDFLAGS '-L../obj_dir_secret -lverilated_secret -static' top.v obj_dir_secret/verilated_secret.sv sim_main.cpp
|
$(VERILATOR) $(TOP_VERILATOR_FLAGS) --exe -LDFLAGS '../obj_dir_secret/libverilated_secret.a' top.v obj_dir_secret/verilated_secret.sv sim_main.cpp
|
||||||
|
|
||||||
@echo
|
@echo
|
||||||
@echo "-- COMPILE entire design --------------------------------------"
|
@echo "-- COMPILE entire design --------------------------------------"
|
||||||
|
|||||||
@@ -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
|
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||||
|
|
||||||
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix). */
|
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix). */
|
||||||
#if !defined(__MINGW32__)
|
#if !defined(__MINGW32__) && !defined(__FreeBSD__)
|
||||||
# define HAVE_ALLOCA_H 1
|
# define HAVE_ALLOCA_H 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -794,6 +794,7 @@ pthread_t thread;
|
|||||||
pthread_attr_t thread_attr;
|
pthread_attr_t thread_attr;
|
||||||
struct fstWriterContext *xc_parent;
|
struct fstWriterContext *xc_parent;
|
||||||
#endif
|
#endif
|
||||||
|
unsigned in_pthread : 1;
|
||||||
|
|
||||||
size_t fst_orig_break_size;
|
size_t fst_orig_break_size;
|
||||||
size_t fst_orig_break_add_size;
|
size_t fst_orig_break_add_size;
|
||||||
@@ -1806,10 +1807,9 @@ static void *fstWriterFlushContextPrivate1(void *ctx)
|
|||||||
{
|
{
|
||||||
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
|
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&(xc->xc_parent->mutex));
|
||||||
fstWriterFlushContextPrivate2(xc);
|
fstWriterFlushContextPrivate2(xc);
|
||||||
|
|
||||||
pthread_mutex_unlock(&(xc->xc_parent->mutex));
|
|
||||||
|
|
||||||
#ifdef FST_REMOVE_DUPLICATE_VC
|
#ifdef FST_REMOVE_DUPLICATE_VC
|
||||||
free(xc->curval_mem);
|
free(xc->curval_mem);
|
||||||
#endif
|
#endif
|
||||||
@@ -1818,6 +1818,9 @@ free(xc->vchg_mem);
|
|||||||
tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam);
|
tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam);
|
||||||
free(xc);
|
free(xc);
|
||||||
|
|
||||||
|
xc->xc_parent->in_pthread = 0;
|
||||||
|
pthread_mutex_unlock(&(xc->xc_parent->mutex));
|
||||||
|
|
||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1865,7 +1868,15 @@ if(xc->parallel_enabled)
|
|||||||
xc->section_header_only = 0;
|
xc->section_header_only = 0;
|
||||||
xc->secnum++;
|
xc->secnum++;
|
||||||
|
|
||||||
|
while (xc->in_pthread)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&xc->mutex);
|
||||||
|
pthread_mutex_unlock(&xc->mutex);
|
||||||
|
};
|
||||||
|
|
||||||
pthread_mutex_lock(&xc->mutex);
|
pthread_mutex_lock(&xc->mutex);
|
||||||
|
xc->in_pthread = 1;
|
||||||
|
pthread_mutex_unlock(&xc->mutex);
|
||||||
|
|
||||||
pthread_create(&xc->thread, &xc->thread_attr, fstWriterFlushContextPrivate1, xc2);
|
pthread_create(&xc->thread, &xc->thread_attr, fstWriterFlushContextPrivate1, xc2);
|
||||||
}
|
}
|
||||||
@@ -1947,6 +1958,12 @@ if(xc && !xc->already_in_close && !xc->already_in_flush)
|
|||||||
#ifdef FST_WRITER_PARALLEL
|
#ifdef FST_WRITER_PARALLEL
|
||||||
pthread_mutex_lock(&xc->mutex);
|
pthread_mutex_lock(&xc->mutex);
|
||||||
pthread_mutex_unlock(&xc->mutex);
|
pthread_mutex_unlock(&xc->mutex);
|
||||||
|
|
||||||
|
while (xc->in_pthread)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&xc->mutex);
|
||||||
|
pthread_mutex_unlock(&xc->mutex);
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+327
-212
File diff suppressed because it is too large
Load Diff
+98
-65
@@ -84,10 +84,6 @@ typedef EData WData; ///< Verilated pack data, >64 bits, as an array
|
|||||||
typedef const WData* WDataInP; ///< Array input to a function
|
typedef const WData* WDataInP; ///< Array input to a function
|
||||||
typedef WData* WDataOutP; ///< Array output from a function
|
typedef WData* WDataOutP; ///< Array output from a function
|
||||||
|
|
||||||
typedef void (*VerilatedVoidCb)(void);
|
|
||||||
|
|
||||||
class SpTraceVcd;
|
|
||||||
class SpTraceVcdCFile;
|
|
||||||
class VerilatedEvalMsgQueue;
|
class VerilatedEvalMsgQueue;
|
||||||
class VerilatedScopeNameMap;
|
class VerilatedScopeNameMap;
|
||||||
class VerilatedVar;
|
class VerilatedVar;
|
||||||
@@ -337,10 +333,10 @@ 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, bool isParam,
|
||||||
int vlflags, int dims, ...) VL_MT_UNSAFE;
|
VerilatedVarType vltype, int vlflags, int dims, ...) VL_MT_UNSAFE;
|
||||||
// ACCESSORS
|
// ACCESSORS
|
||||||
const char* name() const { return m_namep; }
|
const char* name() const { return m_namep; }
|
||||||
const char* identifier() const { return m_identifierp; }
|
const char* identifier() const { return m_identifierp; }
|
||||||
@@ -365,7 +361,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);
|
||||||
};
|
};
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
@@ -376,8 +372,6 @@ class Verilated {
|
|||||||
// Slow path variables
|
// Slow path variables
|
||||||
static VerilatedMutex m_mutex; ///< Mutex for s_s/s_ns members, when VL_THREADED
|
static VerilatedMutex m_mutex; ///< Mutex for s_s/s_ns members, when VL_THREADED
|
||||||
|
|
||||||
static VerilatedVoidCb s_flushCb; ///< Flush callback function
|
|
||||||
|
|
||||||
static struct Serialized { // All these members serialized/deserialized
|
static struct Serialized { // All these members serialized/deserialized
|
||||||
// Fast path
|
// Fast path
|
||||||
int s_debug; ///< See accessors... only when VL_DEBUG set
|
int s_debug; ///< See accessors... only when VL_DEBUG set
|
||||||
@@ -386,8 +380,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
|
||||||
@@ -501,9 +495,15 @@ public:
|
|||||||
static void profThreadsFilenamep(const char* flagp) VL_MT_SAFE;
|
static void profThreadsFilenamep(const char* flagp) VL_MT_SAFE;
|
||||||
static const char* profThreadsFilenamep() VL_MT_SAFE { return s_ns.s_profThreadsFilenamep; }
|
static const char* profThreadsFilenamep() VL_MT_SAFE { return s_ns.s_profThreadsFilenamep; }
|
||||||
|
|
||||||
/// Flush callback for VCD waves
|
typedef void (*VoidPCb)(void*); // Callback type for below
|
||||||
static void flushCb(VerilatedVoidCb cb) VL_MT_SAFE;
|
/// Callbacks to run on global flush
|
||||||
static void flushCall() VL_MT_SAFE;
|
static void addFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE;
|
||||||
|
static void removeFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE;
|
||||||
|
static void runFlushCallbacks() VL_MT_SAFE;
|
||||||
|
/// Callbacks to run prior to termination
|
||||||
|
static void addExitCb(VoidPCb cb, void* datap) VL_MT_SAFE;
|
||||||
|
static void removeExitCb(VoidPCb cb, void* datap) VL_MT_SAFE;
|
||||||
|
static void runExitCallbacks() VL_MT_SAFE;
|
||||||
|
|
||||||
/// Record command line arguments, for retrieval by $test$plusargs/$value$plusargs,
|
/// Record command line arguments, for retrieval by $test$plusargs/$value$plusargs,
|
||||||
/// and for parsing +verilator+ run-time arguments.
|
/// and for parsing +verilator+ run-time arguments.
|
||||||
@@ -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
|
||||||
@@ -847,7 +843,7 @@ inline vluint64_t vl_time_stamp64() { return static_cast<vluint64_t>(sc_time_sta
|
|||||||
// Optimized assuming scale is always constant.
|
// Optimized assuming scale is always constant.
|
||||||
// Can't use multiply in Q flavor, as might lose precision
|
// Can't use multiply in Q flavor, as might lose precision
|
||||||
#define VL_TIME_UNITED_Q(scale) (VL_TIME_Q() / static_cast<QData>(scale))
|
#define VL_TIME_UNITED_Q(scale) (VL_TIME_Q() / static_cast<QData>(scale))
|
||||||
#define VL_TIME_UNITED_D(scale) (VL_TIME_D() * (1.0 / (scale)))
|
#define VL_TIME_UNITED_D(scale) (VL_TIME_D() / static_cast<double>(scale))
|
||||||
/// Time imported from units to time precision
|
/// Time imported from units to time precision
|
||||||
double vl_time_multiplier(int scale);
|
double vl_time_multiplier(int scale);
|
||||||
|
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
@@ -1546,24 +1571,30 @@ static inline WDataOutP VL_MULS_WWW(int, int lbits, int, WDataOutP owp, WDataInP
|
|||||||
|
|
||||||
static inline IData VL_DIVS_III(int lbits, IData lhs, IData rhs) VL_PURE {
|
static inline IData VL_DIVS_III(int lbits, IData lhs, IData rhs) VL_PURE {
|
||||||
if (VL_UNLIKELY(rhs == 0)) return 0;
|
if (VL_UNLIKELY(rhs == 0)) return 0;
|
||||||
|
// -MAX / -1 cannot be represented in twos complement, and will cause SIGFPE
|
||||||
|
if (VL_UNLIKELY(lhs == 0x80000000 && rhs == 0xffffffff)) return 0;
|
||||||
vlsint32_t lhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, lhs);
|
vlsint32_t lhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, lhs);
|
||||||
vlsint32_t rhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, rhs);
|
vlsint32_t rhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, rhs);
|
||||||
return lhs_signed / rhs_signed;
|
return lhs_signed / rhs_signed;
|
||||||
}
|
}
|
||||||
static inline QData VL_DIVS_QQQ(int lbits, QData lhs, QData rhs) VL_PURE {
|
static inline QData VL_DIVS_QQQ(int lbits, QData lhs, QData rhs) VL_PURE {
|
||||||
if (VL_UNLIKELY(rhs == 0)) return 0;
|
if (VL_UNLIKELY(rhs == 0)) return 0;
|
||||||
|
// -MAX / -1 cannot be represented in twos complement, and will cause SIGFPE
|
||||||
|
if (VL_UNLIKELY(lhs == 0x8000000000000000ULL && rhs == 0xffffffffffffffffULL)) return 0;
|
||||||
vlsint64_t lhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, lhs);
|
vlsint64_t lhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, lhs);
|
||||||
vlsint64_t rhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, rhs);
|
vlsint64_t rhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, rhs);
|
||||||
return lhs_signed / rhs_signed;
|
return lhs_signed / rhs_signed;
|
||||||
}
|
}
|
||||||
static inline IData VL_MODDIVS_III(int lbits, IData lhs, IData rhs) VL_PURE {
|
static inline IData VL_MODDIVS_III(int lbits, IData lhs, IData rhs) VL_PURE {
|
||||||
if (VL_UNLIKELY(rhs == 0)) return 0;
|
if (VL_UNLIKELY(rhs == 0)) return 0;
|
||||||
|
if (VL_UNLIKELY(lhs == 0x80000000 && rhs == 0xffffffff)) return 0;
|
||||||
vlsint32_t lhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, lhs);
|
vlsint32_t lhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, lhs);
|
||||||
vlsint32_t rhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, rhs);
|
vlsint32_t rhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, rhs);
|
||||||
return lhs_signed % rhs_signed;
|
return lhs_signed % rhs_signed;
|
||||||
}
|
}
|
||||||
static inline QData VL_MODDIVS_QQQ(int lbits, QData lhs, QData rhs) VL_PURE {
|
static inline QData VL_MODDIVS_QQQ(int lbits, QData lhs, QData rhs) VL_PURE {
|
||||||
if (VL_UNLIKELY(rhs == 0)) return 0;
|
if (VL_UNLIKELY(rhs == 0)) return 0;
|
||||||
|
if (VL_UNLIKELY(lhs == 0x8000000000000000ULL && rhs == 0xffffffffffffffffULL)) return 0;
|
||||||
vlsint64_t lhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, lhs);
|
vlsint64_t lhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, lhs);
|
||||||
vlsint64_t rhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, rhs);
|
vlsint64_t rhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, rhs);
|
||||||
return lhs_signed % rhs_signed;
|
return lhs_signed % rhs_signed;
|
||||||
@@ -1627,7 +1658,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 +1666,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 +1915,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 +1928,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 +2391,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 +2418,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:
|
||||||
|
|||||||
+21
-23
@@ -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
|
||||||
@@ -221,20 +220,19 @@ private:
|
|||||||
}
|
}
|
||||||
static void selftest() VL_MT_SAFE {
|
static void selftest() VL_MT_SAFE {
|
||||||
// Little selftest
|
// Little selftest
|
||||||
#define VL_CST_CHECK(got, exp) \
|
#define SELF_CHECK(got, exp) \
|
||||||
do { \
|
do { \
|
||||||
if ((got) != (exp)) VL_FATAL_MT(__FILE__, __LINE__, "", "%Error: selftest\n"); \
|
if ((got) != (exp)) VL_FATAL_MT(__FILE__, __LINE__, "", "%Error: selftest\n"); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
SELF_CHECK(combineHier("a.b.c", "a.b.c"), "a.b.c");
|
||||||
VL_CST_CHECK(combineHier("a.b.c", "a.b.c"), "a.b.c");
|
SELF_CHECK(combineHier("a.b.c", "a.b"), "a.b*");
|
||||||
VL_CST_CHECK(combineHier("a.b.c", "a.b"), "a.b*");
|
SELF_CHECK(combineHier("a.x.c", "a.y.c"), "a.*.c");
|
||||||
VL_CST_CHECK(combineHier("a.x.c", "a.y.c"), "a.*.c");
|
SELF_CHECK(combineHier("a.z.z.z.c", "a.b.c"), "a.*.c");
|
||||||
VL_CST_CHECK(combineHier("a.z.z.z.c", "a.b.c"), "a.*.c");
|
SELF_CHECK(combineHier("z", "a"), "*");
|
||||||
VL_CST_CHECK(combineHier("z", "a"), "*");
|
SELF_CHECK(combineHier("q.a", "q.b"), "q.*");
|
||||||
VL_CST_CHECK(combineHier("q.a", "q.b"), "q.*");
|
SELF_CHECK(combineHier("q.za", "q.zb"), "q.z*");
|
||||||
VL_CST_CHECK(combineHier("q.za", "q.zb"), "q.z*");
|
SELF_CHECK(combineHier("1.2.3.a", "9.8.7.a"), "*.a");
|
||||||
VL_CST_CHECK(combineHier("1.2.3.a", "9.8.7.a"), "*.a");
|
#undef SELF_CHECK
|
||||||
#undef VL_CST_CHECK
|
|
||||||
}
|
}
|
||||||
void clearGuts() VL_REQUIRES(m_mutex) {
|
void clearGuts() VL_REQUIRES(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) {
|
||||||
@@ -250,12 +248,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 +269,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 +277,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 +330,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 +345,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 +473,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;
|
||||||
|
|||||||
+17
-32
@@ -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,15 @@ 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
|
|
||||||
= 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
|
||||||
@@ -177,40 +172,35 @@ void VerilatedFst::declSymbol(vluint32_t code, const char* name, int dtypenum, f
|
|||||||
fstEnumHandle enumNum = m_local2fstdtype[dtypenum];
|
fstEnumHandle enumNum = m_local2fstdtype[dtypenum];
|
||||||
fstWriterEmitEnumTableRef(m_fst, enumNum);
|
fstWriterEmitEnumTableRef(m_fst, enumNum);
|
||||||
}
|
}
|
||||||
if (p.second) { // New
|
|
||||||
p.first->second = fstWriterCreateVar(m_fst, vartype, vardir, len, name_str.c_str(), 0);
|
Code2SymbolType::const_iterator it = m_code2symbol.find(code);
|
||||||
assert(p.first->second);
|
if (it == m_code2symbol.end()) { // New
|
||||||
|
m_code2symbol[code]
|
||||||
|
= fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), 0);
|
||||||
} 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(), it->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);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class VlWriteMem {
|
class VlWriteMem {
|
||||||
|
bool m_hex; // Hex format
|
||||||
int m_bits; // Bit width of values
|
int m_bits; // Bit width of values
|
||||||
FILE* m_fp; // File handle for filename
|
FILE* m_fp; // File handle for filename
|
||||||
QData m_addr; // Next address to write
|
QData m_addr; // Next address to write
|
||||||
@@ -427,7 +428,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 std::size_t start = std::max<std::size_t>(31UL + 1UL + 3UL, s_s.m_fdps.size());
|
||||||
s_s.m_fdps.resize(start * 2);
|
const std::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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+14
-10
@@ -123,13 +123,13 @@ 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,
|
||||||
O_CREAT | O_WRONLY | O_TRUNC | O_LARGEFILE | O_NONBLOCK | O_CLOEXEC, 0666);
|
O_CREAT | O_WRONLY | O_TRUNC | O_LARGEFILE | O_NONBLOCK | O_CLOEXEC, 0666);
|
||||||
if (m_fd < 0) {
|
if (VL_UNLIKELY(m_fd < 0)) {
|
||||||
// User code can check isOpen()
|
// User code can check isOpen()
|
||||||
m_isOpen = false;
|
m_isOpen = false;
|
||||||
return;
|
return;
|
||||||
@@ -146,12 +146,12 @@ 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);
|
||||||
if (m_fd < 0) {
|
if (VL_UNLIKELY(m_fd < 0)) {
|
||||||
// User code can check isOpen()
|
// User code can check isOpen()
|
||||||
m_isOpen = false;
|
m_isOpen = false;
|
||||||
return;
|
return;
|
||||||
@@ -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;
|
||||||
@@ -263,13 +232,15 @@ class VerilatedVar : public VerilatedVarProps {
|
|||||||
void* m_datap; // Location of data
|
void* m_datap; // Location of data
|
||||||
const char* m_namep; // Name - slowpath
|
const char* m_namep; // Name - slowpath
|
||||||
protected:
|
protected:
|
||||||
|
bool m_isParam;
|
||||||
friend class VerilatedScope;
|
friend class VerilatedScope;
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype,
|
VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype,
|
||||||
VerilatedVarFlags vlflags, int dims)
|
VerilatedVarFlags vlflags, int dims, bool isParam)
|
||||||
: VerilatedVarProps(vltype, vlflags, (dims > 0 ? 1 : 0), ((dims > 1) ? dims - 1 : 0))
|
: VerilatedVarProps(vltype, vlflags, (dims > 0 ? 1 : 0), ((dims > 1) ? dims - 1 : 0))
|
||||||
, m_datap(datap)
|
, m_datap(datap)
|
||||||
, m_namep(namep) {}
|
, m_namep(namep)
|
||||||
|
, m_isParam(isParam) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~VerilatedVar() {}
|
~VerilatedVar() {}
|
||||||
@@ -278,6 +249,7 @@ public:
|
|||||||
const VerilatedRange& range() const { return packed(); } // Deprecated
|
const VerilatedRange& range() const { return packed(); } // Deprecated
|
||||||
const VerilatedRange& array() const { return unpacked(); } // Deprecated
|
const VerilatedRange& array() const { return unpacked(); } // Deprecated
|
||||||
const char* name() const { return m_namep; }
|
const char* name() const { return m_namep; }
|
||||||
|
bool isParam() const { return m_isParam; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // Guard
|
#endif // Guard
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
+42
-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,10 +152,17 @@ 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); }
|
||||||
|
|
||||||
|
// Flush any remaining data for this file
|
||||||
|
static void onFlush(void* selfp) VL_MT_UNSAFE_ONE;
|
||||||
|
// Close the file on termination
|
||||||
|
static void onExit(void* selfp) VL_MT_UNSAFE_ONE;
|
||||||
|
|
||||||
#ifdef VL_TRACE_THREADED
|
#ifdef VL_TRACE_THREADED
|
||||||
// Number of total trace buffers that have been allocated
|
// Number of total trace buffers that have been allocated
|
||||||
vluint32_t m_numTraceBuffers;
|
vluint32_t m_numTraceBuffers;
|
||||||
@@ -209,8 +238,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 +261,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 +290,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 +301,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 +346,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 +393,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,
|
||||||
@@ -287,6 +258,19 @@ template <> void VerilatedTrace<VL_DERIVED_T>::flush() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// Callbacks to run on global events
|
||||||
|
|
||||||
|
template <> void VerilatedTrace<VL_DERIVED_T>::onFlush(void* selfp) {
|
||||||
|
// Note this calls 'flush' on the derived class
|
||||||
|
reinterpret_cast<VL_DERIVED_T*>(selfp)->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> void VerilatedTrace<VL_DERIVED_T>::onExit(void* selfp) {
|
||||||
|
// Note this calls 'close' on the derived class
|
||||||
|
reinterpret_cast<VL_DERIVED_T*>(selfp)->close();
|
||||||
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// VerilatedTrace
|
// VerilatedTrace
|
||||||
|
|
||||||
@@ -311,10 +295,8 @@ 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()) {
|
Verilated::removeFlushCb(VerilatedTrace<VL_DERIVED_T>::onFlush, this);
|
||||||
delete m_callbacks.back();
|
Verilated::removeExitCb(VerilatedTrace<VL_DERIVED_T>::onExit, this);
|
||||||
m_callbacks.pop_back();
|
|
||||||
}
|
|
||||||
#ifdef VL_TRACE_THREADED
|
#ifdef VL_TRACE_THREADED
|
||||||
close();
|
close();
|
||||||
#endif
|
#endif
|
||||||
@@ -334,11 +316,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) {
|
||||||
@@ -350,6 +333,10 @@ template <> void VerilatedTrace<VL_DERIVED_T>::traceInit() VL_MT_UNSAFE {
|
|||||||
// holding previous signal values.
|
// holding previous signal values.
|
||||||
if (!m_sigs_oldvalp) m_sigs_oldvalp = new vluint32_t[nextCode()];
|
if (!m_sigs_oldvalp) m_sigs_oldvalp = new vluint32_t[nextCode()];
|
||||||
|
|
||||||
|
// Set callback so flush/abort will flush this file
|
||||||
|
Verilated::addFlushCb(VerilatedTrace<VL_DERIVED_T>::onFlush, this);
|
||||||
|
Verilated::addExitCb(VerilatedTrace<VL_DERIVED_T>::onExit, this);
|
||||||
|
|
||||||
#ifdef VL_TRACE_THREADED
|
#ifdef VL_TRACE_THREADED
|
||||||
// Compute trace buffer size. we need to be able to store a new value for
|
// Compute trace buffer size. we need to be able to store a new value for
|
||||||
// each signal, which is 'nextCode()' entries after the init callbacks
|
// each signal, which is 'nextCode()' entries after the init callbacks
|
||||||
@@ -409,12 +396,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 +439,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 +473,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 +544,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++) {
|
||||||
|
|||||||
+61
-142
@@ -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
|
||||||
@@ -69,47 +66,6 @@
|
|||||||
#include "verilated_trace_imp.cpp"
|
#include "verilated_trace_imp.cpp"
|
||||||
#undef VL_DERIVED_T
|
#undef VL_DERIVED_T
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
// VerilatedVcdImp
|
|
||||||
/// Base class to hold some static state
|
|
||||||
/// This is an internally used class
|
|
||||||
|
|
||||||
class VerilatedVcdSingleton {
|
|
||||||
private:
|
|
||||||
typedef std::vector<VerilatedVcd*> VcdVec;
|
|
||||||
struct Singleton {
|
|
||||||
VerilatedMutex s_vcdMutex; ///< Protect the singleton
|
|
||||||
VcdVec s_vcdVecp VL_GUARDED_BY(s_vcdMutex); ///< List of all created traces
|
|
||||||
};
|
|
||||||
static Singleton& singleton() {
|
|
||||||
static Singleton s;
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
static void pushVcd(VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
|
|
||||||
VerilatedLockGuard lock(singleton().s_vcdMutex);
|
|
||||||
singleton().s_vcdVecp.push_back(vcdp);
|
|
||||||
}
|
|
||||||
static void removeVcd(const VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
|
|
||||||
VerilatedLockGuard lock(singleton().s_vcdMutex);
|
|
||||||
VcdVec::iterator pos
|
|
||||||
= find(singleton().s_vcdVecp.begin(), singleton().s_vcdVecp.end(), vcdp);
|
|
||||||
if (pos != singleton().s_vcdVecp.end()) { singleton().s_vcdVecp.erase(pos); }
|
|
||||||
}
|
|
||||||
static void flush_all() VL_EXCLUDES(singleton().s_vcdMutex) VL_MT_UNSAFE_ONE {
|
|
||||||
// Thread safety: Although this function is protected by a mutex so
|
|
||||||
// perhaps in the future we can allow tracing in separate threads,
|
|
||||||
// vcdp->flush() assumes call from single thread
|
|
||||||
VerilatedLockGuard lock(singleton().s_vcdMutex);
|
|
||||||
for (VcdVec::const_iterator it = singleton().s_vcdVecp.begin();
|
|
||||||
it != singleton().s_vcdVecp.end(); ++it) {
|
|
||||||
VerilatedVcd* vcdp = *it;
|
|
||||||
vcdp->flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
@@ -155,13 +111,7 @@ void VerilatedVcd::open(const char* filename) {
|
|||||||
|
|
||||||
// Set member variables
|
// Set member variables
|
||||||
m_filename = filename; // "" is ok, as someone may overload open
|
m_filename = filename; // "" is ok, as someone may overload open
|
||||||
VerilatedVcdSingleton::pushVcd(this);
|
|
||||||
|
|
||||||
// SPDIFF_OFF
|
|
||||||
// Set callback so an early exit will flush us
|
|
||||||
Verilated::flushCb(&flush_all);
|
|
||||||
|
|
||||||
// SPDIFF_ON
|
|
||||||
openNext(m_rolloverMB != 0);
|
openNext(m_rolloverMB != 0);
|
||||||
if (!isOpen()) return;
|
if (!isOpen()) return;
|
||||||
|
|
||||||
@@ -203,8 +153,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)) {
|
||||||
@@ -269,7 +219,6 @@ VerilatedVcd::~VerilatedVcd() {
|
|||||||
if (m_wrBufp) VL_DO_CLEAR(delete[] m_wrBufp, m_wrBufp = NULL);
|
if (m_wrBufp) VL_DO_CLEAR(delete[] m_wrBufp, m_wrBufp = NULL);
|
||||||
deleteNameMap();
|
deleteNameMap();
|
||||||
if (m_filep && m_fileNewed) VL_DO_CLEAR(delete m_filep, m_filep = NULL);
|
if (m_filep && m_fileNewed) VL_DO_CLEAR(delete m_filep, m_filep = NULL);
|
||||||
VerilatedVcdSingleton::removeVcd(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VerilatedVcd::closePrev() {
|
void VerilatedVcd::closePrev() {
|
||||||
@@ -358,13 +307,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 +534,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 +647,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 +681,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 +703,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 +731,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,46 +772,12 @@ 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
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// Static members
|
|
||||||
|
|
||||||
void VerilatedVcd::flush_all() VL_MT_UNSAFE_ONE { VerilatedVcdSingleton::flush_all(); }
|
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
//======================================================================
|
//======================================================================
|
||||||
//======================================================================
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
|
|
||||||
#ifdef VERILATED_VCD_TEST
|
#ifdef VERILATED_VCD_TEST
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -882,34 +786,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 +828,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 +842,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 +855,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
-30
@@ -105,9 +105,6 @@ private:
|
|||||||
|
|
||||||
void finishLine(vluint32_t code, char* writep);
|
void finishLine(vluint32_t code, char* writep);
|
||||||
|
|
||||||
/// Flush any remaining data from all files
|
|
||||||
static void flush_all() VL_MT_UNSAFE_ONE;
|
|
||||||
|
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VL_UNCOPYABLE(VerilatedVcd);
|
VL_UNCOPYABLE(VerilatedVcd);
|
||||||
|
|
||||||
@@ -130,7 +127,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 +159,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 +190,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 +208,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 +221,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 +243,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 +284,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 +310,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 +380,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
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
+516
-546
File diff suppressed because it is too large
Load Diff
+23
-16
@@ -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
|
||||||
@@ -428,7 +435,7 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
|||||||
// Performance counters
|
// Performance counters
|
||||||
|
|
||||||
/// The vluint64_t argument is loaded with a high-performance counter for profiling
|
/// The vluint64_t argument is loaded with a high-performance counter for profiling
|
||||||
/// or 0x0 if not implemeted on this platform
|
/// or 0x0 if not implemented on this platform
|
||||||
#if defined(__i386__) || defined(__x86_64__)
|
#if defined(__i386__) || defined(__x86_64__)
|
||||||
#define VL_RDTSC(val) \
|
#define VL_RDTSC(val) \
|
||||||
{ \
|
{ \
|
||||||
|
|||||||
@@ -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,22 @@ 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\(\)
|
||||||
|
|\bSELF_CHECK)/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:
|
|
||||||
+8
-7
@@ -69,22 +69,23 @@ dbg: ../bin/verilator_bin_dbg ../bin/verilator_coverage_bin_dbg
|
|||||||
$(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj serial_vlcov
|
$(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj serial_vlcov
|
||||||
$(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj
|
$(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj
|
||||||
|
|
||||||
|
ifneq ($(VERILATOR_NO_OPT_BUILD),1) # Faster laptop development... don't rebuild each commit
|
||||||
|
ifneq ($(UNDER_GIT),) # If local git tree... else don't burden users
|
||||||
|
GIT_CHANGE_DEP = ${srcdir}/../.git/logs/HEAD
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
prefiles::
|
prefiles::
|
||||||
prefiles:: config_rev.h
|
prefiles:: config_rev.h
|
||||||
ifneq ($(UNDER_GIT),) # If local git tree... Else don't burden users
|
|
||||||
# This output goes into srcdir if locally configured, as we need to distribute it as part of the kit.
|
# This output goes into srcdir if locally configured, as we need to distribute it as part of the kit.
|
||||||
config_rev.h: ${srcdir}/config_rev.pl ${srcdir}/../.git/logs/HEAD
|
config_rev.h: ${srcdir}/config_rev.pl $(GIT_CHANGE_DEP)
|
||||||
$(PERL) ${srcdir}/config_rev.pl ${srcdir} >$@
|
$(PERL) ${srcdir}/config_rev.pl ${srcdir} >$@
|
||||||
else
|
|
||||||
config_rev.h: ${srcdir}/config_rev.pl
|
|
||||||
$(PERL) ${srcdir}/config_rev.pl ${srcdir} >$@
|
|
||||||
endif
|
|
||||||
|
|
||||||
maintainer-copy::
|
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
-7
@@ -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 \
|
||||||
|
|
||||||
@@ -275,7 +278,6 @@ V3__CONCAT.cpp: $(addsuffix .cpp, $(basename $(RAW_OBJS)))
|
|||||||
|
|
||||||
$(TGT): $(PREDEP_H) $(OBJS)
|
$(TGT): $(PREDEP_H) $(OBJS)
|
||||||
@echo " Linking $@..."
|
@echo " Linking $@..."
|
||||||
-rm -rf $@ [email protected]
|
|
||||||
${LINK} ${LDFLAGS} -o $@ $(OBJS) $(CCMALLOC) ${LIBS}
|
${LINK} ${LDFLAGS} -o $@ $(OBJS) $(CCMALLOC) ${LIBS}
|
||||||
|
|
||||||
V3Number_test: V3Number_test.o
|
V3Number_test: V3Number_test.o
|
||||||
@@ -287,21 +289,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
|
||||||
|
|
||||||
|
|||||||
+5
-15
@@ -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
|
||||||
@@ -317,10 +316,8 @@ private:
|
|||||||
|
|
||||||
if (!combo && !sequent) combo = true; // If no list, Verilog 2000: always @ (*)
|
if (!combo && !sequent) combo = true; // If no list, Verilog 2000: always @ (*)
|
||||||
if (combo && sequent) {
|
if (combo && sequent) {
|
||||||
if (!v3Global.opt.bboxUnsup()) {
|
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Mixed edge (pos/negedge) and activity "
|
||||||
nodep->v3error("Unsupported: Mixed edge (pos/negedge) and activity "
|
"(no edge) sensitive activity list");
|
||||||
"(no edge) sensitive activity list");
|
|
||||||
}
|
|
||||||
sequent = false;
|
sequent = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,14 +376,6 @@ private:
|
|||||||
// if (debug() >= 9) nodep->dumpTree(cout, " Alw: ");
|
// if (debug() >= 9) nodep->dumpTree(cout, " Alw: ");
|
||||||
visitAlways(nodep, nodep->sensesp(), VAlwaysKwd::ALWAYS);
|
visitAlways(nodep, nodep->sensesp(), VAlwaysKwd::ALWAYS);
|
||||||
}
|
}
|
||||||
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
|
|
||||||
AstSenItem* subitemp = nodep->sensesp();
|
|
||||||
UASSERT_OBJ(subitemp->edgeType() == VEdgeType::ET_ANYEDGE
|
|
||||||
|| subitemp->edgeType() == VEdgeType::ET_POSEDGE
|
|
||||||
|| subitemp->edgeType() == VEdgeType::ET_NEGEDGE,
|
|
||||||
nodep, "Strange activity type under SenGate");
|
|
||||||
iterateChildren(nodep);
|
|
||||||
}
|
|
||||||
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
|
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
|
||||||
if (nodep->varrefp()) {
|
if (nodep->varrefp()) {
|
||||||
if (AstBasicDType* basicp = nodep->varrefp()->dtypep()->basicp()) {
|
if (AstBasicDType* basicp = nodep->varrefp()->dtypep()->basicp()) {
|
||||||
@@ -406,8 +395,9 @@ private:
|
|||||||
} else if (nodep->varrefp()) {
|
} else if (nodep->varrefp()) {
|
||||||
// V3LinkResolve should have cleaned most of these up
|
// V3LinkResolve should have cleaned most of these up
|
||||||
if (!nodep->varrefp()->width1()) {
|
if (!nodep->varrefp()->width1()) {
|
||||||
nodep->v3error("Unsupported: Non-single bit wide signal pos/negedge sensitivity: "
|
nodep->v3warn(E_UNSUPPORTED,
|
||||||
<< nodep->varrefp()->prettyNameQ());
|
"Unsupported: Non-single bit wide signal pos/negedge sensitivity: "
|
||||||
|
<< nodep->varrefp()->prettyNameQ());
|
||||||
}
|
}
|
||||||
m_itemSequent = true;
|
m_itemSequent = true;
|
||||||
nodep->varrefp()->varp()->usedClock(true);
|
nodep->varrefp()->varp()->usedClock(true);
|
||||||
|
|||||||
+3
-9
@@ -54,7 +54,7 @@ private:
|
|||||||
// VISITORS
|
// VISITORS
|
||||||
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
|
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
|
||||||
m_topscopep = nodep;
|
m_topscopep = nodep;
|
||||||
m_finder.main(m_topscopep);
|
m_finder.init(m_topscopep);
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
m_topscopep = NULL;
|
m_topscopep = NULL;
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
+7
-9
@@ -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
|
||||||
|
|
||||||
@@ -37,11 +34,11 @@ private:
|
|||||||
// NODE STATE/TYPES
|
// NODE STATE/TYPES
|
||||||
// STATE
|
// STATE
|
||||||
// Reset each module:
|
// Reset each module:
|
||||||
AstNodeSenItem* m_seniDefaultp; // Default sensitivity (from AstDefClock)
|
AstSenItem* m_seniDefaultp; // Default sensitivity (from AstDefClock)
|
||||||
// Reset each assertion:
|
// Reset each assertion:
|
||||||
AstNodeSenItem* m_senip; // Last sensitivity
|
AstSenItem* m_senip; // Last sensitivity
|
||||||
// Reset each always:
|
// Reset each always:
|
||||||
AstNodeSenItem* m_seniAlwaysp; // Last sensitivity in always
|
AstSenItem* m_seniAlwaysp; // Last sensitivity in always
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
VL_DEBUG_FUNC; // Declare debug()
|
VL_DEBUG_FUNC; // Declare debug()
|
||||||
@@ -50,11 +47,11 @@ private:
|
|||||||
// Create sentree based on clocked or default clock
|
// Create sentree based on clocked or default clock
|
||||||
// Return NULL for always
|
// Return NULL for always
|
||||||
AstSenTree* newp = NULL;
|
AstSenTree* newp = NULL;
|
||||||
AstNodeSenItem* senip = m_senip;
|
AstSenItem* senip = m_senip;
|
||||||
if (!senip) senip = m_seniDefaultp;
|
if (!senip) senip = m_seniDefaultp;
|
||||||
if (!senip) senip = m_seniAlwaysp;
|
if (!senip) senip = m_seniAlwaysp;
|
||||||
if (!senip) {
|
if (!senip) {
|
||||||
nodep->v3error("Unsupported: Unclocked assertion");
|
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Unclocked assertion");
|
||||||
newp = new AstSenTree(nodep->fileline(), NULL);
|
newp = new AstSenTree(nodep->fileline(), NULL);
|
||||||
} else {
|
} else {
|
||||||
newp = new AstSenTree(nodep->fileline(), senip->cloneTree(true));
|
newp = new AstSenTree(nodep->fileline(), senip->cloneTree(true));
|
||||||
@@ -100,7 +97,8 @@ private:
|
|||||||
virtual void visit(AstPropClocked* nodep) VL_OVERRIDE {
|
virtual void visit(AstPropClocked* nodep) VL_OVERRIDE {
|
||||||
// No need to iterate the body, once replace will get iterated
|
// No need to iterate the body, once replace will get iterated
|
||||||
iterateAndNextNull(nodep->sensesp());
|
iterateAndNextNull(nodep->sensesp());
|
||||||
if (m_senip) nodep->v3error("Unsupported: Only one PSL clock allowed per assertion");
|
if (m_senip)
|
||||||
|
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Only one PSL clock allowed per assertion");
|
||||||
// Block is the new expression to evaluate
|
// Block is the new expression to evaluate
|
||||||
AstNode* blockp = nodep->propp()->unlinkFrBack();
|
AstNode* blockp = nodep->propp()->unlinkFrBack();
|
||||||
if (nodep->disablep()) {
|
if (nodep->disablep()) {
|
||||||
|
|||||||
+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))) {
|
||||||
|
|||||||
+110
-61
@@ -117,6 +117,9 @@ public:
|
|||||||
inline bool operator==(const VLifetime& lhs, const VLifetime& rhs) { return lhs.m_e == rhs.m_e; }
|
inline bool operator==(const VLifetime& lhs, const VLifetime& rhs) { return lhs.m_e == rhs.m_e; }
|
||||||
inline bool operator==(const VLifetime& lhs, VLifetime::en rhs) { return lhs.m_e == rhs; }
|
inline bool operator==(const VLifetime& lhs, VLifetime::en rhs) { return lhs.m_e == rhs; }
|
||||||
inline bool operator==(VLifetime::en lhs, const VLifetime& rhs) { return lhs == rhs.m_e; }
|
inline bool operator==(VLifetime::en lhs, const VLifetime& rhs) { return lhs == rhs.m_e; }
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, const VLifetime& rhs) {
|
||||||
|
return os << rhs.ascii();
|
||||||
|
}
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|
||||||
@@ -193,12 +196,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 +215,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 +260,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 +1083,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 +1103,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 +1313,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 +1350,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 +1503,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 +1784,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; }
|
||||||
@@ -1814,6 +1812,8 @@ public:
|
|||||||
virtual bool hasDType() const { return false; }
|
virtual bool hasDType() const { return false; }
|
||||||
// Iff has a non-null childDTypep(), as generic node function
|
// Iff has a non-null childDTypep(), as generic node function
|
||||||
virtual AstNodeDType* getChildDTypep() const { return NULL; }
|
virtual AstNodeDType* getChildDTypep() const { return NULL; }
|
||||||
|
// Iff has a non-null child2DTypep(), as generic node function
|
||||||
|
virtual AstNodeDType* getChild2DTypep() const { return NULL; }
|
||||||
// Another AstNode* may have a pointer into this node, other then normal front/back/etc.
|
// Another AstNode* may have a pointer into this node, other then normal front/back/etc.
|
||||||
virtual bool maybePointedTo() const { return false; }
|
virtual bool maybePointedTo() const { return false; }
|
||||||
virtual const char* broken() const { return NULL; }
|
virtual const char* broken() const { return NULL; }
|
||||||
@@ -1998,6 +1998,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 +2127,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)
|
||||||
@@ -2195,19 +2246,6 @@ public:
|
|||||||
void addNotParallelp(AstNode* nodep) { setOp3p(nodep); }
|
void addNotParallelp(AstNode* nodep) { setOp3p(nodep); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class AstNodeSenItem : public AstNode {
|
|
||||||
// An AstSenItem or AstSenGate
|
|
||||||
public:
|
|
||||||
AstNodeSenItem(AstType t, FileLine* fl)
|
|
||||||
: AstNode(t, fl) {}
|
|
||||||
ASTNODE_BASE_FUNCS(NodeSenItem)
|
|
||||||
virtual bool isClocked() const = 0;
|
|
||||||
virtual bool isCombo() const = 0;
|
|
||||||
virtual bool isInitial() const = 0;
|
|
||||||
virtual bool isSettle() const = 0;
|
|
||||||
virtual bool isNever() const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AstNodeVarRef : public AstNodeMath {
|
class AstNodeVarRef : public AstNodeMath {
|
||||||
// An AstVarRef or AstVarXRef
|
// An AstVarRef or AstVarXRef
|
||||||
private:
|
private:
|
||||||
@@ -2218,29 +2256,26 @@ private:
|
|||||||
string m_name; // Name of variable
|
string m_name; // Name of variable
|
||||||
string m_hiername; // Scope converted into name-> for emitting
|
string m_hiername; // Scope converted into name-> for emitting
|
||||||
bool m_hierThis; // Hiername points to "this" function
|
bool m_hierThis; // Hiername points to "this" function
|
||||||
void init();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AstNodeVarRef(AstType t, FileLine* fl, const string& name, bool lvalue)
|
AstNodeVarRef(AstType t, FileLine* fl, const string& name, bool lvalue)
|
||||||
: AstNodeMath(t, fl)
|
: AstNodeMath(t, fl)
|
||||||
, m_lvalue(lvalue)
|
, m_lvalue(lvalue)
|
||||||
, m_varp(NULL)
|
|
||||||
, m_varScopep(NULL)
|
, m_varScopep(NULL)
|
||||||
, m_packagep(NULL)
|
, m_packagep(NULL)
|
||||||
, m_name(name)
|
, m_name(name)
|
||||||
, m_hierThis(false) {
|
, m_hierThis(false) {
|
||||||
init();
|
this->varp(NULL);
|
||||||
}
|
}
|
||||||
AstNodeVarRef(AstType t, FileLine* fl, const string& name, AstVar* varp, bool lvalue)
|
AstNodeVarRef(AstType t, FileLine* fl, const string& name, AstVar* varp, bool lvalue)
|
||||||
: AstNodeMath(t, fl)
|
: AstNodeMath(t, fl)
|
||||||
, m_lvalue(lvalue)
|
, m_lvalue(lvalue)
|
||||||
, m_varp(varp)
|
|
||||||
, m_varScopep(NULL)
|
, m_varScopep(NULL)
|
||||||
, m_packagep(NULL)
|
, m_packagep(NULL)
|
||||||
, m_name(name)
|
, m_name(name)
|
||||||
, m_hierThis(false) {
|
, m_hierThis(false) {
|
||||||
// May have varp==NULL
|
// May have varp==NULL
|
||||||
init();
|
this->varp(varp);
|
||||||
}
|
}
|
||||||
ASTNODE_BASE_FUNCS(NodeVarRef)
|
ASTNODE_BASE_FUNCS(NodeVarRef)
|
||||||
virtual bool hasDType() const { return true; }
|
virtual bool hasDType() const { return true; }
|
||||||
@@ -2252,7 +2287,7 @@ public:
|
|||||||
bool lvalue() const { return m_lvalue; }
|
bool lvalue() const { return m_lvalue; }
|
||||||
void lvalue(bool lval) { m_lvalue = lval; } // Avoid using this; Set in constructor
|
void lvalue(bool lval) { m_lvalue = lval; } // Avoid using this; Set in constructor
|
||||||
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
|
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
|
||||||
void varp(AstVar* varp) { m_varp = varp; }
|
void varp(AstVar* varp);
|
||||||
AstVarScope* varScopep() const { return m_varScopep; }
|
AstVarScope* varScopep() const { return m_varScopep; }
|
||||||
void varScopep(AstVarScope* varscp) { m_varScopep = varscp; }
|
void varScopep(AstVarScope* varscp) { m_varScopep = varscp; }
|
||||||
string hiername() const { return m_hiername; }
|
string hiername() const { return m_hiername; }
|
||||||
@@ -2323,9 +2358,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 +2463,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 +2473,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 +2515,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; }
|
||||||
@@ -2594,6 +2625,7 @@ private:
|
|||||||
bool m_taskPublic : 1; // Public task
|
bool m_taskPublic : 1; // Public task
|
||||||
bool m_attrIsolateAssign : 1; // User isolate_assignments attribute
|
bool m_attrIsolateAssign : 1; // User isolate_assignments attribute
|
||||||
bool m_classMethod : 1; // Class method
|
bool m_classMethod : 1; // Class method
|
||||||
|
bool m_extern : 1; // Extern prototype
|
||||||
bool m_prototype : 1; // Just a prototype
|
bool m_prototype : 1; // Just a prototype
|
||||||
bool m_dpiExport : 1; // DPI exported
|
bool m_dpiExport : 1; // DPI exported
|
||||||
bool m_dpiImport : 1; // DPI imported
|
bool m_dpiImport : 1; // DPI imported
|
||||||
@@ -2602,6 +2634,8 @@ private:
|
|||||||
bool m_dpiTask : 1; // DPI import task (vs. void function)
|
bool m_dpiTask : 1; // DPI import task (vs. void function)
|
||||||
bool m_isConstructor : 1; // Class constructor
|
bool m_isConstructor : 1; // Class constructor
|
||||||
bool m_pure : 1; // DPI import pure (vs. virtual pure)
|
bool m_pure : 1; // DPI import pure (vs. virtual pure)
|
||||||
|
bool m_pureVirtual : 1; // Pure virtual
|
||||||
|
bool m_virtual : 1; // Virtual method in class
|
||||||
VLifetime m_lifetime; // Lifetime
|
VLifetime m_lifetime; // Lifetime
|
||||||
public:
|
public:
|
||||||
AstNodeFTask(AstType t, FileLine* fl, const string& name, AstNode* stmtsp)
|
AstNodeFTask(AstType t, FileLine* fl, const string& name, AstNode* stmtsp)
|
||||||
@@ -2611,6 +2645,7 @@ public:
|
|||||||
, m_taskPublic(false)
|
, m_taskPublic(false)
|
||||||
, m_attrIsolateAssign(false)
|
, m_attrIsolateAssign(false)
|
||||||
, m_classMethod(false)
|
, m_classMethod(false)
|
||||||
|
, m_extern(false)
|
||||||
, m_prototype(false)
|
, m_prototype(false)
|
||||||
, m_dpiExport(false)
|
, m_dpiExport(false)
|
||||||
, m_dpiImport(false)
|
, m_dpiImport(false)
|
||||||
@@ -2618,7 +2653,9 @@ public:
|
|||||||
, m_dpiOpenChild(false)
|
, m_dpiOpenChild(false)
|
||||||
, m_dpiTask(false)
|
, m_dpiTask(false)
|
||||||
, m_isConstructor(false)
|
, m_isConstructor(false)
|
||||||
, m_pure(false) {
|
, m_pure(false)
|
||||||
|
, m_pureVirtual(false)
|
||||||
|
, m_virtual(false) {
|
||||||
addNOp3p(stmtsp);
|
addNOp3p(stmtsp);
|
||||||
cname(name); // Might be overridden by dpi import/export
|
cname(name); // Might be overridden by dpi import/export
|
||||||
}
|
}
|
||||||
@@ -2651,6 +2688,8 @@ public:
|
|||||||
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
|
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
|
||||||
void classMethod(bool flag) { m_classMethod = flag; }
|
void classMethod(bool flag) { m_classMethod = flag; }
|
||||||
bool classMethod() const { return m_classMethod; }
|
bool classMethod() const { return m_classMethod; }
|
||||||
|
void isExtern(bool flag) { m_extern = flag; }
|
||||||
|
bool isExtern() const { return m_extern; }
|
||||||
void prototype(bool flag) { m_prototype = flag; }
|
void prototype(bool flag) { m_prototype = flag; }
|
||||||
bool prototype() const { return m_prototype; }
|
bool prototype() const { return m_prototype; }
|
||||||
void dpiExport(bool flag) { m_dpiExport = flag; }
|
void dpiExport(bool flag) { m_dpiExport = flag; }
|
||||||
@@ -2667,6 +2706,10 @@ public:
|
|||||||
bool isConstructor() const { return m_isConstructor; }
|
bool isConstructor() const { return m_isConstructor; }
|
||||||
void pure(bool flag) { m_pure = flag; }
|
void pure(bool flag) { m_pure = flag; }
|
||||||
bool pure() const { return m_pure; }
|
bool pure() const { return m_pure; }
|
||||||
|
void pureVirtual(bool flag) { m_pureVirtual = flag; }
|
||||||
|
bool pureVirtual() const { return m_pureVirtual; }
|
||||||
|
void isVirtual(bool flag) { m_virtual = flag; }
|
||||||
|
bool isVirtual() const { return m_virtual; }
|
||||||
void lifetime(const VLifetime& flag) { m_lifetime = flag; }
|
void lifetime(const VLifetime& flag) { m_lifetime = flag; }
|
||||||
VLifetime lifetime() const { return m_lifetime; }
|
VLifetime lifetime() const { return m_lifetime; }
|
||||||
};
|
};
|
||||||
@@ -2680,11 +2723,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 +2737,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 +2762,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
|
||||||
@@ -2879,8 +2927,9 @@ inline bool AstNode::sameGateTree(const AstNode* node2p) const {
|
|||||||
return sameTreeIter(this, node2p, true, true);
|
return sameTreeIter(this, node2p, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void AstNodeVarRef::init() {
|
inline void AstNodeVarRef::varp(AstVar* varp) {
|
||||||
if (m_varp) dtypep(m_varp->dtypep());
|
m_varp = varp;
|
||||||
|
dtypeFrom(varp);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool AstNodeDType::isFourstate() const { return basicp()->isFourstate(); }
|
inline bool AstNodeDType::isFourstate() const { return basicp()->isFourstate(); }
|
||||||
|
|||||||
+188
-142
@@ -22,9 +22,9 @@
|
|||||||
#include "V3Global.h"
|
#include "V3Global.h"
|
||||||
#include "V3Graph.h"
|
#include "V3Graph.h"
|
||||||
#include "V3PartitionGraph.h" // Just for mtask dumping
|
#include "V3PartitionGraph.h" // Just for mtask dumping
|
||||||
|
#include "V3String.h" // For VString::parseDouble
|
||||||
#include "V3EmitCBase.h"
|
#include "V3EmitCBase.h"
|
||||||
|
|
||||||
#include <cstdarg>
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -226,6 +226,36 @@ AstNode* AstInsideRange::newAndFromInside(AstNode* exprp, AstNode* lhsp, AstNode
|
|||||||
return newp;
|
return newp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AstConst* AstConst::parseParamLiteral(FileLine* fl, const string& literal) {
|
||||||
|
bool success = false;
|
||||||
|
if (literal[0] == '"') {
|
||||||
|
// This is a string
|
||||||
|
string v = literal.substr(1, literal.find('"', 1) - 1);
|
||||||
|
return new AstConst(fl, AstConst::VerilogStringLiteral(), v);
|
||||||
|
} else if (literal.find_first_of(".eEpP") != string::npos) {
|
||||||
|
// This may be a real
|
||||||
|
double v = VString::parseDouble(literal, &success);
|
||||||
|
if (success) return new AstConst(fl, AstConst::RealDouble(), v);
|
||||||
|
}
|
||||||
|
if (!success) {
|
||||||
|
// This is either an integer or an error
|
||||||
|
// We first try to convert it as C literal. If strtol returns
|
||||||
|
// 0 this is either an error or 0 was parsed. But in any case
|
||||||
|
// we will try to parse it as a verilog literal, hence having
|
||||||
|
// the false negative for 0 is okay. If anything remains in
|
||||||
|
// the string after the number, this is invalid C and we try
|
||||||
|
// the Verilog literal parser.
|
||||||
|
char* endp;
|
||||||
|
int v = strtol(literal.c_str(), &endp, 0);
|
||||||
|
if ((v != 0) && (endp[0] == 0)) { // C literal
|
||||||
|
return new AstConst(fl, AstConst::WidthedValue(), 32, v);
|
||||||
|
} else { // Try a Verilog literal (fatals if not)
|
||||||
|
return new AstConst(fl, AstConst::StringToParse(), literal.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void AstNetlist::timeprecisionMerge(FileLine*, const VTimescale& value) {
|
void AstNetlist::timeprecisionMerge(FileLine*, const VTimescale& value) {
|
||||||
VTimescale prec = v3Global.opt.timeComputePrec(value);
|
VTimescale prec = v3Global.opt.timeComputePrec(value);
|
||||||
if (prec.isNone() || prec == m_timeprecision) {
|
if (prec.isNone() || prec == m_timeprecision) {
|
||||||
@@ -282,16 +312,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 +331,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 +462,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -513,8 +526,8 @@ string AstVar::cPubArgType(bool named, bool forReturn) const {
|
|||||||
}
|
}
|
||||||
if (isWide()) {
|
if (isWide()) {
|
||||||
if (forReturn) {
|
if (forReturn) {
|
||||||
v3error("Unsupported: Public functions with >64 bit outputs; "
|
v3warn(E_UNSUPPORTED, "Unsupported: Public functions with >64 bit outputs; "
|
||||||
"make an output of a public task instead");
|
"make an output of a public task instead");
|
||||||
}
|
}
|
||||||
arg += " (& " + name();
|
arg += " (& " + name();
|
||||||
arg += ")[" + cvtToStr(widthWords()) + "]";
|
arg += ")[" + cvtToStr(widthWords()) + "]";
|
||||||
@@ -746,6 +759,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 +774,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 +781,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 +799,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)) {
|
||||||
@@ -797,28 +815,28 @@ string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const {
|
|||||||
|
|
||||||
bool AstSenTree::hasClocked() const {
|
bool AstSenTree::hasClocked() const {
|
||||||
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
||||||
for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) {
|
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
|
||||||
if (senp->isClocked()) return true;
|
if (senp->isClocked()) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool AstSenTree::hasSettle() const {
|
bool AstSenTree::hasSettle() const {
|
||||||
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
||||||
for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) {
|
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
|
||||||
if (senp->isSettle()) return true;
|
if (senp->isSettle()) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool AstSenTree::hasInitial() const {
|
bool AstSenTree::hasInitial() const {
|
||||||
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
||||||
for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) {
|
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
|
||||||
if (senp->isInitial()) return true;
|
if (senp->isInitial()) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool AstSenTree::hasCombo() const {
|
bool AstSenTree::hasCombo() const {
|
||||||
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
||||||
for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) {
|
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
|
||||||
if (senp->isCombo()) return true;
|
if (senp->isCombo()) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -977,27 +995,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 +1170,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 +1255,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 +1280,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 +1425,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 +1443,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 +1495,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 +1503,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 +1518,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 +1550,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);
|
||||||
|
|||||||
+527
-197
File diff suppressed because it is too large
Load Diff
@@ -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
-13
@@ -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;
|
||||||
@@ -697,8 +694,6 @@ private:
|
|||||||
m_inDly = false;
|
m_inDly = false;
|
||||||
}
|
}
|
||||||
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
|
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
|
||||||
// Note we look at only AstSenItems, not AstSenGate's
|
|
||||||
// The gating term of a AstSenGate is normal logic
|
|
||||||
m_inSenItem = true;
|
m_inSenItem = true;
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
m_inSenItem = false;
|
m_inSenItem = false;
|
||||||
@@ -708,11 +703,6 @@ private:
|
|||||||
// CDC doesn't care about public variables
|
// CDC doesn't care about public variables
|
||||||
}
|
}
|
||||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
|
virtual void visit(AstCFunc* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
|
||||||
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
|
|
||||||
// First handle the clock part will be handled in a minute by visit AstSenItem
|
|
||||||
// The logic gating term is dealt with as logic
|
|
||||||
iterateNewStmt(nodep);
|
|
||||||
}
|
|
||||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
|
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
|
||||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
|
virtual void visit(AstAssignW* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
|
||||||
|
|
||||||
@@ -732,7 +722,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);
|
||||||
|
|||||||
+7
-25
@@ -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
|
||||||
@@ -70,8 +66,8 @@ private:
|
|||||||
if (vscp->user1p()) return static_cast<AstVarScope*>(vscp->user1p());
|
if (vscp->user1p()) return static_cast<AstVarScope*>(vscp->user1p());
|
||||||
AstVar* varp = vscp->varp();
|
AstVar* varp = vscp->varp();
|
||||||
if (!varp->width1()) {
|
if (!varp->width1()) {
|
||||||
varp->v3error(
|
varp->v3warn(E_UNSUPPORTED, "Unsupported: Clock edge on non-single bit signal: "
|
||||||
"Unsupported: Clock edge on non-single bit signal: " << varp->prettyNameQ());
|
<< varp->prettyNameQ());
|
||||||
}
|
}
|
||||||
string newvarname
|
string newvarname
|
||||||
= (string("__Vclklast__") + vscp->scopep()->nameDotless() + "__" + varp->name());
|
= (string("__Vclklast__") + vscp->scopep()->nameDotless() + "__" + varp->name());
|
||||||
@@ -107,10 +103,8 @@ private:
|
|||||||
// LOWEDGE: ~var
|
// LOWEDGE: ~var
|
||||||
AstNode* newp = NULL;
|
AstNode* newp = NULL;
|
||||||
if (nodep->edgeType() == VEdgeType::ET_ILLEGAL) {
|
if (nodep->edgeType() == VEdgeType::ET_ILLEGAL) {
|
||||||
if (!v3Global.opt.bboxUnsup()) {
|
nodep->v3warn(E_UNSUPPORTED,
|
||||||
nodep->v3error(
|
"Unsupported: Complicated event expression in sensitive activity list");
|
||||||
"Unsupported: Complicated event expression in sensitive activity list");
|
|
||||||
}
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
AstVarScope* clkvscp = nodep->varrefp()->varScopep();
|
AstVarScope* clkvscp = nodep->varrefp()->varScopep();
|
||||||
@@ -142,23 +136,11 @@ private:
|
|||||||
}
|
}
|
||||||
return newp;
|
return newp;
|
||||||
}
|
}
|
||||||
AstNode* createSenGateEquation(AstSenGate* nodep) {
|
AstNode* createSenseEquation(AstSenItem* nodesp) {
|
||||||
AstNode* newp = new AstAnd(nodep->fileline(), createSenseEquation(nodep->sensesp()),
|
|
||||||
nodep->rhsp()->cloneTree(true));
|
|
||||||
return newp;
|
|
||||||
}
|
|
||||||
AstNode* createSenseEquation(AstNodeSenItem* nodesp) {
|
|
||||||
// Nodep may be a list of elements; we need to walk it
|
// Nodep may be a list of elements; we need to walk it
|
||||||
AstNode* senEqnp = NULL;
|
AstNode* senEqnp = NULL;
|
||||||
for (AstNodeSenItem* senp = nodesp; senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) {
|
for (AstSenItem* senp = nodesp; senp; senp = VN_CAST(senp->nextp(), SenItem)) {
|
||||||
AstNode* senOnep = NULL;
|
AstNode* const senOnep = createSenItemEquation(senp);
|
||||||
if (AstSenItem* itemp = VN_CAST(senp, SenItem)) {
|
|
||||||
senOnep = createSenItemEquation(itemp);
|
|
||||||
} else if (AstSenGate* itemp = VN_CAST(senp, SenGate)) {
|
|
||||||
senOnep = createSenGateEquation(itemp);
|
|
||||||
} else {
|
|
||||||
senp->v3fatalSrc("Strange node under sentree");
|
|
||||||
}
|
|
||||||
if (senEqnp) {
|
if (senEqnp) {
|
||||||
// Add new OR to the sensitivity list equation
|
// Add new OR to the sensitivity list equation
|
||||||
senEqnp = new AstOr(senp->fileline(), senEqnp, senOnep);
|
senEqnp = new AstOr(senp->fileline(), senEqnp, senOnep);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user